summaryrefslogtreecommitdiffstats
path: root/hci
diff options
context:
space:
mode:
authorravindranath <ravindranathx.doddi@intel.com>2013-03-19 11:35:44 -0400
committerRicardo Cerqueira <cyanogenmod@cerqueira.org>2013-07-14 02:52:57 +0100
commit382f7fb0f87989dfa109913c34e3ef1ae32b452d (patch)
treee18b322016da84801a707a5430464798eef3d63c /hci
parenta59fa7ff822e7b0a726f55e12e99b1a1f984ee5f (diff)
downloadexternal_bluetooth_bluedroid-382f7fb0f87989dfa109913c34e3ef1ae32b452d.zip
external_bluetooth_bluedroid-382f7fb0f87989dfa109913c34e3ef1ae32b452d.tar.gz
external_bluetooth_bluedroid-382f7fb0f87989dfa109913c34e3ef1ae32b452d.tar.bz2
Support USB HCI
Issue: AXIA-1459 Change-Id: Ie4cc5766446774a0bae3bbf7d9baa5f44e814f59 Signed-off-by: Ravindranath Doddi <ravindranathx.doddi@intel.com> Signed-off-by: Krishnan V <krishnanx.vaidyanathan.venkitakrishnan@intel.com> Signed-off-by: Daniel Leung <daniel.leung@intel.com> Signed-off-by: Matt Gumbel <matthew.k.gumbel@intel.com>
Diffstat (limited to 'hci')
-rw-r--r--hci/Android.mk17
-rw-r--r--hci/include/usb.h140
-rw-r--r--hci/src/usb.c1169
3 files changed, 1325 insertions, 1 deletions
diff --git a/hci/Android.mk b/hci/Android.mk
index b0dc4aa..b970509 100644
--- a/hci/Android.mk
+++ b/hci/Android.mk
@@ -21,18 +21,33 @@ LOCAL_SRC_FILES += \
else
+ifeq ($(BLUETOOTH_HCI_USE_USB),true)
+
+LOCAL_SRC_FILES += \
+ src/hci_h4.c \
+ src/usb.c
+
+LOCAL_C_INCLUDES += \
+ external/libusb
+
+LOCAL_SHARED_LIBRARIES := \
+ libusb
+else
+
LOCAL_SRC_FILES += \
src/hci_h4.c \
src/userial.c
endif
+endif
+
LOCAL_C_INCLUDES += \
$(LOCAL_PATH)/include \
$(LOCAL_PATH)/../utils/include \
$(bdroid_C_INCLUDES)
-LOCAL_SHARED_LIBRARIES := \
+LOCAL_SHARED_LIBRARIES += \
libcutils \
libdl \
libbt-utils
diff --git a/hci/include/usb.h b/hci/include/usb.h
new file mode 100644
index 0000000..2be07b9
--- /dev/null
+++ b/hci/include/usb.h
@@ -0,0 +1,140 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ * Portions of file: Copyright (C) 2013, Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: usb.h
+ *
+ * Description: Contains definitions used for usb serial port controls
+ *
+ ******************************************************************************/
+
+#ifndef USB_H
+#define USB_H
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+/*
+ * Below are the interfaces to usb driver. At present, either USB is supported
+ * or UART is supported.
+ */
+#define usb_init userial_init
+#define usb_open userial_open
+#define usb_write userial_write
+#define usb_read userial_read
+#define usb_close userial_close
+#define usb_ioctl userial_ioctl
+#define usb_ioctl_op_t userial_ioctl_op_t
+
+#define BT_USB_DEVICE_INFO(cl, sc, pr) \
+ .bDevClass = (cl), \
+ .bDevSubClass = (sc), \
+ .bDevProtocol = (pr)
+
+typedef enum {
+ USERIAL_OP_INIT,
+ USERIAL_OP_RXFLOW_ON,
+ USERIAL_OP_RXFLOW_OFF,
+} userial_ioctl_op_t;
+
+/******************************************************************************
+** Type definitions
+******************************************************************************/
+
+struct bt_usb_device {
+ uint8_t bDevClass;
+ uint8_t bDevSubClass;
+ uint8_t bDevProtocol;
+};
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function usb_init
+**
+** Description Initializes the usb driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t usb_init(void);
+
+/*******************************************************************************
+**
+** Function usb_open
+**
+** Description Open Bluetooth device with the port ID
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t usb_open(uint8_t port);
+
+/*******************************************************************************
+**
+** Function usb_read
+**
+** Description Read data from the usb port
+**
+** Returns Number of bytes actually read from the usb port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t usb_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len);
+
+/*******************************************************************************
+**
+** Function usb_write
+**
+** Description Write data to the usb port
+**
+** Returns Number of bytes actually written to the usb port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t usb_write(uint16_t msg_id, uint8_t *p_data, uint16_t len);
+
+/*******************************************************************************
+**
+** Function usb_close
+**
+** Description Close the usb port
+**
+** Returns None
+**
+*******************************************************************************/
+void usb_close(void);
+
+/*******************************************************************************
+**
+** Function usb_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void usb_ioctl(usb_ioctl_op_t op, void *p_data);
+
+#endif /* USB_H */
+
diff --git a/hci/src/usb.c b/hci/src/usb.c
new file mode 100644
index 0000000..77d0ffa
--- /dev/null
+++ b/hci/src/usb.c
@@ -0,0 +1,1169 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ * Portions of file: Copyright (C) 2013, Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: usb.c
+ *
+ * Description: Contains open/read/write/close functions on usb
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_usb"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include "bt_hci_bdroid.h"
+#include "usb.h"
+#include "utils.h"
+#include "bt_vendor_lib.h"
+#include <sys/prctl.h>
+#include "libusb/libusb.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef USB_DBG
+#define USB_DBG FALSE
+#endif
+
+#if (USB_DBG == TRUE)
+#define USBDBG ALOGD
+#define USBERR ALOGE
+#else
+#define USBDBG
+#define USBERR
+#endif
+
+/*
+ * Bit masks : To check the transfer status
+ */
+#define XMITTED 1
+#define RX_DEAD 2
+#define RX_FAILED 4
+#define XMIT_FAILED 8
+
+/*
+ * Field index values
+ */
+#define EV_LEN_FIELD 1
+#define BLK_LEN_LO 2
+#define BLK_LEN_HI 3
+#define SCO_LEN_FIELD 2
+
+#define BT_CTRL_EP 0x0
+#define BT_INT_EP 0x81
+#define BT_BULK_IN 0x82
+#define BT_BULK_OUT 0x02
+#define BT_ISO_IN 0x83
+#define BT_ISO_OUT 0x03
+
+
+#define BT_HCI_MAX_FRAME_SIZE 1028
+
+#define BT_MAX_ISO_FRAMES 10
+
+#define H4_TYPE_COMMAND 1
+#define H4_TYPE_ACL_DATA 2
+#define H4_TYPE_SCO_DATA 3
+#define H4_TYPE_EVENT 4
+
+/*
+ * USB types, the second of three bRequestType fields
+ */
+#define USB_TYPE_REQ 32
+
+/* Preamble length for HCI Commands:
+** 2-bytes for opcode and 1 byte for length
+*/
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+/* Preamble length for HCI Events:
+** 1-byte for opcode and 1 byte for length
+*/
+#define HCI_EVT_PREAMBLE_SIZE 2
+
+/* Preamble length for SCO Data:
+** 2-byte for Handle and 1 byte for length
+*/
+#define HCI_SCO_PREAMBLE_SIZE 3
+
+/* Preamble length for ACL Data:
+** 2-byte for Handle and 2 byte for length
+*/
+#define HCI_ACL_PREAMBLE_SIZE 4
+#define RX_NEW_PKT 1
+#define RECEIVING_PKT 2
+
+#define CONTAINER_RX_HDR(ptr) \
+ (RX_HDR *)((char *)(ptr) - offsetof(RX_HDR, data))
+
+#define CONTAINER_ISO_HDR(ptr) \
+ (ISO_HDR *)((char *)(ptr) - offsetof(ISO_HDR, data))
+
+#define CONTAINER_CMD_HDR(ptr) \
+ (CMD_HDR *)((char *)(ptr) - offsetof(CMD_HDR, data))
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+/*
+The mutex is protecting send_rx_event and rxed_xfer.
+
+rxed_xfer : Accounting the packet received at recv_xfer_cb() and processed
+ at usb_read().
+send_rx_event : usb_read() signals recv_xfer_cb() to signal the
+ Host/Controller lib thread about new packet arrival.
+
+usb_read() belongs to Host/Controller lib thread.
+recv_xfer_cb() belongs to USB read thread
+*/
+
+typedef struct
+{
+ libusb_device_handle *handle;
+ pthread_t read_thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int rxed_xfer;
+ uint8_t send_rx_event;
+ BUFFER_Q rx_eventq;
+ BUFFER_Q rx_bulkq;
+ BUFFER_Q rx_isoq;
+ int16_t rx_pkt_len;
+ uint8_t rx_status;
+ int iso_frame_ndx;
+ struct libusb_transfer *failed_tx_xfer;
+} tUSB_CB;
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+/* The list will grow and will be updated from btusb.c in kernel */
+static struct bt_usb_device btusb_table[] = {
+ /* Generic Bluetooth USB device */
+ { BT_USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ { } /* Terminating entry */
+};
+
+typedef struct
+{
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ unsigned char data[0];
+} RX_HDR;
+
+struct iso_frames
+{
+ int actual_length;
+ int length;
+};
+
+typedef struct
+{
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ struct iso_frames frames[BT_MAX_ISO_FRAMES];
+ unsigned char data[0];
+} ISO_HDR;
+
+typedef struct
+{
+ uint8_t event;
+ struct libusb_control_setup setup;
+ unsigned char data[0];
+} CMD_HDR;
+
+static tUSB_CB usb;
+static int usb_xfer_status, usb_running;
+static int intr_pkt_size, iso_pkt_size, bulk_pkt_size;
+static int intr_pkt_size_wh, iso_pkt_size_wh, bulk_pkt_size_wh;
+static struct libusb_transfer *data_rx_xfer, *event_rx_xfer, *iso_rx_xfer,
+ *xmit_transfer;
+static int xmited_len;
+RX_HDR *p_rx_hdr = NULL;
+/******************************************************************************
+** Static functions
+******************************************************************************/
+static int is_usb_match_idtable (struct bt_usb_device *id, struct libusb_device_descriptor *desc)
+{
+ int ret = TRUE;
+
+ ret = ((id->bDevClass != libusb_le16_to_cpu(desc->bDeviceClass)) ? FALSE :
+ (id->bDevSubClass != libusb_le16_to_cpu(desc->bDeviceSubClass)) ? FALSE :
+ (id->bDevProtocol != libusb_le16_to_cpu(desc->bDeviceProtocol)) ? FALSE : TRUE);
+
+ return ret;
+}
+
+static int check_bt_usb_endpoints (struct bt_usb_device *id, struct libusb_config_descriptor *cfg_desc)
+{
+ const struct libusb_interface_descriptor *idesc;
+ const struct libusb_endpoint_descriptor *endpoint;
+ int i, num_altsetting;
+
+ endpoint = cfg_desc->interface[0].altsetting[0].endpoint;
+ for(i = 0; i < cfg_desc->interface[0].altsetting[0].bNumEndpoints; i++)
+ {
+ if(!(endpoint[i].bEndpointAddress == BT_CTRL_EP || \
+ endpoint[i].bEndpointAddress == BT_INT_EP || \
+ endpoint[i].bEndpointAddress == BT_BULK_IN || \
+ endpoint[i].bEndpointAddress == BT_BULK_OUT))
+ return FALSE;
+ }
+
+ num_altsetting = cfg_desc->interface[1].num_altsetting;
+ endpoint = cfg_desc->interface[1].altsetting[num_altsetting-1].endpoint;
+ for(i = 0; i < cfg_desc->interface[1].altsetting[num_altsetting-1]. \
+ bNumEndpoints; i++)
+ {
+ if(!(endpoint[i].bEndpointAddress == BT_ISO_IN || \
+ endpoint[i].bEndpointAddress == BT_ISO_OUT))
+ return FALSE;
+ }
+ for(i = 0; i < cfg_desc->interface[1]. \
+ altsetting[num_altsetting-1].bNumEndpoints; i++)
+ {
+ if(endpoint[i].bEndpointAddress == BT_ISO_IN)
+ {
+ iso_pkt_size = libusb_le16_to_cpu(endpoint[i].wMaxPacketSize);
+ USBDBG("iso pkt size is %d", iso_pkt_size);
+ iso_pkt_size_wh = iso_pkt_size * BT_MAX_ISO_FRAMES + \
+ sizeof(ISO_HDR);
+ USBDBG("iso pkt size wh %d", iso_pkt_size_wh);
+ }
+ }
+ return TRUE;
+}
+
+static int is_btusb_device (struct libusb_device *dev)
+{
+ struct bt_usb_device *id;
+ struct libusb_device_descriptor desc;
+ struct libusb_config_descriptor *cfg_desc;
+ int r, match, num_altsetting = 0;
+
+ r = libusb_get_device_descriptor(dev, &desc);
+ if (r < 0)
+ return FALSE;
+
+ match = 0;
+
+ for (id = btusb_table; id->bDevClass; id++)
+ {
+ if (is_usb_match_idtable (id, &desc) == TRUE)
+ {
+ match = 1;
+ break;
+ }
+ }
+
+ if (!match)
+ {
+ return FALSE;
+ }
+
+ r = libusb_get_config_descriptor(dev, 0, &cfg_desc);
+ if (r < 0)
+ {
+ USBERR("libusb_get_config_descriptor %x:%x failed ....%d\n", \
+ desc.idVendor, desc.idProduct, r);
+ return FALSE;
+ }
+
+ r = check_bt_usb_endpoints(id, cfg_desc);
+ libusb_free_config_descriptor(cfg_desc);
+
+ return r;
+}
+
+/*******************************************************************************
+**
+** Function libusb_open_bt_device
+**
+** Description Scan the system USB devices. If match is found on
+** btusb_table ensure that it is a bluetooth device by
+** checking Interface endpoint addresses.
+**
+** Returns NULL: termination
+** !NULL : pointer to the libusb_device_handle
+**
+*******************************************************************************/
+static libusb_device_handle *libusb_open_bt_device()
+{
+ struct libusb_device **devs;
+ struct libusb_device *found = NULL;
+ struct libusb_device *dev;
+ struct libusb_device_handle *handle = NULL;
+ int r, i;
+
+ if (libusb_get_device_list(NULL, &devs) < 0)
+ {
+ return NULL;
+ }
+ for (i = 0; (dev = devs[i]) != NULL; i++)
+ {
+ if (is_btusb_device (dev) == TRUE)
+ break;
+ }
+ if (dev)
+ {
+ r = libusb_open(dev, &handle);
+ if (r < 0)
+ {
+ ALOGE("found USB BT device failed to open .....\n");
+ return NULL;
+ }
+ }
+ else
+ {
+ ALOGE("No matching USB BT device found .....\n");
+ return NULL;
+ }
+
+ libusb_free_device_list(devs, 1);
+ r = libusb_claim_interface(handle, 0);
+ if (r < 0)
+ {
+ ALOGE("usb_claim_interface 0 error %d\n", r);
+ return NULL;
+ }
+
+ intr_pkt_size = libusb_get_max_packet_size(dev, BT_INT_EP);
+ USBDBG("Interrupt pkt size is %d", intr_pkt_size);
+ intr_pkt_size_wh = intr_pkt_size + sizeof(RX_HDR);
+
+ r = libusb_claim_interface(handle, 1);
+ if (r < 0)
+ {
+ ALOGE("usb_claim_interface 1 error %d\n", r);
+ }
+
+ return handle;
+}
+
+static void usb_rx_signal_event()
+{
+ pthread_mutex_lock(&usb.mutex);
+ usb.rxed_xfer++;
+ pthread_cond_signal(&usb.cond);
+ if (usb.send_rx_event == TRUE)
+ {
+ bthc_signal_event(HC_EVENT_RX);
+ usb.send_rx_event = FALSE;
+ }
+ pthread_mutex_unlock(&usb.mutex);
+}
+
+static void recv_xfer_cb(struct libusb_transfer *transfer)
+{
+ RX_HDR *p_rx = NULL;
+ ISO_HDR *p_iso = NULL;
+ int r, i, offset = 0, len = 0, skip = 0;
+ enum libusb_transfer_status status;
+
+ status = transfer->status;
+ if (status == LIBUSB_TRANSFER_COMPLETED)
+ {
+ switch (transfer->endpoint)
+ {
+ struct iso_frames *frames;
+ case BT_INT_EP:
+ if (transfer->actual_length == 0)
+ {
+ USBDBG("*****Rxed zero length packet from usb ....");
+ skip = 1;
+ break;
+ }
+ p_rx = CONTAINER_RX_HDR(transfer->buffer);
+ p_rx->event = H4_TYPE_EVENT;
+ p_rx->len = (uint16_t)transfer->actual_length;
+ utils_enqueue(&(usb.rx_eventq), p_rx);
+ p_rx = (RX_HDR *) bt_hc_cbacks->alloc(intr_pkt_size_wh);
+ transfer->buffer = p_rx->data;
+ transfer->length = intr_pkt_size;
+ break;
+
+ case BT_BULK_IN:
+ if (transfer->actual_length == 0)
+ {
+ USBDBG("*******Rxed zero length packet from usb ....");
+ skip = 1;
+ break;
+ }
+ p_rx = CONTAINER_RX_HDR(transfer->buffer);
+ p_rx->event = H4_TYPE_ACL_DATA;
+ p_rx->len = (uint16_t)transfer->actual_length;
+ utils_enqueue(&(usb.rx_bulkq), p_rx);
+ p_rx = (RX_HDR *) bt_hc_cbacks->alloc(bulk_pkt_size_wh);
+ transfer->buffer = p_rx->data;
+ transfer->length = bulk_pkt_size;
+ break;
+
+ case BT_ISO_IN:
+ if (transfer->actual_length == 0)
+ {
+ USBDBG("*******Rxed zero length packet from usb ....");
+ skip = 1;
+ break;
+ }
+ p_iso = CONTAINER_ISO_HDR(transfer->buffer);
+ frames = p_iso->frames;
+ memset(frames, 0, sizeof(struct iso_frames) * BT_MAX_ISO_FRAMES);
+ p_iso->event = H4_TYPE_SCO_DATA;
+ for(i = 0; i < transfer->num_iso_packets; i++, frames++)
+ {
+ frames->length = transfer->iso_packet_desc[i].length;
+ frames->actual_length = \
+ transfer->iso_packet_desc[i].actual_length;
+ len += frames->actual_length;
+ }
+ p_iso->len = (uint16_t)len;
+ utils_enqueue(&(usb.rx_isoq), p_iso);
+ p_iso = (ISO_HDR *) bt_hc_cbacks->alloc(iso_pkt_size_wh);
+ transfer->buffer = p_iso->data;
+ for(i = 0; i < BT_MAX_ISO_FRAMES; i++)
+ {
+ transfer->iso_packet_desc[i].length = iso_pkt_size;
+ }
+ break;
+
+ default:
+ USBERR("Unexpeted endpoint rx %d\n", transfer->endpoint);
+ return;
+ }
+ if (!skip)
+ usb_rx_signal_event();
+ }
+ else
+ {
+ USBERR("******Transfer to BT Device failed- %d *****", status);
+ usb_xfer_status |= RX_DEAD;
+ return;
+ }
+ r = libusb_submit_transfer(transfer);
+ if (r < 0)
+ {
+ if (transfer->endpoint == BT_ISO_IN)
+ {
+ p_rx = (RX_HDR *)CONTAINER_ISO_HDR(transfer->buffer);
+ }
+ else
+ {
+ p_rx = CONTAINER_RX_HDR(transfer->buffer);
+ }
+ bt_hc_cbacks->dealloc((TRANSAC)p_rx, (char *)(p_rx + 1));
+ transfer->buffer = NULL;
+ USBERR("libusb_submit_transfer : %d : %d : failed", \
+ transfer->endpoint, transfer->status);
+ usb_xfer_status |= RX_FAILED;
+ }
+}
+
+void handle_usb_events ()
+{
+ RX_HDR *rx_buf;
+ ISO_HDR *iso_buf;
+ int r, i, iso_xfer;
+ struct libusb_transfer *transfer;
+ struct timeval timeout = { 1, 0 };
+
+ usb_xfer_status &= ~RX_DEAD;
+ while (!(usb_xfer_status & RX_DEAD))
+ {
+ // This polling introduces two problems:
+ // 1) /1s device wakeups when BT is on
+ // 2) ~0.5s response to user's shutdown request
+ libusb_handle_events_timeout(0, &timeout);
+ transfer = NULL;
+ iso_xfer = 0;
+ if (usb_xfer_status & RX_FAILED)
+ {
+ if (data_rx_xfer->buffer == NULL)
+ {
+ transfer = data_rx_xfer;
+ rx_buf = (RX_HDR *) bt_hc_cbacks->alloc(bulk_pkt_size_wh);
+ if (rx_buf == NULL)
+ {
+ USBERR("%s : Allocation failed", __FUNCTION__);
+ transfer = NULL;
+ }
+ else
+ {
+ transfer->buffer = rx_buf->data;
+ transfer->length = bulk_pkt_size;
+ }
+ }
+ else if (event_rx_xfer->buffer == NULL)
+ {
+ transfer = event_rx_xfer;
+ rx_buf = (RX_HDR *) bt_hc_cbacks->alloc(intr_pkt_size_wh);
+ if (rx_buf == NULL)
+ {
+ USBERR("%s : Allocation failed", __FUNCTION__);
+ transfer = NULL;
+ }
+ else
+ {
+ transfer->buffer = rx_buf->data;
+ transfer->length = intr_pkt_size;
+ }
+ }
+ else if (iso_rx_xfer->buffer == NULL)
+ {
+ transfer = iso_rx_xfer;
+ iso_buf = (ISO_HDR *) bt_hc_cbacks->alloc(iso_pkt_size_wh);
+ if (iso_buf == NULL)
+ {
+ USBERR("%s : Allocation failed", __FUNCTION__);
+ transfer = NULL;
+ }
+ else
+ {
+ transfer->buffer = iso_buf->data;
+ transfer->length = BT_MAX_ISO_FRAMES * iso_pkt_size;
+ for(i = 0; i < transfer->num_iso_packets; i++)
+ {
+ transfer->iso_packet_desc[i].length = iso_pkt_size;
+ }
+ iso_xfer = 1;
+ }
+ }
+ if (transfer != NULL)
+ {
+ usb_xfer_status &= ~(RX_FAILED);
+ r = libusb_submit_transfer(transfer);
+ if (r < 0)
+ {
+ USBERR("libusb_submit_transfer : data_rx_xfer failed");
+ if (iso_xfer)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) iso_buf, \
+ (char *)(iso_buf + 1));
+ }
+ else
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) rx_buf, \
+ (char *)(rx_buf + 1));
+ }
+ transfer->buffer = NULL;
+ }
+ }
+ }
+ else if (usb_xfer_status & XMIT_FAILED)
+ {
+ transfer = usb.failed_tx_xfer;
+ USBDBG("Retransmitting xmit packet %d", \
+ *(transfer->buffer - 1));
+ xmited_len = transfer->length;
+ usb_xfer_status &= ~(XMIT_FAILED);
+ if (libusb_submit_transfer(transfer) < 0)
+ {
+ USBERR("libusb_submit_transfer : %d : failed", \
+ *(transfer->buffer - 1));
+ }
+ }
+ }
+ usb_running = 0;
+}
+
+/*******************************************************************************
+**
+** Function usb_read_thread
+**
+** Description
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *usb_read_thread(void *arg)
+{
+ RX_HDR *rx_buf;
+ ISO_HDR *iso_buf;
+ int size, size_wh, r, i, iso_xfer;
+ struct libusb_transfer *transfer;
+ unsigned char *buf;
+
+ USBDBG("Entering usb_read_thread()");
+ prctl(PR_SET_NAME, (unsigned long)"usb_read", 0, 0, 0);
+
+
+ rx_buf = (RX_HDR *) bt_hc_cbacks->alloc(bulk_pkt_size_wh);
+ buf = rx_buf->data;
+ libusb_fill_bulk_transfer(data_rx_xfer, usb.handle, BT_BULK_IN, \
+ buf, bulk_pkt_size, recv_xfer_cb, NULL, 0);
+ r = libusb_submit_transfer(data_rx_xfer);
+ if (r < 0)
+ {
+ USBERR("libusb_submit_transfer : data_rx_xfer : failed");
+ goto out;
+ }
+
+ rx_buf = (RX_HDR *) bt_hc_cbacks->alloc(intr_pkt_size_wh);
+ buf = rx_buf->data;
+ libusb_fill_interrupt_transfer(event_rx_xfer, usb.handle, BT_INT_EP, \
+ buf, intr_pkt_size, recv_xfer_cb, NULL, 0);
+ r = libusb_submit_transfer(event_rx_xfer);
+ if (r < 0)
+ {
+ USBERR("libusb_submit_transfer : event_rx_xfer : failed");
+ goto out;
+ }
+
+ iso_buf = (ISO_HDR *) bt_hc_cbacks->alloc(iso_pkt_size_wh);
+ buf = iso_buf->data;
+ libusb_fill_iso_transfer(iso_rx_xfer, usb.handle, BT_ISO_IN, buf, \
+ iso_pkt_size * BT_MAX_ISO_FRAMES, BT_MAX_ISO_FRAMES, recv_xfer_cb, \
+ NULL, 0);
+ libusb_set_iso_packet_lengths (iso_rx_xfer, iso_pkt_size);
+
+ usb_running = 1;
+ handle_usb_events();
+out:
+ USBDBG("Leaving usb_read_thread()");
+ if (data_rx_xfer != NULL)
+ {
+ rx_buf = CONTAINER_RX_HDR(data_rx_xfer->buffer);
+ bt_hc_cbacks->dealloc((TRANSAC) rx_buf, (char *)(rx_buf+1));
+ libusb_free_transfer(data_rx_xfer);
+ }
+ if (event_rx_xfer != NULL)
+ {
+ rx_buf = CONTAINER_RX_HDR(event_rx_xfer->buffer);
+ bt_hc_cbacks->dealloc((TRANSAC) rx_buf, (char *)(rx_buf+1));
+ libusb_free_transfer(event_rx_xfer);
+ }
+ if(iso_rx_xfer != NULL)
+ {
+ iso_buf = CONTAINER_ISO_HDR(iso_rx_xfer->buffer);
+ bt_hc_cbacks->dealloc((TRANSAC) iso_buf, (char *)(iso_buf+1));
+ libusb_free_transfer(iso_rx_xfer);
+ }
+
+ pthread_exit(NULL);
+
+ return NULL;
+}
+
+
+/*****************************************************************************
+** USB API Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function usb_init
+**
+** Description Initializes the serial driver for usb
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t usb_init(void)
+{
+ USBDBG("usb_init");
+ memset(&usb, 0, sizeof(tUSB_CB));
+ usb.handle = NULL;
+ utils_queue_init(&(usb.rx_eventq));
+ utils_queue_init(&(usb.rx_bulkq));
+ utils_queue_init(&(usb.rx_isoq));
+ pthread_mutex_init(&usb.mutex, NULL);
+ pthread_cond_init(&usb.cond, NULL);
+ data_rx_xfer = event_rx_xfer = iso_rx_xfer = NULL;
+ usb.send_rx_event = TRUE;
+ usb.rx_status = RX_NEW_PKT;
+
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function usb_open
+**
+** Description Open Bluetooth device with the port ID
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t usb_open(uint8_t port)
+{
+
+ USBDBG("usb_open(port:%d)", port);
+
+ if (usb_running)
+ {
+ /* Userial is open; close it first */
+ usb_close();
+ utils_delay(50);
+ }
+ if (libusb_init(NULL) < 0)
+ {
+ ALOGE("libusb_init : failed");
+ return FALSE;
+ }
+
+ usb.handle = libusb_open_bt_device();
+ bulk_pkt_size_wh = BT_HCI_MAX_FRAME_SIZE + sizeof(RX_HDR);
+ bulk_pkt_size = BT_HCI_MAX_FRAME_SIZE;
+ if (usb.handle == NULL)
+ {
+ ALOGE("usb_open: HCI USB failed to open");
+ goto out;
+ }
+ data_rx_xfer = libusb_alloc_transfer(0);
+ if (!data_rx_xfer)
+ {
+ ALOGE("Failed alloc data_rx_xfer");
+ goto out;
+ }
+
+ event_rx_xfer = libusb_alloc_transfer(0);
+ if (!event_rx_xfer)
+ {
+ ALOGE("Failed alloc event_rx_xfer");
+ goto out;
+ }
+
+
+ iso_rx_xfer = libusb_alloc_transfer(BT_MAX_ISO_FRAMES);
+ if (!iso_rx_xfer)
+ {
+ ALOGE("Failed alloc iso_rx_xfer");
+ goto out;
+ }
+
+
+
+ USBDBG("usb_read_thread is created ....");
+ if (pthread_create(&(usb.read_thread), NULL, \
+ usb_read_thread, NULL) != 0 )
+ {
+ USBERR("pthread_create failed!");
+ goto out;
+ }
+
+ return TRUE;
+out :
+ if (usb.handle != NULL)
+ {
+ if (data_rx_xfer != NULL)
+ libusb_free_transfer(data_rx_xfer);
+ if (event_rx_xfer != NULL)
+ libusb_free_transfer(event_rx_xfer);
+ if (iso_rx_xfer != NULL)
+ libusb_free_transfer(iso_rx_xfer);
+ libusb_release_interface(usb.handle, 1);
+ libusb_release_interface(usb.handle, 0);
+ libusb_close(usb.handle);
+ libusb_exit(NULL);
+ }
+ return FALSE;
+}
+
+
+/*******************************************************************************
+**
+** Function usb_read
+**
+** Description Read data from the usb port
+**
+** Returns Number of bytes actually read from the usb port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t usb_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len)
+{
+ uint16_t total_len = 0;
+ uint16_t copy_len = 0;
+ uint8_t *p_data = NULL, iso_idx;
+ int iso_frame_len = 0;
+ int different_xfer = 0;
+ struct iso_frames *frames;
+ int pkt_rxing = 0;
+ int rem_len = 0;
+ ISO_HDR *p_iso_hdr;
+
+ if (!usb_running)
+ return 0;
+ while (total_len < len)
+ {
+ if (p_rx_hdr == NULL)
+ {
+ pthread_mutex_lock(&usb.mutex);
+ if (usb.rxed_xfer < 0)
+ {
+ USBERR("Rx thread and usb_read out of sync %d", \
+ usb.rxed_xfer);
+ usb.rxed_xfer = 0;
+ }
+ if (usb.rxed_xfer == 0 && usb.rx_status == RX_NEW_PKT)
+ {
+ usb.send_rx_event = TRUE;
+ pthread_mutex_unlock(&usb.mutex);
+ USBDBG("usb_read nothing to rx....");
+ return 0;
+
+ }
+ while (usb.rxed_xfer == 0)
+ {
+ pthread_cond_wait(&usb.cond, &usb.mutex);
+ }
+ usb.rxed_xfer--;
+ pthread_mutex_unlock(&usb.mutex);
+
+ if (usb.rx_status == RX_NEW_PKT)
+ {
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_eventq));
+ if (p_rx_hdr == NULL)
+ {
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_isoq));
+ }
+ if (p_rx_hdr == NULL)
+ {
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_bulkq));
+ }
+ if (p_rx_hdr == NULL)
+ {
+ USBERR("rxed_xfer is %d but no packet found", usb.rxed_xfer);
+ return 0;
+ }
+ switch (p_rx_hdr->event)
+ {
+ case H4_TYPE_EVENT:
+ p_data = p_rx_hdr->data;
+ p_rx_hdr->offset = 0;
+ usb.rx_pkt_len = p_data[EV_LEN_FIELD] + \
+ HCI_EVT_PREAMBLE_SIZE;
+ usb.rx_status = RECEIVING_PKT;
+ *p_buffer = p_rx_hdr->event;
+ total_len += 1;
+ p_buffer++;
+ break;
+
+
+ case H4_TYPE_SCO_DATA:
+ p_iso_hdr = (ISO_HDR *)p_rx_hdr;
+ p_iso_hdr->offset = 0;
+ usb.rx_pkt_len = 0;
+ usb.rx_status = RECEIVING_PKT;
+ usb.iso_frame_ndx = 0;
+ pthread_mutex_lock(&usb.mutex);
+ usb.rxed_xfer++;
+ pthread_mutex_unlock(&usb.mutex);
+ break;
+
+
+ case H4_TYPE_ACL_DATA:
+ p_data = p_rx_hdr->data;
+ p_rx_hdr->offset = 0;
+ usb.rx_pkt_len = ((uint16_t)p_data[BLK_LEN_LO] | \
+ (uint16_t)p_data[BLK_LEN_HI] << 8) + \
+ HCI_ACL_PREAMBLE_SIZE;
+ usb.rx_status = RECEIVING_PKT;
+ *p_buffer = p_rx_hdr->event;
+ total_len += 1;
+ p_buffer++;
+ break;
+ }
+ USBDBG("Received packet from usb of len %d of type %x", \
+ p_rx_hdr->len, p_rx_hdr->event);
+ }
+ else // rx_status == RECIVING_PKT
+ {
+ switch (pkt_rxing)
+ {
+ case H4_TYPE_EVENT:
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_eventq));
+ break;
+
+ case H4_TYPE_SCO_DATA:
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_isoq));
+ break;
+
+ case H4_TYPE_ACL_DATA:
+ p_rx_hdr = (RX_HDR *)utils_dequeue(&(usb.rx_bulkq));
+ break;
+ }
+ if (p_rx_hdr == NULL)
+ {
+ USBDBG("Rxed packet from different end_point.");
+ different_xfer++;
+ }
+ else
+ {
+ p_rx_hdr->offset = 0;
+ USBDBG("Received packet from usb of len %d of type %x",
+ p_rx_hdr->len, p_rx_hdr->event);
+ }
+ }
+ }
+ else //if (p_rx_hdr != NULL)
+ {
+ if (p_rx_hdr->event == H4_TYPE_SCO_DATA)
+ {
+ p_iso_hdr = (ISO_HDR *)p_rx_hdr;
+ frames = p_iso_hdr->frames;
+ p_data = p_iso_hdr->data;
+ frames += usb.iso_frame_ndx;
+ if (usb.rx_pkt_len == 0) // Start of new micro frame
+ {
+ if (frames->actual_length == 0)
+ {
+ /* Previous frame has been processed */
+ usb.iso_frame_ndx++;
+ p_iso_hdr->offset = usb.iso_frame_ndx * iso_pkt_size;
+ }
+ *p_buffer = p_iso_hdr->event;
+ total_len += 1;
+ usb.rx_pkt_len = (uint16_t)p_data[p_iso_hdr->offset + \
+ SCO_LEN_FIELD] + HCI_SCO_PREAMBLE_SIZE;
+ p_buffer++;
+ usb.rx_status = RECEIVING_PKT;
+ }
+ else
+ {
+ frames->actual_length -= len;
+ }
+ if (total_len == len)
+ break;
+ pkt_rxing = p_iso_hdr->event;
+
+ if((p_iso_hdr->len) <= (len - total_len))
+ copy_len = p_iso_hdr->len;
+ else
+ copy_len = (len - total_len);
+
+ p_iso_hdr->offset += copy_len;
+ p_iso_hdr->len -= copy_len;
+ rem_len = p_iso_hdr->len;
+ }
+ else
+ {
+ p_data = p_rx_hdr->data + p_rx_hdr->offset;
+ pkt_rxing = p_rx_hdr->event;
+
+ if((p_rx_hdr->len) <= (len - total_len))
+ copy_len = p_rx_hdr->len;
+ else
+ copy_len = (len - total_len);
+
+ p_rx_hdr->offset += copy_len;
+ p_rx_hdr->len -= copy_len;
+ rem_len = p_rx_hdr->len;
+ }
+
+ memcpy((p_buffer + total_len), p_data, copy_len);
+ total_len += copy_len;
+
+ if (rem_len == 0)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_rx_hdr, (char *)(p_rx_hdr+1));
+ p_rx_hdr = NULL;
+ }
+ usb.rx_pkt_len -= copy_len;
+ if (usb.rx_pkt_len == 0)
+ {
+ usb.rx_status = RX_NEW_PKT;
+ break;
+ }
+ if (usb.rx_pkt_len < 0)
+ {
+ USBERR("pkt len expected %d rxed len of %d", len, total_len);
+ usb.rx_status = RX_NEW_PKT;
+ break;
+ }
+ }
+ }
+ if (different_xfer)
+ {
+ pthread_mutex_lock(&usb.mutex);
+ usb.rxed_xfer += different_xfer;
+ pthread_mutex_unlock(&usb.mutex);
+ }
+
+ return total_len;
+}
+/*******************************************************************************
+**
+** Function xmit_xfer_cb
+**
+** Description Callback function after xmission
+**
+** Returns None
+**
+**
+*******************************************************************************/
+static void xmit_xfer_cb(struct libusb_transfer *transfer)
+{
+ enum libusb_transfer_status status = transfer->status;
+ static int xmit_acked;
+
+ if(transfer->status != LIBUSB_TRANSFER_COMPLETED)
+ {
+ USBERR("xfer did not succeeded .....%d", transfer->status);
+ usb_xfer_status |= XMIT_FAILED;
+ usb.failed_tx_xfer = transfer;
+ xmited_len = 0;
+ } else
+ {
+ xmited_len = transfer->actual_length+1;
+ libusb_free_transfer(transfer);
+ usb_xfer_status |= XMITTED;
+ USBDBG("Xfer Succeded : count %d", ++xmit_acked);
+ }
+}
+/*******************************************************************************
+**
+** Function usb_write
+**
+** Description Write data to the usb port
+**
+** Returns Number of bytes actually written to the usb port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t usb_write(uint16_t msg_id, uint8_t *p_data, uint16_t len)
+{
+ struct timeval tv = {60, 0};
+ char buffer[512], pkt_type;;
+ int x, i;
+ CMD_HDR *cmd_hdr;
+ static int xmit_count;
+
+ if(!(xmit_transfer = libusb_alloc_transfer(0)))
+ {
+ USBERR( "libusb_alloc_tranfer() failed");
+ return 0;
+ }
+
+ x = (len > (sizeof(buffer)-1)/2)? ((sizeof(buffer)-1)/2) : len;
+
+ pkt_type = *p_data;
+ switch(pkt_type)
+ {
+ case H4_TYPE_COMMAND:
+ /* Make use of BT_HDR space to populate setup */
+ cmd_hdr = CONTAINER_CMD_HDR(p_data + 1);
+ cmd_hdr->setup.bmRequestType = USB_TYPE_REQ;
+ cmd_hdr->setup.wLength = len - 1;
+ cmd_hdr->setup.wIndex = 0;
+ cmd_hdr->setup.wValue = 0;
+ cmd_hdr->setup.bRequest = 0;
+ cmd_hdr->event = H4_TYPE_COMMAND;
+ libusb_fill_control_transfer(xmit_transfer, usb.handle,
+ (uint8_t *)&cmd_hdr->setup, xmit_xfer_cb, NULL, 0);
+ break;
+
+ case H4_TYPE_ACL_DATA:
+ libusb_fill_bulk_transfer(xmit_transfer, usb.handle,
+ BT_BULK_OUT, (p_data+1), (len-1), xmit_xfer_cb, NULL, 0);
+ break;
+
+ case H4_TYPE_SCO_DATA:
+ libusb_fill_iso_transfer(xmit_transfer, usb.handle, \
+ BT_ISO_OUT, (p_data+1), (len-1), BT_MAX_ISO_FRAMES, \
+ xmit_xfer_cb, NULL, 0);
+ break;
+
+ default:
+ USBERR("Unknown packet type to transmit %x", *p_data);
+ return 0;
+ }
+
+ if (libusb_submit_transfer(xmit_transfer) < 0)
+ {
+ USBERR("libusb_submit_transfer : %d : failed", *p_data);
+ return 0;
+ }
+ xmited_len = len;
+ usb_xfer_status &= ~(XMITTED);
+
+ while (!(usb_xfer_status & XMITTED))
+ libusb_handle_events_timeout(0, &tv);
+
+ return (xmited_len);
+}
+
+/*******************************************************************************
+**
+** Function usb_close
+**
+** Description Close the serial port
+**
+** Returns None
+**
+*******************************************************************************/
+void usb_close(void)
+{
+ int result;
+ TRANSAC p_buf;
+
+ USBDBG("usb_close \n");
+
+ usb_xfer_status |= RX_DEAD;
+
+ if ((result=pthread_join(usb.read_thread, NULL)) < 0)
+ ALOGE( "pthread_join() FAILED result:%d \n", result);
+
+ if (usb.handle) {
+ libusb_release_interface(usb.handle, 1);
+ libusb_release_interface(usb.handle, 0);
+ libusb_close(usb.handle);
+ }
+ usb.handle = NULL;
+ libusb_exit(NULL);
+ if (bt_hc_cbacks)
+ {
+ while ((p_buf = utils_dequeue (&(usb.rx_eventq))) != NULL)
+ {
+ bt_hc_cbacks->dealloc(p_buf, (char *) ((RX_HDR *)p_buf+1));
+ }
+ while ((p_buf = utils_dequeue (&(usb.rx_isoq))) != NULL)
+ {
+ bt_hc_cbacks->dealloc(p_buf, (char *) ((RX_HDR *)p_buf+1));
+ }
+ while ((p_buf = utils_dequeue (&(usb.rx_bulkq))) != NULL)
+ {
+ bt_hc_cbacks->dealloc(p_buf, (char *) ((RX_HDR *)p_buf+1));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function usb_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void usb_ioctl(usb_ioctl_op_t op, void *p_data)
+{
+ return;
+}
+