summaryrefslogtreecommitdiff
authorJiamin Miao <jiamin.miao@amlogic.com>2015-04-08 02:08:04 (GMT)
committer tao.dong <tao.dong@amlogic.com>2015-11-11 04:51:43 (GMT)
commit10840d5dbd967c086fa1bfbc82fa4cb0840d4893 (patch)
tree9be77945963dd1c999e0a69f9ab7e2b037211c84
parent352745e75d3ab4887ee0e3fa2ddb2f5312b7ca20 (diff)
downloadbtusb-10840d5dbd967c086fa1bfbc82fa4cb0840d4893.zip
btusb-10840d5dbd967c086fa1bfbc82fa4cb0840d4893.tar.gz
btusb-10840d5dbd967c086fa1bfbc82fa4cb0840d4893.tar.bz2
PD#103871:bcm20705 usb bt driver
Diffstat
-rwxr-xr-xMakefile128
-rwxr-xr-xRelease_btusb.txt26
-rwxr-xr-xinc/bt_target.h0
-rwxr-xr-xinc/bt_types.h78
-rwxr-xr-xinc/btusb.h367
-rwxr-xr-xinc/btusb_cq.h118
-rwxr-xr-xinc/btusb_lite.h203
-rwxr-xr-xinc/btusb_lite_av.h135
-rwxr-xr-xinc/btusb_lite_avdt.h148
-rwxr-xr-xinc/btusb_lite_hci.h71
-rwxr-xr-xinc/btusb_lite_l2c.h105
-rwxr-xr-xinc/btusb_proc.h49
-rwxr-xr-xinc/btusbext.h130
-rwxr-xr-xinc/data_types.h79
-rwxr-xr-xinc/gki.h190
-rwxr-xr-xinc/gki_int.h197
-rwxr-xr-xinc/hcidefs.h1819
-rwxr-xr-xinc/target.h121
-rwxr-xr-xsrc/btusb.c1596
-rwxr-xr-xsrc/btusb_dev.c2001
-rwxr-xr-xsrc/btusb_isoc.c292
-rwxr-xr-xsrc/btusb_lite.c1785
-rwxr-xr-xsrc/btusb_lite_av.c1365
-rwxr-xr-xsrc/btusb_lite_avdt.c426
-rwxr-xr-xsrc/btusb_lite_hci.c440
-rwxr-xr-xsrc/btusb_lite_l2c.c278
-rwxr-xr-xsrc/btusb_proc.c763
-rwxr-xr-xsrc/btusb_version.c30
-rwxr-xr-xsrc/gki/gki_buffer.c1291
-rwxr-xr-xsrc/gki/gki_klinux.c271
30 files changed, 14502 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100755
index 0000000..dd522eb
--- a/dev/null
+++ b/Makefile
@@ -0,0 +1,128 @@
+
+# Specify Include folders
+EXTRA_CFLAGS += -I$(SUBDIRS)
+EXTRA_CFLAGS += -I$(SUBDIRS)/inc
+EXTRA_CFLAGS += -I$(SUBDIRS)/src
+EXTRA_CFLAGS += -I$(SUBDIRS)/src/gki
+EXTRA_CFLAGS += -DEXPORT_SYMTAB
+
+LITE ?= FALSE
+ifeq ($(strip $(LITE)),TRUE)
+EXTRA_CFLAGS += -DBUILDCFG
+EXTRA_CFLAGS += -DBTUSB_LITE
+EXTRA_CFLAGS += -I$(SUBDIRS)/../btpcm
+EXTRA_CFLAGS += -I$(SUBDIRS)/../btsbc
+COMPONENTS_PATH := $(SUBDIRS)/../../../../../Components
+EXTRA_CFLAGS += -I$(COMPONENTS_PATH)/bta/include
+EXTRA_CFLAGS += -I$(COMPONENTS_PATH)/stack/include
+EXTRA_CFLAGS += -I$(COMPONENTS_PATH)/hcis
+endif
+
+SEC ?= FALSE
+ifeq ($(strip $(SEC)),TRUE)
+EXTRA_CFLAGS += -DBTUSB_LITE_SEC
+EXTRA_CFLAGS += -I$(SUBDIRS)/../btsec
+endif
+
+EXTRA_CFLAGS += -DEXPORT_SYMTAB
+
+# BTUSB_VID and BTUSB_PID can be defined to support a single BT controller type
+# The following definitions are examples for 20702A1 chip
+#EXTRA_CFLAGS += -DBTUSB_VID=0x0A5C
+#EXTRA_CFLAGS += -DBTUSB_PID=0x22BE
+
+usbobjs := \
+ src/btusb.o \
+ src/btusb_dev.o \
+ src/btusb_isoc.o \
+ src/btusb_version.o
+
+ifeq ($(CONFIG_PROC_FS),y)
+usbobjs += \
+ src/btusb_proc.o
+endif
+
+ifeq ($(strip $(LITE)),TRUE)
+liteobjs := src/btusb_lite.o \
+ src/btusb_lite_av.o \
+ src/btusb_lite_avdt.o \
+ src/btusb_lite_l2c.o \
+ src/btusb_lite_hci.o
+endif
+
+gkiobjs := \
+ src/gki/gki_buffer.o \
+ src/gki/gki_klinux.o
+
+obj-m += btusb.o
+btusb-objs := $(usbobjs) $(gkiobjs) $(liteobjs)
+
+# specify Kernel build location (can be overriden at command line)
+#KDIR ?= /lib/modules/$(shell uname -r)/build
+KDIR ?= /host/android/tiny4412/tiny_4412/linux-3.5
+PWD := $(shell pwd)
+
+default:
+ifeq ($(strip $(LITE)),TRUE)
+ cat ../btpcm/Module.symvers > ./Module.symvers
+ cat ../btsbc/Module.symvers >> ./Module.symvers
+ifeq ($(strip $(SEC)),TRUE)
+ cat ../btsec/Module.symvers >> ./Module.symvers
+endif
+endif
+ $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
+
+install:
+ cp -v btusb.ko /lib/modules/$(uname -r)/kernel/drivers/brcm/btusb.ko
+
+clean:
+ rm -rf *.o *~ core .depend .*.cmd *.ko *.mod.c .tmp_versions
+ rm -f Module.markers
+ rm -f Module.symvers
+ rm -f modules.order
+ rm -f ./src/*.o
+ rm -f ./src/.*.o.cmd
+ rm -f ./src/gki/*.o
+ rm -f ./src/gki/.*.o.cmd
+
+# define the location of the Linux stable repository
+PROJECTS_DIR ?= ~/projects
+LINUX_STABLE = $(PROJECTS_DIR)/linux-stable
+
+# rule to run a regression on a specific file
+v2.% v3.%:
+ @echo Running regression on: $@
+ # clean the previous version before switching version
+ cd $(LINUX_STABLE); make mrproper >/dev/null
+ # switch version
+ cd $(LINUX_STABLE); git checkout $@ >/dev/null
+ # prepare to build modules
+ cd $(LINUX_STABLE); make defconfig >/dev/null
+ cd $(LINUX_STABLE); make modules_prepare >/dev/null
+ make KDIR=$(LINUX_STABLE)
+
+regression-install:
+ cd $(PROJECTS_DIR)
+ git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
+
+regression-update:
+ cd $(LINUX_STABLE)
+ git pull
+
+regression: v2.6.28 v2.6.35 v2.6.36 v3.2.1 v3.12.1
+ @echo Regression completed successfully!
+
+.PHONY: help regression regression-update regression-install clean install
+
+help:
+ @echo "BTUSB module configurations and targets:"
+ @echo " LITE=FALSE : No StackLite (Default)"
+ @echo " LITE=TRUE : StackLite compiled"
+ @echo " SEC=FALSE : No SEC Encoder Support(default)"
+ @echo " SEC=TRUE : SEC Encoder Support. Requires StackLite"
+ @echo " clean : remove the build output files"
+ @echo " install : copy the driver in the current platform modules list"
+ @echo " regression : run a regression on several Linux versions"
+
+
+
diff --git a/Release_btusb.txt b/Release_btusb.txt
new file mode 100755
index 0000000..f6228fe
--- a/dev/null
+++ b/Release_btusb.txt
@@ -0,0 +1,26 @@
+To compile the Bluetooth USB Driver (BTUSB) you have to:
+> cd /3rdparty/embedded/brcm/linux/btusb
+> make
+
+The Makefile may need to be adapted to the target:
+KDIR := /lib/modules/$(shell uname -r)/build => For local kernel (currently running)
+KDIR := /opt/brcm/linux => For different kernel, it should point to the appropriate kernel version
+
+By default btusb supports the most Broadcom's BT controller types.
+To restrict the support to a single VID/PID (USB identifier of the BT controller type), the BTUSB_VID and BTUSB_PID can be defined.
+For 20702 the values to use are:
+EXTRA_CFLAGS += -DBTUSB_VID=0x0A5C
+EXTRA_CFLAGS += -DBTUSB_PID=0x22BE
+
+To install the btusb.ko module, you may have to create a node in /dev:
+mknod btusb0 c 180 194
+
+Furthermore, BlueZ must be uninstalled to avoid driver conflicts.
+
+See BSA Software user guide for further information.
+
+BTUSB Compile Options for Lite Stack Support:
+> make LITE=FALSE => No StackLite (Default)"
+> make LITE=TRUE => StackLite compiled"
+> make SEC=FALSE => No SEC Encoder Support(default)"
+> make SEC=TRUE => SEC Encoder Support (Requires StackLite)
diff --git a/inc/bt_target.h b/inc/bt_target.h
new file mode 100755
index 0000000..e69de29
--- a/dev/null
+++ b/inc/bt_target.h
diff --git a/inc/bt_types.h b/inc/bt_types.h
new file mode 100755
index 0000000..f214d54
--- a/dev/null
+++ b/inc/bt_types.h
@@ -0,0 +1,78 @@
+/*
+*
+* bt_types.h
+*
+*
+*
+* Copyright (C) 2011-2013 Broadcom Corporation.
+*
+*
+*
+* This software is licensed under the terms of the GNU General Public License,
+* version 2, as published by the Free Software Foundation (the "GPL"), and may
+* be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+*
+*
+* A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+* or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA
+*
+*
+*/
+
+#ifndef BT_TYPES_H
+#define BT_TYPES_H
+
+#include "data_types.h"
+
+/* READ WELL !!
+**
+** This section defines global events. These are events that cross layers.
+** Any event that passes between layers MUST be one of these events. Tasks
+** can use their own events internally, but a FUNDAMENTAL design issue is
+** that global events MUST be one of these events defined below.
+**
+** The convention used is the the event name contains the layer that the
+** event is going to.
+*/
+#define BT_EVT_TO_BTU_HCI_EVT 0x1000 /* HCI Event */
+
+#define BT_EVT_TO_BTU_HCI_SCO 0x1200 /* SCO Data from HCI */
+
+#define BT_EVT_TO_LM_HCI_CMD 0x2000 /* HCI Command */
+#define BT_EVT_TO_LM_HCI_ACL 0x2100 /* HCI ACL Data */
+#define BT_EVT_TO_LM_DIAG 0x2c00 /* LM Diagnostics commands */
+
+
+#define BT_EVT_BTU_IPC_EVT 0x9000
+#define BT_EVT_BTU_IPC_LOGMSG_EVT (0x0000 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_ACL_EVT (0x0001 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTU_EVT (0x0002 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_EVT (0x0003 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_L2C_MSG_EVT (0x0004 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTM_EVT (0x0005 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_AVDT_EVT (0x0006 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_SLIP_EVT (0x0007 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_MGMT_EVT (0x0008 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BTTRC_EVT (0x0009 | BT_EVT_BTU_IPC_EVT)
+#define BT_EVT_BTU_IPC_BURST_EVT (0x000A | BT_EVT_BTU_IPC_EVT)
+
+
+/* Define the header of each buffer used in the Bluetooth stack.
+*/
+typedef struct
+{
+ UINT16 event;
+ UINT16 len;
+ UINT16 offset;
+ UINT16 layer_specific;
+} BT_HDR;
+
+#define BT_HDR_SIZE (sizeof (BT_HDR))
+
+
+#endif
diff --git a/inc/btusb.h b/inc/btusb.h
new file mode 100755
index 0000000..b9995db
--- a/dev/null
+++ b/inc/btusb.h
@@ -0,0 +1,367 @@
+/*
+ *
+ * btusb.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef BTUSB_H
+#define BTUSB_H
+
+#include <linux/version.h>
+#include <linux/usb.h>
+#include <linux/tty.h>
+#include <linux/time.h>
+
+#include "bt_types.h"
+#include "btusb_cq.h"
+#include "gki_int.h"
+#include "btusbext.h"
+
+#ifdef BTUSB_LITE
+#include "btusb_lite.h"
+#endif
+
+extern const char bsa_version_string[];
+
+/* Linux kernel compatibility abstraction */
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 34)
+#define BTUSB_USHRT_MAX USHORT_MAX
+#else
+#define BTUSB_USHRT_MAX USHRT_MAX
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
+#define BTUSB_PDE_DATA(inode) PDE(inode)->data
+#define BTUSB_PDE_PARENT_DATA(inode) PDE(inode)->parent->data
+#else
+#define BTUSB_PDE_DATA(inode) PDE_DATA(inode)
+#define BTUSB_PDE_PARENT_DATA(inode) proc_get_parent_data(inode)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
+#define BTUSB_BUFFER_ALLOC usb_buffer_alloc
+#define BTUSB_BUFFER_FREE usb_buffer_free
+#else
+#define BTUSB_BUFFER_ALLOC usb_alloc_coherent
+#define BTUSB_BUFFER_FREE usb_free_coherent
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
+#define BTUSB_EP_TYPE(ep) (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+#define BTUSB_EP_DIR_IN(ep) ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+#define BTUSB_EP_DIR_OUT(ep) ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT)
+#else
+#define BTUSB_EP_TYPE(ep) usb_endpoint_type(ep)
+#define BTUSB_EP_DIR_IN(ep) usb_endpoint_dir_in(ep)
+#define BTUSB_EP_DIR_OUT(ep) usb_endpoint_dir_out(ep)
+#endif
+
+/* debug information flags. one-hot encoded:
+ bit0 : enable printk(KERN_DEBUG)
+ bit1 : enable printk(KERN_INFO)
+ bit16 : enable all message dumps in printk
+ bit17 : enable timestamp calculations on voice RX packets
+ bit18 : enable timestamp calculations on voice TX packets
+ bit19 : enable GKI buffer check */
+#define BTUSB_DBG_MSG 0x0001
+#define BTUSB_INFO_MSG 0x0002
+#define BTUSB_DUMP_MSG 0x0100
+#define BTUSB_VOICERX_TIME 0x0200
+#define BTUSB_VOICETX_TIME 0x0400
+#define BTUSB_GKI_CHK_MSG 0x0800
+/* #define BTUSB_DBGFLAGS (BTUSB_DBG_MSG | BTUSB_INFO_MSG | BTUSB_DUMP_MSG | BTUSB_GKI_CHK_MSG) */
+#define BTUSB_DBGFLAGS 0
+
+extern int dbgflags;
+
+#define BTUSB_DBG(fmt, ...) if (unlikely(dbgflags & BTUSB_DBG_MSG)) \
+ printk(KERN_INFO "BTUSB %s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+
+#define BTUSB_INFO(fmt, ...) if (unlikely(dbgflags & BTUSB_INFO_MSG))\
+ printk(KERN_INFO "BTUSB %s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+
+#define BTUSB_ERR(fmt, ...) \
+ printk(KERN_ERR "BTUSB %s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+
+/* Get a minor range for your devices from the usb maintainer */
+#define BTUSB_MINOR_BASE 194
+
+/* 1025 = size(con_hdl) + size(acl_len) + size(3-dh5) = 2 + 2 + 1021 */
+#define BTUSB_HCI_MAX_ACL_SIZE 1025
+/* Maximum size of command and events packets (events = 255 + 2, commands = 255 + 3) */
+#define BTUSB_HCI_MAX_CMD_SIZE 258
+#define BTUSB_HCI_MAX_EVT_SIZE 257
+
+/* Maximum HCI H4 size = HCI type + ACL packet */
+#define BTUSB_H4_MAX_SIZE (1 + BTUSB_HCI_MAX_ACL_SIZE)
+
+#define BTUSB_NUM_OF_ACL_RX_BUFFERS 12
+#define BTUSB_NUM_OF_ACL_TX_BUFFERS 12
+#define BTUSB_NUM_OF_DIAG_RX_BUFFERS 2 /* must not be less than 2 */
+#define BTUSB_NUM_OF_DIAG_TX_BUFFERS 2
+#define BTUSB_NUM_OF_EVENT_BUFFERS 8 /* must not be less than 2 */
+#define BTUSB_NUM_OF_CMD_BUFFERS 8
+#define BTUSB_MAXIMUM_TX_VOICE_SIZE 192
+#define BTUSB_NUM_OF_VOICE_RX_BUFFERS 2 /* must not be less than 2 */
+#define BTUSB_NUM_OF_VOICE_RX_PACKETS 8 /* maximum voice packets pending for user */
+#define BTUSB_NUM_OF_VOICE_TX_BUFFERS 16
+
+#define BTUSB_VOICE_BURST_SIZE 48
+#define BTUSB_VOICE_HEADER_SIZE 3
+#define BTUSB_VOICE_FRAMES_PER_URB 9
+#define BTUSB_VOICE_BUFFER_MAXSIZE (BTUSB_VOICE_FRAMES_PER_URB * \
+ ALIGN(BTUSB_VOICE_BURST_SIZE + BTUSB_VOICE_HEADER_SIZE, 4))
+
+/* size of the SCO packets sent to user application (5 * 48 is the max below 256) */
+#define BTUSB_SCO_RX_LEN (BTUSB_VOICE_BURST_SIZE * 5)
+#if BTUSB_SCO_RX_LEN > 256
+#error SCO RX packet length is larger than the format supports
+#endif
+
+#ifndef UINT8_TO_STREAM
+#define UINT8_TO_STREAM(p, u8) {*(p)++ = (UINT8)(u8);}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (UINT8)(u16); *(p)++ = (UINT8)((u16) >> 8);}
+#define BDADDR_TO_STREAM(p, a) {register int ijk; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *(p)++ = (UINT8) a[BD_ADDR_LEN - 1 - ijk];}
+#define ARRAY_TO_STREAM(p, a, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) *(p)++ = (UINT8) a[ijk];}
+
+#define STREAM_TO_UINT8(u8, p) {u8 = (UINT8)(*(p)); (p) += 1;}
+#define STREAM_TO_UINT16(u16, p) {u16 = (UINT16)((*(p)) + ((*((p) + 1)) << 8)); (p) += 2;}
+#define STREAM_TO_UINT32(u32, p) {u32 = (((UINT32)(*(p))) + ((((UINT32)(*((p) + 1)))) << 8) + ((((UINT32)(*((p) + 2)))) << 16) + ((((UINT32)(*((p) + 3)))) << 24)); (p) += 4;}
+#define STREAM_TO_BDADDR(a, p) {register int ijk; register UINT8 *pbda = (UINT8 *)a + BD_ADDR_LEN - 1; for (ijk = 0; ijk < BD_ADDR_LEN; ijk++) *pbda-- = *p++;}
+#define STREAM_TO_ARRAY(a, p, len) {register int ijk; for (ijk = 0; ijk < len; ijk++) ((UINT8 *) a)[ijk] = *p++;}
+#endif
+
+#define UINT32_TO_BE_STREAM(p, u32) {*(p)++ = (UINT8)((u32) >> 24); *(p)++ = (UINT8)((u32) >> 16); *(p)++ = (UINT8)((u32) >> 8); *(p)++ = (UINT8)(u32); }
+#define UINT24_TO_BE_STREAM(p, u24) {*(p)++ = (UINT8)((u24) >> 16); *(p)++ = (UINT8)((u24) >> 8); *(p)++ = (UINT8)(u24);}
+#define UINT16_TO_BE_STREAM(p, u16) {*(p)++ = (UINT8)((u16) >> 8); *(p)++ = (UINT8)(u16);}
+#define UINT8_TO_BE_STREAM(p, u8) {*(p)++ = (UINT8)(u8);}
+
+/* macro that helps parsing arrays */
+#define BTUSB_ARRAY_FOR_EACH_TRANS(__a) \
+ for (idx = 0, p_trans = &__a[0]; idx < ARRAY_SIZE(__a); idx++, p_trans = &__a[idx])
+
+/* Layer Specific field: Used to send packet to User Space */
+#define BTUSB_LS_H4_TYPE_SENT (1<<0) /* H4 HCI Type already sent */
+#define BTUSB_LS_GKI_BUFFER (1<<1) /* Locally allocated buffer-not to resubmit */
+
+struct btusb;
+
+/* Container used to copy the URB to sniff the SCO */
+struct btusb_scosniff
+{
+ struct list_head lh; /* to add element to a list */
+ int s; /* start frame */
+ unsigned int n; /* number of descriptors */
+ unsigned int l; /* buffer length */
+ struct usb_iso_packet_descriptor d[0]; /* descriptors */
+};
+
+/* USB transaction */
+struct btusb_trans
+{
+ /* This is mapped to a GKI buffer to allow queuing */
+ BUFFER_HDR_T gki_hdr;
+ /* Sharing queue with other packets -> needs BT header to multiplex */
+ BT_HDR bt_hdr;
+ /* Pointer to the location where the data is stored */
+ UINT8 *dma_buffer;
+ /* DMA structure */
+ dma_addr_t dma;
+ /* URB for this transaction */
+ struct urb *p_urb;
+ /* pointer to the device information */
+ struct btusb *p_dev;
+ void (*complete)(struct btusb *p_dev, struct btusb_trans *p_trans, struct urb *p_urb);
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* Magic number */
+ UINT32 magic;
+#endif
+};
+
+/* Voice packet */
+struct btusb_voice_pkt
+{
+ /* This is mapped to a GKI buffer to allow queuing */
+ BUFFER_HDR_T gki_hdr;
+ /* Sharing queue with other packets -> needs BT header to multiplex */
+ BT_HDR bt_hdr;
+ UINT8 data[BTUSB_VOICE_HEADER_SIZE + BTUSB_SCO_RX_LEN];
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* Magic number */
+ UINT32 magic;
+#endif
+};
+
+/* Voice channel descriptor */
+struct btusb_voice_channel
+{
+ bool used;
+ unsigned short handle;
+ unsigned char burst;
+ /* pointer to HCI packet being reconstructed */
+ struct btusb_voice_pkt *p_pkt;
+};
+
+/* hardware quirks required for some BT controllers */
+#define BTUSB_QUIRK_ZLP_TX_REQ (1 << 0)
+#define BTUSB_QUIRK_EXAMPLE (1 << 1)
+
+/* Define the main structure */
+struct btusb
+{
+ struct usb_device *p_udev; /* usb device for this device */
+ const struct usb_device_id *p_id; /* device id from probe */
+ struct usb_interface *p_main_intf; /* main interface reference */
+ struct usb_interface *p_voice_intf; /* voice interface reference */
+ struct usb_interface *p_dfu_intf; /* DFU interface reference */
+ struct usb_interface *p_diag_intf; /* diag interface reference */
+
+ struct usb_host_endpoint *p_acl_in; /* acl bulk in endpoint */
+ struct usb_host_endpoint *p_acl_out; /* acl bulk out endpoint */
+ struct usb_host_endpoint *p_diag_in; /* diag bulk in endpoint */
+ struct usb_host_endpoint *p_diag_out; /* diag bulk out endpoint */
+ struct usb_host_endpoint *p_event_in; /* event interrupt in endpoint */
+ struct usb_host_endpoint *p_voice_out; /* isoc voice out endpoint */
+ struct usb_host_endpoint *p_voice_in; /* isoc voice in endpoint */
+ struct ktermios kterm; /* TTY emulation */
+ struct kref kref;
+ tBTUSB_STATS stats;
+ bool issharedusb;
+ unsigned int quirks;
+
+ /* reception queue */
+ wait_queue_head_t rx_wait_q;
+
+ /* tx tasklet */
+ struct tasklet_struct tx_task;
+
+ /* proc filesystem entry to retrieve info from driver environment */
+ struct proc_dir_entry *p_pde;
+ bool scosniff_active;
+ struct list_head scosniff_list;
+ struct completion scosniff_completion;
+
+ /* Command transmit path */
+ struct btusb_trans cmd_array[BTUSB_NUM_OF_CMD_BUFFERS];
+ struct usb_ctrlrequest cmd_req_array[BTUSB_NUM_OF_CMD_BUFFERS];
+ struct usb_anchor cmd_submitted;
+
+ /* Event receive path */
+ struct btusb_trans event_array[BTUSB_NUM_OF_EVENT_BUFFERS];
+ struct usb_anchor event_submitted;
+
+ /* ACL receive path */
+ struct btusb_trans acl_rx_array[BTUSB_NUM_OF_ACL_RX_BUFFERS];
+ struct usb_anchor acl_rx_submitted;
+
+ /* ACL transmit path */
+ struct btusb_trans acl_tx_array[BTUSB_NUM_OF_ACL_TX_BUFFERS];
+ struct usb_anchor acl_tx_submitted;
+
+ /* Diagnostics receive path */
+ struct btusb_trans diag_rx_array[BTUSB_NUM_OF_DIAG_RX_BUFFERS];
+ struct usb_anchor diag_rx_submitted;
+
+ /* Diagnostics transmit path */
+ struct btusb_trans diag_tx_array[BTUSB_NUM_OF_DIAG_TX_BUFFERS];
+ struct usb_anchor diag_tx_submitted;
+
+ /* Voice RX */
+ struct btusb_trans voice_rx_array[BTUSB_NUM_OF_VOICE_RX_BUFFERS];
+ struct usb_anchor voice_rx_submitted;
+ struct btusb_voice_pkt voice_rx_pkts[BTUSB_NUM_OF_VOICE_RX_PACKETS];
+ DECLARE_BTUSB_CQ(voice_rx_list, struct btusb_voice_pkt *, BTUSB_NUM_OF_VOICE_RX_PACKETS);
+
+ struct
+ {
+ struct btusb_voice_channel channels[3];
+ unsigned int remaining;
+ struct btusb_voice_pkt **pp_pkt;
+ unsigned char hdr[BTUSB_VOICE_HEADER_SIZE];
+ unsigned int hdr_size;
+ } voice_rx;
+
+ /* Voice TX */
+ struct btusb_trans voice_tx_array[BTUSB_NUM_OF_VOICE_TX_BUFFERS];
+ struct usb_anchor voice_tx_submitted;
+ atomic_t voice_tx_active;
+
+ BT_HDR *p_write_msg;
+
+ BUFFER_Q rx_queue;
+ BT_HDR *p_rx_msg;
+ BUFFER_Q tx_queue;
+
+#ifdef BTUSB_LITE
+ struct btusb_lite_cb lite_cb;
+#endif
+};
+
+/* Function prototypes */
+void btusb_delete(struct kref *kref);
+
+void btusb_tx_task(unsigned long arg);
+
+void btusb_cancel_voice(struct btusb *p_dev);
+void btusb_cancel_urbs(struct btusb *p_dev);
+
+void btusb_voice_stats(unsigned long *p_max, unsigned long *p_min,
+ struct timeval *p_result, struct timeval *p_last_time);
+
+/* URB submit */
+int btusb_submit(struct btusb *p_dev, struct usb_anchor *p_anchor, struct btusb_trans *p_trans, int mem_flags);
+void btusb_submit_voice_rx(struct btusb *p_dev, struct btusb_trans *p_trans, int mem_flags);
+
+/* BT controller to host routines */
+void btusb_rx_enqueue(struct btusb *p_dev, struct btusb_trans *p_trans, UINT8 hcitype);
+void btusb_rx_enqueue_voice(struct btusb *p_dev, struct btusb_voice_pkt *p_pkt);
+void btusb_rx_dequeued(struct btusb *p_dev, BT_HDR *p_msg);
+
+void btusb_dump_data(const UINT8 *p, int len, const char *p_title);
+
+void btusb_cmd_complete(struct btusb *p_dev, struct btusb_trans *p_trans, struct urb *p_urb);
+void btusb_voicetx_complete(struct btusb *p_dev, struct btusb_trans *p_trans, struct urb *p_urb);
+void btusb_urb_out_complete(struct urb *p_urb);
+void btusb_voicerx_complete(struct urb *p_urb);
+
+/* Voice commands */
+int btusb_add_voice_channel(struct btusb *p_dev, unsigned short sco_handle, unsigned char burst);
+int btusb_remove_voice_channel(struct btusb *p_dev, unsigned short sco_handle);
+
+/* USB device interface */
+int btusb_open(struct inode *inode, struct file *file);
+int btusb_release(struct inode *inode, struct file *file);
+ssize_t btusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos);
+ssize_t btusb_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos);
+unsigned int btusb_poll(struct file *file, struct poll_table_struct *p_pt);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+long btusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#else
+int btusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+
+/* Globals */
+extern struct usb_driver btusb_driver;
+extern bool autopm;
+
+#endif /* BTUSB_H */
diff --git a/inc/btusb_cq.h b/inc/btusb_cq.h
new file mode 100755
index 0000000..252b236
--- a/dev/null
+++ b/inc/btusb_cq.h
@@ -0,0 +1,118 @@
+/*
+ *
+ * btusb_cq.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Circular queue implementation, inspired from the Linux kernel cq as of 3.13...
+ * The reason why Linux version is not used is that it changed too much across
+ * kernel versions.
+ *
+ */
+
+#ifndef BTUSB_CQ_H
+#define BTUSB_CQ_H
+
+/* for smp_* */
+#include <linux/spinlock.h>
+
+struct __btusb_cq {
+ unsigned int in;
+ unsigned int out;
+ unsigned int mask;
+};
+
+#define __STRUCT_BTUSB_CQ_COMMON(datatype) \
+ union { \
+ struct __btusb_cq cq; \
+ datatype *type; \
+ const datatype *const_type; \
+ }
+
+/* contains the power of 2 size check when declaring the buf array */
+#define STRUCT_BTUSB_CQ(type, size) \
+struct { \
+ __STRUCT_BTUSB_CQ_COMMON(type); \
+ type buf[((size < 2) || (size & (size - 1))) ? -1 : size]; \
+}
+
+#define DECLARE_BTUSB_CQ(queue, type, size) STRUCT_BTUSB_CQ(type, size) queue
+
+#define INIT_BTUSB_CQ(queue) \
+(void)({ \
+ typeof(&(queue)) __tmp = &(queue); \
+ struct __btusb_cq *__cq = &__tmp->cq; \
+ __cq->in = 0; \
+ __cq->out = 0; \
+ __cq->mask = ARRAY_SIZE(__tmp->buf) - 1;\
+})
+
+#define btusb_cq_len(queue) \
+({ \
+ typeof((queue) + 1) __tmpl = (queue); \
+ __tmpl->cq.in - __tmpl->cq.out; \
+})
+
+#define btusb_cq_is_empty(queue) \
+({ \
+ typeof((queue) + 1) __tmpq = (queue); \
+ __tmpq->cq.in == __tmpq->cq.out; \
+})
+
+#define btusb_cq_is_full(queue) \
+({ \
+ typeof((queue) + 1) __tmpq = (queue); \
+ btusb_cq_len(__tmpq) > __tmpq->cq.mask; \
+})
+
+
+#define btusb_cq_put(queue, val) \
+({ \
+ typeof((queue) + 1) __tmp = (queue); \
+ typeof(*__tmp->const_type) __val = (val); \
+ unsigned int __ret; \
+ struct __btusb_cq *__cq = &__tmp->cq; \
+ __ret = !btusb_cq_is_full(__tmp); \
+ if (__ret) { \
+ __tmp->buf[__cq->in & __cq->mask] = \
+ (typeof(*__tmp->type))__val; \
+ smp_wmb(); \
+ __cq->in++; \
+ } \
+ __ret; \
+})
+
+#define btusb_cq_get(queue, val) \
+({ \
+ typeof((queue) + 1) __tmp = (queue); \
+ typeof(__tmp->type) __val = (val); \
+ unsigned int __ret; \
+ struct __btusb_cq *__cq = &__tmp->cq; \
+ __ret = !btusb_cq_is_empty(__tmp); \
+ if (__ret) { \
+ *(typeof(__tmp->type))__val = \
+ __tmp->buf[__cq->out & __cq->mask]; \
+ smp_wmb(); \
+ __cq->out++; \
+ } \
+ __ret; \
+})
+
+#endif
diff --git a/inc/btusb_lite.h b/inc/btusb_lite.h
new file mode 100755
index 0000000..0f6fe06
--- a/dev/null
+++ b/inc/btusb_lite.h
@@ -0,0 +1,203 @@
+/*
+ *
+ * btusb_lite.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#ifndef BTUSB_LITE_H
+#define BTUSB_LITE_H
+
+struct btusb;
+struct btpcm;
+
+#include "bt_target.h"
+#include "hcidefs.h"
+#include "bd.h"
+#include "uipc_msg.h"
+#include "btusb_lite_av.h"
+#include "btusb_lite_avdt.h"
+#include "btusb_lite_l2c.h"
+#include "btusb_lite_hci.h"
+
+/*
+ * Definitions
+ */
+/* IPC Length Header Size (16 bits) */
+#define BTUSB_LITE_IPC_HDR_LEN_SIZE (sizeof(UINT16))
+
+/* IPC Event Header Size (16 bits) */
+#define BTUSB_LITE_IPC_HDR_EVT_SIZE (sizeof(UINT16))
+
+/* IPC Header contains a Length and an Event code */
+#define BTUSB_LITE_IPC_HDR_SIZE (BTUSB_LITE_IPC_HDR_LEN_SIZE + BTUSB_LITE_IPC_HDR_EVT_SIZE)
+
+struct btusb_lite_mgt_cb
+{
+ bool opened;
+};
+
+struct btusb_lite_stat
+{
+ unsigned long event_bytes;
+ unsigned long event_completed;
+};
+
+struct btusb_lite_from_app
+{
+ BT_HDR *p_rx_msg;
+ UINT8 rx_header[BTUSB_LITE_IPC_HDR_SIZE];
+ UINT8 rx_header_len;
+ UINT16 rx_len; /* Decoded Rx Payload length */
+};
+
+struct btusb_lite_to_app
+{
+ BUFFER_Q ipc_queue; /* IPC message queue */
+ BT_HDR *p_ipc_msg;
+ BT_HDR *p_hdr_msg;
+ BT_HDR *p_hci_msg;
+};
+
+/* Lite Stack mode */
+#define BTU_FULL_STACK_ACTIVE 0
+#define BTU_LITE_STACK_ACTIVE 1
+#define BTU_TRANSPORT_HOLD 2
+#define BTU_FULL_TRANSPORT_ACTIVE 3
+#define BTU_LITE_TRANSPORT_ACTIVE 4
+
+#define BTU_IPC_CMD_SET_TRANSPORT_STATE 0 /* Set transport state (param=transprt state) */
+#define BTU_IPC_CMD_DISABLE_TRANSPORT 1 /* Set transport hardware (param=1 to disable) */
+
+struct btusb_lite_btu_cb
+{
+ UINT8 transport_state;
+ UINT8 transport_disabled;
+};
+
+enum btusb_lite_pcm_state
+{
+ PCM_CLOSED = 0,
+ PCM_OPENED,
+ PCM_CONFIGURED,
+ PCM_STARTED
+};
+
+struct btusb_lite_pcm_ccb
+{
+ enum btusb_lite_pcm_state state;
+ int frequency;
+};
+
+struct btusb_lite_encoder_ccb
+{
+ int channel;
+ int opened;
+ int encoded_frame_size;
+ int pcm_frame_size;
+ int header_size;
+ int type; /* SBC, SEC, etc. */
+ tBTA_AV_AUDIO_CODEC_INFO encoder;
+};
+
+struct btusb_lite_av_cb
+{
+ UINT8 audio_open_cnt;
+ UINT16 stack_mtu; /* received value from bt stack */
+ UINT16 curr_mtu; /* modified value in btusb to meet PCM buffer size */
+ UINT8 multi_av;
+ struct btusb_lite_pcm_ccb pcm;
+ struct btusb_lite_encoder_ccb encoder;
+ struct btusb_lite_av_scb scb[BTA_AV_NUM_STRS];
+ BT_HDR *p_buf_working;
+ UINT8 option;
+ UINT8 m_pt;
+ int header_len;
+ int payload_len;
+ UINT32 timestamp;
+};
+
+/* Main Lite Control Block */
+struct btusb_lite_cb
+{
+ /* static entries */
+ struct proc_dir_entry *p_lite_pde;
+ struct btpcm *p_btpcm;
+ /* dynamic entries */
+ struct {
+ bool opened;
+ struct btusb_lite_stat stat;
+ struct btusb_lite_from_app from_app;
+ struct btusb_lite_to_app to_app;
+ struct btusb_lite_mgt_cb mgt; /* Management */
+ struct btusb_lite_btu_cb btu; /* BTU */
+ struct btusb_lite_l2c_cb l2c; /* L2C */
+ struct btusb_lite_av_cb av; /* AV */
+ struct btusb_lite_avdt_cb avdt;
+ } s;
+};
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_create
+ **
+ ** Description Create BTUSB Lite interface
+ **
+ ** Returns status (< 0 if error)
+ **
+ *******************************************************************************/
+int btusb_lite_create(struct btusb *p_dev, struct usb_interface *p_interface);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_delete
+ **
+ ** Description Delete BTUSB Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+void btusb_lite_delete(struct btusb *p_dev, struct usb_interface *p_interface);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_stop_all
+ **
+ ** Description Stop all sound streams
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_lite_stop_all(struct btusb *p_dev);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_is_hci_over_ipc
+ **
+ ** Description Check if HCI is over IPC (Lite Interface).
+ **
+ ** Returns int (1 if HCI is over IPC otherwise 0)
+ **
+ *******************************************************************************/
+int btusb_lite_is_hci_over_ipc(struct btusb *p_dev);
+
+#endif /* BTUSB_LITE_H*/
+
diff --git a/inc/btusb_lite_av.h b/inc/btusb_lite_av.h
new file mode 100755
index 0000000..5b2f05d
--- a/dev/null
+++ b/inc/btusb_lite_av.h
@@ -0,0 +1,135 @@
+/*
+ *
+ * btusb_lite_av.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#ifndef BTUSB_LITE_AV_H
+#define BTUSB_LITE_AV_H
+
+typedef UINT8 tBTA_AV_CODEC; /* codec type */
+typedef UINT8 tBTA_AV_CHNL; /* the channel: audio/video */
+typedef UINT8 tBTA_AV_HNDL; /* the handle: ((hdi + 1)|chnl) */
+
+/* data type for the Audio Codec Information*/
+typedef struct
+{
+ UINT16 bit_rate; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_busy; /* SBC encoder bit rate in kbps */
+ UINT16 bit_rate_swampd;/* SBC encoder bit rate in kbps */
+ UINT8 busy_level; /* Busy level indicating the bit-rate to be used */
+ UINT8 codec_info[AVDT_CODEC_SIZE];
+ UINT8 codec_type; /* Codec type */
+} tBTA_AV_AUDIO_CODEC_INFO;
+
+/* type for AV stream control block on Lite stack*/
+struct btusb_lite_av_scb
+{
+ BUFFER_Q out_q; /* used for audio channels only */
+ BD_ADDR peer_addr; /* peer BD address */
+ UINT16 l2c_cid; /* L2CAP channel ID */
+ tBTA_AV_CODEC codec_type; /* codec type */
+ BOOLEAN cong; /* TRUE if AVDTP congested */
+ tBTA_AV_CHNL chnl; /* the channel: audio/video */
+ tBTA_AV_HNDL hndl; /* the handle: ((hdi + 1)|chnl) */
+ UINT8 avdt_handle; /* AVDTP handle */
+ UINT8 hdi; /* the index to SCB[] */
+ UINT8 l2c_bufs; /* the number of buffers queued to L2CAP */
+ BOOLEAN started; /* TRUE if stream started from call-out perspective */
+ BOOLEAN start_stop_flag;/* TRUE when snk is INT and bta_av_start_ok() decides that */
+};
+
+/* these bits are defined for btusb_lite_av_cb.multi_av */
+#define BTA_AV_MULTI_AV_SUPPORTED 0x01
+#define BTA_AV_MULTI_AV_IN_USE 0x02
+
+/*
+ * Globals
+ */
+extern int pcm0_mute;
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_add
+**
+** Description Add (Sync) an AV channel.
+**
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_add(struct btusb *p_dev, tBTA_AV_SYNC_INFO *p_sync_info,
+ UINT8 multi_av_supported, UINT16 curr_mtu);
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_remove
+**
+** Description Remove (Cleanup) an AV channel.
+**
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_remove(struct btusb *p_dev, UINT8 scb_idx,
+ UINT8 audio_open_cnt, UINT16 curr_mtu);
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_start
+**
+** Description Start AV
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+void btusb_lite_av_start(struct btusb *p_dev, UINT8 scb_idx, UINT8 start_stop_flag,
+ UINT8 audio_open_cnt, tBTA_AV_AUDIO_CODEC_INFO *p_codec_cfg);
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_stop
+**
+** Description Start AV
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+void btusb_lite_av_stop(struct btusb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt);
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_suspend
+**
+** Description Suspend AV
+**
+** Returns none.
+**
+*******************************************************************************/
+void btusb_lite_av_suspend(struct btusb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt);
+
+#endif /* BTUSB_LITE_AV_H*/
+
diff --git a/inc/btusb_lite_avdt.h b/inc/btusb_lite_avdt.h
new file mode 100755
index 0000000..2be89a1
--- a/dev/null
+++ b/inc/btusb_lite_avdt.h
@@ -0,0 +1,148 @@
+/*
+ *
+ * btusb_lite_avdt.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#ifndef BTUSB_LITE_AVDT_H
+#define BTUSB_LITE_AVDT_H
+
+/* AVDT Option */
+#define BTUSB_LITE_AVDT_OPT_NO_RTP 0x01 /* No RTP Header */
+#define BTUSB_LITE_AVDT_OPT_NO_MPH 0x02 /* No Media Payload Header */
+
+/* Definitions for A2DP packets */
+#define BTUSB_LITE_RTP_SIZE 12 /* RTP Header size */
+#define BTUSB_LITE_MEDIA_SIZE 1 /* Media Header size */
+#define BTUSB_LITE_SCMS_SIZE 1 /* SCMS Header size */
+
+/* Some A2DP Definitions */
+#define AVDT_MEDIA_OCTET1 0x80 /* First byte of media packet header */
+
+#define AVDT_MARKER_SET 0x80
+#define AVDT_RTP_PAYLOAD_TYPE 0x60 /* First Dynamic Payload type */
+
+/* AVDT Header size */
+#define BTUSB_LITE_AVDT_HDR_SIZE (BTUSB_LITE_RTP_SIZE + BTUSB_LITE_MEDIA_SIZE)
+
+/* A2DP Definitions */
+#define A2D_SBC_HDR_NUM_MSK 0x0F /* A2DP Media Header Frame Mask */
+
+
+/* channel control block type */
+struct btusb_lite_avdt_ccb
+{
+ BD_ADDR peer_addr; /* BD address of peer */
+ BOOLEAN allocated; /* Whether ccb is allocated */
+ UINT16 lcid; /* local L2CAP channel ID */
+ UINT16 peer_mtu; /* L2CAP mtu of the peer device */
+};
+
+/* SCMS information */
+struct btusb_lite_avdt_scms
+{
+ BOOLEAN enable; /* Indicates if SCMS is enabled */
+ UINT8 header; /* SCMS Header */
+};
+
+
+/* stream control block type */
+struct btusb_lite_avdt_scb
+{
+ BT_HDR *p_pkt; /* packet waiting to be sent */
+ struct btusb_lite_avdt_ccb *p_ccb; /* ccb associated with this scb */
+ UINT16 media_seq; /* media packet sequence number */
+ BOOLEAN allocated; /* whether scb is allocated or unused */
+ BOOLEAN in_use; /* whether stream being used by peer */
+ BOOLEAN cong; /* Whether media transport channel is congested */
+ UINT8 handle;
+ UINT8 mux_tsid_media; /* TSID for media transport session */
+ struct btusb_lite_avdt_scms scms;
+};
+
+struct btusb_lite_avdt_cb
+{
+ struct btusb_lite_avdt_ccb ccb[AVDT_NUM_LINKS]; /* channel control blocks */
+ struct btusb_lite_avdt_scb scb[AVDT_NUM_SEPS]; /* stream control blocks */
+
+};
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_scb_by_hdl
+**
+** Description Given an scb handle (or seid), return a pointer to the scb.
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+struct btusb_lite_avdt_scb *btusb_lite_avdt_scb_by_hdl(struct btusb *p_dev, UINT8 hdl);
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_init_scb
+**
+** Description allocate and initialize SCB/CCB with received sync info
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_init_scb(struct btusb *p_dev, tAVDT_SCB_SYNC_INFO *p_scb_info);
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_remove_scb
+**
+** Description deallocate SCB and CCB
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_remove_scb(struct btusb *p_dev, UINT8 handle, tAVDT_SCB_SYNC_INFO *p_scb_info);
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_send
+**
+** Description AVDT packet send
+**
+** Returns None
+**
+*******************************************************************************/
+void btusb_lite_avdt_send(struct btusb *p_dev, BT_HDR *p_msg, UINT8 avdt_handle,
+ UINT8 m_pt, UINT8 option, UINT32 timestamp);
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_cp_set_scms
+**
+** Description Set SCMS Content Protection for a channel
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_cp_set_scms(struct btusb *p_dev, UINT8 avdt_handle,
+ BOOLEAN enable, UINT8 scms_hdr);
+
+#endif /* BTUSB_LITE_AVDT_H*/
+
diff --git a/inc/btusb_lite_hci.h b/inc/btusb_lite_hci.h
new file mode 100755
index 0000000..ca634a1
--- a/dev/null
+++ b/inc/btusb_lite_hci.h
@@ -0,0 +1,71 @@
+/*
+ *
+ * btusb_lite_hci.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef BTUSB_LITE_HCI_H
+#define BTUSB_LITE_HCI_H
+
+/* Definitions for HCI ACL packets */
+
+/* HCI ACL Packet: HCI_Type, ConHdl, Length */
+#define BTUSB_LITE_HCI_ACL_HDR_SIZE (sizeof(UINT8) + sizeof(UINT16) + sizeof(UINT16))
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_acl_send
+ **
+ ** Description Send an ACL packet to HCI
+ **
+ ** Returns Status
+ **
+ *******************************************************************************/
+int btusb_lite_hci_acl_send(struct btusb *p_dev, BT_HDR *p_msg, UINT16 con_hdl);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_cmd_filter
+ **
+ ** Description Check if the Sent HCI Command need to be handled/caught (not
+ ** sent to BT controller).
+ **
+ ** Returns status: <> 0 if the command must be send to BT controller
+ ** 0 if the command is handled
+ **
+ *******************************************************************************/
+int btusb_lite_hci_cmd_filter(struct btusb *p_dev, BT_HDR *p_msg);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_event_filter
+ **
+ ** Description Handle/Filter HCI Events received from BT controller
+ **
+ ** Returns int (1 if HCI is over IPC otherwise 0)
+ **
+ *******************************************************************************/
+int btusb_lite_hci_event_filter(struct btusb *p_dev, UINT8 *p_data, int length);
+
+#endif /* BTUSB_LITE_HCI_H */
+
diff --git a/inc/btusb_lite_l2c.h b/inc/btusb_lite_l2c.h
new file mode 100755
index 0000000..c740a29
--- a/dev/null
+++ b/inc/btusb_lite_l2c.h
@@ -0,0 +1,105 @@
+/*
+ *
+ * btusb_lite_l2c.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#ifndef BTUSB_LITE_L2C_H
+#define BTUSB_LITE_L2C_H
+
+/* L2CAP Header Definition (Length, CID) */
+#define BTUSB_LITE_L2CAP_HDR_SIZE (sizeof(UINT16) + sizeof(UINT16))
+
+struct btusb_lite_l2c_ccb
+{
+ BOOLEAN in_use;
+ UINT16 local_cid;
+ UINT16 remote_cid;
+ UINT16 out_mtu;
+ UINT16 handle;
+ UINT16 link_xmit_quota;
+ UINT8 is_flushable;
+
+ UINT16 tx_pending;
+};
+
+struct btusb_lite_l2c_cb
+{
+ /* Req */
+ UINT16 light_xmit_quota;
+ UINT16 acl_data_size;
+ UINT16 non_flushable_pbf;
+ UINT8 multi_av_data_cong_start;
+ UINT8 multi_av_data_cong_end;
+ UINT8 multi_av_data_cong_discard;
+ struct btusb_lite_l2c_ccb ccb[BTM_SYNC_INFO_NUM_STR];
+
+ /* Status */
+ UINT16 light_xmit_unacked;
+};
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_add
+**
+** Description Synchronize (Add) L2CAP Stream
+**
+** Returns Status.
+**
+*******************************************************************************/
+int btusb_lite_l2c_add(struct btusb *p_dev, tL2C_STREAM_INFO *p_l2c_stream);
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_remove
+**
+** Description Synchronize (Remove) L2CAP Stream
+**
+** Returns Status.
+**
+*******************************************************************************/
+int btusb_lite_l2c_remove(struct btusb *p_dev, UINT16 local_cid);
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_send
+**
+** Description Send L2CAP packet
+**
+** Returns Status
+**
+*******************************************************************************/
+int btusb_lite_l2c_send(struct btusb *p_dev, BT_HDR *p_msg, UINT16 local_cid);
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_l2c_nocp_hdlr
+ **
+ ** Description L2CAP NumberOfcompletePacket Handler function
+ **
+ ** Returns Number Of Complete Packet caught
+ **
+ *******************************************************************************/
+UINT16 btusb_lite_l2c_nocp_hdlr(struct btusb *p_dev, UINT16 con_hdl, UINT16 num_cplt_pck);
+
+#endif /* BTUSB_LITE_L2C_H*/
+
diff --git a/inc/btusb_proc.h b/inc/btusb_proc.h
new file mode 100755
index 0000000..4a96270
--- a/dev/null
+++ b/inc/btusb_proc.h
@@ -0,0 +1,49 @@
+/*
+ *
+ * btusb_proc.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Module that defines the proc file system routines.
+ *
+ */
+
+#ifndef BTUSB_PROC_H
+#define BTUSB_PROC_H
+
+struct btusb;
+
+#ifdef CONFIG_PROC_FS
+
+extern void btusb_proc_init(void);
+extern void btusb_proc_exit(void);
+extern void btusb_proc_add(struct btusb *p_dev, const char *name);
+extern void btusb_proc_remove(struct btusb *p_dev, const char *name);
+
+#else
+
+static inline void btusb_proc_init(void) {}
+static inline void btusb_proc_exit(void) {}
+static inline void btusb_proc_add(struct btusb *p_dev, const char *name) {}
+static inline void btusb_proc_remove(struct btusb *p_dev, const char *name) {}
+
+#endif
+
+#endif
diff --git a/inc/btusbext.h b/inc/btusbext.h
new file mode 100755
index 0000000..4654f25
--- a/dev/null
+++ b/inc/btusbext.h
@@ -0,0 +1,130 @@
+/*
+ *
+ * btusbext.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef BTUSBEXT_H
+#define BTUSBEXT_H
+
+#include <linux/time.h>
+
+/* BTUSB Statistics structure */
+typedef struct
+{
+ /* All URB submit counter */
+ unsigned long urb_submit_ok;
+ unsigned long urb_submit_err;
+
+ /* All URB out complete */
+ unsigned long urb_out_complete;
+ unsigned long urb_out_complete_err;
+
+ /* CMD counters */
+ unsigned long cmd_submit_ok;
+ unsigned long cmd_submit_err;
+ unsigned long cmd_complete;
+ unsigned long cmd_complete_err;
+
+ /* ACL RX counters */
+ unsigned long acl_rx_submit_ok;
+ unsigned long acl_rx_submit_err;
+ unsigned long acl_rx_complete;
+ unsigned long acl_rx_complete_err;
+ unsigned long acl_rx_resubmit;
+ unsigned long acl_rx_bytes;
+
+ /* DIAG RX counters */
+ unsigned long diag_rx_submit_ok;
+ unsigned long diag_rx_submit_err;
+ unsigned long diag_rx_complete;
+ unsigned long diag_rx_complete_err;
+ unsigned long diag_rx_resubmit;
+ unsigned long diag_rx_bytes;
+
+ /* EVENT counters */
+ unsigned long event_submit_ok;
+ unsigned long event_submit_err;
+ unsigned long event_complete;
+ unsigned long event_complete_err;
+ unsigned long event_resubmit;
+ unsigned long event_bytes;
+
+ /* VOICE RX counters */
+ unsigned long voicerx_submit_ok;
+ unsigned long voicerx_submit_err;
+ unsigned long voicerx_complete;
+ unsigned long voicerx_complete_err;
+ unsigned long voicerx_bad_frames;
+ unsigned long voicerx_raw_bytes;
+ unsigned long voicerx_skipped_bytes;
+ unsigned long voicerx_split_hdr;
+ unsigned long voicerx_bad_hdr;
+ unsigned long voicerx_bad_size;
+
+ /* VOICE TX counters */
+ unsigned long voicetx_submit_ok;
+ unsigned long voicetx_submit_err;
+ unsigned long voicetx_nobuf;
+ unsigned long voicetx_complete;
+ unsigned long voicetx_complete_err;
+
+ /* voice timings */
+ unsigned long voice_max_tx_done_delta_time;
+ unsigned long voice_min_tx_done_delta_time;
+ struct timeval voice_tx_done_delta_time;
+ struct timeval voice_last_tx_done_ts;
+
+ /* max delta time between 2 consecutive tx done routine in us */
+ unsigned long voice_max_rx_rdy_delta_time;
+ unsigned long voice_min_rx_rdy_delta_time;
+ struct timeval voice_rx_rdy_delta_time;
+ struct timeval voice_last_rx_rdy_ts;
+
+ /* max delta time between 2 consecutive tx done routine in us */
+ unsigned long voice_max_rx_feeding_interval;
+ unsigned long voice_min_rx_feeding_interval;
+ struct timeval voice_rx_feeding_interval;
+ struct timeval voice_last_rx_feeding_ts;
+} tBTUSB_STATS;
+
+/* IOCTL definitions (shared among all user mode applications, do not modify) */
+#define IOCTL_BTWUSB_GET_STATS 0x1001
+#define IOCTL_BTWUSB_CLEAR_STATS 0x1002
+#define IOCTL_BTWUSB_PUT 0x1003
+#define IOCTL_BTWUSB_PUT_CMD 0x1004
+#define IOCTL_BTWUSB_GET 0x1005
+#define IOCTL_BTWUSB_GET_EVENT 0x1006
+#define IOCTL_BTWUSB_PUT_VOICE 0x1007
+#define IOCTL_BTWUSB_GET_VOICE 0x1008
+#define IOCTL_BTWUSB_ADD_VOICE_CHANNEL 0x1009
+#define IOCTL_BTWUSB_REMOVE_VOICE_CHANNEL 0x100a
+#define IOCTL_BTWUSB_DEV_RESET 0x100b
+
+struct btusb_ioctl_sco_info
+{
+ unsigned short handle;
+ unsigned char burst;
+};
+
+#endif
diff --git a/inc/data_types.h b/inc/data_types.h
new file mode 100755
index 0000000..e8ccf4b
--- a/dev/null
+++ b/inc/data_types.h
@@ -0,0 +1,79 @@
+/*
+*
+* data_types.h
+*
+*
+*
+* Copyright (C) 2011 Broadcom Corporation.
+*
+*
+*
+* This software is licensed under the terms of the GNU General Public License,
+* version 2, as published by the Free Software Foundation (the "GPL"), and may
+* be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+*
+*
+* A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+* or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA
+*
+*
+*/
+
+#ifndef DATA_TYPES_H
+#define DATA_TYPES_H
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+typedef unsigned char UINT8;
+typedef unsigned short UINT16;
+typedef unsigned int UINT32, *PUINT32;
+typedef signed int INT32, *PINT32;
+typedef signed char INT8;
+typedef signed short INT16;
+
+
+#if defined(_WIDE_CHAR) || defined(_UNICODE)
+typedef unsigned short WIDECHAR; /* for _BT_WIN32 possibly use wchar_t */
+#define WIDE_NULL_CHAR ((WIDECHAR)0)
+#else
+typedef unsigned char WIDECHAR;
+#define WIDE_NULL_CHAR '\0'
+#endif
+
+typedef UINT32 TIME_STAMP;
+
+
+#ifndef _WINDOWS_VXD
+typedef unsigned char BOOLEAN;
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+#endif
+
+typedef unsigned char UBYTE;
+
+#define PACKED
+#define INLINE
+
+#ifndef BIG_ENDIAN
+#define BIG_ENDIAN FALSE
+#endif
+
+#define UINT16_LOW_BYTE(x) ((x) & 0xff)
+#define UINT16_HI_BYTE(x) ((x) >> 8)
+
+#define ARRAY_SIZEOF(x) (sizeof(x)/sizeof(x[0]))
+
+#endif
diff --git a/inc/gki.h b/inc/gki.h
new file mode 100755
index 0000000..8b04756
--- a/dev/null
+++ b/inc/gki.h
@@ -0,0 +1,190 @@
+/*
+ *
+ * gki.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef GKI_H
+#define GKI_H
+
+#include "target.h"
+#include "data_types.h"
+
+//#define TRACE_GKI_BUFFERS
+
+/* Error codes */
+#define GKI_SUCCESS 0x00
+#define GKI_FAILURE 0x01
+#define GKI_INVALID_TASK 0xF0
+#define GKI_INVALID_POOL 0xFF
+
+
+
+/************************************************************************
+** Mailbox definitions. Each task has 4 mailboxes that are used to
+** send buffers to the task.
+*/
+#define TASK_MBOX_0 0
+#define TASK_MBOX_1 1
+#define TASK_MBOX_2 2
+#define TASK_MBOX_3 3
+
+#define NUM_TASK_MBOX 4
+
+/************************************************************************
+** Event definitions.
+**
+** There are 4 reserved events used to signal messages rcvd in task mailboxes.
+** There are 4 reserved events used to signal timeout events.
+** There are 8 general purpose events available for applications.
+*/
+#define MAX_EVENTS 16
+
+#define TASK_MBOX_0_EVT_MASK 0x0001
+#define TASK_MBOX_1_EVT_MASK 0x0002
+#define TASK_MBOX_2_EVT_MASK 0x0004
+#define TASK_MBOX_3_EVT_MASK 0x0008
+
+
+#define TIMER_0 0
+#define TIMER_1 1
+#define TIMER_2 2
+#define TIMER_3 3
+
+#define TIMER_0_EVT_MASK 0x0010
+#define TIMER_1_EVT_MASK 0x0020
+#define TIMER_2_EVT_MASK 0x0040
+#define TIMER_3_EVT_MASK 0x0080
+
+#define APPL_EVT_0 8
+#define APPL_EVT_1 9
+#define APPL_EVT_2 10
+#define APPL_EVT_3 11
+#define APPL_EVT_4 12
+#define APPL_EVT_5 13
+#define APPL_EVT_6 14
+#define APPL_EVT_7 15
+
+#define EVENT_MASK(evt) ((UINT16)(0x0001 << (evt)))
+
+/***********************************************************************
+** This queue is a general purpose buffer queue, for application use.
+*/
+typedef struct
+{
+ void *p_first;
+ void *p_last;
+ UINT16 count;
+} BUFFER_Q;
+
+#define GKI_IS_QUEUE_EMPTY(p_q) ((p_q)->count == 0)
+
+/* Task constants
+*/
+#ifndef TASKPTR_DEF
+#define TASKPTR_DEF
+#if defined (LINUX_KERNEL)
+typedef int (*TASKPTR)(UINT32);
+#else
+typedef void (*TASKPTR)(UINT32);
+#endif
+#endif
+
+#define GKI_PUBLIC_POOL 0 /* General pool accessible to GKI_getbuf() */
+#define GKI_RESTRICTED_POOL 1 /* Inaccessible pool to GKI_getbuf() */
+
+/***********************************************************************
+** Function prototypes
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Task management */
+BT_API extern void GKI_init(void);
+BT_API extern void GKI_shutdown(void);
+
+/* To get and release buffers, change owner and get size
+*/
+BT_API extern void GKI_change_buf_owner (void *, UINT8);
+BT_API extern UINT8 GKI_create_pool (UINT16, UINT16, UINT8, void *);
+BT_API extern void GKI_delete_pool (UINT8);
+BT_API extern void *GKI_find_buf_start (void *);
+BT_API extern void GKI_freebuf (void *);
+#ifdef TRACE_GKI_BUFFERS
+BT_API extern void *GKI_getbuf_trace (UINT16, char *, int);
+#define GKI_getbuf(_size) GKI_getbuf_trace(_size,__FILE__,__LINE__)
+#else
+BT_API extern void *GKI_getbuf (UINT16);
+#endif
+
+BT_API extern UINT16 GKI_get_buf_size (void *);
+BT_API extern UINT16 GKI_get_pool_bufsize (UINT8 pool_id);
+
+// For compatibility with BTE
+#define GKI_POOL_SIZE(x) GKI_get_pool_bufsize(x)
+
+
+#ifdef TRACE_GKI_BUFFERS
+BT_API extern void *GKI_getpoolbuf_trace (UINT8, char *, int);
+#define GKI_getpoolbuf(_pool) GKI_getpoolbuf_trace(_pool,__FILE__,__LINE__)
+#else
+BT_API extern void *GKI_getpoolbuf (UINT8);
+#endif
+
+BT_API extern UINT16 GKI_poolfreecount (UINT8);
+BT_API extern UINT16 GKI_poolutilization (UINT8);
+BT_API extern UINT8 GKI_set_pool_permission(UINT8, UINT8);
+
+
+/* User buffer queue management
+*/
+BT_API extern void *GKI_dequeue (BUFFER_Q *);
+BT_API extern UINT8 GKI_buffer_status(void *p_buf);
+BT_API extern void GKI_enqueue (BUFFER_Q *, void *);
+BT_API extern void GKI_enqueue_head (BUFFER_Q *, void *);
+BT_API extern void *GKI_getfirst (BUFFER_Q *);
+BT_API extern void *GKI_getnext (void *);
+BT_API extern void GKI_init_q (BUFFER_Q *);
+BT_API extern BOOLEAN GKI_queue_is_empty(BUFFER_Q *);
+BT_API extern void *GKI_remove_from_queue (BUFFER_Q *, void *);
+
+BT_API extern BOOLEAN GKI_chk_buf_pool_damage(UINT8 pool_id);
+
+/* Disable Interrupts, Enable Interrupts
+*/
+BT_API extern void GKI_enable(void);
+BT_API extern void GKI_disable(void);
+
+/* Exception handling
+*/
+BT_API extern void GKI_exception (UINT16, const char *msg, ...);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/inc/gki_int.h b/inc/gki_int.h
new file mode 100755
index 0000000..f210e58
--- a/dev/null
+++ b/inc/gki_int.h
@@ -0,0 +1,197 @@
+/*
+ *
+ * gki_int.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef GKI_INT_H
+#define GKI_INT_H
+
+#include "gki.h"
+
+/* Task States: (For OSRdyTbl) */
+// TASK_DEAD is already defined by Linux => undefine it
+#ifdef TASK_DEAD
+#undef TASK_DEAD
+#endif
+
+#define TASK_DEAD 0 /* b0000 */
+#define TASK_READY 1 /* b0001 */
+#define TASK_WAIT 2 /* b0010 */
+#define TASK_DELAY 4 /* b0100 */
+#define TASK_SUSPEND 8 /* b1000 */
+
+
+/********************************************************************
+** Internal Error codes
+*********************************************************************/
+#define GKI_ERROR_BUF_CORRUPTED 0xFFFF
+#define GKI_ERROR_NOT_BUF_OWNER 0xFFFE
+#define GKI_ERROR_FREEBUF_BAD_QID 0xFFFD
+#define GKI_ERROR_FREEBUF_BUF_LINKED 0xFFFC
+#define GKI_ERROR_SEND_MSG_BAD_DEST 0xFFFB
+#define GKI_ERROR_SEND_MSG_BUF_LINKED 0xFFFA
+#define GKI_ERROR_ENQUEUE_BUF_LINKED 0xFFF9
+#define GKI_ERROR_DELETE_POOL_BAD_QID 0xFFF8
+#define GKI_ERROR_BUF_SIZE_TOOBIG 0xFFF7
+#define GKI_ERROR_BUF_SIZE_ZERO 0xFFF6
+#define GKI_ERROR_ADDR_NOT_IN_BUF 0xFFF5
+#define GKI_ERROR_BUF_POOL_CORRUPT 0xFFF4
+#define GKI_ERROR_BUFFER_TRACE_ON 0xFFF3
+#define GKI_ERROR_SEGS_EXCEEDED 0xFFF2
+#define GKI_ERROR_NO_MEMORY_FOR_SEG 0xFFF1
+
+
+/********************************************************************
+** Buffer Management Data Structures
+*********************************************************************/
+
+typedef struct _buffer_hdr
+{
+ struct _buffer_hdr *p_next;
+ UINT8 q_id;
+ UINT8 task_id;
+ UINT8 status;
+ UINT8 Type;
+#ifdef TRACE_GKI_BUFFERS
+ struct _buffer_hdr *p_next_all;
+ char *pFile;
+ int linenum;
+ UINT32 times_alloc;
+#endif
+} BUFFER_HDR_T;
+
+/* Allocate each buffer pool in up to 4 memory segments, for efficiency
+*/
+#define MAX_BUFFPOOL_SEGS 4
+
+typedef struct _free_queue
+{
+ UINT8 *seg_start[MAX_BUFFPOOL_SEGS];
+ UINT8 *seg_end[MAX_BUFFPOOL_SEGS];
+
+ BUFFER_HDR_T *p_first;
+ BUFFER_HDR_T *p_last;
+ UINT16 total;
+ UINT16 cur_cnt;
+ UINT16 max_cnt;
+#ifdef TRACE_GKI_BUFFERS
+ BUFFER_HDR_T *p_first_all;
+#endif
+} FREE_QUEUE_T;
+
+
+/* Buffer related defines
+*/
+#define BUFFER_HDR_SIZE (sizeof(BUFFER_HDR_T)) /* Offset past header */
+#define BUFFER_PADDING_SIZE (sizeof(BUFFER_HDR_T) + sizeof(UINT32)) /* Header + Magic Number */
+#define MAX_USER_BUF_SIZE ((UINT16)0xffff - BUFFER_PADDING_SIZE) /* pool size must allow for header */
+#define MAGIC_NO 0xDDBADDBA
+
+#define BUF_STATUS_FREE 0
+#define BUF_STATUS_UNLINKED 1
+#define BUF_STATUS_QUEUED 2
+
+/* Exception related structures
+*/
+#define MAX_EXCEPTION 8
+#define MAX_EXCEPTION_MSGLEN 64
+
+typedef struct
+{
+ UINT16 type;
+ UINT8 taskid;
+ UINT8 msg[MAX_EXCEPTION_MSGLEN];
+} EXCEPTION_T;
+
+
+/* Put all GKI variables into one control block
+*/
+typedef struct
+{
+ /* Task management variables
+ */
+ /* The stack and stack size are not used on Windows
+ */
+#if (GKI_USE_DYNAMIC_BUFFERS == FALSE)
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ UINT8 bufpool0[(GKI_BUF0_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ UINT8 bufpool1[(GKI_BUF1_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF1_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ UINT8 bufpool2[(GKI_BUF2_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF2_MAX];
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ UINT8 bufpool3[(GKI_BUF3_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF3_MAX];
+#endif
+
+#endif
+
+ INT IsRunning;
+
+ /* Define the buffer pool management variables
+ */
+ FREE_QUEUE_T freeq[GKI_NUM_TOTAL_BUF_POOLS];
+
+ UINT16 pool_buf_size[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 pool_max_count[GKI_NUM_TOTAL_BUF_POOLS];
+ UINT16 pool_additions[GKI_NUM_TOTAL_BUF_POOLS];
+
+ UINT16 ExceptionCnt;
+ EXCEPTION_T Exception[MAX_EXCEPTION];
+
+ /* Define the buffer pool access control variables */
+ UINT16 pool_access_mask;
+ UINT8 pool_list[GKI_NUM_TOTAL_BUF_POOLS]; /* buffer pools arranged in the order of size */
+ int curr_total_no_of_pools;
+} tGKI_CB;
+
+
+void gki_buffer_init(void);
+BOOLEAN gki_chk_buf_damage(void *p_buf);
+void *gki_reserve_os_memory (UINT32 size);
+void gki_release_os_memory (void *p_mem);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _BT_DYNAMIC_MEMORY
+extern tGKI_CB gki_cb;
+#else
+extern tGKI_CB *gp_gki_cb;
+#define gki_cb (*gp_gki_cb)
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/inc/hcidefs.h b/inc/hcidefs.h
new file mode 100755
index 0000000..57cd195
--- a/dev/null
+++ b/inc/hcidefs.h
@@ -0,0 +1,1819 @@
+/*
+*
+* hcidefs.h
+*
+*
+*
+* Copyright (C) 2011 Broadcom Corporation.
+*
+*
+*
+* This software is licensed under the terms of the GNU General Public License,
+* version 2, as published by the Free Software Foundation (the "GPL"), and may
+* be copied, distributed, and modified under those terms.
+*
+* This program is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+*
+*
+* A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+* or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+* Boston, MA 02111-1307, USA
+*
+*
+*/
+
+#ifndef HCIDEFS_H
+#define HCIDEFS_H
+
+#define HCI_PROTO_VERSION 0x01 /* Version for BT spec 1.1 */
+#define HCI_PROTO_VERSION_1_2 0x02 /* Version for BT spec 1.2 */
+#define HCI_PROTO_VERSION_2_0 0x03 /* Version for BT spec 2.0 */
+#define HCI_PROTO_VERSION_2_1 0x04 /* Version for BT spec 2.1 [Lisbon] */
+#define HCI_PROTO_REVISION 0x000C /* Current implementation version */
+/*
+** Definitions for HCI groups
+*/
+#define HCI_GRP_LINK_CONTROL_CMDS (0x01 << 10)
+#define HCI_GRP_LINK_POLICY_CMDS (0x02 << 10)
+#define HCI_GRP_HOST_CONT_BASEBAND_CMDS (0x03 << 10)
+#define HCI_GRP_INFORMATIONAL_PARAMS (0x04 << 10)
+#define HCI_GRP_STATUS_PARAMS (0x05 << 10)
+#define HCI_GRP_TESTING_CMDS (0x06 << 10)
+#define HCI_GRP_L2CAP_CMDS (0x07 << 10)
+#define HCI_GRP_L2CAP_HCI_EVTS (0x08 << 10)
+
+#define HCI_GRP_VENDOR_SPECIFIC (0x3F << 10)
+
+/* Group occupies high 6 bits of the HCI command rest is opcode itself */
+#define HCI_OGF(p) (UINT8)((0xFC00 & (p)) >> 10)
+#define HCI_OCF(p) ( 0x3FF & (p))
+
+/*
+** Definitions for Link Control Commands
+*/
+/* Following opcode is used only in command complete event for flow control */
+#define HCI_COMMAND_NONE 0x0000
+
+/* Commands of HCI_GRP_LINK_CONTROL_CMDS group */
+#define HCI_INQUIRY (0x0001 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_INQUIRY_CANCEL (0x0002 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PERIODIC_INQUIRY_MODE (0x0003 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_EXIT_PERIODIC_INQUIRY_MODE (0x0004 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION (0x0005 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_DISCONNECT (0x0006 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ADD_SCO_CONNECTION (0x0007 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CREATE_CONNECTION_CANCEL (0x0008 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_CONNECTION_REQUEST (0x0009 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_CONNECTION_REQUEST (0x000A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_REPLY (0x000B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY (0x000C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_REPLY (0x000D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY (0x000E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_PACKET_TYPE (0x000F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_AUTHENTICATION_REQUESTED (0x0011 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SET_CONN_ENCRYPTION (0x0013 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_CHANGE_CONN_LINK_KEY (0x0015 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_MASTER_LINK_KEY (0x0017 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST (0x0019 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_RMT_NAME_REQUEST_CANCEL (0x001A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_FEATURES (0x001B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_EXT_FEATURES (0x001C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_VERSION_INFO (0x001D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_RMT_CLOCK_OFFSET (0x001F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_READ_LMP_HANDLE (0x0020 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_SETUP_ESCO_CONNECTION (0x0028 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_ACCEPT_ESCO_CONNECTION (0x0029 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REJECT_ESCO_CONNECTION (0x002A | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAPABILITY_RESPONSE (0x002B | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_REQUEST_REPLY (0x002C | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_CONF_VALUE_NEG_REPLY (0x002D | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_REPLY (0x002E | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_USER_PASSKEY_REQ_NEG_REPLY (0x002F | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_REPLY (0x0030 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_REM_OOB_DATA_REQ_NEG_REPLY (0x0033 | HCI_GRP_LINK_CONTROL_CMDS)
+#define HCI_IO_CAP_REQ_NEG_REPLY (0x0034 | HCI_GRP_LINK_CONTROL_CMDS)
+
+#define HCI_LINK_CTRL_CMDS_FIRST HCI_INQUIRY
+#define HCI_LINK_CTRL_CMDS_LAST HCI_IO_CAP_REQ_NEG_REPLY
+
+/* Commands of HCI_GRP_LINK_POLICY_CMDS */
+#define HCI_HOLD_MODE (0x0001 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_MODE (0x0003 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_SNIFF_MODE (0x0004 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_PARK_MODE (0x0005 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_EXIT_PARK_MODE (0x0006 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_QOS_SETUP (0x0007 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_ROLE_DISCOVERY (0x0009 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SWITCH_ROLE (0x000B | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_POLICY_SETTINGS (0x000C | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_POLICY_SETTINGS (0x000D | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_READ_DEF_POLICY_SETTINGS (0x000E | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_WRITE_DEF_POLICY_SETTINGS (0x000F | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_FLOW_SPECIFICATION (0x0010 | HCI_GRP_LINK_POLICY_CMDS)
+#define HCI_SNIFF_SUB_RATE (0x0011 | HCI_GRP_LINK_POLICY_CMDS)
+
+#define HCI_LINK_POLICY_CMDS_FIRST HCI_HOLD_MODE
+#define HCI_LINK_POLICY_CMDS_LAST HCI_SNIFF_SUB_RATE
+
+
+/* Commands of HCI_GRP_HOST_CONT_BASEBAND_CMDS */
+#define HCI_SET_EVENT_MASK (0x0001 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_RESET (0x0003 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_EVENT_FILTER (0x0005 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_FLUSH (0x0008 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PIN_TYPE (0x0009 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PIN_TYPE (0x000A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CREATE_NEW_UNIT_KEY (0x000B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_STORED_LINK_KEY (0x000D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_STORED_LINK_KEY (0x0011 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_DELETE_STORED_LINK_KEY (0x0012 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_CHANGE_LOCAL_NAME (0x0013 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_NAME (0x0014 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CONN_ACCEPT_TOUT (0x0015 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CONN_ACCEPT_TOUT (0x0016 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGE_TOUT (0x0017 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGE_TOUT (0x0018 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCAN_ENABLE (0x0019 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCAN_ENABLE (0x001A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_CFG (0x001B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_CFG (0x001C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRYSCAN_CFG (0x001D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRYSCAN_CFG (0x001E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTHENTICATION_ENABLE (0x001F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTHENTICATION_ENABLE (0x0020 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_ENCRYPTION_MODE (0x0021 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_ENCRYPTION_MODE (0x0022 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CLASS_OF_DEVICE (0x0023 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CLASS_OF_DEVICE (0x0024 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_VOICE_SETTINGS (0x0025 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_VOICE_SETTINGS (0x0026 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AUTO_FLUSH_TOUT (0x0027 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AUTO_FLUSH_TOUT (0x0028 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_BCAST_REXMITS (0x0029 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_NUM_BCAST_REXMITS (0x002A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_HOLD_MODE_ACTIVITY (0x002B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_HOLD_MODE_ACTIVITY (0x002C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_TRANSMIT_POWER_LEVEL (0x002D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SCO_FLOW_CTRL_ENABLE (0x002E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SCO_FLOW_CTRL_ENABLE (0x002F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_HC_TO_HOST_FLOW_CTRL (0x0031 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_BUFFER_SIZE (0x0033 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_HOST_NUM_PACKETS_DONE (0x0035 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LINK_SUPER_TOUT (0x0036 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_LINK_SUPER_TOUT (0x0037 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_NUM_SUPPORTED_IAC (0x0038 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_CURRENT_IAC_LAP (0x0039 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_CURRENT_IAC_LAP (0x003A | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_PERIOD_MODE (0x003B | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_PERIOD_MODE (0x003C | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_MODE (0x003D | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_MODE (0x003E | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SET_AFH_CHANNELS (0x003F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_READ_INQSCAN_TYPE (0x0042 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQSCAN_TYPE (0x0043 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQUIRY_MODE (0x0044 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQUIRY_MODE (0x0045 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_PAGESCAN_TYPE (0x0046 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_PAGESCAN_TYPE (0x0047 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_AFH_ASSESSMENT_MODE (0x0048 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_AFH_ASSESSMENT_MODE (0x0049 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_EXT_INQ_RESPONSE (0x0051 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_EXT_INQ_RESPONSE (0x0052 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_REFRESH_ENCRYPTION_KEY (0x0053 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_SIMPLE_PAIRING_MODE (0x0055 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_SIMPLE_PAIRING_MODE (0x0056 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_LOCAL_OOB_DATA (0x0057 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_READ_INQ_TX_POWER_LEVEL (0x0058 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_WRITE_INQ_TX_POWER_LEVEL (0x0059 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+#define HCI_SEND_KEYPRESS_NOTIF (0x0060 | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_ENHANCED_FLUSH (0x005F | HCI_GRP_HOST_CONT_BASEBAND_CMDS)
+
+#define HCI_CONT_BASEBAND_CMDS_FIRST HCI_SET_EVENT_MASK
+#define HCI_CONT_BASEBAND_CMDS_LAST HCI_SEND_KEYPRESS_NOTIF
+
+
+/* Commands of HCI_GRP_INFORMATIONAL_PARAMS group */
+#define HCI_READ_LOCAL_VERSION_INFO (0x0001 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_SUPPORTED_CMDS (0x0002 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_FEATURES (0x0003 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_LOCAL_EXT_FEATURES (0x0004 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BUFFER_SIZE (0x0005 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_COUNTRY_CODE (0x0007 | HCI_GRP_INFORMATIONAL_PARAMS)
+#define HCI_READ_BD_ADDR (0x0009 | HCI_GRP_INFORMATIONAL_PARAMS)
+
+#define HCI_INFORMATIONAL_CMDS_FIRST HCI_READ_LOCAL_VERSION_INFO
+#define HCI_INFORMATIONAL_CMDS_LAST HCI_READ_BD_ADDR
+
+
+/* Commands of HCI_GRP_STATUS_PARAMS group */
+#define HCI_READ_FAILED_CONTACT_COUNT (0x0001 | HCI_GRP_STATUS_PARAMS)
+#define HCI_RESET_FAILED_CONTACT_COUNT (0x0002 | HCI_GRP_STATUS_PARAMS)
+#define HCI_GET_LINK_QUALITY (0x0003 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_RSSI (0x0005 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_AFH_CH_MAP (0x0006 | HCI_GRP_STATUS_PARAMS)
+#define HCI_READ_CLOCK (0x0007 | HCI_GRP_STATUS_PARAMS)
+
+#define HCI_STATUS_PARAMS_CMDS_FIRST HCI_READ_FAILED_CONTACT_COUNT
+#define HCI_STATUS_PARAMS_CMDS_LAST HCI_READ_CLOCK
+
+/* Commands of HCI_GRP_TESTING_CMDS group */
+#define HCI_READ_LOOPBACK_MODE (0x0001 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_LOOPBACK_MODE (0x0002 | HCI_GRP_TESTING_CMDS)
+#define HCI_ENABLE_DEV_UNDER_TEST_MODE (0x0003 | HCI_GRP_TESTING_CMDS)
+#define HCI_WRITE_SIMP_PAIR_DEBUG_MODE (0x0004 | HCI_GRP_TESTING_CMDS)
+
+#define HCI_TESTING_CMDS_FIRST HCI_READ_LOOPBACK_MODE
+#define HCI_TESTING_CMDS_LAST HCI_WRITE_SIMP_PAIR_DEBUG_MODE
+
+#define HCI_VENDOR_CMDS_FIRST 0x0001
+#define HCI_VENDOR_CMDS_LAST 0xFFFF
+
+
+/* Vendor specific commands for BRCM chipset */
+#define HCI_BRCM_UPDATE_BAUD_RATE_ENCODED_LENGTH 0x02
+#define HCI_BRCM_UPDATE_BAUD_RATE_UNENCODED_LENGTH 0x06
+#define HCI_BRCM_WRITE_SLEEP_MODE_LENGTH 10
+#define HCI_BRCM_FM_OPCODE (0x0015 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_UPDATE_BAUDRATE_CMD (0x0018 | HCI_GRP_VENDOR_SPECIFIC) /* set baudrate of BCM2035 */
+#define HCI_BRCM_WRITE_SLEEP_MODE (0x0027 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_READ_SLEEP_MODE (0x0028 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_H4IBSS_CMD (0x0029 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_DOWNLOAD_MINI_DRV (0x002E | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_READ_USER_DEFINED_NVRAM (0x0033 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_ENABLE_RADIO (0x0034 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_READ_DIAGNOSTIC_VALUE (0x0035 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_GET_HID_DEVICE_LIST (0x0036 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_ADD_HID_DEVICE (0x0037 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_WRITE_HID_DEVICE_NVRAM (0x0038 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_DELETE_HID_DEVICE (0x0039 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_ENABLE_USB_HID_EMULATION (0x003B | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_BTW_STARTUP (0x0053 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_SET_ACL_PRIORITY (0x0057 | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_WRITE_RAM (0x004C | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_LAUNCH_RAM (0x004E | HCI_GRP_VENDOR_SPECIFIC)
+
+/* Dual Stack */
+#define HCI_BRCM_PAUSE_TRANSPORT (0x007A | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_TRANSPORT_RESUME (0x007B | HCI_GRP_VENDOR_SPECIFIC)
+#define HCI_BRCM_TRANSPORT_ERROR_EVT 0x0C
+
+/* Parameter information for HCI_BRCM_SET_ACL_PRIORITY */
+#define HCI_BRCM_ACL_PRIORITY_PARAM_SIZE 3
+#define HCI_BRCM_ACL_PRIORITY_LOW 0x00
+#define HCI_BRCM_ACL_PRIORITY_HIGH 0xFF
+
+#define HCI_BRCM_UPDATE_BAUD_RATE_ENCODED_LENGTH 0x02
+#define HCI_BRCM_UPDATE_BAUD_RATE_UNENCODED_LENGTH 0x06
+#define HCI_BRCM_WRITE_SLEEP_MODE_LENGTH 10
+#define HCI_BRCM_PAUSE_TRANSPORT_LENGTH 6
+
+/* Broadcom-specific SCO routing */
+#define HCI_BRCM_Write_SCO_PCM_Int_Params (0x001c | HCI_GRP_VENDOR_SPECIFIC)
+#define BRCM_SCO_PCM_Int_Params_ROUTING_PCM 0
+#define BRCM_SCO_PCM_Int_Params_ROUTING_TRANSPORT 1
+
+#define HCI_BRCM_SYNC_PACKET_TYPE (0x006B | HCI_GRP_VENDOR_SPECIFIC)
+
+#define HCI_BRCM_UIPC_OVER_HCI (0x008B | HCI_GRP_VENDOR_SPECIFIC)
+
+/*
+** Definitions for HCI Events
+*/
+#define HCI_INQUIRY_COMP_EVT 0x01
+#define HCI_INQUIRY_RESULT_EVT 0x02
+#define HCI_CONNECTION_COMP_EVT 0x03
+#define HCI_CONNECTION_REQUEST_EVT 0x04
+#define HCI_DISCONNECTION_COMP_EVT 0x05
+#define HCI_AUTHENTICATION_COMP_EVT 0x06
+#define HCI_RMT_NAME_REQUEST_COMP_EVT 0x07
+#define HCI_ENCRYPTION_CHANGE_EVT 0x08
+#define HCI_CHANGE_CONN_LINK_KEY_EVT 0x09
+#define HCI_MASTER_LINK_KEY_COMP_EVT 0x0A
+#define HCI_READ_RMT_FEATURES_COMP_EVT 0x0B
+#define HCI_READ_RMT_VERSION_COMP_EVT 0x0C
+#define HCI_QOS_SETUP_COMP_EVT 0x0D
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_HARDWARE_ERROR_EVT 0x10
+#define HCI_FLUSH_OCCURED_EVT 0x11
+#define HCI_ROLE_CHANGE_EVT 0x12
+#define HCI_NUM_COMPL_DATA_PKTS_EVT 0x13
+#define HCI_MODE_CHANGE_EVT 0x14
+#define HCI_RETURN_LINK_KEYS_EVT 0x15
+#define HCI_PIN_CODE_REQUEST_EVT 0x16
+#define HCI_LINK_KEY_REQUEST_EVT 0x17
+#define HCI_LINK_KEY_NOTIFICATION_EVT 0x18
+#define HCI_LOOPBACK_COMMAND_EVT 0x19
+#define HCI_DATA_BUF_OVERFLOW_EVT 0x1A
+#define HCI_MAX_SLOTS_CHANGED_EVT 0x1B
+#define HCI_READ_CLOCK_OFF_COMP_EVT 0x1C
+#define HCI_CONN_PKT_TYPE_CHANGE_EVT 0x1D
+#define HCI_QOS_VIOLATION_EVT 0x1E
+#define HCI_PAGE_SCAN_MODE_CHANGE_EVT 0x1F
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EVT 0x20
+#define HCI_FLOW_SPECIFICATION_COMP_EVT 0x21
+#define HCI_INQUIRY_RSSI_RESULT_EVT 0x22
+#define HCI_READ_RMT_EXT_FEATURES_COMP_EVT 0x23
+#define HCI_ESCO_CONNECTION_COMP_EVT 0x2C
+#define HCI_ESCO_CONNECTION_CHANGED_EVT 0x2D
+#define HCI_SNIFF_SUB_RATE_EVT 0x2E
+#define HCI_EXTENDED_INQUIRY_RESULT_EVT 0x2F
+#define HCI_ENCRYPTION_KEY_REFRESH_COMP_EVT 0x30
+#define HCI_IO_CAPABILITY_REQUEST_EVT 0x31
+#define HCI_IO_CAPABILITY_RESPONSE_EVT 0x32
+#define HCI_USER_CONFIRMATION_REQUEST_EVT 0x33
+#define HCI_USER_PASSKEY_REQUEST_EVT 0x34
+#define HCI_REMOTE_OOB_DATA_REQUEST_EVT 0x35
+#define HCI_SIMPLE_PAIRING_COMPLETE_EVT 0x36
+#define HCI_LINK_SUPER_TOUT_CHANGED_EVT 0x38
+#define HCI_ENHANCED_FLUSH_COMPLETE_EVT 0x39
+#define HCI_USER_PASSKEY_NOTIFY_EVT 0x3B
+#define HCI_KEYPRESS_NOTIFY_EVT 0x3C
+#define HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT 0x3D
+
+#define HCI_EVENT_RSP_FIRST HCI_INQUIRY_COMP_EVT
+#define HCI_EVENT_RSP_LAST HCI_RMT_HOST_SUP_FEAT_NOTIFY_EVT
+
+#define HCI_BRCM_H4IBSS_EVT 0xEF /* Vendor specific events for H4IBSS */
+#define HCI_VENDOR_SPECIFIC_EVT 0xFF /* Vendor specific events */
+#define HCI_NAP_TRACE_EVT 0xFF /* was define 0xFE, 0xFD, change to 0xFF
+ because conflict w/ TCI_EVT and per
+ specification compliant */
+
+/*
+** HCI Error Codes definition
+*/
+#define HCI_SUCCESS 0x00
+#define HCI_PENDING 0x00
+#define HCI_ERR_ILLEGAL_COMMAND 0x01
+#define HCI_ERR_NO_CONNECTION 0x02
+#define HCI_ERR_HW_FAILURE 0x03
+#define HCI_ERR_PAGE_TIMEOUT 0x04
+#define HCI_ERR_AUTH_FAILURE 0x05
+#define HCI_ERR_KEY_MISSING 0x06
+#define HCI_ERR_MEMORY_FULL 0x07
+#define HCI_ERR_CONNECTION_TOUT 0x08
+#define HCI_ERR_MAX_NUM_OF_CONNECTIONS 0x09
+#define HCI_ERR_MAX_NUM_OF_SCOS 0x0A
+#define HCI_ERR_CONNECTION_EXISTS 0x0B
+#define HCI_ERR_COMMAND_DISALLOWED 0x0C
+#define HCI_ERR_HOST_REJECT_RESOURCES 0x0D
+#define HCI_ERR_HOST_REJECT_SECURITY 0x0E
+#define HCI_ERR_HOST_REJECT_DEVICE 0x0F
+#define HCI_ERR_HOST_TIMEOUT 0x10
+#define HCI_ERR_UNSUPPORTED_VALUE 0x11
+#define HCI_ERR_ILLEGAL_PARAMETER_FMT 0x12
+#define HCI_ERR_PEER_USER 0x13
+#define HCI_ERR_PEER_LOW_RESOURCES 0x14
+#define HCI_ERR_PEER_POWER_OFF 0x15
+#define HCI_ERR_CONN_CAUSE_LOCAL_HOST 0x16
+#define HCI_ERR_REPEATED_ATTEMPTS 0x17
+#define HCI_ERR_PAIRING_NOT_ALLOWED 0x18
+#define HCI_ERR_UNKNOWN_LMP_PDU 0x19
+#define HCI_ERR_UNSUPPORTED_REM_FEATURE 0x1A
+#define HCI_ERR_SCO_OFFSET_REJECTED 0x1B
+#define HCI_ERR_SCO_INTERVAL_REJECTED 0x1C
+#define HCI_ERR_SCO_AIR_MODE 0x1D
+#define HCI_ERR_INVALID_LMP_PARAM 0x1E
+#define HCI_ERR_UNSPECIFIED 0x1F
+#define HCI_ERR_UNSUPPORTED_LMP_FEATURE 0x20
+#define HCI_ERR_ROLE_CHANGE_NOT_ALLOWED 0x21
+#define HCI_ERR_LMP_RESPONSE_TIMEOUT 0x22
+#define HCI_ERR_LMP_ERR_TRANS_COLLISION 0x23
+#define HCI_ERR_LMP_PDU_NOT_ALLOWED 0x24
+#define HCI_ERR_ENCRY_MODE_NOT_ACCEPTABLE 0x25
+#define HCI_ERR_UNIT_KEY_USED 0x26
+#define HCI_ERR_QOS_NOT_SUPPORTED 0x27
+#define HCI_ERR_INSTANT_PASSED 0x28
+#define HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPPORTED 0x29
+#define HCI_ERR_DIFF_TRANSACTION_COLLISION 0x2A
+#define HCI_ERR_UNDEFINED_0x2B 0x2B
+#define HCI_ERR_QOS_UNACCEPTABLE_PARAM 0x2C
+#define HCI_ERR_QOS_REJECTED 0x2D
+#define HCI_ERR_CHAN_CLASSIF_NOT_SUPPORTED 0x2E
+#define HCI_ERR_INSUFFCIENT_SECURITY 0x2F
+#define HCI_ERR_PARAM_OUT_OF_RANGE 0x30
+#define HCI_ERR_UNDEFINED_0x31 0x31
+#define HCI_ERR_ROLE_SWITCH_PENDING 0x32
+#define HCI_ERR_UNDEFINED_0x33 0x33
+#define HCI_ERR_RESERVED_SLOT_VIOLATION 0x34
+#define HCI_ERR_ROLE_SWITCH_FAILED 0x35
+#define HCI_ERR_INQ_RSP_DATA_TOO_LARGE 0x36
+#define HCI_ERR_SIMPLE_PAIRING_NOT_SUPPORTED 0x37
+#define HCI_ERR_HOST_BUSY_PAIRING 0x38
+
+#define HCI_ERR_MAX_ERR 0x38
+
+/*
+** Definitions for HCI enable event
+*/
+#define HCI_INQUIRY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000001)
+#define HCI_INQUIRY_RESULT_EV(p) (*((UINT32 *)(p)) & 0x00000002)
+#define HCI_CONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000004)
+#define HCI_CONNECTION_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00000008)
+#define HCI_DISCONNECTION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000010)
+#define HCI_AUTHENTICATION_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000020)
+#define HCI_RMT_NAME_REQUEST_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000040)
+#define HCI_CHANGE_CONN_ENCRPT_ENABLE_EV(p) (*((UINT32 *)(p)) & 0x00000080)
+#define HCI_CHANGE_CONN_LINK_KEY_EV(p) (*((UINT32 *)(p)) & 0x00000100)
+#define HCI_MASTER_LINK_KEY_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00000200)
+#define HCI_READ_RMT_FEATURES_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000400)
+#define HCI_READ_RMT_VERSION_COMPL_EV(p) (*((UINT32 *)(p)) & 0x00000800)
+#define HCI_QOS_SETUP_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00001000)
+#define HCI_COMMAND_COMPLETE_EV(p) (*((UINT32 *)(p)) & 0x00002000)
+#define HCI_COMMAND_STATUS_EV(p) (*((UINT32 *)(p)) & 0x00004000)
+#define HCI_HARDWARE_ERROR_EV(p) (*((UINT32 *)(p)) & 0x00008000)
+#define HCI_FLASH_OCCURED_EV(p) (*((UINT32 *)(p)) & 0x00010000)
+#define HCI_ROLE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00020000)
+#define HCI_NUM_COMPLETED_PKTS_EV(p) (*((UINT32 *)(p)) & 0x00040000)
+#define HCI_MODE_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x00080000)
+#define HCI_RETURN_LINK_KEYS_EV(p) (*((UINT32 *)(p)) & 0x00100000)
+#define HCI_PIN_CODE_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00200000)
+#define HCI_LINK_KEY_REQUEST_EV(p) (*((UINT32 *)(p)) & 0x00400000)
+#define HCI_LINK_KEY_NOTIFICATION_EV(p) (*((UINT32 *)(p)) & 0x00800000)
+#define HCI_LOOPBACK_COMMAND_EV(p) (*((UINT32 *)(p)) & 0x01000000)
+#define HCI_DATA_BUF_OVERFLOW_EV(p) (*((UINT32 *)(p)) & 0x02000000)
+#define HCI_MAX_SLOTS_CHANGE_EV(p) (*((UINT32 *)(p)) & 0x04000000)
+#define HCI_READ_CLOCK_OFFSET_COMP_EV(p) (*((UINT32 *)(p)) & 0x08000000)
+#define HCI_CONN_PKT_TYPE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x10000000)
+#define HCI_QOS_VIOLATION_EV(p) (*((UINT32 *)(p)) & 0x20000000)
+#define HCI_PAGE_SCAN_MODE_CHANGED_EV(p) (*((UINT32 *)(p)) & 0x40000000)
+#define HCI_PAGE_SCAN_REP_MODE_CHNG_EV(p) (*((UINT32 *)(p)) & 0x80000000)
+
+/* the default event mask for 2.1+EDR (Lisbon) does not include Lisbon events */
+#define HCI_DEFAULT_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_DEFAULT_EVENT_MASK_1 0x00001FFF
+
+/* the event mask for 2.1+EDR include Lisbon events */
+#define HCI_LISBON_EVENT_MASK_0 0xFFFFFFFF
+#define HCI_LISBON_EVENT_MASK_1 0x1DBFFFFF
+#define HCI_LISBON_EVENT_MASK "\x0D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+#define HCI_LISBON_EVENT_MASK_EXT "\x1D\xBF\xFF\xFF\xFF\xFF\xFF\xFF"
+/* 0x00001FFF FFFFFFFF Default - no Lisbon events
+ 0x00002000 00000000 Sniff Subrate Event
+ 0x00004000 00000000 Extended Inquiry Result Event
+ 0x00008000 00000000 Encryption Key Refresh Complete Event
+ 0x00010000 00000000 IO Capability Request Event
+ 0x00020000 00000000 IO Capability Response Event
+ 0x00040000 00000000 User Confirmation Request Event
+ 0x00080000 00000000 User Passkey Request Event
+ 0x00100000 00000000 Remote OOB Data Request Event
+ 0x00200000 00000000 Simple Pairing Complete Event
+ 0x00800000 00000000 Link Supervision Timeout Changed Event
+ 0x01000000 00000000 Enhanced Flush Complete Event
+ 0x04000000 00000000 User Passkey Notification Event
+ 0x08000000 00000000 Keypress Notification Event
+ 0x10000000 00000000 Remote Host Supported Features Notification Event
+ */
+
+/*
+** Definitions for packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_PKT_TYPES_MASK_NO_2_DH1 0x0002
+#define HCI_PKT_TYPES_MASK_NO_3_DH1 0x0004
+#define HCI_PKT_TYPES_MASK_DM1 0x0008
+#define HCI_PKT_TYPES_MASK_DH1 0x0010
+#define HCI_PKT_TYPES_MASK_HV1 0x0020
+#define HCI_PKT_TYPES_MASK_HV2 0x0040
+#define HCI_PKT_TYPES_MASK_HV3 0x0080
+#define HCI_PKT_TYPES_MASK_NO_2_DH3 0x0100
+#define HCI_PKT_TYPES_MASK_NO_3_DH3 0x0200
+#define HCI_PKT_TYPES_MASK_DM3 0x0400
+#define HCI_PKT_TYPES_MASK_DH3 0x0800
+#define HCI_PKT_TYPES_MASK_NO_2_DH5 0x1000
+#define HCI_PKT_TYPES_MASK_NO_3_DH5 0x2000
+#define HCI_PKT_TYPES_MASK_DM5 0x4000
+#define HCI_PKT_TYPES_MASK_DH5 0x8000
+
+/* Packet type should be one of valid but at least one should be specified */
+#define HCI_VALID_SCO_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_HV1 \
+ | HCI_PKT_TYPES_MASK_HV2 \
+ | HCI_PKT_TYPES_MASK_HV3)) == 0)) \
+ && ((t) != 0))
+
+
+
+
+
+/* Packet type should not be invalid and at least one should be specified */
+#define HCI_VALID_ACL_PKT_TYPE(t) (((((t) & ~(HCI_PKT_TYPES_MASK_DM1 \
+ | HCI_PKT_TYPES_MASK_DH1 \
+ | HCI_PKT_TYPES_MASK_DM3 \
+ | HCI_PKT_TYPES_MASK_DH3 \
+ | HCI_PKT_TYPES_MASK_DM5 \
+ | HCI_PKT_TYPES_MASK_DH5 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH1 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH1 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH3 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH3 \
+ | HCI_PKT_TYPES_MASK_NO_2_DH5 \
+ | HCI_PKT_TYPES_MASK_NO_3_DH5 )) == 0)) \
+ && (((t) & (HCI_PKT_TYPES_MASK_DM1 \
+ | HCI_PKT_TYPES_MASK_DH1 \
+ | HCI_PKT_TYPES_MASK_DM3 \
+ | HCI_PKT_TYPES_MASK_DH3 \
+ | HCI_PKT_TYPES_MASK_DM5 \
+ | HCI_PKT_TYPES_MASK_DH5)) != 0))
+
+
+
+/*
+** Definitions for eSCO packet type masks (BT1.2 and BT2.0 definitions)
+*/
+#define HCI_ESCO_PKT_TYPES_MASK_HV1 0x0001
+#define HCI_ESCO_PKT_TYPES_MASK_HV2 0x0002
+#define HCI_ESCO_PKT_TYPES_MASK_HV3 0x0004
+#define HCI_ESCO_PKT_TYPES_MASK_EV3 0x0008
+#define HCI_ESCO_PKT_TYPES_MASK_EV4 0x0010
+#define HCI_ESCO_PKT_TYPES_MASK_EV5 0x0020
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV3 0x0040
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV3 0x0080
+#define HCI_ESCO_PKT_TYPES_MASK_NO_2_EV5 0x0100
+#define HCI_ESCO_PKT_TYPES_MASK_NO_3_EV5 0x0200
+
+/* Packet type should be one of valid but at least one should be specified for 1.2 */
+#define HCI_VALID_ESCO_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_EV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV4 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+ && ((t) != 0))/* Packet type should be one of valid but at least one should be specified */
+
+#define HCI_VALID_ESCO_SCOPKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3)) == 0)) \
+ && ((t) != 0))
+
+#define HCI_VALID_SCO_ALL_PKT_TYPE(t) (((((t) & ~(HCI_ESCO_PKT_TYPES_MASK_HV1 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV2 \
+ | HCI_ESCO_PKT_TYPES_MASK_HV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV3 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV4 \
+ | HCI_ESCO_PKT_TYPES_MASK_EV5)) == 0)) \
+ && ((t) != 0))
+
+/*
+** Define parameters to allow role switch during create connection
+*/
+#define HCI_CR_CONN_NOT_ALLOW_SWITCH 0x00
+#define HCI_CR_CONN_ALLOW_SWITCH 0x01
+
+/*
+** Hold Mode command destination
+*/
+#define HOLD_MODE_DEST_LOCAL_DEVICE 0x00
+#define HOLD_MODE_DEST_RMT_DEVICE 0x01
+
+/*
+** Definitions of different HCI parameters
+*/
+#define HCI_PER_INQ_MIN_MAX_PERIOD 0x0003
+#define HCI_PER_INQ_MAX_MAX_PERIOD 0xFFFF
+#define HCI_PER_INQ_MIN_MIN_PERIOD 0x0002
+#define HCI_PER_INQ_MAX_MIN_PERIOD 0xFFFE
+
+#define HCI_MAX_INQUIRY_LENGTH 0x30
+
+#define HCI_MIN_INQ_LAP 0x9E8B00
+#define HCI_MAX_INQ_LAP 0x9E8B3F
+
+/* HCI role definition */
+#define HCI_ROLE_MASTER 0x00
+#define HCI_ROLE_SLAVE 0x01
+#define HCI_ROLE_UNKNOWN 0xff
+
+/* HCI mode definition */
+#define HCI_MODE_ACTIVE 0x00
+#define HCI_MODE_HOLD 0x01
+#define HCI_MODE_SNIFF 0x02
+#define HCI_MODE_PARK 0x03
+
+/* Define Packet types as requested by the Host */
+#define HCI_ACL_PKT_TYPE_NONE 0x0000
+#define HCI_ACL_PKT_TYPE_DM1 0x0008
+#define HCI_ACL_PKT_TYPE_DH1 0x0010
+#define HCI_ACL_PKT_TYPE_AUX1 0x0200
+#define HCI_ACL_PKT_TYPE_DM3 0x0400
+#define HCI_ACL_PKT_TYPE_DH3 0x0800
+#define HCI_ACL_PKT_TYPE_DM5 0x4000
+#define HCI_ACL_PKT_TYPE_DH5 0x8000
+
+/* Define key type in the Master Link Key command */
+#define HCI_USE_SEMI_PERMANENT_KEY 0x00
+#define HCI_USE_TEMPORARY_KEY 0x01
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_REP_MODE_R0 0x00
+#define HCI_PAGE_SCAN_REP_MODE_R1 0x01
+#define HCI_PAGE_SCAN_REP_MODE_R2 0x02
+
+/* Define limits for page scan repetition modes */
+#define HCI_PAGE_SCAN_R1_LIMIT 0x0800
+#define HCI_PAGE_SCAN_R2_LIMIT 0x1000
+
+/* Page scan period modes */
+#define HCI_PAGE_SCAN_PER_MODE_P0 0x00
+#define HCI_PAGE_SCAN_PER_MODE_P1 0x01
+#define HCI_PAGE_SCAN_PER_MODE_P2 0x02
+
+/* Page scan modes */
+#define HCI_MANDATARY_PAGE_SCAN_MODE 0x00
+#define HCI_OPTIONAL_PAGE_SCAN_MODE1 0x01
+#define HCI_OPTIONAL_PAGE_SCAN_MODE2 0x02
+#define HCI_OPTIONAL_PAGE_SCAN_MODE3 0x03
+
+/* Page and inquiry scan types */
+#define HCI_SCAN_TYPE_STANDARD 0x00
+#define HCI_SCAN_TYPE_INTERLACED 0x01 /* 1.2 devices or later */
+#define HCI_DEF_SCAN_TYPE HCI_SCAN_TYPE_STANDARD
+
+/* Definitions for quality of service service types */
+#define HCI_SERVICE_NO_TRAFFIC 0x00
+#define HCI_SERVICE_BEST_EFFORT 0x01
+#define HCI_SERVICE_GUARANTEED 0x02
+
+#define HCI_QOS_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+#define HCI_QOS_DELAY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for Flow Specification */
+#define HCI_FLOW_SPEC_LATENCY_DO_NOT_CARE 0xFFFFFFFF
+
+/* Definitions for AFH Channel Map */
+#define HCI_AFH_CHANNEL_MAP_LEN 10
+
+/* Definitions for Extended Inquiry Response */
+#define HCI_EXT_INQ_RESPONSE_LEN 240
+#define HCI_EIR_FLAGS_TYPE 0x01
+#define HCI_EIR_MORE_16BITS_UUID_TYPE 0x02
+#define HCI_EIR_COMPLETE_16BITS_UUID_TYPE 0x03
+#define HCI_EIR_MORE_32BITS_UUID_TYPE 0x04
+#define HCI_EIR_COMPLETE_32BITS_UUID_TYPE 0x05
+#define HCI_EIR_MORE_128BITS_UUID_TYPE 0x06
+#define HCI_EIR_COMPLETE_128BITS_UUID_TYPE 0x07
+#define HCI_EIR_SHORTENED_LOCAL_NAME_TYPE 0x08
+#define HCI_EIR_COMPLETE_LOCAL_NAME_TYPE 0x09
+#define HCI_EIR_TX_POWER_LEVEL_TYPE 0x0A
+#define HCI_EIR_MANUFACTURER_SPECIFIC_TYPE 0xFF
+
+/* Definitions for Write Simple Pairing Mode */
+#define HCI_SP_MODE_UNDEFINED 0x00
+#define HCI_SP_MODE_ENABLED 0x01
+
+/* Definitions for Write Simple Pairing Debug Mode */
+#define HCI_SPD_MODE_DISABLED 0x00
+#define HCI_SPD_MODE_ENABLED 0x01
+
+/* Definitions for IO Capability Response/Command */
+#define HCI_IO_CAP_DISPLAY_ONLY 0x00
+#define HCI_IO_CAP_DISPLAY_YESNO 0x01
+#define HCI_IO_CAP_KEYBOARD_ONLY 0x02
+#define HCI_IO_CAP_NO_IO 0x03
+
+#define HCI_OOB_AUTH_DATA_NOT_PRESENT 0x00
+#define HCI_OOB_REM_AUTH_DATA_PRESENT 0x01
+
+#define HCI_MITM_PROTECT_NOT_REQUIRED 0x00
+#define HCI_MITM_PROTECT_REQUIRED 0x01
+
+
+/* Policy settings status */
+#define HCI_DISABLE_ALL_LM_MODES 0x0000
+#define HCI_ENABLE_MASTER_SLAVE_SWITCH 0x0001
+#define HCI_ENABLE_HOLD_MODE 0x0002
+#define HCI_ENABLE_SNIFF_MODE 0x0004
+#define HCI_ENABLE_PARK_MODE 0x0008
+
+/* By default allow switch, because host can not allow that */
+/* that until he created the connection */
+#define HCI_DEFAULT_POLICY_SETTINGS HCI_DISABLE_ALL_LM_MODES
+
+/* Filters that are sent in set filter command */
+#define HCI_FILTER_TYPE_CLEAR_ALL 0x00
+#define HCI_FILTER_INQUIRY_RESULT 0x01
+#define HCI_FILTER_CONNECTION_SETUP 0x02
+
+#define HCI_FILTER_COND_NEW_DEVICE 0x00
+#define HCI_FILTER_COND_DEVICE_CLASS 0x01
+#define HCI_FILTER_COND_BD_ADDR 0x02
+
+#define HCI_DO_NOT_AUTO_ACCEPT_CONNECT 1
+#define HCI_DO_AUTO_ACCEPT_CONNECT 2 /* role switch disabled */
+#define HCI_DO_AUTO_ACCEPT_CONNECT_RS 3 /* role switch enabled (1.1 errata 1115) */
+
+/* Auto accept flags */
+#define HCI_AUTO_ACCEPT_OFF 0x00
+#define HCI_AUTO_ACCEPT_ACL_CONNECTIONS 0x01
+#define HCI_AUTO_ACCEPT_SCO_CONNECTIONS 0x02
+
+/* PIN type */
+#define HCI_PIN_TYPE_VARIABLE 0
+#define HCI_PIN_TYPE_FIXED 1
+
+/* Loopback Modes */
+#define HCI_LOOPBACK_MODE_DISABLED 0
+#define HCI_LOOPBACK_MODE_LOCAL 1
+#define HCI_LOOPBACK_MODE_REMOTE 2
+
+#define SLOTS_PER_10MS 16 /* 0.625 ms slots in a 10 ms tick */
+
+/* Maximum connection accept timeout in 0.625msec */
+#define HCI_MAX_CONN_ACCEPT_TOUT 0xB540 /* 29 sec */
+#define HCI_DEF_CONN_ACCEPT_TOUT 0x1FA0 /* 5 sec */
+
+/* Page timeout is used in LC only and LC is counting down slots not using OS */
+#define HCI_DEFAULT_PAGE_TOUT 0x2000 /* 5.12 sec (in slots) */
+
+/* Scan enable flags */
+#define HCI_NO_SCAN_ENABLED 0x00
+#define HCI_INQUIRY_SCAN_ENABLED 0x01
+#define HCI_PAGE_SCAN_ENABLED 0x02
+
+/* Pagescan timer definitions in 0.625 ms */
+#define HCI_MIN_PAGESCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_INTERVAL 0x0800 /* 1.28 sec */
+
+/* Parameter for pagescan window is passed to LC and is kept in slots */
+#define HCI_MIN_PAGESCAN_WINDOW 0x12 /* 11.25 ms */
+#define HCI_MAX_PAGESCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_PAGESCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Inquiryscan timer definitions in 0.625 ms */
+#define HCI_MIN_INQUIRYSCAN_INTERVAL 0x12 /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_INTERVAL 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_INTERVAL 0x0800 /* 1.28 sec */
+
+/* Parameter for inquiryscan window is passed to LC and is kept in slots */
+#define HCI_MIN_INQUIRYSCAN_WINDOW 0x12 /* 11.25 ms */
+#define HCI_MAX_INQUIRYSCAN_WINDOW 0x1000 /* 2.56 sec */
+#define HCI_DEF_INQUIRYSCAN_WINDOW 0x12 /* 11.25 ms */
+
+/* Encryption modes */
+#define HCI_ENCRYPT_MODE_DISABLED 0x00
+#define HCI_ENCRYPT_MODE_POINT_TO_POINT 0x01
+#define HCI_ENCRYPT_MODE_ALL 0x02
+
+/* Voice settings */
+#define HCI_INP_CODING_LINEAR 0x0000 /* 0000000000 */
+#define HCI_INP_CODING_U_LAW 0x0100 /* 0100000000 */
+#define HCI_INP_CODING_A_LAW 0x0200 /* 1000000000 */
+#define HCI_INP_CODING_MASK 0x0300 /* 1100000000 */
+
+#define HCI_INP_DATA_FMT_1S_COMPLEMENT 0x0000 /* 0000000000 */
+#define HCI_INP_DATA_FMT_2S_COMPLEMENT 0x0040 /* 0001000000 */
+#define HCI_INP_DATA_FMT_SIGN_MAGNITUDE 0x0080 /* 0010000000 */
+#define HCI_INP_DATA_FMT_UNSIGNED 0x00c0 /* 0011000000 */
+#define HCI_INP_DATA_FMT_MASK 0x00c0 /* 0011000000 */
+
+#define HCI_INP_SAMPLE_SIZE_8BIT 0x0000 /* 0000000000 */
+#define HCI_INP_SAMPLE_SIZE_16BIT 0x0020 /* 0000100000 */
+#define HCI_INP_SAMPLE_SIZE_MASK 0x0020 /* 0000100000 */
+
+#define HCI_INP_LINEAR_PCM_BIT_POS_MASK 0x001c /* 0000011100 */
+#define HCI_INP_LINEAR_PCM_BIT_POS_OFFS 2
+
+#define HCI_AIR_CODING_FORMAT_CVSD 0x0000 /* 0000000000 */
+#define HCI_AIR_CODING_FORMAT_U_LAW 0x0001 /* 0000000001 */
+#define HCI_AIR_CODING_FORMAT_A_LAW 0x0002 /* 0000000010 */
+#define HCI_AIR_CODING_FORMAT_TRANSPNT 0x0003 /* 0000000011 */
+#define HCI_AIR_CODING_FORMAT_MASK 0x0003 /* 0000000011 */
+
+/* default 0001100000 */
+#define HCI_DEFAULT_VOICE_SETTINGS (HCI_INP_CODING_LINEAR \
+ | HCI_INP_DATA_FMT_2S_COMPLEMENT \
+ | HCI_INP_SAMPLE_SIZE_16BIT \
+ | HCI_AIR_CODING_FORMAT_CVSD)
+
+#define HCI_CVSD_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_CVSD)
+#define HCI_U_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_U_LAW)
+#define HCI_A_LAW_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_A_LAW)
+#define HCI_TRANSPNT_SUPPORTED(x) (((x) & HCI_AIR_CODING_FORMAT_MASK) == HCI_AIR_CODING_FORMAT_TRANSPNT)
+
+/* Retransmit timer definitions in 0.625 */
+#define HCI_MAX_AUTO_FLUSH_TOUT 0x07FF
+#define HCI_DEFAULT_AUTO_FLUSH_TOUT 0 /* No auto flush */
+
+/* Broadcast retransmitions */
+#define HCI_DEFAULT_NUM_BCAST_RETRAN 1
+
+/* Define broadcast data types as passed in the hci data packet */
+#define HCI_DATA_POINT_TO_POINT 0x00
+#define HCI_DATA_ACTIVE_BCAST 0x01
+#define HCI_DATA_PICONET_BCAST 0x02
+
+/* Hold mode activity */
+#define HCI_MAINTAIN_CUR_POWER_STATE 0x00
+#define HCI_SUSPEND_PAGE_SCAN 0x01
+#define HCI_SUSPEND_INQUIRY_SCAN 0x02
+#define HCI_SUSPEND_PERIODIC_INQUIRIES 0x04
+
+/* Default Link Supervision timeoout */
+#define HCI_DEFAULT_INACT_TOUT 0x7D00 /* 20 seconds */
+
+/* Read transmit power level parameter */
+#define HCI_READ_CURRENT 0x00
+#define HCI_READ_MAXIMUM 0x01
+
+/* Link types for connection complete event */
+#define HCI_LINK_TYPE_SCO 0x00
+#define HCI_LINK_TYPE_ACL 0x01
+#define HCI_LINK_TYPE_ESCO 0x02
+
+/* Link Key Notification Event (Key Type) definitions */
+#define HCI_LKEY_TYPE_COMBINATION 0x00
+#define HCI_LKEY_TYPE_LOCAL_UNIT 0x01
+#define HCI_LKEY_TYPE_REMOTE_UNIT 0x02
+#define HCI_LKEY_TYPE_DEBUG_COMB 0x03
+#define HCI_LKEY_TYPE_UNAUTH_COMB 0x04
+#define HCI_LKEY_TYPE_AUTH_COMB 0x05
+#define HCI_LKEY_TYPE_CHANGED_COMB 0x06
+
+/* Read Local Version HCI Version return values (Command Complete Event) */
+#define HCI_VERSION_1_0B 0x00
+#define HCI_VERSION_1_1 0x01
+
+/* Define an invalid value for a handle */
+#define HCI_INVALID_HANDLE 0xFFFF
+
+/* Define max amount of data in the HCI command */
+#define HCI_COMMAND_SIZE 255
+
+/* Define the preamble length for all HCI Commands.
+** This is 2-bytes for opcode and 1 byte for length
+*/
+#define HCIC_PREAMBLE_SIZE 3
+
+/* Define the preamble length for all HCI Events
+** This is 1-byte for opcode and 1 byte for length
+*/
+#define HCIE_PREAMBLE_SIZE 2
+#define HCI_SCO_PREAMBLE_SIZE 3
+#define HCI_DATA_PREAMBLE_SIZE 4
+
+
+/* HCI message type definitions (for H4 messages) */
+#define HCIT_TYPE_COMMAND 1
+#define HCIT_TYPE_ACL_DATA 2
+#define HCIT_TYPE_SCO_DATA 3
+#define HCIT_TYPE_EVENT 4
+#define HCIT_TYPE_LM_DIAG 7
+
+#define HCIT_LM_DIAG_LENGTH 63
+
+/* Define values for LMP Test Control parameters
+** Test Scenario, Hopping Mode, Power Control Mode
+*/
+#define LMP_TESTCTL_TESTSC_PAUSE 0
+#define LMP_TESTCTL_TESTSC_TXTEST_0 1
+#define LMP_TESTCTL_TESTSC_TXTEST_1 2
+#define LMP_TESTCTL_TESTSC_TXTEST_1010 3
+#define LMP_TESTCTL_TESTSC_PSRND_BITSEQ 4
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_ACL 5
+#define LMP_TESTCTL_TESTSC_CLOSEDLB_SCO 6
+#define LMP_TESTCTL_TESTSC_ACL_NOWHIT 7
+#define LMP_TESTCTL_TESTSC_SCO_NOWHIT 8
+#define LMP_TESTCTL_TESTSC_TXTEST_11110000 9
+#define LMP_TESTCTL_TESTSC_EXITTESTMODE 255
+
+#define LMP_TESTCTL_HOPMOD_RXTX1FREQ 0
+#define LMP_TESTCTL_HOPMOD_HOP_EURUSA 1
+#define LMP_TESTCTL_HOPMOD_HOP_JAPAN 2
+#define LMP_TESTCTL_HOPMOD_HOP_FRANCE 3
+#define LMP_TESTCTL_HOPMOD_HOP_SPAIN 4
+#define LMP_TESTCTL_HOPMOD_REDUCED_HOP 5
+
+#define LMP_TESTCTL_POWCTL_FIXEDTX_OP 0
+#define LMP_TESTCTL_POWCTL_ADAPTIVE 1
+
+
+/*
+** Define company IDs (from Bluetooth Assigned Numbers v1.1, section 2.2)
+*/
+#define LMP_COMPID_ERICSSON 0
+#define LMP_COMPID_NOKIA 1
+#define LMP_COMPID_INTEL 2
+#define LMP_COMPID_IBM 3
+#define LMP_COMPID_TOSHIBA 4
+#define LMP_COMPID_3COM 5
+#define LMP_COMPID_MICROSOFT 6
+#define LMP_COMPID_LUCENT 7
+#define LMP_COMPID_MOTOROLA 8
+#define LMP_COMPID_INFINEON 9
+#define LMP_COMPID_CSR 10
+#define LMP_COMPID_SILICON_WAVE 11
+#define LMP_COMPID_DIGIANSWER 12
+#define LMP_COMPID_TEXAS_INSTRUMENTS 13
+#define LMP_COMPID_PARTHUS 14
+#define LMP_COMPID_BROADCOM 15
+#define LMP_COMPID_MITEL_SEMI 16
+#define LMP_COMPID_WIDCOMM 17
+#define LMP_COMPID_ZEEVO 18
+#define LMP_COMPID_ATMEL 19
+#define LMP_COMPID_MITSUBISHI 20
+#define LMP_COMPID_RTX_TELECOM 21
+#define LMP_COMPID_KC_TECH 22
+#define LMP_COMPID_NEWLOGIC 23
+#define LMP_COMPID_TRANSILICA 24
+#define LMP_COMPID_ROHDE_SCHWARZ 25
+#define LMP_COMPID_TTPCOM 26
+#define LMP_COMPID_SIGNIA 27
+#define LMP_COMPID_CONEXANT 28
+#define LMP_COMPID_QUALCOMM 29
+#define LMP_COMPID_INVENTEL 30
+#define LMP_COMPID_AVM 31
+#define LMP_COMPID_BANDSPEED 32
+#define LMP_COMPID_MANSELLA 33
+#define LMP_COMPID_NEC_CORP 34
+#define LMP_COMPID_WAVEPLUS 35
+#define LMP_COMPID_ALCATEL 36
+#define LMP_COMPID_PHILIPS 37
+#define LMP_COMPID_C_TECHNOLOGIES 38
+#define LMP_COMPID_OPEN_INTERFACE 39
+#define LMP_COMPID_RF_MICRO 40
+#define LMP_COMPID_HITACHI 41
+#define LMP_COMPID_SYMBOL_TECH 42
+#define LMP_COMPID_TENOVIS 43
+#define LMP_COMPID_MACRONIX 44
+#define LMP_COMPID_GCT_SEMI 45
+#define LMP_COMPID_NORWOOD_SYSTEMS 46
+#define LMP_COMPID_MEWTEL_TECH 47
+#define LMP_COMPID_STM 48
+#define LMP_COMPID_SYNOPSYS 49
+#define LMP_COMPID_RED_M_LTD 50
+#define LMP_COMPID_COMMIL_LTD 51
+#define LMP_COMPID_CATC 52
+#define LMP_COMPID_ECLIPSE 53
+#define LMP_COMPID_RENESAS_TECH 54
+#define LMP_COMPID_MOBILIAN_CORP 55
+#define LMP_COMPID_TERAX 56
+#define LMP_COMPID_ISSC 57
+#define LMP_COMPID_MATSUSHITA 58
+#define LMP_COMPID_GENNUM_CORP 59
+#define LMP_COMPID_RESEARCH_IN_MOTION 60
+#define LMP_COMPID_IPEXTREME 61
+#define LMP_COMPID_SYSTEMS_AND_CHIPS 62
+#define LMP_COMPID_BLUETOOTH_SIG 63
+#define LMP_COMPID_SEIKO_EPSON_CORP 64
+#define LMP_COMPID_ISS_TAIWAN 65
+#define LMP_COMPID_CONWISE_TECHNOLOGIES 66
+#define LMP_COMPID_PARROT_SA 67
+#define LMP_COMPID_SOCKET_COMM 68
+#define LMP_COMPID_MAX_ID 69 /* this is a place holder */
+#define LMP_COMPID_INTERNAL 65535
+
+#define MAX_LMP_COMPID (LMP_COMPID_MAX_ID)
+/*
+** Define the packet types in the packet header, and a couple extra
+*/
+#define PKT_TYPE_NULL 0x00
+#define PKT_TYPE_POLL 0x01
+#define PKT_TYPE_FHS 0x02
+#define PKT_TYPE_DM1 0x03
+
+#define PKT_TYPE_DH1 0x04
+#define PKT_TYPE_HV1 0x05
+#define PKT_TYPE_HV2 0x06
+#define PKT_TYPE_HV3 0x07
+#define PKT_TYPE_DV 0x08
+#define PKT_TYPE_AUX1 0x09
+
+#define PKT_TYPE_DM3 0x0a
+#define PKT_TYPE_DH3 0x0b
+
+#define PKT_TYPE_DM5 0x0e
+#define PKT_TYPE_DH5 0x0f
+
+
+#define PKT_TYPE_ID 0x10 /* Internally used packet types */
+#define PKT_TYPE_BAD 0x11
+#define PKT_TYPE_NONE 0x12
+
+/*
+** Define packet size
+*/
+#define HCI_DM1_PACKET_SIZE 17
+#define HCI_DH1_PACKET_SIZE 27
+#define HCI_DM3_PACKET_SIZE 121
+#define HCI_DH3_PACKET_SIZE 183
+#define HCI_DM5_PACKET_SIZE 224
+#define HCI_DH5_PACKET_SIZE 339
+#define HCI_AUX1_PACKET_SIZE 29
+#define HCI_HV1_PACKET_SIZE 10
+#define HCI_HV2_PACKET_SIZE 20
+#define HCI_HV3_PACKET_SIZE 30
+#define HCI_DV_PACKET_SIZE 9
+#define HCI_EDR2_DH1_PACKET_SIZE 54
+#define HCI_EDR2_DH3_PACKET_SIZE 367
+#define HCI_EDR2_DH5_PACKET_SIZE 679
+#define HCI_EDR3_DH1_PACKET_SIZE 83
+#define HCI_EDR3_DH3_PACKET_SIZE 552
+#define HCI_EDR3_DH5_PACKET_SIZE 1021
+
+/*
+** Features encoding - page 0
+*/
+#define HCI_NUM_FEATURE_BYTES 8
+#define HCI_FEATURES_KNOWN(x) ((x[0] | x[1] | x[2] | x[3] | x[4] | x[5] | x[6] | x[7]) != 0)
+
+#define HCI_FEATURE_3_SLOT_PACKETS_MASK 0x01
+#define HCI_FEATURE_3_SLOT_PACKETS_OFF 0
+#define HCI_3_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_PACKETS_OFF] & HCI_FEATURE_3_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_5_SLOT_PACKETS_MASK 0x02
+#define HCI_FEATURE_5_SLOT_PACKETS_OFF 0
+#define HCI_5_SLOT_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_PACKETS_OFF] & HCI_FEATURE_5_SLOT_PACKETS_MASK)
+
+#define HCI_FEATURE_ENCRYPTION_MASK 0x04
+#define HCI_FEATURE_ENCRYPTION_OFF 0
+#define HCI_ENCRYPTION_SUPPORTED(x) ((x)[HCI_FEATURE_ENCRYPTION_OFF] & HCI_FEATURE_ENCRYPTION_MASK)
+
+#define HCI_FEATURE_SLOT_OFFSET_MASK 0x08
+#define HCI_FEATURE_SLOT_OFFSET_OFF 0
+#define HCI_SLOT_OFFSET_SUPPORTED(x) ((x)[HCI_FEATURE_SLOT_OFFSET_OFF] & HCI_FEATURE_SLOT_OFFSET_MASK)
+
+#define HCI_FEATURE_TIMING_ACC_MASK 0x10
+#define HCI_FEATURE_TIMING_ACC_OFF 0
+#define HCI_TIMING_ACC_SUPPORTED(x) ((x)[HCI_FEATURE_TIMING_ACC_OFF] & HCI_FEATURE_TIMING_ACC_MASK)
+
+#define HCI_FEATURE_SWITCH_MASK 0x20
+#define HCI_FEATURE_SWITCH_OFF 0
+#define HCI_SWITCH_SUPPORTED(x) ((x)[HCI_FEATURE_SWITCH_OFF] & HCI_FEATURE_SWITCH_MASK)
+
+#define HCI_FEATURE_HOLD_MODE_MASK 0x40
+#define HCI_FEATURE_HOLD_MODE_OFF 0
+#define HCI_HOLD_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_HOLD_MODE_OFF] & HCI_FEATURE_HOLD_MODE_MASK)
+
+#define HCI_FEATURE_SNIFF_MODE_MASK 0x80
+#define HCI_FEATURE_SNIFF_MODE_OFF 0
+#define HCI_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_MODE_OFF] & HCI_FEATURE_SNIFF_MODE_MASK)
+
+#define HCI_FEATURE_PARK_MODE_MASK 0x01
+#define HCI_FEATURE_PARK_MODE_OFF 1
+#define HCI_PARK_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_PARK_MODE_OFF] & HCI_FEATURE_PARK_MODE_MASK)
+
+#define HCI_FEATURE_RSSI_MASK 0x02
+#define HCI_FEATURE_RSSI_OFF 1
+#define HCI_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_RSSI_OFF] & HCI_FEATURE_RSSI_MASK)
+
+#define HCI_FEATURE_CQM_DATA_RATE_MASK 0x04
+#define HCI_FEATURE_CQM_DATA_RATE_OFF 1
+#define HCI_CQM_DATA_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_CQM_DATA_RATE_OFF] & HCI_FEATURE_CQM_DATA_RATE_MASK)
+
+#define HCI_FEATURE_SCO_LINK_MASK 0x08
+#define HCI_FEATURE_SCO_LINK_OFF 1
+#define HCI_SCO_LINK_SUPPORTED(x) ((x)[HCI_FEATURE_SCO_LINK_OFF] & HCI_FEATURE_SCO_LINK_MASK)
+
+#define HCI_FEATURE_HV2_PACKETS_MASK 0x10
+#define HCI_FEATURE_HV2_PACKETS_OFF 1
+#define HCI_HV2_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV2_PACKETS_OFF] & HCI_FEATURE_HV2_PACKETS_MASK)
+
+#define HCI_FEATURE_HV3_PACKETS_MASK 0x20
+#define HCI_FEATURE_HV3_PACKETS_OFF 1
+#define HCI_HV3_PACKETS_SUPPORTED(x) ((x)[HCI_FEATURE_HV3_PACKETS_OFF] & HCI_FEATURE_HV3_PACKETS_MASK)
+
+#define HCI_FEATURE_U_LAW_MASK 0x40
+#define HCI_FEATURE_U_LAW_OFF 1
+#define HCI_LMP_U_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_U_LAW_OFF] & HCI_FEATURE_U_LAW_MASK)
+
+#define HCI_FEATURE_A_LAW_MASK 0x80
+#define HCI_FEATURE_A_LAW_OFF 1
+#define HCI_LMP_A_LAW_SUPPORTED(x) ((x)[HCI_FEATURE_A_LAW_OFF] & HCI_FEATURE_A_LAW_MASK)
+
+#define HCI_FEATURE_CVSD_MASK 0x01
+#define HCI_FEATURE_CVSD_OFF 2
+#define HCI_LMP_CVSD_SUPPORTED(x) ((x)[HCI_FEATURE_CVSD_OFF] & HCI_FEATURE_CVSD_MASK)
+
+#define HCI_FEATURE_PAGING_SCHEME_MASK 0x02
+#define HCI_FEATURE_PAGING_SCHEME_OFF 2
+#define HCI_PAGING_SCHEME_SUPPORTED(x) ((x)[HCI_FEATURE_PAGING_SCHEME_OFF] & HCI_FEATURE_PAGING_SCHEME_MASK)
+
+#define HCI_FEATURE_POWER_CTRL_MASK 0x04
+#define HCI_FEATURE_POWER_CTRL_OFF 2
+#define HCI_POWER_CTRL_SUPPORTED(x) ((x)[HCI_FEATURE_POWER_CTRL_OFF] & HCI_FEATURE_POWER_CTRL_MASK)
+
+#define HCI_FEATURE_TRANSPNT_MASK 0x08
+#define HCI_FEATURE_TRANSPNT_OFF 2
+#define HCI_LMP_TRANSPNT_SUPPORTED(x) ((x)[HCI_FEATURE_TRANSPNT_OFF] & HCI_FEATURE_TRANSPNT_MASK)
+
+#define HCI_FEATURE_FLOW_CTRL_LAG_MASK 0x70
+#define HCI_FEATURE_FLOW_CTRL_LAG_OFF 2
+#define HCI_FLOW_CTRL_LAG_VALUE(x) (((x)[HCI_FEATURE_FLOW_CTRL_LAG_OFF] & HCI_FEATURE_FLOW_CTRL_LAG_MASK) >> 4)
+
+#define HCI_FEATURE_BROADCAST_ENC_MASK 0x80
+#define HCI_FEATURE_BROADCAST_ENC_OFF 2
+#define HCI_LMP_BCAST_ENC_SUPPORTED(x) ((x)[HCI_FEATURE_BROADCAST_ENC_OFF] & HCI_FEATURE_BROADCAST_ENC_MASK)
+
+#define HCI_FEATURE_SCATTER_MODE_MASK 0x01
+#define HCI_FEATURE_SCATTER_MODE_OFF 3
+#define HCI_LMP_SCATTER_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_SCATTER_MODE_OFF] & HCI_FEATURE_SCATTER_MODE_MASK)
+
+#define HCI_FEATURE_EDR_ACL_2MPS_MASK 0x02
+#define HCI_FEATURE_EDR_ACL_2MPS_OFF 3
+#define HCI_EDR_ACL_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_2MPS_OFF] & HCI_FEATURE_EDR_ACL_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ACL_3MPS_MASK 0x04
+#define HCI_FEATURE_EDR_ACL_3MPS_OFF 3
+#define HCI_EDR_ACL_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ACL_3MPS_OFF] & HCI_FEATURE_EDR_ACL_3MPS_MASK)
+
+#define HCI_FEATURE_ENHANCED_INQ_MASK 0x08
+#define HCI_FEATURE_ENHANCED_INQ_OFF 3
+#define HCI_ENHANCED_INQ_SUPPORTED(x) ((x)[HCI_FEATURE_ENHANCED_INQ_OFF] & HCI_FEATURE_ENHANCED_INQ_MASK)
+
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_MASK 0x10
+#define HCI_FEATURE_INTERLACED_INQ_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_INQ_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_INQ_SCAN_OFF] & HCI_FEATURE_INTERLACED_INQ_SCAN_MASK)
+
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK 0x20
+#define HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF 3
+#define HCI_LMP_INTERLACED_PAGE_SCAN_SUPPORTED(x) ((x)[HCI_FEATURE_INTERLACED_PAGE_SCAN_OFF] & HCI_FEATURE_INTERLACED_PAGE_SCAN_MASK)
+
+#define HCI_FEATURE_INQ_RSSI_MASK 0x40
+#define HCI_FEATURE_INQ_RSSI_OFF 3
+#define HCI_LMP_INQ_RSSI_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RSSI_OFF] & HCI_FEATURE_INQ_RSSI_MASK)
+
+#define HCI_FEATURE_ESCO_EV3_MASK 0x80
+#define HCI_FEATURE_ESCO_EV3_OFF 3
+#define HCI_ESCO_EV3_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV3_OFF] & HCI_FEATURE_ESCO_EV3_MASK)
+
+#define HCI_FEATURE_ESCO_EV4_MASK 0x01
+#define HCI_FEATURE_ESCO_EV4_OFF 4
+#define HCI_ESCO_EV4_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV4_OFF] & HCI_FEATURE_ESCO_EV4_MASK)
+
+#define HCI_FEATURE_ESCO_EV5_MASK 0x02
+#define HCI_FEATURE_ESCO_EV5_OFF 4
+#define HCI_ESCO_EV5_SUPPORTED(x) ((x)[HCI_FEATURE_ESCO_EV5_OFF] & HCI_FEATURE_ESCO_EV5_MASK)
+
+#define HCI_FEATURE_ABSENCE_MASKS_MASK 0x04
+#define HCI_FEATURE_ABSENCE_MASKS_OFF 4
+#define HCI_LMP_ABSENCE_MASKS_SUPPORTED(x) ((x)[HCI_FEATURE_ABSENCE_MASKS_OFF] & HCI_FEATURE_ABSENCE_MASKS_MASK)
+
+#define HCI_FEATURE_AFH_CAP_SLAVE_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_SLAVE_OFF 4
+#define HCI_LMP_AFH_CAP_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_SLAVE_OFF] & HCI_FEATURE_AFH_CAP_SLAVE_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_SLAVE_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_SLAVE_OFF 4
+#define HCI_LMP_AFH_CLASS_SLAVE_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_SLAVE_OFF] & HCI_FEATURE_AFH_CLASS_SLAVE_MASK)
+
+#define HCI_FEATURE_ALIAS_AUTH_MASK 0x20
+#define HCI_FEATURE_ALIAS_AUTH_OFF 4
+#define HCI_LMP_ALIAS_AUTH_SUPPORTED(x) ((x)[HCI_FEATURE_ALIAS_AUTH_OFF] & HCI_FEATURE_ALIAS_AUTH_MASK)
+
+#define HCI_FEATURE_ANON_MODE_MASK 0x40
+#define HCI_FEATURE_ANON_MODE_OFF 4
+#define HCI_LMP_ANON_MODE_SUPPORTED(x) ((x)[HCI_FEATURE_ANON_MODE_OFF] & HCI_FEATURE_ANON_MODE_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ACL_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ACL_OFF 4
+#define HCI_3_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ACL_OFF] & HCI_FEATURE_3_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_5_SLOT_EDR_ACL_MASK 0x01
+#define HCI_FEATURE_5_SLOT_EDR_ACL_OFF 5
+#define HCI_5_SLOT_EDR_ACL_SUPPORTED(x) ((x)[HCI_FEATURE_5_SLOT_EDR_ACL_OFF] & HCI_FEATURE_5_SLOT_EDR_ACL_MASK)
+
+#define HCI_FEATURE_SNIFF_SUB_RATE_MASK 0x02
+#define HCI_FEATURE_SNIFF_SUB_RATE_OFF 5
+#define HCI_SNIFF_SUB_RATE_SUPPORTED(x) ((x)[HCI_FEATURE_SNIFF_SUB_RATE_OFF] & HCI_FEATURE_SNIFF_SUB_RATE_MASK)
+
+#define HCI_FEATURE_ATOMIC_ENCRYPT_MASK 0x04
+#define HCI_FEATURE_ATOMIC_ENCRYPT_OFF 5
+#define HCI_ATOMIC_ENCRYPT_SUPPORTED(x) ((x)[HCI_FEATURE_ATOMIC_ENCRYPT_OFF] & HCI_FEATURE_ATOMIC_ENCRYPT_MASK)
+
+#define HCI_FEATURE_AFH_CAP_MASTR_MASK 0x08
+#define HCI_FEATURE_AFH_CAP_MASTR_OFF 5
+#define HCI_LMP_AFH_CAP_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CAP_MASTR_OFF] & HCI_FEATURE_AFH_CAP_MASTR_MASK)
+
+#define HCI_FEATURE_AFH_CLASS_MASTR_MASK 0x10
+#define HCI_FEATURE_AFH_CLASS_MASTR_OFF 5
+#define HCI_LMP_AFH_CLASS_MASTR_SUPPORTED(x) ((x)[HCI_FEATURE_AFH_CLASS_MASTR_OFF] & HCI_FEATURE_AFH_CLASS_MASTR_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_2MPS_MASK 0x20
+#define HCI_FEATURE_EDR_ESCO_2MPS_OFF 5
+#define HCI_EDR_ESCO_2MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_2MPS_OFF] & HCI_FEATURE_EDR_ESCO_2MPS_MASK)
+
+#define HCI_FEATURE_EDR_ESCO_3MPS_MASK 0x40
+#define HCI_FEATURE_EDR_ESCO_3MPS_OFF 5
+#define HCI_EDR_ESCO_3MPS_SUPPORTED(x) ((x)[HCI_FEATURE_EDR_ESCO_3MPS_OFF] & HCI_FEATURE_EDR_ESCO_3MPS_MASK)
+
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_MASK 0x80
+#define HCI_FEATURE_3_SLOT_EDR_ESCO_OFF 5
+#define HCI_3_SLOT_EDR_ESCO_SUPPORTED(x) ((x)[HCI_FEATURE_3_SLOT_EDR_ESCO_OFF] & HCI_FEATURE_3_SLOT_EDR_ESCO_MASK)
+
+#define HCI_FEATURE_EXT_INQ_RSP_MASK 0x01
+#define HCI_FEATURE_EXT_INQ_RSP_OFF 6
+#define HCI_EXT_INQ_RSP_SUPPORTED(x) ((x)[HCI_FEATURE_EXT_INQ_RSP_OFF] & HCI_FEATURE_EXT_INQ_RSP_MASK)
+
+#define HCI_FEATURE_ANUM_PIN_AWARE_MASK 0x02
+#define HCI_FEATURE_ANUM_PIN_AWARE_OFF 6
+#define HCI_ANUM_PIN_AWARE_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_AWARE_OFF] & HCI_FEATURE_ANUM_PIN_AWARE_MASK)
+
+#define HCI_FEATURE_ANUM_PIN_CAP_MASK 0x04
+#define HCI_FEATURE_ANUM_PIN_CAP_OFF 6
+#define HCI_ANUM_PIN_CAP_SUPPORTED(x) ((x)[HCI_FEATURE_ANUM_PIN_CAP_OFF] & HCI_FEATURE_ANUM_PIN_CAP_MASK)
+
+#define HCI_FEATURE_SIMPLE_PAIRING_MASK 0x08
+#define HCI_FEATURE_SIMPLE_PAIRING_OFF 6
+#define HCI_SIMPLE_PAIRING_SUPPORTED(x) ((x)[HCI_FEATURE_SIMPLE_PAIRING_OFF] & HCI_FEATURE_SIMPLE_PAIRING_MASK)
+
+#define HCI_FEATURE_ENCAP_PDU_MASK 0x10
+#define HCI_FEATURE_ENCAP_PDU_OFF 6
+#define HCI_ENCAP_PDU_SUPPORTED(x) ((x)[HCI_FEATURE_ENCAP_PDU_OFF] & HCI_FEATURE_ENCAP_PDU_MASK)
+
+#define HCI_FEATURE_ERROR_DATA_MASK 0x20
+#define HCI_FEATURE_ERROR_DATA_OFF 6
+#define HCI_ERROR_DATA_SUPPORTED(x) ((x)[HCI_FEATURE_ERROR_DATA_OFF] & HCI_FEATURE_ERROR_DATA_MASK)
+
+#define HCI_FEATURE_NON_FLUSHABLE_PB_MASK 0x40
+#define HCI_FEATURE_NON_FLUSHABLE_PB_OFF 6
+#define HCI_NON_FLUSHABLE_PB_SUPPORTED(x) ((x)[HCI_FEATURE_NON_FLUSHABLE_PB_OFF] & HCI_FEATURE_NON_FLUSHABLE_PB_MASK)
+
+#define HCI_FEATURE_LINK_SUP_TO_EVT_MASK 0x01
+#define HCI_FEATURE_LINK_SUP_TO_EVT_OFF 7
+#define HCI_LINK_SUP_TO_EVT_SUPPORTED(x) ((x)[HCI_FEATURE_LINK_SUP_TO_EVT_OFF] & HCI_FEATURE_LINK_SUP_TO_EVT_MASK)
+
+#define HCI_FEATURE_INQ_RESP_TX_MASK 0x02
+#define HCI_FEATURE_INQ_RESP_TX_OFF 7
+#define HCI_INQ_RESP_TX_SUPPORTED(x) ((x)[HCI_FEATURE_INQ_RESP_TX_OFF] & HCI_FEATURE_INQ_RESP_TX_MASK)
+
+#define HCI_FEATURE_EXTENDED_MASK 0x80
+#define HCI_FEATURE_EXTENDED_OFF 7
+#define HCI_LMP_EXTENDED_SUPPORTED(x) ((x)[HCI_FEATURE_EXTENDED_OFF] & HCI_FEATURE_EXTENDED_MASK)
+
+/*
+** Features encoding - page 1
+*/
+#define HCI_EXT_FEATURE_SSP_HOST_MASK 0x01
+#define HCI_EXT_FEATURE_SSP_HOST_OFF 0
+#define HCI_SSP_HOST_SUPPORTED(x) ((x)[HCI_EXT_FEATURE_SSP_HOST_OFF] & HCI_EXT_FEATURE_SSP_HOST_MASK)
+
+/*
+** Local Supported Commands encoding
+*/
+#define HCI_NUM_SUPP_COMMANDS_BYTES 64
+
+#define HCI_SUPP_COMMANDS_INQUIRY_MASK 0x01
+#define HCI_SUPP_COMMANDS_INQUIRY_OFF 0
+#define HCI_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_OFF] & HCI_SUPP_COMMANDS_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK 0x02
+#define HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF 0
+#define HCI_INQUIRY_CANCEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_INQUIRY_CANCEL_OFF] & HCI_SUPP_COMMANDS_INQUIRY_CANCEL_MASK)
+
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK 0x04
+#define HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF 0
+#define HCI_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF 0
+#define HCI_EXIT_PERIODIC_INQUIRY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_OFF] & HCI_SUPP_COMMANDS_EXIT_PERIODIC_INQUIRY_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_CONN_OFF 0
+#define HCI_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_DISCONNECT_MASK 0x20
+#define HCI_SUPP_COMMANDS_DISCONNECT_OFF 0
+#define HCI_DISCONNECT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DISCONNECT_OFF] & HCI_SUPP_COMMANDS_DISCONNECT_MASK)
+
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK 0x40
+#define HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF 0
+#define HCI_ADD_SCO_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ADD_SCO_CONN_OFF] & HCI_SUPP_COMMANDS_ADD_SCO_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK 0x80
+#define HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF 0
+#define HCI_CANCEL_CREATE_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_OFF] & HCI_SUPP_COMMANDS_CANCEL_CREATE_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK 0x01
+#define HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF 1
+#define HCI_ACCEPT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_ACCEPT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK 0x02
+#define HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF 1
+#define HCI_REJECT_CONN_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_OFF] & HCI_SUPP_COMMANDS_REJECT_CONN_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF 1
+#define HCI_LINK_KEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_LINK_KEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK 0x20
+#define HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF 1
+#define HCI_PIN_CODE_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_PIN_CODE_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK 0x40
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF 1
+#define HCI_CHANGE_CONN_PKT_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_PKT_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK 0x80
+#define HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF 1
+#define HCI_AUTH_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_AUTH_REQUEST_OFF] & HCI_SUPP_COMMANDS_AUTH_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF 2
+#define HCI_SET_CONN_ENCRYPTION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_OFF] & HCI_SUPP_COMMANDS_SET_CONN_ENCRYPTION_MASK)
+
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK 0x02
+#define HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF 2
+#define HCI_CHANGE_CONN_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_CHANGE_CONN_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF 2
+#define HCI_MASTER_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_MASTER_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_MASTER_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK 0x08
+#define HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK 0x10
+#define HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF 2
+#define HCI_CANCEL_REMOTE_NAME_REQUEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_OFF] & HCI_SUPP_COMMANDS_CANCEL_REMOTE_NAME_REQUEST_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF 2
+#define HCI_READ_REMOTE_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF 2
+#define HCI_READ_REMOTE_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF 2
+#define HCI_READ_REMOTE_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_REMOTE_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF 3
+#define HCI_READ_CLOCK_OFFSET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_OFF] & HCI_SUPP_COMMANDS_READ_CLOCK_OFFSET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF 3
+#define HCI_READ_LMP_HANDLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LMP_HANDLE_OFF] & HCI_SUPP_COMMANDS_READ_LMP_HANDLE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK 0x02
+#define HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF 4
+#define HCI_HOLD_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOLD_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_HOLD_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK 0x04
+#define HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF 4
+#define HCI_SNIFF_MODE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_OFF] & HCI_SUPP_COMMANDS_SNIFF_MODE_CMD_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF 4
+#define HCI_EXIT_SNIFF_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_OFF] & HCI_SUPP_COMMANDS_EXIT_SNIFF_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_PARK_STATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_PARK_STATE_OFF 4
+#define HCI_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK 0x20
+#define HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF 4
+#define HCI_EXIT_PARK_STATE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_EXIT_PARK_STATE_OFF] & HCI_SUPP_COMMANDS_EXIT_PARK_STATE_MASK)
+
+#define HCI_SUPP_COMMANDS_QOS_SETUP_MASK 0x40
+#define HCI_SUPP_COMMANDS_QOS_SETUP_OFF 4
+#define HCI_QOS_SETUP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_QOS_SETUP_OFF] & HCI_SUPP_COMMANDS_QOS_SETUP_MASK)
+
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK 0x80
+#define HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF 4
+#define HCI_ROLE_DISCOVERY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ROLE_DISCOVERY_OFF] & HCI_SUPP_COMMANDS_ROLE_DISCOVERY_MASK)
+
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK 0x01
+#define HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF 5
+#define HCI_SWITCH_ROLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SWITCH_ROLE_OFF] & HCI_SUPP_COMMANDS_SWITCH_ROLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF 5
+#define HCI_READ_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK 0x04
+#define HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_READ_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_READ_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF 5
+#define HCI_WRITE_DEF_LINK_POLICY_SET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_OFF] & HCI_SUPP_COMMANDS_WRITE_DEF_LINK_POLICY_SET_MASK)
+
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK 0x20
+#define HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF 5
+#define HCI_FLOW_SPECIFICATION_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_OFF] & HCI_SUPP_COMMANDS_FLOW_SPECIFICATION_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK 0x40
+#define HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF 5
+#define HCI_SET_EVENT_MASK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_MASK_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_MASK_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_MASK 0x80
+#define HCI_SUPP_COMMANDS_RESET_OFF 5
+#define HCI_RESET_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_OFF] & HCI_SUPP_COMMANDS_RESET_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK 0x01
+#define HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF 6
+#define HCI_SET_EVENT_FILTER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_EVENT_FILTER_OFF] & HCI_SUPP_COMMANDS_SET_EVENT_FILTER_MASK)
+
+#define HCI_SUPP_COMMANDS_FLUSH_MASK 0x02
+#define HCI_SUPP_COMMANDS_FLUSH_OFF 6
+#define HCI_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_FLUSH_OFF] & HCI_SUPP_COMMANDS_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF 6
+#define HCI_READ_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF 6
+#define HCI_WRITE_PIN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PIN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK 0x10
+#define HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF 6
+#define HCI_CREATE_NEW_UNIT_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_OFF] & HCI_SUPP_COMMANDS_CREATE_NEW_UNIT_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF 6
+#define HCI_READ_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_READ_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF 6
+#define HCI_WRITE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_WRITE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK 0x80
+#define HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF 6
+#define HCI_DELETE_STORED_LINK_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_OFF] & HCI_SUPP_COMMANDS_DELETE_STORED_LINK_KEY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF 7
+#define HCI_WRITE_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_WRITE_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF 7
+#define HCI_READ_LOCAL_NAME_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_NAME_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_NAME_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_READ_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF 7
+#define HCI_WRITE_CONN_ACCEPT_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_CONN_ACCEPT_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF 7
+#define HCI_READ_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF 7
+#define HCI_WRITE_PAGE_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF 7
+#define HCI_READ_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF 7
+#define HCI_WRITE_SCAN_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SCAN_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_PAGE_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_READ_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF 8
+#define HCI_WRITE_INQURIY_SCAN_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_INQURIY_SCAN_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF 8
+#define HCI_READ_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF 8
+#define HCI_WRITE_AUTH_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTH_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF 8
+#define HCI_READ_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF 8
+#define HCI_WRITE_ENCRYPT_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_ENCRYPT_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF 9
+#define HCI_READ_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_READ_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF 9
+#define HCI_WRITE_CLASS_DEVICE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_OFF] & HCI_SUPP_COMMANDS_WRITE_CLASS_DEVICE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF 9
+#define HCI_READ_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_READ_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF 9
+#define HCI_WRITE_VOICE_SETTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_OFF] & HCI_SUPP_COMMANDS_WRITE_VOICE_SETTING_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_READ_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF 9
+#define HCI_WRITE_AUTO_FLUSH_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_AUTO_FLUSH_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF 9
+#define HCI_READ_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_READ_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF 9
+#define HCI_WRITE_NUM_BROAD_RETRANS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_OFF] & HCI_SUPP_COMMANDS_WRITE_NUM_BROAD_RETRANS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_READ_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_READ_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF 10
+#define HCI_WRITE_HOLD_MODE_ACTIVITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_OFF] & HCI_SUPP_COMMANDS_WRITE_HOLD_MODE_ACTIVITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF 10
+#define HCI_READ_TRANS_PWR_LEVEL_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_OFF] & HCI_SUPP_COMMANDS_READ_TRANS_PWR_LEVEL_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_READ_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_READ_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF 10
+#define HCI_WRITE_SYNCH_FLOW_CTRL_ENABLE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_OFF] & HCI_SUPP_COMMANDS_WRITE_SYNCH_FLOW_CTRL_ENABLE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK 0x20
+#define HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF 10
+#define HCI_SET_HOST_CTRLR_TO_HOST_FC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_OFF] & HCI_SUPP_COMMANDS_SET_HOST_CTRLR_TO_HOST_FC_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK 0x40
+#define HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF 10
+#define HCI_HOST_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_HOST_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK 0x80
+#define HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF 10
+#define HCI_HOST_NUM_COMPLETED_PKTS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_OFF] & HCI_SUPP_COMMANDS_HOST_NUM_COMPLETED_PKTS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF 11
+#define HCI_READ_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_READ_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF 11
+#define HCI_WRITE_LINK_SUP_TOUT_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_OFF] & HCI_SUPP_COMMANDS_WRITE_LINK_SUP_TOUT_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF 11
+#define HCI_READ_NUM_SUPP_IAC_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_OFF] & HCI_SUPP_COMMANDS_READ_NUM_SUPP_IAC_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF 11
+#define HCI_READ_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_READ_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK 0x10
+#define HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF 11
+#define HCI_WRITE_CURRENT_IAC_LAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_OFF] & HCI_SUPP_COMMANDS_WRITE_CURRENT_IAC_LAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF 11
+#define HCI_WRITE_PAGE_SCAN_PER_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_PER_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF 11
+#define HCI_READ_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF 12
+#define HCI_WRITE_PAGE_SCAN_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK 0x02
+#define HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF 12
+#define HCI_SET_AFH_CHNL_CLASS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_OFF] & HCI_SUPP_COMMANDS_SET_AFH_CHNL_CLASS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_READ_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF 12
+#define HCI_WRITE_INQUIRY_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF 12
+#define HCI_READ_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK 0x80
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF 12
+#define HCI_WRITE_INQUIRY_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF 13
+#define HCI_READ_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_READ_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF 13
+#define HCI_WRITE_PAGE_SCAN_TYPE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_OFF] & HCI_SUPP_COMMANDS_WRITE_PAGE_SCAN_TYPE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_READ_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF 13
+#define HCI_WRITE_AFH_CHNL_ASSESS_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_AFH_CHNL_ASSESS_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK 0x08
+#define HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF 14
+#define HCI_READ_LOCAL_VER_INFO_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_VER_INFO_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK 0x10
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF 14
+#define HCI_READ_LOCAL_SUP_CMDS_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUP_CMDS_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF 14
+#define HCI_READ_LOCAL_SUPP_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_SUPP_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF 14
+#define HCI_READ_LOCAL_EXT_FEATURES_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_EXT_FEATURES_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF 14
+#define HCI_READ_BUFFER_SIZE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_OFF] & HCI_SUPP_COMMANDS_READ_BUFFER_SIZE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF 15
+#define HCI_READ_COUNTRY_CODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_OFF] & HCI_SUPP_COMMANDS_READ_COUNTRY_CODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK 0x02
+#define HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF 15
+#define HCI_READ_BD_ADDR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_ADDR_OFF] & HCI_SUPP_COMMANDS_READ_BD_ADDR_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_READ_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_READ_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK 0x08
+#define HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF 15
+#define HCI_RESET_FAIL_CONTACT_CNTR_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_OFF] & HCI_SUPP_COMMANDS_RESET_FAIL_CONTACT_CNTR_MASK)
+
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK 0x10
+#define HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF 15
+#define HCI_GET_LINK_QUALITY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_GET_LINK_QUALITY_OFF] & HCI_SUPP_COMMANDS_GET_LINK_QUALITY_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_RSSI_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_RSSI_OFF 15
+#define HCI_READ_RSSI_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_RSSI_OFF] & HCI_SUPP_COMMANDS_READ_RSSI_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK 0x40
+#define HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF 15
+#define HCI_READ_AFH_CH_MAP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_OFF] & HCI_SUPP_COMMANDS_READ_AFH_CH_MAP_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF 15
+#define HCI_READ_BD_CLOCK_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_BD_CLOCK_OFF] & HCI_SUPP_COMMANDS_READ_BD_CLOCK_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF 16
+#define HCI_READ_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_READ_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF 16
+#define HCI_WRITE_LOOPBACK_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_LOOPBACK_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK 0x04
+#define HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF 16
+#define HCI_ENABLE_DEV_UNDER_TEST_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_OFF] & HCI_SUPP_COMMANDS_ENABLE_DEV_UNDER_TEST_MASK)
+
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK 0x08
+#define HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF 16
+#define HCI_SETUP_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_SETUP_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK 0x10
+#define HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF 16
+#define HCI_ACCEPT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_ACCEPT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK 0x20
+#define HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF 16
+#define HCI_REJECT_SYNCH_CONN_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_OFF] & HCI_SUPP_COMMANDS_REJECT_SYNCH_CONN_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF 17
+#define HCI_READ_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_READ_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF 17
+#define HCI_WRITE_EXT_INQUIRY_RESP_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_OFF] & HCI_SUPP_COMMANDS_WRITE_EXT_INQUIRY_RESP_MASK)
+
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK 0x04
+#define HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF 17
+#define HCI_REFRESH_ENCRYPTION_KEY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_OFF] & HCI_SUPP_COMMANDS_REFRESH_ENCRYPTION_KEY_MASK)
+
+/* Octet 17, bit 3 is reserved */
+
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK 0x10
+#define HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF 17
+#define HCI_SNIFF_SUB_RATE_CMD_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_OFF] & HCI_SUPP_COMMANDS_SNIFF_SUB_RATE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_READ_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_READ_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK 0x40
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF 17
+#define HCI_WRITE_SIMPLE_PAIRING_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK 0x80
+#define HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF 17
+#define HCI_READ_LOCAL_OOB_DATA_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_OFF] & HCI_SUPP_COMMANDS_READ_LOCAL_OOB_DATA_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK 0x01
+#define HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_READ_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_READ_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK 0x02
+#define HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF 18
+#define HCI_WRITE_INQUIRY_RESPONSE_TX_POWER_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_OFF] & HCI_SUPP_COMMANDS_WRITE_INQUIRY_RESPONSE_TX_POWER_MASK)
+
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x04
+#define HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_READ_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK 0x08
+#define HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF 18
+#define HCI_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_OFF] & HCI_SUPP_COMMANDS_WRITE_DEFAULT_ERRONEOUS_DATA_REPORTING_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_MASK 0x80
+#define HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_OFF 18
+#define HCI_IO_CAPABILITY_RESPONSE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_OFF] & HCI_SUPP_COMMANDS_IO_CAPABILITY_RESPONSE_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK 0x01
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK 0x02
+#define HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_CONFIRMATION_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_CONFIRMATION_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK 0x04
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF 19
+#define HCI_USER_PASSKEY_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_USER_PASSKEY_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK 0x10
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK 0x20
+#define HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF 19
+#define HCI_WRITE_SIMPLE_PAIRING_DBG_MODE_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_OFF] & HCI_SUPP_COMMANDS_WRITE_SIMPLE_PAIRING_DBG_MODE_MASK)
+
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK 0x40
+#define HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF 19
+#define HCI_ENHANCED_FLUSH_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_ENHANCED_FLUSH_OFF] & HCI_SUPP_COMMANDS_ENHANCED_FLUSH_MASK)
+
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK 0x80
+#define HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF 19
+#define HCI_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_REMOTE_OOB_DATA_REQUEST_NEG_REPLY_MASK)
+
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK 0x04
+#define HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF 20
+#define HCI_SEND_NOTIF_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_OFF] & HCI_SUPP_COMMANDS_SEND_KEYPRESS_NOTIF_MASK)
+
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK 0x08
+#define HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF 20
+#define HCI_IO_CAP_REQ_NEG_REPLY_SUPPORTED(x) ((x)[HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_OFF] & HCI_SUPP_COMMANDS_IO_CAP_REQ_NEG_REPLY_MASK)
+
+#endif
+
diff --git a/inc/target.h b/inc/target.h
new file mode 100755
index 0000000..32b5bf9
--- a/dev/null
+++ b/inc/target.h
@@ -0,0 +1,121 @@
+/*
+ *
+ * target.h
+ *
+ *
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#ifndef _TARGET_H
+#define _TARGET_H
+
+#include <linux/usb.h>
+
+#define BT_API
+#define RFC_API
+#define L2C_API
+
+#define INT int
+#define UINT unsigned int
+#define DWORD unsigned long
+
+#ifndef BOOL
+#define BOOL int
+#endif
+
+#ifndef USHORT
+#define USHORT unsigned short
+#endif
+
+#ifndef ULONG
+#define ULONG unsigned long
+#endif
+
+#ifndef VOID
+#define VOID void
+#endif
+
+#define _vsnprintf vsnprintf
+
+#define __cdecl
+
+#define GKI_USE_DYNAMIC_BUFFERS TRUE /* TRUE if using dynamic buffers */
+
+#define GKI_NUM_FIXED_BUF_POOLS 1
+#define GKI_DEF_BUFPOOL_PERM_MASK 0xfffc /* Pool ID 0 is public */
+
+/* Define the total number of buffer pools used, fixed and dynamic (Maximum is 16) */
+#define GKI_NUM_TOTAL_BUF_POOLS 1
+
+#define GKI_BUF0_SIZE 1740
+#ifdef BTUSB_LITE
+#define GKI_BUF0_MAX 10
+#else
+#define GKI_BUF0_MAX 5
+#endif
+
+#define GKI_POOL_ID_0 0
+
+#define HCI_SCO_POOL_ID GKI_POOL_ID_0 // all SCO data to/from the device
+
+/* Set this flag to non zero if you want to do buffer corruption checks.
+** If set, GKI will check buffer tail corruption every time it processes
+** a buffer. This is very useful for debug, and is minimal overhead in
+** a running system.
+*/
+#define GKI_ENABLE_BUF_CORRUPTION_CHECK 1
+
+#define L2CAP_MTU_SIZE 1691
+//#define L2CAP_MTU_SIZE 200
+
+/* Maximum size in bytes of the codec capabilities information element. */
+#ifndef AVDT_CODEC_SIZE
+#define AVDT_CODEC_SIZE 10
+#endif
+
+/* Number of streams for dual stack */
+#ifndef BTM_SYNC_INFO_NUM_STR
+#define BTM_SYNC_INFO_NUM_STR 2
+#endif
+
+/* Number of streams for dual stack in BT Controller (simulation) */
+#ifndef BTM_SYNC_INFO_NUM_STR_BTC
+#define BTM_SYNC_INFO_NUM_STR_BTC 2
+#endif
+
+#ifndef BTA_AV_NUM_STRS
+#define BTA_AV_NUM_STRS 2
+#endif
+
+#define BTU_STACK_LITE_ENABLED TRUE
+#define BTU_MULTI_AV_INCLUDED TRUE
+
+/* Number of simultaneous links to different peer devices. */
+#ifndef AVDT_NUM_LINKS
+#define AVDT_NUM_LINKS 2
+#endif
+
+/* Number of simultaneous stream endpoints. */
+#ifndef AVDT_NUM_SEPS
+#define AVDT_NUM_SEPS 2
+#endif
+
+#endif
diff --git a/src/btusb.c b/src/btusb.c
new file mode 100755
index 0000000..5253dcb
--- a/dev/null
+++ b/src/btusb.c
@@ -0,0 +1,1596 @@
+/*
+ *
+ * btusb.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#include "btusb.h"
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "hcidefs.h"
+#include "btusb_proc.h"
+
+#define BTUSB_VID_BRCM 0x0A5C
+
+/* forward reference */
+struct usb_driver btusb_driver;
+
+/* table of devices that work with this driver */
+static struct usb_device_id btusb_table [] =
+{
+#if defined(BTUSB_VID) && defined(BTUSB_PID)
+ /* If a specific Vid/Pid is specified at compilation time */
+ { USB_DEVICE(BTUSB_VID, BTUSB_PID) },
+#else
+ /* all BT devices */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS |
+ USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
+ .bDeviceClass = USB_CLASS_WIRELESS_CONTROLLER,
+ /* 0x01 / 0x01 = Bluetooth programming interface */
+ .bDeviceSubClass = 0x01,
+ .bDeviceProtocol = 0x01
+ },
+ /* all BRCM BT interfaces */
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS |
+ USB_DEVICE_ID_MATCH_INT_PROTOCOL,
+ .idVendor = BTUSB_VID_BRCM,
+ .bInterfaceClass = USB_CLASS_WIRELESS_CONTROLLER,
+ /* 0x01 / 0x01 = Bluetooth programming interface */
+ .bInterfaceSubClass = 0x01,
+ .bInterfaceProtocol = 0x01
+ },
+ /* all BRCM vendor specific with Bluetooth programming interface */
+ { .match_flags = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_DEV_CLASS |
+ USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL,
+ .idVendor = BTUSB_VID_BRCM,
+ .bDeviceClass = USB_CLASS_VENDOR_SPEC,
+ /* 0x01 / 0x01 = Bluetooth programming interface */
+ .bDeviceSubClass = 0x01,
+ .bDeviceProtocol = 0x01
+ },
+#endif
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, btusb_table);
+
+static struct file_operations btusb_fops =
+{
+ .owner = THIS_MODULE,
+ .read = btusb_read,
+ .write = btusb_write,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+ .unlocked_ioctl = btusb_ioctl,
+#else
+ .ioctl = btusb_ioctl,
+#endif
+ .poll = btusb_poll,
+ .open = btusb_open,
+ .release = btusb_release,
+};
+
+/*
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver btusb_class =
+{
+ .name = "usb/btusb%d",
+ .fops = &btusb_fops,
+ .minor_base = BTUSB_MINOR_BASE,
+};
+
+
+/* static functions */
+static int btusb_create(struct btusb *p_dev, struct usb_interface *p_interface, const struct usb_device_id *p_id);
+
+/* module parameter to enable suspend/resume with remote wakeup */
+bool autopm = 0;
+
+/* module parameter to enable debug flags */
+int dbgflags = BTUSB_DBGFLAGS;
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit
+ **
+ ** Description Submit a BTUSB transaction
+ **
+ ** Parameters p_dev: driver control block
+ ** p_anchor: anchor to hook URB to when submitting
+ ** p_trans: transaction to submit
+ ** mem_flags: memory flags to submit the URB with
+ **
+ ** Returns 0 upon success, error core else.
+ **
+ *******************************************************************************/
+int btusb_submit(struct btusb *p_dev, struct usb_anchor *p_anchor, struct btusb_trans *p_trans, int mem_flags)
+{
+ int status;
+ struct urb *p_urb = p_trans->p_urb;
+
+ BTUSB_DBG("urb %p b=%p\n", p_urb, p_urb->transfer_buffer);
+
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ return -ENODEV;
+ }
+
+ usb_anchor_urb(p_urb, p_anchor);
+ status = usb_submit_urb(p_urb, mem_flags);
+ if (unlikely(status))
+ {
+ /* this can happen when device is disconnecting */
+ BTUSB_DBG("usb_submit_urb failed(%d)\n", status);
+ usb_unanchor_urb(p_urb);
+ p_dev->stats.urb_submit_err++;
+ }
+ else
+ {
+ p_dev->stats.urb_submit_ok++;
+ }
+
+ return status;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_acl_read_complete
+ **
+ ** Description ACL Bulk pipe completion routine
+ **
+ ** Parameters p_urb: URB that completed
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_acl_read_complete(struct urb *p_urb)
+{
+ struct btusb_trans *p_trans = p_urb->context;
+ struct btusb *p_dev = p_trans->p_dev;
+ int count = p_urb->actual_length;
+
+ BTUSB_DBG("urb %p status %d count %d flags x%x\n", p_urb,
+ p_urb->status, count, p_urb->transfer_flags);
+
+ /* number of ACL URB completed */
+ p_dev->stats.acl_rx_complete++;
+
+ /* check if device is disconnecting, has been unplugged or is closing */
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_DBG("not queuing URB\n");
+ p_dev->stats.acl_rx_complete_err++;
+ goto exit;
+ }
+
+ /* if there was no data, do not forward to upper layers */
+ if (unlikely(!count))
+ {
+ p_dev->stats.acl_rx_resubmit++;
+ goto resubmit;
+ }
+
+ /* increment the number of bytes transferred */
+ p_dev->stats.acl_rx_bytes += count;
+
+ /* forward up the data */
+ btusb_dump_data(p_urb->transfer_buffer, count, "btusb_acl_read_complete");
+ btusb_rx_enqueue(p_dev, p_trans, HCIT_TYPE_ACL_DATA);
+
+ /* Do not resubmit since it was forwarded to the user */
+ goto exit;
+
+resubmit:
+ if (unlikely(btusb_submit(p_dev, &p_dev->acl_rx_submitted, p_trans, GFP_ATOMIC)))
+ p_dev->stats.acl_rx_submit_err++;
+ else
+ p_dev->stats.acl_rx_submit_ok++;
+
+exit:
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_diag_read_complete
+ **
+ ** Description Diag Bulk pipe completion routine
+ **
+ ** Parameters p_urb: URB that completed
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_diag_read_complete(struct urb *p_urb)
+{
+ struct btusb_trans *p_trans = p_urb->context;
+ struct btusb *p_dev = p_trans->p_dev;
+ int count = p_urb->actual_length;
+
+ BTUSB_DBG("urb %p status %d count %d flags %x\n", p_urb,
+ p_urb->status, count, p_urb->transfer_flags);
+
+ p_dev->stats.diag_rx_complete++;
+
+ /* check if device is disconnecting, has been unplugged or is closing */
+ if (unlikely(p_urb->status))
+ {
+ p_dev->stats.diag_rx_complete_err++;
+ BTUSB_DBG("not queuing URB\n");
+ goto exit;
+ }
+
+ /* if there was no data or no more submitted diags, do not forward to upper layers */
+ if (unlikely(!count || usb_anchor_empty(&p_dev->diag_rx_submitted)))
+ {
+ p_dev->stats.diag_rx_resubmit++;
+ goto resubmit;
+ }
+
+ /* increment the number of bytes transferred */
+ p_dev->stats.diag_rx_bytes += count;
+
+ /* forward up the data */
+ btusb_dump_data(p_urb->transfer_buffer, count, "btusb_diag_read_complete");
+ btusb_rx_enqueue(p_dev, p_trans, HCIT_TYPE_LM_DIAG);
+
+ /* Do not resubmit since it was forwarded to the user */
+ goto exit;
+
+resubmit:
+ if (unlikely(btusb_submit(p_dev, &p_dev->diag_rx_submitted, p_trans, GFP_ATOMIC)))
+ p_dev->stats.diag_rx_submit_err++;
+ else
+ p_dev->stats.diag_rx_submit_ok++;
+
+exit:
+ return;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_event_complete
+ **
+ ** Description Interrupt pipe completion routine
+ **
+ ** Parameters p_urb: URB that completed
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_event_complete(struct urb *p_urb)
+{
+ struct btusb_trans *p_trans = p_urb->context;
+ struct btusb *p_dev = p_trans->p_dev;
+ int count = p_urb->actual_length;
+#if defined (BTUSB_LITE)
+ BT_HDR *p_buf;
+#endif
+
+ BTUSB_DBG("urb %p status %d count %d flags %x\n", p_urb,
+ p_urb->status, count, p_urb->transfer_flags);
+
+ p_dev->stats.event_complete++;
+
+ /* check if device is disconnecting, has been unplugged or is closing */
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_DBG("not queuing URB\n");
+ p_dev->stats.event_complete_err++;
+ goto exit;
+ }
+
+ /* if there was no data, do not forward to upper layers */
+ if (unlikely(!count))
+ {
+ p_dev->stats.event_resubmit++;
+ goto resubmit;
+ }
+
+#ifdef BTUSB_LITE
+ /* Filter Events received from BT Controller*/
+ if (btusb_lite_hci_event_filter(p_dev, p_trans->dma_buffer, count) == 0)
+ {
+ p_buf = &p_trans->bt_hdr;
+ p_buf->offset = 0;
+ p_buf->event = HCIT_TYPE_EVENT;
+ p_buf->len = p_trans->p_urb->actual_length;
+ btusb_rx_dequeued(p_dev, p_buf);
+ }
+ else
+#endif
+ {
+ /* increment the number of bytes transferred */
+ p_dev->stats.event_bytes += count;
+
+ /* forward up the event */
+ btusb_dump_data(p_urb->transfer_buffer, count, "btusb_event_complete");
+ btusb_rx_enqueue(p_dev, p_trans, HCIT_TYPE_EVENT);
+ }
+
+ /* Do not resubmit since it was forwarded to the user */
+ goto exit;
+
+resubmit:
+ if (unlikely(btusb_submit(p_dev, &p_dev->event_submitted, p_trans, GFP_ATOMIC)))
+ p_dev->stats.event_submit_err++;
+ else
+ p_dev->stats.event_submit_ok++;
+
+exit:
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_probe
+ **
+ ** Description Device probe callback
+ ** assuming the following USB device configuration :
+ **
+ ** NumInterfaces = 4
+ ** Interface 0 Alt settings 0
+ ** 3 end point excluding end point 0
+ ** 1 interrupt end point -> event
+ ** 2 bulk for acl in and out
+ ** Interface 1 Alt settings 0
+ ** 2 Iso end point excluding end point 0
+ ** Interface 1 Alt settings 1
+ ** 2 Iso end point excluding end point 0
+ ** Interface 1 Alt settings 2
+ ** 2 Iso end point excluding end point 0
+ ** Interface 1 Alt settings 3
+ ** 2 Iso end point excluding end point 0
+ ** Interface 1 Alt settings 4
+ ** 2 Iso end point excluding end point 0
+ ** Interface 1 Alt settings 5
+ ** 2 Iso end point excluding end point 0
+ ** Interface 2 Alt settings 0
+ ** 2 bulk end point for diags
+ ** Interface 3 Alt settings 0
+ ** 0 end point point i.e. only the control endpoint is used
+ ** Parameters
+ **
+ ** Returns 0 upon success, error core else.
+ **
+ *******************************************************************************/
+static int btusb_probe(struct usb_interface *p_interface, const struct usb_device_id *p_id)
+{
+ struct btusb *p_dev;
+ struct usb_ctrlrequest *p_dr;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+ struct urb *p_urb;
+ int idx, jdx;
+ struct btusb_trans *p_trans;
+ int retval = -ENOMEM;
+
+ GKI_init();
+
+ BTUSB_INFO("p_interface=%p, p_id=%p\n", p_interface, p_id);
+ BTUSB_INFO("p_interface->cur_altsetting->desc.bInterfaceNumber=%d\n", p_interface->cur_altsetting->desc.bInterfaceNumber);
+ BTUSB_DBG("match=0x%x VID=0x%x PID=0x%x class=0x%x subclass=0x%x protocol=0x%x\n",
+ p_id->match_flags, p_id->idVendor, p_id->idProduct, p_id->bDeviceClass, p_id->bDeviceSubClass,
+ p_id->bDeviceProtocol);
+
+ /* Bluetooth core Interface number must be 0 (hardcoded in the spec) */
+ if (p_interface->cur_altsetting->desc.bInterfaceNumber != 0)
+ {
+ BTUSB_INFO("InterfaceNumber is not 0. This is not a Bluetooth Interface\n");
+ return -ENODEV;
+ }
+
+ /* allocate memory for our device */
+ p_dev = kzalloc(sizeof(struct btusb), GFP_KERNEL);
+ if (p_dev == NULL)
+ {
+ dev_err(&p_interface->dev, "Out of memory\n");
+ goto error;
+ }
+ BTUSB_DBG("allocated p_dev=%p\n", p_dev);
+
+ if (btusb_create(p_dev, p_interface, p_id))
+ {
+ goto error;
+ }
+
+ /* set up the endpoint information
+ use only the first bulk-in and bulk-out endpoints */
+ p_host_intf = p_interface->cur_altsetting;
+ BTUSB_DBG("%u endpoints\n", p_host_intf->desc.bNumEndpoints);
+
+ for (idx = 0; idx < p_host_intf->desc.bNumEndpoints; ++idx)
+ {
+ p_ep_desc = &p_host_intf->endpoint[idx].desc;
+ BTUSB_DBG("endpoint addr 0x%x attr 0x%x\n",
+ p_ep_desc->bEndpointAddress, p_ep_desc->bmAttributes);
+ if ((!p_dev->p_acl_in) &&
+ BTUSB_EP_DIR_IN(p_ep_desc) &&
+ (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_BULK))
+ {
+ /* we found a bulk in endpoint */
+ p_dev->p_acl_in = &p_host_intf->endpoint[idx];
+ }
+
+ if ((!p_dev->p_event_in) &&
+ BTUSB_EP_DIR_IN(p_ep_desc) &&
+ (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_INT))
+ {
+ /* we found an interrupt in end point */
+ p_dev->p_event_in = &p_host_intf->endpoint[idx];
+ }
+
+ if ((!p_dev->p_acl_out) &&
+ BTUSB_EP_DIR_OUT(p_ep_desc) &&
+ (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_BULK))
+ {
+ /* we found a bulk out end point */
+ p_dev->p_acl_out = &p_host_intf->endpoint[idx];
+ }
+ }
+
+ /* now start looking at the voice interface (check if it a BT interface) */
+ p_dev->p_voice_intf = usb_ifnum_to_if(p_dev->p_udev, 1);
+ if (p_dev->p_voice_intf)
+ {
+ p_host_intf = &p_dev->p_voice_intf->altsetting[0];
+ if (((p_host_intf->desc.bInterfaceClass == USB_CLASS_WIRELESS_CONTROLLER) ||
+ (p_host_intf->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC)) &&
+ (p_host_intf->desc.bInterfaceSubClass == 1) &&
+ (p_host_intf->desc.bInterfaceProtocol == 1))
+ {
+ /* can claim here, but prefer to check there are ISO endpoints */
+ }
+ else
+ {
+ BTUSB_INFO("Interface 1 is not VOICE\n");
+ goto no_voice;
+ }
+ for (idx = 0; idx < p_dev->p_voice_intf->num_altsetting; idx++)
+ {
+ p_host_intf = &p_dev->p_voice_intf->altsetting[idx];
+ for (jdx = 0; jdx < p_host_intf->desc.bNumEndpoints; jdx++)
+ {
+ p_ep_desc = &p_host_intf->endpoint[jdx].desc;
+ if (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_ISOC)
+ {
+ /* found an ISO endpoint, claim interface and stop here */
+ if (usb_driver_claim_interface(&btusb_driver, p_dev->p_voice_intf, p_dev) != 0)
+ {
+ BTUSB_ERR("failed claiming iso interface\n");
+ /* reset it to prevent releasing it */
+ p_dev->p_voice_intf = NULL;
+ goto error_claim;
+ }
+ BTUSB_DBG("claimed iso interface\n");
+
+ /* set it into a disabled state */
+ if (usb_set_interface(p_dev->p_udev, 1, 0))
+ {
+ BTUSB_ERR("failed to set iso intf to 0\n");
+ }
+ goto found_voice;
+ }
+ }
+ }
+ }
+no_voice:
+ p_dev->p_voice_intf = NULL;
+found_voice:
+
+ /* grab other interfaces if present */
+ p_dev->p_diag_intf = usb_ifnum_to_if(p_dev->p_udev, 2);
+ if (p_dev->p_diag_intf)
+ {
+ p_host_intf = &p_dev->p_diag_intf->altsetting[0];
+ if ((p_host_intf->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
+ (p_host_intf->desc.bInterfaceSubClass == 255) &&
+ (p_host_intf->desc.bInterfaceProtocol == 255))
+ {
+ if (usb_driver_claim_interface(&btusb_driver, p_dev->p_diag_intf, p_dev) != 0)
+ {
+ BTUSB_ERR("failed claiming diag interface\n");
+ p_dev->p_diag_intf = NULL;
+ goto no_diag;
+ }
+ }
+ else
+ {
+ BTUSB_INFO("Interface 2 is not DIAG\n");
+ p_dev->p_diag_intf = NULL;
+ goto no_diag;
+ }
+
+ BTUSB_DBG("claimed diag interface bNumEndpoints %d\n", p_host_intf->desc.bNumEndpoints);
+ for (idx = 0; idx < p_host_intf->desc.bNumEndpoints; ++idx)
+ {
+ p_ep_desc = &p_host_intf->endpoint[idx].desc;
+ BTUSB_DBG("diag endpoint addr 0x%x attr 0x%x\n",
+ p_ep_desc->bEndpointAddress, p_ep_desc->bmAttributes);
+ if ((!p_dev->p_diag_in) &&
+ BTUSB_EP_DIR_IN(p_ep_desc) &&
+ (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_BULK))
+ {
+ /* we found a bulk in end point */
+ p_dev->p_diag_in = &p_host_intf->endpoint[idx];
+ }
+ if ((!p_dev->p_diag_out) &&
+ BTUSB_EP_DIR_OUT(p_ep_desc) &&
+ (BTUSB_EP_TYPE(p_ep_desc) == USB_ENDPOINT_XFER_BULK))
+ {
+ /* we found a bulk out end point */
+ p_dev->p_diag_out = &p_host_intf->endpoint[idx];
+ }
+ }
+ }
+no_diag:
+
+ /* try to get the DFU interface */
+ p_dev->p_dfu_intf = usb_ifnum_to_if(p_dev->p_udev, 3);
+ if (p_dev->p_dfu_intf)
+ {
+ p_host_intf = &p_dev->p_dfu_intf->altsetting[0];
+ if ((p_host_intf->desc.bInterfaceClass == USB_CLASS_APP_SPEC) &&
+ (p_host_intf->desc.bInterfaceSubClass == 1))
+ {
+ if (usb_driver_claim_interface(&btusb_driver, p_dev->p_dfu_intf, p_dev) != 0)
+ {
+ BTUSB_ERR("failed claiming dfu interface\n");
+ p_dev->p_dfu_intf = NULL;
+ goto no_dfu;
+ }
+ BTUSB_DBG("claimed DFU interface bNumEndpoints %d\n", p_dev->p_dfu_intf->cur_altsetting->desc.bNumEndpoints);
+ }
+ else
+ {
+ BTUSB_INFO("Interface 3 is not DFU\n");
+ p_dev->p_dfu_intf = NULL;
+ goto no_dfu;
+ }
+ }
+no_dfu:
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->cmd_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = btusb_cmd_complete;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_CMD_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("cmd_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ p_dr = &p_dev->cmd_req_array[idx];
+ p_dr->bRequestType = USB_TYPE_CLASS;
+ p_dr->bRequest = 0;
+ p_dr->wIndex = 0;
+ p_dr->wValue = 0;
+ p_dr->wLength = 0;
+
+ usb_fill_control_urb(p_urb,
+ p_dev->p_udev,
+ usb_sndctrlpipe(p_dev->p_udev, 0),
+ (void *)p_dr,
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_CMD_SIZE,
+ btusb_urb_out_complete,
+ p_trans);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+
+ /* initialize the USB data paths */
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->event_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_UNLINKED;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_EVT_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("event_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ usb_fill_int_urb(p_urb,
+ p_dev->p_udev,
+ usb_rcvintpipe(p_dev->p_udev, p_dev->p_event_in->desc.bEndpointAddress),
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_EVT_SIZE,
+ btusb_event_complete,
+ p_trans,
+ p_dev->p_event_in->desc.bInterval);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_rx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_UNLINKED;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_ACL_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("acl_rx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ usb_fill_bulk_urb(p_urb,
+ p_dev->p_udev,
+ usb_rcvbulkpipe(p_dev->p_udev, p_dev->p_acl_in->desc.bEndpointAddress),
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_ACL_SIZE,
+ btusb_acl_read_complete,
+ p_trans);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_tx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_ACL_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("acl_tx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ usb_fill_bulk_urb(p_urb,
+ p_dev->p_udev,
+ usb_sndbulkpipe(p_dev->p_udev, p_dev->p_acl_out->desc.bEndpointAddress),
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_ACL_SIZE,
+ btusb_urb_out_complete,
+ p_trans);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ /* if it is a composite device, BULK out transfers must be ZERO packet terminated */
+ if (p_dev->quirks & BTUSB_QUIRK_ZLP_TX_REQ)
+ {
+ BTUSB_DBG("acl_tx_array[%d]: add ZERO_PACKET\n", idx);
+ p_urb->transfer_flags |= URB_ZERO_PACKET;
+ }
+ }
+
+ if (p_dev->p_diag_in)
+ {
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_rx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_UNLINKED;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_ACL_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("diag_rx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ usb_fill_bulk_urb(p_urb,
+ p_dev->p_udev,
+ usb_rcvbulkpipe(p_dev->p_udev, p_dev->p_diag_in->desc.bEndpointAddress),
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_ACL_SIZE,
+ btusb_diag_read_complete,
+ p_trans);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+ }
+
+ if (p_dev->p_diag_out)
+ {
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_tx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_HCI_MAX_ACL_SIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("diag_tx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+ usb_fill_bulk_urb(p_urb,
+ p_dev->p_udev,
+ usb_sndbulkpipe(p_dev->p_udev, p_dev->p_diag_out->desc.bEndpointAddress),
+ p_trans->dma_buffer,
+ BTUSB_HCI_MAX_ACL_SIZE,
+ btusb_urb_out_complete,
+ p_trans);
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ }
+ }
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_rx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = NULL;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_VOICE_BUFFER_MAXSIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(BTUSB_VOICE_FRAMES_PER_URB, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("voice_rx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+
+ p_urb->dev = p_dev->p_udev;
+ p_urb->transfer_buffer = p_trans->dma_buffer;
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ p_urb->complete = btusb_voicerx_complete;
+ p_urb->context = p_trans;
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP | URB_ISO_ASAP;
+ }
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_tx_array)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_trans->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS;
+ p_trans->magic = MAGIC_NO;
+#endif
+ p_trans->p_dev = p_dev;
+ p_trans->complete = btusb_voicetx_complete;
+ p_trans->dma_buffer = BTUSB_BUFFER_ALLOC(p_dev->p_udev,
+ BTUSB_VOICE_BUFFER_MAXSIZE, GFP_KERNEL, &p_trans->dma);
+ p_urb = p_trans->p_urb = usb_alloc_urb(BTUSB_VOICE_FRAMES_PER_URB, GFP_KERNEL);
+ if (!p_trans->dma_buffer || !p_urb)
+ {
+ BTUSB_ERR("transaction allocation failed\n");
+ goto error_claim;
+ }
+ BTUSB_DBG("voice_tx_array[%d]: b=%p\n", idx, p_trans->dma_buffer);
+
+ p_urb->dev = p_dev->p_udev;
+ p_urb->transfer_buffer = p_trans->dma_buffer;
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ p_urb->complete = btusb_urb_out_complete;
+ p_urb->context = p_trans;
+ p_urb->transfer_dma = p_trans->dma;
+ p_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP | URB_ISO_ASAP;
+ }
+
+ /* we can register the device now, as it is ready */
+ usb_set_intfdata(p_interface, p_dev);
+ retval = usb_register_dev(p_interface, &btusb_class);
+ if (retval)
+ {
+ /* something prevented us from registering this driver */
+ BTUSB_ERR("usb_register_dev failed: %d\n", retval);
+ goto error_claim;
+ }
+
+ /* start sending IN tokens */
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->event_array)
+ {
+ if (btusb_submit(p_dev, &p_dev->event_submitted, p_trans, GFP_KERNEL))
+ {
+ p_dev->stats.event_submit_err++;
+ BTUSB_ERR("btusb_submit(event) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.event_submit_ok++;
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_rx_array)
+ {
+ if (btusb_submit(p_dev, &p_dev->acl_rx_submitted, p_trans, GFP_KERNEL))
+ {
+ p_dev->stats.acl_rx_submit_err++;
+ BTUSB_ERR("btusb_submit(acl_rx) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.acl_rx_submit_ok++;
+ }
+ if (p_dev->p_diag_in)
+ {
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_rx_array)
+ {
+ if (btusb_submit(p_dev, &p_dev->diag_rx_submitted, p_trans, GFP_KERNEL))
+ {
+ p_dev->stats.diag_rx_submit_err++;
+ BTUSB_ERR("btusb_submit(diag) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.diag_rx_submit_ok++;
+ }
+ }
+
+ /* Create the proc filesystem entry. To make it easy to retrieve, the
+ * entry created is called /proc/driver/btusb/btusbN where btusbN matches the
+ * file entry in /dev.
+ * The name of the device in /dev comes from the device created when
+ * usb_register_dev was called (in the current fn). The name was built
+ * from the btusb_class structure. usb_register_dev calls device_create
+ * which creates the VFS entry. This can be found in online linux code.
+ */
+ btusb_proc_add(p_dev, kobject_name(&p_interface->usb_dev->kobj));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+ if (autopm)
+ {
+ BTUSB_INFO("Enabling for remote wakeup\n");
+ p_interface->needs_remote_wakeup = 1;
+
+ BTUSB_INFO("Setting power/wakeup to enabled\n");
+ device_set_wakeup_enable(&p_dev->p_udev->dev, 1);
+
+ BTUSB_INFO("Enabling for autosuspend\n");
+ usb_enable_autosuspend(p_dev->p_udev);
+ }
+#else
+ autopm = 0;
+ BTUSB_INFO("USB suspend/resume not supported for this kernel version\n");
+#endif
+
+#ifdef BTUSB_LITE
+ /* must be called last because it uses the p_dev entries */
+ btusb_lite_create(p_dev, p_interface);
+#endif
+
+ /* let the user know what node this device is now attached to */
+ BTUSB_DBG("device now attached to minor %d\n", p_interface->minor);
+
+ return 0;
+
+error_bt_submit:
+ usb_kill_anchored_urbs(&p_dev->acl_rx_submitted);
+ usb_kill_anchored_urbs(&p_dev->acl_tx_submitted);
+ usb_kill_anchored_urbs(&p_dev->diag_rx_submitted);
+ usb_kill_anchored_urbs(&p_dev->diag_tx_submitted);
+ usb_kill_anchored_urbs(&p_dev->event_submitted);
+ usb_kill_anchored_urbs(&p_dev->cmd_submitted);
+ usb_kill_anchored_urbs(&p_dev->voice_rx_submitted);
+ usb_kill_anchored_urbs(&p_dev->voice_tx_submitted);
+
+ usb_deregister_dev(p_interface, &btusb_class);
+
+error_claim:
+ usb_set_intfdata(p_interface, NULL);
+ if (p_dev->p_diag_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_diag_intf);
+ p_dev->p_diag_intf = NULL;
+ BTUSB_DBG("released diag interface\n");
+ }
+ if (p_dev->p_dfu_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_dfu_intf);
+ p_dev->p_dfu_intf = NULL;
+ BTUSB_DBG("released dfu interface\n");
+ }
+ if (p_dev->p_voice_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_voice_intf);
+ p_dev->p_voice_intf = NULL;
+ BTUSB_DBG("released iso interface\n");
+ }
+
+error:
+ if (p_dev)
+ {
+ kref_put(&p_dev->kref, btusb_delete);
+ }
+ return retval;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_cancel_voice
+ **
+ ** Description Cancel all pending voice requests and wait for their cancellations
+ **
+ ** Parameters p_dev: device instance control block
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+void btusb_cancel_voice(struct btusb *p_dev)
+{
+ int idx;
+ struct btusb_voice_pkt *p_pkt;
+
+ BTUSB_DBG("enter\n");
+
+ /* cancel rx */
+ BTUSB_DBG("Removing SCO RX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->voice_rx_submitted);
+
+ /* since all URB have been killed, safely reset the state variables */
+ p_dev->voice_rx.remaining = 0;
+ p_dev->voice_rx.hdr_size = 0;
+ p_dev->voice_rx.pp_pkt = NULL;
+
+ /* free any SCO HCI message being consolidated on any channel */
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_pkt = p_dev->voice_rx.channels[idx].p_pkt;
+ /* mark the packet bad (length 0) and put it in the reception queue
+ because putting it back in the free list would require protecting
+ the access to the write counter between read and ioctl:
+ btusb_cq_put(&p_dev->voice_rx_list, *p_dev->voice_channels[idx].p_pkt) */
+ if (p_pkt)
+ {
+ p_pkt->bt_hdr.len = 0;
+ btusb_rx_enqueue_voice(p_dev, p_pkt);
+ }
+ p_dev->voice_rx.channels[idx].p_pkt = NULL;
+ }
+
+ /* cancel tx */
+ BTUSB_DBG("Removing SCO RX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->voice_tx_submitted);
+ atomic_set(&p_dev->voice_tx_active, 0);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_cancel_urbs
+ **
+ ** Description Cancel all pending non-voice requests and wait for their cancellations
+ **
+ ** Parameters pointer on usb_bt struck that contains all the btusb info
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+void btusb_cancel_urbs(struct btusb *p_dev)
+{
+ BTUSB_DBG("enter\n");
+
+ /* stop reading data */
+ BTUSB_DBG("Removing ACL RX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->acl_rx_submitted);
+
+ /* stop reading events */
+ BTUSB_DBG("Removing EVENT anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->event_submitted);
+
+ /* stop reading diags */
+ BTUSB_DBG("Removing DIAG anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->diag_rx_submitted);
+
+ /* cancel ACL writes */
+ BTUSB_DBG("Removing ACL TX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->acl_tx_submitted);
+
+ /* cancel commands */
+ BTUSB_DBG("Removing CMD anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->cmd_submitted);
+
+ /* cancel diags */
+ BTUSB_DBG("Removing DIAG TX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->diag_tx_submitted);
+
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_disconnect
+ **
+ ** Description
+ **
+ ** Parameters p_interface: first interface being disconnected
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+static void btusb_disconnect(struct usb_interface *p_interface)
+{
+ struct btusb *p_dev = usb_get_intfdata(p_interface);
+
+ BTUSB_INFO("p_dev=%p\n", p_dev);
+ if (!p_dev)
+ {
+ BTUSB_ERR("p_dev == NULL\n");
+ return;
+ }
+
+ if (p_interface != p_dev->p_main_intf)
+ {
+ BTUSB_DBG("not the main interface\n");
+ return;
+ }
+
+ /* clear the interface data information */
+ usb_set_intfdata(p_interface, NULL);
+
+#ifdef BTUSB_LITE
+ btusb_lite_stop_all(p_dev);
+ btusb_lite_delete(p_dev, p_interface);
+#endif
+
+ btusb_proc_remove(p_dev, p_interface->usb_dev->kobj.name);
+
+ BTUSB_DBG("shutting down HCI intf\n");
+
+ /* prevent more I/O from starting */
+ p_dev->p_main_intf = NULL;
+
+ /* cancel pending requests */
+ btusb_cancel_voice(p_dev);
+ btusb_cancel_urbs(p_dev);
+
+ /* give back our minor */
+ BTUSB_DBG("unregistering #%d\n", p_interface->minor);
+ usb_deregister_dev(p_interface, &btusb_class);
+
+ /* release interfaces */
+ if (p_dev->p_diag_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_diag_intf);
+ p_dev->p_diag_intf = NULL;
+ BTUSB_DBG("released diag interface\n");
+ }
+ if (p_dev->p_dfu_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_dfu_intf);
+ p_dev->p_dfu_intf = NULL;
+ BTUSB_DBG("released dfu interface\n");
+ }
+ if (p_dev->p_voice_intf)
+ {
+ usb_driver_release_interface(&btusb_driver, p_dev->p_voice_intf);
+ p_dev->p_voice_intf = NULL;
+ BTUSB_DBG("released iso interface\n");
+ }
+
+ if (autopm)
+ {
+ BTUSB_INFO("Disabling for remote wakeup\n");
+ p_dev->p_main_intf->needs_remote_wakeup = 0;
+
+ BTUSB_INFO("Setting power/wakeup to disabled\n");
+ device_set_wakeup_enable(&p_dev->p_udev->dev, 0);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
+ BTUSB_INFO("Disabling autosuspend\n");
+ usb_disable_autosuspend(p_dev->p_udev);
+#endif
+ }
+
+ /* decrement the reference counter */
+ BTUSB_DBG("kref_put -> &p_dev->kref 0x%p \n", &p_dev->kref);
+ kref_put(&p_dev->kref, btusb_delete);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_suspend
+ **
+ ** Description
+ **
+ ** Parameters p_interface: first interface being suspended
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+static int btusb_suspend(struct usb_interface *p_interface, pm_message_t message)
+{
+ struct btusb *p_dev = usb_get_intfdata(p_interface);
+
+ if (unlikely(!p_dev))
+ return 0;
+
+ if (p_dev->p_main_intf == p_interface)
+ {
+ BTUSB_INFO("Suspending USB\n");
+ BTUSB_DBG("main interface (%p)\n",p_dev->p_main_intf);
+
+ /* stop reading data */
+ BTUSB_DBG("Removing ACL RX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->acl_rx_submitted);
+
+ /* stop reading events */
+ BTUSB_DBG("Removing EVENT anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->event_submitted);
+
+ /* cancel ACL writes */
+ BTUSB_DBG("Removing ACL TX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->acl_tx_submitted);
+
+ /* cancel commands */
+ BTUSB_DBG("Removing CMD anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->cmd_submitted);
+
+ }
+ if (p_dev->p_voice_intf == p_interface)
+ {
+ BTUSB_DBG("voice interface (%p)\n",p_dev->p_voice_intf);
+ }
+ if (p_dev->p_dfu_intf == p_interface)
+ {
+ BTUSB_DBG("dfu interface (%p)\n",p_dev->p_dfu_intf);
+ }
+ if (p_dev->p_diag_intf == p_interface)
+ {
+ BTUSB_DBG("diag interface (%p)\n",p_dev->p_diag_intf);
+
+ /* stop reading diags */
+ BTUSB_DBG("Removing DIAG RX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->diag_rx_submitted);
+
+ /* cancel diags */
+ BTUSB_DBG("Removing DIAG TX anchored URBs\n");
+ usb_kill_anchored_urbs(&p_dev->diag_tx_submitted);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_resume
+ **
+ ** Description
+ **
+ ** Parameters p_interface: first interface being resumed
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+static int btusb_resume(struct usb_interface *p_interface)
+{
+ struct btusb *p_dev = usb_get_intfdata(p_interface);
+ int idx;
+ int retval = -ENOMEM;
+ struct btusb_trans *p_trans;
+
+ BTUSB_INFO("p_dev=%p\n", p_dev);
+ if (unlikely(p_dev == NULL))
+ {
+ BTUSB_ERR("p_dev == NULL\n");
+ return retval;
+ }
+
+ if (p_dev->p_main_intf == p_interface)
+ {
+ BTUSB_DBG("main interface (%p)\n",p_dev->p_main_intf);
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->event_array)
+ {
+ if (likely(p_trans->dma_buffer != NULL))
+ {
+ if (unlikely(btusb_submit(p_dev, &p_dev->event_submitted, p_trans, GFP_KERNEL)))
+ {
+ p_dev->stats.event_submit_err++;
+ BTUSB_ERR("btusb_submit(event) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.event_submit_ok++;
+ }
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_rx_array)
+ {
+ if (likely(p_trans->dma_buffer != NULL))
+ {
+ if (unlikely(btusb_submit(p_dev, &p_dev->acl_rx_submitted, p_trans, GFP_KERNEL)))
+ {
+ p_dev->stats.acl_rx_submit_err++;
+ BTUSB_ERR("btusb_submit(acl_rx) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.acl_rx_submit_ok++;
+ }
+ }
+ }
+ if (p_dev->p_voice_intf == p_interface)
+ {
+ BTUSB_DBG("voice interface (%p)\n",p_dev->p_voice_intf);
+ }
+ if (p_dev->p_dfu_intf == p_interface)
+ {
+ BTUSB_DBG("dfu interface (%p)\n",p_dev->p_dfu_intf);
+ }
+ if (p_dev->p_diag_intf == p_interface)
+ {
+ BTUSB_DBG("diag interface (%p)\n",p_dev->p_diag_intf);
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_rx_array)
+ {
+ if (likely(p_trans->dma_buffer != NULL))
+ {
+ if (unlikely(btusb_submit(p_dev, &p_dev->diag_rx_submitted, p_trans, GFP_KERNEL)))
+ {
+ p_dev->stats.diag_rx_submit_err++;
+ BTUSB_ERR("btusb_submit(diag) failed\n");
+ goto error_bt_submit;
+ }
+ p_dev->stats.diag_rx_submit_ok++;
+ }
+ }
+ }
+
+ return 0;
+
+error_bt_submit:
+ usb_kill_anchored_urbs(&p_dev->acl_rx_submitted);
+ usb_kill_anchored_urbs(&p_dev->diag_rx_submitted);
+ usb_kill_anchored_urbs(&p_dev->event_submitted);
+
+ usb_deregister_dev(p_interface, &btusb_class);
+ return retval;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_reset_resume
+ **
+ ** Description
+ **
+ ** Parameters p_interface: first interface being resumed
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+static int btusb_reset_resume(struct usb_interface *p_interface)
+{
+ BTUSB_DBG("enter\n");
+
+ return btusb_resume(p_interface);
+}
+
+
+struct usb_driver btusb_driver =
+{
+ .name = "btusb",
+ .id_table = btusb_table,
+ .probe = btusb_probe,
+ .disconnect = btusb_disconnect,
+ .suspend = btusb_suspend,
+ .resume = btusb_resume,
+ .reset_resume = btusb_reset_resume,
+ .supports_autosuspend = 1
+};
+
+/*******************************************************************************
+ **
+ ** Function btusb_create
+ **
+ ** Description Initialize the control block
+ **
+ ** Returns 0 upon success, error core else.
+ **
+ *******************************************************************************/
+static int btusb_create(struct btusb *p_dev, struct usb_interface *p_interface, const struct usb_device_id *p_id)
+{
+ unsigned idx;
+ struct usb_host_config *p_config;
+ struct usb_host_interface *p_host_intf;
+ struct btusb_voice_pkt *p_pkt;
+
+ /* initialize the elements of the device structure */
+ kref_init(&p_dev->kref);
+ GKI_init_q(&p_dev->tx_queue);
+ GKI_init_q(&p_dev->rx_queue);
+ init_waitqueue_head(&p_dev->rx_wait_q);
+ init_usb_anchor(&p_dev->acl_rx_submitted);
+ init_usb_anchor(&p_dev->event_submitted);
+ init_usb_anchor(&p_dev->diag_rx_submitted);
+ init_usb_anchor(&p_dev->acl_tx_submitted);
+ init_usb_anchor(&p_dev->cmd_submitted);
+ init_usb_anchor(&p_dev->diag_tx_submitted);
+ init_usb_anchor(&p_dev->voice_rx_submitted);
+ init_usb_anchor(&p_dev->voice_tx_submitted);
+ atomic_set(&p_dev->voice_tx_active, 0);
+ INIT_LIST_HEAD(&p_dev->scosniff_list);
+ init_completion(&p_dev->scosniff_completion);
+
+
+ /* save the USB information */
+ p_dev->p_udev = usb_get_dev(interface_to_usbdev(p_interface));
+ p_dev->p_id = p_id;
+ p_dev->p_main_intf = p_interface;
+
+ /* register tx task so we can start sending data to transport */
+ tasklet_init(&p_dev->tx_task, btusb_tx_task, (unsigned long)p_dev);
+ BTUSB_DBG("tasklet_init complete\n");
+
+ INIT_BTUSB_CQ(p_dev->voice_rx_list);
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx_pkts); idx++)
+ {
+ p_pkt = &p_dev->voice_rx_pkts[idx];
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ /* write the magic number to allow checking corruption */
+ p_pkt->gki_hdr.q_id = GKI_NUM_TOTAL_BUF_POOLS + 1;
+ p_pkt->magic = MAGIC_NO;
+#endif
+ p_pkt->gki_hdr.status = BUF_STATUS_UNLINKED;
+ p_pkt->bt_hdr.event = HCIT_TYPE_SCO_DATA;
+
+ if (!btusb_cq_put(&p_dev->voice_rx_list, p_pkt))
+ {
+ BTUSB_ERR("btusb_cq_put failed\n");
+ }
+ }
+
+ p_dev->kterm.c_line = N_HCI;
+ p_dev->kterm.c_iflag = IGNPAR | ICRNL;
+ p_dev->kterm.c_oflag = 0;
+ p_dev->kterm.c_cflag = B115200 | CRTSCTS | CS8 | CLOCAL | CREAD;
+ p_dev->kterm.c_lflag = ICANON;
+ p_dev->kterm.c_ispeed = p_dev->kterm.c_ospeed = 115200;
+ p_dev->kterm.c_cc[VEOF] = 4;
+ p_dev->kterm.c_cc[VMIN] = 1;
+
+ /* check if there is a WiFi interface in the same device */
+ p_config = p_dev->p_udev->actconfig;
+ for (idx = 1; idx < p_config->desc.bNumInterfaces; idx++)
+ {
+ p_host_intf = &p_config->interface[idx]->altsetting[0];
+ if ((p_host_intf->desc.bInterfaceClass == USB_CLASS_VENDOR_SPEC) &&
+ (p_host_intf->desc.bInterfaceSubClass == 2) &&
+ (p_host_intf->desc.bInterfaceProtocol == 255))
+ {
+ p_dev->issharedusb = true;
+ }
+ }
+
+ /* set quirks */
+ if (p_dev->issharedusb)
+ {
+ /* all shared USB devices need a ZLP to be sent in TX */
+ p_dev->quirks |= BTUSB_QUIRK_ZLP_TX_REQ;
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_delete
+ **
+ ** Description Fully remove the elements for a device
+ **
+ ** Parameters kref: reference counter
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+void btusb_delete(struct kref *kref)
+{
+ struct btusb *p_dev = container_of(kref, struct btusb, kref);
+ struct btusb_trans *p_trans;
+ BT_HDR *p_buf = NULL;
+ int idx;
+
+ BTUSB_DBG("enter\n");
+
+#ifdef BTUSB_LITE
+ btusb_lite_stop_all(p_dev);
+#endif
+
+ /* stop tx_task and then remove any data packets from tx_q */
+ tasklet_kill(&p_dev->tx_task);
+
+ BTUSB_DBG("tasklet_kill complete\n");
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->tx_queue)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+
+ BTUSB_DBG("dequeued all remaining buffers from TX Q\n");
+
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->rx_queue)) != NULL)
+ {
+ btusb_rx_dequeued(p_dev, p_buf);
+ }
+
+ if (p_dev->p_write_msg)
+ {
+ GKI_freebuf(p_dev->p_write_msg);
+ }
+
+ BTUSB_DBG("dequeued all remaining buffers from RX Q\n");
+
+ /* ensure that the process is not hanging on select()/poll() */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+
+ /* free allocated USB DMA space */
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->cmd_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_CMD_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->event_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_EVT_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_rx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_ACL_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->acl_tx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_ACL_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_rx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_ACL_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->diag_tx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_HCI_MAX_ACL_SIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_rx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_VOICE_BUFFER_MAXSIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_tx_array)
+ {
+ BTUSB_BUFFER_FREE(p_dev->p_udev, BTUSB_VOICE_BUFFER_MAXSIZE,
+ p_trans->dma_buffer,
+ p_trans->dma);
+ usb_free_urb(p_trans->p_urb);
+ }
+ usb_put_dev(p_dev->p_udev);
+
+ kfree(p_dev);
+
+ GKI_shutdown();
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_init
+ **
+ ** Description Module init routine
+ **
+ ** Parameters None
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+static int __init btusb_init(void)
+{
+ int result;
+
+ BTUSB_DBG("built %s,%s\n", __DATE__, __TIME__);
+
+ btusb_proc_init();
+
+ /* register this driver with the USB subsystem */
+ result = usb_register(&btusb_driver);
+ if (result)
+ {
+ BTUSB_ERR("usb_register failed (%d)\n", result);
+ }
+
+ return result;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_exit
+ **
+ ** Description Module exit routine
+ **
+ ** Parameters None
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+static void __exit btusb_exit(void)
+{
+ BTUSB_DBG("enter\n");
+
+ btusb_proc_exit();
+
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&btusb_driver);
+}
+
+module_init(btusb_init);
+module_exit(btusb_exit);
+
+module_param(autopm, bool, 0644);
+MODULE_PARM_DESC(autopm, "Enable suspend/resume with remote wakeup");
+module_param(dbgflags, int, 0644);
+MODULE_PARM_DESC(dbgflags, "Debug flags");
+
+MODULE_DESCRIPTION("Broadcom Bluetooth USB driver");
+MODULE_LICENSE("GPL");
+
diff --git a/src/btusb_dev.c b/src/btusb_dev.c
new file mode 100755
index 0000000..9e24adc
--- a/dev/null
+++ b/src/btusb_dev.c
@@ -0,0 +1,2001 @@
+/*
+ *
+ * btusb_dev.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Module that implements the device routines.
+ *
+ */
+
+#include "btusb.h"
+#include <linux/module.h>
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/serial.h>
+
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "hcidefs.h"
+
+#include "gki_int.h"
+
+/* local functions declaration */
+static int btusb_update_voice_channels(struct btusb *p_dev);
+static int btusb_update_voice_trans(struct btusb *p_dev);
+static void btusb_submit_voice_tx(struct btusb *p_dev, char *p_data, unsigned long lenth);
+static int btusb_submit_cmd(struct btusb *p_dev, char *packet, unsigned long length);
+static int btusb_submit_acl(struct btusb *p_dev, char *packet, unsigned long length);
+static int btusb_submit_diag(struct btusb *p_dev, char *packet, unsigned long length);
+
+/*******************************************************************************
+ **
+ ** Function btusb_alloc_trans
+ **
+ ** Description Allocate a transaction in the array of transactions.
+ **
+ ** Parameters p_array: array of USB transactions
+ ** size: size of the array of transactions
+ **
+ ** Returns Pointer to the next free transaction, NULL if not found
+ **
+ *******************************************************************************/
+static struct btusb_trans *btusb_alloc_trans(struct btusb_trans *p_array, size_t size)
+{
+ int idx;
+ struct btusb_trans *p_trans;
+
+ for (idx = 0; idx < size; idx++)
+ {
+ p_trans = &p_array[idx];
+ if (p_trans->gki_hdr.status == BUF_STATUS_FREE)
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_UNLINKED;
+ return p_trans;
+ }
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_dump_data
+ **
+ ** Description Print the data into the kernel messages
+ **
+ ** Parameters p: pointer to the data to print
+ ** len: length of the data to print
+ ** p_title: title to print before the data
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_dump_data(const UINT8 *p, int len, const char *p_title)
+{
+ int idx;
+
+ if (likely((dbgflags & BTUSB_DBG_MSG) == 0))
+ {
+ return;
+ }
+
+ if (p_title)
+ {
+ printk("---------------------- %s ----------------------\n", p_title);
+ }
+
+ printk("%p: ", p);
+
+ for(idx = 0; idx < len; idx++)
+ {
+ printk("%02x ", p[idx]);
+ }
+ printk("\n--------------------------------------------------------------------\n");
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_voice_stats
+ **
+ ** Description
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_voice_stats(unsigned long *p_max, unsigned long *p_min,
+ struct timeval *p_result, struct timeval *p_last_time)
+{
+ struct timeval current_time;
+
+ do_gettimeofday(&current_time);
+ /* perform the carry for the later subtraction by updating y */
+ if (current_time.tv_usec < p_last_time->tv_usec)
+ {
+ int nsec = (p_last_time->tv_usec - current_time.tv_usec) / 1000000 + 1;
+ p_last_time->tv_usec -= 1000000 * nsec;
+ p_last_time->tv_sec += nsec;
+ }
+ if (current_time.tv_usec - p_last_time->tv_usec > 1000000)
+ {
+ int nsec = (current_time.tv_usec - p_last_time->tv_usec) / 1000000;
+ p_last_time->tv_usec += 1000000 * nsec;
+ p_last_time->tv_sec -= nsec;
+ }
+ /* compute the time remaining to wait */
+ p_result->tv_sec = current_time.tv_sec - p_last_time->tv_sec;
+ p_result->tv_usec = current_time.tv_usec - p_last_time->tv_usec;
+
+ /* update the max except the first time where the calculation is wrong
+ because of the initial value assuming p_last is zero initialized */
+ if (p_max != NULL)
+ {
+ if (p_result->tv_usec > *p_max && (p_last_time->tv_sec) && (p_last_time->tv_usec))
+ {
+ *p_max = p_result->tv_usec;
+ }
+ }
+
+ /* update the min except the first time where the calculation is wrong
+ because of the initial value assuming *p_last and p_min are zero initialized */
+ if (p_min != NULL)
+ {
+ if ((p_result->tv_usec < *p_min || (*p_min == 0)) &&
+ (p_last_time->tv_sec) && (p_last_time->tv_usec))
+ {
+ *p_min = p_result->tv_usec;
+ }
+ }
+
+ *p_last_time = current_time;
+ BTUSB_DBG("btusb_voice_stats len: %lu\n", p_result->tv_usec);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_tx_task
+ **
+ ** Description host to controller tasklet
+ **
+ ** Parameters arg:
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_tx_task(unsigned long arg)
+{
+ struct btusb *p_dev = (struct btusb *) arg;
+ BT_HDR *p_buf;
+ UINT8 *p_data;
+ UINT8 msg_type;
+
+ /* dequeue data packet and submit to transport */
+ if (unlikely((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->tx_queue)) == NULL))
+ {
+ BTUSB_DBG("dequeued data = NULL - just return\n");
+ goto reschedule_task;
+ }
+
+ /* bypass the header and retrieve the type */
+ p_data = (UINT8 *) (p_buf + 1) + p_buf->offset;
+
+ /* extract message type */
+ STREAM_TO_UINT8(msg_type, p_data);
+ switch (msg_type)
+ {
+ case HCIT_TYPE_SCO_DATA:
+ btusb_submit_voice_tx(p_dev, p_data, p_buf->len - 1);
+ break;
+ case HCIT_TYPE_COMMAND:
+#ifdef BTUSB_LITE
+ /* Filter User's Write operation to catch some commands(VSCs) */
+ if (btusb_lite_hci_cmd_filter(p_dev, p_buf))
+#endif
+ {
+ btusb_submit_cmd(p_dev, p_data, p_buf->len - 1);
+ }
+ break;
+ case HCIT_TYPE_ACL_DATA:
+ btusb_submit_acl(p_dev, p_data, p_buf->len - 1);
+ break;
+ case HCIT_TYPE_LM_DIAG:
+ btusb_submit_diag(p_dev, p_data, p_buf->len - 1);
+ break;
+ }
+ GKI_freebuf(p_buf);
+
+reschedule_task:
+ if (p_dev->tx_queue.count)
+ tasklet_schedule(&p_dev->tx_task);
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_rx_enqueue
+ **
+ ** Description Add a received USB message to the RX queue
+ **
+ ** Parameters p_dev: device instance control block
+ ** p_trans: transaction to forward
+ ** hcitype: type of HCI data in the USB transaction
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_rx_enqueue(struct btusb *p_dev, struct btusb_trans *p_trans, UINT8 hcitype)
+{
+ BT_HDR *p_buf = &p_trans->bt_hdr;
+ struct urb *p_urb = p_trans->p_urb;
+ UINT8 *p = (UINT8 *)p_urb->transfer_buffer;
+ UINT16 len;
+
+ BTUSB_DBG("len = %d\n", p_urb->actual_length);
+
+ /* calculate the HCI packet length, depending on the type */
+ switch (hcitype)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ p += 2;
+ STREAM_TO_UINT16(len, p);
+ len += 4;
+ break;
+
+ case HCIT_TYPE_EVENT:
+ p += 1;
+ STREAM_TO_UINT8(len, p);
+ len += 2;
+ break;
+
+ case HCIT_TYPE_LM_DIAG:
+ len = HCIT_LM_DIAG_LENGTH;
+ break;
+
+ default:
+ BTUSB_ERR("Unsupported HCI type: %d\n", hcitype);
+ len = p_urb->actual_length;
+ break;
+ }
+
+ /* check HCI packet length matches that of the USB transaction */
+ if (unlikely(len != p_urb->actual_length))
+ {
+ /* firmware fix for specific HW that do not correctly support ZLP:
+ * - 43242 and 43569 shared USB
+ * - some USB hubs not supporting ZLP packets and requiring a workaround
+ */
+ if (unlikely(((len % 16) == 0) && (p_urb->actual_length == (len + 1))))
+ {
+ BTUSB_DBG("missing ZLP workaround: %d != %d\n", p_urb->actual_length, len);
+ p_urb->actual_length = len;
+ }
+ else
+ {
+ BTUSB_ERR("URB data length does not match packet %d != %d\n", p_urb->actual_length, len);
+ }
+ }
+
+ /* fill up the header of the message */
+ p_buf->event = hcitype;
+ p_buf->len = p_urb->actual_length;
+ p_buf->offset = 0;
+ p_buf->layer_specific &= ~BTUSB_LS_H4_TYPE_SENT;
+
+ /* InQ for user-space to read */
+ GKI_enqueue(&p_dev->rx_queue, p_buf);
+
+ /* if the process is polling, indicate RX event */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_rx_enqueue_voice
+ **
+ ** Description Add a full HCI voice packet to the RX queue
+ **
+ ** Parameters p_dev: device instance control block
+ ** p_pkt: transaction to forward
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_rx_enqueue_voice(struct btusb *p_dev, struct btusb_voice_pkt *p_pkt)
+{
+ /* InQ for user-space to read */
+ GKI_enqueue(&p_dev->rx_queue, &p_pkt->bt_hdr);
+
+ /* if the process is polling, indicate RX event */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_rx_dequeued
+ **
+ ** Description Figure out what to do with a dequeued message
+ **
+ ** Parameters p_dev: driver control block
+ ** p_msg: dequeued message
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_rx_dequeued(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ struct btusb_trans *p_trans = container_of(p_msg, struct btusb_trans, bt_hdr);
+ struct btusb_voice_pkt *p_pkt = container_of(p_msg, struct btusb_voice_pkt, bt_hdr);
+
+#if defined(BTUSB_LITE)
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ GKI_freebuf(p_msg);
+ return;
+ }
+#endif
+
+ switch (p_msg->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ if (unlikely(btusb_submit(p_dev, &p_dev->acl_rx_submitted, p_trans, GFP_KERNEL)))
+ p_dev->stats.acl_rx_submit_err++;
+ else
+ p_dev->stats.acl_rx_submit_ok++;
+ break;
+
+ case HCIT_TYPE_EVENT:
+#if defined(BTUSB_LITE)
+ /* when BTUSB_LITE is defined, EVT may be resubmitted from IRQ context */
+ if (unlikely(btusb_submit(p_dev, &p_dev->event_submitted, p_trans, GFP_ATOMIC)))
+#else
+ if (unlikely(btusb_submit(p_dev, &p_dev->event_submitted, p_trans, GFP_KERNEL)))
+#endif
+ p_dev->stats.event_submit_err++;
+ else
+ p_dev->stats.event_submit_ok++;
+ break;
+
+ case HCIT_TYPE_LM_DIAG:
+ if (unlikely(btusb_submit(p_dev, &p_dev->diag_rx_submitted, p_trans, GFP_KERNEL)))
+ p_dev->stats.diag_rx_submit_err++;
+ else
+ p_dev->stats.diag_rx_submit_ok++;
+ break;
+
+ case HCIT_TYPE_SCO_DATA:
+ if (!btusb_cq_put(&p_dev->voice_rx_list, p_pkt))
+ {
+ BTUSB_ERR("btusb_cq_put failed\n");
+ }
+ break;
+ default:
+ BTUSB_ERR("Unexpected buffer type\n");
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_open
+ **
+ ** Description User mode open callback
+ **
+ *******************************************************************************/
+int btusb_open(struct inode *inode, struct file *file)
+{
+ struct btusb *p_dev;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+
+ BTUSB_INFO("enter\n");
+
+ /* retrieve the minor for this inode */
+ subminor = iminor(inode);
+
+ /* retrieve the USB interface attached to this minor */
+ interface = usb_find_interface(&btusb_driver, subminor);
+ if (!interface)
+ {
+ BTUSB_ERR("can't find interface for minor %d\n", subminor);
+ retval = -ENODEV;
+ goto exit;
+ }
+ BTUSB_INFO("minor %u\n", subminor);
+
+ /* retrieve the device driver structure pointer */
+ p_dev = usb_get_intfdata(interface);
+ BTUSB_INFO("p_dev=%p\n", p_dev);
+ if (!p_dev)
+ {
+ BTUSB_ERR("can't find device\n");
+ retval = -ENODEV;
+ goto exit;
+ }
+
+ /* save our object in the file's private structure */
+ file->private_data = p_dev;
+
+ /* increment our usage count for the device */
+ BTUSB_INFO("kref_get -> &p_dev->kref 0x%p\n", &p_dev->kref);
+ kref_get(&p_dev->kref);
+
+exit:
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_release
+ **
+ ** Description User mode close callback
+ **
+ *******************************************************************************/
+int btusb_release(struct inode *inode, struct file *file)
+{
+ struct btusb *p_dev;
+ int idx;
+
+ BTUSB_INFO("enter\n");
+
+ p_dev = (struct btusb *) file->private_data;
+ BTUSB_INFO("p_dev=%p\n", p_dev);
+ if (p_dev == NULL)
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+#ifdef BTUSB_LITE
+ btusb_lite_stop_all(p_dev);
+#endif
+
+ /* ensure there is no process hanging on poll / select */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ if (p_dev->voice_rx.channels[idx].used)
+ {
+ if (btusb_remove_voice_channel(p_dev, p_dev->voice_rx.channels[idx].handle))
+ {
+ BTUSB_ERR("btusb_remove_voice_channel failed\n");
+ }
+ }
+ }
+
+ /* decrement the usage count on our device */
+ BTUSB_INFO("kref_put -> &p_dev->kref 0x%p\n", &p_dev->kref);
+ kref_put(&p_dev->kref, btusb_delete);
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_get_rx_packet
+ **
+ ** Description Get (extract) next buffer to sent to User Space
+ **
+ *******************************************************************************/
+static BT_HDR *btusb_get_rx_packet(struct btusb *p_dev)
+{
+ /* if there is a pending Rx buffer */
+ if (p_dev->p_rx_msg)
+ {
+ return p_dev->p_rx_msg;
+ }
+#ifdef BTUSB_LITE
+ /* If HCI is over IPC */
+ if (btusb_lite_is_hci_over_ipc(p_dev))
+ {
+ return NULL;
+ }
+#endif
+
+ /* dequeue the next buffer and store its reference */
+ p_dev->p_rx_msg = GKI_dequeue(&p_dev->rx_queue);
+
+ return p_dev->p_rx_msg;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_get_rx_packet_buffer
+ **
+ ** Description Get pointer address of data to send to User Space
+ **
+ *******************************************************************************/
+static UINT8 *btusb_get_rx_packet_buffer(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ struct btusb_trans *p_trans;
+
+ switch(p_msg->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ case HCIT_TYPE_EVENT:
+ case HCIT_TYPE_LM_DIAG:
+#ifdef BTUSB_LITE
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ return ((char *)(p_msg + 1) + p_msg->offset);
+ }
+#endif
+ p_trans = container_of(p_msg, struct btusb_trans, bt_hdr);
+ return (p_trans->dma_buffer + p_msg->offset);
+ default: /* SCO etc... */
+ return ((char *)(p_msg + 1) + p_msg->offset);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_read
+ **
+ ** Description User mode read
+ **
+ ** Returns Number of bytes read, error number if negative
+ **
+ *******************************************************************************/
+ssize_t btusb_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+{
+ struct btusb *p_dev = (struct btusb *)file->private_data;
+ UINT16 len;
+ size_t remainder = count;
+ BT_HDR *p_buf;
+ char *p_data;
+ char type;
+ int retval;
+
+ BTUSB_DBG("p_dev=%p count=%zu\n", p_dev, count);
+ if (unlikely(p_dev == NULL))
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ BTUSB_ERR("device unplugged\n");
+ return -ENODEV;
+ }
+
+ /* if read is non blocking and there is no data */
+ if (unlikely((file->f_flags & O_NONBLOCK) && (!btusb_get_rx_packet(p_dev))))
+ {
+ BTUSB_INFO("Non blocking read without any data\n");
+ return -EAGAIN;
+ }
+
+ /* wait for an event */
+ retval = wait_event_interruptible(p_dev->rx_wait_q, btusb_get_rx_packet(p_dev));
+ if (unlikely(retval))
+ {
+ BTUSB_DBG("read wait interrupted\n");
+ return retval;
+ }
+
+ p_buf = p_dev->p_rx_msg;
+ BTUSB_DBG("buffer=%p len=%u ls=%u\n", p_buf, p_buf->len, p_buf->layer_specific);
+ /* if the buffer is not empty and this is the first time buffer is picked,
+ * add HCI header in user space */
+ if (likely(p_buf->len && !(p_buf->layer_specific & BTUSB_LS_H4_TYPE_SENT)))
+ {
+ if (likely(remainder >= 1))
+ {
+ type = p_buf->event;
+ /* add the H4 packet header */
+ if (unlikely(copy_to_user(buffer, &type, 1)))
+ {
+ BTUSB_ERR("copy to user error\n");
+ return -EINVAL;
+ }
+ p_buf->layer_specific |= BTUSB_LS_H4_TYPE_SENT;
+ buffer += 1;
+ remainder -= 1;
+ }
+ else
+ {
+ BTUSB_ERR("Not enough space to copy H4 ACL header\n");
+ goto read_end;
+ }
+ }
+
+ /* retrieve address of the next data to send (depends on event) */
+ p_data = btusb_get_rx_packet_buffer(p_dev, p_buf);
+
+ /* take the min of remainder and p_buf length */
+ if (likely(p_buf->len < remainder))
+ {
+ len = p_buf->len;
+ }
+ else
+ {
+ len = remainder;
+ }
+
+ /* copy the message data to the available user space */
+ if (unlikely(copy_to_user(buffer, p_data, len)))
+ {
+ BTUSB_ERR("copy to user error\n");
+ return -EINVAL;
+ }
+ remainder -= len;
+ p_buf->len -= len;
+ p_buf->offset += len;
+
+ /* free the first buffer if it is empty */
+ if (likely(p_buf->len == 0))
+ {
+ /* free (fake event) or resubmit (real USB buffer) the buffer sent to app */
+ btusb_rx_dequeued(p_dev, p_buf);
+ p_dev->p_rx_msg = NULL;
+ }
+
+read_end:
+ return (count - remainder);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_write
+ **
+ ** Description User mode write
+ **
+ ** Returns Number of bytes written, error number if negative
+ **
+ *******************************************************************************/
+ssize_t btusb_write(struct file *file, const char __user *user_buffer, size_t count, loff_t *ppos)
+{
+ struct btusb *p_dev;
+ BT_HDR *p_msg;
+ UINT8 *p_data;
+ size_t remainder = count;
+ int err;
+ UINT16 appended, len;
+
+ p_dev = (struct btusb *)file->private_data;
+
+ BTUSB_DBG("p_dev=%p count=%zu\n", p_dev, count);
+
+ if (unlikely(p_dev == NULL))
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ BTUSB_ERR("device unplugged\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(count == 0))
+ {
+ return 0;
+ }
+
+ /* check that the incoming data is good */
+ if (unlikely(!access_ok(VERIFY_READ, (void *)user_buffer, count)))
+ {
+ BTUSB_ERR("buffer access verification failed\n");
+ return -EFAULT;
+ }
+
+ while (remainder)
+ {
+ BTUSB_DBG("remain=%zu p_write_msg=%p\n", remainder, p_dev->p_write_msg);
+ /* check if there is already an active transmission buffer */
+ p_msg = p_dev->p_write_msg;
+ if (likely(!p_msg))
+ {
+ /* get a buffer from the pool */
+ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + BTUSB_H4_MAX_SIZE);
+ if (unlikely(!p_msg))
+ {
+ BTUSB_ERR("unable to get GKI buffer - write failed\n");
+ return -EINVAL;
+ }
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
+ return -EINVAL;
+ }
+ p_dev->p_write_msg = p_msg;
+
+ p_msg->event = 0;
+ p_msg->len = 0;
+ p_msg->offset = 0;
+ p_msg->layer_specific = 0;
+ }
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ /* append the entire data to the buffer (not exceeding buffer length) */
+ if (likely(remainder < (BTUSB_H4_MAX_SIZE - p_msg->len)))
+ appended = remainder;
+ else
+ appended = BTUSB_H4_MAX_SIZE - p_msg->len;
+ if (unlikely(copy_from_user(p_data + p_msg->len, (void *)user_buffer, appended)))
+ {
+ BTUSB_ERR("copy from user error\n");
+ return -EINVAL;
+ }
+ BTUSB_DBG("msg_len=%u appended=%u\n", p_msg->len, appended);
+
+ /* update the size of the buffer */
+ p_msg->len += appended;
+
+ /* compute the real HCI packet length (by default 0xFFFF to mark incomplete) */
+ len = 0xFFFF;
+ switch(p_data[0])
+ {
+ case HCIT_TYPE_SCO_DATA:
+ case HCIT_TYPE_COMMAND:
+ if (likely(p_msg->len >= 4))
+ {
+ /* bypass HCI type + opcode/connection handle */
+ p_data += 3;
+ STREAM_TO_UINT8(len, p_data);
+ len += 4;
+ BTUSB_DBG("SCO/CMD len=%u cur=%u\n", len, p_msg->len);
+ }
+ break;
+ case HCIT_TYPE_ACL_DATA:
+ if (likely(p_msg->len >= 5))
+ {
+ /* bypass HCI type + connection handle */
+ p_data += 3;
+ STREAM_TO_UINT16(len, p_data);
+ len += 5;
+ /* sanity check : ACL buffer should not be larger than supported */
+ if (unlikely(len > BTUSB_H4_MAX_SIZE))
+ {
+ BTUSB_ERR("ACL packet too long (%u)\n", len);
+ GKI_freebuf(p_dev->p_write_msg);
+ p_dev->p_write_msg = NULL;
+ return -EINVAL;
+ }
+ BTUSB_DBG("ACL len=%u cur=%u\n", len, p_msg->len);
+ }
+ break;
+ case HCIT_TYPE_LM_DIAG:
+ /* this packet does not have a length, so just send everything */
+ len = p_msg->len;
+ BTUSB_DBG("DIAG len=%u cur=%u\n", len, p_msg->len);
+ break;
+ default:
+ BTUSB_ERR("unsupported packet type\n");
+ GKI_freebuf(p_dev->p_write_msg);
+ p_dev->p_write_msg = NULL;
+ return count;
+ break;
+ }
+ /* check if the buffer length exceeds the packet length */
+ if (likely(p_msg->len >= len))
+ {
+ /* remove the extra data (belonging to next HCI packet) */
+ if (unlikely(p_msg->len > len))
+ {
+ /* remove exceeding data */
+ appended -= p_msg->len - len;
+ /* set len to computed HCI packet length */
+ p_msg->len = len;
+ }
+ if (autopm)
+ {
+ err = usb_autopm_get_interface(p_dev->p_main_intf);
+ if (unlikely(err < 0))
+ {
+ BTUSB_ERR("autopm failed\n");
+ autopm = 0;
+ }
+ }
+
+ /* add the incoming data and notify the btusb_tx_task to process */
+ GKI_enqueue(&p_dev->tx_queue, p_msg);
+
+ /* wake up tasklet */
+ tasklet_schedule(&p_dev->tx_task);
+
+ /* new write message */
+ p_dev->p_write_msg = NULL;
+ }
+ remainder -= appended;
+ user_buffer += appended;
+ }
+
+ return count;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_poll
+ **
+ ** Description Poll callback (to implement select)
+ **
+ ** Parameters file : file structure of the opened instance
+ ** p_pt : poll table to which the local queue must be added
+ **
+ ** Returns Mask of the type of polling supported, error number if negative
+ **
+ *******************************************************************************/
+unsigned int btusb_poll(struct file *file, struct poll_table_struct *p_pt)
+{
+ struct btusb *p_dev;
+ unsigned int mask;
+
+ BTUSB_DBG("enter\n");
+
+ /* retrieve the device from the file pointer */
+ p_dev = (struct btusb *) file->private_data;
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+ if (unlikely(p_dev == NULL))
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+ /* check if the device was disconnected */
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ BTUSB_ERR("device unplugged\n");
+ return -ENODEV;
+ }
+
+ /* indicate to the system on which queue it should poll (non blocking call) */
+ poll_wait(file, &p_dev->rx_wait_q, p_pt);
+
+ /* enable WRITE (select/poll is not write blocking) */
+ mask = POLLOUT | POLLWRNORM;
+
+ /* enable READ only if data is queued from HCI */
+ if (btusb_get_rx_packet(p_dev))
+ {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+#define BTUSB_RETURN_STR(__c) case __c: return #__c
+static const char *btusb_ioctl_string(unsigned int cmd)
+{
+ switch(cmd)
+ {
+ BTUSB_RETURN_STR(IOCTL_BTWUSB_GET_STATS);
+ BTUSB_RETURN_STR(IOCTL_BTWUSB_CLEAR_STATS);
+ BTUSB_RETURN_STR(IOCTL_BTWUSB_ADD_VOICE_CHANNEL);
+ BTUSB_RETURN_STR(IOCTL_BTWUSB_REMOVE_VOICE_CHANNEL);
+ BTUSB_RETURN_STR(TCGETS);
+ BTUSB_RETURN_STR(TCSETS);
+ BTUSB_RETURN_STR(TCSETSW);
+ BTUSB_RETURN_STR(TCSETSF);
+ BTUSB_RETURN_STR(TCGETA);
+ BTUSB_RETURN_STR(TCSETA);
+ BTUSB_RETURN_STR(TCSETAW);
+ BTUSB_RETURN_STR(TCSETAF);
+ BTUSB_RETURN_STR(TCSBRK);
+ BTUSB_RETURN_STR(TCXONC);
+ BTUSB_RETURN_STR(TCFLSH);
+ BTUSB_RETURN_STR(TIOCGSOFTCAR);
+ BTUSB_RETURN_STR(TIOCSSOFTCAR);
+ BTUSB_RETURN_STR(TIOCGLCKTRMIOS);
+ BTUSB_RETURN_STR(TIOCSLCKTRMIOS);
+#ifdef TIOCGETP
+ BTUSB_RETURN_STR(TIOCGETP);
+ BTUSB_RETURN_STR(TIOCSETP);
+ BTUSB_RETURN_STR(TIOCSETN);
+#endif
+#ifdef TIOCGETC
+ BTUSB_RETURN_STR(TIOCGETC);
+ BTUSB_RETURN_STR(TIOCSETC);
+#endif
+#ifdef TIOCGLTC
+ BTUSB_RETURN_STR(TIOCGLTC);
+ BTUSB_RETURN_STR(TIOCSLTC);
+#endif
+#ifdef TCGETX
+ BTUSB_RETURN_STR(TCGETX);
+ BTUSB_RETURN_STR(TCSETX);
+ BTUSB_RETURN_STR(TCSETXW);
+ BTUSB_RETURN_STR(TCSETXF);
+#endif
+ BTUSB_RETURN_STR(TIOCMGET);
+ BTUSB_RETURN_STR(TIOCMSET);
+ BTUSB_RETURN_STR(TIOCGSERIAL);
+ BTUSB_RETURN_STR(TIOCMIWAIT);
+ BTUSB_RETURN_STR(TIOCMBIC);
+ BTUSB_RETURN_STR(TIOCMBIS);
+ default:
+ return "unknwown";
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_ioctl
+ **
+ ** Description User mode ioctl
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success or an error code.
+ **
+ *******************************************************************************/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
+long btusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+#else
+int btusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+#endif
+{
+ const char *s_cmd;
+ struct btusb *p_dev;
+ struct btusb_ioctl_sco_info sco_info;
+ int retval = 0;
+
+ s_cmd = btusb_ioctl_string(cmd);
+
+ BTUSB_INFO("cmd=%s\n", s_cmd);
+
+ p_dev = (struct btusb *) file->private_data;
+ BTUSB_INFO("p_dev=%p\n", p_dev);
+ if (p_dev == NULL)
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+ /* check if the device was disconnected */
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ BTUSB_ERR("device unplugged\n");
+ return -ENODEV;
+ }
+
+ switch (cmd)
+ {
+ case IOCTL_BTWUSB_GET_STATS:
+ if (copy_to_user((void *) arg, &p_dev->stats, sizeof(tBTUSB_STATS)))
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ break;
+
+ case IOCTL_BTWUSB_CLEAR_STATS:
+ memset(&p_dev->stats, 0, sizeof(tBTUSB_STATS));
+ break;
+
+ case IOCTL_BTWUSB_ADD_VOICE_CHANNEL:
+ if (copy_from_user(&sco_info, (void *) arg, sizeof(sco_info)))
+ {
+ BTUSB_ERR("BTUSB_IOCTL_ADD_VOICE_CHANNEL failed getting 1st par\n");
+ retval = -EFAULT;
+ goto err_out;
+ }
+ return btusb_add_voice_channel(p_dev, sco_info.handle, sco_info.burst);
+
+ case IOCTL_BTWUSB_REMOVE_VOICE_CHANNEL:
+ if (copy_from_user(&sco_info, (void *) arg, sizeof(sco_info)))
+ {
+ BTUSB_ERR("BTUSB_IOCTL_ADD_VOICE_CHANNEL failed getting 1st par\n");
+ retval = -EFAULT;
+ goto err_out;
+ }
+ return btusb_remove_voice_channel(p_dev, sco_info.handle);
+
+ case TCGETS:
+ /* dummy support of TTY IOCTLs */
+ if (!arg)
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+#ifndef TCGETS2
+ if (kernel_termios_to_user_termios((struct termios __user *)arg, &p_dev->kterm))
+#else
+ if (kernel_termios_to_user_termios_1((struct termios __user *)arg, &p_dev->kterm))
+#endif
+ {
+ BTUSB_ERR("failure copying termios\n");
+ retval = -EFAULT;
+ goto err_out;
+ }
+ break;
+
+ case TCSETSW:
+ case TCSETS:
+ if (!arg)
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+#ifndef TCGETS2
+ if (user_termios_to_kernel_termios(&p_dev->kterm, (struct termios __user *)arg))
+#else
+ if (user_termios_to_kernel_termios_1(&p_dev->kterm, (struct termios __user *)arg))
+#endif
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ break;
+
+ case TCSETSF:
+ case TCGETA:
+ case TCSETA:
+ case TCSETAW:
+ case TCSETAF:
+ case TCSBRK:
+ case TCXONC:
+ case TCFLSH:
+ case TIOCGSOFTCAR:
+ case TIOCSSOFTCAR:
+ case TIOCGLCKTRMIOS:
+ case TIOCSLCKTRMIOS:
+#ifdef TIOCGETP
+ case TIOCGETP:
+ case TIOCSETP:
+ case TIOCSETN:
+#endif
+#ifdef TIOCGETC
+ case TIOCGETC:
+ case TIOCSETC:
+#endif
+#ifdef TIOCGLTC
+ case TIOCGLTC:
+ case TIOCSLTC:
+#endif
+#ifdef TCGETX
+ case TCGETX:
+ case TCSETX:
+ case TCSETXW:
+ case TCSETXF:
+#endif
+ case TIOCMSET:
+ case TIOCMBIC:
+ case TIOCMBIS:
+ /* dummy support of TTY IOCTLs */
+ BTUSB_DBG("TTY ioctl not implemented\n");
+ break;
+
+ case TIOCGSERIAL:
+ {
+ struct serial_struct tmp;
+ if (!arg)
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.type = 0;
+ tmp.line = 0;
+ tmp.port = 0;
+ tmp.irq = 0;
+ tmp.flags = ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ;
+ tmp.xmit_fifo_size = 4096;
+ tmp.baud_base = 115200;
+ tmp.close_delay = 5*HZ;
+ tmp.closing_wait = 30*HZ;
+ tmp.custom_divisor = 0;
+ tmp.hub6 = 0;
+ tmp.io_type = 0;
+ if (copy_to_user((void __user *)arg, &tmp, sizeof(tmp)))
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ retval = 0;
+ break;
+ }
+
+ case TIOCMGET:
+ {
+ int tiocm = TIOCM_RTS | TIOCM_CTS;
+ if (!arg)
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+
+ if (copy_to_user((void __user *)arg, &tiocm, sizeof(tiocm)))
+ {
+ retval = -EFAULT;
+ goto err_out;
+ }
+ retval = 0;
+ break;
+ }
+
+ case TIOCMIWAIT:
+ {
+ DECLARE_WAITQUEUE(wait, current);
+
+ BTUSB_DBG("arg = %lu\n", arg);
+ while (1)
+ {
+ BTUSB_DBG("adding task to wait list\n");
+ add_wait_queue(&p_dev->rx_wait_q, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ BTUSB_DBG("removing task from wait list\n");
+ remove_wait_queue(&p_dev->rx_wait_q, &wait);
+ /* see if a signal woke us up */
+ if (signal_pending(current))
+ {
+ BTUSB_ERR("signal was pending\n");
+ retval = -ERESTARTSYS;
+ goto err_out;
+ }
+ /* do not check the expected signals */
+ retval = 0;
+ break;
+ }
+ break;
+ }
+ default:
+ BTUSB_ERR("unknown cmd %u\n", cmd);
+ retval = -ENOIOCTLCMD;
+ break;
+ }
+
+err_out:
+ BTUSB_DBG("returning %d\n", retval);
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_urb_out_complete
+ **
+ ** Description Data write (bulk pipe) completion routine
+ **
+ ** Parameters urb pointer
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_urb_out_complete(struct urb *p_urb)
+{
+ struct btusb_trans *p_trans = p_urb->context;
+ struct btusb *p_dev = p_trans->p_dev;
+
+ BTUSB_DBG("status %d length %u flags %x\n", p_urb->status,
+ p_urb->transfer_buffer_length, p_urb->transfer_flags);
+
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+
+ p_dev->stats.urb_out_complete++;
+ if (unlikely(p_urb->status))
+ {
+ /* this error can happen when unplugging */
+ p_dev->stats.urb_out_complete_err++;
+ }
+
+ if (p_trans->complete)
+ {
+ p_trans->complete(p_dev, p_trans, p_urb);
+ }
+
+ if (autopm)
+ {
+ usb_autopm_put_interface(p_dev->p_main_intf);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_acl
+ **
+ ** Parameters p_dev: device control block reference
+ ** packet: HCI ACL packet to transmit
+ ** length: length of the HCI packet
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_acl(struct btusb *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ struct btusb_trans *p_trans;
+
+ BTUSB_DBG("%p[%lu]\n", packet, length);
+
+ btusb_dump_data(packet, length, "OUTGOING DATA");
+
+ p_trans = btusb_alloc_trans(p_dev->acl_tx_array, ARRAY_SIZE(p_dev->acl_tx_array));
+ if (unlikely(p_trans == NULL))
+ {
+ return -ENOMEM;
+ }
+
+ if (unlikely(length > BTUSB_HCI_MAX_ACL_SIZE))
+ {
+ retval = -E2BIG;
+ goto error;
+ }
+
+#if 0
+ /* if this is called directly from write call */
+ if (copy_from_user(p_trans->dma_buffer, user_buffer, length))
+ {
+ retval = -EFAULT;
+ goto error;
+ }
+#else
+ memcpy(p_trans->dma_buffer, packet, length);
+#endif
+ p_trans->p_urb->transfer_buffer_length = length;
+
+ retval = btusb_submit(p_dev, &p_dev->acl_tx_submitted, p_trans, GFP_ATOMIC);
+ if (unlikely(retval))
+ {
+ goto error;
+ }
+ return retval;
+
+error:
+ BTUSB_ERR("failed : %d\n", retval);
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_diag
+ **
+ ** Parameters p_dev: device control block reference
+ ** packet: HCI DIAG packet to transmit
+ ** length: length of the packet
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_diag(struct btusb *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ struct btusb_trans *p_trans;
+
+ BTUSB_DBG("%p[%lu]\n", packet, length);
+
+ btusb_dump_data(packet, length, "OUTGOING DIAG");
+ if (unlikely(!p_dev->p_diag_out))
+ {
+ return -ENODEV;
+ }
+
+ p_trans = btusb_alloc_trans(p_dev->diag_tx_array, ARRAY_SIZE(p_dev->diag_tx_array));
+ if (unlikely(p_trans == NULL))
+ {
+ return -ENOMEM;
+ }
+
+ if (unlikely(length > BTUSB_HCI_MAX_ACL_SIZE))
+ {
+ retval = -E2BIG;
+ goto error;
+ }
+
+#if 0
+ /* if this is called directly from write call */
+ if (copy_from_user(p_trans->dma_buffer, user_buffer, length))
+ {
+ retval = -EFAULT;
+ goto error;
+ }
+#else
+ memcpy(p_trans->dma_buffer, packet, length);
+#endif
+ p_trans->p_urb->transfer_buffer_length = length;
+
+ retval = btusb_submit(p_dev, &p_dev->diag_tx_submitted, p_trans, GFP_ATOMIC);
+ if (unlikely(retval))
+ {
+ goto error;
+ }
+ return retval;
+
+error:
+ BTUSB_ERR("failed : %d\n", retval);
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+ return retval;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_cmd_complete
+ **
+ ** Description Command (control pipe) completion routine
+ **
+ ** Parameters
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+void btusb_cmd_complete(struct btusb *p_dev, struct btusb_trans *p_trans, struct urb *p_urb)
+{
+ p_dev->stats.cmd_complete++;
+ if (unlikely(p_urb->status))
+ {
+ p_dev->stats.cmd_complete_err++;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_cmd
+ **
+ ** Parameters p_dev: device control block reference
+ ** packet: HCI CMD packet to transmit
+ ** length: length of the HCI packet
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_cmd(struct btusb *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ struct btusb_trans *p_trans;
+ struct usb_ctrlrequest *p_dr = NULL;
+
+ BTUSB_DBG("%p[%lu]\n", packet, length);
+
+ btusb_dump_data(packet, length, "OUTGOING CMD");
+
+ p_trans = btusb_alloc_trans(p_dev->cmd_array, ARRAY_SIZE(p_dev->cmd_array));
+ if (unlikely(!p_trans))
+ {
+ return -ENOMEM;
+ }
+
+ if (unlikely(length > BTUSB_HCI_MAX_CMD_SIZE))
+ {
+ retval = -E2BIG;
+ goto error;
+ }
+
+#if 0
+ /* if this is called directly from write call */
+ if (copy_from_user(p_trans->dma_buffer, packet, length))
+ {
+ retval = -EFAULT;
+ goto error;
+ }
+#else
+ memcpy(p_trans->dma_buffer, packet, length);
+#endif
+ p_dr = (void *)p_trans->p_urb->setup_packet;
+ p_dr->wLength = __cpu_to_le16(length);
+ p_trans->p_urb->transfer_buffer_length = length;
+
+ retval = btusb_submit(p_dev, &p_dev->cmd_submitted, p_trans, GFP_ATOMIC);
+ if (unlikely(retval))
+ {
+ p_dev->stats.cmd_submit_err++;
+ goto error;
+ }
+ else
+ {
+ p_dev->stats.cmd_submit_ok++;
+ }
+ return retval;
+
+error:
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_voicetx_complete
+ **
+ ** Description Voice write (iso pipe) completion routine.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_voicetx_complete(struct btusb *p_dev, struct btusb_trans *p_trans, struct urb *p_urb)
+{
+ p_dev->stats.voicetx_complete++;
+ if (unlikely(p_urb->status))
+ {
+ p_dev->stats.voicetx_complete_err++;
+ }
+
+ if (unlikely(dbgflags & BTUSB_VOICETX_TIME))
+ {
+ btusb_voice_stats(&(p_dev->stats.voice_max_tx_done_delta_time), &(p_dev->stats.voice_min_tx_done_delta_time),
+ &(p_dev->stats.voice_tx_done_delta_time), &(p_dev->stats.voice_last_tx_done_ts));
+ }
+
+ atomic_sub(p_urb->number_of_packets, &p_dev->voice_tx_active);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_tx
+ **
+ ** Description Voice write submission
+ **
+ ** Parameters p_dev: device control block reference
+ ** packet: HCI SCO packet to transmit
+ ** length: length of the HCI packet
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_submit_voice_tx(struct btusb *p_dev, char *packet, unsigned long length)
+{
+ int i, retval;
+ unsigned int packet_size, pkt_used, total_size;
+ unsigned long remain;
+ unsigned char to_send;
+ struct btusb_trans *p_trans;
+ struct usb_iso_packet_descriptor *p_ifd;
+ char *p_cur;
+
+ if (!p_dev->p_main_intf || !p_dev->p_voice_intf || !p_dev->p_voice_out)
+ {
+ BTUSB_DBG(" failing (p_dev removed or no voice intf)\n");
+ return;
+ }
+
+ if (unlikely(dbgflags & BTUSB_VOICETX_TIME))
+ {
+ btusb_voice_stats(&(p_dev->stats.voice_max_rx_feeding_interval), &(p_dev->stats.voice_min_rx_feeding_interval),
+ &(p_dev->stats.voice_rx_feeding_interval), &(p_dev->stats.voice_last_rx_feeding_ts));
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_out->desc.wMaxPacketSize);
+ if (unlikely(!packet_size))
+ {
+ BTUSB_ERR("Max Packet Size = 0\n");
+ return;
+ }
+
+ if (unlikely(length < BTUSB_VOICE_HEADER_SIZE))
+ {
+ BTUSB_ERR("SCO packet length is too short\n");
+ return;
+ }
+
+ resend:
+ to_send = 0;
+ p_cur = packet + BTUSB_VOICE_HEADER_SIZE;
+ remain = length - BTUSB_VOICE_HEADER_SIZE;
+ while (remain)
+ {
+ /* find a free transaction */
+ p_trans = btusb_alloc_trans(p_dev->voice_tx_array, ARRAY_SIZE(p_dev->voice_tx_array));
+ if (unlikely(!p_trans))
+ {
+ p_dev->stats.voicetx_nobuf++;
+ BTUSB_ERR("No transaction available\n");
+ return;
+ }
+
+ total_size = 0;
+ for (i = 0, p_ifd = &p_trans->p_urb->iso_frame_desc[0];
+ i < BTUSB_VOICE_FRAMES_PER_URB; i++, p_ifd++)
+ {
+ if (unlikely(!to_send))
+ {
+ if (!remain)
+ {
+ break;
+ }
+ else
+ {
+ if (remain >= BTUSB_VOICE_BURST_SIZE)
+ {
+ to_send = BTUSB_VOICE_BURST_SIZE;
+ }
+ else
+ {
+ BTUSB_DBG("Sending partial sco data len: %lu\n", remain);
+ to_send = remain;
+ }
+ /* remaining data computed before adding header*/
+ remain -= to_send;
+
+ /* rebuild a SCO header, copying the full packet header */
+ p_cur -= BTUSB_VOICE_HEADER_SIZE;
+ p_cur[0] = packet[0];
+ p_cur[1] = packet[1];
+ p_cur[2] = to_send;
+ to_send += BTUSB_VOICE_HEADER_SIZE;
+ }
+ }
+ if (likely(to_send > packet_size))
+ {
+ pkt_used = packet_size;
+ }
+ else
+ {
+ pkt_used = to_send;
+ }
+ memcpy(&p_trans->dma_buffer[p_ifd->offset], p_cur, pkt_used);
+ p_cur += pkt_used;
+ to_send -= pkt_used;
+ p_ifd->length = pkt_used;
+ total_size += pkt_used;
+ }
+ if (likely(i))
+ {
+ p_trans->p_urb->number_of_packets = i;
+
+ retval = btusb_submit(p_dev, &p_dev->voice_tx_submitted, p_trans, GFP_ATOMIC);
+ if (unlikely(retval))
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+ p_dev->stats.voicetx_submit_err++;
+ }
+ else
+ {
+ atomic_add(i, &p_dev->voice_tx_active);
+ p_dev->stats.voicetx_submit_ok++;
+ }
+ }
+ else
+ {
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+ }
+ }
+
+ /* if there are less than 30 ms of data, send the same data again */
+ if (atomic_read(&p_dev->voice_tx_active) < 30)
+ {
+ BTUSB_DBG("less than 30 ms of data available, resending packet");
+ goto resend;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_fill_isoc_pkts
+ **
+ ** Description Prepare the ISOC packet descriptors
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_fill_isoc_pkts(struct urb *p_urb, int len, int pkt_size)
+{
+ int off = 0, i;
+
+ for (i = 0; len >= pkt_size; i++, off += ALIGN(pkt_size, 4), len -= ALIGN(pkt_size, 4))
+ {
+ p_urb->iso_frame_desc[i].offset = off;
+ p_urb->iso_frame_desc[i].length = pkt_size;
+ BTUSB_DBG("off=%d pkt_size=%d\n", off, pkt_size);
+ }
+ p_urb->number_of_packets = i;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_rx
+ **
+ ** Description Submit a voice RX URB
+ **
+ ** Parameters p_dev: device control block reference
+ ** p_trans: transaction reference
+ ** mem_flags: memory protection flags
+ ** Returns
+ **
+ *******************************************************************************/
+void btusb_submit_voice_rx(struct btusb *p_dev, struct btusb_trans *p_trans, int mem_flags)
+{
+ if (unlikely(btusb_submit(p_dev, &p_dev->voice_rx_submitted, p_trans, mem_flags)))
+ {
+ p_dev->stats.voicerx_submit_err++;
+ }
+ else
+ {
+ p_dev->stats.voicerx_submit_ok++;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_update_voice_trans
+ **
+ ** Description Finish filling the voice URB and submit them. At this point
+ ** the URBs should NOT be submitted.
+ **
+ ** Parameters p_dev: device control block reference
+ **
+ ** Returns 0 upon success, error code otherwise
+ **
+ *******************************************************************************/
+static int btusb_update_voice_trans(struct btusb *p_dev)
+{
+ unsigned int idx;
+ struct btusb_trans *p_trans;
+ struct urb *p_urb;
+ int packet_size;
+
+ BTUSB_DBG("enter\n");
+
+ if (!p_dev->p_main_intf || !p_dev->p_voice_intf || !p_dev->p_voice_in)
+ {
+ BTUSB_ERR("failing (p_dev removed or no voice intf)\n");
+ return -EFAULT;
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_in->desc.wMaxPacketSize);
+ if (!packet_size)
+ {
+ BTUSB_ERR("Max Packet Size = 0\n");
+ return -EINVAL;
+ }
+ BTUSB_DBG("packet_size=%d\n", packet_size);
+
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_rx_array)
+ {
+ p_urb = p_trans->p_urb;
+ p_urb->pipe = usb_rcvisocpipe(p_dev->p_udev, p_dev->p_voice_in->desc.bEndpointAddress);
+ BTUSB_DBG("ep=%d\n", p_dev->p_voice_in->desc.bEndpointAddress);
+ p_urb->interval = p_dev->p_voice_in->desc.bInterval;
+ BTUSB_DBG("interval=%d\n", p_urb->interval);
+ p_urb->transfer_buffer_length = ALIGN(packet_size, 4) * BTUSB_VOICE_FRAMES_PER_URB;
+ BTUSB_DBG("transfer_buffer_length=%d\n", p_urb->transfer_buffer_length);
+ if (p_urb->transfer_buffer_length > BTUSB_VOICE_BUFFER_MAXSIZE)
+ {
+ BTUSB_ERR("rx voice allocated insufficient for MaxPacketSize\n");
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ return -ENOMEM;
+ }
+ btusb_fill_isoc_pkts(p_urb, p_urb->transfer_buffer_length, packet_size);
+
+ btusb_submit_voice_rx(p_dev, p_trans, GFP_KERNEL);
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_out->desc.wMaxPacketSize);
+ if (!packet_size)
+ {
+ BTUSB_ERR("Max Packet Size = 0\n");
+ return -EINVAL;
+ }
+ BTUSB_ARRAY_FOR_EACH_TRANS(p_dev->voice_tx_array)
+ {
+ p_urb = p_trans->p_urb;
+ p_urb->pipe = usb_sndisocpipe(p_dev->p_udev, p_dev->p_voice_out->desc.bEndpointAddress);
+ BTUSB_DBG("ep=%d\n", p_dev->p_voice_out->desc.bEndpointAddress);
+ p_urb->interval = p_dev->p_voice_out->desc.bInterval;
+ BTUSB_DBG("interval=%d\n", p_urb->interval);
+ p_urb->transfer_buffer_length = ALIGN(packet_size, 4) * BTUSB_VOICE_FRAMES_PER_URB;
+ if (p_urb->transfer_buffer_length > BTUSB_VOICE_BUFFER_MAXSIZE)
+ {
+ BTUSB_ERR("tx voice allocated insufficient for MaxPacketSize\n");
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ return -ENOMEM;
+ }
+ btusb_fill_isoc_pkts(p_urb, p_urb->transfer_buffer_length, packet_size);
+ }
+
+ /* at this point, initiate voice TX */
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ struct btusb_voice_channel *p_chan = &p_dev->voice_rx.channels[idx];
+ if (p_chan->used)
+ {
+ UINT8 data[BTUSB_VOICE_HEADER_SIZE + BTUSB_VOICE_BURST_SIZE];
+ UINT8 *p_data = data;
+ memset(data, 0, sizeof(data));
+ UINT16_TO_STREAM(p_data, p_chan->handle);
+ UINT8_TO_STREAM(p_data, BTUSB_VOICE_BURST_SIZE);
+ btusb_submit_voice_tx(p_dev, data, sizeof(data));
+ }
+ }
+ return 0;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_set_voice
+ **
+ ** Description Change voice interface setting processor
+ ** NOTE: Must be called at low execution level
+ **
+ ** Parameters p_dev: pointer to the device control block
+ ** setting_number: new voice interface setting number
+ ** submit_urb: true if the URBs must be submitted
+ **
+ ** Returns 0 upon success, error code otherwise
+ **
+ *******************************************************************************/
+static int btusb_set_voice(struct btusb *p_dev, unsigned char setting_number,
+ bool submit_urb)
+{
+ int idx;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+
+ BTUSB_DBG("setting_number=%d submit_urb=%u\n", setting_number, submit_urb);
+
+ /* cancel all voice requests before switching buffers */
+ p_dev->p_voice_in = NULL;
+ p_dev->p_voice_out = NULL;
+ btusb_cancel_voice(p_dev);
+
+ /* configure the voice interface to the proper setting */
+ if (usb_set_interface(p_dev->p_udev, 1, setting_number))
+ {
+ BTUSB_ERR("failed to set iso intf to %u\n", setting_number);
+ return -EFAULT;
+ }
+
+ /* find the endpoints */
+ p_host_intf = p_dev->p_voice_intf->cur_altsetting;
+
+ for (idx = 0; idx < p_host_intf->desc.bNumEndpoints; idx++)
+ {
+ p_ep_desc = &p_host_intf->endpoint[idx].desc;
+ if (usb_endpoint_type(p_ep_desc) == USB_ENDPOINT_XFER_ISOC)
+ {
+ if (usb_endpoint_dir_in(p_ep_desc))
+ {
+ p_dev->p_voice_in = &p_host_intf->endpoint[idx];
+ }
+ else
+ {
+ p_dev->p_voice_out = &p_host_intf->endpoint[idx];
+ }
+ }
+ }
+
+ if (!p_dev->p_voice_in || !p_dev->p_voice_out)
+ {
+ BTUSB_ERR("no iso pipes found!\n");
+ return -EFAULT;
+ }
+
+ if (submit_urb)
+ {
+ return btusb_update_voice_trans(p_dev);
+ }
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_add_voice_channel
+ **
+ ** Description Add a voice channel in the list of current channels
+ **
+ ** Parameters p_dev: pointer to the device control structure
+ ** sco_handle: handle of the synchronous connection carrying voice
+ ** burst: size of the voice bursts
+ **
+ ** Returns Return 0 upon success, error code otherwise
+ **
+ *******************************************************************************/
+int btusb_add_voice_channel(struct btusb *p_dev, unsigned short sco_handle, unsigned char burst)
+{
+ int idx;
+ struct btusb_voice_channel *p_chan;
+
+ if (!p_dev->p_voice_intf)
+ {
+ BTUSB_ERR("No voice interface detected\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* kludge to support the backward compatibility with older BTKRNLs
+ not supplying the packet size... */
+ if (burst == 0)
+ {
+ BTUSB_INFO("fixing legacy req to 48\n");
+ burst = BTUSB_VOICE_BURST_SIZE;
+ }
+
+ /* look for an available voice channel entry */
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_chan = &p_dev->voice_rx.channels[idx];
+ if (!p_chan->used)
+ {
+ p_chan->handle = sco_handle;
+ p_chan->burst = burst;
+ p_chan->used = true;
+ goto found;
+ }
+ }
+ BTUSB_ERR("Could not find empty slot in internal tables\n");
+ return -EMLINK;
+
+found:
+ if (btusb_update_voice_channels(p_dev))
+ {
+ BTUSB_ERR("Failed adding voice channel\n");
+ /* failure, remove the channel just added */
+ btusb_remove_voice_channel(p_dev, sco_handle);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_remove_voice_channel
+ **
+ ** Description Remove a voice channel from the list of current channels
+ **
+ ** Parameters p_dev: pointer to the device control structure
+ ** sco_handle: handle of the synchronous connection carrying voice
+ **
+ ** Returns Return 0 upon success, error code otherwise
+ **
+ *******************************************************************************/
+int btusb_remove_voice_channel(struct btusb *p_dev, unsigned short sco_handle)
+{
+ int idx;
+ struct btusb_voice_channel *p_chan;
+
+ if (!p_dev->p_voice_intf)
+ {
+ BTUSB_ERR("No voice interface detected\n");
+ return -EOPNOTSUPP;
+ }
+
+ /* find the channel to be removed */
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_chan = &p_dev->voice_rx.channels[idx];
+ if (p_chan->used && (p_chan->handle == sco_handle))
+ {
+ p_chan->used = false;
+ goto found;
+ }
+ }
+ BTUSB_ERR("Could not find SCO handle in internal tables\n");
+ return -ENOENT;
+
+found:
+ return btusb_update_voice_channels(p_dev);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_update_voice_channels
+ **
+ ** Description Voice channels just updated, reconfigure
+ **
+ ** Parameters p_dev: pointer to the device control structure
+ **
+ ** Returns Return 0 upon success, error code otherwise
+ **
+ *******************************************************************************/
+static int btusb_update_voice_channels(struct btusb *p_dev)
+{
+ int idx, jdx;
+ unsigned char min_burst, max_burst, num_voice_chan, voice_setting;
+ unsigned short desired_packet_size, packet_size;
+ struct btusb_voice_channel *p_chan;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+
+ BTUSB_DBG("\n");
+
+ /* get the number of voice channels and the size information */
+ num_voice_chan = 0;
+ min_burst = 0xFF;
+ max_burst = 0;
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_chan = &p_dev->voice_rx.channels[idx];
+ if (p_chan->used)
+ {
+ num_voice_chan++;
+ min_burst = min(min_burst, p_chan->burst);
+ max_burst = max(max_burst, p_chan->burst);
+ }
+ }
+
+ BTUSB_DBG("num_voice_chan=%d\n", num_voice_chan);
+ /* now calculate a desired_packet_size */
+ switch (num_voice_chan)
+ {
+ case 0:
+ desired_packet_size = 0;
+ break;
+
+ case 1:
+ /* single channel: we just need a third of the length
+ (rounded up so we add 2 before dividing) */
+ desired_packet_size = ((max_burst + BTUSB_VOICE_HEADER_SIZE) + 2) / 3;
+ break;
+
+ case 2:
+ /* two channels: we need the smaller one to fit in completely
+ and the larger one to fit in into two... */
+ packet_size = (max_burst + BTUSB_VOICE_HEADER_SIZE + 1) / 2;
+
+ desired_packet_size = min_burst + BTUSB_VOICE_HEADER_SIZE;
+ if (packet_size > desired_packet_size)
+ desired_packet_size = packet_size;
+ break;
+
+ case 3:
+ /* three channels - we need all of them to fit into a single packet */
+ desired_packet_size = max_burst + BTUSB_VOICE_HEADER_SIZE;
+ break;
+
+ default:
+ /* this can not happen */
+ BTUSB_ERR("invalid # (%d) of channels, failing...\n", num_voice_chan);
+ return 0;
+ }
+
+ BTUSB_DBG("desired packet size is %u\n", desired_packet_size);
+
+ /* now convert the desired_packet_size into the interface setting number */
+ packet_size = BTUSB_USHRT_MAX;
+ voice_setting = 0;
+ for (idx = 0; idx < p_dev->p_voice_intf->num_altsetting; idx++)
+ {
+ p_host_intf = &p_dev->p_voice_intf->altsetting[idx];
+ for (jdx = 0; jdx < p_host_intf->desc.bNumEndpoints; jdx++)
+ {
+ p_ep_desc = &p_host_intf->endpoint[jdx].desc;
+ if ((usb_endpoint_type(p_ep_desc) == USB_ENDPOINT_XFER_ISOC) &&
+ usb_endpoint_dir_in(p_ep_desc))
+ {
+ /* if the MaxPacketSize is large enough and if it is smaller
+ than the current setting */
+ if ((desired_packet_size <= le16_to_cpu(p_ep_desc->wMaxPacketSize)) &&
+ (le16_to_cpu(p_ep_desc->wMaxPacketSize) < packet_size))
+ {
+ packet_size = le16_to_cpu(p_ep_desc->wMaxPacketSize);
+ voice_setting = p_host_intf->desc.bAlternateSetting;
+ }
+ }
+ }
+ }
+ if (packet_size == BTUSB_USHRT_MAX)
+ {
+ BTUSB_ERR("no appropriate ISO interface setting found, failing...\n");
+ return -ERANGE;
+ }
+
+ BTUSB_DBG("desired_packet_size=%d voice_setting=%d\n", desired_packet_size, voice_setting);
+
+ /* set the voice setting and only submit the URBs if there is a channel */
+ return btusb_set_voice(p_dev, voice_setting, num_voice_chan != 0);
+}
diff --git a/src/btusb_isoc.c b/src/btusb_isoc.c
new file mode 100755
index 0000000..5987c68
--- a/dev/null
+++ b/src/btusb_isoc.c
@@ -0,0 +1,292 @@
+/*
+ *
+ * btusb_isoc.c
+ *
+ *
+ *
+ * Copyright (C) 2013-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Module that handles the reception of the voice HCI packets on the isochronous
+ * interface.
+ *
+ */
+
+/* for kmalloc */
+#include <linux/slab.h>
+#include "btusb.h"
+#include "hcidefs.h"
+
+/*******************************************************************************
+ **
+ ** Function btusb_isoc_check_hdr
+ **
+ ** Description Check the packet header
+ **
+ ** Parameters p_dev: device instance control block
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static bool btusb_isoc_check_hdr(struct btusb *p_dev)
+{
+ unsigned char *p_data = p_dev->voice_rx.hdr;
+ int idx;
+ unsigned short sco_handle;
+ unsigned char size;
+ struct btusb_voice_pkt *p_pkt;
+ BT_HDR *p_hdr;
+ struct btusb_voice_channel *p_chan;
+
+ STREAM_TO_UINT16(sco_handle, p_data);
+ sco_handle &= 0x0fff;
+ STREAM_TO_UINT8(size, p_data);
+
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_chan = &p_dev->voice_rx.channels[idx];
+ if ((p_chan->used) &&
+ (sco_handle == p_chan->handle) &&
+ (size <= (2 * p_chan->burst)))
+ {
+ /* check if there is already a message being consolidated */
+ if (unlikely(p_chan->p_pkt == NULL))
+ {
+ if (!btusb_cq_get(&p_dev->voice_rx_list, &p_pkt))
+ {
+ BTUSB_ERR("No buffer available for SCO defragmentation\n");
+ return false;
+ }
+ p_hdr = &p_pkt->bt_hdr;
+ p_hdr->len = BTUSB_VOICE_HEADER_SIZE;
+ p_hdr->offset = 0;
+ p_hdr->layer_specific = 0;
+
+ p_data = (unsigned char *) (p_hdr + 1);
+
+ /* add sco handle and buffer size */
+ UINT16_TO_STREAM(p_data, sco_handle);
+ UINT8_TO_STREAM(p_data, BTUSB_SCO_RX_LEN);
+
+ p_chan->p_pkt = p_pkt;
+ }
+ p_dev->voice_rx.remaining = size;
+ p_dev->voice_rx.pp_pkt = &p_chan->p_pkt;
+
+ return true;
+ }
+ }
+ return false;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_isoc_check_pkt
+ **
+ ** Description Check if the reconstructed HCI voice packet is large enough
+ **
+ ** Parameters p_dev: device instance control block
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_isoc_check_pkt(struct btusb *p_dev)
+{
+ struct btusb_voice_pkt *p_pkt = *p_dev->voice_rx.pp_pkt;
+ BT_HDR *p_hdr = &p_pkt->bt_hdr;
+
+ /* if enough data was received */
+ if (unlikely(p_hdr->len == sizeof(((struct btusb_voice_pkt *)0)->data)))
+ {
+ btusb_rx_enqueue_voice(p_dev, p_pkt);
+ /* clear both references to the HCI packet */
+ *p_dev->voice_rx.pp_pkt = NULL;
+ p_dev->voice_rx.pp_pkt = NULL;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_voicerx_complete
+ **
+ ** Description Voice read (iso pipe) completion routine.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_voicerx_complete(struct urb *p_urb)
+{
+ struct btusb_trans *p_trans = p_urb->context;
+ struct btusb *p_dev = p_trans->p_dev;
+ BT_HDR *p_hdr;
+ unsigned int length, packet_length;
+ unsigned char *p_packet, *p_frame, *p_data;
+ struct usb_iso_packet_descriptor *p_uipd, *p_end;
+
+ if (unlikely(dbgflags & BTUSB_VOICERX_TIME))
+ {
+ btusb_voice_stats(&(p_dev->stats.voice_max_rx_rdy_delta_time), &(p_dev->stats.voice_min_rx_rdy_delta_time),
+ &(p_dev->stats.voice_rx_rdy_delta_time), &(p_dev->stats.voice_last_rx_rdy_ts));
+ }
+
+ BTUSB_INFO("enter");
+
+ p_dev->stats.voicerx_complete++;
+
+ if (unlikely(!p_dev->p_main_intf || !p_dev->p_voice_in))
+ {
+ BTUSB_DBG("intf is down\n");
+ return;
+ }
+
+ /* entire URB error? */
+ if (unlikely(p_urb->status))
+ {
+ /* this error can happen when unplugging or updating channels */
+ p_dev->stats.voicerx_complete_err++;
+ return;
+ }
+
+ if (unlikely(p_dev->scosniff_active))
+ {
+ struct btusb_scosniff *bs;
+
+ bs = kmalloc(sizeof(struct btusb_scosniff) +
+ (p_urb->number_of_packets * sizeof(p_urb->iso_frame_desc[0])) +
+ p_urb->transfer_buffer_length, GFP_ATOMIC);
+ if (bs)
+ {
+ bs->s = p_urb->start_frame;
+ bs->n = p_urb->number_of_packets;
+ bs->l = p_urb->transfer_buffer_length;
+ /* copy the descriptors */
+ memcpy(bs->d, p_urb->iso_frame_desc, bs->n * sizeof(p_urb->iso_frame_desc[0]));
+ /* then copy the content of the buffer */
+ memcpy(&bs->d[bs->n], p_urb->transfer_buffer, bs->l);
+ /* protection not required because callback invoked with IRQ disabled */
+ list_add_tail(&bs->lh, &p_dev->scosniff_list);
+ complete(&p_dev->scosniff_completion);
+ }
+ else
+ {
+ BTUSB_ERR("Failed allocating scosniff buffer");
+ }
+ }
+
+ p_frame = p_urb->transfer_buffer;
+ p_end = &p_urb->iso_frame_desc[p_urb->number_of_packets];
+ for (p_uipd = p_urb->iso_frame_desc; p_uipd < p_end; p_uipd++)
+ {
+ if (unlikely(p_uipd->status))
+ {
+ p_dev->stats.voicerx_bad_frames++;
+ /* should we do something if there is expected data? */
+ continue;
+ }
+
+ p_packet = p_frame + p_uipd->offset;
+ packet_length = p_uipd->actual_length;
+ p_dev->stats.voicerx_raw_bytes += packet_length;
+
+ /* waiting for data? */
+ if (likely(p_dev->voice_rx.remaining))
+ {
+ fill_data:
+ if (likely(p_dev->voice_rx.remaining >= packet_length))
+ {
+ length = packet_length;
+ }
+ else
+ {
+ length = p_dev->voice_rx.remaining;
+ }
+ p_hdr = &(*p_dev->voice_rx.pp_pkt)->bt_hdr;
+ p_data = (void *)(p_hdr + 1) + p_hdr->len;
+
+ if (unlikely((p_hdr->len + length) > sizeof(((struct btusb_voice_pkt *)0)->data)))
+ {
+ BTUSB_ERR("SCO message too large for buffer\n");
+ p_dev->stats.voicerx_bad_size++;
+ /* reset the length and pending bytes to end the current packet */
+ p_dev->voice_rx.remaining = length =
+ sizeof(((struct btusb_voice_pkt *)0)->data) - p_hdr->len;
+ }
+ /* append data to the current message */
+ memcpy(p_data, p_packet, length);
+ p_hdr->len += length;
+
+ /* decrement the number of bytes remaining */
+ p_dev->voice_rx.remaining -= length;
+ if (likely(p_dev->voice_rx.remaining))
+ {
+ /* data still needed -> next descriptor */
+ continue;
+ }
+ /* no more pending bytes, check if packet is full */
+ btusb_isoc_check_pkt(p_dev);
+ packet_length -= length;
+ /* speedup peep-hole */
+ if (likely(!packet_length))
+ continue;
+ /* more bytes -> increment pointer */
+ p_packet += length;
+ }
+
+ /* if there is still data in the packet */
+ if (likely(packet_length))
+ {
+ /* at this point, there is NO SCO packet pending */
+ if (likely(packet_length >= (BTUSB_VOICE_HEADER_SIZE - p_dev->voice_rx.hdr_size)))
+ {
+ length = BTUSB_VOICE_HEADER_SIZE - p_dev->voice_rx.hdr_size;
+ }
+ else
+ {
+ length = packet_length;
+ }
+
+ /* fill the hdr (in case header is split across descriptors) */
+ memcpy(&p_dev->voice_rx.hdr[p_dev->voice_rx.hdr_size], p_packet, length);
+ p_dev->voice_rx.hdr_size += length;
+
+ if (likely(p_dev->voice_rx.hdr_size == BTUSB_VOICE_HEADER_SIZE))
+ {
+ /* reset the pending size */
+ p_dev->voice_rx.hdr_size = 0;
+
+ if (likely(btusb_isoc_check_hdr(p_dev)))
+ {
+ p_packet += length;
+ packet_length -= length;
+ /* a correct header was found, get the data */
+ goto fill_data;
+ }
+ p_dev->stats.voicerx_bad_hdr++;
+ p_dev->stats.voicerx_skipped_bytes += packet_length;
+ }
+ else
+ {
+ p_dev->stats.voicerx_split_hdr++;
+ }
+ }
+ }
+
+ btusb_submit_voice_rx(p_dev, p_trans, GFP_ATOMIC);
+}
+
diff --git a/src/btusb_lite.c b/src/btusb_lite.c
new file mode 100755
index 0000000..7a7fc15
--- a/dev/null
+++ b/src/btusb_lite.c
@@ -0,0 +1,1785 @@
+/*
+ *
+ * btusb_lite.c
+ *
+ *
+ *
+ * Copyright (C) 2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#include <linux/proc_fs.h>
+#include <linux/poll.h>
+
+#include "btusb.h"
+#include "btpcm_api.h"
+#include "bd.h"
+
+
+/*
+ * Defines
+ */
+
+#define BTUSB_LITE_IPC_AVDT_SYNC_INFO_RSP_LEN (1 + BTM_SYNC_INFO_NUM_STR * (1+6+2+2+1+2))
+
+/*
+ * Local functions
+ */
+static void btusb_lite_reinit(struct btusb *p_dev);
+static int btusb_lite_open(struct inode *inode, struct file *file);
+static int btusb_lite_close(struct inode *inode, struct file *file);
+static ssize_t btusb_lite_write(struct file *file, const char *buf, size_t count,
+ loff_t *p_off);
+static ssize_t btusb_lite_read(struct file *file, char __user *buffer, size_t count,
+ loff_t *p_off);
+static unsigned int btusb_lite_poll(struct file *file, struct poll_table_struct *p_pt);
+
+static BT_HDR *btusb_lite_msg_to_app_get(struct btusb *p_dev);
+static void btusb_lite_msg_to_app_free(struct btusb *p_dev, BT_HDR *p_msg);
+static UINT8 *btusb_lite_msg_to_app_get_data_addr(struct btusb *p_dev, BT_HDR *p_msg);
+
+static char *btusb_lite_ipc_event_desc(UINT16 event);
+
+static void btusb_lite_ipc_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_hci_cmd_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_hci_acl_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_mgt_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_btu_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_btm_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_l2c_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_ipc_avdt_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+
+static void btusb_lite_ipc_rsp_send(struct btusb *p_dev, UINT16 event, UINT8 op_code,
+ UINT8 *p_param, UINT8 param_len);
+static void btusb_lite_ipc_cmd_cplt_evt_send(struct btusb *p_dev,
+ UINT16 opcode, UINT8 *p_param, UINT8 param_len);
+static void btusb_lite_ipc_avdt_sync_info_send(struct btusb *p_dev,
+ tAVDT_SYNC_INFO *p_sync_rsp);
+
+static void btusb_lite_ipc_sent_to_user(struct btusb *p_dev, BT_HDR *p_msg);
+
+/*
+ * Globals
+ */
+static const struct file_operations btusb_lite_fops =
+{
+ .open = btusb_lite_open,
+ .read = btusb_lite_read,
+ .poll = btusb_lite_poll,
+ .write = btusb_lite_write,
+ .release = btusb_lite_close,
+};
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_reinit
+ **
+ ** Description Init BTUSB Lite interface
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+static void btusb_lite_reinit(struct btusb *p_dev)
+{
+ memset(&p_dev->lite_cb.s, 0, sizeof(p_dev->lite_cb.s));
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_open
+ **
+ ** Description Open BTUSB Lite interface
+ **
+ ** Returns status (< 0 if error)
+ **
+ *******************************************************************************/
+static int btusb_lite_open(struct inode *inode, struct file *file)
+{
+ int rv;
+ struct btusb *p_dev = BTUSB_PDE_DATA(inode);
+
+ BTUSB_INFO("btusb_lite_open\n");
+
+ if (!p_dev)
+ {
+ BTUSB_ERR("Unable to find p_dev reference\n");
+ rv = -ENODEV;
+ goto out;
+ }
+
+ if (p_dev->lite_cb.s.opened)
+ {
+ BTUSB_ERR("Lite interface already opened\n");
+ rv = -EBUSY;;
+ goto out;
+ }
+
+ file->private_data = p_dev; /* Save our private p_dev */
+
+ btusb_lite_reinit(p_dev);
+ p_dev->lite_cb.s.opened = true;
+
+ rv = 0;
+
+out:
+ return rv;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_close
+ **
+ ** Description Close BTUSB Lite interface
+ **
+ ** Returns status (< 0 if error)
+ **
+ *******************************************************************************/
+static int btusb_lite_close(struct inode *inode, struct file *file)
+{
+ int rv;
+ struct btusb *p_dev = BTUSB_PDE_DATA(inode);
+
+ BTUSB_INFO("btusb_lite_close\n");
+
+ if (!p_dev)
+ {
+ BTUSB_ERR("Unable to find p_dev reference\n");
+ rv = -ENODEV;
+ goto out;
+ }
+
+ if (!p_dev->lite_cb.s.opened)
+ {
+ BTUSB_ERR("Lite interface was not opened\n");
+ rv = -EBUSY;;
+ goto out;
+ }
+
+ btusb_lite_reinit(p_dev);
+
+ rv = 0;
+
+out:
+ return rv;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_write
+ **
+ ** Description Write handler of the BTUSB Lite interface
+ **
+ ** Returns Nb bytes written
+ **
+ *******************************************************************************/
+static ssize_t btusb_lite_write(struct file *file, const char *p_user_buffer,
+ size_t count, loff_t *p_off)
+{
+ struct btusb *p_dev = file->private_data;
+ size_t remainder;
+ struct btusb_lite_cb *p_lite_cb;
+ unsigned long copy_len;
+ ssize_t copied_len;
+ UINT8 *p;
+ UINT16 rx_event;
+ BT_HDR *p_msg;
+
+ BTUSB_DBG("btusb_lite_write count=%zu\n", count);
+
+ if (!p_dev)
+ {
+ BTUSB_ERR("Unable to find p_dev reference\n");
+ return -ENODEV;
+ }
+
+ if (!p_dev->lite_cb.s.opened)
+ {
+ BTUSB_ERR("Lite interface was not opened\n");
+ return -EBUSY;
+ }
+
+ if (unlikely(count == 0))
+ {
+ return 0;
+ }
+
+ /* check that the incoming data is good */
+ if (unlikely(!access_ok(VERIFY_READ, (void *)p_user_buffer, count)))
+ {
+ BTUSB_ERR("buffer access verification failed\n");
+ return -EFAULT;
+ }
+
+ p_lite_cb = &p_dev->lite_cb;
+
+ copied_len = 0;
+ remainder = count;
+
+ while(remainder)
+ {
+ /* If a full Header has not yet been received */
+ if (p_lite_cb->s.from_app.rx_header_len < BTUSB_LITE_IPC_HDR_SIZE)
+ {
+ /* How many bytes are needed (1 to 4) */
+ copy_len = BTUSB_LITE_IPC_HDR_SIZE - p_lite_cb->s.from_app.rx_header_len;
+
+ /* If less bytes are available */
+ if (remainder < copy_len)
+ {
+ copy_len = remainder;
+ }
+
+ /* Copy the header (or a part of it) */
+ if (copy_from_user(&p_lite_cb->s.from_app.rx_header[p_lite_cb->s.from_app.rx_header_len],
+ (void *)p_user_buffer, copy_len))
+ {
+ BTUSB_ERR("Copy header from user error\n");
+ return -EINVAL;
+ }
+ remainder -= copy_len;
+ p_lite_cb->s.from_app.rx_header_len += copy_len;
+ p_user_buffer += copy_len;
+ copied_len += copy_len;
+
+ /* If the buffer has been read */
+ if (p_lite_cb->s.from_app.rx_header_len == BTUSB_LITE_IPC_HDR_SIZE)
+ {
+ p = p_lite_cb->s.from_app.rx_header;
+ STREAM_TO_UINT16(p_lite_cb->s.from_app.rx_len, p);
+ STREAM_TO_UINT16(rx_event, p);
+
+ BTUSB_DBG("Rx Len=%d RxEvent=0x%X\n", p_lite_cb->s.from_app.rx_len, rx_event);
+
+ p_lite_cb->s.from_app.rx_len -= sizeof(UINT16); /* Do not count Event Field */
+
+ /* get a buffer from the pool (add one byte for HCI_Type) */
+ if (unlikely((p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + p_lite_cb->s.from_app.rx_len + 1)) == NULL))
+ {
+ BTUSB_ERR("unable to get GKI buffer - write failed\n");
+ return -EINVAL;
+ }
+ p_msg->event = rx_event;
+ p_msg->layer_specific = 0;
+ p_msg->offset = 1;
+ p_msg->len = 0;
+
+ p_lite_cb->s.from_app.p_rx_msg = p_msg;
+ }
+ }
+ /* If Header already received */
+ else
+ {
+ p_msg = p_lite_cb->s.from_app.p_rx_msg;
+
+ if (!p_msg)
+ {
+ BTUSB_ERR("no Rx buffer\n");
+ return EINVAL;
+ }
+ p = (UINT8 *)(p_msg + 1) + p_msg->len + p_msg->offset;
+
+ /* How many payload bytes are expected */
+ copy_len = p_lite_cb->s.from_app.rx_len;
+
+ /* If less bytes are available */
+ if (remainder < copy_len)
+ {
+ copy_len = remainder;
+ }
+
+ /* Copy the Payload (or a part of it) */
+ if (copy_from_user(p, (void *)p_user_buffer, copy_len))
+ {
+ BTUSB_ERR("Copy payload from user error\n");
+ return -EINVAL;
+ }
+ remainder -= copy_len;
+ p_user_buffer += copy_len;
+ copied_len += copy_len;
+ p_lite_cb->s.from_app.rx_len -= copy_len;
+ p_msg->len += copy_len;
+
+ if (p_lite_cb->s.from_app.rx_len == 0)
+ {
+ /* Handle the received message */
+ btusb_lite_ipc_hndl(p_dev, p_msg);
+
+ p_lite_cb->s.from_app.p_rx_msg = NULL;
+ p_lite_cb->s.from_app.rx_header_len = 0; /* Ready to receive a new header */
+ }
+ }
+ }
+
+ return copied_len;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_msg_to_app_get
+ **
+ ** Description Get next message to send to IPC
+ **
+ ** Returns GKI buffer to send (or Null)
+ **
+ *******************************************************************************/
+static BT_HDR *btusb_lite_msg_to_app_get(struct btusb *p_dev)
+{
+ BT_HDR *p_msg;
+ BT_HDR *p_hdr_msg;
+ UINT8 *p_data;
+
+ /* First, check if a locally generated Event (IPC) message is pending */
+ p_msg = p_dev->lite_cb.s.to_app.p_ipc_msg;
+ if (p_msg)
+ {
+ return p_msg;
+ }
+
+ /* Secondly, check if a locally generated IPC Header message is pending */
+ p_msg = p_dev->lite_cb.s.to_app.p_hdr_msg;
+ if (p_msg)
+ {
+ return p_msg;
+ }
+
+ /* Thirdly, check if an HCI message is pending */
+ p_msg = p_dev->lite_cb.s.to_app.p_hci_msg;
+ if (p_msg)
+ {
+ return p_msg;
+ }
+
+ /*
+ * No pending message. Check queues now
+ */
+
+ /* First, check if a locally generated Event (UIPC) message is enqueued */
+ p_msg = GKI_dequeue(&p_dev->lite_cb.s.to_app.ipc_queue);
+ if (p_msg)
+ {
+ p_dev->lite_cb.s.to_app.p_ipc_msg = p_msg;
+ return p_msg;
+ }
+
+ /* If HCI is not over IPC */
+ if (!btusb_lite_is_hci_over_ipc(p_dev))
+ {
+ return NULL; /* Nothing more to send on IPC */
+ }
+
+ /* Check if an HCI message (from BT controller) is ready */
+ p_msg = GKI_getfirst(&p_dev->rx_queue);
+ if (p_msg)
+ {
+ /* We need to Build an IPC Header to send the HCI packet */
+ p_hdr_msg = GKI_getbuf(sizeof(BT_HDR) + BTUSB_LITE_IPC_HDR_SIZE);
+ if (p_hdr_msg == NULL)
+ {
+ /* Leave the Received HCI packet in the queue (for next time) */
+ BTUSB_ERR("No more buffer\n");
+ p_dev->lite_cb.s.to_app.p_hci_msg = NULL;
+ return NULL;
+ }
+ p_hdr_msg->len = BTUSB_LITE_IPC_HDR_SIZE;
+ p_hdr_msg->offset = 0;
+ p_hdr_msg->layer_specific = 0;
+ p_hdr_msg->event = 0;
+ p_data = (UINT8 *)(p_hdr_msg + 1) + p_hdr_msg->offset;
+
+ /* Write Length */
+ UINT16_TO_STREAM(p_data, p_msg->len + BTUSB_LITE_IPC_HDR_EVT_SIZE);
+
+ /* Write Event code */
+ switch(p_msg->event)
+ {
+ case HCIT_TYPE_EVENT:
+ {
+ struct btusb_trans *p_trans;
+ p_trans = container_of(p_msg, struct btusb_trans, bt_hdr);
+ BTUSB_INFO("Event=0x%02X Received from BT Controller\n",
+ *(p_trans->dma_buffer + p_msg->offset));
+ BTUSB_INFO("IPC Buffer TxEvent=BT_EVT_TO_BTU_HCI_EVT(%X) Length=%d\n",
+ BT_EVT_TO_BTU_HCI_EVT, p_msg->len);
+ }
+ UINT16_TO_STREAM(p_data, BT_EVT_TO_BTU_HCI_EVT);
+ break;
+
+ case HCIT_TYPE_ACL_DATA:
+ BTUSB_INFO("IPC Buffer TxEvent=BT_EVT_BTU_IPC_ACL_EVT(%X) Length=%d\n", BT_EVT_BTU_IPC_ACL_EVT, p_msg->len);
+ UINT16_TO_STREAM(p_data, BT_EVT_BTU_IPC_ACL_EVT);
+ break;
+
+ case HCIT_TYPE_LM_DIAG:
+ BTUSB_INFO("IPC Buffer TxEvent=BT_EVT_TO_LM_DIAG(%X) Length=%d\n", BT_EVT_TO_LM_DIAG, p_msg->len);
+ UINT16_TO_STREAM(p_data, BT_EVT_TO_LM_DIAG);
+ break;
+
+ default:
+ /* Should not append. Set Event to 0xFFFF for debug */
+ BTUSB_ERR("Unknown event=0x%x\n", p_msg->event);
+ UINT16_TO_STREAM(p_data, 0xFFFF);
+ break;
+ }
+
+ /* Store Header */
+ p_dev->lite_cb.s.to_app.p_hdr_msg = p_hdr_msg;
+
+ /* Dequeue HCI message */
+ p_msg = GKI_dequeue(&p_dev->rx_queue);
+ p_dev->lite_cb.s.to_app.p_hci_msg = p_msg;
+
+ return p_hdr_msg; /* Return pointer on Header */
+ }
+
+ return p_msg;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_msg_to_app_get_data_addr
+ **
+ ** Description Retrieve the data from a GKI Buffer pointer
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+static UINT8 *btusb_lite_msg_to_app_get_data_addr(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ struct btusb_trans *p_trans;
+
+ /* If the message is a "real" GKI buffer */
+ if ((p_dev->lite_cb.s.to_app.p_ipc_msg == p_msg) ||
+ (p_dev->lite_cb.s.to_app.p_hdr_msg == p_msg))
+ {
+ return (UINT8 *)(p_msg + 1) + p_msg->offset;
+ }
+
+ /* If the message is an HCI message, the data is located in the USB transaction */
+
+ /* Check if the message is an HCI message */
+ if (p_dev->lite_cb.s.to_app.p_hci_msg == p_msg)
+ {
+ p_trans = container_of(p_msg, struct btusb_trans, bt_hdr);
+ return (p_trans->dma_buffer + p_msg->offset);
+ }
+
+ BTUSB_ERR("Unknown buffer=%p\n", p_msg);
+
+ return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_msg_to_app_free
+ **
+ ** Description Free a message which has been sent to IPC
+ **
+ ** Returns None
+ **
+ *******************************************************************************/
+static void btusb_lite_msg_to_app_free(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ /* Check if the message is a locally generated Event (IPC) message */
+ if (p_dev->lite_cb.s.to_app.p_ipc_msg == p_msg)
+ {
+ GKI_freebuf(p_msg);
+ p_dev->lite_cb.s.to_app.p_ipc_msg = NULL;
+ return;
+ }
+
+ /* Check if the message is a locally generated Header (IPC) message */
+ if (p_dev->lite_cb.s.to_app.p_hdr_msg == p_msg)
+ {
+ GKI_freebuf(p_msg);
+ p_dev->lite_cb.s.to_app.p_hdr_msg = NULL;
+ return;
+ }
+
+ /* Check if the message is an HCI message */
+ if (p_dev->lite_cb.s.to_app.p_hci_msg == p_msg)
+ {
+ p_dev->lite_cb.s.to_app.p_hci_msg = NULL;
+ /* The buffer must not be freed. It has to be re-enqueue in USB core */
+ btusb_rx_dequeued(p_dev, p_msg);
+ return;
+ }
+
+ BTUSB_ERR("Unknown buffer=%p\n", p_msg);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_read
+ **
+ ** Description Read handler of the BTUSB Lite interface
+ **
+ ** Returns Nb bytes written
+ **
+ *******************************************************************************/
+static ssize_t btusb_lite_read(struct file *file, char __user *p_user_buffer, size_t count, loff_t *p_off)
+{
+ struct btusb *p_dev = file->private_data;
+ ssize_t size;
+ UINT8 *p_data;
+ unsigned long copy_len;
+ BT_HDR *p_msg;
+ int rv;
+
+ BTUSB_DBG("btusb_lite_read\n");
+
+ if (!p_dev)
+ {
+ BTUSB_ERR("Unable to find p_dev reference\n");
+ size = -ENODEV;
+ goto out;
+ }
+
+ if (!p_dev->lite_cb.s.opened)
+ {
+ BTUSB_ERR("Lite interface was not opened\n");
+ size = -EBUSY;;
+ goto out;
+ }
+
+ if (count == 0)
+ {
+ size = 0;
+ goto out;
+ }
+
+ /* Check that the user buffer is good */
+ if (unlikely(!access_ok(VERIFY_WRITE, (void *)p_user_buffer, count)))
+ {
+ BTUSB_ERR("buffer access verification failed\n");
+ size = -EFAULT;
+ goto out;
+ }
+
+ /* Sleep while nothing for the application */
+ rv = wait_event_interruptible(p_dev->rx_wait_q,
+ ((p_msg = btusb_lite_msg_to_app_get(p_dev)) != NULL));
+
+ if (unlikely(rv))
+ {
+ BTUSB_DBG("read wait interrupted");
+ return rv;
+ }
+
+ if (p_msg)
+ {
+ if (p_msg->len < count)
+ {
+ copy_len = p_msg->len;
+ }
+ else
+ {
+ copy_len = count; /* User asks for count bytes */
+ }
+
+ BTUSB_DBG("p_msg=%p msg->len=%d count=%zu copy_len=%lu\n", p_msg, p_msg->len, count, copy_len);
+
+ p_data = btusb_lite_msg_to_app_get_data_addr(p_dev, p_msg);
+ if (p_data == NULL)
+ {
+ size = -EFAULT;
+ goto out;
+ }
+
+ /* copy the message data to the available user space */
+ if (unlikely(copy_to_user(p_user_buffer, p_data, copy_len)))
+ {
+ BTUSB_ERR("copy to user error\n");
+ size = -EINVAL;
+ goto out;
+ }
+
+ BTUSB_DBG("copied %ld bytes\n", copy_len);
+
+ p_msg->offset += copy_len;
+ p_msg->len -= copy_len;
+ size = copy_len;
+
+ if (p_msg->len == 0)
+ {
+ BTUSB_DBG("free gki buffer\n");
+ btusb_lite_msg_to_app_free(p_dev, p_msg);
+ }
+ goto out;
+ }
+ else
+ {
+ BTUSB_ERR("No Buffer\n");
+ }
+
+ size = 0; /* should not happen */
+
+out:
+ return size;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_poll
+ **
+ ** Description Poll callback (to implement select)
+ **
+ ** Parameters file : file structure of the opened instance
+ ** p_pt : poll table to which the local queue must be added
+ **
+ ** Returns Mask of the type of polling supported, error number if negative
+ **
+ *******************************************************************************/
+static unsigned int btusb_lite_poll(struct file *file, struct poll_table_struct *p_pt)
+{
+ struct btusb *p_dev = file->private_data;
+ unsigned int mask;
+
+ BTUSB_DBG("enter\n");
+
+ /* retrieve the device from the file pointer*/
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+ if (unlikely(p_dev == NULL))
+ {
+ BTUSB_ERR("can't find device\n");
+ return -ENODEV;
+ }
+
+ // check if the device was disconnected
+ if (unlikely(!p_dev->p_main_intf))
+ {
+ BTUSB_ERR("device unplugged\n");
+ return -ENODEV;
+ }
+
+ if (unlikely(!p_dev->lite_cb.s.opened))
+ {
+ BTUSB_ERR("Lite interface was not opened\n");
+ return -EINVAL;
+ }
+
+ /* indicate to the system on which queue it should poll (non blocking call) */
+ poll_wait(file, &p_dev->rx_wait_q, p_pt);
+
+ /* enable WRITE (select/poll is not write blocking) */
+ mask = POLLOUT | POLLWRNORM;
+
+ /* enable READ only if data is queued from HCI */
+ if (btusb_lite_msg_to_app_get(p_dev))
+ {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_create
+ **
+ ** Description Create BTUSB Lite interface
+ **
+ ** Returns status (< 0 if error)
+ **
+ *******************************************************************************/
+int btusb_lite_create(struct btusb *p_dev, struct usb_interface *p_interface)
+{
+ int rv = -1;
+
+ p_dev->lite_cb.p_btpcm = btpcm_init(kobject_name(&p_dev->p_main_intf->usb_dev->kobj));
+ if (!p_dev->lite_cb.p_btpcm)
+ {
+ BTUSB_ERR("btpcm_init failed\n");
+ }
+
+ if (p_dev->p_pde)
+ {
+ p_dev->lite_cb.p_lite_pde = proc_create_data("lite", S_IRUGO | S_IWUGO, p_dev->p_pde, &btusb_lite_fops, p_dev);
+ if (!p_dev->lite_cb.p_lite_pde)
+ {
+ BTUSB_ERR("Couldn't create proc lite entry\n");
+ }
+ else
+ {
+ BTUSB_INFO("Created proc lite entry\n");
+ rv = 0;
+ }
+ }
+
+ return rv;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_delete
+ **
+ ** Description Delete BTUSB Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+void btusb_lite_delete(struct btusb *p_dev, struct usb_interface *p_interface)
+{
+ if (p_dev->p_pde)
+ {
+ remove_proc_entry("lite", p_dev->p_pde);
+ BTUSB_INFO("proc lite removed\n");
+ }
+
+ if (btpcm_exit(p_dev->lite_cb.p_btpcm))
+ {
+ BTUSB_ERR("btpcm_exit failed\n");
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_is_hci_over_ipc
+ **
+ ** Description Check if HCI is over IPC (Lite Interface).
+ **
+ ** Returns int (1 if HCI is over IPC otherwise 0)
+ **
+ *******************************************************************************/
+int btusb_lite_is_hci_over_ipc(struct btusb *p_dev)
+{
+ if ((p_dev->lite_cb.s.opened) && /* User Space opened the Lite interface */
+ (p_dev->lite_cb.s.mgt.opened) && /* IPC MGT Opened */
+ /* Lite Transport is opened */
+ ((p_dev->lite_cb.s.btu.transport_state == BTU_LITE_STACK_ACTIVE) ||
+ (p_dev->lite_cb.s.btu.transport_state == BTU_LITE_TRANSPORT_ACTIVE)))
+ {
+ return 1;
+ }
+ return 0;
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_stop_all
+ **
+ ** Description Stop all sound streams
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_lite_stop_all(struct btusb *p_dev)
+{
+ int i;
+
+ BTUSB_INFO("");
+
+ for (i = 0 ; i < BTA_AV_NUM_STRS ; i++)
+ {
+ btusb_lite_av_stop(p_dev, i, 0);
+ btusb_lite_av_remove(p_dev, i, 0, 0);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_hndl
+ **
+ ** Description Handle received message from BTUSB Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ BTUSB_INFO("IPC Buffer RxEvent=%s(0x%X) Length=%d\n",
+ btusb_lite_ipc_event_desc(p_msg->event), p_msg->event, p_msg->len);
+
+ if (unlikely(dbgflags & BTUSB_DBG_MSG) && p_msg->len)
+ {
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ int len = p_msg->len>20?20:p_msg->len;
+ int i;
+
+ for (i = 0 ; i < len ; i++, p++)
+ {
+ printk("%02X ", *p);
+ }
+ if (p_msg->len>20)
+ printk("...\n");
+ else
+ printk("\n");
+ }
+
+ switch(p_msg->event)
+ {
+ case BT_EVT_TO_LM_HCI_CMD:
+ btusb_lite_ipc_hci_cmd_hndl(p_dev, p_msg);
+ /* NO GKI_freebuf here */
+ break;
+
+ case BT_EVT_TO_LM_HCI_ACL:
+ btusb_lite_ipc_hci_acl_hndl(p_dev, p_msg);
+ /* NO GKI_freebuf here */
+ break;
+
+ case BT_EVT_BTU_IPC_MGMT_EVT:
+ btusb_lite_ipc_mgt_hndl(p_dev, p_msg);
+ GKI_freebuf(p_msg);
+ break;
+
+ case BT_EVT_BTU_IPC_BTU_EVT:
+ btusb_lite_ipc_btu_hndl(p_dev, p_msg);
+ GKI_freebuf(p_msg);
+ break;
+
+ case BT_EVT_BTU_IPC_L2C_EVT:
+ btusb_lite_ipc_l2c_hndl(p_dev, p_msg);
+ GKI_freebuf(p_msg);
+ break;
+
+ case BT_EVT_BTU_IPC_BTM_EVT:
+ btusb_lite_ipc_btm_hndl(p_dev, p_msg);
+ GKI_freebuf(p_msg);
+ break;
+
+ case BT_EVT_BTU_IPC_AVDT_EVT:
+ btusb_lite_ipc_avdt_hndl(p_dev, p_msg);
+ GKI_freebuf(p_msg);
+ break;
+
+ case BT_EVT_BTU_IPC_SLIP_EVT:
+ case BT_EVT_BTU_IPC_BTTRC_EVT:
+ case BT_EVT_BTU_IPC_BURST_EVT:
+ case BT_EVT_BTU_IPC_ACL_EVT:
+ case BT_EVT_BTU_IPC_L2C_MSG_EVT:
+ BTUSB_INFO("Event=0x%X Not expected\n", p_msg->event);
+ GKI_freebuf(p_msg);
+ break;
+
+ default:
+ BTUSB_INFO("Event=0x%X Unknown\n", p_msg->event);
+ GKI_freebuf(p_msg);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_hci_cmd_hndl
+ **
+ ** Description Handle HCI CMD packet received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_hci_cmd_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 *p;
+ UINT16 hci_opcode;
+ UINT8 hci_status;
+
+ /* First check if this HCI command must be caught by BTUSB */
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ STREAM_TO_UINT16(hci_opcode, p); /* Extract HCI Opcode */
+
+ /* If the HCI Opcode must be caught */
+ switch(hci_opcode)
+ {
+ case HCI_BRCM_PAUSE_TRANSPORT:
+ BTUSB_INFO("HCI TransportPause VSC (%X) caught\n", hci_opcode);
+ hci_status = HCI_SUCCESS;
+ btusb_lite_ipc_cmd_cplt_evt_send(p_dev, hci_opcode,
+ &hci_status, sizeof(hci_status));
+ GKI_freebuf(p_msg);
+ return;
+
+ case HCI_BRCM_TRANSPORT_RESUME:
+ BTUSB_INFO("HCI TransportResume VSC (%X) caught\n", hci_opcode);
+
+ hci_status = HCI_SUCCESS;
+ btusb_lite_ipc_cmd_cplt_evt_send(p_dev, hci_opcode,
+ &hci_status, sizeof(hci_status));
+ GKI_freebuf(p_msg);
+ return;
+
+ default:
+ break;
+ }
+
+ BTUSB_INFO("HCI OpCode=0x%04X Sent to BT Controller\n", hci_opcode);
+
+ if (p_msg->offset < 1)
+ {
+ BTUSB_ERR("Offset=%d too small\n", p_msg->offset);
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ p_msg->offset--; /* Reduce Offset to add H4 HCI Type (Command) */
+ p_msg->len++;
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ UINT8_TO_STREAM(p, HCIT_TYPE_COMMAND);
+
+ /* add the incoming data and notify the btusb_tx_task to process */
+ GKI_enqueue(&p_dev->tx_queue, p_msg);
+
+ // wake up tasklet
+ tasklet_schedule(&p_dev->tx_task);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_hci_acl_hndl
+ **
+ ** Description Handle HCI ACL packet received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_hci_acl_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 *p;
+
+ if (p_msg->offset < 1)
+ {
+ BTUSB_ERR("Offset=%d too small\n", p_msg->offset);
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ p_msg->offset--; /* Reduce Offset to add H4 HCI Type (Command) */
+ p_msg->len++;
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ UINT8_TO_STREAM(p, HCIT_TYPE_ACL_DATA);
+
+ /* add the incoming data and notify the btusb_tx_task to process */
+ GKI_enqueue(&p_dev->tx_queue, p_msg);
+
+ // wake up tasklet
+ tasklet_schedule(&p_dev->tx_task);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_mgt_hndl
+ **
+ ** Description Handle Mgt messages received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_mgt_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 cmd;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 response[6];
+ UINT8 *p_response = response;
+
+ STREAM_TO_UINT8(cmd, p); /* Extract UIPC_MGMT Request */
+
+ switch(cmd)
+ {
+ case UIPC_OPEN_REQ:
+ BTUSB_INFO("IPC_MGT:OpenReq received\n");
+ /* If Mgt already opened */
+ if (p_dev->lite_cb.s.mgt.opened)
+ {
+ BTUSB_ERR("IPC_MGT Was already opened\n");
+ UINT8_TO_STREAM(p_response, UIPC_STATUS_FAIL); /* Status */
+ }
+ else
+ {
+ p_dev->lite_cb.s.mgt.opened = true;
+ UINT8_TO_STREAM(p_response, UIPC_STATUS_SUCCESS); /* Status */
+ }
+ UINT16_TO_STREAM(p_response, UIPC_VERSION_MAJOR); /* version_major */
+ UINT16_TO_STREAM(p_response, UIPC_VERSION_MINOR); /* version_minor */
+ UINT8_TO_STREAM(p_response, BTM_SYNC_INFO_NUM_STR); /* Number of simultaneous streams supported by the light stack */
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_MGMT_EVT, UIPC_OPEN_RSP,
+ response, p_response - response);
+ break;
+
+ case UIPC_CLOSE_REQ:
+ BTUSB_INFO("IPC_MGT:CloseReq received\n");
+ p_dev->lite_cb.s.mgt.opened = false;
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_MGMT_EVT, UIPC_CLOSE_RSP, NULL, 0);
+ break;
+
+ default:
+ BTUSB_INFO("Unknown IPC_MGT command=%d\n", cmd);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_btu_hndl
+ **
+ ** Description Handle BTU messages received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_btu_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 cmd;
+ UINT8 byte;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ STREAM_TO_UINT8(cmd, p); /* Extract UIPC_BTU Request */
+
+ switch(cmd)
+ {
+ case BTU_IPC_CMD_SET_TRANSPORT_STATE:
+ STREAM_TO_UINT8(byte, p); /* Extract Param */
+ BTUSB_INFO("IPC_BTU:SetTransportState (%d) received\n", byte);
+ p_dev->lite_cb.s.btu.transport_state = byte;
+ break;
+
+ case BTU_IPC_CMD_DISABLE_TRANSPORT:
+ STREAM_TO_UINT8(byte, p); /* Extract Param */
+ BTUSB_INFO("IPC_BTU:DisableTransport (%d) received\n", byte);
+ p_dev->lite_cb.s.btu.transport_disabled = byte;
+ break;
+
+ default:
+ BTUSB_INFO("Unknown IPC_BTU command=%d\n", cmd);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_btm_hndl
+ **
+ ** Description Handle BTM messages received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_btm_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 cmd;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ tBTA_AV_SYNC_INFO sync_info;
+ UINT8 scb_idx;
+ tBTA_AV_AUDIO_CODEC_INFO codec_cfg;
+ UINT8 start_stop_flag;
+ UINT8 multi_av_supported;
+ UINT16 curr_mtu;
+ UINT8 audio_open_cnt;
+ UINT8 response[1];
+ UINT8 *p_response = response;
+
+ STREAM_TO_UINT8(cmd, p); /* Extract UIPC_BTU Request */
+
+ switch(cmd)
+ {
+ case BTA_AV_SYNC_TO_LITE_REQ:
+ BTUSB_INFO("IPC_BTM:BtaAvSyncToLiteReq (%d)\n", cmd);
+ STREAM_TO_UINT8(sync_info.avdt_handle, p);
+ STREAM_TO_UINT8(sync_info.chnl, p);
+ STREAM_TO_UINT8(sync_info.codec_type, p);
+ STREAM_TO_UINT8(sync_info.cong, p);
+ STREAM_TO_UINT8(sync_info.hdi, p);
+ STREAM_TO_UINT8(sync_info.hndl, p);
+ STREAM_TO_UINT8(sync_info.l2c_bufs, p);
+ STREAM_TO_UINT16(sync_info.l2c_cid, p);
+ STREAM_TO_ARRAY (sync_info.peer_addr, p, BD_ADDR_LEN);
+ STREAM_TO_UINT8(multi_av_supported, p);
+ STREAM_TO_UINT16(curr_mtu, p);
+ BTUSB_INFO("avdt_hdl=0x%x chnl=0x%x codec_type=0x%x cong=%d hdi=%d hndl=0x%x\n",
+ sync_info.avdt_handle, sync_info.chnl, sync_info.codec_type,
+ sync_info.cong, sync_info.hdi, sync_info.hndl);
+ BTUSB_INFO("l2c_bufs=%d l2c_cid=0x%x multi_av_sup=%d curr_mtu=%d\n",
+ sync_info.l2c_bufs, sync_info.l2c_cid, multi_av_supported, curr_mtu);
+ BTUSB_INFO("BdAddr=%02X-%02X-%02X-%02X-%02X-%02X\n",
+ sync_info.peer_addr[0], sync_info.peer_addr[1],sync_info.peer_addr[2],
+ sync_info.peer_addr[3], sync_info.peer_addr[4],sync_info.peer_addr[5]);
+
+ /* Add AV channel */
+ btusb_lite_av_add(p_dev, &sync_info, multi_av_supported, curr_mtu);
+
+ UINT8_TO_STREAM(p_response, sync_info.hdi);
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_BTM_EVT, BTA_AV_SYNC_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ case BTA_AV_STR_START_TO_LITE_REQ:
+ BTUSB_INFO("IPC_BTM:BtaAvStrStartToLiteReq (%d)\n", cmd);
+ STREAM_TO_UINT8(scb_idx, p);
+ STREAM_TO_UINT8(audio_open_cnt, p);
+ STREAM_TO_UINT16 (codec_cfg.bit_rate, p);
+ STREAM_TO_UINT16 (codec_cfg.bit_rate_busy, p);
+ STREAM_TO_UINT16 (codec_cfg.bit_rate_swampd, p);
+ STREAM_TO_UINT8 (codec_cfg.busy_level, p);
+ STREAM_TO_ARRAY (codec_cfg.codec_info, p, AVDT_CODEC_SIZE);
+ STREAM_TO_UINT8 (codec_cfg.codec_type, p);
+ STREAM_TO_UINT8 (start_stop_flag, p);
+ BTUSB_INFO(" scb_idx=%d audio_open_cnt=%d busy_level=%d start_stop_flag=%d\n",
+ scb_idx, audio_open_cnt,
+ codec_cfg.busy_level, start_stop_flag);
+ BTUSB_INFO(" codec_type=0x%x bit_rate=%d busy_level=%d bit_rate_busy=%d bit_rate_swampd=%d\n",
+ codec_cfg.codec_type, codec_cfg.bit_rate, codec_cfg.busy_level,
+ codec_cfg.bit_rate_busy, codec_cfg.bit_rate_swampd);
+ BTUSB_INFO(" CodecInfo:%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
+ codec_cfg.codec_info[0], codec_cfg.codec_info[1], codec_cfg.codec_info[2],
+ codec_cfg.codec_info[3], codec_cfg.codec_info[4], codec_cfg.codec_info[5],
+ codec_cfg.codec_info[6], codec_cfg.codec_info[7], codec_cfg.codec_info[8],
+ codec_cfg.codec_info[9]);
+
+ /* Start AV */
+ btusb_lite_av_start(p_dev, scb_idx, start_stop_flag, audio_open_cnt, &codec_cfg);
+
+ /* Send the response */
+ UINT8_TO_STREAM(p_response, scb_idx);
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_BTM_EVT, BTA_AV_STR_START_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ case BTA_AV_STR_STOP_TO_LITE_REQ:
+ BTUSB_INFO("IPC_BTM:BtaAvStrStopToLiteReq (%d)\n", cmd);
+ STREAM_TO_UINT8(scb_idx, p);
+ STREAM_TO_UINT8(audio_open_cnt, p);
+ BTUSB_INFO(" scb_idx=%d audio_open_cnt=%d\n", scb_idx, audio_open_cnt);
+
+ btusb_lite_av_stop(p_dev, scb_idx, audio_open_cnt);
+
+ UINT8_TO_STREAM(p_response, scb_idx);
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_BTM_EVT, BTA_AV_STR_STOP_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ case BTA_AV_STR_SUSPEND_TO_LITE_REQ:
+ BTUSB_INFO("IPC_BTM:BtaAvStrSuspendToLiteReq (%d)\n", cmd);
+ STREAM_TO_UINT8(scb_idx, p);
+ STREAM_TO_UINT8(audio_open_cnt, p);
+ BTUSB_INFO(" scb_idx=%d audio_open_cnt=%d\n", scb_idx, audio_open_cnt);
+ btusb_lite_av_suspend(p_dev, scb_idx, audio_open_cnt);
+
+ UINT8_TO_STREAM(p_response, scb_idx);
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_BTM_EVT, BTA_AV_STR_SUSPEND_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ case BTA_AV_STR_CLEANUP_TO_LITE_REQ:
+ BTUSB_INFO("IPC_BTM:BtaAvStrCleanupToLiteReq (%d)\n", cmd);
+ STREAM_TO_UINT8(scb_idx, p);
+ STREAM_TO_UINT8(audio_open_cnt, p);
+ STREAM_TO_UINT16(curr_mtu, p);
+ BTUSB_INFO(" scb_idx=%d audio_open_cnt=%d curr_mtu=%d\n", scb_idx, audio_open_cnt,
+ curr_mtu);
+
+ btusb_lite_av_remove(p_dev, scb_idx, audio_open_cnt, curr_mtu);
+
+ UINT8_TO_STREAM(p_response, scb_idx);
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_BTM_EVT, BTA_AV_STR_CLEANUP_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ /* BTC commands (unexpected) */
+ case A2DP_START_REQ:
+ case A2DP_START_RESP:
+ case A2DP_STOP_REQ:
+ case A2DP_STOP_RESP:
+ case A2DP_CLEANUP_REQ:
+ case A2DP_CLEANUP_RESP:
+ case A2DP_SUSPEND_REQ:
+ case A2DP_SUSPEND_RESP:
+ case A2DP_JITTER_DONE_IND:
+
+ /* BTA AV Response commands (unexpected) */
+ case BTA_AV_SYNC_TO_LITE_RESP:
+ case BTA_AV_STR_START_TO_LITE_RESP:
+ case BTA_AV_STR_STOP_TO_LITE_RESP:
+ case BTA_AV_STR_CLEANUP_TO_LITE_RESP:
+ case BTA_AV_STR_SUSPEND_TO_LITE_RESP:
+ case BTA_AV_SYNC_ERROR_RESP:
+ BTUSB_INFO("IPC_BTM: Unexpected Cmd=%d received\n", cmd);
+ break;
+
+ default:
+ BTUSB_INFO("IPC_BTM: Unknown Cmd=%d received\n", cmd);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_avdt_hndl
+ **
+ ** Description Handle AVDT messages received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_avdt_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ tAVDT_SYNC_INFO sync_req;
+ tAVDT_SYNC_INFO sync_rsp;
+ int stream;
+ struct btusb_lite_avdt_scb *p_scb;
+ UINT8 avdt_status;
+
+ STREAM_TO_UINT8(sync_req.op_code, p); /* Extract UIPC_AVDT Request */
+
+ switch(sync_req.op_code)
+ {
+ case AVDT_SYNC_TO_LITE_REQ:
+ BTUSB_INFO("IPC_AVDT:AvdtSyncToLiteReq (%d) received\n", sync_req.op_code);
+ break;
+
+ case AVDT_RESYNC_TO_LITE_REQ:
+ BTUSB_INFO("IPC_AVDT:AvdtReSyncToLiteReq (%d) received\n", sync_req.op_code);
+ break;
+
+ case AVDT_SYNC_TO_FULL_REQ:
+ BTUSB_INFO("IPC_AVDT:AvdtSyncToFullReq (%d) received\n", sync_req.op_code);
+ break;
+
+ case AVDT_REMOVE_TO_LITE_REQ:
+ BTUSB_INFO("IPC_AVDT:AvdtRemoveToLiteReq (%d)\n", sync_req.op_code);
+ break;
+
+ case AVDT_SYNC_CP_TO_LITE_REQ:
+ BTUSB_INFO("IPC_AVDT:AvdtSyncCpToLiteReq (%d)\n", sync_req.op_code);
+ break;
+
+ case AVDT_SYNC_TO_LITE_RESP:
+ case AVDT_RESYNC_TO_LITE_RESP:
+ case AVDT_SYNC_TO_FULL_RESP:
+ case AVDT_REMOVE_TO_LITE_RESP:
+ case AVDT_SYNC_CP_TO_LITE_RESP:
+ BTUSB_INFO("IPC_AVDT: Unexpected Cmd=%d received\n", sync_req.op_code);
+ sync_rsp.op_code = 0xFF;
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+
+ default:
+ BTUSB_INFO("IPC_AVDT: Unknown Cmd=%d received\n", sync_req.op_code);
+ sync_rsp.op_code = 0xFE;
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+
+ /* Extract parameters */
+ STREAM_TO_UINT8(sync_req.status, p);
+
+ /* Decode Sync CP parameters */
+ if (sync_req.op_code == AVDT_SYNC_CP_TO_LITE_REQ)
+ {
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++ )
+ {
+ STREAM_TO_UINT8(sync_req.scb_info[stream].handle, p);
+ STREAM_TO_UINT16(sync_req.scb_info[stream].cp.id, p);
+ STREAM_TO_UINT8(sync_req.scb_info[stream].cp.scms_hdr, p);
+ if (sync_req.scb_info[stream].handle)
+ {
+ BTUSB_INFO(" stream[%d]: handle=0x%x cp_id=0x%04X scms_hdr=0x%x\n",
+ stream, sync_req.scb_info[stream].handle,
+ sync_req.scb_info[stream].cp.id,
+ sync_req.scb_info[stream].cp.scms_hdr);
+ }
+ else
+ {
+ BTUSB_INFO(" stream[%d]: No Data\n", stream);
+ }
+ }
+ }
+ /* Decode other Sync message parameters */
+ else
+ {
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++ )
+ {
+ STREAM_TO_UINT8(sync_req.scb_info[stream].handle, p);
+ STREAM_TO_BDADDR(sync_req.scb_info[stream].peer_addr, p)
+ STREAM_TO_UINT16(sync_req.scb_info[stream].local_cid, p);
+ STREAM_TO_UINT16(sync_req.scb_info[stream].peer_mtu, p);
+ STREAM_TO_UINT8(sync_req.scb_info[stream].mux_tsid_media, p);
+ STREAM_TO_UINT16(sync_req.scb_info[stream].media_seq, p);
+ if (sync_req.scb_info[stream].handle)
+ {
+ BTUSB_INFO(" stream[%d]:\n", stream);
+ BTUSB_INFO(" BdAddr=%02X-%02X-%02X-%02X-%02X-%02X\n",
+ sync_req.scb_info[stream].peer_addr[0],
+ sync_req.scb_info[stream].peer_addr[1],
+ sync_req.scb_info[stream].peer_addr[2],
+ sync_req.scb_info[stream].peer_addr[3],
+ sync_req.scb_info[stream].peer_addr[4],
+ sync_req.scb_info[stream].peer_addr[5]);
+ BTUSB_INFO(" handle=0x%x local_cid=0x%x peer_mtu=%d mux_tsid_media=%d media_seq=%d\n",
+ sync_req.scb_info[stream].handle,
+ sync_req.scb_info[stream].local_cid,
+ sync_req.scb_info[stream].peer_mtu,
+ sync_req.scb_info[stream].mux_tsid_media,
+ sync_req.scb_info[stream].media_seq);
+ }
+ else
+ {
+ BTUSB_INFO(" stream[%d]: No data\n", stream);
+ }
+ }
+ }
+ memset(&sync_rsp, 0, sizeof(sync_rsp));
+
+ switch(sync_req.op_code)
+ {
+ case AVDT_SYNC_TO_LITE_REQ:
+ sync_rsp.op_code = AVDT_SYNC_TO_LITE_RESP;
+
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ if(sync_req.scb_info[stream].handle == 0)
+ continue;
+
+ if(btusb_lite_avdt_init_scb(p_dev, &(sync_req.scb_info[stream])) != AVDT_SYNC_SUCCESS)
+ {
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+ }
+ sync_rsp.status = AVDT_SYNC_SUCCESS;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ break;
+
+ case AVDT_RESYNC_TO_LITE_REQ:
+ sync_rsp.op_code = AVDT_RESYNC_TO_LITE_RESP;
+
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ if(sync_req.scb_info[stream].handle == 0)
+ continue;
+
+ if((p_scb = btusb_lite_avdt_scb_by_hdl(p_dev, sync_req.scb_info[stream].handle)) != NULL)
+ {
+ memcpy(p_scb->p_ccb->peer_addr, sync_req.scb_info[stream].peer_addr, BD_ADDR_LEN);
+ p_scb->p_ccb->lcid = sync_req.scb_info[stream].local_cid;
+ p_scb->p_ccb->peer_mtu = sync_req.scb_info[stream].peer_mtu;
+ p_scb->mux_tsid_media = sync_req.scb_info[stream].mux_tsid_media;
+ p_scb->media_seq = sync_req.scb_info[stream].media_seq;
+ }
+ else if(btusb_lite_avdt_init_scb(p_dev, &(sync_req.scb_info[stream])) != AVDT_SYNC_SUCCESS)
+ {
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+ }
+ sync_rsp.status = AVDT_SYNC_SUCCESS;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ break;
+
+ case AVDT_SYNC_TO_FULL_REQ:
+ sync_rsp.op_code = AVDT_SYNC_TO_FULL_RESP;
+
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ if(sync_req.scb_info[stream].handle == 0)
+ {
+ sync_rsp.scb_info[stream].handle = 0;
+ continue;
+ }
+
+ if(btusb_lite_avdt_remove_scb(p_dev, sync_req.scb_info[stream].handle,
+ &sync_rsp.scb_info[stream]) != AVDT_SYNC_SUCCESS)
+ {
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+ }
+ sync_rsp.status = AVDT_SYNC_SUCCESS;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ break;
+
+ case AVDT_REMOVE_TO_LITE_REQ:
+ sync_rsp.op_code = AVDT_REMOVE_TO_LITE_RESP;
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ if(sync_req.scb_info[stream].handle == 0)
+ continue;
+
+ if(btusb_lite_avdt_remove_scb(p_dev, sync_req.scb_info[stream].handle,
+ &sync_rsp.scb_info[stream]) != AVDT_SYNC_SUCCESS)
+ {
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+ }
+ sync_rsp.status = AVDT_SYNC_SUCCESS;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ break;
+
+ case AVDT_SYNC_CP_TO_LITE_REQ:
+ sync_rsp.op_code = AVDT_SYNC_CP_TO_LITE_RESP;
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ if(sync_req.scb_info[stream].handle == 0)
+ continue;
+
+ switch(sync_req.scb_info[stream].cp.id)
+ {
+ case AVDT_SYNC_CP_ID_NONE:
+ avdt_status = btusb_lite_avdt_cp_set_scms(p_dev,
+ sync_req.scb_info[stream].handle, FALSE, 0x00);
+ break;
+
+ case AVDT_SYNC_CP_ID_SCMS:
+ avdt_status = btusb_lite_avdt_cp_set_scms(p_dev,
+ sync_req.scb_info[stream].handle, TRUE,
+ sync_req.scb_info[stream].cp.scms_hdr);
+ break;
+
+ default:
+ avdt_status = AVDT_SYNC_FAILURE;
+ break;
+ }
+ if (avdt_status != AVDT_SYNC_SUCCESS)
+ {
+ sync_rsp.status = AVDT_SYNC_FAILURE;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ return;
+ }
+ }
+ sync_rsp.status = AVDT_SYNC_SUCCESS;
+ btusb_lite_ipc_avdt_sync_info_send(p_dev, &sync_rsp);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_avdt_sync_info_send
+ **
+ ** Description Build and send an IPC AVDT Sync Info Response
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_avdt_sync_info_send(struct btusb *p_dev, tAVDT_SYNC_INFO *p_sync_rsp)
+{
+ int stream;
+ UINT8 response[BTUSB_LITE_IPC_AVDT_SYNC_INFO_RSP_LEN];
+ UINT8 *p_response = response;
+
+ UINT8_TO_STREAM(p_response, p_sync_rsp->status);
+
+ if (p_sync_rsp->op_code != AVDT_SYNC_CP_TO_LITE_RESP)
+ {
+ for(stream = 0; stream < BTM_SYNC_INFO_NUM_STR; stream++)
+ {
+ UINT8_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].handle);
+ BDADDR_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].peer_addr)
+ UINT16_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].local_cid);
+ UINT16_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].peer_mtu);
+ UINT8_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].mux_tsid_media);
+ UINT16_TO_STREAM(p_response, p_sync_rsp->scb_info[stream].media_seq);
+ }
+ }
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_AVDT_EVT, p_sync_rsp->op_code,
+ response, p_response - response);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_l2c_hndl
+ **
+ ** Description Handle L2C messages received from Lite interface
+ **
+ ** Returns none
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_l2c_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 cmd;
+ UINT8 *p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ UINT8 response[3];
+ UINT8 *p_response = response;
+ struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.s.l2c;
+ int stream;
+ tL2C_STREAM_INFO l2c_stream;
+ UINT16 local_cid;
+ UINT8 num_stream;
+
+ STREAM_TO_UINT8(cmd, p); /* Extract UIPC_MGMT Request */
+
+ switch(cmd)
+ {
+ case L2C_SYNC_TO_LITE_REQ:
+ BTUSB_INFO("IPC_L2C:L2cSyncToLiteReq (%d) received\n", L2C_SYNC_TO_LITE_REQ);
+ STREAM_TO_UINT16(p_l2c->light_xmit_quota, p);
+ STREAM_TO_UINT16(p_l2c->acl_data_size, p);
+ STREAM_TO_UINT16(p_l2c->non_flushable_pbf, p);
+ STREAM_TO_UINT8(p_l2c->multi_av_data_cong_start, p);
+ STREAM_TO_UINT8(p_l2c->multi_av_data_cong_end, p);
+ STREAM_TO_UINT8(p_l2c->multi_av_data_cong_discard, p);
+ STREAM_TO_UINT8(num_stream, p);
+ BTUSB_INFO("Xquota=%d AclSize=%d NFpbf=%d congStart=%d congEnd=%d congDisc=%d NbStr=%d\n",
+ p_l2c->light_xmit_quota, p_l2c->acl_data_size, p_l2c->non_flushable_pbf,
+ p_l2c->multi_av_data_cong_start, p_l2c->multi_av_data_cong_end,
+ p_l2c->multi_av_data_cong_discard, num_stream);
+
+ /* Start building the response */
+ UINT16_TO_STREAM(p_response, p_l2c->light_xmit_unacked);
+ UINT8_TO_STREAM(p_response, num_stream);
+
+ for(stream = 0; stream < num_stream; stream++)
+ {
+ STREAM_TO_UINT16(l2c_stream.local_cid, p);
+ STREAM_TO_UINT16(l2c_stream.remote_cid, p);
+ STREAM_TO_UINT16(l2c_stream.out_mtu, p);
+ STREAM_TO_UINT16(l2c_stream.handle, p);
+ STREAM_TO_UINT16(l2c_stream.link_xmit_quota, p);
+ STREAM_TO_UINT8(l2c_stream.is_flushable, p);
+ BTUSB_INFO(" Stream[%d]:lcid=0x%X rcid=0x%X mtu=%d handle=0x%X xmit_quota=%d flushable=%d\n",
+ stream, l2c_stream.local_cid, l2c_stream.remote_cid,
+ l2c_stream.out_mtu, l2c_stream.handle,
+ l2c_stream.link_xmit_quota, l2c_stream.is_flushable);
+
+ /* Resume building the response */
+ UINT16_TO_STREAM(p_response, l2c_stream.local_cid);
+
+ /* Synchronize (add) this L2CAP Stream */
+ if (btusb_lite_l2c_add(p_dev, &l2c_stream) < 0)
+ {
+ UINT8_TO_STREAM(p_response, L2C_SYNC_FAILURE);
+ }
+ else
+ {
+ UINT8_TO_STREAM(p_response, L2C_SYNC_SUCCESS);
+ }
+ }
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_L2C_EVT, L2C_SYNC_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ case L2C_REMOVE_TO_LITE_REQ:
+ BTUSB_INFO("IPC_L2C:L2cRemoveToLiteReq (%d) received\n", L2C_REMOVE_TO_LITE_REQ);
+ STREAM_TO_UINT16(p_l2c->light_xmit_quota, p);
+ STREAM_TO_UINT8(num_stream, p);
+ BTUSB_INFO("Xquota=%d NbStr=%d\n", p_l2c->light_xmit_quota, num_stream);
+
+ /* Start building the response */
+ UINT16_TO_STREAM(p_response, p_l2c->light_xmit_unacked);
+ UINT8_TO_STREAM(p_response, num_stream);
+
+ for(stream = 0; stream < num_stream; stream++)
+ {
+ STREAM_TO_UINT16(local_cid, p);
+ BTUSB_INFO(" Stream[%d]:lcid=0x%X\n", stream, p_l2c->ccb[stream].local_cid);
+
+ /* Resume building the response */
+ UINT16_TO_STREAM(p_response, local_cid);
+
+ /* Synchronize (remove) this L2CAP Stream */
+ if (btusb_lite_l2c_remove(p_dev, local_cid) < 0)
+ {
+ UINT8_TO_STREAM(p_response, L2C_SYNC_FAILURE);
+ }
+ else
+ {
+ UINT8_TO_STREAM(p_response, L2C_SYNC_SUCCESS);
+ }
+ }
+
+ /* Send the response to the full stack */
+ btusb_lite_ipc_rsp_send(p_dev, BT_EVT_BTU_IPC_L2C_EVT, L2C_REMOVE_TO_LITE_RESP,
+ response, p_response - response);
+ break;
+
+ default:
+ BTUSB_INFO("Unknown IPC_MGT command=%d\n", cmd);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_rsp_send
+ **
+ ** Description Send an Response over Lite interface.
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_rsp_send(struct btusb *p_dev,
+ UINT16 event, UINT8 op_code, UINT8 *p_param, UINT8 param_len)
+{
+ BT_HDR *p_msg;
+ UINT16 size = param_len + BTUSB_LITE_IPC_HDR_SIZE + sizeof(UINT8);
+ UINT8 *p;
+
+ BTUSB_INFO("Event=%s(0x%X), opcode=%d len=%d\n", btusb_lite_ipc_event_desc(event),
+ event, op_code, param_len);
+
+ /* Get a buffer from the pool */
+ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size);
+ if(unlikely(p_msg == NULL))
+ {
+ BTUSB_ERR("Unable to get GKI buffer\n");
+ return;
+ }
+
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
+ return;
+ }
+
+ p_msg->offset = 0;
+ p_msg->event = 0;
+ p_msg->len = size;
+
+ p = (UINT8 *)(p_msg + 1);
+
+ UINT16_TO_STREAM(p, param_len + BTUSB_LITE_IPC_HDR_EVT_SIZE + sizeof(UINT8)); /* Length */
+ UINT16_TO_STREAM(p, event); /* Event */
+ UINT8_TO_STREAM(p, op_code); /* Opcode */
+ if (p_param)
+ {
+ ARRAY_TO_STREAM(p, p_param, param_len)
+ }
+
+ /* Send message to User Space */
+ btusb_lite_ipc_sent_to_user(p_dev, p_msg);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_cmd_cplt_evt_send
+ **
+ ** Description Send an UIPC_Over_HCI VSC Cmd Complete.
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_cmd_cplt_evt_send(struct btusb *p_dev,
+ UINT16 opcode, UINT8 *p_param, UINT8 param_len)
+{
+ BT_HDR *p_msg;
+ UINT16 size = param_len + BTUSB_LITE_IPC_HDR_SIZE + 5;
+ UINT8 *p;
+
+ /* Get a buffer from the pool */
+ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size);
+ if(unlikely(p_msg == NULL))
+ {
+ BTUSB_ERR("Unable to get GKI buffer\n");
+ return;
+ }
+
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
+ return;
+ }
+
+ p_msg->offset = 0;
+ p_msg->event = 0;
+ p_msg->len = size;
+
+ p = (UINT8 *)(p_msg + 1);
+
+ UINT16_TO_STREAM(p, param_len + BTUSB_LITE_IPC_HDR_EVT_SIZE + 5); /* length */
+ UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_EVT); /* IPC OpCode */
+ UINT8_TO_STREAM(p, HCI_COMMAND_COMPLETE_EVT); /* Command Complete Evt */
+ UINT8_TO_STREAM(p, param_len + 3); /* Param Length (param + NumCmd + OpCode) */
+ UINT8_TO_STREAM(p, 0x01); /* HCI Num Command */
+ UINT16_TO_STREAM(p, opcode); /* HCI OpCode */
+
+ if (p_param)
+ {
+ ARRAY_TO_STREAM(p, p_param, param_len)
+ }
+
+ /* Send message to User Space */
+ btusb_lite_ipc_sent_to_user(p_dev, p_msg);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_sent_to_user
+ **
+ ** Description Send message to User Space (via IPC Interface).
+ **
+ ** Returns status: <> 0 if the event must be send to user space (BSA)
+ ** 0 if the event is handled
+ **
+ *******************************************************************************/
+static void btusb_lite_ipc_sent_to_user(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ /* Update Lite Statistics */
+ p_dev->lite_cb.s.stat.event_bytes += p_msg->len;
+ p_dev->lite_cb.s.stat.event_completed++;
+
+ /* Enqueue message in IPC queue */
+ GKI_enqueue(&p_dev->lite_cb.s.to_app.ipc_queue, p_msg);
+
+ /* WakeUp IPC read */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_ipc_event_desc
+ **
+ ** Description Get IPC Event description
+ **
+ ** Returns status: <> 0 if the event must be send to user space (BSA)
+ ** 0 if the event is handled
+ **
+ *******************************************************************************/
+static char *btusb_lite_ipc_event_desc(UINT16 event)
+{
+ switch(event)
+ {
+ case BT_EVT_TO_LM_HCI_CMD:
+ return "BT_EVT_TO_LM_HCI_CMD";
+ case BT_EVT_TO_LM_HCI_ACL:
+ return "BT_EVT_TO_LM_HCI_ACL";
+ case BT_EVT_BTU_IPC_MGMT_EVT:
+ return "BT_EVT_BTU_IPC_MGMT_EVT";
+ case BT_EVT_BTU_IPC_BTU_EVT:
+ return "BT_EVT_BTU_IPC_BTU_EVT";
+ case BT_EVT_BTU_IPC_L2C_EVT:
+ return "BT_EVT_BTU_IPC_L2C_EVT";
+ case BT_EVT_BTU_IPC_ACL_EVT:
+ return "BT_EVT_BTU_IPC_ACL_EVT";
+ case BT_EVT_BTU_IPC_BTM_EVT:
+ return "BT_EVT_BTU_IPC_BTM_EVT";
+ case BT_EVT_BTU_IPC_L2C_MSG_EVT:
+ return "BT_EVT_BTU_IPC_L2C_MSG_EVT";
+ case BT_EVT_BTU_IPC_AVDT_EVT:
+ return "BT_EVT_BTU_IPC_AVDT_EVT";
+ case BT_EVT_BTU_IPC_SLIP_EVT:
+ return "BT_EVT_BTU_IPC_SLIP_EVT";
+ case BT_EVT_BTU_IPC_BTTRC_EVT:
+ return "BT_EVT_BTU_IPC_BTTRC_EVT";
+ case BT_EVT_BTU_IPC_BURST_EVT:
+ return "BT_EVT_BTU_IPC_BURST_EVT";
+ default:
+ return "Unknown Event";
+ }
+}
+
diff --git a/src/btusb_lite_av.c b/src/btusb_lite_av.c
new file mode 100755
index 0000000..dff6cc8
--- a/dev/null
+++ b/src/btusb_lite_av.c
@@ -0,0 +1,1365 @@
+/*
+ *
+ * btusb_lite_av.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#include <linux/moduleparam.h>
+#include "btusb.h"
+#include "bd.h"
+#include "btpcm_api.h"
+#include "btsbc_api.h"
+#ifdef BTUSB_LITE_SEC
+#include "btsec_api.h"
+#endif
+
+struct btusb_lite_av_sbc_param
+{
+ int frequency;
+ unsigned char nb_blocks;
+ unsigned char nb_subbands;
+ unsigned char mode;
+ unsigned char allocation;
+ unsigned char bitpool_min;
+ unsigned char bitpool_max;
+};
+
+
+/* Codec (From BT Spec) */
+#define A2D_MEDIA_TYPE_AUDIO 0x00
+
+#define A2D_MEDIA_CT_SBC 0x00 /* SBC Codec */
+#define A2D_MEDIA_CT_VEND 0xFF /* Vendor specific */
+
+/* SBC Codec (From BT Spec) */
+#define CODEC_SBC_LOSC 6
+
+#define CODEC_SBC_FREQ_MASK 0xF0
+#define CODEC_SBC_FREQ_48 0x10
+#define CODEC_SBC_FREQ_44 0x20
+#define CODEC_SBC_FREQ_32 0x40
+#define CODEC_SBC_FREQ_16 0x80
+
+#define CODEC_MODE_MASK 0x0F
+#define CODEC_MODE_JOIN_STEREO 0x01
+#define CODEC_MODE_STEREO 0x02
+#define CODEC_MODE_DUAL 0x04
+#define CODEC_MODE_MONO 0x08
+
+#define CODEC_SBC_BLOCK_MASK 0xF0
+#define CODEC_SBC_BLOCK_16 0x10
+#define CODEC_SBC_BLOCK_12 0x20
+#define CODEC_SBC_BLOCK_8 0x40
+#define CODEC_SBC_BLOCK_4 0x80
+
+#define CODEC_SBC_NBBAND_MASK 0x0C
+#define CODEC_SBC_NBBAND_8 0x04
+#define CODEC_SBC_NBBAND_4 0x08
+
+#define CODEC_SBC_ALLOC_MASK 0x03
+#define CODEC_SBC_ALLOC_LOUDNESS 0x01
+#define CODEC_SBC_ALLOC_SNR 0x02
+
+/* SEC codec */
+#ifdef BTUSB_LITE_SEC
+#define A2D_MEDIA_CT_SEC 0x07 /* Internal SEC Codec type */
+
+struct btusb_lite_av_sec_param
+{
+ int frequency;
+ unsigned char mode;
+};
+#endif
+
+
+/*
+ * Globals
+ */
+int pcm0_mute = 0;
+module_param(pcm0_mute, int, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+MODULE_PARM_DESC(pcm0_mute, "Mute PCM channel 0");
+
+#define SILENSE_PCM_BUF_SIZE (2 * 128) /* 128 samples, Stereo */
+static const unsigned short btusb_lite_silence_pcm[SILENSE_PCM_BUF_SIZE] = {0};
+
+/*
+ * Local functions
+ */
+static int btusb_lite_av_parse_sbc_codec(struct btusb_lite_av_sbc_param *p_sbc, UINT8 *p_codec);
+static int btusb_lite_sbc_get_bitpool(struct btusb_lite_av_sbc_param *p_sbc_param, int target_bitrate);
+static void btusb_lite_av_pcm_cback(void *p_opaque, void *p_data, int nb_pcm_frames);
+static void btusb_lite_av_send_packet(struct btusb *p_dev, BT_HDR *p_msg);
+
+static int btusb_lite_av_sbc_start(struct btusb *p_dev, UINT8 scb_idx,
+ tBTA_AV_AUDIO_CODEC_INFO*p_codec_cfg);
+
+static int btusb_lite_av_parse_vendor_codec(UINT8 *p_codec_info, UINT32 *p_vendor_id, UINT16 *p_vendor_codec_id);
+
+#ifdef BTUSB_LITE_SEC
+static int btusb_lite_av_parse_sec_codec(struct btusb_lite_av_sec_param *p_sec_param,
+ UINT8 *p_codec_info);
+static int btusb_lite_av_sec_start(struct btusb *p_dev, UINT8 scb_idx,
+ tBTA_AV_AUDIO_CODEC_INFO*p_codec_cfg);
+#endif
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_add
+**
+** Description Add (Sync) an AV channel.
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_add(struct btusb *p_dev, tBTA_AV_SYNC_INFO *p_sync_info,
+ UINT8 multi_av_supported, UINT16 curr_mtu)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_av_scb *p_av_scb;
+ int rv;
+
+ p_av_cb->stack_mtu = curr_mtu; /* Update MTU */
+ p_av_cb->curr_mtu = curr_mtu; /* Update MTU */
+
+ if (p_sync_info->hdi >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad AV Index=%d\n", p_sync_info->hdi);
+ return;
+ }
+
+#if (BTU_MULTI_AV_INCLUDED == TRUE)
+ p_av_cb->multi_av &= ~(BTA_AV_MULTI_AV_SUPPORTED);
+ p_av_cb->multi_av |= multi_av_supported;
+#endif
+
+ p_av_scb = &p_av_cb->scb[p_sync_info->hdi];
+
+ p_av_scb->avdt_handle = p_sync_info->avdt_handle;
+ p_av_scb->chnl = p_sync_info->chnl;
+ p_av_scb->codec_type = p_sync_info->codec_type;
+ p_av_scb->cong = p_sync_info->cong;
+ p_av_scb->hdi = p_sync_info->hdi;
+ p_av_scb->hndl = p_sync_info->hndl;
+ p_av_scb->l2c_bufs = p_sync_info->l2c_bufs;
+ p_av_scb->l2c_cid = p_sync_info->l2c_cid;
+ memcpy(p_av_scb->peer_addr, p_sync_info->peer_addr, BD_ADDR_LEN);
+
+ if (p_av_cb->pcm.state == PCM_CLOSED)
+ {
+ /* Open the PCM Channel */
+ rv = btpcm_open(p_dev->lite_cb.p_btpcm);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_open failed\n");
+ return;
+ }
+ p_av_cb->pcm.state = PCM_OPENED;
+ p_av_cb->pcm.frequency = -1;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_remove
+**
+** Description Remove (Cleanup) an AV channel.
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_remove(struct btusb *p_dev, UINT8 scb_idx,
+ UINT8 audio_open_cnt, UINT16 curr_mtu)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_av_scb *p_av_scb;
+ int av_scb;
+ int cleanup_needed = 1;
+ int rv;
+
+ p_av_cb->curr_mtu = curr_mtu; /* Update MTU */
+ p_av_cb->audio_open_cnt = audio_open_cnt; /* Update audio_open_cnt */
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad Index=%d\n", scb_idx);
+ return;
+ }
+
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ /* Remove AVDT CCB and SCB */
+ btusb_lite_avdt_remove_scb(p_dev, p_av_scb->avdt_handle, NULL);
+
+ /* Clear the AV Stream Control Clock */
+ memset(p_av_scb, 0, sizeof(*p_av_scb));
+
+ /* Check this is the last AV channel removed */
+ p_av_scb = &p_av_cb->scb[0];
+ for (av_scb = 0 ; av_scb < BTA_AV_NUM_STRS ; av_scb++, p_av_scb++)
+ {
+ if (p_av_scb->hndl)
+ {
+ cleanup_needed = 0;
+ break;
+ }
+ }
+
+ if (cleanup_needed)
+ {
+ if (p_av_cb->pcm.state == PCM_STARTED)
+ {
+ /* Stop the PCM Channel */
+ rv = btpcm_stop(p_dev->lite_cb.p_btpcm);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_close failed\n");
+ }
+ p_av_cb->pcm.state = PCM_CONFIGURED;
+ }
+
+ if (p_av_cb->pcm.state != PCM_CLOSED)
+ {
+ /* Close the PCM Channel */
+ rv = btpcm_close(p_dev->lite_cb.p_btpcm);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_close failed\n");
+ }
+ p_av_cb->pcm.state = PCM_CLOSED;
+ }
+
+ if (p_av_cb->encoder.opened)
+ {
+ switch(p_av_cb->encoder.type)
+ {
+ case A2D_MEDIA_CT_SBC:
+ btsbc_free(p_av_cb->encoder.channel);
+ break;
+#ifdef BTUSB_LITE_SEC
+ case A2D_MEDIA_CT_SEC:
+ btsec_free(p_av_cb->encoder.channel);
+ break;
+#endif
+ default:
+ BTUSB_ERR("Unknown Encoder type=%d\n", p_av_cb->encoder.encoder.codec_type);
+ break;
+ }
+ p_av_cb->encoder.opened = 0;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_start
+**
+** Description Start AV
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_start(struct btusb *p_dev, UINT8 scb_idx, UINT8 start_stop_flag,
+ UINT8 audio_open_cnt, tBTA_AV_AUDIO_CODEC_INFO *p_codec_cfg)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ UINT32 vendor_id;
+ UINT16 vendor_codec_id;
+ struct btusb_lite_av_scb *p_av_scb;
+
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad scb_idx=%d", scb_idx);
+ return;
+ }
+
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ if (start_stop_flag)
+ {
+ p_av_cb->scb[scb_idx].started = FALSE;
+ BTUSB_ERR("start_stop_flag TODO!!!");
+ }
+ else
+ {
+ /* If the Codec Type is SBC */
+ if (p_codec_cfg->codec_type == A2D_MEDIA_CT_SBC)
+ {
+ if (btusb_lite_av_sbc_start(p_dev, scb_idx, p_codec_cfg) < 0)
+ {
+ BTUSB_ERR("SBC Stream not started\n");
+ return;
+ }
+ }
+ /* Else if the Codec Type is a Vendor Specific Codec */
+ else if (p_codec_cfg->codec_type == A2D_MEDIA_CT_VEND)
+ {
+ if (btusb_lite_av_parse_vendor_codec(p_codec_cfg->codec_info, &vendor_id, &vendor_codec_id) < 0)
+ {
+ BTUSB_ERR("Unable to parse Vendor Codec\n");
+ return;
+ }
+#ifdef BTUSB_LITE_SEC
+ /* If This is the SEC Encoder */
+ if ((vendor_id == BTSEC_VENDOR_ID) &&
+ (vendor_codec_id == BTSEC_VENDOR_CODEC_ID))
+ {
+ btusb_lite_av_sec_start(p_dev, scb_idx, p_codec_cfg);
+ }
+ else
+#endif
+ /* Add other Vendor Specific Vendor coder Here... */
+ {
+ BTUSB_ERR("Unsupported Codec VendorId=0x%08x VendorCodecId=0x%04x\n", vendor_id, vendor_codec_id);
+ }
+ }
+ else
+ {
+ BTUSB_ERR("Unsupported Encoder type=%d\n", p_codec_cfg->codec_type);
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_parse_vendor_codec
+**
+** Description Parse Vendor Id and Vendor Codec Id from Codec information
+**
+** Returns Status, VendorId and VendorCodecId
+**
+*******************************************************************************/
+static int btusb_lite_av_parse_vendor_codec(UINT8 *p_codec_info, UINT32 *p_vendor_id, UINT16 *p_vendor_codec_id)
+{
+ UINT8 byte;
+ UINT32 vendor_id;
+ UINT16 vendor_codec_id;
+
+ if (!p_codec_info || !p_vendor_id || !p_vendor_codec_id)
+ {
+ BTUSB_ERR("Bad parameter\n");
+ return -1;
+ }
+
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract LOSC */
+ if (byte < (1 + 1 + 4 + 2)) /* Media Type, Media Codec Type, Vid, VCId */
+ {
+ BTUSB_ERR("Codec LOSC=%d too small\n", byte);
+ return -1;
+ }
+
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract Media Type */
+ if (byte != A2D_MEDIA_TYPE_AUDIO)
+ {
+ BTUSB_ERR("Unsupported Media Type=0x%x\n", byte);
+ return -1;
+ }
+
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract Media Codec Type */
+ if (byte != A2D_MEDIA_CT_VEND)
+ {
+ BTUSB_ERR("Media codec Type=0x%x is not Vendor(0xFF)\n", byte);
+ return -1;
+ }
+
+ STREAM_TO_UINT32(vendor_id, p_codec_info); /* Extract Vendor Id */
+ STREAM_TO_UINT16(vendor_codec_id, p_codec_info); /* Extract Vendor Codec Id */
+
+ *p_vendor_id = vendor_id;
+ *p_vendor_codec_id = vendor_codec_id;
+
+ BTUSB_INFO("Extracted Codec VendorId=0x%08x VendorCodecId=0x%04x\n", vendor_id, vendor_codec_id);
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_sbc_start
+**
+** Description Start AV SBC Stream
+**
+** Returns Status
+**
+*******************************************************************************/
+static int btusb_lite_av_sbc_start(struct btusb *p_dev, UINT8 scb_idx,
+ tBTA_AV_AUDIO_CODEC_INFO*p_codec_cfg)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_encoder_ccb *p_encoder;
+ struct btusb_lite_av_scb *p_av_scb;
+ int nb_sbc_frames;
+ int rv;
+ int bitpool;
+ struct btusb_lite_av_sbc_param sbc_param;
+ int av_header_len;
+
+ /* Parse SBC Codec Info */
+ if (btusb_lite_av_parse_sbc_codec(&sbc_param, p_codec_cfg->codec_info) < 0)
+ {
+ BTUSB_ERR("Bad SBC Codec. Stream not started\n");
+ return -1;
+ }
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad scb_idx=%d", scb_idx);
+ return -1;
+ }
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ /* Calculate the BitPool for this BitRate */
+ bitpool = btusb_lite_sbc_get_bitpool(&sbc_param, p_codec_cfg->bit_rate);
+ if (bitpool <= 0)
+ {
+ BTUSB_ERR("btusb_lite_sbc_get_bitpool return wrong bitpool=%d\n", bitpool);
+ return -1;
+ }
+ BTUSB_INFO("SBC BitPool=%d\n", bitpool);
+
+ p_av_cb->timestamp = 0; /* Reset TimeStamp */
+ p_av_cb->option = 0; /* No specific Option (RTP and Media Payload Header presents) */
+ p_av_cb->m_pt = AVDT_RTP_PAYLOAD_TYPE | A2D_MEDIA_CT_SBC;
+ p_av_cb->m_pt &= ~AVDT_MARKER_SET;
+
+ /* Calculate Packet Header Size (HCI, L2CAP, RTP and MediaPayloadHeader) */
+ p_av_cb->header_len = BTUSB_LITE_HCI_ACL_HDR_SIZE +
+ BTUSB_LITE_L2CAP_HDR_SIZE +
+ BTUSB_LITE_RTP_SIZE +
+ BTUSB_LITE_SCMS_SIZE +
+ BTUSB_LITE_MEDIA_SIZE;
+ /* Calculate AV Header Size */
+ av_header_len = BTUSB_LITE_L2CAP_HDR_SIZE +
+ BTUSB_LITE_RTP_SIZE +
+ BTUSB_LITE_SCMS_SIZE +
+ BTUSB_LITE_MEDIA_SIZE;
+
+ /* clear the congestion flag: full stack made it congested when opening */
+ p_av_scb->cong = FALSE;
+ p_av_scb->started = TRUE;
+
+ /* Get reference to AV's encoder */
+ p_encoder = &p_av_cb->encoder;
+
+ if (p_encoder->opened == 0)
+ {
+ /* Allocate an SBC Channel */
+ rv = btsbc_alloc();
+ if (rv < 0)
+ {
+ BTUSB_ERR("btsbc_alloc failed\n");
+ return -1;
+ }
+ p_encoder->opened = 1;
+ p_encoder->channel = rv;
+ p_encoder->type = A2D_MEDIA_CT_SBC;
+ }
+
+ /* Configure the SBC Channel */
+ rv = btsbc_config(p_encoder->channel,
+ sbc_param.frequency,
+ sbc_param.nb_blocks,
+ sbc_param.nb_subbands,
+ sbc_param.mode,
+ sbc_param.allocation,
+ (unsigned char)bitpool);
+ if (rv <= 0)
+ {
+ BTUSB_ERR("btsbc_config failed\n");
+ btsbc_free(p_encoder->channel);
+ p_encoder->opened = 0;
+ return -1;
+ }
+
+ /* Save the calculated SBC Frame size */
+ p_encoder->encoded_frame_size = rv;
+ BTUSB_INFO("encoded_frame_size=%d\n", rv);
+
+ /* Configure the PCM Channel */
+ rv = btpcm_config(p_dev->lite_cb.p_btpcm,
+ p_dev,
+ sbc_param.frequency,
+ sbc_param.mode==CODEC_MODE_MONO?1:2,
+ 16, /* SBC Encoder requires 16 bits per sample */
+ btusb_lite_av_pcm_cback);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_config failed\n");
+ return -1;
+ }
+
+
+ /* Calculate and save the PCM frame size */
+ p_encoder->pcm_frame_size = sbc_param.nb_blocks * sbc_param.nb_subbands;
+ BTUSB_INFO("pcm_frame_size=%d\n", p_encoder->pcm_frame_size);
+
+#if 0
+ /* Calculate nb_sbc_frames depending on MTU */
+ nb_sbc_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_frame_size;
+#else
+ nb_sbc_frames = 10;
+ if(p_av_cb->stack_mtu < (p_encoder->encoded_frame_size * nb_sbc_frames + av_header_len))
+ { /* if 10 SBC frame is bigger than mtu size, should change nb_sbc_frames value to fit in mtu */
+ nb_sbc_frames = (p_av_cb->stack_mtu - av_header_len) / p_encoder->encoded_frame_size;
+ p_av_cb->curr_mtu = p_av_cb->stack_mtu;
+ }
+ else
+ {
+ p_av_cb->curr_mtu = p_encoder->encoded_frame_size * nb_sbc_frames + av_header_len;
+ }
+#endif
+ BTUSB_INFO("mtu:%d, nb_sbc_frames:%d, encoded_frame_size%d\n",
+ p_av_cb->curr_mtu, nb_sbc_frames, p_encoder->pcm_frame_size);
+
+ /* Calculate the size of the Payload */
+ p_av_cb->payload_len = nb_sbc_frames * p_encoder->encoded_frame_size;
+
+ BTUSB_INFO("nb_sbc_frames=%d payload_len=%d\n", nb_sbc_frames, p_av_cb->payload_len);
+
+ /* Start the PCM stream */
+ rv = btpcm_start(p_dev->lite_cb.p_btpcm, p_encoder->pcm_frame_size, nb_sbc_frames, 0);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_start failed\n");
+ return -1;
+ }
+ p_av_cb->pcm.state = PCM_STARTED;
+ return 0;
+}
+
+
+#ifdef BTUSB_LITE_SEC
+/*******************************************************************************
+**
+** Function btusb_lite_av_parse_vendor_codec
+**
+** Description Parse Vendor Id and Vendor Codec Id from Codec information
+**
+** Returns Status, VendorId and VendorCodecId
+**
+*******************************************************************************/
+static int btusb_lite_av_parse_sec_codec(struct btusb_lite_av_sec_param *p_sec_param,
+ UINT8 *p_codec_info)
+{
+ UINT8 byte;
+ UINT32 vendor_id;
+ UINT16 vendor_codec_id;
+
+ if (!p_codec_info || !p_sec_param)
+ {
+ BTUSB_ERR("Bad parameter\n");
+ return -1;
+ }
+
+ /* Extract/Ignore parameters already checked */
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract LOSC */
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract Media Type */
+ STREAM_TO_UINT8(byte, p_codec_info); /* Extract Media Codec Type */
+ STREAM_TO_UINT32(vendor_id, p_codec_info); /* Extract Vendor Id */
+ STREAM_TO_UINT16(vendor_codec_id, p_codec_info); /* Extract Vendor Codec Id */
+
+ STREAM_TO_UINT8(byte, p_codec_info); /* SEC codec configuration */
+
+ /* Check Frequency */
+ switch(byte & BTSEC_FREQ_MASK)
+ {
+ case BTSEC_FREQ_48K:
+ p_sec_param->frequency = 48000;
+ break;
+ case BTSEC_FREQ_44K:
+ p_sec_param->frequency = 44100;
+ break;
+ case BTSEC_FREQ_32K:
+ p_sec_param->frequency = 32000;
+ break;
+ default:
+ BTUSB_ERR("SEC Frequency=0x%x unsupported\n", byte & BTSEC_FREQ_MASK);
+ return -1;
+ }
+
+ /* Check Mode */
+ switch(byte & BTSEC_MODE_MASK)
+ {
+ case BTSEC_MODE_MONO:
+ p_sec_param->mode = BTSEC_MODE_MONO;
+ break;
+ case BTSEC_MODE_STEREO:
+ p_sec_param->mode = BTSEC_MODE_STEREO;
+ break;
+ default:
+ BTUSB_ERR("SEC Mode=0x%x unsupported\n", byte & BTSEC_FREQ_MASK);
+ return -1;
+ }
+
+ BTUSB_INFO("SEC Frequency=%d Mode=%s\n", p_sec_param->frequency,
+ p_sec_param->mode == BTSEC_MODE_MONO?"Mono":"Stereo");
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_sec_start
+**
+** Description Start AV SBC Stream
+**
+** Returns Status
+**
+*******************************************************************************/
+static int btusb_lite_av_sec_start(struct btusb *p_dev, UINT8 scb_idx,
+ tBTA_AV_AUDIO_CODEC_INFO*p_codec_cfg)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_encoder_ccb *p_encoder;
+ struct btusb_lite_av_scb *p_av_scb;
+ int nb_sec_frames;
+ int rv;
+ struct btusb_lite_av_sec_param sec_param;
+ int av_header_len;
+
+ /* Parse SBC Codec Info */
+ if (btusb_lite_av_parse_sec_codec(&sec_param, p_codec_cfg->codec_info) < 0)
+ {
+ BTUSB_ERR("Bad SEC Codec parameters. Stream not started\n");
+ return -1;
+ }
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad scb_idx=%d", scb_idx);
+ return -1;
+ }
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ BTUSB_INFO("SEC Bitrate =%d\n", p_codec_cfg->bit_rate);
+
+ p_av_cb->timestamp = 0; /* Reset TimeStamp */
+ p_av_cb->option = BTUSB_LITE_AVDT_OPT_NO_MPH; /* No Media Payload Header */
+ p_av_cb->m_pt = AVDT_RTP_PAYLOAD_TYPE | A2D_MEDIA_CT_VEND;
+ p_av_cb->m_pt &= ~AVDT_MARKER_SET;
+
+ /* Calculate Packet Header Size (HCI, L2CAP, RTP) */
+ p_av_cb->header_len = BTUSB_LITE_HCI_ACL_HDR_SIZE +
+ BTUSB_LITE_L2CAP_HDR_SIZE +
+ BTUSB_LITE_RTP_SIZE;
+ /* Calculate AV Header Size */
+ av_header_len = BTUSB_LITE_L2CAP_HDR_SIZE +
+ BTUSB_LITE_RTP_SIZE;
+
+ /* Clear the congestion flag: full stack made it congested when opening */
+ p_av_scb->cong = FALSE;
+ p_av_scb->started = TRUE;
+
+ /* Get reference to AV's encoder */
+ p_encoder = &p_av_cb->encoder;
+
+ if (p_encoder->opened == 0)
+ {
+ /* Allocate a SEC Channel */
+ rv = btsec_alloc();
+ if (rv < 0)
+ {
+ BTUSB_ERR("btsec_alloc failed\n");
+ return -1;
+ }
+ p_encoder->opened = 1;
+ p_encoder->channel = rv;
+ p_encoder->type = A2D_MEDIA_CT_SEC;
+
+ }
+
+ /* Configure the SEC Channel */
+ rv = btsec_config(p_encoder->channel,
+ sec_param.frequency,
+ sec_param.mode,
+ p_codec_cfg->bit_rate * 1000);
+ if (rv <= 0)
+ {
+ BTUSB_ERR("btsec_config failed\n");
+ btsec_free(p_encoder->channel);
+ p_encoder->opened = 0;
+ return -1;
+ }
+
+ /* Save the calculated SEC Frame size */
+ p_encoder->encoded_frame_size = rv;
+ BTUSB_INFO("encoded_frame_size=%d\n", rv);
+
+ /* Configure the PCM Channel */
+ rv = btpcm_config(p_dev->lite_cb.p_btpcm,
+ p_dev,
+ sec_param.frequency,
+ sec_param.mode==BTSEC_MODE_MONO?1:2,
+ 16, /* SBC Encoder requires 16 bits per sample */
+ btusb_lite_av_pcm_cback);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_config failed\n");
+ btsec_free(p_encoder->channel);
+ p_encoder->opened = 0;
+ return -1;
+ }
+
+ /* SEC requires a fixed number of PCM Samples */
+ p_encoder->pcm_frame_size = BTSEC_FRAME_SIZE;
+ BTUSB_INFO("pcm_frame_size=%d\n", p_encoder->pcm_frame_size);
+
+
+
+#if 0
+ /* Calculate nb_sec_frames depending on MTU */
+ nb_sec_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_frame_size;
+#else
+ nb_sec_frames = 10;
+ if(p_av_cb->stack_mtu < (p_encoder->encoded_frame_size * nb_sec_frames + av_header_len))
+ { /* if 10 SEC frames is bigger than mtu value, should use mtu */
+ nb_sec_frames = (p_av_cb->stack_mtu - av_header_len) / p_encoder->encoded_frame_size;
+ p_av_cb->curr_mtu = p_av_cb->stack_mtu;
+ }
+ else
+ {
+ p_av_cb->curr_mtu = p_encoder->encoded_frame_size * nb_sec_frames + av_header_len;
+ }
+#endif
+
+ /* Calculate the size of the Payload */
+ p_av_cb->payload_len = nb_sec_frames * p_encoder->encoded_frame_size;
+
+ BTUSB_INFO("nb_sec_frames=%d payload_len=%d\n", nb_sec_frames, p_av_cb->payload_len);
+
+ /* Start the PCM stream */
+ rv = btpcm_start(p_dev->lite_cb.p_btpcm,
+ p_encoder->pcm_frame_size, nb_sec_frames, 0);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_start failed\n");
+ btsec_free(p_encoder->channel);
+ p_encoder->opened = 0;
+ return -1;
+ }
+ p_av_cb->pcm.state = BTPCM_LITE_PCM_STARTED;
+ return 0;
+}
+#endif
+
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_stop
+**
+** Description Start AV
+**
+** Returns None.
+**
+*******************************************************************************/
+void btusb_lite_av_stop(struct btusb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_av_scb *p_av_scb;
+ int rv;
+
+ BTUSB_INFO("scb_idx=%d audio_open_cnt=%d\n", scb_idx, audio_open_cnt);
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad scb_idx=%d", scb_idx);
+ return;
+ }
+
+ p_av_cb->audio_open_cnt = audio_open_cnt;
+
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ p_av_cb->scb[scb_idx].started = FALSE;
+
+ if (p_av_cb->pcm.state != PCM_STARTED)
+ {
+ BTUSB_ERR("BTPCM was not started\n");
+ return;
+ }
+
+ /* Stop the PCM stream */
+ rv = btpcm_stop(p_dev->lite_cb.p_btpcm);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_stop failed\n");
+ return;
+ }
+ p_av_cb->pcm.state = PCM_CONFIGURED;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_suspend
+**
+** Description Suspend AV
+**
+** Returns none.
+**
+*******************************************************************************/
+void btusb_lite_av_suspend(struct btusb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt)
+{
+ struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.s.av;
+ struct btusb_lite_av_scb *p_av_scb;
+ int rv;
+
+ BTUSB_INFO("scb_idx=%d audio_open_cnt=%d\n", scb_idx, audio_open_cnt);
+
+ if (scb_idx >= BTA_AV_NUM_STRS)
+ {
+ BTUSB_ERR("Bad scb_idx=%d", scb_idx);
+ return;
+ }
+
+ p_av_cb->audio_open_cnt = audio_open_cnt;
+
+ p_av_scb = &p_av_cb->scb[scb_idx];
+
+ p_av_cb->scb[scb_idx].started = FALSE;
+
+ if (p_av_cb->pcm.state != PCM_STARTED)
+ {
+ BTUSB_ERR("BTPCM was not started\n");
+ return;
+ }
+
+ /* Stop the PCM stream */
+ rv = btpcm_stop(p_dev->lite_cb.p_btpcm);
+ if (rv < 0)
+ {
+ BTUSB_ERR("btpcm_stop failed\n");
+ return;
+ }
+ p_av_cb->pcm.state = PCM_CONFIGURED;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_av_parse_sbc_codec
+**
+** Description Parse an SBC A2DP Codec
+**
+** Returns Status
+**
+*******************************************************************************/
+static int btusb_lite_av_parse_sbc_codec(struct btusb_lite_av_sbc_param *p_sbc, UINT8 *p_codec)
+{
+ UINT8 byte;
+ unsigned char codec_freq;
+ unsigned char codec_blocks;
+ unsigned char codec_subbands;
+ unsigned char codec_mode;
+ unsigned char codec_alloc;
+ unsigned char bitpool_min;
+ unsigned char bitpool_max;
+
+ if (p_sbc == NULL)
+ {
+ BTUSB_ERR("p_sbc is NULL\n");
+ return -1;
+ }
+
+ /* Extract LOSC */
+ byte = *p_codec++;
+ if (byte != CODEC_SBC_LOSC)
+ {
+ BTUSB_ERR("Bad SBC LOSC=%d", byte);
+ return -1;
+ }
+
+ p_codec++; /* Ignore MT */
+
+ /* Extract Codec Type */
+ byte = *p_codec++;
+ if (byte != A2D_MEDIA_CT_SBC)
+ {
+ BTUSB_ERR("Bad SBC codec type=%d", byte);
+ return -1;
+ }
+
+ /* Extract Freq & Mode */
+ byte = *p_codec++;
+ codec_freq = byte & CODEC_SBC_FREQ_MASK;
+ codec_mode = byte & CODEC_MODE_MASK;
+
+ /* Extract NbBlock NbSubBand and Alloc Method */
+ byte = *p_codec++;
+ codec_blocks = byte & CODEC_SBC_BLOCK_MASK;
+ codec_subbands = byte & CODEC_SBC_NBBAND_MASK;
+ codec_alloc = byte & CODEC_SBC_ALLOC_MASK;
+
+ bitpool_min = *p_codec++;
+ bitpool_max = *p_codec++;
+
+ switch(codec_freq)
+ {
+ case CODEC_SBC_FREQ_48:
+ BTUSB_INFO("SBC Freq=48K\n");
+ p_sbc->frequency = 48000;
+ break;
+ case CODEC_SBC_FREQ_44:
+ BTUSB_INFO("SBC Freq=44.1K\n");
+ p_sbc->frequency = 44100;
+ break;
+ case CODEC_SBC_FREQ_32:
+ BTUSB_INFO("SBC Freq=32K\n");
+ p_sbc->frequency = 32000;
+ break;
+ case CODEC_SBC_FREQ_16:
+ BTUSB_INFO("SBC Freq=16K\n");
+ p_sbc->frequency = 16000;
+ break;
+ default:
+ BTUSB_INFO("Bad SBC Freq=%d\n", codec_freq);
+ return -1;
+ }
+
+ switch(codec_mode)
+ {
+ case CODEC_MODE_JOIN_STEREO:
+ BTUSB_INFO("SBC Join Stereo\n");
+ p_sbc->mode = CODEC_MODE_JOIN_STEREO;
+ break;
+ case CODEC_MODE_STEREO:
+ BTUSB_INFO("SBC Stereo\n");
+ p_sbc->mode = CODEC_MODE_STEREO;
+ break;
+ case CODEC_MODE_DUAL:
+ BTUSB_INFO("SBC Dual\n");
+ p_sbc->mode = CODEC_MODE_DUAL;
+ break;
+ case CODEC_MODE_MONO:
+ BTUSB_INFO("SBC Mono\n");
+ p_sbc->mode = CODEC_MODE_MONO;
+ break;
+ default:
+ BTUSB_INFO("Bad SBC mode=%d\n", codec_mode);
+ return -1;
+ }
+
+ switch(codec_blocks)
+ {
+ case CODEC_SBC_BLOCK_16:
+ BTUSB_INFO("SBC Block=16\n");
+ p_sbc->nb_blocks = 16;
+ break;
+ case CODEC_SBC_BLOCK_12:
+ BTUSB_INFO("SBC Block=12\n");
+ p_sbc->nb_blocks = 12;
+ break;
+ case CODEC_SBC_BLOCK_8:
+ BTUSB_INFO("SBC Block=8\n");
+ p_sbc->nb_blocks = 8;
+ break;
+ case CODEC_SBC_BLOCK_4:
+ BTUSB_INFO("SBC Block=4\n");
+ p_sbc->nb_blocks = 4;
+ break;
+ default:
+ BTUSB_INFO("Bad SBC Block=%d\n", codec_blocks);
+ return -1;
+ }
+
+ switch(codec_subbands)
+ {
+ case CODEC_SBC_NBBAND_8:
+ BTUSB_INFO("SBC NbSubBand=8\n");
+ p_sbc->nb_subbands = 8;
+ break;
+ case CODEC_SBC_NBBAND_4:
+ BTUSB_INFO("SBC NbSubBand=4\n");
+ p_sbc->nb_subbands = 4;
+ break;
+ default:
+ BTUSB_INFO("Bad SBC NbSubBand=%d\n", codec_blocks);
+ return -1;
+ }
+
+ switch(codec_alloc)
+ {
+ case CODEC_SBC_ALLOC_LOUDNESS:
+ BTUSB_INFO("SBC Loudness\n");
+ p_sbc->allocation = CODEC_SBC_ALLOC_LOUDNESS;
+ break;
+ case CODEC_SBC_ALLOC_SNR:
+ BTUSB_INFO("SBC SNR\n");
+ p_sbc->allocation = CODEC_SBC_ALLOC_SNR;
+ break;
+ default:
+ BTUSB_INFO("Bad SBC AllocMethod=%d\n", codec_blocks);
+ return -1;
+ }
+
+ BTUSB_INFO("BitpoolMin=%d BitpoolMax=%d\n", bitpool_min, bitpool_max);
+
+ p_sbc->bitpool_min = bitpool_min;
+ p_sbc->bitpool_max = bitpool_max;
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_sbc_get_bitpool
+ **
+ ** Description Calculate the BitPool for a specified BitRate (and other parameters)
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static int btusb_lite_sbc_get_bitpool(struct btusb_lite_av_sbc_param *p_sbc_param, int target_bitrate)
+{
+ int nb_channels;
+ int frame_length;
+ int bitpool = p_sbc_param->bitpool_max + 1;
+ int bitrate;
+
+ /* Required number of channels */
+ if (p_sbc_param->mode == CODEC_MODE_MONO)
+ nb_channels = 1;
+ else
+ nb_channels = 2;
+
+ target_bitrate *= 1000; /* Bitrate from app is in Kbps */
+
+ do
+ {
+ bitpool--; /* Reduce Bit Pool by one */
+
+ /* Calculate common SBC Frame length */
+ frame_length = 4 + (4 * p_sbc_param->nb_subbands * nb_channels) / 8;
+
+ /* Add specific SBC Frame length (depending on mode) */
+ switch(p_sbc_param->mode)
+ {
+ case CODEC_MODE_MONO:
+ case CODEC_MODE_DUAL:
+ frame_length += (p_sbc_param->nb_blocks * nb_channels * bitpool) / 8;
+ break;
+ case CODEC_MODE_JOIN_STEREO:
+ frame_length += (p_sbc_param->nb_subbands + p_sbc_param->nb_blocks * bitpool) / 8;
+ break;
+ case CODEC_MODE_STEREO:
+ frame_length += (p_sbc_param->nb_blocks * bitpool) / 8;
+ break;
+ }
+
+ /* Calculate bit rate */
+ bitrate = 8 * frame_length * p_sbc_param->frequency / p_sbc_param->nb_subbands / p_sbc_param->nb_blocks;
+
+ } while (bitrate > target_bitrate); /* While bitrate is too big */
+
+ BTUSB_INFO("final bitpool=%d frame_length=%d bitrate=%d\n", bitpool, frame_length, bitrate);
+
+ return (int)bitpool;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_av_pcm_cback
+ **
+ ** Description BTUSB Lte AV PCM Callback function.
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static void btusb_lite_av_pcm_cback(void *p_opaque, void *p_data, int nb_pcm_frames)
+{
+ struct btusb *p_dev = p_opaque;
+ struct btusb_lite_av_cb *p_av_cb;
+ int pcm_frame_size_byte;
+ void *p_dest;
+ int written_enc_size;
+ struct btusb_lite_encoder_ccb *p_encoder;
+
+ if (!p_dev)
+ {
+ BTUSB_ERR("Null p_dev\n");
+ return;
+ }
+
+ if (!p_data)
+ {
+ BTUSB_ERR("Null p_data\n");
+ return;
+ }
+
+ /* Get Reference on the SBC Stream (which is the same than the Encoder channel) */
+ p_av_cb = &p_dev->lite_cb.s.av;
+
+ if (p_av_cb->pcm.state != PCM_STARTED)
+ {
+ BTUSB_ERR("BTPCM is not started\n");
+ btpcm_stop(p_dev->lite_cb.p_btpcm);
+ return;
+ }
+
+ /* Get reference to AV's encoder */
+ p_encoder = &p_av_cb->encoder;
+
+ /* Calculate the size (in byte) of an Input PCM buffer (holding one encoded frame) */
+ pcm_frame_size_byte = p_av_cb->encoder.pcm_frame_size;
+ pcm_frame_size_byte *= 2; /* Stereo */
+ pcm_frame_size_byte *= 2; /* 16 bits per sample */
+
+ /* Sanity Check */
+ if (pcm_frame_size_byte == 0)
+ {
+ BTUSB_ERR("Bad PCM Frame size=%d\n", pcm_frame_size_byte);
+ return;
+ }
+
+ /*
+ * No PCM data in a timer period.
+ * Need to send AV data in a working buffer if it exists
+ */
+ if (nb_pcm_frames == 0)
+ {
+ if (p_av_cb->p_buf_working)
+ {
+ if (p_av_cb->p_buf_working->len)
+ {
+ /* For AV channel, send the packet */
+ btusb_lite_av_send_packet((struct btusb *)p_dev, p_av_cb->p_buf_working);
+
+ /* A new working buffer must be allocated */
+ p_av_cb->p_buf_working = NULL;
+ }
+ }
+ return;
+ }
+
+ /* While received buffer is not empty */
+ while (nb_pcm_frames)
+ {
+ /* Check if there are enough remaining frames in the buffer */
+ if ((nb_pcm_frames * 2 * 2) < pcm_frame_size_byte)
+ {
+ BTUSB_ERR("Bad nb_pcm_frames=%d\n", nb_pcm_frames);
+ return;
+ }
+
+ /* If no working buffer allocated */
+ if (!p_av_cb->p_buf_working)
+ {
+ /* Get a buffer from the pool */
+ p_av_cb->p_buf_working = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + p_av_cb->header_len + p_av_cb->payload_len);
+ if(unlikely(p_av_cb->p_buf_working == NULL))
+ {
+ BTUSB_ERR("Unable to get GKI buffer - sent fail\n");
+ return;
+ }
+
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_av_cb->p_buf_working) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_av_cb->p_buf_working);
+ return;
+ }
+
+ /* Skip headers */
+ p_av_cb->p_buf_working->offset = p_av_cb->header_len;
+ p_av_cb->p_buf_working->len = 0;
+ p_av_cb->p_buf_working->layer_specific = 0; /* Used to store the number of Encoded Frames */
+ }
+
+ /* Fill the ACL Packet with SBC Frames */
+ do
+ {
+ /* Get Write address */
+ p_dest = (UINT8 *)(p_av_cb->p_buf_working + 1) + p_av_cb->p_buf_working->offset +
+ p_av_cb->p_buf_working->len;
+
+ if (p_encoder->type == A2D_MEDIA_CT_SBC)
+ {
+ /* Encode one PCM frame with SBC Encoder*/
+ btsbc_encode(p_encoder->channel,
+ /* If Mute => Zero filled PCM sample*/
+ /* Otherwise => regular PCM data */
+ pcm0_mute?btusb_lite_silence_pcm:p_data,
+ pcm_frame_size_byte,
+ p_dest, /* SBC Output buffer */
+ p_av_cb->encoder.encoded_frame_size, /* Expected Output SBC frame size */
+ &written_enc_size);
+ }
+#ifdef BTUSB_LITE_SEC
+ else if (p_encoder->type == A2D_MEDIA_CT_SEC)
+ {
+ /* Encode one PCM frame with SEC Encoder*/
+ written_enc_size = btsec_encode(p_av_cb->encoder.channel,
+ /* If Mute => Zero filled PCM sample*/
+ /* Otherwise => regular PCM data */
+ pcm0_mute?btusb_lite_silence_pcm:p_data,
+ pcm_frame_size_byte,
+ p_dest, /* SEC Output buffer */
+ p_encoder->encoded_frame_size);/* Expected Output SEC frame size */
+ }
+#endif
+ else
+ {
+ BTUSB_ERR("Bad Encoding TYPE:%d)\n", p_encoder->type);
+ }
+
+ if (written_enc_size != p_av_cb->encoder.encoded_frame_size)
+ {
+ BTUSB_ERR("Bad Encoded Frame length=%d (expected=%d)\n",
+ written_enc_size, p_av_cb->encoder.encoded_frame_size);
+ }
+
+ /* Update Encoded packet length */
+ p_av_cb->p_buf_working->len += (UINT16)p_av_cb->encoder.encoded_frame_size;
+
+ /* One more Encoded Frame */
+ p_av_cb->p_buf_working->layer_specific++;
+
+ p_data += pcm_frame_size_byte; /* Jump to the next PCM sample */
+ nb_pcm_frames -= pcm_frame_size_byte / 4; /* Update number of remaining samples */
+
+ } while (nb_pcm_frames &&
+ (p_av_cb->p_buf_working->layer_specific < A2D_SBC_HDR_NUM_MSK) &&
+ ((p_av_cb->p_buf_working->len + p_av_cb->encoder.encoded_frame_size) < p_av_cb->curr_mtu));
+
+ /* If no more room to store an encoded frame */
+ if (p_av_cb->encoder.encoded_frame_size > (p_av_cb->curr_mtu - p_av_cb->p_buf_working->len))
+ {
+ /* For AV channel, send the packet */
+ btusb_lite_av_send_packet((struct btusb *)p_dev, p_av_cb->p_buf_working);
+
+ /* A new working buffer must be allocated */
+ p_av_cb->p_buf_working = NULL;
+ }
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_av_send_packet
+ **
+ ** Description Send a new BAV packet to the controller
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static void btusb_lite_av_send_packet(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ struct btusb_lite_av_cb *p_av_cb;
+ struct btusb_lite_av_scb *p_av_scb;
+ int stream;
+ int nb_started_streams;
+ BT_HDR *p_msg_dup;
+
+ if (!p_dev || !p_msg)
+ {
+ BTUSB_ERR("Bad reference p_dev=%p p_msg=%p\n", p_dev, p_msg);
+ return;
+ }
+
+ /* Sanity */
+ if (p_msg->len == 0)
+ {
+ BTUSB_ERR("Length is 0=%d\n", p_msg->len);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+
+ /* Get Reference on the AV Streams */
+ p_av_cb = &p_dev->lite_cb.s.av;
+
+ /* Update TimeStamp */
+ p_av_cb->timestamp += p_msg->layer_specific * p_av_cb->encoder.pcm_frame_size;
+
+ nb_started_streams = 0;
+ /* Count how many AV stream are started */
+ for (stream = 0, p_av_scb = p_av_cb->scb ; stream < BTA_AV_NUM_STRS ; stream++, p_av_scb++)
+ {
+ if (p_av_scb->started)
+ {
+ nb_started_streams++; /* One more started stream */
+ }
+ }
+
+ if (nb_started_streams == 0)
+ {
+ BTUSB_ERR("No Started AV stream found\n");
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+ else if (nb_started_streams == 1)
+ {
+ p_msg_dup = NULL;
+ }
+ else
+ {
+ /*
+ * Duplicate the AV packet
+ */
+ /* Get a buffer from the pool */
+ p_msg_dup = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + p_msg->offset + p_msg->offset);
+ if(p_msg_dup)
+ {
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg_dup) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg_dup);
+ p_msg_dup = NULL; /* Do not use this buffer */
+ }
+ if(p_msg_dup)
+ {
+ /* Duplicate all the data (Header, and payload */
+ memcpy(p_msg_dup, p_msg, sizeof(BT_HDR) + p_msg->offset + p_msg->offset);
+ }
+ }
+ if (nb_started_streams > 2)
+ {
+ BTUSB_ERR("nb_started_streams=%d force it to 2\n", nb_started_streams);
+ nb_started_streams = 2;
+ }
+ }
+
+ /* For every AV stream Started */
+ for (stream = 0, p_av_scb = p_av_cb->scb ; stream < BTA_AV_NUM_STRS ; stream++, p_av_scb++)
+ {
+ if (p_av_scb->started)
+ {
+ if (p_msg)
+ {
+ /* Send the original packet to AVDT */
+ btusb_lite_avdt_send(p_dev, p_msg, p_av_scb->avdt_handle,
+ p_av_cb->m_pt, p_av_cb->option, p_av_cb->timestamp);
+ p_msg = NULL;
+ }
+ else if (p_msg_dup)
+ {
+ /* Send the duplicated packet to AVDT */
+ btusb_lite_avdt_send(p_dev, p_msg_dup, p_av_scb->avdt_handle,
+ p_av_cb->m_pt, p_av_cb->option, p_av_cb->timestamp);
+ p_msg_dup = NULL;
+ }
+ else
+ {
+ BTUSB_ERR("No AV data to send for AV stream=%d \n", stream);
+ }
+ }
+ }
+}
+
diff --git a/src/btusb_lite_avdt.c b/src/btusb_lite_avdt.c
new file mode 100755
index 0000000..d1db2b7
--- a/dev/null
+++ b/src/btusb_lite_avdt.c
@@ -0,0 +1,426 @@
+/*
+ *
+ * btusb_lite_avdt.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#include "btusb.h"
+#include "bd.h"
+
+/*
+ * Definitions
+ */
+#define AVDT_MULTIPLEXING FALSE
+
+
+/*
+ * Local functions
+ */
+static struct btusb_lite_avdt_scb *btusb_lite_avdt_allocate_scb(struct btusb *p_dev);
+static void btusb_lite_avdt_free_scb(struct btusb *p_dev, struct btusb_lite_avdt_scb *p_scb_free);
+static struct btusb_lite_avdt_ccb *btusb_lite_avdt_allocate_ccb(struct btusb *p_dev);
+static void btusb_lite_avdt_free_ccb(struct btusb *p_dev, struct btusb_lite_avdt_ccb *p_ccb_free);
+static UINT8 *btusb_lite_avdt_write_rtp_header(UINT8 *p_data, UINT8 m_pt, UINT16 seq_number, UINT32 timestamp, UINT32 ssrc);
+
+
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_scb_by_hdl
+**
+** Description Given an scb handle (or seid), return a pointer to the scb.
+**
+**
+** Returns Pointer to scb or NULL if index is out of range or scb
+** is not allocated.
+**
+*******************************************************************************/
+struct btusb_lite_avdt_scb *btusb_lite_avdt_scb_by_hdl(struct btusb *p_dev, UINT8 handle)
+{
+ struct btusb_lite_avdt_scb *p_scb;
+ UINT8 scb;
+
+ p_scb = &p_dev->lite_cb.s.avdt.scb[0];
+ for(scb = 0; scb < AVDT_NUM_SEPS; scb++, p_scb++ )
+ {
+ if((p_scb->allocated) &&
+ (p_scb->handle == handle))
+ return(p_scb);
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_init_scb
+**
+** Description allocate and initialize SCB/CCB with received sync info
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_init_scb(struct btusb *p_dev, tAVDT_SCB_SYNC_INFO *p_scb_info)
+{
+ struct btusb_lite_avdt_scb *p_scb;
+ struct btusb_lite_avdt_ccb *p_ccb;
+
+ if((p_scb = btusb_lite_avdt_allocate_scb(p_dev)) == NULL)
+ {
+ BTUSB_ERR("No SCB for handle %d\n", p_scb_info->handle);
+ return AVDT_SYNC_FAILURE;
+ }
+ else
+ {
+ if((p_ccb = btusb_lite_avdt_allocate_ccb(p_dev)) == NULL)
+ {
+ BTUSB_ERR("No CCB for handle %d\n", p_scb_info->handle);
+ p_scb->allocated = FALSE;
+ return AVDT_SYNC_FAILURE;
+ }
+ else
+ {
+ memcpy(p_ccb->peer_addr, p_scb_info->peer_addr, BD_ADDR_LEN);
+ p_ccb->lcid = p_scb_info->local_cid;
+ p_ccb->peer_mtu = p_scb_info->peer_mtu;
+#if AVDT_MULTIPLEXING == TRUE
+ GKI_init_q(&p_scb->frag_q);
+#endif
+ p_scb->handle = p_scb_info->handle;
+ p_scb->mux_tsid_media = p_scb_info->mux_tsid_media;
+ p_scb->media_seq = p_scb_info->media_seq;
+ p_scb->p_ccb = p_ccb;
+ BTUSB_INFO("Allocated SCB/CCB for handle %d\n", p_scb_info->handle);
+ }
+ }
+ return AVDT_SYNC_SUCCESS;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_remove_scb
+**
+** Description deallocate SCB and CCB
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_remove_scb(struct btusb *p_dev, UINT8 handle, tAVDT_SCB_SYNC_INFO *p_scb_info)
+{
+ struct btusb_lite_avdt_scb *p_scb;
+
+ if((p_scb = btusb_lite_avdt_scb_by_hdl(p_dev, handle)) == NULL)
+ {
+ BTUSB_ERR("No SCB for handle %d\n", handle);
+ return AVDT_SYNC_FAILURE;
+ }
+ else
+ {
+ if (p_scb_info)
+ {
+ p_scb_info->handle = p_scb->handle;
+ p_scb_info->media_seq = p_scb->media_seq;
+ }
+ /* Free CCB first */
+ btusb_lite_avdt_free_ccb(p_dev, p_scb->p_ccb);
+ /* Free SCB */
+ btusb_lite_avdt_free_scb(p_dev, p_scb);
+
+ return AVDT_SYNC_SUCCESS;
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_allocate_ccb
+**
+** Description allocate CCB in lite stack
+**
+** Returns pointer of CCB
+**
+*******************************************************************************/
+static struct btusb_lite_avdt_ccb *btusb_lite_avdt_allocate_ccb(struct btusb *p_dev)
+{
+ struct btusb_lite_avdt_ccb *p_ccb;
+ UINT8 ccb;
+
+ p_ccb = &p_dev->lite_cb.s.avdt.ccb[0];
+ for(ccb = 0; ccb < AVDT_NUM_LINKS; ccb++, p_ccb++)
+ {
+ if (!p_ccb->allocated)
+ {
+ BTUSB_INFO("CCB=%d allocated\n", ccb);
+ memset(p_ccb, 0, sizeof(struct btusb_lite_avdt_ccb));
+ p_ccb->allocated = TRUE;
+ return(p_ccb);
+ }
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_free_ccb
+**
+** Description Free CCB in lite stack
+**
+** Returns None
+**
+*******************************************************************************/
+static void btusb_lite_avdt_free_ccb(struct btusb *p_dev, struct btusb_lite_avdt_ccb *p_ccb_free)
+{
+ struct btusb_lite_avdt_ccb *p_ccb;
+ UINT8 ccb;
+
+ p_ccb = &p_dev->lite_cb.s.avdt.ccb[0];
+ for(ccb = 0; ccb < AVDT_NUM_LINKS; ccb++, p_ccb++)
+ {
+ if (p_ccb == p_ccb_free)
+ {
+ /* Sanity */
+ if (!p_ccb_free->allocated)
+ {
+ BTUSB_ERR("CCB=%d was not allocated\n", ccb);
+ }
+ BTUSB_INFO("CCB=%d freed\n", ccb);
+ p_ccb_free->allocated = FALSE;
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_allocate_scb
+**
+** Description allocate SCB in lite stack
+**
+** Returns pointer of SCB
+**
+*******************************************************************************/
+static struct btusb_lite_avdt_scb *btusb_lite_avdt_allocate_scb(struct btusb *p_dev)
+{
+ struct btusb_lite_avdt_scb *p_scb;
+ UINT8 scb;
+
+ p_scb = &p_dev->lite_cb.s.avdt.scb[0];
+ for(scb = 0; scb < AVDT_NUM_SEPS; scb++, p_scb++)
+ {
+ if(!p_scb->allocated)
+ {
+ BTUSB_INFO("SCB=%d allocated\n", scb);
+ memset(p_scb, 0, sizeof(struct btusb_lite_avdt_scb));
+ p_scb->allocated = TRUE;
+ return(p_scb);
+ }
+ }
+ return(NULL);
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_free_scb
+**
+** Description Free SCB in lite stack
+**
+** Returns None
+**
+*******************************************************************************/
+static void btusb_lite_avdt_free_scb(struct btusb *p_dev, struct btusb_lite_avdt_scb *p_scb_free)
+{
+ struct btusb_lite_avdt_scb *p_scb;
+ UINT8 scb;
+
+ p_scb = &p_dev->lite_cb.s.avdt.scb[0];
+ for(scb = 0; scb < AVDT_NUM_SEPS; scb++, p_scb++)
+ {
+ if (p_scb == p_scb_free)
+ {
+ /* Sanity */
+ if (!p_scb_free->allocated)
+ {
+ BTUSB_ERR("SCB=%d was not allocated\n", scb);
+ }
+ BTUSB_INFO("SCB=%d freed\n", scb);
+ p_scb_free->allocated = FALSE;
+ return;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_send
+**
+** Description AVDT packet send
+**
+** Returns None
+**
+*******************************************************************************/
+void btusb_lite_avdt_send(struct btusb *p_dev, BT_HDR *p_msg, UINT8 avdt_handle,
+ UINT8 m_pt, UINT8 option, UINT32 timestamp)
+{
+ UINT8 *p_data;
+ struct btusb_lite_avdt_scb *p_avdt_scb;
+ struct btusb_lite_avdt_ccb *p_avdt_ccb;
+
+ if (p_dev == NULL)
+ {
+ BTUSB_ERR("p_dev is NULL\n");
+ if (p_msg)
+ GKI_freebuf(p_msg);
+ return;
+ }
+
+ if (p_msg == NULL)
+ {
+ BTUSB_ERR("p_msg is NULL\n");
+ return;
+ }
+
+ /* Find the AVDT SCB with this handle */
+ p_avdt_scb = btusb_lite_avdt_scb_by_hdl(p_dev, avdt_handle);
+ if (p_avdt_scb == NULL)
+ {
+ BTUSB_ERR("No AVDT SCB stream found\n");
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+
+ /* Get the associated AVDT CCB */
+ p_avdt_ccb = p_avdt_scb->p_ccb;
+ if (p_avdt_ccb == NULL)
+ {
+ BTUSB_ERR("No AVDT CCB stream found\n");
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+
+ /* Write the Media Payload Header if needed */
+ if ((option & BTUSB_LITE_AVDT_OPT_NO_MPH) == 0)
+ {
+ if (p_msg->offset < BTUSB_LITE_MEDIA_SIZE)
+ {
+ BTUSB_ERR("Offset too small=%d for MediaPayloadHeader\n", p_msg->offset);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+ p_msg->offset -= BTUSB_LITE_MEDIA_SIZE;
+ p_msg->len += BTUSB_LITE_MEDIA_SIZE;
+ /* Get write address */
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ /* Write Media Payload Header (Number of SBC Frames) */
+ UINT8_TO_BE_STREAM(p_data, p_msg->layer_specific & A2D_SBC_HDR_NUM_MSK);
+ }
+
+ /* Write the SCMS content Protection Header if needed */
+ if (p_avdt_scb->scms.enable)
+ {
+ if (p_msg->offset < BTUSB_LITE_SCMS_SIZE)
+ {
+ BTUSB_ERR("Offset too small=%d for CP Header\n", p_msg->offset);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+ p_msg->offset -= BTUSB_LITE_SCMS_SIZE;
+ p_msg->len += BTUSB_LITE_SCMS_SIZE;
+ /* Get write address */
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ /* Write Media Payload Header (Number of SBC Frames) */
+ UINT8_TO_BE_STREAM(p_data, p_avdt_scb->scms.header);
+ }
+
+ /* Write the RTP Header if needed */
+ if ((option & BTUSB_LITE_AVDT_OPT_NO_RTP) == 0)
+ {
+ if (p_msg->offset < BTUSB_LITE_RTP_SIZE)
+ {
+ BTUSB_ERR("Offset too small=%d for RTP Header\n", p_msg->offset);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return;
+ }
+ p_msg->offset -= BTUSB_LITE_RTP_SIZE;
+ p_msg->len += BTUSB_LITE_RTP_SIZE;
+ /* Get write address */
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+ /* Write RTP Header */
+ p_data = btusb_lite_avdt_write_rtp_header(p_data, m_pt, p_avdt_scb->media_seq, timestamp, 0);
+ }
+
+ p_avdt_scb->media_seq++; /* Increment Sequence number */
+
+ /* Request L2CAP to send this packet */
+ btusb_lite_l2c_send(p_dev, p_msg, p_avdt_ccb->lcid);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_avdt_write_rtp_header
+ **
+ ** Description Write A2DP RTP Header
+ **
+ ** Returns New buffer location
+ **
+ *******************************************************************************/
+static UINT8 *btusb_lite_avdt_write_rtp_header(UINT8 *p_data, UINT8 m_pt, UINT16 seq_number,
+ UINT32 timestamp, UINT32 ssrc)
+{
+ /* Write RTP Header */
+ UINT8_TO_BE_STREAM(p_data, AVDT_MEDIA_OCTET1); /* Version, Padding, Ext, CSRC */
+ UINT8_TO_BE_STREAM(p_data, m_pt); /* Marker & Packet Type */
+ UINT16_TO_BE_STREAM(p_data, seq_number); /* Sequence number */
+ UINT32_TO_BE_STREAM(p_data, timestamp); /* TimeStamp */
+ UINT32_TO_BE_STREAM(p_data, ssrc); /* SSRC */
+ return p_data;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_avdt_cp_set_scms
+**
+** Description Set SCMS Content Protection for a channel
+**
+** Returns AVDT_SYNC_SUCCESS/AVDT_SYNC_FAILURE
+**
+*******************************************************************************/
+UINT8 btusb_lite_avdt_cp_set_scms(struct btusb *p_dev, UINT8 avdt_handle,
+ BOOLEAN enable, UINT8 scms_hdr)
+{
+ struct btusb_lite_avdt_scb *p_avdt_scb;
+
+ /* Find the AVDT SCB with this handle */
+ p_avdt_scb = btusb_lite_avdt_scb_by_hdl(p_dev, avdt_handle);
+ if (p_avdt_scb == NULL)
+ {
+ BTUSB_ERR("No AVDT SCB stream found\n");
+ return AVDT_SYNC_FAILURE;
+ }
+
+ BTUSB_INFO("btusb_lite_avdt_cp_set_scms handle=0x%x enable=%d header=0x%x\n",
+ avdt_handle, enable, scms_hdr);
+
+ p_avdt_scb->scms.enable = enable;
+ p_avdt_scb->scms.header = scms_hdr;
+
+ return AVDT_SYNC_SUCCESS;
+
+}
diff --git a/src/btusb_lite_hci.c b/src/btusb_lite_hci.c
new file mode 100755
index 0000000..321174a
--- a/dev/null
+++ b/src/btusb_lite_hci.c
@@ -0,0 +1,440 @@
+/*
+ *
+ * btusb_lite_hci.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#include "btusb.h"
+
+/*
+ * Definitions
+ */
+#define BTUSB_LITE_HCI_NUM_CMD 0x01 /* HCI Num Command */
+
+/* HCI Definitions for the NumberOfCompletePacket Event */
+#define BTUSB_LITE_HCI_NOCP_HCI_LEN 7 /* HCI Length of the NumOfCpltPacket Event */
+#define BTUSB_A2DP_NOCP_LEN 5 /* Length of the NumOfCpltPacket Param */
+
+/*
+ * Local functions
+ */
+static UINT8 *btusb_lite_hci_write_acl_header(UINT8 *p_data, UINT16 con_hdl, UINT16 length);
+static UINT8 *btusb_lite_hci_write_evt_header(UINT8 *p_data, UINT8 event, UINT8 length);
+
+static int btusb_lite_hci_transport_pause_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static int btusb_lite_hci_transport_resume_hndl(struct btusb *p_dev, BT_HDR *p_msg);
+static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb *p_dev,
+ UINT16 opcode, UINT8 *p_param, UINT8 param_len);
+static int btusb_lite_hci_nocp_event_hdlr(struct btusb *p_dev, UINT8 *p_data, int length);
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_acl_send
+ **
+ ** Description Send an ACL packet to HCI
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+int btusb_lite_hci_acl_send(struct btusb *p_dev, BT_HDR *p_msg, UINT16 con_hdl)
+{
+ UINT8 *p_data;
+
+ /* Sanity */
+ if (p_msg->offset < BTUSB_LITE_HCI_ACL_HDR_SIZE)
+ {
+ BTUSB_ERR("offset too small=%d\n", p_msg->offset);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return -1;
+ }
+
+ /* Decrement offset to add headers */
+ p_msg->offset -= BTUSB_LITE_HCI_ACL_HDR_SIZE;
+
+ /* Get address of the HCI Header */
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ /* Write L2CAP Header (length field is SBC Frames + RTP/A2DP/Media Header) */
+ p_data = btusb_lite_hci_write_acl_header(p_data, con_hdl, p_msg->len);
+
+ /* Increment length */
+ p_msg->len += BTUSB_LITE_HCI_ACL_HDR_SIZE;
+
+ /* Add this ACL data in the USB Tx queue and notify the btusb_tx_task to process */
+ GKI_enqueue(&p_dev->tx_queue, p_msg);
+
+ /* Wake up tasklet (with High priority) */
+ tasklet_schedule(&p_dev->tx_task);
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_cmd_filter
+ **
+ ** Description Check if the Sent HCI Command need to be handled/caught (not
+ ** sent to BT controller).
+ **
+ ** Returns status: <> 0 if the command must be send to BT controller
+ ** 0 if the command is handled
+ **
+ *******************************************************************************/
+int btusb_lite_hci_cmd_filter(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 *p;
+ UINT8 hci_type;
+ UINT16 opcode;
+ int rv = 1; /* HCI command not handled by default */
+
+ p = (UINT8 *)(p_msg + 1);
+
+ STREAM_TO_UINT8(hci_type, p); /* Extract HCI Type */
+
+ if (hci_type != HCIT_TYPE_COMMAND)
+ {
+ /* This is not an HCI Command */
+ return rv; /* Send it to BT Controller */
+ }
+
+ STREAM_TO_UINT16(opcode, p); /* Extract HCI Command OpCode */
+
+ switch(opcode)
+ {
+ case HCI_BRCM_PAUSE_TRANSPORT:
+ rv = btusb_lite_hci_transport_pause_hndl(p_dev, p_msg);
+ break;
+
+ case HCI_BRCM_TRANSPORT_RESUME:
+ /* Call the function in charge of filtering UIPC Over HCI VSC */
+ rv = btusb_lite_hci_transport_resume_hndl(p_dev, p_msg);
+ break;
+
+ /* Add here other HCI Command OpCodes to filter */
+ default:
+ break;
+ /* Do not filter other HCI Command OpCodes */
+ }
+ return rv;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_transport_pause_hndl
+ **
+ ** Description Handles the HCI Transport Pause VSC.
+ **
+ ** Returns status: <> 0 if the command must be send to BT controller
+ ** 0 if the command is handled
+ **
+ *******************************************************************************/
+static int btusb_lite_hci_transport_pause_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 param[sizeof(UINT8)];
+ UINT8 *p_param = param;
+
+ BTUSB_INFO("HCI_TransportPause VSC caught\n");
+
+ UINT8_TO_STREAM(p_param, HCI_SUCCESS);
+
+ btusb_lite_hci_cmd_cplt_evt_send(p_dev, HCI_BRCM_PAUSE_TRANSPORT, param,
+ p_param - param);
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_transport_resume_hndl
+ **
+ ** Description Handles the HCI Transport Pause VSC.
+ **
+ ** Returns status: <> 0 if the command must be send to BT controller
+ ** 0 if the command is handled
+ **
+ *******************************************************************************/
+static int btusb_lite_hci_transport_resume_hndl(struct btusb *p_dev, BT_HDR *p_msg)
+{
+ UINT8 param[sizeof(UINT8)];
+ UINT8 *p_param = param;
+
+ BTUSB_INFO("HCI_TransportResume VSC caught\n");
+
+ UINT8_TO_STREAM(p_param, HCI_SUCCESS);
+
+ btusb_lite_hci_cmd_cplt_evt_send(p_dev, HCI_BRCM_TRANSPORT_RESUME, param,
+ p_param - param);
+
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_event_filter
+ **
+ ** Description Filter HCI Events received from BT Controller.
+ **
+ ** Returns status: <> 0 if the event must be send to user space (BSA)
+ ** 0 if the event is handled
+ **
+ *******************************************************************************/
+int btusb_lite_hci_event_filter(struct btusb *p_dev, UINT8 *p_data, int length)
+{
+#if 0
+ BT_HDR *p_msg;
+ UINT8 *p;
+ UINT16 size;
+#endif
+
+ /* Check if HCI is over IPC */
+ if (btusb_lite_is_hci_over_ipc(p_dev) == 0)
+ {
+ /* If it is not, the event have to be sent through regular HCI */
+ return 1;
+ }
+
+ /* Check if the Event is a NumberOfCompletePacket Event */
+ if (btusb_lite_hci_nocp_event_hdlr(p_dev, p_data, length) == 0)
+ {
+ return 0; /* Do not Send this event to user space (we handled it) */
+ }
+
+ /* TODO: check if CSB VSE */
+
+ return 1;
+
+#if 0
+
+ /* Add size of both UIPC Length and Event header */
+ size = length + sizeof(UINT16) + sizeof(UINT16);
+
+ /* Get a buffer from the pool */
+ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size);
+ if(unlikely(p_msg == NULL))
+ {
+ BTUSB_ERR("Unable to get GKI buffer\n");
+ return 0;
+ }
+
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
+ return;
+ }
+
+ p_msg->offset = 0;
+ p_msg->event = 0;
+ p_msg->len = size;
+
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ UINT16_TO_STREAM(p, length + sizeof(UINT16)); /* UIPC Length */
+ UINT16_TO_STREAM(p, BT_EVT_TO_BTU_HCI_EVT); /* UIPC Event */
+ UINT8_TO_STREAM(p, hci_event); /* Write back the HCI Event (we already read it) */
+ ARRAY_TO_STREAM(p, p_data, length - 1); /* Copy Event data */
+
+ /* Send message to User Space */
+ btusb_lite_ipc_sent_to_user(p_dev, p_msg);
+
+ return 0; /* Event handled by the Stack Lite. No need to send it to HCI */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_nocp_event_hdlr
+ **
+ ** Description Check if the received HCI Event is A NumberOfdComplete Evt
+ ** sub opcode for a Started BAV stream.
+ **
+ ** Returns status: <> 0 if the event must be send to user space (BSA)
+ ** 0 if the event is handled
+ **
+ *******************************************************************************/
+static int btusb_lite_hci_nocp_event_hdlr(struct btusb *p_dev, UINT8 *p_data, int length)
+{
+ UINT8 nb_handle;
+ UINT16 con_hdl;
+ UINT16 num_cplt_pck;
+ UINT8 byte;
+ UINT8 *p_save;
+ int send_to_user;
+ UINT16 num_cplt_pck_caugth;
+
+ /* We are waiting for an Event of, at least, 7 bytes */
+ if (length < BTUSB_LITE_HCI_NOCP_HCI_LEN)
+ {
+ return 1; /* This is not a NOCP. Send this event to user space */
+ }
+
+ /* Extract Event */
+ STREAM_TO_UINT8(byte, p_data);
+
+ /* Check if it's a NumberOfCompletePacket Event */
+ if (byte != HCI_NUM_COMPL_DATA_PKTS_EVT)
+ {
+ return 1; /* This is not a NOCP. Send this event to user space */
+ }
+
+ /* Extract Parameter Length */
+ STREAM_TO_UINT8(byte, p_data);
+
+ /* Extract Number Of Handle */
+ STREAM_TO_UINT8(nb_handle, p_data);
+
+ /* Sanity */
+ if (byte != (1 + (2 + 2) * nb_handle))
+ {
+ BTUSB_ERR("Unexpected Evt Size=%d vs.NumberOfHandle=%d\n", byte, nb_handle);
+ return 1; /* This is not a NOCP. Send this event to user space */
+ }
+
+ send_to_user = 0; /* For the moment, no Complete Packet sent to user */
+
+ /* For every Handle */
+ while(nb_handle--)
+ {
+ /* Extract the Connection Handle */
+ STREAM_TO_UINT16(con_hdl, p_data);
+
+ /* Save the current pointer position (to overwrite number of packet) */
+ p_save = p_data;
+
+ /* Extract the Number Of Complete Packet */
+ STREAM_TO_UINT16(num_cplt_pck, p_data);
+
+ /* Call the L2CAP NumberOfcompletePacket Handler */
+ num_cplt_pck_caugth = btusb_lite_l2c_nocp_hdlr(p_dev, con_hdl, num_cplt_pck);
+
+ /* If L2CAP "caught"at least one nocp packet */
+ if (num_cplt_pck_caugth)
+ {
+ /* Overwrite the Number Of Complete Packet */
+ UINT16_TO_STREAM(p_save, num_cplt_pck - num_cplt_pck_caugth);
+
+ /* If at least one Number Of Complete Packet remains */
+ if (num_cplt_pck - num_cplt_pck_caugth)
+ {
+ /* Send the event to user space */
+ send_to_user = 1;
+ }
+ }
+ else
+ {
+ /* Don't update the number but send the event to user space */
+ send_to_user = 1;
+ }
+ }
+
+ return send_to_user;
+}
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_cmd_cplt_evt_send
+ **
+ ** Description Send an HCI VSC Cmd Complete.
+ **
+ ** Returns Void
+ **
+ *******************************************************************************/
+static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb *p_dev,
+ UINT16 opcode, UINT8 *p_param, UINT8 param_len)
+{
+ BT_HDR *p_msg;
+ UINT16 size = param_len + 5;
+ UINT8 *p;
+
+ /* Get a buffer from the pool */
+ p_msg = (BT_HDR *)GKI_getbuf(sizeof(BT_HDR) + size);
+ if(unlikely(p_msg == NULL))
+ {
+ BTUSB_ERR("Unable to get GKI buffer\n");
+ return;
+ }
+
+ if (unlikely(dbgflags & BTUSB_GKI_CHK_MSG) &&
+ unlikely(GKI_buffer_status(p_msg) != BUF_STATUS_UNLINKED))
+ {
+ BTUSB_ERR("buffer != BUF_STATUS_UNLINKED 0x%p\n", p_msg);
+ return;
+ }
+
+ p_msg->offset = 0;
+ p_msg->event = HCIT_TYPE_EVENT;
+ p_msg->len = size;
+ p_msg->layer_specific = BTUSB_LS_GKI_BUFFER;
+
+ p = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ p = btusb_lite_hci_write_evt_header(p, HCI_COMMAND_COMPLETE_EVT, size - 2);
+
+ UINT8_TO_STREAM(p, BTUSB_LITE_HCI_NUM_CMD); /* HCI Num Command */
+ UINT16_TO_STREAM(p, opcode); /* HCI OpCode */
+
+ if (p_param)
+ {
+ ARRAY_TO_STREAM(p, p_param, param_len)
+ }
+
+ /* InQ for user-space to read */
+ GKI_enqueue(&p_dev->rx_queue, p_msg);
+
+ /* if the process is polling, indicate RX event */
+ wake_up_interruptible(&p_dev->rx_wait_q);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_write_acl_header
+ **
+ ** Description Write HCI ACL Header (HCI_Type, Connection Handle, Length)
+ **
+ ** Returns New buffer location
+ **
+ *******************************************************************************/
+static UINT8 *btusb_lite_hci_write_acl_header(UINT8 *p_data, UINT16 con_hdl, UINT16 length)
+{
+ UINT8_TO_STREAM(p_data, HCIT_TYPE_ACL_DATA); /* HCI_Type */
+ UINT16_TO_STREAM(p_data, con_hdl); /* Connection Handle */
+ UINT16_TO_STREAM(p_data, length); /* Length */
+ return p_data;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_hci_write_evt_header
+ **
+ ** Description Write HCI Event Header (HCI_Type, Connection Handle, Length)
+ **
+ ** Returns New buffer location
+ **
+ *******************************************************************************/
+static UINT8 *btusb_lite_hci_write_evt_header(UINT8 *p_data, UINT8 event, UINT8 length)
+{
+ UINT8_TO_STREAM(p_data, event);
+ UINT8_TO_STREAM(p_data, length); /* Param Length */
+ return p_data;
+}
+
diff --git a/src/btusb_lite_l2c.c b/src/btusb_lite_l2c.c
new file mode 100755
index 0000000..9d227d2
--- a/dev/null
+++ b/src/btusb_lite_l2c.c
@@ -0,0 +1,278 @@
+/*
+ *
+ * btusb_lite_l2c.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2013 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#include "btusb.h"
+
+/*
+ * Definitions
+ */
+
+/*
+ * Local functions
+ */
+static UINT8 *btusb_lite_l2c_write_header(UINT8 *p_data, UINT16 length, UINT16 cid);
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_add
+**
+** Description Synchronize (Add) L2CAP Stream
+**
+** Returns Status.
+**
+*******************************************************************************/
+int btusb_lite_l2c_add(struct btusb *p_dev, tL2C_STREAM_INFO *p_l2c_stream)
+{
+ int idx;
+ struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.s.l2c;
+ struct btusb_lite_l2c_ccb *p_l2c_ccb;
+
+ /* Check if this L2CAP Stream exists */
+ for (idx = 0, p_l2c_ccb = p_l2c->ccb ; idx < ARRAY_SIZE(p_l2c->ccb) ; idx++, p_l2c_ccb++)
+ {
+ if ((p_l2c_ccb->in_use) &&
+ (p_l2c_ccb->handle == p_l2c_stream->handle))
+ {
+ BTUSB_INFO("CCB=%d was already allocated. Update it.\n", idx);
+ break;
+ }
+ }
+ /* If Not found */
+ if (idx == BTM_SYNC_INFO_NUM_STR)
+ {
+ /* Look for a free CCB */
+ for (idx = 0, p_l2c_ccb = p_l2c->ccb ; idx < ARRAY_SIZE(p_l2c->ccb) ; idx++, p_l2c_ccb++)
+ {
+ if (p_l2c_ccb->in_use == FALSE)
+ {
+ BTUSB_INFO("CCB=%d allocated\n", idx);
+ memset(p_l2c_ccb, 0, sizeof(*p_l2c_ccb));
+ p_l2c_ccb->in_use = TRUE;
+ p_l2c_ccb->local_cid = p_l2c_stream->local_cid;
+ p_l2c_ccb->remote_cid = p_l2c_stream->remote_cid;
+ p_l2c_ccb->out_mtu = p_l2c_stream->out_mtu;
+ p_l2c_ccb->handle = p_l2c_stream->handle;
+ p_l2c_ccb->is_flushable = p_l2c_stream->is_flushable;
+ break;
+ }
+ }
+ }
+
+ /* If Not found ot not allocated */
+ if (idx == BTM_SYNC_INFO_NUM_STR)
+ {
+ BTUSB_ERR("No Free L2C CCB found (handle=0x%x)\n", p_l2c_stream->handle);
+ return -1;
+ }
+
+ /* Update Transmit Quota */
+ p_l2c_ccb->link_xmit_quota = p_l2c_stream->link_xmit_quota;
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_remove
+**
+** Description Synchronize (Remove) L2CAP Stream
+**
+** Returns Status.
+**
+*******************************************************************************/
+int btusb_lite_l2c_remove(struct btusb *p_dev, UINT16 local_cid)
+{
+ int idx;
+ struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.s.l2c;
+ struct btusb_lite_l2c_ccb *p_l2c_ccb;
+
+ /* Check if this L2CAP Stream exists */
+ for (idx = 0, p_l2c_ccb = p_l2c->ccb ; idx < ARRAY_SIZE(p_l2c->ccb) ; idx++, p_l2c_ccb++)
+ {
+ if ((p_l2c_ccb->in_use) &&
+ (p_l2c_ccb->local_cid == local_cid))
+ {
+ break;
+ }
+ }
+ /* If Not found */
+ if (idx == BTM_SYNC_INFO_NUM_STR)
+ {
+ BTUSB_ERR("L2C CCB found (lcid=0x%x)\n",local_cid);
+ return -1;
+ }
+
+ BTUSB_INFO("CCB=%d freed\n", idx);
+
+ /* Reset (Free) the L2CAP Stream */
+ memset(p_l2c_ccb, 0, sizeof(*p_l2c_ccb));
+
+ return 0;
+}
+
+/*******************************************************************************
+**
+** Function btusb_lite_l2c_send
+**
+** Description Send L2CAP packet
+**
+** Returns Status.
+**
+*******************************************************************************/
+int btusb_lite_l2c_send(struct btusb *p_dev, BT_HDR *p_msg, UINT16 local_cid)
+{
+ int idx;
+ struct btusb_lite_l2c_cb *p_l2c;
+ struct btusb_lite_l2c_ccb *p_l2c_ccb;
+ UINT8 *p_data;
+
+ /* Look for the first AV stream Started */
+ p_l2c = &p_dev->lite_cb.s.l2c;
+ for (idx = 0, p_l2c_ccb = p_l2c->ccb ; idx < BTM_SYNC_INFO_NUM_STR ; idx++, p_l2c_ccb++)
+ {
+ if (p_l2c_ccb->local_cid == local_cid)
+ {
+ break;
+ }
+ }
+ if (idx == BTM_SYNC_INFO_NUM_STR)
+ {
+ BTUSB_ERR("No L2C CCB found (lcid=0x%x)\n", local_cid);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return -1;
+ }
+
+ /* Check if the Tx Quota has been reached for this channel */
+ if (p_l2c_ccb->tx_pending >= p_l2c_ccb->link_xmit_quota)
+ {
+ BTUSB_ERR("Tx Quota reached for L2CAP channel (lcid=0x%x). Drop buffer\n", local_cid);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return -1;
+ }
+
+ /* Sanity */
+ if (p_msg->offset < BTUSB_LITE_L2CAP_HDR_SIZE)
+ {
+ BTUSB_ERR("offset too small=%d\n", p_msg->offset);
+ GKI_freebuf(p_msg); /* Free this ACL buffer */
+ return-1;
+ }
+
+ /* Decrement offset to add headers */
+ p_msg->offset -= BTUSB_LITE_L2CAP_HDR_SIZE;
+
+ /* Get address of the HCI Header */
+ p_data = (UINT8 *)(p_msg + 1) + p_msg->offset;
+
+ /* Write L2CAP Header (length field is SBC Frames + RTP/A2DP/Media Header) */
+ p_data = btusb_lite_l2c_write_header(p_data, p_msg->len, p_l2c_ccb->remote_cid);
+
+ /* Increment length */
+ p_msg->len += BTUSB_LITE_L2CAP_HDR_SIZE;
+
+
+ GKI_disable(); /* tx_pending field can be updated by another context */
+ p_l2c_ccb->tx_pending++; /* One more A2DP L2CAP packet pending */
+ BTUSB_DBG("L2C Tx Pending=%d\n", p_l2c_ccb->tx_pending);
+ GKI_enable();
+
+ if (btusb_lite_hci_acl_send(p_dev, p_msg, p_l2c_ccb->handle) < 0)
+ {
+ GKI_disable(); /* tx_pending field can be updated by another context */
+ p_l2c_ccb->tx_pending--; /* Remove A2DP L2CAP packet pending */
+ GKI_enable();
+ return -1;
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_l2c_write_header
+ **
+ ** Description Write L2CAP ACL Header (Length, Channel Id)
+ **
+ ** Returns New buffer location
+ **
+ *******************************************************************************/
+static UINT8 *btusb_lite_l2c_write_header(UINT8 *p_data, UINT16 length, UINT16 cid)
+{
+ UINT16_TO_STREAM(p_data, length); /* Length */
+ UINT16_TO_STREAM(p_data, cid); /* Channel Id */
+ return p_data;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_lite_l2c_nocp_hdlr
+ **
+ ** Description L2CAP NumberOfcompletePacket Handler function
+ **
+ ** Returns Number Of Complete Packet caught
+ **
+ *******************************************************************************/
+UINT16 btusb_lite_l2c_nocp_hdlr(struct btusb *p_dev, UINT16 con_hdl, UINT16 num_cplt_pck)
+{
+ struct btusb_lite_l2c_cb *p_l2c;
+ struct btusb_lite_l2c_ccb *p_l2c_ccb;
+ int i;
+ UINT16 num_cplt_pck_caugth;
+
+ /* Look for the L2CAP channel matching the Connection Handle */
+ p_l2c = &p_dev->lite_cb.s.l2c;
+ for (i = 0, p_l2c_ccb = p_l2c->ccb ; i < BTM_SYNC_INFO_NUM_STR ; i++, p_l2c_ccb++)
+ {
+ if (p_l2c_ccb->handle == con_hdl)
+ {
+ break;
+ }
+ }
+ /* If L2CAP channel not found/known */
+ if (i == BTM_SYNC_INFO_NUM_STR)
+ {
+ return 0;
+ }
+
+ /* If no Tx Pending */
+ if (p_l2c_ccb->tx_pending == 0)
+ {
+ return 0;
+ }
+
+ GKI_disable(); /* tx_pending field can be updated by another context */
+
+ /* Take the min between the number of pending packet and the number of acked packet */
+ num_cplt_pck_caugth = min(p_l2c_ccb->tx_pending, num_cplt_pck);
+
+ /* Update the number of pending packet */
+ p_l2c_ccb->tx_pending-= num_cplt_pck_caugth;
+
+ BTUSB_DBG("L2C NOCP Tx Pending=%d\n", p_l2c_ccb->tx_pending);
+
+ GKI_enable();
+
+ return num_cplt_pck_caugth;
+}
diff --git a/src/btusb_proc.c b/src/btusb_proc.c
new file mode 100755
index 0000000..809b25c
--- a/dev/null
+++ b/src/btusb_proc.c
@@ -0,0 +1,763 @@
+/*
+ *
+ * btusb_proc.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Module that implements the proc file system routines.
+ *
+ */
+
+#include "btusb_proc.h"
+
+#include <linux/slab.h> /* for kmalloc/kfree */
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+#include "btusb.h"
+
+static struct proc_dir_entry *btusb_proc_dir = NULL;
+
+/* Definition of the proc interface */
+struct btusb_proc_file
+{
+ const char *name;
+ umode_t mode;
+ const struct seq_operations seq_ops;
+};
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_version_show
+ **
+ ** Description Version display function
+ **
+ *******************************************************************************/
+int btusb_version_show(struct seq_file *s, void *unused)
+{
+ /* s->private points to unknown data */
+ seq_printf(s, "version : %s\n", bsa_version_string);
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_info_show
+ **
+ ** Description Information display function
+ **
+ *******************************************************************************/
+int btusb_info_show(struct seq_file *s, void *unused)
+{
+ struct btusb *p_dev = s->private;
+ const struct usb_device_id *p_id = p_dev->p_id;
+ struct usb_device *udev = p_dev->p_udev;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+ int idx, jdx;
+
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+
+ seq_printf(s, "USB device :\n");
+ seq_printf(s, " - Match info:\n");
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_VENDOR)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_VENDOR (0x%02X)\n", p_id->idVendor);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_PRODUCT 0x%02X)\n", p_id->idProduct);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_LO (%u)\n", p_id->bcdDevice_lo);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_HI (%u)\n", p_id->bcdDevice_hi);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_CLASS (0x%02X)\n", p_id->bDeviceClass);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_SUBCLASS (0x%02X)\n", p_id->bDeviceSubClass);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_PROTOCOL (0x%02X)\n", p_id->bDeviceProtocol);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_CLASS (0x%02X)\n", p_id->bInterfaceClass);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_SUBCLASS (0x%02X)\n", p_id->bInterfaceSubClass);
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_PROTOCOL (0x%02X)\n", p_id->bInterfaceProtocol);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ if (p_id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_NUMBER (%u)\n", p_id->bInterfaceNumber);
+#endif
+
+ seq_printf(s, " - Address = %d\n", udev->devnum);
+ seq_printf(s, " - VendorId = %04x\n", le16_to_cpu(udev->descriptor.idVendor));
+ seq_printf(s, " - ProductId = %04x\n", le16_to_cpu(udev->descriptor.idProduct));
+ seq_printf(s, " - Manufacturer String = %s\n", udev->manufacturer);
+ seq_printf(s, " - Product String = %s\n", udev->product);
+ seq_printf(s, " - USB bus number = %d\n", udev->bus->busnum);
+ seq_printf(s, " - USB devpath = %s\n", udev->devpath);
+ seq_printf(s, " - USB devnum = %d\n", udev->devnum);
+ seq_printf(s, " - USB ttport = %d\n", udev->ttport);
+ seq_printf(s, " - Interfaces :\n");
+ seq_printf(s, " * MAIN : ");
+ if (p_dev->p_main_intf)
+ {
+ seq_printf(s, "intf = %d (nb alt settings = %d, ",
+ p_dev->p_main_intf->cur_altsetting->desc.bInterfaceNumber,
+ p_dev->p_main_intf->num_altsetting);
+ seq_printf(s, "cur alt setting = %d)\n", p_dev->p_main_intf->cur_altsetting->desc.bAlternateSetting);
+ seq_printf(s, " * HCI EVENT : ");
+ if (p_dev->p_event_in)
+ {
+ seq_printf(s, "ep = 0x%02x\n", p_dev->p_event_in->desc.bEndpointAddress);
+ }
+ else
+ {
+ seq_printf(s, "ERROR (endpoint not found)\n");
+ }
+ seq_printf(s, " * ACL RX : ");
+ if (p_dev->p_acl_in)
+ {
+ seq_printf(s, "ep = 0x%02x\n", p_dev->p_acl_in->desc.bEndpointAddress);
+ }
+ else
+ {
+ seq_printf(s, "ERROR (endpoint not found)\n");
+ }
+ seq_printf(s, " * ACL TX : ");
+ if (p_dev->p_acl_out)
+ {
+ seq_printf(s, "ep = 0x%02x\n", p_dev->p_acl_out->desc.bEndpointAddress);
+ }
+ else
+ {
+ seq_printf(s, "ERROR (endpoint not found)\n");
+ }
+ }
+ else
+ {
+ seq_printf(s, "Not present\n");
+ }
+ seq_printf(s, " * VOICE :");
+ if (p_dev->p_voice_intf)
+ {
+ seq_printf(s, " intf = %d (nb alt setting = %d, ", p_dev->p_voice_intf->cur_altsetting->desc.bInterfaceNumber, p_dev->p_voice_intf->num_altsetting);
+ seq_printf(s, "cur alt setting = %d)\n", p_dev->p_voice_intf->cur_altsetting->desc.bAlternateSetting);
+ for (idx = 0; idx < p_dev->p_voice_intf->num_altsetting; idx++)
+ {
+ p_host_intf = &p_dev->p_voice_intf->altsetting[idx];
+ seq_printf(s, " * alt setting %d (idx %d) : %d enpoints\n",
+ p_host_intf->desc.bAlternateSetting, idx, p_host_intf->desc.bNumEndpoints);
+ for (jdx = 0; jdx < p_host_intf->desc.bNumEndpoints; jdx++)
+ {
+ p_ep_desc = &p_host_intf->endpoint[jdx].desc;
+ seq_printf(s, " * ep = 0x%02x : ", p_ep_desc->bEndpointAddress);
+ if (usb_endpoint_type(p_ep_desc) == USB_ENDPOINT_XFER_ISOC)
+ {
+ seq_printf(s, "Isoch ");
+ if (usb_endpoint_dir_out(p_ep_desc))
+ {
+ seq_printf(s, "(OUT) ");
+ }
+ else
+ {
+ seq_printf(s, "(IN) ");
+ }
+ seq_printf(s, "wMaxPacketSize = %d\n", le16_to_cpu(p_ep_desc->wMaxPacketSize));
+ }
+ else
+ {
+ seq_printf(s, "not isochronous endpoint\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ seq_printf(s, "Not present\n");
+ }
+ seq_printf(s, " * DIAG RX : ");
+ if (p_dev->p_diag_in)
+ {
+ seq_printf(s, "intf = %d ep = 0x%02x\n", p_dev->p_diag_intf->cur_altsetting->desc.bInterfaceNumber, p_dev->p_diag_in->desc.bEndpointAddress);
+ }
+ else
+ {
+ seq_printf(s, "Not present\n");
+ }
+ seq_printf(s, " * DIAG TX : ");
+ if (p_dev->p_diag_out)
+ {
+ seq_printf(s, "intf = %d ep = 0x%02x\n", p_dev->p_diag_intf->cur_altsetting->desc.bInterfaceNumber, p_dev->p_diag_out->desc.bEndpointAddress);
+ }
+ else
+ {
+ seq_printf(s, "Not present\n");
+ }
+ seq_printf(s, " * DFU : ");
+ if (p_dev->p_dfu_intf)
+ {
+ seq_printf(s, "intf = %d\n", p_dev->p_dfu_intf->cur_altsetting->desc.bInterfaceNumber);
+ }
+ else
+ {
+ seq_printf(s, "Not present\n");
+ }
+
+ seq_printf(s, "Memory usage :\n");
+ seq_printf(s, " - p_dev = %p\n", p_dev);
+ seq_printf(s, " - size = %zd\n", sizeof(*p_dev));
+ seq_printf(s, " * CMD = off:%zd/size=%zd\n", offsetof(struct btusb, cmd_array), sizeof(p_dev->cmd_array));
+ seq_printf(s, " * EVENT = off:%zd/size=%zd\n", offsetof(struct btusb, event_array), sizeof(p_dev->event_array));
+ seq_printf(s, " * ACL RX = off:%zd/size=%zd\n", offsetof(struct btusb, acl_rx_array), sizeof(p_dev->acl_rx_array));
+ seq_printf(s, " * ACL TX = off:%zd/size=%zd\n", offsetof(struct btusb, acl_tx_array), sizeof(p_dev->acl_tx_array));
+ seq_printf(s, " * DIAG RX = off:%zd/size=%zd\n", offsetof(struct btusb, diag_rx_array), sizeof(p_dev->diag_rx_array));
+ seq_printf(s, " * DIAG TX = off:%zd/size=%zd\n", offsetof(struct btusb, diag_tx_array), sizeof(p_dev->diag_tx_array));
+ seq_printf(s, " * VOICE = off:%zd/size=%zd\n", offsetof(struct btusb, voice_rx.channels), offsetof(struct btusb, rx_queue)-offsetof(struct btusb, voice_rx.channels));
+
+ seq_printf(s, "Config :\n");
+ seq_printf(s, " - issharedusb = %u\n", p_dev->issharedusb);
+ seq_printf(s, " - quirks = %u\n", p_dev->quirks);
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_status_show
+ **
+ ** Description Status display function
+ **
+ *******************************************************************************/
+int btusb_status_show(struct seq_file *s, void *unused)
+{
+ struct btusb *p_dev = s->private;
+ struct btusb_voice_channel *p_chan;
+ struct btusb_scosniff *p, *n;
+ int idx, jdx;
+
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+
+ seq_printf(s, "Voice :\n");
+ jdx = 0;
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_rx.channels); idx++)
+ {
+ p_chan = &p_dev->voice_rx.channels[idx];
+ if (p_chan->used)
+ {
+ seq_printf(s, " - channel %d : SCO handle = %d(0x%02x) burst = %d\n", idx,
+ p_chan->handle, p_chan->handle, p_chan->burst);
+ jdx = 1;
+ }
+ }
+ if (!jdx)
+ {
+ seq_printf(s, " - No active channels\n");
+ }
+ seq_printf(s, "SCO sniffing :\n");
+ seq_printf(s, " - list: %p\n", &p_dev->scosniff_list);
+ seq_printf(s, " - list.next: %p\n", p_dev->scosniff_list.next);
+ seq_printf(s, " - list.prev: %p\n", p_dev->scosniff_list.prev);
+ seq_printf(s, " - whole list:\n");
+ list_for_each_entry_safe(p, n, &p_dev->scosniff_list, lh)
+ {
+ seq_printf(s, " > %p\n", p);
+ }
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_stats_show
+ **
+ ** Description Statistics display function
+ **
+ *******************************************************************************/
+#define BTUSB_STATS(__n) \
+ seq_printf(s, #__n " = %lu\n", p_dev->stats.__n)
+int btusb_stats_show(struct seq_file *s, void *unused)
+{
+ struct btusb *p_dev = s->private;
+
+ BTUSB_STATS(urb_submit_ok);
+ BTUSB_STATS(urb_submit_err);
+ BTUSB_STATS(acl_rx_submit_ok);
+ BTUSB_STATS(acl_rx_submit_err);
+ BTUSB_STATS(acl_rx_complete);
+ BTUSB_STATS(acl_rx_complete_err);
+ BTUSB_STATS(acl_rx_resubmit);
+ BTUSB_STATS(acl_rx_bytes);
+ BTUSB_STATS(event_submit_ok);
+ BTUSB_STATS(event_submit_err);
+ BTUSB_STATS(event_complete);
+ BTUSB_STATS(event_complete_err);
+ BTUSB_STATS(event_resubmit);
+ BTUSB_STATS(event_bytes);
+ BTUSB_STATS(diag_rx_submit_ok);
+ BTUSB_STATS(diag_rx_submit_err);
+ BTUSB_STATS(diag_rx_complete);
+ BTUSB_STATS(diag_rx_complete_err);
+ BTUSB_STATS(diag_rx_resubmit);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(urb_out_complete);
+ BTUSB_STATS(urb_out_complete_err);
+ BTUSB_STATS(cmd_submit_ok);
+ BTUSB_STATS(cmd_submit_err);
+ BTUSB_STATS(cmd_complete);
+ BTUSB_STATS(cmd_complete_err);
+ BTUSB_STATS(voicerx_submit_ok);
+ BTUSB_STATS(voicerx_submit_err);
+ BTUSB_STATS(voicerx_complete);
+ BTUSB_STATS(voicerx_complete_err);
+ BTUSB_STATS(voicerx_bad_frames);
+ BTUSB_STATS(voicerx_bad_hdr);
+ BTUSB_STATS(voicerx_split_hdr);
+ BTUSB_STATS(voicerx_raw_bytes);
+ BTUSB_STATS(voicerx_skipped_bytes);
+ BTUSB_STATS(voicerx_bad_size);
+ BTUSB_STATS(voicetx_submit_ok);
+ BTUSB_STATS(voicetx_submit_err);
+ BTUSB_STATS(voicetx_nobuf);
+ BTUSB_STATS(voicetx_complete);
+ BTUSB_STATS(voicetx_complete_err);
+ return 0;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_scosniff_start
+ **
+ ** Description SCO sniffing sequence start function
+ **
+ *******************************************************************************/
+void *btusb_scosniff_start(struct seq_file *s, loff_t *pos)
+{
+ struct btusb *p_dev = s->private;
+ struct btusb_scosniff *bs;
+ int rv;
+
+ BTUSB_INFO("waiting %p\n", p_dev);
+ rv = wait_for_completion_interruptible(&p_dev->scosniff_completion);
+ if (rv < 0)
+ return NULL;
+
+ BTUSB_INFO("triggered\n");
+
+ if (!list_empty(&p_dev->scosniff_list))
+ {
+ bs = list_first_entry(&p_dev->scosniff_list, struct btusb_scosniff, lh);
+
+ /* remove the element from the list */
+ list_del(&bs->lh);
+ BTUSB_INFO("receiving %p\n", bs);
+
+ return bs;
+ }
+ return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_scosniff_next
+ **
+ ** Description SCO sniffing sequence next function
+ **
+ *******************************************************************************/
+void *btusb_scosniff_next(struct seq_file *s, void *v, loff_t *pos)
+{
+ struct btusb_scosniff *bs = v;
+ BTUSB_INFO("next\n");
+
+ kfree(bs);
+
+ (*pos)++;
+
+ /* if you do not want to buffer the data, just return NULL, otherwise, call start
+ * again in order to use as much of the allocated PAGE in seq_read
+ *
+ * optional:
+ * return btusb_scosniff_start(s, pos);
+ */
+ return NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_scosniff_stop
+ **
+ ** Description SCO sniffing sequence stop function
+ **
+ *******************************************************************************/
+void btusb_scosniff_stop(struct seq_file *s, void *v)
+{
+ BTUSB_INFO("stop\n");
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_scosniff_show
+ **
+ ** Description SCO sniffing display function
+ **
+ *******************************************************************************/
+int btusb_scosniff_show(struct seq_file *s, void *v)
+{
+ struct btusb_scosniff *bs = v;
+ unsigned int i, j;
+ unsigned char *p_buf, *p_c;
+ unsigned char c;
+ struct usb_iso_packet_descriptor *p_uipd;
+ const char hexdigit[16] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
+
+ seq_printf(s, "%u %u %d \n", bs->n, bs->l, bs->s);
+ p_buf = (unsigned char *)&bs->d[bs->n];
+ for (i = 0; i < bs->n; i++)
+ {
+ p_uipd = &bs->d[i];
+ seq_printf(s, " %d %u %u %u\n", p_uipd->status, p_uipd->actual_length, p_uipd->length, p_uipd->offset);
+ for (j = 0, p_c = &p_buf[p_uipd->offset]; j < p_uipd->actual_length; j++, p_c++)
+ {
+ c = *p_c;
+ seq_putc(s, hexdigit[c >> 4]);
+ seq_putc(s, hexdigit[c & 0xF]);
+ seq_putc(s, ' ');
+ }
+ seq_putc(s, '\n');
+ }
+
+ return 0;
+}
+
+const struct seq_operations btusb_scosniff_seq_ops =
+{
+ .start = btusb_scosniff_start,
+ .next = btusb_scosniff_next,
+ .stop = btusb_scosniff_stop,
+ .show = btusb_scosniff_show,
+};
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_open
+ **
+ ** Description Open handler of the proc interface
+ **
+ *******************************************************************************/
+int btusb_proc_open(struct inode *inode, struct file *file)
+{
+ int rv;
+ struct btusb_proc_file *p_file = BTUSB_PDE_DATA(inode);
+ /* in case of proc_files, there is no p_dev */
+ struct btusb *p_dev = BTUSB_PDE_PARENT_DATA(inode);
+
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+ /* check if it is a single sequence */
+ if (!p_file->seq_ops.start)
+ {
+ return single_open(file, p_file->seq_ops.show, p_dev);
+ }
+ else
+ {
+ rv = seq_open(file, &p_file->seq_ops);
+ if (!rv)
+ {
+ p_dev->scosniff_active = true;
+ ((struct seq_file *)file->private_data)->private = p_dev;
+ }
+ return rv;
+ }
+ return -1;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_release
+ **
+ ** Description Close handler of the proc interface
+ **
+ *******************************************************************************/
+int btusb_proc_release(struct inode *inode, struct file *file)
+{
+ struct btusb_proc_file *p_file = BTUSB_PDE_DATA(inode);
+ struct btusb *p_dev = BTUSB_PDE_PARENT_DATA(inode);
+ struct btusb_scosniff *p, *n;
+
+ BTUSB_DBG("p_dev=%p\n", p_dev);
+ if (!p_file->seq_ops.start)
+ {
+ return single_release(inode, file);
+ }
+ else
+ {
+ p_dev->scosniff_active = false;
+ list_for_each_entry_safe(p, n, &p_dev->scosniff_list, lh)
+ {
+ list_del(&p->lh);
+ kfree(p);
+ }
+ return seq_release(inode, file);
+ }
+ return -1;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_write
+ **
+ ** Description Write handler of the proc interface
+ **
+ *******************************************************************************/
+ssize_t btusb_proc_write(struct file *file, const char *buf,
+ size_t count, loff_t *pos)
+{
+ struct seq_file *s = file->private_data;
+ struct btusb *p_dev = s->private;
+ unsigned char cmd;
+
+ /* copy the first byte from the data written */
+ if (copy_from_user(&cmd, buf, 1))
+ {
+ return -EFAULT;
+ }
+
+ /* unconditional print on purpose */
+ BTUSB_INFO("'%c'\n", cmd);
+
+ switch (cmd)
+ {
+ case '0':
+ /* reset the stats */
+ memset(&p_dev->stats, 0, sizeof(p_dev->stats));
+ break;
+ case '1':
+ btusb_add_voice_channel(p_dev, 6, BTUSB_VOICE_BURST_SIZE);
+ break;
+
+ case '2':
+ btusb_remove_voice_channel(p_dev, 6);
+ break;
+
+ case '3':
+ if (p_dev->scosniff_active)
+ {
+ struct btusb_scosniff *bs;
+ bs = kmalloc(sizeof(*bs), GFP_ATOMIC);
+ if (bs)
+ {
+ BTUSB_INFO("SCOSNIFF: adding %p\n", bs);
+ bs->n = 0;
+ list_add_tail(&bs->lh, &p_dev->scosniff_list);
+ complete(&p_dev->scosniff_completion);
+ }
+ }
+ break;
+
+#ifdef BTUSB_LITE
+ case '4':
+ BTUSB_INFO("Mute PCM0\n");
+ pcm0_mute = 1;
+ break;
+
+ case '5':
+ BTUSB_INFO("Unmute PCM0\n");
+ pcm0_mute = 0;
+ break;
+#endif
+
+ default:
+ break;
+ }
+
+ return count;
+}
+
+static struct btusb_proc_file btusb_proc_files[] =
+{
+ {
+ "version", S_IRUGO,
+ {
+ .show=btusb_version_show,
+ .start=NULL
+ }
+ },
+ {NULL, 0, {.start=NULL}}
+};
+
+static struct btusb_proc_file btusb_proc_dev_files[] =
+{
+ {
+ "info", S_IRUGO,
+ {
+ .show=btusb_info_show,
+ .start=NULL
+ }
+ },
+ {
+ "stats", S_IRUGO | S_IWUGO,
+ {
+ .show=btusb_stats_show,
+ .start=NULL
+ }
+ },
+ {
+ "status", S_IRUGO,
+ {
+ .show=btusb_status_show,
+ .start=NULL
+ }
+ },
+ {
+ "scosniff", S_IRUGO,
+ {
+ .show=btusb_scosniff_show,
+ .start=btusb_scosniff_start,
+ .stop=btusb_scosniff_stop,
+ .next=btusb_scosniff_next
+ }
+ },
+ {NULL, 0, {.start=NULL}}
+};
+
+static const struct file_operations btusb_proc_fops =
+{
+ .open = btusb_proc_open,
+ .read = seq_read,
+ .write = btusb_proc_write,
+ .llseek = seq_lseek,
+ .release = btusb_proc_release,
+};
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_create_files
+ **
+ ** Description Proc interface file creation
+ **
+ *******************************************************************************/
+static void btusb_proc_create_files(struct btusb_proc_file proc_files[],
+ struct proc_dir_entry *p_parent)
+{
+ struct proc_dir_entry *p_pde;
+ struct btusb_proc_file *p_file;
+
+ if (p_parent)
+ {
+ for (p_file = proc_files; p_file->name; p_file++)
+ {
+ p_pde = proc_create_data(p_file->name, p_file->mode,
+ p_parent, &btusb_proc_fops, p_file);
+ if (!p_pde)
+ {
+ BTUSB_ERR("failed creating %s\n", p_file->name);
+ }
+ }
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_remove_files
+ **
+ ** Description Proc interface file removal
+ **
+ *******************************************************************************/
+static void btusb_proc_remove_files(struct btusb_proc_file proc_files[],
+ struct proc_dir_entry *p_parent)
+{
+ struct btusb_proc_file *p_file;
+ if (p_parent)
+ {
+ for (p_file = proc_files; p_file->name; p_file++)
+ {
+ remove_proc_entry(p_file->name, p_parent);
+ }
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_init
+ **
+ ** Description Proc interface init
+ **
+ *******************************************************************************/
+void btusb_proc_init(void)
+{
+ btusb_proc_dir = proc_mkdir("driver/btusb", NULL);
+ btusb_proc_create_files(btusb_proc_files, btusb_proc_dir);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_exit
+ **
+ ** Description Proc interface exit
+ **
+ *******************************************************************************/
+void btusb_proc_exit(void)
+{
+ btusb_proc_remove_files(btusb_proc_files, btusb_proc_dir);
+ remove_proc_entry("driver/btusb", NULL);
+ btusb_proc_dir = NULL;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_add
+ **
+ ** Description Add a device to the proc interface
+ **
+ *******************************************************************************/
+void btusb_proc_add(struct btusb *p_dev, const char *name)
+{
+ if (btusb_proc_dir)
+ {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0)
+ p_dev->p_pde = create_proc_entry(name, S_IFDIR | S_IRUGO | S_IWUGO | S_IXUGO, btusb_proc_dir);
+ if (p_dev->p_pde)
+ p_dev->p_pde->data = p_dev;
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0)
+ p_dev->p_pde = proc_mkdir_mode(name, S_IRUGO | S_IWUGO | S_IXUGO, btusb_proc_dir);
+ if (p_dev->p_pde)
+ p_dev->p_pde->data = p_dev;
+#else
+ p_dev->p_pde = proc_mkdir_data(name, S_IRUGO | S_IWUGO | S_IXUGO, btusb_proc_dir, p_dev);
+#endif
+ if (!p_dev->p_pde)
+ {
+ BTUSB_ERR("Couldn't create proc entry %s\n", name);
+ return;
+ }
+
+ btusb_proc_create_files(btusb_proc_dev_files, p_dev->p_pde);
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_proc_remove
+ **
+ ** Description Remove a device from the proc interface
+ **
+ *******************************************************************************/
+void btusb_proc_remove(struct btusb *p_dev, const char *name)
+{
+ btusb_proc_remove_files(btusb_proc_dev_files, p_dev->p_pde);
+ remove_proc_entry(name, btusb_proc_dir);
+}
+
diff --git a/src/btusb_version.c b/src/btusb_version.c
new file mode 100755
index 0000000..01f5c8f
--- a/dev/null
+++ b/src/btusb_version.c
@@ -0,0 +1,30 @@
+/*
+ *
+ * btusb_version.c
+ *
+ *
+ *
+ * Copyright (C) 2014 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ * Module that implements the device routines.
+ *
+ */
+
+#include "btusb.h"
+
+const char bsa_version_string[] = "BSA0106_00.40.00";
diff --git a/src/gki/gki_buffer.c b/src/gki/gki_buffer.c
new file mode 100755
index 0000000..aa09483
--- a/dev/null
+++ b/src/gki/gki_buffer.c
@@ -0,0 +1,1291 @@
+/*
+ *
+ * gki_buffer.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+#include "gki_int.h"
+#include "btusb.h"
+
+#if (GKI_NUM_TOTAL_BUF_POOLS > 16)
+#error Number of pools out of range (16 Max)!
+#endif
+
+static void gki_add_to_pool_list(UINT8 pool_id);
+static void gki_remove_from_pool_list(UINT8 pool_id);
+
+static BOOL _b_in_gki_getbuf = FALSE;
+
+/*******************************************************************************
+**
+** Function gki_init_free_queue
+**
+** Description Internal function called at startup to initialize a free
+** queue. It is called once for each free queue.
+**
+** Returns void
+**
+*******************************************************************************/
+static BOOL gki_init_free_queue(UINT8 id, UINT16 size, UINT16 total, void *p_mem)
+{
+ UINT16 i;
+ UINT16 act_size;
+ BUFFER_HDR_T *hdr;
+ BUFFER_HDR_T *hdr1 = NULL;
+ UINT32 *magic;
+ int seg_inx = gki_cb.pool_additions[id];
+ FREE_QUEUE_T *p_freeq = &gki_cb.freeq[id];
+
+ if (seg_inx >= MAX_BUFFPOOL_SEGS)
+ {
+ GKI_exception(GKI_ERROR_SEGS_EXCEEDED, "Max segs exceeded");
+ return(FALSE);
+ }
+
+ act_size = (UINT16)(size + BUFFER_PADDING_SIZE);
+
+ if (!p_mem)
+ p_mem = gki_reserve_os_memory(act_size * total);
+
+ if (!p_mem)
+ {
+ GKI_exception(GKI_ERROR_NO_MEMORY_FOR_SEG, "No memory for segment");
+ return(FALSE);
+ }
+
+ /* Remember pool start and end addresses */
+ p_freeq->seg_start[seg_inx] = (UINT8 *)p_mem;
+ p_freeq->seg_end[seg_inx] = (UINT8 *)p_mem + (act_size * total);
+
+ if (seg_inx == 0)
+ {
+ gki_cb.freeq[id].total = total;
+ gki_cb.freeq[id].cur_cnt = 0;
+ gki_cb.freeq[id].max_cnt = 0;
+ }
+ else
+ gki_cb.freeq[id].total += total;
+
+ /* Initialize index table */
+ hdr = (BUFFER_HDR_T *)p_mem;
+ p_freeq->p_first = hdr;
+
+#ifdef TRACE_GKI_BUFFERS
+ gki_cb.freeq[id].p_first_all = hdr;
+#endif
+
+ for (i = 0; i < total; i++)
+ {
+ hdr->task_id = GKI_INVALID_TASK;
+ hdr->q_id = id;
+ hdr->status = BUF_STATUS_FREE;
+ magic = (UINT32 *)((UINT8 *)hdr + BUFFER_HDR_SIZE + size);
+ *magic = MAGIC_NO;
+ hdr1 = hdr;
+ hdr = (BUFFER_HDR_T *)((UINT8 *)hdr + act_size);
+ hdr1->p_next = hdr;
+#ifdef TRACE_GKI_BUFFERS
+ hdr1->p_next_all = hdr;
+ hdr1->pFile = NULL;
+ hdr1->linenum = 0;
+ hdr1->times_alloc = 0;
+#endif
+ }
+
+ hdr1->p_next = NULL;
+ p_freeq->p_last = hdr1;
+
+ gki_cb.pool_additions[id]++;
+
+ return(TRUE);
+}
+
+
+/*******************************************************************************
+**
+** Function gki_buffer_init
+**
+** Description Called once internally by GKI at startup to initialize all
+** buffers and free buffer pools.
+**
+** Returns void
+**
+*******************************************************************************/
+void gki_buffer_init(void)
+{
+ UINT8 tt;
+ UINT16 access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
+
+#ifdef TRACE_GKI_BUFFERS
+ char aString[200];
+ sprintf(aString,"%s: %d: WARNING! Running with GKI buffer tracing enabled!!",__FILE__,__LINE__);
+ GKI_exception(GKI_ERROR_BUFFER_TRACE_ON,aString);
+#endif
+
+ for (tt = 0; tt < GKI_NUM_TOTAL_BUF_POOLS; tt++)
+ {
+ memset(&gki_cb.freeq[tt], 0, sizeof(FREE_QUEUE_T));
+
+ gki_cb.pool_buf_size[tt] = 0;
+ gki_cb.pool_max_count[tt] = 0;
+ gki_cb.pool_additions[tt] = 0;
+ }
+
+ /* Use default from target.h */
+ gki_cb.pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
+
+#if (GKI_USE_DYNAMIC_BUFFERS == TRUE)
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ GKI_create_pool(GKI_BUF0_SIZE, GKI_BUF0_MAX, (UINT8) (access_mask & 1), NULL);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ GKI_create_pool(GKI_BUF1_SIZE, GKI_BUF1_MAX, (UINT8) (access_mask & 1), NULL);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ GKI_create_pool(GKI_BUF2_SIZE, GKI_BUF2_MAX, (UINT8) (access_mask & 1), NULL);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ GKI_create_pool(GKI_BUF3_SIZE, GKI_BUF3_MAX, (UINT8) (access_mask & 1), NULL);
+#endif
+
+#else
+
+/* Static buffers */
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 0)
+ GKI_create_pool(GKI_BUF0_SIZE, GKI_BUF0_MAX, (UINT8) (access_mask & 1), gki_cb.bufpool0);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 1)
+ GKI_create_pool(GKI_BUF1_SIZE, GKI_BUF1_MAX, (UINT8) (access_mask & 1), gki_cb.bufpool1);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 2)
+ GKI_create_pool(GKI_BUF2_SIZE, GKI_BUF2_MAX, (UINT8) (access_mask & 1), gki_cb.bufpool2);
+ access_mask = access_mask >> 1;
+#endif
+
+#if (GKI_NUM_FIXED_BUF_POOLS > 3)
+ GKI_create_pool(GKI_BUF3_SIZE, GKI_BUF3_MAX, (UINT8) (access_mask & 1), gki_cb.bufpool3);
+#endif
+
+#endif
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_set_pool_permission
+**
+** Description This function is called to set or change the permissions for
+** the specified pool ID.
+**
+** Parameters pool_id - (input) pool ID to be set or changed
+** permission - (input) GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL
+**
+** Returns GKI_SUCCESS if successful
+** GKI_INVALID_POOL if unsuccessful
+**
+*******************************************************************************/
+UINT8 GKI_set_pool_permission(UINT8 pool_id, UINT8 permission)
+{
+ if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ if (permission == GKI_RESTRICTED_POOL)
+ gki_cb.pool_access_mask |= (1 << pool_id);
+
+ else /* mark the pool as public */
+ gki_cb.pool_access_mask &= ~(1 << pool_id);
+
+ return(GKI_SUCCESS);
+ }
+ else
+ return(GKI_INVALID_POOL);
+}
+
+
+/*******************************************************************************
+**
+** Function gki_add_to_pool_list
+**
+** Description Adds pool to the pool list which is arranged in the
+** order of size
+**
+** Returns void
+**
+*******************************************************************************/
+static void gki_add_to_pool_list(UINT8 pool_id)
+{
+ INT32 i, j;
+
+ /* Find the position where the specified pool should be inserted into the list */
+ for (i = 0; i < gki_cb.curr_total_no_of_pools; i++)
+ {
+ if (gki_cb.pool_buf_size[pool_id] <= gki_cb.pool_buf_size[gki_cb.pool_list[i]])
+ break;
+ }
+
+ /* Insert the new buffer pool ID into the list of pools */
+ for (j = gki_cb.curr_total_no_of_pools; j > i; j--)
+ {
+ gki_cb.pool_list[j] = gki_cb.pool_list[j-1];
+ }
+
+ /* Prevent warning */
+ if ( i < GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ gki_cb.pool_list[i] = pool_id;
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function gki_remove_from_pool_list
+**
+** Description Removes pool from the pool list. Called when a pool is deleted
+**
+** Returns void
+**
+*******************************************************************************/
+static void gki_remove_from_pool_list(UINT8 pool_id)
+{
+ INT8 i;
+
+ for (i = 0; (i < gki_cb.curr_total_no_of_pools) && (i < GKI_NUM_TOTAL_BUF_POOLS); i++)
+ {
+ if (pool_id == gki_cb.pool_list[i])
+ break;
+ }
+
+/* Prevent warning.
+ * Since GKI_NUM_TOTAL_BUF_POOLS value is 1, this code was not needed */
+/*
+ while (i < (GKI_NUM_TOTAL_BUF_POOLS - 1))
+ {
+ gki_cb.pool_list[i] = gki_cb.pool_list[i+1];
+ i++;
+ }
+*/
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_init_q
+**
+** Description Called by an application to initialize a buffer queue.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_init_q(BUFFER_Q *p_q)
+{
+ p_q->p_first = p_q->p_last = NULL;
+ p_q->count = 0;
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getbuf
+**
+** Description Called by an application to get a free buffer which
+** is of size greater or equal to the requested size.
+**
+** Note: This routine only takes buffers from public pools.
+** It will not use any buffers from pools
+** marked GKI_RESTRICTED_POOL.
+**
+** Parameters size - (input) number of bytes needed.
+**
+** Returns A pointer to the buffer, or NULL if none available
+**
+*******************************************************************************/
+#ifdef TRACE_GKI_BUFFERS
+void *GKI_getbuf_trace(UINT16 size, char *pFile, int linenum)
+#else
+void *GKI_getbuf(UINT16 size)
+#endif
+{
+ UINT8 i, pool_id;
+ void *pp;
+
+ if (unlikely(size == 0))
+ {
+ GKI_exception(GKI_ERROR_BUF_SIZE_ZERO, "getbuf: Size is zero");
+ return(NULL);
+ }
+
+ /* Find the first buffer pool that is public that can hold the desired size */
+ for (i = 0; i < gki_cb.curr_total_no_of_pools; i++)
+ {
+ if (gki_cb.pool_buf_size[gki_cb.pool_list[i]] >= size)
+ break;
+ }
+
+ if (i == gki_cb.curr_total_no_of_pools)
+ {
+ char buff[40];
+ snprintf(buff, sizeof(buff), "getbuf: Size: %u is too big", size);
+ GKI_exception(GKI_ERROR_BUF_SIZE_TOOBIG, buff);
+ return(NULL);
+ }
+
+ _b_in_gki_getbuf = TRUE;
+
+ /* search the public buffer pools that are big enough to hold the size
+ * until a free buffer is found */
+ for ( ; i < gki_cb.curr_total_no_of_pools; i++)
+ {
+ pool_id = gki_cb.pool_list[i];
+
+ /* Only look at PUBLIC buffer pools (bypass RESTRICTED pools) */
+ if (((UINT16)1 << pool_id) & gki_cb.pool_access_mask)
+ continue;
+
+ if ((pp = GKI_getpoolbuf(pool_id)) != NULL)
+ {
+ _b_in_gki_getbuf = FALSE;
+ return(pp);
+ }
+ }
+
+ _b_in_gki_getbuf = FALSE;
+
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getpoolbuf
+**
+** Description Called by an application to get a free buffer from
+** a specific buffer pool.
+**
+** Note: If there are no more buffers available from the pool,
+** the public buffers are searched for an available buffer.
+**
+** Parameters pool_id - (input) pool ID to get a buffer out of.
+**
+** Returns A pointer to the buffer, or NULL if none available
+**
+*******************************************************************************/
+#ifdef TRACE_GKI_BUFFERS
+void *GKI_getpoolbuf_trace(UINT8 pool_id, char *pFile, int linenum)
+#else
+void *GKI_getpoolbuf(UINT8 pool_id)
+#endif
+{
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return(NULL);
+
+ /* Make sure the buffers aren't disturbed til finished with allocation */
+ GKI_disable();
+
+ Q = &gki_cb.freeq[pool_id];
+
+ /* If we have no buffers left, see if we can allocate another segment */
+ if ((Q->cur_cnt >= Q->total) && (gki_cb.pool_additions[pool_id] < MAX_BUFFPOOL_SEGS))
+ {
+ UINT16 count = (gki_cb.pool_max_count[pool_id] + MAX_BUFFPOOL_SEGS - 1) / MAX_BUFFPOOL_SEGS;
+
+ gki_init_free_queue(pool_id, gki_cb.pool_buf_size[pool_id], count, NULL);
+ }
+
+ if (Q->cur_cnt < Q->total)
+ {
+ p_hdr = Q->p_first;
+ Q->p_first = p_hdr->p_next;
+
+ if (!Q->p_first)
+ Q->p_last = NULL;
+
+ if (++Q->cur_cnt > Q->max_cnt)
+ Q->max_cnt = Q->cur_cnt;
+
+ GKI_enable();
+
+ p_hdr->status = BUF_STATUS_UNLINKED;
+ p_hdr->p_next = NULL;
+ p_hdr->Type = 0;
+
+#ifdef TRACE_GKI_BUFFERS
+ p_hdr->pFile = pFile;
+ p_hdr->linenum = linenum;
+ p_hdr->times_alloc++;
+ /* The following is here to allow the test engineer to recognize and */
+ /* set a breakpoint when a particular buffer is allocated for the nth time. */
+ /* Simply change the address and allocation number in the following 'if' */
+ /* statement to reflect the buffer and occurance desired. */
+ if ((p_hdr == (BUFFER_HDR_T *)0x12345678) && (p_hdr->times_alloc == 123))
+ p_hdr->times_alloc = 123;
+#endif
+
+ return((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE));
+ }
+
+ /* If here, no buffers in the specified pool */
+ GKI_enable();
+
+ /* Try for free buffers in public pools. NOTE - no recursion allowed */
+ if (!_b_in_gki_getbuf)
+ return(GKI_getbuf(gki_cb.pool_buf_size[pool_id]));
+ else
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_freebuf
+**
+** Description Called by an application to return a buffer to the free pool.
+**
+** Parameters p_buf - (input) address of the beginning of a buffer.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_freebuf(void *p_buf)
+{
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+ void *pNextBuf;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (!p_buf || gki_chk_buf_damage(p_buf))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Free - Buf Corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *)p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_FREEBUF_BUF_LINKED, "Freeing Linked Buf");
+ return;
+ }
+
+ if (p_hdr->q_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ GKI_exception(GKI_ERROR_FREEBUF_BAD_QID, "Bad Buf QId");
+ return;
+ }
+
+#ifdef TRACE_GKI_BUFFERS
+ if ((p_hdr->pFile == NULL) || (p_hdr->linenum == 0))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Free - no file or line number");
+ }
+#endif
+
+ GKI_disable();
+
+ /*
+ ** Releasing all buffers in the linked list
+ */
+ while (p_buf)
+ {
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *)p_buf - BUFFER_HDR_SIZE);
+
+ pNextBuf = NULL;
+ Q = &gki_cb.freeq[p_hdr->q_id];
+ if (Q->p_last)
+ Q->p_last->p_next = p_hdr;
+ else
+ Q->p_first = p_hdr;
+
+ Q->p_last = p_hdr;
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_FREE;
+ p_hdr->task_id = GKI_INVALID_TASK;
+#ifdef TRACE_GKI_BUFFERS
+ p_hdr->pFile = NULL;
+ p_hdr->linenum = 0;
+#endif
+ if (Q->cur_cnt > 0)
+ Q->cur_cnt--;
+
+ p_buf = pNextBuf;
+ }
+
+ GKI_enable();
+
+ return;
+}
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+/*******************************************************************************
+**
+** Function GKI_get_buf_size
+**
+** Description Called by an application to get the size of a buffer.
+**
+** Parameters p_buf - (input) address of the beginning of a buffer.
+**
+** Returns the size of the buffer
+**
+*******************************************************************************/
+UINT16 GKI_get_buf_size(void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (BUFFER_HDR_T *)((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if ((uintptr_t)p_hdr & 1)
+ {
+ return(0);
+ }
+
+ if (p_hdr->q_id < GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ return(gki_cb.pool_buf_size[p_hdr->q_id]);
+ }
+ else if (p_hdr->q_id == GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ return offsetof(struct btusb_trans, magic) - offsetof(struct btusb_trans, bt_hdr);
+ }
+ else if (p_hdr->q_id == (GKI_NUM_TOTAL_BUF_POOLS + 1))
+ {
+ return offsetof(struct btusb_voice_pkt, magic) - offsetof(struct btusb_voice_pkt, bt_hdr);
+ }
+
+
+ return(0);
+}
+#endif
+
+/*******************************************************************************
+**
+** Function GKI_get_pool_bufsize
+**
+** Description Called by an application to get the size of buffers in a pool
+**
+** Parameters Pool ID.
+**
+** Returns the size of buffers in the pool
+**
+*******************************************************************************/
+UINT16 GKI_get_pool_bufsize(UINT8 pool_id)
+{
+ if (pool_id < GKI_NUM_TOTAL_BUF_POOLS)
+ return(gki_cb.pool_buf_size[pool_id]);
+
+ return(0);
+}
+
+/*******************************************************************************
+**
+** Function GKI_poolfreecount
+**
+** Description Called by an application to get the number of free buffers
+** in the specified buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get the free count of.
+**
+** Returns the number of free buffers in the pool
+**
+*******************************************************************************/
+UINT16 GKI_poolfreecount(UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return(0);
+
+ Q = &gki_cb.freeq[pool_id];
+
+ return((UINT16)(Q->total - Q->cur_cnt));
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_poolutilization
+**
+** Description Called by an application to get the buffer utilization
+** in the specified buffer pool.
+**
+** Parameters pool_id - (input) pool ID to get the free count of.
+**
+** Returns % of buffers used from 0 to 100
+**
+*******************************************************************************/
+UINT16 GKI_poolutilization(UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ return(100);
+
+ Q = &gki_cb.freeq[pool_id];
+
+ if (Q->total == 0)
+ return(100);
+
+ return((Q->cur_cnt * 100) / Q->total);
+}
+
+
+
+/*******************************************************************************
+**
+** Function gki_chk_buf_damage
+**
+** Description Called internally by OSS to check for buffer corruption.
+**
+** Returns TRUE if there is a problem, else FALSE
+**
+*******************************************************************************/
+BOOLEAN gki_chk_buf_damage(void *p_buf)
+{
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+
+ UINT32 *magic;
+ magic = (UINT32 *)((UINT8 *) p_buf + GKI_get_buf_size(p_buf));
+
+ if ((uintptr_t)magic & 1)
+ return(TRUE);
+
+ if (*magic == MAGIC_NO)
+ return(FALSE);
+
+ return(TRUE);
+
+#else
+
+ return(FALSE);
+
+#endif
+}
+
+/*******************************************************************************
+**
+** Function gki_chk_buf_owner
+**
+** Description Called internally by OSS to check if the current task
+** is the owner of the buffer.
+**
+** Returns TRUE if not owner, else FALSE
+**
+*******************************************************************************/
+BOOLEAN gki_chk_buf_owner(void *p_buf)
+{
+ return(FALSE);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_change_buf_owner
+**
+** Description Called to change the task ownership of a buffer.
+**
+** Parameters: p_buf - (input) pointer to the buffer
+** task_id - (input) task id to change ownership to
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_change_buf_owner(void *p_buf, UINT8 task_id)
+{
+ BUFFER_HDR_T *p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ p_hdr->task_id = task_id;
+
+ return;
+}
+
+
+
+/*******************************************************************************
+**
+** Function GKI_buffer_status
+**
+** Description check status of the buffer to see if it is linked
+**
+** Parameters: p_buf - (input) address of the buffer to enqueue
+**
+** Returns state
+* BUF_STATUS_FREE 0
+* BUF_STATUS_UNLINKED 1
+* BUF_STATUS_QUEUED 2
+**
+*******************************************************************************/
+UINT8 GKI_buffer_status(void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ return(p_hdr->status);
+}
+
+/*******************************************************************************
+**
+** Function GKI_enqueue
+**
+** Description Enqueue a buffer at the tail of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enqueue(BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(p_buf))
+ {
+ //printk("Enqueue - Buffer corrupted\n");
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ printk("Enqueue - buf already linked\n");
+ GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Enqueue - buf already linked : p_hdr->status: %d, buffer: 0x%p",p_hdr->status, p_buf);
+ return;
+ }
+
+ GKI_disable();
+
+ /* Since the queue is exposed (C vs C++), keep the pointers in exposed format */
+ /* check p_last != NULL before dereferencing it and if p_last == NULL then p_first == NULL */
+ if (p_q->p_last)
+ {
+ BUFFER_HDR_T *p_last_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_last - BUFFER_HDR_SIZE);
+ p_last_hdr->p_next = p_hdr;
+
+ /* sanity check, this should not happen */
+ if (p_q->p_first == NULL)
+ {
+ printk("ERROR: Enqueue - first == NULL , last != NULL (0x%p)\n", p_q->p_last);
+ }
+ }
+ else
+ {
+ /* sanity check, this should not happen */
+ if (p_q->p_first != NULL)
+ {
+ printk("ERROR: Enqueue - first != NULL (0x%p), last == NULL\n", p_q->p_first);
+ }
+
+ p_q->p_first = p_buf;
+ }
+
+ p_q->p_last = p_buf;
+ p_q->count++;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_QUEUED;
+
+ GKI_enable();
+ // printk("Enqueue: out from GKI_enqueue\n");
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_enqueue_head
+**
+** Description Enqueue a buffer at the head of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enqueue_head(BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ if (gki_chk_buf_damage(p_buf))
+ {
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Enqueue - Buffer corrupted");
+ return;
+ }
+#endif
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->status != BUF_STATUS_UNLINKED)
+ {
+ GKI_exception(GKI_ERROR_ENQUEUE_BUF_LINKED, "Enqeueue head - buf already linked");
+ return;
+ }
+
+ GKI_disable();
+
+ if (p_q->p_first)
+ {
+ p_hdr->p_next = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+ p_q->p_first = p_buf;
+ }
+ else
+ {
+ p_q->p_first = p_buf;
+ p_q->p_last = p_buf;
+ p_hdr->p_next = NULL;
+ }
+ p_q->count++;
+
+ p_hdr->status = BUF_STATUS_QUEUED;
+
+ GKI_enable();
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_dequeue
+**
+** Description Dequeues a buffer from the head of a queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *GKI_dequeue(BUFFER_Q *p_q)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ GKI_disable();
+
+ if (!p_q || !p_q->count)
+ {
+ GKI_enable();
+ return(NULL);
+ }
+
+ p_hdr = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+
+ /* Keep buffers such that GKI header is invisible */
+ if (p_hdr->p_next)
+ p_q->p_first = ((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
+ else
+ {
+ p_q->p_first = NULL;
+ p_q->p_last = NULL;
+ }
+
+ p_q->count--;
+
+ p_hdr->p_next = NULL;
+ p_hdr->status = BUF_STATUS_UNLINKED;
+
+ GKI_enable();
+
+ return((UINT8 *)p_hdr + BUFFER_HDR_SIZE);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_remove_from_queue
+**
+** Description Dequeue a buffer from the middle of the queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+** p_buf - (input) address of the buffer to enqueue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *GKI_remove_from_queue(BUFFER_Q *p_q, void *p_buf)
+{
+ BUFFER_HDR_T *p_prev;
+ BUFFER_HDR_T *p_buf_hdr;
+
+ GKI_disable();
+
+ if (p_buf == p_q->p_first)
+ {
+ GKI_enable();
+ return(GKI_dequeue(p_q));
+ }
+
+ p_buf_hdr = (BUFFER_HDR_T *)((UINT8 *)p_buf - BUFFER_HDR_SIZE);
+ p_prev = (BUFFER_HDR_T *)((UINT8 *)p_q->p_first - BUFFER_HDR_SIZE);
+
+ for ( ; p_prev; p_prev = p_prev->p_next)
+ {
+ /* If the previous points to this one, move the pointers around */
+ if (p_prev->p_next == p_buf_hdr)
+ {
+ p_prev->p_next = p_buf_hdr->p_next;
+
+ /* If we are removing the last guy in the queue, update p_last */
+ if (p_buf == p_q->p_last)
+ p_q->p_last = p_prev + 1;
+
+ /* One less in the queue */
+ p_q->count--;
+
+ /* The buffer is now unlinked */
+ p_buf_hdr->p_next = NULL;
+ p_buf_hdr->status = BUF_STATUS_UNLINKED;
+
+ GKI_enable();
+ return(p_buf);
+ }
+ }
+
+ GKI_enable();
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getfirst
+**
+** Description Return a pointer to the first buffer in a queue
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns NULL if queue is empty, else buffer address
+**
+*******************************************************************************/
+void *GKI_getfirst(BUFFER_Q *p_q)
+{
+ return(p_q->p_first);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_getnext
+**
+** Description Return a pointer to the next buffer in a queue
+**
+** Parameters: p_buf - (input) pointer to the buffer to find the next one from.
+**
+** Returns NULL if no more buffers in the queue, else next buffer address
+**
+*******************************************************************************/
+void *GKI_getnext(void *p_buf)
+{
+ BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (BUFFER_HDR_T *) ((UINT8 *) p_buf - BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ return((UINT8 *)p_hdr->p_next + BUFFER_HDR_SIZE);
+ else
+ return(NULL);
+}
+
+
+
+/*******************************************************************************
+**
+** Function GKI_queue_is_empty
+**
+** Description Check the status of a queue.
+**
+** Parameters: p_q - (input) pointer to a queue.
+**
+** Returns TRUE if queue is empty, else FALSE
+**
+*******************************************************************************/
+BOOLEAN GKI_queue_is_empty(BUFFER_Q *p_q)
+{
+ return((BOOLEAN)(p_q->count == 0));
+}
+
+/*******************************************************************************
+**
+** Function GKI_find_buf_start
+**
+** Description This function is called with an address inside a buffer,
+** and returns the start address of the buffer.
+**
+** The buffer should be one allocated from one of GKI's pools.
+**
+** Parameters: p_user_area - (input) address of anywhere in a GKI buffer.
+**
+** Returns void * - Address of the beginning of the specified buffer if successful,
+** otherwise NULL if unsuccessful
+**
+*******************************************************************************/
+void *GKI_find_buf_start(void *p_user_area)
+{
+ int pool_id, seg_inx;
+ UINT16 size;
+ UINT32 yy;
+ UINT8 *p_ua = (UINT8 *)p_user_area;
+ FREE_QUEUE_T *p_fq = gki_cb.freeq;
+
+ for (pool_id = 0; pool_id < gki_cb.curr_total_no_of_pools; pool_id++, p_fq++)
+ {
+ for (seg_inx = 0; (seg_inx < MAX_BUFFPOOL_SEGS) && (p_fq->seg_start[seg_inx] != NULL); seg_inx++)
+ {
+ if ((p_ua > p_fq->seg_start[seg_inx]) && (p_ua < p_fq->seg_end[seg_inx]))
+ {
+ yy = (UINT32)(p_ua - p_fq->seg_start[seg_inx]);
+
+ size = gki_cb.pool_buf_size[pool_id] + BUFFER_PADDING_SIZE;
+
+ yy = (yy / size) * size;
+
+ return((void *) (p_fq->seg_start[seg_inx] + yy + sizeof(BUFFER_HDR_T)) );
+ }
+ }
+ }
+
+ /* If here, invalid address - not in one of our buffers */
+ GKI_exception(GKI_ERROR_BUF_SIZE_ZERO, "GKI_get_buf_start:: bad addr");
+
+ return(NULL);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_create_pool
+**
+** Description Called by applications to create a buffer pool.
+**
+** Parameters: size - (input) length (in bytes) of each buffer in the pool
+** count - (input) number of buffers to allocate for the pool
+** permission - (input) restricted or public access?
+** (GKI_PUBLIC_POOL or GKI_RESTRICTED_POOL)
+** p_mem_pool - (input) pointer to an OS memory pool, NULL if not provided
+**
+** Returns the buffer pool ID, which should be used in calls to
+** GKI_getpoolbuf(). If a pool could not be created, this
+** function returns 0xff.
+**
+*******************************************************************************/
+UINT8 GKI_create_pool(UINT16 size, UINT16 count, UINT8 permission, void *p_mem_pool)
+{
+ int xx;
+
+ /* First make sure the size of each pool has a valid size with room for the header info */
+ if (size > MAX_USER_BUF_SIZE)
+ return(GKI_INVALID_POOL);
+
+ /* First, look for an unused pool */
+ for (xx = 0; xx < GKI_NUM_TOTAL_BUF_POOLS; xx++)
+ {
+ if (!gki_cb.pool_buf_size[xx])
+ break;
+ }
+
+ if (xx == GKI_NUM_TOTAL_BUF_POOLS)
+ return(GKI_INVALID_POOL);
+
+ GKI_disable();
+
+ /* Ensure an even number of longwords */
+ size = ((size + 3) / 4) * 4;
+
+ gki_cb.pool_buf_size[xx] = size;
+ gki_cb.pool_max_count[xx] = count;
+ gki_cb.pool_additions[xx] = 0;
+
+ /* If memory was not passed in, create the pool in segments */
+ if (!p_mem_pool)
+ count = (count + MAX_BUFFPOOL_SEGS - 1) / MAX_BUFFPOOL_SEGS;
+
+ /* Initialize the new pool */
+ if (gki_init_free_queue(xx, size, count, p_mem_pool))
+ {
+ gki_add_to_pool_list(xx);
+
+ (void) GKI_set_pool_permission(xx, permission);
+ gki_cb.curr_total_no_of_pools++;
+ }
+ else
+ {
+ /* Failed to create the pool ? */
+ gki_cb.pool_buf_size[xx] = 0;
+ GKI_enable();
+ return(GKI_INVALID_POOL);
+ }
+
+ /* If memory was passed in, no pool additions allowed */
+ if (p_mem_pool)
+ gki_cb.pool_additions[xx] = MAX_BUFFPOOL_SEGS;
+
+ GKI_enable();
+ return(xx);
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_delete_pool
+**
+** Description Called by applications to delete a buffer pool. The function
+** calls the operating specific function to free the actual memory.
+** An exception is generated if an error is detected.
+**
+** Parameters: pool_id - (input) Id of the poll being deleted.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_delete_pool(UINT8 pool_id)
+{
+ FREE_QUEUE_T *Q;
+ int xx;
+
+ if ( (pool_id >= GKI_NUM_TOTAL_BUF_POOLS) || (!gki_cb.pool_buf_size[pool_id]) )
+ return;
+
+ GKI_disable();
+
+ Q = &gki_cb.freeq[pool_id];
+
+ Q->total = 0;
+ Q->cur_cnt = 0;
+ Q->max_cnt = 0;
+ Q->p_first = NULL;
+ Q->p_last = NULL;
+
+ for (xx = 0; xx < MAX_BUFFPOOL_SEGS; xx++)
+ {
+ if (Q->seg_start[xx])
+ gki_release_os_memory(Q->seg_start[xx]);
+
+ Q->seg_start[xx] = NULL;
+ Q->seg_end[xx] = NULL;
+ }
+
+ gki_cb.pool_buf_size[pool_id] = 0;
+
+ gki_remove_from_pool_list(pool_id);
+ gki_cb.curr_total_no_of_pools--;
+
+ GKI_enable();
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_chk_buf_pool_damage
+**
+** Description Called internally by OSS to check for buffer queue corruption.
+**
+** Returns TRUE if there is a problem, else FALSE
+**
+*******************************************************************************/
+BOOLEAN GKI_chk_buf_pool_damage(UINT8 pool_id)
+{
+#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
+ int i;
+ FREE_QUEUE_T *Q;
+ BUFFER_HDR_T *p_hdr;
+ UINT8 *p_buf;
+
+ if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
+ {
+ GKI_exception(GKI_ERROR_BUF_POOL_CORRUPT, "pool_id out of range");
+ return(TRUE);
+ }
+
+ /* Make sure the buffers aren't disturbed til finished with checking */
+ GKI_disable();
+
+ Q = &gki_cb.freeq[pool_id];
+ if (!Q->p_first)
+ {
+ if (Q->cur_cnt != Q->total)
+ {
+ GKI_enable();
+ GKI_exception(GKI_ERROR_BUF_POOL_CORRUPT, "p_first is NULL in non-empty pool");
+ return(TRUE);
+ }
+ return(FALSE);
+ }
+ p_hdr = Q->p_first;
+ i = 1;
+ while (p_hdr->p_next)
+ {
+ p_hdr = p_hdr->p_next;
+ p_buf = ((UINT8 *)p_hdr + BUFFER_HDR_SIZE);
+ if (gki_chk_buf_damage(p_buf))
+ {
+ GKI_enable();
+ GKI_exception(GKI_ERROR_BUF_CORRUPTED, "CHk Pool - Buf Corrupted");
+ return(TRUE);
+ }
+ i++;
+ }
+ if (p_hdr != Q->p_last)
+ {
+ GKI_enable();
+ GKI_exception(GKI_ERROR_BUF_POOL_CORRUPT, "last buffer in chain != p_last");
+ return(TRUE);
+ }
+ if (i != (Q->total - Q->cur_cnt))
+ {
+ GKI_enable();
+ GKI_exception(GKI_ERROR_BUF_POOL_CORRUPT, "cur_cnt != number of buffers in pool");
+ return(TRUE);
+ }
+
+ GKI_enable();
+ return(FALSE);
+
+#else
+
+ return(FALSE);
+
+#endif
+}
+
diff --git a/src/gki/gki_klinux.c b/src/gki/gki_klinux.c
new file mode 100755
index 0000000..fb424ee
--- a/dev/null
+++ b/src/gki/gki_klinux.c
@@ -0,0 +1,271 @@
+/*
+ *
+ * gki_klinux.c
+ *
+ *
+ *
+ * Copyright (C) 2011-2012 Broadcom Corporation.
+ *
+ *
+ *
+ * This software is licensed under the terms of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation (the "GPL"), and may
+ * be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GPL for more details.
+ *
+ *
+ * A copy of the GPL is available at http://www.broadcom.com/licenses/GPLv2.php
+ * or by writing to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA
+ *
+ *
+ */
+
+#include <linux/version.h>
+#include <linux/slab.h>
+
+/* The location folder of the semaphore.h file changed at Kernel version 2.6.26 */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
+#include <linux/semaphore.h>
+#else
+#include <asm/semaphore.h>
+#endif
+
+#include "target.h"
+#include "gki_int.h"
+#include "bt_types.h"
+
+
+volatile unsigned int _gki_lock_nesting = 0;
+volatile pid_t LockThread = 0xffff; // thread currently holding the spinlock
+DEFINE_SPINLOCK(Lock);
+volatile unsigned long Kirql; // saved execution priority
+
+/* Define the structure that holds the GKI variables
+*/
+#ifndef _BT_DYNAMIC_MEMORY
+tGKI_CB gki_cb = {0};
+#else
+tGKI_CB *gp_gki_cb = NULL;
+#endif
+
+void LogMsg(int TraceMask, const char *format, ...)
+{
+ char temp1[400];
+ char *temp = temp1;
+ va_list Next;
+ int len;
+
+ // Go ahead and trace...
+ va_start(Next, format);
+ len = _vsnprintf(temp, 380, format, Next);
+ va_end(Next);
+
+
+ if ((len < 0) || (len > 380))
+ {
+ len = strlen(temp);
+ }
+
+ if (len > 380)
+ {
+ temp[380] = 0;
+ len = 380;
+
+ }
+
+ if (temp[len - 1] >= ' ')
+ {
+ temp[len] = '\n';
+ temp[len + 1] = '\0';
+ }
+
+
+ printk("%s", temp);
+ return;
+}
+
+/*******************************************************************************
+**
+** Function GKI_init
+**
+** Description This function is called once at startup to initialize
+** all the timer structures.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_init(void)
+{
+ memset(&gki_cb, 0, sizeof(gki_cb));
+
+ gki_buffer_init();
+
+ spin_lock_init(&Lock);
+ gki_cb.IsRunning = TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_shutdown
+**
+** Description This function is called to shut down GKI
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_shutdown(void)
+{
+ int i;
+
+ if (!gki_cb.IsRunning)
+ return;
+
+ gki_cb.IsRunning = FALSE;
+
+#if (GKI_USE_DYNAMIC_BUFFERS == TRUE)
+
+ for (i = 0; i < GKI_NUM_TOTAL_BUF_POOLS; i++)
+ {
+ if (gki_cb.pool_buf_size[i])
+ GKI_delete_pool((UINT8)i);
+ }
+
+#endif
+
+}
+
+/*******************************************************************************
+**
+** Function GKI_enable
+**
+** Description This function enables interrupts.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_enable(void)
+{
+ spin_unlock_irqrestore(&Lock, Kirql);
+}
+
+/*******************************************************************************
+**
+** Function GKI_disable
+**
+** Description This function disables interrupts.
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_disable(void)
+{
+ volatile unsigned long tmp_irql;
+
+ spin_lock_irqsave(&Lock, tmp_irql);
+
+ // OK, we've acquired the spinlock. It means that
+ // the other guy has released it already and we can
+ // safely overwrite his saved irql...
+ Kirql = tmp_irql;
+}
+
+
+/*******************************************************************************
+**
+** Function GKI_exception
+**
+** Description This function throws an exception.
+** This is normally only called for a non recoverable error.
+**
+** Parameters: code - (input) The code for the error
+** msg - (input) The message that has to be logged
+**
+** Returns void
+**
+*******************************************************************************/
+void GKI_exception(UINT16 code, const char *msg, ...)
+{
+ char buff[MAX_EXCEPTION_MSGLEN];
+ va_list Next;
+ int len;
+
+ va_start(Next, msg);
+ len = vsnprintf(buff, MAX_EXCEPTION_MSGLEN - 1, msg, Next);
+ va_end(Next);
+
+ LogMsg(-1, "GKI_exception: Entry Code %d Message %s\n", code, buff);
+ GKI_disable();
+
+ if (gki_cb.ExceptionCnt < MAX_EXCEPTION)
+ {
+ EXCEPTION_T *pExp;
+
+ pExp = &gki_cb.Exception[gki_cb.ExceptionCnt++];
+ pExp->type = code;
+ pExp->taskid = 0;
+ strncpy((INT8 *)pExp->msg, msg, MAX_EXCEPTION_MSGLEN - 1);
+ }
+
+ GKI_enable();
+
+ LogMsg(-1, "GKI_Exception called with code: %d", code);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function gki_reserve_os_memory
+**
+** Description This function allocates memory
+**
+** Parameters: size - (input) The size of the memory that has to be
+** allocated
+**
+** Returns the address of the memory allocated, or NULL if failed
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. It is only called from within GKI if dynamic
+** buffer pools are used.
+**
+*******************************************************************************/
+void *gki_reserve_os_memory(UINT32 size)
+{
+ void *p;
+ p = kmalloc(size, GFP_ATOMIC);
+ if (p == NULL)
+ return NULL;
+ memset(p, 0x00, sizeof(*p));
+ return p;
+}
+
+/*******************************************************************************
+**
+** Function gki_release_os_memory
+**
+** Description This function frees memory
+**
+** Parameters: size - (input) The address of the memory that has to be
+** freed
+**
+** Returns void
+**
+** NOTE This function is NOT called by the Widcomm stack and
+** profiles. It is only called from within GKI if dynamic
+** buffer pools are used.
+**
+*******************************************************************************/
+void gki_release_os_memory(void *p_mem)
+{
+ kfree(p_mem);
+
+ return;
+}
+
+