├── .gitignore ├── tests └── test_class_host │ ├── 99-usb-test-class.rules │ ├── device.rs │ ├── main.rs │ └── tests.rs ├── .github └── workflows │ ├── rustfmt.yml │ └── ci.yml ├── src ├── macros.rs ├── dummy.rs ├── control.rs ├── device_builder.rs ├── class.rs ├── endpoint.rs ├── control_pipe.rs ├── lib.rs ├── test_class.rs ├── bus.rs ├── descriptor.rs ├── descriptor │ └── lang_id.rs └── device.rs ├── LICENSE ├── Cargo.toml ├── README.md └── CHANGELOG.md /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | Cargo.lock 3 | scratch.txt -------------------------------------------------------------------------------- /tests/test_class_host/99-usb-test-class.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEM=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", ATTRS{serial}=="TestClass Serial", MODE="0666" 2 | -------------------------------------------------------------------------------- /.github/workflows/rustfmt.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: Code formatting check 7 | 8 | jobs: 9 | fmt: 10 | name: Rustfmt 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - uses: dtolnay/rust-toolchain@stable 15 | with: 16 | components: rustfmt 17 | - run: cargo fmt --all -- --check 18 | - run: cargo clippy --all-features 19 | - run: cargo clippy --features defmt 20 | - run: cargo clippy --features log 21 | - run: cargo clippy 22 | -------------------------------------------------------------------------------- /src/macros.rs: -------------------------------------------------------------------------------- 1 | #[cfg(all(feature = "log", not(feature = "defmt")))] 2 | macro_rules! usb_log { 3 | (trace, $($arg:expr),*) => { log::trace!($($arg),*) }; 4 | (debug, $($arg:expr),*) => { log::debug!($($arg),*) }; 5 | } 6 | 7 | #[cfg(feature = "defmt")] 8 | macro_rules! usb_log { 9 | (trace, $($arg:expr),*) => { defmt::trace!($($arg),*) }; 10 | (debug, $($arg:expr),*) => { defmt::debug!($($arg),*) }; 11 | } 12 | 13 | #[cfg(not(any(feature = "log", feature = "defmt")))] 14 | macro_rules! usb_log { 15 | ($level:ident, $($arg:expr),*) => {{ $( let _ = $arg; )* }} 16 | } 17 | 18 | macro_rules! usb_trace { 19 | ($($arg:expr),*) => (usb_log!(trace, $($arg),*)); 20 | } 21 | 22 | macro_rules! usb_debug { 23 | ($($arg:expr),*) => (usb_log!(debug, $($arg),*)); 24 | } 25 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: [ staging, trying, master ] 4 | pull_request: 5 | 6 | name: CI 7 | 8 | jobs: 9 | ci-linux: 10 | name: CI 11 | runs-on: ubuntu-latest 12 | 13 | strategy: 14 | matrix: 15 | rust: [stable] 16 | 17 | include: 18 | # Test nightly but don't fail 19 | - rust: nightly 20 | experimental: true 21 | TARGET: x86_64-unknown-linux-gnu 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - uses: dtolnay/rust-toolchain@master 26 | with: 27 | toolchain: ${{ matrix.rust }} 28 | targets: ${{ matrix.TARGET }} 29 | 30 | - name: Install libusb library 31 | run: sudo apt-get install -y libusb-1.0.0-dev 32 | 33 | - run: cargo check --all-targets 34 | - run: cargo check --features defmt 35 | - run: cargo check --features log 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Matti Virkkunen 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "usb-device" 3 | description = "USB stack for embedded devices." 4 | version = "0.3.2" 5 | edition = "2018" 6 | readme = "README.md" 7 | keywords = ["no-std", "embedded", "usb"] 8 | license = "MIT" 9 | authors = ["Matti Virkkunen "] 10 | repository = "https://github.com/rust-embedded-community/usb-device" 11 | 12 | [dependencies] 13 | defmt = { version = "0.3", optional = true } 14 | portable-atomic = { version = "1.2.0", default-features = false } 15 | heapless = "0.8" 16 | log = { version = "0.4", default-features = false, optional = true} 17 | 18 | [dev-dependencies] 19 | rusb = "0.9.1" 20 | rand = "0.8.5" 21 | 22 | [features] 23 | 24 | # Use larger endpoint buffers for highspeed operation (default fullspeed) 25 | # 26 | # Note: usb-device doesn't truly support high speed enumeration yet, so setting this will make 27 | # TestClass only compliant with high speed mode. It may still manage to be enumerated as a full 28 | # speed device, but the descriptors will be invalid. 29 | test-class-high-speed = [] 30 | 31 | [[test]] 32 | name = "test_class_host" 33 | path = "tests/test_class_host/main.rs" 34 | harness = false 35 | -------------------------------------------------------------------------------- /src/dummy.rs: -------------------------------------------------------------------------------- 1 | #![allow(unused_variables)] 2 | 3 | use crate::bus::UsbBus; 4 | 5 | /// Dummy bus implementation with no functionality. 6 | /// 7 | /// Examples can create an instance of this bus just to make them compile. 8 | pub struct DummyUsbBus; 9 | 10 | impl DummyUsbBus { 11 | /// Creates a new `DummyUsbBus`. 12 | pub fn new() -> Self { 13 | Self 14 | } 15 | } 16 | 17 | impl Default for DummyUsbBus { 18 | fn default() -> Self { 19 | Self::new() 20 | } 21 | } 22 | 23 | impl UsbBus for DummyUsbBus { 24 | fn alloc_ep( 25 | &mut self, 26 | ep_dir: crate::UsbDirection, 27 | ep_addr: Option, 28 | ep_type: crate::class_prelude::EndpointType, 29 | max_packet_size: u16, 30 | interval: u8, 31 | ) -> crate::Result { 32 | unimplemented!() 33 | } 34 | 35 | fn enable(&mut self) { 36 | unimplemented!() 37 | } 38 | 39 | fn force_reset(&self) -> crate::Result<()> { 40 | unimplemented!() 41 | } 42 | 43 | fn is_stalled(&self, ep_addr: crate::class_prelude::EndpointAddress) -> bool { 44 | unimplemented!() 45 | } 46 | 47 | fn poll(&self) -> crate::bus::PollResult { 48 | unimplemented!() 49 | } 50 | 51 | fn read( 52 | &self, 53 | ep_addr: crate::class_prelude::EndpointAddress, 54 | buf: &mut [u8], 55 | ) -> crate::Result { 56 | unimplemented!() 57 | } 58 | 59 | fn reset(&self) { 60 | unimplemented!() 61 | } 62 | 63 | fn resume(&self) { 64 | unimplemented!() 65 | } 66 | 67 | fn set_device_address(&self, addr: u8) { 68 | unimplemented!() 69 | } 70 | 71 | fn set_stalled(&self, ep_addr: crate::class_prelude::EndpointAddress, stalled: bool) { 72 | unimplemented!() 73 | } 74 | 75 | fn suspend(&self) { 76 | unimplemented!() 77 | } 78 | 79 | fn write( 80 | &self, 81 | ep_addr: crate::class_prelude::EndpointAddress, 82 | buf: &[u8], 83 | ) -> crate::Result { 84 | unimplemented!() 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/test_class_host/device.rs: -------------------------------------------------------------------------------- 1 | use rusb::{ConfigDescriptor, Context, DeviceDescriptor, DeviceHandle, Language, UsbContext as _}; 2 | use std::time::Duration; 3 | use usb_device::test_class; 4 | 5 | pub const TIMEOUT: Duration = Duration::from_secs(1); 6 | pub const EN_US: u16 = 0x0409; 7 | 8 | pub struct DeviceHandles { 9 | pub device_descriptor: DeviceDescriptor, 10 | pub config_descriptor: ConfigDescriptor, 11 | pub handle: DeviceHandle, 12 | pub en_us: Language, 13 | } 14 | 15 | impl DeviceHandles { 16 | /// Indicates if this device is (true) or isn't (false) a 17 | /// high-speed device. 18 | pub fn is_high_speed(&self) -> bool { 19 | self.handle.device().speed() == rusb::Speed::High 20 | } 21 | /// Returns the max packet size for the `TestClass` bulk endpoint(s). 22 | pub fn bulk_max_packet_size(&self) -> u16 { 23 | self.config_descriptor 24 | .interfaces() 25 | .flat_map(|intf| intf.descriptors()) 26 | .flat_map(|desc| { 27 | desc.endpoint_descriptors() 28 | .find(|ep| { 29 | // Assumes that IN and OUT endpoint MPSes are the same. 30 | ep.transfer_type() == rusb::TransferType::Bulk 31 | }) 32 | .map(|ep| ep.max_packet_size()) 33 | }) 34 | .next() 35 | .expect("TestClass has at least one bulk endpoint") 36 | } 37 | } 38 | 39 | impl ::std::ops::Deref for DeviceHandles { 40 | type Target = DeviceHandle; 41 | 42 | fn deref(&self) -> &DeviceHandle { 43 | &self.handle 44 | } 45 | } 46 | 47 | impl ::std::ops::DerefMut for DeviceHandles { 48 | fn deref_mut(&mut self) -> &mut DeviceHandle { 49 | &mut self.handle 50 | } 51 | } 52 | 53 | pub fn open_device(ctx: &Context) -> rusb::Result { 54 | for device in ctx.devices()?.iter() { 55 | let device_descriptor = device.device_descriptor()?; 56 | 57 | if !(device_descriptor.vendor_id() == test_class::VID 58 | && device_descriptor.product_id() == test_class::PID) 59 | { 60 | continue; 61 | } 62 | 63 | let mut handle = device.open()?; 64 | 65 | let langs = handle.read_languages(TIMEOUT)?; 66 | if langs.is_empty() || langs[0].lang_id() != EN_US { 67 | continue; 68 | } 69 | 70 | let prod = handle.read_product_string(langs[0], &device_descriptor, TIMEOUT)?; 71 | 72 | if prod == test_class::PRODUCT { 73 | handle.reset()?; 74 | 75 | let config_descriptor = device.config_descriptor(0)?; 76 | 77 | return Ok(DeviceHandles { 78 | device_descriptor, 79 | config_descriptor, 80 | handle, 81 | en_us: langs[0], 82 | }); 83 | } 84 | } 85 | 86 | Err(rusb::Error::NoDevice) 87 | } 88 | -------------------------------------------------------------------------------- /tests/test_class_host/main.rs: -------------------------------------------------------------------------------- 1 | mod device; 2 | /// Runs tests against a TestClass device running on actual hardware using libusb. 3 | /// 4 | /// This is implemented as an example as opposed to a test because the Rust test runner system is 5 | /// not well suited for running tests that must depend on outside resources such as hardware and 6 | /// cannot be run in parallel. 7 | mod tests; 8 | 9 | use crate::device::open_device; 10 | use crate::tests::{get_tests, TestFn}; 11 | use std::io::prelude::*; 12 | use std::io::stdout; 13 | use std::panic; 14 | use std::thread; 15 | use std::time::Duration; 16 | use usb_device::device::CONFIGURATION_VALUE; 17 | 18 | fn main() { 19 | let tests = get_tests(); 20 | run_tests(&tests[..]); 21 | } 22 | 23 | fn run_tests(tests: &[(&str, TestFn)]) { 24 | const INTERFACE: u8 = 0; 25 | 26 | println!("test_class_host starting"); 27 | println!("looking for device..."); 28 | 29 | let ctx = rusb::Context::new().expect("create libusb context"); 30 | 31 | // Look for the device for about 5 seconds in case it hasn't finished enumerating yet 32 | let mut dev = Err(rusb::Error::NoDevice); 33 | for _ in 0..50 { 34 | dev = open_device(&ctx); 35 | if dev.is_ok() { 36 | break; 37 | } 38 | 39 | thread::sleep(Duration::from_millis(100)); 40 | } 41 | 42 | let mut dev = match dev { 43 | Ok(d) => d, 44 | Err(err) => { 45 | println!("Did not find a TestClass device. Make sure the device is correctly programmed and plugged in. Last error: {}", err); 46 | return; 47 | } 48 | }; 49 | 50 | println!("\nrunning {} tests", tests.len()); 51 | 52 | let mut success = 0; 53 | for (name, test) in tests { 54 | if let Err(err) = dev.reset() { 55 | println!("Failed to reset the device: {}", err); 56 | return; 57 | } 58 | 59 | if let Err(err) = dev.set_active_configuration(CONFIGURATION_VALUE) { 60 | println!("Failed to set active configuration: {}", err); 61 | return; 62 | } 63 | 64 | if let Err(err) = dev.claim_interface(INTERFACE) { 65 | println!("Failed to claim interface: {}", err); 66 | return; 67 | } 68 | 69 | print!("test {} ... ", name); 70 | let _ = stdout().flush(); 71 | 72 | let mut out = String::new(); 73 | 74 | let res = { 75 | let hook = panic::take_hook(); 76 | panic::set_hook(Box::new(|_| {})); 77 | let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { 78 | test(&mut dev, &mut out); 79 | })); 80 | panic::set_hook(hook); 81 | 82 | res 83 | }; 84 | 85 | dev.release_interface(INTERFACE) 86 | .expect("failed to release interface"); 87 | 88 | if let Err(err) = res { 89 | let err = if let Some(err) = err.downcast_ref::<&'static str>() { 90 | String::from(*err) 91 | } else if let Some(err) = err.downcast_ref::() { 92 | err.clone() 93 | } else { 94 | String::from("???") 95 | }; 96 | 97 | println!("FAILED\nerror: {}\n", err); 98 | } else { 99 | println!("ok"); 100 | 101 | if !out.is_empty() { 102 | print!("{}", out); 103 | } 104 | 105 | success += 1; 106 | } 107 | } 108 | 109 | println!("{} failed, {} succeeded", tests.len() - success, success); 110 | 111 | if success == tests.len() { 112 | println!("\nALL TESTS PASSED!"); 113 | } else { 114 | std::process::exit(1); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | usb-device 2 | ========== 3 | 4 | USB stack for embedded devices in Rust. 5 | 6 | The UsbDevice object represents a composite USB device and is the most important object for 7 | application implementors. The UsbDevice combines a number of UsbClasses (either custom ones, or 8 | pre-existing ones provided by other crates) and a UsbBus device driver to implement the USB device. 9 | 10 | The UsbClass trait can be used to implement USB classes such as a HID device or a serial port. An 11 | implementation may also use a custom class if the required functionality isn't covered by a standard 12 | class. 13 | 14 | The UsbBus trait is intended to be implemented by device-specific crates to provide a driver for 15 | each device's USB peripheral. 16 | 17 | Hardware driver crates 18 | ---------------------- 19 | 20 | * [atsam4](https://github.com/atsam-rs/atsam4-hal) - device-driver implementation for atsam4e & atsam4s microcontrollers (UDP). Examples can be found [here](https://github.com/atsam-rs/sam_xplained). While not expressly supported with this crate, atsam3s and atsam55g could also be supported with a similar code-base. 21 | 22 | * [atsamd](https://github.com/atsamd-rs/atsamd) - device-driver implementation for samd21 & samd51 microcontrollers. An example for the 23 | itsybitsy_m4 board from Adafruit can be found [here](https://github.com/atsamd-rs/atsamd/blob/master/boards/itsybitsy_m4/examples/usb_serial.rs). 24 | 25 | * [imxrt-usbd](https://github.com/imxrt-rs/imxrt-usbd) - device-driver implementation for NXP i.MX RT microcontrollers. Examples for 26 | i.MX RT boards, like the Teensy 4, are maintained with the driver. 27 | 28 | * [musb](https://github.com/decaday/musb) - device-driver implementation for musb (Mentor USB, USB2.0 IP), widely used in various microcontrollers and SoCs from vendors like TI, MediaTek, Puya, and Allwinner. 29 | Examples can be found in [py32-hal](https://github.com/py32-rs/py32-hal/tree/main/examples/usbd-f072). 30 | 31 | * [rp2040-hal](https://github.com/rp-rs/rp-hal) - 32 | device-driver implementation for the raspberry pi RP2040 33 | microcontroller. Examples can be found in the various boards 34 | crates [here](https://github.com/rp-rs/rp-hal-boards). 35 | 36 | * [stm32-usbd](https://github.com/stm32-rs/stm32-usbd) - device-driver implementation for multiple STM32 microcontroller families. 37 | Examples can be found in each individual HAL crate that implements the USB peripheral. 38 | 39 | Class crates 40 | ------------ 41 | 42 | * [usbd-hid](https://github.com/twitchyliquid64/usbd-hid) [![Crates.io](https://img.shields.io/crates/v/usbd-hid.svg)](https://crates.io/crates/usbd-hid) - HID class 43 | * [usbd-human-interface-device](https://github.com/dlkj/usbd-human-interface-device) [![Crates.io](https://img.shields.io/crates/v/usbd-human-interface-device.svg)](https://crates.io/crates/usbd-human-interface-device) - HID class 44 | * [usbd-serial](https://github.com/rust-embedded-community/usbd-serial) [![Crates.io](https://img.shields.io/crates/v/usbd-serial.svg)](https://crates.io/crates/usbd-serial) - CDC-ACM serial port class 45 | * [usbd-storage](https://github.com/apohrebniak/usbd-storage) [![Crates.io](https://img.shields.io/crates/v/usbd-storage.svg)](https://crates.io/crates/usbd-storage) - (Experimental) Mass storage port class 46 | * [usbd-dfu](https://github.com/vitalyvb/usbd-dfu) [![Crates.io](https://img.shields.io/crates/v/usbd-dfu.svg)](https://crates.io/crates/usbd-dfu) - Device Firmware Upgrade class 47 | * [usbd-picotool-reset](https://github.com/ithinuel/usbd-picotool-reset) [![Crates.io](https://img.shields.io/crates/v/usbd-picotool-reset.svg)](https://crates.io/crates/usbd-picotool-reset) - picotool-reset class 48 | * [usbd-midi](https://github.com/rust-embedded-community/usbd-midi) [![Crates.io](https://img.shields.io/crates/v/usbd-midi.svg)](https://crates.io/crates/usbd-midi) - MIDI class 49 | * [usbd-audio](https://github.com/kiffie/usbd-audio) [![Crates.io](https://img.shields.io/crates/v/usbd-audio.svg)](https://crates.io/crates/usbd-audio) - (Experimental) Audio class 50 | 51 | Others 52 | ------ 53 | 54 | Other implementations for USB in Rust 55 | 56 | * The [Embassy](https://github.com/embassy-rs/embassy) project has an async USB stack, embassy-usb. 57 | -------------------------------------------------------------------------------- /src/control.rs: -------------------------------------------------------------------------------- 1 | use crate::{Result, UsbDirection, UsbError}; 2 | use core::mem; 3 | 4 | /// Control request type. 5 | #[repr(u8)] 6 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 7 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 8 | pub enum RequestType { 9 | /// Request is a USB standard request. Usually handled by 10 | /// [`UsbDevice`](crate::device::UsbDevice). 11 | Standard = 0, 12 | /// Request is intended for a USB class. 13 | Class = 1, 14 | /// Request is vendor-specific. 15 | Vendor = 2, 16 | /// Reserved. 17 | Reserved = 3, 18 | } 19 | 20 | /// Control request recipient. 21 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 22 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 23 | pub enum Recipient { 24 | /// Request is intended for the entire device. 25 | Device = 0, 26 | /// Request is intended for an interface. Generally, the `index` field of the request specifies 27 | /// the interface number. 28 | Interface = 1, 29 | /// Request is intended for an endpoint. Generally, the `index` field of the request specifies 30 | /// the endpoint address. 31 | Endpoint = 2, 32 | /// None of the above. 33 | Other = 3, 34 | /// Reserved. 35 | Reserved = 4, 36 | } 37 | 38 | /// A control request read from a SETUP packet. 39 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 40 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 41 | pub struct Request { 42 | /// Direction of the request. 43 | pub direction: UsbDirection, 44 | /// Type of the request. 45 | pub request_type: RequestType, 46 | /// Recipient of the request. 47 | pub recipient: Recipient, 48 | /// Request code. The meaning of the value depends on the previous fields. 49 | pub request: u8, 50 | /// Request value. The meaning of the value depends on the previous fields. 51 | pub value: u16, 52 | /// Request index. The meaning of the value depends on the previous fields. 53 | pub index: u16, 54 | /// Length of the DATA stage. For control OUT transfers this is the exact length of the data the 55 | /// host sent. For control IN transfers this is the maximum length of data the device should 56 | /// return. 57 | pub length: u16, 58 | } 59 | 60 | impl Request { 61 | /// Standard USB control request Get Status 62 | pub const GET_STATUS: u8 = 0; 63 | 64 | /// Standard USB control request Clear Feature 65 | pub const CLEAR_FEATURE: u8 = 1; 66 | 67 | /// Standard USB control request Set Feature 68 | pub const SET_FEATURE: u8 = 3; 69 | 70 | /// Standard USB control request Set Address 71 | pub const SET_ADDRESS: u8 = 5; 72 | 73 | /// Standard USB control request Get Descriptor 74 | pub const GET_DESCRIPTOR: u8 = 6; 75 | 76 | /// Standard USB control request Set Descriptor 77 | pub const SET_DESCRIPTOR: u8 = 7; 78 | 79 | /// Standard USB control request Get Configuration 80 | pub const GET_CONFIGURATION: u8 = 8; 81 | 82 | /// Standard USB control request Set Configuration 83 | pub const SET_CONFIGURATION: u8 = 9; 84 | 85 | /// Standard USB control request Get Interface 86 | pub const GET_INTERFACE: u8 = 10; 87 | 88 | /// Standard USB control request Set Interface 89 | pub const SET_INTERFACE: u8 = 11; 90 | 91 | /// Standard USB control request Synch Frame 92 | pub const SYNCH_FRAME: u8 = 12; 93 | 94 | /// Standard USB feature Endpoint Halt for Set/Clear Feature 95 | pub const FEATURE_ENDPOINT_HALT: u16 = 0; 96 | 97 | /// Standard USB feature Device Remote Wakeup for Set/Clear Feature 98 | pub const FEATURE_DEVICE_REMOTE_WAKEUP: u16 = 1; 99 | 100 | pub(crate) fn parse(buf: &[u8]) -> Result { 101 | if buf.len() != 8 { 102 | return Err(UsbError::ParseError); 103 | } 104 | 105 | let rt = buf[0]; 106 | let recipient = rt & 0b11111; 107 | 108 | Ok(Request { 109 | direction: rt.into(), 110 | request_type: unsafe { mem::transmute((rt >> 5) & 0b11) }, 111 | recipient: if recipient <= 3 { 112 | unsafe { mem::transmute(recipient) } 113 | } else { 114 | Recipient::Reserved 115 | }, 116 | request: buf[1], 117 | value: (buf[2] as u16) | ((buf[3] as u16) << 8), 118 | index: (buf[4] as u16) | ((buf[5] as u16) << 8), 119 | length: (buf[6] as u16) | ((buf[7] as u16) << 8), 120 | }) 121 | } 122 | 123 | /// Gets the descriptor type and index from the value field of a GET_DESCRIPTOR request. 124 | pub fn descriptor_type_index(&self) -> (u8, u8) { 125 | ((self.value >> 8) as u8, self.value as u8) 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) 6 | and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ### Added 11 | 12 | * `DummyUsbBus` without functionality to allow examples that actually compile (but not run). 13 | * Extended `UsbRev` enum with variants for USB 1.0 and 1.1. 14 | 15 | ### Changed 16 | 17 | * [breaking] The control pipe is now provided in the `UsbDeviceBuilder` API to allow for user-provided control 18 | pipes. This makes it so that control pipes have configurable sizing. 19 | * Don't require UsbBus to be Sync. If a UsbBus is not Sync, it can still be used to make a UsbDevice, but that UsbDevice will not be Sync (ensuring soundness). 20 | 21 | ## [0.3.2] - 2024-03-06 22 | 23 | ### Added 24 | 25 | * A new `log` feature can be enabled to provide logging and tracing information about the USB 26 | interface. 27 | 28 | ### Changed 29 | 30 | * [breaking] LangIDs no longer implement `TryFromPrimitive`. The minor version has not been bumped 31 | as this was not intended to be used in the public API. 32 | * If this is problematic, please open an issue in the main `usb-device` repository. 33 | * Changed handling of EP0 state to eliminate unexpected issues with device enumeration 34 | 35 | ## [0.3.1] - 2023-11-15 36 | 37 | ### Added 38 | 39 | * `BuilderError`, `LangID`, `StringDescriptors` now in `prelude` 40 | * `LangID` now in `class_prelude` 41 | 42 | ### Changed 43 | 44 | * Updated documentation, including example code 45 | 46 | ## [0.3.0] - 2023-11-13 47 | 48 | ### Fixed 49 | 50 | * Fixed a defect where enumeration may fail due to timing-related issues ([#128](https://github.com/rust-embedded-community/usb-device/issues/128)) 51 | 52 | ### Added 53 | 54 | * New enums and allocators for Isochronous endpoints ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)). 55 | * Ability to select USB revision ([#116](https://github.com/rust-embedded-community/usb-device/pull/116)). 56 | * Added support for alternate settings on interfaces ([#114](https://github.com/rust-embedded-community/usb-device/pull/114)). 57 | * Added support for architectures without atomics ([#115](https://github.com/rust-embedded-community/usb-device/pull/115)). 58 | * Added support for multi-language STRING desc ([#122](https://github.com/rust-embedded-community/usb-device/pull/122)). 59 | * `UsbDeviceBuilder` has a public `.extra_lang_ids()` method to specify LANGIDs besides ENGLISH_US(0x0409) 60 | 61 | ### Breaking 62 | 63 | * Acess numeric form of `EndpointType` variants now require a `.to_bm_attributes()`. ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)) 64 | * `DescriptorWriter::iad()` now requires a `Option` to optionally specify a string for describing the function ([#121](https://github.com/rust-embedded-community/usb-device/pull/121)) 65 | * `.manufacturer()`, `.product()` and `.serial_number()` of `UsbDeviceBuilder` are now replaced with the `strings()` function that accepts a `StringDescriptor` list to allow multilanguage support ([#122](https://github.com/rust-embedded-community/usb-device/pull/122)) 66 | * Various methods of the `UsbDeviceBuilder` now return `Result<>` types instead of internally panicking. 67 | 68 | ### Changed 69 | 70 | * `EndpointType` enum now has fields for isochronous synchronization and usage ([#60](https://github.com/rust-embedded-community/usb-device/pull/60)). 71 | * `descriptor_type::STRING` of `fn get_descriptor()` will send the LANGIDs supported by device, and respond STRING Request with specified LANGID. ([#122](https://github.com/rust-embedded-community/usb-device/pull/122)) 72 | * `UsbError` is now copyable and comparable ([#127](https://github.com/rust-embedded-community/usb-device/pull/127)) 73 | 74 | ## [0.2.9] - 2022-08-02 75 | 76 | ### Added 77 | 78 | * Optional support for defmt ([#76](https://github.com/rust-embedded-community/usb-device/pull/76)). 79 | 80 | ### Fixed 81 | 82 | * Fixed an issue where USB devices were not enumerating on Windows ([#32](https://github.com/rust-embedded-community/usb-device/issues/82)) 83 | * Fixed Suspend state transition so it goes back to the previous state, not just Default ([#97](https://github.com/rust-embedded-community/usb-device/pull/97)) 84 | 85 | ## [0.2.8] - 2021-03-13 86 | 87 | ## [0.2.7] - 2020-10-03 88 | 89 | ## [0.2.6] - 2020-09-22 90 | 91 | ## [0.2.5] - 2020-02-10 92 | 93 | ## [0.2.4] - 2020-02-01 94 | 95 | ## [0.2.3] - 2019-08-28 96 | 97 | ## [0.2.2] - 2019-07-27 98 | 99 | ## [0.2.1] - 2019-06-07 100 | 101 | ## [0.2.0] - 2019-06-07 102 | 103 | ## 0.1.0 - 2019-06-07 104 | 105 | This is the initial release to crates.io. 106 | 107 | [Unreleased]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.2...HEAD 108 | [0.3.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.1...v0.3.2 109 | [0.3.1]: https://github.com/rust-embedded-community/usb-device/compare/v0.3.0...v0.3.1 110 | [0.3.0]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.9...v0.3.0 111 | [0.2.9]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.8...v0.2.9 112 | [0.2.8]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.7...v0.2.8 113 | [0.2.7]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.6...v0.2.7 114 | [0.2.6]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.5...v0.2.6 115 | [0.2.5]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.4...v0.2.5 116 | [0.2.4]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.3...v0.2.4 117 | [0.2.3]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.2...v0.2.3 118 | [0.2.2]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.1...v0.2.2 119 | [0.2.1]: https://github.com/rust-embedded-community/usb-device/compare/v0.2.0...v0.2.1 120 | [0.2.0]: https://github.com/rust-embedded-community/usb-device/compare/v0.1.0...v0.2.0 121 | -------------------------------------------------------------------------------- /src/device_builder.rs: -------------------------------------------------------------------------------- 1 | use crate::bus::{UsbBus, UsbBusAllocator}; 2 | use crate::descriptor::lang_id::LangID; 3 | use crate::device::{Config, UsbDevice, UsbRev}; 4 | 5 | /// A USB vendor ID and product ID pair. 6 | pub struct UsbVidPid(pub u16, pub u16); 7 | 8 | /// Used to build new [`UsbDevice`]s. 9 | pub struct UsbDeviceBuilder<'a, B: UsbBus> { 10 | alloc: &'a UsbBusAllocator, 11 | control_buffer: &'a mut [u8], 12 | config: Config<'a>, 13 | } 14 | 15 | macro_rules! builder_fields { 16 | ( $( $(#[$meta:meta])* $name:ident: $type:ty, )* ) => { 17 | $( 18 | $(#[$meta])* 19 | pub fn $name(mut self, $name: $type) -> Self { 20 | self.config.$name = $name; 21 | self 22 | } 23 | )* 24 | } 25 | } 26 | 27 | #[derive(Copy, Clone, Debug, PartialEq)] 28 | /// Error type for the USB device builder 29 | pub enum BuilderError { 30 | /// String descriptors were provided in more languages than are supported 31 | TooManyLanguages, 32 | /// Control endpoint can only be 8, 16, 32, or 64 byte max packet size 33 | InvalidPacketSize, 34 | /// Configuration specifies higher USB power draw than allowed 35 | PowerTooHigh, 36 | /// The provided control buffer is too small for the provided maximum packet size. 37 | ControlBufferTooSmall, 38 | } 39 | 40 | /// Provides basic string descriptors about the device, including the manufacturer, product name, 41 | /// and serial number of the device in a specified language. 42 | #[derive(Copy, Clone, Debug, PartialEq)] 43 | pub struct StringDescriptors<'a> { 44 | pub(crate) id: LangID, 45 | pub(crate) serial: Option<&'a str>, 46 | pub(crate) product: Option<&'a str>, 47 | pub(crate) manufacturer: Option<&'a str>, 48 | } 49 | 50 | impl<'a> Default for StringDescriptors<'a> { 51 | fn default() -> Self { 52 | Self::new(LangID::EN_US) 53 | } 54 | } 55 | 56 | impl<'a> StringDescriptors<'a> { 57 | /// Create a new descriptor list with the provided language. 58 | pub fn new(lang_id: LangID) -> Self { 59 | Self { 60 | id: lang_id, 61 | serial: None, 62 | product: None, 63 | manufacturer: None, 64 | } 65 | } 66 | 67 | /// Specify the serial number for this language. 68 | pub fn serial_number(mut self, serial: &'a str) -> Self { 69 | self.serial.replace(serial); 70 | self 71 | } 72 | 73 | /// Specify the manufacturer name for this language. 74 | pub fn manufacturer(mut self, manufacturer: &'a str) -> Self { 75 | self.manufacturer.replace(manufacturer); 76 | self 77 | } 78 | 79 | /// Specify the product name for this language. 80 | pub fn product(mut self, product: &'a str) -> Self { 81 | self.product.replace(product); 82 | self 83 | } 84 | } 85 | 86 | impl<'a, B: UsbBus> UsbDeviceBuilder<'a, B> { 87 | /// Creates a builder for constructing a new [`UsbDevice`]. 88 | pub fn new( 89 | alloc: &'a UsbBusAllocator, 90 | vid_pid: UsbVidPid, 91 | control_buffer: &'a mut [u8], 92 | ) -> UsbDeviceBuilder<'a, B> { 93 | UsbDeviceBuilder { 94 | alloc, 95 | control_buffer, 96 | config: Config { 97 | device_class: 0x00, 98 | device_sub_class: 0x00, 99 | device_protocol: 0x00, 100 | max_packet_size_0: 8, 101 | vendor_id: vid_pid.0, 102 | product_id: vid_pid.1, 103 | usb_rev: UsbRev::Usb210, 104 | device_release: 0x0010, 105 | string_descriptors: heapless::Vec::new(), 106 | self_powered: false, 107 | supports_remote_wakeup: false, 108 | composite_with_iads: false, 109 | max_power: 50, 110 | }, 111 | } 112 | } 113 | 114 | /// Creates the [`UsbDevice`] instance with the configuration in this builder. 115 | pub fn build(self) -> Result, BuilderError> { 116 | if self.control_buffer.len() < self.config.max_packet_size_0 as usize { 117 | return Err(BuilderError::ControlBufferTooSmall); 118 | } 119 | 120 | Ok(UsbDevice::build( 121 | self.alloc, 122 | self.config, 123 | self.control_buffer, 124 | )) 125 | } 126 | 127 | builder_fields! { 128 | /// Sets the device class code assigned by USB.org. Set to `0xff` for vendor-specific 129 | /// devices that do not conform to any class. 130 | /// 131 | /// Default: `0x00` (class code specified by interfaces) 132 | device_class: u8, 133 | 134 | /// Sets the device sub-class code. Depends on class. 135 | /// 136 | /// Default: `0x00` 137 | device_sub_class: u8, 138 | 139 | /// Sets the device protocol code. Depends on class and sub-class. 140 | /// 141 | /// Default: `0x00` 142 | device_protocol: u8, 143 | 144 | /// Sets the device release version in BCD. 145 | /// 146 | /// Default: `0x0010` ("0.1") 147 | device_release: u16, 148 | 149 | /// Sets whether the device may have an external power source. 150 | /// 151 | /// This should be set to `true` even if the device is sometimes self-powered and may not 152 | /// always draw power from the USB bus. 153 | /// 154 | /// Default: `false` 155 | /// 156 | /// See also: `max_power` 157 | self_powered: bool, 158 | 159 | /// Sets whether the device supports remotely waking up the host is requested. 160 | /// 161 | /// Default: `false` 162 | supports_remote_wakeup: bool, 163 | 164 | /// Sets which Usb 2 revision to comply to. 165 | /// 166 | /// Default: `UsbRev::Usb210` 167 | usb_rev: UsbRev, 168 | } 169 | 170 | /// Configures the device as a composite device with interface association descriptors. 171 | pub fn composite_with_iads(mut self) -> Self { 172 | // Magic values specified in USB-IF ECN on IADs. 173 | self.config.device_class = 0xEF; 174 | self.config.device_sub_class = 0x02; 175 | self.config.device_protocol = 0x01; 176 | 177 | self.config.composite_with_iads = true; 178 | self 179 | } 180 | 181 | /// Specify the strings for the device. 182 | /// 183 | /// # Note 184 | /// Up to 16 languages may be provided. 185 | pub fn strings(mut self, descriptors: &[StringDescriptors<'a>]) -> Result { 186 | // The 16 language limit comes from the size of the buffer used to provide the list of 187 | // language descriptors to the host. 188 | self.config.string_descriptors = 189 | heapless::Vec::from_slice(descriptors).map_err(|_| BuilderError::TooManyLanguages)?; 190 | 191 | Ok(self) 192 | } 193 | 194 | /// Sets the maximum packet size in bytes for the control endpoint 0. 195 | /// 196 | /// Valid values are 8, 16, 32 and 64. There's generally no need to change this from the default 197 | /// value of 8 bytes unless a class uses control transfers for sending large amounts of data, in 198 | /// which case using a larger packet size may be more efficient. 199 | /// 200 | /// Default: 8 bytes 201 | pub fn max_packet_size_0(mut self, max_packet_size_0: u8) -> Result { 202 | match max_packet_size_0 { 203 | 8 | 16 | 32 | 64 => {} 204 | _ => return Err(BuilderError::InvalidPacketSize), 205 | } 206 | 207 | if self.control_buffer.len() < max_packet_size_0 as usize { 208 | return Err(BuilderError::ControlBufferTooSmall); 209 | } 210 | 211 | self.config.max_packet_size_0 = max_packet_size_0; 212 | Ok(self) 213 | } 214 | 215 | /// Sets the maximum current drawn from the USB bus by the device in milliamps. 216 | /// 217 | /// The default is 100 mA. If your device always uses an external power source and never draws 218 | /// power from the USB bus, this can be set to 0. 219 | /// 220 | /// See also: `self_powered` 221 | /// 222 | /// Default: 100mA 223 | pub fn max_power(mut self, max_power_ma: usize) -> Result { 224 | if max_power_ma > 500 { 225 | return Err(BuilderError::PowerTooHigh); 226 | } 227 | 228 | self.config.max_power = (max_power_ma / 2) as u8; 229 | Ok(self) 230 | } 231 | } 232 | -------------------------------------------------------------------------------- /src/class.rs: -------------------------------------------------------------------------------- 1 | use crate::bus::{InterfaceNumber, StringIndex, UsbBus}; 2 | use crate::control; 3 | use crate::control_pipe::ControlPipe; 4 | use crate::descriptor::lang_id::LangID; 5 | use crate::descriptor::{BosWriter, DescriptorWriter}; 6 | use crate::endpoint::EndpointAddress; 7 | use crate::{Result, UsbError}; 8 | 9 | /// A trait for implementing USB classes. 10 | /// 11 | /// All methods are optional callbacks that will be called by 12 | /// [UsbBus::poll](crate::bus::UsbBus::poll) 13 | pub trait UsbClass { 14 | /// Called when a GET_DESCRIPTOR request is received for a configuration descriptor. When 15 | /// called, the implementation should write its interface, endpoint and any extra class 16 | /// descriptors into `writer`. The configuration descriptor itself will be written by 17 | /// [UsbDevice](crate::device::UsbDevice) and shouldn't be written by classes. 18 | /// 19 | /// # Errors 20 | /// 21 | /// Generally errors returned by `DescriptorWriter`. Implementors should propagate any errors 22 | /// using `?`. 23 | fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { 24 | let _ = writer; 25 | Ok(()) 26 | } 27 | 28 | /// Called when a GET_DESCRIPTOR request is received for a BOS descriptor. 29 | /// When called, the implementation should write its blobs such as capability 30 | /// descriptors into `writer`. The BOS descriptor itself will be written by 31 | /// [UsbDevice](crate::device::UsbDevice) and shouldn't be written by classes. 32 | fn get_bos_descriptors(&self, writer: &mut BosWriter) -> Result<()> { 33 | let _ = writer; 34 | Ok(()) 35 | } 36 | 37 | /// Gets a class-specific string descriptor. 38 | /// 39 | /// Note: All string descriptor requests are passed to all classes in turn, so implementations 40 | /// should return [`None`] if an unknown index is requested. 41 | /// 42 | /// # Arguments 43 | /// 44 | /// * `index` - A string index allocated earlier with 45 | /// [`UsbAllocator`](crate::bus::UsbBusAllocator). 46 | /// * `lang_id` - The language ID for the string to retrieve. If the requested lang_id is not 47 | /// valid it will default to EN_US. 48 | fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { 49 | let _ = (index, lang_id); 50 | None 51 | } 52 | 53 | /// Called after a USB reset after the bus reset sequence is complete. 54 | fn reset(&mut self) {} 55 | 56 | /// Called whenever the `UsbDevice` is polled. 57 | fn poll(&mut self) {} 58 | 59 | /// Called when a control request is received with direction HostToDevice. 60 | /// 61 | /// All requests are passed to classes in turn, which can choose to accept, ignore or report an 62 | /// error. Classes can even choose to override standard requests, but doing that is rarely 63 | /// necessary. 64 | /// 65 | /// See [`ControlOut`] for how to respond to the transfer. 66 | /// 67 | /// When implementing your own class, you should ignore any requests that are not meant for your 68 | /// class so that any other classes in the composite device can process them. 69 | /// 70 | /// # Arguments 71 | /// 72 | /// * `req` - The request from the SETUP packet. 73 | /// * `xfer` - A handle to the transfer. 74 | fn control_out(&mut self, xfer: ControlOut) { 75 | let _ = xfer; 76 | } 77 | 78 | /// Called when a control request is received with direction DeviceToHost. 79 | /// 80 | /// All requests are passed to classes in turn, which can choose to accept, ignore or report an 81 | /// error. Classes can even choose to override standard requests, but doing that is rarely 82 | /// necessary. 83 | /// 84 | /// See [`ControlIn`] for how to respond to the transfer. 85 | /// 86 | /// When implementing your own class, you should ignore any requests that are not meant for your 87 | /// class so that any other classes in the composite device can process them. 88 | /// 89 | /// # Arguments 90 | /// 91 | /// * `req` - The request from the SETUP packet. 92 | /// * `data` - Data to send in the DATA stage of the control transfer. 93 | fn control_in(&mut self, xfer: ControlIn) { 94 | let _ = xfer; 95 | } 96 | 97 | /// Called when endpoint with address `addr` has received a SETUP packet. Implementing this 98 | /// shouldn't be necessary in most cases, but is provided for completeness' sake. 99 | /// 100 | /// Note: This method may be called for an endpoint address you didn't allocate, and in that 101 | /// case you should ignore the event. 102 | fn endpoint_setup(&mut self, addr: EndpointAddress) { 103 | let _ = addr; 104 | } 105 | 106 | /// Called when endpoint with address `addr` has received data (OUT packet). 107 | /// 108 | /// Note: This method may be called for an endpoint address you didn't allocate, and in that 109 | /// case you should ignore the event. 110 | fn endpoint_out(&mut self, addr: EndpointAddress) { 111 | let _ = addr; 112 | } 113 | 114 | /// Called when endpoint with address `addr` has completed transmitting data (IN packet). 115 | /// 116 | /// Note: This method may be called for an endpoint address you didn't allocate, and in that 117 | /// case you should ignore the event. 118 | fn endpoint_in_complete(&mut self, addr: EndpointAddress) { 119 | let _ = addr; 120 | } 121 | 122 | /// Called when the interfaces alternate setting state is requested. 123 | /// 124 | /// Note: This method may be called on interfaces, that are not relevant to this class. 125 | /// You should return `None, if `interface` belongs to an interface you don't know. 126 | fn get_alt_setting(&mut self, interface: InterfaceNumber) -> Option { 127 | let _ = interface; 128 | None 129 | } 130 | 131 | /// Called when the interfaces alternate setting state is altered. 132 | /// 133 | /// Note: This method may be called on interfaces, that are not relevant to this class. 134 | /// You should return `false`, if `interface` belongs to an interface you don't know. 135 | fn set_alt_setting(&mut self, interface: InterfaceNumber, alternative: u8) -> bool { 136 | let _ = (interface, alternative); 137 | false 138 | } 139 | } 140 | 141 | /// Handle for a control IN transfer. When implementing a class, use the methods of this object to 142 | /// response to the transfer with either data or an error (STALL condition). To ignore the request 143 | /// and pass it on to the next class, simply don't call any method. 144 | pub struct ControlIn<'a, 'p, 'r, B: UsbBus> { 145 | pipe: &'p mut ControlPipe<'a, B>, 146 | req: &'r control::Request, 147 | } 148 | 149 | impl<'a, 'p, 'r, B: UsbBus> ControlIn<'a, 'p, 'r, B> { 150 | pub(crate) fn new(pipe: &'p mut ControlPipe<'a, B>, req: &'r control::Request) -> Self { 151 | ControlIn { pipe, req } 152 | } 153 | 154 | /// Gets the request from the SETUP packet. 155 | pub fn request(&self) -> &control::Request { 156 | self.req 157 | } 158 | 159 | /// Accepts the transfer with the supplied buffer. 160 | pub fn accept_with(self, data: &[u8]) -> Result<()> { 161 | self.pipe.accept_in(|buf| { 162 | if data.len() > buf.len() { 163 | return Err(UsbError::BufferOverflow); 164 | } 165 | 166 | buf[..data.len()].copy_from_slice(data); 167 | 168 | Ok(data.len()) 169 | }) 170 | } 171 | 172 | /// Accepts the transfer with the supplied static buffer. 173 | /// This method is useful when you have a large static descriptor to send as one packet. 174 | pub fn accept_with_static(self, data: &'static [u8]) -> Result<()> { 175 | self.pipe.accept_in_static(data) 176 | } 177 | 178 | /// Accepts the transfer with a callback that can write to the internal buffer of the control 179 | /// pipe. Can be used to avoid an extra copy. 180 | pub fn accept(self, f: impl FnOnce(&mut [u8]) -> Result) -> Result<()> { 181 | self.pipe.accept_in(f) 182 | } 183 | 184 | /// Rejects the transfer by stalling the pipe. 185 | pub fn reject(self) -> Result<()> { 186 | self.pipe.reject() 187 | } 188 | } 189 | 190 | /// Handle for a control OUT transfer. When implementing a class, use the methods of this object to 191 | /// response to the transfer with an ACT or an error (STALL condition). To ignore the request and 192 | /// pass it on to the next class, simply don't call any method. 193 | pub struct ControlOut<'a, 'p, 'r, B: UsbBus> { 194 | pipe: &'p mut ControlPipe<'a, B>, 195 | req: &'r control::Request, 196 | } 197 | 198 | impl<'a, 'p, 'r, B: UsbBus> ControlOut<'a, 'p, 'r, B> { 199 | pub(crate) fn new(pipe: &'p mut ControlPipe<'a, B>, req: &'r control::Request) -> Self { 200 | ControlOut { pipe, req } 201 | } 202 | 203 | /// Gets the request from the SETUP packet. 204 | pub fn request(&self) -> &control::Request { 205 | self.req 206 | } 207 | 208 | /// Gets the data from the data stage of the request. May be empty if there was no data stage. 209 | pub fn data(&self) -> &[u8] { 210 | self.pipe.data() 211 | } 212 | 213 | /// Accepts the transfer by succesfully responding to the status stage. 214 | pub fn accept(self) -> Result<()> { 215 | self.pipe.accept_out() 216 | } 217 | 218 | /// Rejects the transfer by stalling the pipe. 219 | pub fn reject(self) -> Result<()> { 220 | self.pipe.reject() 221 | } 222 | } 223 | -------------------------------------------------------------------------------- /src/endpoint.rs: -------------------------------------------------------------------------------- 1 | use crate::bus::UsbBus; 2 | use crate::{Result, UsbDirection}; 3 | use core::marker::PhantomData; 4 | use portable_atomic::{AtomicPtr, Ordering}; 5 | 6 | /// Trait for endpoint type markers. 7 | pub trait EndpointDirection { 8 | /// Direction value of the marker type. 9 | const DIRECTION: UsbDirection; 10 | } 11 | 12 | /// Marker type for OUT endpoints. 13 | pub struct Out; 14 | 15 | impl EndpointDirection for Out { 16 | const DIRECTION: UsbDirection = UsbDirection::Out; 17 | } 18 | 19 | /// Marker type for IN endpoints. 20 | pub struct In; 21 | 22 | impl EndpointDirection for In { 23 | const DIRECTION: UsbDirection = UsbDirection::In; 24 | } 25 | 26 | /// A host-to-device (OUT) endpoint. 27 | pub type EndpointOut<'a, B> = Endpoint<'a, B, Out>; 28 | 29 | /// A device-to-host (IN) endpoint. 30 | pub type EndpointIn<'a, B> = Endpoint<'a, B, In>; 31 | 32 | /// Isochronous transfers employ one of three synchronization schemes. See USB 2.0 spec 5.12.4.1. 33 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 34 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 35 | pub enum IsochronousSynchronizationType { 36 | /// Synchronization is not implemented for this endpoint. 37 | NoSynchronization, 38 | /// Source and Sink sample clocks are free running. 39 | Asynchronous, 40 | /// Source sample clock is locked to Sink, Sink sample clock is locked to data flow. 41 | Adaptive, 42 | /// Source and Sink sample clocks are locked to USB SOF. 43 | Synchronous, 44 | } 45 | 46 | /// Intended use of an isochronous endpoint, see USB 2.0 spec sections 5.12 and 9.6.6. 47 | /// Associations between data and feedback endpoints are described in section 9.6.6. 48 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 49 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 50 | pub enum IsochronousUsageType { 51 | /// Endpoint is used for isochronous data. 52 | Data, 53 | /// Feedback for synchronization. 54 | Feedback, 55 | /// Endpoint is data and provides implicit feedback for synchronization. 56 | ImplicitFeedbackData, 57 | } 58 | 59 | /// USB endpoint transfer type. 60 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 61 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 62 | pub enum EndpointType { 63 | /// Control endpoint. Used for device management. Only the host can initiate requests. Usually 64 | /// used only endpoint 0. 65 | Control, 66 | /// Isochronous endpoint. Used for time-critical unreliable data. 67 | /// 68 | /// See USB 2.0 spec section 5.12 "Special Considerations for Isochronous Transfers" 69 | Isochronous { 70 | /// Synchronization model used for the data stream that this endpoint relates to. 71 | synchronization: IsochronousSynchronizationType, 72 | /// Endpoint's role in the synchronization model selected by [Self::Isochronous::synchronization]. 73 | usage: IsochronousUsageType, 74 | }, 75 | /// Bulk endpoint. Used for large amounts of best-effort reliable data. 76 | Bulk, 77 | /// Interrupt endpoint. Used for small amounts of time-critical reliable data. 78 | Interrupt, 79 | } 80 | 81 | impl EndpointType { 82 | /// Format EndpointType for use in bmAttributes transfer type field USB 2.0 spec section 9.6.6 83 | pub fn to_bm_attributes(&self) -> u8 { 84 | match self { 85 | EndpointType::Control => 0b00, 86 | EndpointType::Isochronous { 87 | synchronization, 88 | usage, 89 | } => { 90 | let sync_bits = match synchronization { 91 | IsochronousSynchronizationType::NoSynchronization => 0b00, 92 | IsochronousSynchronizationType::Asynchronous => 0b01, 93 | IsochronousSynchronizationType::Adaptive => 0b10, 94 | IsochronousSynchronizationType::Synchronous => 0b11, 95 | }; 96 | let usage_bits = match usage { 97 | IsochronousUsageType::Data => 0b00, 98 | IsochronousUsageType::Feedback => 0b01, 99 | IsochronousUsageType::ImplicitFeedbackData => 0b10, 100 | }; 101 | (usage_bits << 4) | (sync_bits << 2) | 0b01 102 | } 103 | EndpointType::Bulk => 0b10, 104 | EndpointType::Interrupt => 0b11, 105 | } 106 | } 107 | } 108 | 109 | /// Handle for a USB endpoint. The endpoint direction is constrained by the `D` type argument, which 110 | /// must be either `In` or `Out`. 111 | pub struct Endpoint<'a, B: UsbBus, D: EndpointDirection> { 112 | bus_ptr: &'a AtomicPtr, 113 | address: EndpointAddress, 114 | ep_type: EndpointType, 115 | max_packet_size: u16, 116 | interval: u8, 117 | _marker: PhantomData, 118 | } 119 | 120 | impl Endpoint<'_, B, D> { 121 | pub(crate) fn new( 122 | bus_ptr: &AtomicPtr, 123 | address: EndpointAddress, 124 | ep_type: EndpointType, 125 | max_packet_size: u16, 126 | interval: u8, 127 | ) -> Endpoint<'_, B, D> { 128 | Endpoint { 129 | bus_ptr, 130 | address, 131 | ep_type, 132 | max_packet_size, 133 | interval, 134 | _marker: PhantomData, 135 | } 136 | } 137 | 138 | fn bus(&self) -> &B { 139 | let bus_ptr = self.bus_ptr.load(Ordering::SeqCst); 140 | if bus_ptr.is_null() { 141 | panic!("UsbBus initialization not complete"); 142 | } 143 | 144 | unsafe { &*bus_ptr } 145 | } 146 | 147 | /// Gets the endpoint address including direction bit. 148 | pub fn address(&self) -> EndpointAddress { 149 | self.address 150 | } 151 | 152 | /// Gets the endpoint transfer type. 153 | pub fn ep_type(&self) -> EndpointType { 154 | self.ep_type 155 | } 156 | 157 | /// Gets the maximum packet size for the endpoint. 158 | pub fn max_packet_size(&self) -> u16 { 159 | self.max_packet_size 160 | } 161 | 162 | /// Gets the poll interval for interrupt endpoints. 163 | pub fn interval(&self) -> u8 { 164 | self.interval 165 | } 166 | 167 | /// Sets the STALL condition for the endpoint. 168 | pub fn stall(&self) { 169 | self.bus().set_stalled(self.address, true); 170 | } 171 | 172 | /// Clears the STALL condition of the endpoint. 173 | pub fn unstall(&self) { 174 | self.bus().set_stalled(self.address, false); 175 | } 176 | } 177 | 178 | impl Endpoint<'_, B, In> { 179 | /// Writes a single packet of data to the specified endpoint and returns number of bytes 180 | /// actually written. The buffer must not be longer than the `max_packet_size` specified when 181 | /// allocating the endpoint. 182 | /// 183 | /// # Errors 184 | /// 185 | /// Note: USB bus implementation errors are directly passed through, so be prepared to handle 186 | /// other errors as well. 187 | /// 188 | /// * [`WouldBlock`](crate::UsbError::WouldBlock) - The transmission buffer of the USB 189 | /// peripheral is full and the packet cannot be sent now. A peripheral may or may not support 190 | /// concurrent transmission of packets. 191 | /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The data is longer than the 192 | /// `max_packet_size` specified when allocating the endpoint. This is generally an error in 193 | /// the class implementation. 194 | pub fn write(&self, data: &[u8]) -> Result { 195 | self.bus().write(self.address, data) 196 | } 197 | } 198 | 199 | impl Endpoint<'_, B, Out> { 200 | /// Reads a single packet of data from the specified endpoint and returns the actual length of 201 | /// the packet. The buffer should be large enough to fit at least as many bytes as the 202 | /// `max_packet_size` specified when allocating the endpoint. 203 | /// 204 | /// # Errors 205 | /// 206 | /// Note: USB bus implementation errors are directly passed through, so be prepared to handle 207 | /// other errors as well. 208 | /// 209 | /// * [`WouldBlock`](crate::UsbError::WouldBlock) - There is no packet to be read. Note that 210 | /// this is different from a received zero-length packet, which is valid and significant in 211 | /// USB. A zero-length packet will return `Ok(0)`. 212 | /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The received packet is too long to 213 | /// fit in `data`. This is generally an error in the class implementation. 214 | pub fn read(&self, data: &mut [u8]) -> Result { 215 | self.bus().read(self.address, data) 216 | } 217 | } 218 | 219 | /// Type-safe endpoint address. 220 | #[derive(Debug, Clone, Copy, Eq, PartialEq)] 221 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 222 | pub struct EndpointAddress(u8); 223 | 224 | impl From for EndpointAddress { 225 | #[inline] 226 | fn from(addr: u8) -> EndpointAddress { 227 | EndpointAddress(addr) 228 | } 229 | } 230 | 231 | impl From for u8 { 232 | #[inline] 233 | fn from(addr: EndpointAddress) -> u8 { 234 | addr.0 235 | } 236 | } 237 | 238 | impl EndpointAddress { 239 | const INBITS: u8 = UsbDirection::In as u8; 240 | 241 | /// Constructs a new EndpointAddress with the given index and direction. 242 | #[inline] 243 | pub fn from_parts(index: usize, dir: UsbDirection) -> Self { 244 | EndpointAddress(index as u8 | dir as u8) 245 | } 246 | 247 | /// Gets the direction part of the address. 248 | #[inline] 249 | pub fn direction(&self) -> UsbDirection { 250 | if (self.0 & Self::INBITS) != 0 { 251 | UsbDirection::In 252 | } else { 253 | UsbDirection::Out 254 | } 255 | } 256 | 257 | /// Returns true if the direction is IN, otherwise false. 258 | #[inline] 259 | pub fn is_in(&self) -> bool { 260 | (self.0 & Self::INBITS) != 0 261 | } 262 | 263 | /// Returns true if the direction is OUT, otherwise false. 264 | #[inline] 265 | pub fn is_out(&self) -> bool { 266 | (self.0 & Self::INBITS) == 0 267 | } 268 | 269 | /// Gets the index part of the endpoint address. 270 | #[inline] 271 | pub fn index(&self) -> usize { 272 | (self.0 & !Self::INBITS) as usize 273 | } 274 | } 275 | -------------------------------------------------------------------------------- /src/control_pipe.rs: -------------------------------------------------------------------------------- 1 | use crate::bus::UsbBus; 2 | use crate::control::Request; 3 | use crate::endpoint::{EndpointIn, EndpointOut}; 4 | use crate::{Result, UsbDirection, UsbError}; 5 | use core::cmp::min; 6 | 7 | #[derive(Debug)] 8 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 9 | #[allow(unused)] 10 | enum ControlState { 11 | Idle, 12 | DataIn, 13 | DataInZlp, 14 | DataInLast, 15 | CompleteIn(Request), 16 | StatusOut, 17 | CompleteOut, 18 | DataOut(Request), 19 | StatusIn, 20 | Error, 21 | } 22 | 23 | /// Buffers and parses USB control transfers. 24 | pub struct ControlPipe<'a, B: UsbBus> { 25 | ep_out: EndpointOut<'a, B>, 26 | ep_in: EndpointIn<'a, B>, 27 | state: ControlState, 28 | buf: &'a mut [u8], 29 | static_in_buf: Option<&'static [u8]>, 30 | i: usize, 31 | len: usize, 32 | } 33 | 34 | impl ControlPipe<'_, B> { 35 | pub fn new<'a>( 36 | buf: &'a mut [u8], 37 | ep_out: EndpointOut<'a, B>, 38 | ep_in: EndpointIn<'a, B>, 39 | ) -> ControlPipe<'a, B> { 40 | ControlPipe { 41 | ep_out, 42 | ep_in, 43 | state: ControlState::Idle, 44 | buf, 45 | static_in_buf: None, 46 | i: 0, 47 | len: 0, 48 | } 49 | } 50 | 51 | pub fn waiting_for_response(&self) -> bool { 52 | matches!( 53 | self.state, 54 | ControlState::CompleteOut | ControlState::CompleteIn(_) 55 | ) 56 | } 57 | 58 | pub fn data(&self) -> &[u8] { 59 | &self.buf[0..self.len] 60 | } 61 | 62 | pub fn reset(&mut self) { 63 | usb_trace!("Control pipe reset"); 64 | self.state = ControlState::Idle; 65 | } 66 | 67 | pub fn handle_setup(&mut self) -> Option { 68 | let count = match self.ep_out.read(&mut self.buf[..]) { 69 | Ok(count) => { 70 | usb_trace!("Read {} bytes on EP0-OUT: {:?}", count, &self.buf[..count]); 71 | count 72 | } 73 | Err(UsbError::WouldBlock) => return None, 74 | Err(_) => { 75 | return None; 76 | } 77 | }; 78 | 79 | let req = match Request::parse(&self.buf[0..count]) { 80 | Ok(req) => req, 81 | Err(_) => { 82 | // Failed to parse SETUP packet. We are supposed to silently ignore this. 83 | return None; 84 | } 85 | }; 86 | 87 | // Now that we have properly parsed the setup packet, ensure the end-point is no longer in 88 | // a stalled state. 89 | self.ep_out.unstall(); 90 | 91 | usb_debug!("EP0 request received: {:?}", req); 92 | 93 | /*sprintln!("SETUP {:?} {:?} {:?} req:{} val:{} idx:{} len:{} {:?}", 94 | req.direction, req.request_type, req.recipient, 95 | req.request, req.value, req.index, req.length, 96 | self.state);*/ 97 | 98 | if req.direction == UsbDirection::Out { 99 | // OUT transfer 100 | 101 | if req.length > 0 { 102 | // Has data stage 103 | 104 | if req.length as usize > self.buf.len() { 105 | // Data stage won't fit in buffer 106 | return None; 107 | } 108 | 109 | self.i = 0; 110 | self.len = req.length as usize; 111 | self.state = ControlState::DataOut(req); 112 | } else { 113 | // No data stage 114 | 115 | self.len = 0; 116 | self.state = ControlState::CompleteOut; 117 | return Some(req); 118 | } 119 | } else { 120 | // IN transfer 121 | 122 | self.state = ControlState::CompleteIn(req); 123 | return Some(req); 124 | } 125 | 126 | None 127 | } 128 | 129 | pub fn handle_out(&mut self) -> Result> { 130 | match self.state { 131 | ControlState::DataOut(req) => { 132 | let i = self.i; 133 | let count = match self.ep_out.read(&mut self.buf[i..]) { 134 | Ok(count) => count, 135 | Err(UsbError::WouldBlock) => return Ok(None), 136 | Err(_err) => { 137 | // Failed to read or buffer overflow (overflow is only possible if the host 138 | // sends more data than it indicated in the SETUP request) 139 | usb_debug!("Failed EP0 read: {:?}", _err); 140 | self.set_error(); 141 | return Ok(None); 142 | } 143 | }; 144 | 145 | usb_trace!( 146 | "Read {} bytes on EP0-OUT: {:?}", 147 | count, 148 | &self.buf[i..(i + count)] 149 | ); 150 | self.i += count; 151 | 152 | if self.i >= self.len { 153 | usb_debug!("Request OUT complete: {:?}", req); 154 | self.state = ControlState::CompleteOut; 155 | return Ok(Some(req)); 156 | } 157 | } 158 | // The host may terminate a DATA stage early by sending a zero-length status packet 159 | // acknowledging the data we sent it. 160 | ControlState::DataIn 161 | | ControlState::DataInLast 162 | | ControlState::DataInZlp 163 | | ControlState::StatusOut => { 164 | usb_debug!( 165 | "Control transfer completed. Current state: {:?}", 166 | self.state 167 | ); 168 | self.ep_out.read(&mut [])?; 169 | self.state = ControlState::Idle; 170 | } 171 | _ => { 172 | // Discard the packet 173 | usb_debug!( 174 | "Discarding EP0 data due to unexpected state. Current state: {:?}", 175 | self.state 176 | ); 177 | self.ep_out.read(&mut [])?; 178 | 179 | // Unexpected OUT packet 180 | self.set_error() 181 | } 182 | } 183 | 184 | Ok(None) 185 | } 186 | 187 | pub fn handle_in_complete(&mut self) -> Result { 188 | match self.state { 189 | ControlState::DataIn => { 190 | self.write_in_chunk()?; 191 | } 192 | ControlState::DataInZlp => { 193 | self.ep_in.write(&[])?; 194 | usb_trace!("wrote EP0: ZLP"); 195 | self.state = ControlState::DataInLast; 196 | } 197 | ControlState::DataInLast => { 198 | self.ep_out.unstall(); 199 | self.state = ControlState::StatusOut; 200 | } 201 | ControlState::StatusIn => { 202 | self.state = ControlState::Idle; 203 | return Ok(true); 204 | } 205 | ControlState::Idle => { 206 | // If we received a message on EP0 while sending the last portion of an IN 207 | // transfer, we may have already transitioned to IDLE without getting the last 208 | // IN-complete status. Just ignore this indication. 209 | } 210 | _ => { 211 | // If we get IN-COMPLETE indications in unexpected states, it's generally because 212 | // of control flow in previous phases updating after our packet was successfully 213 | // sent. Ignore these indications if they don't drive any further behavior. 214 | } 215 | }; 216 | 217 | Ok(false) 218 | } 219 | 220 | fn write_in_chunk(&mut self) -> Result<()> { 221 | let count = min(self.len - self.i, self.ep_in.max_packet_size() as usize); 222 | 223 | let buffer = self.static_in_buf.unwrap_or(&self.buf); 224 | let count = self.ep_in.write(&buffer[self.i..(self.i + count)])?; 225 | usb_trace!("wrote EP0: {:?}", &buffer[self.i..(self.i + count)]); 226 | 227 | self.i += count; 228 | 229 | if self.i >= self.len { 230 | self.static_in_buf = None; 231 | 232 | self.state = if count == self.ep_in.max_packet_size() as usize { 233 | ControlState::DataInZlp 234 | } else { 235 | ControlState::DataInLast 236 | }; 237 | } 238 | 239 | Ok(()) 240 | } 241 | 242 | pub fn accept_out(&mut self) -> Result<()> { 243 | match self.state { 244 | ControlState::CompleteOut => {} 245 | _ => { 246 | usb_debug!("Cannot ACK, invalid state: {:?}", self.state); 247 | return Err(UsbError::InvalidState); 248 | } 249 | }; 250 | 251 | self.ep_in.write(&[])?; 252 | self.state = ControlState::StatusIn; 253 | Ok(()) 254 | } 255 | 256 | pub fn accept_in(&mut self, f: impl FnOnce(&mut [u8]) -> Result) -> Result<()> { 257 | let req = match self.state { 258 | ControlState::CompleteIn(req) => req, 259 | _ => { 260 | usb_debug!("EP0-IN cannot ACK, invalid state: {:?}", self.state); 261 | return Err(UsbError::InvalidState); 262 | } 263 | }; 264 | 265 | let len = f(&mut self.buf[..])?; 266 | 267 | if len > self.buf.len() { 268 | self.set_error(); 269 | return Err(UsbError::BufferOverflow); 270 | } 271 | 272 | self.start_in_transfer(req, len) 273 | } 274 | 275 | pub fn accept_in_static(&mut self, data: &'static [u8]) -> Result<()> { 276 | let req = match self.state { 277 | ControlState::CompleteIn(req) => req, 278 | _ => { 279 | usb_debug!("EP0-IN cannot ACK, invalid state: {:?}", self.state); 280 | return Err(UsbError::InvalidState); 281 | } 282 | }; 283 | 284 | self.static_in_buf = Some(data); 285 | 286 | self.start_in_transfer(req, data.len()) 287 | } 288 | 289 | fn start_in_transfer(&mut self, req: Request, data_len: usize) -> Result<()> { 290 | self.len = min(data_len, req.length as usize); 291 | self.i = 0; 292 | self.state = ControlState::DataIn; 293 | self.write_in_chunk()?; 294 | 295 | Ok(()) 296 | } 297 | 298 | pub fn reject(&mut self) -> Result<()> { 299 | usb_debug!("EP0 transfer rejected"); 300 | if !self.waiting_for_response() { 301 | return Err(UsbError::InvalidState); 302 | } 303 | 304 | self.set_error(); 305 | Ok(()) 306 | } 307 | 308 | fn set_error(&mut self) { 309 | usb_debug!("EP0 stalled - error"); 310 | self.state = ControlState::Error; 311 | self.ep_out.stall(); 312 | self.ep_in.stall(); 313 | } 314 | } 315 | -------------------------------------------------------------------------------- /tests/test_class_host/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::device::*; 2 | use rand::prelude::*; 3 | use rusb::{request_type, Direction, Recipient, RequestType, TransferType}; 4 | use std::cmp::max; 5 | use std::fmt::Write; 6 | use std::time::{Duration, Instant}; 7 | use usb_device::test_class; 8 | 9 | pub type TestFn = fn(&mut DeviceHandles, &mut String) -> (); 10 | 11 | const BENCH_TIMEOUT: Duration = Duration::from_secs(10); 12 | 13 | macro_rules! tests { 14 | { $(fn $name:ident($dev:ident, $out:ident) $body:expr)* } => { 15 | pub fn get_tests() -> Vec<(&'static str, TestFn)> { 16 | let mut tests: Vec<(&'static str, TestFn)> = Vec::new(); 17 | 18 | $( 19 | fn $name($dev: &mut DeviceHandles, $out: &mut String) { 20 | $body 21 | } 22 | 23 | tests.push((stringify!($name), $name)); 24 | )* 25 | 26 | tests 27 | } 28 | } 29 | } 30 | 31 | tests! { 32 | 33 | fn control_request(dev, _out) { 34 | let mut rng = rand::thread_rng(); 35 | 36 | let value: u16 = rng.gen(); 37 | let index: u16 = rng.gen(); 38 | let data = random_data(rng.gen_range(0..16)); 39 | 40 | let mut expected = [0u8; 8]; 41 | expected[0] = 0x02_u8 << 5; 42 | expected[1] = test_class::REQ_STORE_REQUEST; 43 | expected[2..4].copy_from_slice(&value.to_le_bytes()); 44 | expected[4..6].copy_from_slice(&index.to_le_bytes()); 45 | expected[6..8].copy_from_slice(&(data.len() as u16).to_le_bytes()); 46 | 47 | assert_eq!( 48 | dev.write_control( 49 | request_type(Direction::Out, RequestType::Vendor, Recipient::Device), 50 | test_class::REQ_STORE_REQUEST, value, index, 51 | &data, TIMEOUT).expect("control write"), 52 | data.len()); 53 | 54 | let mut response = [0u8; 8]; 55 | 56 | assert_eq!( 57 | dev.read_control( 58 | request_type(Direction::In, RequestType::Vendor, Recipient::Device), 59 | test_class::REQ_READ_BUFFER, 0, 0, 60 | &mut response, TIMEOUT).expect("control read"), 61 | response.len()); 62 | 63 | assert_eq!(&response, &expected); 64 | } 65 | 66 | fn control_data(dev, _out) { 67 | for len in &[0, 7, 8, 9, 15, 16, 17] { 68 | let data = random_data(*len); 69 | 70 | assert_eq!( 71 | dev.write_control( 72 | request_type(Direction::Out, RequestType::Vendor, Recipient::Device), 73 | test_class::REQ_WRITE_BUFFER, 0, 0, 74 | &data, TIMEOUT).unwrap_or_else(|_| panic!("control write len {}", len)), 75 | data.len()); 76 | 77 | let mut response = vec![0u8; *len]; 78 | 79 | assert_eq!( 80 | dev.read_control( 81 | request_type(Direction::In, RequestType::Vendor, Recipient::Device), 82 | test_class::REQ_READ_BUFFER, 0, 0, 83 | &mut response, TIMEOUT).unwrap_or_else(|_| panic!("control read len {}", len)), 84 | data.len()); 85 | 86 | assert_eq!(&response, &data); 87 | } 88 | } 89 | 90 | fn control_data_static(dev, _out) { 91 | let mut response = [0u8; 257]; 92 | 93 | assert_eq!( 94 | dev.read_control( 95 | request_type(Direction::In, RequestType::Vendor, Recipient::Device), 96 | test_class::REQ_READ_LONG_DATA, 0, 0, 97 | &mut response, TIMEOUT).expect("control read"), 98 | response.len()); 99 | 100 | assert_eq!(&response[..], test_class::LONG_DATA); 101 | } 102 | 103 | fn control_error(dev, _out) { 104 | let res = dev.write_control( 105 | request_type(Direction::Out, RequestType::Vendor, Recipient::Device), 106 | test_class::REQ_UNKNOWN, 0, 0, 107 | &[], TIMEOUT); 108 | 109 | if res.is_ok() { 110 | panic!("unknown control request succeeded"); 111 | } 112 | } 113 | 114 | fn string_descriptors(dev, _out) { 115 | assert_eq!( 116 | dev.read_product_string(dev.en_us, &dev.device_descriptor, TIMEOUT) 117 | .expect("read product string"), 118 | test_class::PRODUCT); 119 | 120 | assert_eq!( 121 | dev.read_manufacturer_string(dev.en_us, &dev.device_descriptor, TIMEOUT) 122 | .expect("read manufacturer string"), 123 | test_class::MANUFACTURER); 124 | 125 | assert_eq!( 126 | dev.read_serial_number_string(dev.en_us, &dev.device_descriptor, TIMEOUT) 127 | .expect("read serial number string"), 128 | test_class::SERIAL_NUMBER); 129 | 130 | assert_eq!( 131 | dev.read_string_descriptor(dev.en_us, 4, TIMEOUT) 132 | .expect("read custom string"), 133 | test_class::CUSTOM_STRING); 134 | } 135 | 136 | fn interface_descriptor(dev, _out) { 137 | let iface = dev.config_descriptor 138 | .interfaces() 139 | .find(|i| i.number() == 0) 140 | .expect("interface not found"); 141 | 142 | let default_alt_setting = iface.descriptors() 143 | .find(|i| i.setting_number() == 0) 144 | .expect("default alt setting not found"); 145 | 146 | assert_eq!(default_alt_setting.description_string_index(), None); 147 | assert_eq!(default_alt_setting.class_code(), 0xff); 148 | assert_eq!(default_alt_setting.sub_class_code(), 0x00); 149 | 150 | let second_alt_setting = iface.descriptors() 151 | .find(|i| i.setting_number() == 1) 152 | .expect("second alt setting not found"); 153 | 154 | assert_eq!(second_alt_setting.class_code(), 0xff); 155 | assert_eq!(second_alt_setting.sub_class_code(), 0x01); 156 | 157 | let string_index = second_alt_setting.description_string_index() 158 | .expect("second alt setting string is undefined"); 159 | 160 | assert_eq!( 161 | dev.read_string_descriptor(dev.en_us, string_index, TIMEOUT) 162 | .expect("read interface string"), 163 | test_class::INTERFACE_STRING); 164 | } 165 | 166 | fn iso_endpoint_descriptors(dev, _out) { 167 | // Tests that an isochronous endpoint descriptor is present in the first 168 | // alternate setting, but not in the default setting. 169 | let iface = dev.config_descriptor 170 | .interfaces() 171 | .find(|i| i.number() == 0) 172 | .expect("interface not found"); 173 | 174 | let mut iso_ep_count = 0; 175 | for iface_descriptor in iface.descriptors() { 176 | if iface_descriptor.setting_number() == 0 { 177 | // Default setting - no isochronous endpoints allowed. Per USB 2.0 178 | // spec rev 2.0, 5.6.3 Isochronous Transfer Packet Size Constraints: 179 | // 180 | // All device default interface settings must not include any 181 | // isochronous endpoints with non-zero data payload sizes (specified 182 | // via wMaxPacketSize in the endpoint descriptor) 183 | let issue = iface_descriptor 184 | .endpoint_descriptors() 185 | .find(|ep| ep.transfer_type() == TransferType::Isochronous 186 | && ep.max_packet_size() != 0); 187 | if let Some(ep) = issue { 188 | panic!("Endpoint {} is isochronous and in the default setting", 189 | ep.number()); 190 | } 191 | } else { 192 | iso_ep_count += iface_descriptor.endpoint_descriptors() 193 | .filter(|ep| ep.transfer_type() == TransferType::Isochronous) 194 | .count(); 195 | } 196 | } 197 | assert!(iso_ep_count > 0, "At least one isochronous endpoint is expected"); 198 | } 199 | 200 | fn bulk_loopback(dev, _out) { 201 | let mut lens = vec![0, 1, 2, 32, 63, 64, 65, 127, 128, 129]; 202 | if dev.is_high_speed() { 203 | lens.extend([255, 256, 257, 511, 512, 513, 1023, 1024, 1025]); 204 | } 205 | 206 | let max_packet_size: usize = dev.bulk_max_packet_size().into(); 207 | for len in &lens { 208 | let data = random_data(*len); 209 | 210 | assert_eq!( 211 | dev.write_bulk(0x01, &data, TIMEOUT) 212 | .unwrap_or_else(|_| panic!("bulk write len {}", len)), 213 | data.len(), 214 | "bulk write len {}", len); 215 | 216 | if *len > 0 && *len % max_packet_size == 0 { 217 | assert_eq!( 218 | dev.write_bulk(0x01, &[], TIMEOUT) 219 | .expect("bulk write zero-length packet"), 220 | 0, 221 | "bulk write zero-length packet"); 222 | } 223 | 224 | // Prevent libusb from instantaneously reading an empty packet on Windows when 225 | // zero-sized buffer is passed. 226 | let mut response = vec![0u8; max(*len, 1)]; 227 | 228 | assert_eq!( 229 | dev.read_bulk(0x81, &mut response, TIMEOUT) 230 | .unwrap_or_else(|_| panic!("bulk read len {}", len)), 231 | data.len(), 232 | "bulk read len {}", len); 233 | 234 | assert_eq!(&response[..*len], &data[..]); 235 | } 236 | } 237 | 238 | fn interrupt_loopback(dev, _out) { 239 | for len in &[0, 1, 2, 15, 31] { 240 | let data = random_data(*len); 241 | 242 | assert_eq!( 243 | dev.write_interrupt(0x02, &data, TIMEOUT) 244 | .unwrap_or_else(|_| panic!("interrupt write len {}", len)), 245 | data.len(), 246 | "interrupt write len {}", len); 247 | 248 | // Prevent libusb from instantaneously reading an empty packet on Windows when 249 | // zero-sized buffer is passed. 250 | let mut response = vec![0u8; max(*len, 1)]; 251 | 252 | assert_eq!( 253 | dev.read_interrupt(0x82, &mut response, TIMEOUT) 254 | .unwrap_or_else(|_| panic!("interrupt read len {}", len)), 255 | data.len(), 256 | "interrupt read len {}", len); 257 | 258 | assert_eq!(&response[..*len], &data[..]); 259 | } 260 | } 261 | 262 | fn bench_bulk_write(dev, out) { 263 | run_bench(dev, out, |data| { 264 | assert_eq!( 265 | dev.write_bulk(0x01, data, BENCH_TIMEOUT) 266 | .expect("bulk write"), 267 | data.len(), 268 | "bulk write"); 269 | }); 270 | } 271 | 272 | fn bench_bulk_read(dev, out) { 273 | run_bench(dev, out, |data| { 274 | assert_eq!( 275 | dev.read_bulk(0x81, data, BENCH_TIMEOUT) 276 | .expect("bulk read"), 277 | data.len(), 278 | "bulk read"); 279 | }); 280 | } 281 | 282 | } 283 | 284 | fn run_bench(dev: &DeviceHandles, out: &mut String, f: impl Fn(&mut [u8])) { 285 | const TRANSFER_BYTES: usize = 64 * 1024; 286 | const TRANSFERS: usize = 16; 287 | const TOTAL_BYTES: usize = TRANSFER_BYTES * TRANSFERS; 288 | 289 | dev.write_control( 290 | request_type(Direction::Out, RequestType::Vendor, Recipient::Device), 291 | test_class::REQ_SET_BENCH_ENABLED, 292 | 1, 293 | 0, 294 | &[], 295 | TIMEOUT, 296 | ) 297 | .expect("enable bench mode"); 298 | 299 | let mut data = random_data(TRANSFER_BYTES); 300 | 301 | let start = Instant::now(); 302 | 303 | for _ in 0..TRANSFERS { 304 | f(&mut data); 305 | } 306 | 307 | let elapsed = start.elapsed(); 308 | let elapsed = elapsed.as_secs() as f64 + (elapsed.subsec_micros() as f64) * 0.000_001; 309 | let throughput = (TOTAL_BYTES * 8) as f64 / 1_000_000.0 / elapsed; 310 | 311 | writeln!( 312 | out, 313 | " {} transfers of {} bytes in {:.3}s -> {:.3}Mbit/s", 314 | TRANSFERS, TRANSFER_BYTES, elapsed, throughput 315 | ) 316 | .expect("write failed"); 317 | } 318 | 319 | fn random_data(len: usize) -> Vec { 320 | let mut data = vec![0u8; len]; 321 | rand::thread_rng().fill(data.as_mut_slice()); 322 | data 323 | } 324 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Experimental device-side USB stack for embedded devices. 2 | //! 3 | //! ## Implementing a USB device 4 | //! 5 | //! A USB device consists of a [`UsbDevice`](device::UsbDevice) instance, one or more 6 | //! [`UsbClass`](crate::class::UsbClass)es, and a platform-specific [`UsbBus`](bus::UsbBus) 7 | //! implementation which together form a USB composite device. 8 | //! 9 | //! In the future USB device implementors will be able to use pre-existing peripheral driver crates 10 | //! and USB class implementation crates. The necessary types for the basic USB composite device 11 | //! implementation are available with: 12 | //! 13 | //! `use usb_device::prelude::*`. 14 | //! 15 | //! See the [`device`] module for a more complete example. 16 | //! 17 | //! ## USB classes 18 | //! 19 | //! For information on how to implement new USB classes, see the [`class`] module and the 20 | //! [`TestClass`](test_class::TestClass) source code for an example of a custom USB device class 21 | //! implementation. The necessary types for creating new classes are available with: 22 | //! 23 | //! `use usb_device::class_prelude::*`. 24 | //! 25 | //! ## USB peripheral drivers 26 | //! 27 | //! New peripheral driver crates can be created by implementing the [`UsbBus`](bus::UsbBus) trait. 28 | //! 29 | //! # Note about terminology 30 | //! 31 | //! This crate uses standard host-centric USB terminology for transfer directions. Therefore an OUT 32 | //! transfer refers to a host-to-device transfer, and an IN transfer refers to a device-to-host 33 | //! transfer. This is mainly a concern for implementing new USB peripheral drivers and USB classes, 34 | //! and people doing that should be familiar with the USB standard. 35 | 36 | #![no_std] 37 | #![warn(missing_docs)] 38 | 39 | #[macro_use] 40 | mod macros; 41 | 42 | /// A USB stack error. 43 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 44 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 45 | pub enum UsbError { 46 | /// An operation would block because the device is currently busy or there is no data available. 47 | WouldBlock, 48 | 49 | /// Parsing failed due to invalid input. 50 | ParseError, 51 | 52 | /// A buffer too short for the data to read was passed, or provided data cannot fit within 53 | /// length constraints. 54 | BufferOverflow, 55 | 56 | /// Classes attempted to allocate more endpoints than the peripheral supports. 57 | EndpointOverflow, 58 | 59 | /// Classes attempted to allocate more packet buffer memory than the peripheral supports. This 60 | /// can be caused by either a single class trying to allocate a packet buffer larger than the 61 | /// peripheral supports per endpoint, or multiple allocated endpoints together using more memory 62 | /// than the peripheral has available for the buffers. 63 | EndpointMemoryOverflow, 64 | 65 | /// The endpoint address is invalid or already used. 66 | InvalidEndpoint, 67 | 68 | /// Operation is not supported by device or configuration. 69 | Unsupported, 70 | 71 | /// Operation is not valid in the current state of the object. 72 | InvalidState, 73 | } 74 | 75 | /// Direction of USB traffic. Note that in the USB standard the direction is always indicated from 76 | /// the perspective of the host, which is backward for devices, but the standard directions are used 77 | /// for consistency. 78 | /// 79 | /// The values of the enum also match the direction bit used in endpoint addresses and control 80 | /// request types. 81 | #[repr(u8)] 82 | #[derive(Copy, Clone, Eq, PartialEq, Debug)] 83 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 84 | pub enum UsbDirection { 85 | /// Host to device (OUT) 86 | Out = 0x00, 87 | /// Device to host (IN) 88 | In = 0x80, 89 | } 90 | 91 | impl From for UsbDirection { 92 | fn from(value: u8) -> Self { 93 | unsafe { core::mem::transmute(value & 0x80) } 94 | } 95 | } 96 | 97 | /// Result for USB operations. 98 | pub type Result = core::result::Result; 99 | 100 | /// USB control transfers and the SETUP packet. 101 | pub mod control; 102 | 103 | /// For implementing peripheral drivers. 104 | pub mod bus; 105 | 106 | /// For implementing standard as well as vendor-specific USB classes. 107 | /// 108 | /// To implement a new class, implement the [`UsbClass`](class::UsbClass) trait. The trait contains 109 | /// numerous callbacks that you can use to respond to USB events. None of the methods are required, 110 | /// and you only need to override the ones that your specific class needs to function. See the trait 111 | /// documentation for more information on the callback methods. 112 | /// 113 | /// Your class should *not* hold a direct reference to the [`UsbBus`](bus::UsbBus) object. Rather it 114 | /// should take a temporary reference to the [`UsbBusAllocator`](bus::UsbBusAllocator) object 115 | /// exposed by the bus in its constructor, and use that to allocate endpoints, as well as interface 116 | /// and string handles. Using the [`Endpoint`](endpoint::Endpoint) handles which wrap a reference to 117 | /// the `UsbBus` instance ensures that classes cannot inadvertently access an endpoint owned by 118 | /// another class. 119 | /// 120 | /// In addition to implementing the trait, add struct methods for the end-user to send and receive 121 | /// data via your class. For example, a serial port class might have class-specific methods `read` 122 | /// and `write` to read and write data. 123 | pub mod class; 124 | 125 | /// USB endpoints. 126 | pub mod endpoint; 127 | 128 | /// USB composite device. 129 | /// 130 | /// The [UsbDevice](device::UsbDevice) type in this module is the core of this crate. It combines 131 | /// multiple USB class implementations and the USB bus driver and dispatches bus state changes and 132 | /// control messages between them. 133 | /// 134 | /// To implement USB support for your own project, the required code is usually as follows: 135 | /// 136 | /// ``` ignore 137 | /// use core::cell::UnsafeCell; 138 | /// use usb_device::prelude::*; 139 | /// use usb_serial; // example class crate (not included) 140 | /// 141 | /// static mut CONTROL_BUFFER: UnsafeCell<[u8; 128]> = UnsafeCell::new([0; 128]); 142 | /// 143 | /// // Create the device-specific USB peripheral driver. The exact name and arguments are device 144 | /// // specific, so check the documentation for your device driver crate. 145 | /// let usb_bus = device_specific_usb::UsbBus::new(...); 146 | /// 147 | /// // Create one or more USB class implementation. The name and arguments depend on the class, 148 | /// // however most classes require the UsbAllocator as the first argument in order to allocate 149 | /// // the required shared resources. 150 | /// let mut serial = usb_serial::SerialPort::new(&usb_bus.allocator()); 151 | /// 152 | /// // Build the final [UsbDevice](device::UsbDevice) instance. The required arguments are a 153 | /// // reference to the peripheral driver created earlier, as well as a USB vendor ID/product ID 154 | /// // pair. Additional builder arguments can specify parameters such as device class code or 155 | /// // product name. If using an existing class, remember to check the class crate documentation 156 | /// // for correct values. 157 | /// let mut usb_dev = UsbDeviceBuilder::new(&usb_bus, UsbVidPid(0x5824, 0x27dd), unsafe { CONTROL_BUFFER.get_mut() }) 158 | /// .strings(&[StringDescriptors::new(LangID::EN) 159 | /// .product("Serial port")]) 160 | /// .expect("Failed to set strings") 161 | /// .device_class(usb_serial::DEVICE_CLASS) 162 | /// .build().unwrap(); 163 | /// 164 | /// // At this point the USB peripheral is enabled and a connected host will attempt to enumerate 165 | /// // it. 166 | /// loop { 167 | /// // Must be called more often than once every 10ms to handle events and stay USB compilant, 168 | /// // or from a device-specific interrupt handler. 169 | /// if (usb_dev.poll(&mut [&mut serial])) { 170 | /// // Call class-specific methods here 171 | /// serial.read(...); 172 | /// } 173 | /// } 174 | /// ``` 175 | pub mod device; 176 | 177 | /// Creating USB descriptors 178 | pub mod descriptor; 179 | 180 | pub use descriptor::lang_id::LangID; 181 | 182 | /// Test USB class for testing USB driver implementations. Peripheral driver implementations should 183 | /// include an example called "test_class" that creates a device with this class to enable the 184 | /// driver to be tested with the test_class_host example in this crate. 185 | pub mod test_class; 186 | 187 | /// Dummy bus with no functionality. 188 | /// 189 | /// Examples can create an instance of this bus so they can be compile-checked. 190 | /// Note that the lack of functionality does not allow to run the examples. 191 | /// 192 | /// ``` 193 | /// use usb_device::dummy::DummyUsbBus; 194 | /// use usb_device::class_prelude::UsbBusAllocator; 195 | /// 196 | /// let usb_bus = UsbBusAllocator::new(DummyUsbBus::new()); 197 | /// ``` 198 | pub mod dummy; 199 | 200 | mod control_pipe; 201 | 202 | mod device_builder; 203 | 204 | /// Prelude for device implementors. 205 | pub mod prelude { 206 | pub use crate::device::{ 207 | StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbDeviceState, UsbVidPid, 208 | }; 209 | pub use crate::device_builder::BuilderError; 210 | pub use crate::LangID; 211 | pub use crate::UsbError; 212 | } 213 | 214 | /// Prelude for class implementors. 215 | pub mod class_prelude { 216 | pub use crate::bus::{InterfaceNumber, StringIndex, UsbBus, UsbBusAllocator}; 217 | pub use crate::class::{ControlIn, ControlOut, UsbClass}; 218 | pub use crate::control; 219 | pub use crate::descriptor::{BosWriter, DescriptorWriter}; 220 | pub use crate::endpoint::{ 221 | EndpointAddress, EndpointIn, EndpointOut, EndpointType, IsochronousSynchronizationType, 222 | IsochronousUsageType, 223 | }; 224 | pub use crate::LangID; 225 | pub use crate::UsbError; 226 | } 227 | 228 | fn _ensure_sync() { 229 | use crate::bus::PollResult; 230 | use crate::class_prelude::*; 231 | 232 | struct DummyBus<'a> { 233 | _a: &'a str, 234 | } 235 | 236 | impl UsbBus for DummyBus<'_> { 237 | fn alloc_ep( 238 | &mut self, 239 | _ep_dir: UsbDirection, 240 | _ep_addr: Option, 241 | _ep_type: EndpointType, 242 | _max_packet_size: u16, 243 | _interval: u8, 244 | ) -> Result { 245 | Err(UsbError::EndpointOverflow) 246 | } 247 | 248 | fn enable(&mut self) {} 249 | 250 | fn reset(&self) {} 251 | fn set_device_address(&self, _addr: u8) {} 252 | 253 | fn write(&self, _ep_addr: EndpointAddress, _buf: &[u8]) -> Result { 254 | Err(UsbError::InvalidEndpoint) 255 | } 256 | 257 | fn read(&self, _ep_addr: EndpointAddress, _buf: &mut [u8]) -> Result { 258 | Err(UsbError::InvalidEndpoint) 259 | } 260 | 261 | fn set_stalled(&self, _ep_addr: EndpointAddress, _stalled: bool) {} 262 | fn is_stalled(&self, _ep_addr: EndpointAddress) -> bool { 263 | false 264 | } 265 | fn suspend(&self) {} 266 | fn resume(&self) {} 267 | fn poll(&self) -> PollResult { 268 | PollResult::None 269 | } 270 | } 271 | 272 | struct DummyClass<'a, B: UsbBus> { 273 | _ep: crate::endpoint::EndpointIn<'a, B>, 274 | } 275 | 276 | impl DummyClass<'_, B> { 277 | fn _new(alloc: &UsbBusAllocator) -> DummyClass<'_, B> { 278 | DummyClass { 279 | _ep: alloc.bulk(64), 280 | } 281 | } 282 | } 283 | 284 | impl UsbClass for DummyClass<'_, B> {} 285 | 286 | fn ensure_sync() {} 287 | 288 | ensure_sync::(); 289 | ensure_sync::>(); 290 | ensure_sync::>(); 291 | ensure_sync::>(); 292 | } 293 | -------------------------------------------------------------------------------- /src/test_class.rs: -------------------------------------------------------------------------------- 1 | #![allow(missing_docs)] 2 | 3 | use crate::class_prelude::*; 4 | use crate::device::{StringDescriptors, UsbDevice, UsbDeviceBuilder, UsbVidPid}; 5 | use crate::Result; 6 | use core::cell::UnsafeCell; 7 | use core::cmp; 8 | 9 | #[cfg(feature = "test-class-high-speed")] 10 | mod sizes { 11 | pub const BUFFER: usize = 2048; 12 | pub const CONTROL_ENDPOINT: u8 = 64; 13 | pub const BULK_ENDPOINT: u16 = 512; 14 | pub const INTERRUPT_ENDPOINT: u16 = 1024; 15 | } 16 | 17 | #[cfg(not(feature = "test-class-high-speed"))] 18 | mod sizes { 19 | pub const BUFFER: usize = 256; 20 | pub const CONTROL_ENDPOINT: u8 = 8; 21 | pub const BULK_ENDPOINT: u16 = 64; 22 | pub const INTERRUPT_ENDPOINT: u16 = 31; 23 | } 24 | 25 | static mut CONTROL_BUFFER: UnsafeCell<[u8; 256]> = UnsafeCell::new([0; 256]); 26 | 27 | /// Test USB class for testing USB driver implementations. Supports various endpoint types and 28 | /// requests for testing USB peripheral drivers on actual hardware. 29 | pub struct TestClass<'a, B: UsbBus> { 30 | custom_string: StringIndex, 31 | interface_string: StringIndex, 32 | iface: InterfaceNumber, 33 | ep_bulk_in: EndpointIn<'a, B>, 34 | ep_bulk_out: EndpointOut<'a, B>, 35 | ep_interrupt_in: EndpointIn<'a, B>, 36 | ep_interrupt_out: EndpointOut<'a, B>, 37 | ep_iso_in: EndpointIn<'a, B>, 38 | control_buf: [u8; sizes::BUFFER], 39 | bulk_buf: [u8; sizes::BUFFER], 40 | interrupt_buf: [u8; sizes::BUFFER], 41 | len: usize, 42 | i: usize, 43 | bench: bool, 44 | expect_bulk_in_complete: bool, 45 | expect_bulk_out: bool, 46 | expect_interrupt_in_complete: bool, 47 | expect_interrupt_out: bool, 48 | } 49 | 50 | pub const VID: u16 = 0x16c0; 51 | pub const PID: u16 = 0x05dc; 52 | pub const MANUFACTURER: &str = "TestClass Manufacturer"; 53 | pub const PRODUCT: &str = "virkkunen.net usb-device TestClass"; 54 | pub const SERIAL_NUMBER: &str = "TestClass Serial"; 55 | pub const CUSTOM_STRING: &str = "TestClass Custom String"; 56 | pub const INTERFACE_STRING: &str = "TestClass Interface"; 57 | 58 | pub const REQ_STORE_REQUEST: u8 = 1; 59 | pub const REQ_READ_BUFFER: u8 = 2; 60 | pub const REQ_WRITE_BUFFER: u8 = 3; 61 | pub const REQ_SET_BENCH_ENABLED: u8 = 4; 62 | pub const REQ_READ_LONG_DATA: u8 = 5; 63 | pub const REQ_UNKNOWN: u8 = 42; 64 | 65 | pub const LONG_DATA: &[u8] = &[0x17; 257]; 66 | 67 | impl TestClass<'_, B> { 68 | /// Creates a new TestClass. 69 | pub fn new(alloc: &UsbBusAllocator) -> TestClass<'_, B> { 70 | TestClass { 71 | custom_string: alloc.string(), 72 | interface_string: alloc.string(), 73 | iface: alloc.interface(), 74 | ep_bulk_in: alloc.bulk(sizes::BULK_ENDPOINT), 75 | ep_bulk_out: alloc.bulk(sizes::BULK_ENDPOINT), 76 | ep_interrupt_in: alloc.interrupt(sizes::INTERRUPT_ENDPOINT, 1), 77 | ep_interrupt_out: alloc.interrupt(sizes::INTERRUPT_ENDPOINT, 1), 78 | ep_iso_in: alloc.isochronous( 79 | IsochronousSynchronizationType::Asynchronous, 80 | IsochronousUsageType::ImplicitFeedbackData, 81 | 500, // These last two args are arbitrary in this usage, they 82 | 1, // let the host know how much bandwidth to reserve. 83 | ), 84 | control_buf: [0; sizes::BUFFER], 85 | bulk_buf: [0; sizes::BUFFER], 86 | interrupt_buf: [0; sizes::BUFFER], 87 | len: 0, 88 | i: 0, 89 | bench: false, 90 | expect_bulk_in_complete: false, 91 | expect_bulk_out: false, 92 | expect_interrupt_in_complete: false, 93 | expect_interrupt_out: false, 94 | } 95 | } 96 | 97 | /// Convenience method to create a UsbDevice that is configured correctly for TestClass. 98 | pub fn make_device<'a>(&self, usb_bus: &'a UsbBusAllocator) -> UsbDevice<'a, B> { 99 | self.make_device_builder(usb_bus).build().unwrap() 100 | } 101 | 102 | /// Convenience method to create a UsbDeviceBuilder that is configured correctly for TestClass. 103 | /// 104 | /// The methods sets 105 | /// 106 | /// - manufacturer 107 | /// - product 108 | /// - serial number 109 | /// - max_packet_size_0 110 | /// 111 | /// on the returned builder. If you change the manufacturer, product, or serial number fields, 112 | /// the test host may misbehave. 113 | pub fn make_device_builder<'a>( 114 | &self, 115 | usb_bus: &'a UsbBusAllocator, 116 | ) -> UsbDeviceBuilder<'a, B> { 117 | UsbDeviceBuilder::new(usb_bus, UsbVidPid(VID, PID), unsafe { 118 | CONTROL_BUFFER.get_mut() 119 | }) 120 | .strings(&[StringDescriptors::default() 121 | .manufacturer(MANUFACTURER) 122 | .product(PRODUCT) 123 | .serial_number(SERIAL_NUMBER)]) 124 | .unwrap() 125 | .max_packet_size_0(sizes::CONTROL_ENDPOINT) 126 | .unwrap() 127 | } 128 | 129 | /// Must be called after polling the UsbDevice. 130 | pub fn poll(&mut self) { 131 | if self.bench { 132 | match self.ep_bulk_out.read(&mut self.bulk_buf) { 133 | Ok(_) | Err(UsbError::WouldBlock) => {} 134 | Err(err) => panic!("bulk bench read {:?}", err), 135 | }; 136 | 137 | match self 138 | .ep_bulk_in 139 | .write(&self.bulk_buf[0..self.ep_bulk_in.max_packet_size() as usize]) 140 | { 141 | Ok(_) | Err(UsbError::WouldBlock) => {} 142 | Err(err) => panic!("bulk bench write {:?}", err), 143 | }; 144 | 145 | return; 146 | } 147 | 148 | let temp_i = self.i; 149 | match self.ep_bulk_out.read(&mut self.bulk_buf[temp_i..]) { 150 | Ok(count) => { 151 | if self.expect_bulk_out { 152 | self.expect_bulk_out = false; 153 | } else { 154 | panic!("unexpectedly read data from bulk out endpoint"); 155 | } 156 | 157 | self.i += count; 158 | 159 | if count < self.ep_bulk_out.max_packet_size() as usize { 160 | self.len = self.i; 161 | self.i = 0; 162 | 163 | self.write_bulk_in(count == 0); 164 | } 165 | } 166 | Err(UsbError::WouldBlock) => {} 167 | Err(err) => panic!("bulk read {:?}", err), 168 | }; 169 | 170 | match self.ep_interrupt_out.read(&mut self.interrupt_buf) { 171 | Ok(count) => { 172 | if self.expect_interrupt_out { 173 | self.expect_interrupt_out = false; 174 | } else { 175 | panic!("unexpectedly read data from interrupt out endpoint"); 176 | } 177 | 178 | self.ep_interrupt_in 179 | .write(&self.interrupt_buf[0..count]) 180 | .expect("interrupt write"); 181 | 182 | self.expect_interrupt_in_complete = true; 183 | } 184 | Err(UsbError::WouldBlock) => {} 185 | Err(err) => panic!("interrupt read {:?}", err), 186 | }; 187 | } 188 | 189 | fn write_bulk_in(&mut self, write_empty: bool) { 190 | let to_write = cmp::min( 191 | self.len - self.i, 192 | self.ep_bulk_in.max_packet_size() as usize, 193 | ); 194 | 195 | if to_write == 0 && !write_empty { 196 | self.len = 0; 197 | self.i = 0; 198 | 199 | return; 200 | } 201 | 202 | match self 203 | .ep_bulk_in 204 | .write(&self.bulk_buf[self.i..self.i + to_write]) 205 | { 206 | Ok(count) => { 207 | assert_eq!(count, to_write); 208 | self.expect_bulk_in_complete = true; 209 | self.i += count; 210 | } 211 | Err(UsbError::WouldBlock) => {} 212 | Err(err) => panic!("bulk write {:?}", err), 213 | }; 214 | } 215 | } 216 | 217 | impl UsbClass for TestClass<'_, B> { 218 | fn reset(&mut self) { 219 | self.len = 0; 220 | self.i = 0; 221 | self.bench = false; 222 | self.expect_bulk_in_complete = false; 223 | self.expect_bulk_out = false; 224 | self.expect_interrupt_in_complete = false; 225 | self.expect_interrupt_out = false; 226 | } 227 | 228 | fn get_configuration_descriptors(&self, writer: &mut DescriptorWriter) -> Result<()> { 229 | writer.interface(self.iface, 0xff, 0x00, 0x00)?; 230 | writer.endpoint(&self.ep_bulk_in)?; 231 | writer.endpoint(&self.ep_bulk_out)?; 232 | writer.endpoint(&self.ep_interrupt_in)?; 233 | writer.endpoint(&self.ep_interrupt_out)?; 234 | writer.interface_alt(self.iface, 1, 0xff, 0x01, 0x00, Some(self.interface_string))?; 235 | writer.endpoint(&self.ep_iso_in)?; 236 | Ok(()) 237 | } 238 | 239 | fn get_string(&self, index: StringIndex, lang_id: LangID) -> Option<&str> { 240 | if lang_id == LangID::EN_US { 241 | if index == self.custom_string { 242 | return Some(CUSTOM_STRING); 243 | } else if index == self.interface_string { 244 | return Some(INTERFACE_STRING); 245 | } 246 | } 247 | 248 | None 249 | } 250 | 251 | fn endpoint_in_complete(&mut self, addr: EndpointAddress) { 252 | if self.bench { 253 | return; 254 | } 255 | 256 | if addr == self.ep_bulk_in.address() { 257 | if self.expect_bulk_in_complete { 258 | self.expect_bulk_in_complete = false; 259 | 260 | self.write_bulk_in(false); 261 | } else { 262 | panic!("unexpected endpoint_in_complete"); 263 | } 264 | } else if addr == self.ep_interrupt_in.address() { 265 | if self.expect_interrupt_in_complete { 266 | self.expect_interrupt_in_complete = false; 267 | } else { 268 | panic!("unexpected endpoint_in_complete"); 269 | } 270 | } 271 | } 272 | 273 | fn endpoint_out(&mut self, addr: EndpointAddress) { 274 | if addr == self.ep_bulk_out.address() { 275 | self.expect_bulk_out = true; 276 | } else if addr == self.ep_interrupt_out.address() { 277 | self.expect_interrupt_out = true; 278 | } 279 | } 280 | 281 | fn control_in(&mut self, xfer: ControlIn) { 282 | let req = *xfer.request(); 283 | 284 | if !(req.request_type == control::RequestType::Vendor 285 | && req.recipient == control::Recipient::Device) 286 | { 287 | return; 288 | } 289 | 290 | match req.request { 291 | REQ_READ_BUFFER if req.length as usize <= self.control_buf.len() => xfer 292 | .accept_with(&self.control_buf[0..req.length as usize]) 293 | .expect("control_in REQ_READ_BUFFER failed"), 294 | REQ_READ_LONG_DATA => xfer 295 | .accept_with_static(LONG_DATA) 296 | .expect("control_in REQ_READ_LONG_DATA failed"), 297 | _ => xfer.reject().expect("control_in reject failed"), 298 | } 299 | } 300 | 301 | fn control_out(&mut self, xfer: ControlOut) { 302 | let req = *xfer.request(); 303 | 304 | if !(req.request_type == control::RequestType::Vendor 305 | && req.recipient == control::Recipient::Device) 306 | { 307 | return; 308 | } 309 | 310 | match req.request { 311 | REQ_STORE_REQUEST => { 312 | self.control_buf[0] = 313 | (req.direction as u8) | (req.request_type as u8) << 5 | (req.recipient as u8); 314 | self.control_buf[1] = req.request; 315 | self.control_buf[2..4].copy_from_slice(&req.value.to_le_bytes()); 316 | self.control_buf[4..6].copy_from_slice(&req.index.to_le_bytes()); 317 | self.control_buf[6..8].copy_from_slice(&req.length.to_le_bytes()); 318 | 319 | xfer.accept().expect("control_out REQ_STORE_REQUEST failed"); 320 | } 321 | REQ_WRITE_BUFFER if xfer.data().len() <= self.control_buf.len() => { 322 | assert_eq!( 323 | xfer.data().len(), 324 | req.length as usize, 325 | "xfer data len == req.length" 326 | ); 327 | 328 | self.control_buf[0..xfer.data().len()].copy_from_slice(xfer.data()); 329 | 330 | xfer.accept().expect("control_out REQ_WRITE_BUFFER failed"); 331 | } 332 | REQ_SET_BENCH_ENABLED => { 333 | self.bench = req.value != 0; 334 | 335 | xfer.accept() 336 | .expect("control_out REQ_SET_BENCH_ENABLED failed"); 337 | } 338 | _ => xfer.reject().expect("control_out reject failed"), 339 | } 340 | } 341 | } 342 | -------------------------------------------------------------------------------- /src/bus.rs: -------------------------------------------------------------------------------- 1 | use crate::endpoint::{ 2 | Endpoint, EndpointAddress, EndpointDirection, EndpointType, IsochronousSynchronizationType, 3 | IsochronousUsageType, 4 | }; 5 | use crate::{Result, UsbDirection, UsbError}; 6 | use core::cell::RefCell; 7 | use core::mem; 8 | use core::ptr; 9 | use portable_atomic::{AtomicPtr, Ordering}; 10 | 11 | /// A trait for device-specific USB peripherals. Implement this to add support for a new hardware 12 | /// platform. 13 | /// 14 | /// The UsbBus is shared by reference between the global [`UsbDevice`](crate::device::UsbDevice) as 15 | /// well as [`UsbClass`](crate::class::UsbClass)es, and therefore any required mutability must be 16 | /// implemented using interior mutability. Most operations that may mutate the bus object itself 17 | /// take place before [`enable`](UsbBus::enable) is called. After the bus is enabled, in practice 18 | /// most access won't mutate the object itself but only endpoint-specific registers and buffers, the 19 | /// access to which is mostly arbitrated by endpoint handles. 20 | pub trait UsbBus: Sized { 21 | /// Allocates an endpoint and specified endpoint parameters. This method is called by the device 22 | /// and class implementations to allocate endpoints, and can only be called before 23 | /// [`enable`](UsbBus::enable) is called. 24 | /// 25 | /// # Arguments 26 | /// 27 | /// * `ep_dir` - The endpoint direction. 28 | /// * `ep_addr` - A static endpoint address to allocate. If Some, the implementation should 29 | /// attempt to return an endpoint with the specified address. If None, the implementation 30 | /// should return the next available one. 31 | /// * `max_packet_size` - Maximum packet size in bytes. 32 | /// * `interval` - Polling interval parameter for interrupt endpoints. 33 | /// 34 | /// # Errors 35 | /// 36 | /// * [`EndpointOverflow`](crate::UsbError::EndpointOverflow) - Available total number of 37 | /// endpoints, endpoints of the specified type, or endpoind packet memory has been exhausted. 38 | /// This is generally caused when a user tries to add too many classes to a composite device. 39 | /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - A specific `ep_addr` was specified 40 | /// but the endpoint in question has already been allocated. 41 | fn alloc_ep( 42 | &mut self, 43 | ep_dir: UsbDirection, 44 | ep_addr: Option, 45 | ep_type: EndpointType, 46 | max_packet_size: u16, 47 | interval: u8, 48 | ) -> Result; 49 | 50 | /// Enables and initializes the USB peripheral. Soon after enabling the device will be reset, so 51 | /// there is no need to perform a USB reset in this method. 52 | fn enable(&mut self); 53 | 54 | /// Called when the host resets the device. This will be soon called after 55 | /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Reset`]. This method should 56 | /// reset the state of all endpoints and peripheral flags back to a state suitable for 57 | /// enumeration, as well as ensure that all endpoints previously allocated with alloc_ep are 58 | /// initialized as specified. 59 | fn reset(&self); 60 | 61 | /// Sets the device USB address to `addr`. 62 | fn set_device_address(&self, addr: u8); 63 | 64 | /// Writes a single packet of data to the specified endpoint and returns number of bytes 65 | /// actually written. 66 | /// 67 | /// The only reason for a short write is if the caller passes a slice larger than the amount of 68 | /// memory allocated earlier, and this is generally an error in the class implementation. 69 | /// 70 | /// # Errors 71 | /// 72 | /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - The `ep_addr` does not point to a 73 | /// valid endpoint that was previously allocated with [`UsbBus::alloc_ep`]. 74 | /// * [`WouldBlock`](crate::UsbError::WouldBlock) - A previously written packet is still pending 75 | /// to be sent. 76 | /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The packet is too long to fit in the 77 | /// transmission buffer. This is generally an error in the class implementation, because the 78 | /// class shouldn't provide more data than the `max_packet_size` it specified when allocating 79 | /// the endpoint. 80 | /// 81 | /// Implementations may also return other errors if applicable. 82 | fn write(&self, ep_addr: EndpointAddress, buf: &[u8]) -> Result; 83 | 84 | /// Reads a single packet of data from the specified endpoint and returns the actual length of 85 | /// the packet. 86 | /// 87 | /// This should also clear any NAK flags and prepare the endpoint to receive the next packet. 88 | /// 89 | /// # Errors 90 | /// 91 | /// * [`InvalidEndpoint`](crate::UsbError::InvalidEndpoint) - The `ep_addr` does not point to a 92 | /// valid endpoint that was previously allocated with [`UsbBus::alloc_ep`]. 93 | /// * [`WouldBlock`](crate::UsbError::WouldBlock) - There is no packet to be read. Note that 94 | /// this is different from a received zero-length packet, which is valid in USB. A zero-length 95 | /// packet will return `Ok(0)`. 96 | /// * [`BufferOverflow`](crate::UsbError::BufferOverflow) - The received packet is too long to 97 | /// fit in `buf`. This is generally an error in the class implementation, because the class 98 | /// should use a buffer that is large enough for the `max_packet_size` it specified when 99 | /// allocating the endpoint. 100 | /// 101 | /// Implementations may also return other errors if applicable. 102 | fn read(&self, ep_addr: EndpointAddress, buf: &mut [u8]) -> Result; 103 | 104 | /// Sets or clears the STALL condition for an endpoint. If the endpoint is an OUT endpoint, it 105 | /// should be prepared to receive data again. 106 | fn set_stalled(&self, ep_addr: EndpointAddress, stalled: bool); 107 | 108 | /// Gets whether the STALL condition is set for an endpoint. 109 | fn is_stalled(&self, ep_addr: EndpointAddress) -> bool; 110 | 111 | /// Causes the USB peripheral to enter USB suspend mode, lowering power consumption and 112 | /// preparing to detect a USB wakeup event. This will be called after 113 | /// [`poll`](crate::device::UsbDevice::poll) returns [`PollResult::Suspend`]. The device will 114 | /// continue be polled, and it shall return a value other than `Suspend` from `poll` when it no 115 | /// longer detects the suspend condition. 116 | fn suspend(&self); 117 | 118 | /// Resumes from suspend mode. This may only be called after the peripheral has been previously 119 | /// suspended. 120 | fn resume(&self); 121 | 122 | /// Gets information about events and incoming data. Usually called in a loop or from an 123 | /// interrupt handler. See the [`PollResult`] struct for more information. 124 | fn poll(&self) -> PollResult; 125 | 126 | /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the 127 | /// device. 128 | /// 129 | /// The default implementation just returns `Unsupported`. 130 | /// 131 | /// # Errors 132 | /// 133 | /// * [`Unsupported`](crate::UsbError::Unsupported) - This UsbBus implementation doesn't support 134 | /// simulating a disconnect or it has not been enabled at creation time. 135 | fn force_reset(&self) -> Result<()> { 136 | Err(UsbError::Unsupported) 137 | } 138 | 139 | /// Indicates that `set_device_address` must be called before accepting the corresponding 140 | /// control transfer, not after. 141 | /// 142 | /// The default value for this constant is `false`, which corresponds to the USB 2.0 spec, 9.4.6 143 | const QUIRK_SET_ADDRESS_BEFORE_STATUS: bool = false; 144 | } 145 | 146 | struct AllocatorState { 147 | next_interface_number: u8, 148 | next_string_index: u8, 149 | } 150 | 151 | /// Helper type used for UsbBus resource allocation and initialization. 152 | pub struct UsbBusAllocator { 153 | bus: RefCell, 154 | bus_ptr: AtomicPtr, 155 | state: RefCell, 156 | } 157 | 158 | impl UsbBusAllocator { 159 | /// Creates a new [`UsbBusAllocator`] that wraps the provided [`UsbBus`]. Usually only called by 160 | /// USB driver implementations. 161 | pub fn new(bus: B) -> UsbBusAllocator { 162 | UsbBusAllocator { 163 | bus: RefCell::new(bus), 164 | bus_ptr: AtomicPtr::new(ptr::null_mut()), 165 | state: RefCell::new(AllocatorState { 166 | next_interface_number: 0, 167 | next_string_index: 4, 168 | }), 169 | } 170 | } 171 | 172 | pub(crate) fn freeze(&self) -> &B { 173 | // Prevent further allocation by borrowing the allocation state permanently. 174 | mem::forget(self.state.borrow_mut()); 175 | 176 | // Enable the USB bus 177 | self.bus.borrow_mut().enable(); 178 | 179 | // An AtomicPtr is used for the reference from Endpoints to UsbBus, in order to ensure that 180 | // Endpoints stay Sync (if the Endpoints had a reference to a RefCell, they would not be 181 | // Sync) Set the pointer used by the Endpoints to access the UsbBus to point to the UsbBus 182 | // in the RefCell. 183 | let mut bus_ref = self.bus.borrow_mut(); 184 | let bus_ptr_v = &mut *bus_ref as *mut B; 185 | self.bus_ptr.store(bus_ptr_v, Ordering::SeqCst); 186 | 187 | // And then leave the RefCell borrowed permanently so that it cannot be borrowed mutably 188 | // anymore. 189 | mem::forget(bus_ref); 190 | 191 | // Return the reference to the UsbBus, for use by UsbDevice. 192 | unsafe { &*bus_ptr_v } 193 | } 194 | 195 | /// Allocates a new interface number. 196 | pub fn interface(&self) -> InterfaceNumber { 197 | let mut state = self.state.borrow_mut(); 198 | let number = state.next_interface_number; 199 | state.next_interface_number += 1; 200 | 201 | InterfaceNumber(number) 202 | } 203 | 204 | /// Allocates a new string index. 205 | pub fn string(&self) -> StringIndex { 206 | let mut state = self.state.borrow_mut(); 207 | let index = state.next_string_index; 208 | state.next_string_index += 1; 209 | 210 | StringIndex(index) 211 | } 212 | 213 | /// Allocates an endpoint with the specified direction and address. 214 | /// 215 | /// This directly delegates to [`UsbBus::alloc_ep`], so see that method for details. In most 216 | /// cases classes should call the endpoint type specific methods instead. 217 | pub fn alloc( 218 | &self, 219 | ep_addr: Option, 220 | ep_type: EndpointType, 221 | max_packet_size: u16, 222 | interval: u8, 223 | ) -> Result> { 224 | self.bus 225 | .borrow_mut() 226 | .alloc_ep(D::DIRECTION, ep_addr, ep_type, max_packet_size, interval) 227 | .map(|a| Endpoint::new(&self.bus_ptr, a, ep_type, max_packet_size, interval)) 228 | } 229 | 230 | /// Allocates a control endpoint. 231 | /// 232 | /// This crate implements the control state machine only for endpoint 0. If classes want to 233 | /// support control requests in other endpoints, the state machine must be implemented manually. 234 | /// This should rarely be needed by classes. 235 | /// 236 | /// # Arguments 237 | /// 238 | /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64. 239 | /// 240 | /// # Panics 241 | /// 242 | /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 243 | /// feasibly recoverable. 244 | #[inline] 245 | pub fn control(&self, max_packet_size: u16) -> Endpoint<'_, B, D> { 246 | self.alloc(None, EndpointType::Control, max_packet_size, 0) 247 | .expect("alloc_ep failed") 248 | } 249 | 250 | /// Allocates an isochronous endpoint. 251 | /// 252 | /// # Arguments 253 | /// 254 | /// * `synchronization` - Type of synchronization used by the endpoint 255 | /// * `usage` - Whether the endpoint is data, explicit feedback, or data+implicit feedback 256 | /// * `payload_size` - Payload size in bytes. 257 | /// * `interval` - Interval for polling, expressed in frames/microframes. 258 | /// 259 | /// See USB 2.0 section 9.6.6. 260 | /// 261 | /// # Panics 262 | /// 263 | /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 264 | /// feasibly recoverable. 265 | #[inline] 266 | pub fn isochronous( 267 | &self, 268 | synchronization: IsochronousSynchronizationType, 269 | usage: IsochronousUsageType, 270 | payload_size: u16, 271 | interval: u8, 272 | ) -> Endpoint<'_, B, D> { 273 | self.alloc( 274 | None, 275 | EndpointType::Isochronous { 276 | synchronization, 277 | usage, 278 | }, 279 | payload_size, 280 | interval, 281 | ) 282 | .expect("alloc_ep failed") 283 | } 284 | 285 | /// Allocates a bulk endpoint. 286 | /// 287 | /// # Arguments 288 | /// 289 | /// * `max_packet_size` - Maximum packet size in bytes. Must be one of 8, 16, 32 or 64. 290 | /// 291 | /// # Panics 292 | /// 293 | /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 294 | /// feasibly recoverable. 295 | #[inline] 296 | pub fn bulk(&self, max_packet_size: u16) -> Endpoint<'_, B, D> { 297 | self.alloc(None, EndpointType::Bulk, max_packet_size, 0) 298 | .expect("alloc_ep failed") 299 | } 300 | 301 | /// Allocates an interrupt endpoint. 302 | /// 303 | /// * `max_packet_size` - Maximum packet size in bytes. Cannot exceed 64 bytes. 304 | /// * `interval` - Polling interval. 305 | /// 306 | /// # Panics 307 | /// 308 | /// Panics if endpoint allocation fails, because running out of endpoints or memory is not 309 | /// feasibly recoverable. 310 | #[inline] 311 | pub fn interrupt( 312 | &self, 313 | max_packet_size: u16, 314 | interval: u8, 315 | ) -> Endpoint<'_, B, D> { 316 | self.alloc(None, EndpointType::Interrupt, max_packet_size, interval) 317 | .expect("alloc_ep failed") 318 | } 319 | } 320 | 321 | /// A handle for a USB interface that contains its number. 322 | #[derive(Copy, Clone, Eq, PartialEq)] 323 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 324 | pub struct InterfaceNumber(pub(crate) u8); 325 | 326 | impl From for u8 { 327 | fn from(n: InterfaceNumber) -> u8 { 328 | n.0 329 | } 330 | } 331 | 332 | /// A handle for a USB string descriptor that contains its index. 333 | #[derive(Copy, Clone, Eq, PartialEq)] 334 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 335 | pub struct StringIndex(u8); 336 | 337 | impl StringIndex { 338 | pub(crate) fn new(index: u8) -> StringIndex { 339 | StringIndex(index) 340 | } 341 | } 342 | 343 | impl From for u8 { 344 | fn from(i: StringIndex) -> u8 { 345 | i.0 346 | } 347 | } 348 | 349 | /// Event and incoming packet information returned by [`UsbBus::poll`]. 350 | pub enum PollResult { 351 | /// No events or packets to report. 352 | None, 353 | 354 | /// The USB reset condition has been detected. 355 | Reset, 356 | 357 | /// USB packets have been received or sent. Each data field is a bit-field where the least 358 | /// significant bit represents endpoint 0 etc., and a set bit signifies the event has occurred 359 | /// for the corresponding endpoint. 360 | Data { 361 | /// An OUT packet has been received. This event should continue to be reported until the 362 | /// packet is read. 363 | ep_out: u16, 364 | 365 | /// An IN packet has finished transmitting. This event should only be reported once for each 366 | /// completed transfer. 367 | ep_in_complete: u16, 368 | 369 | /// A SETUP packet has been received. This event should continue to be reported until the 370 | /// packet is read. The corresponding bit in `ep_out` may also be set but is ignored. 371 | ep_setup: u16, 372 | }, 373 | 374 | /// A USB suspend request has been detected or, in the case of self-powered devices, the device 375 | /// has been disconnected from the USB bus. 376 | Suspend, 377 | 378 | /// A USB resume request has been detected after being suspended or, in the case of self-powered 379 | /// devices, the device has been connected to the USB bus. 380 | Resume, 381 | } 382 | -------------------------------------------------------------------------------- /src/descriptor.rs: -------------------------------------------------------------------------------- 1 | use core::cmp::min; 2 | 3 | use crate::bus::{InterfaceNumber, StringIndex, UsbBus}; 4 | use crate::device; 5 | use crate::endpoint::{Endpoint, EndpointDirection}; 6 | use crate::{Result, UsbError}; 7 | 8 | /// Standard descriptor types 9 | #[allow(missing_docs)] 10 | pub mod descriptor_type { 11 | pub const DEVICE: u8 = 1; 12 | pub const CONFIGURATION: u8 = 2; 13 | pub const STRING: u8 = 3; 14 | pub const INTERFACE: u8 = 4; 15 | pub const ENDPOINT: u8 = 5; 16 | pub const IAD: u8 = 11; 17 | pub const BOS: u8 = 15; 18 | pub const CAPABILITY: u8 = 16; 19 | } 20 | 21 | /// String descriptor language IDs. 22 | pub mod lang_id; 23 | 24 | /// Standard capability descriptor types 25 | #[allow(missing_docs)] 26 | pub mod capability_type { 27 | pub const WIRELESS_USB: u8 = 1; 28 | pub const USB_2_0_EXTENSION: u8 = 2; 29 | pub const SS_USB_DEVICE: u8 = 3; 30 | pub const CONTAINER_ID: u8 = 4; 31 | pub const PLATFORM: u8 = 5; 32 | } 33 | 34 | /// A writer for USB descriptors. 35 | pub struct DescriptorWriter<'a> { 36 | buf: &'a mut [u8], 37 | position: usize, 38 | num_interfaces_mark: Option, 39 | num_endpoints_mark: Option, 40 | write_iads: bool, 41 | } 42 | 43 | impl DescriptorWriter<'_> { 44 | pub(crate) fn new(buf: &mut [u8]) -> DescriptorWriter<'_> { 45 | DescriptorWriter { 46 | buf, 47 | position: 0, 48 | num_interfaces_mark: None, 49 | num_endpoints_mark: None, 50 | write_iads: false, 51 | } 52 | } 53 | 54 | /// Gets the current position in the buffer, i.e. the number of bytes written so far. 55 | pub fn position(&self) -> usize { 56 | self.position 57 | } 58 | 59 | /// Writes an arbitrary (usually class-specific) descriptor. 60 | pub fn write(&mut self, descriptor_type: u8, descriptor: &[u8]) -> Result<()> { 61 | self.write_with(descriptor_type, |buf| { 62 | if descriptor.len() > buf.len() { 63 | return Err(UsbError::BufferOverflow); 64 | } 65 | 66 | buf[..descriptor.len()].copy_from_slice(descriptor); 67 | 68 | Ok(descriptor.len()) 69 | }) 70 | } 71 | 72 | /// Writes an arbitrary (usually class-specific) descriptor by using a callback function. 73 | /// 74 | /// The callback function gets a reference to the remaining buffer space, and it should write 75 | /// the descriptor into it and return the number of bytes written. If the descriptor doesn't 76 | /// fit, the function should return `Err(UsbError::BufferOverflow)`. That and any error returned 77 | /// by it will be propagated up. 78 | pub fn write_with( 79 | &mut self, 80 | descriptor_type: u8, 81 | f: impl FnOnce(&mut [u8]) -> Result, 82 | ) -> Result<()> { 83 | if self.position + 2 > self.buf.len() { 84 | return Err(UsbError::BufferOverflow); 85 | } 86 | 87 | let data_end = min(self.buf.len(), self.position + 256); 88 | let data_buf = &mut self.buf[self.position + 2..data_end]; 89 | 90 | let total_len = f(data_buf)? + 2; 91 | 92 | if self.position + total_len > self.buf.len() { 93 | return Err(UsbError::BufferOverflow); 94 | } 95 | 96 | self.buf[self.position] = total_len as u8; 97 | self.buf[self.position + 1] = descriptor_type; 98 | 99 | self.position += total_len; 100 | 101 | Ok(()) 102 | } 103 | 104 | pub(crate) fn device(&mut self, config: &device::Config) -> Result<()> { 105 | self.write( 106 | descriptor_type::DEVICE, 107 | &[ 108 | (config.usb_rev as u16) as u8, 109 | (config.usb_rev as u16 >> 8) as u8, // bcdUSB 110 | config.device_class, // bDeviceClass 111 | config.device_sub_class, // bDeviceSubClass 112 | config.device_protocol, // bDeviceProtocol 113 | config.max_packet_size_0, // bMaxPacketSize0 114 | config.vendor_id as u8, 115 | (config.vendor_id >> 8) as u8, // idVendor 116 | config.product_id as u8, 117 | (config.product_id >> 8) as u8, // idProduct 118 | config.device_release as u8, 119 | (config.device_release >> 8) as u8, // bcdDevice 120 | config.string_descriptors.first().map_or(0, |lang| { 121 | if lang.manufacturer.is_some() { 122 | 1 123 | } else { 124 | 0 125 | } 126 | }), 127 | config.string_descriptors.first().map_or(0, |lang| { 128 | if lang.product.is_some() { 129 | 2 130 | } else { 131 | 0 132 | } 133 | }), 134 | config.string_descriptors.first().map_or(0, |lang| { 135 | if lang.serial.is_some() { 136 | 3 137 | } else { 138 | 0 139 | } 140 | }), 141 | 1, // bNumConfigurations 142 | ], 143 | ) 144 | } 145 | 146 | pub(crate) fn configuration(&mut self, config: &device::Config) -> Result<()> { 147 | self.num_interfaces_mark = Some(self.position + 4); 148 | 149 | self.write_iads = config.composite_with_iads; 150 | 151 | self.write( 152 | descriptor_type::CONFIGURATION, 153 | &[ 154 | 0, 155 | 0, // wTotalLength 156 | 0, // bNumInterfaces 157 | device::CONFIGURATION_VALUE, // bConfigurationValue 158 | 0, // iConfiguration 159 | 0x80 | if config.self_powered { 0x40 } else { 0x00 } 160 | | if config.supports_remote_wakeup { 161 | 0x20 162 | } else { 163 | 0x00 164 | }, // bmAttributes 165 | config.max_power, // bMaxPower 166 | ], 167 | ) 168 | } 169 | 170 | pub(crate) fn end_class(&mut self) { 171 | self.num_endpoints_mark = None; 172 | } 173 | 174 | pub(crate) fn end_configuration(&mut self) { 175 | let position = self.position as u16; 176 | self.buf[2..4].copy_from_slice(&position.to_le_bytes()); 177 | } 178 | 179 | /// Writes a interface association descriptor. Call from `UsbClass::get_configuration_descriptors` 180 | /// before writing the USB class or function's interface descriptors if your class has more than 181 | /// one interface and wants to play nicely with composite devices on Windows. If the USB device 182 | /// hosting the class was not configured as composite with IADs enabled, calling this function 183 | /// does nothing, so it is safe to call from libraries. 184 | /// 185 | /// # Arguments 186 | /// 187 | /// * `first_interface` - Number of the function's first interface, previously allocated with 188 | /// [`UsbBusAllocator::interface`](crate::bus::UsbBusAllocator::interface). 189 | /// * `interface_count` - Number of interfaces in the function. 190 | /// * `function_class` - Class code assigned by USB.org. Use `0xff` for vendor-specific devices 191 | /// that do not conform to any class. 192 | /// * `function_sub_class` - Sub-class code. Depends on class. 193 | /// * `function_protocol` - Protocol code. Depends on class and sub-class. 194 | /// * `function_string` - Index of string descriptor describing this function 195 | pub fn iad( 196 | &mut self, 197 | first_interface: InterfaceNumber, 198 | interface_count: u8, 199 | function_class: u8, 200 | function_sub_class: u8, 201 | function_protocol: u8, 202 | function_string: Option, 203 | ) -> Result<()> { 204 | if !self.write_iads { 205 | return Ok(()); 206 | } 207 | 208 | let str_index = function_string.map_or(0, Into::into); 209 | 210 | self.write( 211 | descriptor_type::IAD, 212 | &[ 213 | first_interface.into(), // bFirstInterface 214 | interface_count, // bInterfaceCount 215 | function_class, 216 | function_sub_class, 217 | function_protocol, 218 | str_index, 219 | ], 220 | )?; 221 | 222 | Ok(()) 223 | } 224 | 225 | /// Writes a interface descriptor. 226 | /// 227 | /// # Arguments 228 | /// 229 | /// * `number` - Interface number previously allocated with 230 | /// [`UsbBusAllocator::interface`](crate::bus::UsbBusAllocator::interface). 231 | /// * `interface_class` - Class code assigned by USB.org. Use `0xff` for vendor-specific devices 232 | /// that do not conform to any class. 233 | /// * `interface_sub_class` - Sub-class code. Depends on class. 234 | /// * `interface_protocol` - Protocol code. Depends on class and sub-class. 235 | pub fn interface( 236 | &mut self, 237 | number: InterfaceNumber, 238 | interface_class: u8, 239 | interface_sub_class: u8, 240 | interface_protocol: u8, 241 | ) -> Result<()> { 242 | self.interface_alt( 243 | number, 244 | device::DEFAULT_ALTERNATE_SETTING, 245 | interface_class, 246 | interface_sub_class, 247 | interface_protocol, 248 | None, 249 | ) 250 | } 251 | 252 | /// Writes a interface descriptor with a specific alternate setting and 253 | /// interface string identifier. 254 | /// 255 | /// # Arguments 256 | /// 257 | /// * `number` - Interface number previously allocated with 258 | /// [`UsbBusAllocator::interface`](crate::bus::UsbBusAllocator::interface). 259 | /// * `alternate_setting` - Number of the alternate setting 260 | /// * `interface_class` - Class code assigned by USB.org. Use `0xff` for vendor-specific devices 261 | /// that do not conform to any class. 262 | /// * `interface_sub_class` - Sub-class code. Depends on class. 263 | /// * `interface_protocol` - Protocol code. Depends on class and sub-class. 264 | /// * `interface_string` - Index of string descriptor describing this interface 265 | 266 | pub fn interface_alt( 267 | &mut self, 268 | number: InterfaceNumber, 269 | alternate_setting: u8, 270 | interface_class: u8, 271 | interface_sub_class: u8, 272 | interface_protocol: u8, 273 | interface_string: Option, 274 | ) -> Result<()> { 275 | if alternate_setting == device::DEFAULT_ALTERNATE_SETTING { 276 | match self.num_interfaces_mark { 277 | Some(mark) => self.buf[mark] += 1, 278 | None => return Err(UsbError::InvalidState), 279 | }; 280 | } 281 | 282 | let str_index = interface_string.map_or(0, Into::into); 283 | 284 | self.num_endpoints_mark = Some(self.position + 4); 285 | 286 | self.write( 287 | descriptor_type::INTERFACE, 288 | &[ 289 | number.into(), // bInterfaceNumber 290 | alternate_setting, // bAlternateSetting 291 | 0, // bNumEndpoints 292 | interface_class, // bInterfaceClass 293 | interface_sub_class, // bInterfaceSubClass 294 | interface_protocol, // bInterfaceProtocol 295 | str_index, // iInterface 296 | ], 297 | )?; 298 | 299 | Ok(()) 300 | } 301 | 302 | /// Writes an endpoint descriptor. 303 | /// 304 | /// # Arguments 305 | /// 306 | /// * `endpoint` - Endpoint previously allocated with 307 | /// [`UsbBusAllocator`](crate::bus::UsbBusAllocator). 308 | pub fn endpoint( 309 | &mut self, 310 | endpoint: &Endpoint<'_, B, D>, 311 | ) -> Result<()> { 312 | self.endpoint_ex(endpoint, |_| Ok(0)) 313 | } 314 | 315 | /// Writes an endpoint descriptor with extra trailing data. 316 | /// 317 | /// This is rarely needed and shouldn't be used except for compatibility with standard USB 318 | /// classes that require it. Extra data is normally written in a separate class specific 319 | /// descriptor. 320 | /// 321 | /// # Arguments 322 | /// 323 | /// * `endpoint` - Endpoint previously allocated with 324 | /// [`UsbBusAllocator`](crate::bus::UsbBusAllocator). 325 | /// * `f` - Callback for the extra data. See `write_with` for more information. 326 | pub fn endpoint_ex( 327 | &mut self, 328 | endpoint: &Endpoint<'_, B, D>, 329 | f: impl FnOnce(&mut [u8]) -> Result, 330 | ) -> Result<()> { 331 | match self.num_endpoints_mark { 332 | Some(mark) => self.buf[mark] += 1, 333 | None => return Err(UsbError::InvalidState), 334 | }; 335 | 336 | self.write_with(descriptor_type::ENDPOINT, |buf| { 337 | if buf.len() < 5 { 338 | return Err(UsbError::BufferOverflow); 339 | } 340 | 341 | let mps = endpoint.max_packet_size(); 342 | 343 | buf[0] = endpoint.address().into(); 344 | buf[1] = endpoint.ep_type().to_bm_attributes(); 345 | buf[2] = mps as u8; 346 | buf[3] = (mps >> 8) as u8; 347 | buf[4] = endpoint.interval(); 348 | 349 | Ok(f(&mut buf[5..])? + 5) 350 | }) 351 | } 352 | 353 | /// Writes a string descriptor. 354 | pub(crate) fn string(&mut self, string: &str) -> Result<()> { 355 | let mut pos = self.position; 356 | 357 | if pos + 2 > self.buf.len() { 358 | return Err(UsbError::BufferOverflow); 359 | } 360 | 361 | self.buf[pos] = 0; // length placeholder 362 | self.buf[pos + 1] = descriptor_type::STRING; 363 | 364 | pos += 2; 365 | 366 | for c in string.encode_utf16() { 367 | if pos >= self.buf.len() { 368 | return Err(UsbError::BufferOverflow); 369 | } 370 | 371 | self.buf[pos..pos + 2].copy_from_slice(&c.to_le_bytes()); 372 | pos += 2; 373 | } 374 | 375 | self.buf[self.position] = (pos - self.position) as u8; 376 | 377 | self.position = pos; 378 | 379 | Ok(()) 380 | } 381 | } 382 | 383 | /// A writer for Binary Object Store descriptor. 384 | pub struct BosWriter<'w, 'a: 'w> { 385 | writer: &'w mut DescriptorWriter<'a>, 386 | num_caps_mark: Option, 387 | } 388 | 389 | impl<'w, 'a: 'w> BosWriter<'w, 'a> { 390 | pub(crate) fn new(writer: &'w mut DescriptorWriter<'a>) -> Self { 391 | Self { 392 | writer, 393 | num_caps_mark: None, 394 | } 395 | } 396 | 397 | pub(crate) fn bos(&mut self) -> Result<()> { 398 | self.num_caps_mark = Some(self.writer.position + 4); 399 | self.writer.write( 400 | descriptor_type::BOS, 401 | &[ 402 | 0x00, 0x00, // wTotalLength 403 | 0x00, // bNumDeviceCaps 404 | ], 405 | )?; 406 | 407 | self.capability(capability_type::USB_2_0_EXTENSION, &[0; 4])?; 408 | 409 | Ok(()) 410 | } 411 | 412 | /// Writes capability descriptor to a BOS 413 | /// 414 | /// # Arguments 415 | /// 416 | /// * `capability_type` - Type of a capability 417 | /// * `data` - Binary data of the descriptor 418 | pub fn capability(&mut self, capability_type: u8, data: &[u8]) -> Result<()> { 419 | match self.num_caps_mark { 420 | Some(mark) => self.writer.buf[mark] += 1, 421 | None => return Err(UsbError::InvalidState), 422 | } 423 | 424 | let mut start = self.writer.position; 425 | let blen = data.len(); 426 | 427 | if (start + blen + 3) > self.writer.buf.len() || (blen + 3) > 255 { 428 | return Err(UsbError::BufferOverflow); 429 | } 430 | 431 | self.writer.buf[start] = (blen + 3) as u8; 432 | self.writer.buf[start + 1] = descriptor_type::CAPABILITY; 433 | self.writer.buf[start + 2] = capability_type; 434 | 435 | start += 3; 436 | self.writer.buf[start..start + blen].copy_from_slice(data); 437 | self.writer.position = start + blen; 438 | 439 | Ok(()) 440 | } 441 | 442 | pub(crate) fn end_bos(&mut self) { 443 | self.num_caps_mark = None; 444 | let position = self.writer.position as u16; 445 | self.writer.buf[2..4].copy_from_slice(&position.to_le_bytes()); 446 | } 447 | } 448 | -------------------------------------------------------------------------------- /src/descriptor/lang_id.rs: -------------------------------------------------------------------------------- 1 | #![allow(non_upper_case_globals, non_camel_case_types)] 2 | 3 | #[allow(missing_docs)] 4 | #[derive(Clone, Copy, PartialEq, Eq, Debug)] 5 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 6 | pub struct LangID(u16); 7 | 8 | impl From for u16 { 9 | fn from(lang_id: LangID) -> Self { 10 | let LangID(id) = lang_id; 11 | id 12 | } 13 | } 14 | 15 | impl From for LangID { 16 | fn from(id: u16) -> Self { 17 | LangID(id) 18 | } 19 | } 20 | 21 | #[allow(missing_docs)] 22 | impl LangID { 23 | pub const AR: LangID = LangID(0x0001); 24 | pub const BG: LangID = LangID(0x0002); 25 | pub const CA: LangID = LangID(0x0003); 26 | pub const ZH_HANS: LangID = LangID(0x0004); 27 | pub const CS: LangID = LangID(0x0005); 28 | pub const DA: LangID = LangID(0x0006); 29 | pub const DE: LangID = LangID(0x0007); 30 | pub const EL: LangID = LangID(0x0008); 31 | pub const EN: LangID = LangID(0x0009); 32 | pub const ES: LangID = LangID(0x000A); 33 | pub const FI: LangID = LangID(0x000B); 34 | pub const FR: LangID = LangID(0x000C); 35 | pub const HE: LangID = LangID(0x000D); 36 | pub const HU: LangID = LangID(0x000E); 37 | pub const IS: LangID = LangID(0x000F); 38 | pub const IT: LangID = LangID(0x0010); 39 | pub const JA: LangID = LangID(0x0011); 40 | pub const KO: LangID = LangID(0x0012); 41 | pub const NL: LangID = LangID(0x0013); 42 | pub const NO: LangID = LangID(0x0014); 43 | pub const PL: LangID = LangID(0x0015); 44 | pub const PT: LangID = LangID(0x0016); 45 | pub const RM: LangID = LangID(0x0017); 46 | pub const RO: LangID = LangID(0x0018); 47 | pub const RU: LangID = LangID(0x0019); 48 | pub const HR: LangID = LangID(0x001A); 49 | pub const SK: LangID = LangID(0x001B); 50 | pub const SQ: LangID = LangID(0x001C); 51 | pub const SV: LangID = LangID(0x001D); 52 | pub const TH: LangID = LangID(0x001E); 53 | pub const TR: LangID = LangID(0x001F); 54 | pub const UR: LangID = LangID(0x0020); 55 | pub const ID: LangID = LangID(0x0021); 56 | pub const UK: LangID = LangID(0x0022); 57 | pub const BE: LangID = LangID(0x0023); 58 | pub const SL: LangID = LangID(0x0024); 59 | pub const ET: LangID = LangID(0x0025); 60 | pub const LV: LangID = LangID(0x0026); 61 | pub const LT: LangID = LangID(0x0027); 62 | pub const TG: LangID = LangID(0x0028); 63 | pub const FA: LangID = LangID(0x0029); 64 | pub const VI: LangID = LangID(0x002A); 65 | pub const HY: LangID = LangID(0x002B); 66 | pub const AZ: LangID = LangID(0x002C); 67 | pub const EU: LangID = LangID(0x002D); 68 | pub const HSB: LangID = LangID(0x002E); 69 | pub const MK: LangID = LangID(0x002F); 70 | pub const ST: LangID = LangID(0x0030); 71 | pub const TS: LangID = LangID(0x0031); 72 | pub const TN: LangID = LangID(0x0032); 73 | pub const VE: LangID = LangID(0x0033); 74 | pub const XH: LangID = LangID(0x0034); 75 | pub const ZU: LangID = LangID(0x0035); 76 | pub const AF: LangID = LangID(0x0036); 77 | pub const KA: LangID = LangID(0x0037); 78 | pub const FO: LangID = LangID(0x0038); 79 | pub const HI: LangID = LangID(0x0039); 80 | pub const MT: LangID = LangID(0x003A); 81 | pub const SE: LangID = LangID(0x003B); 82 | pub const GA: LangID = LangID(0x003C); 83 | pub const YI: LangID = LangID(0x003D); 84 | pub const MS: LangID = LangID(0x003E); 85 | pub const KK: LangID = LangID(0x003F); 86 | pub const KY: LangID = LangID(0x0040); 87 | pub const SW: LangID = LangID(0x0041); 88 | pub const TK: LangID = LangID(0x0042); 89 | pub const UZ: LangID = LangID(0x0043); 90 | pub const TT: LangID = LangID(0x0044); 91 | pub const BN: LangID = LangID(0x0045); 92 | pub const PA: LangID = LangID(0x0046); 93 | pub const GU: LangID = LangID(0x0047); 94 | pub const OR: LangID = LangID(0x0048); 95 | pub const TA: LangID = LangID(0x0049); 96 | pub const TE: LangID = LangID(0x004A); 97 | pub const KN: LangID = LangID(0x004B); 98 | pub const ML: LangID = LangID(0x004C); 99 | pub const AS: LangID = LangID(0x004D); 100 | pub const MR: LangID = LangID(0x004E); 101 | pub const SA: LangID = LangID(0x004F); 102 | pub const MN: LangID = LangID(0x0050); 103 | pub const BO: LangID = LangID(0x0051); 104 | pub const CY: LangID = LangID(0x0052); 105 | pub const KM: LangID = LangID(0x0053); 106 | pub const LO: LangID = LangID(0x0054); 107 | pub const MY: LangID = LangID(0x0055); 108 | pub const GL: LangID = LangID(0x0056); 109 | pub const KOK: LangID = LangID(0x0057); 110 | pub const MNI: LangID = LangID(0x0058); 111 | pub const SD: LangID = LangID(0x0059); 112 | pub const SYR: LangID = LangID(0x005A); 113 | pub const SI: LangID = LangID(0x005B); 114 | pub const CHR: LangID = LangID(0x005C); 115 | pub const IU: LangID = LangID(0x005D); 116 | pub const AM: LangID = LangID(0x005E); 117 | pub const TZM: LangID = LangID(0x005F); 118 | pub const KS: LangID = LangID(0x0060); 119 | pub const NE: LangID = LangID(0x0061); 120 | pub const FY: LangID = LangID(0x0062); 121 | pub const PS: LangID = LangID(0x0063); 122 | pub const FIL: LangID = LangID(0x0064); 123 | pub const DV: LangID = LangID(0x0065); 124 | pub const BIN: LangID = LangID(0x0066); 125 | pub const FF: LangID = LangID(0x0067); 126 | pub const HA: LangID = LangID(0x0068); 127 | pub const IBB: LangID = LangID(0x0069); 128 | pub const YO: LangID = LangID(0x006A); 129 | pub const QUZ: LangID = LangID(0x006B); 130 | pub const NSO: LangID = LangID(0x006C); 131 | pub const BA: LangID = LangID(0x006D); 132 | pub const LB: LangID = LangID(0x006E); 133 | pub const KL: LangID = LangID(0x006F); 134 | pub const IG: LangID = LangID(0x0070); 135 | pub const KR: LangID = LangID(0x0071); 136 | pub const OM: LangID = LangID(0x0072); 137 | pub const TI: LangID = LangID(0x0073); 138 | pub const GN: LangID = LangID(0x0074); 139 | pub const HAW: LangID = LangID(0x0075); 140 | pub const LA: LangID = LangID(0x0076); 141 | pub const SO: LangID = LangID(0x0077); 142 | pub const II: LangID = LangID(0x0078); 143 | pub const PAP: LangID = LangID(0x0079); 144 | pub const ARN: LangID = LangID(0x007A); 145 | pub const MOH: LangID = LangID(0x007C); 146 | pub const BR: LangID = LangID(0x007E); 147 | pub const UG: LangID = LangID(0x0080); 148 | pub const MI: LangID = LangID(0x0081); 149 | pub const OC: LangID = LangID(0x0082); 150 | pub const CO: LangID = LangID(0x0083); 151 | pub const GSW: LangID = LangID(0x0084); 152 | pub const SAH: LangID = LangID(0x0085); 153 | pub const QUT: LangID = LangID(0x0086); 154 | pub const RW: LangID = LangID(0x0087); 155 | pub const WO: LangID = LangID(0x0088); 156 | pub const PRS: LangID = LangID(0x008C); 157 | pub const GD: LangID = LangID(0x0091); 158 | pub const KU: LangID = LangID(0x0092); 159 | pub const QUC: LangID = LangID(0x0093); 160 | pub const AR_SA: LangID = LangID(0x0401); 161 | pub const BG_BG: LangID = LangID(0x0402); 162 | pub const CA_ES: LangID = LangID(0x0403); 163 | pub const ZH_TW: LangID = LangID(0x0404); 164 | pub const CS_CZ: LangID = LangID(0x0405); 165 | pub const DA_DK: LangID = LangID(0x0406); 166 | pub const DE_DE: LangID = LangID(0x0407); 167 | pub const EL_GR: LangID = LangID(0x0408); 168 | pub const EN_US: LangID = LangID(0x0409); 169 | pub const ES_ES_TRADNL: LangID = LangID(0x040A); 170 | pub const FI_FI: LangID = LangID(0x040B); 171 | pub const FR_FR: LangID = LangID(0x040C); 172 | pub const HE_IL: LangID = LangID(0x040D); 173 | pub const HU_HU: LangID = LangID(0x040E); 174 | pub const IS_IS: LangID = LangID(0x040F); 175 | pub const IT_IT: LangID = LangID(0x0410); 176 | pub const JA_JP: LangID = LangID(0x0411); 177 | pub const KO_KR: LangID = LangID(0x0412); 178 | pub const NL_NL: LangID = LangID(0x0413); 179 | pub const NB_NO: LangID = LangID(0x0414); 180 | pub const PL_PL: LangID = LangID(0x0415); 181 | pub const PT_BR: LangID = LangID(0x0416); 182 | pub const RM_CH: LangID = LangID(0x0417); 183 | pub const RO_RO: LangID = LangID(0x0418); 184 | pub const RU_RU: LangID = LangID(0x0419); 185 | pub const HR_HR: LangID = LangID(0x041A); 186 | pub const SK_SK: LangID = LangID(0x041B); 187 | pub const SQ_AL: LangID = LangID(0x041C); 188 | pub const SV_SE: LangID = LangID(0x041D); 189 | pub const TH_TH: LangID = LangID(0x041E); 190 | pub const TR_TR: LangID = LangID(0x041F); 191 | pub const UR_PK: LangID = LangID(0x0420); 192 | pub const ID_ID: LangID = LangID(0x0421); 193 | pub const UK_UA: LangID = LangID(0x0422); 194 | pub const BE_BY: LangID = LangID(0x0423); 195 | pub const SL_SI: LangID = LangID(0x0424); 196 | pub const ET_EE: LangID = LangID(0x0425); 197 | pub const LV_LV: LangID = LangID(0x0426); 198 | pub const LT_LT: LangID = LangID(0x0427); 199 | pub const TG_CYRL_TJ: LangID = LangID(0x0428); 200 | pub const FA_IR: LangID = LangID(0x0429); 201 | pub const VI_VN: LangID = LangID(0x042A); 202 | pub const HY_AM: LangID = LangID(0x042B); 203 | pub const AZ_LATN_AZ: LangID = LangID(0x042C); 204 | pub const EU_ES: LangID = LangID(0x042D); 205 | pub const HSB_DE: LangID = LangID(0x042E); 206 | pub const MK_MK: LangID = LangID(0x042F); 207 | pub const ST_ZA: LangID = LangID(0x0430); 208 | pub const TS_ZA: LangID = LangID(0x0431); 209 | pub const TN_ZA: LangID = LangID(0x0432); 210 | pub const VE_ZA: LangID = LangID(0x0433); 211 | pub const XH_ZA: LangID = LangID(0x0434); 212 | pub const ZU_ZA: LangID = LangID(0x0435); 213 | pub const AF_ZA: LangID = LangID(0x0436); 214 | pub const KA_GE: LangID = LangID(0x0437); 215 | pub const FO_FO: LangID = LangID(0x0438); 216 | pub const HI_IN: LangID = LangID(0x0439); 217 | pub const MT_MT: LangID = LangID(0x043A); 218 | pub const SE_NO: LangID = LangID(0x043B); 219 | pub const YI_001: LangID = LangID(0x043D); 220 | pub const MS_MY: LangID = LangID(0x043E); 221 | pub const KK_KZ: LangID = LangID(0x043F); 222 | pub const KY_KG: LangID = LangID(0x0440); 223 | pub const SW_KE: LangID = LangID(0x0441); 224 | pub const TK_TM: LangID = LangID(0x0442); 225 | pub const UZ_LATN_UZ: LangID = LangID(0x0443); 226 | pub const TT_RU: LangID = LangID(0x0444); 227 | pub const BN_IN: LangID = LangID(0x0445); 228 | pub const PA_IN: LangID = LangID(0x0446); 229 | pub const GU_IN: LangID = LangID(0x0447); 230 | pub const OR_IN: LangID = LangID(0x0448); 231 | pub const TA_IN: LangID = LangID(0x0449); 232 | pub const TE_IN: LangID = LangID(0x044A); 233 | pub const KN_IN: LangID = LangID(0x044B); 234 | pub const ML_IN: LangID = LangID(0x044C); 235 | pub const AS_IN: LangID = LangID(0x044D); 236 | pub const MR_IN: LangID = LangID(0x044E); 237 | pub const SA_IN: LangID = LangID(0x044F); 238 | pub const MN_MN: LangID = LangID(0x0450); 239 | pub const BO_CN: LangID = LangID(0x0451); 240 | pub const CY_GB: LangID = LangID(0x0452); 241 | pub const KM_KH: LangID = LangID(0x0453); 242 | pub const LO_LA: LangID = LangID(0x0454); 243 | pub const MY_MM: LangID = LangID(0x0455); 244 | pub const GL_ES: LangID = LangID(0x0456); 245 | pub const KOK_IN: LangID = LangID(0x0457); 246 | pub const MNI_IN: LangID = LangID(0x0458); 247 | pub const SD_DEVA_IN: LangID = LangID(0x0459); 248 | pub const SYR_SY: LangID = LangID(0x045A); 249 | pub const SI_LK: LangID = LangID(0x045B); 250 | pub const CHR_CHER_US: LangID = LangID(0x045C); 251 | pub const IU_CANS_CA: LangID = LangID(0x045D); 252 | pub const AM_ET: LangID = LangID(0x045E); 253 | pub const TZM_ARAB_MA: LangID = LangID(0x045F); 254 | pub const KS_ARAB: LangID = LangID(0x0460); 255 | pub const NE_NP: LangID = LangID(0x0461); 256 | pub const FY_NL: LangID = LangID(0x0462); 257 | pub const PS_AF: LangID = LangID(0x0463); 258 | pub const FIL_PH: LangID = LangID(0x0464); 259 | pub const DV_MV: LangID = LangID(0x0465); 260 | pub const BIN_NG: LangID = LangID(0x0466); 261 | pub const FF_NG__FF_LATN_NG: LangID = LangID(0x0467); 262 | pub const HA_LATN_NG: LangID = LangID(0x0468); 263 | pub const IBB_NG: LangID = LangID(0x0469); 264 | pub const YO_NG: LangID = LangID(0x046A); 265 | pub const QUZ_BO: LangID = LangID(0x046B); 266 | pub const NSO_ZA: LangID = LangID(0x046C); 267 | pub const BA_RU: LangID = LangID(0x046D); 268 | pub const LB_LU: LangID = LangID(0x046E); 269 | pub const KL_GL: LangID = LangID(0x046F); 270 | pub const IG_NG: LangID = LangID(0x0470); 271 | pub const KR_LATN_NG: LangID = LangID(0x0471); 272 | pub const OM_ET: LangID = LangID(0x0472); 273 | pub const TI_ET: LangID = LangID(0x0473); 274 | pub const GN_PY: LangID = LangID(0x0474); 275 | pub const HAW_US: LangID = LangID(0x0475); 276 | pub const LA_VA: LangID = LangID(0x0476); 277 | pub const SO_SO: LangID = LangID(0x0477); 278 | pub const II_CN: LangID = LangID(0x0478); 279 | pub const PAP_029: LangID = LangID(0x0479); 280 | pub const ARN_CL: LangID = LangID(0x047A); 281 | pub const MOH_CA: LangID = LangID(0x047C); 282 | pub const BR_FR: LangID = LangID(0x047E); 283 | pub const UG_CN: LangID = LangID(0x0480); 284 | pub const MI_NZ: LangID = LangID(0x0481); 285 | pub const OC_FR: LangID = LangID(0x0482); 286 | pub const CO_FR: LangID = LangID(0x0483); 287 | pub const GSW_FR: LangID = LangID(0x0484); 288 | pub const SAH_RU: LangID = LangID(0x0485); 289 | pub const QUT_GT: LangID = LangID(0x0486); 290 | pub const RW_RW: LangID = LangID(0x0487); 291 | pub const WO_SN: LangID = LangID(0x0488); 292 | pub const PRS_AF: LangID = LangID(0x048C); 293 | pub const PLT_MG: LangID = LangID(0x048D); 294 | pub const ZH_YUE_HK: LangID = LangID(0x048E); 295 | pub const TDD_TALE_CN: LangID = LangID(0x048F); 296 | pub const KHB_TALU_CN: LangID = LangID(0x0490); 297 | pub const GD_GB: LangID = LangID(0x0491); 298 | pub const KU_ARAB_IQ: LangID = LangID(0x0492); 299 | pub const QUC_CO: LangID = LangID(0x0493); 300 | pub const QPS_PLOC: LangID = LangID(0x0501); 301 | pub const QPS_PLOCA: LangID = LangID(0x05FE); 302 | pub const AR_IQ: LangID = LangID(0x0801); 303 | pub const CA_ES_VALENCIA: LangID = LangID(0x0803); 304 | pub const ZH_CN: LangID = LangID(0x0804); 305 | pub const DE_CH: LangID = LangID(0x0807); 306 | pub const EN_GB: LangID = LangID(0x0809); 307 | pub const ES_MX: LangID = LangID(0x080A); 308 | pub const FR_BE: LangID = LangID(0x080C); 309 | pub const IT_CH: LangID = LangID(0x0810); 310 | pub const JA_PLOC_JP: LangID = LangID(0x0811); 311 | pub const NL_BE: LangID = LangID(0x0813); 312 | pub const NN_NO: LangID = LangID(0x0814); 313 | pub const PT_PT: LangID = LangID(0x0816); 314 | pub const RO_MD: LangID = LangID(0x0818); 315 | pub const RU_MD: LangID = LangID(0x0819); 316 | pub const SR_LATN_CS: LangID = LangID(0x081A); 317 | pub const SV_FI: LangID = LangID(0x081D); 318 | pub const UR_IN: LangID = LangID(0x0820); 319 | pub const AZ_CYRL_AZ: LangID = LangID(0x082C); 320 | pub const DSB_DE: LangID = LangID(0x082E); 321 | pub const TN_BW: LangID = LangID(0x0832); 322 | pub const SE_SE: LangID = LangID(0x083B); 323 | pub const GA_IE: LangID = LangID(0x083C); 324 | pub const MS_BN: LangID = LangID(0x083E); 325 | pub const KK_LATN_KZ: LangID = LangID(0x083F); 326 | pub const UZ_CYRL_UZ: LangID = LangID(0x0843); 327 | pub const BN_BD: LangID = LangID(0x0845); 328 | pub const PA_ARAB_PK: LangID = LangID(0x0846); 329 | pub const TA_LK: LangID = LangID(0x0849); 330 | pub const MN_MONG_CN: LangID = LangID(0x0850); 331 | pub const BO_BT: LangID = LangID(0x0851); 332 | pub const SD_ARAB_PK: LangID = LangID(0x0859); 333 | pub const IU_LATN_CA: LangID = LangID(0x085D); 334 | pub const TZM_LATN_DZ: LangID = LangID(0x085F); 335 | pub const KS_DEVA_IN: LangID = LangID(0x0860); 336 | pub const NE_IN: LangID = LangID(0x0861); 337 | pub const FF_LATN_SN: LangID = LangID(0x0867); 338 | pub const QUZ_EC: LangID = LangID(0x086B); 339 | pub const TI_ER: LangID = LangID(0x0873); 340 | pub const QPS_PLOCM: LangID = LangID(0x09FF); 341 | pub const LOCALE_CUSTOM_USER_DEFAULT: LangID = LangID(0x0C00); 342 | pub const AR_EG: LangID = LangID(0x0C01); 343 | pub const ZH_HK: LangID = LangID(0x0C04); 344 | pub const DE_AT: LangID = LangID(0x0C07); 345 | pub const EN_AU: LangID = LangID(0x0C09); 346 | pub const ES_ES: LangID = LangID(0x0C0A); 347 | pub const FR_CA: LangID = LangID(0x0C0C); 348 | pub const SR_CYRL_CS: LangID = LangID(0x0C1A); 349 | pub const SE_FI: LangID = LangID(0x0C3B); 350 | pub const MN_MONG_MN: LangID = LangID(0x0C50); 351 | pub const DZ_BT: LangID = LangID(0x0C51); 352 | pub const TMZ_MA: LangID = LangID(0x0C5F); 353 | pub const QUZ_PE: LangID = LangID(0x0C6B); 354 | pub const LOCALE_CUSTOM_UNSPECIFIED: LangID = LangID(0x1000); 355 | pub const AR_LY: LangID = LangID(0x1001); 356 | pub const ZH_SG: LangID = LangID(0x1004); 357 | pub const DE_LU: LangID = LangID(0x1007); 358 | pub const EN_CA: LangID = LangID(0x1009); 359 | pub const ES_GT: LangID = LangID(0x100A); 360 | pub const FR_CH: LangID = LangID(0x100C); 361 | pub const HR_BA: LangID = LangID(0x101A); 362 | pub const SMJ_NO: LangID = LangID(0x103B); 363 | pub const TZM_TFNG_MA: LangID = LangID(0x105F); 364 | pub const AR_DZ: LangID = LangID(0x1401); 365 | pub const ZH_MO: LangID = LangID(0x1404); 366 | pub const DE_LI: LangID = LangID(0x1407); 367 | pub const EN_NZ: LangID = LangID(0x1409); 368 | pub const ES_CR: LangID = LangID(0x140A); 369 | pub const FR_LU: LangID = LangID(0x140C); 370 | pub const BS_LATN_BA: LangID = LangID(0x141A); 371 | pub const SMJ_SE: LangID = LangID(0x143B); 372 | pub const AR_MA: LangID = LangID(0x1801); 373 | pub const EN_IE: LangID = LangID(0x1809); 374 | pub const ES_PA: LangID = LangID(0x180A); 375 | pub const FR_MC: LangID = LangID(0x180C); 376 | pub const SR_LATN_BA: LangID = LangID(0x181A); 377 | pub const SMA_NO: LangID = LangID(0x183B); 378 | pub const AR_TN: LangID = LangID(0x1C01); 379 | pub const EN_ZA: LangID = LangID(0x1C09); 380 | pub const ES_DO: LangID = LangID(0x1C0A); 381 | pub const FR_029: LangID = LangID(0x1C0C); 382 | pub const SR_CYRL_BA: LangID = LangID(0x1C1A); 383 | pub const SMA_SE: LangID = LangID(0x1C3B); 384 | pub const AR_OM: LangID = LangID(0x2001); 385 | pub const EN_JM: LangID = LangID(0x2009); 386 | pub const ES_VE: LangID = LangID(0x200A); 387 | pub const FR_RE: LangID = LangID(0x200C); 388 | pub const BS_CYRL_BA: LangID = LangID(0x201A); 389 | pub const SMS_FI: LangID = LangID(0x203B); 390 | pub const AR_YE: LangID = LangID(0x2401); 391 | pub const EN_029: LangID = LangID(0x2409); 392 | pub const ES_CO: LangID = LangID(0x240A); 393 | pub const FR_CD: LangID = LangID(0x240C); 394 | pub const SR_LATN_RS: LangID = LangID(0x241A); 395 | pub const SMN_FI: LangID = LangID(0x243B); 396 | pub const AR_SY: LangID = LangID(0x2801); 397 | pub const EN_BZ: LangID = LangID(0x2809); 398 | pub const ES_PE: LangID = LangID(0x280A); 399 | pub const FR_SN: LangID = LangID(0x280C); 400 | pub const SR_CYRL_RS: LangID = LangID(0x281A); 401 | pub const AR_JO: LangID = LangID(0x2C01); 402 | pub const EN_TT: LangID = LangID(0x2C09); 403 | pub const ES_AR: LangID = LangID(0x2C0A); 404 | pub const FR_CM: LangID = LangID(0x2C0C); 405 | pub const SR_LATN_ME: LangID = LangID(0x2C1A); 406 | pub const AR_LB: LangID = LangID(0x3001); 407 | pub const EN_ZW: LangID = LangID(0x3009); 408 | pub const ES_EC: LangID = LangID(0x300A); 409 | pub const FR_CI: LangID = LangID(0x300C); 410 | pub const SR_CYRL_ME: LangID = LangID(0x301A); 411 | pub const AR_KW: LangID = LangID(0x3401); 412 | pub const EN_PH: LangID = LangID(0x3409); 413 | pub const ES_CL: LangID = LangID(0x340A); 414 | pub const FR_ML: LangID = LangID(0x340C); 415 | pub const AR_AE: LangID = LangID(0x3801); 416 | pub const EN_ID: LangID = LangID(0x3809); 417 | pub const ES_UY: LangID = LangID(0x380A); 418 | pub const FR_MA: LangID = LangID(0x380C); 419 | pub const AR_BH: LangID = LangID(0x3C01); 420 | pub const EN_HK: LangID = LangID(0x3C09); 421 | pub const ES_PY: LangID = LangID(0x3C0A); 422 | pub const FR_HT: LangID = LangID(0x3C0C); 423 | pub const AR_QA: LangID = LangID(0x4001); 424 | pub const EN_IN: LangID = LangID(0x4009); 425 | pub const ES_BO: LangID = LangID(0x400A); 426 | pub const AR_PLOC_SA: LangID = LangID(0x4401); 427 | pub const EN_MY: LangID = LangID(0x4409); 428 | pub const ES_SV: LangID = LangID(0x440A); 429 | pub const AR_145: LangID = LangID(0x4801); 430 | pub const EN_SG: LangID = LangID(0x4809); 431 | pub const ES_HN: LangID = LangID(0x480A); 432 | pub const EN_AE: LangID = LangID(0x4C09); 433 | pub const ES_NI: LangID = LangID(0x4C0A); 434 | pub const EN_BH: LangID = LangID(0x5009); 435 | pub const ES_PR: LangID = LangID(0x500A); 436 | pub const EN_EG: LangID = LangID(0x5409); 437 | pub const ES_US: LangID = LangID(0x540A); 438 | pub const EN_JO: LangID = LangID(0x5809); 439 | pub const ES_419: LangID = LangID(0x580A); 440 | pub const EN_KW: LangID = LangID(0x5C09); 441 | pub const ES_CU: LangID = LangID(0x5C0A); 442 | pub const EN_TR: LangID = LangID(0x6009); 443 | pub const EN_YE: LangID = LangID(0x6409); 444 | pub const BS_CYRL: LangID = LangID(0x641A); 445 | pub const BS_LATN: LangID = LangID(0x681A); 446 | pub const SR_CYRL: LangID = LangID(0x6C1A); 447 | pub const SR_LATN: LangID = LangID(0x701A); 448 | pub const SMN: LangID = LangID(0x703B); 449 | pub const AZ_CYRL: LangID = LangID(0x742C); 450 | pub const SMS: LangID = LangID(0x743B); 451 | pub const ZH: LangID = LangID(0x7804); 452 | pub const NN: LangID = LangID(0x7814); 453 | pub const BS: LangID = LangID(0x781A); 454 | pub const AZ_LATN: LangID = LangID(0x782C); 455 | pub const SMA: LangID = LangID(0x783B); 456 | pub const KK_CYRL: LangID = LangID(0x783F); 457 | pub const UZ_CYRL: LangID = LangID(0x7843); 458 | pub const MN_CYRL: LangID = LangID(0x7850); 459 | pub const IU_CANS: LangID = LangID(0x785D); 460 | pub const TZM_TFNG: LangID = LangID(0x785F); 461 | pub const ZH_HANT: LangID = LangID(0x7C04); 462 | pub const NB: LangID = LangID(0x7C14); 463 | pub const SR: LangID = LangID(0x7C1A); 464 | pub const TG_CYRL: LangID = LangID(0x7C28); 465 | pub const DSB: LangID = LangID(0x7C2E); 466 | pub const SMJ: LangID = LangID(0x7C3B); 467 | pub const KK_LATN: LangID = LangID(0x7C3F); 468 | pub const UZ_LATN: LangID = LangID(0x7C43); 469 | pub const PA_ARAB: LangID = LangID(0x7C46); 470 | pub const MN_MONG: LangID = LangID(0x7C50); 471 | pub const SD_ARAB: LangID = LangID(0x7C59); 472 | pub const CHR_CHER: LangID = LangID(0x7C5C); 473 | pub const IU_LATN: LangID = LangID(0x7C5D); 474 | pub const TZM_LATN: LangID = LangID(0x7C5F); 475 | pub const FF_LATN: LangID = LangID(0x7C67); 476 | pub const HA_LATN: LangID = LangID(0x7C68); 477 | pub const KU_ARAB: LangID = LangID(0x7C92); 478 | pub const FR_015: LangID = LangID(0xE40C); 479 | } 480 | -------------------------------------------------------------------------------- /src/device.rs: -------------------------------------------------------------------------------- 1 | use crate::bus::{InterfaceNumber, PollResult, StringIndex, UsbBus, UsbBusAllocator}; 2 | use crate::class::{ControlIn, ControlOut, UsbClass}; 3 | use crate::control; 4 | use crate::control_pipe::ControlPipe; 5 | use crate::descriptor::{descriptor_type, lang_id::LangID, BosWriter, DescriptorWriter}; 6 | pub use crate::device_builder::{StringDescriptors, UsbDeviceBuilder, UsbVidPid}; 7 | use crate::endpoint::{EndpointAddress, EndpointType}; 8 | use crate::{Result, UsbDirection}; 9 | 10 | /// The global state of the USB device. 11 | /// 12 | /// In general class traffic is only possible in the `Configured` state. 13 | #[repr(u8)] 14 | #[derive(PartialEq, Eq, Copy, Clone, Debug)] 15 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] 16 | pub enum UsbDeviceState { 17 | /// The USB device has just been created or reset. 18 | Default, 19 | 20 | /// The USB device has received an address from the host. 21 | Addressed, 22 | 23 | /// The USB device has been configured and is fully functional. 24 | Configured, 25 | 26 | /// The USB device has been suspended by the host or it has been unplugged from the USB bus. 27 | Suspend, 28 | } 29 | 30 | // Maximum number of endpoints in one direction. Specified by the USB specification. 31 | const MAX_ENDPOINTS: usize = 16; 32 | 33 | /// Usb spec revision. 34 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] 35 | #[repr(u16)] 36 | pub enum UsbRev { 37 | /// USB 1.0 compliance 38 | Usb100 = 0x100, 39 | /// USB 1.1 compliance 40 | Usb110 = 0x110, 41 | /// USB 2.0 compliance 42 | Usb200 = 0x200, 43 | /// USB 2.1 compliance. 44 | /// 45 | /// Typically adds support for BOS requests. 46 | Usb210 = 0x210, 47 | } 48 | 49 | /// A USB device consisting of one or more device classes. 50 | pub struct UsbDevice<'a, B: UsbBus> { 51 | bus: &'a B, 52 | config: Config<'a>, 53 | control: ControlPipe<'a, B>, 54 | device_state: UsbDeviceState, 55 | remote_wakeup_enabled: bool, 56 | self_powered: bool, 57 | suspended_device_state: Option, 58 | pending_address: u8, 59 | } 60 | 61 | pub(crate) struct Config<'a> { 62 | pub device_class: u8, 63 | pub device_sub_class: u8, 64 | pub device_protocol: u8, 65 | pub max_packet_size_0: u8, 66 | pub vendor_id: u16, 67 | pub product_id: u16, 68 | pub usb_rev: UsbRev, 69 | pub device_release: u16, 70 | pub string_descriptors: heapless::Vec, 16>, 71 | pub self_powered: bool, 72 | pub supports_remote_wakeup: bool, 73 | pub composite_with_iads: bool, 74 | pub max_power: u8, 75 | } 76 | 77 | /// The bConfiguration value for the not configured state. 78 | pub const CONFIGURATION_NONE: u8 = 0; 79 | 80 | /// The bConfiguration value for the single configuration supported by this device. 81 | pub const CONFIGURATION_VALUE: u8 = 1; 82 | 83 | /// The default value for bAlternateSetting for all interfaces. 84 | pub const DEFAULT_ALTERNATE_SETTING: u8 = 0; 85 | 86 | type ClassList<'a, B> = [&'a mut dyn UsbClass]; 87 | 88 | impl UsbDevice<'_, B> { 89 | pub(crate) fn build<'a>( 90 | alloc: &'a UsbBusAllocator, 91 | config: Config<'a>, 92 | control_buffer: &'a mut [u8], 93 | ) -> UsbDevice<'a, B> { 94 | let control_out = alloc 95 | .alloc( 96 | Some(0x00.into()), 97 | EndpointType::Control, 98 | config.max_packet_size_0 as u16, 99 | 0, 100 | ) 101 | .expect("failed to alloc control endpoint"); 102 | 103 | let control_in = alloc 104 | .alloc( 105 | Some(0x80.into()), 106 | EndpointType::Control, 107 | config.max_packet_size_0 as u16, 108 | 0, 109 | ) 110 | .expect("failed to alloc control endpoint"); 111 | 112 | let bus = alloc.freeze(); 113 | 114 | UsbDevice { 115 | bus, 116 | config, 117 | control: ControlPipe::new(control_buffer, control_out, control_in), 118 | device_state: UsbDeviceState::Default, 119 | remote_wakeup_enabled: false, 120 | self_powered: false, 121 | suspended_device_state: None, 122 | pending_address: 0, 123 | } 124 | } 125 | 126 | /// Gets a reference to the [`UsbBus`] implementation used by this `UsbDevice`. You can use this 127 | /// to call platform-specific methods on the `UsbBus`. 128 | /// 129 | /// While it is also possible to call the standard `UsbBus` trait methods through this 130 | /// reference, this is not recommended as it can cause the device to misbehave. 131 | pub fn bus(&self) -> &B { 132 | self.bus 133 | } 134 | 135 | /// Gets the current state of the device. 136 | /// 137 | /// In general class traffic is only possible in the `Configured` state. 138 | pub fn state(&self) -> UsbDeviceState { 139 | self.device_state 140 | } 141 | 142 | /// Gets whether host remote wakeup has been enabled by the host. 143 | pub fn remote_wakeup_enabled(&self) -> bool { 144 | self.remote_wakeup_enabled 145 | } 146 | 147 | /// Gets whether the device is currently self powered. 148 | pub fn self_powered(&self) -> bool { 149 | self.self_powered 150 | } 151 | 152 | /// Sets whether the device is currently self powered. 153 | pub fn set_self_powered(&mut self, is_self_powered: bool) { 154 | self.self_powered = is_self_powered; 155 | } 156 | 157 | /// Simulates a disconnect from the USB bus, causing the host to reset and re-enumerate the 158 | /// device. 159 | /// 160 | /// Mostly useful for development. Calling this at the start of your program ensures that the 161 | /// host re-enumerates your device after a new program has been flashed. 162 | pub fn force_reset(&mut self) -> Result<()> { 163 | self.bus.force_reset() 164 | } 165 | 166 | /// Polls the [`UsbBus`] for new events and dispatches them to the provided classes. Returns 167 | /// true if one of the classes may have data available for reading or be ready for writing, 168 | /// false otherwise. This should be called periodically as often as possible for the best data 169 | /// rate, or preferably from an interrupt handler. Must be called at least once every 10 170 | /// milliseconds while connected to the USB host to be USB compliant. 171 | /// 172 | /// Note: The list of classes passed in must be the same classes in the same order for every 173 | /// call while the device is configured, or the device may enumerate incorrectly or otherwise 174 | /// misbehave. The easiest way to do this is to call the `poll` method in only one place in your 175 | /// code, as follows: 176 | /// 177 | /// ``` ignore 178 | /// usb_dev.poll(&mut [&mut class1, &mut class2]); 179 | /// ``` 180 | /// 181 | /// Strictly speaking the list of classes is allowed to change between polls if the device has 182 | /// been reset, which is indicated by `state` being equal to [`UsbDeviceState::Default`]. 183 | pub fn poll(&mut self, classes: &mut ClassList<'_, B>) -> bool { 184 | let pr = self.bus.poll(); 185 | 186 | if self.device_state == UsbDeviceState::Suspend { 187 | match pr { 188 | PollResult::Suspend | PollResult::None => { 189 | return false; 190 | } 191 | _ => { 192 | self.bus.resume(); 193 | 194 | self.device_state = self 195 | .suspended_device_state 196 | .expect("Unknown state before suspend"); 197 | self.suspended_device_state = None; 198 | } 199 | } 200 | } 201 | 202 | match pr { 203 | PollResult::None => {} 204 | PollResult::Reset => self.reset(classes), 205 | PollResult::Data { 206 | ep_out, 207 | ep_in_complete, 208 | ep_setup, 209 | } => { 210 | // Combine bit fields for quick tests 211 | let mut eps = ep_out | ep_in_complete | ep_setup; 212 | 213 | // Pending events for endpoint 0? 214 | if (eps & 1) != 0 { 215 | usb_debug!( 216 | "EP0: setup={}, in_complete={}, out={}", 217 | ep_setup & 1, 218 | ep_in_complete & 1, 219 | ep_out & 1 220 | ); 221 | 222 | let req = if (ep_setup & 1) != 0 { 223 | self.control.handle_setup() 224 | } else if (ep_out & 1) != 0 { 225 | match self.control.handle_out() { 226 | Ok(req) => req, 227 | Err(_err) => { 228 | // TODO: Propagate error out of `poll()` 229 | usb_debug!("Failed to handle EP0: {:?}", _err); 230 | None 231 | } 232 | } 233 | } else { 234 | None 235 | }; 236 | 237 | match req { 238 | Some(req) if req.direction == UsbDirection::In => { 239 | if let Err(_err) = self.control_in(classes, req) { 240 | // TODO: Propagate error out of `poll()` 241 | usb_debug!("Failed to handle input control request: {:?}", _err); 242 | } 243 | } 244 | Some(req) if req.direction == UsbDirection::Out => { 245 | if let Err(_err) = self.control_out(classes, req) { 246 | // TODO: Propagate error out of `poll()` 247 | usb_debug!("Failed to handle output control request: {:?}", _err); 248 | } 249 | } 250 | 251 | None if ((ep_in_complete & 1) != 0) => { 252 | // We only handle EP0-IN completion if there's no other request being 253 | // processed. EP0-IN tokens may be issued due to completed STATUS 254 | // phases of the control transfer. If we just got a SETUP packet or 255 | // an OUT token, we can safely ignore the IN-COMPLETE indication and 256 | // continue with the next transfer. 257 | let completed = match self.control.handle_in_complete() { 258 | Ok(completed) => completed, 259 | Err(_err) => { 260 | // TODO: Propagate this out of `poll()` 261 | usb_debug!( 262 | "Failed to process control-input complete: {:?}", 263 | _err 264 | ); 265 | false 266 | } 267 | }; 268 | 269 | if !B::QUIRK_SET_ADDRESS_BEFORE_STATUS 270 | && completed 271 | && self.pending_address != 0 272 | { 273 | self.bus.set_device_address(self.pending_address); 274 | self.pending_address = 0; 275 | 276 | self.device_state = UsbDeviceState::Addressed; 277 | } 278 | } 279 | 280 | _ => (), 281 | }; 282 | 283 | eps &= !1; 284 | } 285 | 286 | // Pending events for other endpoints? 287 | if eps != 0 { 288 | let mut bit = 2u16; 289 | 290 | for i in 1..MAX_ENDPOINTS { 291 | if (ep_setup & bit) != 0 { 292 | for cls in classes.iter_mut() { 293 | usb_trace!("Handling EP{}-SETUP", i); 294 | cls.endpoint_setup(EndpointAddress::from_parts( 295 | i, 296 | UsbDirection::Out, 297 | )); 298 | } 299 | } else if (ep_out & bit) != 0 { 300 | usb_trace!("Handling EP{}-OUT", i); 301 | for cls in classes.iter_mut() { 302 | cls.endpoint_out(EndpointAddress::from_parts(i, UsbDirection::Out)); 303 | } 304 | } 305 | 306 | if (ep_in_complete & bit) != 0 { 307 | usb_trace!("Handling EP{}-IN", i); 308 | for cls in classes.iter_mut() { 309 | cls.endpoint_in_complete(EndpointAddress::from_parts( 310 | i, 311 | UsbDirection::In, 312 | )); 313 | } 314 | } 315 | 316 | eps &= !bit; 317 | 318 | if eps == 0 { 319 | // No more pending events for higher endpoints 320 | break; 321 | } 322 | 323 | bit <<= 1; 324 | } 325 | } 326 | 327 | for cls in classes.iter_mut() { 328 | cls.poll(); 329 | } 330 | 331 | return true; 332 | } 333 | PollResult::Resume => {} 334 | PollResult::Suspend => { 335 | usb_debug!("Suspending bus"); 336 | self.bus.suspend(); 337 | self.suspended_device_state = Some(self.device_state); 338 | self.device_state = UsbDeviceState::Suspend; 339 | } 340 | } 341 | 342 | false 343 | } 344 | 345 | fn control_in(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) -> Result<()> { 346 | use crate::control::{Recipient, Request}; 347 | 348 | for cls in classes.iter_mut() { 349 | cls.control_in(ControlIn::new(&mut self.control, &req)); 350 | 351 | if !self.control.waiting_for_response() { 352 | return Ok(()); 353 | } 354 | } 355 | 356 | if req.request_type == control::RequestType::Standard { 357 | let xfer = ControlIn::new(&mut self.control, &req); 358 | 359 | match (req.recipient, req.request) { 360 | (Recipient::Device, Request::GET_STATUS) => { 361 | usb_trace!("Processing Device::GetStatus"); 362 | let status: u16 = if self.self_powered { 0x0001 } else { 0x0000 } 363 | | if self.remote_wakeup_enabled { 364 | 0x0002 365 | } else { 366 | 0x0000 367 | }; 368 | 369 | xfer.accept_with(&status.to_le_bytes())?; 370 | } 371 | 372 | (Recipient::Interface, Request::GET_STATUS) => { 373 | usb_trace!("Processing Interface::GetStatus"); 374 | let status: u16 = 0x0000; 375 | 376 | xfer.accept_with(&status.to_le_bytes())?; 377 | } 378 | 379 | (Recipient::Endpoint, Request::GET_STATUS) => { 380 | usb_trace!("Processing EP::GetStatus"); 381 | let ep_addr = ((req.index as u8) & 0x8f).into(); 382 | 383 | let status: u16 = if self.bus.is_stalled(ep_addr) { 384 | 0x0001 385 | } else { 386 | 0x0000 387 | }; 388 | 389 | xfer.accept_with(&status.to_le_bytes())?; 390 | } 391 | 392 | (Recipient::Device, Request::GET_DESCRIPTOR) => { 393 | usb_trace!("Processing Device::GetDescriptor"); 394 | UsbDevice::get_descriptor(&self.config, classes, xfer)?; 395 | } 396 | 397 | (Recipient::Device, Request::GET_CONFIGURATION) => { 398 | usb_trace!("Processing Device::GetConfiguration"); 399 | let config = match self.device_state { 400 | UsbDeviceState::Configured => CONFIGURATION_VALUE, 401 | _ => CONFIGURATION_NONE, 402 | }; 403 | 404 | xfer.accept_with(&config.to_le_bytes())?; 405 | } 406 | 407 | (Recipient::Interface, Request::GET_INTERFACE) => { 408 | usb_trace!("Processing Interface::GetInterface"); 409 | // Reject interface numbers bigger than 255 410 | if req.index > core::u8::MAX.into() { 411 | return xfer.reject(); 412 | } 413 | 414 | // Ask class implementations, whether they know the alternate setting 415 | // of the interface in question 416 | for cls in classes { 417 | if let Some(setting) = cls.get_alt_setting(InterfaceNumber(req.index as u8)) 418 | { 419 | return xfer.accept_with(&setting.to_le_bytes()); 420 | } 421 | } 422 | 423 | // If no class returned an alternate setting, return the default value 424 | xfer.accept_with(&DEFAULT_ALTERNATE_SETTING.to_le_bytes())?; 425 | } 426 | 427 | _ => {} 428 | }; 429 | } 430 | 431 | if self.control.waiting_for_response() { 432 | usb_debug!("Rejecting control transfer because we were waiting for a response"); 433 | self.control.reject()?; 434 | } 435 | 436 | Ok(()) 437 | } 438 | 439 | fn control_out(&mut self, classes: &mut ClassList<'_, B>, req: control::Request) -> Result<()> { 440 | use crate::control::{Recipient, Request}; 441 | 442 | for cls in classes.iter_mut() { 443 | cls.control_out(ControlOut::new(&mut self.control, &req)); 444 | 445 | if !self.control.waiting_for_response() { 446 | return Ok(()); 447 | } 448 | } 449 | 450 | if req.request_type == control::RequestType::Standard { 451 | let xfer = ControlOut::new(&mut self.control, &req); 452 | 453 | const CONFIGURATION_NONE_U16: u16 = CONFIGURATION_NONE as u16; 454 | const CONFIGURATION_VALUE_U16: u16 = CONFIGURATION_VALUE as u16; 455 | const DEFAULT_ALTERNATE_SETTING_U16: u16 = DEFAULT_ALTERNATE_SETTING as u16; 456 | 457 | match (req.recipient, req.request, req.value) { 458 | ( 459 | Recipient::Device, 460 | Request::CLEAR_FEATURE, 461 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, 462 | ) => { 463 | usb_debug!("Remote wakeup disabled"); 464 | self.remote_wakeup_enabled = false; 465 | xfer.accept()?; 466 | } 467 | 468 | (Recipient::Endpoint, Request::CLEAR_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { 469 | usb_debug!("EP{} halt removed", req.index & 0x8f); 470 | self.bus 471 | .set_stalled(((req.index as u8) & 0x8f).into(), false); 472 | xfer.accept()?; 473 | } 474 | 475 | ( 476 | Recipient::Device, 477 | Request::SET_FEATURE, 478 | Request::FEATURE_DEVICE_REMOTE_WAKEUP, 479 | ) => { 480 | usb_debug!("Remote wakeup enabled"); 481 | self.remote_wakeup_enabled = true; 482 | xfer.accept()?; 483 | } 484 | 485 | (Recipient::Endpoint, Request::SET_FEATURE, Request::FEATURE_ENDPOINT_HALT) => { 486 | usb_debug!("EP{} halted", req.index & 0x8f); 487 | self.bus 488 | .set_stalled(((req.index as u8) & 0x8f).into(), true); 489 | xfer.accept()?; 490 | } 491 | 492 | (Recipient::Device, Request::SET_ADDRESS, 1..=127) => { 493 | usb_debug!("Setting device address to {}", req.value); 494 | if B::QUIRK_SET_ADDRESS_BEFORE_STATUS { 495 | self.bus.set_device_address(req.value as u8); 496 | self.device_state = UsbDeviceState::Addressed; 497 | } else { 498 | self.pending_address = req.value as u8; 499 | } 500 | xfer.accept()?; 501 | } 502 | 503 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_VALUE_U16) => { 504 | usb_debug!("Device configured"); 505 | self.device_state = UsbDeviceState::Configured; 506 | xfer.accept()?; 507 | } 508 | 509 | (Recipient::Device, Request::SET_CONFIGURATION, CONFIGURATION_NONE_U16) => { 510 | usb_debug!("Device deconfigured"); 511 | match self.device_state { 512 | UsbDeviceState::Default => { 513 | xfer.accept()?; 514 | } 515 | _ => { 516 | self.device_state = UsbDeviceState::Addressed; 517 | xfer.accept()?; 518 | } 519 | } 520 | } 521 | 522 | (Recipient::Interface, Request::SET_INTERFACE, alt_setting) => { 523 | // Reject interface numbers and alt settings bigger than 255 524 | if req.index > core::u8::MAX.into() || alt_setting > core::u8::MAX.into() { 525 | xfer.reject()?; 526 | return Ok(()); 527 | } 528 | 529 | // Ask class implementations, whether they accept the alternate interface setting. 530 | for cls in classes { 531 | if cls.set_alt_setting(InterfaceNumber(req.index as u8), alt_setting as u8) 532 | { 533 | xfer.accept()?; 534 | return Ok(()); 535 | } 536 | } 537 | 538 | // Default behaviour, if no class implementation accepted the alternate setting. 539 | if alt_setting == DEFAULT_ALTERNATE_SETTING_U16 { 540 | usb_debug!("Accepting unused alternate settings"); 541 | xfer.accept()?; 542 | } else { 543 | usb_debug!("Rejecting unused alternate settings"); 544 | xfer.reject()?; 545 | } 546 | } 547 | 548 | _ => { 549 | xfer.reject()?; 550 | return Ok(()); 551 | } 552 | } 553 | } 554 | 555 | if self.control.waiting_for_response() { 556 | usb_debug!("Rejecting control transfer due to waiting response"); 557 | self.control.reject()?; 558 | } 559 | 560 | Ok(()) 561 | } 562 | 563 | fn get_descriptor( 564 | config: &Config, 565 | classes: &mut ClassList<'_, B>, 566 | xfer: ControlIn, 567 | ) -> Result<()> { 568 | let req = *xfer.request(); 569 | 570 | let (dtype, index) = req.descriptor_type_index(); 571 | 572 | fn accept_writer( 573 | xfer: ControlIn, 574 | f: impl FnOnce(&mut DescriptorWriter) -> Result<()>, 575 | ) -> Result<()> { 576 | xfer.accept(|buf| { 577 | let mut writer = DescriptorWriter::new(buf); 578 | f(&mut writer)?; 579 | Ok(writer.position()) 580 | })?; 581 | 582 | Ok(()) 583 | } 584 | 585 | match dtype { 586 | descriptor_type::BOS if config.usb_rev > UsbRev::Usb200 => accept_writer(xfer, |w| { 587 | let mut bw = BosWriter::new(w); 588 | bw.bos()?; 589 | 590 | for cls in classes { 591 | cls.get_bos_descriptors(&mut bw)?; 592 | } 593 | 594 | bw.end_bos(); 595 | 596 | Ok(()) 597 | })?, 598 | 599 | descriptor_type::DEVICE => accept_writer(xfer, |w| w.device(config))?, 600 | 601 | descriptor_type::CONFIGURATION => accept_writer(xfer, |w| { 602 | w.configuration(config)?; 603 | 604 | for cls in classes { 605 | cls.get_configuration_descriptors(w)?; 606 | w.end_class(); 607 | } 608 | 609 | w.end_configuration(); 610 | 611 | Ok(()) 612 | })?, 613 | 614 | descriptor_type::STRING => match index { 615 | // first STRING Request 616 | 0 => { 617 | let mut lang_id_bytes = [0u8; 32]; 618 | for (lang, buf) in config 619 | .string_descriptors 620 | .iter() 621 | .zip(lang_id_bytes.chunks_exact_mut(2)) 622 | { 623 | buf.copy_from_slice(&u16::from(lang.id).to_le_bytes()); 624 | } 625 | accept_writer(xfer, |w| { 626 | w.write( 627 | descriptor_type::STRING, 628 | &lang_id_bytes[..config.string_descriptors.len() * 2], 629 | ) 630 | })?; 631 | } 632 | 633 | // rest STRING Requests 634 | _ => { 635 | let lang_id = LangID::from(req.index); 636 | 637 | let string = match index { 638 | // Manufacturer, product, and serial are handled directly here. 639 | 1..=3 => { 640 | let Some(lang) = config 641 | .string_descriptors 642 | .iter() 643 | .find(|lang| lang.id == lang_id) 644 | else { 645 | xfer.reject()?; 646 | return Ok(()); 647 | }; 648 | 649 | match index { 650 | 1 => lang.manufacturer, 651 | 2 => lang.product, 652 | 3 => lang.serial, 653 | _ => unreachable!(), 654 | } 655 | } 656 | _ => { 657 | let index = StringIndex::new(index); 658 | classes 659 | .iter() 660 | .find_map(|cls| cls.get_string(index, lang_id)) 661 | } 662 | }; 663 | 664 | if let Some(string_descriptor) = string { 665 | accept_writer(xfer, |w| w.string(string_descriptor))?; 666 | } else { 667 | xfer.reject()?; 668 | } 669 | } 670 | }, 671 | 672 | _ => { 673 | xfer.reject()?; 674 | } 675 | }; 676 | 677 | Ok(()) 678 | } 679 | 680 | fn reset(&mut self, classes: &mut ClassList<'_, B>) { 681 | self.bus.reset(); 682 | 683 | self.device_state = UsbDeviceState::Default; 684 | self.suspended_device_state = None; // We may reset during Suspend 685 | self.remote_wakeup_enabled = false; 686 | self.pending_address = 0; 687 | 688 | self.control.reset(); 689 | 690 | for cls in classes { 691 | cls.reset(); 692 | } 693 | } 694 | } 695 | --------------------------------------------------------------------------------