15da69017SMatthias Ringwald /*
25da69017SMatthias Ringwald * Copyright (C) 2014 BlueKitchen GmbH
35da69017SMatthias Ringwald *
45da69017SMatthias Ringwald * Redistribution and use in source and binary forms, with or without
55da69017SMatthias Ringwald * modification, are permitted provided that the following conditions
65da69017SMatthias Ringwald * are met:
75da69017SMatthias Ringwald *
85da69017SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright
95da69017SMatthias Ringwald * notice, this list of conditions and the following disclaimer.
105da69017SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright
115da69017SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the
125da69017SMatthias Ringwald * documentation and/or other materials provided with the distribution.
135da69017SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of
145da69017SMatthias Ringwald * contributors may be used to endorse or promote products derived
155da69017SMatthias Ringwald * from this software without specific prior written permission.
165da69017SMatthias Ringwald * 4. Any redistribution, use, or modification is done solely for
175da69017SMatthias Ringwald * personal benefit and not for any commercial purpose or for
185da69017SMatthias Ringwald * monetary gain.
195da69017SMatthias Ringwald *
205da69017SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
215da69017SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225da69017SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
255da69017SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
265da69017SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
275da69017SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
285da69017SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
295da69017SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
305da69017SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
315da69017SMatthias Ringwald * SUCH DAMAGE.
325da69017SMatthias Ringwald *
335da69017SMatthias Ringwald * Please inquire about commercial licensing options at
345da69017SMatthias Ringwald * [email protected]
355da69017SMatthias Ringwald *
365da69017SMatthias Ringwald */
37ab2c6ae4SMatthias Ringwald
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "hci_transport_h2_winusb.c"
395da69017SMatthias Ringwald
405da69017SMatthias Ringwald /*
415da69017SMatthias Ringwald * hci_transport_usb.c
425da69017SMatthias Ringwald *
435da69017SMatthias Ringwald * HCI Transport API implementation for USB
445da69017SMatthias Ringwald *
455da69017SMatthias Ringwald * Created by Matthias Ringwald on 7/5/09.
465da69017SMatthias Ringwald */
475da69017SMatthias Ringwald
485da69017SMatthias Ringwald // Interface Number - Alternate Setting - suggested Endpoint Address - Endpoint Type - Suggested Max Packet Size
495da69017SMatthias Ringwald // HCI Commands 0 0 0x00 Control 8/16/32/64
505da69017SMatthias Ringwald // HCI Events 0 0 0x81 Interrupt (IN) 16
515da69017SMatthias Ringwald // ACL Data 0 0 0x82 Bulk (IN) 32/64
525da69017SMatthias Ringwald // ACL Data 0 0 0x02 Bulk (OUT) 32/64
535da69017SMatthias Ringwald // SCO Data 0 0 0x83 Isochronous (IN)
545da69017SMatthias Ringwald // SCO Data 0 0 0x03 Isochronous (Out)
555da69017SMatthias Ringwald
56*b795dcd0SMarcel Wappler #include <Windows.h>
57*b795dcd0SMarcel Wappler
585da69017SMatthias Ringwald #include <stdio.h>
595da69017SMatthias Ringwald #include <string.h>
605da69017SMatthias Ringwald #include <sys/types.h>
61f258f416SMatthias Ringwald #include <inttypes.h> // to print long long int (aka 64 bit ints)
625da69017SMatthias Ringwald
635da69017SMatthias Ringwald #include "btstack_config.h"
645da69017SMatthias Ringwald
655da69017SMatthias Ringwald #include "btstack_debug.h"
665da69017SMatthias Ringwald #include "hci.h"
675da69017SMatthias Ringwald #include "hci_transport.h"
68c8dfe071SMatthias Ringwald #include "hci_transport_usb.h"
695da69017SMatthias Ringwald
705da69017SMatthias Ringwald #include <SetupAPI.h>
715da69017SMatthias Ringwald #include <Winusb.h>
725da69017SMatthias Ringwald
73f258f416SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
745da69017SMatthias Ringwald
755da69017SMatthias Ringwald // Isochronous Add-On
765da69017SMatthias Ringwald
77f258f416SMatthias Ringwald // Function signatures frome https://abi-laboratory.pro/compatibility/Windows_7.0_to_Windows_8.1/x86_64/info/winusb.dll/symbols.html
78f258f416SMatthias Ringwald // MSDN documentation has multiple errors (Jan 2017), annotated below
79f258f416SMatthias Ringwald
80ecf76c8dSMatthias Ringwald // As Isochochronous functions are provided by newer versions of ming64, we use a BTstack/BTSTACK prefix to prevent name collisions
81f258f416SMatthias Ringwald
82ecf76c8dSMatthias Ringwald typedef PVOID BTSTACK_WINUSB_ISOCH_BUFFER_HANDLE, *BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE;
83ecf76c8dSMatthias Ringwald
84ecf76c8dSMatthias Ringwald typedef struct _BTSTACK_WINUSB_PIPE_INFORMATION_EX {
855da69017SMatthias Ringwald USBD_PIPE_TYPE PipeType;
865da69017SMatthias Ringwald UCHAR PipeId;
875da69017SMatthias Ringwald USHORT MaximumPacketSize;
885da69017SMatthias Ringwald UCHAR Interval;
895da69017SMatthias Ringwald ULONG MaximumBytesPerInterval;
90ecf76c8dSMatthias Ringwald } BTSTACK_WINUSB_PIPE_INFORMATION_EX, *BTSTACK_PWINUSB_PIPE_INFORMATION_EX;
915da69017SMatthias Ringwald
92b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_QueryPipeEx_t) (
935da69017SMatthias Ringwald WINUSB_INTERFACE_HANDLE InterfaceHandle,
945da69017SMatthias Ringwald UCHAR AlternateInterfaceNumber,
955da69017SMatthias Ringwald UCHAR PipeIndex,
96ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_PIPE_INFORMATION_EX PipeInformationEx
975da69017SMatthias Ringwald );
98b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_RegisterIsochBuffer_t)(
995da69017SMatthias Ringwald WINUSB_INTERFACE_HANDLE InterfaceHandle,
1005da69017SMatthias Ringwald UCHAR PipeID,
1015da69017SMatthias Ringwald PVOID Buffer,
1025da69017SMatthias Ringwald ULONG BufferLength,
103ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
1045da69017SMatthias Ringwald );
105b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_ReadIsochPipe_t)(
106ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
1075da69017SMatthias Ringwald ULONG Offset,
1085da69017SMatthias Ringwald ULONG Length,
1095da69017SMatthias Ringwald PULONG FrameNumber,
110f258f416SMatthias Ringwald ULONG NumberOfPackets, // MSDN lists PULONG
111f258f416SMatthias Ringwald PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors, // MSDN lists PULONG
1125da69017SMatthias Ringwald LPOVERLAPPED Overlapped
1135da69017SMatthias Ringwald );
114b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_ReadIsochPipeAsap_t)(
115ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
1165da69017SMatthias Ringwald ULONG Offset,
1175da69017SMatthias Ringwald ULONG Length,
1185da69017SMatthias Ringwald BOOL ContinueStream,
119f258f416SMatthias Ringwald ULONG NumberOfPackets, // MSDN lists PULONG
1205da69017SMatthias Ringwald PUSBD_ISO_PACKET_DESCRIPTOR IsoPacketDescriptors,
1215da69017SMatthias Ringwald LPOVERLAPPED Overlapped
1225da69017SMatthias Ringwald );
123b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_WriteIsochPipe_t)(
124ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
1255da69017SMatthias Ringwald ULONG Offset,
1265da69017SMatthias Ringwald ULONG Length,
1275da69017SMatthias Ringwald PULONG FrameNumber,
1285da69017SMatthias Ringwald LPOVERLAPPED Overlapped
1295da69017SMatthias Ringwald );
130b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_WriteIsochPipeAsap_t)(
131ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle,
1325da69017SMatthias Ringwald ULONG Offset,
1335da69017SMatthias Ringwald ULONG Length,
1345da69017SMatthias Ringwald BOOL ContinueStream,
1355da69017SMatthias Ringwald LPOVERLAPPED Overlapped
1365da69017SMatthias Ringwald );
137b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_UnregisterIsochBuffer_t)(
138ecf76c8dSMatthias Ringwald BTSTACK_PWINUSB_ISOCH_BUFFER_HANDLE BufferHandle
1395da69017SMatthias Ringwald );
140b115538eSMatthias Ringwald typedef BOOL (WINAPI * BTstack_WinUsb_GetCurrentFrameNumber_t)(
141f258f416SMatthias Ringwald WINUSB_INTERFACE_HANDLE InterfaceHandle, // MSDN lists 'Device handle returned from CreateFile'
142f258f416SMatthias Ringwald PULONG CurrentFrameNumber,
143f258f416SMatthias Ringwald LARGE_INTEGER *TimeStamp
144f258f416SMatthias Ringwald );
1455da69017SMatthias Ringwald
146ecf76c8dSMatthias Ringwald static BTstack_WinUsb_QueryPipeEx_t BTstack_WinUsb_QueryPipeEx;
147ecf76c8dSMatthias Ringwald static BTstack_WinUsb_RegisterIsochBuffer_t BTstack_WinUsb_RegisterIsochBuffer;
148ecf76c8dSMatthias Ringwald static BTstack_WinUsb_ReadIsochPipe_t BTstack_WinUsb_ReadIsochPipe;
149ecf76c8dSMatthias Ringwald static BTstack_WinUsb_ReadIsochPipeAsap_t BTstack_WinUsb_ReadIsochPipeAsap;
150ecf76c8dSMatthias Ringwald static BTstack_WinUsb_WriteIsochPipe_t BTstack_WinUsb_WriteIsochPipe;
151ecf76c8dSMatthias Ringwald static BTstack_WinUsb_WriteIsochPipeAsap_t BTstack_WinUsb_WriteIsochPipeAsap;
152ecf76c8dSMatthias Ringwald static BTstack_WinUsb_UnregisterIsochBuffer_t BTstack_WinUsb_UnregisterIsochBuffer;
153ecf76c8dSMatthias Ringwald static BTstack_WinUsb_GetCurrentFrameNumber_t BTstack_WinUsb_GetCurrentFrameNumber;
1545da69017SMatthias Ringwald #endif
1555da69017SMatthias Ringwald
15608dc2fadSMatthias Ringwald // Doesn't work as expected
15708dc2fadSMatthias Ringwald // #define SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
15808dc2fadSMatthias Ringwald
15908dc2fadSMatthias Ringwald // Not tested yet
16008dc2fadSMatthias Ringwald // #define SCHEDULE_SCO_OUT_TRANSFERS_MANUALLY
16108dc2fadSMatthias Ringwald
1625da69017SMatthias Ringwald //
1635da69017SMatthias Ringwald // Bluetooth USB Transport Alternate Settings:
1645da69017SMatthias Ringwald //
1655da69017SMatthias Ringwald // 0: No active voice channels (for USB compliance)
1665da69017SMatthias Ringwald // 1: One 8 kHz voice channel with 8-bit encoding
1675da69017SMatthias Ringwald // 2: Two 8 kHz voice channels with 8-bit encoding or one 8 kHz voice channel with 16-bit encoding
1685da69017SMatthias Ringwald // 3: Three 8 kHz voice channels with 8-bit encoding
1695da69017SMatthias Ringwald // 4: Two 8 kHz voice channels with 16-bit encoding or one 16 kHz voice channel with 16-bit encoding
1705da69017SMatthias Ringwald // 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
1715da69017SMatthias Ringwald // --> support only a single SCO connection
1725da69017SMatthias Ringwald #define ALT_SETTING (1)
1735da69017SMatthias Ringwald
174a93756fcSMatthias Ringwald // alt setting for 1-3 connections and 8/16 bit
175a93756fcSMatthias Ringwald const int alt_setting_8_bit[] = {1,2,3};
176a93756fcSMatthias Ringwald const int alt_setting_16_bit[] = {2,4,5};
177a93756fcSMatthias Ringwald
1785da69017SMatthias Ringwald // for ALT_SETTING >= 1 and 8-bit channel, we need the following isochronous packets
1795da69017SMatthias Ringwald // One complete SCO packet with 24 frames every 3 frames (== 3 ms)
18008dc2fadSMatthias Ringwald #define NUM_ISO_PACKETS (3)
1815da69017SMatthias Ringwald
182a93756fcSMatthias Ringwald const uint16_t iso_packet_size_for_alt_setting[] = {
183a93756fcSMatthias Ringwald 0,
184a93756fcSMatthias Ringwald 9,
185a93756fcSMatthias Ringwald 17,
186a93756fcSMatthias Ringwald 25,
187a93756fcSMatthias Ringwald 33,
188a93756fcSMatthias Ringwald 49,
189a93756fcSMatthias Ringwald 63,
190a93756fcSMatthias Ringwald };
191a93756fcSMatthias Ringwald
1925da69017SMatthias Ringwald // 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)
1935da69017SMatthias Ringwald // 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
1945a97f1baSMatthias Ringwald #define SCO_PACKET_SIZE (49 * NUM_ISO_PACKETS)
1955da69017SMatthias Ringwald
19608dc2fadSMatthias Ringwald #define ISOC_BUFFERS 8
1975da69017SMatthias Ringwald
198f258f416SMatthias Ringwald // Outgoing SCO packet queue
199f258f416SMatthias Ringwald // simplified ring buffer implementation
20011cb6f2dSMatthias Ringwald #define SCO_RING_BUFFER_COUNT (20)
201f258f416SMatthias Ringwald #define SCO_RING_BUFFER_SIZE (SCO_RING_BUFFER_COUNT * SCO_PACKET_SIZE)
202f258f416SMatthias Ringwald
2035da69017SMatthias Ringwald /** Request type bits of the "bmRequestType" field in control transfers. */
2045da69017SMatthias Ringwald enum usb_request_type {
2055da69017SMatthias Ringwald USB_REQUEST_TYPE_STANDARD = (0x00 << 5),
2065da69017SMatthias Ringwald USB_REQUEST_TYPE_CLASS = (0x01 << 5),
2075da69017SMatthias Ringwald USB_REQUEST_TYPE_VENDOR = (0x02 << 5),
2085da69017SMatthias Ringwald };
2095da69017SMatthias Ringwald
2105da69017SMatthias Ringwald /** Recipient bits of the "bmRequestType" field in control transfers. Values 4 through 31 are reserved. */
2115da69017SMatthias Ringwald enum usb_request_recipient {
2125da69017SMatthias Ringwald USB_RECIPIENT_DEVICE = 0x00,
2135da69017SMatthias Ringwald USB_RECIPIENT_INTERFACE = 0x01,
2145da69017SMatthias Ringwald USB_RECIPIENT_ENDPOINT = 0x02,
2155da69017SMatthias Ringwald USB_RECIPIENT_OTHER = 0x03,
2165da69017SMatthias Ringwald };
2175da69017SMatthias Ringwald
2185da69017SMatthias Ringwald // This is the GUID for the USB device class
2195da69017SMatthias Ringwald static GUID GUID_DEVINTERFACE_USB_DEVICE =
2205da69017SMatthias Ringwald { 0xA5DCBF10L, 0x6530, 0x11D2, { 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED } };
2215da69017SMatthias Ringwald
2225da69017SMatthias Ringwald static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size);
2235da69017SMatthias Ringwald
2245da69017SMatthias Ringwald static void (*packet_handler)(uint8_t packet_type, uint8_t *packet, uint16_t size) = &usb_dummy_handler;
2255da69017SMatthias Ringwald
2265da69017SMatthias Ringwald // endpoint addresses
2275da69017SMatthias Ringwald static int event_in_addr;
2285da69017SMatthias Ringwald static int acl_in_addr;
2295da69017SMatthias Ringwald static int acl_out_addr;
2305da69017SMatthias Ringwald static int sco_in_addr;
2315da69017SMatthias Ringwald static int sco_out_addr;
2325da69017SMatthias Ringwald
2335da69017SMatthias Ringwald //
2345da69017SMatthias Ringwald static HANDLE usb_device_handle;
2355da69017SMatthias Ringwald static WINUSB_INTERFACE_HANDLE usb_interface_0_handle;
2365da69017SMatthias Ringwald static WINUSB_INTERFACE_HANDLE usb_interface_1_handle;
2375da69017SMatthias Ringwald static OVERLAPPED usb_overlapped_event_in;
2385da69017SMatthias Ringwald static OVERLAPPED usb_overlapped_command_out;
2395da69017SMatthias Ringwald static OVERLAPPED usb_overlapped_acl_in;
2405da69017SMatthias Ringwald static OVERLAPPED usb_overlapped_acl_out;
2415da69017SMatthias Ringwald static btstack_data_source_t usb_data_source_event_in;
2425da69017SMatthias Ringwald static btstack_data_source_t usb_data_source_command_out;
2435da69017SMatthias Ringwald static btstack_data_source_t usb_data_source_acl_in;
2445da69017SMatthias Ringwald static btstack_data_source_t usb_data_source_acl_out;
2455da69017SMatthias Ringwald
2465da69017SMatthias Ringwald //
2475da69017SMatthias Ringwald static int usb_command_out_active;
2485da69017SMatthias Ringwald static int usb_acl_out_active;
2495da69017SMatthias Ringwald
2505da69017SMatthias Ringwald // buffer for HCI Events and ACL Packets
2515da69017SMatthias Ringwald static uint8_t hci_event_in_buffer[2 + 255];
2525da69017SMatthias Ringwald static uint8_t hci_acl_in_buffer[HCI_INCOMING_PRE_BUFFER_SIZE + HCI_ACL_BUFFER_SIZE];
2535da69017SMatthias Ringwald
254d2b52257SMatthias Ringwald // transport interface state
255d2b52257SMatthias Ringwald static int usb_transport_open;
256f258f416SMatthias Ringwald
257e29e1f07SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
258e29e1f07SMatthias Ringwald
259f258f416SMatthias Ringwald typedef enum {
260f258f416SMatthias Ringwald H2_W4_SCO_HEADER = 1,
261f258f416SMatthias Ringwald H2_W4_PAYLOAD,
262f258f416SMatthias Ringwald } H2_SCO_STATE;
263f258f416SMatthias Ringwald
2645da69017SMatthias Ringwald // SCO Incoming Windows
2655da69017SMatthias Ringwald static uint8_t hci_sco_in_buffer[ISOC_BUFFERS * SCO_PACKET_SIZE];
266ecf76c8dSMatthias Ringwald static BTSTACK_WINUSB_ISOCH_BUFFER_HANDLE hci_sco_in_buffer_handle;
2675da69017SMatthias Ringwald static USBD_ISO_PACKET_DESCRIPTOR hci_sco_packet_descriptors[ISOC_BUFFERS * NUM_ISO_PACKETS];
2685da69017SMatthias Ringwald static OVERLAPPED usb_overlapped_sco_in[ISOC_BUFFERS];
269f258f416SMatthias Ringwald static int usb_sco_in_expected_transfer;
2705da69017SMatthias Ringwald
2715da69017SMatthias Ringwald // SCO Incoming Run Loop
2725da69017SMatthias Ringwald static btstack_data_source_t usb_data_source_sco_in[ISOC_BUFFERS];
2735da69017SMatthias Ringwald
2745da69017SMatthias Ringwald // SCO Incoming HCI
2755da69017SMatthias Ringwald static H2_SCO_STATE sco_state;
2765da69017SMatthias Ringwald static uint8_t sco_buffer[SCO_PACKET_SIZE];
2775da69017SMatthias Ringwald static uint16_t sco_read_pos;
2785da69017SMatthias Ringwald static uint16_t sco_bytes_to_read;
2795da69017SMatthias Ringwald
280f258f416SMatthias Ringwald // SCO Outgoing Windows
281ecf76c8dSMatthias Ringwald static BTSTACK_WINUSB_ISOCH_BUFFER_HANDLE hci_sco_out_buffer_handle;
282f258f416SMatthias Ringwald static OVERLAPPED usb_overlapped_sco_out[SCO_RING_BUFFER_COUNT];
283f258f416SMatthias Ringwald static int sco_ring_transfers_active;
28483f31aa4SMatthias Ringwald static int usb_sco_out_expected_transfer;
285f258f416SMatthias Ringwald
286fdd32934SMatthias Ringwald #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
287f258f416SMatthias Ringwald // next tranfer
288f258f416SMatthias Ringwald static ULONG sco_next_transfer_at_frame;
289fdd32934SMatthias Ringwald #endif
290f258f416SMatthias Ringwald
291f258f416SMatthias Ringwald // SCO Outgoing Run Loop
292f258f416SMatthias Ringwald static btstack_data_source_t usb_data_source_sco_out[SCO_RING_BUFFER_COUNT];
293f258f416SMatthias Ringwald
294f258f416SMatthias Ringwald // SCO Outgoing HCI
295f258f416SMatthias Ringwald static uint8_t sco_ring_buffer[SCO_RING_BUFFER_SIZE];
296f258f416SMatthias Ringwald static int sco_ring_write; // packet idx
297f258f416SMatthias Ringwald
2981b3ee5c3SMatthias Ringwald // SCO Reconfiguration - pause/resume
2991b3ee5c3SMatthias Ringwald static uint16_t sco_voice_setting;
3001b3ee5c3SMatthias Ringwald static int sco_num_connections;
301c6ac61cdSMatthias Ringwald static int sco_shutdown;
3025a97f1baSMatthias Ringwald
3035a97f1baSMatthias Ringwald static uint16_t iso_packet_size;
304e29e1f07SMatthias Ringwald #endif
305e29e1f07SMatthias Ringwald
30683159bb6SMatthias Ringwald // list of known devices, using VendorID/ProductID tuples
30783159bb6SMatthias Ringwald static const uint16_t known_bluetooth_devices[] = {
3089c30c2b3SMatthias Ringwald // BCM20702A0 - DeLOCK Bluetooth 4.0
30983159bb6SMatthias Ringwald 0x0a5c, 0x21e8,
3109c30c2b3SMatthias Ringwald // BCM20702A0 - Asus BT400
31183159bb6SMatthias Ringwald 0x0b05, 0x17cb,
3129c30c2b3SMatthias Ringwald // BCM20702B0 - Generic USB Detuned Class 1 @ 20 MHz
313bc71fcbbSMatthias Ringwald 0x0a5c, 0x22be,
3149c30c2b3SMatthias Ringwald // nRF5x Zephyr USB HCI, e.g nRF52840-PCA10056
3159c30c2b3SMatthias Ringwald 0x2fe3, 0x0100,
3169c30c2b3SMatthias Ringwald 0x2fe3, 0x000b,
31783159bb6SMatthias Ringwald };
31883159bb6SMatthias Ringwald
31983159bb6SMatthias Ringwald static int num_known_devices = sizeof(known_bluetooth_devices) / sizeof(uint16_t) / 2;
32083159bb6SMatthias Ringwald
32118343f0bSMatthias Ringwald // known devices
32218343f0bSMatthias Ringwald typedef struct {
32318343f0bSMatthias Ringwald btstack_linked_item_t next;
32418343f0bSMatthias Ringwald uint16_t vendor_id;
32518343f0bSMatthias Ringwald uint16_t product_id;
32618343f0bSMatthias Ringwald } usb_known_device_t;
32718343f0bSMatthias Ringwald
32818343f0bSMatthias Ringwald static btstack_linked_list_t usb_knwon_devices;
32918343f0bSMatthias Ringwald
hci_transport_usb_add_device(uint16_t vendor_id,uint16_t product_id)33018343f0bSMatthias Ringwald void hci_transport_usb_add_device(uint16_t vendor_id, uint16_t product_id) {
33118343f0bSMatthias Ringwald usb_known_device_t * device = malloc(sizeof(usb_known_device_t));
33218343f0bSMatthias Ringwald if (device != NULL) {
33318343f0bSMatthias Ringwald device->vendor_id = vendor_id;
33418343f0bSMatthias Ringwald device->product_id = product_id;
33518343f0bSMatthias Ringwald btstack_linked_list_add(&usb_knwon_devices, (btstack_linked_item_t *) device);
33683159bb6SMatthias Ringwald }
33783159bb6SMatthias Ringwald }
33883159bb6SMatthias Ringwald
usb_is_vmware_bluetooth_adapter(const char * device_path)33918343f0bSMatthias Ringwald static bool usb_is_vmware_bluetooth_adapter(const char * device_path){
3409d31f827SMilanka Ringwald // VMware Vendor ID 0e0f
3419d31f827SMilanka Ringwald const char * pos = strstr(device_path, "\\usb#vid_0e0f&pid");
34218343f0bSMatthias Ringwald return (pos > 0);
34318343f0bSMatthias Ringwald }
34418343f0bSMatthias Ringwald
usb_device_path_match(const char * device_path,uint16_t vendor_id,uint16_t product_id)34569007160SMatthias Ringwald static bool usb_device_path_match(const char * device_path, uint16_t vendor_id, uint16_t product_id){
34618343f0bSMatthias Ringwald // construct pid/vid substring
34718343f0bSMatthias Ringwald char substring[20];
348d900fa19SMatthias Ringwald sprintf_s(substring, sizeof(substring), "vid_%04x&pid_%04x", vendor_id, product_id);
34918343f0bSMatthias Ringwald const char * pos = strstr(device_path, substring);
35018343f0bSMatthias Ringwald log_info("check %s in %s -> %p", substring, device_path, pos);
35118343f0bSMatthias Ringwald return (pos > 0);
35218343f0bSMatthias Ringwald }
35318343f0bSMatthias Ringwald
usb_is_known_bluetooth_device(const char * device_path)35418343f0bSMatthias Ringwald static bool usb_is_known_bluetooth_device(const char * device_path){
35518343f0bSMatthias Ringwald int i;
35618343f0bSMatthias Ringwald for (i=0; i<num_known_devices; i++){
35769007160SMatthias Ringwald if (usb_device_path_match( device_path, known_bluetooth_devices[i*2], known_bluetooth_devices[i*2+1])){
35818343f0bSMatthias Ringwald return true;
35918343f0bSMatthias Ringwald }
36018343f0bSMatthias Ringwald }
36118343f0bSMatthias Ringwald btstack_linked_list_iterator_t it;
36218343f0bSMatthias Ringwald btstack_linked_list_iterator_init(&it, &usb_knwon_devices);
36318343f0bSMatthias Ringwald while (btstack_linked_list_iterator_has_next(&it)) {
36418343f0bSMatthias Ringwald usb_known_device_t * device = (usb_known_device_t *) btstack_linked_list_iterator_next(&it);
36569007160SMatthias Ringwald if (usb_device_path_match( device_path, device->vendor_id, device->product_id)){
36618343f0bSMatthias Ringwald return true;
36718343f0bSMatthias Ringwald }
36818343f0bSMatthias Ringwald }
36918343f0bSMatthias Ringwald return false;
3709d31f827SMilanka Ringwald }
3719d31f827SMilanka Ringwald
372f258f416SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
sco_ring_init(void)373f258f416SMatthias Ringwald static void sco_ring_init(void){
374f258f416SMatthias Ringwald sco_ring_write = 0;
375f258f416SMatthias Ringwald sco_ring_transfers_active = 0;
376f258f416SMatthias Ringwald }
sco_ring_have_space(void)377f258f416SMatthias Ringwald static int sco_ring_have_space(void){
378f258f416SMatthias Ringwald return sco_ring_transfers_active < SCO_RING_BUFFER_COUNT;
379f258f416SMatthias Ringwald }
usb_sco_register_buffers(void)380c4cea4aeSMatthias Ringwald static void usb_sco_register_buffers(void){
381c4cea4aeSMatthias Ringwald BOOL result;
382ecf76c8dSMatthias Ringwald result = BTstack_WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_in_addr, hci_sco_in_buffer, sizeof(hci_sco_in_buffer), &hci_sco_in_buffer_handle);
383c4cea4aeSMatthias Ringwald if (!result) {
384c4cea4aeSMatthias Ringwald log_error("usb_sco_register_buffers: register in buffer failed, error %lu", GetLastError());
385c4cea4aeSMatthias Ringwald }
386c4cea4aeSMatthias Ringwald log_info("hci_sco_in_buffer_handle %p", hci_sco_in_buffer_handle);
387c4cea4aeSMatthias Ringwald
388ecf76c8dSMatthias Ringwald result = BTstack_WinUsb_RegisterIsochBuffer(usb_interface_1_handle, sco_out_addr, sco_ring_buffer, sizeof(sco_ring_buffer), &hci_sco_out_buffer_handle);
389c4cea4aeSMatthias Ringwald if (!result) {
390c4cea4aeSMatthias Ringwald log_error("usb_sco_unregister_buffers: register out buffer failed, error %lu", GetLastError());
391c4cea4aeSMatthias Ringwald }
392c4cea4aeSMatthias Ringwald log_info("hci_sco_out_buffer_handle %p", hci_sco_out_buffer_handle);
393c4cea4aeSMatthias Ringwald }
usb_sco_unregister_buffers(void)394c4cea4aeSMatthias Ringwald static void usb_sco_unregister_buffers(void){
395c4cea4aeSMatthias Ringwald if (hci_sco_in_buffer_handle){
396ecf76c8dSMatthias Ringwald BTstack_WinUsb_UnregisterIsochBuffer(hci_sco_in_buffer_handle);
397c4cea4aeSMatthias Ringwald hci_sco_in_buffer_handle = NULL;
398c4cea4aeSMatthias Ringwald }
399c4cea4aeSMatthias Ringwald if (hci_sco_out_buffer_handle){
400ecf76c8dSMatthias Ringwald BTstack_WinUsb_UnregisterIsochBuffer(hci_sco_out_buffer_handle);
401c4cea4aeSMatthias Ringwald hci_sco_out_buffer_handle = NULL;
402c4cea4aeSMatthias Ringwald }
403c4cea4aeSMatthias Ringwald }
404f258f416SMatthias Ringwald #endif
405f258f416SMatthias Ringwald
usb_register_packet_handler(void (* handler)(uint8_t packet_type,uint8_t * packet,uint16_t size))4065da69017SMatthias Ringwald static void usb_register_packet_handler(void (*handler)(uint8_t packet_type, uint8_t *packet, uint16_t size)){
4075da69017SMatthias Ringwald log_info("registering packet handler");
4085da69017SMatthias Ringwald packet_handler = handler;
4095da69017SMatthias Ringwald }
4105da69017SMatthias Ringwald
usb_dummy_handler(uint8_t packet_type,uint8_t * packet,uint16_t size)4115da69017SMatthias Ringwald static void usb_dummy_handler(uint8_t packet_type, uint8_t *packet, uint16_t size){
4125da69017SMatthias Ringwald }
4135da69017SMatthias Ringwald
usb_init(const void * transport_config)4145da69017SMatthias Ringwald static void usb_init(const void *transport_config){
4155da69017SMatthias Ringwald }
4165da69017SMatthias Ringwald
usb_free_resources(void)4175da69017SMatthias Ringwald static void usb_free_resources(void){
4185da69017SMatthias Ringwald if (usb_interface_1_handle){
4195da69017SMatthias Ringwald WinUsb_Free(usb_interface_1_handle);
4205da69017SMatthias Ringwald usb_interface_1_handle = NULL;
4215da69017SMatthias Ringwald }
4225da69017SMatthias Ringwald
4235da69017SMatthias Ringwald if (usb_interface_0_handle){
4245da69017SMatthias Ringwald WinUsb_Free(usb_interface_0_handle);
4255da69017SMatthias Ringwald usb_interface_0_handle = NULL;
4265da69017SMatthias Ringwald }
4275da69017SMatthias Ringwald
4285da69017SMatthias Ringwald if (usb_device_handle) {
4295da69017SMatthias Ringwald CloseHandle(usb_device_handle);
4305da69017SMatthias Ringwald usb_device_handle = NULL;
4315da69017SMatthias Ringwald }
432e29e1f07SMatthias Ringwald
433e29e1f07SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
434c4cea4aeSMatthias Ringwald usb_sco_unregister_buffers();
435e29e1f07SMatthias Ringwald #endif
4365da69017SMatthias Ringwald }
4375da69017SMatthias Ringwald
usb_submit_event_in_transfer(void)4385da69017SMatthias Ringwald static void usb_submit_event_in_transfer(void){
4395da69017SMatthias Ringwald // submit transfer
4405da69017SMatthias Ringwald 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);
4415da69017SMatthias Ringwald if (!result) {
4425da69017SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
4435da69017SMatthias Ringwald }
4445da69017SMatthias Ringwald
4455da69017SMatthias Ringwald // IO_PENDING -> wait for completed
4465da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_event_in, DATA_SOURCE_CALLBACK_READ);
4475da69017SMatthias Ringwald return;
4485da69017SMatthias Ringwald
4495da69017SMatthias Ringwald exit_on_error:
45083159bb6SMatthias Ringwald log_error("usb_submit_event_in_transfer: winusb last error %lu", GetLastError());
4515da69017SMatthias Ringwald }
4525da69017SMatthias Ringwald
usb_submit_acl_in_transfer(void)4535da69017SMatthias Ringwald static void usb_submit_acl_in_transfer(void){
4545da69017SMatthias Ringwald // submit transfer
4555da69017SMatthias Ringwald 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);
4565da69017SMatthias Ringwald if (!result) {
4575da69017SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
4585da69017SMatthias Ringwald }
4595da69017SMatthias Ringwald
4605da69017SMatthias Ringwald // IO_PENDING -> wait for completed
4615da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_in, DATA_SOURCE_CALLBACK_READ);
4625da69017SMatthias Ringwald return;
4635da69017SMatthias Ringwald
4645da69017SMatthias Ringwald exit_on_error:
46583159bb6SMatthias Ringwald log_error("usb_submit_acl_in_transfer: winusb last error %lu", GetLastError());
4665da69017SMatthias Ringwald }
4675da69017SMatthias Ringwald
46819423ce7SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
469fdd32934SMatthias Ringwald #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
470f258f416SMatthias Ringwald
471f258f416SMatthias Ringwald // frame number gets updated
usb_submit_sco_in_transfer_at_frame(int i,ULONG * frame_number)472f258f416SMatthias Ringwald static void usb_submit_sco_in_transfer_at_frame(int i, ULONG * frame_number){
473f258f416SMatthias Ringwald
474c6ac61cdSMatthias Ringwald if (sco_shutdown){
475c6ac61cdSMatthias Ringwald log_info("USB SCO Shutdown:: usb_submit_sco_in_transfer_at_frame called");
476c6ac61cdSMatthias Ringwald return;
477c6ac61cdSMatthias Ringwald }
478c6ac61cdSMatthias Ringwald
479f258f416SMatthias Ringwald LARGE_INTEGER timestamp;
480f258f416SMatthias Ringwald ULONG current_frame_number;
481f258f416SMatthias Ringwald WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
482f258f416SMatthias Ringwald
483f258f416SMatthias Ringwald ULONG frame_before = *frame_number;
484f258f416SMatthias Ringwald
485ecf76c8dSMatthias Ringwald BOOL result = BTstack_WinUsb_ReadIsochPipe(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, iso_packet_size * NUM_ISO_PACKETS,
486f258f416SMatthias Ringwald frame_number, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
487f258f416SMatthias Ringwald
488ecf76c8dSMatthias Ringwald // log_info("BTstack_WinUsb_ReadIsochPipe #%02u: current %lu, planned %lu - buffer %lu", i, current_frame_number, frame_before, frame_before - current_frame_number);
489f258f416SMatthias Ringwald
490f258f416SMatthias Ringwald if (!result) {
491f258f416SMatthias Ringwald if (GetLastError() == ERROR_IO_PENDING) {
492f258f416SMatthias Ringwald } else {
493f258f416SMatthias Ringwald goto exit_on_error;
494f258f416SMatthias Ringwald }
495f258f416SMatthias Ringwald }
496f258f416SMatthias Ringwald
4975da69017SMatthias Ringwald return;
4985da69017SMatthias Ringwald
4995da69017SMatthias Ringwald exit_on_error:
50083159bb6SMatthias Ringwald log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
5015da69017SMatthias Ringwald }
502fdd32934SMatthias Ringwald
503fdd32934SMatthias Ringwald #else
504fdd32934SMatthias Ringwald
usb_submit_sco_in_transfer_asap(int i,int continue_stream)505fdd32934SMatthias Ringwald static void usb_submit_sco_in_transfer_asap(int i, int continue_stream){
506fdd32934SMatthias Ringwald
507c6ac61cdSMatthias Ringwald if (sco_shutdown){
508c6ac61cdSMatthias Ringwald log_info("USB SCO Shutdown:: usb_submit_sco_in_transfer_at_frame called");
509c6ac61cdSMatthias Ringwald return;
510c6ac61cdSMatthias Ringwald }
511c6ac61cdSMatthias Ringwald
512fdd32934SMatthias Ringwald LARGE_INTEGER timestamp;
513fdd32934SMatthias Ringwald ULONG current_frame_number;
514ecf76c8dSMatthias Ringwald BTstack_WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
515fdd32934SMatthias Ringwald
516fdd32934SMatthias Ringwald // log_info("usb_submit_sco_in_transfer[%02u]: current frame %lu", i, current_frame_number);
517fdd32934SMatthias Ringwald
518ecf76c8dSMatthias Ringwald BOOL result = BTstack_WinUsb_ReadIsochPipeAsap(hci_sco_in_buffer_handle, i * SCO_PACKET_SIZE, iso_packet_size * NUM_ISO_PACKETS,
519fdd32934SMatthias Ringwald continue_stream, NUM_ISO_PACKETS, &hci_sco_packet_descriptors[i * NUM_ISO_PACKETS], &usb_overlapped_sco_in[i]);
520fdd32934SMatthias Ringwald
521fdd32934SMatthias Ringwald if (!result) {
522fdd32934SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
523fdd32934SMatthias Ringwald }
524fdd32934SMatthias Ringwald
525fdd32934SMatthias Ringwald return;
526fdd32934SMatthias Ringwald
527fdd32934SMatthias Ringwald exit_on_error:
528fdd32934SMatthias Ringwald log_error("usb_submit_sco_in_transfer: winusb last error %lu", GetLastError());
529fdd32934SMatthias Ringwald }
530f258f416SMatthias Ringwald #endif
53119423ce7SMatthias Ringwald #endif
5325da69017SMatthias Ringwald
usb_process_event_in(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)5335da69017SMatthias Ringwald static void usb_process_event_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
5345da69017SMatthias Ringwald
5355da69017SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
5365da69017SMatthias Ringwald
5375da69017SMatthias Ringwald DWORD bytes_read;
5385da69017SMatthias Ringwald BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_event_in, &bytes_read, FALSE);
5395da69017SMatthias Ringwald if(!ok){
5405da69017SMatthias Ringwald DWORD err = GetLastError();
5415da69017SMatthias Ringwald if (err == ERROR_IO_INCOMPLETE){
5425da69017SMatthias Ringwald // IO_INCOMPLETE -> wait for completed
5435da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
5445da69017SMatthias Ringwald } else {
5455da69017SMatthias Ringwald log_error("usb_process_event_in: error reading");
5465da69017SMatthias Ringwald }
5475da69017SMatthias Ringwald return;
5485da69017SMatthias Ringwald }
5495da69017SMatthias Ringwald
5505da69017SMatthias Ringwald // notify uppper
551d900fa19SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, hci_event_in_buffer, (uint16_t) bytes_read);
5525da69017SMatthias Ringwald
5535da69017SMatthias Ringwald // re-submit transfer
5545da69017SMatthias Ringwald usb_submit_event_in_transfer();
5555da69017SMatthias Ringwald }
5565da69017SMatthias Ringwald
usb_process_acl_in(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)5575da69017SMatthias Ringwald static void usb_process_acl_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type) {
5585da69017SMatthias Ringwald
5595da69017SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
5605da69017SMatthias Ringwald
5615da69017SMatthias Ringwald DWORD bytes_read;
5625da69017SMatthias Ringwald BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_acl_in, &bytes_read, FALSE);
5635da69017SMatthias Ringwald if(!ok){
5645da69017SMatthias Ringwald DWORD err = GetLastError();
5655da69017SMatthias Ringwald if (err == ERROR_IO_INCOMPLETE){
5665da69017SMatthias Ringwald // IO_INCOMPLETE -> wait for completed
5675da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
5685da69017SMatthias Ringwald } else {
569507db037SMatthias Ringwald log_error("usb_process_acl_in: error reading");
570507db037SMatthias Ringwald
571507db037SMatthias Ringwald // Reset Pipe
572507db037SMatthias Ringwald err = WinUsb_ResetPipe(usb_interface_0_handle, acl_in_addr);
5731b5d2ea0SMatthias Ringwald log_info("WinUsb_ResetPipe: result %u", (int) err);
574507db037SMatthias Ringwald if (err){
5751b5d2ea0SMatthias Ringwald log_info("WinUsb_ResetPipe error %u", (int) GetLastError());
576507db037SMatthias Ringwald }
577507db037SMatthias Ringwald
578507db037SMatthias Ringwald // re-submit transfer
579507db037SMatthias Ringwald usb_submit_acl_in_transfer();
5805da69017SMatthias Ringwald }
5815da69017SMatthias Ringwald return;
5825da69017SMatthias Ringwald }
5835da69017SMatthias Ringwald
5845da69017SMatthias Ringwald // notify uppper
585d900fa19SMatthias Ringwald packet_handler(HCI_ACL_DATA_PACKET, hci_acl_in_buffer, (uint16_t) bytes_read);
5865da69017SMatthias Ringwald
5875da69017SMatthias Ringwald // re-submit transfer
5885da69017SMatthias Ringwald usb_submit_acl_in_transfer();
5895da69017SMatthias Ringwald }
5905da69017SMatthias Ringwald
59119423ce7SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
sco_state_machine_init(void)5925da69017SMatthias Ringwald static void sco_state_machine_init(void){
5935da69017SMatthias Ringwald sco_state = H2_W4_SCO_HEADER;
5945da69017SMatthias Ringwald sco_read_pos = 0;
5955da69017SMatthias Ringwald sco_bytes_to_read = 3;
5965da69017SMatthias Ringwald }
5975da69017SMatthias Ringwald
sco_handle_data(uint8_t * buffer,uint16_t size)5985da69017SMatthias Ringwald static void sco_handle_data(uint8_t * buffer, uint16_t size){
59983159bb6SMatthias Ringwald // printf("sco_handle_data: state %u, pos %u, to read %u, size %u", sco_state, sco_read_pos, sco_bytes_to_read, size);
6005da69017SMatthias Ringwald while (size){
6015da69017SMatthias Ringwald if (size < sco_bytes_to_read){
6025da69017SMatthias Ringwald // just store incomplete data
6035da69017SMatthias Ringwald memcpy(&sco_buffer[sco_read_pos], buffer, size);
6045da69017SMatthias Ringwald sco_read_pos += size;
6055da69017SMatthias Ringwald sco_bytes_to_read -= size;
6065da69017SMatthias Ringwald return;
6075da69017SMatthias Ringwald }
6085da69017SMatthias Ringwald // copy requested data
6095da69017SMatthias Ringwald memcpy(&sco_buffer[sco_read_pos], buffer, sco_bytes_to_read);
6105da69017SMatthias Ringwald sco_read_pos += sco_bytes_to_read;
6115da69017SMatthias Ringwald buffer += sco_bytes_to_read;
6125da69017SMatthias Ringwald size -= sco_bytes_to_read;
6135da69017SMatthias Ringwald
6145da69017SMatthias Ringwald // chunk read successfully, next action
6155da69017SMatthias Ringwald switch (sco_state){
6165da69017SMatthias Ringwald case H2_W4_SCO_HEADER:
6175da69017SMatthias Ringwald sco_state = H2_W4_PAYLOAD;
6185da69017SMatthias Ringwald sco_bytes_to_read = sco_buffer[2];
6195da69017SMatthias Ringwald if (sco_bytes_to_read > (sizeof(sco_buffer)-3)){
6205da69017SMatthias Ringwald log_error("sco_handle_data: sco packet len > packet size");
6215da69017SMatthias Ringwald sco_state_machine_init();
6225da69017SMatthias Ringwald }
6235da69017SMatthias Ringwald break;
6245da69017SMatthias Ringwald case H2_W4_PAYLOAD:
6255da69017SMatthias Ringwald // packet complete
6265da69017SMatthias Ringwald packet_handler(HCI_SCO_DATA_PACKET, sco_buffer, sco_read_pos);
6275da69017SMatthias Ringwald sco_state_machine_init();
6285da69017SMatthias Ringwald break;
629b115538eSMatthias Ringwald default:
630b115538eSMatthias Ringwald btstack_unreachable();
631b115538eSMatthias Ringwald break;
6325da69017SMatthias Ringwald }
6335da69017SMatthias Ringwald }
6345da69017SMatthias Ringwald }
6355da69017SMatthias Ringwald
usb_process_sco_out(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)636f258f416SMatthias Ringwald static void usb_process_sco_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
63783f31aa4SMatthias Ringwald
638f258f416SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
6395da69017SMatthias Ringwald
640c6ac61cdSMatthias Ringwald if (sco_shutdown){
641c6ac61cdSMatthias Ringwald log_info("USB SCO Shutdown:: usb_process_sco_out called");
642c6ac61cdSMatthias Ringwald return;
643c6ac61cdSMatthias Ringwald }
644c6ac61cdSMatthias Ringwald
64583f31aa4SMatthias Ringwald // get current frame number
64683f31aa4SMatthias Ringwald ULONG current_frame_number;
64783f31aa4SMatthias Ringwald LARGE_INTEGER timestamp;
648ecf76c8dSMatthias Ringwald BTstack_WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
64983f31aa4SMatthias Ringwald
6505da69017SMatthias Ringwald // find index
65183f31aa4SMatthias Ringwald int transfer_index;
65283f31aa4SMatthias Ringwald for (transfer_index=0;transfer_index<SCO_RING_BUFFER_COUNT;transfer_index++){
65383f31aa4SMatthias Ringwald if (ds == &usb_data_source_sco_out[transfer_index]) break;
6545da69017SMatthias Ringwald }
655f258f416SMatthias Ringwald
656c6ac61cdSMatthias Ringwald // log_info("usb_process_sco_out[%02u] -- current frame %lu", transfer_index, current_frame_number);
6575da69017SMatthias Ringwald
6585da69017SMatthias Ringwald DWORD bytes_transferred;
659f258f416SMatthias Ringwald BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_out[transfer_index], &bytes_transferred, FALSE);
660c6ac61cdSMatthias Ringwald // log_info("usb_process_sco_out_done: #%u result %u, bytes %u, state %u", transfer_index, ok, (int) bytes_transferred, sco_state);
6615da69017SMatthias Ringwald if(!ok){
6625da69017SMatthias Ringwald DWORD err = GetLastError();
6635da69017SMatthias Ringwald if (err == ERROR_IO_INCOMPLETE){
6645da69017SMatthias Ringwald // IO_INCOMPLETE -> wait for completed
66583f31aa4SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
6665da69017SMatthias Ringwald return;
6675da69017SMatthias Ringwald }
66883f31aa4SMatthias Ringwald 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);
66983f31aa4SMatthias Ringwald }
67083f31aa4SMatthias Ringwald
67183f31aa4SMatthias Ringwald // decrease tab
67283f31aa4SMatthias Ringwald sco_ring_transfers_active--;
67383f31aa4SMatthias Ringwald
67483f31aa4SMatthias Ringwald // enable next data source callback
67583f31aa4SMatthias Ringwald if (sco_ring_transfers_active){
67683f31aa4SMatthias Ringwald // update expected and wait for completion
67783f31aa4SMatthias Ringwald usb_sco_out_expected_transfer = (transfer_index+ 1) % SCO_RING_BUFFER_COUNT;
678c6ac61cdSMatthias Ringwald // log_info("usb_process_sco_out_done[%02u]: wait for transfer %02u", transfer_index, usb_sco_out_expected_transfer);
67983f31aa4SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[usb_sco_out_expected_transfer], DATA_SOURCE_CALLBACK_WRITE);
6805da69017SMatthias Ringwald }
6815da69017SMatthias Ringwald
682c6ac61cdSMatthias Ringwald // log_info("usb_process_sco_out_done: transfers active %u", sco_ring_transfers_active);
68311cb6f2dSMatthias Ringwald
684f258f416SMatthias Ringwald // mark free
685f258f416SMatthias Ringwald if (sco_ring_have_space()) {
686f258f416SMatthias Ringwald uint8_t event[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
687f258f416SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
688f258f416SMatthias Ringwald }
689f258f416SMatthias Ringwald }
690f258f416SMatthias Ringwald
usb_process_sco_in(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)691f258f416SMatthias Ringwald static void usb_process_sco_in(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
692f258f416SMatthias Ringwald
69383f31aa4SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
694f9644fc5SMatthias Ringwald
695c6ac61cdSMatthias Ringwald if (sco_shutdown){
696c6ac61cdSMatthias Ringwald log_info("USB SCO Shutdown: usb_process_sco_out called");
697c6ac61cdSMatthias Ringwald return;
698c6ac61cdSMatthias Ringwald }
699f258f416SMatthias Ringwald
700f9644fc5SMatthias Ringwald // find index
701f9644fc5SMatthias Ringwald int i;
702f9644fc5SMatthias Ringwald for (i=0;i<ISOC_BUFFERS;i++){
703f9644fc5SMatthias Ringwald if (ds == &usb_data_source_sco_in[i]) break;
704f9644fc5SMatthias Ringwald }
705f9644fc5SMatthias Ringwald int transfer_index = i;
706f9644fc5SMatthias Ringwald
70708dc2fadSMatthias Ringwald // ULONG current_frame_number;
70808dc2fadSMatthias Ringwald // LARGE_INTEGER timestamp;
709ecf76c8dSMatthias Ringwald // BTstack_WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
71008dc2fadSMatthias Ringwald
71108dc2fadSMatthias Ringwald // log_info("usb_process_sco_in[%02u] -- current frame %lu", transfer_index, current_frame_number);
712f9644fc5SMatthias Ringwald
713f9644fc5SMatthias Ringwald DWORD bytes_transferred;
714f9644fc5SMatthias Ringwald BOOL ok = WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_sco_in[transfer_index], &bytes_transferred, FALSE);
715f9644fc5SMatthias Ringwald
716f9644fc5SMatthias Ringwald if(!ok) {
717f9644fc5SMatthias Ringwald DWORD err = GetLastError();
718f9644fc5SMatthias Ringwald if (err == ERROR_IO_INCOMPLETE) {
719f9644fc5SMatthias Ringwald // IO_INCOMPLETE -> wait for completed
720f9644fc5SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_READ);
721f9644fc5SMatthias Ringwald return;
722f9644fc5SMatthias Ringwald }
723f9644fc5SMatthias Ringwald log_error("usb_process_sco_in[%02u]: error reading %u, Internal %x", transfer_index, (int) err, (int) usb_overlapped_sco_out[i].Internal);
724f9644fc5SMatthias Ringwald }
725f9644fc5SMatthias Ringwald
726f9644fc5SMatthias Ringwald if (ok){
727f9644fc5SMatthias Ringwald for (i=0;i<NUM_ISO_PACKETS;i++){
728f9644fc5SMatthias Ringwald USBD_ISO_PACKET_DESCRIPTOR * packet_descriptor = &hci_sco_packet_descriptors[transfer_index * NUM_ISO_PACKETS + i];
729f9644fc5SMatthias Ringwald if (packet_descriptor->Length){
730f9644fc5SMatthias Ringwald uint8_t * iso_data = &hci_sco_in_buffer[transfer_index * SCO_PACKET_SIZE + packet_descriptor->Offset];
731d900fa19SMatthias Ringwald uint16_t iso_len = (uint16_t) packet_descriptor->Length;
732f9644fc5SMatthias Ringwald sco_handle_data(iso_data, iso_len);
733f9644fc5SMatthias Ringwald }
734f9644fc5SMatthias Ringwald }
735f9644fc5SMatthias Ringwald }
736f9644fc5SMatthias Ringwald
737fdd32934SMatthias Ringwald #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
738fdd32934SMatthias Ringwald usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
739fdd32934SMatthias Ringwald #else
740fdd32934SMatthias Ringwald usb_submit_sco_in_transfer_asap(transfer_index, 1);
741fdd32934SMatthias Ringwald #endif
742f9644fc5SMatthias Ringwald // update expected and wait for completion
743f9644fc5SMatthias Ringwald usb_sco_in_expected_transfer = (transfer_index+ 1) % ISOC_BUFFERS;
744f9644fc5SMatthias Ringwald
745f9644fc5SMatthias Ringwald // log_info("usb_process_sco_in[%02u]: enable data source %02u", transfer_index, usb_sco_in_expected_transfer);
74683f31aa4SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
7475da69017SMatthias Ringwald }
74819423ce7SMatthias Ringwald #endif
7495da69017SMatthias Ringwald
usb_process_command_out(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)7505da69017SMatthias Ringwald static void usb_process_command_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
7515da69017SMatthias Ringwald
7525da69017SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
7535da69017SMatthias Ringwald
7545da69017SMatthias Ringwald // update stata before submitting transfer
7555da69017SMatthias Ringwald usb_command_out_active = 0;
7565da69017SMatthias Ringwald
7575da69017SMatthias Ringwald // notify upper stack that provided buffer can be used again
7585da69017SMatthias Ringwald uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
7595da69017SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
7605da69017SMatthias Ringwald }
7615da69017SMatthias Ringwald
usb_process_acl_out(btstack_data_source_t * ds,btstack_data_source_callback_type_t callback_type)7625da69017SMatthias Ringwald static void usb_process_acl_out(btstack_data_source_t *ds, btstack_data_source_callback_type_t callback_type){
7635da69017SMatthias Ringwald
7645da69017SMatthias Ringwald btstack_run_loop_disable_data_source_callbacks(ds, DATA_SOURCE_CALLBACK_WRITE);
7655da69017SMatthias Ringwald
7665da69017SMatthias Ringwald // update stata before submitting transfer
7675da69017SMatthias Ringwald usb_acl_out_active = 0;
7685da69017SMatthias Ringwald
7695da69017SMatthias Ringwald // notify upper stack that provided buffer can be used again
7705da69017SMatthias Ringwald uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
7715da69017SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
7725da69017SMatthias Ringwald }
7735da69017SMatthias Ringwald
usb_scan_for_bluetooth_endpoints(void)77498820164SMatthias Ringwald static BOOL usb_scan_for_bluetooth_endpoints(void) {
77598820164SMatthias Ringwald int i;
77698820164SMatthias Ringwald USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
77798820164SMatthias Ringwald
77898820164SMatthias Ringwald // reset
77998820164SMatthias Ringwald event_in_addr = 0;
78098820164SMatthias Ringwald acl_in_addr = 0;
78198820164SMatthias Ringwald acl_out_addr = 0;
78298820164SMatthias Ringwald
78398820164SMatthias Ringwald log_info("Scanning USB Entpoints:");
78498820164SMatthias Ringwald
78598820164SMatthias Ringwald // look for Event and ACL pipes on Interface #0
78698820164SMatthias Ringwald BOOL result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
78798820164SMatthias Ringwald if (!result) goto exit_on_error;
78898820164SMatthias Ringwald for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
78998820164SMatthias Ringwald WINUSB_PIPE_INFORMATION pipe;
79098820164SMatthias Ringwald result = WinUsb_QueryPipe(
79198820164SMatthias Ringwald usb_interface_0_handle,
79298820164SMatthias Ringwald 0,
79398820164SMatthias Ringwald (UCHAR) i,
79498820164SMatthias Ringwald &pipe);
79598820164SMatthias Ringwald if (!result) goto exit_on_error;
79698820164SMatthias Ringwald log_info("Interface #0, Alt #0, Pipe idx #%u: type %u, id 0x%02x, max packet size %u,",
79798820164SMatthias Ringwald i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize);
79898820164SMatthias Ringwald switch (pipe.PipeType){
79998820164SMatthias Ringwald case USB_ENDPOINT_TYPE_INTERRUPT:
80098820164SMatthias Ringwald if (event_in_addr) continue;
80198820164SMatthias Ringwald event_in_addr = pipe.PipeId;
80298820164SMatthias Ringwald log_info("-> using 0x%2.2X for HCI Events", event_in_addr);
80398820164SMatthias Ringwald break;
80498820164SMatthias Ringwald case USB_ENDPOINT_TYPE_BULK:
80598820164SMatthias Ringwald if (pipe.PipeId & 0x80) {
80698820164SMatthias Ringwald if (acl_in_addr) continue;
80798820164SMatthias Ringwald acl_in_addr = pipe.PipeId;
80898820164SMatthias Ringwald log_info("-> using 0x%2.2X for ACL Data In", acl_in_addr);
80998820164SMatthias Ringwald } else {
81098820164SMatthias Ringwald if (acl_out_addr) continue;
81198820164SMatthias Ringwald acl_out_addr = pipe.PipeId;
81298820164SMatthias Ringwald log_info("-> using 0x%2.2X for ACL Data Out", acl_out_addr);
81398820164SMatthias Ringwald }
81498820164SMatthias Ringwald break;
81598820164SMatthias Ringwald default:
81698820164SMatthias Ringwald break;
81798820164SMatthias Ringwald }
81898820164SMatthias Ringwald }
81998820164SMatthias Ringwald
82098820164SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
82198820164SMatthias Ringwald sco_out_addr = 0;
82298820164SMatthias Ringwald sco_in_addr = 0;
82398820164SMatthias Ringwald
82499fc8027SMatthias Ringwald // look for SCO pipes on Interface #1, Alt Setting 1
82599fc8027SMatthias Ringwald int alt_setting = 1;
82699fc8027SMatthias Ringwald result = WinUsb_QueryInterfaceSettings(usb_interface_1_handle, alt_setting, &usb_interface_descriptor);
82798820164SMatthias Ringwald if (!result) goto exit_on_error;
82898820164SMatthias Ringwald for (i=0;i<usb_interface_descriptor.bNumEndpoints;i++){
829ecf76c8dSMatthias Ringwald BTSTACK_WINUSB_PIPE_INFORMATION_EX pipe;
830ecf76c8dSMatthias Ringwald result = BTstack_WinUsb_QueryPipeEx(
83198820164SMatthias Ringwald usb_interface_1_handle,
83299fc8027SMatthias Ringwald alt_setting,
83398820164SMatthias Ringwald (UCHAR) i,
83498820164SMatthias Ringwald &pipe);
83598820164SMatthias Ringwald if (!result) goto exit_on_error;
83698820164SMatthias Ringwald 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",
83799fc8027SMatthias Ringwald alt_setting, i, pipe.PipeType, pipe.PipeId, pipe.MaximumPacketSize, pipe.Interval, (int) pipe.MaximumBytesPerInterval);
83898820164SMatthias Ringwald switch (pipe.PipeType){
83998820164SMatthias Ringwald case USB_ENDPOINT_TYPE_ISOCHRONOUS:
84098820164SMatthias Ringwald if (pipe.PipeId & 0x80) {
84198820164SMatthias Ringwald if (sco_in_addr) continue;
84298820164SMatthias Ringwald sco_in_addr = pipe.PipeId;
84398820164SMatthias Ringwald log_info("-> using 0x%2.2X for SCO Data In", sco_in_addr);
84498820164SMatthias Ringwald } else {
84598820164SMatthias Ringwald if (sco_out_addr) continue;
84698820164SMatthias Ringwald sco_out_addr = pipe.PipeId;
84798820164SMatthias Ringwald log_info("-> using 0x%2.2X for SCO Data Out", sco_out_addr);
84898820164SMatthias Ringwald }
84998820164SMatthias Ringwald break;
85098820164SMatthias Ringwald default:
85198820164SMatthias Ringwald break;
85298820164SMatthias Ringwald }
85398820164SMatthias Ringwald }
85498820164SMatthias Ringwald if (!sco_in_addr){
85598820164SMatthias Ringwald log_error("Couldn't find pipe for SCO IN!");
85698820164SMatthias Ringwald return FALSE;
85798820164SMatthias Ringwald }
85898820164SMatthias Ringwald if (!sco_out_addr){
85998820164SMatthias Ringwald log_error("Couldn't find pipe for SCO IN!");
86098820164SMatthias Ringwald return FALSE;
86198820164SMatthias Ringwald }
86298820164SMatthias Ringwald #endif
86398820164SMatthias Ringwald
86498820164SMatthias Ringwald // check if all found
86598820164SMatthias Ringwald if (!event_in_addr){
86698820164SMatthias Ringwald log_error("Couldn't find pipe for Event IN!");
86798820164SMatthias Ringwald return FALSE;
86898820164SMatthias Ringwald }
86998820164SMatthias Ringwald if (!acl_in_addr){
87098820164SMatthias Ringwald log_error("Couldn't find pipe for ACL IN!");
87198820164SMatthias Ringwald return FALSE;
87298820164SMatthias Ringwald }
87398820164SMatthias Ringwald if (!acl_out_addr){
87498820164SMatthias Ringwald log_error("Couldn't find pipe for ACL OUT!");
87598820164SMatthias Ringwald return FALSE;
87698820164SMatthias Ringwald }
87798820164SMatthias Ringwald
87898820164SMatthias Ringwald // all clear
87998820164SMatthias Ringwald return TRUE;
88098820164SMatthias Ringwald
88198820164SMatthias Ringwald exit_on_error:
88283159bb6SMatthias Ringwald log_error("usb_scan_for_bluetooth_endpoints: last error %lu", GetLastError());
88398820164SMatthias Ringwald return FALSE;
88498820164SMatthias Ringwald }
88598820164SMatthias Ringwald
886b9227387SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
887c4cea4aeSMatthias Ringwald
usb_sco_start(void)888b9227387SMatthias Ringwald static int usb_sco_start(void){
889b9227387SMatthias Ringwald printf("usb_sco_start\n");
890b9227387SMatthias Ringwald log_info("usb_sco_start");
891b9227387SMatthias Ringwald
892c6ac61cdSMatthias Ringwald sco_shutdown = 0;
893c6ac61cdSMatthias Ringwald
894b9227387SMatthias Ringwald sco_state_machine_init();
895b9227387SMatthias Ringwald sco_ring_init();
896b9227387SMatthias Ringwald
897b9227387SMatthias Ringwald // calc alt setting
898b9227387SMatthias Ringwald int alt_setting;
899b9227387SMatthias Ringwald if (sco_voice_setting & 0x0020){
900b9227387SMatthias Ringwald // 16-bit PCM
901b9227387SMatthias Ringwald alt_setting = alt_setting_16_bit[sco_num_connections-1];
902b9227387SMatthias Ringwald } else {
903b9227387SMatthias Ringwald // 8-bit PCM or mSBC
904b9227387SMatthias Ringwald alt_setting = alt_setting_8_bit[sco_num_connections-1];
905b9227387SMatthias Ringwald }
9065a97f1baSMatthias Ringwald
907b9227387SMatthias Ringwald log_info("Switching to setting %u on interface 1..", alt_setting);
908b9227387SMatthias Ringwald // WinUsb_SetCurrentAlternateSetting returns TRUE if the operation succeeds.
909b9227387SMatthias Ringwald BOOL result = WinUsb_SetCurrentAlternateSetting(usb_interface_1_handle, alt_setting);
910b9227387SMatthias Ringwald if (!result) goto exit_on_error;
911c6ac61cdSMatthias Ringwald
9125a97f1baSMatthias Ringwald // derive iso packet size from alt setting
9135a97f1baSMatthias Ringwald iso_packet_size = iso_packet_size_for_alt_setting[alt_setting];
9145a97f1baSMatthias Ringwald
915c6ac61cdSMatthias Ringwald // register isochronous buffer after setting alternate setting
916c6ac61cdSMatthias Ringwald usb_sco_register_buffers();
917b9227387SMatthias Ringwald
918b9227387SMatthias Ringwald #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
919b9227387SMatthias Ringwald // get current frame number
920b9227387SMatthias Ringwald ULONG current_frame_number;
921b9227387SMatthias Ringwald LARGE_INTEGER timestamp;
922ecf76c8dSMatthias Ringwald BTstack_WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
923b9227387SMatthias Ringwald // plan for next tranfer
924b9227387SMatthias Ringwald sco_next_transfer_at_frame = current_frame_number + ISOC_BUFFERS * NUM_ISO_PACKETS;
925b9227387SMatthias Ringwald #endif
926b9227387SMatthias Ringwald
927b9227387SMatthias Ringwald int i;
928b9227387SMatthias Ringwald for (i=0;i<ISOC_BUFFERS;i++){
929b9227387SMatthias Ringwald #ifdef SCHEDULE_SCO_IN_TRANSFERS_MANUALLY
930b9227387SMatthias Ringwald usb_submit_sco_in_transfer_at_frame(i, &sco_next_transfer_at_frame);
931b9227387SMatthias Ringwald #else
932b9227387SMatthias Ringwald usb_submit_sco_in_transfer_asap(i, 0);
933b9227387SMatthias Ringwald #endif
934b9227387SMatthias Ringwald }
935b9227387SMatthias Ringwald
936b9227387SMatthias Ringwald usb_sco_in_expected_transfer = 0;
937b9227387SMatthias Ringwald
938b9227387SMatthias Ringwald // only await first transfer to return
939b9227387SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_in[usb_sco_in_expected_transfer], DATA_SOURCE_CALLBACK_READ);
940b9227387SMatthias Ringwald return 1;
941b9227387SMatthias Ringwald
942b9227387SMatthias Ringwald exit_on_error:
943b9227387SMatthias Ringwald log_error("usb_sco_start: last error %lu", GetLastError());
944b9227387SMatthias Ringwald usb_free_resources();
945b9227387SMatthias Ringwald return 0;
946b9227387SMatthias Ringwald }
947b9227387SMatthias Ringwald
usb_sco_stop(void)948b9227387SMatthias Ringwald static void usb_sco_stop(void){
949c6ac61cdSMatthias Ringwald printf("usb_sco_stop\n");
950c6ac61cdSMatthias Ringwald log_info("usb_sco_stop");
951c6ac61cdSMatthias Ringwald
952c6ac61cdSMatthias Ringwald sco_shutdown = 1;
953c6ac61cdSMatthias Ringwald
954c6ac61cdSMatthias Ringwald // abort SCO transfers
955b9227387SMatthias Ringwald WinUsb_AbortPipe(usb_interface_0_handle, sco_in_addr);
956b9227387SMatthias Ringwald WinUsb_AbortPipe(usb_interface_0_handle, sco_out_addr);
957c6ac61cdSMatthias Ringwald
958c6ac61cdSMatthias Ringwald // unlock/free SCO buffers
959c6ac61cdSMatthias Ringwald usb_sco_unregister_buffers();
960c6ac61cdSMatthias Ringwald
961b9227387SMatthias Ringwald int alt_setting = 0;
962b9227387SMatthias Ringwald log_info("Switching to setting %u on interface 1..", alt_setting);
963b9227387SMatthias Ringwald // WinUsb_SetCurrentAlternateSetting returns TRUE if the operation succeeds.
964b9227387SMatthias Ringwald WinUsb_SetCurrentAlternateSetting(usb_interface_1_handle, alt_setting);
965b9227387SMatthias Ringwald }
966b9227387SMatthias Ringwald #endif
967b9227387SMatthias Ringwald
9685da69017SMatthias Ringwald // returns 0 if successful, -1 otherwise
usb_try_open_device(const char * device_path)9695da69017SMatthias Ringwald static int usb_try_open_device(const char * device_path){
9705da69017SMatthias Ringwald
9715da69017SMatthias Ringwald // open file
9725da69017SMatthias Ringwald usb_device_handle = CreateFile(device_path,
9735da69017SMatthias Ringwald GENERIC_WRITE | GENERIC_READ,
9745da69017SMatthias Ringwald FILE_SHARE_WRITE | FILE_SHARE_READ,
9755da69017SMatthias Ringwald NULL,
9765da69017SMatthias Ringwald OPEN_EXISTING,
9775da69017SMatthias Ringwald FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
9785da69017SMatthias Ringwald NULL);
97983159bb6SMatthias Ringwald log_info("Opening USB device: %p", usb_device_handle);
9805da69017SMatthias Ringwald if (!usb_device_handle) goto exit_on_error;
9815da69017SMatthias Ringwald
9825da69017SMatthias Ringwald // WinUsb_Initialize returns TRUE if the operation succeed
9835da69017SMatthias Ringwald BOOL result = WinUsb_Initialize(usb_device_handle, &usb_interface_0_handle);
9845da69017SMatthias Ringwald if (!result) goto exit_on_error;
98583159bb6SMatthias Ringwald
98683159bb6SMatthias Ringwald // Detect USB Dongle based Class, Subclass, and Protocol
98783159bb6SMatthias Ringwald // The class code (bDeviceClass) is 0xE0 – Wireless Controller.
98883159bb6SMatthias Ringwald // The SubClass code (bDeviceSubClass) is 0x01 – RF Controller.
98983159bb6SMatthias Ringwald // The Protocol code (bDeviceProtocol) is 0x01 – Bluetooth programming.
99083159bb6SMatthias Ringwald USB_INTERFACE_DESCRIPTOR usb_interface_descriptor;
99183159bb6SMatthias Ringwald result = WinUsb_QueryInterfaceSettings(usb_interface_0_handle, 0, &usb_interface_descriptor);
99283159bb6SMatthias Ringwald if (!result) goto exit_on_error;
9939d31f827SMilanka Ringwald
9949d31f827SMilanka Ringwald // ignore virtual Bluetooth adapter of VMware
995784eb10cSMilanka Ringwald if (usb_is_vmware_bluetooth_adapter(device_path)) {
9969d31f827SMilanka Ringwald log_info("Ignoring simulated VMware Bluetooth adapter");
9979d31f827SMilanka Ringwald usb_free_resources();
9989d31f827SMilanka Ringwald return -1;
9999d31f827SMilanka Ringwald }
10009d31f827SMilanka Ringwald
100183159bb6SMatthias Ringwald //
100283159bb6SMatthias Ringwald if (usb_interface_descriptor.bInterfaceClass != 0xe0 ||
100383159bb6SMatthias Ringwald usb_interface_descriptor.bInterfaceSubClass != 0x01 ||
100483159bb6SMatthias Ringwald usb_interface_descriptor.bInterfaceProtocol != 0x01){
100583159bb6SMatthias Ringwald
1006ecf76c8dSMatthias Ringwald // check whitelist
1007ecf76c8dSMatthias Ringwald if (!usb_is_known_bluetooth_device(device_path)){
100883159bb6SMatthias Ringwald log_info("Class, Subclass, Protocol does not match Bluetooth device");
100983159bb6SMatthias Ringwald usb_free_resources();
101083159bb6SMatthias Ringwald return 0;
101183159bb6SMatthias Ringwald }
1012ecf76c8dSMatthias Ringwald }
10135da69017SMatthias Ringwald
10145da69017SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
10155da69017SMatthias Ringwald log_info("Claiming interface 1...");
10165da69017SMatthias Ringwald // WinUsb_GetAssociatedInterface returns TRUE if the operation succeeds.
10175da69017SMatthias Ringwald // We use index 1 - assuming it refers to interface #1 with libusb
10185da69017SMatthias Ringwald // A value of 0 indicates the first associated interface, a value of 1 indicates the second associated interface, and so on.
10195da69017SMatthias Ringwald result = WinUsb_GetAssociatedInterface(usb_interface_0_handle, 0, &usb_interface_1_handle);
10205da69017SMatthias Ringwald if (!result) goto exit_on_error;
10215da69017SMatthias Ringwald log_info("Claiming interface 1: success");
10225da69017SMatthias Ringwald #endif
10235da69017SMatthias Ringwald
102498820164SMatthias Ringwald result = usb_scan_for_bluetooth_endpoints();
102598820164SMatthias Ringwald if (!result) {
102698820164SMatthias Ringwald log_error("Could not find all Bluetooth Endpoints!");
102798820164SMatthias Ringwald usb_free_resources();
102898820164SMatthias Ringwald return 0;
10295da69017SMatthias Ringwald }
10305da69017SMatthias Ringwald
103151a84de6SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
103298820164SMatthias Ringwald int i;
103398820164SMatthias Ringwald
10345da69017SMatthias Ringwald memset(hci_sco_packet_descriptors, 0, sizeof(hci_sco_packet_descriptors));
103583f31aa4SMatthias Ringwald log_info("Size of packet descriptors for SCO IN%u", (int) sizeof(hci_sco_packet_descriptors));
103683f31aa4SMatthias Ringwald
103751a84de6SMatthias Ringwald // setup async io && btstack handler
10385da69017SMatthias Ringwald memset(&usb_overlapped_sco_in, 0, sizeof(usb_overlapped_sco_in));
10395da69017SMatthias Ringwald for (i=0;i<ISOC_BUFFERS;i++){
10405da69017SMatthias Ringwald usb_overlapped_sco_in[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
104183159bb6SMatthias Ringwald // log_info_hexdump(&usb_overlapped_sco_in[i], sizeof(OVERLAPPED));
1042f258f416SMatthias Ringwald // log_info("data source SCO in %u, handle %p", i, usb_overlapped_sco_in[i].hEvent);
1043b43fd83dSMatthias Ringwald usb_data_source_sco_in[i].source.handle = usb_overlapped_sco_in[i].hEvent;
10445da69017SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_sco_in[i], &usb_process_sco_in);
10455da69017SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_sco_in[i]);
10465da69017SMatthias Ringwald }
10475da69017SMatthias Ringwald
1048f258f416SMatthias Ringwald memset(&usb_overlapped_sco_out, 0, sizeof(usb_overlapped_sco_out));
1049f258f416SMatthias Ringwald for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
1050f258f416SMatthias Ringwald usb_overlapped_sco_out[i].hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
1051f258f416SMatthias Ringwald // log_info("data source SCO out %u, handle %p", i, usb_overlapped_sco_out[i].hEvent);
1052b43fd83dSMatthias Ringwald usb_data_source_sco_out[i].source.handle = usb_overlapped_sco_out[i].hEvent;
1053f258f416SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_sco_out[i], &usb_process_sco_out);
1054f258f416SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_sco_out[i]);
10555da69017SMatthias Ringwald }
105619423ce7SMatthias Ringwald #endif
10575da69017SMatthias Ringwald
10585da69017SMatthias Ringwald // setup async io
10595da69017SMatthias Ringwald memset(&usb_overlapped_event_in, 0, sizeof(usb_overlapped_event_in));
10605da69017SMatthias Ringwald memset(&usb_overlapped_command_out, 0, sizeof(usb_overlapped_command_out));
10615da69017SMatthias Ringwald memset(&usb_overlapped_acl_out, 0, sizeof(usb_overlapped_acl_out));
10625da69017SMatthias Ringwald memset(&usb_overlapped_acl_in, 0, sizeof(usb_overlapped_acl_in));
10635da69017SMatthias Ringwald usb_overlapped_event_in.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
10645da69017SMatthias Ringwald usb_overlapped_command_out.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
10655da69017SMatthias Ringwald usb_overlapped_acl_in.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
10665da69017SMatthias Ringwald usb_overlapped_acl_out.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
10675da69017SMatthias Ringwald
10685da69017SMatthias Ringwald // setup btstack data soures
1069b43fd83dSMatthias Ringwald usb_data_source_event_in.source.handle = usb_overlapped_event_in.hEvent;
10705da69017SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_event_in, &usb_process_event_in);
10715da69017SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_event_in);
10725da69017SMatthias Ringwald
1073b43fd83dSMatthias Ringwald usb_data_source_command_out.source.handle = usb_overlapped_command_out.hEvent;
10745da69017SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_command_out, &usb_process_command_out);
10755da69017SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_command_out);
10765da69017SMatthias Ringwald
1077b43fd83dSMatthias Ringwald usb_data_source_acl_in.source.handle = usb_overlapped_acl_in.hEvent;
10785da69017SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_acl_in, &usb_process_acl_in);
10795da69017SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_acl_in);
10805da69017SMatthias Ringwald
1081b43fd83dSMatthias Ringwald usb_data_source_acl_out.source.handle = usb_overlapped_acl_out.hEvent;
10825da69017SMatthias Ringwald btstack_run_loop_set_data_source_handler(&usb_data_source_acl_out, &usb_process_acl_out);
10835da69017SMatthias Ringwald btstack_run_loop_add_data_source(&usb_data_source_acl_out);
10845da69017SMatthias Ringwald
1085f258f416SMatthias Ringwald // submit all incoming transfers
10865da69017SMatthias Ringwald usb_submit_event_in_transfer();
10875da69017SMatthias Ringwald usb_submit_acl_in_transfer();
10885da69017SMatthias Ringwald return 1;
10895da69017SMatthias Ringwald
10905da69017SMatthias Ringwald exit_on_error:
109183159bb6SMatthias Ringwald log_error("usb_try_open_device: last error %lu", GetLastError());
10925da69017SMatthias Ringwald usb_free_resources();
10935da69017SMatthias Ringwald return 0;
10945da69017SMatthias Ringwald }
10955da69017SMatthias Ringwald
1096cea08008SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
1097cea08008SMatthias Ringwald
1098ecf76c8dSMatthias Ringwald #define WinUSB_Lookup(fn) do { BTstack_##fn = (BTstack_##fn##_t) GetProcAddress(h, #fn); log_info("%-30s %p", #fn, BTstack_##fn); if (!BTstack_##fn) return FALSE; } while(0)
10995da69017SMatthias Ringwald
usb_lookup_symbols(void)1100f258f416SMatthias Ringwald static BOOL usb_lookup_symbols(void){
11015da69017SMatthias Ringwald // lookup runtime symbols missing in current mingw64 distribution
11025da69017SMatthias Ringwald HMODULE h = GetModuleHandleA("WinUSB");
110351a84de6SMatthias Ringwald log_info("%-30s %p", "WinUSB", h);
11045da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_QueryPipeEx);
11055da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_RegisterIsochBuffer);
11065da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_ReadIsochPipe);
11075da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_ReadIsochPipeAsap);
11085da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_WriteIsochPipe);
11095da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_WriteIsochPipeAsap);
11105da69017SMatthias Ringwald WinUSB_Lookup(WinUsb_UnregisterIsochBuffer);
1111f258f416SMatthias Ringwald WinUSB_Lookup(WinUsb_GetCurrentFrameNumber);
1112f258f416SMatthias Ringwald return TRUE;
11135da69017SMatthias Ringwald }
1114cea08008SMatthias Ringwald #endif
11155da69017SMatthias Ringwald
11165da69017SMatthias Ringwald // returns 0 on success, -1 otherwise
usb_open(void)11175da69017SMatthias Ringwald static int usb_open(void){
11185da69017SMatthias Ringwald
1119d2b52257SMatthias Ringwald if (usb_transport_open) return 0;
1120d2b52257SMatthias Ringwald
11215da69017SMatthias Ringwald int r = -1;
11225da69017SMatthias Ringwald
1123cea08008SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
1124f258f416SMatthias Ringwald BOOL ok = usb_lookup_symbols();
1125f258f416SMatthias Ringwald if (!ok){
1126f258f416SMatthias Ringwald log_error("usb_open: Failed to lookup WinSUB ISOCHRONOUS functions. Please disable ENABLE_SCO_OVER_HCI or use Windows 8.1 or higher");
1127f258f416SMatthias Ringwald return r;
1128f258f416SMatthias Ringwald }
1129f258f416SMatthias Ringwald sco_state_machine_init();
1130f258f416SMatthias Ringwald sco_ring_init();
1131cea08008SMatthias Ringwald #endif
1132cea08008SMatthias Ringwald
11335da69017SMatthias Ringwald HDEVINFO hDevInfo;
11345da69017SMatthias Ringwald SP_DEVICE_INTERFACE_DATA DevIntfData;
11355da69017SMatthias Ringwald PSP_DEVICE_INTERFACE_DETAIL_DATA DevIntfDetailData;
11365da69017SMatthias Ringwald SP_DEVINFO_DATA DevData;
11375da69017SMatthias Ringwald
11385da69017SMatthias Ringwald DWORD dwSize;
11395da69017SMatthias Ringwald DWORD dwMemberIdx;
11405da69017SMatthias Ringwald
11415da69017SMatthias Ringwald // default endpoint addresses
11425da69017SMatthias Ringwald event_in_addr = 0x81; // EP1, IN interrupt
11435da69017SMatthias Ringwald acl_in_addr = 0x82; // EP2, IN bulk
11445da69017SMatthias Ringwald acl_out_addr = 0x02; // EP2, OUT bulk
11455da69017SMatthias Ringwald sco_in_addr = 0x83; // EP3, IN isochronous
11465da69017SMatthias Ringwald sco_out_addr = 0x03; // EP3, OUT isochronous
11475da69017SMatthias Ringwald
11485da69017SMatthias Ringwald // We will try to get device information set for all USB devices that have a
11495da69017SMatthias Ringwald // device interface and are currently present on the system (plugged in).
11505da69017SMatthias Ringwald hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_USB_DEVICE, NULL, 0, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
11515da69017SMatthias Ringwald
11525da69017SMatthias Ringwald log_info("usb_open: SetupDiGetClassDevs -> %p", hDevInfo);
11535da69017SMatthias Ringwald if (hDevInfo == INVALID_HANDLE_VALUE) return -1;
11545da69017SMatthias Ringwald
11555da69017SMatthias Ringwald // Prepare to enumerate all device interfaces for the device information
11565da69017SMatthias Ringwald // set that we retrieved with SetupDiGetClassDevs(..)
11575da69017SMatthias Ringwald DevIntfData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
11585da69017SMatthias Ringwald dwMemberIdx = 0;
11595da69017SMatthias Ringwald
11605da69017SMatthias Ringwald // Next, we will keep calling this SetupDiEnumDeviceInterfaces(..) until this
11615da69017SMatthias Ringwald // function causes GetLastError() to return ERROR_NO_MORE_ITEMS. With each
11625da69017SMatthias Ringwald // call the dwMemberIdx value needs to be incremented to retrieve the next
11635da69017SMatthias Ringwald // device interface information.
11645da69017SMatthias Ringwald
11655da69017SMatthias Ringwald SetupDiEnumDeviceInterfaces(hDevInfo, NULL, (LPGUID) &GUID_DEVINTERFACE_USB_DEVICE,
11665da69017SMatthias Ringwald dwMemberIdx, &DevIntfData);
11675da69017SMatthias Ringwald
11685da69017SMatthias Ringwald while(GetLastError() != ERROR_NO_MORE_ITEMS){
11695da69017SMatthias Ringwald
11705da69017SMatthias Ringwald // As a last step we will need to get some more details for each
11715da69017SMatthias Ringwald // of device interface information we are able to retrieve. This
11725da69017SMatthias Ringwald // device interface detail gives us the information we need to identify
11735da69017SMatthias Ringwald // the device (VID/PID), and decide if it's useful to us. It will also
11745da69017SMatthias Ringwald // provide a DEVINFO_DATA structure which we can use to know the serial
11755da69017SMatthias Ringwald // port name for a virtual com port.
11765da69017SMatthias Ringwald
11775da69017SMatthias Ringwald DevData.cbSize = sizeof(DevData);
11785da69017SMatthias Ringwald
11795da69017SMatthias Ringwald // Get the required buffer size. Call SetupDiGetDeviceInterfaceDetail with
11805da69017SMatthias Ringwald // a NULL DevIntfDetailData pointer, a DevIntfDetailDataSize
11815da69017SMatthias Ringwald // of zero, and a valid RequiredSize variable. In response to such a call,
11825da69017SMatthias Ringwald // this function returns the required buffer size at dwSize.
11835da69017SMatthias Ringwald
11845da69017SMatthias Ringwald SetupDiGetDeviceInterfaceDetail(
11855da69017SMatthias Ringwald hDevInfo, &DevIntfData, NULL, 0, &dwSize, NULL);
11865da69017SMatthias Ringwald
11875da69017SMatthias Ringwald // Allocate memory for the DeviceInterfaceDetail struct. Don't forget to
11885da69017SMatthias Ringwald // deallocate it later!
11895da69017SMatthias Ringwald DevIntfDetailData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
11905da69017SMatthias Ringwald DevIntfDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
11915da69017SMatthias Ringwald
11925da69017SMatthias Ringwald if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &DevIntfData,
11935da69017SMatthias Ringwald DevIntfDetailData, dwSize, &dwSize, &DevData))
11945da69017SMatthias Ringwald {
11955da69017SMatthias Ringwald // Finally we can start checking if we've found a useable device,
11965da69017SMatthias Ringwald // by inspecting the DevIntfDetailData->DevicePath variable.
11975da69017SMatthias Ringwald // The DevicePath looks something like this:
11985da69017SMatthias Ringwald //
11995da69017SMatthias Ringwald // \\?\usb#vid_04d8&pid_0033#5&19f2438f&0&2#{a5dcbf10-6530-11d2-901f-00c04fb951ed}
12005da69017SMatthias Ringwald //
12015da69017SMatthias Ringwald
12025da69017SMatthias Ringwald log_info("usb_open: Device Path: %s", DevIntfDetailData->DevicePath);
12035da69017SMatthias Ringwald
12045da69017SMatthias Ringwald #if 0
120583159bb6SMatthias Ringwald // check for hard-coded vendor/product ids
12065da69017SMatthias Ringwald char vid_pid_match[30];
12075da69017SMatthias Ringwald uint16_t vid = 0x0a12;
12085da69017SMatthias Ringwald uint16_t pid = 0x0001;
12095da69017SMatthias Ringwald sprintf(vid_pid_match, "\\\\?\\usb#vid_%04x&pid_%04x", vid, pid);
12105da69017SMatthias Ringwald if (strncmp(DevIntfDetailData->DevicePath, &vid_pid_match[0], strlen(vid_pid_match)) == 0 ){
12115da69017SMatthias Ringwald log_info("Matched search string %s", vid_pid_match);
12125da69017SMatthias Ringwald
12135da69017SMatthias Ringwald BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
12145da69017SMatthias Ringwald if (result){
12155da69017SMatthias Ringwald log_info("usb_open: Device opened, stop scanning");
12165da69017SMatthias Ringwald r = 0;
12175da69017SMatthias Ringwald } else {
12185da69017SMatthias Ringwald log_error("usb_open: Device open failed");
12195da69017SMatthias Ringwald }
12205da69017SMatthias Ringwald }
122183159bb6SMatthias Ringwald #endif
12225da69017SMatthias Ringwald
122383159bb6SMatthias Ringwald // try all devices
122483159bb6SMatthias Ringwald BOOL result = usb_try_open_device(DevIntfDetailData->DevicePath);
122583159bb6SMatthias Ringwald if (result){
122683159bb6SMatthias Ringwald log_info("usb_open: Device opened, stop scanning");
122783159bb6SMatthias Ringwald r = 0;
122883159bb6SMatthias Ringwald } else {
122983159bb6SMatthias Ringwald log_error("usb_open: Device open failed");
123083159bb6SMatthias Ringwald }
123183159bb6SMatthias Ringwald }
12325da69017SMatthias Ringwald HeapFree(GetProcessHeap(), 0, DevIntfDetailData);
12335da69017SMatthias Ringwald
12345da69017SMatthias Ringwald if (r == 0) break;
12355da69017SMatthias Ringwald
12365da69017SMatthias Ringwald // Continue looping
12375da69017SMatthias Ringwald SetupDiEnumDeviceInterfaces(
12385da69017SMatthias Ringwald hDevInfo, NULL, &GUID_DEVINTERFACE_USB_DEVICE, ++dwMemberIdx, &DevIntfData);
12395da69017SMatthias Ringwald }
12405da69017SMatthias Ringwald
12415da69017SMatthias Ringwald SetupDiDestroyDeviceInfoList(hDevInfo);
12425da69017SMatthias Ringwald
1243d2b52257SMatthias Ringwald log_info("usb_open: done, r = %x", r);
1244d2b52257SMatthias Ringwald
1245d2b52257SMatthias Ringwald if (r == 0){
1246d2b52257SMatthias Ringwald // opened
1247d2b52257SMatthias Ringwald usb_transport_open = 1;
1248d2b52257SMatthias Ringwald }
12495da69017SMatthias Ringwald
12505da69017SMatthias Ringwald return r;
12515da69017SMatthias Ringwald }
12525da69017SMatthias Ringwald
usb_close(void)12535da69017SMatthias Ringwald static int usb_close(void){
1254cea08008SMatthias Ringwald
1255eec4d6c6SMatthias Ringwald if (!usb_transport_open) return 0;
1256d2b52257SMatthias Ringwald
1257cea08008SMatthias Ringwald // remove data sources
1258cea08008SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_command_out);
1259cea08008SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_event_in);
1260cea08008SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_acl_in);
1261cea08008SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_acl_out);
1262cea08008SMatthias Ringwald
1263cea08008SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
1264cea08008SMatthias Ringwald int i;
1265cea08008SMatthias Ringwald for (i=0;i<ISOC_BUFFERS;i++){
1266cea08008SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_sco_in[i]);
1267cea08008SMatthias Ringwald }
1268f258f416SMatthias Ringwald for (i=0;i<SCO_RING_BUFFER_COUNT;i++){
1269f258f416SMatthias Ringwald btstack_run_loop_remove_data_source(&usb_data_source_sco_out[i]);
1270f258f416SMatthias Ringwald }
1271cea08008SMatthias Ringwald #endif
1272cea08008SMatthias Ringwald
1273661115eeSMatthias Ringwald log_info("usb_close abort event and acl pipes");
1274661115eeSMatthias Ringwald
1275cea08008SMatthias Ringwald // stop transfers
1276cea08008SMatthias Ringwald WinUsb_AbortPipe(usb_interface_0_handle, event_in_addr);
1277cea08008SMatthias Ringwald WinUsb_AbortPipe(usb_interface_0_handle, acl_in_addr);
1278cea08008SMatthias Ringwald WinUsb_AbortPipe(usb_interface_0_handle, acl_out_addr);
1279cea08008SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
1280b9227387SMatthias Ringwald usb_sco_stop();
1281cea08008SMatthias Ringwald #endif
1282cea08008SMatthias Ringwald usb_acl_out_active = 0;
1283cea08008SMatthias Ringwald
1284cea08008SMatthias Ringwald // control transfer cannot be stopped, just wait for completion
1285cea08008SMatthias Ringwald if (usb_command_out_active){
1286661115eeSMatthias Ringwald log_info("usb_close command out active, wait for complete");
1287cea08008SMatthias Ringwald DWORD bytes_transferred;
1288cea08008SMatthias Ringwald WinUsb_GetOverlappedResult(usb_interface_0_handle, &usb_overlapped_command_out, &bytes_transferred, TRUE);
1289cea08008SMatthias Ringwald usb_command_out_active = 0;
1290cea08008SMatthias Ringwald }
1291cea08008SMatthias Ringwald
1292661115eeSMatthias Ringwald log_info("usb_close free resources");
1293661115eeSMatthias Ringwald
1294cea08008SMatthias Ringwald // free everything
12955da69017SMatthias Ringwald usb_free_resources();
1296d2b52257SMatthias Ringwald
1297d2b52257SMatthias Ringwald // transport closed
1298d2b52257SMatthias Ringwald usb_transport_open = 0;
1299d2b52257SMatthias Ringwald
1300cea08008SMatthias Ringwald return 0;
13015da69017SMatthias Ringwald }
13025da69017SMatthias Ringwald
usb_can_send_packet_now(uint8_t packet_type)13035da69017SMatthias Ringwald static int usb_can_send_packet_now(uint8_t packet_type){
1304f258f416SMatthias Ringwald // return 0;
13055da69017SMatthias Ringwald switch (packet_type){
13065da69017SMatthias Ringwald case HCI_COMMAND_DATA_PACKET:
13075da69017SMatthias Ringwald return !usb_command_out_active;
13085da69017SMatthias Ringwald case HCI_ACL_DATA_PACKET:
13095da69017SMatthias Ringwald return !usb_acl_out_active;
13105da69017SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
13115da69017SMatthias Ringwald case HCI_SCO_DATA_PACKET:
131211cb6f2dSMatthias Ringwald // return 0;
13135da69017SMatthias Ringwald return sco_ring_have_space();
13145da69017SMatthias Ringwald #endif
13155da69017SMatthias Ringwald default:
13165da69017SMatthias Ringwald return 0;
13175da69017SMatthias Ringwald }
13185da69017SMatthias Ringwald }
13195da69017SMatthias Ringwald
usb_send_cmd_packet(uint8_t * packet,int size)13205da69017SMatthias Ringwald static int usb_send_cmd_packet(uint8_t *packet, int size){
13215da69017SMatthias Ringwald
13225da69017SMatthias Ringwald // update stata before submitting transfer
13235da69017SMatthias Ringwald usb_command_out_active = 1;
13245da69017SMatthias Ringwald
13255da69017SMatthias Ringwald // Start trasnsfer
13265da69017SMatthias Ringwald WINUSB_SETUP_PACKET setup_packet;
13275da69017SMatthias Ringwald memset(&setup_packet, 0, sizeof(setup_packet));
13285da69017SMatthias Ringwald setup_packet.RequestType = USB_REQUEST_TYPE_CLASS | USB_RECIPIENT_INTERFACE;
13295da69017SMatthias Ringwald setup_packet.Length = sizeof(size);
13305da69017SMatthias Ringwald BOOL result = WinUsb_ControlTransfer(usb_interface_0_handle, setup_packet, packet, size, NULL, &usb_overlapped_command_out);
13315da69017SMatthias Ringwald if (!result) {
13325da69017SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
13335da69017SMatthias Ringwald }
13345da69017SMatthias Ringwald
13355da69017SMatthias Ringwald // IO_PENDING -> wait for completed
13365da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_command_out, DATA_SOURCE_CALLBACK_WRITE);
13375da69017SMatthias Ringwald
13385da69017SMatthias Ringwald return 0;
13395da69017SMatthias Ringwald
13405da69017SMatthias Ringwald exit_on_error:
134183159bb6SMatthias Ringwald log_error("winusb: last error %lu", GetLastError());
13425da69017SMatthias Ringwald return -1;
13435da69017SMatthias Ringwald }
13445da69017SMatthias Ringwald
usb_send_acl_packet(uint8_t * packet,int size)13455da69017SMatthias Ringwald static int usb_send_acl_packet(uint8_t *packet, int size){
13465da69017SMatthias Ringwald
13475da69017SMatthias Ringwald // update stata before submitting transfer
13485da69017SMatthias Ringwald usb_acl_out_active = 1;
13495da69017SMatthias Ringwald
13505da69017SMatthias Ringwald // Start trasnsfer
135183f31aa4SMatthias Ringwald BOOL ok = WinUsb_WritePipe(usb_interface_0_handle, acl_out_addr, packet, size, NULL, &usb_overlapped_acl_out);
135283f31aa4SMatthias Ringwald if (!ok) {
13535da69017SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
13545da69017SMatthias Ringwald }
13555da69017SMatthias Ringwald
13565da69017SMatthias Ringwald // IO_PENDING -> wait for completed
13575da69017SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_acl_out, DATA_SOURCE_CALLBACK_WRITE);
13585da69017SMatthias Ringwald return 0;
13595da69017SMatthias Ringwald
13605da69017SMatthias Ringwald exit_on_error:
136183159bb6SMatthias Ringwald log_error("winusb: last error %lu", GetLastError());
13625da69017SMatthias Ringwald return -1;
13635da69017SMatthias Ringwald }
13645da69017SMatthias Ringwald
1365f258f416SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
usb_send_sco_packet(uint8_t * packet,int size)1366f258f416SMatthias Ringwald static int usb_send_sco_packet(uint8_t *packet, int size){
1367f258f416SMatthias Ringwald
136883f31aa4SMatthias Ringwald if (size > SCO_PACKET_SIZE){
136983f31aa4SMatthias Ringwald log_error("usb_send_sco_packet: size %u > SCO_PACKET_SIZE %u", size, SCO_PACKET_SIZE);
1370f258f416SMatthias Ringwald return -1;
1371f258f416SMatthias Ringwald }
137283f31aa4SMatthias Ringwald
137311cb6f2dSMatthias Ringwald // get current frame number
137411cb6f2dSMatthias Ringwald ULONG current_frame_number;
137511cb6f2dSMatthias Ringwald LARGE_INTEGER timestamp;
1376ecf76c8dSMatthias Ringwald BTstack_WinUsb_GetCurrentFrameNumber(usb_interface_0_handle, ¤t_frame_number, ×tamp);
137783f31aa4SMatthias Ringwald
137883f31aa4SMatthias Ringwald // store packet in free slot
137983f31aa4SMatthias Ringwald int transfer_index = sco_ring_write;
138083f31aa4SMatthias Ringwald uint8_t * data = &sco_ring_buffer[transfer_index * SCO_PACKET_SIZE];
138183f31aa4SMatthias Ringwald memcpy(data, packet, size);
138283f31aa4SMatthias Ringwald
138383f31aa4SMatthias Ringwald
138483f31aa4SMatthias Ringwald // setup transfer
138583f31aa4SMatthias Ringwald int continue_stream = sco_ring_transfers_active > 0;
1386ecf76c8dSMatthias Ringwald BOOL ok = BTstack_WinUsb_WriteIsochPipeAsap(hci_sco_out_buffer_handle, transfer_index * SCO_PACKET_SIZE, size, continue_stream, &usb_overlapped_sco_out[transfer_index]);
1387c6ac61cdSMatthias Ringwald // 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);
138883f31aa4SMatthias Ringwald if (!ok) {
138983f31aa4SMatthias Ringwald if (GetLastError() != ERROR_IO_PENDING) goto exit_on_error;
139083f31aa4SMatthias Ringwald }
139183f31aa4SMatthias Ringwald
139283f31aa4SMatthias Ringwald // successful started transfer, enable data source callback if first active transfer
139383f31aa4SMatthias Ringwald if (sco_ring_transfers_active == 0){
139483f31aa4SMatthias Ringwald usb_sco_out_expected_transfer = transfer_index;
139583f31aa4SMatthias Ringwald btstack_run_loop_enable_data_source_callbacks(&usb_data_source_sco_out[transfer_index], DATA_SOURCE_CALLBACK_WRITE);
139683f31aa4SMatthias Ringwald }
1397f258f416SMatthias Ringwald
1398f258f416SMatthias Ringwald // mark slot as full
139983f31aa4SMatthias Ringwald sco_ring_write = (sco_ring_write + 1) % SCO_RING_BUFFER_COUNT;
1400f258f416SMatthias Ringwald sco_ring_transfers_active++;
1401f258f416SMatthias Ringwald
1402f258f416SMatthias Ringwald // notify upper stack that provided buffer can be used again
1403f258f416SMatthias Ringwald uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0};
1404f258f416SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
1405f258f416SMatthias Ringwald
1406c6ac61cdSMatthias Ringwald // log_info("usb_send_sco_packet: transfers active %u", sco_ring_transfers_active);
140711cb6f2dSMatthias Ringwald
1408f258f416SMatthias Ringwald // and if we have more space for SCO packets
1409f258f416SMatthias Ringwald if (sco_ring_have_space()) {
1410f258f416SMatthias Ringwald uint8_t event_sco[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0};
1411f258f416SMatthias Ringwald packet_handler(HCI_EVENT_PACKET, &event_sco[0], sizeof(event_sco));
1412f258f416SMatthias Ringwald }
1413f258f416SMatthias Ringwald return 0;
141483f31aa4SMatthias Ringwald
141583f31aa4SMatthias Ringwald exit_on_error:
141683f31aa4SMatthias Ringwald log_error("usb_send_sco_packet: last error %lu", GetLastError());
141783f31aa4SMatthias Ringwald return -1;
1418f258f416SMatthias Ringwald }
1419f258f416SMatthias Ringwald #endif
14205da69017SMatthias Ringwald
usb_send_packet(uint8_t packet_type,uint8_t * packet,int size)14215da69017SMatthias Ringwald static int usb_send_packet(uint8_t packet_type, uint8_t * packet, int size){
14225da69017SMatthias Ringwald switch (packet_type){
14235da69017SMatthias Ringwald case HCI_COMMAND_DATA_PACKET:
14245da69017SMatthias Ringwald return usb_send_cmd_packet(packet, size);
14255da69017SMatthias Ringwald case HCI_ACL_DATA_PACKET:
14265da69017SMatthias Ringwald return usb_send_acl_packet(packet, size);
14275da69017SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
14285da69017SMatthias Ringwald case HCI_SCO_DATA_PACKET:
14295da69017SMatthias Ringwald return usb_send_sco_packet(packet, size);
14305da69017SMatthias Ringwald #endif
14315da69017SMatthias Ringwald default:
14325da69017SMatthias Ringwald return -1;
14335da69017SMatthias Ringwald }
14345da69017SMatthias Ringwald }
14355da69017SMatthias Ringwald
14361b3ee5c3SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
usb_set_sco_config(uint16_t voice_setting,int num_connections)14371b3ee5c3SMatthias Ringwald static void usb_set_sco_config(uint16_t voice_setting, int num_connections){
14381b3ee5c3SMatthias Ringwald log_info("usb_set_sco_config: voice settings 0x%04x, num connections %u", voice_setting, num_connections);
14391b3ee5c3SMatthias Ringwald
14401b3ee5c3SMatthias Ringwald if (num_connections != sco_num_connections){
14411b3ee5c3SMatthias Ringwald sco_voice_setting = voice_setting;
14421b3ee5c3SMatthias Ringwald if (sco_num_connections){
1443b5ffb4caSMatthias Ringwald usb_sco_stop();
14441b3ee5c3SMatthias Ringwald }
14451b3ee5c3SMatthias Ringwald sco_num_connections = num_connections;
14461b3ee5c3SMatthias Ringwald if (num_connections){
1447b5ffb4caSMatthias Ringwald usb_sco_start();
14481b3ee5c3SMatthias Ringwald }
14491b3ee5c3SMatthias Ringwald }
14501b3ee5c3SMatthias Ringwald }
14511b3ee5c3SMatthias Ringwald #endif
14521b3ee5c3SMatthias Ringwald
14535da69017SMatthias Ringwald // get usb singleton
14545da69017SMatthias Ringwald static const hci_transport_t hci_transport_usb = {
14555da69017SMatthias Ringwald /* const char * name; */ "H2_WINUSB",
14565da69017SMatthias Ringwald /* void (*init) (const void *transport_config); */ &usb_init,
14575da69017SMatthias Ringwald /* int (*open)(void); */ &usb_open,
14585da69017SMatthias Ringwald /* int (*close)(void); */ &usb_close,
14595da69017SMatthias Ringwald /* void (*register_packet_handler)(void (*handler)(...); */ &usb_register_packet_handler,
14605da69017SMatthias Ringwald /* int (*can_send_packet_now)(uint8_t packet_type); */ &usb_can_send_packet_now,
14615da69017SMatthias Ringwald /* int (*send_packet)(...); */ &usb_send_packet,
14625da69017SMatthias Ringwald /* int (*set_baudrate)(uint32_t baudrate); */ NULL,
14635da69017SMatthias Ringwald /* void (*reset_link)(void); */ NULL,
1464c4218671SMatthias Ringwald #ifdef ENABLE_SCO_OVER_HCI
14651b3ee5c3SMatthias Ringwald /* void (*set_sco_config)(uint16_t voice_setting, int num_connections); */ usb_set_sco_config,
1466c4218671SMatthias Ringwald #else
1467c4218671SMatthias Ringwald /* void (*set_sco_config)(uint16_t voice_setting, int num_connections); */ NULL,
1468c4218671SMatthias Ringwald #endif
14695da69017SMatthias Ringwald };
14705da69017SMatthias Ringwald
hci_transport_usb_instance(void)14715da69017SMatthias Ringwald const hci_transport_t * hci_transport_usb_instance(void) {
14725da69017SMatthias Ringwald return &hci_transport_usb;
14735da69017SMatthias Ringwald }
1474