author | Weiguang Ruan <Weiguang.ruan@amlogic.com> | 2016-01-27 06:52:08 (GMT) |
---|---|---|
committer | Weiguang Ruan <Weiguang.ruan@amlogic.com> | 2016-01-27 06:52:08 (GMT) |
commit | 3935905e634318e3b3affbd569aea6dedb433eb1 (patch) | |
tree | 7eca3bbda26602c3688e761c152573c3c2457f49 | |
parent | af8b243c66ebd4e40bed51b4114d6c7dcb45293f (diff) | |
download | btusb-3935905e634318e3b3affbd569aea6dedb433eb1.zip btusb-3935905e634318e3b3affbd569aea6dedb433eb1.tar.gz btusb-3935905e634318e3b3affbd569aea6dedb433eb1.tar.bz2 |
PD #xxxx bt: add support for AP6269
Change-Id: I1a0495cd4b4aab016864780fbe60ae6ebb75f0b3
63 files changed, 29563 insertions, 0 deletions
diff --git a/btusb_1_6_29_1/.svn/all-wcprops b/btusb_1_6_29_1/.svn/all-wcprops new file mode 100755 index 0000000..cccf6b0 --- a/dev/null +++ b/btusb_1_6_29_1/.svn/all-wcprops @@ -0,0 +1,23 @@ +K 25 +svn:wc:ra_dav:version-url +V 68 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1 +END +Makefile +K 25 +svn:wc:ra_dav:version-url +V 77 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/Makefile +END +Release_btusb.txt +K 25 +svn:wc:ra_dav:version-url +V 86 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/Release_btusb.txt +END +cpmod +K 25 +svn:wc:ra_dav:version-url +V 74 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/cpmod +END diff --git a/btusb_1_6_29_1/.svn/entries b/btusb_1_6_29_1/.svn/entries new file mode 100755 index 0000000..f497902 --- a/dev/null +++ b/btusb_1_6_29_1/.svn/entries @@ -0,0 +1,136 @@ +10 + +dir +941 +http://10.10.29.8/svn/SiP/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1 +http://10.10.29.8/svn/SiP + + + +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + +e48500f2-7125-4e9d-852c-c0ee60673d08 + +inc +dir + +Makefile +file + + + + +2014-08-14T08:53:29.628694Z +613a7ac6f3c22a8df0d808dc9ea41cab +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +2281 + +Release_btusb.txt +file + + + + +2014-08-14T08:53:29.628694Z +5ae7fa642bcfd9d734a5a2d0e73f29ef +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +1168 + +cpmod +file + + + + +2014-08-14T08:53:29.684694Z +f5fbc1e2f70baab680ccd2922670616a +2014-08-14T09:21:52.961444Z +725 +luke +has-props + + + + + + + + + + + + + + + + + + + + +69 + +src +dir + diff --git a/btusb_1_6_29_1/.svn/prop-base/cpmod.svn-base b/btusb_1_6_29_1/.svn/prop-base/cpmod.svn-base new file mode 100755 index 0000000..869ac71 --- a/dev/null +++ b/btusb_1_6_29_1/.svn/prop-base/cpmod.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/btusb_1_6_29_1/.svn/text-base/Makefile.svn-base b/btusb_1_6_29_1/.svn/text-base/Makefile.svn-base new file mode 100755 index 0000000..6180ea6 --- a/dev/null +++ b/btusb_1_6_29_1/.svn/text-base/Makefile.svn-base @@ -0,0 +1,87 @@ + +# 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 + +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 +KDIR := /lib/modules/$(shell uname -r)/build + +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 + +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 + +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" + diff --git a/btusb_1_6_29_1/.svn/text-base/Release_btusb.txt.svn-base b/btusb_1_6_29_1/.svn/text-base/Release_btusb.txt.svn-base new file mode 100755 index 0000000..f6228fe --- a/dev/null +++ b/btusb_1_6_29_1/.svn/text-base/Release_btusb.txt.svn-base @@ -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/btusb_1_6_29_1/.svn/text-base/cpmod.svn-base b/btusb_1_6_29_1/.svn/text-base/cpmod.svn-base new file mode 100755 index 0000000..28919a8 --- a/dev/null +++ b/btusb_1_6_29_1/.svn/text-base/cpmod.svn-base @@ -0,0 +1 @@ +cp -v btusb.ko /lib/modules/$(uname -r)/kernel/drivers/brcm/btusb.ko diff --git a/btusb_1_6_29_1/Makefile b/btusb_1_6_29_1/Makefile new file mode 100755 index 0000000..12b77ca --- a/dev/null +++ b/btusb_1_6_29_1/Makefile @@ -0,0 +1,86 @@ +# Specify Include folders +EXTRA_CFLAGS += -I$(src) +EXTRA_CFLAGS += -I$(src)/inc +EXTRA_CFLAGS += -I$(src)/src +EXTRA_CFLAGS += -I$(src)/src/gki + +EXTRA_CFLAGS += -DEXPORT_SYMTAB + +LITE ?= FALSE +ifeq ($(strip $(LITE)),TRUE) +EXTRA_CFLAGS += -DBUILDCFG +EXTRA_CFLAGS += -DBTUSB_LITE +EXTRA_CFLAGS += -I$(src)/../btpcm +EXTRA_CFLAGS += -I$(src)/../btsbc +COMPONENTS_PATH := $(src)/../../../../../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$(src)/../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 + +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 +KDIR := /lib/modules/$(shell uname -r)/build + +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) src=$(PWD) modules + +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 + +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" + diff --git a/btusb_1_6_29_1/Release_btusb.txt b/btusb_1_6_29_1/Release_btusb.txt new file mode 100755 index 0000000..f6228fe --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/cpmod b/btusb_1_6_29_1/cpmod new file mode 100755 index 0000000..28919a8 --- a/dev/null +++ b/btusb_1_6_29_1/cpmod @@ -0,0 +1 @@ +cp -v btusb.ko /lib/modules/$(uname -r)/kernel/drivers/brcm/btusb.ko diff --git a/btusb_1_6_29_1/inc/.svn/all-wcprops b/btusb_1_6_29_1/inc/.svn/all-wcprops new file mode 100755 index 0000000..7907fbf --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/all-wcprops @@ -0,0 +1,89 @@ +K 25 +svn:wc:ra_dav:version-url +V 72 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc +END +btusb.h +K 25 +svn:wc:ra_dav:version-url +V 80 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb.h +END +btusb_lite_hci.h +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb_lite_hci.h +END +btusbext.h +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusbext.h +END +btusb_lite_av.h +K 25 +svn:wc:ra_dav:version-url +V 88 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb_lite_av.h +END +gki_int.h +K 25 +svn:wc:ra_dav:version-url +V 82 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/gki_int.h +END +hcidefs.h +K 25 +svn:wc:ra_dav:version-url +V 82 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/hcidefs.h +END +target.h +K 25 +svn:wc:ra_dav:version-url +V 81 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/target.h +END +bt_types.h +K 25 +svn:wc:ra_dav:version-url +V 83 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/bt_types.h +END +btusb_lite_avdt.h +K 25 +svn:wc:ra_dav:version-url +V 90 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb_lite_avdt.h +END +gki.h +K 25 +svn:wc:ra_dav:version-url +V 78 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/gki.h +END +bt_target.h +K 25 +svn:wc:ra_dav:version-url +V 84 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/bt_target.h +END +btusb_lite.h +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb_lite.h +END +btusb_lite_l2c.h +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/btusb_lite_l2c.h +END +data_types.h +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc/data_types.h +END diff --git a/btusb_1_6_29_1/inc/.svn/entries b/btusb_1_6_29_1/inc/.svn/entries new file mode 100755 index 0000000..0300d47 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/entries @@ -0,0 +1,504 @@ +10 + +dir +941 +http://10.10.29.8/svn/SiP/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/inc +http://10.10.29.8/svn/SiP + + + +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + +e48500f2-7125-4e9d-852c-c0ee60673d08 + +gki_int.h +file + + + + +2014-08-14T08:53:29.672694Z +e12699f83ff72e3ea04eb7b4e695d999 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +5217 + +hcidefs.h +file + + + + +2014-08-14T08:53:29.684694Z +dc513c53ca589714768661c65bbd4ba6 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +98140 + +target.h +file + + + + +2014-08-14T08:53:29.684694Z +83d3483cbd12dab6fc402e79269e1a05 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +2927 + +bt_types.h +file + + + + +2014-08-14T08:53:29.672694Z +d4dac46e67c5b708bb4ac7f465ca6bef +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +2658 + +btusb_lite_avdt.h +file + + + + +2014-08-14T08:53:29.644694Z +81424e4fa8b627779450ac671f8e97ed +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +5378 + +gki.h +file + + + + +2014-08-14T08:53:29.664694Z +01a5cb997d8a01694f2c0a7edb41da11 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +5192 + +bt_target.h +file + + + + +2014-08-14T08:53:29.684694Z +d41d8cd98f00b204e9800998ecf8427e +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +0 + +btusb_lite.h +file + + + + +2014-08-14T08:53:29.652694Z +97874c1b893d5614d484d7de067947a0 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +5144 + +btusb_lite_l2c.h +file + + + + +2014-08-14T08:53:29.664694Z +3fa9e2192480e62e9e46499deb2bee84 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +3040 + +data_types.h +file + + + + +2014-08-14T08:53:29.684694Z +a14133e6bdadaeee7a812045308ceee7 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +1689 + +btusb_lite_hci.h +file + + + + +2014-08-14T08:53:29.640694Z +4ed1c472b2461f945a9f9a4b7f0f9f56 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +2389 + +btusb.h +file + + + + +2014-08-14T08:53:29.672694Z +4229196b0ea098c53b26f8482495f2d0 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +12940 + +btusbext.h +file + + + + +2014-08-14T08:53:29.660694Z +e41460795e6d063a6e512457c955ad1d +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +5138 + +btusb_lite_av.h +file + + + + +2014-08-14T08:53:29.652694Z +7e808f53488a2e2274a186adc40502c6 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +4745 + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/bt_target.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/bt_target.h.svn-base new file mode 100755 index 0000000..e69de29 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/bt_target.h.svn-base diff --git a/btusb_1_6_29_1/inc/.svn/text-base/bt_types.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/bt_types.h.svn-base new file mode 100755 index 0000000..f214d54 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/bt_types.h.svn-base @@ -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/btusb_1_6_29_1/inc/.svn/text-base/btusb.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb.h.svn-base new file mode 100755 index 0000000..aa7534d --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb.h.svn-base @@ -0,0 +1,367 @@ +/* + * + * btusb.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_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 "gki_int.h" +#include "btusbext.h" + +#ifdef BTUSB_LITE +#include "btusb_lite.h" +#endif + +/* 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 +#else +#define BTUSB_PDE_DATA(inode) PDE_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 +// bit18 : enable GKI buffer check +// bit19 : enable RX ACL size check +#define BTUSB_DBG_MSG 0x0001 +#define BTUSB_INFO_MSG 0x0002 +#define BTUSB_DUMP_MSG 0x0100 +#define BTUSB_GKI_CHK_MSG 0x0400 +//#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_DEBUG "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__) + +// TBD: how do we assign the minor range? +#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 258 + +// 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 // should 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 // for now should match 2 urbs +#define BTUSB_NUM_OF_VOICE_TX_BUFFERS 32 + +#define SCO_RX_BUFF_SIZE 360 +#define SCO_RX_MAX_LEN 240 + +#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)) + + +#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 */ + +// +// 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 +}; + +// +// This data structure is used for isochronous transfers +// +typedef struct +{ + // These two must go in sequence + void *dev; + unsigned char *packet; + int length; + unsigned long index; + int used; + + // URB & related info must be the last fields + struct urb urb; + // enough to cover the longest request + struct usb_iso_packet_descriptor IsoPacket[(BTUSB_MAXIMUM_TX_VOICE_SIZE /9) + 1]; +} tBTUSB_ISO_ELEMENT; + +// BTUSB transaction +typedef struct +{ + /* 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 USB data is received */ + UINT8 *dma_buffer; + /* DMA structure */ + dma_addr_t dma; + /* URB for this transaction */ + struct urb *p_urb; + void *context; +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + /* Magic number */ + UINT32 magic; +#endif +} tBTUSB_TRANSACTION; + +// Voice channel descriptor +typedef struct +{ + unsigned short sco_handle; + unsigned char burst; +} tBTUSB_SCO_INFO; + +typedef struct +{ + int used; + BT_HDR *p_msg; + tBTUSB_SCO_INFO info; +} tBTUSB_VOICE_CHANNEL; + +#define BTUSB_QUIRK_ZLP_TX_REQ (1 << 0) +#define BTUSB_QUIRK_ZLP_RX_WA (1 << 1) + +// Define the main structure +typedef struct btusb_cb +{ + struct usb_device *p_udev; // the 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; // the acl bulk in endpoint + struct usb_host_endpoint *p_acl_out; // the acl bulk out endpoint + struct usb_host_endpoint *p_diag_in; // the diag bulk in endpoint + struct usb_host_endpoint *p_diag_out; // the diag bulk out endpoint + struct usb_host_endpoint *p_event_in; // the interrupt in endpoint + struct usb_host_endpoint *p_voice_out; // iso out endpoint + struct usb_host_endpoint *p_voice_in; // voice in endpoint + struct ktermios kterm; // TTY emulation + struct mutex open_mutex; // protect concurrent open accesses + spinlock_t tasklet_lock; + struct kref kref; + tBTUSB_STATS stats; + bool opened; + 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_debug_pde; + bool scosniff_active; + struct proc_dir_entry *p_scosniff_pde; + struct list_head scosniff_list; + struct completion scosniff_completion; + + // Command transmit path + tBTUSB_TRANSACTION 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 + tBTUSB_TRANSACTION event_array[BTUSB_NUM_OF_EVENT_BUFFERS]; + struct usb_anchor event_submitted; + + // ACL receive path + tBTUSB_TRANSACTION acl_rx_array[BTUSB_NUM_OF_ACL_RX_BUFFERS]; + struct usb_anchor acl_rx_submitted; + + // ACL transmit path + tBTUSB_TRANSACTION acl_tx_array[BTUSB_NUM_OF_ACL_TX_BUFFERS]; + struct usb_anchor acl_tx_submitted; + + // Diagnostics receive path + tBTUSB_TRANSACTION diag_rx_array[BTUSB_NUM_OF_DIAG_RX_BUFFERS]; + struct usb_anchor diag_rx_submitted; + + // Diagnostics transmit path + tBTUSB_TRANSACTION diag_tx_array[BTUSB_NUM_OF_DIAG_TX_BUFFERS]; + struct usb_anchor diag_tx_submitted; + + // Voice + tBTUSB_TRANSACTION voice_rx_array[BTUSB_NUM_OF_VOICE_RX_BUFFERS]; + struct usb_anchor voice_rx_submitted; + + tBTUSB_VOICE_CHANNEL voice_channels[3]; + unsigned short desired_packet_size; + unsigned int pending_bytes; + BT_HDR **pp_pending_msg; + unsigned char pending_hdr[BTUSB_VOICE_HEADER_SIZE]; + unsigned int pending_hdr_size; + + BT_HDR *p_write_msg; + + unsigned long room_for_device_object; // must be here before the pending buffer + tBTUSB_ISO_ELEMENT *p_voicetxIrpList; + unsigned long voicetxIrpIndex; + + BUFFER_Q rx_queue; + BT_HDR *p_rx_msg; + BUFFER_Q tx_queue; + +#ifdef BTUSB_LITE + struct btusb_lite_cb lite_cb; +#endif +} tBTUSB_CB; + + +// +// Function prototypes +// +void btusb_delete(struct kref *kref); + +void btusb_tx_task(unsigned long arg); + +void btusb_cancel_voice(tBTUSB_CB *p_dev); +void btusb_cancel_urbs(tBTUSB_CB *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(tBTUSB_CB *p_dev, struct usb_anchor *p_anchor, tBTUSB_TRANSACTION *p_trans, int mem_flags); +void btusb_submit_voice_rx(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, int mem_flags); + +/* bt controller to host routines */ +void btusb_enqueue(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, UINT8 hcitype); +void btusb_dequeued(tBTUSB_CB *p_dev, BT_HDR *p_msg); + +void btusb_dump_data(const UINT8 *p, int len, const char *p_title); + +void btusb_cmd_complete(struct urb *p_urb); +void btusb_write_complete(struct urb *p_urb); +void btusb_voicerx_complete(struct urb *p_urb); + +// 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 + +// proc standard interface +int btusb_debug_open(struct inode *inode, struct file *file); +ssize_t btusb_debug_write(struct file *file, const char *buf, size_t count, loff_t *pos); + +ssize_t btusb_scosniff_read(struct file *file, char __user *buf, size_t size, loff_t *ppos); +int btusb_scosniff_open(struct inode *inode, struct file *file); +int btusb_scosniff_release(struct inode *inode, struct file *file); + +// +// Globals +// +extern struct usb_driver btusb_driver; +extern bool autopm; + +#endif // BTUSB_H diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite.h.svn-base new file mode 100755 index 0000000..66faaaa --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite.h.svn-base @@ -0,0 +1,198 @@ +/* + * + * 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 + +/* Forward declaration of BTUSB CB */ +struct btusb_cb; + +#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 +{ + int 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; +}; + +typedef enum +{ + BTPCM_LITE_PCM_CLOSED = 0, + BTPCM_LITE_PCM_OPENED, + BTPCM_LITE_PCM_CONFIGURED, + BTPCM_LITE_PCM_STARTED +} btusb_lite_pcm_state_t; + +struct btusb_lite_pcm_ccb +{ + btusb_lite_pcm_state_t state; + int channel; + 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 curr_mtu; + 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 +{ + struct proc_dir_entry *p_lite_pde; + int 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; +}; + +/******************************************************************************* + ** + ** Function btusb_lite_create + ** + ** Description Create BTUSB Lite interface + ** + ** Returns status (< 0 if error) + ** + *******************************************************************************/ +int btusb_lite_create(struct btusb_cb *p_dev, struct usb_interface *p_interface); + +/******************************************************************************* + ** + ** Function btusb_lite_delete + ** + ** Description Delete BTUSB Lite interface + ** + ** Returns none + ** + *******************************************************************************/ +void btusb_lite_delete(struct btusb_cb *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_cb *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_cb *p_dev); + +#endif /* BTUSB_LITE_H*/ + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_av.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_av.h.svn-base new file mode 100755 index 0000000..f19ad0b --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_av.h.svn-base @@ -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_cb *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_cb *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_cb *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_cb *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_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt); + +#endif /* BTUSB_LITE_AV_H*/ + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_avdt.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_avdt.h.svn-base new file mode 100755 index 0000000..3538cc7 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_avdt.h.svn-base @@ -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_cb *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_cb *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_cb *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_cb *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_cb *p_dev, UINT8 avdt_handle, + BOOLEAN enable, UINT8 scms_hdr); + +#endif /* BTUSB_LITE_AVDT_H*/ + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_hci.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_hci.h.svn-base new file mode 100755 index 0000000..bb88d26 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_hci.h.svn-base @@ -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_cb *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_cb *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_cb *p_dev, UINT8 *p_data, int length); + +#endif /* BTUSB_LITE_HCI_H */ + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_l2c.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_l2c.h.svn-base new file mode 100755 index 0000000..bf5aa6a --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusb_lite_l2c.h.svn-base @@ -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_cb *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_cb *p_dev, UINT16 local_cid); + +/******************************************************************************* +** +** Function btusb_lite_l2c_send +** +** Description Send L2CAP packet +** +** Returns Status +** +*******************************************************************************/ +int btusb_lite_l2c_send(struct btusb_cb *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_cb *p_dev, UINT16 con_hdl, UINT16 num_cplt_pck); + +#endif /* BTUSB_LITE_L2C_H*/ + diff --git a/btusb_1_6_29_1/inc/.svn/text-base/btusbext.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/btusbext.h.svn-base new file mode 100755 index 0000000..ccdff66 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/btusbext.h.svn-base @@ -0,0 +1,169 @@ +/* + * + * 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; + + // ACL RX counters + unsigned long acl_rx_submit_ok; + unsigned long acl_rx_submit_err; + unsigned long acl_rx_completed; + 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_completed; + 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_completed; + unsigned long event_resubmit; + unsigned long event_bytes; + + // Number of Write IRPs submitted + unsigned long writes_submitted; + + // Number of Write IRPs submitted in error + unsigned long writes_submitted_error; + + // Number of Write IRPs completed + unsigned long writes_completed; + + // Number of Write IRPs completed in error + unsigned long writes_completed_error; + + // Number of Command IRPs submitted + unsigned long commands_submitted; + + // Number of Command IRPs submitted in error + unsigned long commands_submitted_error; + + // Number of Command IRPs completed + unsigned long commands_completed; + + // Number of Command IRPs completed in error + unsigned long commands_completed_error; + + // Number of voice reqs submitted to the USB software stack + unsigned long voicerx_submitted; + + // Number of voice rx submitted in error + unsigned long voicerx_submitted_error; + + // Number of voice req completions from the USB software stack + unsigned long voicerx_completed; + + // Number of Voice req completions in error + unsigned long voicerx_completed_error; + + // Number of bad voice RX packets received + unsigned long voicerx_bad_packets; + + // Bytes received altogether + unsigned long voicerx_raw_bytes; + + // Bytes skipped + unsigned long voicerx_skipped_bytes; + + // SCO headers split across packets + unsigned long voicerx_split_hdr; + + // Voice frames discarded due to no headers in data + unsigned long voicerx_disc_nohdr; + + // Number of Voice Tx reqs submitted + unsigned long voicetx_submitted; + + // Number of voice tx submitted in error + unsigned long voicetx_submitted_error; + + // Number of Voice Tx reqs completed + unsigned long voicetx_completed; + + // Number of Voice Tx reqs completed in error + unsigned long voicetx_completed_error; + + // Number of Voice Tx not submitted due to no room on the tx queue + unsigned long voicetx_disc_nobuf; + + // Number of Voice tx not submitted due to too long data + unsigned long voicetx_disc_toolong; + + /* number of Voice packet pending */ + unsigned long voice_tx_cnt; + + /* max number of Voice packet pending */ + unsigned long voice_max_tx_cnt; + + /* max delta time between 2 consecutive tx done routine in us */ + 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 + +#endif // BTUSBEXT_H diff --git a/btusb_1_6_29_1/inc/.svn/text-base/data_types.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/data_types.h.svn-base new file mode 100755 index 0000000..e8ccf4b --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/data_types.h.svn-base @@ -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/btusb_1_6_29_1/inc/.svn/text-base/gki.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/gki.h.svn-base new file mode 100755 index 0000000..8b04756 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/gki.h.svn-base @@ -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/btusb_1_6_29_1/inc/.svn/text-base/gki_int.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/gki_int.h.svn-base new file mode 100755 index 0000000..f210e58 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/gki_int.h.svn-base @@ -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/btusb_1_6_29_1/inc/.svn/text-base/hcidefs.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/hcidefs.h.svn-base new file mode 100755 index 0000000..ec2e802 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/hcidefs.h.svn-base @@ -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)) + +/* +** Defentions 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 */ + +/* +** Defentions for HCI Error Codes that are past in the events +*/ +#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 + +/* +** Defentions for 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 defenitions */ +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 +#define HCI_ROLE_UNKNOWN 0xff + +/* HCI mode defenitions */ +#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/btusb_1_6_29_1/inc/.svn/text-base/target.h.svn-base b/btusb_1_6_29_1/inc/.svn/text-base/target.h.svn-base new file mode 100755 index 0000000..32b5bf9 --- a/dev/null +++ b/btusb_1_6_29_1/inc/.svn/text-base/target.h.svn-base @@ -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/btusb_1_6_29_1/inc/bt_target.h b/btusb_1_6_29_1/inc/bt_target.h new file mode 100755 index 0000000..e69de29 --- a/dev/null +++ b/btusb_1_6_29_1/inc/bt_target.h diff --git a/btusb_1_6_29_1/inc/bt_types.h b/btusb_1_6_29_1/inc/bt_types.h new file mode 100755 index 0000000..f214d54 --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/inc/btusb.h b/btusb_1_6_29_1/inc/btusb.h new file mode 100755 index 0000000..aa7534d --- a/dev/null +++ b/btusb_1_6_29_1/inc/btusb.h @@ -0,0 +1,367 @@ +/* + * + * btusb.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_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 "gki_int.h" +#include "btusbext.h" + +#ifdef BTUSB_LITE +#include "btusb_lite.h" +#endif + +/* 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 +#else +#define BTUSB_PDE_DATA(inode) PDE_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 +// bit18 : enable GKI buffer check +// bit19 : enable RX ACL size check +#define BTUSB_DBG_MSG 0x0001 +#define BTUSB_INFO_MSG 0x0002 +#define BTUSB_DUMP_MSG 0x0100 +#define BTUSB_GKI_CHK_MSG 0x0400 +//#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_DEBUG "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__) + +// TBD: how do we assign the minor range? +#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 258 + +// 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 // should 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 // for now should match 2 urbs +#define BTUSB_NUM_OF_VOICE_TX_BUFFERS 32 + +#define SCO_RX_BUFF_SIZE 360 +#define SCO_RX_MAX_LEN 240 + +#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)) + + +#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 */ + +// +// 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 +}; + +// +// This data structure is used for isochronous transfers +// +typedef struct +{ + // These two must go in sequence + void *dev; + unsigned char *packet; + int length; + unsigned long index; + int used; + + // URB & related info must be the last fields + struct urb urb; + // enough to cover the longest request + struct usb_iso_packet_descriptor IsoPacket[(BTUSB_MAXIMUM_TX_VOICE_SIZE /9) + 1]; +} tBTUSB_ISO_ELEMENT; + +// BTUSB transaction +typedef struct +{ + /* 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 USB data is received */ + UINT8 *dma_buffer; + /* DMA structure */ + dma_addr_t dma; + /* URB for this transaction */ + struct urb *p_urb; + void *context; +#if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE) + /* Magic number */ + UINT32 magic; +#endif +} tBTUSB_TRANSACTION; + +// Voice channel descriptor +typedef struct +{ + unsigned short sco_handle; + unsigned char burst; +} tBTUSB_SCO_INFO; + +typedef struct +{ + int used; + BT_HDR *p_msg; + tBTUSB_SCO_INFO info; +} tBTUSB_VOICE_CHANNEL; + +#define BTUSB_QUIRK_ZLP_TX_REQ (1 << 0) +#define BTUSB_QUIRK_ZLP_RX_WA (1 << 1) + +// Define the main structure +typedef struct btusb_cb +{ + struct usb_device *p_udev; // the 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; // the acl bulk in endpoint + struct usb_host_endpoint *p_acl_out; // the acl bulk out endpoint + struct usb_host_endpoint *p_diag_in; // the diag bulk in endpoint + struct usb_host_endpoint *p_diag_out; // the diag bulk out endpoint + struct usb_host_endpoint *p_event_in; // the interrupt in endpoint + struct usb_host_endpoint *p_voice_out; // iso out endpoint + struct usb_host_endpoint *p_voice_in; // voice in endpoint + struct ktermios kterm; // TTY emulation + struct mutex open_mutex; // protect concurrent open accesses + spinlock_t tasklet_lock; + struct kref kref; + tBTUSB_STATS stats; + bool opened; + 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_debug_pde; + bool scosniff_active; + struct proc_dir_entry *p_scosniff_pde; + struct list_head scosniff_list; + struct completion scosniff_completion; + + // Command transmit path + tBTUSB_TRANSACTION 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 + tBTUSB_TRANSACTION event_array[BTUSB_NUM_OF_EVENT_BUFFERS]; + struct usb_anchor event_submitted; + + // ACL receive path + tBTUSB_TRANSACTION acl_rx_array[BTUSB_NUM_OF_ACL_RX_BUFFERS]; + struct usb_anchor acl_rx_submitted; + + // ACL transmit path + tBTUSB_TRANSACTION acl_tx_array[BTUSB_NUM_OF_ACL_TX_BUFFERS]; + struct usb_anchor acl_tx_submitted; + + // Diagnostics receive path + tBTUSB_TRANSACTION diag_rx_array[BTUSB_NUM_OF_DIAG_RX_BUFFERS]; + struct usb_anchor diag_rx_submitted; + + // Diagnostics transmit path + tBTUSB_TRANSACTION diag_tx_array[BTUSB_NUM_OF_DIAG_TX_BUFFERS]; + struct usb_anchor diag_tx_submitted; + + // Voice + tBTUSB_TRANSACTION voice_rx_array[BTUSB_NUM_OF_VOICE_RX_BUFFERS]; + struct usb_anchor voice_rx_submitted; + + tBTUSB_VOICE_CHANNEL voice_channels[3]; + unsigned short desired_packet_size; + unsigned int pending_bytes; + BT_HDR **pp_pending_msg; + unsigned char pending_hdr[BTUSB_VOICE_HEADER_SIZE]; + unsigned int pending_hdr_size; + + BT_HDR *p_write_msg; + + unsigned long room_for_device_object; // must be here before the pending buffer + tBTUSB_ISO_ELEMENT *p_voicetxIrpList; + unsigned long voicetxIrpIndex; + + BUFFER_Q rx_queue; + BT_HDR *p_rx_msg; + BUFFER_Q tx_queue; + +#ifdef BTUSB_LITE + struct btusb_lite_cb lite_cb; +#endif +} tBTUSB_CB; + + +// +// Function prototypes +// +void btusb_delete(struct kref *kref); + +void btusb_tx_task(unsigned long arg); + +void btusb_cancel_voice(tBTUSB_CB *p_dev); +void btusb_cancel_urbs(tBTUSB_CB *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(tBTUSB_CB *p_dev, struct usb_anchor *p_anchor, tBTUSB_TRANSACTION *p_trans, int mem_flags); +void btusb_submit_voice_rx(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, int mem_flags); + +/* bt controller to host routines */ +void btusb_enqueue(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, UINT8 hcitype); +void btusb_dequeued(tBTUSB_CB *p_dev, BT_HDR *p_msg); + +void btusb_dump_data(const UINT8 *p, int len, const char *p_title); + +void btusb_cmd_complete(struct urb *p_urb); +void btusb_write_complete(struct urb *p_urb); +void btusb_voicerx_complete(struct urb *p_urb); + +// 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 + +// proc standard interface +int btusb_debug_open(struct inode *inode, struct file *file); +ssize_t btusb_debug_write(struct file *file, const char *buf, size_t count, loff_t *pos); + +ssize_t btusb_scosniff_read(struct file *file, char __user *buf, size_t size, loff_t *ppos); +int btusb_scosniff_open(struct inode *inode, struct file *file); +int btusb_scosniff_release(struct inode *inode, struct file *file); + +// +// Globals +// +extern struct usb_driver btusb_driver; +extern bool autopm; + +#endif // BTUSB_H diff --git a/btusb_1_6_29_1/inc/btusb_lite.h b/btusb_1_6_29_1/inc/btusb_lite.h new file mode 100755 index 0000000..66faaaa --- a/dev/null +++ b/btusb_1_6_29_1/inc/btusb_lite.h @@ -0,0 +1,198 @@ +/* + * + * 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 + +/* Forward declaration of BTUSB CB */ +struct btusb_cb; + +#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 +{ + int 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; +}; + +typedef enum +{ + BTPCM_LITE_PCM_CLOSED = 0, + BTPCM_LITE_PCM_OPENED, + BTPCM_LITE_PCM_CONFIGURED, + BTPCM_LITE_PCM_STARTED +} btusb_lite_pcm_state_t; + +struct btusb_lite_pcm_ccb +{ + btusb_lite_pcm_state_t state; + int channel; + 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 curr_mtu; + 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 +{ + struct proc_dir_entry *p_lite_pde; + int 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; +}; + +/******************************************************************************* + ** + ** Function btusb_lite_create + ** + ** Description Create BTUSB Lite interface + ** + ** Returns status (< 0 if error) + ** + *******************************************************************************/ +int btusb_lite_create(struct btusb_cb *p_dev, struct usb_interface *p_interface); + +/******************************************************************************* + ** + ** Function btusb_lite_delete + ** + ** Description Delete BTUSB Lite interface + ** + ** Returns none + ** + *******************************************************************************/ +void btusb_lite_delete(struct btusb_cb *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_cb *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_cb *p_dev); + +#endif /* BTUSB_LITE_H*/ + diff --git a/btusb_1_6_29_1/inc/btusb_lite_av.h b/btusb_1_6_29_1/inc/btusb_lite_av.h new file mode 100755 index 0000000..f19ad0b --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *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_cb *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_cb *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_cb *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_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt); + +#endif /* BTUSB_LITE_AV_H*/ + diff --git a/btusb_1_6_29_1/inc/btusb_lite_avdt.h b/btusb_1_6_29_1/inc/btusb_lite_avdt.h new file mode 100755 index 0000000..3538cc7 --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *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_cb *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_cb *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_cb *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_cb *p_dev, UINT8 avdt_handle, + BOOLEAN enable, UINT8 scms_hdr); + +#endif /* BTUSB_LITE_AVDT_H*/ + diff --git a/btusb_1_6_29_1/inc/btusb_lite_hci.h b/btusb_1_6_29_1/inc/btusb_lite_hci.h new file mode 100755 index 0000000..bb88d26 --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *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_cb *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_cb *p_dev, UINT8 *p_data, int length); + +#endif /* BTUSB_LITE_HCI_H */ + diff --git a/btusb_1_6_29_1/inc/btusb_lite_l2c.h b/btusb_1_6_29_1/inc/btusb_lite_l2c.h new file mode 100755 index 0000000..bf5aa6a --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *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_cb *p_dev, UINT16 local_cid); + +/******************************************************************************* +** +** Function btusb_lite_l2c_send +** +** Description Send L2CAP packet +** +** Returns Status +** +*******************************************************************************/ +int btusb_lite_l2c_send(struct btusb_cb *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_cb *p_dev, UINT16 con_hdl, UINT16 num_cplt_pck); + +#endif /* BTUSB_LITE_L2C_H*/ + diff --git a/btusb_1_6_29_1/inc/btusbext.h b/btusb_1_6_29_1/inc/btusbext.h new file mode 100755 index 0000000..ccdff66 --- a/dev/null +++ b/btusb_1_6_29_1/inc/btusbext.h @@ -0,0 +1,169 @@ +/* + * + * 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; + + // ACL RX counters + unsigned long acl_rx_submit_ok; + unsigned long acl_rx_submit_err; + unsigned long acl_rx_completed; + 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_completed; + 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_completed; + unsigned long event_resubmit; + unsigned long event_bytes; + + // Number of Write IRPs submitted + unsigned long writes_submitted; + + // Number of Write IRPs submitted in error + unsigned long writes_submitted_error; + + // Number of Write IRPs completed + unsigned long writes_completed; + + // Number of Write IRPs completed in error + unsigned long writes_completed_error; + + // Number of Command IRPs submitted + unsigned long commands_submitted; + + // Number of Command IRPs submitted in error + unsigned long commands_submitted_error; + + // Number of Command IRPs completed + unsigned long commands_completed; + + // Number of Command IRPs completed in error + unsigned long commands_completed_error; + + // Number of voice reqs submitted to the USB software stack + unsigned long voicerx_submitted; + + // Number of voice rx submitted in error + unsigned long voicerx_submitted_error; + + // Number of voice req completions from the USB software stack + unsigned long voicerx_completed; + + // Number of Voice req completions in error + unsigned long voicerx_completed_error; + + // Number of bad voice RX packets received + unsigned long voicerx_bad_packets; + + // Bytes received altogether + unsigned long voicerx_raw_bytes; + + // Bytes skipped + unsigned long voicerx_skipped_bytes; + + // SCO headers split across packets + unsigned long voicerx_split_hdr; + + // Voice frames discarded due to no headers in data + unsigned long voicerx_disc_nohdr; + + // Number of Voice Tx reqs submitted + unsigned long voicetx_submitted; + + // Number of voice tx submitted in error + unsigned long voicetx_submitted_error; + + // Number of Voice Tx reqs completed + unsigned long voicetx_completed; + + // Number of Voice Tx reqs completed in error + unsigned long voicetx_completed_error; + + // Number of Voice Tx not submitted due to no room on the tx queue + unsigned long voicetx_disc_nobuf; + + // Number of Voice tx not submitted due to too long data + unsigned long voicetx_disc_toolong; + + /* number of Voice packet pending */ + unsigned long voice_tx_cnt; + + /* max number of Voice packet pending */ + unsigned long voice_max_tx_cnt; + + /* max delta time between 2 consecutive tx done routine in us */ + 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 + +#endif // BTUSBEXT_H diff --git a/btusb_1_6_29_1/inc/data_types.h b/btusb_1_6_29_1/inc/data_types.h new file mode 100755 index 0000000..e8ccf4b --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/inc/gki.h b/btusb_1_6_29_1/inc/gki.h new file mode 100755 index 0000000..8b04756 --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/inc/gki_int.h b/btusb_1_6_29_1/inc/gki_int.h new file mode 100755 index 0000000..f210e58 --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/inc/hcidefs.h b/btusb_1_6_29_1/inc/hcidefs.h new file mode 100755 index 0000000..ec2e802 --- a/dev/null +++ b/btusb_1_6_29_1/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)) + +/* +** Defentions 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 */ + +/* +** Defentions for HCI Error Codes that are past in the events +*/ +#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 + +/* +** Defentions for 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 defenitions */ +#define HCI_ROLE_MASTER 0x00 +#define HCI_ROLE_SLAVE 0x01 +#define HCI_ROLE_UNKNOWN 0xff + +/* HCI mode defenitions */ +#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/btusb_1_6_29_1/inc/target.h b/btusb_1_6_29_1/inc/target.h new file mode 100755 index 0000000..32b5bf9 --- a/dev/null +++ b/btusb_1_6_29_1/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/btusb_1_6_29_1/src/.svn/all-wcprops b/btusb_1_6_29_1/src/.svn/all-wcprops new file mode 100755 index 0000000..635e606 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/all-wcprops @@ -0,0 +1,53 @@ +K 25 +svn:wc:ra_dav:version-url +V 72 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src +END +btusb_lite_avdt.c +K 25 +svn:wc:ra_dav:version-url +V 90 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_lite_avdt.c +END +btusb_isoc.c +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_isoc.c +END +btusb_lite.c +K 25 +svn:wc:ra_dav:version-url +V 85 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_lite.c +END +btusb_lite_l2c.c +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_lite_l2c.c +END +btusb_dev.c +K 25 +svn:wc:ra_dav:version-url +V 84 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_dev.c +END +btusb.c +K 25 +svn:wc:ra_dav:version-url +V 80 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb.c +END +btusb_lite_hci.c +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_lite_hci.c +END +btusb_lite_av.c +K 25 +svn:wc:ra_dav:version-url +V 88 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/btusb_lite_av.c +END diff --git a/btusb_1_6_29_1/src/.svn/entries b/btusb_1_6_29_1/src/.svn/entries new file mode 100755 index 0000000..6dd8271 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/entries @@ -0,0 +1,303 @@ +10 + +dir +941 +http://10.10.29.8/svn/SiP/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src +http://10.10.29.8/svn/SiP + + + +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + +e48500f2-7125-4e9d-852c-c0ee60673d08 + +gki +dir + +btusb_lite_avdt.c +file + + + + +2014-08-14T08:53:29.712694Z +96e56af7608a2483f31e8be2670a74c4 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +13339 + +btusb_isoc.c +file + + + + +2014-08-14T08:53:29.696694Z +c7a1595ae14bd4bc54e1328e59842609 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +9907 + +btusb_lite_l2c.c +file + + + + +2014-08-14T08:53:29.696694Z +7af6b7cffd47addfab3f40ce66a262c6 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +8409 + +btusb_lite.c +file + + + + +2014-08-14T08:53:29.696694Z +dbfebe033d70c0fe73fcf7e9ae866ef9 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +58849 + +btusb_dev.c +file + + + + +2014-08-14T08:53:29.696694Z +25ec78a3bf1f9fec81c0d671cc88ef3d +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +83812 + +btusb_lite_hci.c +file + + + + +2014-08-14T08:53:29.712694Z +1b19eacf4b53b70988c2688bae676bfb +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +13843 + +btusb.c +file + + + + +2014-08-14T08:53:29.712694Z +66ab3af0259c5840e3a666ab81dcea36 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +52984 + +btusb_lite_av.c +file + + + + +2014-08-14T08:53:29.696694Z +7e8bf3f1f79838f5b4d3ea6ad11bcaeb +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +40155 + diff --git a/btusb_1_6_29_1/src/.svn/text-base/btusb.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb.c.svn-base new file mode 100755 index 0000000..9300a02 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb.c.svn-base @@ -0,0 +1,1625 @@ +/* + * + * btusb.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 <linux/module.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + +#include "btusb.h" +#include "hcidefs.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 const struct file_operations btusb_debug_fops = +{ + .open = btusb_debug_open, + .read = seq_read, + .write = btusb_debug_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations btusb_scosniff_fops = +{ + .open = btusb_scosniff_open, + .read = seq_read, + .llseek = seq_lseek, + .release = btusb_scosniff_release, +}; + +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(tBTUSB_CB *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(tBTUSB_CB *p_dev, struct usb_anchor *p_anchor, tBTUSB_TRANSACTION *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)) + { + BTUSB_ERR("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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data, do not forward to upper layers + if (unlikely(p_urb->status || !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_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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data or no more submitted diags, do not forward to upper layers + if (unlikely(p_urb->status || !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_enqueue(p_dev, p_trans, HCIT_TYPE_LM_DIAG); + + 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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data, do not forward to upper layers + if (unlikely(p_urb->status || !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_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_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) +{ + tBTUSB_CB *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; + tBTUSB_TRANSACTION *p_trans; + int retval = -ENOMEM; + char procname[64]; + + 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(tBTUSB_CB), 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->context = p_dev; + 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_cmd_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->context = p_dev; + 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->context = p_dev; + 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->context = p_dev; + 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_write_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->context = p_dev; + 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->context = p_dev; + 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_write_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->context = p_dev; + 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; + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + usb_init_urb(&p_dev->p_voicetxIrpList[idx].urb); + } + + // 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("Not able to get a minor for this device\n"); + 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/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. + */ + scnprintf(procname, sizeof(procname), "driver/%s", p_interface->usb_dev->kobj.name); + p_dev->p_debug_pde = proc_create_data(procname, S_IRUGO | S_IWUGO, NULL, &btusb_debug_fops, p_dev); + if (p_dev->p_debug_pde == NULL) + { + BTUSB_ERR("Couldn't create proc entry\n"); + } + else + { + BTUSB_DBG("created /proc/%s\n", procname); + } + + scnprintf(procname, sizeof(procname), "driver/%s-scosniff", p_interface->usb_dev->kobj.name); + p_dev->p_scosniff_pde = proc_create_data(procname, S_IRUGO, NULL, &btusb_scosniff_fops, p_dev); + if (p_dev->p_scosniff_pde == NULL) + { + BTUSB_ERR("Couldn't create proc SCO sniff entry\n"); + } + else + { + BTUSB_DBG("created /proc/%s\n", procname); + INIT_LIST_HEAD(&p_dev->scosniff_list); + init_completion(&p_dev->scosniff_completion); + } + +#ifdef BTUSB_LITE + btusb_lite_create(p_dev, p_interface); +#endif + +#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 + + // 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_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(tBTUSB_CB *p_dev) +{ + int idx; + tBTUSB_VOICE_CHANNEL *p_chan; + + BTUSB_DBG("enter\n"); + + // cancel rx + BTUSB_DBG("Removing SCO RX anchored URBs\n"); + usb_kill_anchored_urbs(&p_dev->voice_rx_submitted); + + // free any SCO HCI message being consolidated + for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_channels); idx++) + { + p_chan = &p_dev->voice_channels[idx]; + if (p_chan->p_msg != NULL) + { + GKI_freebuf(p_chan->p_msg); + p_chan->p_msg = NULL; + } + } + // clear active RX processing + p_dev->pending_bytes = 0; + p_dev->pp_pending_msg = NULL; + p_dev->pending_hdr_size = 0; + + + // cancel tx + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + if (p_dev->p_voicetxIrpList[idx].used) + { + BTUSB_DBG("canceling tx URB %d\n", idx); + usb_kill_urb(&p_dev->p_voicetxIrpList[idx].urb); + p_dev->p_voicetxIrpList[idx].used = 0; + BTUSB_DBG("tx URB %d canceled\n", idx); + } + } + +} + +/******************************************************************************* + ** + ** 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(tBTUSB_CB *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) +{ + tBTUSB_CB *p_dev = usb_get_intfdata(p_interface); + int idx; + char procname[64]; + + BTUSB_INFO("p_dev=%p\n", p_dev); + if (p_dev == NULL) + { + 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); + + scnprintf(procname, sizeof(procname), "driver/%s", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + + scnprintf(procname, sizeof(procname), "driver/%s-scosniff", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + +#ifdef BTUSB_LITE + btusb_lite_stop_all(p_dev); + btusb_lite_delete(p_dev, p_interface); +#endif + + BTUSB_DBG("shutting down HCI intf\n"); + + /* prevent more I/O from starting */ + spin_lock_bh(&p_dev->tasklet_lock); + p_dev->p_main_intf = NULL; + spin_unlock_bh(&p_dev->tasklet_lock); + + // 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"); + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + p_dev->p_voicetxIrpList[idx].used = 0; + } + + 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) +{ + tBTUSB_CB *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) +{ + tBTUSB_CB *p_dev = usb_get_intfdata(p_interface); + int idx; + int retval = -ENOMEM; + tBTUSB_TRANSACTION *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(tBTUSB_CB *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; + + // initialize the elements of the device structure + mutex_init(&p_dev->open_mutex); + spin_lock_init(&p_dev->tasklet_lock); + 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); + + // 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"); + + BTUSB_DBG("sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS=%zu\n", + sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS); + p_dev->p_voicetxIrpList = kzalloc(sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS, GFP_KERNEL); + if (p_dev->p_voicetxIrpList == NULL) + { + dev_err(&p_interface->dev, "Out of memory for voice TX\n"); + return -ENOMEM; + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + p_dev->p_voicetxIrpList[idx].packet = kmalloc(BTUSB_MAXIMUM_TX_VOICE_SIZE, GFP_KERNEL); + if (p_dev->p_voicetxIrpList[idx].packet == NULL) + return -ENOMEM; + } + + 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; + + if ((le16_to_cpu(p_dev->p_udev->descriptor.idVendor) == 0x0A5C) && + (le16_to_cpu(p_dev->p_udev->descriptor.idProduct) == 0x0BDC)) + { + // the 43242 has a specific bug that needs to append 1 byte because it + // can not send ZLP + p_dev->quirks |= BTUSB_QUIRK_ZLP_RX_WA; + } + } + 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) +{ + tBTUSB_CB *p_dev = container_of(kref, tBTUSB_CB, kref); + tBTUSB_TRANSACTION *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_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); + } + usb_put_dev(p_dev->p_udev); + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + if (p_dev->p_voicetxIrpList[idx].packet) + { + kfree(p_dev->p_voicetxIrpList[idx].packet); + } + } + + if (p_dev->p_voicetxIrpList) + { + kfree(p_dev->p_voicetxIrpList); + } + kfree(p_dev); +} + + +/******************************************************************************* + ** + ** 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__); + + // initialize the GKI + GKI_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"); + + // shutdown the GKI + GKI_shutdown(); + + // 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/btusb_1_6_29_1/src/.svn/text-base/btusb_dev.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_dev.c.svn-base new file mode 100755 index 0000000..3638b1b --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_dev.c.svn-base @@ -0,0 +1,2630 @@ +/*
+ *
+ * btusb_dev.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 <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 <linux/jiffies.h>
+
+#include "btusb.h"
+
+#include "hcidefs.h"
+
+#include "gki_int.h"
+
+// delay between the voice samples: 3 ms
+#define BTUSB_VOICE_DELAY 3
+
+// local functions declaration
+static int btusb_add_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle, unsigned char burst);
+static int btusb_remove_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle);
+static int btusb_update_voice_channels(tBTUSB_CB *p_dev);
+static void btusb_update_voice_rx(tBTUSB_CB *p_dev);
+static void btusb_submit_voice_tx(tBTUSB_CB *p_dev, UINT8 *p_data, int len);
+static int btusb_submit_cmd(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_acl(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_diag(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_write_voice(tBTUSB_CB *p_dev, void *p_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 tBTUSB_TRANSACTION *btusb_alloc_trans(tBTUSB_TRANSACTION *p_array, size_t size)
+{
+ int idx;
+ tBTUSB_TRANSACTION *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(¤t_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;
+ }
+ }
+
+ memcpy(p_last_time, ¤t_time, sizeof(struct timeval));
+ 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)
+{
+ tBTUSB_CB *p_dev = (tBTUSB_CB *) 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 - 4);
+ 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_enqueue
+ **
+ ** Description Add a received USB message into the user 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_enqueue(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *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);
+
+ switch (hcitype)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ // retrieve the length in the packet header
+ p += 2;
+ STREAM_TO_UINT16(len, p);
+ len += 4;
+ break;
+
+ case HCIT_TYPE_EVENT:
+ // retrieve the length in the packet header
+ 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;
+ }
+
+ // quirk for the ZLP HW issue
+ if (unlikely(((len % 16) == 0) && (p_dev->quirks & BTUSB_QUIRK_ZLP_RX_WA) &&
+ (p_urb->actual_length == (len + 1))))
+ {
+ BTUSB_DBG("missing ZLP workaround: %d != %d\n", p_urb->actual_length, len);
+ p_urb->actual_length = len;
+ }
+ // check if the length matches that of the ACL packet
+ if (unlikely(len != p_urb->actual_length))
+ {
+ 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_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_dequeued(tBTUSB_CB *p_dev, BT_HDR *p_msg)
+{
+ tBTUSB_TRANSACTION *p_trans = container_of(p_msg, tBTUSB_TRANSACTION, bt_hdr);
+
+ 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;
+
+ default:
+ GKI_freebuf(p_msg);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_open
+ **
+ ** Description User mode open callback
+ **
+ *******************************************************************************/
+int btusb_open(struct inode *inode, struct file *file)
+{
+ tBTUSB_CB *p_dev;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+ BT_HDR *p_buf;
+
+ 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;
+ }
+
+ mutex_lock(&p_dev->open_mutex);
+ if (p_dev->opened)
+ {
+ mutex_unlock(&p_dev->open_mutex);
+ BTUSB_ERR("multiple open not allowed %d\n", p_dev->opened);
+ retval = -EBUSY;
+ goto exit;
+ }
+ // save our object in the file's private structure
+ file->private_data = p_dev;
+ p_dev->opened = true;
+ mutex_unlock(&p_dev->open_mutex);
+
+ // 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);
+
+ // free all pending messages in Rx queue
+ BTUSB_DBG("Free Rx Queue count:%d\n", p_dev->rx_queue.count);
+ while ((p_buf = (BT_HDR *)GKI_dequeue(&p_dev->rx_queue)) != NULL)
+ {
+ btusb_dequeued(p_dev, p_buf);
+ }
+
+exit:
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_release
+ **
+ ** Description User mode close callback
+ **
+ *******************************************************************************/
+int btusb_release(struct inode *inode, struct file *file)
+{
+ tBTUSB_CB *p_dev;
+ BT_HDR *p_buf = NULL;
+ int idx;
+
+ BTUSB_INFO("enter\n");
+
+ p_dev = (tBTUSB_CB *) 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
+
+ // indicate driver is closed
+ mutex_lock(&p_dev->open_mutex);
+ p_dev->opened = false;
+ mutex_unlock(&p_dev->open_mutex);
+
+ // free all the pending elements
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->tx_queue)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->rx_queue)) != NULL)
+ {
+ btusb_dequeued(p_dev, p_buf);
+ }
+
+ // 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_channels); idx++)
+ {
+ if (p_dev->voice_channels[idx].used)
+ {
+ if (btusb_remove_voice_channel(p_dev, p_dev->voice_channels[idx].info.sco_handle))
+ {
+ BTUSB_ERR("btusb_remove_voice_channel failed\n");
+ }
+ }
+ }
+
+ for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++)
+ {
+ p_dev->p_voicetxIrpList[idx].used = 0;
+ }
+
+ // 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_cb *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_free_rx_packet
+ **
+ ** Description Free buffer sent to User Space
+ **
+ *******************************************************************************/
+static void btusb_free_rx_packet(struct btusb_cb *p_dev, BT_HDR *p_msg)
+{
+ if (unlikely(p_msg != p_dev->p_rx_msg))
+ {
+ BTUSB_ERR("Dequeued buffer (%p) does not matched working buffer (%p)\n",
+ p_msg, p_dev->p_rx_msg);
+ }
+
+ p_dev->p_rx_msg = NULL;
+
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ // buffer received from USB -> resubmit
+ btusb_dequeued(p_dev, p_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_cb *p_dev, BT_HDR *p_msg)
+{
+ tBTUSB_TRANSACTION *p_trans;
+
+ switch(p_msg->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ case HCIT_TYPE_EVENT:
+ case HCIT_TYPE_LM_DIAG:
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ return ((char *)(p_msg + 1) + p_msg->offset);
+ }
+ else
+ {
+ p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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)
+{
+ tBTUSB_CB *p_dev = (tBTUSB_CB *)file->private_data;
+ UINT16 len;
+ size_t remainder = count;
+ BT_HDR *p_buf = NULL;
+ 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 (unlikely(!p_dev->opened))
+ {
+ BTUSB_ERR("driver is not open\n");
+ return -EINVAL;
+ }
+
+ // if read is non blocking and there is no data
+ if (unlikely((file->f_flags & O_NONBLOCK) && (btusb_get_rx_packet(p_dev) == NULL)))
+ {
+ BTUSB_INFO("Non blocking read without any data\n");
+ return -EAGAIN;
+ }
+
+ // wait for an event
+ retval = wait_event_interruptible(p_dev->rx_wait_q,
+ ((p_buf = btusb_get_rx_packet(p_dev)) != NULL));
+ if (unlikely(retval))
+ {
+ BTUSB_DBG("read wait interrupted\n");
+ return retval;
+ }
+ BTUSB_DBG("buffer=%p len=%u ls=%u\n", p_buf, p_buf->len, p_buf->layer_specific);
+
+ switch(p_buf->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ case HCIT_TYPE_EVENT:
+ case HCIT_TYPE_LM_DIAG:
+ // if this is the first time buffer is picked, add HCI header in user space
+ if (likely(!(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;
+ }
+ buffer += 1;
+ remainder -= 1;
+ }
+ else
+ {
+ BTUSB_ERR("Not enough space to copy H4 ACL header\n");
+ goto read_end;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // 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;
+ p_buf->layer_specific |= BTUSB_LS_H4_TYPE_SENT;
+
+ // 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_free_rx_packet(p_dev, p_buf);
+ }
+
+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)
+{
+ tBTUSB_CB *p_dev;
+ BT_HDR *p_msg;
+ UINT8 *p_data;
+ size_t remainder = count;
+ int err;
+ UINT16 appended, len;
+
+ p_dev = (tBTUSB_CB *)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(!p_dev->opened))
+ {
+ return -EINVAL;
+ }
+
+ 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");
+ 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)
+{
+ tBTUSB_CB *p_dev;
+ unsigned int mask;
+
+ BTUSB_DBG("enter\n");
+
+ // retrieve the device from the file pointer
+ p_dev = (tBTUSB_CB *) 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;
+ }
+
+ if (unlikely(!p_dev->opened))
+ {
+ 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_get_rx_packet(p_dev))
+ {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_print_voice_stat
+ **
+ ** Description SCO print voice stats
+ **
+ ** Parameters p_stat buffer holding the statistic to display.
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+void btusb_print_voice_stat(tBTUSB_STATS * p_stat)
+{
+ printk("______________btusb_print_voice_stat______________\n");
+
+ printk("Number of voice reqs submitted USB stack %lu\n", p_stat->voicerx_submitted);
+ printk("Number of voice rx submitted in error %lu\n", p_stat->voicerx_submitted_error);
+ printk("Number of voice req completions from the USB software stack %lu\n", p_stat->voicerx_completed);
+ printk("Number of Voice req completions in error %lu\n", p_stat->voicerx_completed_error);
+ printk("Voice frames discarded due to bad status %lu\n", p_stat->voicerx_bad_packets);
+ printk("Voice frames discarded due to no headers in data %lu\n", p_stat->voicerx_disc_nohdr);
+
+ printk("Raw bytes received %lu\n",p_stat->voicerx_raw_bytes);
+ printk("Skipped bytes because no header matched %lu\n",p_stat->voicerx_skipped_bytes);
+ printk("Number of Voice Tx reqs submitted %lu\n",p_stat->voicetx_submitted);
+ printk("Number of voice tx submitted in error %lu\n",p_stat->voicetx_submitted_error);
+ printk("Number of Voice Tx reqs completed %lu\n",p_stat->voicetx_completed);
+ printk("Number of Voice Tx reqs completed in error %lu\n",p_stat->voicetx_completed_error);
+ printk("Number of Voice Tx not submitted due to no room on the tx queue %lu\n",
+ p_stat->voicetx_disc_nobuf);
+ printk("Number of Voice tx not submitted due to too long data %lu\n",
+ p_stat->voicetx_disc_toolong);
+
+ printk("voice pending counter %lu, max %lu\n", p_stat->voice_tx_cnt, p_stat->voice_max_tx_cnt);
+ p_stat->voice_tx_cnt=0;p_stat->voice_max_tx_cnt=0;
+
+ printk("Delta time between voice tx_done routine in us max: %lu, min: %lu\n", p_stat->voice_max_tx_done_delta_time, p_stat->voice_min_tx_done_delta_time);
+ memset(&(p_stat->voice_tx_done_delta_time) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_tx_done_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_tx_done_delta_time = 0;
+ p_stat->voice_min_tx_done_delta_time = 0;
+
+ printk("Delta time between voice tx feeding routine in us max: %lu, min: %lu\n", p_stat->voice_max_rx_feeding_interval, p_stat->voice_min_rx_feeding_interval);
+ memset(&(p_stat->voice_rx_feeding_interval) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_rx_feeding_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_rx_feeding_interval = 0;
+ p_stat->voice_min_rx_feeding_interval = 0;
+
+ printk("Delta time between voice rx_rdy routine max in us: %lu, min : %lu\n", p_stat->voice_max_rx_rdy_delta_time, p_stat->voice_min_rx_rdy_delta_time);
+ memset(&(p_stat->voice_rx_rdy_delta_time) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_rx_rdy_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_rx_rdy_delta_time = 0;
+ p_stat->voice_min_rx_rdy_delta_time = 0;
+
+ printk("_______________________________________________________\n");
+}
+
+#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;
+ tBTUSB_CB *p_dev;
+ tBTUSB_SCO_INFO sco_info;
+ int retval = 0;
+
+ s_cmd = btusb_ioctl_string(cmd);
+
+ BTUSB_INFO("cmd=%s\n", s_cmd);
+
+ p_dev = (tBTUSB_CB *) 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.sco_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.sco_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_write_complete
+ **
+ ** Description Data write (bulk pipe) completion routine
+ **
+ ** Parameters urb pointer
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_write_complete(struct urb *p_urb)
+{
+ tBTUSB_TRANSACTION *p_trans = p_urb->context;
+ tBTUSB_CB *p_dev = p_trans->context;
+
+ 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;
+
+ if (unlikely(p_urb->status))
+ {
+ p_dev->stats.writes_completed_error++;
+ printk(KERN_ERR "BTUSB btusb_write_complete failure %d\n", p_urb->status);
+ }
+ else
+ {
+ p_dev->stats.writes_completed++;
+ }
+
+ if(autopm)
+ {
+ usb_autopm_put_interface(p_dev->p_main_intf);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_strip_off_acl_handle
+ **
+ ** Description Strip off the ACL handle if this is firmware download packet
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_strip_off_acl_handle(char* *packet, unsigned long *length)
+{
+ UINT8* p = (UINT8 *) (*packet);
+
+ BTUSB_DBG("first bytes are %02X %02X\n", *p, *(p+1));
+
+ // check special handle for firmware download packet
+ if ((*p == 0xEF) && (*(p+1) == 0xBE))
+ {
+ *packet = (char *) (p + 4);
+ *length -= 4;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_acl
+ **
+ ** Description ACL write submission to the controller
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_acl(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *p_trans;
+
+ BTUSB_DBG("%p[%lu]\n", packet, length);
+
+ // strip off the ACL handle if this is a firmware download packet
+ btusb_strip_off_acl_handle (&packet, &length);
+ BTUSB_DBG("after adjusting %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;
+#if 0
+ return btusb_submit_bulk(p_dev, packet, length, p_dev->p_acl_out, &p_dev->acl_tx_submitted);
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_diag
+ **
+ ** Description Diag write submission to the controller
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_diag(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *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 urb *p_urb)
+{
+ tBTUSB_TRANSACTION *p_trans = p_urb->context;
+ tBTUSB_CB *p_dev = p_trans->context;
+
+ BTUSB_DBG("status %d %u length flags %x\n", p_urb->status,
+ p_urb->transfer_buffer_length, p_urb->transfer_flags);
+
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_ERR("failure %d\n", p_urb->status);
+ p_dev->stats.commands_completed_error++;
+ }
+ else
+ {
+ p_dev->stats.commands_completed++;
+ }
+
+ if(autopm)
+ usb_autopm_put_interface(p_dev->p_main_intf);
+
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_cmd
+ **
+ ** Description
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_cmd(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *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 == NULL))
+ {
+ 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.commands_submitted_error++;
+ goto error;
+ }
+ 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
+ **
+ *******************************************************************************/
+static void btusb_voicetx_complete(struct urb *p_urb)
+{
+ tBTUSB_ISO_ELEMENT *pIsoXfer = p_urb->context;
+ tBTUSB_CB *p_dev = (void *) pIsoXfer->dev;
+
+ 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));
+
+ // keep track on the number of Tx buffer pending
+ p_dev->stats.voice_tx_cnt--;
+
+ if (unlikely(!p_dev->p_main_intf))
+ goto exit;
+
+ pIsoXfer->used = 0;
+
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_ERR("btusb_voicetx_complete failure %d\n", p_urb->status);
+ p_dev->stats.voicetx_completed_error++;
+ }
+ else
+ {
+ p_dev->stats.voicetx_completed++;
+ }
+
+exit:
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_fill_iso_pkts
+ **
+ ** Description Useful voice utility.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_fill_iso_pkts(struct urb *p_urb, int len, int pkt_size)
+{
+ int off = 0, i;
+
+ for (i = 0; len >= pkt_size; i++, off += pkt_size, len -= pkt_size)
+ {
+ p_urb->iso_frame_desc[i].offset = off;
+ p_urb->iso_frame_desc[i].length = pkt_size;
+ }
+
+ // remainder?
+ if (len)
+ {
+ p_urb->iso_frame_desc[i].offset = off;
+ p_urb->iso_frame_desc[i].length = len;
+ i++;
+ }
+
+ p_urb->number_of_packets = i;
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_fill_iso_rx_pkts
+ **
+ ** Description Useful voice utility.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_fill_iso_rx_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;
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_rx
+ **
+ ** Description Resubmit an already filled URB request
+ **
+ ** Parameters
+ **
+ ** Returns
+ **
+ *******************************************************************************/
+void btusb_submit_voice_rx(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, int mem_flags)
+{
+ if (unlikely(btusb_submit(p_dev, &p_dev->voice_rx_submitted, p_trans, mem_flags)))
+ {
+ p_dev->stats.voicerx_submitted_error++;
+ }
+ else
+ {
+ p_dev->stats.voicerx_submitted++;
+ }
+
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_update_voice_rx
+ **
+ ** Description Finish filling the voice URB and submit them. At this point
+ ** the URBs should NOT be submitted.
+ **
+ ** Parameters
+ **
+ ** Returns
+ **
+ *******************************************************************************/
+static void btusb_update_voice_rx(tBTUSB_CB *p_dev)
+{
+ unsigned int idx;
+ tBTUSB_TRANSACTION *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;
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_in->desc.wMaxPacketSize);
+ if (!packet_size)
+ {
+ BTUSB_ERR("failing, 0 packet size)\n");
+ return;
+ }
+ 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("Required buffer size larger than allocated size\n");
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ }
+ btusb_fill_iso_rx_pkts(p_urb, p_urb->transfer_buffer_length, packet_size);
+
+ btusb_submit_voice_rx(p_dev, p_trans, GFP_KERNEL);
+ }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_tx
+ **
+ ** Description Voice write submission
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_submit_voice_tx(tBTUSB_CB *p_dev, UINT8 *p_data, int len)
+{
+ int to_send = 0;
+
+ 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));
+
+ while (len > 0)
+ {
+ if (len >= BTUSB_VOICE_BURST_SIZE)
+ {
+ to_send = BTUSB_VOICE_BURST_SIZE;
+ }
+ else
+ {
+ BTUSB_DBG("Sending partial sco data len: %d\n", len);
+ }
+ p_data[2] = to_send;
+ len -= to_send;
+ btusb_submit_write_voice(p_dev, p_data, to_send + 3);
+
+ if (len)
+ {
+ // copy the header for the next chunk
+ memcpy(p_data + BTUSB_VOICE_BURST_SIZE, p_data , 3);
+ p_data += BTUSB_VOICE_BURST_SIZE;
+ }
+ }
+
+ // we should always have at least 30 ms of audio ready to send
+ // if not fill up with silence
+ if (p_dev->stats.voice_tx_cnt<10)
+ {
+ BTUSB_DBG("less than 10 buffer in the Tx Q %lu insert silence \n", p_dev->stats.voice_tx_cnt);
+ while(p_dev->stats.voice_tx_cnt < 30)
+ {
+ memset(p_data + 3, 0, BTUSB_VOICE_BURST_SIZE );
+ btusb_submit_write_voice(p_dev, p_data, BTUSB_VOICE_BURST_SIZE + 3);
+ }
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_write_voice
+ **
+ ** Description Voice write submission, length should be
+ ** smaller than or equal to VOICE_SAMPLE_SIZE
+ **
+ ** Parameters
+ **
+ ** Returns A zero value upon success.
+ **
+ *******************************************************************************/
+int btusb_submit_write_voice(tBTUSB_CB *p_dev, void *p_packet, unsigned long length)
+{
+ tBTUSB_ISO_ELEMENT *pIsoXfer;
+ struct urb *p_urb;
+ int status, pipe;
+ int packet_size, cur_frame_number;
+
+ 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 -1;
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_out->desc.wMaxPacketSize);
+ if ((length > BTUSB_MAXIMUM_TX_VOICE_SIZE) || !packet_size)
+ {
+ BTUSB_ERR("failing (%lu bytes - too many for %d packet size)\n", length, packet_size);
+ p_dev->stats.voicetx_disc_toolong++;
+ return -11;
+ }
+
+ // advance to the next voice tx IRP
+ if (++p_dev->voicetxIrpIndex == BTUSB_NUM_OF_VOICE_TX_BUFFERS)
+ p_dev->voicetxIrpIndex = 0;
+
+ // keep track on the number of tx buffer for stats debug and optimization
+ p_dev->stats.voice_tx_cnt++;
+ if (p_dev->stats.voice_tx_cnt>p_dev->stats.voice_max_tx_cnt)
+ {
+ p_dev->stats.voice_max_tx_cnt = p_dev->stats.voice_tx_cnt;
+ }
+
+ pIsoXfer = &p_dev->p_voicetxIrpList[p_dev->voicetxIrpIndex];
+
+ // buffer available?
+ if (pIsoXfer->used)
+ {
+ BTUSB_ERR("failed, no buf!\n");
+ p_dev->stats.voicetx_disc_nobuf++;
+ return -111;
+ }
+
+ p_urb = &pIsoXfer->urb;
+ pIsoXfer->index = p_dev->voicetxIrpIndex;
+ pIsoXfer->dev = p_dev;
+ memcpy(pIsoXfer->packet, p_packet, length);
+ pipe = usb_sndisocpipe(p_dev->p_udev, p_dev->p_voice_out->desc.bEndpointAddress);
+ p_urb->complete = btusb_voicetx_complete;
+ p_urb->context = pIsoXfer;
+ p_urb->dev = p_dev->p_udev;
+ p_urb->pipe = pipe;
+ p_urb->interval = p_dev->p_voice_out->desc.bInterval;
+ p_urb->transfer_buffer = pIsoXfer->packet;
+ p_urb->transfer_buffer_length = length;
+ btusb_fill_iso_pkts(p_urb, length, packet_size);
+ // p_urb->transfer_flags = 0;
+ p_urb->transfer_flags = URB_ISO_ASAP;
+ cur_frame_number = usb_get_current_frame_number(p_dev->p_udev);
+
+ BTUSB_INFO("len %lu idx %lu frm %u\n", length, pIsoXfer->index, cur_frame_number);
+ pIsoXfer->used = 1;
+ status = usb_submit_urb(p_urb, GFP_ATOMIC);
+ if (status)
+ {
+ BTUSB_ERR("usb_submit_urb failed %d\n", status);
+ p_dev->stats.voicetx_submitted_error++;
+ pIsoXfer->used = 0;
+ }
+ else
+ {
+ p_dev->stats.voicetx_submitted++;
+ BTUSB_DBG("success\n");
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+ **
+ ** 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(tBTUSB_CB *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)
+ {
+ btusb_update_voice_rx(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
+ **
+ *******************************************************************************/
+static int btusb_add_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle, unsigned char burst)
+{
+ int idx;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (!p_chan->used)
+ {
+ p_chan->info.sco_handle = sco_handle;
+ p_chan->info.burst = burst;
+ p_chan->used = 1;
+ 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
+ **
+ *******************************************************************************/
+static int btusb_remove_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle)
+{
+ int idx;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used && (p_chan->info.sco_handle == sco_handle))
+ {
+ p_chan->used = 0;
+ 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(tBTUSB_CB *p_dev)
+{
+ int idx, jdx;
+ unsigned char min_burst, max_burst, num_voice_chan, voice_setting;
+ unsigned short desired_packet_size, packet_size;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used)
+ {
+ num_voice_chan++;
+ min_burst = min(min_burst, p_chan->info.burst);
+ max_burst = max(max_burst, p_chan->info.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);
+ // store the desired packet size
+ p_dev->desired_packet_size = desired_packet_size;
+
+ // 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);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_debug_show
+ **
+ ** Description Function called when reading the /proc file created by our driver
+ **
+ *******************************************************************************/
+#define BTUSB_STATS(__n) \
+ seq_printf(s, " - " #__n " = %lu\n", p_dev->stats.__n)
+
+static int btusb_debug_show(struct seq_file *s, void *unused)
+{
+ tBTUSB_CB *p_dev = s->private;
+ struct usb_device *udev = p_dev->p_udev;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+ tBTUSB_VOICE_CHANNEL *p_chan;
+ int idx, jdx;
+
+ seq_printf(s, "USB device :\n");
+ seq_printf(s, " - Match info:\n");
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_VENDOR)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_VENDOR (0x%02X)\n", p_dev->p_id->idVendor);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_PRODUCT 0x%02X)\n", p_dev->p_id->idProduct);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_LO (%u)\n", p_dev->p_id->bcdDevice_lo);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_HI (%u)\n", p_dev->p_id->bcdDevice_hi);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_CLASS (0x%02X)\n", p_dev->p_id->bDeviceClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_SUBCLASS (0x%02X)\n", p_dev->p_id->bDeviceSubClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_PROTOCOL (0x%02X)\n", p_dev->p_id->bDeviceProtocol);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_CLASS (0x%02X)\n", p_dev->p_id->bInterfaceClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_SUBCLASS (0x%02X)\n", p_dev->p_id->bInterfaceSubClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_PROTOCOL (0x%02X)\n", p_dev->p_id->bInterfaceProtocol);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_NUMBER (%u)\n", p_dev->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_event_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, " * 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(tBTUSB_CB, cmd_array), sizeof(p_dev->cmd_array));
+ seq_printf(s, " * EVENT = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, event_array), sizeof(p_dev->event_array));
+ seq_printf(s, " * ACL RX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, acl_rx_array), sizeof(p_dev->acl_rx_array));
+ seq_printf(s, " * ACL TX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, acl_tx_array), sizeof(p_dev->acl_tx_array));
+ seq_printf(s, " * DIAG RX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, diag_rx_array), sizeof(p_dev->diag_rx_array));
+ seq_printf(s, " * DIAG TX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, diag_tx_array), sizeof(p_dev->diag_tx_array));
+ seq_printf(s, " * VOICE = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, voice_channels), offsetof(tBTUSB_CB, rx_queue)-offsetof(tBTUSB_CB, voice_channels));
+
+ seq_printf(s, "Status :\n");
+ seq_printf(s, " - issharedusb = %u\n", p_dev->issharedusb);
+ seq_printf(s, " - quirks = %u\n", p_dev->quirks);
+ seq_printf(s, " - opened = %d\n", p_dev->opened);
+ seq_printf(s, "Voice :\n");
+ // calculate number of voice sample per timer expiration
+ // HZ could be 100, 250 or 1000
+ if ((1000 / HZ) <= BTUSB_VOICE_DELAY)
+ {
+ seq_printf(s, " - number of voice samples per timer expiration = 1\n");
+ }
+ else
+ {
+ seq_printf(s, " - number of voice samples per timer expiration = %d\n",
+ (1000 / (HZ * BTUSB_VOICE_DELAY)));
+ }
+ jdx = 0;
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used)
+ {
+ seq_printf(s, " - channel %d : SCO handle = %d(0x%02x) burst = %d\n", idx,
+ p_chan->info.sco_handle, p_chan->info.sco_handle, p_chan->info.burst);
+ jdx = 1;
+ }
+ }
+ if (jdx)
+ {
+ seq_printf(s, " - desired_packet_size = %d\n", p_dev->desired_packet_size);
+ }
+ else
+ {
+ seq_printf(s, " - No active channels\n");
+ }
+ seq_printf(s, "Statistics :\n");
+ 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_completed);
+ BTUSB_STATS(acl_rx_resubmit);
+ BTUSB_STATS(acl_rx_bytes);
+ BTUSB_STATS(event_submit_ok);
+ BTUSB_STATS(event_submit_err);
+ BTUSB_STATS(event_completed);
+ BTUSB_STATS(event_resubmit);
+ BTUSB_STATS(event_bytes);
+ BTUSB_STATS(diag_rx_submit_ok);
+ BTUSB_STATS(diag_rx_submit_err);
+ BTUSB_STATS(diag_rx_completed);
+ BTUSB_STATS(diag_rx_resubmit);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(writes_submitted);
+ BTUSB_STATS(writes_submitted_error);
+ BTUSB_STATS(writes_completed);
+ BTUSB_STATS(writes_completed_error);
+ BTUSB_STATS(commands_submitted);
+ BTUSB_STATS(commands_submitted_error);
+ BTUSB_STATS(commands_completed);
+ BTUSB_STATS(commands_completed_error);
+ BTUSB_STATS(voicerx_submitted);
+ BTUSB_STATS(voicerx_submitted_error);
+ BTUSB_STATS(voicerx_completed);
+ BTUSB_STATS(voicerx_completed_error);
+ BTUSB_STATS(voicerx_bad_packets);
+ BTUSB_STATS(voicerx_disc_nohdr);
+ BTUSB_STATS(voicerx_split_hdr);
+ BTUSB_STATS(voicerx_raw_bytes);
+ BTUSB_STATS(voicerx_skipped_bytes);
+ BTUSB_STATS(voicetx_submitted);
+ BTUSB_STATS(voicetx_submitted_error);
+ BTUSB_STATS(voicetx_completed);
+ BTUSB_STATS(voicetx_completed_error);
+ BTUSB_STATS(voicetx_disc_nobuf);
+ BTUSB_STATS(voicetx_disc_toolong);
+ BTUSB_STATS(voice_tx_cnt);
+ BTUSB_STATS(voice_max_tx_cnt);
+
+ {
+ struct btusb_scosniff *p, *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_debug_write
+ **
+ ** Description Write handler of the debug /proc interface
+ **
+ *******************************************************************************/
+ssize_t btusb_debug_write(struct file *file, const char *buf,
+ size_t count, loff_t *pos)
+{
+ struct seq_file *s = file->private_data;
+ tBTUSB_CB *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;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_debug_open
+ **
+ ** Description Open handler of the debug /proc interface
+ **
+ *******************************************************************************/
+int btusb_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, btusb_debug_show, BTUSB_PDE_DATA(inode));
+}
+
+static void * btusb_scosniff_start(struct seq_file *s, loff_t *pos)
+{
+ tBTUSB_CB *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;
+}
+
+static void btusb_scosniff_stop(struct seq_file *s, void *v)
+{
+ BTUSB_INFO("stop\n");
+}
+
+static 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;
+}
+
+ static 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;
+}
+
+static const struct seq_operations btusb_scosniff_seq_ops = {
+ .start = btusb_scosniff_start,
+ .next = btusb_scosniff_next,
+ .stop = btusb_scosniff_stop,
+ .show = btusb_scosniff_show,
+};
+
+int btusb_scosniff_open(struct inode *inode, struct file *file)
+{
+ int rv;
+ tBTUSB_CB *p_dev = BTUSB_PDE_DATA(inode);
+
+ rv = seq_open(file, &btusb_scosniff_seq_ops);
+ if (!rv)
+ {
+ p_dev->scosniff_active = true;
+ ((struct seq_file *)file->private_data)->private = p_dev;
+ }
+ return rv;
+}
+
+int btusb_scosniff_release(struct inode *inode, struct file *file)
+{
+ struct btusb_scosniff *p, *n;
+ tBTUSB_CB *p_dev = BTUSB_PDE_DATA(inode);
+
+ 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);
+}
diff --git a/btusb_1_6_29_1/src/.svn/text-base/btusb_isoc.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_isoc.c.svn-base new file mode 100755 index 0000000..bc3acff --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_isoc.c.svn-base @@ -0,0 +1,311 @@ +/* + * + * btusb_isoc.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 + * + * + */ + +// for kmalloc +#include <linux/slab.h> +#include "btusb.h" +#include "hcidefs.h" + +/******************************************************************************* + ** + ** Function btusb_isoc_reset_msg + ** + ** Description Reset the currently receiving voice message + ** + ** Parameters p_dev: device instance control block + ** + ** Returns void + ** + *******************************************************************************/ +static void btusb_isoc_reset_msg(tBTUSB_CB *p_dev) +{ + p_dev->pending_bytes = 0; + if (p_dev->pp_pending_msg && *p_dev->pp_pending_msg) + { + GKI_freebuf(*p_dev->pp_pending_msg); + } + p_dev->pp_pending_msg = NULL; + p_dev->pending_hdr_size = 0; +} + +/******************************************************************************* + ** + ** 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(tBTUSB_CB *p_dev) +{ + unsigned char *p_data = p_dev->pending_hdr; + int idx; + unsigned short sco_handle; + unsigned char size; + BT_HDR *p_hdr; + tBTUSB_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_channels); idx++) + { + p_chan = &p_dev->voice_channels[idx]; + if ((p_chan->used) && + (sco_handle == p_chan->info.sco_handle) && + (size <= (2 * p_chan->info.burst))) + { + // check if there is already a message being consolidated + if (unlikely(p_chan->p_msg == NULL)) + { + p_hdr = (BT_HDR *) GKI_getpoolbuf(HCI_SCO_POOL_ID); + if (unlikely(p_hdr == NULL)) + { + return false; + } + p_hdr->event = BT_EVT_TO_BTU_HCI_SCO; + p_hdr->len = 1 + BTUSB_VOICE_HEADER_SIZE; // sizeof(data_type) + SCO header + p_hdr->offset = 0; + p_hdr->layer_specific = 0; + + p_data = (void *) (p_hdr + 1); + + // add data type + UINT8_TO_STREAM(p_data, HCIT_TYPE_SCO_DATA); + UINT16_TO_STREAM(p_data, sco_handle); + + p_chan->p_msg = p_hdr; + } + p_dev->pending_bytes = size; + p_dev->pp_pending_msg = &p_chan->p_msg; + + return true; + } + } + return false; +} + +/******************************************************************************* + ** + ** Function btusb_isoc_check_msg + ** + ** Description Check the currently receiving message + ** + ** Parameters p_dev: device instance control block + ** pp_hdr: pointer to the receiving message + ** + ** Returns void + ** + *******************************************************************************/ +static void btusb_isoc_check_msg(tBTUSB_CB *p_dev, BT_HDR **pp_hdr) +{ + BT_HDR *p_hdr = *pp_hdr; + unsigned char *p_data; + + // if enough data was received + if (unlikely(p_hdr->len >= (1 + BTUSB_VOICE_HEADER_SIZE + SCO_RX_MAX_LEN))) + { + p_data = (void *)(p_hdr + 1); + p_data[BTUSB_VOICE_HEADER_SIZE] = p_hdr->len - BTUSB_VOICE_HEADER_SIZE - 1; + GKI_enqueue(&p_dev->rx_queue, p_hdr); + + // notify RX event(in case of select/poll + wake_up_interruptible(&p_dev->rx_wait_q); + + *pp_hdr = NULL; + } +} + +/******************************************************************************* + ** + ** Function btusb_voicerx_complete + ** + ** Description Voice read (iso pipe) completion routine. + ** + ** Parameters + ** + ** Returns void + ** + *******************************************************************************/ +void btusb_voicerx_complete(struct urb *p_urb) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + BT_HDR **pp_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; + + BTUSB_INFO("enter"); + + 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)); + + p_dev->stats.voicerx_completed++; + + 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)) + { + BTUSB_ERR("failure %d\n", p_urb->status); + p_dev->stats.voicerx_completed_error++; + 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); + 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_packets++; + // 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->pending_bytes)) + { + fill_data: + if (likely(p_dev->pending_bytes >= packet_length)) + { + length = packet_length; + } + else + { + length = p_dev->pending_bytes; + } + pp_hdr = p_dev->pp_pending_msg; + p_hdr = *pp_hdr; + p_data = (void *)(p_hdr + 1) + p_hdr->len; + // add data at the tail of the current message + memcpy(p_data, p_packet, length); + p_hdr->len += length; + + // decrement the number of bytes remaining + p_dev->pending_bytes -= length; + if (likely(p_dev->pending_bytes)) + { + // data still needed -> next descriptor + continue; + } + // no more pending bytes, check if it is full + btusb_isoc_check_msg(p_dev, pp_hdr); + packet_length -= length; + 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->pending_hdr_size))) + { + length = BTUSB_VOICE_HEADER_SIZE - p_dev->pending_hdr_size; + } + else + { + length = packet_length; + } + + // fill the hdr (in case header is split across descriptors) + memcpy(&p_dev->pending_hdr[p_dev->pending_hdr_size], p_packet, length); + p_dev->pending_hdr_size += length; + + if (likely(p_dev->pending_hdr_size == BTUSB_VOICE_HEADER_SIZE)) + { + p_dev->pending_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_disc_nohdr++; + p_dev->stats.voicerx_skipped_bytes += packet_length; + // this is not a correct header -> next descriptor + continue; + } + else if (likely(p_dev->pending_hdr_size < BTUSB_VOICE_HEADER_SIZE)) + { + p_dev->stats.voicerx_split_hdr++; + // header not complete -> next descriptor + continue; + } + else + { + BTUSB_ERR("ISOC Header larger than possible. This is a major failure.\n"); + btusb_isoc_reset_msg(p_dev); + } + } + } + + btusb_submit_voice_rx(p_dev, p_trans, GFP_ATOMIC); +} + diff --git a/btusb_1_6_29_1/src/.svn/text-base/btusb_lite.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite.c.svn-base new file mode 100755 index 0000000..f6d1374 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite.c.svn-base @@ -0,0 +1,1794 @@ +/* + * + * 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 "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_init(struct btusb_cb *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_cb *p_dev); +static void btusb_lite_msg_to_app_free(struct btusb_cb *p_dev, BT_HDR *p_msg); +static UINT8 *btusb_lite_msg_to_app_get_data_addr(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static char *btusb_lite_ipc_event_desc(UINT16 event); + +static void btusb_lite_ipc_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_hci_cmd_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_hci_acl_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_mgt_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_btu_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_btm_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_l2c_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_avdt_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static void btusb_lite_ipc_rsp_send(struct btusb_cb *p_dev, UINT16 event, UINT8 op_code, + UINT8 *p_param, UINT8 param_len); +static void btusb_lite_ipc_cmd_cplt_evt_send(struct btusb_cb *p_dev, + UINT16 opcode, UINT8 *p_param, UINT8 param_len); +static void btusb_lite_ipc_avdt_sync_info_send(struct btusb_cb *p_dev, + tAVDT_SYNC_INFO *p_sync_rsp); + +static void btusb_lite_ipc_sent_to_user(struct btusb_cb *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_open + ** + ** Description Open BTUSB Lite interface + ** + ** Returns None + ** + *******************************************************************************/ +static void btusb_lite_init(struct btusb_cb *p_dev) +{ + struct proc_dir_entry *p_lite_pde; + + /* Save p_lite_pde */ + p_lite_pde = p_dev->lite_cb.p_lite_pde; + + /* Clear Control Block */ + memset(&p_dev->lite_cb, 0x00, sizeof(p_dev->lite_cb)); + + /* Restore p_lite_pde */ + p_dev->lite_cb.p_lite_pde = p_lite_pde; +} + +/******************************************************************************* + ** + ** 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_cb *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.opened) + { + BTUSB_ERR("Lite interface already opened\n"); + rv = -EBUSY;; + goto out; + } + + file->private_data = p_dev; /* Save our private p_dev */ + + p_dev->lite_cb.opened = 1; /* Lite Interface opened */ + + /* Clear Every Lite Stack Control Block */ + memset(&p_dev->lite_cb.stat, 0, sizeof(p_dev->lite_cb.stat)); + memset(&p_dev->lite_cb.from_app, 0, sizeof(p_dev->lite_cb.from_app)); + memset(&p_dev->lite_cb.to_app, 0, sizeof(p_dev->lite_cb.to_app)); + memset(&p_dev->lite_cb.mgt, 0, sizeof(p_dev->lite_cb.mgt)); + memset(&p_dev->lite_cb.btu, 0, sizeof(p_dev->lite_cb.btu)); + memset(&p_dev->lite_cb.l2c, 0, sizeof(p_dev->lite_cb.l2c)); + memset(&p_dev->lite_cb.av, 0, sizeof(p_dev->lite_cb.av)); + memset(&p_dev->lite_cb.avdt, 0, sizeof(p_dev->lite_cb.avdt)); + + 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_cb *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.opened) + { + BTUSB_ERR("Lite interface was not opened\n"); + rv = -EBUSY;; + goto out; + } + + BTUSB_ERR("To do, flush/free pending data\n"); + btusb_lite_init(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_cb *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.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->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->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->from_app.rx_header[p_lite_cb->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->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->from_app.rx_header_len == BTUSB_LITE_IPC_HDR_SIZE) + { + p = p_lite_cb->from_app.rx_header; + STREAM_TO_UINT16(p_lite_cb->from_app.rx_len, p); + STREAM_TO_UINT16(rx_event, p); + + BTUSB_DBG("Rx Len=%d RxEvent=0x%X\n", p_lite_cb->from_app.rx_len, rx_event); + + p_lite_cb->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->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->from_app.p_rx_msg = p_msg; + } + } + /* If Header already received */ + else + { + p_msg = p_lite_cb->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->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->from_app.rx_len -= copy_len; + p_msg->len += copy_len; + + if (p_lite_cb->from_app.rx_len == 0) + { + /* Handle the received message */ + btusb_lite_ipc_hndl(p_dev, p_msg); + + p_lite_cb->from_app.p_rx_msg = NULL; + p_lite_cb->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_cb *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.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.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.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.to_app.ipc_queue); + if (p_msg) + { + p_dev->lite_cb.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.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: + { + tBTUSB_TRANSACTION *p_trans; + p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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.to_app.p_hdr_msg = p_hdr_msg; + + /* Dequeue HCI message */ + p_msg = GKI_dequeue(&p_dev->rx_queue); + p_dev->lite_cb.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_cb *p_dev, BT_HDR *p_msg) +{ + tBTUSB_TRANSACTION *p_trans; + + /* If the message is a "real" GKI buffer */ + if ((p_dev->lite_cb.to_app.p_ipc_msg == p_msg) || + (p_dev->lite_cb.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.to_app.p_hci_msg == p_msg) + { + p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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_cb *p_dev, BT_HDR *p_msg) +{ + /* Check if the message is a locally generated Event (IPC) message */ + if (p_dev->lite_cb.to_app.p_ipc_msg == p_msg) + { + GKI_freebuf(p_msg); + p_dev->lite_cb.to_app.p_ipc_msg = NULL; + return; + } + + /* Check if the message is a locally generated Header (IPC) message */ + if (p_dev->lite_cb.to_app.p_hdr_msg == p_msg) + { + GKI_freebuf(p_msg); + p_dev->lite_cb.to_app.p_hdr_msg = NULL; + return; + } + + /* Check if the message is an HCI message */ + if (p_dev->lite_cb.to_app.p_hci_msg == p_msg) + { + p_dev->lite_cb.to_app.p_hci_msg = NULL; + /* The buffer must not be freed. It has to be re-enqueue in USB core */ + btusb_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_cb *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.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_cb *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.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_cb *p_dev, struct usb_interface *p_interface) +{ + int rv; + char procname[64]; + + btusb_lite_init(p_dev); + + scnprintf(procname, sizeof(procname), "driver/%s-lite", p_interface->usb_dev->kobj.name); + p_dev->lite_cb.p_lite_pde = proc_create_data(procname, S_IRUGO | S_IWUGO, NULL, &btusb_lite_fops, p_dev); + if (p_dev->lite_cb.p_lite_pde == NULL) + { + BTUSB_ERR("Couldn't create %s entry\n", procname); + rv = -1; + } + else + { + BTUSB_INFO("Created /proc/%s\n", procname); + rv = 0; + } + + return rv; +} + +/******************************************************************************* + ** + ** Function btusb_lite_delete + ** + ** Description Delete BTUSB Lite interface + ** + ** Returns none + ** + *******************************************************************************/ +void btusb_lite_delete(struct btusb_cb *p_dev, struct usb_interface *p_interface) +{ + char procname[64]; + + scnprintf(procname, sizeof(procname), "driver/%s-lite", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + BTUSB_INFO("/proc/%s deleted\n", procname); +} + +/******************************************************************************* + ** + ** 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_cb *p_dev) +{ + if ((p_dev->lite_cb.opened) && /* User Space opened the Lite interface */ + (p_dev->lite_cb.mgt.opened) && /* IPC MGT Opened */ + /* Lite Transport is opened */ + ((p_dev->lite_cb.btu.transport_state == BTU_LITE_STACK_ACTIVE) || + (p_dev->lite_cb.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_cb *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_cb *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_cb *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_cb *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_cb *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.mgt.opened) + { + BTUSB_ERR("IPC_MGT Was already opened\n"); + UINT8_TO_STREAM(p_response, UIPC_STATUS_FAIL); /* Status */ + } + else + { + p_dev->lite_cb.mgt.opened = 1; + 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.mgt.opened = 0; + 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_cb *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.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.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_cb *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_cb *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_cb *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_cb *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.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_cb *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_cb *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_cb *p_dev, BT_HDR *p_msg) +{ + /* Update Lite Statistics */ + p_dev->lite_cb.stat.event_bytes += p_msg->len; + p_dev->lite_cb.stat.event_completed++; + + /* Enqueue message in IPC queue */ + GKI_enqueue(&p_dev->lite_cb.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/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_av.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_av.c.svn-base new file mode 100755 index 0000000..b2a1400 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_av.c.svn-base @@ -0,0 +1,1322 @@ +/* + * + * btusb_lite_av.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 <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 + +/* + * Definitions + */ +#define BTUSB_LITE_AV_PCM_CHANNEL 0 + +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(int pcm_stream, void *p_dev, void *p_data, + int nb_pcm_frames); +static void btusb_lite_av_send_packet(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static int btusb_lite_av_sbc_start(struct btusb_cb *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_cb *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_cb *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.av; + struct btusb_lite_av_scb *p_av_scb; + int rv; + + 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 == BTPCM_LITE_PCM_CLOSED) + { + /* Open the PCM Channel */ + rv = btpcm_open(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_open failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_OPENED; + p_av_cb->pcm.frequency = -1; + p_av_cb->pcm.channel = BTUSB_LITE_AV_PCM_CHANNEL; + } +} + +/******************************************************************************* +** +** Function btusb_lite_av_remove +** +** Description Remove (Cleanup) an AV channel. +** +** Returns None. +** +*******************************************************************************/ +void btusb_lite_av_remove(struct btusb_cb *p_dev, UINT8 scb_idx, + UINT8 audio_open_cnt, UINT16 curr_mtu) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 == BTPCM_LITE_PCM_STARTED) + { + /* Stop the PCM Channel */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_close failed\n"); + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_CONFIGURED; + } + + if (p_av_cb->pcm.state != BTPCM_LITE_PCM_CLOSED) + { + /* Close the PCM Channel */ + rv = btpcm_close(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_close failed\n"); + } + p_av_cb->pcm.state = BTPCM_LITE_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_cb *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.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_cb *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.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(BTUSB_LITE_AV_PCM_CHANNEL, + 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); + + /* Calculate nb_sbc_frames depending on MTU */ + nb_sbc_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_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(BTUSB_LITE_AV_PCM_CHANNEL, + 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 = BTPCM_LITE_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_cb *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.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(BTUSB_LITE_AV_PCM_CHANNEL, + 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); + + /* Calculate nb_sbc_frames depending on MTU */ + nb_sec_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_frame_size; + + /* 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(BTUSB_LITE_AV_PCM_CHANNEL, + 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_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM was not started\n"); + return; + } + + /* Stop the PCM stream */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_stop failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_CONFIGURED; +} + +/******************************************************************************* +** +** Function btusb_lite_av_suspend +** +** Description Suspend AV +** +** Returns none. +** +*******************************************************************************/ +void btusb_lite_av_suspend(struct btusb_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM was not started\n"); + return; + } + + /* Stop the PCM stream */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_stop failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_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(int pcm_stream, void *p_dev, void *p_data, + int nb_pcm_frames) +{ + 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 == NULL) + { + BTUSB_ERR("Null _p_dev\n"); + return; + } + + if (p_data == NULL) + { + BTUSB_ERR("Null p_data\n"); + return; + } + + if (pcm_stream != BTUSB_LITE_AV_PCM_CHANNEL) + { + BTUSB_ERR("Bad stream=%d\n", pcm_stream); + return; + } + + /* Get Reference on the SBC Stream (which is the same than the Encoder channel) */ + p_av_cb = &((struct btusb_cb *)p_dev)->lite_cb.av; + + if (p_av_cb->pcm.state != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM is not started\n"); + btpcm_stop(pcm_stream); + 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; + } + + /* 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 == NULL) + { + /* 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 + if (written_enc_size != p_av_cb->encoder.encoded_frame_size) + { + BTUSB_ERR("Bad Encoded Fame lenght=%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_cb *)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_cb *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 = &((struct btusb_cb *)p_dev)->lite_cb.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/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_avdt.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_avdt.c.svn-base new file mode 100755 index 0000000..46cf0ce --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_avdt.c.svn-base @@ -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_cb *p_dev); +static void btusb_lite_avdt_free_scb(struct btusb_cb *p_dev, struct btusb_lite_avdt_scb *p_scb_free); +static struct btusb_lite_avdt_ccb *btusb_lite_avdt_allocate_ccb(struct btusb_cb *p_dev); +static void btusb_lite_avdt_free_ccb(struct btusb_cb *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_cb *p_dev, UINT8 handle) +{ + struct btusb_lite_avdt_scb *p_scb; + UINT8 scb; + + p_scb = &p_dev->lite_cb.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_cb *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_cb *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_cb *p_dev) +{ + struct btusb_lite_avdt_ccb *p_ccb; + UINT8 ccb; + + p_ccb = &p_dev->lite_cb.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_cb *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.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_cb *p_dev) +{ + struct btusb_lite_avdt_scb *p_scb; + UINT8 scb; + + p_scb = &p_dev->lite_cb.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_cb *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.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_cb *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_cb *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/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_hci.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_hci.c.svn-base new file mode 100755 index 0000000..83835d9 --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_hci.c.svn-base @@ -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_cb *p_dev, BT_HDR *p_msg); +static int btusb_lite_hci_transport_resume_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb_cb *p_dev, + UINT16 opcode, UINT8 *p_param, UINT8 param_len); +static int btusb_lite_hci_nocp_event_hdlr(struct btusb_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_l2c.c.svn-base b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_l2c.c.svn-base new file mode 100755 index 0000000..5db7ecc --- a/dev/null +++ b/btusb_1_6_29_1/src/.svn/text-base/btusb_lite_l2c.c.svn-base @@ -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_cb *p_dev, tL2C_STREAM_INFO *p_l2c_stream) +{ + int idx; + struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.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_cb *p_dev, UINT16 local_cid) +{ + int idx; + struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.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_cb *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.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_cb *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.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/btusb_1_6_29_1/src/btusb.c b/btusb_1_6_29_1/src/btusb.c new file mode 100755 index 0000000..0cda85b --- a/dev/null +++ b/btusb_1_6_29_1/src/btusb.c @@ -0,0 +1,1625 @@ +/* + * + * btusb.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 <linux/module.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + +#include "btusb.h" +#include "hcidefs.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 const struct file_operations btusb_debug_fops = +{ + .open = btusb_debug_open, + .read = seq_read, + .write = btusb_debug_write, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations btusb_scosniff_fops = +{ + .open = btusb_scosniff_open, + .read = seq_read, + .llseek = seq_lseek, + .release = btusb_scosniff_release, +}; + +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(tBTUSB_CB *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(tBTUSB_CB *p_dev, struct usb_anchor *p_anchor, tBTUSB_TRANSACTION *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)) + { + BTUSB_ERR("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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data, do not forward to upper layers + if (unlikely(p_urb->status || !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_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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data or no more submitted diags, do not forward to upper layers + if (unlikely(p_urb->status || !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_enqueue(p_dev, p_trans, HCIT_TYPE_LM_DIAG); + + 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) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + 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_completed++; + + // check if device is disconnecting, has been unplugged or is closing + if (unlikely((p_urb->status == -ESHUTDOWN) || + (p_urb->status == -ENOENT) || + (p_urb->status == -EILSEQ))) + { + BTUSB_DBG("not queuing URB\n"); + goto exit; + } + + // if there was an error or no data, do not forward to upper layers + if (unlikely(p_urb->status || !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_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_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) +{ + tBTUSB_CB *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; + tBTUSB_TRANSACTION *p_trans; + int retval = -ENOMEM; + char procname[64]; + + 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(tBTUSB_CB), 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->context = p_dev; + 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_cmd_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->context = p_dev; + 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->context = p_dev; + 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->context = p_dev; + 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_write_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->context = p_dev; + 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->context = p_dev; + 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_write_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->context = p_dev; + 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; + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + usb_init_urb(&p_dev->p_voicetxIrpList[idx].urb); + } + + // 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("Not able to get a minor for this device\n"); + 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/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. + */ + scnprintf(procname, sizeof(procname), "driver/%s", p_interface->usb_dev->kobj.name); + p_dev->p_debug_pde = proc_create_data(procname, S_IRUGO | S_IWUGO, NULL, &btusb_debug_fops, p_dev); + if (p_dev->p_debug_pde == NULL) + { + BTUSB_ERR("Couldn't create proc entry\n"); + } + else + { + BTUSB_DBG("created /proc/%s\n", procname); + } + + scnprintf(procname, sizeof(procname), "driver/%s-scosniff", p_interface->usb_dev->kobj.name); + p_dev->p_scosniff_pde = proc_create_data(procname, S_IRUGO, NULL, &btusb_scosniff_fops, p_dev); + if (p_dev->p_scosniff_pde == NULL) + { + BTUSB_ERR("Couldn't create proc SCO sniff entry\n"); + } + else + { + BTUSB_DBG("created /proc/%s\n", procname); + INIT_LIST_HEAD(&p_dev->scosniff_list); + init_completion(&p_dev->scosniff_completion); + } + +#ifdef BTUSB_LITE + btusb_lite_create(p_dev, p_interface); +#endif + +#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 + + // 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_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(tBTUSB_CB *p_dev) +{ + int idx; + tBTUSB_VOICE_CHANNEL *p_chan; + + BTUSB_DBG("enter\n"); + + // cancel rx + BTUSB_DBG("Removing SCO RX anchored URBs\n"); + usb_kill_anchored_urbs(&p_dev->voice_rx_submitted); + + // free any SCO HCI message being consolidated + for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_channels); idx++) + { + p_chan = &p_dev->voice_channels[idx]; + if (p_chan->p_msg != NULL) + { + GKI_freebuf(p_chan->p_msg); + p_chan->p_msg = NULL; + } + } + // clear active RX processing + p_dev->pending_bytes = 0; + p_dev->pp_pending_msg = NULL; + p_dev->pending_hdr_size = 0; + + + // cancel tx + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + if (p_dev->p_voicetxIrpList[idx].used) + { + BTUSB_DBG("canceling tx URB %d\n", idx); + usb_kill_urb(&p_dev->p_voicetxIrpList[idx].urb); + p_dev->p_voicetxIrpList[idx].used = 0; + BTUSB_DBG("tx URB %d canceled\n", idx); + } + } + +} + +/******************************************************************************* + ** + ** 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(tBTUSB_CB *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) +{ + tBTUSB_CB *p_dev = usb_get_intfdata(p_interface); + int idx; + char procname[64]; + + BTUSB_INFO("p_dev=%p\n", p_dev); + if (p_dev == NULL) + { + 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); + + scnprintf(procname, sizeof(procname), "driver/%s", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + + scnprintf(procname, sizeof(procname), "driver/%s-scosniff", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + +#ifdef BTUSB_LITE + btusb_lite_stop_all(p_dev); + btusb_lite_delete(p_dev, p_interface); +#endif + + BTUSB_DBG("shutting down HCI intf\n"); + + /* prevent more I/O from starting */ + spin_lock_bh(&p_dev->tasklet_lock); + p_dev->p_main_intf = NULL; + spin_unlock_bh(&p_dev->tasklet_lock); + + // 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"); + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + p_dev->p_voicetxIrpList[idx].used = 0; + } + + 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) +{ + tBTUSB_CB *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) +{ + tBTUSB_CB *p_dev = usb_get_intfdata(p_interface); + int idx; + int retval = -ENOMEM; + tBTUSB_TRANSACTION *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(tBTUSB_CB *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; + + // initialize the elements of the device structure + mutex_init(&p_dev->open_mutex); + spin_lock_init(&p_dev->tasklet_lock); + 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); + + // 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"); + + BTUSB_DBG("sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS=%zu\n", + sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS); + p_dev->p_voicetxIrpList = kzalloc(sizeof(tBTUSB_ISO_ELEMENT)*BTUSB_NUM_OF_VOICE_TX_BUFFERS, GFP_KERNEL); + if (p_dev->p_voicetxIrpList == NULL) + { + dev_err(&p_interface->dev, "Out of memory for voice TX\n"); + return -ENOMEM; + } + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + p_dev->p_voicetxIrpList[idx].packet = kmalloc(BTUSB_MAXIMUM_TX_VOICE_SIZE, GFP_KERNEL); + if (p_dev->p_voicetxIrpList[idx].packet == NULL) + return -ENOMEM; + } + + 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; + + if ((le16_to_cpu(p_dev->p_udev->descriptor.idVendor) == 0x0A5C) && + (le16_to_cpu(p_dev->p_udev->descriptor.idProduct) == 0x0BDC)) + { + // the 43242 has a specific bug that needs to append 1 byte because it + // can not send ZLP + p_dev->quirks |= BTUSB_QUIRK_ZLP_RX_WA; + } + } + 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) +{ + tBTUSB_CB *p_dev = container_of(kref, tBTUSB_CB, kref); + tBTUSB_TRANSACTION *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_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); + } + usb_put_dev(p_dev->p_udev); + + for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++) + { + if (p_dev->p_voicetxIrpList[idx].packet) + { + kfree(p_dev->p_voicetxIrpList[idx].packet); + } + } + + if (p_dev->p_voicetxIrpList) + { + kfree(p_dev->p_voicetxIrpList); + } + kfree(p_dev); +} + + +/******************************************************************************* + ** + ** 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__); + + // initialize the GKI + GKI_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"); + + // shutdown the GKI + GKI_shutdown(); + + // 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/btusb_1_6_29_1/src/btusb_dev.c b/btusb_1_6_29_1/src/btusb_dev.c new file mode 100755 index 0000000..3638b1b --- a/dev/null +++ b/btusb_1_6_29_1/src/btusb_dev.c @@ -0,0 +1,2630 @@ +/*
+ *
+ * btusb_dev.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 <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 <linux/jiffies.h>
+
+#include "btusb.h"
+
+#include "hcidefs.h"
+
+#include "gki_int.h"
+
+// delay between the voice samples: 3 ms
+#define BTUSB_VOICE_DELAY 3
+
+// local functions declaration
+static int btusb_add_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle, unsigned char burst);
+static int btusb_remove_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle);
+static int btusb_update_voice_channels(tBTUSB_CB *p_dev);
+static void btusb_update_voice_rx(tBTUSB_CB *p_dev);
+static void btusb_submit_voice_tx(tBTUSB_CB *p_dev, UINT8 *p_data, int len);
+static int btusb_submit_cmd(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_acl(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_diag(tBTUSB_CB *p_dev, char *packet, unsigned long length);
+static int btusb_submit_write_voice(tBTUSB_CB *p_dev, void *p_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 tBTUSB_TRANSACTION *btusb_alloc_trans(tBTUSB_TRANSACTION *p_array, size_t size)
+{
+ int idx;
+ tBTUSB_TRANSACTION *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(¤t_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;
+ }
+ }
+
+ memcpy(p_last_time, ¤t_time, sizeof(struct timeval));
+ 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)
+{
+ tBTUSB_CB *p_dev = (tBTUSB_CB *) 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 - 4);
+ 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_enqueue
+ **
+ ** Description Add a received USB message into the user 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_enqueue(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *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);
+
+ switch (hcitype)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ // retrieve the length in the packet header
+ p += 2;
+ STREAM_TO_UINT16(len, p);
+ len += 4;
+ break;
+
+ case HCIT_TYPE_EVENT:
+ // retrieve the length in the packet header
+ 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;
+ }
+
+ // quirk for the ZLP HW issue
+ if (unlikely(((len % 16) == 0) && (p_dev->quirks & BTUSB_QUIRK_ZLP_RX_WA) &&
+ (p_urb->actual_length == (len + 1))))
+ {
+ BTUSB_DBG("missing ZLP workaround: %d != %d\n", p_urb->actual_length, len);
+ p_urb->actual_length = len;
+ }
+ // check if the length matches that of the ACL packet
+ if (unlikely(len != p_urb->actual_length))
+ {
+ 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_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_dequeued(tBTUSB_CB *p_dev, BT_HDR *p_msg)
+{
+ tBTUSB_TRANSACTION *p_trans = container_of(p_msg, tBTUSB_TRANSACTION, bt_hdr);
+
+ 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;
+
+ default:
+ GKI_freebuf(p_msg);
+ break;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_open
+ **
+ ** Description User mode open callback
+ **
+ *******************************************************************************/
+int btusb_open(struct inode *inode, struct file *file)
+{
+ tBTUSB_CB *p_dev;
+ struct usb_interface *interface;
+ int subminor;
+ int retval = 0;
+ BT_HDR *p_buf;
+
+ 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;
+ }
+
+ mutex_lock(&p_dev->open_mutex);
+ if (p_dev->opened)
+ {
+ mutex_unlock(&p_dev->open_mutex);
+ BTUSB_ERR("multiple open not allowed %d\n", p_dev->opened);
+ retval = -EBUSY;
+ goto exit;
+ }
+ // save our object in the file's private structure
+ file->private_data = p_dev;
+ p_dev->opened = true;
+ mutex_unlock(&p_dev->open_mutex);
+
+ // 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);
+
+ // free all pending messages in Rx queue
+ BTUSB_DBG("Free Rx Queue count:%d\n", p_dev->rx_queue.count);
+ while ((p_buf = (BT_HDR *)GKI_dequeue(&p_dev->rx_queue)) != NULL)
+ {
+ btusb_dequeued(p_dev, p_buf);
+ }
+
+exit:
+ return retval;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_release
+ **
+ ** Description User mode close callback
+ **
+ *******************************************************************************/
+int btusb_release(struct inode *inode, struct file *file)
+{
+ tBTUSB_CB *p_dev;
+ BT_HDR *p_buf = NULL;
+ int idx;
+
+ BTUSB_INFO("enter\n");
+
+ p_dev = (tBTUSB_CB *) 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
+
+ // indicate driver is closed
+ mutex_lock(&p_dev->open_mutex);
+ p_dev->opened = false;
+ mutex_unlock(&p_dev->open_mutex);
+
+ // free all the pending elements
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->tx_queue)) != NULL)
+ {
+ GKI_freebuf(p_buf);
+ }
+
+ while ((p_buf = (BT_HDR *) GKI_dequeue(&p_dev->rx_queue)) != NULL)
+ {
+ btusb_dequeued(p_dev, p_buf);
+ }
+
+ // 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_channels); idx++)
+ {
+ if (p_dev->voice_channels[idx].used)
+ {
+ if (btusb_remove_voice_channel(p_dev, p_dev->voice_channels[idx].info.sco_handle))
+ {
+ BTUSB_ERR("btusb_remove_voice_channel failed\n");
+ }
+ }
+ }
+
+ for (idx = 0; idx < BTUSB_NUM_OF_VOICE_TX_BUFFERS; idx++)
+ {
+ p_dev->p_voicetxIrpList[idx].used = 0;
+ }
+
+ // 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_cb *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_free_rx_packet
+ **
+ ** Description Free buffer sent to User Space
+ **
+ *******************************************************************************/
+static void btusb_free_rx_packet(struct btusb_cb *p_dev, BT_HDR *p_msg)
+{
+ if (unlikely(p_msg != p_dev->p_rx_msg))
+ {
+ BTUSB_ERR("Dequeued buffer (%p) does not matched working buffer (%p)\n",
+ p_msg, p_dev->p_rx_msg);
+ }
+
+ p_dev->p_rx_msg = NULL;
+
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ GKI_freebuf(p_msg);
+ }
+ else
+ {
+ // buffer received from USB -> resubmit
+ btusb_dequeued(p_dev, p_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_cb *p_dev, BT_HDR *p_msg)
+{
+ tBTUSB_TRANSACTION *p_trans;
+
+ switch(p_msg->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ case HCIT_TYPE_EVENT:
+ case HCIT_TYPE_LM_DIAG:
+ if (unlikely(p_msg->layer_specific & BTUSB_LS_GKI_BUFFER))
+ {
+ return ((char *)(p_msg + 1) + p_msg->offset);
+ }
+ else
+ {
+ p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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)
+{
+ tBTUSB_CB *p_dev = (tBTUSB_CB *)file->private_data;
+ UINT16 len;
+ size_t remainder = count;
+ BT_HDR *p_buf = NULL;
+ 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 (unlikely(!p_dev->opened))
+ {
+ BTUSB_ERR("driver is not open\n");
+ return -EINVAL;
+ }
+
+ // if read is non blocking and there is no data
+ if (unlikely((file->f_flags & O_NONBLOCK) && (btusb_get_rx_packet(p_dev) == NULL)))
+ {
+ BTUSB_INFO("Non blocking read without any data\n");
+ return -EAGAIN;
+ }
+
+ // wait for an event
+ retval = wait_event_interruptible(p_dev->rx_wait_q,
+ ((p_buf = btusb_get_rx_packet(p_dev)) != NULL));
+ if (unlikely(retval))
+ {
+ BTUSB_DBG("read wait interrupted\n");
+ return retval;
+ }
+ BTUSB_DBG("buffer=%p len=%u ls=%u\n", p_buf, p_buf->len, p_buf->layer_specific);
+
+ switch(p_buf->event)
+ {
+ case HCIT_TYPE_ACL_DATA:
+ case HCIT_TYPE_EVENT:
+ case HCIT_TYPE_LM_DIAG:
+ // if this is the first time buffer is picked, add HCI header in user space
+ if (likely(!(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;
+ }
+ buffer += 1;
+ remainder -= 1;
+ }
+ else
+ {
+ BTUSB_ERR("Not enough space to copy H4 ACL header\n");
+ goto read_end;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // 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;
+ p_buf->layer_specific |= BTUSB_LS_H4_TYPE_SENT;
+
+ // 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_free_rx_packet(p_dev, p_buf);
+ }
+
+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)
+{
+ tBTUSB_CB *p_dev;
+ BT_HDR *p_msg;
+ UINT8 *p_data;
+ size_t remainder = count;
+ int err;
+ UINT16 appended, len;
+
+ p_dev = (tBTUSB_CB *)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(!p_dev->opened))
+ {
+ return -EINVAL;
+ }
+
+ 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");
+ 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)
+{
+ tBTUSB_CB *p_dev;
+ unsigned int mask;
+
+ BTUSB_DBG("enter\n");
+
+ // retrieve the device from the file pointer
+ p_dev = (tBTUSB_CB *) 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;
+ }
+
+ if (unlikely(!p_dev->opened))
+ {
+ 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_get_rx_packet(p_dev))
+ {
+ mask |= POLLIN | POLLRDNORM;
+ }
+
+ return mask;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_print_voice_stat
+ **
+ ** Description SCO print voice stats
+ **
+ ** Parameters p_stat buffer holding the statistic to display.
+ **
+ ** Returns void.
+ **
+ *******************************************************************************/
+void btusb_print_voice_stat(tBTUSB_STATS * p_stat)
+{
+ printk("______________btusb_print_voice_stat______________\n");
+
+ printk("Number of voice reqs submitted USB stack %lu\n", p_stat->voicerx_submitted);
+ printk("Number of voice rx submitted in error %lu\n", p_stat->voicerx_submitted_error);
+ printk("Number of voice req completions from the USB software stack %lu\n", p_stat->voicerx_completed);
+ printk("Number of Voice req completions in error %lu\n", p_stat->voicerx_completed_error);
+ printk("Voice frames discarded due to bad status %lu\n", p_stat->voicerx_bad_packets);
+ printk("Voice frames discarded due to no headers in data %lu\n", p_stat->voicerx_disc_nohdr);
+
+ printk("Raw bytes received %lu\n",p_stat->voicerx_raw_bytes);
+ printk("Skipped bytes because no header matched %lu\n",p_stat->voicerx_skipped_bytes);
+ printk("Number of Voice Tx reqs submitted %lu\n",p_stat->voicetx_submitted);
+ printk("Number of voice tx submitted in error %lu\n",p_stat->voicetx_submitted_error);
+ printk("Number of Voice Tx reqs completed %lu\n",p_stat->voicetx_completed);
+ printk("Number of Voice Tx reqs completed in error %lu\n",p_stat->voicetx_completed_error);
+ printk("Number of Voice Tx not submitted due to no room on the tx queue %lu\n",
+ p_stat->voicetx_disc_nobuf);
+ printk("Number of Voice tx not submitted due to too long data %lu\n",
+ p_stat->voicetx_disc_toolong);
+
+ printk("voice pending counter %lu, max %lu\n", p_stat->voice_tx_cnt, p_stat->voice_max_tx_cnt);
+ p_stat->voice_tx_cnt=0;p_stat->voice_max_tx_cnt=0;
+
+ printk("Delta time between voice tx_done routine in us max: %lu, min: %lu\n", p_stat->voice_max_tx_done_delta_time, p_stat->voice_min_tx_done_delta_time);
+ memset(&(p_stat->voice_tx_done_delta_time) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_tx_done_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_tx_done_delta_time = 0;
+ p_stat->voice_min_tx_done_delta_time = 0;
+
+ printk("Delta time between voice tx feeding routine in us max: %lu, min: %lu\n", p_stat->voice_max_rx_feeding_interval, p_stat->voice_min_rx_feeding_interval);
+ memset(&(p_stat->voice_rx_feeding_interval) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_rx_feeding_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_rx_feeding_interval = 0;
+ p_stat->voice_min_rx_feeding_interval = 0;
+
+ printk("Delta time between voice rx_rdy routine max in us: %lu, min : %lu\n", p_stat->voice_max_rx_rdy_delta_time, p_stat->voice_min_rx_rdy_delta_time);
+ memset(&(p_stat->voice_rx_rdy_delta_time) , 0, sizeof(struct timeval));
+ memset(&(p_stat->voice_last_rx_rdy_ts) , 0, sizeof(struct timeval));
+ p_stat->voice_max_rx_rdy_delta_time = 0;
+ p_stat->voice_min_rx_rdy_delta_time = 0;
+
+ printk("_______________________________________________________\n");
+}
+
+#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;
+ tBTUSB_CB *p_dev;
+ tBTUSB_SCO_INFO sco_info;
+ int retval = 0;
+
+ s_cmd = btusb_ioctl_string(cmd);
+
+ BTUSB_INFO("cmd=%s\n", s_cmd);
+
+ p_dev = (tBTUSB_CB *) 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.sco_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.sco_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_write_complete
+ **
+ ** Description Data write (bulk pipe) completion routine
+ **
+ ** Parameters urb pointer
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_write_complete(struct urb *p_urb)
+{
+ tBTUSB_TRANSACTION *p_trans = p_urb->context;
+ tBTUSB_CB *p_dev = p_trans->context;
+
+ 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;
+
+ if (unlikely(p_urb->status))
+ {
+ p_dev->stats.writes_completed_error++;
+ printk(KERN_ERR "BTUSB btusb_write_complete failure %d\n", p_urb->status);
+ }
+ else
+ {
+ p_dev->stats.writes_completed++;
+ }
+
+ if(autopm)
+ {
+ usb_autopm_put_interface(p_dev->p_main_intf);
+ }
+
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_strip_off_acl_handle
+ **
+ ** Description Strip off the ACL handle if this is firmware download packet
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+void btusb_strip_off_acl_handle(char* *packet, unsigned long *length)
+{
+ UINT8* p = (UINT8 *) (*packet);
+
+ BTUSB_DBG("first bytes are %02X %02X\n", *p, *(p+1));
+
+ // check special handle for firmware download packet
+ if ((*p == 0xEF) && (*(p+1) == 0xBE))
+ {
+ *packet = (char *) (p + 4);
+ *length -= 4;
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_acl
+ **
+ ** Description ACL write submission to the controller
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_acl(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *p_trans;
+
+ BTUSB_DBG("%p[%lu]\n", packet, length);
+
+ // strip off the ACL handle if this is a firmware download packet
+ btusb_strip_off_acl_handle (&packet, &length);
+ BTUSB_DBG("after adjusting %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;
+#if 0
+ return btusb_submit_bulk(p_dev, packet, length, p_dev->p_acl_out, &p_dev->acl_tx_submitted);
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_diag
+ **
+ ** Description Diag write submission to the controller
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_diag(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *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 urb *p_urb)
+{
+ tBTUSB_TRANSACTION *p_trans = p_urb->context;
+ tBTUSB_CB *p_dev = p_trans->context;
+
+ BTUSB_DBG("status %d %u length flags %x\n", p_urb->status,
+ p_urb->transfer_buffer_length, p_urb->transfer_flags);
+
+ p_trans->gki_hdr.status = BUF_STATUS_FREE;
+
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_ERR("failure %d\n", p_urb->status);
+ p_dev->stats.commands_completed_error++;
+ }
+ else
+ {
+ p_dev->stats.commands_completed++;
+ }
+
+ if(autopm)
+ usb_autopm_put_interface(p_dev->p_main_intf);
+
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_cmd
+ **
+ ** Description
+ **
+ ** Parameters
+ **
+ ** Returns 0 upon success, negative value if error
+ **
+ *******************************************************************************/
+int btusb_submit_cmd(tBTUSB_CB *p_dev, char *packet, unsigned long length)
+{
+ int retval;
+ tBTUSB_TRANSACTION *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 == NULL))
+ {
+ 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.commands_submitted_error++;
+ goto error;
+ }
+ 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
+ **
+ *******************************************************************************/
+static void btusb_voicetx_complete(struct urb *p_urb)
+{
+ tBTUSB_ISO_ELEMENT *pIsoXfer = p_urb->context;
+ tBTUSB_CB *p_dev = (void *) pIsoXfer->dev;
+
+ 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));
+
+ // keep track on the number of Tx buffer pending
+ p_dev->stats.voice_tx_cnt--;
+
+ if (unlikely(!p_dev->p_main_intf))
+ goto exit;
+
+ pIsoXfer->used = 0;
+
+ if (unlikely(p_urb->status))
+ {
+ BTUSB_ERR("btusb_voicetx_complete failure %d\n", p_urb->status);
+ p_dev->stats.voicetx_completed_error++;
+ }
+ else
+ {
+ p_dev->stats.voicetx_completed++;
+ }
+
+exit:
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_fill_iso_pkts
+ **
+ ** Description Useful voice utility.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_fill_iso_pkts(struct urb *p_urb, int len, int pkt_size)
+{
+ int off = 0, i;
+
+ for (i = 0; len >= pkt_size; i++, off += pkt_size, len -= pkt_size)
+ {
+ p_urb->iso_frame_desc[i].offset = off;
+ p_urb->iso_frame_desc[i].length = pkt_size;
+ }
+
+ // remainder?
+ if (len)
+ {
+ p_urb->iso_frame_desc[i].offset = off;
+ p_urb->iso_frame_desc[i].length = len;
+ i++;
+ }
+
+ p_urb->number_of_packets = i;
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_fill_iso_rx_pkts
+ **
+ ** Description Useful voice utility.
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_fill_iso_rx_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;
+ return;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_rx
+ **
+ ** Description Resubmit an already filled URB request
+ **
+ ** Parameters
+ **
+ ** Returns
+ **
+ *******************************************************************************/
+void btusb_submit_voice_rx(tBTUSB_CB *p_dev, tBTUSB_TRANSACTION *p_trans, int mem_flags)
+{
+ if (unlikely(btusb_submit(p_dev, &p_dev->voice_rx_submitted, p_trans, mem_flags)))
+ {
+ p_dev->stats.voicerx_submitted_error++;
+ }
+ else
+ {
+ p_dev->stats.voicerx_submitted++;
+ }
+
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_update_voice_rx
+ **
+ ** Description Finish filling the voice URB and submit them. At this point
+ ** the URBs should NOT be submitted.
+ **
+ ** Parameters
+ **
+ ** Returns
+ **
+ *******************************************************************************/
+static void btusb_update_voice_rx(tBTUSB_CB *p_dev)
+{
+ unsigned int idx;
+ tBTUSB_TRANSACTION *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;
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_in->desc.wMaxPacketSize);
+ if (!packet_size)
+ {
+ BTUSB_ERR("failing, 0 packet size)\n");
+ return;
+ }
+ 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("Required buffer size larger than allocated size\n");
+ p_urb->transfer_buffer_length = BTUSB_VOICE_BUFFER_MAXSIZE;
+ }
+ btusb_fill_iso_rx_pkts(p_urb, p_urb->transfer_buffer_length, packet_size);
+
+ btusb_submit_voice_rx(p_dev, p_trans, GFP_KERNEL);
+ }
+}
+
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_voice_tx
+ **
+ ** Description Voice write submission
+ **
+ ** Parameters
+ **
+ ** Returns void
+ **
+ *******************************************************************************/
+static void btusb_submit_voice_tx(tBTUSB_CB *p_dev, UINT8 *p_data, int len)
+{
+ int to_send = 0;
+
+ 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));
+
+ while (len > 0)
+ {
+ if (len >= BTUSB_VOICE_BURST_SIZE)
+ {
+ to_send = BTUSB_VOICE_BURST_SIZE;
+ }
+ else
+ {
+ BTUSB_DBG("Sending partial sco data len: %d\n", len);
+ }
+ p_data[2] = to_send;
+ len -= to_send;
+ btusb_submit_write_voice(p_dev, p_data, to_send + 3);
+
+ if (len)
+ {
+ // copy the header for the next chunk
+ memcpy(p_data + BTUSB_VOICE_BURST_SIZE, p_data , 3);
+ p_data += BTUSB_VOICE_BURST_SIZE;
+ }
+ }
+
+ // we should always have at least 30 ms of audio ready to send
+ // if not fill up with silence
+ if (p_dev->stats.voice_tx_cnt<10)
+ {
+ BTUSB_DBG("less than 10 buffer in the Tx Q %lu insert silence \n", p_dev->stats.voice_tx_cnt);
+ while(p_dev->stats.voice_tx_cnt < 30)
+ {
+ memset(p_data + 3, 0, BTUSB_VOICE_BURST_SIZE );
+ btusb_submit_write_voice(p_dev, p_data, BTUSB_VOICE_BURST_SIZE + 3);
+ }
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_submit_write_voice
+ **
+ ** Description Voice write submission, length should be
+ ** smaller than or equal to VOICE_SAMPLE_SIZE
+ **
+ ** Parameters
+ **
+ ** Returns A zero value upon success.
+ **
+ *******************************************************************************/
+int btusb_submit_write_voice(tBTUSB_CB *p_dev, void *p_packet, unsigned long length)
+{
+ tBTUSB_ISO_ELEMENT *pIsoXfer;
+ struct urb *p_urb;
+ int status, pipe;
+ int packet_size, cur_frame_number;
+
+ 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 -1;
+ }
+
+ packet_size = le16_to_cpu(p_dev->p_voice_out->desc.wMaxPacketSize);
+ if ((length > BTUSB_MAXIMUM_TX_VOICE_SIZE) || !packet_size)
+ {
+ BTUSB_ERR("failing (%lu bytes - too many for %d packet size)\n", length, packet_size);
+ p_dev->stats.voicetx_disc_toolong++;
+ return -11;
+ }
+
+ // advance to the next voice tx IRP
+ if (++p_dev->voicetxIrpIndex == BTUSB_NUM_OF_VOICE_TX_BUFFERS)
+ p_dev->voicetxIrpIndex = 0;
+
+ // keep track on the number of tx buffer for stats debug and optimization
+ p_dev->stats.voice_tx_cnt++;
+ if (p_dev->stats.voice_tx_cnt>p_dev->stats.voice_max_tx_cnt)
+ {
+ p_dev->stats.voice_max_tx_cnt = p_dev->stats.voice_tx_cnt;
+ }
+
+ pIsoXfer = &p_dev->p_voicetxIrpList[p_dev->voicetxIrpIndex];
+
+ // buffer available?
+ if (pIsoXfer->used)
+ {
+ BTUSB_ERR("failed, no buf!\n");
+ p_dev->stats.voicetx_disc_nobuf++;
+ return -111;
+ }
+
+ p_urb = &pIsoXfer->urb;
+ pIsoXfer->index = p_dev->voicetxIrpIndex;
+ pIsoXfer->dev = p_dev;
+ memcpy(pIsoXfer->packet, p_packet, length);
+ pipe = usb_sndisocpipe(p_dev->p_udev, p_dev->p_voice_out->desc.bEndpointAddress);
+ p_urb->complete = btusb_voicetx_complete;
+ p_urb->context = pIsoXfer;
+ p_urb->dev = p_dev->p_udev;
+ p_urb->pipe = pipe;
+ p_urb->interval = p_dev->p_voice_out->desc.bInterval;
+ p_urb->transfer_buffer = pIsoXfer->packet;
+ p_urb->transfer_buffer_length = length;
+ btusb_fill_iso_pkts(p_urb, length, packet_size);
+ // p_urb->transfer_flags = 0;
+ p_urb->transfer_flags = URB_ISO_ASAP;
+ cur_frame_number = usb_get_current_frame_number(p_dev->p_udev);
+
+ BTUSB_INFO("len %lu idx %lu frm %u\n", length, pIsoXfer->index, cur_frame_number);
+ pIsoXfer->used = 1;
+ status = usb_submit_urb(p_urb, GFP_ATOMIC);
+ if (status)
+ {
+ BTUSB_ERR("usb_submit_urb failed %d\n", status);
+ p_dev->stats.voicetx_submitted_error++;
+ pIsoXfer->used = 0;
+ }
+ else
+ {
+ p_dev->stats.voicetx_submitted++;
+ BTUSB_DBG("success\n");
+ }
+
+ return(status);
+}
+
+/*******************************************************************************
+ **
+ ** 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(tBTUSB_CB *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)
+ {
+ btusb_update_voice_rx(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
+ **
+ *******************************************************************************/
+static int btusb_add_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle, unsigned char burst)
+{
+ int idx;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (!p_chan->used)
+ {
+ p_chan->info.sco_handle = sco_handle;
+ p_chan->info.burst = burst;
+ p_chan->used = 1;
+ 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
+ **
+ *******************************************************************************/
+static int btusb_remove_voice_channel(tBTUSB_CB *p_dev, unsigned short sco_handle)
+{
+ int idx;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used && (p_chan->info.sco_handle == sco_handle))
+ {
+ p_chan->used = 0;
+ 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(tBTUSB_CB *p_dev)
+{
+ int idx, jdx;
+ unsigned char min_burst, max_burst, num_voice_chan, voice_setting;
+ unsigned short desired_packet_size, packet_size;
+ tBTUSB_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_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used)
+ {
+ num_voice_chan++;
+ min_burst = min(min_burst, p_chan->info.burst);
+ max_burst = max(max_burst, p_chan->info.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);
+ // store the desired packet size
+ p_dev->desired_packet_size = desired_packet_size;
+
+ // 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);
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_debug_show
+ **
+ ** Description Function called when reading the /proc file created by our driver
+ **
+ *******************************************************************************/
+#define BTUSB_STATS(__n) \
+ seq_printf(s, " - " #__n " = %lu\n", p_dev->stats.__n)
+
+static int btusb_debug_show(struct seq_file *s, void *unused)
+{
+ tBTUSB_CB *p_dev = s->private;
+ struct usb_device *udev = p_dev->p_udev;
+ struct usb_host_interface *p_host_intf;
+ struct usb_endpoint_descriptor *p_ep_desc;
+ tBTUSB_VOICE_CHANNEL *p_chan;
+ int idx, jdx;
+
+ seq_printf(s, "USB device :\n");
+ seq_printf(s, " - Match info:\n");
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_VENDOR)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_VENDOR (0x%02X)\n", p_dev->p_id->idVendor);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_PRODUCT 0x%02X)\n", p_dev->p_id->idProduct);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_LO (%u)\n", p_dev->p_id->bcdDevice_lo);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_HI (%u)\n", p_dev->p_id->bcdDevice_hi);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_CLASS (0x%02X)\n", p_dev->p_id->bDeviceClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_SUBCLASS (0x%02X)\n", p_dev->p_id->bDeviceSubClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_DEV_PROTOCOL (0x%02X)\n", p_dev->p_id->bDeviceProtocol);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_CLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_CLASS (0x%02X)\n", p_dev->p_id->bInterfaceClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_SUBCLASS)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_SUBCLASS (0x%02X)\n", p_dev->p_id->bInterfaceSubClass);
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_PROTOCOL (0x%02X)\n", p_dev->p_id->bInterfaceProtocol);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 6, 0)
+ if (p_dev->p_id->match_flags & USB_DEVICE_ID_MATCH_INT_NUMBER)
+ seq_printf(s, " * USB_DEVICE_ID_MATCH_INT_NUMBER (%u)\n", p_dev->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_event_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, " * 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(tBTUSB_CB, cmd_array), sizeof(p_dev->cmd_array));
+ seq_printf(s, " * EVENT = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, event_array), sizeof(p_dev->event_array));
+ seq_printf(s, " * ACL RX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, acl_rx_array), sizeof(p_dev->acl_rx_array));
+ seq_printf(s, " * ACL TX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, acl_tx_array), sizeof(p_dev->acl_tx_array));
+ seq_printf(s, " * DIAG RX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, diag_rx_array), sizeof(p_dev->diag_rx_array));
+ seq_printf(s, " * DIAG TX = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, diag_tx_array), sizeof(p_dev->diag_tx_array));
+ seq_printf(s, " * VOICE = off:%zd/size=%zd\n", offsetof(tBTUSB_CB, voice_channels), offsetof(tBTUSB_CB, rx_queue)-offsetof(tBTUSB_CB, voice_channels));
+
+ seq_printf(s, "Status :\n");
+ seq_printf(s, " - issharedusb = %u\n", p_dev->issharedusb);
+ seq_printf(s, " - quirks = %u\n", p_dev->quirks);
+ seq_printf(s, " - opened = %d\n", p_dev->opened);
+ seq_printf(s, "Voice :\n");
+ // calculate number of voice sample per timer expiration
+ // HZ could be 100, 250 or 1000
+ if ((1000 / HZ) <= BTUSB_VOICE_DELAY)
+ {
+ seq_printf(s, " - number of voice samples per timer expiration = 1\n");
+ }
+ else
+ {
+ seq_printf(s, " - number of voice samples per timer expiration = %d\n",
+ (1000 / (HZ * BTUSB_VOICE_DELAY)));
+ }
+ jdx = 0;
+ for (idx = 0; idx < ARRAY_SIZE(p_dev->voice_channels); idx++)
+ {
+ p_chan = &p_dev->voice_channels[idx];
+ if (p_chan->used)
+ {
+ seq_printf(s, " - channel %d : SCO handle = %d(0x%02x) burst = %d\n", idx,
+ p_chan->info.sco_handle, p_chan->info.sco_handle, p_chan->info.burst);
+ jdx = 1;
+ }
+ }
+ if (jdx)
+ {
+ seq_printf(s, " - desired_packet_size = %d\n", p_dev->desired_packet_size);
+ }
+ else
+ {
+ seq_printf(s, " - No active channels\n");
+ }
+ seq_printf(s, "Statistics :\n");
+ 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_completed);
+ BTUSB_STATS(acl_rx_resubmit);
+ BTUSB_STATS(acl_rx_bytes);
+ BTUSB_STATS(event_submit_ok);
+ BTUSB_STATS(event_submit_err);
+ BTUSB_STATS(event_completed);
+ BTUSB_STATS(event_resubmit);
+ BTUSB_STATS(event_bytes);
+ BTUSB_STATS(diag_rx_submit_ok);
+ BTUSB_STATS(diag_rx_submit_err);
+ BTUSB_STATS(diag_rx_completed);
+ BTUSB_STATS(diag_rx_resubmit);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(diag_rx_bytes);
+ BTUSB_STATS(writes_submitted);
+ BTUSB_STATS(writes_submitted_error);
+ BTUSB_STATS(writes_completed);
+ BTUSB_STATS(writes_completed_error);
+ BTUSB_STATS(commands_submitted);
+ BTUSB_STATS(commands_submitted_error);
+ BTUSB_STATS(commands_completed);
+ BTUSB_STATS(commands_completed_error);
+ BTUSB_STATS(voicerx_submitted);
+ BTUSB_STATS(voicerx_submitted_error);
+ BTUSB_STATS(voicerx_completed);
+ BTUSB_STATS(voicerx_completed_error);
+ BTUSB_STATS(voicerx_bad_packets);
+ BTUSB_STATS(voicerx_disc_nohdr);
+ BTUSB_STATS(voicerx_split_hdr);
+ BTUSB_STATS(voicerx_raw_bytes);
+ BTUSB_STATS(voicerx_skipped_bytes);
+ BTUSB_STATS(voicetx_submitted);
+ BTUSB_STATS(voicetx_submitted_error);
+ BTUSB_STATS(voicetx_completed);
+ BTUSB_STATS(voicetx_completed_error);
+ BTUSB_STATS(voicetx_disc_nobuf);
+ BTUSB_STATS(voicetx_disc_toolong);
+ BTUSB_STATS(voice_tx_cnt);
+ BTUSB_STATS(voice_max_tx_cnt);
+
+ {
+ struct btusb_scosniff *p, *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_debug_write
+ **
+ ** Description Write handler of the debug /proc interface
+ **
+ *******************************************************************************/
+ssize_t btusb_debug_write(struct file *file, const char *buf,
+ size_t count, loff_t *pos)
+{
+ struct seq_file *s = file->private_data;
+ tBTUSB_CB *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;
+}
+
+/*******************************************************************************
+ **
+ ** Function btusb_debug_open
+ **
+ ** Description Open handler of the debug /proc interface
+ **
+ *******************************************************************************/
+int btusb_debug_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, btusb_debug_show, BTUSB_PDE_DATA(inode));
+}
+
+static void * btusb_scosniff_start(struct seq_file *s, loff_t *pos)
+{
+ tBTUSB_CB *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;
+}
+
+static void btusb_scosniff_stop(struct seq_file *s, void *v)
+{
+ BTUSB_INFO("stop\n");
+}
+
+static 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;
+}
+
+ static 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;
+}
+
+static const struct seq_operations btusb_scosniff_seq_ops = {
+ .start = btusb_scosniff_start,
+ .next = btusb_scosniff_next,
+ .stop = btusb_scosniff_stop,
+ .show = btusb_scosniff_show,
+};
+
+int btusb_scosniff_open(struct inode *inode, struct file *file)
+{
+ int rv;
+ tBTUSB_CB *p_dev = BTUSB_PDE_DATA(inode);
+
+ rv = seq_open(file, &btusb_scosniff_seq_ops);
+ if (!rv)
+ {
+ p_dev->scosniff_active = true;
+ ((struct seq_file *)file->private_data)->private = p_dev;
+ }
+ return rv;
+}
+
+int btusb_scosniff_release(struct inode *inode, struct file *file)
+{
+ struct btusb_scosniff *p, *n;
+ tBTUSB_CB *p_dev = BTUSB_PDE_DATA(inode);
+
+ 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);
+}
diff --git a/btusb_1_6_29_1/src/btusb_isoc.c b/btusb_1_6_29_1/src/btusb_isoc.c new file mode 100755 index 0000000..bc3acff --- a/dev/null +++ b/btusb_1_6_29_1/src/btusb_isoc.c @@ -0,0 +1,311 @@ +/* + * + * btusb_isoc.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 + * + * + */ + +// for kmalloc +#include <linux/slab.h> +#include "btusb.h" +#include "hcidefs.h" + +/******************************************************************************* + ** + ** Function btusb_isoc_reset_msg + ** + ** Description Reset the currently receiving voice message + ** + ** Parameters p_dev: device instance control block + ** + ** Returns void + ** + *******************************************************************************/ +static void btusb_isoc_reset_msg(tBTUSB_CB *p_dev) +{ + p_dev->pending_bytes = 0; + if (p_dev->pp_pending_msg && *p_dev->pp_pending_msg) + { + GKI_freebuf(*p_dev->pp_pending_msg); + } + p_dev->pp_pending_msg = NULL; + p_dev->pending_hdr_size = 0; +} + +/******************************************************************************* + ** + ** 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(tBTUSB_CB *p_dev) +{ + unsigned char *p_data = p_dev->pending_hdr; + int idx; + unsigned short sco_handle; + unsigned char size; + BT_HDR *p_hdr; + tBTUSB_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_channels); idx++) + { + p_chan = &p_dev->voice_channels[idx]; + if ((p_chan->used) && + (sco_handle == p_chan->info.sco_handle) && + (size <= (2 * p_chan->info.burst))) + { + // check if there is already a message being consolidated + if (unlikely(p_chan->p_msg == NULL)) + { + p_hdr = (BT_HDR *) GKI_getpoolbuf(HCI_SCO_POOL_ID); + if (unlikely(p_hdr == NULL)) + { + return false; + } + p_hdr->event = BT_EVT_TO_BTU_HCI_SCO; + p_hdr->len = 1 + BTUSB_VOICE_HEADER_SIZE; // sizeof(data_type) + SCO header + p_hdr->offset = 0; + p_hdr->layer_specific = 0; + + p_data = (void *) (p_hdr + 1); + + // add data type + UINT8_TO_STREAM(p_data, HCIT_TYPE_SCO_DATA); + UINT16_TO_STREAM(p_data, sco_handle); + + p_chan->p_msg = p_hdr; + } + p_dev->pending_bytes = size; + p_dev->pp_pending_msg = &p_chan->p_msg; + + return true; + } + } + return false; +} + +/******************************************************************************* + ** + ** Function btusb_isoc_check_msg + ** + ** Description Check the currently receiving message + ** + ** Parameters p_dev: device instance control block + ** pp_hdr: pointer to the receiving message + ** + ** Returns void + ** + *******************************************************************************/ +static void btusb_isoc_check_msg(tBTUSB_CB *p_dev, BT_HDR **pp_hdr) +{ + BT_HDR *p_hdr = *pp_hdr; + unsigned char *p_data; + + // if enough data was received + if (unlikely(p_hdr->len >= (1 + BTUSB_VOICE_HEADER_SIZE + SCO_RX_MAX_LEN))) + { + p_data = (void *)(p_hdr + 1); + p_data[BTUSB_VOICE_HEADER_SIZE] = p_hdr->len - BTUSB_VOICE_HEADER_SIZE - 1; + GKI_enqueue(&p_dev->rx_queue, p_hdr); + + // notify RX event(in case of select/poll + wake_up_interruptible(&p_dev->rx_wait_q); + + *pp_hdr = NULL; + } +} + +/******************************************************************************* + ** + ** Function btusb_voicerx_complete + ** + ** Description Voice read (iso pipe) completion routine. + ** + ** Parameters + ** + ** Returns void + ** + *******************************************************************************/ +void btusb_voicerx_complete(struct urb *p_urb) +{ + tBTUSB_TRANSACTION *p_trans = p_urb->context; + tBTUSB_CB *p_dev = p_trans->context; + BT_HDR **pp_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; + + BTUSB_INFO("enter"); + + 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)); + + p_dev->stats.voicerx_completed++; + + 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)) + { + BTUSB_ERR("failure %d\n", p_urb->status); + p_dev->stats.voicerx_completed_error++; + 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); + 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_packets++; + // 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->pending_bytes)) + { + fill_data: + if (likely(p_dev->pending_bytes >= packet_length)) + { + length = packet_length; + } + else + { + length = p_dev->pending_bytes; + } + pp_hdr = p_dev->pp_pending_msg; + p_hdr = *pp_hdr; + p_data = (void *)(p_hdr + 1) + p_hdr->len; + // add data at the tail of the current message + memcpy(p_data, p_packet, length); + p_hdr->len += length; + + // decrement the number of bytes remaining + p_dev->pending_bytes -= length; + if (likely(p_dev->pending_bytes)) + { + // data still needed -> next descriptor + continue; + } + // no more pending bytes, check if it is full + btusb_isoc_check_msg(p_dev, pp_hdr); + packet_length -= length; + 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->pending_hdr_size))) + { + length = BTUSB_VOICE_HEADER_SIZE - p_dev->pending_hdr_size; + } + else + { + length = packet_length; + } + + // fill the hdr (in case header is split across descriptors) + memcpy(&p_dev->pending_hdr[p_dev->pending_hdr_size], p_packet, length); + p_dev->pending_hdr_size += length; + + if (likely(p_dev->pending_hdr_size == BTUSB_VOICE_HEADER_SIZE)) + { + p_dev->pending_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_disc_nohdr++; + p_dev->stats.voicerx_skipped_bytes += packet_length; + // this is not a correct header -> next descriptor + continue; + } + else if (likely(p_dev->pending_hdr_size < BTUSB_VOICE_HEADER_SIZE)) + { + p_dev->stats.voicerx_split_hdr++; + // header not complete -> next descriptor + continue; + } + else + { + BTUSB_ERR("ISOC Header larger than possible. This is a major failure.\n"); + btusb_isoc_reset_msg(p_dev); + } + } + } + + btusb_submit_voice_rx(p_dev, p_trans, GFP_ATOMIC); +} + diff --git a/btusb_1_6_29_1/src/btusb_lite.c b/btusb_1_6_29_1/src/btusb_lite.c new file mode 100755 index 0000000..f6d1374 --- a/dev/null +++ b/btusb_1_6_29_1/src/btusb_lite.c @@ -0,0 +1,1794 @@ +/* + * + * 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 "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_init(struct btusb_cb *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_cb *p_dev); +static void btusb_lite_msg_to_app_free(struct btusb_cb *p_dev, BT_HDR *p_msg); +static UINT8 *btusb_lite_msg_to_app_get_data_addr(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static char *btusb_lite_ipc_event_desc(UINT16 event); + +static void btusb_lite_ipc_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_hci_cmd_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_hci_acl_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_mgt_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_btu_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_btm_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_l2c_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_ipc_avdt_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static void btusb_lite_ipc_rsp_send(struct btusb_cb *p_dev, UINT16 event, UINT8 op_code, + UINT8 *p_param, UINT8 param_len); +static void btusb_lite_ipc_cmd_cplt_evt_send(struct btusb_cb *p_dev, + UINT16 opcode, UINT8 *p_param, UINT8 param_len); +static void btusb_lite_ipc_avdt_sync_info_send(struct btusb_cb *p_dev, + tAVDT_SYNC_INFO *p_sync_rsp); + +static void btusb_lite_ipc_sent_to_user(struct btusb_cb *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_open + ** + ** Description Open BTUSB Lite interface + ** + ** Returns None + ** + *******************************************************************************/ +static void btusb_lite_init(struct btusb_cb *p_dev) +{ + struct proc_dir_entry *p_lite_pde; + + /* Save p_lite_pde */ + p_lite_pde = p_dev->lite_cb.p_lite_pde; + + /* Clear Control Block */ + memset(&p_dev->lite_cb, 0x00, sizeof(p_dev->lite_cb)); + + /* Restore p_lite_pde */ + p_dev->lite_cb.p_lite_pde = p_lite_pde; +} + +/******************************************************************************* + ** + ** 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_cb *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.opened) + { + BTUSB_ERR("Lite interface already opened\n"); + rv = -EBUSY;; + goto out; + } + + file->private_data = p_dev; /* Save our private p_dev */ + + p_dev->lite_cb.opened = 1; /* Lite Interface opened */ + + /* Clear Every Lite Stack Control Block */ + memset(&p_dev->lite_cb.stat, 0, sizeof(p_dev->lite_cb.stat)); + memset(&p_dev->lite_cb.from_app, 0, sizeof(p_dev->lite_cb.from_app)); + memset(&p_dev->lite_cb.to_app, 0, sizeof(p_dev->lite_cb.to_app)); + memset(&p_dev->lite_cb.mgt, 0, sizeof(p_dev->lite_cb.mgt)); + memset(&p_dev->lite_cb.btu, 0, sizeof(p_dev->lite_cb.btu)); + memset(&p_dev->lite_cb.l2c, 0, sizeof(p_dev->lite_cb.l2c)); + memset(&p_dev->lite_cb.av, 0, sizeof(p_dev->lite_cb.av)); + memset(&p_dev->lite_cb.avdt, 0, sizeof(p_dev->lite_cb.avdt)); + + 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_cb *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.opened) + { + BTUSB_ERR("Lite interface was not opened\n"); + rv = -EBUSY;; + goto out; + } + + BTUSB_ERR("To do, flush/free pending data\n"); + btusb_lite_init(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_cb *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.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->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->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->from_app.rx_header[p_lite_cb->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->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->from_app.rx_header_len == BTUSB_LITE_IPC_HDR_SIZE) + { + p = p_lite_cb->from_app.rx_header; + STREAM_TO_UINT16(p_lite_cb->from_app.rx_len, p); + STREAM_TO_UINT16(rx_event, p); + + BTUSB_DBG("Rx Len=%d RxEvent=0x%X\n", p_lite_cb->from_app.rx_len, rx_event); + + p_lite_cb->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->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->from_app.p_rx_msg = p_msg; + } + } + /* If Header already received */ + else + { + p_msg = p_lite_cb->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->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->from_app.rx_len -= copy_len; + p_msg->len += copy_len; + + if (p_lite_cb->from_app.rx_len == 0) + { + /* Handle the received message */ + btusb_lite_ipc_hndl(p_dev, p_msg); + + p_lite_cb->from_app.p_rx_msg = NULL; + p_lite_cb->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_cb *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.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.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.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.to_app.ipc_queue); + if (p_msg) + { + p_dev->lite_cb.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.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: + { + tBTUSB_TRANSACTION *p_trans; + p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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.to_app.p_hdr_msg = p_hdr_msg; + + /* Dequeue HCI message */ + p_msg = GKI_dequeue(&p_dev->rx_queue); + p_dev->lite_cb.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_cb *p_dev, BT_HDR *p_msg) +{ + tBTUSB_TRANSACTION *p_trans; + + /* If the message is a "real" GKI buffer */ + if ((p_dev->lite_cb.to_app.p_ipc_msg == p_msg) || + (p_dev->lite_cb.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.to_app.p_hci_msg == p_msg) + { + p_trans = container_of(p_msg, tBTUSB_TRANSACTION, 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_cb *p_dev, BT_HDR *p_msg) +{ + /* Check if the message is a locally generated Event (IPC) message */ + if (p_dev->lite_cb.to_app.p_ipc_msg == p_msg) + { + GKI_freebuf(p_msg); + p_dev->lite_cb.to_app.p_ipc_msg = NULL; + return; + } + + /* Check if the message is a locally generated Header (IPC) message */ + if (p_dev->lite_cb.to_app.p_hdr_msg == p_msg) + { + GKI_freebuf(p_msg); + p_dev->lite_cb.to_app.p_hdr_msg = NULL; + return; + } + + /* Check if the message is an HCI message */ + if (p_dev->lite_cb.to_app.p_hci_msg == p_msg) + { + p_dev->lite_cb.to_app.p_hci_msg = NULL; + /* The buffer must not be freed. It has to be re-enqueue in USB core */ + btusb_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_cb *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.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_cb *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.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_cb *p_dev, struct usb_interface *p_interface) +{ + int rv; + char procname[64]; + + btusb_lite_init(p_dev); + + scnprintf(procname, sizeof(procname), "driver/%s-lite", p_interface->usb_dev->kobj.name); + p_dev->lite_cb.p_lite_pde = proc_create_data(procname, S_IRUGO | S_IWUGO, NULL, &btusb_lite_fops, p_dev); + if (p_dev->lite_cb.p_lite_pde == NULL) + { + BTUSB_ERR("Couldn't create %s entry\n", procname); + rv = -1; + } + else + { + BTUSB_INFO("Created /proc/%s\n", procname); + rv = 0; + } + + return rv; +} + +/******************************************************************************* + ** + ** Function btusb_lite_delete + ** + ** Description Delete BTUSB Lite interface + ** + ** Returns none + ** + *******************************************************************************/ +void btusb_lite_delete(struct btusb_cb *p_dev, struct usb_interface *p_interface) +{ + char procname[64]; + + scnprintf(procname, sizeof(procname), "driver/%s-lite", p_interface->usb_dev->kobj.name); + remove_proc_entry(procname, NULL); + BTUSB_INFO("/proc/%s deleted\n", procname); +} + +/******************************************************************************* + ** + ** 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_cb *p_dev) +{ + if ((p_dev->lite_cb.opened) && /* User Space opened the Lite interface */ + (p_dev->lite_cb.mgt.opened) && /* IPC MGT Opened */ + /* Lite Transport is opened */ + ((p_dev->lite_cb.btu.transport_state == BTU_LITE_STACK_ACTIVE) || + (p_dev->lite_cb.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_cb *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_cb *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_cb *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_cb *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_cb *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.mgt.opened) + { + BTUSB_ERR("IPC_MGT Was already opened\n"); + UINT8_TO_STREAM(p_response, UIPC_STATUS_FAIL); /* Status */ + } + else + { + p_dev->lite_cb.mgt.opened = 1; + 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.mgt.opened = 0; + 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_cb *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.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.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_cb *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_cb *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_cb *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_cb *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.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_cb *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_cb *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_cb *p_dev, BT_HDR *p_msg) +{ + /* Update Lite Statistics */ + p_dev->lite_cb.stat.event_bytes += p_msg->len; + p_dev->lite_cb.stat.event_completed++; + + /* Enqueue message in IPC queue */ + GKI_enqueue(&p_dev->lite_cb.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/btusb_1_6_29_1/src/btusb_lite_av.c b/btusb_1_6_29_1/src/btusb_lite_av.c new file mode 100755 index 0000000..b2a1400 --- a/dev/null +++ b/btusb_1_6_29_1/src/btusb_lite_av.c @@ -0,0 +1,1322 @@ +/* + * + * btusb_lite_av.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 <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 + +/* + * Definitions + */ +#define BTUSB_LITE_AV_PCM_CHANNEL 0 + +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(int pcm_stream, void *p_dev, void *p_data, + int nb_pcm_frames); +static void btusb_lite_av_send_packet(struct btusb_cb *p_dev, BT_HDR *p_msg); + +static int btusb_lite_av_sbc_start(struct btusb_cb *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_cb *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_cb *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.av; + struct btusb_lite_av_scb *p_av_scb; + int rv; + + 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 == BTPCM_LITE_PCM_CLOSED) + { + /* Open the PCM Channel */ + rv = btpcm_open(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_open failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_OPENED; + p_av_cb->pcm.frequency = -1; + p_av_cb->pcm.channel = BTUSB_LITE_AV_PCM_CHANNEL; + } +} + +/******************************************************************************* +** +** Function btusb_lite_av_remove +** +** Description Remove (Cleanup) an AV channel. +** +** Returns None. +** +*******************************************************************************/ +void btusb_lite_av_remove(struct btusb_cb *p_dev, UINT8 scb_idx, + UINT8 audio_open_cnt, UINT16 curr_mtu) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 == BTPCM_LITE_PCM_STARTED) + { + /* Stop the PCM Channel */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_close failed\n"); + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_CONFIGURED; + } + + if (p_av_cb->pcm.state != BTPCM_LITE_PCM_CLOSED) + { + /* Close the PCM Channel */ + rv = btpcm_close(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_close failed\n"); + } + p_av_cb->pcm.state = BTPCM_LITE_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_cb *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.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_cb *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.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(BTUSB_LITE_AV_PCM_CHANNEL, + 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); + + /* Calculate nb_sbc_frames depending on MTU */ + nb_sbc_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_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(BTUSB_LITE_AV_PCM_CHANNEL, + 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 = BTPCM_LITE_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_cb *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.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(BTUSB_LITE_AV_PCM_CHANNEL, + 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); + + /* Calculate nb_sbc_frames depending on MTU */ + nb_sec_frames = (p_av_cb->curr_mtu - av_header_len) / p_encoder->encoded_frame_size; + + /* 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(BTUSB_LITE_AV_PCM_CHANNEL, + 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_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM was not started\n"); + return; + } + + /* Stop the PCM stream */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_stop failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_PCM_CONFIGURED; +} + +/******************************************************************************* +** +** Function btusb_lite_av_suspend +** +** Description Suspend AV +** +** Returns none. +** +*******************************************************************************/ +void btusb_lite_av_suspend(struct btusb_cb *p_dev, UINT8 scb_idx, UINT8 audio_open_cnt) +{ + struct btusb_lite_av_cb *p_av_cb = &p_dev->lite_cb.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 != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM was not started\n"); + return; + } + + /* Stop the PCM stream */ + rv = btpcm_stop(BTUSB_LITE_AV_PCM_CHANNEL); + if (rv < 0) + { + BTUSB_ERR("btpcm_stop failed\n"); + return; + } + p_av_cb->pcm.state = BTPCM_LITE_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(int pcm_stream, void *p_dev, void *p_data, + int nb_pcm_frames) +{ + 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 == NULL) + { + BTUSB_ERR("Null _p_dev\n"); + return; + } + + if (p_data == NULL) + { + BTUSB_ERR("Null p_data\n"); + return; + } + + if (pcm_stream != BTUSB_LITE_AV_PCM_CHANNEL) + { + BTUSB_ERR("Bad stream=%d\n", pcm_stream); + return; + } + + /* Get Reference on the SBC Stream (which is the same than the Encoder channel) */ + p_av_cb = &((struct btusb_cb *)p_dev)->lite_cb.av; + + if (p_av_cb->pcm.state != BTPCM_LITE_PCM_STARTED) + { + BTUSB_ERR("BTPCM is not started\n"); + btpcm_stop(pcm_stream); + 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; + } + + /* 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 == NULL) + { + /* 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 + if (written_enc_size != p_av_cb->encoder.encoded_frame_size) + { + BTUSB_ERR("Bad Encoded Fame lenght=%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_cb *)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_cb *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 = &((struct btusb_cb *)p_dev)->lite_cb.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/btusb_1_6_29_1/src/btusb_lite_avdt.c b/btusb_1_6_29_1/src/btusb_lite_avdt.c new file mode 100755 index 0000000..46cf0ce --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *p_dev); +static void btusb_lite_avdt_free_scb(struct btusb_cb *p_dev, struct btusb_lite_avdt_scb *p_scb_free); +static struct btusb_lite_avdt_ccb *btusb_lite_avdt_allocate_ccb(struct btusb_cb *p_dev); +static void btusb_lite_avdt_free_ccb(struct btusb_cb *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_cb *p_dev, UINT8 handle) +{ + struct btusb_lite_avdt_scb *p_scb; + UINT8 scb; + + p_scb = &p_dev->lite_cb.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_cb *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_cb *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_cb *p_dev) +{ + struct btusb_lite_avdt_ccb *p_ccb; + UINT8 ccb; + + p_ccb = &p_dev->lite_cb.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_cb *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.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_cb *p_dev) +{ + struct btusb_lite_avdt_scb *p_scb; + UINT8 scb; + + p_scb = &p_dev->lite_cb.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_cb *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.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_cb *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_cb *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/btusb_1_6_29_1/src/btusb_lite_hci.c b/btusb_1_6_29_1/src/btusb_lite_hci.c new file mode 100755 index 0000000..83835d9 --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *p_dev, BT_HDR *p_msg); +static int btusb_lite_hci_transport_resume_hndl(struct btusb_cb *p_dev, BT_HDR *p_msg); +static void btusb_lite_hci_cmd_cplt_evt_send(struct btusb_cb *p_dev, + UINT16 opcode, UINT8 *p_param, UINT8 param_len); +static int btusb_lite_hci_nocp_event_hdlr(struct btusb_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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_cb *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/btusb_1_6_29_1/src/btusb_lite_l2c.c b/btusb_1_6_29_1/src/btusb_lite_l2c.c new file mode 100755 index 0000000..5db7ecc --- a/dev/null +++ b/btusb_1_6_29_1/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_cb *p_dev, tL2C_STREAM_INFO *p_l2c_stream) +{ + int idx; + struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.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_cb *p_dev, UINT16 local_cid) +{ + int idx; + struct btusb_lite_l2c_cb *p_l2c = &p_dev->lite_cb.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_cb *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.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_cb *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.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/btusb_1_6_29_1/src/gki/.svn/all-wcprops b/btusb_1_6_29_1/src/gki/.svn/all-wcprops new file mode 100755 index 0000000..0fc5fe2 --- a/dev/null +++ b/btusb_1_6_29_1/src/gki/.svn/all-wcprops @@ -0,0 +1,17 @@ +K 25 +svn:wc:ra_dav:version-url +V 76 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/gki +END +gki_buffer.c +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/gki/gki_buffer.c +END +gki_klinux.c +K 25 +svn:wc:ra_dav:version-url +V 89 +/svn/SiP/!svn/ver/725/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/gki/gki_klinux.c +END diff --git a/btusb_1_6_29_1/src/gki/.svn/entries b/btusb_1_6_29_1/src/gki/.svn/entries new file mode 100755 index 0000000..6ded4eb --- a/dev/null +++ b/btusb_1_6_29_1/src/gki/.svn/entries @@ -0,0 +1,96 @@ +10 + +dir +941 +http://10.10.29.8/svn/SiP/Broadcom/Android/Trunk/BT/BTUSB/btusb_1_6_29_1/src/gki +http://10.10.29.8/svn/SiP + + + +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + +e48500f2-7125-4e9d-852c-c0ee60673d08 + +gki_buffer.c +file + + + + +2014-08-14T08:53:29.712694Z +a2f67e488104296ce096c5aa1706cdb6 +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +35299 + +gki_klinux.c +file + + + + +2014-08-14T08:53:29.708694Z +74401143a2ce1b771b31aaeb0b14e10e +2014-08-14T09:21:52.961444Z +725 +luke + + + + + + + + + + + + + + + + + + + + + +6695 + diff --git a/btusb_1_6_29_1/src/gki/.svn/text-base/gki_buffer.c.svn-base b/btusb_1_6_29_1/src/gki/.svn/text-base/gki_buffer.c.svn-base new file mode 100755 index 0000000..e85670d --- a/dev/null +++ b/btusb_1_6_29_1/src/gki/.svn/text-base/gki_buffer.c.svn-base @@ -0,0 +1,1280 @@ +/* + * + * 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]; + } + + 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) +{ + UINT8 i; + + for (i = 0; i < gki_cb.curr_total_no_of_pools; i++) + { + if (pool_id == gki_cb.pool_list[i]) + break; + } + + 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]; + sprintf(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(tBTUSB_TRANSACTION, magic) - offsetof(tBTUSB_TRANSACTION, 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/btusb_1_6_29_1/src/gki/.svn/text-base/gki_klinux.c.svn-base b/btusb_1_6_29_1/src/gki/.svn/text-base/gki_klinux.c.svn-base new file mode 100755 index 0000000..fb424ee --- a/dev/null +++ b/btusb_1_6_29_1/src/gki/.svn/text-base/gki_klinux.c.svn-base @@ -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; +} + + diff --git a/btusb_1_6_29_1/src/gki/gki_buffer.c b/btusb_1_6_29_1/src/gki/gki_buffer.c new file mode 100755 index 0000000..496cb90 --- a/dev/null +++ b/btusb_1_6_29_1/src/gki/gki_buffer.c @@ -0,0 +1,1282 @@ +/* + * + * 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 */ + j = (gki_cb.curr_total_no_of_pools < GKI_NUM_TOTAL_BUF_POOLS - 1) ? gki_cb.curr_total_no_of_pools : GKI_NUM_TOTAL_BUF_POOLS - 1; + + for (; j > i; j--) + { + gki_cb.pool_list[j] = gki_cb.pool_list[j-1]; + } + + 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) +{ + UINT8 i; + + for (i = 0; i < gki_cb.curr_total_no_of_pools; i++) + { + if (pool_id == gki_cb.pool_list[i]) + break; + } + + 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]; + sprintf(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(tBTUSB_TRANSACTION, magic) - offsetof(tBTUSB_TRANSACTION, 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/btusb_1_6_29_1/src/gki/gki_klinux.c b/btusb_1_6_29_1/src/gki/gki_klinux.c new file mode 100755 index 0000000..fb424ee --- a/dev/null +++ b/btusb_1_6_29_1/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; +} + + |