usbd_microsoft_os/
lib.rs

1//! Microsoft OS USB descriptors for usb-device
2//!
3//! Implementation of Microsoft OS USB descriptors for [usb-device](https://crates.io/crates/usb-device).
4//! Currently only the new [Microsoft OS 2.0 Descriptors](https://learn.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification)
5//! standard is supported. Version 1.0 may be added in the future if needed.
6//!
7//! This crate provides class `MsOsUsbClass` that is responsible for sending MS OS USB descriptors
8//! and appropriate BOS capabilities. It is meant to be configured using `const` structures that
9//! describe the descriptors, and `const fn` methods that generate raw descriptor data, e.g. for WinUSB:
10//!
11//! ```rust
12//! use usbd_microsoft_os::{os_20, MsOsUsbClass, WindowsVersion, utf16_lit, utf16_null_le_bytes};
13//!
14//! const DESCRIPTOR_SET: os_20::DescriptorSet = os_20::DescriptorSet {
15//!     version: WindowsVersion::MINIMAL,
16//!     features: &[],
17//!     configurations: &[
18//!         os_20::ConfigurationSubset {
19//!             configuration: 0,
20//!             features: &[],
21//!             functions: &[
22//!                 os_20::FunctionSubset {
23//!                     first_interface: 3,
24//!                     features: &[
25//!                         os_20::FeatureDescriptor::CompatibleId {
26//!                             id: b"WINUSB\0\0",
27//!                             sub_id: b"\0\0\0\0\0\0\0\0",
28//!                         },
29//!                         os_20::FeatureDescriptor::RegistryProperty {
30//!                             data_type: os_20::PropertyDataType::RegMutliSz,
31//!                             name: &utf16_lit::utf16_null!("DeviceInterfaceGUIDs"),
32//!                             data: &utf16_null_le_bytes!("{6b09aac4-333f-4467-9e23-f88b9e9d95f7}\0"),
33//!                         },
34//!                     ]
35//!                 }
36//!             ]
37//!         }
38//!     ],
39//! };
40//!
41//! const CAPABILITIES: os_20::Capabilities = os_20::Capabilities {
42//!     infos: &[
43//!         os_20::CapabilityInfo {
44//!             descriptors: &DESCRIPTOR_SET,
45//!             alt_enum_cmd: os_20::ALT_ENUM_CODE_NOT_SUPPORTED,
46//!         }
47//!     ],
48//! };
49//!
50//! const DESCRIPTOR_SET_BYTES: [u8; DESCRIPTOR_SET.size()] = DESCRIPTOR_SET.descriptor();
51//! const CAPABILITIES_BYTES: [u8; CAPABILITIES.data_len()] = CAPABILITIES.descriptor_data();
52//!
53//! pub const fn class() -> MsOsUsbClass {
54//!     MsOsUsbClass {
55//!         os_20_capabilities_data: &CAPABILITIES_BYTES,
56//!         os_20_descriptor_sets: &[&DESCRIPTOR_SET_BYTES],
57//!     }
58//! }
59//! ```
60//!
61//! Check test cases to see more examples from the specification.
62
63#![no_std]
64#![deny(missing_docs)]
65
66// Include std when running tests
67#[cfg(test)]
68#[macro_use]
69extern crate std;
70
71/// Re-export of utf16_lit for constructing utf16 literals in compile time
72pub extern crate utf16_lit;
73
74/// USB class definition
75pub mod class;
76/// Microsoft OS 2.0 Descriptors
77pub mod os_20;
78/// Windows NTDDI version definitions
79pub mod windows_version;
80
81pub use class::MsOsUsbClass;
82pub use windows_version::WindowsVersion;
83
84/// Generate UTF-16 string using [`utf16_lit::utf16_null`] and get it as little-endian bytes array
85///
86/// This is useful for constructing registry property values:
87/// ```
88/// use usbd_microsoft_os::{os_20::{FeatureDescriptor, PropertyDataType}, utf16_null_le_bytes};
89/// const FEAT: FeatureDescriptor = FeatureDescriptor::RegistryProperty {
90///     data_type: PropertyDataType::RegMutliSz,
91///     name: &utf16_lit::utf16_null!("DeviceInterfaceGUIDs"),
92///     data: &utf16_null_le_bytes!("{897d7b90-5aae-43e5-9c36-aa0f2fdbafc9}\0"),
93/// };
94/// ```
95#[macro_export]
96macro_rules! utf16_null_le_bytes {
97    ($string:literal) => {
98        {
99            const UTF16: &[u16] = $crate::utf16_lit::utf16_null!($string).as_slice();
100            const BYTES: [u8; 2 * UTF16.len()] = {
101                let mut buffer = [0u8; 2 * UTF16.len()];
102                let mut i = 0;
103                while i < UTF16.len() {
104                    let value = UTF16[i].to_le_bytes();
105                    buffer[2 * i] = value[0];
106                    buffer[2 * i + 1] = value[1];
107                    i += 1;
108                }
109                buffer
110            };
111            BYTES
112        }
113    };
114}
115
116/// Generate UTF-16 string using [`utf16_lit::utf16`] and get it as little-endian bytes array
117///
118/// Usually it is better to use [`utf16_null_le_bytes`].
119#[macro_export]
120macro_rules! utf16_le_bytes {
121    ($string:literal) => {
122        {
123            const UTF16: &[u16] = $crate::utf16_lit::utf16!($string).as_slice();
124            const BYTES: [u8; 2 * UTF16.len()] = {
125                let mut buffer = [0u8; 2 * UTF16.len()];
126                let mut i = 0;
127                while i < UTF16.len() {
128                    let value = UTF16[i].to_le_bytes();
129                    buffer[2 * i] = value[0];
130                    buffer[2 * i + 1] = value[1];
131                    i += 1;
132                }
133                buffer
134            };
135            BYTES
136        }
137    };
138}