1.蓝牙驱动
This commit is contained in:
parent
a369f09caa
commit
c671d5050a
|
@ -80,6 +80,8 @@ CONFIG_PREEMPT_COUNT=y
|
|||
CONFIG_TICK_CPU_ACCOUNTING=y
|
||||
# CONFIG_VIRT_CPU_ACCOUNTING_GEN is not set
|
||||
# CONFIG_IRQ_TIME_ACCOUNTING is not set
|
||||
# CONFIG_BSD_PROCESS_ACCT is not set
|
||||
# CONFIG_TASKSTATS is not set
|
||||
|
||||
#
|
||||
# RCU Subsystem
|
||||
|
@ -96,6 +98,7 @@ CONFIG_LOG_BUF_SHIFT=15
|
|||
CONFIG_PRINTK_SAFE_LOG_BUF_SHIFT=12
|
||||
CONFIG_GENERIC_SCHED_CLOCK=y
|
||||
# CONFIG_CGROUPS is not set
|
||||
# CONFIG_NAMESPACES is not set
|
||||
# CONFIG_CHECKPOINT_RESTORE is not set
|
||||
# CONFIG_SCHED_AUTOGROUP is not set
|
||||
# CONFIG_SYSFS_DEPRECATED is not set
|
||||
|
@ -116,7 +119,8 @@ CONFIG_ANON_INODES=y
|
|||
CONFIG_HAVE_UID16=y
|
||||
CONFIG_BPF=y
|
||||
CONFIG_EXPERT=y
|
||||
# CONFIG_MULTIUSER is not set
|
||||
CONFIG_UID16=y
|
||||
CONFIG_MULTIUSER=y
|
||||
# CONFIG_SGETMASK_SYSCALL is not set
|
||||
CONFIG_SYSFS_SYSCALL=y
|
||||
# CONFIG_SYSCTL_SYSCALL is not set
|
||||
|
@ -128,7 +132,7 @@ CONFIG_PRINTK_NMI=y
|
|||
# CONFIG_BASE_FULL is not set
|
||||
CONFIG_FUTEX=y
|
||||
CONFIG_FUTEX_PI=y
|
||||
# CONFIG_EPOLL is not set
|
||||
CONFIG_EPOLL=y
|
||||
CONFIG_SIGNALFD=y
|
||||
CONFIG_TIMERFD=y
|
||||
CONFIG_EVENTFD=y
|
||||
|
@ -653,7 +657,30 @@ CONFIG_BQL=y
|
|||
# CONFIG_NET_PKTGEN is not set
|
||||
# CONFIG_HAMRADIO is not set
|
||||
# CONFIG_CAN is not set
|
||||
# CONFIG_BT is not set
|
||||
CONFIG_BT=y
|
||||
CONFIG_BT_BREDR=y
|
||||
# CONFIG_BT_RFCOMM is not set
|
||||
# CONFIG_BT_BNEP is not set
|
||||
CONFIG_BT_HS=y
|
||||
CONFIG_BT_LE=y
|
||||
# CONFIG_BT_SELFTEST is not set
|
||||
CONFIG_BT_DEBUGFS=y
|
||||
|
||||
#
|
||||
# Bluetooth device drivers
|
||||
#
|
||||
# CONFIG_BT_HCIBTUSB is not set
|
||||
# CONFIG_BT_HCIBTSDIO is not set
|
||||
CONFIG_BT_HCIUART=y
|
||||
CONFIG_BT_HCIUART_H4=y
|
||||
# CONFIG_BT_HCIUART_BCSP is not set
|
||||
CONFIG_BT_HCIUART_RTKH5=y
|
||||
# CONFIG_BT_HCIUART_LL is not set
|
||||
# CONFIG_BT_HCIBCM203X is not set
|
||||
# CONFIG_BT_HCIBPA10X is not set
|
||||
# CONFIG_BT_HCIBFUSB is not set
|
||||
# CONFIG_BT_HCIVHCI is not set
|
||||
# CONFIG_BT_MRVL is not set
|
||||
# CONFIG_AF_RXRPC is not set
|
||||
# CONFIG_AF_KCM is not set
|
||||
CONFIG_WIRELESS=y
|
||||
|
@ -2602,6 +2629,7 @@ CONFIG_KEYS=y
|
|||
# CONFIG_ENCRYPTED_KEYS is not set
|
||||
# CONFIG_KEY_DH_OPERATIONS is not set
|
||||
# CONFIG_SECURITY_DMESG_RESTRICT is not set
|
||||
# CONFIG_SECURITY is not set
|
||||
# CONFIG_SECURITYFS is not set
|
||||
CONFIG_HAVE_HARDENED_USERCOPY_ALLOCATOR=y
|
||||
# CONFIG_HARDENED_USERCOPY is not set
|
||||
|
@ -2628,10 +2656,11 @@ CONFIG_CRYPTO_RNG_DEFAULT=y
|
|||
CONFIG_CRYPTO_AKCIPHER2=y
|
||||
CONFIG_CRYPTO_AKCIPHER=y
|
||||
CONFIG_CRYPTO_KPP2=y
|
||||
CONFIG_CRYPTO_KPP=y
|
||||
CONFIG_CRYPTO_ACOMP2=y
|
||||
CONFIG_CRYPTO_RSA=y
|
||||
# CONFIG_CRYPTO_DH is not set
|
||||
# CONFIG_CRYPTO_ECDH is not set
|
||||
CONFIG_CRYPTO_ECDH=y
|
||||
CONFIG_CRYPTO_MANAGER=y
|
||||
CONFIG_CRYPTO_MANAGER2=y
|
||||
# CONFIG_CRYPTO_USER is not set
|
||||
|
@ -2677,7 +2706,7 @@ CONFIG_CRYPTO_ECB=y
|
|||
#
|
||||
# Hash modes
|
||||
#
|
||||
CONFIG_CRYPTO_CMAC=m
|
||||
CONFIG_CRYPTO_CMAC=y
|
||||
CONFIG_CRYPTO_HMAC=y
|
||||
# CONFIG_CRYPTO_XCBC is not set
|
||||
# CONFIG_CRYPTO_VMAC is not set
|
||||
|
|
|
@ -1,28 +1,10 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
menu "Bluetooth device drivers"
|
||||
depends on BT
|
||||
|
||||
config BT_INTEL
|
||||
tristate
|
||||
select REGMAP
|
||||
|
||||
config BT_BCM
|
||||
tristate
|
||||
select FW_LOADER
|
||||
|
||||
config BT_RTL
|
||||
tristate
|
||||
select FW_LOADER
|
||||
|
||||
config BT_QCA
|
||||
tristate
|
||||
select FW_LOADER
|
||||
|
||||
config BT_HCIBTUSB
|
||||
tristate "HCI USB driver"
|
||||
depends on USB
|
||||
select BT_INTEL
|
||||
help
|
||||
Bluetooth HCI USB driver.
|
||||
This driver is required if you want to use Bluetooth devices with
|
||||
|
@ -31,38 +13,6 @@ config BT_HCIBTUSB
|
|||
Say Y here to compile support for Bluetooth USB devices into the
|
||||
kernel or say M to compile it as module (btusb).
|
||||
|
||||
config BT_HCIBTUSB_AUTOSUSPEND
|
||||
bool "Enable USB autosuspend for Bluetooth USB devices by default"
|
||||
depends on BT_HCIBTUSB
|
||||
help
|
||||
Say Y here to enable USB autosuspend for Bluetooth USB devices by
|
||||
default.
|
||||
|
||||
This can be overridden by passing btusb.enable_autosuspend=[y|n]
|
||||
on the kernel commandline.
|
||||
|
||||
config BT_HCIBTUSB_BCM
|
||||
bool "Broadcom protocol support"
|
||||
depends on BT_HCIBTUSB
|
||||
select BT_BCM
|
||||
default y
|
||||
help
|
||||
The Broadcom protocol support enables firmware and patchram
|
||||
download support for Broadcom Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Broadcom protocol.
|
||||
|
||||
config BT_HCIBTUSB_RTL
|
||||
bool "Realtek protocol support"
|
||||
depends on BT_HCIBTUSB
|
||||
select BT_RTL
|
||||
default y
|
||||
help
|
||||
The Realtek protocol support enables firmware and configuration
|
||||
download support for Realtek Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Realtek protocol.
|
||||
|
||||
config BT_HCIBTSDIO
|
||||
tristate "HCI SDIO driver"
|
||||
depends on MMC
|
||||
|
@ -76,9 +26,6 @@ config BT_HCIBTSDIO
|
|||
|
||||
config BT_HCIUART
|
||||
tristate "HCI UART driver"
|
||||
depends on SERIAL_DEV_BUS || !SERIAL_DEV_BUS
|
||||
depends on NVMEM || !NVMEM
|
||||
depends on TTY
|
||||
help
|
||||
Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use Bluetooth devices with
|
||||
|
@ -89,11 +36,6 @@ config BT_HCIUART
|
|||
Say Y here to compile support for Bluetooth UART devices into the
|
||||
kernel or say M to compile it as module (hci_uart).
|
||||
|
||||
config BT_HCIUART_SERDEV
|
||||
bool
|
||||
depends on SERIAL_DEV_BUS && BT_HCIUART
|
||||
default y
|
||||
|
||||
config BT_HCIUART_H4
|
||||
bool "UART (H4) protocol support"
|
||||
depends on BT_HCIUART
|
||||
|
@ -104,21 +46,6 @@ config BT_HCIUART_H4
|
|||
|
||||
Say Y here to compile support for HCI UART (H4) protocol.
|
||||
|
||||
config BT_HCIUART_NOKIA
|
||||
tristate "UART Nokia H4+ protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
depends on GPIOLIB
|
||||
depends on PM
|
||||
select BT_HCIUART_H4
|
||||
select BT_BCM
|
||||
help
|
||||
Nokia H4+ is serial protocol for communication between Bluetooth
|
||||
device and host. This protocol is required for Bluetooth devices
|
||||
with UART interface in Nokia devices.
|
||||
|
||||
Say Y here to compile support for Nokia's H4+ protocol.
|
||||
|
||||
config BT_HCIUART_BCSP
|
||||
bool "BCSP protocol support"
|
||||
depends on BT_HCIUART
|
||||
|
@ -131,23 +58,19 @@ config BT_HCIUART_BCSP
|
|||
|
||||
Say Y here to compile support for HCI BCSP protocol.
|
||||
|
||||
config BT_HCIUART_ATH3K
|
||||
bool "Atheros AR300x serial support"
|
||||
config BT_HCIUART_RTKH5
|
||||
bool "Realtek H5 protocol support"
|
||||
depends on BT_HCIUART
|
||||
select BT_HCIUART_H4
|
||||
help
|
||||
HCIATH3K (HCI Atheros AR300x) is a serial protocol for
|
||||
communication between host and Atheros AR300x Bluetooth devices.
|
||||
This protocol enables AR300x chips to be enabled with
|
||||
power management support.
|
||||
Enable this if you have Atheros AR300x serial Bluetooth device.
|
||||
Realtek H5 is serial protocol for communication
|
||||
between Realtek Bluetooth device and host. This protocol is required for
|
||||
Realtek uart h5 bluetooth controller
|
||||
|
||||
Say Y here to compile support for HCI UART ATH3K protocol.
|
||||
Say Y here to compile support for Realtek HCI H5 protocol.
|
||||
|
||||
config BT_HCIUART_LL
|
||||
bool "HCILL protocol support"
|
||||
depends on BT_HCIUART_SERDEV
|
||||
select BT_HCIUART_H4
|
||||
depends on BT_HCIUART
|
||||
help
|
||||
HCILL (HCI Low Level) is a serial protocol for communication
|
||||
between Bluetooth device and host. This protocol is required for
|
||||
|
@ -156,95 +79,6 @@ config BT_HCIUART_LL
|
|||
|
||||
Say Y here to compile support for HCILL protocol.
|
||||
|
||||
config BT_HCIUART_3WIRE
|
||||
bool "Three-wire UART (H5) protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
help
|
||||
The HCI Three-wire UART Transport Layer makes it possible to
|
||||
user the Bluetooth HCI over a serial port interface. The HCI
|
||||
Three-wire UART Transport Layer assumes that the UART
|
||||
communication may have bit errors, overrun errors or burst
|
||||
errors and thereby making CTS/RTS lines unnecessary.
|
||||
|
||||
Say Y here to compile support for Three-wire UART protocol.
|
||||
|
||||
config BT_HCIUART_INTEL
|
||||
bool "Intel protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on GPIOLIB
|
||||
select BT_HCIUART_H4
|
||||
select BT_INTEL
|
||||
help
|
||||
The Intel protocol support enables Bluetooth HCI over serial
|
||||
port interface for Intel Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Intel protocol.
|
||||
|
||||
config BT_HCIUART_BCM
|
||||
bool "Broadcom protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
depends on (!ACPI || SERIAL_DEV_CTRL_TTYPORT)
|
||||
depends on GPIOLIB
|
||||
select BT_HCIUART_H4
|
||||
select BT_BCM
|
||||
help
|
||||
The Broadcom protocol support enables Bluetooth HCI over serial
|
||||
port interface for Broadcom Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Broadcom protocol.
|
||||
|
||||
config BT_HCIUART_RTL
|
||||
bool "Realtek protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
depends on GPIOLIB
|
||||
depends on ACPI
|
||||
select BT_HCIUART_3WIRE
|
||||
select BT_RTL
|
||||
help
|
||||
The Realtek protocol support enables Bluetooth HCI over 3-Wire
|
||||
serial port internface for Realtek Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Realtek protocol.
|
||||
|
||||
config BT_HCIUART_QCA
|
||||
bool "Qualcomm Atheros protocol support"
|
||||
depends on BT_HCIUART
|
||||
depends on BT_HCIUART_SERDEV
|
||||
select BT_HCIUART_H4
|
||||
select BT_QCA
|
||||
help
|
||||
The Qualcomm Atheros protocol supports HCI In-Band Sleep feature
|
||||
over serial port interface(H4) between controller and host.
|
||||
This protocol is required for UART clock control for QCA Bluetooth
|
||||
devices.
|
||||
|
||||
Say Y here to compile support for QCA protocol.
|
||||
|
||||
config BT_HCIUART_AG6XX
|
||||
bool "Intel AG6XX protocol support"
|
||||
depends on BT_HCIUART
|
||||
select BT_HCIUART_H4
|
||||
select BT_INTEL
|
||||
help
|
||||
The Intel/AG6XX protocol support enables Bluetooth HCI over serial
|
||||
port interface for Intel ibt 2.1 Bluetooth controllers.
|
||||
|
||||
Say Y here to compile support for Intel AG6XX protocol.
|
||||
|
||||
config BT_HCIUART_MRVL
|
||||
bool "Marvell protocol support"
|
||||
depends on BT_HCIUART
|
||||
select BT_HCIUART_H4
|
||||
help
|
||||
Marvell is serial protocol for communication between Bluetooth
|
||||
device and host. This protocol is required for most Marvell Bluetooth
|
||||
devices with UART interface.
|
||||
|
||||
Say Y here to compile support for HCI MRVL protocol.
|
||||
|
||||
config BT_HCIBCM203X
|
||||
tristate "HCI BCM203x USB driver"
|
||||
depends on USB
|
||||
|
@ -321,6 +155,22 @@ config BT_HCIBLUECARD
|
|||
Say Y here to compile support for HCI BlueCard devices into the
|
||||
kernel or say M to compile it as module (bluecard_cs).
|
||||
|
||||
config BT_HCIBTUART
|
||||
tristate "HCI UART (PC Card) device driver"
|
||||
depends on PCMCIA
|
||||
help
|
||||
Bluetooth HCI UART (PC Card) driver.
|
||||
This driver provides support for Bluetooth PCMCIA devices with
|
||||
an UART interface:
|
||||
Xircom CreditCard Bluetooth Adapter
|
||||
Xircom RealPort2 Bluetooth Adapter
|
||||
Sphinx PICO Card
|
||||
H-Soft blue+Card
|
||||
Cyber-blue Compact Flash Card
|
||||
|
||||
Say Y here to compile support for HCI UART devices into the
|
||||
kernel or say M to compile it as module (btuart_cs).
|
||||
|
||||
config BT_HCIVHCI
|
||||
tristate "HCI VHCI (Virtual HCI device) driver"
|
||||
help
|
||||
|
@ -336,7 +186,7 @@ config BT_MRVL
|
|||
The core driver to support Marvell Bluetooth devices.
|
||||
|
||||
This driver is required if you want to support
|
||||
Marvell Bluetooth devices, such as 8688/8787/8797/8887/8897/8997.
|
||||
Marvell Bluetooth devices, such as 8688.
|
||||
|
||||
Say Y here to compile Marvell Bluetooth driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
@ -345,13 +195,12 @@ config BT_MRVL_SDIO
|
|||
tristate "Marvell BT-over-SDIO driver"
|
||||
depends on BT_MRVL && MMC
|
||||
select FW_LOADER
|
||||
select WANT_DEV_COREDUMP
|
||||
help
|
||||
The driver for Marvell Bluetooth chipsets with SDIO interface.
|
||||
|
||||
This driver is required if you want to use Marvell Bluetooth
|
||||
devices with SDIO interface. Currently SD8688/SD8787/SD8797/SD8887/SD8897/SD8997
|
||||
chipsets are supported.
|
||||
devices with SDIO interface. Currently only SD8688 chipset is
|
||||
supported.
|
||||
|
||||
Say Y here to compile support for Marvell BT-over-SDIO driver
|
||||
into the kernel or say M to compile it as module.
|
||||
|
@ -368,49 +217,4 @@ config BT_ATH3K
|
|||
Say Y here to compile support for "Atheros firmware download driver"
|
||||
into the kernel or say M to compile it as module (ath3k).
|
||||
|
||||
config BT_WILINK
|
||||
tristate "Texas Instruments WiLink7 driver"
|
||||
depends on TI_ST
|
||||
help
|
||||
This enables the Bluetooth driver for Texas Instrument's BT/FM/GPS
|
||||
combo devices. This makes use of shared transport line discipline
|
||||
core driver to communicate with the BT core of the combo chip.
|
||||
|
||||
Say Y here to compile support for Texas Instrument's WiLink7 driver
|
||||
into the kernel or say M to compile it as module (btwilink).
|
||||
|
||||
config BT_MTKUART
|
||||
tristate "MediaTek HCI UART driver"
|
||||
depends on SERIAL_DEV_BUS
|
||||
help
|
||||
MediaTek Bluetooth HCI UART driver.
|
||||
This driver is required if you want to use MediaTek Bluetooth
|
||||
with serial interface.
|
||||
|
||||
Say Y here to compile support for MediaTek Bluetooth UART devices
|
||||
into the kernel or say M to compile it as module (btmtkuart).
|
||||
|
||||
config BT_QCOMSMD
|
||||
tristate "Qualcomm SMD based HCI support"
|
||||
depends on RPMSG || (COMPILE_TEST && RPMSG=n)
|
||||
depends on QCOM_WCNSS_CTRL || (COMPILE_TEST && QCOM_WCNSS_CTRL=n)
|
||||
select BT_QCA
|
||||
help
|
||||
Qualcomm SMD based HCI driver.
|
||||
This driver is used to bridge HCI data onto the shared memory
|
||||
channels to the WCNSS core.
|
||||
|
||||
Say Y here to compile support for HCI over Qualcomm SMD into the
|
||||
kernel or say M to compile as a module.
|
||||
|
||||
config BT_HCIRSI
|
||||
tristate
|
||||
help
|
||||
Redpine BT driver.
|
||||
This driver handles BT traffic from upper layers and pass
|
||||
to the RSI_91x coex module for further scheduling to device
|
||||
|
||||
Say Y here to compile support for HCI over Redpine into the
|
||||
kernel or say M to compile as a module.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,48 +1,17 @@
|
|||
# SPDX-License-Identifier: GPL-2.0
|
||||
#
|
||||
# Makefile for the Linux Bluetooth HCI device drivers.
|
||||
#
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := hci_uart.o
|
||||
hci_uart-y := hci_ldisc.o hci_h4.o hci_rtk_h5.o rtk_coex.o
|
||||
#EXTRA_CFLAGS += -DDEBUG
|
||||
|
||||
obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o
|
||||
obj-$(CONFIG_BT_HCIUART) += hci_uart.o
|
||||
obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o
|
||||
obj-$(CONFIG_BT_HCIBPA10X) += bpa10x.o
|
||||
obj-$(CONFIG_BT_HCIBFUSB) += bfusb.o
|
||||
obj-$(CONFIG_BT_HCIDTL1) += dtl1_cs.o
|
||||
obj-$(CONFIG_BT_HCIBT3C) += bt3c_cs.o
|
||||
obj-$(CONFIG_BT_HCIBLUECARD) += bluecard_cs.o
|
||||
else
|
||||
PWD := $(shell pwd)
|
||||
KVER := $(shell uname -r)
|
||||
KDIR := /lib/modules/$(KVER)/build
|
||||
|
||||
obj-$(CONFIG_BT_HCIBTUSB) += btusb.o
|
||||
obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
obj-$(CONFIG_BT_INTEL) += btintel.o
|
||||
obj-$(CONFIG_BT_ATH3K) += ath3k.o
|
||||
obj-$(CONFIG_BT_MRVL) += btmrvl.o
|
||||
obj-$(CONFIG_BT_MRVL_SDIO) += btmrvl_sdio.o
|
||||
obj-$(CONFIG_BT_WILINK) += btwilink.o
|
||||
obj-$(CONFIG_BT_MTKUART) += btmtkuart.o
|
||||
obj-$(CONFIG_BT_QCOMSMD) += btqcomsmd.o
|
||||
obj-$(CONFIG_BT_BCM) += btbcm.o
|
||||
obj-$(CONFIG_BT_RTL) += btrtl.o
|
||||
obj-$(CONFIG_BT_QCA) += btqca.o
|
||||
clean:
|
||||
rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.order *.a
|
||||
|
||||
obj-$(CONFIG_BT_HCIUART_NOKIA) += hci_nokia.o
|
||||
|
||||
obj-$(CONFIG_BT_HCIRSI) += btrsi.o
|
||||
|
||||
btmrvl-y := btmrvl_main.o
|
||||
btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o
|
||||
|
||||
hci_uart-y := hci_ldisc.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_SERDEV) += hci_serdev.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_H4) += hci_h4.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_QCA) += hci_qca.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_AG6XX) += hci_ag6xx.o
|
||||
hci_uart-$(CONFIG_BT_HCIUART_MRVL) += hci_mrvl.o
|
||||
hci_uart-objs := $(hci_uart-y)
|
||||
endif
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
|
@ -32,7 +31,6 @@
|
|||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
|
@ -40,18 +38,32 @@
|
|||
#include <linux/signal.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
#endif
|
||||
|
||||
//#define VERSION "1.2"
|
||||
|
||||
struct h4_struct {
|
||||
unsigned long rx_state;
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
struct sk_buff_head txq;
|
||||
};
|
||||
|
||||
/* H4 receiver States */
|
||||
#define H4_W4_PACKET_TYPE 0
|
||||
#define H4_W4_EVENT_HDR 1
|
||||
#define H4_W4_ACL_HDR 2
|
||||
#define H4_W4_SCO_HDR 3
|
||||
#define H4_W4_DATA 4
|
||||
|
||||
/* Initialize protocol */
|
||||
static int h4_open(struct hci_uart *hu)
|
||||
{
|
||||
|
@ -59,7 +71,7 @@ static int h4_open(struct hci_uart *hu)
|
|||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
h4 = kzalloc(sizeof(*h4), GFP_KERNEL);
|
||||
h4 = kzalloc(sizeof(*h4), GFP_ATOMIC);
|
||||
if (!h4)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -108,33 +120,174 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
|||
BT_DBG("hu %p skb %p", hu, skb);
|
||||
|
||||
/* Prepend skb with frame type */
|
||||
memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
|
||||
memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
|
||||
skb_queue_tail(&h4->txq, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct h4_recv_pkt h4_recv_pkts[] = {
|
||||
{ H4_RECV_ACL, .recv = hci_recv_frame },
|
||||
{ H4_RECV_SCO, .recv = hci_recv_frame },
|
||||
{ H4_RECV_EVENT, .recv = hci_recv_frame },
|
||||
};
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
static inline int h4_check_data_len(struct h4_struct *h4, int len)
|
||||
#else
|
||||
static inline int h4_check_data_len(struct hci_dev *hdev, struct h4_struct *h4, int len)
|
||||
#endif
|
||||
{
|
||||
register int room = skb_tailroom(h4->rx_skb);
|
||||
|
||||
BT_DBG("len %d room %d", len, room);
|
||||
|
||||
if (!len) {
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
hci_recv_frame(h4->rx_skb);
|
||||
#else
|
||||
hci_recv_frame(hdev, h4->rx_skb);
|
||||
#endif
|
||||
} else if (len > room) {
|
||||
BT_ERR("Data length is too large");
|
||||
kfree_skb(h4->rx_skb);
|
||||
} else {
|
||||
h4->rx_state = H4_W4_DATA;
|
||||
h4->rx_count = len;
|
||||
return len;
|
||||
}
|
||||
|
||||
h4->rx_state = H4_W4_PACKET_TYPE;
|
||||
h4->rx_skb = NULL;
|
||||
h4->rx_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Recv data */
|
||||
static int h4_recv(struct hci_uart *hu, const void *data, int count)
|
||||
static int h4_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
struct h4_struct *h4 = hu->priv;
|
||||
register char *ptr;
|
||||
struct hci_event_hdr *eh;
|
||||
struct hci_acl_hdr *ah;
|
||||
struct hci_sco_hdr *sh;
|
||||
register int len, type, dlen;
|
||||
|
||||
if (!test_bit(HCI_UART_REGISTERED, &hu->flags))
|
||||
return -EUNATCH;
|
||||
BT_DBG("hu %p count %d rx_state %ld rx_count %ld",
|
||||
hu, count, h4->rx_state, h4->rx_count);
|
||||
|
||||
h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count,
|
||||
h4_recv_pkts, ARRAY_SIZE(h4_recv_pkts));
|
||||
if (IS_ERR(h4->rx_skb)) {
|
||||
int err = PTR_ERR(h4->rx_skb);
|
||||
bt_dev_err(hu->hdev, "Frame reassembly failed (%d)", err);
|
||||
ptr = data;
|
||||
while (count) {
|
||||
if (h4->rx_count) {
|
||||
len = min_t(unsigned int, h4->rx_count, count);
|
||||
memcpy(skb_put(h4->rx_skb, len), ptr, len);
|
||||
h4->rx_count -= len; count -= len; ptr += len;
|
||||
|
||||
if (h4->rx_count)
|
||||
continue;
|
||||
|
||||
switch (h4->rx_state) {
|
||||
case H4_W4_DATA:
|
||||
BT_DBG("Complete data");
|
||||
#ifdef BTCOEX
|
||||
if(bt_cb(h4->rx_skb)->pkt_type == HCI_EVENT_PKT)
|
||||
rtk_btcoex_parse_event(
|
||||
h4->rx_skb->data,
|
||||
h4->rx_skb->len);
|
||||
|
||||
if(bt_cb(h4->rx_skb)->pkt_type == HCI_ACLDATA_PKT)
|
||||
rtk_btcoex_parse_l2cap_data_rx(
|
||||
h4->rx_skb->data,
|
||||
h4->rx_skb->len);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
hci_recv_frame(h4->rx_skb);
|
||||
#else
|
||||
hci_recv_frame(hu->hdev, h4->rx_skb);
|
||||
#endif
|
||||
|
||||
h4->rx_state = H4_W4_PACKET_TYPE;
|
||||
h4->rx_skb = NULL;
|
||||
return err;
|
||||
continue;
|
||||
|
||||
case H4_W4_EVENT_HDR:
|
||||
eh = hci_event_hdr(h4->rx_skb);
|
||||
|
||||
BT_DBG("Event header: evt 0x%2.2x plen %d", eh->evt, eh->plen);
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
h4_check_data_len(h4, eh->plen);
|
||||
#else
|
||||
h4_check_data_len(hu->hdev, h4, eh->plen);
|
||||
#endif
|
||||
continue;
|
||||
|
||||
case H4_W4_ACL_HDR:
|
||||
ah = hci_acl_hdr(h4->rx_skb);
|
||||
dlen = __le16_to_cpu(ah->dlen);
|
||||
|
||||
BT_DBG("ACL header: dlen %d", dlen);
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
h4_check_data_len(h4, dlen);
|
||||
#else
|
||||
h4_check_data_len(hu->hdev, h4, dlen);
|
||||
#endif
|
||||
continue;
|
||||
|
||||
case H4_W4_SCO_HDR:
|
||||
sh = hci_sco_hdr(h4->rx_skb);
|
||||
|
||||
BT_DBG("SCO header: dlen %d", sh->dlen);
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
h4_check_data_len(h4, sh->dlen);
|
||||
#else
|
||||
h4_check_data_len(hu->hdev, h4, sh->dlen);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* H4_W4_PACKET_TYPE */
|
||||
switch (*ptr) {
|
||||
case HCI_EVENT_PKT:
|
||||
BT_DBG("Event packet");
|
||||
h4->rx_state = H4_W4_EVENT_HDR;
|
||||
h4->rx_count = HCI_EVENT_HDR_SIZE;
|
||||
type = HCI_EVENT_PKT;
|
||||
break;
|
||||
|
||||
case HCI_ACLDATA_PKT:
|
||||
BT_DBG("ACL packet");
|
||||
h4->rx_state = H4_W4_ACL_HDR;
|
||||
h4->rx_count = HCI_ACL_HDR_SIZE;
|
||||
type = HCI_ACLDATA_PKT;
|
||||
break;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
BT_DBG("SCO packet");
|
||||
h4->rx_state = H4_W4_SCO_HDR;
|
||||
h4->rx_count = HCI_SCO_HDR_SIZE;
|
||||
type = HCI_SCODATA_PKT;
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Unknown HCI packet type %2.2x", (__u8)*ptr);
|
||||
hu->hdev->stat.err_rx++;
|
||||
ptr++; count--;
|
||||
continue;
|
||||
};
|
||||
|
||||
ptr++; count--;
|
||||
|
||||
/* Allocate packet */
|
||||
h4->rx_skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
|
||||
if (!h4->rx_skb) {
|
||||
BT_ERR("Can't allocate mem for new packet");
|
||||
h4->rx_state = H4_W4_PACKET_TYPE;
|
||||
h4->rx_count = 0;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
h4->rx_skb->dev = (void *) hu->hdev;
|
||||
bt_cb(h4->rx_skb)->pkt_type = type;
|
||||
}
|
||||
|
||||
return count;
|
||||
|
@ -146,9 +299,8 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu)
|
|||
return skb_dequeue(&h4->txq);
|
||||
}
|
||||
|
||||
static const struct hci_uart_proto h4p = {
|
||||
static struct hci_uart_proto h4p = {
|
||||
.id = HCI_UART_H4,
|
||||
.name = "H4",
|
||||
.open = h4_open,
|
||||
.close = h4_close,
|
||||
.recv = h4_recv,
|
||||
|
@ -159,132 +311,17 @@ static const struct hci_uart_proto h4p = {
|
|||
|
||||
int __init h4_init(void)
|
||||
{
|
||||
return hci_uart_register_proto(&h4p);
|
||||
int err = hci_uart_register_proto(&h4p);
|
||||
|
||||
if (!err)
|
||||
BT_INFO("HCI H4 protocol initialized");
|
||||
else
|
||||
BT_ERR("HCI H4 protocol registration failed");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int __exit h4_deinit(void)
|
||||
{
|
||||
return hci_uart_unregister_proto(&h4p);
|
||||
}
|
||||
|
||||
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
const unsigned char *buffer, int count,
|
||||
const struct h4_recv_pkt *pkts, int pkts_count)
|
||||
{
|
||||
struct hci_uart *hu = hci_get_drvdata(hdev);
|
||||
u8 alignment = hu->alignment ? hu->alignment : 1;
|
||||
|
||||
/* Check for error from previous call */
|
||||
if (IS_ERR(skb))
|
||||
skb = NULL;
|
||||
|
||||
while (count) {
|
||||
int i, len;
|
||||
|
||||
/* remove padding bytes from buffer */
|
||||
for (; hu->padding && count > 0; hu->padding--) {
|
||||
count--;
|
||||
buffer++;
|
||||
}
|
||||
if (!count)
|
||||
break;
|
||||
|
||||
if (!skb) {
|
||||
for (i = 0; i < pkts_count; i++) {
|
||||
if (buffer[0] != (&pkts[i])->type)
|
||||
continue;
|
||||
|
||||
skb = bt_skb_alloc((&pkts[i])->maxlen,
|
||||
GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
hci_skb_pkt_type(skb) = (&pkts[i])->type;
|
||||
hci_skb_expect(skb) = (&pkts[i])->hlen;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check for invalid packet type */
|
||||
if (!skb)
|
||||
return ERR_PTR(-EILSEQ);
|
||||
|
||||
count -= 1;
|
||||
buffer += 1;
|
||||
}
|
||||
|
||||
len = min_t(uint, hci_skb_expect(skb) - skb->len, count);
|
||||
skb_put_data(skb, buffer, len);
|
||||
|
||||
count -= len;
|
||||
buffer += len;
|
||||
|
||||
/* Check for partial packet */
|
||||
if (skb->len < hci_skb_expect(skb))
|
||||
continue;
|
||||
|
||||
for (i = 0; i < pkts_count; i++) {
|
||||
if (hci_skb_pkt_type(skb) == (&pkts[i])->type)
|
||||
break;
|
||||
}
|
||||
|
||||
if (i >= pkts_count) {
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-EILSEQ);
|
||||
}
|
||||
|
||||
if (skb->len == (&pkts[i])->hlen) {
|
||||
u16 dlen;
|
||||
|
||||
switch ((&pkts[i])->lsize) {
|
||||
case 0:
|
||||
/* No variable data length */
|
||||
dlen = 0;
|
||||
break;
|
||||
case 1:
|
||||
/* Single octet variable length */
|
||||
dlen = skb->data[(&pkts[i])->loff];
|
||||
hci_skb_expect(skb) += dlen;
|
||||
|
||||
if (skb_tailroom(skb) < dlen) {
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-EMSGSIZE);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
/* Double octet variable length */
|
||||
dlen = get_unaligned_le16(skb->data +
|
||||
(&pkts[i])->loff);
|
||||
hci_skb_expect(skb) += dlen;
|
||||
|
||||
if (skb_tailroom(skb) < dlen) {
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-EMSGSIZE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* Unsupported variable length */
|
||||
kfree_skb(skb);
|
||||
return ERR_PTR(-EILSEQ);
|
||||
}
|
||||
|
||||
if (!dlen) {
|
||||
hu->padding = (skb->len - 1) % alignment;
|
||||
hu->padding = (alignment - hu->padding) % alignment;
|
||||
|
||||
/* No more data, complete frame */
|
||||
(&pkts[i])->recv(hdev, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
} else {
|
||||
hu->padding = (skb->len - 1) % alignment;
|
||||
hu->padding = (alignment - hu->padding) % alignment;
|
||||
|
||||
/* Complete frame */
|
||||
(&pkts[i])->recv(hdev, skb);
|
||||
skb = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(h4_recv_buf);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
908
BSP/linux-kernel/drivers/bluetooth/hci_rtk_h5.c
Executable file
908
BSP/linux-kernel/drivers/bluetooth/hci_rtk_h5.c
Executable file
|
@ -0,0 +1,908 @@
|
|||
/*
|
||||
*
|
||||
* Bluetooth HCI UART driver
|
||||
*
|
||||
* Copyright (C) 2011-2014 wifi_fae<wifi_fae@realtek.com.tw>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ptrace.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/bitrev.h>
|
||||
#include <asm/unaligned.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/version.h>
|
||||
|
||||
#include "hci_uart.h"
|
||||
|
||||
#ifdef BTCOEX
|
||||
#include "rtk_coex.h"
|
||||
#endif
|
||||
|
||||
//#define VERSION "1.0"
|
||||
|
||||
static int txcrc = 1;
|
||||
//static int hciextn = 1;
|
||||
|
||||
#define H5_TXWINSIZE 4
|
||||
#define H5_ACK_PKT 0x00
|
||||
#define H5_LE_PKT 0x0F
|
||||
#define H5_VDRSPEC_PKT 0x0E
|
||||
|
||||
struct h5_struct {
|
||||
struct sk_buff_head unack; /* Unack'ed packets queue */
|
||||
struct sk_buff_head rel; /* Reliable packets queue */
|
||||
struct sk_buff_head unrel; /* Unreliable packets queue */
|
||||
|
||||
unsigned long rx_count;
|
||||
struct sk_buff *rx_skb;
|
||||
struct delayed_work retrans_work;
|
||||
struct hci_uart *hu; /* Parent HCI UART */
|
||||
|
||||
enum {
|
||||
H5_W4_PKT_DELIMITER,
|
||||
H5_W4_PKT_START,
|
||||
H5_W4_HDR,
|
||||
H5_W4_DATA,
|
||||
H5_W4_CRC
|
||||
} rx_state;
|
||||
|
||||
enum {
|
||||
H5_ESCSTATE_NOESC,
|
||||
H5_ESCSTATE_ESC
|
||||
} rx_esc_state;
|
||||
|
||||
u16 message_crc;
|
||||
u8 use_crc;
|
||||
u8 rxack; /* Last packet sent by us that the peer ack'ed */
|
||||
|
||||
u8 rxseq_txack; /* rxseq == txack. */
|
||||
u8 txack_req; /* Do we need to send ack's to the peer? */
|
||||
/* Reliable packet sequence number - used to assign seq to each rel pkt. */
|
||||
u8 msgq_txseq;
|
||||
|
||||
/* The spin lock protects seq, ack and ack req */
|
||||
spinlock_t lock;
|
||||
};
|
||||
|
||||
/* ---- H5 CRC calculation ---- */
|
||||
|
||||
/* Table for calculating CRC for polynomial 0x1021, LSB processed first,
|
||||
initial value 0xffff, bits shifted in reverse order. */
|
||||
|
||||
static const u16 crc_table[] = {
|
||||
0x0000, 0x1081, 0x2102, 0x3183,
|
||||
0x4204, 0x5285, 0x6306, 0x7387,
|
||||
0x8408, 0x9489, 0xa50a, 0xb58b,
|
||||
0xc60c, 0xd68d, 0xe70e, 0xf78f
|
||||
};
|
||||
|
||||
/* Initialise the crc calculator */
|
||||
#define H5_CRC_INIT(x) x = 0xffff
|
||||
|
||||
/*
|
||||
Update crc with next data byte
|
||||
|
||||
Implementation note
|
||||
The data byte is treated as two nibbles. The crc is generated
|
||||
in reverse, i.e., bits are fed into the register from the top.
|
||||
*/
|
||||
static void h5_crc_update(u16 * crc, u8 d)
|
||||
{
|
||||
u16 reg = *crc;
|
||||
|
||||
reg = (reg >> 4) ^ crc_table[(reg ^ d) & 0x000f];
|
||||
reg = (reg >> 4) ^ crc_table[(reg ^ (d >> 4)) & 0x000f];
|
||||
|
||||
*crc = reg;
|
||||
}
|
||||
|
||||
/* ---- H5 core ---- */
|
||||
|
||||
static void h5_slip_msgdelim(struct sk_buff *skb)
|
||||
{
|
||||
const char pkt_delim = 0xc0;
|
||||
|
||||
memcpy(skb_put(skb, 1), &pkt_delim, 1);
|
||||
}
|
||||
|
||||
static void h5_slip_one_byte(struct sk_buff *skb, u8 c)
|
||||
{
|
||||
const char esc_c0[2] = { 0xdb, 0xdc };
|
||||
const char esc_db[2] = { 0xdb, 0xdd };
|
||||
const char esc_11[2] = { 0xdb, 0xde };
|
||||
const char esc_13[2] = { 0xdb, 0xdf };
|
||||
|
||||
switch (c) {
|
||||
case 0xc0:
|
||||
memcpy(skb_put(skb, 2), &esc_c0, 2);
|
||||
break;
|
||||
case 0xdb:
|
||||
memcpy(skb_put(skb, 2), &esc_db, 2);
|
||||
break;
|
||||
case 0x11:
|
||||
memcpy(skb_put(skb, 2), &esc_11, 2);
|
||||
break;
|
||||
case 0x13:
|
||||
memcpy(skb_put(skb, 2), &esc_13, 2);
|
||||
break;
|
||||
default:
|
||||
memcpy(skb_put(skb, 1), &c, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static int h5_enqueue(struct hci_uart *hu, struct sk_buff *skb)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
|
||||
if (skb->len > 0xFFF) { //Pkt length must be less than 4095 bytes
|
||||
BT_ERR("Packet too long");
|
||||
kfree_skb(skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (bt_cb(skb)->pkt_type) {
|
||||
case HCI_ACLDATA_PKT:
|
||||
case HCI_COMMAND_PKT:
|
||||
skb_queue_tail(&h5->rel, skb);
|
||||
break;
|
||||
|
||||
case HCI_SCODATA_PKT:
|
||||
skb_queue_tail(&h5->unrel, skb);
|
||||
break;
|
||||
case H5_LE_PKT:
|
||||
case H5_ACK_PKT:
|
||||
case H5_VDRSPEC_PKT:
|
||||
skb_queue_tail(&h5->unrel, skb); /* 3-wire LinkEstablishment */
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Unknown packet type");
|
||||
kfree_skb(skb);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct sk_buff *h5_prepare_pkt(struct h5_struct *h5, u8 * data,
|
||||
int len, int pkt_type)
|
||||
{
|
||||
struct sk_buff *nskb;
|
||||
u8 hdr[4], chan;
|
||||
u16 H5_CRC_INIT(h5_txmsg_crc);
|
||||
int rel, i;
|
||||
u8 tmp;
|
||||
unsigned long flags;
|
||||
|
||||
switch (pkt_type) {
|
||||
case HCI_ACLDATA_PKT:
|
||||
chan = 2; /* 3-wire ACL channel */
|
||||
rel = 1; /* reliable channel */
|
||||
break;
|
||||
case HCI_COMMAND_PKT:
|
||||
chan = 1; /* 3-wire cmd channel */
|
||||
rel = 1; /* reliable channel */
|
||||
break;
|
||||
case HCI_EVENT_PKT:
|
||||
chan = 4; /* 3-wire cmd channel */
|
||||
rel = 1; /* reliable channel */
|
||||
break;
|
||||
case HCI_SCODATA_PKT:
|
||||
chan = 3; /* 3-wire SCO channel */
|
||||
rel = 0; /* unreliable channel */
|
||||
break;
|
||||
case H5_LE_PKT:
|
||||
chan = 15; /* 3-wire LinkEstablishment channel */
|
||||
rel = 0; /* unreliable channel */
|
||||
break;
|
||||
case H5_ACK_PKT:
|
||||
chan = 0; /* 3-wire ACK channel */
|
||||
rel = 0; /* unreliable channel */
|
||||
break;
|
||||
case H5_VDRSPEC_PKT:
|
||||
chan = 14; /* 3-wire Vendor Specific channel */
|
||||
rel = 0; /* unreliable channel */
|
||||
break;
|
||||
default:
|
||||
BT_ERR("Unknown packet type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Max len of packet: (original len +4(h5 hdr) +2(crc))*2
|
||||
(because bytes 0xc0 and 0xdb are escaped, worst case is
|
||||
when the packet is all made of 0xc0 and 0xdb :) )
|
||||
+ 2 (0xc0 delimiters at start and end). */
|
||||
|
||||
nskb = alloc_skb((len + 6) * 2 + 2, GFP_ATOMIC);
|
||||
if (!nskb)
|
||||
return NULL;
|
||||
|
||||
bt_cb(nskb)->pkt_type = pkt_type;
|
||||
|
||||
h5_slip_msgdelim(nskb);
|
||||
|
||||
spin_lock_irqsave(&h5->lock, flags);
|
||||
tmp = h5->rxseq_txack;
|
||||
hdr[0] = h5->rxseq_txack << 3;
|
||||
h5->txack_req = 0;
|
||||
spin_unlock_irqrestore(&h5->lock, flags);
|
||||
BT_DBG("We request packet no %u to card", tmp);
|
||||
|
||||
if (rel) {
|
||||
spin_lock_irqsave(&h5->lock, flags);
|
||||
tmp = h5->msgq_txseq;
|
||||
hdr[0] |= 0x80 + h5->msgq_txseq;
|
||||
h5->msgq_txseq = (h5->msgq_txseq + 1) & 0x07;
|
||||
spin_unlock_irqrestore(&h5->lock, flags);
|
||||
BT_DBG("Sending packet with seqno %u", tmp);
|
||||
}
|
||||
|
||||
if (h5->use_crc)
|
||||
hdr[0] |= 0x40;
|
||||
|
||||
hdr[1] = ((len << 4) & 0xff) | chan;
|
||||
hdr[2] = len >> 4;
|
||||
hdr[3] = ~(hdr[0] + hdr[1] + hdr[2]);
|
||||
|
||||
/* Put H5 header */
|
||||
for (i = 0; i < 4; i++) {
|
||||
h5_slip_one_byte(nskb, hdr[i]);
|
||||
|
||||
if (h5->use_crc)
|
||||
h5_crc_update(&h5_txmsg_crc, hdr[i]);
|
||||
}
|
||||
|
||||
/* Put payload */
|
||||
for (i = 0; i < len; i++) {
|
||||
h5_slip_one_byte(nskb, data[i]);
|
||||
|
||||
if (h5->use_crc)
|
||||
h5_crc_update(&h5_txmsg_crc, data[i]);
|
||||
}
|
||||
|
||||
/* Put CRC */
|
||||
if (h5->use_crc) {
|
||||
h5_txmsg_crc = bitrev16(h5_txmsg_crc);
|
||||
h5_slip_one_byte(nskb, (u8) ((h5_txmsg_crc >> 8) & 0x00ff));
|
||||
h5_slip_one_byte(nskb, (u8) (h5_txmsg_crc & 0x00ff));
|
||||
}
|
||||
|
||||
h5_slip_msgdelim(nskb);
|
||||
return nskb;
|
||||
}
|
||||
|
||||
/* This is a rewrite of pkt_avail in AH5 */
|
||||
static struct sk_buff *h5_dequeue(struct hci_uart *hu)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
unsigned long flags;
|
||||
struct sk_buff *skb;
|
||||
|
||||
/* First of all, check for unreliable messages in the queue,
|
||||
since they have priority */
|
||||
|
||||
if ((skb = skb_dequeue(&h5->unrel)) != NULL) {
|
||||
struct sk_buff *nskb =
|
||||
h5_prepare_pkt(h5, skb->data, skb->len,
|
||||
bt_cb(skb)->pkt_type);
|
||||
if (nskb) {
|
||||
kfree_skb(skb);
|
||||
return nskb;
|
||||
} else {
|
||||
skb_queue_head(&h5->unrel, skb);
|
||||
BT_ERR
|
||||
("Could not dequeue pkt because alloc_skb failed");
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, try to send a reliable pkt. We can only send a
|
||||
reliable packet if the number of packets sent but not yet ack'ed
|
||||
is < than the winsize */
|
||||
|
||||
spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
|
||||
|
||||
if (h5->unack.qlen < H5_TXWINSIZE
|
||||
&& (skb = skb_dequeue(&h5->rel)) != NULL) {
|
||||
struct sk_buff *nskb =
|
||||
h5_prepare_pkt(h5, skb->data, skb->len,
|
||||
bt_cb(skb)->pkt_type);
|
||||
if (nskb) {
|
||||
__skb_queue_tail(&h5->unack, skb);
|
||||
schedule_delayed_work(&h5->retrans_work, HZ / 4);
|
||||
spin_unlock_irqrestore(&h5->unack.lock, flags);
|
||||
return nskb;
|
||||
} else {
|
||||
skb_queue_head(&h5->rel, skb);
|
||||
BT_ERR
|
||||
("Could not dequeue pkt because alloc_skb failed");
|
||||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&h5->unack.lock, flags);
|
||||
|
||||
/* We could not send a reliable packet, either because there are
|
||||
none or because there are too many unack'ed pkts. Did we receive
|
||||
any packets we have not acknowledged yet ? */
|
||||
|
||||
if (h5->txack_req) {
|
||||
/* if so, craft an empty ACK pkt and send it on H5 unreliable
|
||||
channel 0 */
|
||||
struct sk_buff *nskb = h5_prepare_pkt(h5, NULL, 0, H5_ACK_PKT);
|
||||
return nskb;
|
||||
}
|
||||
|
||||
/* We have nothing to send */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int h5_flush(struct hci_uart *hu)
|
||||
{
|
||||
BT_DBG("hu %p", hu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove ack'ed packets */
|
||||
static void h5_pkt_cull(struct h5_struct *h5)
|
||||
{
|
||||
struct sk_buff *skb, *tmp;
|
||||
unsigned long flags;
|
||||
int i, pkts_to_be_removed;
|
||||
u8 seqno;
|
||||
|
||||
spin_lock_irqsave(&h5->unack.lock, flags);
|
||||
|
||||
pkts_to_be_removed = skb_queue_len(&h5->unack);
|
||||
seqno = h5->msgq_txseq;
|
||||
|
||||
while (pkts_to_be_removed) {
|
||||
if (h5->rxack == seqno)
|
||||
break;
|
||||
pkts_to_be_removed--;
|
||||
seqno = (seqno - 1) & 0x07;
|
||||
}
|
||||
|
||||
if (h5->rxack != seqno)
|
||||
BT_ERR("Peer acked invalid packet");
|
||||
|
||||
BT_DBG("Removing %u pkts out of %u, up to seqno %u",
|
||||
pkts_to_be_removed, skb_queue_len(&h5->unack),
|
||||
(seqno - 1) & 0x07);
|
||||
|
||||
i = 0;
|
||||
skb_queue_walk_safe(&h5->unack, skb, tmp) {
|
||||
if (i >= pkts_to_be_removed)
|
||||
break;
|
||||
i++;
|
||||
|
||||
__skb_unlink(skb, &h5->unack);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
if (skb_queue_empty(&h5->unack))
|
||||
cancel_delayed_work(&h5->retrans_work);
|
||||
|
||||
spin_unlock_irqrestore(&h5->unack.lock, flags);
|
||||
|
||||
if (i != pkts_to_be_removed)
|
||||
BT_ERR("Removed only %u out of %u pkts", i, pkts_to_be_removed);
|
||||
}
|
||||
|
||||
/* Handle H5 link-establishment packets. When we
|
||||
detect a "sync" packet, symptom that the BT module has reset,
|
||||
we do nothing :) (yet) */
|
||||
#if 0
|
||||
static void h5_handle_le_pkt(struct hci_uart *hu)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
u8 conf_pkt[2] = { 0x03, 0xfc };
|
||||
u8 conf_rsp_pkt[3] = { 0x04, 0x7b, 0x00 };
|
||||
u8 sync_pkt[2] = { 0x01, 0x7e };
|
||||
u8 sync_rsp_pkt[2] = { 0x02, 0x7d };
|
||||
|
||||
u8 wakeup_pkt[2] = { 0x05, 0xfa };
|
||||
u8 woken_pkt[2] = { 0x06, 0xf9 };
|
||||
u8 sleep_pkt[2] = { 0x07, 0x78 };
|
||||
|
||||
/* spot "conf" pkts and reply with a "conf rsp" pkt */
|
||||
if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], conf_pkt, 2)) {
|
||||
struct sk_buff *nskb = alloc_skb(3, GFP_ATOMIC);
|
||||
|
||||
BT_DBG("Found a LE conf pkt");
|
||||
if (!nskb)
|
||||
return;
|
||||
|
||||
conf_rsp_pkt[2] |= txcrc << 0x4; //crc check enable, version no = 0. needed to be as avariable.
|
||||
memcpy(skb_put(nskb, 3), conf_rsp_pkt, 3);
|
||||
bt_cb(nskb)->pkt_type = H5_LE_PKT;
|
||||
|
||||
skb_queue_head(&h5->unrel, nskb);
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
/* spot "conf resp" pkts */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], conf_rsp_pkt, 2)) {
|
||||
BT_DBG("Found a LE conf resp pkt, device go into active state");
|
||||
txcrc = (h5->rx_skb->data[6] >> 0x4) & 0x1;
|
||||
}
|
||||
|
||||
/* Spot "sync" pkts. If we find one...disaster! */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], sync_pkt, 2)) {
|
||||
BT_ERR("Found a LE sync pkt, card has reset");
|
||||
//DO Something here
|
||||
}
|
||||
/* Spot "sync resp" pkts. If we find one...disaster! */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], sync_rsp_pkt, 2)) {
|
||||
BT_ERR
|
||||
("Found a LE sync resp pkt, device go into initialized state");
|
||||
// DO Something here
|
||||
}
|
||||
/* Spot "wakeup" pkts. reply woken message when in active mode */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], wakeup_pkt, 2)) {
|
||||
struct sk_buff *nskb = alloc_skb(2, GFP_ATOMIC);
|
||||
|
||||
BT_ERR("Found a LE Wakeup pkt, and reply woken message");
|
||||
// DO Something here
|
||||
|
||||
memcpy(skb_put(nskb, 2), woken_pkt, 2);
|
||||
bt_cb(nskb)->pkt_type = H5_LE_PKT;
|
||||
|
||||
skb_queue_head(&h5->unrel, nskb);
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
/* Spot "woken" pkts. receive woken message from device */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_skb->data[4], woken_pkt, 2)) {
|
||||
BT_ERR("Found a LE woken pkt from device");
|
||||
// DO Something here
|
||||
}
|
||||
/* Spot "Sleep" pkts */
|
||||
else if (h5->rx_skb->data[1] >> 4 == 2 && h5->rx_skb->data[2] == 0 &&
|
||||
!memcmp(&h5->rx_indent: Standard input:620: Error:Unmatched 'else'
|
||||
skb->data[4], sleep_pkt, 2)) {
|
||||
BT_ERR("Found a LE Sleep pkt");
|
||||
// DO Something here
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline void h5_unslip_one_byte(struct h5_struct *h5, unsigned char byte)
|
||||
{
|
||||
const u8 c0 = 0xc0, db = 0xdb;
|
||||
const u8 oof1 = 0x11, oof2 = 0x13;
|
||||
|
||||
switch (h5->rx_esc_state) {
|
||||
case H5_ESCSTATE_NOESC:
|
||||
switch (byte) {
|
||||
case 0xdb:
|
||||
h5->rx_esc_state = H5_ESCSTATE_ESC;
|
||||
break;
|
||||
default:
|
||||
memcpy(skb_put(h5->rx_skb, 1), &byte, 1);
|
||||
if ((h5->rx_skb->data[0] & 0x40) != 0 &&
|
||||
h5->rx_state != H5_W4_CRC)
|
||||
h5_crc_update(&h5->message_crc, byte);
|
||||
h5->rx_count--;
|
||||
}
|
||||
break;
|
||||
|
||||
case H5_ESCSTATE_ESC:
|
||||
switch (byte) {
|
||||
case 0xdc:
|
||||
memcpy(skb_put(h5->rx_skb, 1), &c0, 1);
|
||||
if ((h5->rx_skb->data[0] & 0x40) != 0 &&
|
||||
h5->rx_state != H5_W4_CRC)
|
||||
h5_crc_update(&h5->message_crc, 0xc0);
|
||||
h5->rx_esc_state = H5_ESCSTATE_NOESC;
|
||||
h5->rx_count--;
|
||||
break;
|
||||
|
||||
case 0xdd:
|
||||
memcpy(skb_put(h5->rx_skb, 1), &db, 1);
|
||||
if ((h5->rx_skb->data[0] & 0x40) != 0 &&
|
||||
h5->rx_state != H5_W4_CRC)
|
||||
h5_crc_update(&h5->message_crc, 0xdb);
|
||||
h5->rx_esc_state = H5_ESCSTATE_NOESC;
|
||||
h5->rx_count--;
|
||||
break;
|
||||
|
||||
case 0xde:
|
||||
memcpy(skb_put(h5->rx_skb, 1), &oof1, 1);
|
||||
if ((h5->rx_skb->data[0] & 0x40) != 0
|
||||
&& h5->rx_state != H5_W4_CRC)
|
||||
h5_crc_update(&h5->message_crc, oof1);
|
||||
h5->rx_esc_state = H5_ESCSTATE_NOESC;
|
||||
h5->rx_count--;
|
||||
break;
|
||||
|
||||
case 0xdf:
|
||||
memcpy(skb_put(h5->rx_skb, 1), &oof2, 1);
|
||||
if ((h5->rx_skb->data[0] & 0x40) != 0
|
||||
&& h5->rx_state != H5_W4_CRC)
|
||||
h5_crc_update(&h5->message_crc, oof2);
|
||||
h5->rx_esc_state = H5_ESCSTATE_NOESC;
|
||||
h5->rx_count--;
|
||||
break;
|
||||
|
||||
default:
|
||||
BT_ERR("Invalid byte %02x after esc byte", byte);
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_skb = NULL;
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_count = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void h5_complete_rx_pkt(struct hci_uart *hu)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
int pass_up;
|
||||
|
||||
if (h5->rx_skb->data[0] & 0x80) { /* reliable pkt */
|
||||
unsigned long flags;
|
||||
u8 rxseq;
|
||||
|
||||
spin_lock_irqsave(&h5->lock, flags);
|
||||
rxseq = h5->rxseq_txack;
|
||||
h5->rxseq_txack++;
|
||||
h5->rxseq_txack %= 0x8;
|
||||
h5->txack_req = 1;
|
||||
spin_unlock_irqrestore(&h5->lock, flags);
|
||||
|
||||
BT_DBG("Received seqno %u from card", rxseq);
|
||||
}
|
||||
|
||||
h5->rxack = (h5->rx_skb->data[0] >> 3) & 0x07;
|
||||
BT_DBG("Request for pkt %u from card", h5->rxack);
|
||||
|
||||
h5_pkt_cull(h5);
|
||||
|
||||
hci_uart_tx_wakeup(hu);
|
||||
|
||||
if ((h5->rx_skb->data[1] & 0x0f) == 2 && h5->rx_skb->data[0] & 0x80) {
|
||||
bt_cb(h5->rx_skb)->pkt_type = HCI_ACLDATA_PKT;
|
||||
pass_up = 1;
|
||||
} else if ((h5->rx_skb->data[1] & 0x0f) == 4 &&
|
||||
h5->rx_skb->data[0] & 0x80) {
|
||||
bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT;
|
||||
pass_up = 1;
|
||||
} else if ((h5->rx_skb->data[1] & 0x0f) == 3) {
|
||||
bt_cb(h5->rx_skb)->pkt_type = HCI_SCODATA_PKT;
|
||||
pass_up = 1;
|
||||
} else if ((h5->rx_skb->data[1] & 0x0f) == 15 &&
|
||||
!(h5->rx_skb->data[0] & 0x80)) {
|
||||
//h5_handle_le_pkt(hu);//Link Establishment Pkt
|
||||
pass_up = 0;
|
||||
} else if ((h5->rx_skb->data[1] & 0x0f) == 1 &&
|
||||
h5->rx_skb->data[0] & 0x80) {
|
||||
bt_cb(h5->rx_skb)->pkt_type = HCI_COMMAND_PKT;
|
||||
pass_up = 1;
|
||||
} else if ((h5->rx_skb->data[1] & 0x0f) == 14) {
|
||||
bt_cb(h5->rx_skb)->pkt_type = H5_VDRSPEC_PKT;
|
||||
pass_up = 1;
|
||||
} else
|
||||
pass_up = 0;
|
||||
|
||||
if (!pass_up) {
|
||||
/* struct hci_event_hdr hdr; */
|
||||
u8 desc = (h5->rx_skb->data[1] & 0x0f);
|
||||
|
||||
if (desc != H5_ACK_PKT && desc != H5_LE_PKT) {
|
||||
/* if (hciextn) {
|
||||
* desc |= 0xc0;
|
||||
* skb_pull(h5->rx_skb, 4);
|
||||
* memcpy(skb_push(h5->rx_skb, 1), &desc, 1);
|
||||
|
||||
* hdr.evt = 0xff;
|
||||
* hdr.plen = h5->rx_skb->len;
|
||||
* memcpy(skb_push(h5->rx_skb, HCI_EVENT_HDR_SIZE),
|
||||
* &hdr, HCI_EVENT_HDR_SIZE);
|
||||
* bt_cb(h5->rx_skb)->pkt_type = HCI_EVENT_PKT;
|
||||
|
||||
* hci_recv_frame(h5->rx_skb);
|
||||
* } else { */
|
||||
BT_ERR("Packet for unknown channel (%u %s)",
|
||||
h5->rx_skb->data[1] & 0x0f,
|
||||
h5->rx_skb->data[0] & 0x80 ?
|
||||
"reliable" : "unreliable");
|
||||
kfree_skb(h5->rx_skb);
|
||||
/* } */
|
||||
} else
|
||||
kfree_skb(h5->rx_skb);
|
||||
} else {
|
||||
/* Pull out H5 hdr */
|
||||
skb_pull(h5->rx_skb, 4);
|
||||
|
||||
#ifdef BTCOEX
|
||||
if (bt_cb(h5->rx_skb)->pkt_type == HCI_EVENT_PKT)
|
||||
rtk_btcoex_parse_event(h5->rx_skb->data,
|
||||
h5->rx_skb->len);
|
||||
|
||||
if (bt_cb(h5->rx_skb)->pkt_type == HCI_ACLDATA_PKT)
|
||||
rtk_btcoex_parse_l2cap_data_rx(h5->rx_skb->data,
|
||||
h5->rx_skb->len);
|
||||
#endif
|
||||
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
hci_recv_frame(h5->rx_skb);
|
||||
#else
|
||||
hci_recv_frame(hu->hdev, h5->rx_skb);
|
||||
#endif
|
||||
}
|
||||
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_skb = NULL;
|
||||
}
|
||||
|
||||
static u16 bscp_get_crc(struct h5_struct *h5) {
|
||||
return get_unaligned_be16(&h5->rx_skb->
|
||||
data[h5->rx_skb->len - 2]);
|
||||
}
|
||||
|
||||
/* Recv data */
|
||||
static int h5_recv(struct hci_uart *hu, void *data, int count)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
register unsigned char *ptr;
|
||||
u8 rxseq;
|
||||
unsigned long flags;
|
||||
|
||||
BT_DBG("hu %p count %d rx_state %d rx_count %ld",
|
||||
hu, count, h5->rx_state, h5->rx_count);
|
||||
|
||||
ptr = data;
|
||||
while (count) {
|
||||
if (h5->rx_count) {
|
||||
if (*ptr == 0xc0) {
|
||||
BT_ERR("Short H5 packet");
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_state = H5_W4_PKT_START;
|
||||
h5->rx_count = 0;
|
||||
} else
|
||||
h5_unslip_one_byte(h5, *ptr);
|
||||
|
||||
ptr++;
|
||||
count--;
|
||||
continue;
|
||||
}
|
||||
|
||||
switch (h5->rx_state) {
|
||||
case H5_W4_HDR:
|
||||
if ((0xff & (u8) ~
|
||||
(h5->rx_skb->data[0] +
|
||||
h5->rx_skb->data[1] +
|
||||
h5->rx_skb->data[2])) != h5->rx_skb->data[3]) {
|
||||
BT_ERR("Error in H5 hdr checksum");
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_count = 0;
|
||||
continue;
|
||||
}
|
||||
rxseq = h5->rxseq_txack;
|
||||
if (h5->rx_skb->data[0] & 0x80 /* reliable pkt */
|
||||
&& (h5->rx_skb->data[0] & 0x07) != rxseq) {
|
||||
BT_ERR("Out-of-order packet arrived, got %u expected %u",
|
||||
h5->rx_skb->data[0] & 0x07, rxseq);
|
||||
|
||||
spin_lock_irqsave(&h5->lock, flags);
|
||||
h5->txack_req = 1;
|
||||
spin_unlock_irqrestore(&h5->lock, flags);
|
||||
hci_uart_tx_wakeup(hu);
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_count = 0;
|
||||
continue;
|
||||
}
|
||||
h5->rx_state = H5_W4_DATA;
|
||||
h5->rx_count = (h5->rx_skb->data[1] >> 4) + (h5->rx_skb->data[2] << 4); /* May be 0 */
|
||||
continue;
|
||||
|
||||
case H5_W4_DATA:
|
||||
if (h5->rx_skb->data[0] & 0x40) { /* pkt with crc */
|
||||
h5->rx_state = H5_W4_CRC;
|
||||
h5->rx_count = 2;
|
||||
} else
|
||||
h5_complete_rx_pkt(hu);
|
||||
continue;
|
||||
|
||||
case H5_W4_CRC:
|
||||
if (bitrev16(h5->message_crc) != bscp_get_crc(h5)) {
|
||||
BT_ERR
|
||||
("Checksum failed: computed %04x received %04x",
|
||||
bitrev16(h5->message_crc),
|
||||
bscp_get_crc(h5));
|
||||
|
||||
kfree_skb(h5->rx_skb);
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_count = 0;
|
||||
continue;
|
||||
}
|
||||
skb_trim(h5->rx_skb, h5->rx_skb->len - 2);
|
||||
h5_complete_rx_pkt(hu);
|
||||
continue;
|
||||
|
||||
case H5_W4_PKT_DELIMITER:
|
||||
switch (*ptr) {
|
||||
case 0xc0:
|
||||
h5->rx_state = H5_W4_PKT_START;
|
||||
break;
|
||||
default:
|
||||
/*BT_ERR("Ignoring byte %02x", *ptr); */
|
||||
break;
|
||||
}
|
||||
ptr++;
|
||||
count--;
|
||||
break;
|
||||
|
||||
case H5_W4_PKT_START:
|
||||
switch (*ptr) {
|
||||
case 0xc0:
|
||||
ptr++;
|
||||
count--;
|
||||
break;
|
||||
|
||||
default:
|
||||
h5->rx_state = H5_W4_HDR;
|
||||
h5->rx_count = 4;
|
||||
h5->rx_esc_state = H5_ESCSTATE_NOESC;
|
||||
H5_CRC_INIT(h5->message_crc);
|
||||
|
||||
/* Do not increment ptr or decrement count
|
||||
* Allocate packet. Max len of a H5 pkt=
|
||||
* 0xFFF (payload) +4 (header) +2 (crc) */
|
||||
|
||||
h5->rx_skb = bt_skb_alloc(0x1005, GFP_ATOMIC);
|
||||
if (!h5->rx_skb) {
|
||||
BT_ERR
|
||||
("Can't allocate mem for new packet");
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
h5->rx_count = 0;
|
||||
return 0;
|
||||
}
|
||||
h5->rx_skb->dev = (void *)hu->hdev;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Arrange to retransmit all messages in the relq. */
|
||||
static void h5_timed_event(struct work_struct *work)
|
||||
{
|
||||
struct h5_struct *h5;
|
||||
struct hci_uart *hu;
|
||||
unsigned long flags;
|
||||
unsigned long flags2;
|
||||
struct sk_buff *skb;
|
||||
|
||||
h5 = container_of(work, struct h5_struct, retrans_work.work);
|
||||
hu = h5->hu;
|
||||
|
||||
BT_INFO("hu %p retransmitting %u pkts", hu, h5->unack.qlen);
|
||||
|
||||
spin_lock_irqsave_nested(&h5->unack.lock, flags, SINGLE_DEPTH_NESTING);
|
||||
|
||||
/* Move the pkt from unack queue to the head of reliable tx queue and
|
||||
* roll back the tx seq number
|
||||
*/
|
||||
while ((skb = __skb_dequeue_tail(&h5->unack)) != NULL) {
|
||||
spin_lock_irqsave(&h5->lock, flags2);
|
||||
h5->msgq_txseq = (h5->msgq_txseq - 1) & 0x07;
|
||||
spin_unlock_irqrestore(&h5->lock, flags2);
|
||||
skb_queue_head(&h5->rel, skb);
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&h5->unack.lock, flags);
|
||||
|
||||
hci_uart_tx_wakeup(hu);
|
||||
}
|
||||
|
||||
static int h5_open(struct hci_uart *hu)
|
||||
{
|
||||
struct h5_struct *h5;
|
||||
|
||||
BT_DBG("hu %p", hu);
|
||||
|
||||
BT_INFO("h5_open");
|
||||
h5 = kzalloc(sizeof(*h5), GFP_ATOMIC);
|
||||
if (!h5)
|
||||
return -ENOMEM;
|
||||
|
||||
hu->priv = h5;
|
||||
skb_queue_head_init(&h5->unack);
|
||||
skb_queue_head_init(&h5->rel);
|
||||
skb_queue_head_init(&h5->unrel);
|
||||
spin_lock_init(&h5->lock);
|
||||
|
||||
h5->hu = hu;
|
||||
INIT_DELAYED_WORK(&h5->retrans_work, (void *)h5_timed_event);
|
||||
|
||||
h5->rx_state = H5_W4_PKT_DELIMITER;
|
||||
|
||||
if (txcrc)
|
||||
h5->use_crc = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int h5_close(struct hci_uart *hu)
|
||||
{
|
||||
struct h5_struct *h5 = hu->priv;
|
||||
|
||||
BT_INFO("h5_close");
|
||||
|
||||
cancel_delayed_work_sync(&h5->retrans_work);
|
||||
|
||||
hu->priv = NULL;
|
||||
|
||||
skb_queue_purge(&h5->unack);
|
||||
skb_queue_purge(&h5->rel);
|
||||
skb_queue_purge(&h5->unrel);
|
||||
|
||||
kfree(h5);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct hci_uart_proto h5 = {
|
||||
.id = HCI_UART_3WIRE,
|
||||
.open = h5_open,
|
||||
.close = h5_close,
|
||||
.enqueue = h5_enqueue,
|
||||
.dequeue = h5_dequeue,
|
||||
.recv = h5_recv,
|
||||
.flush = h5_flush
|
||||
};
|
||||
|
||||
int h5_init(void)
|
||||
{
|
||||
int err = hci_uart_register_proto(&h5);
|
||||
|
||||
if (!err)
|
||||
BT_INFO("HCI Realtek H5 protocol initialized");
|
||||
else
|
||||
BT_ERR("HCI Realtek H5 protocol registration failed");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int h5_deinit(void)
|
||||
{
|
||||
return hci_uart_unregister_proto(&h5);
|
||||
}
|
|
@ -22,11 +22,40 @@
|
|||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <linux/version.h>
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
|
||||
/* #define HCI_VERSION_CODE KERNEL_VERSION(3, 14, 41) */
|
||||
#define HCI_VERSION_CODE LINUX_VERSION_CODE
|
||||
|
||||
#ifndef N_HCI
|
||||
#define N_HCI 15
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_BT_HCIUART_H4
|
||||
#define CONFIG_BT_HCIUART_H4
|
||||
#endif
|
||||
|
||||
#define BTCOEX
|
||||
|
||||
/* Send host sleep notification to Controller */
|
||||
#define WOBT_NOTIFY 0 /* 1 enable; 0 disable */
|
||||
|
||||
/* Send LE whitelist only for Background scan parameters */
|
||||
#define WOBT_NOTIFY_BG_SCAN_LE_WHITELIST_ONLY (0 * WOBT_NOTIFY) /* 1 enable; 0 disable */
|
||||
|
||||
/* RTKBT Power-on Whitelist for sideband wake-up by LE Advertising from Remote.
|
||||
* Note that it's necessary to apply TV FW Patch. */
|
||||
#define RTKBT_TV_POWERON_WHITELIST (0 * WOBT_NOTIFY) /* 1 enable; 0 disable */
|
||||
|
||||
/* RTKBT Power-on Data Filter for Manufacturer field */
|
||||
/* Note that please edit the datafilter in
|
||||
* rtkbt_set_le_device_poweron_data_filter() of hci_ldisc.c */
|
||||
#define RTKBT_TV_POWERON_DATA_FILTER (0 * WOBT_NOTIFY) /* 1 enable; 0 disable */
|
||||
|
||||
#define RTKBT_POWERKEY_WAKEUP
|
||||
|
||||
/* Ioctls */
|
||||
#define HCIUARTSETPROTO _IOW('U', 200, int)
|
||||
#define HCIUARTGETPROTO _IOR('U', 201, int)
|
||||
|
@ -35,7 +64,7 @@
|
|||
#define HCIUARTGETFLAGS _IOR('U', 204, int)
|
||||
|
||||
/* UART protocols */
|
||||
#define HCI_UART_MAX_PROTO 12
|
||||
#define HCI_UART_MAX_PROTO 6
|
||||
|
||||
#define HCI_UART_H4 0
|
||||
#define HCI_UART_BCSP 1
|
||||
|
@ -43,12 +72,6 @@
|
|||
#define HCI_UART_H4DS 3
|
||||
#define HCI_UART_LL 4
|
||||
#define HCI_UART_ATH3K 5
|
||||
#define HCI_UART_INTEL 6
|
||||
#define HCI_UART_BCM 7
|
||||
#define HCI_UART_QCA 8
|
||||
#define HCI_UART_AG6XX 9
|
||||
#define HCI_UART_NOKIA 10
|
||||
#define HCI_UART_MRVL 11
|
||||
|
||||
#define HCI_UART_RAW_DEVICE 0
|
||||
#define HCI_UART_RESET_ON_INIT 1
|
||||
|
@ -58,46 +81,43 @@
|
|||
#define HCI_UART_VND_DETECT 5
|
||||
|
||||
struct hci_uart;
|
||||
struct serdev_device;
|
||||
|
||||
struct hci_uart_proto {
|
||||
unsigned int id;
|
||||
const char *name;
|
||||
unsigned int manufacturer;
|
||||
unsigned int init_speed;
|
||||
unsigned int oper_speed;
|
||||
int (*open)(struct hci_uart *hu);
|
||||
int (*close)(struct hci_uart *hu);
|
||||
int (*flush)(struct hci_uart *hu);
|
||||
int (*setup)(struct hci_uart *hu);
|
||||
int (*set_baudrate)(struct hci_uart *hu, unsigned int speed);
|
||||
int (*recv)(struct hci_uart *hu, const void *data, int len);
|
||||
int (*recv)(struct hci_uart *hu, void *data, int len);
|
||||
int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb);
|
||||
struct sk_buff *(*dequeue)(struct hci_uart *hu);
|
||||
};
|
||||
|
||||
struct hci_uart {
|
||||
struct tty_struct *tty;
|
||||
struct serdev_device *serdev;
|
||||
struct hci_dev *hdev;
|
||||
unsigned long flags;
|
||||
unsigned long hdev_flags;
|
||||
|
||||
struct work_struct init_ready;
|
||||
struct work_struct write_work;
|
||||
struct workqueue_struct *hci_uart_wq;
|
||||
|
||||
const struct hci_uart_proto *proto;
|
||||
struct hci_uart_proto *proto;
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 7, 0)
|
||||
struct percpu_rw_semaphore proto_lock; /* Stop work for proto close */
|
||||
#else
|
||||
struct rw_semaphore proto_lock;
|
||||
#endif
|
||||
void *priv;
|
||||
|
||||
struct semaphore tx_sem; /* semaphore for tx */
|
||||
|
||||
struct sk_buff *tx_skb;
|
||||
unsigned long tx_state;
|
||||
|
||||
unsigned int init_speed;
|
||||
unsigned int oper_speed;
|
||||
|
||||
u8 alignment;
|
||||
u8 padding;
|
||||
#if WOBT_NOTIFY
|
||||
struct notifier_block pm_notify_block;
|
||||
struct notifier_block shutdown_notifier;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* HCI_UART proto flag bits */
|
||||
|
@ -109,100 +129,20 @@ struct hci_uart {
|
|||
#define HCI_UART_SENDING 1
|
||||
#define HCI_UART_TX_WAKEUP 2
|
||||
|
||||
int hci_uart_register_proto(const struct hci_uart_proto *p);
|
||||
int hci_uart_unregister_proto(const struct hci_uart_proto *p);
|
||||
int hci_uart_register_device(struct hci_uart *hu, const struct hci_uart_proto *p);
|
||||
void hci_uart_unregister_device(struct hci_uart *hu);
|
||||
|
||||
int hci_uart_tx_wakeup(struct hci_uart *hu);
|
||||
int hci_uart_init_ready(struct hci_uart *hu);
|
||||
void hci_uart_init_work(struct work_struct *work);
|
||||
void hci_uart_set_baudrate(struct hci_uart *hu, unsigned int speed);
|
||||
bool hci_uart_has_flow_control(struct hci_uart *hu);
|
||||
void hci_uart_set_flow_control(struct hci_uart *hu, bool enable);
|
||||
void hci_uart_set_speeds(struct hci_uart *hu, unsigned int init_speed,
|
||||
unsigned int oper_speed);
|
||||
extern int hci_uart_register_proto(struct hci_uart_proto *p);
|
||||
extern int hci_uart_unregister_proto(struct hci_uart_proto *p);
|
||||
extern int hci_uart_tx_wakeup(struct hci_uart *hu);
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_H4
|
||||
int h4_init(void);
|
||||
int h4_deinit(void);
|
||||
|
||||
struct h4_recv_pkt {
|
||||
u8 type; /* Packet type */
|
||||
u8 hlen; /* Header length */
|
||||
u8 loff; /* Data length offset in header */
|
||||
u8 lsize; /* Data length field size */
|
||||
u16 maxlen; /* Max overall packet length */
|
||||
int (*recv)(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
};
|
||||
|
||||
#define H4_RECV_ACL \
|
||||
.type = HCI_ACLDATA_PKT, \
|
||||
.hlen = HCI_ACL_HDR_SIZE, \
|
||||
.loff = 2, \
|
||||
.lsize = 2, \
|
||||
.maxlen = HCI_MAX_FRAME_SIZE \
|
||||
|
||||
#define H4_RECV_SCO \
|
||||
.type = HCI_SCODATA_PKT, \
|
||||
.hlen = HCI_SCO_HDR_SIZE, \
|
||||
.loff = 2, \
|
||||
.lsize = 1, \
|
||||
.maxlen = HCI_MAX_SCO_SIZE
|
||||
|
||||
#define H4_RECV_EVENT \
|
||||
.type = HCI_EVENT_PKT, \
|
||||
.hlen = HCI_EVENT_HDR_SIZE, \
|
||||
.loff = 1, \
|
||||
.lsize = 1, \
|
||||
.maxlen = HCI_MAX_EVENT_SIZE
|
||||
|
||||
struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb,
|
||||
const unsigned char *buffer, int count,
|
||||
const struct h4_recv_pkt *pkts, int pkts_count);
|
||||
extern int h4_init(void);
|
||||
extern int h4_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_BCSP
|
||||
int bcsp_init(void);
|
||||
int bcsp_deinit(void);
|
||||
#endif
|
||||
extern int h5_init(void);
|
||||
extern int h5_deinit(void);
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_LL
|
||||
int ll_init(void);
|
||||
int ll_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_ATH3K
|
||||
int ath_init(void);
|
||||
int ath_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_3WIRE
|
||||
int h5_init(void);
|
||||
int h5_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_INTEL
|
||||
int intel_init(void);
|
||||
int intel_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_BCM
|
||||
int bcm_init(void);
|
||||
int bcm_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_QCA
|
||||
int qca_init(void);
|
||||
int qca_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_AG6XX
|
||||
int ag6xx_init(void);
|
||||
int ag6xx_deinit(void);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_HCIUART_MRVL
|
||||
int mrvl_init(void);
|
||||
int mrvl_deinit(void);
|
||||
#if HCI_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
extern int hci_uart_send_frame(struct sk_buff *skb);
|
||||
#else
|
||||
extern int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb);
|
||||
#endif
|
||||
|
|
3068
BSP/linux-kernel/drivers/bluetooth/rtk_coex.c
Executable file
3068
BSP/linux-kernel/drivers/bluetooth/rtk_coex.c
Executable file
File diff suppressed because it is too large
Load Diff
377
BSP/linux-kernel/drivers/bluetooth/rtk_coex.h
Executable file
377
BSP/linux-kernel/drivers/bluetooth/rtk_coex.h
Executable file
|
@ -0,0 +1,377 @@
|
|||
/*
|
||||
*
|
||||
* Realtek Bluetooth USB driver
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
*/
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
/***********************************
|
||||
** Realtek - For coexistence **
|
||||
***********************************/
|
||||
#define BTRTL_HCIUSB 0
|
||||
#define BTRTL_HCIUART 1
|
||||
|
||||
#define BTRTL_HCI_IF BTRTL_HCIUART
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
#define CONNECT_PORT 30001
|
||||
#define CONNECT_PORT_WIFI 30000
|
||||
|
||||
#define invite_req "INVITE_REQ"
|
||||
#define invite_rsp "INVITE_RSP"
|
||||
#define attend_req "ATTEND_REQ"
|
||||
#define attend_ack "ATTEND_ACK"
|
||||
#define wifi_leave "WIFI_LEAVE"
|
||||
#define leave_ack "LEAVE_ACK"
|
||||
#define bt_leave "BT_LEAVE"
|
||||
|
||||
#define HCI_OP_PERIODIC_INQ 0x0403
|
||||
#define HCI_EV_LE_META 0x3e
|
||||
#define HCI_EV_LE_CONN_COMPLETE 0x01
|
||||
#define HCI_EV_LE_CONN_UPDATE_COMPLETE 0x03
|
||||
#define HCI_EV_LE_ENHANCED_CONN_COMPLETE 0x0a
|
||||
|
||||
//vendor cmd to fw
|
||||
#define HCI_VENDOR_ENABLE_PROFILE_REPORT_COMMAND 0xfc18
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_LEGACY_COMMAND 0xfc19
|
||||
#define HCI_VENDOR_SET_PROFILE_REPORT_COMMAND 0xfc1B
|
||||
#define HCI_VENDOR_MAILBOX_CMD 0xfc8f
|
||||
#define HCI_VENDOR_SET_BITPOOL 0xfc51
|
||||
|
||||
//subcmd to fw
|
||||
#define HCI_VENDOR_SUB_CMD_WIFI_CHANNEL_AND_BANDWIDTH_CMD 0x11
|
||||
#define HCI_VENDOR_SUB_CMD_WIFI_FORCE_TX_POWER_CMD 0x17
|
||||
#define HCI_VENDOR_SUB_CMD_BT_ENABLE_IGNORE_WLAN_ACT_CMD 0x1B
|
||||
#define HCI_VENDOR_SUB_CMD_BT_REPORT_CONN_SCO_INQ_INFO 0x23
|
||||
#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_STATUS_INFO 0x27
|
||||
#define HCI_VENDOR_SUB_CMD_BT_AUTO_REPORT_ENABLE 0x28
|
||||
#define HCI_VENDOR_SUB_CMD_BT_SET_TXRETRY_REPORT_PARAM 0x29
|
||||
#define HCI_VENDOR_SUB_CMD_BT_SET_PTATABLE 0x2A
|
||||
#define HCI_VENDOR_SUB_CMD_SET_BT_PSD_MODE 0x31
|
||||
#define HCI_VENDOR_SUB_CMD_SET_BT_LNA_CONSTRAINT 0x32
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_L 0x40
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_M 0x41
|
||||
#define HCI_VENDOR_SUB_CMD_GET_AFH_MAP_H 0x42
|
||||
#define HCI_VENDOR_SUB_CMD_RD_REG_REQ 0x43
|
||||
#define HCI_VENDOR_SUB_CMD_WR_REG_REQ 0x44
|
||||
|
||||
#define HCI_EV_VENDOR_SPECIFIC 0xff
|
||||
|
||||
//sub event from fw start
|
||||
#define HCI_VENDOR_PTA_REPORT_EVENT 0x24
|
||||
#define HCI_VENDOR_PTA_AUTO_REPORT_EVENT 0x25
|
||||
|
||||
//vendor cmd to wifi driver
|
||||
#define HCI_GRP_VENDOR_SPECIFIC (0x3f << 10)
|
||||
#define HCI_OP_HCI_EXTENSION_VERSION_NOTIFY (0x0100 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_BT_OPERATION_NOTIFY (0x0102 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_INFO_NOTIFY (0x0106 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_COEX_NOTIFY (0x0107 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_PATCH_VER_NOTIFY (0x0108 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_AFH_MAP_NOTIFY (0x0109 | HCI_GRP_VENDOR_SPECIFIC)
|
||||
#define HCI_OP_HCI_BT_REGISTER_VALUE_NOTIFY (0x010a | HCI_GRP_VENDOR_SPECIFIC)
|
||||
|
||||
//bt info reason to wifi
|
||||
#define HOST_RESPONSE 0 //Host response when receive the BT Info Control Event
|
||||
#define POLLING_RESPONSE 1 //The BT Info response for polling by BT firmware.
|
||||
#define AUTO_REPORT 2 //BT auto report by BT firmware.
|
||||
#define STACK_REPORT_WHILE_DEVICE_D2 3 //Stack report when BT firmware is under power save state(ex:D2)
|
||||
|
||||
// vendor event from wifi
|
||||
#define RTK_HS_EXTENSION_EVENT_WIFI_SCAN 0x01
|
||||
#define RTK_HS_EXTENSION_EVENT_RADIO_STATUS_NOTIFY 0x02
|
||||
#define RTK_HS_EXTENSION_EVENT_HCI_BT_INFO_CONTROL 0x03
|
||||
#define RTK_HS_EXTENSION_EVENT_HCI_BT_COEX_CONTROL 0x04
|
||||
|
||||
//op code from wifi
|
||||
#define BT_PATCH_VERSION_QUERY 0x00
|
||||
#define IGNORE_WLAN_ACTIVE_CONTROL 0x01
|
||||
#define LNA_CONSTRAIN_CONTROL 0x02
|
||||
#define BT_POWER_DECREASE_CONTROL 0x03
|
||||
#define BT_PSD_MODE_CONTROL 0x04
|
||||
#define WIFI_BW_CHNL_NOTIFY 0x05
|
||||
#define QUERY_BT_AFH_MAP 0x06
|
||||
#define BT_REGISTER_ACCESS 0x07
|
||||
|
||||
//bt operation to notify
|
||||
#define BT_OPCODE_NONE 0
|
||||
#define BT_OPCODE_INQUIRY_START 1
|
||||
#define BT_OPCODE_INQUIRY_END 2
|
||||
#define BT_OPCODE_PAGE_START 3
|
||||
#define BT_OPCODE_PAGE_SUCCESS_END 4
|
||||
#define BT_OPCODE_PAGE_UNSUCCESS_END 5
|
||||
#define BT_OPCODE_PAIR_START 6
|
||||
#define BT_OPCODE_PAIR_END 7
|
||||
#define BT_OPCODE_ENABLE_BT 8
|
||||
#define BT_OPCODE_DISABLE_BT 9
|
||||
|
||||
#define HCI_EXTENSION_VERSION 0x0004
|
||||
#define HCI_CMD_PREAMBLE_SIZE 3
|
||||
#define PAN_PACKET_COUNT 5
|
||||
|
||||
#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
|
||||
#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
|
||||
|
||||
#define PSM_SDP 0x0001
|
||||
#define PSM_RFCOMM 0x0003
|
||||
#define PSM_PAN 0x000F
|
||||
#define PSM_HID 0x0011
|
||||
#define PSM_HID_INT 0x0013
|
||||
#define PSM_AVCTP 0x0017
|
||||
#define PSM_AVDTP 0x0019
|
||||
#define PSM_FTP 0x1001
|
||||
#define PSM_BIP 0x1003
|
||||
#define PSM_OPP 0x1005
|
||||
//--add more if needed--//
|
||||
|
||||
enum {
|
||||
profile_sco = 0,
|
||||
profile_hid = 1,
|
||||
profile_a2dp = 2,
|
||||
profile_pan = 3,
|
||||
profile_hid_interval = 4,
|
||||
profile_hogp = 5,
|
||||
profile_voice = 6,
|
||||
profile_sink = 7,
|
||||
profile_max = 8
|
||||
};
|
||||
|
||||
#define A2DP_SIGNAL 0x01
|
||||
#define A2DP_MEDIA 0x02
|
||||
//profile info data
|
||||
typedef struct {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
uint16_t psm;
|
||||
uint16_t dcid;
|
||||
uint16_t scid;
|
||||
uint8_t profile_index;
|
||||
uint8_t flags;
|
||||
} rtk_prof_info, *prtk_prof_info;
|
||||
|
||||
//profile info for each connection
|
||||
typedef struct rtl_hci_conn {
|
||||
struct list_head list;
|
||||
uint16_t handle;
|
||||
struct delayed_work a2dp_count_work;
|
||||
struct delayed_work pan_count_work;
|
||||
struct delayed_work hogp_count_work;
|
||||
uint32_t a2dp_packet_count;
|
||||
uint32_t pan_packet_count;
|
||||
uint32_t hogp_packet_count;
|
||||
uint32_t voice_packet_count;
|
||||
uint8_t type; // 0:l2cap, 1:sco/esco, 2:le
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
} rtk_conn_prof, *prtk_conn_prof;
|
||||
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
|
||||
struct rtl_btinfo {
|
||||
u8 cmd;
|
||||
u8 len;
|
||||
u8 data[6];
|
||||
};
|
||||
#define RTL_BTINFO_LEN (sizeof(struct rtl_btinfo))
|
||||
/* typedef struct {
|
||||
* uint8_t cmd_index;
|
||||
* uint8_t cmd_length;
|
||||
* uint8_t link_status;
|
||||
* uint8_t retry_cnt;
|
||||
* uint8_t rssi;
|
||||
* uint8_t mailbox_info;
|
||||
* uint16_t acl_throughput;
|
||||
* } hci_linkstatus_report; */
|
||||
|
||||
typedef struct {
|
||||
uint8_t type;
|
||||
uint32_t offset;
|
||||
uint32_t value;
|
||||
} hci_mailbox_register;
|
||||
|
||||
struct rtl_btinfo_ctl {
|
||||
uint8_t polling_enable;
|
||||
uint8_t polling_time;
|
||||
uint8_t autoreport_enable;
|
||||
};
|
||||
#endif /* RTB_SOFTWARE_MAILBOX */
|
||||
|
||||
#define MAX_LEN_OF_HCI_EV 32
|
||||
#define NUM_RTL_HCI_EV 32
|
||||
struct rtl_hci_ev {
|
||||
__u8 data[MAX_LEN_OF_HCI_EV];
|
||||
__u16 len;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#define L2_MAX_SUBSEC_LEN 128
|
||||
#define L2_MAX_PKTS 16
|
||||
struct rtl_l2_buff {
|
||||
__u8 data[L2_MAX_SUBSEC_LEN];
|
||||
__u16 len;
|
||||
__u16 out;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
struct rtl_coex_struct {
|
||||
struct list_head conn_hash; //hash for connections
|
||||
struct list_head profile_list; //hash for profile info
|
||||
struct hci_dev *hdev;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct socket *udpsock;
|
||||
struct sockaddr_in addr;
|
||||
struct sockaddr_in wifi_addr;
|
||||
struct timer_list polling_timer;
|
||||
#endif
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct workqueue_struct *sock_wq;
|
||||
struct delayed_work sock_work;
|
||||
#endif
|
||||
struct workqueue_struct *fw_wq;
|
||||
struct workqueue_struct *timer_wq;
|
||||
struct delayed_work fw_work;
|
||||
struct delayed_work l2_work;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
struct sock *sk;
|
||||
#endif
|
||||
struct urb *urb;
|
||||
spinlock_t spin_lock_sock;
|
||||
struct mutex profile_mutex;
|
||||
uint16_t profile_bitmap;
|
||||
uint16_t profile_status;
|
||||
int8_t profile_refcount[8];
|
||||
uint8_t ispairing;
|
||||
uint8_t isinquirying;
|
||||
uint8_t ispaging;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
uint8_t wifi_state;
|
||||
uint8_t autoreport;
|
||||
uint8_t polling_enable;
|
||||
uint8_t polling_interval;
|
||||
uint8_t piconet_id;
|
||||
uint8_t mode;
|
||||
uint8_t afh_map[10];
|
||||
#endif
|
||||
uint16_t hci_reversion;
|
||||
uint16_t lmp_subversion;
|
||||
#ifdef RTB_SOFTWARE_MAILBOX
|
||||
uint8_t wifi_on;
|
||||
uint8_t sock_open;
|
||||
#endif
|
||||
|
||||
unsigned long cmd_last_tx;
|
||||
|
||||
/* hci ev buff */
|
||||
struct list_head ev_used_list;
|
||||
struct list_head ev_free_list;
|
||||
|
||||
spinlock_t rxlock;
|
||||
__u8 pkt_type;
|
||||
__u16 expect;
|
||||
__u8 *tbuff;
|
||||
__u16 elen;
|
||||
__u8 back_buff[HCI_MAX_EVENT_SIZE];
|
||||
|
||||
/* l2cap rx buff */
|
||||
struct list_head l2_used_list;
|
||||
struct list_head l2_free_list;
|
||||
|
||||
/* buff addr and size */
|
||||
spinlock_t buff_lock;
|
||||
unsigned long pages_addr;
|
||||
unsigned long buff_size;
|
||||
|
||||
#define RTL_COEX_RUNNING (1 << 0)
|
||||
unsigned long flags;
|
||||
|
||||
};
|
||||
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
struct sbc_frame_hdr {
|
||||
uint8_t syncword:8; /* Sync word */
|
||||
uint8_t subbands:1; /* Subbands */
|
||||
uint8_t allocation_method:1; /* Allocation method */
|
||||
uint8_t channel_mode:2; /* Channel mode */
|
||||
uint8_t blocks:2; /* Blocks */
|
||||
uint8_t sampling_frequency:2; /* Sampling frequency */
|
||||
uint8_t bitpool:8; /* Bitpool */
|
||||
uint8_t crc_check:8; /* CRC check */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
/* NOTE: The code is copied from pa.
|
||||
* only the bit field in 8-bit is affected by endian, not the 16-bit or 32-bit.
|
||||
* why?
|
||||
*/
|
||||
struct rtp_header {
|
||||
unsigned cc:4;
|
||||
unsigned x:1;
|
||||
unsigned p:1;
|
||||
unsigned v:2;
|
||||
|
||||
unsigned pt:7;
|
||||
unsigned m:1;
|
||||
|
||||
uint16_t sequence_number;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[0];
|
||||
} __attribute__ ((packed));
|
||||
|
||||
#else
|
||||
/* big endian */
|
||||
struct sbc_frame_hdr {
|
||||
uint8_t syncword:8; /* Sync word */
|
||||
uint8_t sampling_frequency:2; /* Sampling frequency */
|
||||
uint8_t blocks:2; /* Blocks */
|
||||
uint8_t channel_mode:2; /* Channel mode */
|
||||
uint8_t allocation_method:1; /* Allocation method */
|
||||
uint8_t subbands:1; /* Subbands */
|
||||
uint8_t bitpool:8; /* Bitpool */
|
||||
uint8_t crc_check:8; /* CRC check */
|
||||
} __attribute__ ((packed));
|
||||
|
||||
struct rtp_header {
|
||||
unsigned v:2;
|
||||
unsigned p:1;
|
||||
unsigned x:1;
|
||||
unsigned cc:4;
|
||||
|
||||
unsigned m:1;
|
||||
unsigned pt:7;
|
||||
|
||||
uint16_t sequence_number;
|
||||
uint32_t timestamp;
|
||||
uint32_t ssrc;
|
||||
uint32_t csrc[0];
|
||||
} __attribute__ ((packed));
|
||||
#endif /* __LITTLE_ENDIAN */
|
||||
|
||||
void rtk_btcoex_parse_event(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_cmd(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_l2cap_data_tx(uint8_t *buffer, int count);
|
||||
void rtk_btcoex_parse_l2cap_data_rx(uint8_t *buffer, int count);
|
||||
|
||||
void rtk_btcoex_open(struct hci_dev *hdev);
|
||||
void rtk_btcoex_close(void);
|
||||
void rtk_btcoex_probe(struct hci_dev *hdev);
|
||||
void rtk_btcoex_init(void);
|
||||
void rtk_btcoex_exit(void);
|
Loading…
Reference in New Issue
Block a user