diff options
| author | alexmoon <[email protected]> | 2023-02-07 14:19:51 -0500 |
|---|---|---|
| committer | alexmoon <[email protected]> | 2023-02-07 14:24:35 -0500 |
| commit | aa21aebb0b321a2085571e5be5fffcea4703584d (patch) | |
| tree | 9b45fb26d9a32b806931fcc6d379af00f4ffec21 /embassy-usb/src | |
| parent | 9f9230ae7abb545822e59c6f06cabb721b63e0a1 (diff) | |
Lazily encode UTF16 values and add docs
Diffstat (limited to 'embassy-usb/src')
| -rw-r--r-- | embassy-usb/src/msos.rs | 316 |
1 files changed, 156 insertions, 160 deletions
diff --git a/embassy-usb/src/msos.rs b/embassy-usb/src/msos.rs index 360f80d91..19ed34979 100644 --- a/embassy-usb/src/msos.rs +++ b/embassy-usb/src/msos.rs | |||
| @@ -5,16 +5,9 @@ | |||
| 5 | //! <https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification> | 5 | //! <https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification> |
| 6 | 6 | ||
| 7 | use core::mem::size_of; | 7 | use core::mem::size_of; |
| 8 | use core::ops::Range; | ||
| 9 | |||
| 10 | pub use widestring::{u16cstr, u16str, U16CStr, U16Str}; | ||
| 11 | 8 | ||
| 12 | use super::{capability_type, BosWriter}; | 9 | use super::{capability_type, BosWriter}; |
| 13 | 10 | ||
| 14 | fn write_u16<T: Into<u16>>(buf: &mut [u8], range: Range<usize>, data: T) { | ||
| 15 | (&mut buf[range]).copy_from_slice(data.into().to_le_bytes().as_slice()) | ||
| 16 | } | ||
| 17 | |||
| 18 | /// A serialized Microsoft OS 2.0 Descriptor set. | 11 | /// A serialized Microsoft OS 2.0 Descriptor set. |
| 19 | /// | 12 | /// |
| 20 | /// Create with [`DeviceDescriptorSetBuilder`]. | 13 | /// Create with [`DeviceDescriptorSetBuilder`]. |
| @@ -24,14 +17,17 @@ pub struct MsOsDescriptorSet<'d> { | |||
| 24 | } | 17 | } |
| 25 | 18 | ||
| 26 | impl<'d> MsOsDescriptorSet<'d> { | 19 | impl<'d> MsOsDescriptorSet<'d> { |
| 20 | /// Gets the raw bytes of the MS OS descriptor | ||
| 27 | pub fn descriptor(&self) -> &[u8] { | 21 | pub fn descriptor(&self) -> &[u8] { |
| 28 | self.descriptor | 22 | self.descriptor |
| 29 | } | 23 | } |
| 30 | 24 | ||
| 25 | /// Gets the vendor code used by the host to retrieve the MS OS descriptor | ||
| 31 | pub fn vendor_code(&self) -> u8 { | 26 | pub fn vendor_code(&self) -> u8 { |
| 32 | self.vendor_code | 27 | self.vendor_code |
| 33 | } | 28 | } |
| 34 | 29 | ||
| 30 | /// Returns `true` if no MS OS descriptor data is available | ||
| 35 | pub fn is_empty(&self) -> bool { | 31 | pub fn is_empty(&self) -> bool { |
| 36 | self.descriptor.is_empty() | 32 | self.descriptor.is_empty() |
| 37 | } | 33 | } |
| @@ -39,7 +35,7 @@ impl<'d> MsOsDescriptorSet<'d> { | |||
| 39 | 35 | ||
| 40 | /// Writes a Microsoft OS 2.0 Descriptor set into a buffer. | 36 | /// Writes a Microsoft OS 2.0 Descriptor set into a buffer. |
| 41 | pub struct MsOsDescriptorWriter<'d> { | 37 | pub struct MsOsDescriptorWriter<'d> { |
| 42 | pub buf: &'d mut [u8], | 38 | buf: &'d mut [u8], |
| 43 | 39 | ||
| 44 | position: usize, | 40 | position: usize, |
| 45 | config_mark: Option<usize>, | 41 | config_mark: Option<usize>, |
| @@ -75,14 +71,17 @@ impl<'d> MsOsDescriptorWriter<'d> { | |||
| 75 | } | 71 | } |
| 76 | } | 72 | } |
| 77 | 73 | ||
| 74 | /// Returns `true` if the MS OS descriptor header has not yet been written | ||
| 78 | pub fn is_empty(&self) -> bool { | 75 | pub fn is_empty(&self) -> bool { |
| 79 | self.position == 0 | 76 | self.position == 0 |
| 80 | } | 77 | } |
| 81 | 78 | ||
| 79 | /// Returns `true` if a configuration subset header has been started | ||
| 82 | pub fn is_in_config_subset(&self) -> bool { | 80 | pub fn is_in_config_subset(&self) -> bool { |
| 83 | self.config_mark.is_some() | 81 | self.config_mark.is_some() |
| 84 | } | 82 | } |
| 85 | 83 | ||
| 84 | /// Returns `true` if a function subset header has been started and not yet ended | ||
| 86 | pub fn is_in_function_subset(&self) -> bool { | 85 | pub fn is_in_function_subset(&self) -> bool { |
| 87 | self.function_mark.is_some() | 86 | self.function_mark.is_some() |
| 88 | } | 87 | } |
| @@ -148,6 +147,7 @@ impl<'d> MsOsDescriptorWriter<'d> { | |||
| 148 | self.write(desc); | 147 | self.write(desc); |
| 149 | } | 148 | } |
| 150 | 149 | ||
| 150 | /// Ends the current function subset (if any) | ||
| 151 | pub fn end_function(&mut self) { | 151 | pub fn end_function(&mut self) { |
| 152 | Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark); | 152 | Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark); |
| 153 | } | 153 | } |
| @@ -212,29 +212,13 @@ impl<'d> MsOsDescriptorWriter<'d> { | |||
| 212 | } | 212 | } |
| 213 | } | 213 | } |
| 214 | 214 | ||
| 215 | /// Microsoft Windows version codes | ||
| 216 | /// | ||
| 217 | /// Windows 8.1 is the minimum version allowed for MS OS 2.0 descriptors. | ||
| 215 | pub mod windows_version { | 218 | pub mod windows_version { |
| 216 | pub const WIN2K: u32 = 0x05000000; | 219 | /// Windows 8.1 (aka `NTDDI_WINBLUE`) |
| 217 | pub const WIN2KSP1: u32 = 0x05000100; | ||
| 218 | pub const WIN2KSP2: u32 = 0x05000200; | ||
| 219 | pub const WIN2KSP3: u32 = 0x05000300; | ||
| 220 | pub const WIN2KSP4: u32 = 0x05000400; | ||
| 221 | |||
| 222 | pub const WINXP: u32 = 0x05010000; | ||
| 223 | pub const WINXPSP1: u32 = 0x05010100; | ||
| 224 | pub const WINXPSP2: u32 = 0x05010200; | ||
| 225 | pub const WINXPSP3: u32 = 0x05010300; | ||
| 226 | pub const WINXPSP4: u32 = 0x05010400; | ||
| 227 | |||
| 228 | pub const VISTA: u32 = 0x06000000; | ||
| 229 | pub const VISTASP1: u32 = 0x06000100; | ||
| 230 | pub const VISTASP2: u32 = 0x06000200; | ||
| 231 | pub const VISTASP3: u32 = 0x06000300; | ||
| 232 | pub const VISTASP4: u32 = 0x06000400; | ||
| 233 | |||
| 234 | pub const WIN7: u32 = 0x06010000; | ||
| 235 | pub const WIN8: u32 = 0x06020000; | ||
| 236 | /// AKA `NTDDI_WINBLUE` | ||
| 237 | pub const WIN8_1: u32 = 0x06030000; | 220 | pub const WIN8_1: u32 = 0x06030000; |
| 221 | /// Windows 10 | ||
| 238 | pub const WIN10: u32 = 0x0A000000; | 222 | pub const WIN10: u32 = 0x0A000000; |
| 239 | } | 223 | } |
| 240 | 224 | ||
| @@ -266,7 +250,7 @@ use sealed::*; | |||
| 266 | /// The type `T` must be able to be safely cast to `&[u8]`. (e.g. it is a `#[repr(packed)]` struct) | 250 | /// The type `T` must be able to be safely cast to `&[u8]`. (e.g. it is a `#[repr(packed)]` struct) |
| 267 | unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { | 251 | unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { |
| 268 | let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>()); | 252 | let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>()); |
| 269 | assert!(buf.len() >= bytes.len(), "MSOS descriptor buffer full"); | 253 | assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full"); |
| 270 | (&mut buf[..bytes.len()]).copy_from_slice(bytes); | 254 | (&mut buf[..bytes.len()]).copy_from_slice(bytes); |
| 271 | } | 255 | } |
| 272 | 256 | ||
| @@ -274,14 +258,23 @@ unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) { | |||
| 274 | #[derive(Clone, Copy, PartialEq, Eq)] | 258 | #[derive(Clone, Copy, PartialEq, Eq)] |
| 275 | #[repr(u16)] | 259 | #[repr(u16)] |
| 276 | pub enum DescriptorType { | 260 | pub enum DescriptorType { |
| 261 | /// MS OS descriptor set header | ||
| 277 | SetHeaderDescriptor = 0, | 262 | SetHeaderDescriptor = 0, |
| 263 | /// Configuration subset header | ||
| 278 | SubsetHeaderConfiguration = 1, | 264 | SubsetHeaderConfiguration = 1, |
| 265 | /// Function subset header | ||
| 279 | SubsetHeaderFunction = 2, | 266 | SubsetHeaderFunction = 2, |
| 267 | /// Compatible device ID feature descriptor | ||
| 280 | FeatureCompatibleId = 3, | 268 | FeatureCompatibleId = 3, |
| 269 | /// Registry property feature descriptor | ||
| 281 | FeatureRegProperty = 4, | 270 | FeatureRegProperty = 4, |
| 271 | /// Minimum USB resume time feature descriptor | ||
| 282 | FeatureMinResumeTime = 5, | 272 | FeatureMinResumeTime = 5, |
| 273 | /// Vendor revision feature descriptor | ||
| 283 | FeatureModelId = 6, | 274 | FeatureModelId = 6, |
| 275 | /// CCGP device descriptor feature descriptor | ||
| 284 | FeatureCcgpDevice = 7, | 276 | FeatureCcgpDevice = 7, |
| 277 | /// Vendor revision feature descriptor | ||
| 285 | FeatureVendorRevision = 8, | 278 | FeatureVendorRevision = 8, |
| 286 | } | 279 | } |
| 287 | 280 | ||
| @@ -318,6 +311,9 @@ pub struct DescriptorSetHeader { | |||
| 318 | } | 311 | } |
| 319 | 312 | ||
| 320 | impl DescriptorSetHeader { | 313 | impl DescriptorSetHeader { |
| 314 | /// Creates a MS OS descriptor set header. | ||
| 315 | /// | ||
| 316 | /// `windows_version` is the minimum Windows version the descriptor set can apply to. | ||
| 321 | pub fn new(windows_version: u32) -> Self { | 317 | pub fn new(windows_version: u32) -> Self { |
| 322 | DescriptorSetHeader { | 318 | DescriptorSetHeader { |
| 323 | wLength: (size_of::<Self>() as u16).to_le(), | 319 | wLength: (size_of::<Self>() as u16).to_le(), |
| @@ -351,6 +347,7 @@ pub struct ConfigurationSubsetHeader { | |||
| 351 | } | 347 | } |
| 352 | 348 | ||
| 353 | impl ConfigurationSubsetHeader { | 349 | impl ConfigurationSubsetHeader { |
| 350 | /// Creates a configuration subset header | ||
| 354 | pub fn new(config: u8) -> Self { | 351 | pub fn new(config: u8) -> Self { |
| 355 | ConfigurationSubsetHeader { | 352 | ConfigurationSubsetHeader { |
| 356 | wLength: (size_of::<Self>() as u16).to_le(), | 353 | wLength: (size_of::<Self>() as u16).to_le(), |
| @@ -385,6 +382,7 @@ pub struct FunctionSubsetHeader { | |||
| 385 | } | 382 | } |
| 386 | 383 | ||
| 387 | impl FunctionSubsetHeader { | 384 | impl FunctionSubsetHeader { |
| 385 | /// Creates a function subset header | ||
| 388 | pub fn new(first_interface: u8) -> Self { | 386 | pub fn new(first_interface: u8) -> Self { |
| 389 | FunctionSubsetHeader { | 387 | FunctionSubsetHeader { |
| 390 | wLength: (size_of::<Self>() as u16).to_le(), | 388 | wLength: (size_of::<Self>() as u16).to_le(), |
| @@ -436,11 +434,8 @@ impl Descriptor for CompatibleIdFeatureDescriptor { | |||
| 436 | } | 434 | } |
| 437 | 435 | ||
| 438 | impl CompatibleIdFeatureDescriptor { | 436 | impl CompatibleIdFeatureDescriptor { |
| 439 | /// Creates a compatible ID descriptor that signals WINUSB driver compatiblilty. | 437 | /// Creates a compatible ID feature descriptor |
| 440 | pub fn new_winusb() -> Self { | 438 | /// |
| 441 | Self::new_raw([b'W', b'I', b'N', b'U', b'S', b'B', 0, 0], [0u8; 8]) | ||
| 442 | } | ||
| 443 | |||
| 444 | /// The ids must be 8 ASCII bytes or fewer. | 439 | /// The ids must be 8 ASCII bytes or fewer. |
| 445 | pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self { | 440 | pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self { |
| 446 | assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8); | 441 | assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8); |
| @@ -451,7 +446,7 @@ impl CompatibleIdFeatureDescriptor { | |||
| 451 | Self::new_raw(cid, scid) | 446 | Self::new_raw(cid, scid) |
| 452 | } | 447 | } |
| 453 | 448 | ||
| 454 | pub fn new_raw(compatible_id: [u8; 8], sub_compatible_id: [u8; 8]) -> Self { | 449 | fn new_raw(compatible_id: [u8; 8], sub_compatible_id: [u8; 8]) -> Self { |
| 455 | Self { | 450 | Self { |
| 456 | wLength: (size_of::<Self>() as u16).to_le(), | 451 | wLength: (size_of::<Self>() as u16).to_le(), |
| 457 | wDescriptorType: (Self::TYPE as u16).to_le(), | 452 | wDescriptorType: (Self::TYPE as u16).to_le(), |
| @@ -464,129 +459,87 @@ impl CompatibleIdFeatureDescriptor { | |||
| 464 | /// Table 14. Microsoft OS 2.0 registry property descriptor | 459 | /// Table 14. Microsoft OS 2.0 registry property descriptor |
| 465 | #[allow(non_snake_case)] | 460 | #[allow(non_snake_case)] |
| 466 | pub struct RegistryPropertyFeatureDescriptor<'a> { | 461 | pub struct RegistryPropertyFeatureDescriptor<'a> { |
| 467 | wLength: u16, | 462 | name: &'a str, |
| 468 | wDescriptorType: u16, | 463 | data: PropertyData<'a>, |
| 469 | wPropertyDataType: u16, | 464 | } |
| 470 | PropertyName: &'a [u8], | 465 | |
| 471 | PropertyData: &'a [u8], | 466 | /// Data values that can be encoded into a registry property descriptor |
| 472 | } | 467 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] |
| 473 | 468 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | |
| 474 | impl<'a> DeviceLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {} | 469 | pub enum PropertyData<'a> { |
| 475 | impl<'a> FunctionLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {} | 470 | /// A registry property containing a string. |
| 476 | 471 | Sz(&'a str), | |
| 477 | impl<'a> Descriptor for RegistryPropertyFeatureDescriptor<'a> { | 472 | /// A registry property containing a string that expands environment variables. |
| 478 | const TYPE: DescriptorType = DescriptorType::FeatureRegProperty; | 473 | ExpandSz(&'a str), |
| 479 | fn size(&self) -> usize { | ||
| 480 | 10 + self.PropertyName.len() + self.PropertyData.len() | ||
| 481 | } | ||
| 482 | fn write_to(&self, buf: &mut [u8]) { | ||
| 483 | assert!(buf.len() >= self.size(), "MSOS descriptor buffer full"); | ||
| 484 | write_u16(buf, 0..2, self.wLength); | ||
| 485 | write_u16(buf, 2..4, self.wDescriptorType); | ||
| 486 | write_u16(buf, 4..6, self.wPropertyDataType); | ||
| 487 | write_u16(buf, 6..8, (self.PropertyName.len() as u16).to_le()); | ||
| 488 | let pne = 8 + self.PropertyName.len(); | ||
| 489 | (&mut buf[8..pne]).copy_from_slice(self.PropertyName); | ||
| 490 | let pds = pne + 2; | ||
| 491 | let pde = pds + self.PropertyData.len(); | ||
| 492 | write_u16(buf, pne..pds, (self.PropertyData.len() as u16).to_le()); | ||
| 493 | (&mut buf[pds..pde]).copy_from_slice(self.PropertyData); | ||
| 494 | } | ||
| 495 | } | ||
| 496 | |||
| 497 | impl<'a> RegistryPropertyFeatureDescriptor<'a> { | ||
| 498 | pub const DEVICE_INTERFACE_GUIDS_NAME: &U16CStr = { | ||
| 499 | // Can't use defmt::panic in constant expressions (inside u16cstr!) | ||
| 500 | macro_rules! panic { | ||
| 501 | ($($x:tt)*) => { | ||
| 502 | { | ||
| 503 | ::core::panic!($($x)*); | ||
| 504 | } | ||
| 505 | }; | ||
| 506 | } | ||
| 507 | |||
| 508 | u16cstr!("DeviceInterfaceGUIDs") | ||
| 509 | }; | ||
| 510 | |||
| 511 | /// A registry property. | ||
| 512 | /// | ||
| 513 | /// `name` should be a NUL-terminated 16-bit Unicode string. | ||
| 514 | pub fn new_raw<'n: 'a, 'd: 'a>(name: &'a [u8], data: &'d [u8], data_type: PropertyDataType) -> Self { | ||
| 515 | assert!(name.len() < usize::from(u16::MAX) && data.len() < usize::from(u16::MAX)); | ||
| 516 | Self { | ||
| 517 | wLength: ((10 + name.len() + data.len()) as u16).to_le(), | ||
| 518 | wDescriptorType: (Self::TYPE as u16).to_le(), | ||
| 519 | wPropertyDataType: (data_type as u16).to_le(), | ||
| 520 | PropertyName: name, | ||
| 521 | PropertyData: data, | ||
| 522 | } | ||
| 523 | } | ||
| 524 | |||
| 525 | fn u16str_bytes(s: &U16CStr) -> &[u8] { | ||
| 526 | unsafe { core::slice::from_raw_parts(s.as_ptr() as *const u8, (s.len() + 1) * 2) } | ||
| 527 | } | ||
| 528 | |||
| 529 | /// A registry property containing a NUL-terminated 16-bit Unicode string. | ||
| 530 | pub fn new_string<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d U16CStr) -> Self { | ||
| 531 | Self::new_raw(Self::u16str_bytes(name), Self::u16str_bytes(data), PropertyDataType::Sz) | ||
| 532 | } | ||
| 533 | |||
| 534 | /// A registry property containing a NUL-terminated 16-bit Unicode string that expands environment variables. | ||
| 535 | pub fn new_string_expand<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d U16CStr) -> Self { | ||
| 536 | Self::new_raw( | ||
| 537 | Self::u16str_bytes(name), | ||
| 538 | Self::u16str_bytes(data), | ||
| 539 | PropertyDataType::ExpandSz, | ||
| 540 | ) | ||
| 541 | } | ||
| 542 | |||
| 543 | /// A registry property containing a NUL-terminated 16-bit Unicode string that contains a symbolic link. | ||
| 544 | pub fn new_link<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d U16CStr) -> Self { | ||
| 545 | Self::new_raw( | ||
| 546 | Self::u16str_bytes(name), | ||
| 547 | Self::u16str_bytes(data), | ||
| 548 | PropertyDataType::Link, | ||
| 549 | ) | ||
| 550 | } | ||
| 551 | |||
| 552 | /// A registry property containing multiple NUL-terminated 16-bit Unicode strings. | ||
| 553 | pub fn new_multi_string<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d [u16]) -> Self { | ||
| 554 | assert!( | ||
| 555 | data.len() >= 2 && data[data.len() - 1] == 0 && data[data.len() - 2] == 0, | ||
| 556 | "multi-strings must end in double nul terminators" | ||
| 557 | ); | ||
| 558 | Self::new_raw( | ||
| 559 | Self::u16str_bytes(name), | ||
| 560 | unsafe { core::slice::from_raw_parts(data.as_ptr() as *const u8, data.len() * 2) }, | ||
| 561 | PropertyDataType::RegMultiSz, | ||
| 562 | ) | ||
| 563 | } | ||
| 564 | |||
| 565 | /// A registry property containing binary data. | 474 | /// A registry property containing binary data. |
| 566 | pub fn new_binary<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d [u8]) -> Self { | 475 | Binary(&'a [u8]), |
| 567 | Self::new_raw(Self::u16str_bytes(name), data, PropertyDataType::Binary) | 476 | /// A registry property containing a little-endian 32-bit integer. |
| 477 | DwordLittleEndian(u32), | ||
| 478 | /// A registry property containing a big-endian 32-bit integer. | ||
| 479 | DwordBigEndian(u32), | ||
| 480 | /// A registry property containing a string that contains a symbolic link. | ||
| 481 | Link(&'a str), | ||
| 482 | /// A registry property containing multiple strings. | ||
| 483 | RegMultiSz(&'a [&'a str]), | ||
| 484 | } | ||
| 485 | |||
| 486 | fn write_bytes(val: &[u8], buf: &mut [u8]) -> usize { | ||
| 487 | assert!(buf.len() >= val.len()); | ||
| 488 | buf[..val.len()].copy_from_slice(val); | ||
| 489 | val.len() | ||
| 490 | } | ||
| 491 | |||
| 492 | fn write_utf16(val: &str, buf: &mut [u8]) -> usize { | ||
| 493 | let mut pos = 0; | ||
| 494 | for c in val.encode_utf16() { | ||
| 495 | pos += write_bytes(&c.to_le_bytes(), &mut buf[pos..]); | ||
| 496 | } | ||
| 497 | pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..]) | ||
| 498 | } | ||
| 499 | |||
| 500 | impl<'a> PropertyData<'a> { | ||
| 501 | /// Gets the `PropertyDataType` for this property value | ||
| 502 | pub fn kind(&self) -> PropertyDataType { | ||
| 503 | match self { | ||
| 504 | PropertyData::Sz(_) => PropertyDataType::Sz, | ||
| 505 | PropertyData::ExpandSz(_) => PropertyDataType::ExpandSz, | ||
| 506 | PropertyData::Binary(_) => PropertyDataType::Binary, | ||
| 507 | PropertyData::DwordLittleEndian(_) => PropertyDataType::DwordLittleEndian, | ||
| 508 | PropertyData::DwordBigEndian(_) => PropertyDataType::DwordBigEndian, | ||
| 509 | PropertyData::Link(_) => PropertyDataType::Link, | ||
| 510 | PropertyData::RegMultiSz(_) => PropertyDataType::RegMultiSz, | ||
| 511 | } | ||
| 568 | } | 512 | } |
| 569 | 513 | ||
| 570 | /// A registry property containing a Little-Endian 32-bit integer. | 514 | /// Gets the size (in bytes) of this property value when encoded. |
| 571 | /// | 515 | pub fn size(&self) -> usize { |
| 572 | /// The function assumes that `data` is already little-endian, it does not convert it. | 516 | match self { |
| 573 | pub fn new_dword_le<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d i32) -> Self { | 517 | PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => { |
| 574 | Self::new_raw( | 518 | core::mem::size_of::<u16>() * (val.encode_utf16().count() + 1) |
| 575 | Self::u16str_bytes(name), | 519 | } |
| 576 | unsafe { core::slice::from_raw_parts(data as *const i32 as *const u8, size_of::<i32>()) }, | 520 | PropertyData::Binary(val) => val.len(), |
| 577 | PropertyDataType::DwordLittleEndian, | 521 | PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val), |
| 578 | ) | 522 | PropertyData::RegMultiSz(val) => { |
| 523 | core::mem::size_of::<u16>() * val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1 | ||
| 524 | } | ||
| 525 | } | ||
| 579 | } | 526 | } |
| 580 | 527 | ||
| 581 | /// A registry property containing a big-endian 32-bit integer. | 528 | /// Encodes the data for this property value and writes it to `buf`. |
| 582 | /// | 529 | pub fn write(&self, buf: &mut [u8]) -> usize { |
| 583 | /// The function assumes that `data` is already big-endian, it does not convert it. | 530 | match self { |
| 584 | pub fn new_dword_be<'n: 'a, 'd: 'a>(name: &'n U16CStr, data: &'d i32) -> Self { | 531 | PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => write_utf16(val, buf), |
| 585 | Self::new_raw( | 532 | PropertyData::Binary(val) => write_bytes(val, buf), |
| 586 | Self::u16str_bytes(name), | 533 | PropertyData::DwordLittleEndian(val) => write_bytes(&val.to_le_bytes(), buf), |
| 587 | unsafe { core::slice::from_raw_parts(data as *const i32 as *const u8, size_of::<i32>()) }, | 534 | PropertyData::DwordBigEndian(val) => write_bytes(&val.to_be_bytes(), buf), |
| 588 | PropertyDataType::DwordBigEndian, | 535 | PropertyData::RegMultiSz(val) => { |
| 589 | ) | 536 | let mut pos = 0; |
| 537 | for s in *val { | ||
| 538 | pos += write_utf16(s, &mut buf[pos..]); | ||
| 539 | } | ||
| 540 | pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..]) | ||
| 541 | } | ||
| 542 | } | ||
| 590 | } | 543 | } |
| 591 | } | 544 | } |
| 592 | 545 | ||
| @@ -594,15 +547,57 @@ impl<'a> RegistryPropertyFeatureDescriptor<'a> { | |||
| 594 | #[derive(Clone, Copy, PartialEq, Eq)] | 547 | #[derive(Clone, Copy, PartialEq, Eq)] |
| 595 | #[repr(u16)] | 548 | #[repr(u16)] |
| 596 | pub enum PropertyDataType { | 549 | pub enum PropertyDataType { |
| 550 | /// A registry property containing a string. | ||
| 597 | Sz = 1, | 551 | Sz = 1, |
| 552 | /// A registry property containing a string that expands environment variables. | ||
| 598 | ExpandSz = 2, | 553 | ExpandSz = 2, |
| 554 | /// A registry property containing binary data. | ||
| 599 | Binary = 3, | 555 | Binary = 3, |
| 556 | /// A registry property containing a little-endian 32-bit integer. | ||
| 600 | DwordLittleEndian = 4, | 557 | DwordLittleEndian = 4, |
| 558 | /// A registry property containing a big-endian 32-bit integer. | ||
| 601 | DwordBigEndian = 5, | 559 | DwordBigEndian = 5, |
| 560 | /// A registry property containing a string that contains a symbolic link. | ||
| 602 | Link = 6, | 561 | Link = 6, |
| 562 | /// A registry property containing multiple strings. | ||
| 603 | RegMultiSz = 7, | 563 | RegMultiSz = 7, |
| 604 | } | 564 | } |
| 605 | 565 | ||
| 566 | impl<'a> DeviceLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {} | ||
| 567 | impl<'a> FunctionLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {} | ||
| 568 | |||
| 569 | impl<'a> Descriptor for RegistryPropertyFeatureDescriptor<'a> { | ||
| 570 | const TYPE: DescriptorType = DescriptorType::FeatureRegProperty; | ||
| 571 | |||
| 572 | fn size(&self) -> usize { | ||
| 573 | 10 + self.name_size() + self.data.size() | ||
| 574 | } | ||
| 575 | |||
| 576 | fn write_to(&self, buf: &mut [u8]) { | ||
| 577 | assert!(buf.len() >= self.size(), "MS OS descriptor buffer full"); | ||
| 578 | |||
| 579 | let mut pos = 0; | ||
| 580 | pos += write_bytes(&(self.size() as u16).to_le_bytes(), &mut buf[pos..]); | ||
| 581 | pos += write_bytes(&(Self::TYPE as u16).to_le_bytes(), &mut buf[pos..]); | ||
| 582 | pos += write_bytes(&(self.data.kind() as u16).to_le_bytes(), &mut buf[pos..]); | ||
| 583 | pos += write_bytes(&(self.name_size() as u16).to_le_bytes(), &mut buf[pos..]); | ||
| 584 | pos += write_utf16(self.name, &mut buf[pos..]); | ||
| 585 | pos += write_bytes(&(self.data.size() as u16).to_le_bytes(), &mut buf[pos..]); | ||
| 586 | self.data.write(&mut buf[pos..]); | ||
| 587 | } | ||
| 588 | } | ||
| 589 | |||
| 590 | impl<'a> RegistryPropertyFeatureDescriptor<'a> { | ||
| 591 | /// A registry property. | ||
| 592 | pub fn new(name: &'a str, data: PropertyData<'a>) -> Self { | ||
| 593 | Self { name, data } | ||
| 594 | } | ||
| 595 | |||
| 596 | fn name_size(&self) -> usize { | ||
| 597 | core::mem::size_of::<u16>() * (self.name.encode_utf16().count() + 1) | ||
| 598 | } | ||
| 599 | } | ||
| 600 | |||
| 606 | /// Table 16. Microsoft OS 2.0 minimum USB recovery time descriptor. | 601 | /// Table 16. Microsoft OS 2.0 minimum USB recovery time descriptor. |
| 607 | #[allow(non_snake_case)] | 602 | #[allow(non_snake_case)] |
| 608 | #[repr(C, packed(1))] | 603 | #[repr(C, packed(1))] |
| @@ -658,15 +653,14 @@ impl Descriptor for ModelIdDescriptor { | |||
| 658 | } | 653 | } |
| 659 | 654 | ||
| 660 | impl ModelIdDescriptor { | 655 | impl ModelIdDescriptor { |
| 656 | /// Creates a new model ID descriptor | ||
| 657 | /// | ||
| 658 | /// `model_id` should be a uuid that uniquely identifies a physical device. | ||
| 661 | pub fn new(model_id: u128) -> Self { | 659 | pub fn new(model_id: u128) -> Self { |
| 662 | Self::new_bytes(model_id.to_le_bytes()) | ||
| 663 | } | ||
| 664 | |||
| 665 | pub fn new_bytes(model_id: [u8; 16]) -> Self { | ||
| 666 | Self { | 660 | Self { |
| 667 | wLength: (size_of::<Self>() as u16).to_le(), | 661 | wLength: (size_of::<Self>() as u16).to_le(), |
| 668 | wDescriptorType: (Self::TYPE as u16).to_le(), | 662 | wDescriptorType: (Self::TYPE as u16).to_le(), |
| 669 | modelId: model_id, | 663 | modelId: model_id.to_le_bytes(), |
| 670 | } | 664 | } |
| 671 | } | 665 | } |
| 672 | } | 666 | } |
| @@ -689,6 +683,7 @@ impl Descriptor for CcgpDeviceDescriptor { | |||
| 689 | } | 683 | } |
| 690 | 684 | ||
| 691 | impl CcgpDeviceDescriptor { | 685 | impl CcgpDeviceDescriptor { |
| 686 | /// Creates a new CCGP device descriptor | ||
| 692 | pub fn new() -> Self { | 687 | pub fn new() -> Self { |
| 693 | Self { | 688 | Self { |
| 694 | wLength: (size_of::<Self>() as u16).to_le(), | 689 | wLength: (size_of::<Self>() as u16).to_le(), |
| @@ -704,7 +699,7 @@ pub struct VendorRevisionDescriptor { | |||
| 704 | wLength: u16, | 699 | wLength: u16, |
| 705 | wDescriptorType: u16, | 700 | wDescriptorType: u16, |
| 706 | /// Revision number associated with the descriptor set. Modify it every time you add/modify a registry property or | 701 | /// Revision number associated with the descriptor set. Modify it every time you add/modify a registry property or |
| 707 | /// other MSOS descriptor. Shell set to greater than or equal to 1. | 702 | /// other MS OS descriptor. Shell set to greater than or equal to 1. |
| 708 | VendorRevision: u16, | 703 | VendorRevision: u16, |
| 709 | } | 704 | } |
| 710 | 705 | ||
| @@ -719,6 +714,7 @@ impl Descriptor for VendorRevisionDescriptor { | |||
| 719 | } | 714 | } |
| 720 | 715 | ||
| 721 | impl VendorRevisionDescriptor { | 716 | impl VendorRevisionDescriptor { |
| 717 | /// Creates a new vendor revision descriptor | ||
| 722 | pub fn new(revision: u16) -> Self { | 718 | pub fn new(revision: u16) -> Self { |
| 723 | assert!(revision >= 1); | 719 | assert!(revision >= 1); |
| 724 | Self { | 720 | Self { |
