aboutsummaryrefslogtreecommitdiffstats
path: root/usbh/src/usbproto.rs
diff options
context:
space:
mode:
authorBrian Cully <bjc@kublai.com>2019-07-25 09:40:31 -0400
committerBrian Cully <bjc@kublai.com>2019-07-25 10:14:46 -0400
commit7966be1419d3eaa088ed83f95282383182585640 (patch)
tree3b7b09eb768d47e327035301f53f3bd23b7596f2 /usbh/src/usbproto.rs
parent5b48a5c2f5526f088187fa341f64368994c9f517 (diff)
downloadsamd21-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.rs331
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,
+}