2009-10-29 20:25:42 +00:00
|
|
|
|
/*
|
2012-05-07 21:54:09 +00:00
|
|
|
|
* Copyright (C) 2009-2012 by Matthias Ringwald
|
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
|
|
|
|
*
|
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
|
|
|
|
|
* ``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.
|
|
|
|
|
*
|
2012-05-07 21:54:09 +00:00
|
|
|
|
* Please inquire about commercial licensing options at btstack@ringwald.ch
|
|
|
|
|
*
|
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
|
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>
|
|
|
|
|
|
|
|
|
|
#include <libusb-1.0/libusb.h>
|
|
|
|
|
|
2014-01-19 16:45:57 +00:00
|
|
|
|
#include "btstack-config.h"
|
2011-01-12 19:48:08 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
#include "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
|
|
|
|
#include "hci_dump.h"
|
|
|
|
|
|
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
|
|
|
|
|
|
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);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
static int usb_close(void *transport_config);
|
2009-07-08 22:21:02 +00: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_KERNEL_DETACHED,
|
|
|
|
|
LIB_USB_INTERFACE_CLAIMED,
|
|
|
|
|
LIB_USB_TRANSFERS_ALLOCATED
|
2013-05-21 12:10:36 +00:00
|
|
|
|
} libusb_state_t;
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
#define ASYNC_BUFFERS 20
|
2013-02-24 19:59:57 +00:00
|
|
|
|
#define AYSNC_POLLING_INTERVAL_MS 3
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
|
|
|
|
static struct libusb_transfer *event_in_transfer[ASYNC_BUFFERS];
|
|
|
|
|
static struct libusb_transfer *bulk_in_transfer[ASYNC_BUFFERS];
|
2013-03-06 13:24:04 +00:00
|
|
|
|
static struct libusb_transfer *bulk_out_transfer;
|
|
|
|
|
static struct libusb_transfer *command_out_transfer;
|
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
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
|
|
|
|
|
static uint8_t hci_bulk_in_buffer[ASYNC_BUFFERS][HCI_ACL_BUFFER_SIZE]; // bigger than largest packet
|
2013-03-06 18:06:22 +00:00
|
|
|
|
static uint8_t hci_control_buffer[3 + 256 + LIBUSB_CONTROL_SETUP_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;
|
|
|
|
|
static timer_source_t usb_timer;
|
|
|
|
|
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;
|
2009-07-05 21:06:38 +00:00
|
|
|
|
|
2013-06-04 10:10:50 +00:00
|
|
|
|
#ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
|
2013-09-16 18:57:33 +00:00
|
|
|
|
|
2014-01-08 08:27:05 +00:00
|
|
|
|
// list of known devices, using VendorID/ProductID tuples
|
2013-09-16 18:57:33 +00:00
|
|
|
|
static uint16_t known_bt_devices[] = {
|
|
|
|
|
// DeLOCK Bluetooth 4.0
|
2013-12-19 14:24:58 +00:00
|
|
|
|
0x0a5c, 0x21e8,
|
|
|
|
|
// Asus BT400
|
|
|
|
|
0x0b05, 0x17cb,
|
2013-09-16 18:57:33 +00:00
|
|
|
|
};
|
|
|
|
|
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; 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void scan_for_bt_endpoints(void) {
|
2011-06-23 18:52:07 +00:00
|
|
|
|
int r;
|
2009-07-05 21:06:38 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
// get endpoints from interface descriptor
|
|
|
|
|
struct libusb_config_descriptor *config_descriptor;
|
|
|
|
|
r = libusb_get_active_config_descriptor(dev, &config_descriptor);
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("configuration: %u interfaces", config_descriptor->bNumInterfaces);
|
2009-07-06 21:40:30 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
const struct libusb_interface *interface = config_descriptor->interface;
|
|
|
|
|
const struct libusb_interface_descriptor * interface0descriptor = interface->altsetting;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("interface 0: %u endpoints", interface0descriptor->bNumEndpoints);
|
2009-10-18 20:49:27 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
const struct libusb_endpoint_descriptor *endpoint = interface0descriptor->endpoint;
|
2009-10-18 20:49:27 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
for (r=0;r<interface0descriptor->bNumEndpoints;r++,endpoint++){
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("endpoint %x, attributes %x", endpoint->bEndpointAddress, endpoint->bmAttributes);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
|
|
|
|
if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_INTERRUPT){
|
|
|
|
|
event_in_addr = endpoint->bEndpointAddress;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("Using 0x%2.2X for HCI Events", event_in_addr);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
if ((endpoint->bmAttributes & 0x3) == LIBUSB_TRANSFER_TYPE_BULK){
|
|
|
|
|
if (endpoint->bEndpointAddress & 0x80) {
|
|
|
|
|
acl_in_addr = endpoint->bEndpointAddress;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("Using 0x%2.2X for ACL Data In", acl_in_addr);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
} else {
|
|
|
|
|
acl_out_addr = endpoint->bEndpointAddress;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("Using 0x%2.2X for ACL Data Out", acl_out_addr);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2009-07-08 22:21:02 +00:00
|
|
|
|
}
|
2013-02-18 14:07:34 +00:00
|
|
|
|
libusb_free_config_descriptor(config_descriptor);
|
2009-07-06 21:40:30 +00:00
|
|
|
|
}
|
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
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) {
|
2011-09-11 16:07:40 +00:00
|
|
|
|
log_error("failed to get device descriptor");
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2009-10-18 20:49:27 +00:00
|
|
|
|
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("%04x:%04x (bus %d, device %d) - class %x subclass %x protocol %x ",
|
2011-06-23 18:52:07 +00:00
|
|
|
|
desc.idVendor, desc.idProduct,
|
|
|
|
|
libusb_get_bus_number(dev), libusb_get_device_address(dev),
|
|
|
|
|
desc.bDeviceClass, desc.bDeviceSubClass, desc.bDeviceProtocol);
|
|
|
|
|
|
2013-09-16 18:57:33 +00:00
|
|
|
|
// Detect USB Dongle based Class, Subclass, and Protocol
|
2011-06-23 18:52:07 +00:00
|
|
|
|
// 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) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("BT Dongle found.");
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return dev;
|
|
|
|
|
}
|
2013-09-16 18:57:33 +00:00
|
|
|
|
|
|
|
|
|
// Detect USB Dongle based on whitelist
|
|
|
|
|
if (is_known_bt_device(desc.idVendor, desc.idProduct)) return dev;
|
2009-10-18 20:49:27 +00:00
|
|
|
|
}
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return NULL;
|
2009-10-18 20:49:27 +00:00
|
|
|
|
}
|
2011-06-23 18:52:07 +00:00
|
|
|
|
#endif
|
2009-10-18 20:49:27 +00: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 {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("async_callback 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
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
int r;
|
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
int resubmit = 0;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
if (transfer->endpoint == event_in_addr) {
|
|
|
|
|
hci_dump_packet( HCI_EVENT_PACKET, 1, transfer-> buffer,
|
|
|
|
|
transfer->actual_length);
|
|
|
|
|
packet_handler(HCI_EVENT_PACKET, transfer-> buffer,
|
|
|
|
|
transfer->actual_length);
|
|
|
|
|
resubmit = 1;
|
|
|
|
|
}
|
2013-02-24 18:13:16 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
else if (transfer->endpoint == acl_in_addr) {
|
|
|
|
|
// log_info("-> acl");
|
|
|
|
|
hci_dump_packet( HCI_ACL_DATA_PACKET, 1, transfer-> buffer,
|
|
|
|
|
transfer->actual_length);
|
|
|
|
|
packet_handler(HCI_ACL_DATA_PACKET, transfer-> buffer,
|
|
|
|
|
transfer->actual_length);
|
2013-02-24 18:13:16 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
resubmit = 1;
|
|
|
|
|
} else if (transfer->endpoint == acl_out_addr){
|
2013-09-02 19:36:28 +00:00
|
|
|
|
// log_info("acl out done, size %u", transfer->actual_length);
|
2013-03-06 18:40:47 +00:00
|
|
|
|
usb_acl_out_active = 0;
|
|
|
|
|
|
2013-09-02 19:56:51 +00:00
|
|
|
|
// notify upper stack that iit might be possible to send again
|
2013-11-22 12:48:47 +00:00
|
|
|
|
uint8_t event[] = { DAEMON_EVENT_HCI_PACKET_SENT, 0};
|
2013-12-20 19:22:19 +00:00
|
|
|
|
packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
|
2013-09-02 19:56:51 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
resubmit = 0;
|
|
|
|
|
} else if (transfer->endpoint == 0){
|
2013-09-02 19:36:28 +00:00
|
|
|
|
// log_info("command done, size %u", transfer->actual_length);
|
2013-03-06 18:40:47 +00:00
|
|
|
|
usb_command_active = 0;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-09-02 19:34:21 +00:00
|
|
|
|
// notify upper stack that iit might be possible to send again
|
2013-11-22 12:48:47 +00:00
|
|
|
|
uint8_t event[] = { DAEMON_EVENT_HCI_PACKET_SENT, 0};
|
2013-12-20 19:22:19 +00:00
|
|
|
|
packet_handler(HCI_EVENT_PACKET, &event[0], sizeof(event));
|
2013-09-02 19:34:21 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
resubmit = 0;
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
log_info("usb_process_ds endpoint unknown %x", transfer->endpoint);
|
|
|
|
|
}
|
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;
|
|
|
|
|
r = libusb_submit_transfer(transfer);
|
2013-03-06 13:24:04 +00:00
|
|
|
|
|
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
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
static int usb_process_ds(struct data_source *ds) {
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) return -1;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
|
2013-09-02 19:36:28 +00:00
|
|
|
|
// log_info("begin usb_process_ds");
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
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-03-06 13:24:04 +00:00
|
|
|
|
|
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);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
void * next = handle_packet->user_data;
|
2013-03-06 13:24:04 +00:00
|
|
|
|
|
2013-03-06 18:40:47 +00:00
|
|
|
|
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
|
|
|
|
|
if (libusb_state != LIB_USB_TRANSFERS_ALLOCATED) return -1;
|
|
|
|
|
|
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");
|
2013-02-24 18:13:16 +00:00
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
void usb_process_ts(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
|
2011-06-23 18:52:07 +00:00
|
|
|
|
usb_process_ds((struct data_source *) NULL);
|
|
|
|
|
|
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
|
|
|
|
|
run_loop_set_timer(&usb_timer, msec);
|
|
|
|
|
run_loop_add_timer(&usb_timer);
|
|
|
|
|
usb_timer_active = 1;
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
static int usb_open(void *transport_config){
|
2011-10-08 16:58:36 +00:00
|
|
|
|
int r,c;
|
2013-06-04 10:10:50 +00:00
|
|
|
|
#ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
|
2011-06-23 18:52:07 +00:00
|
|
|
|
libusb_device * aDev;
|
2009-07-08 22:21:02 +00:00
|
|
|
|
libusb_device **devs;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
ssize_t cnt;
|
2011-10-08 16:58:36 +00:00
|
|
|
|
#endif
|
2011-06-23 18:52:07 +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
|
|
|
|
|
|
|
|
|
|
// USB init
|
2009-07-08 22:21:02 +00:00
|
|
|
|
r = libusb_init(NULL);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
if (r < 0) return -1;
|
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
libusb_state = LIB_USB_OPENED;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
|
|
|
|
// configure debug level
|
2013-03-06 17:47:50 +00:00
|
|
|
|
libusb_set_debug(NULL,1);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
|
2013-06-04 10:10:50 +00:00
|
|
|
|
#ifdef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
|
2011-06-23 18:52:07 +00:00
|
|
|
|
// Use a specified device
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("Want vend: %04x, prod: %04x", USB_VENDOR_ID, USB_PRODUCT_ID);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
handle = libusb_open_device_with_vid_pid(NULL, USB_VENDOR_ID, USB_PRODUCT_ID);
|
|
|
|
|
|
|
|
|
|
if (!handle){
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("libusb_open_device_with_vid_pid failed!");
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
#else
|
|
|
|
|
// Scan system for an appropriate device
|
2011-07-22 18:31:02 +00:00
|
|
|
|
log_info("Scanning for a device");
|
2009-07-08 22:21:02 +00:00
|
|
|
|
cnt = libusb_get_device_list(NULL, &devs);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
if (cnt < 0) {
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-01-12 19:45:29 +00:00
|
|
|
|
return -1;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
// Find BT modul
|
|
|
|
|
aDev = scan_for_bt_device(devs);
|
2011-01-12 19:45:29 +00:00
|
|
|
|
if (!aDev){
|
2013-09-16 18:57:33 +00:00
|
|
|
|
log_error("No USB Bluetooth device found");
|
2011-01-12 19:45:29 +00:00
|
|
|
|
libusb_free_device_list(devs, 1);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-01-12 19:45:29 +00:00
|
|
|
|
return -1;
|
|
|
|
|
}
|
2013-09-16 18:57:33 +00:00
|
|
|
|
log_info("USB Bluetooth device found");
|
|
|
|
|
|
2011-01-12 19:45:29 +00:00
|
|
|
|
dev = aDev;
|
|
|
|
|
r = libusb_open(dev, &handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-02-24 18:13:16 +00:00
|
|
|
|
// reset device
|
|
|
|
|
libusb_reset_device(handle);
|
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
libusb_free_device_list(devs, 1);
|
|
|
|
|
|
|
|
|
|
if (r < 0) {
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return r;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("libusb open %d, handle %p", r, handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
// Detach OS driver (not possible for OS X)
|
2009-07-06 21:40:30 +00:00
|
|
|
|
#ifndef __APPLE__
|
2011-06-23 18:52:07 +00:00
|
|
|
|
r = libusb_kernel_driver_active(handle, 0);
|
|
|
|
|
if (r < 0) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("libusb_kernel_driver_active error %d", r);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return r;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == 1) {
|
|
|
|
|
r = libusb_detach_kernel_driver(handle, 0);
|
|
|
|
|
if (r < 0) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("libusb_detach_kernel_driver error %d", r);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("libusb_detach_kernel_driver");
|
2009-07-06 16:37:53 +00:00
|
|
|
|
#endif
|
2009-07-08 22:21:02 +00:00
|
|
|
|
libusb_state = LIB_USB_KERNEL_DETACHED;
|
2009-07-06 16:37:53 +00:00
|
|
|
|
|
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...");
|
2011-06-23 18:52:07 +00:00
|
|
|
|
r = libusb_claim_interface(handle, 0);
|
|
|
|
|
if (r < 0) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("Error claiming interface %d", r);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return r;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
libusb_state = LIB_USB_INTERFACE_CLAIMED;
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_info("claimed interface 0");
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-06-04 10:10:50 +00:00
|
|
|
|
#ifndef HAVE_USB_VENDOR_ID_AND_PRODUCT_ID
|
2011-06-23 18:52:07 +00:00
|
|
|
|
scan_for_bt_endpoints();
|
|
|
|
|
#endif
|
2011-01-12 20:43:27 +00:00
|
|
|
|
|
2011-06-23 18:52:07 +00:00
|
|
|
|
// allocate transfer handlers
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
if ( !event_in_transfer[c] || !bulk_in_transfer[c] ) {
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
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
|
|
|
|
bulk_out_transfer = libusb_alloc_transfer(0);
|
|
|
|
|
command_out_transfer = libusb_alloc_transfer(0);
|
|
|
|
|
|
|
|
|
|
// 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
|
|
|
|
|
|
|
|
|
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);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// configure bulk_in handlers
|
|
|
|
|
libusb_fill_bulk_transfer(bulk_in_transfer[c], handle, acl_in_addr,
|
2013-02-24 19:59:57 +00:00
|
|
|
|
hci_bulk_in_buffer[c], HCI_ACL_BUFFER_SIZE, async_callback, NULL, 0) ;
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
|
|
|
|
r = libusb_submit_transfer(bulk_in_transfer[c]);
|
|
|
|
|
if (r) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("Error submitting bulk in transfer %d", r);
|
2011-10-08 16:58:36 +00:00
|
|
|
|
usb_close(handle);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
return r;
|
|
|
|
|
}
|
2009-07-08 22:21:02 +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);
|
|
|
|
|
for (r = 0 ; pollfd[r] ; r++) {
|
2013-05-21 12:40:09 +00:00
|
|
|
|
data_source_t *ds = (data_source_t*)malloc(sizeof(data_source_t));
|
2011-06-23 18:52:07 +00:00
|
|
|
|
ds->fd = pollfd[r]->fd;
|
|
|
|
|
ds->process = usb_process_ds;
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
} 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;
|
2013-02-18 14:58:29 +00:00
|
|
|
|
run_loop_set_timer(&usb_timer, AYSNC_POLLING_INTERVAL_MS);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
run_loop_add_timer(&usb_timer);
|
|
|
|
|
usb_timer_active = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return 0;
|
|
|
|
|
}
|
2011-11-09 15:57:15 +00:00
|
|
|
|
static int usb_close(void *transport_config){
|
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) {
|
|
|
|
|
run_loop_remove_timer(&usb_timer);
|
|
|
|
|
usb_timer_active = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cancel any asynchronous transfers
|
|
|
|
|
for (c = 0 ; c < ASYNC_BUFFERS ; c++) {
|
|
|
|
|
libusb_cancel_transfer(event_in_transfer[c]);
|
|
|
|
|
libusb_cancel_transfer(bulk_in_transfer[c]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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);
|
|
|
|
|
|
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]);
|
|
|
|
|
if (bulk_in_transfer[c]) libusb_free_transfer(bulk_in_transfer[c]);
|
|
|
|
|
}
|
|
|
|
|
|
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_KERNEL_DETACHED:
|
|
|
|
|
#ifndef __APPLE__
|
|
|
|
|
libusb_attach_kernel_driver (handle, 0);
|
|
|
|
|
#endif
|
|
|
|
|
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
|
|
|
|
|
libusb_fill_control_setup(hci_control_buffer, LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE, 0, 0, 0, size);
|
|
|
|
|
memcpy(hci_control_buffer + LIBUSB_CONTROL_SETUP_SIZE, packet, size);
|
|
|
|
|
|
|
|
|
|
int completed = 0;
|
|
|
|
|
libusb_fill_control_transfer(command_out_transfer, handle, hci_control_buffer, async_callback, &completed, 0);
|
|
|
|
|
command_out_transfer->flags = LIBUSB_TRANSFER_FREE_BUFFER;
|
|
|
|
|
r = libusb_submit_transfer(command_out_transfer);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
|
2013-03-06 18:06:22 +00:00
|
|
|
|
// // Use synchronous call to sent out command
|
|
|
|
|
// r = libusb_control_transfer(handle,
|
|
|
|
|
// LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_INTERFACE,
|
|
|
|
|
// 0, 0, 0, packet, size, 0);
|
2011-06-23 18:52:07 +00:00
|
|
|
|
|
2013-03-07 14:57:09 +00:00
|
|
|
|
if (r < 0) {
|
2013-02-24 18:13:16 +00:00
|
|
|
|
log_error("Error submitting control 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
|
|
|
|
|
|
|
|
|
hci_dump_packet( HCI_COMMAND_DATA_PACKET, 0, packet, size);
|
2009-07-08 22:21:02 +00:00
|
|
|
|
|
2013-03-06 18:06:22 +00:00
|
|
|
|
usb_command_active = 1;
|
|
|
|
|
|
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
|
|
|
|
|
2013-03-06 13:24:04 +00:00
|
|
|
|
int completed = 0;
|
|
|
|
|
libusb_fill_bulk_transfer(bulk_out_transfer, handle, acl_out_addr, packet, size,
|
|
|
|
|
async_callback, &completed, 0);
|
|
|
|
|
bulk_out_transfer->type = LIBUSB_TRANSFER_TYPE_BULK;
|
|
|
|
|
|
|
|
|
|
r = libusb_submit_transfer(bulk_out_transfer);
|
|
|
|
|
if (r < 0) {
|
2013-03-05 16:04:53 +00:00
|
|
|
|
log_error("Error submitting data 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
|
|
|
|
|
2013-03-06 17:47:50 +00:00
|
|
|
|
hci_dump_packet( HCI_ACL_DATA_PACKET, 0, packet, size);
|
|
|
|
|
|
2013-03-06 13:24:04 +00:00
|
|
|
|
usb_acl_out_active = 1;
|
|
|
|
|
|
2013-03-06 17:47:50 +00:00
|
|
|
|
// log_info("usb_send_acl_packet exit");
|
2013-03-06 13:24:04 +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;
|
|
|
|
|
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);
|
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
2011-10-08 16:58:36 +00:00
|
|
|
|
static const char * usb_get_transport_name(void){
|
2009-07-08 22:21:02 +00:00
|
|
|
|
return "USB";
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
|
hci_transport_t * hci_transport_usb_instance() {
|
|
|
|
|
if (!hci_transport_usb) {
|
2013-05-21 12:40:09 +00:00
|
|
|
|
hci_transport_usb = (hci_transport_t*) malloc( sizeof(hci_transport_t));
|
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->send_packet = usb_send_packet;
|
|
|
|
|
hci_transport_usb->register_packet_handler = usb_register_packet_handler;
|
2009-07-08 22:21:02 +00:00
|
|
|
|
hci_transport_usb->get_transport_name = usb_get_transport_name;
|
2011-07-12 20:09:07 +00:00
|
|
|
|
hci_transport_usb->set_baudrate = NULL;
|
2013-03-06 13:24:04 +00:00
|
|
|
|
hci_transport_usb->can_send_packet_now = usb_can_send_packet_now;
|
2009-07-08 22:21:02 +00:00
|
|
|
|
}
|
|
|
|
|
return hci_transport_usb;
|
2011-10-08 16:58:36 +00:00
|
|
|
|
}
|