2009-10-29 20:25:42 +00:00
/*
2015-02-06 16:19:27 +00:00
* Copyright ( C ) 2014 BlueKitchen GmbH
2009-10-29 20:25:42 +00:00
*
* Redistribution and use in source and binary forms , with or without
* modification , are permitted provided that the following conditions
* are met :
*
* 1. Redistributions of source code must retain the above copyright
* notice , this list of conditions and the following disclaimer .
* 2. Redistributions in binary form must reproduce the above copyright
* notice , this list of conditions and the following disclaimer in the
* documentation and / or other materials provided with the distribution .
* 3. Neither the name of the copyright holders nor the names of
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission .
2012-05-07 21:54:09 +00:00
* 4. Any redistribution , use , or modification is done solely for
* personal benefit and not for any commercial purpose or for
* monetary gain .
2009-10-29 20:25:42 +00:00
*
2015-02-06 16:19:27 +00:00
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
2009-10-29 20:25:42 +00:00
* ` ` AS IS ' ' AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
* LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL MATTHIAS
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT ,
* INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING ,
* BUT NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS
* OF USE , DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY ,
* OR TORT ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE .
*
2015-02-06 16:19:27 +00:00
* Please inquire about commercial licensing options at
* contact @ bluekitchen - gmbh . com
2012-05-07 21:54:09 +00:00
*
2009-10-29 20:25:42 +00:00
*/
2017-03-24 23:39:20 +01:00
# define __BTSTACK_FILE__ "hci_transport_h2_libusb.c"
2009-07-05 21:06:38 +00:00
/*
* hci_transport_usb . c
*
2009-07-08 22:21:02 +00:00
* HCI Transport API implementation for USB
*
2009-07-05 21:06:38 +00:00
* Created by Matthias Ringwald on 7 / 5 / 09.
*/
// Interface Number - Alternate Setting - suggested Endpoint Address - Endpoint Type - Suggested Max Packet Size
// HCI Commands 0 0 0x00 Control 8/16/32/64
// HCI Events 0 0 0x81 Interrupt (IN) 16
2011-01-12 20:43:27 +00:00
// ACL Data 0 0 0x82 Bulk (IN) 32/64
// ACL Data 0 0 0x02 Bulk (OUT) 32/64
2015-02-13 14:58:47 +00:00
// SCO Data 0 0 0x83 Isochronous (IN)
// SCO Data 0 0 0x03 Isochronous (Out)
2009-07-05 21:06:38 +00:00
# include <stdio.h>
2009-07-08 22:21:02 +00:00
# include <strings.h>
2011-06-23 18:52:07 +00:00
# include <string.h>
2009-07-08 22:21:02 +00:00
# include <unistd.h> /* UNIX standard function definitions */
2009-07-05 21:06:38 +00:00
# include <sys/types.h>
2014-09-10 21:03:38 +00:00
# include <libusb.h>
2009-07-05 21:06:38 +00:00
2016-01-21 15:41:16 +01:00
# include "btstack_config.h"
2011-01-12 19:48:08 +00:00
2016-01-20 14:52:45 +01:00
# include "btstack_debug.h"
2009-07-08 22:21:02 +00:00
# include "hci.h"
2010-06-04 18:10:12 +00:00
# include "hci_transport.h"
2009-07-08 22:21:02 +00:00
2013-06-04 10:10:50 +00:00
# if (USB_VENDOR_ID != 0) && (USB_PRODUCT_ID != 0)
# define HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
# endif
2017-01-11 10:21:07 +01:00
# define ACL_IN_BUFFER_COUNT 3
# define EVENT_IN_BUFFER_COUNT 3
# define SCO_IN_BUFFER_COUNT 10
2016-05-23 13:57:53 +02:00
# define ASYNC_POLLING_INTERVAL_MS 1
2016-01-18 13:58:34 +01:00
//
2016-05-23 13:57:53 +02:00
// Bluetooth USB Transport Alternate Settings:
2016-01-18 13:58:34 +01:00
//
// 0: No active voice channels (for USB compliance)
// 1: One 8 kHz voice channel with 8-bit encoding
// 2: Two 8 kHz voice channels with 8-bit encoding or one 8 kHz voice channel with 16-bit encoding
// 3: Three 8 kHz voice channels with 8-bit encoding
// 4: Two 8 kHz voice channels with 16-bit encoding or one 16 kHz voice channel with 16-bit encoding
// 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
// --> support only a single SCO connection
2017-01-20 22:26:57 +01:00
// #define ALT_SETTING (1)
2016-01-18 13:58:34 +01:00
2017-07-04 17:38:30 +02:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-19 18:10:47 +01:00
// alt setting for 1-3 connections and 8/16 bit
static const int alt_setting_8_bit [ ] = { 1 , 2 , 3 } ;
static const int alt_setting_16_bit [ ] = { 2 , 4 , 5 } ;
2016-01-18 13:58:34 +01:00
// for ALT_SETTING >= 1 and 8-bit channel, we need the following isochronous packets
// One complete SCO packet with 24 frames every 3 frames (== 3 ms)
# define NUM_ISO_PACKETS (3)
2017-01-19 12:12:25 +01:00
2017-05-18 15:15:46 +02:00
static const uint16_t iso_packet_size_for_alt_setting [ ] = {
2017-01-19 12:12:25 +01:00
0 ,
9 ,
17 ,
25 ,
33 ,
49 ,
63 ,
} ;
2017-07-04 17:38:30 +02:00
# endif
2017-01-19 12:12:25 +01:00
2016-01-18 13:58:34 +01:00
// 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)
// 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
2017-01-20 22:26:57 +01:00
# define SCO_PACKET_SIZE (49 * NUM_ISO_PACKETS)
2016-01-18 13:58:34 +01:00
// Outgoing SCO packet queue
// simplified ring buffer implementation
2017-01-11 10:21:07 +01:00
# define SCO_OUT_BUFFER_COUNT (8)
# define SCO_OUT_BUFFER_SIZE (SCO_OUT_BUFFER_COUNT * SCO_PACKET_SIZE)
2016-01-18 13:58:34 +01:00
2016-07-09 16:10:45 +02:00
// seems to be the max depth for USB 3
# define USB_MAX_PATH_LEN 7
2009-07-08 22:21:02 +00:00
// prototypes
2010-09-21 17:18:50 +00:00
static void dummy_handler ( uint8_t packet_type , uint8_t * packet , uint16_t size ) ;
2016-01-27 15:30:31 +01:00
static int usb_close ( void ) ;
2016-01-18 13:58:34 +01:00
2013-05-21 12:10:36 +00:00
typedef enum {
2011-06-23 18:52:07 +00:00
LIB_USB_CLOSED = 0 ,
2009-07-08 22:21:02 +00:00
LIB_USB_OPENED ,
LIB_USB_DEVICE_OPENDED ,
LIB_USB_INTERFACE_CLAIMED ,
LIB_USB_TRANSFERS_ALLOCATED
2013-05-21 12:10:36 +00:00
} libusb_state_t ;
2015-02-17 21:32:57 +00:00
// SCO packet state machine
typedef enum {
H2_W4_SCO_HEADER = 1 ,
H2_W4_PAYLOAD ,
} H2_SCO_STATE ;
2013-05-21 12:10:36 +00:00
static libusb_state_t libusb_state = LIB_USB_CLOSED ;
2009-07-08 22:21:02 +00:00
// single instance
static hci_transport_t * hci_transport_usb = NULL ;
2013-09-16 18:57:33 +00:00
static void ( * packet_handler ) ( uint8_t packet_type , uint8_t * packet , uint16_t size ) = dummy_handler ;
2009-07-08 22:21:02 +00:00
// libusb
2013-06-04 10:10:50 +00:00
# ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
2009-07-08 22:21:02 +00:00
static struct libusb_device_descriptor desc ;
static libusb_device * dev ;
2011-10-08 16:58:36 +00:00
# endif
2009-07-08 22:21:02 +00:00
static libusb_device_handle * handle ;
2011-06-23 18:52:07 +00:00
2013-03-06 13:24:04 +00:00
static struct libusb_transfer * command_out_transfer ;
2015-02-13 14:58:47 +00:00
static struct libusb_transfer * acl_out_transfer ;
2017-01-11 10:21:07 +01:00
static struct libusb_transfer * event_in_transfer [ EVENT_IN_BUFFER_COUNT ] ;
static struct libusb_transfer * acl_in_transfer [ ACL_IN_BUFFER_COUNT ] ;
2013-03-06 13:24:04 +00:00
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2016-01-18 13:58:34 +01:00
2016-02-15 21:49:39 +01:00
# ifdef _WIN32
2016-03-01 17:29:04 +01:00
# error "SCO not working on Win32 (Windows 8, libusb 1.0.19, Zadic WinUSB), please uncomment ENABLE_SCO_OVER_HCI in btstack-config.h for now"
2016-02-15 21:49:39 +01:00
# endif
2016-01-18 13:58:34 +01:00
// incoming SCO
2015-02-17 22:42:08 +00:00
static H2_SCO_STATE sco_state ;
2015-02-17 21:32:57 +00:00
static uint8_t sco_buffer [ 255 + 3 + SCO_PACKET_SIZE ] ;
static uint16_t sco_read_pos ;
static uint16_t sco_bytes_to_read ;
2017-01-11 10:21:07 +01:00
static struct libusb_transfer * sco_in_transfer [ SCO_IN_BUFFER_COUNT ] ;
static uint8_t hci_sco_in_buffer [ SCO_IN_BUFFER_COUNT ] [ SCO_PACKET_SIZE ] ;
2016-01-18 13:58:34 +01:00
// outgoing SCO
2017-01-11 10:21:07 +01:00
static uint8_t sco_out_ring_buffer [ SCO_OUT_BUFFER_SIZE ] ;
2016-01-18 13:58:34 +01:00
static int sco_ring_write ; // packet idx
2017-01-11 10:21:07 +01:00
static int sco_out_transfers_active ;
static struct libusb_transfer * sco_out_transfers [ SCO_OUT_BUFFER_COUNT ] ;
static int sco_out_transfers_in_flight [ SCO_OUT_BUFFER_COUNT ] ;
2017-01-19 17:44:52 +01:00
// pause/resume
static uint16_t sco_voice_setting ;
static int sco_num_connections ;
static int sco_shutdown ;
2017-01-20 22:26:57 +01:00
// dynamic SCO configuration
static uint16_t iso_packet_size ;
2015-02-13 14:58:47 +00:00
# endif
2011-06-23 18:52:07 +00:00
2016-01-18 13:58:34 +01:00
// outgoing buffer for HCI Command packets
2015-02-13 14:58:47 +00:00
static uint8_t hci_cmd_buffer [ 3 + 256 + LIBUSB_CONTROL_SETUP_SIZE ] ;
2016-01-18 13:58:34 +01:00
// incoming buffer for HCI Events and ACL Packets
2017-01-11 10:21:07 +01:00
static uint8_t hci_event_in_buffer [ EVENT_IN_BUFFER_COUNT ] [ HCI_ACL_BUFFER_SIZE ] ; // bigger than largest packet
static uint8_t hci_acl_in_buffer [ ACL_IN_BUFFER_COUNT ] [ HCI_INCOMING_PRE_BUFFER_SIZE + HCI_ACL_BUFFER_SIZE ] ;
2011-06-23 18:52:07 +00:00
// For (ab)use as a linked list of received packets
static struct libusb_transfer * handle_packet ;
static int doing_pollfds ;
2014-06-12 15:24:51 +00:00
static int num_pollfds ;
2016-01-20 16:00:45 +01:00
static btstack_data_source_t * pollfd_data_sources ;
static btstack_timer_source_t usb_timer ;
2011-06-23 18:52:07 +00:00
static int usb_timer_active ;
2009-10-18 20:49:27 +00:00
2013-03-06 13:24:04 +00:00
static int usb_acl_out_active = 0 ;
2013-03-06 18:06:22 +00:00
static int usb_command_active = 0 ;
2013-03-06 13:24:04 +00:00
2011-01-12 20:43:27 +00:00
// endpoint addresses
static int event_in_addr ;
static int acl_in_addr ;
static int acl_out_addr ;
2015-02-13 14:58:47 +00:00
static int sco_in_addr ;
static int sco_out_addr ;
2016-07-09 16:10:45 +02:00
// device path
static int usb_path_len ;
static uint8_t usb_path [ USB_MAX_PATH_LEN ] ;
2016-01-15 22:11:56 +01:00
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2016-01-15 22:11:56 +01:00
static void sco_ring_init ( void ) {
sco_ring_write = 0 ;
2017-01-11 10:21:07 +01:00
sco_out_transfers_active = 0 ;
2016-01-15 22:11:56 +01:00
}
static int sco_ring_have_space ( void ) {
2017-01-11 10:21:07 +01:00
return sco_out_transfers_active < SCO_OUT_BUFFER_COUNT ;
2016-01-15 22:11:56 +01:00
}
2016-01-27 15:30:31 +01:00
# endif
2016-01-15 22:11:56 +01:00
2016-07-09 16:10:45 +02:00
void hci_transport_usb_set_path ( int len , uint8_t * port_numbers ) {
if ( len > USB_MAX_PATH_LEN | | ! port_numbers ) {
log_error ( " hci_transport_usb_set_path: len or port numbers invalid " ) ;
return ;
}
usb_path_len = len ;
memcpy ( usb_path , port_numbers , len ) ;
}
2009-07-05 21:06:38 +00:00
2016-01-15 22:11:56 +01:00
//
2013-03-06 18:40:47 +00:00
static void queue_transfer ( struct libusb_transfer * transfer ) {
2013-03-05 16:04:53 +00:00
2013-09-02 19:36:28 +00:00
// log_info("queue_transfer %p, endpoint %x size %u", transfer, transfer->endpoint, transfer->actual_length);
2013-03-05 16:04:53 +00:00
2013-02-24 18:13:16 +00:00
transfer - > user_data = NULL ;
// insert first element
if ( handle_packet = = NULL ) {
handle_packet = transfer ;
return ;
}
// Walk to end of list and add current packet there
struct libusb_transfer * temp = handle_packet ;
while ( temp - > user_data ) {
2013-06-04 10:10:50 +00:00
temp = ( struct libusb_transfer * ) temp - > user_data ;
2013-02-24 18:13:16 +00:00
}
temp - > user_data = transfer ;
}
2016-11-27 17:01:51 +01:00
LIBUSB_CALL static void async_callback ( struct libusb_transfer * transfer ) {
2017-01-11 10:21:07 +01:00
2016-12-05 22:38:19 +01:00
int c ;
2017-01-11 10:21:07 +01:00
// identify and free transfers as part of shutdown
2016-11-23 23:15:02 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-19 17:44:52 +01:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED | | sco_shutdown ) {
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
2016-11-23 23:15:02 +01:00
if ( transfer = = sco_in_transfer [ c ] ) {
libusb_free_transfer ( transfer ) ;
sco_in_transfer [ c ] = 0 ;
return ;
}
}
2016-12-05 20:01:23 +00:00
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( transfer = = sco_out_transfers [ c ] ) {
sco_out_transfers_in_flight [ c ] = 0 ;
2016-12-05 20:01:23 +00:00
libusb_free_transfer ( transfer ) ;
2017-01-11 10:21:07 +01:00
sco_out_transfers [ c ] = 0 ;
2016-12-05 20:01:23 +00:00
return ;
}
}
2017-01-19 17:44:52 +01:00
}
2016-11-23 23:15:02 +01:00
# endif
2017-01-19 17:44:52 +01:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) {
for ( c = 0 ; c < EVENT_IN_BUFFER_COUNT ; c + + ) {
if ( transfer = = event_in_transfer [ c ] ) {
libusb_free_transfer ( transfer ) ;
event_in_transfer [ c ] = 0 ;
return ;
}
}
for ( c = 0 ; c < ACL_IN_BUFFER_COUNT ; c + + ) {
if ( transfer = = acl_in_transfer [ c ] ) {
libusb_free_transfer ( transfer ) ;
acl_in_transfer [ c ] = 0 ;
return ;
}
}
2016-11-23 23:15:02 +01:00
return ;
}
2017-01-14 22:23:38 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-11 10:21:07 +01:00
// mark SCO OUT transfer as done
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( transfer = = sco_out_transfers [ c ] ) {
sco_out_transfers_in_flight [ c ] = 0 ;
2016-12-05 20:01:23 +00:00
}
}
2017-01-14 22:23:38 +01:00
# endif
2016-12-05 20:01:23 +00:00
2011-06-23 18:52:07 +00:00
int r ;
2013-02-24 19:59:57 +00:00
// log_info("begin async_callback endpoint %x, status %x, actual length %u", transfer->endpoint, transfer->status, transfer->actual_length );
2011-06-23 18:52:07 +00:00
2013-03-05 16:04:53 +00:00
if ( transfer - > status = = LIBUSB_TRANSFER_COMPLETED ) {
2013-03-06 18:40:47 +00:00
queue_transfer ( transfer ) ;
2013-03-06 13:24:04 +00:00
} else if ( transfer - > status = = LIBUSB_TRANSFER_STALL ) {
log_info ( " -> Transfer stalled, trying again " ) ;
2013-03-06 17:47:50 +00:00
r = libusb_clear_halt ( handle , transfer - > endpoint ) ;
if ( r ) {
log_error ( " Error rclearing halt %d " , r ) ;
}
2013-03-06 13:24:04 +00:00
r = libusb_submit_transfer ( transfer ) ;
if ( r ) {
log_error ( " Error re-submitting transfer %d " , r ) ;
}
2011-06-23 18:52:07 +00:00
} else {
2015-11-06 16:26:25 +01:00
log_info ( " async_callback. not data -> resubmit transfer, endpoint %x, status %x, length %u " , transfer - > endpoint , transfer - > status , transfer - > actual_length ) ;
2011-06-23 18:52:07 +00:00
// No usable data, just resubmit packet
2013-03-06 13:24:04 +00:00
r = libusb_submit_transfer ( transfer ) ;
if ( r ) {
log_error ( " Error re-submitting transfer %d " , r ) ;
2011-06-23 18:52:07 +00:00
}
}
2013-02-24 19:59:57 +00:00
// log_info("end async_callback");
2011-06-23 18:52:07 +00:00
}
2016-01-15 22:11:56 +01:00
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2016-01-27 15:30:31 +01:00
static int usb_send_sco_packet ( uint8_t * packet , int size ) {
2016-01-15 22:11:56 +01:00
int r ;
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return - 1 ;
// log_info("usb_send_acl_packet enter, size %u", size);
// store packet in free slot
int tranfer_index = sco_ring_write ;
2017-01-11 10:21:07 +01:00
uint8_t * data = & sco_out_ring_buffer [ tranfer_index * SCO_PACKET_SIZE ] ;
2016-01-15 23:14:15 +01:00
memcpy ( data , packet , size ) ;
2016-01-15 22:11:56 +01:00
// setup transfer
2017-01-20 22:26:57 +01:00
// log_info("usb_send_sco_packet: size %u, max size %u, iso packet size %u", size, NUM_ISO_PACKETS * iso_packet_size, iso_packet_size);
2017-01-11 10:21:07 +01:00
struct libusb_transfer * sco_transfer = sco_out_transfers [ tranfer_index ] ;
2017-01-20 22:26:57 +01:00
libusb_fill_iso_transfer ( sco_transfer , handle , sco_out_addr , data , NUM_ISO_PACKETS * iso_packet_size , NUM_ISO_PACKETS , async_callback , NULL , 0 ) ;
libusb_set_iso_packet_lengths ( sco_transfer , iso_packet_size ) ;
2016-01-15 22:11:56 +01:00
r = libusb_submit_transfer ( sco_transfer ) ;
if ( r < 0 ) {
log_error ( " Error submitting sco transfer, %d " , r ) ;
return - 1 ;
}
// mark slot as full
sco_ring_write + + ;
2017-01-11 10:21:07 +01:00
if ( sco_ring_write = = SCO_OUT_BUFFER_COUNT ) {
2016-01-15 22:11:56 +01:00
sco_ring_write = 0 ;
}
2017-01-11 10:21:07 +01:00
sco_out_transfers_active + + ;
sco_out_transfers_in_flight [ tranfer_index ] = 1 ;
2016-01-15 22:11:56 +01:00
2017-01-11 10:21:07 +01:00
// log_info("H2: queued packet at index %u, num active %u", tranfer_index, sco_out_transfers_active);
2016-01-15 22:11:56 +01:00
2016-02-18 14:48:41 +01:00
// notify upper stack that provided buffer can be used again
uint8_t event [ ] = { HCI_EVENT_TRANSPORT_PACKET_SENT , 0 } ;
packet_handler ( HCI_EVENT_PACKET , & event [ 0 ] , sizeof ( event ) ) ;
2016-02-18 15:05:38 +01:00
// and if we have more space for SCO packets
if ( sco_ring_have_space ( ) ) {
uint8_t event_sco [ ] = { HCI_EVENT_SCO_CAN_SEND_NOW , 0 } ;
packet_handler ( HCI_EVENT_PACKET , & event_sco [ 0 ] , sizeof ( event_sco ) ) ;
}
2016-01-15 22:11:56 +01:00
return 0 ;
}
2015-05-13 10:30:46 +02:00
static void sco_state_machine_init ( void ) {
2015-02-14 21:52:09 +00:00
sco_state = H2_W4_SCO_HEADER ;
sco_read_pos = 0 ;
sco_bytes_to_read = 3 ;
}
static void handle_isochronous_data ( uint8_t * buffer , uint16_t size ) {
while ( size ) {
if ( size < sco_bytes_to_read ) {
// just store incomplete data
memcpy ( & sco_buffer [ sco_read_pos ] , buffer , size ) ;
sco_read_pos + = size ;
sco_bytes_to_read - = size ;
return ;
}
// copy requested data
memcpy ( & sco_buffer [ sco_read_pos ] , buffer , sco_bytes_to_read ) ;
sco_read_pos + = sco_bytes_to_read ;
buffer + = sco_bytes_to_read ;
size - = sco_bytes_to_read ;
// chunk read successfully, next action
switch ( sco_state ) {
case H2_W4_SCO_HEADER :
sco_state = H2_W4_PAYLOAD ;
sco_bytes_to_read = sco_buffer [ 2 ] ;
break ;
case H2_W4_PAYLOAD :
// packet complete
packet_handler ( HCI_SCO_DATA_PACKET , sco_buffer , sco_read_pos ) ;
sco_state_machine_init ( ) ;
break ;
}
}
}
2016-01-27 15:30:31 +01:00
# endif
2015-02-14 21:52:09 +00:00
2013-03-06 18:40:47 +00:00
static void handle_completed_transfer ( struct libusb_transfer * transfer ) {
2013-02-24 18:13:16 +00:00
2013-03-06 18:40:47 +00:00
int resubmit = 0 ;
2015-02-13 14:58:47 +00:00
int signal_done = 0 ;
2011-06-23 18:52:07 +00:00
2013-03-06 18:40:47 +00:00
if ( transfer - > endpoint = = event_in_addr ) {
2014-11-16 20:05:18 +00:00
packet_handler ( HCI_EVENT_PACKET , transfer - > buffer , transfer - > actual_length ) ;
2013-03-06 18:40:47 +00:00
resubmit = 1 ;
2015-02-13 14:58:47 +00:00
} else if ( transfer - > endpoint = = acl_in_addr ) {
2013-03-06 18:40:47 +00:00
// log_info("-> acl");
2014-11-16 20:05:18 +00:00
packet_handler ( HCI_ACL_DATA_PACKET , transfer - > buffer , transfer - > actual_length ) ;
2013-03-06 18:40:47 +00:00
resubmit = 1 ;
2016-01-27 15:30:31 +01:00
} else if ( transfer - > endpoint = = 0 ) {
// log_info("command done, size %u", transfer->actual_length);
usb_command_active = 0 ;
signal_done = 1 ;
} else if ( transfer - > endpoint = = acl_out_addr ) {
// log_info("acl out done, size %u", transfer->actual_length);
usb_acl_out_active = 0 ;
signal_done = 1 ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
} else if ( transfer - > endpoint = = sco_in_addr ) {
2016-01-18 13:58:34 +01:00
// log_info("handle_completed_transfer for SCO IN! num packets %u", transfer->NUM_ISO_PACKETS);
2015-02-13 22:43:42 +00:00
int i ;
for ( i = 0 ; i < transfer - > num_iso_packets ; i + + ) {
struct libusb_iso_packet_descriptor * pack = & transfer - > iso_packet_desc [ i ] ;
if ( pack - > status ! = LIBUSB_TRANSFER_COMPLETED ) {
log_error ( " Error: pack %u status %d \n " , i , pack - > status ) ;
continue ;
}
2015-11-06 16:26:25 +01:00
if ( ! pack - > actual_length ) continue ;
uint8_t * data = libusb_get_iso_packet_buffer_simple ( transfer , i ) ;
// printf_hexdump(data, pack->actual_length);
2016-01-15 22:11:56 +01:00
// log_info("handle_isochronous_data,size %u/%u", pack->length, pack->actual_length);
2015-11-06 16:26:25 +01:00
handle_isochronous_data ( data , pack - > actual_length ) ;
2015-02-13 22:43:42 +00:00
}
2015-02-13 14:58:47 +00:00
resubmit = 1 ;
} else if ( transfer - > endpoint = = sco_out_addr ) {
2016-12-05 22:38:19 +01:00
int i ;
for ( i = 0 ; i < transfer - > num_iso_packets ; i + + ) {
2016-12-05 20:01:23 +00:00
struct libusb_iso_packet_descriptor * pack = & transfer - > iso_packet_desc [ i ] ;
if ( pack - > status ! = LIBUSB_TRANSFER_COMPLETED ) {
log_error ( " Error: pack %u status %d \n " , i , pack - > status ) ;
}
}
// log_info("sco out done, {{ %u/%u (%x)}, { %u/%u (%x)}, { %u/%u (%x)}}",
// transfer->iso_packet_desc[0].actual_length, transfer->iso_packet_desc[0].length, transfer->iso_packet_desc[0].status,
// transfer->iso_packet_desc[1].actual_length, transfer->iso_packet_desc[1].length, transfer->iso_packet_desc[1].status,
// transfer->iso_packet_desc[2].actual_length, transfer->iso_packet_desc[2].length, transfer->iso_packet_desc[2].status);
2016-02-18 14:48:41 +01:00
// notify upper layer if there's space for new SCO packets
2016-12-05 20:01:23 +00:00
2016-02-18 14:48:41 +01:00
if ( sco_ring_have_space ( ) ) {
uint8_t event [ ] = { HCI_EVENT_SCO_CAN_SEND_NOW , 0 } ;
packet_handler ( HCI_EVENT_PACKET , & event [ 0 ] , sizeof ( event ) ) ;
2016-01-15 22:11:56 +01:00
}
// decrease tab
2017-01-11 10:21:07 +01:00
sco_out_transfers_active - - ;
// log_info("H2: sco out complete, num active num active %u", sco_out_transfers_active);
2016-01-27 15:30:31 +01:00
# endif
2015-02-13 14:58:47 +00:00
} else {
log_info ( " usb_process_ds endpoint unknown %x " , transfer - > endpoint ) ;
}
2013-03-06 18:40:47 +00:00
2015-02-13 14:58:47 +00:00
if ( signal_done ) {
2016-02-18 14:48:41 +01:00
// notify upper stack that provided buffer can be used again
uint8_t event [ ] = { HCI_EVENT_TRANSPORT_PACKET_SENT , 0 } ;
2013-12-20 19:22:19 +00:00
packet_handler ( HCI_EVENT_PACKET , & event [ 0 ] , sizeof ( event ) ) ;
2013-03-06 18:40:47 +00:00
}
2013-03-06 13:24:04 +00:00
2014-06-12 12:22:51 +00:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return ;
2013-03-06 18:40:47 +00:00
if ( resubmit ) {
// Re-submit transfer
transfer - > user_data = NULL ;
2015-02-13 14:58:47 +00:00
int r = libusb_submit_transfer ( transfer ) ;
2013-03-06 18:40:47 +00:00
if ( r ) {
log_error ( " Error re-submitting transfer %d " , r ) ;
2011-06-23 18:52:07 +00:00
}
2013-03-06 18:40:47 +00:00
}
}
2011-06-23 18:52:07 +00:00
2016-03-24 20:46:20 +01:00
static void usb_process_ds ( btstack_data_source_t * ds , btstack_data_source_callback_type_t callback_type ) {
2016-12-22 22:16:16 +01:00
UNUSED ( ds ) ;
UNUSED ( callback_type ) ;
2016-03-24 20:50:00 +01:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return ;
2013-02-24 18:13:16 +00:00
2013-09-02 19:36:28 +00:00
// log_info("begin usb_process_ds");
2013-03-06 18:40:47 +00:00
// always handling an event as we're called when data is ready
struct timeval tv ;
memset ( & tv , 0 , sizeof ( struct timeval ) ) ;
libusb_handle_events_timeout ( NULL , & tv ) ;
2013-03-06 18:06:22 +00:00
2013-03-06 18:40:47 +00:00
// Handle any packet in the order that they were received
while ( handle_packet ) {
2013-09-02 19:36:28 +00:00
// log_info("handle packet %p, endpoint %x, status %x", handle_packet, handle_packet->endpoint, handle_packet->status);
2013-03-06 18:40:47 +00:00
void * next = handle_packet - > user_data ;
handle_completed_transfer ( handle_packet ) ;
2014-06-12 12:22:51 +00:00
// handle case where libusb_close might be called by hci packet handler
2016-03-24 20:50:00 +01:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return ;
2014-06-12 12:22:51 +00:00
2011-06-23 18:52:07 +00:00
// Move to next in the list of packets to handle
if ( next ) {
2013-06-04 10:10:50 +00:00
handle_packet = ( struct libusb_transfer * ) next ;
2011-06-23 18:52:07 +00:00
} else {
handle_packet = NULL ;
}
}
2013-09-02 19:36:28 +00:00
// log_info("end usb_process_ds");
2009-07-08 22:21:02 +00:00
}
2016-01-20 16:00:45 +01:00
static void usb_process_ts ( btstack_timer_source_t * timer ) {
2016-12-22 22:16:16 +01:00
UNUSED ( timer ) ;
2013-02-24 18:13:16 +00:00
// log_info("in usb_process_ts");
2011-06-23 18:52:07 +00:00
2013-02-18 14:07:34 +00:00
// timer is deactive, when timer callback gets called
2011-06-23 18:52:07 +00:00
usb_timer_active = 0 ;
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return ;
2013-02-18 14:07:34 +00:00
// actually handled the packet in the pollfds function
2016-03-24 20:50:00 +01:00
usb_process_ds ( ( struct btstack_data_source * ) NULL , DATA_SOURCE_CALLBACK_READ ) ;
2011-06-23 18:52:07 +00:00
2013-02-18 14:54:36 +00:00
// Get the amount of time until next event is due
2016-05-23 13:57:53 +02:00
long msec = ASYNC_POLLING_INTERVAL_MS ;
2011-06-23 18:52:07 +00:00
// Activate timer
2016-01-20 15:58:46 +01:00
btstack_run_loop_set_timer ( & usb_timer , msec ) ;
btstack_run_loop_add_timer ( & usb_timer ) ;
2011-06-23 18:52:07 +00:00
usb_timer_active = 1 ;
return ;
}
2013-06-04 10:10:50 +00:00
# ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
2011-06-23 18:52:07 +00:00
2015-02-06 13:37:18 +00:00
// list of known devices, using VendorID/ProductID tuples
static const uint16_t known_bt_devices [ ] = {
// DeLOCK Bluetooth 4.0
0x0a5c , 0x21e8 ,
// Asus BT400
0x0b05 , 0x17cb ,
} ;
2015-02-13 14:58:47 +00:00
2015-02-06 13:37:18 +00:00
static int num_known_devices = sizeof ( known_bt_devices ) / sizeof ( uint16_t ) / 2 ;
2011-06-23 18:52:07 +00:00
2015-02-06 13:37:18 +00:00
static int is_known_bt_device ( uint16_t vendor_id , uint16_t product_id ) {
int i ;
for ( i = 0 ; i < num_known_devices ; i + + ) {
if ( known_bt_devices [ i * 2 ] = = vendor_id & & known_bt_devices [ i * 2 + 1 ] = = product_id ) {
return 1 ;
}
}
return 0 ;
}
2011-06-23 18:52:07 +00:00
2015-02-06 13:37:18 +00:00
static void scan_for_bt_endpoints ( void ) {
int r ;
2011-06-23 18:52:07 +00:00
2015-02-13 15:34:43 +00:00
event_in_addr = 0 ;
acl_in_addr = 0 ;
acl_out_addr = 0 ;
sco_out_addr = 0 ;
sco_in_addr = 0 ;
2015-02-06 13:37:18 +00:00
// get endpoints from interface descriptor
struct libusb_config_descriptor * config_descriptor ;
r = libusb_get_active_config_descriptor ( dev , & config_descriptor ) ;
2011-06-23 18:52:07 +00:00
2015-02-13 11:53:08 +00:00
int num_interfaces = config_descriptor - > bNumInterfaces ;
log_info ( " active configuration has %u interfaces " , num_interfaces ) ;
2011-06-23 18:52:07 +00:00
2015-02-13 11:53:08 +00:00
int i ;
for ( i = 0 ; i < num_interfaces ; i + + ) {
const struct libusb_interface * interface = & config_descriptor - > interface [ i ] ;
const struct libusb_interface_descriptor * interface_descriptor = interface - > altsetting ;
log_info ( " interface %u: %u endpoints " , i , interface_descriptor - > bNumEndpoints ) ;
const struct libusb_endpoint_descriptor * endpoint = interface_descriptor - > endpoint ;
for ( r = 0 ; r < interface_descriptor - > bNumEndpoints ; r + + , endpoint + + ) {
log_info ( " - endpoint %x, attributes %x " , endpoint - > bEndpointAddress , endpoint - > bmAttributes ) ;
switch ( endpoint - > bmAttributes & 0x3 ) {
case LIBUSB_TRANSFER_TYPE_INTERRUPT :
2015-02-13 15:34:43 +00:00
if ( event_in_addr ) continue ;
2015-02-13 11:53:08 +00:00
event_in_addr = endpoint - > bEndpointAddress ;
log_info ( " -> using 0x%2.2X for HCI Events " , event_in_addr ) ;
break ;
case LIBUSB_TRANSFER_TYPE_BULK :
if ( endpoint - > bEndpointAddress & 0x80 ) {
2015-02-13 15:34:43 +00:00
if ( acl_in_addr ) continue ;
2015-02-13 11:53:08 +00:00
acl_in_addr = endpoint - > bEndpointAddress ;
log_info ( " -> using 0x%2.2X for ACL Data In " , acl_in_addr ) ;
} else {
2015-02-13 15:34:43 +00:00
if ( acl_out_addr ) continue ;
2015-02-13 11:53:08 +00:00
acl_out_addr = endpoint - > bEndpointAddress ;
log_info ( " -> using 0x%2.2X for ACL Data Out " , acl_out_addr ) ;
}
break ;
case LIBUSB_TRANSFER_TYPE_ISOCHRONOUS :
if ( endpoint - > bEndpointAddress & 0x80 ) {
2015-02-13 15:34:43 +00:00
if ( sco_in_addr ) continue ;
sco_in_addr = endpoint - > bEndpointAddress ;
log_info ( " -> using 0x%2.2X for SCO Data In " , sco_in_addr ) ;
2015-02-13 11:53:08 +00:00
} else {
2015-02-13 15:34:43 +00:00
if ( sco_out_addr ) continue ;
sco_out_addr = endpoint - > bEndpointAddress ;
log_info ( " -> using 0x%2.2X for SCO Data Out " , sco_out_addr ) ;
2015-02-13 11:53:08 +00:00
}
break ;
default :
break ;
2015-02-06 13:37:18 +00:00
}
}
}
libusb_free_config_descriptor ( config_descriptor ) ;
}
2011-06-23 18:52:07 +00:00
2015-02-06 13:37:18 +00:00
// returns index of found device or -1
static int scan_for_bt_device ( libusb_device * * devs , int start_index ) {
int i ;
for ( i = start_index ; devs [ i ] ; i + + ) {
dev = devs [ i ] ;
int r = libusb_get_device_descriptor ( dev , & desc ) ;
if ( r < 0 ) {
log_error ( " failed to get device descriptor " ) ;
return 0 ;
}
log_info ( " %04x:%04x (bus %d, device %d) - class %x subclass %x protocol %x " ,
desc . idVendor , desc . idProduct ,
libusb_get_bus_number ( dev ) , libusb_get_device_address ( dev ) ,
desc . bDeviceClass , desc . bDeviceSubClass , desc . bDeviceProtocol ) ;
// Detect USB Dongle based Class, Subclass, and Protocol
// The class code (bDeviceClass) is 0xE0 – Wireless Controller.
// The SubClass code (bDeviceSubClass) is 0x01 – RF Controller.
// The Protocol code (bDeviceProtocol) is 0x01 – Bluetooth programming.
// if (desc.bDeviceClass == 0xe0 && desc.bDeviceSubClass == 0x01 && desc.bDeviceProtocol == 0x01){
if ( desc . bDeviceClass = = 0xE0 & & desc . bDeviceSubClass = = 0x01 & & desc . bDeviceProtocol = = 0x01 ) {
return i ;
}
// Detect USB Dongle based on whitelist
if ( is_known_bt_device ( desc . idVendor , desc . idProduct ) ) {
return i ;
}
2011-06-23 18:52:07 +00:00
}
2015-02-06 13:37:18 +00:00
return - 1 ;
}
2011-06-23 18:52:07 +00:00
# endif
2015-11-06 20:53:12 +01:00
static int prepare_device ( libusb_device_handle * aHandle ) {
2015-02-06 13:37:18 +00:00
2016-07-08 22:50:35 +02:00
// print device path
2016-07-09 16:10:45 +02:00
uint8_t port_numbers [ USB_MAX_PATH_LEN ] ;
2016-07-08 22:50:35 +02:00
libusb_device * device = libusb_get_device ( aHandle ) ;
2016-07-09 16:10:45 +02:00
int path_len = libusb_get_port_numbers ( device , port_numbers , USB_MAX_PATH_LEN ) ;
2016-07-08 22:50:35 +02:00
printf ( " USB Path: " ) ;
int i ;
for ( i = 0 ; i < path_len ; i + + ) {
if ( i ) printf ( " - " ) ;
printf ( " %02x " , port_numbers [ i ] ) ;
}
printf ( " \n " ) ;
2015-02-06 13:37:18 +00:00
int r ;
int kernel_driver_detached = 0 ;
2011-06-23 18:52:07 +00:00
2014-11-11 21:25:04 +00:00
// Detach OS driver (not possible for OS X and WIN32)
# if !defined(__APPLE__) && !defined(_WIN32)
2015-11-06 20:53:12 +01:00
r = libusb_kernel_driver_active ( aHandle , 0 ) ;
2011-06-23 18:52:07 +00:00
if ( r < 0 ) {
2013-02-24 18:13:16 +00:00
log_error ( " libusb_kernel_driver_active error %d " , r ) ;
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2009-07-08 22:21:02 +00:00
return r ;
2011-06-23 18:52:07 +00:00
}
if ( r = = 1 ) {
2015-11-06 20:53:12 +01:00
r = libusb_detach_kernel_driver ( aHandle , 0 ) ;
2011-06-23 18:52:07 +00:00
if ( r < 0 ) {
2013-02-24 18:13:16 +00:00
log_error ( " libusb_detach_kernel_driver error %d " , r ) ;
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2011-06-23 18:52:07 +00:00
return r ;
}
2015-02-06 13:37:18 +00:00
kernel_driver_detached = 1 ;
2011-06-23 18:52:07 +00:00
}
2013-02-24 18:13:16 +00:00
log_info ( " libusb_detach_kernel_driver " ) ;
2009-07-06 16:37:53 +00:00
# endif
2014-11-11 21:25:04 +00:00
const int configuration = 1 ;
log_info ( " setting configuration %d... " , configuration ) ;
2015-11-06 20:53:12 +01:00
r = libusb_set_configuration ( aHandle , configuration ) ;
2014-11-11 21:25:04 +00:00
if ( r < 0 ) {
2015-02-06 13:37:18 +00:00
log_error ( " Error libusb_set_configuration: %d " , r ) ;
if ( kernel_driver_detached ) {
2015-11-06 20:53:12 +01:00
libusb_attach_kernel_driver ( aHandle , 0 ) ;
2015-02-06 13:37:18 +00:00
}
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2014-11-11 21:25:04 +00:00
return r ;
}
2009-07-08 22:21:02 +00:00
// reserve access to device
2013-02-24 18:13:16 +00:00
log_info ( " claiming interface 0... " ) ;
2015-11-06 20:53:12 +01:00
r = libusb_claim_interface ( aHandle , 0 ) ;
2011-06-23 18:52:07 +00:00
if ( r < 0 ) {
2013-02-24 18:13:16 +00:00
log_error ( " Error claiming interface %d " , r ) ;
2015-02-06 13:37:18 +00:00
if ( kernel_driver_detached ) {
2015-11-06 20:53:12 +01:00
libusb_attach_kernel_driver ( aHandle , 0 ) ;
2015-02-06 13:37:18 +00:00
}
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2009-07-08 22:21:02 +00:00
return r ;
2011-06-23 18:52:07 +00:00
}
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
log_info ( " claiming interface 1... " ) ;
2015-11-06 20:53:12 +01:00
r = libusb_claim_interface ( aHandle , 1 ) ;
2015-02-13 14:58:47 +00:00
if ( r < 0 ) {
log_error ( " Error claiming interface %d " , r ) ;
if ( kernel_driver_detached ) {
2015-11-06 20:53:12 +01:00
libusb_attach_kernel_driver ( aHandle , 0 ) ;
2015-02-13 14:58:47 +00:00
}
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2015-02-13 14:58:47 +00:00
return r ;
}
# endif
2015-02-06 13:37:18 +00:00
return 0 ;
}
2016-07-09 16:10:45 +02:00
static libusb_device_handle * try_open_device ( libusb_device * device ) {
int r ;
libusb_device_handle * dev_handle ;
r = libusb_open ( device , & dev_handle ) ;
if ( r < 0 ) {
log_error ( " libusb_open failed! " ) ;
dev_handle = NULL ;
return NULL ;
}
log_info ( " libusb open %d, handle %p " , r , dev_handle ) ;
// reset device
libusb_reset_device ( dev_handle ) ;
if ( r < 0 ) {
log_error ( " libusb_reset_device failed! " ) ;
libusb_close ( dev_handle ) ;
return NULL ;
}
return dev_handle ;
}
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-19 17:44:52 +01:00
static int usb_sco_start ( void ) {
printf ( " usb_sco_start \n " ) ;
log_info ( " usb_sco_start " ) ;
2015-02-14 21:52:09 +00:00
sco_state_machine_init ( ) ;
2016-01-15 22:11:56 +01:00
sco_ring_init ( ) ;
2017-01-19 17:44:52 +01:00
2017-01-19 18:10:47 +01:00
int alt_setting ;
if ( sco_voice_setting & 0x0020 ) {
// 16-bit PCM
alt_setting = alt_setting_16_bit [ sco_num_connections - 1 ] ;
} else {
// 8-bit PCM or mSBC
alt_setting = alt_setting_8_bit [ sco_num_connections - 1 ] ;
}
2017-01-20 22:26:57 +01:00
// derive iso packet size from alt setting
iso_packet_size = iso_packet_size_for_alt_setting [ alt_setting ] ;
2017-01-19 18:10:47 +01:00
log_info ( " Switching to setting %u on interface 1.. " , alt_setting ) ;
int r = libusb_set_interface_alt_setting ( handle , 1 , alt_setting ) ;
2017-01-19 17:55:42 +01:00
if ( r < 0 ) {
2017-01-19 18:10:47 +01:00
log_error ( " Error setting alternative setting %u for interface 1: %s \n " , alt_setting , libusb_error_name ( r ) ) ;
2017-01-19 17:55:42 +01:00
return r ;
}
2017-01-19 17:44:52 +01:00
// incoming
int c ;
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
sco_in_transfer [ c ] = libusb_alloc_transfer ( NUM_ISO_PACKETS ) ; // isochronous transfers SCO in
if ( ! sco_in_transfer [ c ] ) {
usb_close ( ) ;
return LIBUSB_ERROR_NO_MEM ;
}
// configure sco_in handlers
libusb_fill_iso_transfer ( sco_in_transfer [ c ] , handle , sco_in_addr ,
2017-01-20 22:26:57 +01:00
hci_sco_in_buffer [ c ] , NUM_ISO_PACKETS * iso_packet_size , NUM_ISO_PACKETS , async_callback , NULL , 0 ) ;
libusb_set_iso_packet_lengths ( sco_in_transfer [ c ] , iso_packet_size ) ;
2017-01-19 17:55:42 +01:00
r = libusb_submit_transfer ( sco_in_transfer [ c ] ) ;
2017-01-19 17:44:52 +01:00
if ( r ) {
log_error ( " Error submitting isochronous in transfer %d " , r ) ;
usb_close ( ) ;
return r ;
}
}
// outgoing
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
sco_out_transfers [ c ] = libusb_alloc_transfer ( NUM_ISO_PACKETS ) ; // 1 isochronous transfers SCO out - up to 3 parts
sco_out_transfers_in_flight [ c ] = 0 ;
}
return 0 ;
}
static void usb_sco_stop ( void ) {
printf ( " usb_sco_stop \n " ) ;
log_info ( " usb_sco_stop " ) ;
sco_shutdown = 1 ;
libusb_set_debug ( NULL , LIBUSB_LOG_LEVEL_ERROR ) ;
int c ;
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
libusb_cancel_transfer ( sco_in_transfer [ c ] ) ;
}
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( sco_out_transfers_in_flight [ c ] ) {
libusb_cancel_transfer ( sco_out_transfers [ c ] ) ;
} else {
libusb_free_transfer ( sco_out_transfers [ c ] ) ;
sco_out_transfers [ c ] = 0 ;
}
}
// wait until all transfers are completed
int completed = 0 ;
while ( ! completed ) {
struct timeval tv ;
memset ( & tv , 0 , sizeof ( struct timeval ) ) ;
libusb_handle_events_timeout ( NULL , & tv ) ;
// check if all done
completed = 1 ;
// Cancel all synchronous transfer
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
if ( sco_in_transfer [ c ] ) {
completed = 0 ;
break ;
}
}
if ( ! completed ) continue ;
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( sco_out_transfers [ c ] ) {
completed = 0 ;
break ;
}
}
}
sco_shutdown = 0 ;
libusb_set_debug ( NULL , LIBUSB_LOG_LEVEL_WARNING ) ;
2017-01-19 17:55:42 +01:00
log_info ( " Switching to setting %u on interface 1.. " , 0 ) ;
int r = libusb_set_interface_alt_setting ( handle , 1 , 0 ) ;
if ( r < 0 ) {
log_error ( " Error setting alternative setting %u for interface 1: %s " , 0 , libusb_error_name ( r ) ) ;
return ;
}
2017-01-19 17:44:52 +01:00
printf ( " usb_sco_stop done \n " ) ;
}
2016-01-27 15:30:31 +01:00
# endif
2017-01-19 17:44:52 +01:00
static int usb_open ( void ) {
int r ;
2015-02-06 13:37:18 +00:00
handle_packet = NULL ;
// default endpoint addresses
event_in_addr = 0x81 ; // EP1, IN interrupt
acl_in_addr = 0x82 ; // EP2, IN bulk
acl_out_addr = 0x02 ; // EP2, OUT bulk
2015-02-13 14:58:47 +00:00
sco_in_addr = 0x83 ; // EP3, IN isochronous
sco_out_addr = 0x03 ; // EP3, OUT isochronous
2015-02-06 13:37:18 +00:00
// USB init
r = libusb_init ( NULL ) ;
if ( r < 0 ) return - 1 ;
libusb_state = LIB_USB_OPENED ;
// configure debug level
libusb_set_debug ( NULL , LIBUSB_LOG_LEVEL_WARNING ) ;
2011-06-23 18:52:07 +00:00
2015-02-06 13:37:18 +00:00
# ifdef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
// Use a specified device
log_info ( " Want vend: %04x, prod: %04x " , USB_VENDOR_ID , USB_PRODUCT_ID ) ;
handle = libusb_open_device_with_vid_pid ( NULL , USB_VENDOR_ID , USB_PRODUCT_ID ) ;
if ( ! handle ) {
log_error ( " libusb_open_device_with_vid_pid failed! " ) ;
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-06 13:37:18 +00:00
return - 1 ;
}
log_info ( " libusb open %d, handle %p " , r , handle ) ;
r = prepare_device ( handle ) ;
if ( r < 0 ) {
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-06 13:37:18 +00:00
return - 1 ;
}
# else
// Scan system for an appropriate devices
libusb_device * * devs ;
2016-07-09 16:10:45 +02:00
ssize_t num_devices ;
2015-02-06 13:37:18 +00:00
log_info ( " Scanning for USB Bluetooth device " ) ;
2016-07-09 16:10:45 +02:00
num_devices = libusb_get_device_list ( NULL , & devs ) ;
if ( num_devices < 0 ) {
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-06 13:37:18 +00:00
return - 1 ;
}
dev = NULL ;
2016-07-09 16:10:45 +02:00
if ( usb_path_len ) {
int i ;
for ( i = 0 ; i < num_devices ; i + + ) {
uint8_t port_numbers [ USB_MAX_PATH_LEN ] ;
int len = libusb_get_port_numbers ( devs [ i ] , port_numbers , USB_MAX_PATH_LEN ) ;
if ( len ! = usb_path_len ) continue ;
if ( memcmp ( usb_path , port_numbers , len ) = = 0 ) {
log_info ( " USB device found at specified path " ) ;
handle = try_open_device ( devs [ i ] ) ;
if ( ! handle ) continue ;
r = prepare_device ( handle ) ;
if ( r < 0 ) continue ;
dev = devs [ i ] ;
libusb_state = LIB_USB_INTERFACE_CLAIMED ;
break ;
} ;
2015-02-06 13:37:18 +00:00
}
2016-07-09 16:10:45 +02:00
if ( ! handle ) {
log_error ( " USB device with given path not found " ) ;
printf ( " USB device with given path not found \n " ) ;
return - 1 ;
2015-02-06 13:37:18 +00:00
}
2016-07-09 16:10:45 +02:00
} else {
2015-02-06 13:37:18 +00:00
2016-07-09 16:10:45 +02:00
int deviceIndex = - 1 ;
while ( 1 ) {
// look for next Bluetooth dongle
deviceIndex = scan_for_bt_device ( devs , deviceIndex + 1 ) ;
if ( deviceIndex < 0 ) break ;
2015-02-06 13:37:18 +00:00
2016-07-09 16:10:45 +02:00
log_info ( " USB Bluetooth device found, index %u " , deviceIndex ) ;
handle = try_open_device ( devs [ deviceIndex ] ) ;
if ( ! handle ) continue ;
2015-02-06 13:37:18 +00:00
2016-07-09 16:10:45 +02:00
r = prepare_device ( handle ) ;
if ( r < 0 ) continue ;
2015-02-06 13:37:18 +00:00
2016-07-09 16:10:45 +02:00
dev = devs [ deviceIndex ] ;
libusb_state = LIB_USB_INTERFACE_CLAIMED ;
break ;
}
2015-02-06 13:37:18 +00:00
}
libusb_free_device_list ( devs , 1 ) ;
if ( handle = = 0 ) {
log_error ( " No USB Bluetooth device found " ) ;
return - 1 ;
}
2011-06-23 18:52:07 +00:00
scan_for_bt_endpoints ( ) ;
2011-01-12 20:43:27 +00:00
2015-02-06 13:37:18 +00:00
# endif
2011-06-23 18:52:07 +00:00
// allocate transfer handlers
2015-02-06 13:37:18 +00:00
int c ;
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < EVENT_IN_BUFFER_COUNT ; c + + ) {
2011-06-23 18:52:07 +00:00
event_in_transfer [ c ] = libusb_alloc_transfer ( 0 ) ; // 0 isochronous transfers Events
2017-01-11 10:21:07 +01:00
if ( ! event_in_transfer [ c ] ) {
usb_close ( ) ;
return LIBUSB_ERROR_NO_MEM ;
}
}
for ( c = 0 ; c < ACL_IN_BUFFER_COUNT ; c + + ) {
2015-02-13 14:58:47 +00:00
acl_in_transfer [ c ] = libusb_alloc_transfer ( 0 ) ; // 0 isochronous transfers ACL in
2017-01-11 10:21:07 +01:00
if ( ! acl_in_transfer [ c ] ) {
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2011-06-23 18:52:07 +00:00
return LIBUSB_ERROR_NO_MEM ;
2011-01-12 20:43:27 +00:00
}
2009-07-08 22:21:02 +00:00
}
2011-06-23 18:52:07 +00:00
2013-03-06 13:24:04 +00:00
command_out_transfer = libusb_alloc_transfer ( 0 ) ;
2015-02-13 14:58:47 +00:00
acl_out_transfer = libusb_alloc_transfer ( 0 ) ;
2013-03-06 13:24:04 +00:00
// TODO check for error
2009-07-08 22:21:02 +00:00
libusb_state = LIB_USB_TRANSFERS_ALLOCATED ;
2011-06-23 18:52:07 +00:00
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < EVENT_IN_BUFFER_COUNT ; c + + ) {
2011-06-23 18:52:07 +00:00
// configure event_in handlers
libusb_fill_interrupt_transfer ( event_in_transfer [ c ] , handle , event_in_addr ,
2013-02-24 19:59:57 +00:00
hci_event_in_buffer [ c ] , HCI_ACL_BUFFER_SIZE , async_callback , NULL , 0 ) ;
2011-06-23 18:52:07 +00:00
r = libusb_submit_transfer ( event_in_transfer [ c ] ) ;
if ( r ) {
2013-02-24 18:13:16 +00:00
log_error ( " Error submitting interrupt transfer %d " , r ) ;
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2011-06-23 18:52:07 +00:00
return r ;
}
2017-01-11 10:21:07 +01:00
}
for ( c = 0 ; c < ACL_IN_BUFFER_COUNT ; c + + ) {
2015-02-13 14:58:47 +00:00
// configure acl_in handlers
libusb_fill_bulk_transfer ( acl_in_transfer [ c ] , handle , acl_in_addr ,
hci_acl_in_buffer [ c ] + HCI_INCOMING_PRE_BUFFER_SIZE , HCI_ACL_BUFFER_SIZE , async_callback , NULL , 0 ) ;
r = libusb_submit_transfer ( acl_in_transfer [ c ] ) ;
2011-06-23 18:52:07 +00:00
if ( r ) {
2013-02-24 18:13:16 +00:00
log_error ( " Error submitting bulk in transfer %d " , r ) ;
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2011-06-23 18:52:07 +00:00
return r ;
}
2015-02-13 14:58:47 +00:00
}
2011-06-23 18:52:07 +00:00
// Check for pollfds functionality
doing_pollfds = libusb_pollfds_handle_timeouts ( NULL ) ;
2009-07-08 22:21:02 +00:00
2014-05-15 10:45:53 +00:00
// NOTE: using pollfds doesn't work on Linux, so it is disable until further investigation here
doing_pollfds = 0 ;
2011-06-23 18:52:07 +00:00
if ( doing_pollfds ) {
2013-02-24 18:13:16 +00:00
log_info ( " Async using pollfds: " ) ;
2011-06-23 18:52:07 +00:00
const struct libusb_pollfd * * pollfd = libusb_get_pollfds ( NULL ) ;
2014-06-12 15:24:51 +00:00
for ( num_pollfds = 0 ; pollfd [ num_pollfds ] ; num_pollfds + + ) ;
2017-05-23 11:50:08 +02:00
pollfd_data_sources = ( btstack_data_source_t * ) malloc ( sizeof ( btstack_data_source_t ) * num_pollfds ) ;
2014-06-12 15:24:51 +00:00
if ( ! pollfd_data_sources ) {
log_error ( " Cannot allocate data sources for pollfds " ) ;
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2014-06-12 15:24:51 +00:00
return 1 ;
}
for ( r = 0 ; r < num_pollfds ; r + + ) {
2016-01-20 16:00:45 +01:00
btstack_data_source_t * ds = & pollfd_data_sources [ r ] ;
2016-03-24 20:04:14 +01:00
btstack_run_loop_set_data_source_fd ( ds , pollfd [ r ] - > fd ) ;
2016-03-24 19:36:55 +01:00
btstack_run_loop_set_data_source_handler ( ds , & usb_process_ds ) ;
2016-03-24 22:12:50 +01:00
btstack_run_loop_enable_data_source_callbacks ( ds , DATA_SOURCE_CALLBACK_READ ) ;
2016-01-20 15:58:46 +01:00
btstack_run_loop_add_data_source ( ds ) ;
2013-02-24 18:13:16 +00:00
log_info ( " %u: %p fd: %u, events %x " , r , pollfd [ r ] , pollfd [ r ] - > fd , pollfd [ r ] - > events ) ;
2011-06-23 18:52:07 +00:00
}
2014-06-12 15:24:51 +00:00
free ( pollfd ) ;
2011-06-23 18:52:07 +00:00
} else {
2013-02-24 18:13:16 +00:00
log_info ( " Async using timers: " ) ;
2011-06-23 18:52:07 +00:00
usb_timer . process = usb_process_ts ;
2016-05-23 13:57:53 +02:00
btstack_run_loop_set_timer ( & usb_timer , ASYNC_POLLING_INTERVAL_MS ) ;
2016-01-20 15:58:46 +01:00
btstack_run_loop_add_timer ( & usb_timer ) ;
2011-06-23 18:52:07 +00:00
usb_timer_active = 1 ;
}
2009-07-08 22:21:02 +00:00
return 0 ;
}
2015-02-06 13:37:18 +00:00
2016-01-27 15:30:31 +01:00
static int usb_close ( void ) {
2011-06-23 18:52:07 +00:00
int c ;
2017-05-23 11:50:08 +02:00
int completed = 0 ;
2009-07-08 22:21:02 +00:00
switch ( libusb_state ) {
2011-10-08 16:58:36 +00:00
case LIB_USB_CLOSED :
break ;
2009-07-08 22:21:02 +00:00
case LIB_USB_TRANSFERS_ALLOCATED :
2011-06-23 18:52:07 +00:00
libusb_state = LIB_USB_INTERFACE_CLAIMED ;
if ( usb_timer_active ) {
2016-01-20 15:58:46 +01:00
btstack_run_loop_remove_timer ( & usb_timer ) ;
2011-06-23 18:52:07 +00:00
usb_timer_active = 0 ;
}
2014-06-12 15:24:51 +00:00
if ( doing_pollfds ) {
int r ;
for ( r = 0 ; r < num_pollfds ; r + + ) {
2016-01-20 16:00:45 +01:00
btstack_data_source_t * ds = & pollfd_data_sources [ r ] ;
2016-01-20 15:58:46 +01:00
btstack_run_loop_remove_data_source ( ds ) ;
2014-06-12 15:24:51 +00:00
}
free ( pollfd_data_sources ) ;
pollfd_data_sources = NULL ;
num_pollfds = 0 ;
doing_pollfds = 0 ;
}
2009-07-08 22:21:02 +00:00
case LIB_USB_INTERFACE_CLAIMED :
2016-11-23 23:15:02 +01:00
// Cancel all transfers, ignore warnings for this
libusb_set_debug ( NULL , LIBUSB_LOG_LEVEL_ERROR ) ;
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < EVENT_IN_BUFFER_COUNT ; c + + ) {
2016-05-23 13:57:53 +02:00
libusb_cancel_transfer ( event_in_transfer [ c ] ) ;
2017-01-11 10:21:07 +01:00
}
for ( c = 0 ; c < ACL_IN_BUFFER_COUNT ; c + + ) {
2016-05-23 13:57:53 +02:00
libusb_cancel_transfer ( acl_in_transfer [ c ] ) ;
}
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
2016-05-23 13:57:53 +02:00
libusb_cancel_transfer ( sco_in_transfer [ c ] ) ;
2016-12-05 20:01:23 +00:00
}
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( sco_out_transfers_in_flight [ c ] ) {
libusb_cancel_transfer ( sco_out_transfers [ c ] ) ;
2016-12-05 20:01:23 +00:00
} else {
2017-01-11 10:21:07 +01:00
libusb_free_transfer ( sco_out_transfers [ c ] ) ;
sco_out_transfers [ c ] = 0 ;
2016-12-05 20:01:23 +00:00
}
2011-06-23 18:52:07 +00:00
}
2016-05-23 13:57:53 +02:00
# endif
2016-11-23 23:15:02 +01:00
libusb_set_debug ( NULL , LIBUSB_LOG_LEVEL_WARNING ) ;
// wait until all transfers are completed
while ( ! completed ) {
struct timeval tv ;
memset ( & tv , 0 , sizeof ( struct timeval ) ) ;
libusb_handle_events_timeout ( NULL , & tv ) ;
// check if all done
completed = 1 ;
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < EVENT_IN_BUFFER_COUNT ; c + + ) {
if ( event_in_transfer [ c ] ) {
2016-11-23 23:15:02 +01:00
completed = 0 ;
break ;
}
}
2017-01-11 10:21:07 +01:00
if ( ! completed ) continue ;
for ( c = 0 ; c < ACL_IN_BUFFER_COUNT ; c + + ) {
if ( acl_in_transfer [ c ] ) {
completed = 0 ;
break ;
}
}
2016-11-23 23:15:02 +01:00
# ifdef ENABLE_SCO_OVER_HCI
if ( ! completed ) continue ;
// Cancel all synchronous transfer
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_IN_BUFFER_COUNT ; c + + ) {
2016-11-23 23:15:02 +01:00
if ( sco_in_transfer [ c ] ) {
completed = 0 ;
break ;
}
}
2016-12-05 20:01:23 +00:00
if ( ! completed ) continue ;
2017-01-11 10:21:07 +01:00
for ( c = 0 ; c < SCO_OUT_BUFFER_COUNT ; c + + ) {
if ( sco_out_transfers [ c ] ) {
2016-12-05 20:01:23 +00:00
completed = 0 ;
break ;
}
}
2016-11-23 23:15:02 +01:00
# endif
}
2011-06-23 18:52:07 +00:00
2016-11-23 23:15:02 +01:00
// finally release interface
2011-06-23 18:52:07 +00:00
libusb_release_interface ( handle , 0 ) ;
2016-11-23 23:15:02 +01:00
# ifdef ENABLE_SCO_OVER_HCI
libusb_release_interface ( handle , 1 ) ;
# endif
2016-12-05 20:01:23 +00:00
log_info ( " Libusb shutdown complete " ) ;
2011-06-23 18:52:07 +00:00
2009-07-08 22:21:02 +00:00
case LIB_USB_DEVICE_OPENDED :
libusb_close ( handle ) ;
2011-06-23 18:52:07 +00:00
2009-07-08 22:21:02 +00:00
case LIB_USB_OPENED :
libusb_exit ( NULL ) ;
}
2014-06-12 12:22:51 +00:00
libusb_state = LIB_USB_CLOSED ;
handle = NULL ;
2009-07-08 22:21:02 +00:00
return 0 ;
}
2011-06-23 18:52:07 +00:00
static int usb_send_cmd_packet ( uint8_t * packet , int size ) {
int r ;
2009-07-06 21:40:30 +00:00
2009-07-08 22:21:02 +00:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return - 1 ;
2013-03-06 18:06:22 +00:00
// async
2015-02-13 14:58:47 +00:00
libusb_fill_control_setup ( hci_cmd_buffer , LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE , 0 , 0 , 0 , size ) ;
memcpy ( hci_cmd_buffer + LIBUSB_CONTROL_SETUP_SIZE , packet , size ) ;
2013-03-06 18:06:22 +00:00
2014-07-08 12:25:12 +00:00
// prepare transfer
2013-03-06 18:06:22 +00:00
int completed = 0 ;
2015-02-13 14:58:47 +00:00
libusb_fill_control_transfer ( command_out_transfer , handle , hci_cmd_buffer , async_callback , & completed , 0 ) ;
2013-03-06 18:06:22 +00:00
command_out_transfer - > flags = LIBUSB_TRANSFER_FREE_BUFFER ;
2014-07-08 12:25:12 +00:00
// update stata before submitting transfer
usb_command_active = 1 ;
// submit transfer
2013-03-06 18:06:22 +00:00
r = libusb_submit_transfer ( command_out_transfer ) ;
2009-07-08 22:21:02 +00:00
2013-03-07 14:57:09 +00:00
if ( r < 0 ) {
2014-07-08 12:25:12 +00:00
usb_command_active = 0 ;
2015-02-13 14:58:47 +00:00
log_error ( " Error submitting cmd transfer %d " , r ) ;
2013-03-06 18:06:22 +00:00
return - 1 ;
2011-06-23 18:52:07 +00:00
}
2013-03-06 17:47:50 +00:00
2009-07-08 22:21:02 +00:00
return 0 ;
}
2009-07-06 21:40:30 +00:00
2009-07-08 22:21:02 +00:00
static int usb_send_acl_packet ( uint8_t * packet , int size ) {
2013-03-06 17:47:50 +00:00
int r ;
2013-03-06 13:24:04 +00:00
2009-07-08 22:21:02 +00:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return - 1 ;
2013-03-06 13:24:04 +00:00
2013-03-06 17:47:50 +00:00
// log_info("usb_send_acl_packet enter, size %u", size);
2011-06-23 18:52:07 +00:00
2014-07-08 12:25:12 +00:00
// prepare transfer
2013-03-06 13:24:04 +00:00
int completed = 0 ;
2015-02-13 14:58:47 +00:00
libusb_fill_bulk_transfer ( acl_out_transfer , handle , acl_out_addr , packet , size ,
2013-03-06 13:24:04 +00:00
async_callback , & completed , 0 ) ;
2015-02-13 14:58:47 +00:00
acl_out_transfer - > type = LIBUSB_TRANSFER_TYPE_BULK ;
2013-03-06 13:24:04 +00:00
2014-07-08 12:25:12 +00:00
// update stata before submitting transfer
usb_acl_out_active = 1 ;
2015-02-13 14:58:47 +00:00
r = libusb_submit_transfer ( acl_out_transfer ) ;
2013-03-06 13:24:04 +00:00
if ( r < 0 ) {
2014-07-08 12:25:12 +00:00
usb_acl_out_active = 0 ;
2015-02-13 14:58:47 +00:00
log_error ( " Error submitting acl transfer, %d " , r ) ;
2013-03-06 17:47:50 +00:00
return - 1 ;
2009-10-18 21:06:57 +00:00
}
2011-06-23 18:52:07 +00:00
2009-07-08 22:21:02 +00:00
return 0 ;
}
2009-07-06 21:40:30 +00:00
2013-03-06 18:06:22 +00:00
static int usb_can_send_packet_now ( uint8_t packet_type ) {
switch ( packet_type ) {
case HCI_COMMAND_DATA_PACKET :
return ! usb_command_active ;
case HCI_ACL_DATA_PACKET :
return ! usb_acl_out_active ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
case HCI_SCO_DATA_PACKET :
2016-01-15 22:11:56 +01:00
return sco_ring_have_space ( ) ;
2016-01-27 15:30:31 +01:00
# endif
2013-03-06 18:06:22 +00:00
default :
return 0 ;
}
}
2010-09-21 17:18:50 +00:00
static int usb_send_packet ( uint8_t packet_type , uint8_t * packet , int size ) {
2010-08-16 17:23:22 +00:00
switch ( packet_type ) {
case HCI_COMMAND_DATA_PACKET :
return usb_send_cmd_packet ( packet , size ) ;
case HCI_ACL_DATA_PACKET :
return usb_send_acl_packet ( packet , size ) ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
case HCI_SCO_DATA_PACKET :
return usb_send_sco_packet ( packet , size ) ;
2016-01-27 15:30:31 +01:00
# endif
2010-08-16 17:23:22 +00:00
default :
return - 1 ;
}
}
2017-01-19 17:44:52 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-19 17:05:43 +01:00
static void usb_set_sco_config ( uint16_t voice_setting , int num_connections ) {
2017-01-19 18:10:47 +01:00
log_info ( " usb_set_sco_config: voice settings 0x%04x, num connections %u " , voice_setting , num_connections ) ;
2017-01-19 17:44:52 +01:00
if ( num_connections ! = sco_num_connections ) {
sco_voice_setting = voice_setting ;
if ( sco_num_connections ) {
usb_sco_stop ( ) ;
}
2017-01-19 18:10:47 +01:00
sco_num_connections = num_connections ;
2017-01-19 17:44:52 +01:00
if ( num_connections ) {
usb_sco_start ( ) ;
}
}
2017-01-19 17:05:43 +01:00
}
2017-01-19 17:44:52 +01:00
# endif
2017-01-19 17:05:43 +01:00
2010-09-21 17:18:50 +00:00
static void usb_register_packet_handler ( void ( * handler ) ( uint8_t packet_type , uint8_t * packet , uint16_t size ) ) {
2013-02-24 18:13:16 +00:00
log_info ( " registering packet handler " ) ;
2010-09-21 17:18:50 +00:00
packet_handler = handler ;
2009-07-05 21:06:38 +00:00
}
2010-09-21 17:18:50 +00:00
static void dummy_handler ( uint8_t packet_type , uint8_t * packet , uint16_t size ) {
2016-12-22 22:16:16 +01:00
UNUSED ( packet_type ) ;
UNUSED ( packet ) ;
UNUSED ( size ) ;
2009-07-08 22:21:02 +00:00
}
// get usb singleton
2016-03-28 11:44:30 +02:00
const hci_transport_t * hci_transport_usb_instance ( void ) {
2009-07-08 22:21:02 +00:00
if ( ! hci_transport_usb ) {
2013-05-21 12:40:09 +00:00
hci_transport_usb = ( hci_transport_t * ) malloc ( sizeof ( hci_transport_t ) ) ;
2016-01-27 15:30:31 +01:00
memset ( hci_transport_usb , 0 , sizeof ( hci_transport_t ) ) ;
hci_transport_usb - > name = " H2_LIBUSB " ;
2009-07-08 22:21:02 +00:00
hci_transport_usb - > open = usb_open ;
hci_transport_usb - > close = usb_close ;
2010-09-21 17:18:50 +00:00
hci_transport_usb - > register_packet_handler = usb_register_packet_handler ;
2013-03-06 13:24:04 +00:00
hci_transport_usb - > can_send_packet_now = usb_can_send_packet_now ;
2016-01-27 15:30:31 +01:00
hci_transport_usb - > send_packet = usb_send_packet ;
2017-01-19 17:44:52 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2017-01-19 17:05:43 +01:00
hci_transport_usb - > set_sco_config = usb_set_sco_config ;
2017-01-19 17:44:52 +01:00
# endif
2009-07-08 22:21:02 +00:00
}
return hci_transport_usb ;
2011-10-08 16:58:36 +00:00
}