diff options
author | Brian Cully <bjc@kublai.com> | 2019-07-25 09:40:31 -0400 |
---|---|---|
committer | Brian Cully <bjc@kublai.com> | 2019-07-25 10:14:46 -0400 |
commit | 7966be1419d3eaa088ed83f95282383182585640 (patch) | |
tree | 3b7b09eb768d47e327035301f53f3bd23b7596f2 /usbh/src/usbproto.rs | |
parent | 5b48a5c2f5526f088187fa341f64368994c9f517 (diff) | |
download | samd21-demo-7966be1419d3eaa088ed83f95282383182585640.tar.gz samd21-demo-7966be1419d3eaa088ed83f95282383182585640.zip |
Move USB host stuff to separate crate.
Diffstat (limited to 'usbh/src/usbproto.rs')
-rw-r--r-- | usbh/src/usbproto.rs | 331 |
1 files changed, 331 insertions, 0 deletions
diff --git a/usbh/src/usbproto.rs b/usbh/src/usbproto.rs new file mode 100644 index 0000000..9c1dbcb --- /dev/null +++ b/usbh/src/usbproto.rs @@ -0,0 +1,331 @@ +/// USB Protocol level types and functions. +/// +/// Everything in here is defined by the USB specification, and +/// hardware independent. + +// TODO: Put protocol section references in for types and +// documentation. + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct USBDeviceDescriptor { + pub b_length: u8, + pub b_descriptor_type: u8, + pub bcd_usb: u16, + pub b_device_class: u8, + pub b_device_sub_class: u8, + pub b_device_protocol: u8, + pub b_max_packet_size: u8, + pub id_vendor: u16, + pub id_product: u16, + pub bcd_device: u16, + pub i_manufacturer: u8, + pub i_product: u8, + pub i_serial_number: u8, + pub b_num_configurations: u8, +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct USBConfigurationDescriptor { + pub b_length: u8, + pub b_descriptor_type: u8, + pub w_total_length: u16, + pub b_num_interfaces: u8, + pub b_configuration_value: u8, + pub i_configuration: u8, + pub bm_attributes: u8, + pub b_max_power: u8, +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct USBInterfaceDescriptor { + pub b_length: u8, + pub b_descriptor_type: u8, + pub b_interface_number: u8, + pub b_alternate_setting: u8, + pub b_num_endpoints: u8, + pub b_interface_class: u8, + pub b_interface_sub_class: u8, + pub b_interface_protocol: u8, + pub i_interface: u8, +} + +#[derive(Copy, Clone, Debug, Default)] +#[repr(C)] +pub struct USBEndpointDescriptor { + pub b_length: u8, + pub b_descriptor_type: u8, + pub b_endpoint_address: u8, + pub bm_attributes: u8, + pub w_max_packet_size: u16, + pub b_interval: u8, +} + +#[derive(Copy, Clone, Debug)] +#[repr(C)] +pub struct USBSetupPacket { + pub bm_request_type: BMRequestType, + pub b_request: USBRequest, + pub w_value: WValue, + pub w_index: u16, + pub w_length: u16, +} +// TODO: shortcuts for standard device requests ยง9.4 of USB standard. + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum USBSetupDirection { + HostToDevice = 0x00, + DeviceToHost = 0x80, +} +impl<T> From<T> for USBSetupDirection +where + T: Into<u8>, +{ + fn from(v: T) -> Self { + match v.into() { + 0x00 => Self::HostToDevice, + 0x80 => Self::DeviceToHost, + _ => panic!("direction can only be 0x00 or 0x80"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum USBSetupType { + Standard = 0x00, + Class = 0x20, + Vendor = 0x40, +} +impl<T> From<T> for USBSetupType +where + T: Into<u8>, +{ + fn from(v: T) -> Self { + match v.into() { + 0x00 => Self::Standard, + 0x20 => Self::Class, + 0x40 => Self::Vendor, + _ => panic!("type can only be 0x00, 0x20, or 0x40"), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum USBSetupRecipient { + Device = 0x00, + Interface = 0x01, + Endpoint = 0x02, + Other = 0x03, +} +impl<T> From<T> for USBSetupRecipient +where + T: Into<u8>, +{ + fn from(v: T) -> Self { + match v.into() { + 0x00 => Self::Device, + 0x01 => Self::Interface, + 0x02 => Self::Endpoint, + 0x03 => Self::Other, + _ => panic!("recipient can only be between 0 and 3"), + } + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[repr(C)] +pub struct BMRequestType(u8); +impl BMRequestType { + // Get descriptor request type. + pub fn get_descr() -> Self { + Self::from(( + USBSetupDirection::DeviceToHost, + USBSetupType::Standard, + USBSetupRecipient::Device, + )) + } + + // Set request type for all but 'set feature' and 'set interface'. + pub fn set() -> Self { + Self::from(( + USBSetupDirection::HostToDevice, + USBSetupType::Standard, + USBSetupRecipient::Device, + )) + } + + // Get interface request type. + pub fn cl_get_intf() -> Self { + Self::from(( + USBSetupDirection::DeviceToHost, + USBSetupType::Class, + USBSetupRecipient::Interface, + )) + } + + pub fn recipient(&self) -> USBSetupRecipient { + const POS: u8 = 0; + const MASK: u8 = 0x1f; + (self.0 & (MASK << POS)).into() + } + + pub fn set_recipient(&mut self, v: USBSetupRecipient) { + const POS: u8 = 0; + const MASK: u8 = 0x1f; + self.0 &= !(MASK << POS); + self.0 |= v as u8 & MASK; + } + + pub fn typ(&self) -> USBSetupType { + const POS: u8 = 5; + const MASK: u8 = 0x3; + (self.0 & (MASK << POS)).into() + } + + pub fn set_typ(&mut self, v: USBSetupType) { + const POS: u8 = 5; + const MASK: u8 = 0x3; + self.0 &= !(MASK << POS); + self.0 |= v as u8 & MASK; + } + + pub fn direction(&self) -> USBSetupDirection { + const POS: u8 = 7; + const MASK: u8 = 0x1; + (self.0 & (MASK << POS)).into() + } + + pub fn set_direction(&mut self, v: USBSetupDirection) { + const POS: u8 = 7; + const MASK: u8 = 0x1; + self.0 &= !(MASK << POS); + self.0 |= v as u8 & MASK; + } +} +impl From<u8> for BMRequestType { + fn from(v: u8) -> Self { + Self(v) + } +} +impl From<(USBSetupDirection, USBSetupType, USBSetupRecipient)> for BMRequestType { + fn from(v: (USBSetupDirection, USBSetupType, USBSetupRecipient)) -> Self { + Self(v.0 as u8 | v.1 as u8 | v.2 as u8) + } +} + +#[derive(Clone, Copy, Debug, Default, PartialEq)] +#[repr(C)] +pub struct WValue(u16); +impl WValue { + pub fn w_value_lo(&self) -> u8 { + const POS: u8 = 0; + const MASK: u16 = 0xff; + ((self.0 >> POS) & MASK) as u8 + } + + pub fn set_w_value_lo(&mut self, v: u8) { + const POS: u8 = 0; + const MASK: u8 = 0xff; + self.0 &= !((MASK as u16) << POS); + self.0 |= ((v & MASK) as u16) << POS; + } + + pub fn w_value_hi(&self) -> u8 { + const POS: u8 = 8; + const MASK: u16 = 0xff; + ((self.0 >> POS) & MASK) as u8 + } + + pub fn set_w_value_hi(&mut self, v: u8) { + const POS: u8 = 8; + const MASK: u8 = 0xff; + self.0 &= !((MASK as u16) << POS); + self.0 |= ((v & MASK) as u16) << POS; + } +} +impl From<(u8, u8)> for WValue { + fn from(v: (u8, u8)) -> Self { + let mut rc = Self(0); + rc.set_w_value_lo(v.0); + rc.set_w_value_hi(v.1); + rc + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum USBRequest { + GetStatus = 0, + ClearFeature = 1, + SetFeature = 3, + SetAddress = 5, + GetDescriptor = 6, + SetDescriptor = 7, + GetConfiguration = 8, + SetConfiguration = 9, + GetInterface = 10, + SetInterface = 11, + SynchFrame = 12, +} +impl<T> From<T> for USBRequest +where + T: Into<u8>, +{ + fn from(v: T) -> Self { + match v.into() { + 0 => Self::GetStatus, + 1 => Self::ClearFeature, + 3 => Self::SetFeature, + 5 => Self::SetAddress, + 6 => Self::GetDescriptor, + 7 => Self::SetDescriptor, + 8 => Self::GetConfiguration, + 9 => Self::SetConfiguration, + 10 => Self::GetInterface, + 11 => Self::SetInterface, + 12 => Self::SynchFrame, + _ => panic!("invalid request value"), + } + } +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum USBFeature { + EndpointHalt = 0, + DeviceRemoteWakeup = 1, + TestMode = 2, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum USBDescriptor { + Device = 0x01, + Configuration = 0x02, + String = 0x03, + Interface = 0x04, + Endpoint = 0x05, + DeviceQualifier = 0x06, + OtherSpeed = 0x07, + InterfacePower = 0x08, + OTG = 0x09, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum HIDDescriptor { + HID = 0x21, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum OTGFeature { + BHNPEnable = 3, + AHNPSupport = 4, + AAltHNPSupport = 5, +} + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum USBTransferType { + Control = 0x00, + Isochronous = 0x01, + Bulk = 0x02, + Interrupt = 0x03, +} |