1use core::mem::size_of;
6
7use crate::descriptor::{BosWriter, capability_type};
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 self.write(desc);
114 }
115
116 pub fn configuration(&mut self, config: u8) {
118 assert!(
119 !self.is_empty(),
120 "MsOsDescriptorWriter: configuration must be called after header"
121 );
122 Self::end_subset::<ConfigurationSubsetHeader>(self.buf, self.position, &mut self.config_mark);
123 self.config_mark = Some(self.position);
124 self.write(ConfigurationSubsetHeader::new(config));
125 }
126
127 pub fn function(&mut self, first_interface: InterfaceNumber) {
129 assert!(
130 self.config_mark.is_some(),
131 "MsOsDescriptorWriter: function subset requires a configuration subset"
132 );
133 self.end_function();
134 self.function_mark = Some(self.position);
135 self.write(FunctionSubsetHeader::new(first_interface));
136 }
137
138 pub fn function_feature<T: FunctionLevelDescriptor>(&mut self, desc: T) {
143 assert!(
144 self.function_mark.is_some(),
145 "function features may only be added to a function subset"
146 );
147 self.write(desc);
148 }
149
150 pub fn end_function(&mut self) {
152 Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark);
153 }
154
155 fn write<T: Descriptor>(&mut self, desc: T) {
156 desc.write_to(&mut self.buf[self.position..]);
157 self.position += desc.size();
158 }
159
160 fn end_subset<T: DescriptorSet>(buf: &mut [u8], position: usize, mark: &mut Option<usize>) {
161 if let Some(mark) = mark.take() {
162 let len = position - mark;
163 let p = mark + T::LENGTH_OFFSET;
164 buf[p..(p + 2)].copy_from_slice(&(len as u16).to_le_bytes());
165 }
166 }
167
168 fn end(&mut self) {
169 if self.position > 0 {
170 Self::end_subset::<FunctionSubsetHeader>(self.buf, self.position, &mut self.function_mark);
171 Self::end_subset::<ConfigurationSubsetHeader>(self.buf, self.position, &mut self.config_mark);
172 Self::end_subset::<DescriptorSetHeader>(self.buf, self.position, &mut Some(0));
173 }
174 }
175
176 fn write_bos(&mut self, bos: &mut BosWriter) {
177 let windows_version = &self.buf[4..8];
178 let len = (self.position as u16).to_le_bytes();
179 bos.capability(
180 capability_type::PLATFORM,
181 &[
182 0, 0xdf,
185 0x60,
186 0xdd,
187 0xd8,
188 0x89,
189 0x45,
190 0xc7,
191 0x4c,
192 0x9c,
193 0xd2,
194 0x65,
195 0x9d,
196 0x9e,
197 0x64,
198 0x8a,
199 0x9f,
200 windows_version[0],
202 windows_version[1],
203 windows_version[2],
204 windows_version[3],
205 len[0],
207 len[1],
208 self.vendor_code,
209 0x0, ],
211 );
212 }
213}
214
215pub mod windows_version {
219 pub const WIN8_1: u32 = 0x06030000;
221 pub const WIN10: u32 = 0x0A000000;
223}
224
225trait Descriptor: Sized {
227 const TYPE: DescriptorType;
228
229 fn size(&self) -> usize {
231 size_of::<Self>()
232 }
233
234 fn write_to(&self, buf: &mut [u8]);
235}
236
237trait DescriptorSet: Descriptor {
238 const LENGTH_OFFSET: usize;
239}
240
241unsafe fn transmute_write_to<T: Sized>(t: &T, buf: &mut [u8]) {
246 let bytes = core::slice::from_raw_parts((t as *const T) as *const u8, size_of::<T>());
247 assert!(buf.len() >= bytes.len(), "MS OS descriptor buffer full");
248 buf[..bytes.len()].copy_from_slice(bytes);
249}
250
251#[derive(Clone, Copy, PartialEq, Eq)]
253#[repr(u16)]
254pub enum DescriptorType {
255 SetHeaderDescriptor = 0,
257 SubsetHeaderConfiguration = 1,
259 SubsetHeaderFunction = 2,
261 FeatureCompatibleId = 3,
263 FeatureRegProperty = 4,
265 FeatureMinResumeTime = 5,
267 FeatureModelId = 6,
269 FeatureCcgpDevice = 7,
271 FeatureVendorRevision = 8,
273}
274
275#[allow(non_snake_case)]
277#[allow(unused)]
278#[repr(C, packed(1))]
279pub struct DescriptorSetInformation {
280 dwWindowsVersion: u32,
281 wMSOSDescriptorSetTotalLength: u16,
282 bMS_VendorCode: u8,
283 bAltEnumCode: u8,
284}
285
286#[allow(non_snake_case)]
288#[allow(unused)]
289#[repr(C, packed(1))]
290pub struct PlatformDescriptor {
291 bLength: u8,
292 bDescriptorType: u8,
293 bDevCapabilityType: u8,
294 bReserved: u8,
295 platformCapabilityUUID: [u8; 16],
296 descriptor_set_information: DescriptorSetInformation,
297}
298
299#[allow(non_snake_case)]
301#[repr(C, packed(1))]
302pub struct DescriptorSetHeader {
303 wLength: u16,
304 wDescriptorType: u16,
305 dwWindowsVersion: u32,
306 wTotalLength: u16,
307}
308
309impl DescriptorSetHeader {
310 pub fn new(windows_version: u32) -> Self {
314 DescriptorSetHeader {
315 wLength: (size_of::<Self>() as u16).to_le(),
316 wDescriptorType: (Self::TYPE as u16).to_le(),
317 dwWindowsVersion: windows_version.to_le(),
318 wTotalLength: 0,
319 }
320 }
321}
322
323impl Descriptor for DescriptorSetHeader {
324 const TYPE: DescriptorType = DescriptorType::SetHeaderDescriptor;
325 fn write_to(&self, buf: &mut [u8]) {
326 unsafe { transmute_write_to(self, buf) }
327 }
328}
329
330impl DescriptorSet for DescriptorSetHeader {
331 const LENGTH_OFFSET: usize = 8;
332}
333
334#[allow(non_snake_case)]
336#[repr(C, packed(1))]
337pub struct ConfigurationSubsetHeader {
338 wLength: u16,
339 wDescriptorType: u16,
340 bConfigurationValue: u8,
341 bReserved: u8,
342 wTotalLength: u16,
343}
344
345impl ConfigurationSubsetHeader {
346 pub fn new(config: u8) -> Self {
348 ConfigurationSubsetHeader {
349 wLength: (size_of::<Self>() as u16).to_le(),
350 wDescriptorType: (Self::TYPE as u16).to_le(),
351 bConfigurationValue: config,
352 bReserved: 0,
353 wTotalLength: 0,
354 }
355 }
356}
357
358impl Descriptor for ConfigurationSubsetHeader {
359 const TYPE: DescriptorType = DescriptorType::SubsetHeaderConfiguration;
360 fn write_to(&self, buf: &mut [u8]) {
361 unsafe { transmute_write_to(self, buf) }
362 }
363}
364
365impl DescriptorSet for ConfigurationSubsetHeader {
366 const LENGTH_OFFSET: usize = 6;
367}
368
369#[allow(non_snake_case)]
371#[repr(C, packed(1))]
372pub struct FunctionSubsetHeader {
373 wLength: u16,
374 wDescriptorType: u16,
375 bFirstInterface: InterfaceNumber,
376 bReserved: u8,
377 wSubsetLength: u16,
378}
379
380impl FunctionSubsetHeader {
381 pub fn new(first_interface: InterfaceNumber) -> Self {
383 FunctionSubsetHeader {
384 wLength: (size_of::<Self>() as u16).to_le(),
385 wDescriptorType: (Self::TYPE as u16).to_le(),
386 bFirstInterface: first_interface,
387 bReserved: 0,
388 wSubsetLength: 0,
389 }
390 }
391}
392
393impl Descriptor for FunctionSubsetHeader {
394 const TYPE: DescriptorType = DescriptorType::SubsetHeaderFunction;
395 fn write_to(&self, buf: &mut [u8]) {
396 unsafe { transmute_write_to(self, buf) }
397 }
398}
399
400impl DescriptorSet for FunctionSubsetHeader {
401 const LENGTH_OFFSET: usize = 6;
402}
403
404#[allow(private_bounds)]
408pub trait DeviceLevelDescriptor: Descriptor {}
409
410#[allow(private_bounds)]
412pub trait FunctionLevelDescriptor: Descriptor {}
413
414#[allow(non_snake_case)]
416#[repr(C, packed(1))]
417pub struct CompatibleIdFeatureDescriptor {
418 wLength: u16,
419 wDescriptorType: u16,
420 compatibleId: [u8; 8],
421 subCompatibleId: [u8; 8],
422}
423
424impl DeviceLevelDescriptor for CompatibleIdFeatureDescriptor {}
425impl FunctionLevelDescriptor for CompatibleIdFeatureDescriptor {}
426
427impl Descriptor for CompatibleIdFeatureDescriptor {
428 const TYPE: DescriptorType = DescriptorType::FeatureCompatibleId;
429 fn write_to(&self, buf: &mut [u8]) {
430 unsafe { transmute_write_to(self, buf) }
431 }
432}
433
434impl CompatibleIdFeatureDescriptor {
435 pub fn new(compatible_id: &str, sub_compatible_id: &str) -> Self {
439 assert!(compatible_id.len() <= 8 && sub_compatible_id.len() <= 8);
440 let mut cid = [0u8; 8];
441 cid[..compatible_id.len()].copy_from_slice(compatible_id.as_bytes());
442 let mut scid = [0u8; 8];
443 scid[..sub_compatible_id.len()].copy_from_slice(sub_compatible_id.as_bytes());
444 Self::new_raw(cid, scid)
445 }
446
447 fn new_raw(compatible_id: [u8; 8], sub_compatible_id: [u8; 8]) -> Self {
448 Self {
449 wLength: (size_of::<Self>() as u16).to_le(),
450 wDescriptorType: (Self::TYPE as u16).to_le(),
451 compatibleId: compatible_id,
452 subCompatibleId: sub_compatible_id,
453 }
454 }
455}
456
457#[allow(non_snake_case)]
459pub struct RegistryPropertyFeatureDescriptor<'a> {
460 name: &'a str,
461 data: PropertyData<'a>,
462}
463
464#[derive(Debug, Clone, Copy, PartialEq, Eq)]
466#[cfg_attr(feature = "defmt", derive(defmt::Format))]
467pub enum PropertyData<'a> {
468 Sz(&'a str),
470 ExpandSz(&'a str),
472 Binary(&'a [u8]),
474 DwordLittleEndian(u32),
476 DwordBigEndian(u32),
478 Link(&'a str),
480 RegMultiSz(&'a [&'a str]),
482}
483
484fn write_bytes(val: &[u8], buf: &mut [u8]) -> usize {
485 assert!(buf.len() >= val.len());
486 buf[..val.len()].copy_from_slice(val);
487 val.len()
488}
489
490fn write_utf16(val: &str, buf: &mut [u8]) -> usize {
491 let mut pos = 0;
492 for c in val.encode_utf16() {
493 pos += write_bytes(&c.to_le_bytes(), &mut buf[pos..]);
494 }
495 pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..])
496}
497
498impl<'a> PropertyData<'a> {
499 pub fn kind(&self) -> PropertyDataType {
501 match self {
502 PropertyData::Sz(_) => PropertyDataType::Sz,
503 PropertyData::ExpandSz(_) => PropertyDataType::ExpandSz,
504 PropertyData::Binary(_) => PropertyDataType::Binary,
505 PropertyData::DwordLittleEndian(_) => PropertyDataType::DwordLittleEndian,
506 PropertyData::DwordBigEndian(_) => PropertyDataType::DwordBigEndian,
507 PropertyData::Link(_) => PropertyDataType::Link,
508 PropertyData::RegMultiSz(_) => PropertyDataType::RegMultiSz,
509 }
510 }
511
512 pub fn size(&self) -> usize {
514 match self {
515 PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => {
516 core::mem::size_of::<u16>() * (val.encode_utf16().count() + 1)
517 }
518 PropertyData::Binary(val) => val.len(),
519 PropertyData::DwordLittleEndian(val) | PropertyData::DwordBigEndian(val) => core::mem::size_of_val(val),
520 PropertyData::RegMultiSz(val) => {
521 core::mem::size_of::<u16>() * (val.iter().map(|x| x.encode_utf16().count() + 1).sum::<usize>() + 1)
522 }
523 }
524 }
525
526 pub fn write(&self, buf: &mut [u8]) -> usize {
528 match self {
529 PropertyData::Sz(val) | PropertyData::ExpandSz(val) | PropertyData::Link(val) => write_utf16(val, buf),
530 PropertyData::Binary(val) => write_bytes(val, buf),
531 PropertyData::DwordLittleEndian(val) => write_bytes(&val.to_le_bytes(), buf),
532 PropertyData::DwordBigEndian(val) => write_bytes(&val.to_be_bytes(), buf),
533 PropertyData::RegMultiSz(val) => {
534 let mut pos = 0;
535 for s in *val {
536 pos += write_utf16(s, &mut buf[pos..]);
537 }
538 pos + write_bytes(&0u16.to_le_bytes(), &mut buf[pos..])
539 }
540 }
541 }
542}
543
544#[derive(Clone, Copy, PartialEq, Eq)]
546#[repr(u16)]
547pub enum PropertyDataType {
548 Sz = 1,
550 ExpandSz = 2,
552 Binary = 3,
554 DwordLittleEndian = 4,
556 DwordBigEndian = 5,
558 Link = 6,
560 RegMultiSz = 7,
562}
563
564impl<'a> DeviceLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {}
565impl<'a> FunctionLevelDescriptor for RegistryPropertyFeatureDescriptor<'a> {}
566
567impl<'a> Descriptor for RegistryPropertyFeatureDescriptor<'a> {
568 const TYPE: DescriptorType = DescriptorType::FeatureRegProperty;
569
570 fn size(&self) -> usize {
571 10 + self.name_size() + self.data.size()
572 }
573
574 fn write_to(&self, buf: &mut [u8]) {
575 assert!(buf.len() >= self.size(), "MS OS descriptor buffer full");
576
577 let mut pos = 0;
578 pos += write_bytes(&(self.size() as u16).to_le_bytes(), &mut buf[pos..]);
579 pos += write_bytes(&(Self::TYPE as u16).to_le_bytes(), &mut buf[pos..]);
580 pos += write_bytes(&(self.data.kind() as u16).to_le_bytes(), &mut buf[pos..]);
581 pos += write_bytes(&(self.name_size() as u16).to_le_bytes(), &mut buf[pos..]);
582 pos += write_utf16(self.name, &mut buf[pos..]);
583 pos += write_bytes(&(self.data.size() as u16).to_le_bytes(), &mut buf[pos..]);
584 self.data.write(&mut buf[pos..]);
585 }
586}
587
588impl<'a> RegistryPropertyFeatureDescriptor<'a> {
589 pub fn new(name: &'a str, data: PropertyData<'a>) -> Self {
591 Self { name, data }
592 }
593
594 fn name_size(&self) -> usize {
595 core::mem::size_of::<u16>() * (self.name.encode_utf16().count() + 1)
596 }
597}
598
599#[allow(non_snake_case)]
601#[repr(C, packed(1))]
602pub struct MinimumRecoveryTimeDescriptor {
603 wLength: u16,
604 wDescriptorType: u16,
605 bResumeRecoveryTime: u8,
606 bResumeSignalingTime: u8,
607}
608
609impl DeviceLevelDescriptor for MinimumRecoveryTimeDescriptor {}
610
611impl Descriptor for MinimumRecoveryTimeDescriptor {
612 const TYPE: DescriptorType = DescriptorType::FeatureMinResumeTime;
613 fn write_to(&self, buf: &mut [u8]) {
614 unsafe { transmute_write_to(self, buf) }
615 }
616}
617
618impl MinimumRecoveryTimeDescriptor {
619 pub fn new(resume_recovery_time: u8, resume_signaling_time: u8) -> Self {
624 assert!(resume_recovery_time <= 10);
625 assert!(resume_signaling_time >= 1 && resume_signaling_time <= 20);
626 Self {
627 wLength: (size_of::<Self>() as u16).to_le(),
628 wDescriptorType: (Self::TYPE as u16).to_le(),
629 bResumeRecoveryTime: resume_recovery_time,
630 bResumeSignalingTime: resume_signaling_time,
631 }
632 }
633}
634
635#[allow(non_snake_case)]
637#[repr(C, packed(1))]
638pub struct ModelIdDescriptor {
639 wLength: u16,
640 wDescriptorType: u16,
641 modelId: [u8; 16],
642}
643
644impl DeviceLevelDescriptor for ModelIdDescriptor {}
645
646impl Descriptor for ModelIdDescriptor {
647 const TYPE: DescriptorType = DescriptorType::FeatureModelId;
648 fn write_to(&self, buf: &mut [u8]) {
649 unsafe { transmute_write_to(self, buf) }
650 }
651}
652
653impl ModelIdDescriptor {
654 pub fn new(model_id: u128) -> Self {
658 Self {
659 wLength: (size_of::<Self>() as u16).to_le(),
660 wDescriptorType: (Self::TYPE as u16).to_le(),
661 modelId: model_id.to_le_bytes(),
662 }
663 }
664}
665
666#[allow(non_snake_case)]
668#[repr(C, packed(1))]
669pub struct CcgpDeviceDescriptor {
670 wLength: u16,
671 wDescriptorType: u16,
672}
673
674impl DeviceLevelDescriptor for CcgpDeviceDescriptor {}
675
676impl Descriptor for CcgpDeviceDescriptor {
677 const TYPE: DescriptorType = DescriptorType::FeatureCcgpDevice;
678 fn write_to(&self, buf: &mut [u8]) {
679 unsafe { transmute_write_to(self, buf) }
680 }
681}
682
683impl CcgpDeviceDescriptor {
684 pub fn new() -> Self {
686 Self {
687 wLength: (size_of::<Self>() as u16).to_le(),
688 wDescriptorType: (Self::TYPE as u16).to_le(),
689 }
690 }
691}
692
693#[allow(non_snake_case)]
695#[repr(C, packed(1))]
696pub struct VendorRevisionDescriptor {
697 wLength: u16,
698 wDescriptorType: u16,
699 VendorRevision: u16,
702}
703
704impl DeviceLevelDescriptor for VendorRevisionDescriptor {}
705impl FunctionLevelDescriptor for VendorRevisionDescriptor {}
706
707impl Descriptor for VendorRevisionDescriptor {
708 const TYPE: DescriptorType = DescriptorType::FeatureVendorRevision;
709 fn write_to(&self, buf: &mut [u8]) {
710 unsafe { transmute_write_to(self, buf) }
711 }
712}
713
714impl VendorRevisionDescriptor {
715 pub fn new(revision: u16) -> Self {
717 assert!(revision >= 1);
718 Self {
719 wLength: (size_of::<Self>() as u16).to_le(),
720 wDescriptorType: (Self::TYPE as u16).to_le(),
721 VendorRevision: revision.to_le(),
722 }
723 }
724}