// Copyright 2019 Robin Krahl // SPDX-License-Identifier: GPL-3.0-or-later use usb_device::bus::{InterfaceNumber, StringIndex, UsbBus, UsbBusAllocator}; use usb_device::class::{ControlIn, ControlOut, UsbClass}; use usb_device::descriptor::DescriptorWriter; use usb_device::endpoint::{EndpointAddress, EndpointIn}; use usb_device::Result; const INTERFACE_CLASS_HID: u8 = 0x03; enum_u8! { #[derive(Clone, Copy, Debug, PartialEq)] pub enum Subclass { None = 0x00, BootInterface = 0x01, } } enum_u8! { #[derive(Clone, Copy, Debug, PartialEq)] pub enum Protocol { None = 0x00, Keyboard = 0x01, Mouse = 0x02, } } pub trait HidDevice { fn subclass(&self) -> Subclass; fn protocol(&self) -> Protocol; } pub struct HidClass<'a, B: UsbBus, D: HidDevice> { device: D, interface: InterfaceNumber, endpoint_interrupt_in: EndpointIn<'a, B>, expect_interrupt_in_complete: bool, } impl HidClass<'_, B, D> { pub fn new(device: D, alloc: &UsbBusAllocator) -> HidClass<'_, B, D> { HidClass { device, interface: alloc.interface(), endpoint_interrupt_in: alloc.interrupt(8, 10), expect_interrupt_in_complete: false, } } } impl UsbClass for HidClass<'_, B, D> { fn poll(&mut self) {} fn reset(&mut self) { self.expect_interrupt_in_complete = false; } fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { writer.interface( self.interface, INTERFACE_CLASS_HID, self.device.subclass().into(), self.device.protocol().into(), )?; writer.endpoint(&self.endpoint_interrupt_in)?; Ok(()) } fn get_string(&self, _index: StringIndex, _lang_id: u16) -> Option<&str> { None } fn endpoint_in_complete(&mut self, addr: EndpointAddress) { if addr == self.endpoint_interrupt_in.address() { if self.expect_interrupt_in_complete { self.expect_interrupt_in_complete = false; } else { panic!("unexpected endpoint_in_complete"); } } } fn endpoint_out(&mut self, _addr: EndpointAddress) {} fn control_in(&mut self, _xfer: ControlIn) {} fn control_out(&mut self, _xfer: ControlOut) {} }