mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
usb_sco_start/stop support
This commit is contained in:
parent
1c318ca5b6
commit
ad8a3861e6
@ -74,6 +74,8 @@
|
||||
#include "hci_transport.h"
|
||||
#include "hci_transport_usb.h"
|
||||
|
||||
#define DEBUG
|
||||
|
||||
// deal with changes in libusb API:
|
||||
#ifdef LIBUSB_API_VERSION
|
||||
#if LIBUSB_API_VERSION >= 0x01000106
|
||||
@ -131,7 +133,7 @@ static const uint16_t iso_packet_size_for_alt_setting[] = {
|
||||
|
||||
// Outgoing SCO packet queue
|
||||
// simplified ring buffer implementation
|
||||
#define SCO_OUT_BUFFER_COUNT (8)
|
||||
#define SCO_OUT_BUFFER_COUNT (20)
|
||||
#define SCO_OUT_BUFFER_SIZE (SCO_OUT_BUFFER_COUNT * SCO_PACKET_SIZE)
|
||||
|
||||
// seems to be the max depth for USB 3
|
||||
@ -168,10 +170,6 @@ static struct libusb_device_descriptor desc;
|
||||
#endif
|
||||
static libusb_device_handle * handle;
|
||||
|
||||
//static struct libusb_transfer *acl_out_transfer;
|
||||
//static struct libusb_transfer *event_in_transfer[EVENT_IN_BUFFER_COUNT];
|
||||
//static struct libusb_transfer *acl_in_transfer[ACL_IN_BUFFER_COUNT];
|
||||
|
||||
// known devices
|
||||
typedef struct {
|
||||
btstack_linked_item_t next;
|
||||
@ -245,6 +243,7 @@ static struct libusb_transfer *usb_transfer_list_acquire( usb_transfer_list_t *l
|
||||
current->in_flight = true;
|
||||
return transfer;
|
||||
}
|
||||
void usb_transfer_list_free( usb_transfer_list_t *list );
|
||||
|
||||
static void usb_transfer_list_release( usb_transfer_list_t *list, struct libusb_transfer *transfer ) {
|
||||
usb_transfer_list_entry_t *current = (usb_transfer_list_entry_t*)transfer->user_data;
|
||||
@ -267,7 +266,6 @@ static usb_transfer_list_t *usb_transfer_list_alloc( int nbr, int iso_packets, i
|
||||
struct libusb_transfer *transfer = libusb_alloc_transfer(iso_packets);
|
||||
entry->data = malloc( length );
|
||||
transfer->buffer = entry->data;
|
||||
// transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
|
||||
transfer->user_data = entry;
|
||||
entry->t = transfer;
|
||||
usb_transfer_list_release( list, transfer );
|
||||
@ -328,17 +326,8 @@ static void enqueue_transfer(struct libusb_transfer *transfer) {
|
||||
list_add_tail( ¤t->list, &handle_packet_list );
|
||||
}
|
||||
|
||||
static void signal_acknowledge();
|
||||
static void signal_sco_can_send_now();
|
||||
|
||||
// outgoing buffer for HCI Command packets
|
||||
//static uint8_t hci_cmd_buffer[3 + 256 + LIBUSB_CONTROL_SETUP_SIZE];
|
||||
|
||||
// incoming buffer for HCI Events and ACL Packets
|
||||
//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];
|
||||
|
||||
|
||||
static void signal_acknowledge(void);
|
||||
static void signal_sco_can_send_now(void);
|
||||
|
||||
#ifdef ENABLE_SCO_OVER_HCI
|
||||
|
||||
@ -351,20 +340,11 @@ static H2_SCO_STATE sco_state;
|
||||
static uint8_t sco_buffer[255+3 + SCO_PACKET_SIZE];
|
||||
static uint16_t sco_read_pos;
|
||||
static uint16_t sco_bytes_to_read;
|
||||
//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];
|
||||
|
||||
// outgoing SCO
|
||||
//static uint8_t sco_out_ring_buffer[SCO_OUT_BUFFER_SIZE];
|
||||
//static int sco_ring_write; // packet idx
|
||||
//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];
|
||||
|
||||
// pause/resume
|
||||
static uint16_t sco_voice_setting;
|
||||
static int sco_num_connections;
|
||||
static int sco_shutdown;
|
||||
static bool sco_activated;
|
||||
|
||||
// dynamic SCO configuration
|
||||
static uint16_t iso_packet_size;
|
||||
@ -375,8 +355,6 @@ usb_transfer_list_t *sco_transfer_list = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
static int doing_pollfds;
|
||||
static int num_pollfds;
|
||||
static btstack_data_source_t * pollfd_data_sources;
|
||||
@ -436,67 +414,12 @@ void hci_transport_usb_set_path(int len, uint8_t * port_numbers){
|
||||
memcpy(usb_path, port_numbers, len);
|
||||
}
|
||||
|
||||
LIBUSB_CALL static void async_callback(struct libusb_transfer *transfer){
|
||||
|
||||
int c;
|
||||
|
||||
LIBUSB_CALL static void async_callback(struct libusb_transfer *transfer) {
|
||||
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) {
|
||||
log_info("shutdown, transfer %p", transfer);
|
||||
usb_transfer_list_free_entry( transfer );
|
||||
return;
|
||||
}
|
||||
#if 0
|
||||
|
||||
// identify and free transfers as part of shutdown
|
||||
#ifdef ENABLE_SCO_OVER_HCI
|
||||
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED || sco_shutdown) {
|
||||
for (c=0;c<SCO_IN_BUFFER_COUNT;c++){
|
||||
if (transfer == sco_in_transfer[c]){
|
||||
libusb_free_transfer(transfer);
|
||||
sco_in_transfer[c] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (c=0;c<SCO_OUT_BUFFER_COUNT;c++){
|
||||
if (transfer == sco_out_transfers[c]){
|
||||
sco_out_transfers_in_flight[c] = 0;
|
||||
libusb_free_transfer(transfer);
|
||||
sco_out_transfers[c] = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCO_OVER_HCI
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
int r;
|
||||
// log_info("begin async_callback endpoint %x, status %x, actual length %u", transfer->endpoint, transfer->status, transfer->actual_length );
|
||||
@ -529,6 +452,11 @@ LIBUSB_CALL static void async_callback(struct libusb_transfer *transfer){
|
||||
static int usb_send_sco_packet(uint8_t *packet, int size){
|
||||
int r;
|
||||
|
||||
if( !sco_activated ) {
|
||||
log_error("sco send without beeing active!");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) return -1;
|
||||
|
||||
struct libusb_transfer *transfer = usb_transfer_list_acquire( sco_transfer_list );
|
||||
@ -624,7 +552,7 @@ static void handle_completed_transfer(struct libusb_transfer *transfer){
|
||||
// log_info("handle_completed_transfer for SCO IN! num packets %u", transfer->NUM_ISO_PACKETS);
|
||||
|
||||
// give the transfer back to the pool, without resubmiting
|
||||
if( sco_shutdown ) {
|
||||
if( !sco_activated ) {
|
||||
usb_transfer_list_release( sco_transfer_list, transfer );
|
||||
return;
|
||||
}
|
||||
@ -650,7 +578,7 @@ static void handle_completed_transfer(struct libusb_transfer *transfer){
|
||||
}
|
||||
}
|
||||
usb_transfer_list_release( sco_transfer_list, transfer );
|
||||
if( sco_shutdown ) {
|
||||
if( !sco_activated ) {
|
||||
return;
|
||||
}
|
||||
// log_info("sco out done, {{ %u/%u (%x)}, { %u/%u (%x)}, { %u/%u (%x)}}",
|
||||
@ -672,7 +600,6 @@ static void handle_completed_transfer(struct libusb_transfer *transfer){
|
||||
|
||||
if (resubmit){
|
||||
// Re-submit transfer
|
||||
// transfer->user_data = NULL;
|
||||
int r = libusb_submit_transfer(transfer);
|
||||
if (r) {
|
||||
log_error("Error re-submitting transfer %d", r);
|
||||
@ -680,7 +607,8 @@ static void handle_completed_transfer(struct libusb_transfer *transfer){
|
||||
}
|
||||
}
|
||||
|
||||
void usb_handle_pending_events() {
|
||||
void usb_handle_pending_events(void);
|
||||
void usb_handle_pending_events(void) {
|
||||
struct timeval tv = { 0 };
|
||||
libusb_handle_events_timeout_completed(NULL, &tv, NULL);
|
||||
}
|
||||
@ -985,6 +913,11 @@ static libusb_device_handle * try_open_device(libusb_device * device){
|
||||
static int usb_sco_start(void){
|
||||
|
||||
log_info("usb_sco_start");
|
||||
if( sco_activated ) {
|
||||
log_error("double sco start!");
|
||||
return -1;
|
||||
}
|
||||
sco_activated = true;
|
||||
|
||||
sco_state_machine_init();
|
||||
|
||||
@ -1000,12 +933,19 @@ static int usb_sco_start(void){
|
||||
iso_packet_size = iso_packet_size_for_alt_setting[alt_setting];
|
||||
|
||||
log_info("Switching to setting %u on interface 1..", alt_setting);
|
||||
int r = libusb_set_interface_alt_setting(handle, 1, alt_setting);
|
||||
int r = libusb_set_interface_alt_setting(handle, 1, alt_setting);
|
||||
if (r < 0) {
|
||||
log_error("Error setting alternative setting %u for interface 1: %s\n", alt_setting, libusb_error_name(r));
|
||||
return r;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int in_flight = usb_transfer_list_in_flight( sco_transfer_list );
|
||||
// there need to be at least SCO_IN_BUFFER_COUNT packets available to
|
||||
// fill them in below
|
||||
assert( in_flight <= SCO_OUT_BUFFER_COUNT );
|
||||
#endif
|
||||
|
||||
// incoming
|
||||
int c;
|
||||
for (c = 0 ; c < SCO_IN_BUFFER_COUNT ; c++) {
|
||||
@ -1031,97 +971,12 @@ static int usb_sco_start(void){
|
||||
static void usb_sco_stop(void){
|
||||
|
||||
log_info("usb_sco_stop");
|
||||
sco_shutdown = 1;
|
||||
#if 0
|
||||
// Free SCO transfers already in queue
|
||||
struct libusb_transfer* transfer = handle_packet;
|
||||
struct libusb_transfer* prev_transfer = NULL;
|
||||
while (transfer != NULL) {
|
||||
uint16_t c;
|
||||
bool drop_transfer = false;
|
||||
for (c=0;c<SCO_IN_BUFFER_COUNT;c++){
|
||||
if (transfer == sco_in_transfer[c]){
|
||||
sco_in_transfer[c] = NULL;
|
||||
drop_transfer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (c=0;c<SCO_OUT_BUFFER_COUNT;c++){
|
||||
if (transfer == sco_out_transfers[c]){
|
||||
sco_out_transfers_in_flight[c] = 0;
|
||||
sco_out_transfers[c] = NULL;
|
||||
drop_transfer = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct libusb_transfer * next_transfer = (struct libusb_transfer *) transfer->user_data;
|
||||
if (drop_transfer) {
|
||||
log_info("Drop completed SCO transfer %p", transfer);
|
||||
if (prev_transfer == NULL) {
|
||||
// first item
|
||||
handle_packet = (struct libusb_transfer *) next_transfer;
|
||||
} else {
|
||||
// other item
|
||||
prev_transfer->user_data = (struct libusb_transfer *) next_transfer;
|
||||
}
|
||||
libusb_free_transfer(transfer);
|
||||
} else {
|
||||
prev_transfer = transfer;
|
||||
}
|
||||
transfer = next_transfer;
|
||||
}
|
||||
sco_activated = false;
|
||||
|
||||
libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_ERROR);
|
||||
usb_transfer_list_cancel( sco_transfer_list );
|
||||
|
||||
int c;
|
||||
for (c = 0 ; c < SCO_IN_BUFFER_COUNT ; c++) {
|
||||
if (sco_in_transfer[c] != NULL) {
|
||||
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 {
|
||||
if (sco_out_transfers[c] != NULL) {
|
||||
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_completed(NULL, &tv, NULL);
|
||||
// check if all done
|
||||
completed = 1;
|
||||
|
||||
// Cancel all synchronous transfer
|
||||
for (c = 0 ; c < SCO_IN_BUFFER_COUNT ; c++) {
|
||||
if (sco_in_transfer[c] != NULL){
|
||||
completed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!completed) continue;
|
||||
|
||||
for (c=0; c < SCO_OUT_BUFFER_COUNT ; c++){
|
||||
if (sco_out_transfers[c] != NULL){
|
||||
completed = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
sco_shutdown = 0;
|
||||
libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_WARNING);
|
||||
#endif
|
||||
log_info("Switching to setting %u on interface 1..", 0);
|
||||
int r = libusb_set_interface_alt_setting(handle, 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;
|
||||
@ -1129,24 +984,24 @@ static void usb_sco_stop(void){
|
||||
|
||||
log_info("usb_sco_stop done");
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
void pollfd_added_cb(int fd, short events, void *user_data)
|
||||
{
|
||||
printf("add %d\n", fd);
|
||||
void pollfd_added_cb(int fd, short events, void *user_data);
|
||||
void pollfd_remove_cb(int fd, void *user_data);
|
||||
|
||||
void pollfd_added_cb(int fd, short events, void *user_data) {
|
||||
UNUSED(events);
|
||||
UNUSED(user_data);
|
||||
log_error("add fd: %d", fd);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
void pollfd_remove_cb(int fd, void *user_data)
|
||||
{
|
||||
printf("remove %d\n", fd);
|
||||
void pollfd_remove_cb(int fd, void *user_data) {
|
||||
UNUSED(user_data);
|
||||
log_error("remove fd: %d", fd);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
|
||||
static int usb_open(void){
|
||||
int r;
|
||||
|
||||
@ -1384,10 +1239,7 @@ static int usb_open(void){
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int usb_close(void){
|
||||
int c;
|
||||
int completed = 0;
|
||||
|
||||
static int usb_close(void) {
|
||||
if (!usb_transport_open) return 0;
|
||||
|
||||
log_info("usb_close");
|
||||
@ -1442,8 +1294,8 @@ static int usb_close(void){
|
||||
usb_transfer_list_free( default_transfer_list );
|
||||
#ifdef ENABLE_SCO_OVER_HCI
|
||||
usb_transfer_list_free( sco_transfer_list );
|
||||
#endif
|
||||
sco_enabled = 0;
|
||||
#endif
|
||||
|
||||
// finally release interface
|
||||
libusb_release_interface(handle, 0);
|
||||
@ -1493,12 +1345,12 @@ static void usb_transport_response_ds(btstack_data_source_t *ds, btstack_data_so
|
||||
// printf("%s packet sent: %d sco can send now: %d\n", __FUNCTION__, acknowledge_count, sco_can_send_now_count);
|
||||
for(; acknowledge_count>0; --acknowledge_count) {
|
||||
static const uint8_t event[] = { HCI_EVENT_TRANSPORT_PACKET_SENT, 0 };
|
||||
packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
|
||||
packet_handler(HCI_EVENT_PACKET, (uint8_t*)&event[0], sizeof(event));
|
||||
}
|
||||
|
||||
for(; sco_can_send_now_count>0; --sco_can_send_now_count) {
|
||||
static const uint8_t event[] = { HCI_EVENT_SCO_CAN_SEND_NOW, 0 };
|
||||
packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
|
||||
packet_handler(HCI_EVENT_PACKET, (uint8_t*)&event[0], sizeof(event));
|
||||
}
|
||||
|
||||
}
|
||||
@ -1566,22 +1418,26 @@ static int usb_can_send_packet_now(uint8_t packet_type){
|
||||
switch (packet_type){
|
||||
case HCI_COMMAND_DATA_PACKET: {
|
||||
int ret = !usb_transfer_list_empty( default_transfer_list );
|
||||
btstack_assert( ret == 1 );
|
||||
// printf("can send now: %d\n", ret );
|
||||
if( !ret ) {
|
||||
log_error("command transfers shouldn't be empty!");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
case HCI_ACL_DATA_PACKET: {
|
||||
int ret = !usb_transfer_list_empty( default_transfer_list );
|
||||
btstack_assert( ret == 1 );
|
||||
// printf("can send now: %d\n", ret );
|
||||
if( !ret ) {
|
||||
log_error("acl transfers shouldn't be empty!");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SCO_OVER_HCI
|
||||
case HCI_SCO_DATA_PACKET: {
|
||||
// printf("%s sco\n", __FUNCTION__);
|
||||
if (!sco_enabled) return 0;
|
||||
if (!sco_enabled || !sco_activated) return 0;
|
||||
int ret = !usb_transfer_list_empty( sco_transfer_list );
|
||||
if( !ret ) {
|
||||
log_error("sco transfers shouldn't be empty!");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user