@@ -72,8 +72,11 @@ tusb_desc_device_t const desc_device =
7272{
7373 .bLength = sizeof (tusb_desc_device_t ),
7474 .bDescriptorType = TUSB_DESC_DEVICE ,
75+ #if CFG_TUD_NCM
76+ .bcdUSB = 0x0201 ,
77+ #else
7578 .bcdUSB = 0x0200 ,
76-
79+ #endif
7780 // Use Interface Association Descriptor (IAD) device class
7881 .bDeviceClass = TUSB_CLASS_MISC ,
7982 .bDeviceSubClass = MISC_SUBCLASS_COMMON ,
@@ -188,6 +191,110 @@ uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
188191 return (index < CONFIG_ID_COUNT ) ? configuration_arr [index ] : NULL ;
189192}
190193
194+ #if CFG_TUD_NCM
195+ //--------------------------------------------------------------------+
196+ // BOS Descriptor
197+ //--------------------------------------------------------------------+
198+
199+ /* Used to automatically load the NCM driver on Windows 10, otherwise manual driver install is needed.
200+ Associate NCM interface with WINNCM driver. */
201+
202+ /* Microsoft OS 2.0 registry property descriptor
203+ Per MS requirements https://msdn.microsoft.com/en-us/library/windows/hardware/hh450799(v=vs.85).aspx
204+ device should create DeviceInterfaceGUIDs. It can be done by driver and
205+ in case of real PnP solution device should expose MS "Microsoft OS 2.0
206+ registry property descriptor". Such descriptor can insert any record
207+ into Windows registry per device/configuration/interface. In our case it
208+ will insert "DeviceInterfaceGUIDs" multistring property.
209+
210+ GUID is freshly generated and should be OK to use.
211+
212+ https://developers.google.com/web/fundamentals/native-hardware/build-for-webusb/
213+ (Section Microsoft OS compatibility descriptors)
214+ */
215+
216+ #define BOS_TOTAL_LEN (TUD_BOS_DESC_LEN + TUD_BOS_MICROSOFT_OS_DESC_LEN)
217+
218+ #define MS_OS_20_DESC_LEN 0xB2
219+
220+ // BOS Descriptor is required for webUSB
221+ uint8_t const desc_bos [] =
222+ {
223+ // total length, number of device caps
224+ TUD_BOS_DESCRIPTOR (BOS_TOTAL_LEN , 1 ),
225+
226+ // Microsoft OS 2.0 descriptor
227+ TUD_BOS_MS_OS_20_DESCRIPTOR (MS_OS_20_DESC_LEN , 1 )
228+ };
229+
230+ uint8_t const * tud_descriptor_bos_cb (void )
231+ {
232+ return desc_bos ;
233+ }
234+
235+ uint8_t const desc_ms_os_20 [] =
236+ {
237+ // Set header: length, type, windows version, total length
238+ U16_TO_U8S_LE (0x000A ), U16_TO_U8S_LE (MS_OS_20_SET_HEADER_DESCRIPTOR ), U32_TO_U8S_LE (0x06030000 ), U16_TO_U8S_LE (MS_OS_20_DESC_LEN ),
239+
240+ // Configuration subset header: length, type, configuration index, reserved, configuration total length
241+ U16_TO_U8S_LE (0x0008 ), U16_TO_U8S_LE (MS_OS_20_SUBSET_HEADER_CONFIGURATION ), 0 , 0 , U16_TO_U8S_LE (MS_OS_20_DESC_LEN - 0x0A ),
242+
243+ // Function Subset header: length, type, first interface, reserved, subset length
244+ U16_TO_U8S_LE (0x0008 ), U16_TO_U8S_LE (MS_OS_20_SUBSET_HEADER_FUNCTION ), ITF_NUM_CDC , 0 , U16_TO_U8S_LE (MS_OS_20_DESC_LEN - 0x0A - 0x08 ),
245+
246+ // MS OS 2.0 Compatible ID descriptor: length, type, compatible ID, sub compatible ID
247+ U16_TO_U8S_LE (0x0014 ), U16_TO_U8S_LE (MS_OS_20_FEATURE_COMPATBLE_ID ), 'W' , 'I' , 'N' , 'N' , 'C' , 'M' , 0x00 , 0x00 ,
248+ 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , // sub-compatible
249+
250+ // MS OS 2.0 Registry property descriptor: length, type
251+ U16_TO_U8S_LE (MS_OS_20_DESC_LEN - 0x0A - 0x08 - 0x08 - 0x14 ), U16_TO_U8S_LE (MS_OS_20_FEATURE_REG_PROPERTY ),
252+ U16_TO_U8S_LE (0x0007 ), U16_TO_U8S_LE (0x002A ), // wPropertyDataType, wPropertyNameLength and PropertyName "DeviceInterfaceGUIDs\0" in UTF-16
253+ 'D' , 0x00 , 'e' , 0x00 , 'v' , 0x00 , 'i' , 0x00 , 'c' , 0x00 , 'e' , 0x00 , 'I' , 0x00 , 'n' , 0x00 , 't' , 0x00 , 'e' , 0x00 ,
254+ 'r' , 0x00 , 'f' , 0x00 , 'a' , 0x00 , 'c' , 0x00 , 'e' , 0x00 , 'G' , 0x00 , 'U' , 0x00 , 'I' , 0x00 , 'D' , 0x00 , 's' , 0x00 , 0x00 , 0x00 ,
255+ U16_TO_U8S_LE (0x0050 ), // wPropertyDataLength
256+ //bPropertyData: {12345678-0D08-43FD-8B3E-127CA8AFFF9D}
257+ '{' , 0x00 , '1' , 0x00 , '2' , 0x00 , '3' , 0x00 , '4' , 0x00 , '5' , 0x00 , '6' , 0x00 , '7' , 0x00 , '8' , 0x00 , '-' , 0x00 ,
258+ '0' , 0x00 , 'D' , 0x00 , '0' , 0x00 , '8' , 0x00 , '-' , 0x00 , '4' , 0x00 , '3' , 0x00 , 'F' , 0x00 , 'D' , 0x00 , '-' , 0x00 ,
259+ '8' , 0x00 , 'B' , 0x00 , '3' , 0x00 , 'E' , 0x00 , '-' , 0x00 , '1' , 0x00 , '2' , 0x00 , '7' , 0x00 , 'C' , 0x00 , 'A' , 0x00 ,
260+ '8' , 0x00 , 'A' , 0x00 , 'F' , 0x00 , 'F' , 0x00 , 'F' , 0x00 , '9' , 0x00 , 'D' , 0x00 , '}' , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
261+ };
262+
263+ TU_VERIFY_STATIC (sizeof (desc_ms_os_20 ) == MS_OS_20_DESC_LEN , "Incorrect size" );
264+
265+ // Invoked when a control transfer occurred on an interface of this class
266+ // Driver response accordingly to the request and the transfer stage (setup/data/ack)
267+ // return false to stall control endpoint (e.g unsupported request)
268+ bool tud_vendor_control_xfer_cb (uint8_t rhport , uint8_t stage , tusb_control_request_t const * request ) {
269+ // nothing to with DATA & ACK stage
270+ if (stage != CONTROL_STAGE_SETUP ) return true;
271+
272+ switch (request -> bmRequestType_bit .type ) {
273+ case TUSB_REQ_TYPE_VENDOR :
274+ switch (request -> bRequest ) {
275+ case 1 :
276+ if (request -> wIndex == 7 ) {
277+ // Get Microsoft OS 2.0 compatible descriptor
278+ uint16_t total_len ;
279+ memcpy (& total_len , desc_ms_os_20 + 8 , 2 );
280+
281+ return tud_control_xfer (rhport , request , (void * )(uintptr_t )desc_ms_os_20 , total_len );
282+ } else {
283+ return false;
284+ }
285+
286+ default : break ;
287+ }
288+ break ;
289+
290+ default : break ;
291+ }
292+
293+ // stall unknown request
294+ return false;
295+ }
296+
297+ #endif
191298//--------------------------------------------------------------------+
192299// String Descriptors
193300//--------------------------------------------------------------------+
0 commit comments