From b5a986ac93e3082d4139c2abb28e1d4e7291467b Mon Sep 17 00:00:00 2001 From: "matthias.ringwald@gmail.com" Date: Fri, 6 Feb 2015 13:37:18 +0000 Subject: [PATCH] rework hci_transport_h2_usb to continue searching for a valid Bluetooth dongle even if the first one is already in use --- platforms/posix/src/hci_transport_h2_libusb.c | 364 ++++++++++-------- 1 file changed, 206 insertions(+), 158 deletions(-) diff --git a/platforms/posix/src/hci_transport_h2_libusb.c b/platforms/posix/src/hci_transport_h2_libusb.c index f64dfea4b..7b6b22c71 100644 --- a/platforms/posix/src/hci_transport_h2_libusb.c +++ b/platforms/posix/src/hci_transport_h2_libusb.c @@ -74,7 +74,6 @@ typedef enum { LIB_USB_CLOSED = 0, LIB_USB_OPENED, LIB_USB_DEVICE_OPENDED, - LIB_USB_KERNEL_DETACHED, LIB_USB_INTERFACE_CLAIMED, LIB_USB_TRANSFERS_ALLOCATED } libusb_state_t; @@ -123,90 +122,6 @@ static int event_in_addr; static int acl_in_addr; static int acl_out_addr; -#ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID - -// list of known devices, using VendorID/ProductID tuples -static uint16_t known_bt_devices[] = { - // DeLOCK Bluetooth 4.0 - 0x0a5c, 0x21e8, - // Asus BT400 - 0x0b05, 0x17cb, -}; -static int num_known_devices = sizeof(known_bt_devices) / sizeof(uint16_t) / 2; - -static int is_known_bt_device(uint16_t vendor_id, uint16_t product_id){ - int i; - for (i=0; ibNumInterfaces); - - const struct libusb_interface *interface = config_descriptor->interface; - const struct libusb_interface_descriptor * interface0descriptor = interface->altsetting; - log_info("interface 0: %u endpoints", interface0descriptor->bNumEndpoints); - - const struct libusb_endpoint_descriptor *endpoint = interface0descriptor->endpoint; - - for (r=0;rbNumEndpoints;r++,endpoint++){ - log_info("endpoint %x, attributes %x", endpoint->bEndpointAddress, endpoint->bmAttributes); - - if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_INTERRUPT){ - event_in_addr = endpoint->bEndpointAddress; - log_info("Using 0x%2.2X for HCI Events", event_in_addr); - } - if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_BULK){ - if (endpoint->bEndpointAddress & 0x80) { - acl_in_addr = endpoint->bEndpointAddress; - log_info("Using 0x%2.2X for ACL Data In", acl_in_addr); - } else { - acl_out_addr = endpoint->bEndpointAddress; - log_info("Using 0x%2.2X for ACL Data Out", acl_out_addr); - } - } - } - libusb_free_config_descriptor(config_descriptor); -} - -static libusb_device * scan_for_bt_device(libusb_device **devs) { - int i = 0; - while ((dev = devs[i++]) != NULL) { - 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 dev; - } - - // Detect USB Dongle based on whitelist - if (is_known_bt_device(desc.idVendor, desc.idProduct)) return dev; - } - return NULL; -} -#endif static void queue_transfer(struct libusb_transfer *transfer){ @@ -367,14 +282,151 @@ void usb_process_ts(timer_source_t *timer) { return; } -static int usb_open(void *transport_config){ - int r,c; #ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID - libusb_device * aDev; - libusb_device **devs; - ssize_t cnt; + +// 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, +}; +static int num_known_devices = sizeof(known_bt_devices) / sizeof(uint16_t) / 2; + +static int is_known_bt_device(uint16_t vendor_id, uint16_t product_id){ + int i; + for (i=0; ibNumInterfaces); + + const struct libusb_interface *interface = config_descriptor->interface; + const struct libusb_interface_descriptor * interface0descriptor = interface->altsetting; + log_info("interface 0: %u endpoints", interface0descriptor->bNumEndpoints); + + const struct libusb_endpoint_descriptor *endpoint = interface0descriptor->endpoint; + + for (r=0;rbNumEndpoints;r++,endpoint++){ + log_info("endpoint %x, attributes %x", endpoint->bEndpointAddress, endpoint->bmAttributes); + + if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_INTERRUPT){ + event_in_addr = endpoint->bEndpointAddress; + log_info("Using 0x%2.2X for HCI Events", event_in_addr); + } + if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_BULK){ + if (endpoint->bEndpointAddress & 0x80) { + acl_in_addr = endpoint->bEndpointAddress; + log_info("Using 0x%2.2X for ACL Data In", acl_in_addr); + } else { + acl_out_addr = endpoint->bEndpointAddress; + log_info("Using 0x%2.2X for ACL Data Out", acl_out_addr); + } + } + } + libusb_free_config_descriptor(config_descriptor); +} + +// 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; + } + } + return -1; +} #endif +static int prepare_device(libusb_device_handle * handle){ + + int r; + int kernel_driver_detached = 0; + + // Detach OS driver (not possible for OS X and WIN32) +#if !defined(__APPLE__) && !defined(_WIN32) + r = libusb_kernel_driver_active(handle, 0); + if (r < 0) { + log_error("libusb_kernel_driver_active error %d", r); + libusb_close(handle); + return r; + } + + if (r == 1) { + r = libusb_detach_kernel_driver(handle, 0); + if (r < 0) { + log_error("libusb_detach_kernel_driver error %d", r); + libusb_close(handle); + return r; + } + kernel_driver_detached = 1; + } + log_info("libusb_detach_kernel_driver"); +#endif + + const int configuration = 1; + log_info("setting configuration %d...", configuration); + r = libusb_set_configuration(handle, configuration); + if (r < 0) { + log_error("Error libusb_set_configuration: %d", r); + if (kernel_driver_detached){ + libusb_attach_kernel_driver(handle, 0); + } + libusb_close(handle); + return r; + } + + // reserve access to device + log_info("claiming interface 0..."); + r = libusb_claim_interface(handle, 0); + if (r < 0) { + log_error("Error claiming interface %d", r); + if (kernel_driver_detached){ + libusb_attach_kernel_driver(handle, 0); + } + libusb_close(handle); + return r; + } + + return 0; +} + +static int usb_open(void *transport_config){ + int r; + handle_packet = NULL; // default endpoint addresses @@ -392,6 +444,7 @@ static int usb_open(void *transport_config){ libusb_set_debug(NULL, LIBUSB_LOG_LEVEL_WARNING); #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); @@ -401,86 +454,83 @@ static int usb_open(void *transport_config){ usb_close(handle); return -1; } + log_info("libusb open %d, handle %p", r, handle); + + r = prepare_device(handle); + if (r < 0){ + usb_close(handle); + return -1; + } + #else - // Scan system for an appropriate device + // 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) { usb_close(handle); return -1; } - // Find BT modul - aDev = scan_for_bt_device(devs); - if (!aDev){ - log_error("No USB Bluetooth device found"); - libusb_free_device_list(devs, 1); - usb_close(handle); - return -1; - } - log_info("USB Bluetooth device found"); - - dev = aDev; - r = libusb_open(dev, &handle); - // reset device - libusb_reset_device(handle); + 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 (r < 0) { - usb_close(handle); - return r; - } -#endif - - log_info("libusb open %d, handle %p", r, handle); - - // Detach OS driver (not possible for OS X and WIN32) -#if !defined(__APPLE__) && !defined(_WIN32) - r = libusb_kernel_driver_active(handle, 0); - if (r < 0) { - log_error("libusb_kernel_driver_active error %d", r); - usb_close(handle); - return r; + if (handle == 0){ + log_error("No USB Bluetooth device found"); + return -1; } - if (r == 1) { - r = libusb_detach_kernel_driver(handle, 0); - if (r < 0) { - log_error("libusb_detach_kernel_driver error %d", r); - usb_close(handle); - return r; - } - } - log_info("libusb_detach_kernel_driver"); -#endif - libusb_state = LIB_USB_KERNEL_DETACHED; - - const int configuration = 1; - log_info("setting configuration %d...", configuration); - r = libusb_set_configuration(handle, configuration); - if (r < 0) { - log_error("Error libusb_set_configuration: %d\n", r); - usb_close(handle); - return r; - } - - // reserve access to device - log_info("claiming interface 0..."); - r = libusb_claim_interface(handle, 0); - if (r < 0) { - log_error("Error claiming interface %d", r); - usb_close(handle); - return r; - } - - libusb_state = LIB_USB_INTERFACE_CLAIMED; - -#ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID scan_for_bt_endpoints(); -#endif +#endif + // allocate transfer handlers + int c; for (c = 0 ; c < ASYNC_BUFFERS ; c++) { event_in_transfer[c] = libusb_alloc_transfer(0); // 0 isochronous transfers Events bulk_in_transfer[c] = libusb_alloc_transfer(0); // 0 isochronous transfers ACL in @@ -558,6 +608,8 @@ static int usb_open(void *transport_config){ return 0; } + + static int usb_close(void *transport_config){ int c; // @TODO: remove all run loops! @@ -607,10 +659,6 @@ static int usb_close(void *transport_config){ libusb_release_interface(handle, 0); - case LIB_USB_KERNEL_DETACHED: -#if !defined(__APPLE__) && !defined(_WIN32) - libusb_attach_kernel_driver (handle, 0); -#endif case LIB_USB_DEVICE_OPENDED: libusb_close(handle);