xref: /btstack/platform/windows/hci_transport_h2_winusb.c (revision f12924e0a61c0582b548a1e70cea1bd59ba21f1d)
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 // alt setting for 1-3 connections and 8/16 bit
171 const int alt_setting_8_bit[]  = {1,2,3};
172 const int alt_setting_16_bit[] = {2,4,5};
173 
174 // for ALT_SETTING >= 1 and 8-bit channel, we need the following isochronous packets
175 // One complete SCO packet with 24 frames every 3 frames (== 3 ms)
176 #define NUM_ISO_PACKETS (3)
177 
178 const uint16_t iso_packet_size_for_alt_setting[] = {
179     0,
180     9,
181     17,
182     25,
183     33,
184     49,
185     63,
186 };
187 
188 // 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)
189 // 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
190 #define SCO_PACKET_SIZE  (49 * NUM_ISO_PACKETS)
191 
192 #define ISOC_BUFFERS   8
193 
194 // Outgoing SCO packet queue
195 // simplified ring buffer implementation
196 #define SCO_RING_BUFFER_COUNT  (20)
197 #define SCO_RING_BUFFER_SIZE (SCO_RING_BUFFER_COUNT * SCO_PACKET_SIZE)
198 
199 /** Request type bits of the "bmRequestType" field in control transfers. */
200 enum usb_request_type {
201 	USB_REQUEST_TYPE_STANDARD = (0x00 << 5),
202 	USB_REQUEST_TYPE_CLASS = (0x01 << 5),
203 	USB_REQUEST_TYPE_VENDOR = (0x02 << 5),
204 };
205 
206 /** Recipient bits of the "bmRequestType" field in control transfers. Values 4 through 31 are reserved. */
207 enum usb_request_recipient {
208 	USB_RECIPIENT_DEVICE = 0x00,
209 	USB_RECIPIENT_INTERFACE = 0x01,
210 	USB_RECIPIENT_ENDPOINT = 0x02,
211 	USB_RECIPIENT_OTHER = 0x03,
212 };
213 
214 // This is the GUID for the USB device class
215 static GUID GUID_DEVINTERFACE_USB_DEVICE =
216 { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
217 
218 static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
219 
220 static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = &usb_dummy_handler;
221 
222 // endpoint addresses
223 static int event_in_addr;
224 static int acl_in_addr;
225 static int acl_out_addr;
226 static int sco_in_addr;
227 static int sco_out_addr;
228 
229 //
230 static HANDLE usb_device_handle;
231 static WINUSB_INTERFACE_HANDLE usb_interface_0_handle;
232 static WINUSB_INTERFACE_HANDLE usb_interface_1_handle;
233 static OVERLAPPED usb_overlapped_event_in;
234 static OVERLAPPED usb_overlapped_command_out;
235 static OVERLAPPED usb_overlapped_acl_in;
236 static OVERLAPPED usb_overlapped_acl_out;
237 static btstack_data_source_t usb_data_source_event_in;
238 static btstack_data_source_t usb_data_source_command_out;
239 static btstack_data_source_t usb_data_source_acl_in;
240 static btstack_data_source_t usb_data_source_acl_out;
241 
242 //
243 static int usb_command_out_active;
244 static int usb_acl_out_active;
245 
246 // buffer for HCI Events and ACL Packets
247 static uint8_t hci_event_in_buffer[2 + 255];
248 static uint8_t hci_acl_in_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_ACL_BUFFER_SIZE];
249 
250 
251 #ifdef ENABLE_SCO_OVER_HCI
252 
253 typedef enum {
254     H2_W4_SCO_HEADER = 1,
255     H2_W4_PAYLOAD,
256 } H2_SCO_STATE;
257 
258 // SCO Incoming Windows
259 static uint8_t hci_sco_in_buffer[ISOC_BUFFERS * SCO_PACKET_SIZE];
260 static WINUSB_ISOCH_BUFFER_HANDLE hci_sco_in_buffer_handle;
261 static USBD_ISO_PACKET_DESCRIPTOR hci_sco_packet_descriptors[ISOC_BUFFERS * NUM_ISO_PACKETS];
262 static OVERLAPPED usb_overlapped_sco_in[ISOC_BUFFERS];
263 static int usb_sco_in_expected_transfer;
264 
265 // SCO Incoming Run Loop
266 static btstack_data_source_t usb_data_source_sco_in[ISOC_BUFFERS];
267 
268 // SCO Incoming HCI
269 static H2_SCO_STATE sco_state;
270 static uint8_t  sco_buffer[SCO_PACKET_SIZE];
271 static uint16_t sco_read_pos;
272 static uint16_t sco_bytes_to_read;
273 
274 // SCO Outgoing Windows
275 static WINUSB_ISOCH_BUFFER_HANDLE hci_sco_out_buffer_handle;
276 static OVERLAPPED usb_overlapped_sco_out[SCO_RING_BUFFER_COUNT];
277 static int        sco_ring_transfers_active;
278 static int        usb_sco_out_expected_transfer;
279 
280 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
281 // next tranfer
282 static ULONG sco_next_transfer_at_frame;
283 #endif
284 
285 // SCO Outgoing Run Loop
286 static btstack_data_source_t usb_data_source_sco_out[SCO_RING_BUFFER_COUNT];
287 
288 // SCO Outgoing HCI
289 static uint8_t  sco_ring_buffer[SCO_RING_BUFFER_SIZE];
290 static int      sco_ring_write;  // packet idx
291 
292 // SCO Reconfiguration - pause/resume
293 static uint16_t sco_voice_setting;
294 static int      sco_num_connections;
295 static int      sco_shutdown;
296 
297 static uint16_t iso_packet_size;
298 #endif
299 
300 #if 0
301 // list of known devices, using VendorID/ProductID tuples
302 static const uint16_t known_bluetooth_devices[] = {
303     // DeLOCK Bluetooth 4.0
304     0x0a5c, 0x21e8,
305     // Asus BT400
306     0x0b05, 0x17cb,
307 };
308 
309 static int num_known_devices = sizeof(known_bluetooth_devices) / sizeof(uint16_t) / 2;
310 
311 static int usb_is_known_bluetooth_device(uint16_t vendor_id, uint16_t product_id){
312     int i;
313     for (i=0; i<num_known_devices; i++){
314         if (known_bluetooth_devices[i*2] == vendor_id && known_bluetooth_devices[i*2+1] == product_id){
315             return 1;
316         }
317     }
318     return 0;
319 }
320 #endif
321 
322 #ifdef ENABLE_SCO_OVER_HCI
323 static void sco_ring_init(void){
324     sco_ring_write = 0;
325     sco_ring_transfers_active = 0;
326 }
327 static int sco_ring_have_space(void){
328     return sco_ring_transfers_active < SCO_RING_BUFFER_COUNT;
329 }
330 static void usb_sco_register_buffers(void){
331     BOOL result;
332     result = WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_in_addr, hci_sco_in_buffer, sizeof(hci_sco_in_buffer), &hci_sco_in_buffer_handle);
333     if (!result) {
334         log_error("usb_sco_register_buffers: register in buffer failed, error %lu", GetLastError());
335     }
336     log_info("hci_sco_in_buffer_handle %p", hci_sco_in_buffer_handle);
337 
338     result = WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_out_addr, sco_ring_buffer, sizeof(sco_ring_buffer), &hci_sco_out_buffer_handle);
339     if (!result) {
340         log_error("usb_sco_unregister_buffers: register out buffer failed, error %lu", GetLastError());
341     }
342     log_info("hci_sco_out_buffer_handle %p", hci_sco_out_buffer_handle);
343 }
344 static void usb_sco_unregister_buffers(void){
345     if (hci_sco_in_buffer_handle){
346         WinUsb_UnregisterIsochBuffer(hci_sco_in_buffer_handle);
347         hci_sco_in_buffer_handle = NULL;
348     }
349     if (hci_sco_out_buffer_handle){
350         WinUsb_UnregisterIsochBuffer(hci_sco_out_buffer_handle);
351         hci_sco_out_buffer_handle = NULL;
352     }
353 }
354 #endif
355 
356 static void usb_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
357     log_info("registering packet handler");
358     packet_handler = handler;
359 }
360 
361 static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
362 }
363 
364 static void usb_init(const void *transport_config){
365 }
366 
367 static void usb_free_resources(void){
368 	if (usb_interface_1_handle){
369 		WinUsb_Free(usb_interface_1_handle);
370 		usb_interface_1_handle = NULL;
371 	}
372 
373 	if (usb_interface_0_handle){
374 		WinUsb_Free(usb_interface_0_handle);
375 		usb_interface_0_handle = NULL;
376 	}
377 
378 	if (usb_device_handle) {
379 		CloseHandle(usb_device_handle);
380 		usb_device_handle = NULL;
381 	}
382 
383 #ifdef ENABLE_SCO_OVER_HCI
384     usb_sco_unregister_buffers();
385 #endif
386 }
387 
388 static void usb_submit_event_in_transfer(void){
389 	// submit transfer
390 	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);
391 	if (!result) {
392 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
393 	}
394 
395     // IO_PENDING -> wait for completed
396     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_event_in, DATA_SOURCE_CALLBACK_READ);
397     return;
398 
399 exit_on_error:
400 	log_error("usb_submit_event_in_transfer: winusb last error %lu", GetLastError());
401 }
402 
403 static void usb_submit_acl_in_transfer(void){
404 	// submit transfer
405 	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);
406 	if (!result) {
407 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
408 	}
409 
410     // IO_PENDING -> wait for completed
411     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_in, DATA_SOURCE_CALLBACK_READ);
412     return;
413 
414 exit_on_error:
415 	log_error("usb_submit_acl_in_transfer: winusb last error %lu", GetLastError());
416 }
417 
418 #ifdef ENABLE_SCO_OVER_HCI
419 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
420 
421 // frame number gets updated
422 static void usb_submit_sco_in_transfer_at_frame(int i, ULONG * frame_number){
423 
424     if (sco_shutdown){
425         log_info("USB SCO Shutdown:: usb_submit_sco_in_transfer_at_frame called");
426         return;
427     }
428 
429     LARGE_INTEGER timestamp;
430     ULONG current_frame_number;
431     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
432 
433     ULONG frame_before = *frame_number;
434 
435     BOOL result = WinUsb_ReadIsochPipe(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, iso_packet_size * NUM_ISO_PACKETS,
436         frame_number, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
437 
438     // log_info("WinUsb_ReadIsochPipe #%02u: current %lu, planned %lu - buffer %lu", i, current_frame_number, frame_before, frame_before - current_frame_number);
439 
440     if (!result) {
441         if (GetLastError() == ERROR_IO_PENDING) {
442         } else {
443             goto exit_on_error;
444         }
445     }
446 
447     return;
448 
449 exit_on_error:
450     log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
451 }
452 
453 #else
454 
455 static void usb_submit_sco_in_transfer_asap(int i, int continue_stream){
456 
457     if (sco_shutdown){
458         log_info("USB SCO Shutdown:: usb_submit_sco_in_transfer_at_frame called");
459         return;
460     }
461 
462     LARGE_INTEGER timestamp;
463     ULONG current_frame_number;
464     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
465 
466     // log_info("usb_submit_sco_in_transfer[%02u]: current frame %lu", i, current_frame_number);
467 
468     BOOL result = WinUsb_ReadIsochPipeAsap(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, iso_packet_size * NUM_ISO_PACKETS,
469         continue_stream, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
470 
471     if (!result) {
472         if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
473     }
474 
475     return;
476 
477 exit_on_error:
478     log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
479 }
480 #endif
481 #endif
482 
483 static void usb_process_event_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
484 
485     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
486 
487     DWORD bytes_read;
488     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_event_in, &bytes_read, FALSE);
489     if(!ok){
490         DWORD err = GetLastError();
491         if (err == ERROR_IO_INCOMPLETE){
492             // IO_INCOMPLETE -> wait for completed
493             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
494         } else {
495             log_error("usb_process_event_in: error reading");
496         }
497         return;
498     }
499 
500     // notify uppper
501     packet_handler(HCI_EVENT_PACKET, hci_event_in_buffer, bytes_read);
502 
503 	// re-submit transfer
504 	usb_submit_event_in_transfer();
505 }
506 
507 static void usb_process_acl_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
508 
509     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
510 
511     DWORD bytes_read;
512     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_acl_in, &bytes_read, FALSE);
513     if(!ok){
514         DWORD err = GetLastError();
515         if (err == ERROR_IO_INCOMPLETE){
516             // IO_INCOMPLETE -> wait for completed
517             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
518         } else {
519             log_error("usb_process_acl_in: error writing");
520         }
521         return;
522     }
523 
524     // notify uppper
525     packet_handler(HCI_ACL_DATA_PACKET, hci_acl_in_buffer, bytes_read);
526 
527 	// re-submit transfer
528 	usb_submit_acl_in_transfer();
529 }
530 
531 #ifdef ENABLE_SCO_OVER_HCI
532 static void sco_state_machine_init(void){
533     sco_state = H2_W4_SCO_HEADER;
534     sco_read_pos = 0;
535     sco_bytes_to_read = 3;
536 }
537 
538 static void sco_handle_data(uint8_t * buffer, uint16_t size){
539 	// printf("sco_handle_data: state %u, pos %u, to read %u, size %u", sco_state, sco_read_pos, sco_bytes_to_read, size);
540     while (size){
541         if (size < sco_bytes_to_read){
542             // just store incomplete data
543             memcpy(&sco_buffer[sco_read_pos], buffer, size);
544             sco_read_pos      += size;
545             sco_bytes_to_read -= size;
546             return;
547         }
548         // copy requested data
549         memcpy(&sco_buffer[sco_read_pos], buffer, sco_bytes_to_read);
550         sco_read_pos += sco_bytes_to_read;
551         buffer       += sco_bytes_to_read;
552         size         -= sco_bytes_to_read;
553 
554         // chunk read successfully, next action
555         switch (sco_state){
556             case H2_W4_SCO_HEADER:
557                 sco_state = H2_W4_PAYLOAD;
558                 sco_bytes_to_read = sco_buffer[2];
559                 if (sco_bytes_to_read > (sizeof(sco_buffer)-3)){
560                 	log_error("sco_handle_data: sco packet len > packet size");
561 	                sco_state_machine_init();
562                 }
563                 break;
564             case H2_W4_PAYLOAD:
565                 // packet complete
566                 packet_handler(HCI_SCO_DATA_PACKET, sco_buffer, sco_read_pos);
567                 sco_state_machine_init();
568                 break;
569         }
570     }
571 }
572 
573 static void usb_process_sco_out(btstack_data_source_t *ds,  btstack_data_source_callback_type_t callback_type){
574 
575     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
576 
577     if (sco_shutdown){
578         log_info("USB SCO Shutdown:: usb_process_sco_out called");
579         return;
580     }
581 
582     // get current frame number
583     ULONG current_frame_number;
584     LARGE_INTEGER timestamp;
585     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
586 
587     // find index
588     int transfer_index;
589     for (transfer_index=0;transfer_index<SCO_RING_BUFFER_COUNT;transfer_index++){
590         if (ds == &usb_data_source_sco_out[transfer_index]) break;
591     }
592 
593     // log_info("usb_process_sco_out[%02u] -- current frame %lu", transfer_index, current_frame_number);
594 
595     DWORD bytes_transferred;
596     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_out[transfer_index], &bytes_transferred, FALSE);
597     // log_info("usb_process_sco_out_done: #%u result %u, bytes %u, state %u", transfer_index, ok, (int) bytes_transferred, sco_state);
598     if(!ok){
599         DWORD err = GetLastError();
600         if (err == ERROR_IO_INCOMPLETE){
601             // IO_INCOMPLETE -> wait for completed
602             btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
603             return;
604         }
605         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);
606     }
607 
608     // decrease tab
609     sco_ring_transfers_active--;
610 
611     // enable next data source callback
612     if (sco_ring_transfers_active){
613         // update expected and wait for completion
614         usb_sco_out_expected_transfer = (transfer_index+ 1) % SCO_RING_BUFFER_COUNT;
615         // log_info("usb_process_sco_out_done[%02u]: wait for transfer %02u", transfer_index, usb_sco_out_expected_transfer);
616         btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[usb_sco_out_expected_transfer], DATA_SOURCE_CALLBACK_WRITE);
617     }
618 
619     // log_info("usb_process_sco_out_done: transfers active %u", sco_ring_transfers_active);
620 
621     // mark free
622     if (sco_ring_have_space()) {
623         uint8_t event[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
624         packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
625     }
626 }
627 
628 static void usb_process_sco_in(btstack_data_source_t *ds,  btstack_data_source_callback_type_t callback_type){
629 
630     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
631 
632     if (sco_shutdown){
633         log_info("USB SCO Shutdown: usb_process_sco_out called");
634         return;
635     }
636 
637     // find index
638     int i;
639     for (i=0;i<ISOC_BUFFERS;i++){
640         if (ds == &usb_data_source_sco_in[i]) break;
641     }
642     int transfer_index = i;
643 
644     // ULONG current_frame_number;
645     // LARGE_INTEGER timestamp;
646     // WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
647 
648     // log_info("usb_process_sco_in[%02u] -- current frame %lu", transfer_index, current_frame_number);
649 
650     DWORD bytes_transferred;
651     BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_in[transfer_index], &bytes_transferred, FALSE);
652 
653     if(!ok) {
654         DWORD err = GetLastError();
655         if (err == ERROR_IO_INCOMPLETE) {
656             // IO_INCOMPLETE -> wait for completed
657             btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
658             return;
659         }
660         log_error("usb_process_sco_in[%02u]: error reading %u, Internal %x", transfer_index, (int) err, (int) usb_overlapped_sco_out[i].Internal);
661     }
662 
663     if (ok){
664         for (i=0;i<NUM_ISO_PACKETS;i++){
665             USBD_ISO_PACKET_DESCRIPTOR * packet_descriptor = &hci_sco_packet_descriptors[transfer_index * NUM_ISO_PACKETS + i];
666             if (packet_descriptor->Length){
667                 uint8_t * iso_data = &hci_sco_in_buffer[transfer_index * SCO_PACKET_SIZE + packet_descriptor->Offset];
668                 uint16_t  iso_len  = packet_descriptor->Length;
669                 sco_handle_data(iso_data, iso_len);
670             }
671         }
672     }
673 
674 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
675     usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
676 #else
677     usb_submit_sco_in_transfer_asap(transfer_index, 1);
678 #endif
679     // update expected and wait for completion
680     usb_sco_in_expected_transfer = (transfer_index+ 1) % ISOC_BUFFERS;
681 
682     // log_info("usb_process_sco_in[%02u]: enable data source %02u", transfer_index, usb_sco_in_expected_transfer);
683     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
684 }
685 #endif
686 
687 static void usb_process_command_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
688 
689     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
690 
691     // update stata before submitting transfer
692     usb_command_out_active = 0;
693 
694     // notify upper stack that provided buffer can be used again
695     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
696     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
697 }
698 
699 static void usb_process_acl_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
700 
701     btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
702 
703     // update stata before submitting transfer
704     usb_acl_out_active = 0;
705 
706     // notify upper stack that provided buffer can be used again
707     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
708     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
709 }
710 
711 static BOOL usb_scan_for_bluetooth_endpoints(void) {
712     int i;
713     USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
714 
715     // reset
716     event_in_addr = 0;
717     acl_in_addr = 0;
718     acl_out_addr = 0;
719 
720     log_info("Scanning USB Entpoints:");
721 
722     // look for Event and ACL pipes on Interface #0
723     BOOL result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
724     if (!result) goto exit_on_error;
725     for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
726         WINUSB_PIPE_INFORMATION pipe;
727         result = WinUsb_QueryPipe(
728                      usb_interface_0_handle,
729                      0,
730                      (UCHAR) i,
731                      &pipe);
732         if (!result) goto exit_on_error;
733         log_info("Interface #0, Alt #0, Pipe idx #%u: type %u, id 0x%02x, max packet size %u,",
734             i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize);
735         switch (pipe.PipeType){
736             case USB_ENDPOINT_TYPE_INTERRUPT:
737                 if (event_in_addr) continue;
738                 event_in_addr = pipe.PipeId;
739                 log_info("-> using 0x%2.2X for HCI Events", event_in_addr);
740                 break;
741             case USB_ENDPOINT_TYPE_BULK:
742                 if (pipe.PipeId & 0x80) {
743                     if (acl_in_addr) continue;
744                     acl_in_addr = pipe.PipeId;
745                     log_info("-> using 0x%2.2X for ACL Data In", acl_in_addr);
746                 } else {
747                     if (acl_out_addr) continue;
748                     acl_out_addr = pipe.PipeId;
749                     log_info("-> using 0x%2.2X for ACL Data Out", acl_out_addr);
750                 }
751                 break;
752             default:
753                 break;
754         }
755     }
756 
757 #ifdef ENABLE_SCO_OVER_HCI
758     sco_out_addr = 0;
759     sco_in_addr = 0;
760 
761     // look for SCO pipes on Interface #1, Alt Setting 1
762     int alt_setting = 1;
763     result = WinUsb_QueryInterfaceSettings(usb_interface_1_handle, alt_setting, &usb_interface_descriptor);
764     if (!result) goto exit_on_error;
765     for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
766         WINUSB_PIPE_INFORMATION_EX pipe;
767         result = WinUsb_QueryPipeEx(
768                      usb_interface_1_handle,
769                      alt_setting,
770                      (UCHAR) i,
771                      &pipe);
772         if (!result) goto exit_on_error;
773         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",
774             alt_setting, i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize, pipe.Interval, (int) pipe.MaximumBytesPerInterval);
775         switch (pipe.PipeType){
776             case USB_ENDPOINT_TYPE_ISOCHRONOUS:
777                 if (pipe.PipeId & 0x80) {
778                     if (sco_in_addr) continue;
779                     sco_in_addr = pipe.PipeId;
780                     log_info("-> using 0x%2.2X for SCO Data In", sco_in_addr);
781                 } else {
782                     if (sco_out_addr) continue;
783                     sco_out_addr = pipe.PipeId;
784                     log_info("-> using 0x%2.2X for SCO Data Out", sco_out_addr);
785                 }
786                 break;
787             default:
788                 break;
789         }
790     }
791     if (!sco_in_addr){
792         log_error("Couldn't find pipe for SCO IN!");
793         return FALSE;
794     }
795     if (!sco_out_addr){
796         log_error("Couldn't find pipe for SCO IN!");
797         return FALSE;
798     }
799 #endif
800 
801     // check if all found
802     if (!event_in_addr){
803         log_error("Couldn't find pipe for Event IN!");
804         return FALSE;
805     }
806     if (!acl_in_addr){
807         log_error("Couldn't find pipe for ACL IN!");
808         return FALSE;
809     }
810     if (!acl_out_addr){
811         log_error("Couldn't find pipe for ACL OUT!");
812         return FALSE;
813     }
814 
815     // all clear
816     return TRUE;
817 
818 exit_on_error:
819     log_error("usb_scan_for_bluetooth_endpoints: last error %lu", GetLastError());
820     return FALSE;
821 }
822 
823 #ifdef ENABLE_SCO_OVER_HCI
824 
825 static int usb_sco_start(void){
826     printf("usb_sco_start\n");
827     log_info("usb_sco_start");
828 
829     sco_shutdown = 0;
830 
831     sco_state_machine_init();
832     sco_ring_init();
833 
834     // calc alt setting
835     int alt_setting;
836     if (sco_voice_setting & 0x0020){
837         // 16-bit PCM
838         alt_setting = alt_setting_16_bit[sco_num_connections-1];
839     } else {
840         // 8-bit PCM or mSBC
841         alt_setting = alt_setting_8_bit[sco_num_connections-1];
842     }
843 
844     log_info("Switching to setting %u on interface 1..", alt_setting);
845     // WinUsb_SetCurrentAlternateSetting returns TRUE if the operation succeeds.
846     BOOL result = WinUsb_SetCurrentAlternateSetting(usb_interface_1_handle, alt_setting);
847     if (!result) goto exit_on_error;
848 
849     // derive iso packet size from alt setting
850     iso_packet_size = iso_packet_size_for_alt_setting[alt_setting];
851 
852     // register isochronous buffer after setting alternate setting
853     usb_sco_register_buffers();
854 
855 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
856     // get current frame number
857     ULONG current_frame_number;
858     LARGE_INTEGER timestamp;
859     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
860     // plan for next tranfer
861     sco_next_transfer_at_frame = current_frame_number + ISOC_BUFFERS * NUM_ISO_PACKETS;
862 #endif
863 
864     int i;
865     for (i=0;i<ISOC_BUFFERS;i++){
866 #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
867         usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
868 #else
869         usb_submit_sco_in_transfer_asap(i, 0);
870 #endif
871     }
872 
873     usb_sco_in_expected_transfer = 0;
874 
875     // only await first transfer to return
876     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
877     return 1;
878 
879 exit_on_error:
880     log_error("usb_sco_start: last error %lu", GetLastError());
881     usb_free_resources();
882     return 0;
883 }
884 
885 static void usb_sco_stop(void){
886     printf("usb_sco_stop\n");
887     log_info("usb_sco_stop");
888 
889     sco_shutdown = 1;
890 
891     // abort SCO transfers
892     WinUsb_AbortPipe(usb_interface_0_handle, sco_in_addr);
893     WinUsb_AbortPipe(usb_interface_0_handle, sco_out_addr);
894 
895     // unlock/free SCO buffers
896     usb_sco_unregister_buffers();
897 
898     int alt_setting = 0;
899     log_info("Switching to setting %u on interface 1..", alt_setting);
900     // WinUsb_SetCurrentAlternateSetting returns TRUE if the operation succeeds.
901     WinUsb_SetCurrentAlternateSetting(usb_interface_1_handle, alt_setting);
902 }
903 #endif
904 
905 // returns 0 if successful, -1 otherwise
906 static int usb_try_open_device(const char * device_path){
907 
908 	// open file
909 	usb_device_handle = CreateFile(device_path,
910 		GENERIC_WRITE | GENERIC_READ,
911         FILE_SHARE_WRITE | FILE_SHARE_READ,
912         NULL,
913         OPEN_EXISTING,
914         FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
915         NULL);
916 	log_info("Opening USB device: %p", usb_device_handle);
917 	if (!usb_device_handle) goto exit_on_error;
918 
919 	// WinUsb_Initialize returns TRUE if the operation succeed
920 	BOOL result = WinUsb_Initialize(usb_device_handle, &usb_interface_0_handle);
921 	if (!result) goto exit_on_error;
922 
923     // Detect USB Dongle based Class, Subclass, and Protocol
924     // The class code (bDeviceClass) is 0xE0 – Wireless Controller.
925     // The SubClass code (bDeviceSubClass) is 0x01 – RF Controller.
926     // The Protocol code (bDeviceProtocol) is 0x01 – Bluetooth programming.
927     USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
928     result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
929     if (!result) goto exit_on_error;
930     //
931     if (usb_interface_descriptor.bInterfaceClass    != 0xe0 ||
932         usb_interface_descriptor.bInterfaceSubClass != 0x01 ||
933         usb_interface_descriptor.bInterfaceProtocol != 0x01){
934 
935         // TODO: fallback to whitelist
936         log_info("Class, Subclass, Protocol does not match Bluetooth device");
937         usb_free_resources();
938         return 0;
939     }
940 
941 #ifdef ENABLE_SCO_OVER_HCI
942 	log_info("Claiming interface 1...");
943 	// WinUsb_GetAssociatedInterface returns TRUE if the operation succeeds.
944 	// We use index 1 - assuming it refers to interface #1 with libusb
945 	// A value of 0 indicates the first associated interface, a value of 1 indicates the second associated interface, and so on.
946 	result = WinUsb_GetAssociatedInterface(usb_interface_0_handle, 0, &usb_interface_1_handle);
947 	if (!result) goto exit_on_error;
948 	log_info("Claiming interface 1: success");
949 #endif
950 
951     result = usb_scan_for_bluetooth_endpoints();
952     if (!result) {
953         log_error("Could not find all Bluetooth Endpoints!");
954         usb_free_resources();
955         return 0;
956     }
957 
958 #ifdef ENABLE_SCO_OVER_HCI
959     int i;
960 
961 	memset(hci_sco_packet_descriptors, 0, sizeof(hci_sco_packet_descriptors));
962 	log_info("Size of packet descriptors for SCO IN%u", (int) sizeof(hci_sco_packet_descriptors));
963 
964 	// setup async io && btstack handler
965 	memset(&usb_overlapped_sco_in, 0, sizeof(usb_overlapped_sco_in));
966 	for (i=0;i<ISOC_BUFFERS;i++){
967 		usb_overlapped_sco_in[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
968 		// log_info_hexdump(&usb_overlapped_sco_in[i], sizeof(OVERLAPPED));
969         // log_info("data source SCO in %u, handle %p", i, usb_overlapped_sco_in[i].hEvent);
970 		usb_data_source_sco_in[i].handle = usb_overlapped_sco_in[i].hEvent;
971 	    btstack_run_loop_set_data_source_handler(&usb_data_source_sco_in[i], &usb_process_sco_in);
972         btstack_run_loop_add_data_source(&usb_data_source_sco_in[i]);
973 	}
974 
975     memset(&usb_overlapped_sco_out, 0, sizeof(usb_overlapped_sco_out));
976     for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
977         usb_overlapped_sco_out[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
978         // log_info("data source SCO out %u, handle %p", i, usb_overlapped_sco_out[i].hEvent);
979         usb_data_source_sco_out[i].handle = usb_overlapped_sco_out[i].hEvent;
980         btstack_run_loop_set_data_source_handler(&usb_data_source_sco_out[i], &usb_process_sco_out);
981         btstack_run_loop_add_data_source(&usb_data_source_sco_out[i]);
982     }
983 #endif
984 
985 	// setup async io
986     memset(&usb_overlapped_event_in,     0, sizeof(usb_overlapped_event_in));
987     memset(&usb_overlapped_command_out,  0, sizeof(usb_overlapped_command_out));
988     memset(&usb_overlapped_acl_out,      0, sizeof(usb_overlapped_acl_out));
989     memset(&usb_overlapped_acl_in,       0, sizeof(usb_overlapped_acl_in));
990     usb_overlapped_event_in.hEvent    = CreateEvent(NULL, TRUE, FALSE, NULL);
991     usb_overlapped_command_out.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
992     usb_overlapped_acl_in.hEvent      = CreateEvent(NULL, TRUE, FALSE, NULL);
993     usb_overlapped_acl_out.hEvent     = CreateEvent(NULL, TRUE, FALSE, NULL);
994 
995 	// setup btstack data soures
996     usb_data_source_event_in.handle = usb_overlapped_event_in.hEvent;
997     btstack_run_loop_set_data_source_handler(&usb_data_source_event_in, &usb_process_event_in);
998     btstack_run_loop_add_data_source(&usb_data_source_event_in);
999 
1000     usb_data_source_command_out.handle = usb_overlapped_command_out.hEvent;
1001     btstack_run_loop_set_data_source_handler(&usb_data_source_command_out, &usb_process_command_out);
1002     btstack_run_loop_add_data_source(&usb_data_source_command_out);
1003 
1004     usb_data_source_acl_in.handle = usb_overlapped_acl_in.hEvent;
1005     btstack_run_loop_set_data_source_handler(&usb_data_source_acl_in, &usb_process_acl_in);
1006     btstack_run_loop_add_data_source(&usb_data_source_acl_in);
1007 
1008     usb_data_source_acl_out.handle = usb_overlapped_acl_out.hEvent;
1009     btstack_run_loop_set_data_source_handler(&usb_data_source_acl_out, &usb_process_acl_out);
1010     btstack_run_loop_add_data_source(&usb_data_source_acl_out);
1011 
1012     // submit all incoming transfers
1013     usb_submit_event_in_transfer();
1014     usb_submit_acl_in_transfer();
1015 	return 1;
1016 
1017 exit_on_error:
1018 	log_error("usb_try_open_device: last error %lu", GetLastError());
1019 	usb_free_resources();
1020 	return 0;
1021 }
1022 
1023 #ifdef ENABLE_SCO_OVER_HCI
1024 
1025 #define WinUSB_Lookup(fn) do { fn = (fn##_t) GetProcAddress(h, #fn); log_info("%-30s %p", #fn, fn); if (!fn) return FALSE; } while(0)
1026 
1027 static BOOL usb_lookup_symbols(void){
1028 	// lookup runtime symbols missing in current mingw64 distribution
1029 	HMODULE h = GetModuleHandleA("WinUSB");
1030 	log_info("%-30s %p", "WinUSB", h);
1031 	WinUSB_Lookup(WinUsb_QueryPipeEx);
1032 	WinUSB_Lookup(WinUsb_RegisterIsochBuffer);
1033 	WinUSB_Lookup(WinUsb_ReadIsochPipe);
1034 	WinUSB_Lookup(WinUsb_ReadIsochPipeAsap);
1035 	WinUSB_Lookup(WinUsb_WriteIsochPipe);
1036 	WinUSB_Lookup(WinUsb_WriteIsochPipeAsap);
1037 	WinUSB_Lookup(WinUsb_UnregisterIsochBuffer);
1038     WinUSB_Lookup(WinUsb_GetCurrentFrameNumber);
1039     return TRUE;
1040 }
1041 #endif
1042 
1043 // returns 0 on success, -1 otherwise
1044 static int usb_open(void){
1045 
1046     int r = -1;
1047 
1048 #ifdef ENABLE_SCO_OVER_HCI
1049 	BOOL ok = usb_lookup_symbols();
1050     if (!ok){
1051         log_error("usb_open: Failed to lookup WinSUB ISOCHRONOUS functions. Please disable ENABLE_SCO_OVER_HCI or use Windows 8.1 or higher");
1052         return r;
1053     }
1054     sco_state_machine_init();
1055     sco_ring_init();
1056 #endif
1057 
1058 	HDEVINFO                         hDevInfo;
1059 	SP_DEVICE_INTERFACE_DATA         DevIntfData;
1060 	PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
1061 	SP_DEVINFO_DATA                  DevData;
1062 
1063 	DWORD dwSize;
1064 	DWORD dwMemberIdx;
1065 
1066     // default endpoint addresses
1067     event_in_addr = 0x81; // EP1, IN interrupt
1068     acl_in_addr =   0x82; // EP2, IN bulk
1069     acl_out_addr =  0x02; // EP2, OUT bulk
1070     sco_in_addr  =  0x83; // EP3, IN isochronous
1071     sco_out_addr =  0x03; // EP3, OUT isochronous
1072 
1073 	// We will try to get device information set for all USB devices that have a
1074 	// device interface and are currently present on the system (plugged in).
1075 	hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
1076 
1077 	log_info("usb_open: SetupDiGetClassDevs -> %p", hDevInfo);
1078 	if (hDevInfo == INVALID_HANDLE_VALUE) return -1;
1079 
1080 	// Prepare to enumerate all device interfaces for the device information
1081 	// set that we retrieved with SetupDiGetClassDevs(..)
1082 	DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
1083 	dwMemberIdx = 0;
1084 
1085 	// Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
1086 	// function causes GetLastError() to return  ERROR_NO_MORE_ITEMS. With each
1087 	// call the dwMemberIdx value needs to be incremented to retrieve the next
1088 	// device interface information.
1089 
1090 	SetupDiEnumDeviceInterfaces(hDevInfo, NULL, (LPGUID) &GUID_DEVINTERFACE_USB_DEVICE,
1091 		dwMemberIdx, &DevIntfData);
1092 
1093 	while(GetLastError() != ERROR_NO_MORE_ITEMS){
1094 
1095 		// As a last step we will need to get some more details for each
1096 		// of device interface information we are able to retrieve. This
1097 		// device interface detail gives us the information we need to identify
1098 		// the device (VID/PID), and decide if it's useful to us. It will also
1099 		// provide a DEVINFO_DATA structure which we can use to know the serial
1100 		// port name for a virtual com port.
1101 
1102 		DevData.cbSize = sizeof(DevData);
1103 
1104 		// Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
1105 		// a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
1106 		// of zero, and a valid RequiredSize variable. In response to such a call,
1107 		// this function returns the required buffer size at dwSize.
1108 
1109 		SetupDiGetDeviceInterfaceDetail(
1110 			  hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
1111 
1112 		// Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
1113 		// deallocate it later!
1114 		DevIntfDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
1115 		DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
1116 
1117 		if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData,
1118 			DevIntfDetailData, dwSize, &dwSize, &DevData))
1119 		{
1120 			// Finally we can start checking if we've found a useable device,
1121 			// by inspecting the DevIntfDetailData->DevicePath variable.
1122 			// The DevicePath looks something like this:
1123 			//
1124 			// \\?\usb#vid_04d8&pid_0033#5&19f2438f&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
1125 			//
1126 
1127 			log_info("usb_open: Device Path: %s", DevIntfDetailData->DevicePath);
1128 
1129 #if 0
1130             // check for hard-coded vendor/product ids
1131 			char vid_pid_match[30];
1132 			uint16_t vid = 0x0a12;
1133 			uint16_t pid = 0x0001;
1134 			sprintf(vid_pid_match, "\\\\?\\usb#vid_%04x&pid_%04x", vid, pid);
1135 			if (strncmp(DevIntfDetailData->DevicePath, &vid_pid_match[0], strlen(vid_pid_match)) == 0 ){
1136 				log_info("Matched search string %s", vid_pid_match);
1137 
1138 				BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
1139 				if (result){
1140 					log_info("usb_open: Device opened, stop scanning");
1141 					r = 0;
1142 				} else {
1143 					log_error("usb_open: Device open failed");
1144 				}
1145 			}
1146 #endif
1147 
1148             // try all devices
1149             BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
1150             if (result){
1151                 log_info("usb_open: Device opened, stop scanning");
1152                 r = 0;
1153             } else {
1154                 log_error("usb_open: Device open failed");
1155             }
1156         }
1157 		HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
1158 
1159 		if (r == 0) break;
1160 
1161 		// Continue looping
1162 		SetupDiEnumDeviceInterfaces(
1163 			hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, ++dwMemberIdx, &DevIntfData);
1164 	}
1165 
1166 	SetupDiDestroyDeviceInfoList(hDevInfo);
1167 
1168 	log_info("usb_open: done");
1169 
1170     return r;
1171 }
1172 
1173 static int usb_close(void){
1174 
1175     // remove data sources
1176     btstack_run_loop_remove_data_source(&usb_data_source_command_out);
1177     btstack_run_loop_remove_data_source(&usb_data_source_event_in);
1178     btstack_run_loop_remove_data_source(&usb_data_source_acl_in);
1179     btstack_run_loop_remove_data_source(&usb_data_source_acl_out);
1180 
1181 #ifdef ENABLE_SCO_OVER_HCI
1182     int i;
1183     for (i=0;i<ISOC_BUFFERS;i++){
1184         btstack_run_loop_remove_data_source(&usb_data_source_sco_in[i]);
1185     }
1186     for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
1187         btstack_run_loop_remove_data_source(&usb_data_source_sco_out[i]);
1188     }
1189 #endif
1190 
1191     // stop transfers
1192     WinUsb_AbortPipe(usb_interface_0_handle, event_in_addr);
1193     WinUsb_AbortPipe(usb_interface_0_handle, acl_in_addr);
1194     WinUsb_AbortPipe(usb_interface_0_handle, acl_out_addr);
1195 #ifdef ENABLE_SCO_OVER_HCI
1196     usb_sco_stop();
1197 #endif
1198     usb_acl_out_active = 0;
1199 
1200     // control transfer cannot be stopped, just wait for completion
1201     if (usb_command_out_active){
1202         DWORD bytes_transferred;
1203         WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_command_out, &bytes_transferred, TRUE);
1204         usb_command_out_active = 0;
1205     }
1206 
1207     // free everything
1208     usb_free_resources();
1209     return 0;
1210 }
1211 
1212 static int usb_can_send_packet_now(uint8_t packet_type){
1213     // return 0;
1214     switch (packet_type){
1215         case HCI_COMMAND_DATA_PACKET:
1216             return !usb_command_out_active;
1217         case HCI_ACL_DATA_PACKET:
1218             return !usb_acl_out_active;
1219 #ifdef ENABLE_SCO_OVER_HCI
1220         case HCI_SCO_DATA_PACKET:
1221             // return 0;
1222             return sco_ring_have_space();
1223 #endif
1224         default:
1225             return 0;
1226     }
1227 }
1228 
1229 static int usb_send_cmd_packet(uint8_t *packet, int size){
1230 
1231     // update stata before submitting transfer
1232     usb_command_out_active = 1;
1233 
1234 	// Start trasnsfer
1235 	WINUSB_SETUP_PACKET setup_packet;
1236 	memset(&setup_packet, 0, sizeof(setup_packet));
1237 	setup_packet.RequestType =  USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE;
1238 	setup_packet.Length = sizeof(size);
1239 	BOOL result = WinUsb_ControlTransfer(usb_interface_0_handle, setup_packet, packet, size,  NULL, &usb_overlapped_command_out);
1240 	if (!result) {
1241 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1242 	}
1243 
1244     // IO_PENDING -> wait for completed
1245     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_command_out, DATA_SOURCE_CALLBACK_WRITE);
1246 
1247     return 0;
1248 
1249 exit_on_error:
1250 	log_error("winusb: last error %lu", GetLastError());
1251 	return -1;
1252 }
1253 
1254 static int usb_send_acl_packet(uint8_t *packet, int size){
1255 
1256     // update stata before submitting transfer
1257     usb_acl_out_active = 1;
1258 
1259 	// Start trasnsfer
1260 	BOOL ok = WinUsb_WritePipe(usb_interface_0_handle, acl_out_addr, packet, size,  NULL, &usb_overlapped_acl_out);
1261 	if (!ok) {
1262 		if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1263 	}
1264 
1265     // IO_PENDING -> wait for completed
1266     btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_out, DATA_SOURCE_CALLBACK_WRITE);
1267     return 0;
1268 
1269 exit_on_error:
1270 	log_error("winusb: last error %lu", GetLastError());
1271 	return -1;
1272 }
1273 
1274 #ifdef ENABLE_SCO_OVER_HCI
1275 static int usb_send_sco_packet(uint8_t *packet, int size){
1276 
1277     if (size > SCO_PACKET_SIZE){
1278         log_error("usb_send_sco_packet: size %u > SCO_PACKET_SIZE %u", size, SCO_PACKET_SIZE);
1279         return -1;
1280     }
1281 
1282     // get current frame number
1283     ULONG current_frame_number;
1284     LARGE_INTEGER timestamp;
1285     WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, &current_frame_number, &timestamp);
1286 
1287     // store packet in free slot
1288     int transfer_index = sco_ring_write;
1289     uint8_t * data = &sco_ring_buffer[transfer_index * SCO_PACKET_SIZE];
1290     memcpy(data, packet, size);
1291 
1292 
1293     // setup transfer
1294     int continue_stream = sco_ring_transfers_active > 0;
1295     BOOL ok = WinUsb_WriteIsochPipeAsap(hci_sco_out_buffer_handle, transfer_index * SCO_PACKET_SIZE, size, continue_stream, &usb_overlapped_sco_out[transfer_index]);
1296     // 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);
1297     if (!ok) {
1298         if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
1299     }
1300 
1301     // successful started transfer, enable data source callback if first active transfer
1302     if (sco_ring_transfers_active == 0){
1303         usb_sco_out_expected_transfer = transfer_index;
1304         btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
1305     }
1306 
1307     // mark slot as full
1308     sco_ring_write = (sco_ring_write + 1) % SCO_RING_BUFFER_COUNT;
1309     sco_ring_transfers_active++;
1310 
1311     // notify upper stack that provided buffer can be used again
1312     uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
1313     packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
1314 
1315     // log_info("usb_send_sco_packet: transfers active %u", sco_ring_transfers_active);
1316 
1317     // and if we have more space for SCO packets
1318     if (sco_ring_have_space()) {
1319         uint8_t event_sco[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
1320         packet_handler(HCI_EVENT_PACKET, &event_sco[0], sizeof(event_sco));
1321     }
1322     return 0;
1323 
1324 exit_on_error:
1325     log_error("usb_send_sco_packet: last error %lu", GetLastError());
1326     return -1;
1327 }
1328 #endif
1329 
1330 static int usb_send_packet(uint8_t packet_type, uint8_t * packet, int size){
1331     switch (packet_type){
1332         case HCI_COMMAND_DATA_PACKET:
1333             return usb_send_cmd_packet(packet, size);
1334         case HCI_ACL_DATA_PACKET:
1335             return usb_send_acl_packet(packet, size);
1336 #ifdef ENABLE_SCO_OVER_HCI
1337         case HCI_SCO_DATA_PACKET:
1338             return usb_send_sco_packet(packet, size);
1339 #endif
1340         default:
1341             return -1;
1342     }
1343 }
1344 
1345 #ifdef ENABLE_SCO_OVER_HCI
1346 static void usb_set_sco_config(uint16_t voice_setting, int num_connections){
1347     log_info("usb_set_sco_config: voice settings 0x%04x, num connections %u", voice_setting, num_connections);
1348 
1349     if (num_connections != sco_num_connections){
1350         sco_voice_setting = voice_setting;
1351         if (sco_num_connections){
1352            usb_sco_stop();
1353         }
1354         sco_num_connections = num_connections;
1355         if (num_connections){
1356            usb_sco_start();
1357         }
1358     }
1359 }
1360 #endif
1361 
1362 // get usb singleton
1363 static const hci_transport_t hci_transport_usb = {
1364     /* const char * name; */                                        "H2_WINUSB",
1365     /* void   (*init) (const void *transport_config); */            &usb_init,
1366     /* int    (*open)(void); */                                     &usb_open,
1367     /* int    (*close)(void); */                                    &usb_close,
1368     /* void   (*register_packet_handler)(void (*handler)(...); */   &usb_register_packet_handler,
1369     /* int    (*can_send_packet_now)(uint8_t packet_type); */       &usb_can_send_packet_now,
1370     /* int    (*send_packet)(...); */                               &usb_send_packet,
1371     /* int    (*set_baudrate)(uint32_t baudrate); */                NULL,
1372     /* void   (*reset_link)(void); */                               NULL,
1373     /* void   (*set_sco_config)(uint16_t voice_setting, int num_connections); */ usb_set_sco_config,
1374 };
1375 
1376 const hci_transport_t * hci_transport_usb_instance(void) {
1377     return &hci_transport_usb;
1378 }
1379