usb_device/
descriptor.rs

1use core::cmp::min;
2
3use crate::bus::{InterfaceNumber, StringIndex, UsbBus};
4use crate::device;
5use crate::endpoint::{Endpoint, EndpointDirection};
6use crate::{Result, UsbError};
7
8/// Standard descriptor types
9#[allow(missing_docs)]
10pub 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.
22pub mod lang_id;
23
24/// Standard capability descriptor types
25#[allow(missing_docs)]
26pub 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.
35pub struct DescriptorWriter<'a> {
36    buf: &'a mut [u8],
37    position: usize,
38    num_interfaces_mark: Option<usize>,
39    num_endpoints_mark: Option<usize>,
40    write_iads: bool,
41}
42
43impl 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<usize>,
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<StringIndex>,
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<StringIndex>,
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<B: UsbBus, D: EndpointDirection>(
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<B: UsbBus, D: EndpointDirection>(
327        &mut self,
328        endpoint: &Endpoint<'_, B, D>,
329        f: impl FnOnce(&mut [u8]) -> Result<usize>,
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.
384pub struct BosWriter<'w, 'a: 'w> {
385    writer: &'w mut DescriptorWriter<'a>,
386    num_caps_mark: Option<usize>,
387}
388
389impl<'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}