diff options
| author | Robin Krahl <robin.krahl@ireas.org> | 2019-02-18 14:20:14 +0000 | 
|---|---|---|
| committer | Robin Krahl <robin.krahl@ireas.org> | 2019-02-18 15:53:20 +0100 | 
| commit | 97e448c1d9921cd084e1da70f3943bead03474ed (patch) | |
| tree | f48471939041af16d1347fee1e877bffaada3dcb | |
| parent | a9e4071913ef1ce32cb4a1581d5683ad56627ec2 (diff) | |
| download | ntw-97e448c1d9921cd084e1da70f3943bead03474ed.tar.gz ntw-97e448c1d9921cd084e1da70f3943bead03474ed.tar.bz2 | |
hid: Add support for {Get,Set}_Report requests
This patch adds support for Get_Report and Set_Report requests to
HidClass.  We parse the request metadata and the delegate the request
handling to the HidDevice.
Our HidDevice implementation, Nitrokey, stores the data sent with
Set_Report requests.  The Get_Report handling is not implemented yet.
| -rw-r--r-- | src/device.rs | 30 | ||||
| -rw-r--r-- | src/hid.rs | 106 | 
2 files changed, 120 insertions, 16 deletions
| diff --git a/src/device.rs b/src/device.rs index f71caf0..f7c4fc7 100644 --- a/src/device.rs +++ b/src/device.rs @@ -4,11 +4,12 @@  use usb_device::bus::{UsbBus, UsbBusAllocator};  use usb_device::device::{UsbDevice, UsbDeviceBuilder, UsbVidPid}; -use crate::hid::{HidDevice, Protocol, Subclass}; +use crate::hid::{HidDevice, Protocol, ReportType, Subclass};  const VID_CLAY_LOGIC: u16 = 0x20a0;  const PID_NITROKEY_PRO: u16 = 0x4108; +const REPORT_LEN: usize = 64;  const REPORT_DESCRIPTOR: &[u8] = &[      0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01,      0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x03, 0x95, 0x05, 0x75, 0x01, @@ -17,11 +18,15 @@ const REPORT_DESCRIPTOR: &[u8] = &[      0x75, 0x08, 0x95, 0x40, 0xB1, 0x02, 0xC0,  ]; -pub struct Nitrokey {} +pub struct Nitrokey { +    buf: [u8; REPORT_LEN], +}  impl Nitrokey {      pub fn new() -> Self { -        Nitrokey {} +        Nitrokey { +            buf: [0; REPORT_LEN], +        }      }  } @@ -37,6 +42,25 @@ impl HidDevice for Nitrokey {      fn report_descriptor(&self) -> &[u8] {          REPORT_DESCRIPTOR      } + +    fn get_report(&mut self, report_type: ReportType, report_id: u8) -> Result<&[u8], ()> { +        let _ = (report_type, report_id); +        Err(()) +    } + +    fn set_report( +        &mut self, +        report_type: ReportType, +        report_id: u8, +        data: &[u8], +    ) -> Result<(), ()> { +        if report_type != ReportType::Feature || report_id != 0 || data.len() != REPORT_LEN { +            Err(()) +        } else { +            self.buf.copy_from_slice(data); +            Ok(()) +        } +    }  }  pub fn create_usb_device<B: UsbBus>(alloc: &UsbBusAllocator<B>) -> UsbDevice<'_, B> { @@ -3,10 +3,13 @@  use usb_device::bus::{InterfaceNumber, StringIndex, UsbBus, UsbBusAllocator};  use usb_device::class::{ControlIn, ControlOut, UsbClass}; -use usb_device::control::{Recipient, Request, RequestType}; +use usb_device::control; +use usb_device::control::{Recipient, RequestType};  use usb_device::descriptor::DescriptorWriter;  use usb_device::endpoint::{EndpointAddress, EndpointIn}; -use usb_device::{Result, UsbError}; +use usb_device::UsbError; + +use crate::util::TryFrom;  const SPECIFICATION_RELEASE: u16 = 0x111;  const INTERFACE_CLASS_HID: u8 = 0x03; @@ -37,12 +40,48 @@ enum_u8! {      }  } +enum_u8! { +    #[derive(Debug, Clone, Copy, PartialEq)] +    pub enum Request { +        GetReport = 0x01, +        GetIdle = 0x02, +        GetProtocol = 0x03, +        SetReport = 0x09, +        SetIdle = 0x0a, +        SetProtocol = 0x0b, +    } +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ReportType { +    Input, +    Output, +    Feature, +    Reserved(u8), +} + +impl From<u8> for ReportType { +    fn from(val: u8) -> Self { +        match val { +            1 => ReportType::Input, +            2 => ReportType::Output, +            3 => ReportType::Feature, +            _ => ReportType::Reserved(val), +        } +    } +} +  pub trait HidDevice {      fn subclass(&self) -> Subclass;      fn protocol(&self) -> Protocol;      fn report_descriptor(&self) -> &[u8]; + +    fn set_report(&mut self, report_type: ReportType, report_id: u8, data: &[u8]) +        -> Result<(), ()>; + +    fn get_report(&mut self, report_type: ReportType, report_id: u8) -> Result<&[u8], ()>;  }  pub struct HidClass<'a, B: UsbBus, D: HidDevice> { @@ -62,7 +101,7 @@ impl<B: UsbBus, D: HidDevice> HidClass<'_, B, D> {          }      } -    fn get_report_descriptor(&self, index: u8, buf: &mut [u8]) -> Result<usize> { +    fn get_report_descriptor(&self, index: u8, buf: &mut [u8]) -> usb_device::Result<usize> {          if index == 0 {              let report_descriptor = self.device.report_descriptor();              let len = report_descriptor.len(); @@ -76,6 +115,26 @@ impl<B: UsbBus, D: HidDevice> HidClass<'_, B, D> {              Err(UsbError::InvalidState)          }      } + +    fn get_report(&mut self, xfer: ControlIn<B>) { +        let req = xfer.request(); +        let [report_type, report_id] = req.value.to_be_bytes(); +        let report_type = ReportType::from(report_type); +        match self.device.get_report(report_type, report_id) { +            Ok(data) => xfer.accept_with(data).ok(), +            Err(()) => xfer.reject().ok(), +        }; +    } + +    fn set_report(&mut self, xfer: ControlOut<B>) { +        let req = xfer.request(); +        let [report_type, report_id] = req.value.to_be_bytes(); +        let report_type = ReportType::from(report_type); +        match self.device.set_report(report_type, report_id, xfer.data()) { +            Ok(()) => xfer.accept().ok(), +            Err(()) => xfer.reject().ok(), +        }; +    }  }  impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> { @@ -85,7 +144,10 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {          self.expect_interrupt_in_complete = false;      } -    fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { +    fn get_configuration_descriptors( +        &self, +        writer: &mut DescriptorWriter, +    ) -> usb_device::Result<()> {          writer.interface(              self.interface,              INTERFACE_CLASS_HID, @@ -136,17 +198,35 @@ impl<B: UsbBus, D: HidDevice> UsbClass<B> for HidClass<'_, B, D> {      fn control_in(&mut self, xfer: ControlIn<B>) {          let req = xfer.request(); -        if req.request_type == RequestType::Standard -            && req.recipient == Recipient::Interface -            && req.request == Request::GET_DESCRIPTOR -        { -            let (dtype, index) = req.descriptor_type_index(); -            if dtype == DescriptorType::Report.into() { -                xfer.accept(|mut buf| self.get_report_descriptor(index, &mut buf)) -                    .ok(); +        match (req.request_type, req.recipient) { +            (RequestType::Standard, Recipient::Interface) => { +                if req.request == control::Request::GET_DESCRIPTOR { +                    let (dtype, index) = req.descriptor_type_index(); +                    if dtype == DescriptorType::Report.into() { +                        xfer.accept(|mut buf| self.get_report_descriptor(index, &mut buf)) +                            .ok(); +                    } +                } +            } +            (RequestType::Class, Recipient::Interface) => { +                if let Ok(request) = Request::try_from(req.request) { +                    if request == Request::GetReport { +                        self.get_report(xfer); +                    } +                }              } +            _ => {}          }      } -    fn control_out(&mut self, _xfer: ControlOut<B>) {} +    fn control_out(&mut self, xfer: ControlOut<B>) { +        let req = xfer.request(); +        if req.request_type == RequestType::Class && req.recipient == Recipient::Interface { +            if let Ok(request) = Request::try_from(req.request) { +                if request == Request::SetReport { +                    self.set_report(xfer); +                } +            } +        } +    }  } | 
