dap_rs/usb/
winusb.rs

1use num_enum::TryFromPrimitive;
2use usb_device::class_prelude::*;
3use usb_device::control::RequestType;
4
5const fn u16_low(val: u16) -> u8 {
6    val.to_le_bytes()[0]
7}
8
9const fn u16_high(val: u16) -> u8 {
10    val.to_le_bytes()[1]
11}
12
13#[allow(non_snake_case)]
14#[repr(u16)]
15#[derive(TryFromPrimitive)]
16pub enum OSFeatureDescriptorType {
17    CompatibleID = 4,
18    Properties = 5,
19    Descriptor = 7,
20}
21
22const LEN: u16 = 330;
23
24const VENDOR_CODE: u8 = 0x41;
25
26const DAP_V2_INTERFACE: u8 = 3;
27const DFU_INTERFACE: u8 = 4;
28
29enum MsDescriptorTypes {
30    Header = 0x0,
31    HeaderConfiguration = 0x1,
32    HeaderFunction = 0x2,
33    CompatibleId = 0x3,
34    RegistryProperty = 0x4,
35}
36
37/// Microsoft OS 2.0 descriptor, according to https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-os-2-0-descriptors-specification
38///
39/// For interface ['DAP_V2_INTERFACE'] this configures:
40/// - compatible ID 'WinUSB'
41/// - registry property DeviceInterfaceGUIDs = ['{CDB3B5AD-293B-4663-AA36-1AAE46463776}']
42///
43/// For interface ['DFU_INTERFACE']:
44/// - compatible ID 'WinUSB'
45/// - registry property DeviceInterfaceGUIDs = ['{A5DCBF10-6530-11D2-901F-00C04FB951ED}']
46const MS_OS_DESCRIPTOR: [u8; LEN as usize] = [
47    0xa,
48    0x00, // Length 10 bytes
49    MsDescriptorTypes::Header as u8,
50    0x00, // HEADER_DESCRIPTOR
51    0x00,
52    0x00,
53    0x03,
54    0x06, // Windows version
55    u16_low(LEN),
56    u16_high(LEN), // Total descriptor length
57    // Function header,
58    0x8,
59    0x0, // Length 8
60    MsDescriptorTypes::HeaderFunction as u8,
61    0x00,
62    DAP_V2_INTERFACE, // First interface (dap v2)
63    0x0,              // reserved
64    8 + 20 + 132,
65    0x00, // Subset length, including header
66    // compatible ID descriptor
67    20,
68    0x00, // length 20
69    MsDescriptorTypes::CompatibleId as u8,
70    0x00,
71    b'W',
72    b'I',
73    b'N',
74    b'U',
75    b'S',
76    b'B',
77    0x00,
78    0x00, // Compatible ID: 8 bytes ASCII
79    0x00,
80    0x00,
81    0x00,
82    0x00,
83    0x00,
84    0x00,
85    0x00,
86    0x00, // Sub-Compatible ID: 8 bytes ASCII
87    // Registry property
88    80 + 2 + 42 + 2 + 2 + 2 + 2,
89    0x00, // length
90    MsDescriptorTypes::RegistryProperty as u8,
91    0x00,
92    7,
93    0, // Data type: multi sz
94    42,
95    0x00, // property name length,
96    b'D',
97    0,
98    b'e',
99    0,
100    b'v',
101    0,
102    b'i',
103    0,
104    b'c',
105    0,
106    b'e',
107    0,
108    b'I',
109    0,
110    b'n',
111    0,
112    b't',
113    0,
114    b'e',
115    0,
116    b'r',
117    0,
118    b'f',
119    0,
120    b'a',
121    0,
122    b'c',
123    0,
124    b'e',
125    0,
126    b'G',
127    0,
128    b'U',
129    0,
130    b'I',
131    0,
132    b'D',
133    0,
134    b's',
135    0,
136    0,
137    0,
138    80,
139    0x00, // data length
140    b'{',
141    0,
142    b'C',
143    0,
144    b'D',
145    0,
146    b'B',
147    0,
148    b'3',
149    0,
150    b'B',
151    0,
152    b'5',
153    0,
154    b'A',
155    0,
156    b'D',
157    0,
158    b'-',
159    0,
160    b'2',
161    0,
162    b'9',
163    0,
164    b'3',
165    0,
166    b'B',
167    0,
168    b'-',
169    0,
170    b'4',
171    0,
172    b'6',
173    0,
174    b'6',
175    0,
176    b'3',
177    0,
178    b'-',
179    0,
180    b'A',
181    0,
182    b'A',
183    0,
184    b'3',
185    0,
186    b'6',
187    0,
188    b'-',
189    0,
190    b'1',
191    0,
192    b'A',
193    0,
194    b'A',
195    0,
196    b'E',
197    0,
198    b'4',
199    0,
200    b'6',
201    0,
202    b'4',
203    0,
204    b'6',
205    0,
206    b'3',
207    0,
208    b'7',
209    0,
210    b'7',
211    0,
212    b'6',
213    0,
214    b'}',
215    0,
216    0,
217    0,
218    0,
219    0,
220    // Function header,
221    0x8,
222    0x0, // Length 8
223    MsDescriptorTypes::HeaderFunction as u8,
224    0x00,
225    DFU_INTERFACE, // First interface (dap v2 -> 1)
226    0x0,           // reserved
227    8 + 20 + 132,  // Header + compatible ID
228    0x00,          // Subset length, including header
229    // compatible ID descriptor
230    20,
231    0x00, // length 20
232    MsDescriptorTypes::CompatibleId as u8,
233    0x00,
234    b'W',
235    b'I',
236    b'N',
237    b'U',
238    b'S',
239    b'B',
240    0x00,
241    0x00, // Compatible ID: 8 bytes ASCII
242    0x00,
243    0x00,
244    0x00,
245    0x00,
246    0x00,
247    0x00,
248    0x00,
249    0x00, // Sub-Compatible ID: 8 bytes ASCII
250    // Registry property
251    80 + 2 + 42 + 2 + 2 + 2 + 2,
252    0x00, // length
253    MsDescriptorTypes::RegistryProperty as u8,
254    0x00,
255    7,
256    0, // Data type: multi sz
257    42,
258    0x00, // property name length,
259    b'D',
260    0,
261    b'e',
262    0,
263    b'v',
264    0,
265    b'i',
266    0,
267    b'c',
268    0,
269    b'e',
270    0,
271    b'I',
272    0,
273    b'n',
274    0,
275    b't',
276    0,
277    b'e',
278    0,
279    b'r',
280    0,
281    b'f',
282    0,
283    b'a',
284    0,
285    b'c',
286    0,
287    b'e',
288    0,
289    b'G',
290    0,
291    b'U',
292    0,
293    b'I',
294    0,
295    b'D',
296    0,
297    b's',
298    0,
299    0,
300    0,
301    80,
302    0x00, // data length
303    b'{',
304    0,
305    b'A',
306    0,
307    b'5',
308    0,
309    b'D',
310    0,
311    b'C',
312    0,
313    b'B',
314    0,
315    b'F',
316    0,
317    b'1',
318    0,
319    b'0',
320    0,
321    b'-',
322    0,
323    b'6',
324    0,
325    b'5',
326    0,
327    b'3',
328    0,
329    b'0',
330    0,
331    b'-',
332    0,
333    b'1',
334    0,
335    b'1',
336    0,
337    b'D',
338    0,
339    b'2',
340    0,
341    b'-',
342    0,
343    b'9',
344    0,
345    b'0',
346    0,
347    b'1',
348    0,
349    b'F',
350    0,
351    b'-',
352    0,
353    b'0',
354    0,
355    b'0',
356    0,
357    b'C',
358    0,
359    b'0',
360    0,
361    b'4',
362    0,
363    b'F',
364    0,
365    b'B',
366    0,
367    b'9',
368    0,
369    b'5',
370    0,
371    b'1',
372    0,
373    b'E',
374    0,
375    b'D',
376    0,
377    b'}',
378    0,
379    0,
380    0,
381    0,
382    0,
383];
384
385pub struct MicrosoftDescriptors;
386
387impl<B: UsbBus> UsbClass<B> for MicrosoftDescriptors {
388    fn get_bos_descriptors(&self, writer: &mut BosWriter) -> usb_device::Result<()> {
389        writer.capability(
390            5, // Platform capability
391            &[
392                0, // reserved
393                0xdf,
394                0x60,
395                0xdd,
396                0xd8,
397                0x89,
398                0x45,
399                0xc7,
400                0x4c,
401                0x9c,
402                0xd2,
403                0x65,
404                0x9d,
405                0x9e,
406                0x64,
407                0x8A,
408                0x9f, // platform capability UUID , Microsoft OS 2.0 platform compabitility
409                0x00,
410                0x00,
411                0x03,
412                0x06, // Minimum compatible Windows version (8.1)
413                u16_low(LEN),
414                u16_high(LEN), // desciptor set total len ,
415                VENDOR_CODE,
416                0x0, // Device does not support alternate enumeration
417            ],
418        )
419    }
420
421    fn control_in(&mut self, xfer: ControlIn<B>) {
422        let req = xfer.request();
423        if req.request_type != RequestType::Vendor {
424            return;
425        }
426
427        // The Microsoft OS descriptors are requested with the vendor code which
428        // is returned in the BOS descriptor.
429        if req.request == VENDOR_CODE {
430            if req.index == 0x7 {
431                xfer.accept_with_static(&MS_OS_DESCRIPTOR).ok();
432            } else {
433                xfer.reject().ok();
434            }
435        }
436    }
437}