xref: /btstack/platform/windows/hci_transport_h2_winusb.c (revision d43fe610a00629e57536be68513fb5cf1c8d3a85)
1 /*
2  * Copyright (C) 2014 BlueKitchen GmbH
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the copyright holders nor the names of
14  *    contributors may be used to endorse or promote products derived
15  *    from this software without specific prior written permission.
16  * 4. Any redistribution, use, or modification is done solely for
17  *    personal benefit and not for any commercial purpose or for
18  *    monetary gain.
19  *
20  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
24  * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * Please inquire about commercial licensing options at
34  * [email protected]
35  *
36  */
37 
38 /*
39  *  hci_transport_usb.c
40  *
41  *  HCI Transport API implementation for USB
42  *
43  *  Created by Matthias Ringwald on 7/5/09.
44  */
45 
46 // Interface Number - Alternate Setting - suggested Endpoint Address - Endpoint Type - Suggested Max Packet Size
47 // HCI Commands 0 0 0x00 Control 8/16/32/64
48 // HCI Events   0 0 0x81 Interrupt (IN) 16
49 // ACL Data     0 0 0x82 Bulk (IN) 32/64
50 // ACL Data     0 0 0x02 Bulk (OUT) 32/64
51 // SCO Data     0 0 0x83 Isochronous (IN)
52 // SCO Data     0 0 0x03 Isochronous (Out)
53 
54 #include <stdio.h>
55 #include <strings.h>
56 #include <string.h>
57 #include <unistd.h>   /* UNIX standard function definitions */
58 #include <sys/types.h>
59 #include <inttypes.h>   // to print long long int (aka 64 bit ints)
60 
61 #include "btstack_config.h"
62 
63 #include "btstack_debug.h"
64 #include "hci.h"
65 #include "hci_transport.h"
66 
67 #include <Windows.h>
68 #include <SetupAPI.h>
69 #include <Winusb.h>
70 
71 #ifdef ENABLE_SCO_OVER_HCI
72 
73 // Isochronous Add-On
74 
75 // Function signatures frome https://abi-laboratory.pro/compatibility/Windows_7.0_to_Windows_8.1/x86_64/info/winusb.dll/symbols.html
76 // MSDN documentation has multiple errors (Jan 2017), annotated below
77 
78 typedef PVOID WINUSB_ISOCH_BUFFER_HANDLE, *PWINUSB_ISOCH_BUFFER_HANDLE;
79 
80 typedef struct _WINUSB_PIPE_INFORMATION_EX {
81   USBD_PIPE_TYPE PipeType;
82   UCHAR          PipeId;
83   USHORT         MaximumPacketSize;
84   UCHAR          Interval;
85   ULONG          MaximumBytesPerInterval;
86 } WINUSB_PIPE_INFORMATION_EX, *PWINUSB_PIPE_INFORMATION_EX;
87 
88 typedef WINBOOL (WINAPI * WinUsb_QueryPipeEx_t) (
89 	WINUSB_INTERFACE_HANDLE 	InterfaceHandle,
90 	UCHAR						AlternateInterfaceNumber,
91 	UCHAR 						PipeIndex,
92 	PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
93 );
94 typedef WINBOOL (WINAPI * WinUsb_RegisterIsochBuffer_t)(
95 	WINUSB_INTERFACE_HANDLE     InterfaceHandle,
96 	UCHAR                       PipeID,
97 	PVOID                       Buffer,
98 	ULONG                       BufferLength,
99 	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
100 );
101 typedef WINBOOL (WINAPI * WinUsb_ReadIsochPipe_t)(
102     PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
103     ULONG                       Offset,
104     ULONG                       Length,
105     PULONG                      FrameNumber,
106     ULONG                       NumberOfPackets,        // MSDN lists PULONG
107     PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,   // MSDN lists PULONG
108     LPOVERLAPPED                Overlapped
109 );
110 typedef WINBOOL (WINAPI * WinUsb_ReadIsochPipeAsap_t)(
111     PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
112     ULONG                       Offset,
113     ULONG                       Length,
114     BOOL                        ContinueStream,
115     ULONG                      	NumberOfPackets,        // MSDN lists PULONG
116     PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
117  	LPOVERLAPPED                Overlapped
118 );
119 typedef WINBOOL (WINAPI * WinUsb_WriteIsochPipe_t)(
120     PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
121     ULONG                       Offset,
122     ULONG                       Length,
123     PULONG                      FrameNumber,
124 	LPOVERLAPPED                Overlapped
125 );
126 typedef WINBOOL (WINAPI * WinUsb_WriteIsochPipeAsap_t)(
127     PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
128     ULONG                       Offset,
129     ULONG                       Length,
130     BOOL                        ContinueStream,
131 	LPOVERLAPPED                Overlapped
132 );
133 typedef WINBOOL (WINAPI * WinUsb_UnregisterIsochBuffer_t)(
134 	PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
135 );
136 typedef WINBOOL (WINAPI * WinUsb_GetCurrentFrameNumber_t)(
137     WINUSB_INTERFACE_HANDLE     InterfaceHandle,        // MSDN lists 'Device handle returned from CreateFile'
138     PULONG                      CurrentFrameNumber,
139     LARGE_INTEGER               *TimeStamp
140 );
141 
142 static WinUsb_QueryPipeEx_t 			WinUsb_QueryPipeEx;
143 static WinUsb_RegisterIsochBuffer_t 	WinUsb_RegisterIsochBuffer;
144 static WinUsb_ReadIsochPipe_t 			WinUsb_ReadIsochPipe;
145 static WinUsb_ReadIsochPipeAsap_t 		WinUsb_ReadIsochPipeAsap;
146 static WinUsb_WriteIsochPipe_t 			WinUsb_WriteIsochPipe;
147 static WinUsb_WriteIsochPipeAsap_t 		WinUsb_WriteIsochPipeAsap;
148 static WinUsb_UnregisterIsochBuffer_t 	WinUsb_UnregisterIsochBuffer;
149 static WinUsb_GetCurrentFrameNumber_t   WinUsb_GetCurrentFrameNumber;
150 #endif
151 
152 // Doesn't work as expected
153 // #define SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
154 
155 // Not tested yet
156 // #define SCHEDULE_SCO_OUT_TRANSFERS_MANUALLY
157 
158 //
159 // Bluetooth USB Transport Alternate Settings:
160 //
161 // 0: No active voice channels (for USB compliance)
162 // 1: One 8 kHz voice channel with 8-bit encoding
163 // 2: Two 8 kHz voice channels with 8-bit encoding or one 8 kHz voice channel with 16-bit encoding
164 // 3: Three 8 kHz voice channels with 8-bit encoding
165 // 4: Two 8 kHz voice channels with 16-bit encoding or one 16 kHz voice channel with 16-bit encoding
166 // 5: Three 8 kHz voice channels with 16-bit encoding or one 8 kHz voice channel with 16-bit encoding and one 16 kHz voice channel with 16-bit encoding
167 // --> support only a single SCO connection
168 #define ALT_SETTING (1)
169 
170 // for ALT_SETTING >= 1 and 8-bit channel, we need the following isochronous packets
171 // One complete SCO packet with 24 frames every 3 frames (== 3 ms)
172 #define NUM_ISO_PACKETS (3)
173 
174 // results in 9 bytes per frame
175 #define ISO_PACKET_SIZE (9)
176 
177 // 49 bytes is the max usb packet size for alternate setting 5 (Three 8 kHz 16-bit channels or one 8 kHz 16-bit channel and one 16 kHz 16-bit channel)
178 // note: alt setting 6 has max packet size of 63 every 7.5 ms = 472.5 bytes / HCI packet, while max SCO packet has 255 byte payload
179 #define SCO_PACKET_SIZE (NUM_ISO_PACKETS * ISO_PACKET_SIZE)
180 
181 #define ISOC_BUFFERS   8
182 
183 // Outgoing SCO packet queue
184 // simplified ring buffer implementation
185 #define SCO_RING_BUFFER_COUNT  (20)
186 #define SCO_RING_BUFFER_SIZE (SCO_RING_BUFFER_COUNT * SCO_PACKET_SIZE)
187 
188 /** Request type bits of the "bmRequestType" field in control transfers. */
189 enum usb_request_type {
190 	USB_REQUEST_TYPE_STANDARD = (0x00 << 5),
191 	USB_REQUEST_TYPE_CLASS = (0x01 << 5),
192 	USB_REQUEST_TYPE_VENDOR = (0x02 << 5),
193 };
194 
195 /** Recipient bits of the "bmRequestType" field in control transfers. Values 4 through 31 are reserved. */
196 enum usb_request_recipient {
197 	USB_RECIPIENT_DEVICE = 0x00,
198 	USB_RECIPIENT_INTERFACE = 0x01,
199 	USB_RECIPIENT_ENDPOINT = 0x02,
200 	USB_RECIPIENT_OTHER = 0x03,
201 };
202 
203 // This is the GUID for the USB device class
204 static GUID GUID_DEVINTERFACE_USB_DEVICE =
205 { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
206 
207 static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
208 
209 static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = &usb_dummy_handler;
210 
211 // endpoint addresses
212 static int event_in_addr;
213 static int acl_in_addr;
214 static int acl_out_addr;
215 static int sco_in_addr;
216 static int sco_out_addr;
217 
218 //
219 static HANDLE usb_device_handle;
220 static WINUSB_INTERFACE_HANDLE usb_interface_0_handle;
221 static WINUSB_INTERFACE_HANDLE usb_interface_1_handle;
222 static OVERLAPPED usb_overlapped_event_in;
223 static OVERLAPPED usb_overlapped_command_out;
224 static OVERLAPPED usb_overlapped_acl_in;
225 static OVERLAPPED usb_overlapped_acl_out;
226 static btstack_data_source_t usb_data_source_event_in;
227 static btstack_data_source_t usb_data_source_command_out;
228 static btstack_data_source_t usb_data_source_acl_in;
229 static btstack_data_source_t usb_data_source_acl_out;
230 
231 //
232 static int usb_command_out_active;
233 static int usb_acl_out_active;
234 
235 // buffer for HCI Events and ACL Packets
236 static uint8_t hci_event_in_buffer[2 + 255];
237 static uint8_t hci_acl_in_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_ACL_BUFFER_SIZE];
238 
239 
240 #ifdef ENABLE_SCO_OVER_HCI
241 
242 typedef enum {
243     H2_W4_SCO_HEADER = 1,
244     H2_W4_PAYLOAD,
245 } H2_SCO_STATE;
246 
247 // SCO Incoming Windows
248 static uint8_t hci_sco_in_buffer[ISOC_BUFFERS * SCO_PACKET_SIZE];
249 static WINUSB_ISOCH_BUFFER_HANDLE hci_sco_in_buffer_handle;
250 static USBD_ISO_PACKET_DESCRIPTOR hci_sco_packet_descriptors[ISOC_BUFFERS * NUM_ISO_PACKETS];
251 static OVERLAPPED usb_overlapped_sco_in[ISOC_BUFFERS];
252 static int usb_sco_in_expected_transfer;
253 
254 // SCO Incoming Run Loop
255 static btstack_data_source_t usb_data_source_sco_in[ISOC_BUFFERS];
256 
257 // SCO Incoming HCI
258 static H2_SCO_STATE sco_state;
259 static uint8_t  sco_buffer[SCO_PACKET_SIZE];
260 static uint16_t sco_read_pos;
261 static uint16_t sco_bytes_to_read;
262 
263 // SCO Outgoing Windows
264 static WINUSB_ISOCH_BUFFER_HANDLE hci_sco_out_buffer_handle;
265 static OVERLAPPED usb_overlapped_sco_out[SCO_RING_BUFFER_COUNT];
266 static int        sco_ring_transfers_active;
267 static int        usb_sco_out_expected_transfer;
268 
269 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
270 // next tranfer
271 static ULONG sco_next_transfer_at_frame;
272 #endif
273 
274 // SCO Outgoing Run Loop
275 static btstack_data_source_t usb_data_source_sco_out[SCO_RING_BUFFER_COUNT];
276 
277 // SCO Outgoing HCI
278 static uint8_t  sco_ring_buffer[SCO_RING_BUFFER_SIZE];
279 static int      sco_ring_write;  // packet idx
280 
281 #endif
282 
283 #if 0
284 // list of known devices, using VendorID/ProductID tuples
285 static const uint16_t known_bluetooth_devices[] = {
286     // DeLOCK Bluetooth 4.0
287     0x0a5c, 0x21e8,
288     // Asus BT400
289     0x0b05, 0x17cb,
290 };
291 
292 static int num_known_devices = sizeof(known_bluetooth_devices) / sizeof(uint16_t) / 2;
293 
294 static int usb_is_known_bluetooth_device(uint16_t vendor_id, uint16_t product_id){
295     int i;
296     for (i=0; i<num_known_devices; i++){
297         if (known_bluetooth_devices[i*2] == vendor_id && known_bluetooth_devices[i*2+1] == product_id){
298             return 1;
299         }
300     }
301     return 0;
302 }
303 #endif
304 
305 #ifdef ENABLE_SCO_OVER_HCI
306 static void sco_ring_init(void){
307     sco_ring_write = 0;
308     sco_ring_transfers_active = 0;
309 }
310 static int sco_ring_have_space(void){
311     return sco_ring_transfers_active < SCO_RING_BUFFER_COUNT;
312 }
313 #endif
314 
315 static void usb_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
316     log_info("registering packet handler");
317     packet_handler = handler;
318 }
319 
320 static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
321 }
322 
323 static void usb_init(const void *transport_config){
324 }
325 
326 static void usb_free_resources(void){
327 	if (usb_interface_1_handle){
328 		WinUsb_Free(usb_interface_1_handle);
329 		usb_interface_1_handle = NULL;
330 	}
331 
332 	if (usb_interface_0_handle){
333 		WinUsb_Free(usb_interface_0_handle);
334 		usb_interface_0_handle = NULL;
335 	}
336 
337 	if (usb_device_handle) {
338 		CloseHandle(usb_device_handle);
339 		usb_device_handle = NULL;
340 	}
341 
342 #ifdef ENABLE_SCO_OVER_HCI
343     if (hci_sco_in_buffer_handle){
344         WinUsb_UnregisterIsochBuffer(hci_sco_in_buffer_handle);
345         hci_sco_in_buffer_handle = NULL;
346     }
347     if (hci_sco_out_buffer_handle){
348         WinUsb_UnregisterIsochBuffer(hci_sco_out_buffer_handle);
349         hci_sco_out_buffer_handle = NULL;
350     }
351 #endif
352 }
353 
354 static void usb_submit_event_in_transfer(void){
355 	// submit transfer
356 	BOOL result = WinUsb_ReadPipe(usb_interface_0_handle, event_in_addr, hci_event_in_buffer, sizeof(hci_event_in_buffer), NULL, &usb_overlapped_event_in);
357 	if (!result) {
358 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
359 	}
360 
361     // IO_PENDING -> wait for completed
362     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_event_in, DATA_SOURCE_CALLBACK_READ);
363     return;
364 
365 exit_on_error:
366 	log_error("usb_submit_event_in_transfer: winusb last error %lu", GetLastError());
367 }
368 
369 static void usb_submit_acl_in_transfer(void){
370 	// submit transfer
371 	BOOL result = WinUsb_ReadPipe(usb_interface_0_handle, acl_in_addr, hci_acl_in_buffer, sizeof(hci_acl_in_buffer), NULL, &usb_overlapped_acl_in);
372 	if (!result) {
373 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
374 	}
375 
376     // IO_PENDING -> wait for completed
377     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_in, DATA_SOURCE_CALLBACK_READ);
378     return;
379 
380 exit_on_error:
381 	log_error("usb_submit_acl_in_transfer: winusb last error %lu", GetLastError());
382 }
383 
384 #ifdef ENABLE_SCO_OVER_HCI
385 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
386 
387 // frame number gets updated
388 static void usb_submit_sco_in_transfer_at_frame(int i, ULONG * frame_number){
389 
390     LARGE_INTEGER timestamp;
391     ULONG current_frame_number;
392     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
393 
394     ULONG frame_before = *frame_number;
395 
396     BOOL result = WinUsb_ReadIsochPipe(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, SCO_PACKET_SIZE,
397         frame_number, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
398 
399     log_info("WinUsb_ReadIsochPipe #%02u: current %lu, planned %lu - buffer %lu", i, current_frame_number, frame_before, frame_before - current_frame_number);
400 
401     if (!result) {
402         if (GetLastError() == ERROR_IO_PENDING) {
403         } else {
404             goto exit_on_error;
405         }
406     }
407 
408     return;
409 
410 exit_on_error:
411     log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
412 }
413 
414 #else
415 
416 static void usb_submit_sco_in_transfer_asap(int i, int continue_stream){
417 
418     LARGE_INTEGER timestamp;
419     ULONG current_frame_number;
420     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
421 
422     // log_info("usb_submit_sco_in_transfer[%02u]: current frame %lu", i, current_frame_number);
423 
424     BOOL result = WinUsb_ReadIsochPipeAsap(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, SCO_PACKET_SIZE,
425         continue_stream, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
426 
427     if (!result) {
428         if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
429     }
430 
431     return;
432 
433 exit_on_error:
434     log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
435 }
436 #endif
437 #endif
438 
439 static void usb_process_event_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
440 
441     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
442 
443     DWORD bytes_read;
444     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_event_in, &bytes_read, FALSE);
445     if(!ok){
446         DWORD err = GetLastError();
447         if (err == ERROR_IO_INCOMPLETE){
448             // IO_INCOMPLETE -> wait for completed
449             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
450         } else {
451             log_error("usb_process_event_in: error reading");
452         }
453         return;
454     }
455 
456     // notify uppper
457     packet_handler(HCI_EVENT_PACKET, hci_event_in_buffer, bytes_read);
458 
459 	// re-submit transfer
460 	usb_submit_event_in_transfer();
461 }
462 
463 static void usb_process_acl_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
464 
465     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
466 
467     DWORD bytes_read;
468     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_acl_in, &bytes_read, FALSE);
469     if(!ok){
470         DWORD err = GetLastError();
471         if (err == ERROR_IO_INCOMPLETE){
472             // IO_INCOMPLETE -> wait for completed
473             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
474         } else {
475             log_error("usb_process_acl_in: error writing");
476         }
477         return;
478     }
479 
480     // notify uppper
481     packet_handler(HCI_ACL_DATA_PACKET, hci_acl_in_buffer, bytes_read);
482 
483 	// re-submit transfer
484 	usb_submit_acl_in_transfer();
485 }
486 
487 #ifdef ENABLE_SCO_OVER_HCI
488 static void sco_state_machine_init(void){
489     sco_state = H2_W4_SCO_HEADER;
490     sco_read_pos = 0;
491     sco_bytes_to_read = 3;
492 }
493 
494 static void sco_handle_data(uint8_t * buffer, uint16_t size){
495 	// printf("sco_handle_data: state %u, pos %u, to read %u, size %u", sco_state, sco_read_pos, sco_bytes_to_read, size);
496     while (size){
497         if (size < sco_bytes_to_read){
498             // just store incomplete data
499             memcpy(&sco_buffer[sco_read_pos], buffer, size);
500             sco_read_pos      += size;
501             sco_bytes_to_read -= size;
502             return;
503         }
504         // copy requested data
505         memcpy(&sco_buffer[sco_read_pos], buffer, sco_bytes_to_read);
506         sco_read_pos += sco_bytes_to_read;
507         buffer       += sco_bytes_to_read;
508         size         -= sco_bytes_to_read;
509 
510         // chunk read successfully, next action
511         switch (sco_state){
512             case H2_W4_SCO_HEADER:
513                 sco_state = H2_W4_PAYLOAD;
514                 sco_bytes_to_read = sco_buffer[2];
515                 if (sco_bytes_to_read > (sizeof(sco_buffer)-3)){
516                 	log_error("sco_handle_data: sco packet len > packet size");
517 	                sco_state_machine_init();
518                 }
519                 break;
520             case H2_W4_PAYLOAD:
521                 // packet complete
522                 packet_handler(HCI_SCO_DATA_PACKET, sco_buffer, sco_read_pos);
523                 sco_state_machine_init();
524                 break;
525         }
526     }
527 }
528 
529 static void usb_process_sco_out(btstack_data_source_t *ds,  btstack_data_source_callback_type_t callback_type){
530 
531     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
532 
533     // get current frame number
534     ULONG current_frame_number;
535     LARGE_INTEGER timestamp;
536     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
537 
538     // find index
539     int transfer_index;
540     for (transfer_index=0;transfer_index<SCO_RING_BUFFER_COUNT;transfer_index++){
541         if (ds == &usb_data_source_sco_out[transfer_index]) break;
542     }
543 
544     log_info("usb_process_sco_out[%02u] -- current frame %lu", transfer_index, current_frame_number);
545 
546     DWORD bytes_transferred;
547     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_out[transfer_index], &bytes_transferred, FALSE);
548     log_info("usb_process_sco_out_done: #%u result %u, bytes %u, state %u", transfer_index, ok, (int) bytes_transferred, sco_state);
549     if(!ok){
550         DWORD err = GetLastError();
551         if (err == ERROR_IO_INCOMPLETE){
552             // IO_INCOMPLETE -> wait for completed
553             btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
554             return;
555         }
556         log_error("usb_process_sco_out_done[%02u]: error writing %u, Internal %x", transfer_index, (int) err, (int) usb_overlapped_sco_out[transfer_index].Internal);
557     }
558 
559     // decrease tab
560     sco_ring_transfers_active--;
561 
562     // enable next data source callback
563     if (sco_ring_transfers_active){
564         // update expected and wait for completion
565         usb_sco_out_expected_transfer = (transfer_index+ 1) % SCO_RING_BUFFER_COUNT;
566         log_info("usb_process_sco_out_done[%02u]: wait for transfer %02u", transfer_index, usb_sco_out_expected_transfer);
567         btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[usb_sco_out_expected_transfer], DATA_SOURCE_CALLBACK_WRITE);
568     }
569 
570     log_info("usb_process_sco_out_done: transfers active %u", sco_ring_transfers_active);
571 
572     // mark free
573     if (sco_ring_have_space()) {
574         uint8_t event[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
575         packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
576     }
577 }
578 
579 static void usb_process_sco_in(btstack_data_source_t *ds,  btstack_data_source_callback_type_t callback_type){
580 
581     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
582 
583 
584     // find index
585     int i;
586     for (i=0;i<ISOC_BUFFERS;i++){
587         if (ds == &usb_data_source_sco_in[i]) break;
588     }
589     int transfer_index = i;
590 
591     // ULONG current_frame_number;
592     // LARGE_INTEGER timestamp;
593     // WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
594 
595     // log_info("usb_process_sco_in[%02u] -- current frame %lu", transfer_index, current_frame_number);
596 
597     DWORD bytes_transferred;
598     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_in[transfer_index], &bytes_transferred, FALSE);
599 
600     if(!ok) {
601         DWORD err = GetLastError();
602         if (err == ERROR_IO_INCOMPLETE) {
603             // IO_INCOMPLETE -> wait for completed
604             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
605             return;
606         }
607         log_error("usb_process_sco_in[%02u]: error reading %u, Internal %x", transfer_index, (int) err, (int) usb_overlapped_sco_out[i].Internal);
608     }
609 
610     if (ok){
611         for (i=0;i<NUM_ISO_PACKETS;i++){
612             USBD_ISO_PACKET_DESCRIPTOR * packet_descriptor = &hci_sco_packet_descriptors[transfer_index * NUM_ISO_PACKETS + i];
613             if (packet_descriptor->Length){
614                 uint8_t * iso_data = &hci_sco_in_buffer[transfer_index * SCO_PACKET_SIZE + packet_descriptor->Offset];
615                 uint16_t  iso_len  = packet_descriptor->Length;
616                 sco_handle_data(iso_data, iso_len);
617             }
618         }
619     }
620 
621 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
622     usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
623 #else
624     usb_submit_sco_in_transfer_asap(transfer_index, 1);
625 #endif
626     // update expected and wait for completion
627     usb_sco_in_expected_transfer = (transfer_index+ 1) % ISOC_BUFFERS;
628 
629     // log_info("usb_process_sco_in[%02u]: enable data source %02u", transfer_index, usb_sco_in_expected_transfer);
630     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
631 }
632 #endif
633 
634 static void usb_process_command_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
635 
636     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
637 
638     // update stata before submitting transfer
639     usb_command_out_active = 0;
640 
641     // notify upper stack that provided buffer can be used again
642     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
643     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
644 }
645 
646 static void usb_process_acl_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
647 
648     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
649 
650     // update stata before submitting transfer
651     usb_acl_out_active = 0;
652 
653     // notify upper stack that provided buffer can be used again
654     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
655     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
656 }
657 
658 static BOOL usb_scan_for_bluetooth_endpoints(void) {
659     int i;
660     USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
661 
662     // reset
663     event_in_addr = 0;
664     acl_in_addr = 0;
665     acl_out_addr = 0;
666 
667     log_info("Scanning USB Entpoints:");
668 
669     // look for Event and ACL pipes on Interface #0
670     BOOL result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
671     if (!result) goto exit_on_error;
672     for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
673         WINUSB_PIPE_INFORMATION pipe;
674         result = WinUsb_QueryPipe(
675                      usb_interface_0_handle,
676                      0,
677                      (UCHAR) i,
678                      &pipe);
679         if (!result) goto exit_on_error;
680         log_info("Interface #0, Alt #0, Pipe idx #%u: type %u, id 0x%02x, max packet size %u,",
681             i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize);
682         switch (pipe.PipeType){
683             case USB_ENDPOINT_TYPE_INTERRUPT:
684                 if (event_in_addr) continue;
685                 event_in_addr = pipe.PipeId;
686                 log_info("-> using 0x%2.2X for HCI Events", event_in_addr);
687                 break;
688             case USB_ENDPOINT_TYPE_BULK:
689                 if (pipe.PipeId & 0x80) {
690                     if (acl_in_addr) continue;
691                     acl_in_addr = pipe.PipeId;
692                     log_info("-> using 0x%2.2X for ACL Data In", acl_in_addr);
693                 } else {
694                     if (acl_out_addr) continue;
695                     acl_out_addr = pipe.PipeId;
696                     log_info("-> using 0x%2.2X for ACL Data Out", acl_out_addr);
697                 }
698                 break;
699             default:
700                 break;
701         }
702     }
703 
704 #ifdef ENABLE_SCO_OVER_HCI
705     sco_out_addr = 0;
706     sco_in_addr = 0;
707 
708     // look for SCO pipes on Interface #1, Alt Setting ALT_SETTING
709     result = WinUsb_QueryInterfaceSettings(usb_interface_1_handle, ALT_SETTING, &usb_interface_descriptor);
710     if (!result) goto exit_on_error;
711     for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
712         WINUSB_PIPE_INFORMATION_EX pipe;
713         result = WinUsb_QueryPipeEx(
714                      usb_interface_1_handle,
715                      ALT_SETTING,
716                      (UCHAR) i,
717                      &pipe);
718         if (!result) goto exit_on_error;
719         log_info("Interface #1, Alt #%u, Pipe idx #%u: type %u, id 0x%02x, max packet size %u, interval %u, max bytes per interval %u",
720             ALT_SETTING, i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize, pipe.Interval, (int) pipe.MaximumBytesPerInterval);
721         switch (pipe.PipeType){
722             case USB_ENDPOINT_TYPE_ISOCHRONOUS:
723                 if (pipe.PipeId & 0x80) {
724                     if (sco_in_addr) continue;
725                     sco_in_addr = pipe.PipeId;
726                     log_info("-> using 0x%2.2X for SCO Data In", sco_in_addr);
727                 } else {
728                     if (sco_out_addr) continue;
729                     sco_out_addr = pipe.PipeId;
730                     log_info("-> using 0x%2.2X for SCO Data Out", sco_out_addr);
731                 }
732                 break;
733             default:
734                 break;
735         }
736     }
737     if (!sco_in_addr){
738         log_error("Couldn't find pipe for SCO IN!");
739         return FALSE;
740     }
741     if (!sco_out_addr){
742         log_error("Couldn't find pipe for SCO IN!");
743         return FALSE;
744     }
745 #endif
746 
747     // check if all found
748     if (!event_in_addr){
749         log_error("Couldn't find pipe for Event IN!");
750         return FALSE;
751     }
752     if (!acl_in_addr){
753         log_error("Couldn't find pipe for ACL IN!");
754         return FALSE;
755     }
756     if (!acl_out_addr){
757         log_error("Couldn't find pipe for ACL OUT!");
758         return FALSE;
759     }
760 
761     // all clear
762     return TRUE;
763 
764 exit_on_error:
765     log_error("usb_scan_for_bluetooth_endpoints: last error %lu", GetLastError());
766     return FALSE;
767 }
768 
769 // returns 0 if successful, -1 otherwise
770 static int usb_try_open_device(const char * device_path){
771 
772 	// open file
773 	usb_device_handle = CreateFile(device_path,
774 		GENERIC_WRITE | GENERIC_READ,
775         FILE_SHARE_WRITE | FILE_SHARE_READ,
776         NULL,
777         OPEN_EXISTING,
778         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
779         NULL);
780 	log_info("Opening USB device: %p", usb_device_handle);
781 	if (!usb_device_handle) goto exit_on_error;
782 
783 	// WinUsb_Initialize returns TRUE if the operation succeed
784 	BOOL result = WinUsb_Initialize(usb_device_handle, &usb_interface_0_handle);
785 	if (!result) goto exit_on_error;
786 
787     // Detect USB Dongle based Class, Subclass, and Protocol
788     // The class code (bDeviceClass) is 0xE0 – Wireless Controller.
789     // The SubClass code (bDeviceSubClass) is 0x01 – RF Controller.
790     // The Protocol code (bDeviceProtocol) is 0x01 – Bluetooth programming.
791     USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
792     result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
793     if (!result) goto exit_on_error;
794     //
795     if (usb_interface_descriptor.bInterfaceClass    != 0xe0 ||
796         usb_interface_descriptor.bInterfaceSubClass != 0x01 ||
797         usb_interface_descriptor.bInterfaceProtocol != 0x01){
798 
799         // TODO: fallback to whitelist
800         log_info("Class, Subclass, Protocol does not match Bluetooth device");
801         usb_free_resources();
802         return 0;
803     }
804 
805 #ifdef ENABLE_SCO_OVER_HCI
806 	log_info("Claiming interface 1...");
807 	// WinUsb_GetAssociatedInterface returns TRUE if the operation succeeds.
808 	// We use index 1 - assuming it refers to interface #1 with libusb
809 	// A value of 0 indicates the first associated interface, a value of 1 indicates the second associated interface, and so on.
810 	result = WinUsb_GetAssociatedInterface(usb_interface_0_handle, 0, &usb_interface_1_handle);
811 	if (!result) goto exit_on_error;
812 	log_info("Claiming interface 1: success");
813 
814 	log_info("Switching to setting %u on interface 1..", ALT_SETTING);
815 	// WinUsb_SetCurrentAlternateSetting returns TRUE if the operation succeeds.
816 	result = WinUsb_SetCurrentAlternateSetting(usb_interface_1_handle, ALT_SETTING);
817 	if (!result) goto exit_on_error;
818 #endif
819 
820     result = usb_scan_for_bluetooth_endpoints();
821     if (!result) {
822         log_error("Could not find all Bluetooth Endpoints!");
823         usb_free_resources();
824         return 0;
825     }
826 
827 #ifdef ENABLE_SCO_OVER_HCI
828     int i;
829 
830 	memset(hci_sco_packet_descriptors, 0, sizeof(hci_sco_packet_descriptors));
831 	log_info("Size of packet descriptors for SCO IN%u", (int) sizeof(hci_sco_packet_descriptors));
832 
833 	result = WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_in_addr, hci_sco_in_buffer, ISOC_BUFFERS * SCO_PACKET_SIZE, &hci_sco_in_buffer_handle);
834 	if (!result) goto exit_on_error;
835 	log_info("hci_sco_in_buffer_handle %p", hci_sco_in_buffer_handle);
836 
837     result = WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_out_addr, sco_ring_buffer, sizeof(sco_ring_buffer), &hci_sco_out_buffer_handle);
838     if (!result) goto exit_on_error;
839     log_info("hci_sco_out_buffer_handle %p", hci_sco_out_buffer_handle);
840 
841 	// setup async io && btstack handler
842 	memset(&usb_overlapped_sco_in, 0, sizeof(usb_overlapped_sco_in));
843 	for (i=0;i<ISOC_BUFFERS;i++){
844 		usb_overlapped_sco_in[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
845 		// log_info_hexdump(&usb_overlapped_sco_in[i], sizeof(OVERLAPPED));
846         // log_info("data source SCO in %u, handle %p", i, usb_overlapped_sco_in[i].hEvent);
847 		usb_data_source_sco_in[i].handle = usb_overlapped_sco_in[i].hEvent;
848 	    btstack_run_loop_set_data_source_handler(&usb_data_source_sco_in[i], &usb_process_sco_in);
849         btstack_run_loop_add_data_source(&usb_data_source_sco_in[i]);
850 	}
851 
852     memset(&usb_overlapped_sco_out, 0, sizeof(usb_overlapped_sco_out));
853     for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
854         usb_overlapped_sco_out[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
855         // log_info("data source SCO out %u, handle %p", i, usb_overlapped_sco_out[i].hEvent);
856         usb_data_source_sco_out[i].handle = usb_overlapped_sco_out[i].hEvent;
857         btstack_run_loop_set_data_source_handler(&usb_data_source_sco_out[i], &usb_process_sco_out);
858         btstack_run_loop_add_data_source(&usb_data_source_sco_out[i]);
859     }
860 #endif
861 
862 	// setup async io
863     memset(&usb_overlapped_event_in,     0, sizeof(usb_overlapped_event_in));
864     memset(&usb_overlapped_command_out,  0, sizeof(usb_overlapped_command_out));
865     memset(&usb_overlapped_acl_out,      0, sizeof(usb_overlapped_acl_out));
866     memset(&usb_overlapped_acl_in,       0, sizeof(usb_overlapped_acl_in));
867     usb_overlapped_event_in.hEvent    = CreateEvent(NULL, TRUE, FALSE, NULL);
868     usb_overlapped_command_out.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
869     usb_overlapped_acl_in.hEvent      = CreateEvent(NULL, TRUE, FALSE, NULL);
870     usb_overlapped_acl_out.hEvent     = CreateEvent(NULL, TRUE, FALSE, NULL);
871 
872 	// setup btstack data soures
873     usb_data_source_event_in.handle = usb_overlapped_event_in.hEvent;
874     btstack_run_loop_set_data_source_handler(&usb_data_source_event_in, &usb_process_event_in);
875     btstack_run_loop_add_data_source(&usb_data_source_event_in);
876 
877     usb_data_source_command_out.handle = usb_overlapped_command_out.hEvent;
878     btstack_run_loop_set_data_source_handler(&usb_data_source_command_out, &usb_process_command_out);
879     btstack_run_loop_add_data_source(&usb_data_source_command_out);
880 
881     usb_data_source_acl_in.handle = usb_overlapped_acl_in.hEvent;
882     btstack_run_loop_set_data_source_handler(&usb_data_source_acl_in, &usb_process_acl_in);
883     btstack_run_loop_add_data_source(&usb_data_source_acl_in);
884 
885     usb_data_source_acl_out.handle = usb_overlapped_acl_out.hEvent;
886     btstack_run_loop_set_data_source_handler(&usb_data_source_acl_out, &usb_process_acl_out);
887     btstack_run_loop_add_data_source(&usb_data_source_acl_out);
888 
889 	// submit all incoming transfers
890 	usb_submit_event_in_transfer();
891 	usb_submit_acl_in_transfer();
892 
893 #ifdef ENABLE_SCO_OVER_HCI
894 
895 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
896     // get current frame number
897     ULONG current_frame_number;
898     LARGE_INTEGER timestamp;
899     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
900 
901     // plan for next tranfer
902     sco_next_transfer_at_frame = current_frame_number + ISOC_BUFFERS * NUM_ISO_PACKETS;
903 #endif
904 
905     for (i=0;i<ISOC_BUFFERS;i++){
906 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
907         usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
908 #else
909         usb_submit_sco_in_transfer_asap(i, 0);
910 #endif
911     }
912 
913     usb_sco_in_expected_transfer = 0;
914 
915     // only await first transfer to return
916     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
917 
918 #if 0
919     // AUTO_CLEAR_STALL, RAW_IO, IGNORE_SHORT_PACKETS is not callable for ISO EP
920     uint8_t value = 0;
921     ULONG   value_len = 1;
922     result = WinUsb_GetPipePolicy(usb_interface_0_handle, event_in_addr, IGNORE_SHORT_PACKETS, &value_len, &value);
923     if (!result) goto exit_on_error;
924     log_info("IGNORE_SHORT_PACKETS = %u", value);
925 
926     uint8_t value_on = 0;
927     result = WinUsb_SetPipePolicy(usb_interface_1_handle, sco_in_addr, IGNORE_SHORT_PACKETS, sizeof(value_on), &value_on);
928     if (!result) goto exit_on_error;
929 #endif
930 
931 #if 0
932     while (1){
933         //
934         DWORD bytes_transferred;
935         BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_in[usb_sco_in_expected_transfer], &bytes_transferred, TRUE);
936 
937         // WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
938 
939         // log_info("WinUsb_GetOverlappedResult[%02u]: ok = %u, current frame %lu", usb_sco_in_expected_transfer, ok, current_frame_number);
940         if (!ok){
941             log_error("WinUsb_GetOverlappedResult res %x", (int) GetLastError());
942             // return 0;
943         }
944         // update expected and wait for completion
945         usb_sco_in_expected_transfer = (usb_sco_in_expected_transfer + 1) % ISOC_BUFFERS;
946 
947         usb_submit_sco_in_transfer_at_frame(usb_sco_in_expected_transfer, &sco_next_transfer_at_frame);
948     }
949 #endif
950 
951 #endif
952 
953 	return 1;
954 
955 exit_on_error:
956 	log_error("usb_try_open_device: last error %lu", GetLastError());
957 	usb_free_resources();
958 	return 0;
959 }
960 
961 #ifdef ENABLE_SCO_OVER_HCI
962 
963 #define WinUSB_Lookup(fn) do { fn = (fn##_t) GetProcAddress(h, #fn); log_info("%-30s %p", #fn, fn); if (!fn) return FALSE; } while(0)
964 
965 static BOOL usb_lookup_symbols(void){
966 	// lookup runtime symbols missing in current mingw64 distribution
967 	HMODULE h = GetModuleHandleA("WinUSB");
968 	log_info("%-30s %p", "WinUSB", h);
969 	WinUSB_Lookup(WinUsb_QueryPipeEx);
970 	WinUSB_Lookup(WinUsb_RegisterIsochBuffer);
971 	WinUSB_Lookup(WinUsb_ReadIsochPipe);
972 	WinUSB_Lookup(WinUsb_ReadIsochPipeAsap);
973 	WinUSB_Lookup(WinUsb_WriteIsochPipe);
974 	WinUSB_Lookup(WinUsb_WriteIsochPipeAsap);
975 	WinUSB_Lookup(WinUsb_UnregisterIsochBuffer);
976     WinUSB_Lookup(WinUsb_GetCurrentFrameNumber);
977     return TRUE;
978 }
979 #endif
980 
981 // returns 0 on success, -1 otherwise
982 static int usb_open(void){
983 
984     int r = -1;
985 
986 #ifdef ENABLE_SCO_OVER_HCI
987 	BOOL ok = usb_lookup_symbols();
988     if (!ok){
989         log_error("usb_open: Failed to lookup WinSUB ISOCHRONOUS functions. Please disable ENABLE_SCO_OVER_HCI or use Windows 8.1 or higher");
990         return r;
991     }
992     sco_state_machine_init();
993     sco_ring_init();
994 #endif
995 
996 	HDEVINFO                         hDevInfo;
997 	SP_DEVICE_INTERFACE_DATA         DevIntfData;
998 	PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
999 	SP_DEVINFO_DATA                  DevData;
1000 
1001 	DWORD dwSize;
1002 	DWORD dwMemberIdx;
1003 
1004     // default endpoint addresses
1005     event_in_addr = 0x81; // EP1, IN interrupt
1006     acl_in_addr =   0x82; // EP2, IN bulk
1007     acl_out_addr =  0x02; // EP2, OUT bulk
1008     sco_in_addr  =  0x83; // EP3, IN isochronous
1009     sco_out_addr =  0x03; // EP3, OUT isochronous
1010 
1011 	// We will try to get device information set for all USB devices that have a
1012 	// device interface and are currently present on the system (plugged in).
1013 	hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
1014 
1015 	log_info("usb_open: SetupDiGetClassDevs -> %p", hDevInfo);
1016 	if (hDevInfo == INVALID_HANDLE_VALUE) return -1;
1017 
1018 	// Prepare to enumerate all device interfaces for the device information
1019 	// set that we retrieved with SetupDiGetClassDevs(..)
1020 	DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1021 	dwMemberIdx = 0;
1022 
1023 	// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
1024 	// function causes GetLastError() to return  ERROR_NO_MORE_ITEMS. With each
1025 	// call the dwMemberIdx value needs to be incremented to retrieve the next
1026 	// device interface information.
1027 
1028 	SetupDiEnumDeviceInterfaces(hDevInfo, NULL, (LPGUID) &GUID_DEVINTERFACE_USB_DEVICE,
1029 		dwMemberIdx, &DevIntfData);
1030 
1031 	while(GetLastError() != ERROR_NO_MORE_ITEMS){
1032 
1033 		// As a last step we will need to get some more details for each
1034 		// of device interface information we are able to retrieve. This
1035 		// device interface detail gives us the information we need to identify
1036 		// the device (VID/PID), and decide if it's useful to us. It will also
1037 		// provide a DEVINFO_DATA structure which we can use to know the serial
1038 		// port name for a virtual com port.
1039 
1040 		DevData.cbSize = sizeof(DevData);
1041 
1042 		// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
1043 		// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
1044 		// of zero, and a valid RequiredSize variable. In response to such a call,
1045 		// this function returns the required buffer size at dwSize.
1046 
1047 		SetupDiGetDeviceInterfaceDetail(
1048 			  hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
1049 
1050 		// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
1051 		// deallocate it later!
1052 		DevIntfDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
1053 		DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
1054 
1055 		if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData,
1056 			DevIntfDetailData, dwSize, &dwSize, &DevData))
1057 		{
1058 			// Finally we can start checking if we've found a useable device,
1059 			// by inspecting the DevIntfDetailData->DevicePath variable.
1060 			// The DevicePath looks something like this:
1061 			//
1062 			// \\?\usb#vid_04d8&pid_0033#5&19f2438f&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
1063 			//
1064 
1065 			log_info("usb_open: Device Path: %s", DevIntfDetailData->DevicePath);
1066 
1067 #if 0
1068             // check for hard-coded vendor/product ids
1069 			char vid_pid_match[30];
1070 			uint16_t vid = 0x0a12;
1071 			uint16_t pid = 0x0001;
1072 			sprintf(vid_pid_match, "\\\\?\\usb#vid_%04x&pid_%04x", vid, pid);
1073 			if (strncmp(DevIntfDetailData->DevicePath, &vid_pid_match[0], strlen(vid_pid_match)) == 0 ){
1074 				log_info("Matched search string %s", vid_pid_match);
1075 
1076 				BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
1077 				if (result){
1078 					log_info("usb_open: Device opened, stop scanning");
1079 					r = 0;
1080 				} else {
1081 					log_error("usb_open: Device open failed");
1082 				}
1083 			}
1084 #endif
1085 
1086             // try all devices
1087             BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
1088             if (result){
1089                 log_info("usb_open: Device opened, stop scanning");
1090                 r = 0;
1091             } else {
1092                 log_error("usb_open: Device open failed");
1093             }
1094         }
1095 		HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
1096 
1097 		if (r == 0) break;
1098 
1099 		// Continue looping
1100 		SetupDiEnumDeviceInterfaces(
1101 			hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, ++dwMemberIdx, &DevIntfData);
1102 	}
1103 
1104 	SetupDiDestroyDeviceInfoList(hDevInfo);
1105 
1106 	log_info("usb_open: done");
1107 
1108     return r;
1109 }
1110 
1111 static int usb_close(void){
1112 
1113     // remove data sources
1114     btstack_run_loop_remove_data_source(&usb_data_source_command_out);
1115     btstack_run_loop_remove_data_source(&usb_data_source_event_in);
1116     btstack_run_loop_remove_data_source(&usb_data_source_acl_in);
1117     btstack_run_loop_remove_data_source(&usb_data_source_acl_out);
1118 
1119 #ifdef ENABLE_SCO_OVER_HCI
1120     int i;
1121     for (i=0;i<ISOC_BUFFERS;i++){
1122         btstack_run_loop_remove_data_source(&usb_data_source_sco_in[i]);
1123     }
1124     for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
1125         btstack_run_loop_remove_data_source(&usb_data_source_sco_out[i]);
1126     }
1127 #endif
1128 
1129     // stop transfers
1130     WinUsb_AbortPipe(usb_interface_0_handle, event_in_addr);
1131     WinUsb_AbortPipe(usb_interface_0_handle, acl_in_addr);
1132     WinUsb_AbortPipe(usb_interface_0_handle, acl_out_addr);
1133 #ifdef ENABLE_SCO_OVER_HCI
1134     WinUsb_AbortPipe(usb_interface_0_handle, sco_in_addr);
1135     WinUsb_AbortPipe(usb_interface_0_handle, sco_out_addr);
1136 #endif
1137     usb_acl_out_active = 0;
1138 
1139     // control transfer cannot be stopped, just wait for completion
1140     if (usb_command_out_active){
1141         DWORD bytes_transferred;
1142         WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_command_out, &bytes_transferred, TRUE);
1143         usb_command_out_active = 0;
1144     }
1145 
1146     // free everything
1147     usb_free_resources();
1148     return 0;
1149 }
1150 
1151 static int usb_can_send_packet_now(uint8_t packet_type){
1152     // return 0;
1153     switch (packet_type){
1154         case HCI_COMMAND_DATA_PACKET:
1155             return !usb_command_out_active;
1156         case HCI_ACL_DATA_PACKET:
1157             return !usb_acl_out_active;
1158 #ifdef ENABLE_SCO_OVER_HCI
1159         case HCI_SCO_DATA_PACKET:
1160             // return 0;
1161             return sco_ring_have_space();
1162 #endif
1163         default:
1164             return 0;
1165     }
1166 }
1167 
1168 static int usb_send_cmd_packet(uint8_t *packet, int size){
1169 
1170     // update stata before submitting transfer
1171     usb_command_out_active = 1;
1172 
1173 	// Start trasnsfer
1174 	WINUSB_SETUP_PACKET setup_packet;
1175 	memset(&setup_packet, 0, sizeof(setup_packet));
1176 	setup_packet.RequestType =  USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE;
1177 	setup_packet.Length = sizeof(size);
1178 	BOOL result = WinUsb_ControlTransfer(usb_interface_0_handle, setup_packet, packet, size,  NULL, &usb_overlapped_command_out);
1179 	if (!result) {
1180 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1181 	}
1182 
1183     // IO_PENDING -> wait for completed
1184     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_command_out, DATA_SOURCE_CALLBACK_WRITE);
1185 
1186     return 0;
1187 
1188 exit_on_error:
1189 	log_error("winusb: last error %lu", GetLastError());
1190 	return -1;
1191 }
1192 
1193 static int usb_send_acl_packet(uint8_t *packet, int size){
1194 
1195     // update stata before submitting transfer
1196     usb_acl_out_active = 1;
1197 
1198 	// Start trasnsfer
1199 	BOOL ok = WinUsb_WritePipe(usb_interface_0_handle, acl_out_addr, packet, size,  NULL, &usb_overlapped_acl_out);
1200 	if (!ok) {
1201 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1202 	}
1203 
1204     // IO_PENDING -> wait for completed
1205     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_out, DATA_SOURCE_CALLBACK_WRITE);
1206     return 0;
1207 
1208 exit_on_error:
1209 	log_error("winusb: last error %lu", GetLastError());
1210 	return -1;
1211 }
1212 
1213 #ifdef ENABLE_SCO_OVER_HCI
1214 static int usb_send_sco_packet(uint8_t *packet, int size){
1215 
1216     if (size > SCO_PACKET_SIZE){
1217         log_error("usb_send_sco_packet: size %u > SCO_PACKET_SIZE %u", size, SCO_PACKET_SIZE);
1218         return -1;
1219     }
1220 
1221     // get current frame number
1222     ULONG current_frame_number;
1223     LARGE_INTEGER timestamp;
1224     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
1225 
1226     // store packet in free slot
1227     int transfer_index = sco_ring_write;
1228     uint8_t * data = &sco_ring_buffer[transfer_index * SCO_PACKET_SIZE];
1229     memcpy(data, packet, size);
1230 
1231 
1232     // setup transfer
1233     int continue_stream = sco_ring_transfers_active > 0;
1234     BOOL ok = WinUsb_WriteIsochPipeAsap(hci_sco_out_buffer_handle, transfer_index * SCO_PACKET_SIZE, size, continue_stream, &usb_overlapped_sco_out[transfer_index]);
1235     log_info("usb_send_sco_packet: using slot #%02u, current frame %lu, continue stream %u, ok %u", transfer_index, current_frame_number, continue_stream, ok);
1236     if (!ok) {
1237         if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1238     }
1239 
1240     // successful started transfer, enable data source callback if first active transfer
1241     if (sco_ring_transfers_active == 0){
1242         usb_sco_out_expected_transfer = transfer_index;
1243         btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
1244     }
1245 
1246     // mark slot as full
1247     sco_ring_write = (sco_ring_write + 1) % SCO_RING_BUFFER_COUNT;
1248     sco_ring_transfers_active++;
1249 
1250     // notify upper stack that provided buffer can be used again
1251     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
1252     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
1253 
1254     log_info("usb_send_sco_packet: transfers active %u", sco_ring_transfers_active);
1255 
1256     // and if we have more space for SCO packets
1257     if (sco_ring_have_space()) {
1258         uint8_t event_sco[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
1259         packet_handler(HCI_EVENT_PACKET, &event_sco[0], sizeof(event_sco));
1260     }
1261     return 0;
1262 
1263 exit_on_error:
1264     log_error("usb_send_sco_packet: last error %lu", GetLastError());
1265     return -1;
1266 }
1267 #endif
1268 
1269 static int usb_send_packet(uint8_t packet_type, uint8_t * packet, int size){
1270     switch (packet_type){
1271         case HCI_COMMAND_DATA_PACKET:
1272             return usb_send_cmd_packet(packet, size);
1273         case HCI_ACL_DATA_PACKET:
1274             return usb_send_acl_packet(packet, size);
1275 #ifdef ENABLE_SCO_OVER_HCI
1276         case HCI_SCO_DATA_PACKET:
1277             return usb_send_sco_packet(packet, size);
1278 #endif
1279         default:
1280             return -1;
1281     }
1282 }
1283 
1284 // get usb singleton
1285 static const hci_transport_t hci_transport_usb = {
1286     /* const char * name; */                                        "H2_WINUSB",
1287     /* void   (*init) (const void *transport_config); */            &usb_init,
1288     /* int    (*open)(void); */                                     &usb_open,
1289     /* int    (*close)(void); */                                    &usb_close,
1290     /* void   (*register_packet_handler)(void (*handler)(...); */   &usb_register_packet_handler,
1291     /* int    (*can_send_packet_now)(uint8_t packet_type); */       &usb_can_send_packet_now,
1292     /* int    (*send_packet)(...); */                               &usb_send_packet,
1293     /* int    (*set_baudrate)(uint32_t baudrate); */                NULL,
1294     /* void   (*reset_link)(void); */                               NULL,
1295     /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL,
1296 };
1297 
1298 const hci_transport_t * hci_transport_usb_instance(void) {
1299     return &hci_transport_usb;
1300 }
1301