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}