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
*/
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
2016-01-18 13:58:34 +01:00
# define ASYNC_BUFFERS 2
# define AYSNC_POLLING_INTERVAL_MS 1
//
// Bluetooth USB Transprot Alternate Settings:
//
// 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
# define ALT_SETTING (2)
// 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)
// results in 9 bytes per frame
# define ISO_PACKET_SIZE (9)
// 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
# define SCO_PACKET_SIZE (49)
// Outgoing SCO packet queue
// simplified ring buffer implementation
# define SCO_RING_BUFFER_COUNT (8)
# define SCO_RING_BUFFER_SIZE (SCO_RING_BUFFER_COUNT * SCO_PACKET_SIZE)
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 ;
static struct libusb_transfer * event_in_transfer [ ASYNC_BUFFERS ] ;
static struct libusb_transfer * acl_in_transfer [ ASYNC_BUFFERS ] ;
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 ;
2015-02-13 14:58:47 +00:00
static struct libusb_transfer * sco_in_transfer [ ASYNC_BUFFERS ] ;
2016-01-18 13:58:34 +01:00
static uint8_t hci_sco_in_buffer [ ASYNC_BUFFERS ] [ SCO_PACKET_SIZE ] ;
// outgoing SCO
static uint8_t sco_ring_buffer [ SCO_RING_BUFFER_SIZE ] ;
static int sco_ring_write ; // packet idx
static int sco_ring_transfers_active ;
static struct libusb_transfer * sco_ring_transfers [ SCO_RING_BUFFER_COUNT ] ;
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
2011-07-26 21:18:45 +00:00
static uint8_t hci_event_in_buffer [ ASYNC_BUFFERS ] [ HCI_ACL_BUFFER_SIZE ] ; // bigger than largest packet
2015-02-13 14:58:47 +00:00
static uint8_t hci_acl_in_buffer [ ASYNC_BUFFERS ] [ 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-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 ;
sco_ring_transfers_active = 0 ;
}
static int sco_ring_have_space ( void ) {
return sco_ring_transfers_active < SCO_RING_BUFFER_COUNT ;
}
2016-01-27 15:30:31 +01:00
# endif
2016-01-15 22:11:56 +01:00
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 ;
}
2013-02-24 19:59:57 +00:00
static void async_callback ( struct libusb_transfer * transfer )
2011-06-23 18:52:07 +00:00
{
2013-03-06 13:24:04 +00:00
if ( libusb_state ! = LIB_USB_TRANSFERS_ALLOCATED ) return ;
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 ;
2016-01-18 13:58:34 +01:00
uint8_t * data = & sco_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
struct libusb_transfer * sco_transfer = sco_ring_transfers [ tranfer_index ] ;
2016-01-18 13:58:34 +01:00
libusb_fill_iso_transfer ( sco_transfer , handle , sco_out_addr , data , 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 + + ;
if ( sco_ring_write = = SCO_RING_BUFFER_COUNT ) {
sco_ring_write = 0 ;
}
sco_ring_transfers_active + + ;
// log_info("H2: queued packet at index %u, num active %u", tranfer_index, sco_ring_transfers_active);
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-01-15 22:11:56 +01:00
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
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
sco_ring_transfers_active - - ;
// log_info("H2: sco out complete, num active num active %u", sco_ring_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-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 ) {
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
long msec = AYSNC_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
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 ;
}
2016-01-18 13:58:34 +01:00
log_info ( " Switching to setting %u on interface 1.. " , ALT_SETTING ) ;
r = libusb_set_interface_alt_setting ( aHandle , 1 , ALT_SETTING ) ;
2015-02-13 22:43:42 +00:00
if ( r < 0 ) {
2016-01-18 13:58:34 +01:00
fprintf ( stderr , " Error setting alternative setting %u for interface 1: %s \n " , ALT_SETTING , libusb_error_name ( r ) ) ;
2015-11-06 20:53:12 +01:00
libusb_close ( aHandle ) ;
2015-02-13 22:43:42 +00:00
return r ;
}
2015-02-13 14:58:47 +00:00
# endif
2015-02-06 13:37:18 +00:00
return 0 ;
}
2016-01-27 15:30:31 +01:00
static int usb_open ( void ) {
2015-02-06 13:37:18 +00:00
int r ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-14 21:52:09 +00:00
sco_state_machine_init ( ) ;
2016-01-15 22:11:56 +01:00
sco_ring_init ( ) ;
2016-01-27 15:30:31 +01:00
# endif
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 ;
ssize_t cnt ;
log_info ( " Scanning for USB Bluetooth device " ) ;
cnt = libusb_get_device_list ( NULL , & devs ) ;
if ( cnt < 0 ) {
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-06 13:37:18 +00:00
return - 1 ;
}
int startIndex = 0 ;
dev = NULL ;
while ( 1 ) {
int deviceIndex = scan_for_bt_device ( devs , startIndex ) ;
if ( deviceIndex < 0 ) {
break ;
}
startIndex = deviceIndex + 1 ;
log_info ( " USB Bluetooth device found, index %u " , deviceIndex ) ;
handle = NULL ;
r = libusb_open ( devs [ deviceIndex ] , & handle ) ;
if ( r < 0 ) {
log_error ( " libusb_open failed! " ) ;
handle = NULL ;
continue ;
}
log_info ( " libusb open %d, handle %p " , r , handle ) ;
// reset device
libusb_reset_device ( handle ) ;
if ( r < 0 ) {
log_error ( " libusb_reset_device failed! " ) ;
libusb_close ( handle ) ;
handle = NULL ;
continue ;
}
// device found
r = prepare_device ( handle ) ;
if ( r < 0 ) {
continue ;
}
libusb_state = LIB_USB_INTERFACE_CLAIMED ;
break ;
}
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 ;
2011-06-23 18:52:07 +00:00
for ( c = 0 ; c < ASYNC_BUFFERS ; c + + ) {
event_in_transfer [ c ] = libusb_alloc_transfer ( 0 ) ; // 0 isochronous transfers Events
2015-02-13 14:58:47 +00:00
acl_in_transfer [ c ] = libusb_alloc_transfer ( 0 ) ; // 0 isochronous transfers ACL in
if ( ! event_in_transfer [ c ] | | ! 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
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 15:34:43 +00:00
2016-01-18 13:58:34 +01:00
// incoming
2015-02-13 15:34:43 +00:00
for ( c = 0 ; c < ASYNC_BUFFERS ; c + + ) {
sco_in_transfer [ c ] = libusb_alloc_transfer ( NUM_ISO_PACKETS ) ; // isochronous transfers SCO in
log_info ( " Alloc iso transfer " ) ;
if ( ! sco_in_transfer [ c ] ) {
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-13 15:34:43 +00:00
return LIBUSB_ERROR_NO_MEM ;
}
2016-01-18 13:58:34 +01:00
// configure sco_in handlers
2015-02-13 15:34:43 +00:00
libusb_fill_iso_transfer ( sco_in_transfer [ c ] , handle , sco_in_addr ,
2016-01-18 13:58:34 +01:00
hci_sco_in_buffer [ c ] , SCO_PACKET_SIZE , NUM_ISO_PACKETS , async_callback , NULL , 0 ) ;
libusb_set_iso_packet_lengths ( sco_in_transfer [ c ] , ISO_PACKET_SIZE ) ;
2015-02-13 15:34:43 +00:00
r = libusb_submit_transfer ( sco_in_transfer [ c ] ) ;
log_info ( " Submit iso transfer res = %d " , r ) ;
if ( r ) {
log_error ( " Error submitting isochronous in transfer %d " , r ) ;
2016-01-27 15:30:31 +01:00
usb_close ( ) ;
2015-02-13 15:34:43 +00:00
return r ;
}
}
2016-01-18 13:58:34 +01:00
// outgoing
2016-01-15 22:11:56 +01:00
for ( c = 0 ; c < SCO_RING_BUFFER_COUNT ; c + + ) {
2016-01-18 13:58:34 +01:00
sco_ring_transfers [ c ] = libusb_alloc_transfer ( NUM_ISO_PACKETS ) ; // 1 isochronous transfers SCO out - up to 3 parts
2016-01-15 22:11:56 +01:00
}
2015-02-13 15:34:43 +00:00
# endif
2011-06-23 18:52:07 +00:00
for ( c = 0 ; c < ASYNC_BUFFERS ; c + + ) {
// 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 ;
}
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 + + ) ;
2016-01-20 16:00:45 +01:00
pollfd_data_sources = 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-01-20 15:58:46 +01:00
btstack_run_loop_set_timer ( & usb_timer , AYSNC_POLLING_INTERVAL_MS ) ;
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 ;
2009-07-31 21:41:15 +00:00
// @TODO: remove all run loops!
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 ;
}
// Cancel any asynchronous transfers
for ( c = 0 ; c < ASYNC_BUFFERS ; c + + ) {
libusb_cancel_transfer ( event_in_transfer [ c ] ) ;
2015-02-13 14:58:47 +00:00
libusb_cancel_transfer ( acl_in_transfer [ c ] ) ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
libusb_cancel_transfer ( sco_in_transfer [ c ] ) ;
# endif
2011-06-23 18:52:07 +00:00
}
/* TODO - find a better way to ensure that all transfers have completed */
struct timeval tv ;
2011-08-18 16:43:15 +00:00
memset ( & tv , 0 , sizeof ( struct timeval ) ) ;
2011-06-23 18:52:07 +00:00
libusb_handle_events_timeout ( NULL , & tv ) ;
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 :
2011-06-23 18:52:07 +00:00
for ( c = 0 ; c < ASYNC_BUFFERS ; c + + ) {
if ( event_in_transfer [ c ] ) libusb_free_transfer ( event_in_transfer [ c ] ) ;
2015-02-13 14:58:47 +00:00
if ( acl_in_transfer [ c ] ) libusb_free_transfer ( acl_in_transfer [ c ] ) ;
2016-03-01 17:29:04 +01:00
# ifdef ENABLE_SCO_OVER_HCI
2015-02-13 14:58:47 +00:00
if ( sco_in_transfer [ c ] ) libusb_free_transfer ( sco_in_transfer [ c ] ) ;
# endif
2011-06-23 18:52:07 +00:00
}
2013-03-06 13:24:04 +00:00
// TODO free control and acl out transfers
2011-06-23 18:52:07 +00:00
libusb_release_interface ( handle , 0 ) ;
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 ;
}
}
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 ) {
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 ;
2009-07-08 22:21:02 +00:00
}
return hci_transport_usb ;
2011-10-08 16:58:36 +00:00
}