From fb2ce8d11f0399a1359e02fa2fcc5ad7e595544a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 16:13:01 -0700 Subject: [PATCH 01/38] Bluetooth: hci_uart: Add support for vendor detection flag This adds a new HCI_UART_VND_DETECT flag to allow automatic vendor detection. This allows to enable known vendor commands (for example for setting the public device address) when using a standard H:4 UART protocol or when running in virtual machines. When this new flag is configured and no vendor specific setup routine is provided, then the local version information are read and the provided manufacturer information can be evaluated to configure extra vendor callbacks. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 29 ++++++++++++++++++++++++++++- drivers/bluetooth/hci_uart.h | 1 + 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 1363dc616ace..b1e8083044ce 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -264,10 +264,36 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) static int hci_uart_setup(struct hci_dev *hdev) { struct hci_uart *hu = hci_get_drvdata(hdev); + struct hci_rp_read_local_version *ver; + struct sk_buff *skb; if (hu->proto->setup) return hu->proto->setup(hu); + if (!test_bit(HCI_UART_VND_DETECT, &hu->hdev_flags)) + return 0; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: Reading local version information failed (%ld)", + hdev->name, PTR_ERR(skb)); + return 0; + } + + if (skb->len != sizeof(*ver)) { + BT_ERR("%s: Event length mismatch for version information", + hdev->name); + goto done; + } + + ver = (struct hci_rp_read_local_version *)skb->data; + + switch (le16_to_cpu(ver->manufacturer)) { + } + +done: + kfree_skb(skb); return 0; } @@ -497,7 +523,8 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) BIT(HCI_UART_RESET_ON_INIT) | BIT(HCI_UART_CREATE_AMP) | BIT(HCI_UART_INIT_PENDING) | - BIT(HCI_UART_EXT_CONFIG); + BIT(HCI_UART_EXT_CONFIG) | + BIT(HCI_UART_VND_DETECT); if (flags & ~valid_flags) return -EINVAL; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 074ed29092b4..22a5f7c74266 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -49,6 +49,7 @@ #define HCI_UART_CREATE_AMP 2 #define HCI_UART_INIT_PENDING 3 #define HCI_UART_EXT_CONFIG 4 +#define HCI_UART_VND_DETECT 5 struct hci_uart; From 16e3887f9c625dbcbc5d7cc939881dd4515141c5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 16:13:02 -0700 Subject: [PATCH 02/38] Bluetooth: hci_uart: Add support Intel address configuration When using vendor detection, this adds support for the Intel specific address configuration command. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 9 +++++++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_intel.c | 48 +++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 5 ++++ drivers/bluetooth/hci_uart.h | 7 ++++- 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci_intel.c diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 364f080768d0..4356f718ea3d 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -94,6 +94,15 @@ config BT_HCIUART_3WIRE Say Y here to compile support for Three-wire UART protocol. +config BT_HCIUART_INTEL + bool "Intel protocol support" + depends on BT_HCIUART + 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_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 9fe8a875a827..adb99457d016 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -29,6 +29,7 @@ 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-objs := $(hci_uart-y) ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c new file mode 100644 index 000000000000..b7bd50a41080 --- /dev/null +++ b/drivers/bluetooth/hci_intel.c @@ -0,0 +1,48 @@ +/* + * + * Bluetooth HCI UART driver for Intel devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 +#include +#include + +#include +#include + +#include "hci_uart.h" + +int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Changing Intel device address failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); + + return 0; +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b1e8083044ce..03f9defac39d 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -290,6 +290,11 @@ static int hci_uart_setup(struct hci_dev *hdev) ver = (struct hci_rp_read_local_version *)skb->data; switch (le16_to_cpu(ver->manufacturer)) { +#ifdef CONFIG_BT_HCIUART_INTEL + case 2: + hdev->set_bdaddr = intel_set_bdaddr; + break; +#endif } done: diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 22a5f7c74266..687aa7e9eb2e 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -35,7 +35,7 @@ #define HCIUARTGETFLAGS _IOR('U', 204, int) /* UART protocols */ -#define HCI_UART_MAX_PROTO 6 +#define HCI_UART_MAX_PROTO 7 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 @@ -43,6 +43,7 @@ #define HCI_UART_H4DS 3 #define HCI_UART_LL 4 #define HCI_UART_ATH3K 5 +#define HCI_UART_INTEL 6 #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 @@ -118,3 +119,7 @@ int ath_deinit(void); int h5_init(void); int h5_deinit(void); #endif + +#ifdef CONFIG_BT_HCIUART_INTEL +int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +#endif From e9a2dd261ac3d7bffbf55368a60401f5982dcc59 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 16:13:03 -0700 Subject: [PATCH 03/38] Bluetooth: hci_uart: Add support Broadcom address configuration When using vendor detection, this adds support for the Broadcom specific address configuration command. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 9 +++++++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/hci_bcm.c | 48 +++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 5 ++++ drivers/bluetooth/hci_uart.h | 7 ++++- 5 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 drivers/bluetooth/hci_bcm.c diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4356f718ea3d..e8630b605aa9 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -103,6 +103,15 @@ config BT_HCIUART_INTEL Say Y here to compile support for Intel protocol. +config BT_HCIUART_BCM + bool "Broadcom protocol support" + depends on BT_HCIUART + 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_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index adb99457d016..51f9d0c18963 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -30,6 +30,7 @@ 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-objs := $(hci_uart-y) ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c new file mode 100644 index 000000000000..1a5817bda7c6 --- /dev/null +++ b/drivers/bluetooth/hci_bcm.c @@ -0,0 +1,48 @@ +/* + * + * Bluetooth HCI UART driver for Broadcom devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 +#include +#include + +#include +#include + +#include "hci_uart.h" + +int bcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Change address command failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); + + return 0; +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 03f9defac39d..b6d1ff4fbba6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -294,6 +294,11 @@ static int hci_uart_setup(struct hci_dev *hdev) case 2: hdev->set_bdaddr = intel_set_bdaddr; break; +#endif +#ifdef CONFIG_BT_HCIUART_BCM + case 15: + hdev->set_bdaddr = bcm_set_bdaddr; + break; #endif } diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 687aa7e9eb2e..4dc8ab3009a9 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -35,7 +35,7 @@ #define HCIUARTGETFLAGS _IOR('U', 204, int) /* UART protocols */ -#define HCI_UART_MAX_PROTO 7 +#define HCI_UART_MAX_PROTO 8 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 @@ -44,6 +44,7 @@ #define HCI_UART_LL 4 #define HCI_UART_ATH3K 5 #define HCI_UART_INTEL 6 +#define HCI_UART_BCM 7 #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 @@ -123,3 +124,7 @@ int h5_deinit(void); #ifdef CONFIG_BT_HCIUART_INTEL int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); #endif + +#ifdef CONFIG_BT_HCIUART_BCM +int bcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +#endif From dfe19d28200f0d2306ef1510bbea3df18e22a6bc Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 19:57:21 -0700 Subject: [PATCH 04/38] Bluetooth: hci_uart: Remove unneeded cast of tty->disc_data Casting the tty->disc_data to (void *) is not needed at all. So just remove this cast and assign the object without a cast. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b6d1ff4fbba6..c577a40e790d 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -362,7 +362,7 @@ static int hci_uart_tty_open(struct tty_struct *tty) */ static void hci_uart_tty_close(struct tty_struct *tty) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; struct hci_dev *hdev; BT_DBG("tty %p", tty); @@ -401,7 +401,7 @@ static void hci_uart_tty_close(struct tty_struct *tty) */ static void hci_uart_tty_wakeup(struct tty_struct *tty) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; BT_DBG(""); @@ -431,7 +431,7 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) */ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; if (!hu || tty != hu->tty) return; @@ -560,7 +560,7 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { - struct hci_uart *hu = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; int err = 0; BT_DBG(""); From facf5225e88c03170e66f76ff498e0c29f41a64a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 19:57:22 -0700 Subject: [PATCH 05/38] Bluetooth: hci_uart: Fix indentation issues for multi-line functions Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ldisc.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index c577a40e790d..a3b906bcfca6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -429,7 +429,8 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty) * * Return Value: None */ -static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count) +static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, + char *flags, int count) { struct hci_uart *hu = tty->disc_data; @@ -557,8 +558,8 @@ static int hci_uart_set_flags(struct hci_uart *hu, unsigned long flags) * * Return Value: Command dependent */ -static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { struct hci_uart *hu = tty->disc_data; int err = 0; @@ -614,19 +615,19 @@ static int hci_uart_tty_ioctl(struct tty_struct *tty, struct file * file, * We don't provide read/write/poll interface for user space. */ static ssize_t hci_uart_tty_read(struct tty_struct *tty, struct file *file, - unsigned char __user *buf, size_t nr) + unsigned char __user *buf, size_t nr) { return 0; } static ssize_t hci_uart_tty_write(struct tty_struct *tty, struct file *file, - const unsigned char *data, size_t count) + const unsigned char *data, size_t count) { return 0; } static unsigned int hci_uart_tty_poll(struct tty_struct *tty, - struct file *filp, poll_table *wait) + struct file *filp, poll_table *wait) { return 0; } From 72b9439be96ffc816a131cd92fd33ef6541871d7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 20:25:50 -0700 Subject: [PATCH 06/38] Bluetooth: hci_uart: Remove unused h4->rx_skb field The h4->rx_skb is not used anymore and with that just remove it. Seems this was a leftover and even the kfree_skb call freeing it is rather pointless since it got never allocated. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h4.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 66db9a803373..3ea8f0886ed1 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -51,7 +51,6 @@ struct h4_struct { unsigned long rx_state; unsigned long rx_count; - struct sk_buff *rx_skb; struct sk_buff_head txq; }; @@ -95,8 +94,6 @@ static int h4_close(struct hci_uart *hu) skb_queue_purge(&h4->txq); - kfree_skb(h4->rx_skb); - hu->priv = NULL; kfree(h4); From 940cbe3a6b2282551e2e458d307967ae37cbba18 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 20:29:27 -0700 Subject: [PATCH 07/38] Bluetooth: hci_uart: Remove unused h4->rx_state and h4->rx_count field The fields h4->rx_state and h4->rx_count are not used at all and with that they can be just removed. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h4.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 3ea8f0886ed1..0d9ba07d2730 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -49,8 +49,6 @@ #define VERSION "1.2" struct h4_struct { - unsigned long rx_state; - unsigned long rx_count; struct sk_buff_head txq; }; From 5c7d2dd2852c7cd8f07cf91291b351c01b781044 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 20:59:40 -0700 Subject: [PATCH 08/38] Bluetooth: Make data pointer of hci_recv_stream_fragment const The data pointer provided to hci_recv_stream_fragment function should have been marked const. The function has no business in modifying the original data. So fix this now. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 2 +- net/bluetooth/hci_core.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index 93fd3e756b8a..ad957f336ead 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -1012,7 +1012,7 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); -int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count); +int hci_recv_stream_fragment(struct hci_dev *hdev, const void *data, int count); void hci_init_sysfs(struct hci_dev *hdev); void hci_conn_init_sysfs(struct hci_conn *conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 46b114c0140b..c9e7cafb245a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3320,7 +3320,7 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) } EXPORT_SYMBOL(hci_recv_frame); -static int hci_reassembly(struct hci_dev *hdev, int type, void *data, +static int hci_reassembly(struct hci_dev *hdev, int type, const void *data, int count, __u8 index) { int len = 0; @@ -3430,7 +3430,7 @@ static int hci_reassembly(struct hci_dev *hdev, int type, void *data, #define STREAM_REASSEMBLY 0 -int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) +int hci_recv_stream_fragment(struct hci_dev *hdev, const void *data, int count) { int type; int rem = 0; @@ -3439,7 +3439,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count) struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY]; if (!skb) { - struct { char type; } *pkt; + const struct { char type; } *pkt; /* Start of the frame */ pkt = data; From 9d1c40ebb66416f166b92c6828af48549ca99307 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 20:59:41 -0700 Subject: [PATCH 09/38] Bluetooth: hci_uart: Use const data pointer for received data The TTY layer provides its data pointers as const, but the HCI UART callbacks expect them as general data pointers. This is of course wrong and instead of casting them, just fix the individual drivers to actually take a const data pointer. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ath.c | 2 +- drivers/bluetooth/hci_bcsp.c | 4 ++-- drivers/bluetooth/hci_h4.c | 2 +- drivers/bluetooth/hci_h5.c | 4 ++-- drivers/bluetooth/hci_ldisc.c | 2 +- drivers/bluetooth/hci_ll.c | 4 ++-- drivers/bluetooth/hci_uart.h | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 9c4dcf4c62ea..4e89d3e33b7b 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -188,7 +188,7 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) } /* Recv data */ -static int ath_recv(struct hci_uart *hu, void *data, int count) +static int ath_recv(struct hci_uart *hu, const void *data, int count) { int ret; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 21cc45b34f13..50ef2e613d59 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -554,10 +554,10 @@ static u16 bscp_get_crc(struct bcsp_struct *bcsp) } /* Recv data */ -static int bcsp_recv(struct hci_uart *hu, void *data, int count) +static int bcsp_recv(struct hci_uart *hu, const void *data, int count) { struct bcsp_struct *bcsp = hu->priv; - unsigned char *ptr; + const unsigned char *ptr; BT_DBG("hu %p count %d rx_state %d rx_count %ld", hu, count, bcsp->rx_state, bcsp->rx_count); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 0d9ba07d2730..97a5df4941b4 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -113,7 +113,7 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) } /* Recv data */ -static int h4_recv(struct hci_uart *hu, void *data, int count) +static int h4_recv(struct hci_uart *hu, const void *data, int count) { int ret; diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index ec0fa7732c0d..0f681cc1af64 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -511,10 +511,10 @@ static void h5_reset_rx(struct h5 *h5) clear_bit(H5_RX_ESC, &h5->flags); } -static int h5_recv(struct hci_uart *hu, void *data, int count) +static int h5_recv(struct hci_uart *hu, const void *data, int count) { struct h5 *h5 = hu->priv; - unsigned char *ptr = data; + const unsigned char *ptr = data; BT_DBG("%s pending %zu count %d", hu->hdev->name, h5->rx_pending, count); diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index a3b906bcfca6..50dbaf3579ed 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -441,7 +441,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, return; spin_lock(&hu->rx_lock); - hu->proto->recv(hu, (void *) data, count); + hu->proto->recv(hu, data, count); if (hu->hdev) hu->hdev->stat.byte_rx += count; diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 69a90b1b5ff5..79eea1cbd988 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -370,10 +370,10 @@ static inline int ll_check_data_len(struct hci_dev *hdev, struct ll_struct *ll, } /* Recv data */ -static int ll_recv(struct hci_uart *hu, void *data, int count) +static int ll_recv(struct hci_uart *hu, const void *data, int count) { struct ll_struct *ll = hu->priv; - char *ptr; + const char *ptr; struct hci_event_hdr *eh; struct hci_acl_hdr *ah; struct hci_sco_hdr *sh; diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 4dc8ab3009a9..79bbcefb0112 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -60,7 +60,7 @@ struct hci_uart_proto { int (*open)(struct hci_uart *hu); int (*close)(struct hci_uart *hu); int (*flush)(struct hci_uart *hu); - int (*recv)(struct hci_uart *hu, void *data, int len); + int (*recv)(struct hci_uart *hu, const void *data, int len); int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); int (*setup)(struct hci_uart *hu); struct sk_buff *(*dequeue)(struct hci_uart *hu); From e1a38d70d8e07db6fbf93621f289c08bbcca0ba3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 21:59:24 -0700 Subject: [PATCH 10/38] Bluetooth: hci_uart: Introduce h4_recv_buf helper function The h4_recv_buf helper function can be used for receiving H:4 packets out of a TTY stream. It is self-contained and allows for reuse by all HCI UART protocols. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h4.c | 98 ++++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_uart.h | 3 ++ 2 files changed, 101 insertions(+) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 97a5df4941b4..09270bc26654 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -161,3 +161,101 @@ 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) +{ + while (count) { + int len; + + if (!skb) { + switch (buffer[0]) { + case HCI_ACLDATA_PKT: + skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; + bt_cb(skb)->expect = HCI_ACL_HDR_SIZE; + break; + case HCI_SCODATA_PKT: + skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; + bt_cb(skb)->expect = HCI_SCO_HDR_SIZE; + break; + case HCI_EVENT_PKT: + skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + bt_cb(skb)->pkt_type = HCI_EVENT_PKT; + bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE; + break; + default: + return ERR_PTR(-EILSEQ); + } + + count -= 1; + buffer += 1; + } + + len = min_t(uint, bt_cb(skb)->expect, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + bt_cb(skb)->expect -= len; + + switch (bt_cb(skb)->pkt_type) { + case HCI_ACLDATA_PKT: + if (skb->len == HCI_ACL_HDR_SIZE) { + __le16 dlen = hci_acl_hdr(skb)->dlen; + + /* Complete ACL header */ + bt_cb(skb)->expect = __le16_to_cpu(dlen); + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + } + break; + case HCI_SCODATA_PKT: + if (skb->len == HCI_SCO_HDR_SIZE) { + /* Complete SCO header */ + bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + } + break; + case HCI_EVENT_PKT: + if (skb->len == HCI_EVENT_HDR_SIZE) { + /* Complete event header */ + bt_cb(skb)->expect = hci_event_hdr(skb)->plen; + + if (skb_tailroom(skb) < bt_cb(skb)->expect) { + kfree_skb(skb); + return ERR_PTR(-EMSGSIZE); + } + } + break; + } + + if (bt_cb(skb)->expect == 0) { + /* Complete frame */ + hci_recv_frame(hdev, skb); + skb = NULL; + } + } + + return skb; +} diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 79bbcefb0112..53b329229f2e 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -99,6 +99,9 @@ int hci_uart_init_ready(struct hci_uart *hu); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); int h4_deinit(void); + +struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, + const unsigned char *buffer, int count); #endif #ifdef CONFIG_BT_HCIUART_BCSP From c27799f99f589e76ea84642508a32638091a409a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 21:59:25 -0700 Subject: [PATCH 11/38] Bluetooth: hci_uart: Use h4_recv_buf helper for H:4 protocol Instead of using hci_recv_stream_fragment, use the local available h4_recv_buf helper function. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_h4.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 09270bc26654..d8414540f743 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -49,6 +49,7 @@ #define VERSION "1.2" struct h4_struct { + struct sk_buff *rx_skb; struct sk_buff_head txq; }; @@ -92,6 +93,8 @@ static int h4_close(struct hci_uart *hu) skb_queue_purge(&h4->txq); + kfree_skb(h4->rx_skb); + hu->priv = NULL; kfree(h4); @@ -115,15 +118,16 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *skb) /* Recv data */ static int h4_recv(struct hci_uart *hu, const void *data, int count) { - int ret; + struct h4_struct *h4 = hu->priv; if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) return -EUNATCH; - ret = hci_recv_stream_fragment(hu->hdev, data, count); - if (ret < 0) { - BT_ERR("Frame Reassembly Failed"); - return ret; + h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, count); + if (IS_ERR(h4->rx_skb)) { + int err = PTR_ERR(h4->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + return err; } return count; From d90aa68236137d4170e39055dba41a5a000c568e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 21:59:26 -0700 Subject: [PATCH 12/38] Bluetooth: hci_uart: Use h4_recv_buf helper for Atheros AR300x Instead of using hci_recv_stream_fragment, use the local available h4_recv_buf helper function. To ensure that the function is available select BT_HCIUART_H4. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_ath.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index e8630b605aa9..f8a41975c30d 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -62,6 +62,7 @@ config BT_HCIUART_BCSP config BT_HCIUART_ATH3K bool "Atheros AR300x serial 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. diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 4e89d3e33b7b..15beb974f3a0 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -45,6 +45,7 @@ struct ath_struct { struct hci_uart *hu; unsigned int cur_sleep; + struct sk_buff *rx_skb; struct sk_buff_head txq; struct work_struct ctxtsw; }; @@ -136,6 +137,8 @@ static int ath_close(struct hci_uart *hu) skb_queue_purge(&ath->txq); + kfree_skb(ath->rx_skb); + cancel_work_sync(&ath->ctxtsw); hu->priv = NULL; @@ -190,12 +193,13 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) /* Recv data */ static int ath_recv(struct hci_uart *hu, const void *data, int count) { - int ret; + struct ath_struct *ath = hu->priv; - ret = hci_recv_stream_fragment(hu->hdev, data, count); - if (ret < 0) { - BT_ERR("Frame Reassembly Failed"); - return ret; + ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count); + if (IS_ERR(ath->rx_skb)) { + int err = PTR_ERR(ath->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + return err; } return count; From 2d7cc19eebc182dbdda228aa26eb5bfff97ac072 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 21:59:27 -0700 Subject: [PATCH 13/38] Bluetooth: Remove hci_recv_stream_fragment function The hci_recv_stream_fragment function should have never been introduced in the first place. The Bluetooth core does not need to know anything about the HCI transport protocol. With all transport protocol specific detailed moved back into the drivers where they belong (mainly generic USB and UART drivers), this function can now be removed. This reduces the size of hci_dev structure and also removes an exported symbol from the Bluetooth core module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci_core.h | 3 - net/bluetooth/hci_core.c | 148 +------------------------------ 2 files changed, 1 insertion(+), 150 deletions(-) diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h index ad957f336ead..a056c2bfeb81 100644 --- a/include/net/bluetooth/hci_core.h +++ b/include/net/bluetooth/hci_core.h @@ -185,7 +185,6 @@ struct amp_assoc { #define HCI_MAX_PAGES 3 -#define NUM_REASSEMBLY 4 struct hci_dev { struct list_head list; struct mutex lock; @@ -327,7 +326,6 @@ struct hci_dev { struct sk_buff_head cmd_q; struct sk_buff *sent_cmd; - struct sk_buff *reassembly[NUM_REASSEMBLY]; struct mutex req_lock; wait_queue_head_t req_wait_q; @@ -1012,7 +1010,6 @@ int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb); int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb); -int hci_recv_stream_fragment(struct hci_dev *hdev, const void *data, int count); void hci_init_sysfs(struct hci_dev *hdev); void hci_conn_init_sysfs(struct hci_conn *conn); diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index c9e7cafb245a..476709bd068a 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -3200,7 +3200,7 @@ EXPORT_SYMBOL(hci_register_dev); /* Unregister HCI device */ void hci_unregister_dev(struct hci_dev *hdev) { - int i, id; + int id; BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus); @@ -3214,9 +3214,6 @@ void hci_unregister_dev(struct hci_dev *hdev) hci_dev_do_close(hdev); - for (i = 0; i < NUM_REASSEMBLY; i++) - kfree_skb(hdev->reassembly[i]); - cancel_work_sync(&hdev->power_on); if (!test_bit(HCI_INIT, &hdev->flags) && @@ -3320,149 +3317,6 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb) } EXPORT_SYMBOL(hci_recv_frame); -static int hci_reassembly(struct hci_dev *hdev, int type, const void *data, - int count, __u8 index) -{ - int len = 0; - int hlen = 0; - int remain = count; - struct sk_buff *skb; - struct bt_skb_cb *scb; - - if ((type < HCI_ACLDATA_PKT || type > HCI_EVENT_PKT) || - index >= NUM_REASSEMBLY) - return -EILSEQ; - - skb = hdev->reassembly[index]; - - if (!skb) { - switch (type) { - case HCI_ACLDATA_PKT: - len = HCI_MAX_FRAME_SIZE; - hlen = HCI_ACL_HDR_SIZE; - break; - case HCI_EVENT_PKT: - len = HCI_MAX_EVENT_SIZE; - hlen = HCI_EVENT_HDR_SIZE; - break; - case HCI_SCODATA_PKT: - len = HCI_MAX_SCO_SIZE; - hlen = HCI_SCO_HDR_SIZE; - break; - } - - skb = bt_skb_alloc(len, GFP_ATOMIC); - if (!skb) - return -ENOMEM; - - scb = (void *) skb->cb; - scb->expect = hlen; - scb->pkt_type = type; - - hdev->reassembly[index] = skb; - } - - while (count) { - scb = (void *) skb->cb; - len = min_t(uint, scb->expect, count); - - memcpy(skb_put(skb, len), data, len); - - count -= len; - data += len; - scb->expect -= len; - remain = count; - - switch (type) { - case HCI_EVENT_PKT: - if (skb->len == HCI_EVENT_HDR_SIZE) { - struct hci_event_hdr *h = hci_event_hdr(skb); - scb->expect = h->plen; - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - - case HCI_ACLDATA_PKT: - if (skb->len == HCI_ACL_HDR_SIZE) { - struct hci_acl_hdr *h = hci_acl_hdr(skb); - scb->expect = __le16_to_cpu(h->dlen); - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - - case HCI_SCODATA_PKT: - if (skb->len == HCI_SCO_HDR_SIZE) { - struct hci_sco_hdr *h = hci_sco_hdr(skb); - scb->expect = h->dlen; - - if (skb_tailroom(skb) < scb->expect) { - kfree_skb(skb); - hdev->reassembly[index] = NULL; - return -ENOMEM; - } - } - break; - } - - if (scb->expect == 0) { - /* Complete frame */ - - bt_cb(skb)->pkt_type = type; - hci_recv_frame(hdev, skb); - - hdev->reassembly[index] = NULL; - return remain; - } - } - - return remain; -} - -#define STREAM_REASSEMBLY 0 - -int hci_recv_stream_fragment(struct hci_dev *hdev, const void *data, int count) -{ - int type; - int rem = 0; - - while (count) { - struct sk_buff *skb = hdev->reassembly[STREAM_REASSEMBLY]; - - if (!skb) { - const struct { char type; } *pkt; - - /* Start of the frame */ - pkt = data; - type = pkt->type; - - data++; - count--; - } else - type = bt_cb(skb)->pkt_type; - - rem = hci_reassembly(hdev, type, data, count, - STREAM_REASSEMBLY); - if (rem < 0) - return rem; - - data += (count - rem); - count = rem; - } - - return rem; -} -EXPORT_SYMBOL(hci_recv_stream_fragment); - /* ---- Interface to upper protocols ---- */ int hci_register_cb(struct hci_cb *cb) From 4ee7ef19894c0ac35cc6dc374d65658a26d7496a Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 22:11:43 -0700 Subject: [PATCH 14/38] Bluetooth: hci_uart: Make struct hci_uart_proto always const The usage of struct hci_uart_proto should always be const. Change the function headers and individual protocol drivers. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ath.c | 2 +- drivers/bluetooth/hci_bcsp.c | 2 +- drivers/bluetooth/hci_h4.c | 2 +- drivers/bluetooth/hci_h5.c | 2 +- drivers/bluetooth/hci_ldisc.c | 10 +++++----- drivers/bluetooth/hci_ll.c | 2 +- drivers/bluetooth/hci_uart.h | 6 +++--- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 15beb974f3a0..c1c0b0c7e1c9 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -205,7 +205,7 @@ static int ath_recv(struct hci_uart *hu, const void *data, int count) return count; } -static struct hci_uart_proto athp = { +static const struct hci_uart_proto athp = { .id = HCI_UART_ATH3K, .open = ath_open, .close = ath_close, diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 50ef2e613d59..7d30e05a973f 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -735,7 +735,7 @@ static int bcsp_close(struct hci_uart *hu) return 0; } -static struct hci_uart_proto bcsp = { +static const struct hci_uart_proto bcsp = { .id = HCI_UART_BCSP, .open = bcsp_open, .close = bcsp_close, diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index d8414540f743..fc783103ee36 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -139,7 +139,7 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) return skb_dequeue(&h4->txq); } -static struct hci_uart_proto h4p = { +static const struct hci_uart_proto h4p = { .id = HCI_UART_H4, .open = h4_open, .close = h4_close, diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index 0f681cc1af64..aac0e8f718b0 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -743,7 +743,7 @@ static int h5_flush(struct hci_uart *hu) return 0; } -static struct hci_uart_proto h5p = { +static const struct hci_uart_proto h5p = { .id = HCI_UART_3WIRE, .open = h5_open, .close = h5_close, diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 50dbaf3579ed..ba3b988ce60a 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -48,9 +48,9 @@ #define VERSION "2.2" -static struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; +static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; -int hci_uart_register_proto(struct hci_uart_proto *p) +int hci_uart_register_proto(const struct hci_uart_proto *p) { if (p->id >= HCI_UART_MAX_PROTO) return -EINVAL; @@ -63,7 +63,7 @@ int hci_uart_register_proto(struct hci_uart_proto *p) return 0; } -int hci_uart_unregister_proto(struct hci_uart_proto *p) +int hci_uart_unregister_proto(const struct hci_uart_proto *p) { if (p->id >= HCI_UART_MAX_PROTO) return -EINVAL; @@ -76,7 +76,7 @@ int hci_uart_unregister_proto(struct hci_uart_proto *p) return 0; } -static struct hci_uart_proto *hci_uart_get_proto(unsigned int id) +static const struct hci_uart_proto *hci_uart_get_proto(unsigned int id) { if (id >= HCI_UART_MAX_PROTO) return NULL; @@ -506,7 +506,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) static int hci_uart_set_proto(struct hci_uart *hu, int id) { - struct hci_uart_proto *p; + const struct hci_uart_proto *p; int err; p = hci_uart_get_proto(id); diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index 79eea1cbd988..e66f0fa65485 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -505,7 +505,7 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu) return skb_dequeue(&ll->txq); } -static struct hci_uart_proto llp = { +static const struct hci_uart_proto llp = { .id = HCI_UART_LL, .open = ll_open, .close = ll_close, diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 53b329229f2e..683153d2e9db 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -75,7 +75,7 @@ struct hci_uart { struct work_struct init_ready; struct work_struct write_work; - struct hci_uart_proto *proto; + const struct hci_uart_proto *proto; void *priv; struct sk_buff *tx_skb; @@ -91,8 +91,8 @@ struct hci_uart { #define HCI_UART_SENDING 1 #define HCI_UART_TX_WAKEUP 2 -int hci_uart_register_proto(struct hci_uart_proto *p); -int hci_uart_unregister_proto(struct hci_uart_proto *p); +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_tx_wakeup(struct hci_uart *hu); int hci_uart_init_ready(struct hci_uart *hu); From 7c40fb8db135288485f4f6226ceb69d64610a84e Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 22:27:34 -0700 Subject: [PATCH 15/38] Bluetooth: hci_uart: Add name information to hci_uart_proto struct This adds an extra name field to the hci_uart_proto struct that provides a simple way of adding a string identifier to the protocol. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ath.c | 15 ++++++++------- drivers/bluetooth/hci_bcsp.c | 1 + drivers/bluetooth/hci_h4.c | 1 + drivers/bluetooth/hci_h5.c | 1 + drivers/bluetooth/hci_ll.c | 1 + drivers/bluetooth/hci_uart.h | 1 + 6 files changed, 13 insertions(+), 7 deletions(-) diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index c1c0b0c7e1c9..32c46cd40d85 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -206,13 +206,14 @@ static int ath_recv(struct hci_uart *hu, const void *data, int count) } static const struct hci_uart_proto athp = { - .id = HCI_UART_ATH3K, - .open = ath_open, - .close = ath_close, - .recv = ath_recv, - .enqueue = ath_enqueue, - .dequeue = ath_dequeue, - .flush = ath_flush, + .id = HCI_UART_ATH3K, + .name = "ATH3K", + .open = ath_open, + .close = ath_close, + .recv = ath_recv, + .enqueue = ath_enqueue, + .dequeue = ath_dequeue, + .flush = ath_flush, }; int __init ath_init(void) diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 7d30e05a973f..285fd0a97311 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -737,6 +737,7 @@ static int bcsp_close(struct hci_uart *hu) static const struct hci_uart_proto bcsp = { .id = HCI_UART_BCSP, + .name = "BCSP", .open = bcsp_open, .close = bcsp_close, .enqueue = bcsp_enqueue, diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index fc783103ee36..7c5e68cb9959 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -141,6 +141,7 @@ static struct sk_buff *h4_dequeue(struct hci_uart *hu) static const struct hci_uart_proto h4p = { .id = HCI_UART_H4, + .name = "H4", .open = h4_open, .close = h4_close, .recv = h4_recv, diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index aac0e8f718b0..de7da17ccdab 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -745,6 +745,7 @@ static int h5_flush(struct hci_uart *hu) static const struct hci_uart_proto h5p = { .id = HCI_UART_3WIRE, + .name = "Three-wire (H5)", .open = h5_open, .close = h5_close, .recv = h5_recv, diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index e66f0fa65485..c6a1aeb4e7fb 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -507,6 +507,7 @@ static struct sk_buff *ll_dequeue(struct hci_uart *hu) static const struct hci_uart_proto llp = { .id = HCI_UART_LL, + .name = "LL", .open = ll_open, .close = ll_close, .recv = ll_recv, diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 683153d2e9db..80e694a36143 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -57,6 +57,7 @@ struct hci_uart; struct hci_uart_proto { unsigned int id; + const char *name; int (*open)(struct hci_uart *hu); int (*close)(struct hci_uart *hu); int (*flush)(struct hci_uart *hu); From 01009eec70a7d80773267b34522b0bb1208a73e9 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 22:27:35 -0700 Subject: [PATCH 16/38] Bluetooth: hci_uart: Remove the manual protocol init message The init function for each HCI UART protocol prints the same on success and failure. This information is so generic, remove it and let the main HCI UART handling print it instead. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ath.c | 9 +-------- drivers/bluetooth/hci_bcsp.c | 9 +-------- drivers/bluetooth/hci_h4.c | 9 +-------- drivers/bluetooth/hci_h5.c | 9 +-------- drivers/bluetooth/hci_ldisc.c | 2 ++ drivers/bluetooth/hci_ll.c | 9 +-------- 6 files changed, 7 insertions(+), 40 deletions(-) diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 32c46cd40d85..54af95c95b07 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -218,14 +218,7 @@ static const struct hci_uart_proto athp = { int __init ath_init(void) { - int err = hci_uart_register_proto(&athp); - - if (!err) - BT_INFO("HCIATH3K protocol initialized"); - else - BT_ERR("HCIATH3K protocol registration failed"); - - return err; + return hci_uart_register_proto(&athp); } int __exit ath_deinit(void) diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 285fd0a97311..a467aa28009a 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -748,14 +748,7 @@ static const struct hci_uart_proto bcsp = { int __init bcsp_init(void) { - int err = hci_uart_register_proto(&bcsp); - - if (!err) - BT_INFO("HCI BCSP protocol initialized"); - else - BT_ERR("HCI BCSP protocol registration failed"); - - return err; + return hci_uart_register_proto(&bcsp); } int __exit bcsp_deinit(void) diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 7c5e68cb9959..81ad249fc44f 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -152,14 +152,7 @@ static const struct hci_uart_proto h4p = { int __init h4_init(void) { - 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; + return hci_uart_register_proto(&h4p); } int __exit h4_deinit(void) diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index de7da17ccdab..3455cecc9ecf 100644 --- a/drivers/bluetooth/hci_h5.c +++ b/drivers/bluetooth/hci_h5.c @@ -756,14 +756,7 @@ static const struct hci_uart_proto h5p = { int __init h5_init(void) { - int err = hci_uart_register_proto(&h5p); - - if (!err) - BT_INFO("HCI Three-wire UART (H5) protocol initialized"); - else - BT_ERR("HCI Three-wire UART (H5) protocol init failed"); - - return err; + return hci_uart_register_proto(&h5p); } int __exit h5_deinit(void) diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index ba3b988ce60a..19d0960489b6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -60,6 +60,8 @@ int hci_uart_register_proto(const struct hci_uart_proto *p) hup[p->id] = p; + BT_INFO("HCI UART protocol %s registered", p->name); + return 0; } diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c index c6a1aeb4e7fb..9ee24b075f79 100644 --- a/drivers/bluetooth/hci_ll.c +++ b/drivers/bluetooth/hci_ll.c @@ -518,14 +518,7 @@ static const struct hci_uart_proto llp = { int __init ll_init(void) { - int err = hci_uart_register_proto(&llp); - - if (!err) - BT_INFO("HCILL protocol initialized"); - else - BT_ERR("HCILL protocol registration failed"); - - return err; + return hci_uart_register_proto(&llp); } int __exit ll_deinit(void) From 788a675675b3ec5b64d232eae25e8e3e897cd31b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sat, 4 Apr 2015 22:36:04 -0700 Subject: [PATCH 17/38] Bluetooth: hci_uart: Update version number driver This version number is more cosmetic and for debugging purposes, but since there has been a few changes lately, increase it now. Two left-over and not used version constants that were never exposed anywhere are removed since they have no actual value. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_bcsp.c | 2 -- drivers/bluetooth/hci_h4.c | 2 -- drivers/bluetooth/hci_ldisc.c | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index a467aa28009a..dc8e3d4356a0 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -47,8 +47,6 @@ #include "hci_uart.h" -#define VERSION "0.3" - static bool txcrc = 1; static bool hciextn = 1; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 81ad249fc44f..07f5f7a21961 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -46,8 +46,6 @@ #include "hci_uart.h" -#define VERSION "1.2" - struct h4_struct { struct sk_buff *rx_skb; struct sk_buff_head txq; diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 19d0960489b6..b265abcb9eb6 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -46,7 +46,7 @@ #include "hci_uart.h" -#define VERSION "2.2" +#define VERSION "2.3" static const struct hci_uart_proto *hup[HCI_UART_MAX_PROTO]; From 4fba30f07f51617438835f75b58e37fb610b2d8d Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:10 -0700 Subject: [PATCH 18/38] Bluetooth: btbcm: Introduce generic Broadcom Bluetooth support The majority of Broadcom Bluetooth vendor commands are shared between USB and UART transports. This creates a separate module that eventually will hold all Broadcom specific commands, but for now just start with the commands to change the Bluetooth public address and check for the default address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 3 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btbcm.c | 99 ++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btbcm.h | 41 ++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 drivers/bluetooth/btbcm.c create mode 100644 drivers/bluetooth/btbcm.h diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index f8a41975c30d..4fbe067cd33a 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -2,6 +2,9 @@ menu "Bluetooth device drivers" depends on BT +config BT_BCM + tristate + config BT_HCIBTUSB tristate "HCI USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 51f9d0c18963..51c98546fa03 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -19,6 +19,7 @@ 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_BCM) += btbcm.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c new file mode 100644 index 000000000000..20c744a9a3f1 --- /dev/null +++ b/drivers/bluetooth/btbcm.c @@ -0,0 +1,99 @@ +/* + * + * Bluetooth support for Broadcom devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 + +#include +#include + +#include "btbcm.h" + +#define VERSION "0.1" + +#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) + +int btbcm_check_bdaddr(struct hci_dev *hdev) +{ + struct hci_rp_read_bd_addr *bda; + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + int err = PTR_ERR(skb); + BT_ERR("%s: BCM: Reading device address failed (%d)", + hdev->name, err); + return err; + } + + if (skb->len != sizeof(*bda)) { + BT_ERR("%s: BCM: Device address length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + bda = (struct hci_rp_read_bd_addr *)skb->data; + if (bda->status) { + BT_ERR("%s: BCM: Device address result failed (%02x)", + hdev->name, bda->status); + kfree_skb(skb); + return -bt_to_errno(bda->status); + } + + /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller + * with no configured address. + */ + if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { + BT_INFO("%s: BCM: Using default device address (%pMR)", + hdev->name, &bda->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_check_bdaddr); + +int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Change address command failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h new file mode 100644 index 000000000000..813f7e7e191d --- /dev/null +++ b/drivers/bluetooth/btbcm.h @@ -0,0 +1,41 @@ +/* + * + * Bluetooth support for Broadcom devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 + * + */ + +#if IS_ENABLED(CONFIG_BT_BCM) + +int btbcm_check_bdaddr(struct hci_dev *hdev); +int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); + +#else + +static inline int btbcm_check_bdaddr(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + return -EOPNOTSUPP; +} + +#endif From 1df1f5910825821ebac5eb1a74da2af8fdcaebf3 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:11 -0700 Subject: [PATCH 19/38] Bluetooth: btusb: Use generic functionality by Broadcom module The new Broadcom Bluetooth support module provides generic functionality for changing and checking the Bluetooth device address. Use these new features instead of keeping a duplicate in the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/btusb.c | 62 +++------------------------------------ 2 files changed, 5 insertions(+), 58 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 4fbe067cd33a..b593e5f766df 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -8,6 +8,7 @@ config BT_BCM config BT_HCIBTUSB tristate "HCI USB driver" depends on USB + select BT_BCM help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 6e4ff16e487b..08561ad7a638 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -29,6 +29,8 @@ #include #include +#include "btbcm.h" + #define VERSION "0.7" static bool disable_scofix; @@ -2418,8 +2420,6 @@ static const struct { { } }; -#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) - static int btusb_setup_bcm_patchram(struct hci_dev *hdev) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -2434,7 +2434,6 @@ static int btusb_setup_bcm_patchram(struct hci_dev *hdev) const char *hw_name = NULL; struct sk_buff *skb; struct hci_rp_read_local_version *ver; - struct hci_rp_read_bd_addr *bda; long ret; int i; @@ -2572,43 +2571,7 @@ reset_fw: hw_name ? : "BCM", (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - /* Read BD Address */ - skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_READ_BD_ADDR failed (%ld)", - hdev->name, ret); - goto done; - } - - if (skb->len != sizeof(*bda)) { - BT_ERR("%s: HCI_OP_READ_BD_ADDR event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; - goto done; - } - - bda = (struct hci_rp_read_bd_addr *)skb->data; - if (bda->status) { - BT_ERR("%s: HCI_OP_READ_BD_ADDR error status (%02x)", - hdev->name, bda->status); - kfree_skb(skb); - ret = -bt_to_errno(bda->status); - goto done; - } - - /* The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller - * with no configured address. - */ - if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) { - BT_INFO("%s: BCM: using default device address (%pMR)", - hdev->name, &bda->bdaddr); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); - } - - kfree_skb(skb); + btbcm_check_bdaddr(hdev); done: release_firmware(fw); @@ -2616,23 +2579,6 @@ done: return ret; } -static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) -{ - struct sk_buff *skb; - long ret; - - skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: BCM: Change address command failed (%ld)", - hdev->name, ret); - return ret; - } - kfree_skb(skb); - - return 0; -} - static int btusb_setup_bcm_apple(struct hci_dev *hdev) { struct sk_buff *skb; @@ -3056,7 +3002,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM_PATCHRAM) { hdev->setup = btusb_setup_bcm_patchram; - hdev->set_bdaddr = btusb_set_bdaddr_bcm; + hdev->set_bdaddr = btbcm_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } From 3e0ac12a1a610b4ab47282a25ee5945064228e35 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:12 -0700 Subject: [PATCH 20/38] Bluetooth: hci_uart: Use generic functionality from Broadcom module The new Broadcom Bluetooth support module provides generic functionality for changing and checking the Bluetooth device address. Use these new features instead of keeping a duplicate in the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_bcm.c | 17 ----------------- drivers/bluetooth/hci_ldisc.c | 4 +++- drivers/bluetooth/hci_uart.h | 4 ---- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index b593e5f766df..9f68e11c1671 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -111,6 +111,7 @@ config BT_HCIUART_INTEL config BT_HCIUART_BCM bool "Broadcom protocol support" depends on BT_HCIUART + select BT_BCM help The Broadcom protocol support enables Bluetooth HCI over serial port interface for Broadcom Bluetooth controllers. diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index 1a5817bda7c6..dd338fa77433 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -29,20 +29,3 @@ #include #include "hci_uart.h" - -int bcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) -{ - struct sk_buff *skb; - int err; - - skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: Change address command failed (%d)", - hdev->name, err); - return err; - } - kfree_skb(skb); - - return 0; -} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b265abcb9eb6..b182ddc43dfe 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -44,6 +44,7 @@ #include #include +#include "btbcm.h" #include "hci_uart.h" #define VERSION "2.3" @@ -299,7 +300,8 @@ static int hci_uart_setup(struct hci_dev *hdev) #endif #ifdef CONFIG_BT_HCIUART_BCM case 15: - hdev->set_bdaddr = bcm_set_bdaddr; + hdev->set_bdaddr = btbcm_set_bdaddr; + btbcm_check_bdaddr(hdev); break; #endif } diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 80e694a36143..ad03f57e794b 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -128,7 +128,3 @@ int h5_deinit(void); #ifdef CONFIG_BT_HCIUART_INTEL int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); #endif - -#ifdef CONFIG_BT_HCIUART_BCM -int bcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); -#endif From 1c8ba6d013c553bd13c50c139d652daac3348685 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:13 -0700 Subject: [PATCH 21/38] Bluetooth: btbcm: Add support for Broadcom controller setup To unify the controller setup of Broadcom devices between USB and UART transport, add the patchram download support into the Broadcom module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/btbcm.c | 258 ++++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btbcm.h | 13 ++ 3 files changed, 272 insertions(+) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 9f68e11c1671..0801649a3b41 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -4,6 +4,7 @@ menu "Bluetooth device drivers" config BT_BCM tristate + select FW_LOADER config BT_HCIBTUSB tristate "HCI USB driver" diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 20c744a9a3f1..17565ab610f4 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -22,6 +22,8 @@ */ #include +#include +#include #include #include @@ -93,6 +95,262 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); +static int btbcm_reset(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + int err = PTR_ERR(skb); + BT_ERR("%s: BCM: Reset failed (%d)", hdev->name, err); + return err; + } + kfree_skb(skb); + + return 0; +} + +static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: BCM: Reading local version info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: BCM: Local version length mismatch", hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + +static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: BCM: Read verbose config info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != 7) { + BT_ERR("%s: BCM: Verbose config length mismatch", hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + +static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + BT_ERR("%s: BCM: Read USB product info failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != 5) { + BT_ERR("%s: BCM: USB product length mismatch", hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + +static const struct { + u16 subver; + const char *name; +} bcm_subver_table[] = { + { 0x210b, "BCM43142A0" }, /* 001.001.011 */ + { 0x2112, "BCM4314A0" }, /* 001.001.018 */ + { 0x2118, "BCM20702A0" }, /* 001.001.024 */ + { 0x2126, "BCM4335A0" }, /* 001.001.038 */ + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ + { 0x230f, "BCM4354A2" }, /* 001.003.015 */ + { 0x4106, "BCM4335B0" }, /* 002.001.006 */ + { 0x410e, "BCM20702B0" }, /* 002.001.014 */ + { 0x6109, "BCM4335C0" }, /* 003.001.009 */ + { 0x610c, "BCM4354" }, /* 003.001.012 */ + { } +}; + +int btbcm_setup_patchram(struct hci_dev *hdev) +{ + const struct hci_command_hdr *cmd; + const struct firmware *fw; + const u8 *fw_ptr; + size_t fw_size; + char fw_name[64]; + u16 opcode, subver, rev, pid, vid; + const char *hw_name = NULL; + struct sk_buff *skb; + struct hci_rp_read_local_version *ver; + int i, err; + + /* Reset */ + err = btbcm_reset(hdev); + if (err) + return err; + + /* Read Local Version Info */ + skb = btbcm_read_local_version(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + ver = (struct hci_rp_read_local_version *)skb->data; + rev = le16_to_cpu(ver->hci_rev); + subver = le16_to_cpu(ver->lmp_subver); + kfree_skb(skb); + + /* Read Verbose Config Version Info */ + skb = btbcm_read_verbose_config(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); + kfree_skb(skb); + + /* Read USB Product Info */ + skb = btbcm_read_usb_product(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + vid = get_unaligned_le16(skb->data + 1); + pid = get_unaligned_le16(skb->data + 3); + kfree_skb(skb); + + for (i = 0; bcm_subver_table[i].name; i++) { + if (subver == bcm_subver_table[i].subver) { + hw_name = bcm_subver_table[i].name; + break; + } + } + + BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, + hw_name ? : "BCM", (subver & 0x7000) >> 13, + (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); + + snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd", + hw_name ? : "BCM", vid, pid); + + err = request_firmware(&fw, fw_name, &hdev->dev); + if (err < 0) { + BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); + return 0; + } + + /* Start Download */ + skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: Download Minidrv command failed (%d)", + hdev->name, err); + goto reset; + } + kfree_skb(skb); + + /* 50 msec delay after Download Minidrv completes */ + msleep(50); + + fw_ptr = fw->data; + fw_size = fw->size; + + while (fw_size >= sizeof(*cmd)) { + const u8 *cmd_param; + + cmd = (struct hci_command_hdr *)fw_ptr; + fw_ptr += sizeof(*cmd); + fw_size -= sizeof(*cmd); + + if (fw_size < cmd->plen) { + BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, + fw_name); + err = -EINVAL; + goto reset; + } + + cmd_param = fw_ptr; + fw_ptr += cmd->plen; + fw_size -= cmd->plen; + + opcode = le16_to_cpu(cmd->opcode); + + skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: BCM: patch command %04x failed (%d)", + hdev->name, opcode, err); + goto reset; + } + kfree_skb(skb); + } + + /* 250 msec delay after Launch Ram completes */ + msleep(250); + +reset: + /* Reset */ + err = btbcm_reset(hdev); + if (err) + goto done; + + /* Read Local Version Info */ + skb = btbcm_read_local_version(hdev); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + goto done; + } + + ver = (struct hci_rp_read_local_version *)skb->data; + rev = le16_to_cpu(ver->hci_rev); + subver = le16_to_cpu(ver->lmp_subver); + kfree_skb(skb); + + BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, + hw_name ? : "BCM", (subver & 0x7000) >> 13, + (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); + + btbcm_check_bdaddr(hdev); + +done: + release_firmware(fw); + + return err; +} +EXPORT_SYMBOL_GPL(btbcm_setup_patchram); + +int btbcm_setup_apple(struct hci_dev *hdev) +{ + struct sk_buff *skb; + + /* Read Verbose Config Version Info */ + skb = btbcm_read_verbose_config(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1], + get_unaligned_le16(skb->data + 5)); + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_setup_apple); + MODULE_AUTHOR("Marcel Holtmann "); MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION); MODULE_VERSION(VERSION); diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index 813f7e7e191d..34268ae3eb46 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h @@ -26,6 +26,9 @@ int btbcm_check_bdaddr(struct hci_dev *hdev); int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); +int btbcm_setup_patchram(struct hci_dev *hdev); +int btbcm_setup_apple(struct hci_dev *hdev); + #else static inline int btbcm_check_bdaddr(struct hci_dev *hdev) @@ -38,4 +41,14 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) return -EOPNOTSUPP; } +static inline int btbcm_setup_patchram(struct hci_dev *hdev) +{ + return 0; +} + +static inline int btbcm_setup_apple(struct hci_dev *hdev) +{ + return 0; +} + #endif From c2bfb10092ece07f9e9cf5096cfeec0ef92a97c5 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:14 -0700 Subject: [PATCH 22/38] Bluetooth: btusb: Add option for Broadcom protocol support With the generic Broadcom Bluetooth support module, it is possible to turn support for firmware and patchram download into an optional feature. To keep backwards compatibility with previous kernel configurations, the new option defaults to enabled. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 12 ++- drivers/bluetooth/btusb.c | 211 +------------------------------------- 2 files changed, 15 insertions(+), 208 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 0801649a3b41..ea76031eb93f 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -9,7 +9,6 @@ config BT_BCM config BT_HCIBTUSB tristate "HCI USB driver" depends on USB - select BT_BCM help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with @@ -18,6 +17,17 @@ 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_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_HCIBTSDIO tristate "HCI SDIO driver" depends on MMC diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 08561ad7a638..53275c55c782 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -24,7 +24,6 @@ #include #include #include -#include #include #include @@ -2403,210 +2402,6 @@ static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, return 0; } -static const struct { - u16 subver; - const char *name; -} bcm_subver_table[] = { - { 0x210b, "BCM43142A0" }, /* 001.001.011 */ - { 0x2112, "BCM4314A0" }, /* 001.001.018 */ - { 0x2118, "BCM20702A0" }, /* 001.001.024 */ - { 0x2126, "BCM4335A0" }, /* 001.001.038 */ - { 0x220e, "BCM20702A1" }, /* 001.002.014 */ - { 0x230f, "BCM4354A2" }, /* 001.003.015 */ - { 0x4106, "BCM4335B0" }, /* 002.001.006 */ - { 0x410e, "BCM20702B0" }, /* 002.001.014 */ - { 0x6109, "BCM4335C0" }, /* 003.001.009 */ - { 0x610c, "BCM4354" }, /* 003.001.012 */ - { } -}; - -static int btusb_setup_bcm_patchram(struct hci_dev *hdev) -{ - struct btusb_data *data = hci_get_drvdata(hdev); - struct usb_device *udev = data->udev; - char fw_name[64]; - const struct firmware *fw; - const u8 *fw_ptr; - size_t fw_size; - const struct hci_command_hdr *cmd; - const u8 *cmd_param; - u16 opcode, subver, rev; - const char *hw_name = NULL; - struct sk_buff *skb; - struct hci_rp_read_local_version *ver; - long ret; - int i; - - /* Reset */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); - return ret; - } - kfree_skb(skb); - - /* Read Local Version Info */ - skb = btusb_read_local_version(hdev); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - ver = (struct hci_rp_read_local_version *)skb->data; - rev = le16_to_cpu(ver->hci_rev); - subver = le16_to_cpu(ver->lmp_subver); - kfree_skb(skb); - - /* Read Verbose Config Version Info */ - skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: BCM: Read Verbose Version failed (%ld)", - hdev->name, ret); - return ret; - } - - if (skb->len != 7) { - BT_ERR("%s: BCM: Read Verbose Version event length mismatch", - hdev->name); - kfree_skb(skb); - return -EIO; - } - - BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); - kfree_skb(skb); - - for (i = 0; bcm_subver_table[i].name; i++) { - if (subver == bcm_subver_table[i].subver) { - hw_name = bcm_subver_table[i].name; - break; - } - } - - BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, - hw_name ? : "BCM", (subver & 0x7000) >> 13, - (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - - snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd", - hw_name ? : "BCM", - le16_to_cpu(udev->descriptor.idVendor), - le16_to_cpu(udev->descriptor.idProduct)); - - ret = request_firmware(&fw, fw_name, &hdev->dev); - if (ret < 0) { - BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); - return 0; - } - - /* Start Download */ - skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: BCM: Download Minidrv command failed (%ld)", - hdev->name, ret); - goto reset_fw; - } - kfree_skb(skb); - - /* 50 msec delay after Download Minidrv completes */ - msleep(50); - - fw_ptr = fw->data; - fw_size = fw->size; - - while (fw_size >= sizeof(*cmd)) { - cmd = (struct hci_command_hdr *)fw_ptr; - fw_ptr += sizeof(*cmd); - fw_size -= sizeof(*cmd); - - if (fw_size < cmd->plen) { - BT_ERR("%s: BCM: patch %s is corrupted", - hdev->name, fw_name); - ret = -EINVAL; - goto reset_fw; - } - - cmd_param = fw_ptr; - fw_ptr += cmd->plen; - fw_size -= cmd->plen; - - opcode = le16_to_cpu(cmd->opcode); - - skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: BCM: patch command %04x failed (%ld)", - hdev->name, opcode, ret); - goto reset_fw; - } - kfree_skb(skb); - } - - /* 250 msec delay after Launch Ram completes */ - msleep(250); - -reset_fw: - /* Reset */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); - goto done; - } - kfree_skb(skb); - - /* Read Local Version Info */ - skb = btusb_read_local_version(hdev); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - goto done; - } - - ver = (struct hci_rp_read_local_version *)skb->data; - rev = le16_to_cpu(ver->hci_rev); - subver = le16_to_cpu(ver->lmp_subver); - kfree_skb(skb); - - BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, - hw_name ? : "BCM", (subver & 0x7000) >> 13, - (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - - btbcm_check_bdaddr(hdev); - -done: - release_firmware(fw); - - return ret; -} - -static int btusb_setup_bcm_apple(struct hci_dev *hdev) -{ - struct sk_buff *skb; - int err; - - /* Read Verbose Config Version Info */ - skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: BCM: Read Verbose Version failed (%d)", - hdev->name, err); - return err; - } - - if (skb->len != 7) { - BT_ERR("%s: BCM: Read Verbose Version event length mismatch", - hdev->name); - kfree_skb(skb); - return -EIO; - } - - BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1], - get_unaligned_le16(skb->data + 5)); - kfree_skb(skb); - - return 0; -} - static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, const bdaddr_t *bdaddr) { @@ -3000,16 +2795,18 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM92035) hdev->setup = btusb_setup_bcm92035; +#ifdef CONFIG_BT_HCIBTUSB_BCM if (id->driver_info & BTUSB_BCM_PATCHRAM) { - hdev->setup = btusb_setup_bcm_patchram; + hdev->setup = btbcm_setup_patchram; hdev->set_bdaddr = btbcm_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } if (id->driver_info & BTUSB_BCM_APPLE) { - hdev->setup = btusb_setup_bcm_apple; + hdev->setup = btbcm_setup_apple; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } +#endif if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; From 941521e24fa8019b94eedecdd0b39942b0060399 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:15 -0700 Subject: [PATCH 23/38] Bluetooth: btusb: Move Broadcom quirk setting into support module The quirks for Broadcom devices can be set from the setup function and to keep the code simple, just move them into Broadcom support module. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btbcm.c | 4 ++++ drivers/bluetooth/btusb.c | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index 17565ab610f4..c90401261ab4 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -327,6 +327,8 @@ reset: btbcm_check_bdaddr(hdev); + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + done: release_firmware(fw); @@ -347,6 +349,8 @@ int btbcm_setup_apple(struct hci_dev *hdev) get_unaligned_le16(skb->data + 5)); kfree_skb(skb); + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + return 0; } EXPORT_SYMBOL_GPL(btbcm_setup_apple); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 53275c55c782..ea7c726adcb1 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -2799,13 +2799,10 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BCM_PATCHRAM) { hdev->setup = btbcm_setup_patchram; hdev->set_bdaddr = btbcm_set_bdaddr; - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } - if (id->driver_info & BTUSB_BCM_APPLE) { + if (id->driver_info & BTUSB_BCM_APPLE) hdev->setup = btbcm_setup_apple; - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); - } #endif if (id->driver_info & BTUSB_INTEL) { From 34dced9bd6baf677fa6cfbfb65f002601a10d1e7 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:16 -0700 Subject: [PATCH 24/38] Bluetooth: btusb: Update version number of the module The version number is cosmetic, but pretty handy for debugging purposes and since the Broadcom protocol support is now optional, just increase it to indicate the difference. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btusb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index ea7c726adcb1..8dae3daf821d 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -30,7 +30,7 @@ #include "btbcm.h" -#define VERSION "0.7" +#define VERSION "0.8" static bool disable_scofix; static bool force_scofix; From 6ae4fddf78c11dedfb13a518a9050e9b265529ca Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:17 -0700 Subject: [PATCH 25/38] Bluetooth: hci_uart: Move setup callback into different location The setup callback got wrongly inserted between the enqueue and dequeue callbacks. Move it to a better location. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index ad03f57e794b..466798acf049 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -61,9 +61,9 @@ struct hci_uart_proto { 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 (*recv)(struct hci_uart *hu, const void *data, int len); int (*enqueue)(struct hci_uart *hu, struct sk_buff *skb); - int (*setup)(struct hci_uart *hu); struct sk_buff *(*dequeue)(struct hci_uart *hu); }; From bdd8818e05da187cd028f64ef2c0a2a6a582bcb1 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:18 -0700 Subject: [PATCH 26/38] Bluetooth: hci_uart: Add protocol support for Broadcom UART devices This adds the protocol support for Broadcom based UART devices to enable firmware and patchram download procedure. It is a pretty straight forward H:4 driver with the exception of actually having its own setup and address configuration callbacks. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_bcm.c | 115 ++++++++++++++++++++++++++++++++++ drivers/bluetooth/hci_ldisc.c | 6 ++ drivers/bluetooth/hci_uart.h | 5 ++ 4 files changed, 127 insertions(+) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index ea76031eb93f..93351b91bbb4 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -122,6 +122,7 @@ config BT_HCIUART_INTEL config BT_HCIUART_BCM bool "Broadcom protocol support" depends on BT_HCIUART + select BT_HCIUART_H4 select BT_BCM help The Broadcom protocol support enables Bluetooth HCI over serial diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index dd338fa77433..fe1905c4beb2 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -28,4 +28,119 @@ #include #include +#include "btbcm.h" #include "hci_uart.h" + +struct bcm_data { + struct sk_buff *rx_skb; + struct sk_buff_head txq; +}; + +static int bcm_open(struct hci_uart *hu) +{ + struct bcm_data *bcm; + + BT_DBG("hu %p", hu); + + bcm = kzalloc(sizeof(*bcm), GFP_KERNEL); + if (!bcm) + return -ENOMEM; + + skb_queue_head_init(&bcm->txq); + + hu->priv = bcm; + return 0; +} + +static int bcm_close(struct hci_uart *hu) +{ + struct bcm_data *bcm = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&bcm->txq); + kfree_skb(bcm->rx_skb); + kfree(bcm); + + hu->priv = NULL; + return 0; +} + +static int bcm_flush(struct hci_uart *hu) +{ + struct bcm_data *bcm = hu->priv; + + BT_DBG("hu %p", hu); + + skb_queue_purge(&bcm->txq); + + return 0; +} + +static int bcm_setup(struct hci_uart *hu) +{ + BT_DBG("hu %p", hu); + + hu->hdev->set_bdaddr = btbcm_set_bdaddr; + + return btbcm_setup_patchram(hu->hdev); +} + +static int bcm_recv(struct hci_uart *hu, const void *data, int count) +{ + struct bcm_data *bcm = hu->priv; + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + + bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count); + if (IS_ERR(bcm->rx_skb)) { + int err = PTR_ERR(bcm->rx_skb); + BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); + return err; + } + + return count; +} + +static int bcm_enqueue(struct hci_uart *hu, struct sk_buff *skb) +{ + struct bcm_data *bcm = hu->priv; + + BT_DBG("hu %p skb %p", hu, skb); + + /* Prepend skb with frame type */ + memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1); + skb_queue_tail(&bcm->txq, skb); + + return 0; +} + +static struct sk_buff *bcm_dequeue(struct hci_uart *hu) +{ + struct bcm_data *bcm = hu->priv; + + return skb_dequeue(&bcm->txq); +} + +static const struct hci_uart_proto bcm_proto = { + .id = HCI_UART_BCM, + .name = "BCM", + .open = bcm_open, + .close = bcm_close, + .flush = bcm_flush, + .setup = bcm_setup, + .recv = bcm_recv, + .enqueue = bcm_enqueue, + .dequeue = bcm_dequeue, +}; + +int __init bcm_init(void) +{ + return hci_uart_register_proto(&bcm_proto); +} + +int __exit bcm_deinit(void) +{ + return hci_uart_unregister_proto(&bcm_proto); +} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index b182ddc43dfe..a106c3e201e3 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -679,6 +679,9 @@ static int __init hci_uart_init(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_init(); #endif +#ifdef CONFIG_BT_HCIUART_BCM + bcm_init(); +#endif return 0; } @@ -702,6 +705,9 @@ static void __exit hci_uart_exit(void) #ifdef CONFIG_BT_HCIUART_3WIRE h5_deinit(); #endif +#ifdef CONFIG_BT_HCIUART_BCM + bcm_deinit(); +#endif /* Release tty registration of line discipline */ err = tty_unregister_ldisc(N_HCI); diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 466798acf049..a3108abce5d3 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -128,3 +128,8 @@ int h5_deinit(void); #ifdef CONFIG_BT_HCIUART_INTEL int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); #endif + +#ifdef CONFIG_BT_HCIUART_BCM +int bcm_init(void); +int bcm_deinit(void); +#endif From 9a0bb57d2d08f1923aeef3af1877ec0b6f3209ba Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 22:52:19 -0700 Subject: [PATCH 27/38] Bluetooth: btbcm: Add firmware table for UART based devices The Broadcom UART based devices seem to use a little bit different firmare naming prefix. So add a separate table for these devices. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btbcm.c | 60 ++++++++++++++++++++++++++++----------- 1 file changed, 43 insertions(+), 17 deletions(-) diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index c90401261ab4..d0741f3ed7ec 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c @@ -174,7 +174,15 @@ static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) static const struct { u16 subver; const char *name; -} bcm_subver_table[] = { +} bcm_uart_subver_table[] = { + { 0x410e, "BCM43341B0" }, /* 002.001.014 */ + { } +}; + +static const struct { + u16 subver; + const char *name; +} bcm_usb_subver_table[] = { { 0x210b, "BCM43142A0" }, /* 001.001.011 */ { 0x2112, "BCM4314A0" }, /* 001.001.018 */ { 0x2118, "BCM20702A0" }, /* 001.001.024 */ @@ -224,29 +232,47 @@ int btbcm_setup_patchram(struct hci_dev *hdev) BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]); kfree_skb(skb); - /* Read USB Product Info */ - skb = btbcm_read_usb_product(hdev); - if (IS_ERR(skb)) - return PTR_ERR(skb); - - vid = get_unaligned_le16(skb->data + 1); - pid = get_unaligned_le16(skb->data + 3); - kfree_skb(skb); - - for (i = 0; bcm_subver_table[i].name; i++) { - if (subver == bcm_subver_table[i].subver) { - hw_name = bcm_subver_table[i].name; - break; + switch ((rev & 0xf000) >> 12) { + case 0: + for (i = 0; bcm_uart_subver_table[i].name; i++) { + if (subver == bcm_uart_subver_table[i].subver) { + hw_name = bcm_uart_subver_table[i].name; + break; + } } + + snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd", + hw_name ? : "BCM"); + break; + case 1: + case 2: + /* Read USB Product Info */ + skb = btbcm_read_usb_product(hdev); + if (IS_ERR(skb)) + return PTR_ERR(skb); + + vid = get_unaligned_le16(skb->data + 1); + pid = get_unaligned_le16(skb->data + 3); + kfree_skb(skb); + + for (i = 0; bcm_usb_subver_table[i].name; i++) { + if (subver == bcm_usb_subver_table[i].subver) { + hw_name = bcm_usb_subver_table[i].name; + break; + } + } + + snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd", + hw_name ? : "BCM", vid, pid); + break; + default: + return 0; } BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name, hw_name ? : "BCM", (subver & 0x7000) >> 13, (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); - snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd", - hw_name ? : "BCM", vid, pid); - err = request_firmware(&fw, fw_name, &hdev->dev); if (err < 0) { BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); From 79b8df9362e8bd1951e1fddbd65ca87af8df52c8 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Sun, 5 Apr 2015 23:44:59 -0700 Subject: [PATCH 28/38] Bluetooth: hci_uart: Provide generic H:4 receive framework Future H:4 based UART drivers require custom packet types and custom receive functions. To support this, extended the h4_recv_buf function with a packet definition table. For the default H:4 packets types of ACL data, SCO data and events, provide helpers to reduce the amount of code duplication. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/hci_ath.c | 9 ++- drivers/bluetooth/hci_bcm.c | 9 ++- drivers/bluetooth/hci_h4.c | 139 ++++++++++++++++++----------------- drivers/bluetooth/hci_uart.h | 33 ++++++++- 4 files changed, 120 insertions(+), 70 deletions(-) diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 54af95c95b07..1b3f8647ea2f 100644 --- a/drivers/bluetooth/hci_ath.c +++ b/drivers/bluetooth/hci_ath.c @@ -190,12 +190,19 @@ static struct sk_buff *ath_dequeue(struct hci_uart *hu) return skb_dequeue(&ath->txq); } +static const struct h4_recv_pkt ath_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, +}; + /* Recv data */ static int ath_recv(struct hci_uart *hu, const void *data, int count) { struct ath_struct *ath = hu->priv; - ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count); + ath->rx_skb = h4_recv_buf(hu->hdev, ath->rx_skb, data, count, + ath_recv_pkts, ARRAY_SIZE(ath_recv_pkts)); if (IS_ERR(ath->rx_skb)) { int err = PTR_ERR(ath->rx_skb); BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); diff --git a/drivers/bluetooth/hci_bcm.c b/drivers/bluetooth/hci_bcm.c index fe1905c4beb2..1ec0b4a5ffa6 100644 --- a/drivers/bluetooth/hci_bcm.c +++ b/drivers/bluetooth/hci_bcm.c @@ -86,6 +86,12 @@ static int bcm_setup(struct hci_uart *hu) return btbcm_setup_patchram(hu->hdev); } +static const struct h4_recv_pkt bcm_recv_pkts[] = { + { H4_RECV_ACL, .recv = hci_recv_frame }, + { H4_RECV_SCO, .recv = hci_recv_frame }, + { H4_RECV_EVENT, .recv = hci_recv_frame }, +}; + static int bcm_recv(struct hci_uart *hu, const void *data, int count) { struct bcm_data *bcm = hu->priv; @@ -93,7 +99,8 @@ static int bcm_recv(struct hci_uart *hu, const void *data, int count) if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) return -EUNATCH; - bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count); + bcm->rx_skb = h4_recv_buf(hu->hdev, bcm->rx_skb, data, count, + bcm_recv_pkts, ARRAY_SIZE(bcm_recv_pkts)); if (IS_ERR(bcm->rx_skb)) { int err = PTR_ERR(bcm->rx_skb); BT_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index 07f5f7a21961..f7190f01e135 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -113,6 +114,12 @@ static int h4_enqueue(struct hci_uart *hu, struct sk_buff *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 }, +}; + /* Recv data */ static int h4_recv(struct hci_uart *hu, const void *data, int count) { @@ -121,7 +128,8 @@ static int h4_recv(struct hci_uart *hu, const void *data, int count) if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) return -EUNATCH; - h4->rx_skb = h4_recv_buf(hu->hdev, h4->rx_skb, data, 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_ERR("%s: Frame reassembly failed (%d)", hu->hdev->name, err); @@ -159,96 +167,93 @@ int __exit h4_deinit(void) } struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, - const unsigned char *buffer, int count) + const unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count) { while (count) { - int len; + int i, len; if (!skb) { - switch (buffer[0]) { - case HCI_ACLDATA_PKT: - skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, + 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); - bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT; - bt_cb(skb)->expect = HCI_ACL_HDR_SIZE; + bt_cb(skb)->pkt_type = (&pkts[i])->type; + bt_cb(skb)->expect = (&pkts[i])->hlen; break; - case HCI_SCODATA_PKT: - skb = bt_skb_alloc(HCI_MAX_SCO_SIZE, - GFP_ATOMIC); - if (!skb) - return ERR_PTR(-ENOMEM); - - bt_cb(skb)->pkt_type = HCI_SCODATA_PKT; - bt_cb(skb)->expect = HCI_SCO_HDR_SIZE; - break; - case HCI_EVENT_PKT: - skb = bt_skb_alloc(HCI_MAX_EVENT_SIZE, - GFP_ATOMIC); - if (!skb) - return ERR_PTR(-ENOMEM); - - bt_cb(skb)->pkt_type = HCI_EVENT_PKT; - bt_cb(skb)->expect = HCI_EVENT_HDR_SIZE; - break; - default: - return ERR_PTR(-EILSEQ); } + /* Check for invalid packet type */ + if (!skb) + return ERR_PTR(-EILSEQ); + count -= 1; buffer += 1; } - len = min_t(uint, bt_cb(skb)->expect, count); + len = min_t(uint, bt_cb(skb)->expect - skb->len, count); memcpy(skb_put(skb, len), buffer, len); count -= len; buffer += len; - bt_cb(skb)->expect -= len; - switch (bt_cb(skb)->pkt_type) { - case HCI_ACLDATA_PKT: - if (skb->len == HCI_ACL_HDR_SIZE) { - __le16 dlen = hci_acl_hdr(skb)->dlen; + /* Check for partial packet */ + if (skb->len < bt_cb(skb)->expect) + continue; - /* Complete ACL header */ - bt_cb(skb)->expect = __le16_to_cpu(dlen); - - if (skb_tailroom(skb) < bt_cb(skb)->expect) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - } - break; - case HCI_SCODATA_PKT: - if (skb->len == HCI_SCO_HDR_SIZE) { - /* Complete SCO header */ - bt_cb(skb)->expect = hci_sco_hdr(skb)->dlen; - - if (skb_tailroom(skb) < bt_cb(skb)->expect) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - } - break; - case HCI_EVENT_PKT: - if (skb->len == HCI_EVENT_HDR_SIZE) { - /* Complete event header */ - bt_cb(skb)->expect = hci_event_hdr(skb)->plen; - - if (skb_tailroom(skb) < bt_cb(skb)->expect) { - kfree_skb(skb); - return ERR_PTR(-EMSGSIZE); - } - } - break; + for (i = 0; i < pkts_count; i++) { + if (bt_cb(skb)->pkt_type == (&pkts[i])->type) + break; } - if (bt_cb(skb)->expect == 0) { + 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 */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + break; + case 1: + /* Single octet variable length */ + dlen = skb->data[(&pkts[i])->loff]; + bt_cb(skb)->expect += 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); + bt_cb(skb)->expect += 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); + } + } else { /* Complete frame */ - hci_recv_frame(hdev, skb); + (&pkts[i])->recv(hdev, skb); skb = NULL; } } diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index a3108abce5d3..d1fa6263f7c2 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -101,8 +101,39 @@ int hci_uart_init_ready(struct hci_uart *hu); 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 unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count); #endif #ifdef CONFIG_BT_HCIUART_BCSP From 48f0ed1bb68589db5d6566bd3cd28ec675feaf2f Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 6 Apr 2015 00:52:11 -0700 Subject: [PATCH 29/38] Bluetooth: btintel: Introduce generic Intel Bluetooth support The majority of Intel Bluetooth vendor commands are shared between USB and UART transports. This creates a separate module that eventually will hold all Intel specific commands, but for now just start with the commands to change the Bluetooth public address and check for the default address. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 3 ++ drivers/bluetooth/Makefile | 1 + drivers/bluetooth/btintel.c | 101 ++++++++++++++++++++++++++++++++++++ drivers/bluetooth/btintel.h | 41 +++++++++++++++ 4 files changed, 146 insertions(+) create mode 100644 drivers/bluetooth/btintel.c create mode 100644 drivers/bluetooth/btintel.h diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 93351b91bbb4..e4aff8ca7870 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -2,6 +2,9 @@ menu "Bluetooth device drivers" depends on BT +config BT_INTEL + tristate + config BT_BCM tristate select FW_LOADER diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 51c98546fa03..dd0d9c40b999 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_BT_HCIBTUART) += btuart_cs.o obj-$(CONFIG_BT_HCIBTUSB) += btusb.o obj-$(CONFIG_BT_HCIBTSDIO) += btsdio.o +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 diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c new file mode 100644 index 000000000000..2d43d4279b00 --- /dev/null +++ b/drivers/bluetooth/btintel.c @@ -0,0 +1,101 @@ +/* + * + * Bluetooth support for Intel devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 + +#include +#include + +#include "btintel.h" + +#define VERSION "0.1" + +#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) + +int btintel_check_bdaddr(struct hci_dev *hdev) +{ + struct hci_rp_read_bd_addr *bda; + struct sk_buff *skb; + + skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, + HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + int err = PTR_ERR(skb); + BT_ERR("%s: Reading Intel device address failed (%d)", + hdev->name, err); + return err; + } + + if (skb->len != sizeof(*bda)) { + BT_ERR("%s: Intel device address length mismatch", hdev->name); + kfree_skb(skb); + return -EIO; + } + + bda = (struct hci_rp_read_bd_addr *)skb->data; + if (bda->status) { + BT_ERR("%s: Intel device address result failed (%02x)", + hdev->name, bda->status); + kfree_skb(skb); + return -bt_to_errno(bda->status); + } + + /* For some Intel based controllers, the default Bluetooth device + * address 00:03:19:9E:8B:00 can be found. These controllers are + * fully operational, but have the danger of duplicate addresses + * and that in turn can cause problems with Bluetooth operation. + */ + if (!bacmp(&bda->bdaddr, BDADDR_INTEL)) { + BT_ERR("%s: Found Intel default device address (%pMR)", + hdev->name, &bda->bdaddr); + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); + } + + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_check_bdaddr); + +int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + struct sk_buff *skb; + int err; + + skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + if (IS_ERR(skb)) { + err = PTR_ERR(skb); + BT_ERR("%s: Changing Intel device address failed (%d)", + hdev->name, err); + return err; + } + kfree_skb(skb); + + return 0; +} +EXPORT_SYMBOL_GPL(btintel_set_bdaddr); + +MODULE_AUTHOR("Marcel Holtmann "); +MODULE_DESCRIPTION("Bluetooth support for Intel devices ver " VERSION); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h new file mode 100644 index 000000000000..20be247d2ff6 --- /dev/null +++ b/drivers/bluetooth/btintel.h @@ -0,0 +1,41 @@ +/* + * + * Bluetooth support for Intel devices + * + * Copyright (C) 2015 Intel Corporation + * + * + * 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 + * + */ + +#if IS_ENABLED(CONFIG_BT_INTEL) + +int btintel_check_bdaddr(struct hci_dev *hdev); +int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); + +#else + +static inline int btintel_check_bdaddr(struct hci_dev *hdev) +{ + return -EOPNOTSUPP; +} + +static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) +{ + return -EOPNOTSUPP; +} + +#endif From 4185a0f5d0431bf91ea1ec202fdf12e6e3b73c46 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 6 Apr 2015 00:52:12 -0700 Subject: [PATCH 30/38] Bluetooth: btusb: Use generic Intel support for address support The Bluetooth address handling for Intel devices is provided by a generic module now. Start using that module instead of relying it being included in the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/btusb.c | 79 +++++---------------------------------- 2 files changed, 10 insertions(+), 70 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index e4aff8ca7870..b50fe3361659 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -12,6 +12,7 @@ config BT_BCM 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 diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8dae3daf821d..5798aec44824 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -28,6 +28,7 @@ #include #include +#include "btintel.h" #include "btbcm.h" #define VERSION "0.8" @@ -1533,51 +1534,6 @@ static int btusb_setup_intel_patching(struct hci_dev *hdev, return 0; } -#define BDADDR_INTEL (&(bdaddr_t) {{0x00, 0x8b, 0x9e, 0x19, 0x03, 0x00}}) - -static int btusb_check_bdaddr_intel(struct hci_dev *hdev) -{ - struct sk_buff *skb; - struct hci_rp_read_bd_addr *rp; - - skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("%s reading Intel device address failed (%ld)", - hdev->name, PTR_ERR(skb)); - return PTR_ERR(skb); - } - - if (skb->len != sizeof(*rp)) { - BT_ERR("%s Intel device address length mismatch", hdev->name); - kfree_skb(skb); - return -EIO; - } - - rp = (struct hci_rp_read_bd_addr *)skb->data; - if (rp->status) { - BT_ERR("%s Intel device address result failed (%02x)", - hdev->name, rp->status); - kfree_skb(skb); - return -bt_to_errno(rp->status); - } - - /* For some Intel based controllers, the default Bluetooth device - * address 00:03:19:9E:8B:00 can be found. These controllers are - * fully operational, but have the danger of duplicate addresses - * and that in turn can cause problems with Bluetooth operation. - */ - if (!bacmp(&rp->bdaddr, BDADDR_INTEL)) { - BT_ERR("%s found Intel default device address (%pMR)", - hdev->name, &rp->bdaddr); - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); - } - - kfree_skb(skb); - - return 0; -} - static int btusb_setup_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1650,7 +1606,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel device is already patched. patch num: %02x", hdev->name, ver->fw_patch_num); kfree_skb(skb); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; } @@ -1663,7 +1619,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) fw = btusb_setup_intel_get_fw(hdev, ver); if (!fw) { kfree_skb(skb); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; } fw_ptr = fw->data; @@ -1744,7 +1700,7 @@ static int btusb_setup_intel(struct hci_dev *hdev) BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", hdev->name); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; exit_mfg_disable: @@ -1760,7 +1716,7 @@ exit_mfg_disable: BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; exit_mfg_deactivate: @@ -1781,7 +1737,7 @@ exit_mfg_deactivate: BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", hdev->name); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; } @@ -2057,7 +2013,7 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) if (ver->fw_variant == 0x23) { kfree_skb(skb); clear_bit(BTUSB_BOOTLOADER, &data->flags); - btusb_check_bdaddr_intel(hdev); + btintel_check_bdaddr(hdev); return 0; } @@ -2341,23 +2297,6 @@ static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code) kfree_skb(skb); } -static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr) -{ - struct sk_buff *skb; - long ret; - - skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: changing Intel device address failed (%ld)", - hdev->name, ret); - return ret; - } - kfree_skb(skb); - - return 0; -} - static int btusb_shutdown_intel(struct hci_dev *hdev) { struct sk_buff *skb; @@ -2808,7 +2747,7 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; hdev->shutdown = btusb_shutdown_intel; - hdev->set_bdaddr = btusb_set_bdaddr_intel; + hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); } @@ -2817,7 +2756,7 @@ static int btusb_probe(struct usb_interface *intf, hdev->send = btusb_send_frame_intel; hdev->setup = btusb_setup_intel_new; hdev->hw_error = btusb_hw_error_intel; - hdev->set_bdaddr = btusb_set_bdaddr_intel; + hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } From 59a077c4792e2226b8a95430c0f17d1098939647 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 6 Apr 2015 00:52:13 -0700 Subject: [PATCH 31/38] Bluetooth: btusb: Move Intel command structs into its own header Since the Intel Bluetooth support has its own header, it makes sense to move all command structs into it. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.h | 33 +++++++++++++++++++++++++++++++++ drivers/bluetooth/btusb.c | 33 --------------------------------- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 20be247d2ff6..d1581150679a 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -21,6 +21,39 @@ * */ +struct intel_version { + u8 status; + u8 hw_platform; + u8 hw_variant; + u8 hw_revision; + u8 fw_variant; + u8 fw_revision; + u8 fw_build_num; + u8 fw_build_ww; + u8 fw_build_yy; + u8 fw_patch_num; +} __packed; + +struct intel_boot_params { + __u8 status; + __u8 otp_format; + __u8 otp_content; + __u8 otp_patch; + __le16 dev_revid; + __u8 secure_boot; + __u8 key_from_hdr; + __u8 key_type; + __u8 otp_lock; + __u8 api_lock; + __u8 debug_lock; + bdaddr_t otp_bdaddr; + __u8 min_fw_build_nn; + __u8 min_fw_build_cw; + __u8 min_fw_build_yy; + __u8 limited_cce; + __u8 unlocked_state; +} __packed; + #if IS_ENABLED(CONFIG_BT_INTEL) int btintel_check_bdaddr(struct hci_dev *hdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 5798aec44824..c06ceec13dbb 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1345,39 +1345,6 @@ static int btusb_setup_csr(struct hci_dev *hdev) return ret; } -struct intel_version { - u8 status; - u8 hw_platform; - u8 hw_variant; - u8 hw_revision; - u8 fw_variant; - u8 fw_revision; - u8 fw_build_num; - u8 fw_build_ww; - u8 fw_build_yy; - u8 fw_patch_num; -} __packed; - -struct intel_boot_params { - __u8 status; - __u8 otp_format; - __u8 otp_content; - __u8 otp_patch; - __le16 dev_revid; - __u8 secure_boot; - __u8 key_from_hdr; - __u8 key_type; - __u8 otp_lock; - __u8 api_lock; - __u8 debug_lock; - bdaddr_t otp_bdaddr; - __u8 min_fw_build_nn; - __u8 min_fw_build_cw; - __u8 min_fw_build_yy; - __u8 limited_cce; - __u8 unlocked_state; -} __packed; - static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev, struct intel_version *ver) { From bca03c959ab377010d87bef2679890a4a4e66e37 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Mon, 6 Apr 2015 00:52:14 -0700 Subject: [PATCH 32/38] Bluetooth: hci_uart: Use generic Intel support for address setting The Bluetooth address setting for Intel devices is provided by a generic module now. Start using that module instead of relying it being included in the driver. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/Kconfig | 1 + drivers/bluetooth/hci_intel.c | 17 ----------------- drivers/bluetooth/hci_ldisc.c | 4 +++- drivers/bluetooth/hci_uart.h | 4 ---- 4 files changed, 4 insertions(+), 22 deletions(-) diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index b50fe3361659..ed5c2738bea2 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -117,6 +117,7 @@ config BT_HCIUART_3WIRE config BT_HCIUART_INTEL bool "Intel protocol support" depends on BT_HCIUART + select BT_INTEL help The Intel protocol support enables Bluetooth HCI over serial port interface for Intel Bluetooth controllers. diff --git a/drivers/bluetooth/hci_intel.c b/drivers/bluetooth/hci_intel.c index b7bd50a41080..5dd07bf05236 100644 --- a/drivers/bluetooth/hci_intel.c +++ b/drivers/bluetooth/hci_intel.c @@ -29,20 +29,3 @@ #include #include "hci_uart.h" - -int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) -{ - struct sk_buff *skb; - int err; - - skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - err = PTR_ERR(skb); - BT_ERR("%s: Changing Intel device address failed (%d)", - hdev->name, err); - return err; - } - kfree_skb(skb); - - return 0; -} diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index a106c3e201e3..5c9a73f02664 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -44,6 +44,7 @@ #include #include +#include "btintel.h" #include "btbcm.h" #include "hci_uart.h" @@ -295,7 +296,8 @@ static int hci_uart_setup(struct hci_dev *hdev) switch (le16_to_cpu(ver->manufacturer)) { #ifdef CONFIG_BT_HCIUART_INTEL case 2: - hdev->set_bdaddr = intel_set_bdaddr; + hdev->set_bdaddr = btintel_set_bdaddr; + btintel_check_bdaddr(hdev); break; #endif #ifdef CONFIG_BT_HCIUART_BCM diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index d1fa6263f7c2..72120a5ba13c 100644 --- a/drivers/bluetooth/hci_uart.h +++ b/drivers/bluetooth/hci_uart.h @@ -156,10 +156,6 @@ int h5_init(void); int h5_deinit(void); #endif -#ifdef CONFIG_BT_HCIUART_INTEL -int intel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); -#endif - #ifdef CONFIG_BT_HCIUART_BCM int bcm_init(void); int bcm_deinit(void); From d619ffcfbd07983d34dc87d474af6cb5c21adf27 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 7 Apr 2015 21:52:21 +0300 Subject: [PATCH 33/38] Bluetooth: Update SSP OOB data EIR definitions Since Bluetooth 4.1 there are two additional values for SSP OOB data, namely C-256 and R-256. This patch updates the EIR definitions to take into account both the 192 and 256 bit variants of C and R. Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- include/net/bluetooth/hci.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3acecf35420b..2f8c830e600c 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -463,12 +463,14 @@ enum { #define EIR_NAME_COMPLETE 0x09 /* complete local name */ #define EIR_TX_POWER 0x0A /* transmit power level */ #define EIR_CLASS_OF_DEV 0x0D /* Class of Device */ -#define EIR_SSP_HASH_C 0x0E /* Simple Pairing Hash C */ -#define EIR_SSP_RAND_R 0x0F /* Simple Pairing Randomizer R */ +#define EIR_SSP_HASH_C192 0x0E /* Simple Pairing Hash C-192 */ +#define EIR_SSP_RAND_R192 0x0F /* Simple Pairing Randomizer R-192 */ #define EIR_DEVICE_ID 0x10 /* device ID */ #define EIR_APPEARANCE 0x19 /* Device appearance */ #define EIR_LE_BDADDR 0x1B /* LE Bluetooth device address */ #define EIR_LE_ROLE 0x1C /* LE role */ +#define EIR_SSP_HASH_C256 0x1D /* Simple Pairing Hash C-256 */ +#define EIR_SSP_RAND_R256 0x1E /* Simple Pairing Rand R-256 */ #define EIR_LE_SC_CONFIRM 0x22 /* LE SC Confirmation Value */ #define EIR_LE_SC_RANDOM 0x23 /* LE SC Random Value */ From 40f66c05c360777e847033ddbe076d88123719d1 Mon Sep 17 00:00:00 2001 From: Johan Hedberg Date: Tue, 7 Apr 2015 21:52:22 +0300 Subject: [PATCH 34/38] Bluetooth: Add local SSP OOB data to OOB ext data mgmt command The Read Local Out Of Band Extended Data mgmt command is specified to return the SSP values when given a BR/EDR address type as input parameter. The returned values may include either the 192-bit variants of C and R, or their 256-bit variants, or both, depending on the status of Secure Connections and Secure Connections Only modes. If SSP is not enabled the command will only return the Class of Device value (like it has done so far). Signed-off-by: Johan Hedberg Signed-off-by: Marcel Holtmann --- net/bluetooth/mgmt.c | 154 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 152 insertions(+), 2 deletions(-) diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c index 845dfcc43a20..7fd87e7135b5 100644 --- a/net/bluetooth/mgmt.c +++ b/net/bluetooth/mgmt.c @@ -6466,6 +6466,145 @@ static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data, return eir_len; } +static void read_local_oob_ext_data_complete(struct hci_dev *hdev, u8 status, + u16 opcode, struct sk_buff *skb) +{ + const struct mgmt_cp_read_local_oob_ext_data *mgmt_cp; + struct mgmt_rp_read_local_oob_ext_data *mgmt_rp; + u8 *h192, *r192, *h256, *r256; + struct mgmt_pending_cmd *cmd; + u16 eir_len; + int err; + + BT_DBG("%s status %u", hdev->name, status); + + cmd = pending_find(MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev); + if (!cmd) + return; + + mgmt_cp = cmd->param; + + if (status) { + status = mgmt_status(status); + eir_len = 0; + + h192 = NULL; + r192 = NULL; + h256 = NULL; + r256 = NULL; + } else if (opcode == HCI_OP_READ_LOCAL_OOB_DATA) { + struct hci_rp_read_local_oob_data *rp; + + if (skb->len != sizeof(*rp)) { + status = MGMT_STATUS_FAILED; + eir_len = 0; + } else { + status = MGMT_STATUS_SUCCESS; + rp = (void *)skb->data; + + eir_len = 5 + 18 + 18; + h192 = rp->hash; + r192 = rp->rand; + h256 = NULL; + r256 = NULL; + } + } else { + struct hci_rp_read_local_oob_ext_data *rp; + + if (skb->len != sizeof(*rp)) { + status = MGMT_STATUS_FAILED; + eir_len = 0; + } else { + status = MGMT_STATUS_SUCCESS; + rp = (void *)skb->data; + + if (hci_dev_test_flag(hdev, HCI_SC_ONLY)) { + eir_len = 5 + 18 + 18; + h192 = NULL; + r192 = NULL; + } else { + eir_len = 5 + 18 + 18 + 18 + 18; + h192 = rp->hash192; + r192 = rp->rand192; + } + + h256 = rp->hash256; + r256 = rp->rand256; + } + } + + mgmt_rp = kmalloc(sizeof(*mgmt_rp) + eir_len, GFP_KERNEL); + if (!mgmt_rp) + goto done; + + if (status) + goto send_rsp; + + eir_len = eir_append_data(mgmt_rp->eir, 0, EIR_CLASS_OF_DEV, + hdev->dev_class, 3); + + if (h192 && r192) { + eir_len = eir_append_data(mgmt_rp->eir, eir_len, + EIR_SSP_HASH_C192, h192, 16); + eir_len = eir_append_data(mgmt_rp->eir, eir_len, + EIR_SSP_RAND_R192, r192, 16); + } + + if (h256 && r256) { + eir_len = eir_append_data(mgmt_rp->eir, eir_len, + EIR_SSP_HASH_C256, h256, 16); + eir_len = eir_append_data(mgmt_rp->eir, eir_len, + EIR_SSP_RAND_R256, r256, 16); + } + +send_rsp: + mgmt_rp->type = mgmt_cp->type; + mgmt_rp->eir_len = cpu_to_le16(eir_len); + + err = mgmt_cmd_complete(cmd->sk, hdev->id, + MGMT_OP_READ_LOCAL_OOB_EXT_DATA, status, + mgmt_rp, sizeof(*mgmt_rp) + eir_len); + if (err < 0 || status) + goto done; + + hci_sock_set_flag(cmd->sk, HCI_MGMT_OOB_DATA_EVENTS); + + err = mgmt_limited_event(MGMT_EV_LOCAL_OOB_DATA_UPDATED, hdev, + mgmt_rp, sizeof(*mgmt_rp) + eir_len, + HCI_MGMT_OOB_DATA_EVENTS, cmd->sk); +done: + kfree(mgmt_rp); + mgmt_pending_remove(cmd); +} + +static int read_local_ssp_oob_req(struct hci_dev *hdev, struct sock *sk, + struct mgmt_cp_read_local_oob_ext_data *cp) +{ + struct mgmt_pending_cmd *cmd; + struct hci_request req; + int err; + + cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_EXT_DATA, hdev, + cp, sizeof(*cp)); + if (!cmd) + return -ENOMEM; + + hci_req_init(&req, hdev); + + if (bredr_sc_enabled(hdev)) + hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_EXT_DATA, 0, NULL); + else + hci_req_add(&req, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL); + + err = hci_req_run_skb(&req, read_local_oob_ext_data_complete); + if (err < 0) { + mgmt_pending_remove(cmd); + return err; + } + + return 0; +} + static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, void *data, u16 data_len) { @@ -6517,8 +6656,19 @@ static int read_local_oob_ext_data(struct sock *sk, struct hci_dev *hdev, eir_len = 0; switch (cp->type) { case BIT(BDADDR_BREDR): - eir_len = eir_append_data(rp->eir, eir_len, EIR_CLASS_OF_DEV, - hdev->dev_class, 3); + if (hci_dev_test_flag(hdev, HCI_SSP_ENABLED)) { + err = read_local_ssp_oob_req(hdev, sk, cp); + hci_dev_unlock(hdev); + if (!err) + goto done; + + status = MGMT_STATUS_FAILED; + goto complete; + } else { + eir_len = eir_append_data(rp->eir, eir_len, + EIR_CLASS_OF_DEV, + hdev->dev_class, 3); + } break; case (BIT(BDADDR_LE_PUBLIC) | BIT(BDADDR_LE_RANDOM)): if (hci_dev_test_flag(hdev, HCI_SC_ENABLED) && From 0fe29fd1cd77ffbdb8e36ec1715868d9d8011c9b Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Wed, 8 Apr 2015 09:05:27 -0700 Subject: [PATCH 35/38] Bluetooth: Read LE remote features during connection establishment When establishing a Bluetooth LE connection, read the remote used features mask to determine which features are supported. This was not really needed with Bluetooth 4.0, but since Bluetooth 4.1 and also 4.2 have introduced new optional features, this becomes more important. This works the same as with BR/EDR where the connection enters the BT_CONFIG stage and hci_connect_cfm call is delayed until the remote features have been retrieved. Only after successfully receiving the remote features, the connection enters the BT_CONNECTED state. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- include/net/bluetooth/hci.h | 13 +++++ net/bluetooth/hci_event.c | 107 +++++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 2 deletions(-) diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 2f8c830e600c..d95da83cb1b0 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -374,6 +374,7 @@ enum { /* LE features */ #define HCI_LE_ENCRYPTION 0x01 #define HCI_LE_CONN_PARAM_REQ_PROC 0x02 +#define HCI_LE_SLAVE_FEATURES 0x08 #define HCI_LE_PING 0x10 #define HCI_LE_DATA_LEN_EXT 0x20 #define HCI_LE_EXT_SCAN_POLICY 0x80 @@ -1376,6 +1377,11 @@ struct hci_cp_le_conn_update { __le16 max_ce_len; } __packed; +#define HCI_OP_LE_READ_REMOTE_FEATURES 0x2016 +struct hci_cp_le_read_remote_features { + __le16 handle; +} __packed; + #define HCI_OP_LE_START_ENC 0x2019 struct hci_cp_le_start_enc { __le16 handle; @@ -1868,6 +1874,13 @@ struct hci_ev_le_conn_update_complete { __le16 supervision_timeout; } __packed; +#define HCI_EV_LE_REMOTE_FEAT_COMPLETE 0x04 +struct hci_ev_le_remote_feat_complete { + __u8 status; + __le16 handle; + __u8 features[8]; +} __packed; + #define HCI_EV_LE_LTK_REQ 0x05 struct hci_ev_le_ltk_req { __le16 handle; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index 01031038eb0e..7b61be73650f 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -2036,6 +2036,33 @@ unlock: hci_dev_unlock(hdev); } +static void hci_cs_le_read_remote_features(struct hci_dev *hdev, u8 status) +{ + struct hci_cp_le_read_remote_features *cp; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, status); + + if (!status) + return; + + cp = hci_sent_cmd_data(hdev, HCI_OP_LE_READ_REMOTE_FEATURES); + if (!cp) + return; + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(cp->handle)); + if (conn) { + if (conn->state == BT_CONFIG) { + hci_connect_cfm(conn, status); + hci_conn_drop(conn); + } + } + + hci_dev_unlock(hdev); +} + static void hci_cs_le_start_enc(struct hci_dev *hdev, u8 status) { struct hci_cp_le_start_enc *cp; @@ -3104,6 +3131,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb, hci_cs_le_create_conn(hdev, ev->status); break; + case HCI_OP_LE_READ_REMOTE_FEATURES: + hci_cs_le_read_remote_features(hdev, ev->status); + break; + case HCI_OP_LE_START_ENC: hci_cs_le_start_enc(hdev, ev->status); break; @@ -4515,7 +4546,7 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) conn->sec_level = BT_SECURITY_LOW; conn->handle = __le16_to_cpu(ev->handle); - conn->state = BT_CONNECTED; + conn->state = BT_CONFIG; conn->le_conn_interval = le16_to_cpu(ev->interval); conn->le_conn_latency = le16_to_cpu(ev->latency); @@ -4524,7 +4555,33 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_debugfs_create_conn(conn); hci_conn_add_sysfs(conn); - hci_connect_cfm(conn, ev->status); + if (!ev->status) { + /* The remote features procedure is defined for master + * role only. So only in case of an initiated connection + * request the remote features. + * + * If the local controller supports slave-initiated features + * exchange, then requesting the remote features in slave + * role is possible. Otherwise just transition into the + * connected state without requesting the remote features. + */ + if (conn->out || + (hdev->le_features[0] & HCI_LE_SLAVE_FEATURES)) { + struct hci_cp_le_read_remote_features cp; + + cp.handle = __cpu_to_le16(conn->handle); + + hci_send_cmd(hdev, HCI_OP_LE_READ_REMOTE_FEATURES, + sizeof(cp), &cp); + + hci_conn_hold(conn); + } else { + conn->state = BT_CONNECTED; + hci_connect_cfm(conn, ev->status); + } + } else { + hci_connect_cfm(conn, ev->status); + } params = hci_pend_le_action_lookup(&hdev->pend_le_conns, &conn->dst, conn->dst_type); @@ -4826,6 +4883,48 @@ static void hci_le_adv_report_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_dev_unlock(hdev); } +static void hci_le_remote_feat_complete_evt(struct hci_dev *hdev, + struct sk_buff *skb) +{ + struct hci_ev_le_remote_feat_complete *ev = (void *)skb->data; + struct hci_conn *conn; + + BT_DBG("%s status 0x%2.2x", hdev->name, ev->status); + + hci_dev_lock(hdev); + + conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle)); + if (conn) { + if (!ev->status) + memcpy(conn->features[0], ev->features, 8); + + if (conn->state == BT_CONFIG) { + __u8 status; + + /* If the local controller supports slave-initiated + * features exchange, but the remote controller does + * not, then it is possible that the error code 0x1a + * for unsupported remote feature gets returned. + * + * In this specific case, allow the connection to + * transition into connected state and mark it as + * successful. + */ + if ((hdev->le_features[0] & HCI_LE_SLAVE_FEATURES) && + !conn->out && ev->status == 0x1a) + status = 0x00; + else + status = ev->status; + + conn->state = BT_CONNECTED; + hci_connect_cfm(conn, status); + hci_conn_drop(conn); + } + } + + hci_dev_unlock(hdev); +} + static void hci_le_ltk_request_evt(struct hci_dev *hdev, struct sk_buff *skb) { struct hci_ev_le_ltk_req *ev = (void *) skb->data; @@ -4999,6 +5098,10 @@ static void hci_le_meta_evt(struct hci_dev *hdev, struct sk_buff *skb) hci_le_adv_report_evt(hdev, skb); break; + case HCI_EV_LE_REMOTE_FEAT_COMPLETE: + hci_le_remote_feat_complete_evt(hdev, skb); + break; + case HCI_EV_LE_LTK_REQ: hci_le_ltk_request_evt(hdev, skb); break; From 94910d419a506a8e21333cc87ffb80db8b89d88a Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 9 Apr 2015 12:05:43 +0530 Subject: [PATCH 36/38] mac802154: fix typo for device Signed-off-by: Varka Bhadram Signed-off-by: Marcel Holtmann --- include/net/mac802154.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/net/mac802154.h b/include/net/mac802154.h index fb4e8a3d6229..2f0644c0612a 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -247,7 +247,7 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src) __put_unaligned_memmove64(swab64p(le64_src), be64_dst); } -/* Basic interface to register ieee802154 hwice */ +/* Basic interface to register ieee802154 device */ struct ieee802154_hw * ieee802154_alloc_hw(size_t priv_data_len, const struct ieee802154_ops *ops); void ieee802154_free_hw(struct ieee802154_hw *hw); From ccd6da2ab81815e03c0713069597a8fc8f6f8431 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 9 Apr 2015 00:35:19 -0700 Subject: [PATCH 37/38] Bluetooth: btusb: Use proper data structures for Intel vendor events The Intel vendors events indicating firmware loading result and the bootup of the operational firmware are currently hardcoded byte comparisons. So intead of doing that, provide proper data structures and actually use them. Signed-off-by: Marcel Holtmann Signed-off-by: Johan Hedberg --- drivers/bluetooth/btintel.h | 15 ++++++++ drivers/bluetooth/btusb.c | 77 +++++++++++++++++++++++++------------ 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index d1581150679a..4bda6ab34f60 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h @@ -54,6 +54,21 @@ struct intel_boot_params { __u8 unlocked_state; } __packed; +struct intel_bootup { + __u8 zero; + __u8 num_cmds; + __u8 source; + __u8 reset_type; + __u8 reset_reason; + __u8 ddc_status; +} __packed; + +struct intel_secure_send_result { + __u8 result; + __le16 opcode; + __u8 status; +} __packed; + #if IS_ENABLED(CONFIG_BT_INTEL) int btintel_check_bdaddr(struct hci_dev *hdev); diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index c06ceec13dbb..de7b236eeae7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -1746,6 +1746,38 @@ static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer, return btusb_recv_bulk(data, buffer, count); } +static void btusb_intel_bootup(struct btusb_data *data, const void *ptr, + unsigned int len) +{ + const struct intel_bootup *evt = ptr; + + if (len != sizeof(*evt)) + return; + + if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&data->flags, BTUSB_BOOTING); + } +} + +static void btusb_intel_secure_send_result(struct btusb_data *data, + const void *ptr, unsigned int len) +{ + const struct intel_secure_send_result *evt = ptr; + + if (len != sizeof(*evt)) + return; + + if (evt->result) + set_bit(BTUSB_FIRMWARE_FAILED, &data->flags); + + if (test_and_clear_bit(BTUSB_DOWNLOADING, &data->flags) && + test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) { + smp_mb__after_atomic(); + wake_up_bit(&data->flags, BTUSB_DOWNLOADING); + } +} + static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) { struct btusb_data *data = hci_get_drvdata(hdev); @@ -1753,32 +1785,27 @@ static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb) if (test_bit(BTUSB_BOOTLOADER, &data->flags)) { struct hci_event_hdr *hdr = (void *)skb->data; - /* When the firmware loading completes the device sends - * out a vendor specific event indicating the result of - * the firmware loading. - */ - if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 && - skb->data[2] == 0x06) { - if (skb->data[3] != 0x00) - test_bit(BTUSB_FIRMWARE_FAILED, &data->flags); + if (skb->len > HCI_EVENT_HDR_SIZE && hdr->evt == 0xff && + hdr->plen > 0) { + const void *ptr = skb->data + HCI_EVENT_HDR_SIZE + 1; + unsigned int len = skb->len - HCI_EVENT_HDR_SIZE - 1; - if (test_and_clear_bit(BTUSB_DOWNLOADING, - &data->flags) && - test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) { - smp_mb__after_atomic(); - wake_up_bit(&data->flags, BTUSB_DOWNLOADING); - } - } - - /* When switching to the operational firmware the device - * sends a vendor specific event indicating that the bootup - * completed. - */ - if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 && - skb->data[2] == 0x02) { - if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) { - smp_mb__after_atomic(); - wake_up_bit(&data->flags, BTUSB_BOOTING); + switch (skb->data[2]) { + case 0x02: + /* When switching to the operational firmware + * the device sends a vendor specific event + * indicating that the bootup completed. + */ + btusb_intel_bootup(data, ptr, len); + break; + case 0x06: + /* When the firmware loading completes the + * device sends out a vendor specific event + * indicating the result of the firmware + * loading. + */ + btusb_intel_secure_send_result(data, ptr, len); + break; } } } From 23310f6f3a8f30f4b6794e941763da4708f7471a Mon Sep 17 00:00:00 2001 From: Varka Bhadram Date: Thu, 9 Apr 2015 13:55:11 +0530 Subject: [PATCH 38/38] mac802154: fix transmission power datatype Netlink attribute for the power is s8. But for the driver level operations we are collection power level value into integer. It has to be change to s8 from int. Signed-off-by: Varka Bhadram Acked-by: Alexander Aring Signed-off-by: Marcel Holtmann --- drivers/net/ieee802154/at86rf230.c | 2 +- include/net/mac802154.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c index 5ad46f7f514f..38026650c038 100644 --- a/drivers/net/ieee802154/at86rf230.c +++ b/drivers/net/ieee802154/at86rf230.c @@ -1173,7 +1173,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw, } static int -at86rf230_set_txpower(struct ieee802154_hw *hw, int db) +at86rf230_set_txpower(struct ieee802154_hw *hw, s8 db) { struct at86rf230_local *lp = hw->priv; diff --git a/include/net/mac802154.h b/include/net/mac802154.h index 2f0644c0612a..e18e7fd43f47 100644 --- a/include/net/mac802154.h +++ b/include/net/mac802154.h @@ -213,7 +213,7 @@ struct ieee802154_ops { int (*set_hw_addr_filt)(struct ieee802154_hw *hw, struct ieee802154_hw_addr_filt *filt, unsigned long changed); - int (*set_txpower)(struct ieee802154_hw *hw, int db); + int (*set_txpower)(struct ieee802154_hw *hw, s8 dbm); int (*set_lbt)(struct ieee802154_hw *hw, bool on); int (*set_cca_mode)(struct ieee802154_hw *hw, const struct wpan_phy_cca *cca);