1use core::mem::size_of;
6
7use crate::descriptor::{capability_type, BosWriter};
8use crate::types::InterfaceNumber;
9
10pub struct MsOsDescriptorSet<'d> {
14 descriptor: &'d [u8],
15 vendor_code: u8,
16}
17
18impl<'d> MsOsDescriptorSet<'d> {
19 pub fn descriptor(&self) -> &[u8] {
21 self.descriptor
22 }
23
24 pub fn vendor_code(&self) -> u8 {
26 self.vendor_code
27 }
28
29 pub fn is_empty(&self) -> bool {
31 self.descriptor.is_empty()
32 }
33
34 pub fn len(&self) -> usize {
36 self.descriptor.len()
37 }
38}
39
40pub struct MsOsDescriptorWriter<'d> {
42 buf: &'d mut [u8],
43
44 position: usize,
45 config_mark: Option<usize>,
46 function_mark: Option<usize>,
47 vendor_code: u8,
48}
49
50impl<'d> MsOsDescriptorWriter<'d> {
51 pub(crate) fn new(buf: &'d mut [u8]) -> Self {
52 MsOsDescriptorWriter {
53 buf,
54 position: 0,
55 config_mark: None,
56 function_mark: None,
57 vendor_code: 0,
58 }
59 }
60
61 pub(crate) fn build(mut self, bos: &mut BosWriter) -> MsOsDescriptorSet<'d> {
62 self.end();
63
64 if self.is_empty() {
65 MsOsDescriptorSet {
66 descriptor: &[],
67 vendor_code: 0,
68 }
69 } else {
70 self.write_bos(bos);
71 MsOsDescriptorSet {
72 descriptor: &self.buf[..self.position],
73 vendor_code: self.vendor_code,
74 }
75 }
76 }
77
78 pub fn is_empty(&self) -> bool {
80 self.position == 0
81 }
82
83 pub fn is_in_config_subset(&self) -> bool {
85 self.config_mark.is_some()
86 }
87
88 pub fn is_in_function_subset(&self) -> bool {
90 self.function_mark.is_some()
91 }
92
93 pub fn header(&mut self, windows_version: u32, vendor_code: u8) {
99 assert!(self.is_empty(), "You can only call MsOsDescriptorWriter::header once");
100 self.write(DescriptorSetHeader::new(windows_version));
101 self.vendor_code = vendor_code;
102 }
103
104 pub fn device_feature<T: DeviceLevelDescriptor>(&mut self, desc: T) {
109 assert!(
110 !self.is_empty(),
111 "device features may only be added after the header is written"
112 );
113 assert!(
114 self.config_mark.is_none(),
115 "device features must be added before the first configuration subset"
116 );
117 self.write(desc);
118 }
119
120 pub fn configuration(&mut self, config: u8) {
122 assert!(
123 !self.is_empty(),
124 "MsOsDescriptorWriter: configuration must be called after header"
125 );
126 Self::end_subset::<ConfigurationSubsetHeader>(self.buf, self.position, &mut self.config_mark);
127 self.config_mark = Some(self.position);
128 self.write(ConfigurationSubsetHeader::new(config));
129 }
130
131 pub fn function(&mut self, first_interface: InterfaceNumber) {
133 assert!(
134 self.config_mark.is_some(),
135 "MsOsDescriptorWriter: function subset requires a configuration subset"
136 );
137 self.end_function();
138 self.function_mark = Some(self.position);
139 self.write(FunctionSubsetHeader::new(first_interface));
140 }
141
142 pub fn function_feature<T: FunctionLevelDescriptor>(&mut self, desc: T) {
147 assert!(
148 self.function_mark.is_some(),
149 "function features may only be added to a function subset"
150 );
151 self.write(desc);
152 }
153
154 pub fn end_function(&mut self) {
156 Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark);
157 }
158
159 fn write<T: Descriptor>(&mut self, desc: T) {
160 desc.write_to(&mut self.buf[self.position..]);
161 self.position += desc.size();
162 }
163
164 fn end_subset<T: DescriptorSet>(buf: &mut [u8], position: usize, mark: &mut Option<usize>) {
165 if let Some(mark) = mark.take() {
166 let len = position - mark;
167 let p = mark + T::LENGTH_OFFSET;
168 buf[p..(p + 2)].copy_from_slice(&(len as u16).to_le_bytes());
169 }
170 }
171
172 fn end(&mut self) {
173 if self.position > 0 {
174 Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark);
175 Self::end_subset::<ConfigurationSubsetHeader>(self.buf, self.position, &mut self.config_mark);
176 Self::end_subset::<DescriptorSetHeader>(self.buf, self.position, &mut Some(0));
177 }
178 }
179
180 fn write_bos(&mut self, bos: &mut BosWriter) {
181 let windows_version = &self.buf[4..8];
182 let len = (self.position as u16).to_le_bytes();
183 bos.capability(
184 capability_type::PLATFORM,
185 &[
186 0, 0xdf,
189 0x60,
190 0xdd,
191 0xd8,
192 0x89,
193 0x45,
194 0xc7,
195 0x4c,
196 0x9c,
197 0xd2,
198 0x65,
199 0x9d,
200 0x9e,
201 0x64,
202 0x8a,
203 0x9f,
204 windows_version[0],
206 windows_version[1],
207 windows_version[2],
208 windows_version[3],
209 len[0],
211 len[1],
212 self.vendor_code,
213 0x0, ],
215 );
216 }
217}
218
219pub mod windows_version {
223 pub const WIN8_1: u32 = 0x06030000;
225 pub const WIN10: u32 = 0x0A000000;
227}
228
229trait Descriptor: Sized {
231 const TYPE: DescriptorType;
232
233 fn size(&self) -> usize {
235 size_of::<Self>()
236 }
237
238 fn write_to(&self, buf: &mut [u8]);
239}
240
241trait DescriptorSet: Descriptor {
242 const LENGTH_OFFSET: usize;
243}
244
245unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) {
250 let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>());
251 assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full");
252 buf[..bytes.len()].copy_from_slice(bytes);
253}
254
255#[derive(Clone, Copy, PartialEq, Eq)]
257#[repr(u16)]
258pub enum DescriptorType {
259 SetHeaderDescriptor = 0,
261 SubsetHeaderConfiguration = 1,
263 SubsetHeaderFunction = 2,
265 FeatureCompatibleId = 3,
267 FeatureRegProperty = 4,
269 FeatureMinResumeTime = 5,
271 FeatureModelId = 6,
273 FeatureCcgpDevice = 7,
275 FeatureVendorRevision = 8,
277}
278
279#[allow(non_snake_case)]
281#[allow(unused)]
282#[repr(C, packed(1))]
283pub struct DescriptorSetInformation {
284 dwWindowsVersion: u32,
285 wMSOSDescriptorSetTotalLength: u16,
286 bMS_VendorCode: u8,
287 bAltEnumCode: u8,
288}
289
290#[allow(non_snake_case)]
292#[allow(unused)]
293#[repr(C, packed(1))]
294pub struct PlatformDescriptor {
295 bLength: u8,
296 bDescriptorType: u8,
297 bDevCapabilityType: u8,
298 bReserved: u8,
299 platformCapabilityUUID: [u8; 16],
300 descriptor_set_information: DescriptorSetInformation,
301}
302
303#[allow(non_snake_case)]
305#[repr(C, packed(1))]
306pub struct DescriptorSetHeader {
307 wLength: u16,
308 wDescriptorType: u16,
309 dwWindowsVersion: u32,
310 wTotalLength: u16,
311}
312
313impl DescriptorSetHeader {
314 pub fn new(windows_version: u32) -> Self {
318 DescriptorSetHeader {
319 wLength: (size_of::<Self>() as u16).to_le(),
320 wDescriptorType: (Self::TYPE as u16).to_le(),
321 dwWindowsVersion: windows_version.to_le(),
322 wTotalLength: 0,
323 }
324 }
325}
326
327impl Descriptor for DescriptorSetHeader {
328 const TYPE: DescriptorType = DescriptorType::SetHeaderDescriptor;
329 fn write_to(&self, buf: &mut [u8]) {
330 unsafe { transmute_write_to(self, buf) }
331 }
332}
333
334impl DescriptorSet for DescriptorSetHeader {
335 const LENGTH_OFFSET: usize = 8;
336}
337
338#[allow(non_snake_case)]
340#[repr(C, packed(1))]
341pub struct ConfigurationSubsetHeader {
342 wLength: u16,
343 wDescriptorType: u16,
344 bConfigurationValue: u8,
345 bReserved: u8,
346 wTotalLength: u16,
347}
348
349impl ConfigurationSubsetHeader {
350 pub fn new(config: u8) -> Self {
352 ConfigurationSubsetHeader {
353 wLength: (size_of::<Self>() as u16).to_le(),
354 wDescriptorType: (Self::TYPE as u16).to_le(),
355 bConfigurationValue: config,
356 bReserved: 0,
357 wTotalLength: 0,
358 }
359 }
360}
361
362impl Descriptor for ConfigurationSubsetHeader {
363 const TYPE: DescriptorType = DescriptorType::SubsetHeaderConfiguration;
364 fn write_to(&self, buf: &mut [u8]) {
365 unsafe { transmute_write_to(self, buf) }
366 }
367}
368
369impl DescriptorSet for ConfigurationSubsetHeader {
370 const LENGTH_OFFSET: usize = 6;
371}
372
373#[allow(non_snake_case)]
375#[repr(C, packed(1))]
376pub struct FunctionSubsetHeader {
377 wLength: u16,
378 wDescriptorType: u16,
379 bFirstInterface: InterfaceNumber,
380 bReserved: u8,
381 wSubsetLength: u16,
382}
383
384impl FunctionSubsetHeader {
385 pub fn new(first_interface: InterfaceNumber) -> Self {
387 FunctionSubsetHeader {
388 wLength: (size_of::<Self>() as u16).to_le(),
389 wDescriptorType: (Self::TYPE as u16).to_le(),
390 bFirstInterface: first_interface,
391 bReserved: 0,
392 wSubsetLength: 0,
393 }
394 }
395}
396
397impl Descriptor for FunctionSubsetHeader {
398 const TYPE: DescriptorType = DescriptorType::SubsetHeaderFunction;
399 fn write_to(&self, buf: &mut [u8]) {
400 unsafe { transmute_write_to(self, buf) }
401 }
402}
403
404impl DescriptorSet for FunctionSubsetHeader {
405 const LENGTH_OFFSET: usize = 6;
406}
407
408#[allow(private_bounds)]
412pub trait DeviceLevelDescriptor: Descriptor {}
413
414#[allow(private_bounds)]
416pub trait FunctionLevelDescriptor: Descriptor {}
417
418#[allow(non_snake_case)]
420#[repr(C, packed(1))]
421pub struct CompatibleIdFeatureDescriptor {
422 wLength: u16,
423 wDescriptorType: u16,
424 compatibleId: [u8; 8],
425 subCompatibleId: [u8; 8],
426}
427
428impl DeviceLevelDescriptor for CompatibleIdFeatureDescriptor {}
429impl FunctionLevelDescriptor for CompatibleIdFeatureDescriptor {}
430
431impl Descriptor for CompatibleIdFeatureDescriptor {
432 const TYPE: DescriptorType = DescriptorType::FeatureCompatibleId;
433 fn write_to(&self, buf: &mut [u8]) {
434 unsafe { transmute_write_to(self, buf) }
435 }
436}
437
438impl CompatibleIdFeatureDescriptor {
439 pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self {
443 assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8);
444 let mut cid = [0u8; 8];
445 cid[..compatible_id.len()].copy_from_slice(compatible_id.as_bytes());
446 let mut scid = [0u8; 8];
447 scid[..sub_compatible_id.len()].copy_from_slice(sub_compatible_id.as_bytes());
448 Self::new_raw(cid, scid)
449 }
450
451 fn new_raw(compatible_id: [u8; 8], sub_compatible_id: [u8; 8]) -> Self {
452 Self {
453 wLength: (size_of::<Self>() as u16).to_le(),
454 wDescriptorType: (Self::TYPE as u16).to_le(),
455 compatibleId: compatible_id,
456 subCompatibleId: sub_compatible_id,
457 }
458 }
459}
460
461#[allow(non_snake_case)]
463pub struct RegistryPropertyFeatureDescriptor<'a> {
464 name: &'a str,
465 data: PropertyData<'a>,
466}
467
468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
470#[cfg_attr(feature = "defmt", derive(defmt::Format))]
471pub enum PropertyData<'a> {
472 Sz(&'a str),
474 ExpandSz(&'a str),
476 Binary(&'a [u8]),
478 DwordLittleEndian(u32),
480 DwordBigEndian(u32),
482 Link(&'a str),
484 RegMultiSz(&'a [&'a str]),
486}
487
488fn write_bytes(val: &[u8], buf: &mut [u8]) -> usize {
489 assert!(buf.len() >= val.len());
490 buf[..val.len()].copy_from_slice(val);
491 val.len()
492}
493
494fn write_utf16(val: &str, buf: &mut [u8]) -> usize {
495 let mut pos = 0;
496 for c in val.encode_utf16() {
497 pos += write_bytes(&c.to_le_bytes(), &mut buf[pos..]);
498 }
499 pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..])
500}
501
502impl<'a> PropertyData<'a> {
503 pub fn kind(&self) -> PropertyDataType {
505 match self {
506 PropertyData::Sz(_) => PropertyDataType::Sz,
507 PropertyData::ExpandSz(_) => PropertyDataType::ExpandSz,
508 PropertyData::Binary(_) => PropertyDataType::Binary,
509 PropertyData::DwordLittleEndian(_) => PropertyDataType::DwordLittleEndian,
510 PropertyData::DwordBigEndian(_) => PropertyDataType::DwordBigEndian,
511 PropertyData::Link(_) => PropertyDataType::Link,
512 PropertyData::RegMultiSz(_) => PropertyDataType::RegMultiSz,
513 }
514 }
515
516 pub fn size(&self) -> usize {
518 match self {
519 PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => {
520 core::mem::size_of::<u16>() * (val.encode_utf16().count() + 1)
521 }
522 PropertyData::Binary(val) => val.len(),
523 PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val),
524 PropertyData::RegMultiSz(val) => {
525 core::mem::size_of::<u16>() * (val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1)
526 }
527 }
528 }
529
530 pub fn write(&self, buf: &mut [u8]) -> usize {
532 match self {
533 PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => write_utf16(val, buf),
534 PropertyData::Binary(val) => write_bytes(val, buf),
535 PropertyData::DwordLittleEndian(val) => write_bytes(&val.to_le_bytes(), buf),
536 PropertyData::DwordBigEndian(val) => write_bytes(&val.to_be_bytes(), buf),
537 PropertyData::RegMultiSz(val) => {
538 let mut pos = 0;
539 for s in *val {
540 pos += write_utf16(s, &mut buf[pos..]);
541 }
542 pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..])
543 }
544 }
545 }
546}
547
548#[derive(Clone, Copy, PartialEq, Eq)]
550#[repr(u16)]
551pub enum PropertyDataType {
552 Sz = 1,
554 ExpandSz = 2,
556 Binary = 3,
558 DwordLittleEndian = 4,
560 DwordBigEndian = 5,
562 Link = 6,
564 RegMultiSz = 7,
566}
567
568impl<'a> DeviceLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {}
569impl<'a> FunctionLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {}
570
571impl<'a> Descriptor for RegistryPropertyFeatureDescriptor<'a> {
572 const TYPE: DescriptorType = DescriptorType::FeatureRegProperty;
573
574 fn size(&self) -> usize {
575 10 + self.name_size() + self.data.size()
576 }
577
578 fn write_to(&self, buf: &mut [u8]) {
579 assert!(buf.len() >= self.size(), "MS OS descriptor buffer full");
580
581 let mut pos = 0;
582 pos += write_bytes(&(self.size() as u16).to_le_bytes(), &mut buf[pos..]);
583 pos += write_bytes(&(Self::TYPE as u16).to_le_bytes(), &mut buf[pos..]);
584 pos += write_bytes(&(self.data.kind() as u16).to_le_bytes(), &mut buf[pos..]);
585 pos += write_bytes(&(self.name_size() as u16).to_le_bytes(), &mut buf[pos..]);
586 pos += write_utf16(self.name, &mut buf[pos..]);
587 pos += write_bytes(&(self.data.size() as u16).to_le_bytes(), &mut buf[pos..]);
588 self.data.write(&mut buf[pos..]);
589 }
590}
591
592impl<'a> RegistryPropertyFeatureDescriptor<'a> {
593 pub fn new(name: &'a str, data: PropertyData<'a>) -> Self {
595 Self { name, data }
596 }
597
598 fn name_size(&self) -> usize {
599 core::mem::size_of::<u16>() * (self.name.encode_utf16().count() + 1)
600 }
601}
602
603#[allow(non_snake_case)]
605#[repr(C, packed(1))]
606pub struct MinimumRecoveryTimeDescriptor {
607 wLength: u16,
608 wDescriptorType: u16,
609 bResumeRecoveryTime: u8,
610 bResumeSignalingTime: u8,
611}
612
613impl DeviceLevelDescriptor for MinimumRecoveryTimeDescriptor {}
614
615impl Descriptor for MinimumRecoveryTimeDescriptor {
616 const TYPE: DescriptorType = DescriptorType::FeatureMinResumeTime;
617 fn write_to(&self, buf: &mut [u8]) {
618 unsafe { transmute_write_to(self, buf) }
619 }
620}
621
622impl MinimumRecoveryTimeDescriptor {
623 pub fn new(resume_recovery_time: u8, resume_signaling_time: u8) -> Self {
628 assert!(resume_recovery_time <= 10);
629 assert!(resume_signaling_time >= 1 && resume_signaling_time <= 20);
630 Self {
631 wLength: (size_of::<Self>() as u16).to_le(),
632 wDescriptorType: (Self::TYPE as u16).to_le(),
633 bResumeRecoveryTime: resume_recovery_time,
634 bResumeSignalingTime: resume_signaling_time,
635 }
636 }
637}
638
639#[allow(non_snake_case)]
641#[repr(C, packed(1))]
642pub struct ModelIdDescriptor {
643 wLength: u16,
644 wDescriptorType: u16,
645 modelId: [u8; 16],
646}
647
648impl DeviceLevelDescriptor for ModelIdDescriptor {}
649
650impl Descriptor for ModelIdDescriptor {
651 const TYPE: DescriptorType = DescriptorType::FeatureModelId;
652 fn write_to(&self, buf: &mut [u8]) {
653 unsafe { transmute_write_to(self, buf) }
654 }
655}
656
657impl ModelIdDescriptor {
658 pub fn new(model_id: u128) -> Self {
662 Self {
663 wLength: (size_of::<Self>() as u16).to_le(),
664 wDescriptorType: (Self::TYPE as u16).to_le(),
665 modelId: model_id.to_le_bytes(),
666 }
667 }
668}
669
670#[allow(non_snake_case)]
672#[repr(C, packed(1))]
673pub struct CcgpDeviceDescriptor {
674 wLength: u16,
675 wDescriptorType: u16,
676}
677
678impl DeviceLevelDescriptor for CcgpDeviceDescriptor {}
679
680impl Descriptor for CcgpDeviceDescriptor {
681 const TYPE: DescriptorType = DescriptorType::FeatureCcgpDevice;
682 fn write_to(&self, buf: &mut [u8]) {
683 unsafe { transmute_write_to(self, buf) }
684 }
685}
686
687impl CcgpDeviceDescriptor {
688 pub fn new() -> Self {
690 Self {
691 wLength: (size_of::<Self>() as u16).to_le(),
692 wDescriptorType: (Self::TYPE as u16).to_le(),
693 }
694 }
695}
696
697#[allow(non_snake_case)]
699#[repr(C, packed(1))]
700pub struct VendorRevisionDescriptor {
701 wLength: u16,
702 wDescriptorType: u16,
703 VendorRevision: u16,
706}
707
708impl DeviceLevelDescriptor for VendorRevisionDescriptor {}
709impl FunctionLevelDescriptor for VendorRevisionDescriptor {}
710
711impl Descriptor for VendorRevisionDescriptor {
712 const TYPE: DescriptorType = DescriptorType::FeatureVendorRevision;
713 fn write_to(&self, buf: &mut [u8]) {
714 unsafe { transmute_write_to(self, buf) }
715 }
716}
717
718impl VendorRevisionDescriptor {
719 pub fn new(revision: u16) -> Self {
721 assert!(revision >= 1);
722 Self {
723 wLength: (size_of::<Self>() as u16).to_le(),
724 wDescriptorType: (Self::TYPE as u16).to_le(),
725 VendorRevision: revision.to_le(),
726 }
727 }
728}