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