1.蓝牙驱动

This commit is contained in:
payton 2023-10-13 10:20:38 +08:00
parent a369f09caa
commit c671d5050a
9 changed files with 5555 additions and 907 deletions

View File

@ -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

View File

@ -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,78 +26,51 @@ 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
serial port interface. You will also need this driver if you have
UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
serial port interface. You will also need this driver if you have
UART based Bluetooth PCMCIA and CF devices like Xircom Credit Card
adapter and BrainBoxes Bluetooth PC Card.
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
help
UART (H4) is serial protocol for communication between Bluetooth
device and host. This protocol is required for most Bluetooth devices
with UART interface, including PCMCIA and CF cards.
UART (H4) is serial protocol for communication between Bluetooth
device and host. This protocol is required for most Bluetooth devices
with UART interface, including PCMCIA and CF cards.
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
select BITREVERSE
help
BCSP (BlueCore Serial Protocol) is serial protocol for communication
BCSP (BlueCore Serial Protocol) is serial protocol for communication
between Bluetooth device and host. This protocol is required for non
USB Bluetooth devices based on CSR BlueCore chip, including PCMCIA and
CF cards.
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

View File

@ -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

View File

@ -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);
h4->rx_skb = NULL;
return 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;
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

View 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);
}

View File

@ -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 percpu_rw_semaphore proto_lock; /* Stop work for proto close */
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

File diff suppressed because it is too large Load Diff

View 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);