diff options
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/Kconfig | 41 | ||||
-rw-r--r-- | drivers/bluetooth/Makefile | 4 | ||||
-rw-r--r-- | drivers/bluetooth/ath3k.c | 1 | ||||
-rw-r--r-- | drivers/bluetooth/btbcm.c | 387 | ||||
-rw-r--r-- | drivers/bluetooth/btbcm.h | 54 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.c | 101 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 89 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_drv.h | 1 | ||||
-rw-r--r-- | drivers/bluetooth/btmrvl_main.c | 14 | ||||
-rw-r--r-- | drivers/bluetooth/btusb.c | 689 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ath.c | 49 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcm.c | 153 | ||||
-rw-r--r-- | drivers/bluetooth/hci_bcsp.c | 18 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h4.c | 132 | ||||
-rw-r--r-- | drivers/bluetooth/hci_h5.c | 16 | ||||
-rw-r--r-- | drivers/bluetooth/hci_intel.c | 31 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ldisc.c | 99 | ||||
-rw-r--r-- | drivers/bluetooth/hci_ll.c | 16 | ||||
-rw-r--r-- | drivers/bluetooth/hci_uart.h | 54 |
19 files changed, 1525 insertions, 424 deletions
diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 364f080768d0..ed5c2738bea2 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -2,9 +2,17 @@ menu "Bluetooth device drivers" depends on BT +config BT_INTEL + tristate + +config BT_BCM + tristate + select FW_LOADER + config BT_HCIBTUSB tristate "HCI USB driver" depends on USB + select BT_INTEL help Bluetooth HCI USB driver. This driver is required if you want to use Bluetooth devices with @@ -13,6 +21,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 @@ -62,6 +81,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. @@ -94,6 +114,27 @@ 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 + select BT_INTEL + help + The Intel protocol support enables Bluetooth HCI over serial + port interface for Intel Bluetooth controllers. + + Say Y here to compile support for Intel protocol. + +config BT_HCIUART_BCM + bool "Broadcom protocol support" + depends on BT_HCIUART + select BT_HCIUART_H4 + select BT_BCM + help + The Broadcom protocol support enables Bluetooth HCI over serial + port interface for Broadcom Bluetooth controllers. + + Say Y here to compile support for Broadcom protocol. + config BT_HCIBCM203X tristate "HCI BCM203x USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 9fe8a875a827..dd0d9c40b999 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -15,10 +15,12 @@ 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 obj-$(CONFIG_BT_WILINK) += btwilink.o +obj-$(CONFIG_BT_BCM) += btbcm.o btmrvl-y := btmrvl_main.o btmrvl-$(CONFIG_DEBUG_FS) += btmrvl_debugfs.o @@ -29,6 +31,8 @@ hci_uart-$(CONFIG_BT_HCIUART_BCSP) += hci_bcsp.o hci_uart-$(CONFIG_BT_HCIUART_LL) += hci_ll.o hci_uart-$(CONFIG_BT_HCIUART_ATH3K) += hci_ath.o hci_uart-$(CONFIG_BT_HCIUART_3WIRE) += hci_h5.o +hci_uart-$(CONFIG_BT_HCIUART_INTEL) += hci_intel.o +hci_uart-$(CONFIG_BT_HCIUART_BCM) += hci_bcm.o hci_uart-objs := $(hci_uart-y) ccflags-y += -D__CHECK_ENDIAN__ diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c index de4c8499cbac..288547a3c566 100644 --- a/drivers/bluetooth/ath3k.c +++ b/drivers/bluetooth/ath3k.c @@ -65,6 +65,7 @@ static const struct usb_device_id ath3k_table[] = { /* Atheros AR3011 with sflash firmware*/ { USB_DEVICE(0x0489, 0xE027) }, { USB_DEVICE(0x0489, 0xE03D) }, + { USB_DEVICE(0x04F2, 0xAFF1) }, { USB_DEVICE(0x0930, 0x0215) }, { USB_DEVICE(0x0CF3, 0x3002) }, { USB_DEVICE(0x0CF3, 0xE019) }, diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c new file mode 100644 index 000000000000..d0741f3ed7ec --- /dev/null +++ b/drivers/bluetooth/btbcm.c @@ -0,0 +1,387 @@ +/* + * + * 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 <linux/module.h> +#include <linux/firmware.h> +#include <asm/unaligned.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#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); + +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_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 */ + { 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); + + 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); + + 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); + + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + +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); + + set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + + return 0; +} +EXPORT_SYMBOL_GPL(btbcm_setup_apple); + +MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); +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..34268ae3eb46 --- /dev/null +++ b/drivers/bluetooth/btbcm.h @@ -0,0 +1,54 @@ +/* + * + * 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); + +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) +{ + return -EOPNOTSUPP; +} + +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 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 <linux/module.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#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 <marcel@holtmann.org>"); +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..4bda6ab34f60 --- /dev/null +++ b/drivers/bluetooth/btintel.h @@ -0,0 +1,89 @@ +/* + * + * 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 + * + */ + +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; + +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); +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 diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h index e75f8ee2512c..086f0ec89580 100644 --- a/drivers/bluetooth/btmrvl_drv.h +++ b/drivers/bluetooth/btmrvl_drv.h @@ -111,6 +111,7 @@ struct btmrvl_private { /* Vendor specific Bluetooth commands */ #define BT_CMD_PSCAN_WIN_REPORT_ENABLE 0xFC03 +#define BT_CMD_ROUTE_SCO_TO_HOST 0xFC1D #define BT_CMD_SET_BDADDR 0xFC22 #define BT_CMD_AUTO_SLEEP_MODE 0xFC23 #define BT_CMD_HOST_SLEEP_CONFIG 0xFC59 diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c index 413597789c61..de05deb444ce 100644 --- a/drivers/bluetooth/btmrvl_main.c +++ b/drivers/bluetooth/btmrvl_main.c @@ -230,6 +230,18 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, u8 subcmd) } EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd); +static int btmrvl_enable_sco_routing_to_host(struct btmrvl_private *priv) +{ + int ret; + u8 subcmd = 0; + + ret = btmrvl_send_sync_cmd(priv, BT_CMD_ROUTE_SCO_TO_HOST, &subcmd, 1); + if (ret) + BT_ERR("BT_CMD_ROUTE_SCO_TO_HOST command failed: %#x", ret); + + return ret; +} + int btmrvl_pscan_window_reporting(struct btmrvl_private *priv, u8 subcmd) { struct btmrvl_sdio_card *card = priv->btmrvl_dev.card; @@ -558,6 +570,8 @@ static int btmrvl_setup(struct hci_dev *hdev) btmrvl_check_device_tree(priv); + btmrvl_enable_sco_routing_to_host(priv); + btmrvl_pscan_window_reporting(priv, 0x01); priv->btmrvl_dev.psmode = 1; diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 8bfc4c2bba87..de7b236eeae7 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -28,7 +28,10 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> -#define VERSION "0.7" +#include "btintel.h" +#include "btbcm.h" + +#define VERSION "0.8" static bool disable_scofix; static bool force_scofix; @@ -52,6 +55,8 @@ static struct usb_driver btusb_driver; #define BTUSB_SWAVE 0x1000 #define BTUSB_INTEL_NEW 0x2000 #define BTUSB_AMP 0x4000 +#define BTUSB_QCA_ROME 0x8000 +#define BTUSB_BCM_APPLE 0x10000 static const struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -61,7 +66,8 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP }, /* Apple-specific (Broadcom) devices */ - { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_APPLE }, /* MediaTek MT76x0E */ { USB_DEVICE(0x0e8d, 0x763f) }, @@ -107,13 +113,7 @@ static const struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0c10, 0x0000) }, /* Broadcom BCM20702A0 */ - { USB_DEVICE(0x0489, 0xe042) }, - { USB_DEVICE(0x04ca, 0x2003) }, - { USB_DEVICE(0x0b05, 0x17b5) }, - { USB_DEVICE(0x0b05, 0x17cb) }, { USB_DEVICE(0x413c, 0x8197) }, - { USB_DEVICE(0x13d3, 0x3404), - .driver_info = BTUSB_BCM_PATCHRAM }, /* Broadcom BCM20702B0 (Dynex/Insignia) */ { USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM }, @@ -135,10 +135,12 @@ static const struct usb_device_id btusb_table[] = { .driver_info = BTUSB_BCM_PATCHRAM }, /* Belkin F8065bf - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* IMC Networks - Broadcom based */ - { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01) }, + { USB_VENDOR_AND_INTERFACE_INFO(0x13d3, 0xff, 0x01, 0x01), + .driver_info = BTUSB_BCM_PATCHRAM }, /* Intel Bluetooth USB Bootloader (RAM module) */ { USB_DEVICE(0x8087, 0x0a5a), @@ -159,6 +161,7 @@ static const struct usb_device_id blacklist_table[] = { /* Atheros 3011 with sflash firmware */ { USB_DEVICE(0x0489, 0xe027), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0489, 0xe03d), .driver_info = BTUSB_IGNORE }, + { USB_DEVICE(0x04f2, 0xaff1), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0930, 0x0215), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE }, { USB_DEVICE(0x0cf3, 0xe019), .driver_info = BTUSB_IGNORE }, @@ -212,6 +215,10 @@ static const struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0489, 0xe036), .driver_info = BTUSB_ATH3012 }, { USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 }, + /* QCA ROME chipset */ + { USB_DEVICE(0x0cf3, 0xe300), .driver_info = BTUSB_QCA_ROME }, + { USB_DEVICE(0x0cf3, 0xe360), .driver_info = BTUSB_QCA_ROME }, + /* Broadcom BCM2035 */ { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, @@ -337,17 +344,9 @@ struct btusb_data { int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb); int (*recv_bulk)(struct btusb_data *data, void *buffer, int count); -}; -static int btusb_wait_on_bit_timeout(void *word, int bit, unsigned long timeout, - unsigned mode) -{ - might_sleep(); - if (!test_bit(bit, word)) - return 0; - return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout, - mode, timeout); -} + int (*setup_on_usb)(struct hci_dev *hdev); +}; static inline void btusb_free_frags(struct btusb_data *data) { @@ -888,6 +887,15 @@ static int btusb_open(struct hci_dev *hdev) BT_DBG("%s", hdev->name); + /* Patching USB firmware files prior to starting any URBs of HCI path + * It is more safe to use USB bulk channel for downloading USB patch + */ + if (data->setup_on_usb) { + err = data->setup_on_usb(hdev); + if (err <0) + return err; + } + err = usb_autopm_get_interface(data->intf); if (err < 0) return err; @@ -1263,6 +1271,28 @@ static void btusb_waker(struct work_struct *work) usb_autopm_put_interface(data->intf); } +static struct sk_buff *btusb_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: HCI_OP_READ_LOCAL_VERSION failed (%ld)", + hdev->name, PTR_ERR(skb)); + return skb; + } + + if (skb->len != sizeof(struct hci_rp_read_local_version)) { + BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", + hdev->name); + kfree_skb(skb); + return ERR_PTR(-EIO); + } + + return skb; +} + static int btusb_setup_bcm92035(struct hci_dev *hdev) { struct sk_buff *skb; @@ -1287,12 +1317,9 @@ static int btusb_setup_csr(struct hci_dev *hdev) BT_DBG("%s", hdev->name); - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - BT_ERR("Reading local version failed (%ld)", -PTR_ERR(skb)); + skb = btusb_read_local_version(hdev); + if (IS_ERR(skb)) return -PTR_ERR(skb); - } rp = (struct hci_rp_read_local_version *)skb->data; @@ -1318,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) { @@ -1507,51 +1501,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; @@ -1624,7 +1573,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; } @@ -1637,7 +1586,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; @@ -1718,7 +1667,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: @@ -1734,7 +1683,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: @@ -1755,7 +1704,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; } @@ -1797,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); @@ -1804,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 (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); + 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; + + 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; } } } @@ -2031,7 +2007,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; } @@ -2197,9 +2173,9 @@ static int btusb_setup_intel_new(struct hci_dev *hdev) * and thus just timeout if that happens and fail the setup * of this device. */ - err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING, - msecs_to_jiffies(5000), - TASK_INTERRUPTIBLE); + err = wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(5000)); if (err == 1) { BT_ERR("%s: Firmware loading interrupted", hdev->name); err = -EINTR; @@ -2250,9 +2226,9 @@ done: */ BT_INFO("%s: Waiting for device to boot", hdev->name); - err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_BOOTING, - msecs_to_jiffies(1000), - TASK_INTERRUPTIBLE); + err = wait_on_bit_timeout(&data->flags, BTUSB_BOOTING, + TASK_INTERRUPTIBLE, + msecs_to_jiffies(1000)); if (err == 1) { BT_ERR("%s: Device boot interrupted", hdev->name); @@ -2315,15 +2291,19 @@ 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) +static int btusb_shutdown_intel(struct hci_dev *hdev) { struct sk_buff *skb; long ret; - skb = __hci_cmd_sync(hdev, 0xfc31, 6, bdaddr, HCI_INIT_TIMEOUT); + /* Some platforms have an issue with BT LED when the interface is + * down or BT radio is turned off, which takes 5 seconds to BT LED + * goes off. This command turns off the BT LED immediately. + */ + skb = __hci_cmd_sync(hdev, 0xfc3f, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); - BT_ERR("%s: changing Intel device address failed (%ld)", + BT_ERR("%s: turning off Intel device LED failed (%ld)", hdev->name, ret); return ret; } @@ -2355,232 +2335,279 @@ static int btusb_set_bdaddr_marvell(struct hci_dev *hdev, return 0; } -#define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) - -static int btusb_setup_bcm_patchram(struct hci_dev *hdev) +static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, + const bdaddr_t *bdaddr) { - 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; struct sk_buff *skb; - struct hci_rp_read_local_version *ver; - struct hci_rp_read_bd_addr *bda; + u8 buf[10]; long ret; - snprintf(fw_name, sizeof(fw_name), "brcm/%s-%04x-%04x.hcd", - udev->product ? udev->product : "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; - } + buf[0] = 0x01; + buf[1] = 0x01; + buf[2] = 0x00; + buf[3] = sizeof(bdaddr_t); + memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); - /* Reset */ - skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); + skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret); - goto done; + BT_ERR("%s: Change address command failed (%ld)", + hdev->name, ret); + return ret; } kfree_skb(skb); - /* Read Local Version Info */ - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); - goto done; - } + return 0; +} - if (skb->len != sizeof(*ver)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; - goto done; - } +#define QCA_DFU_PACKET_LEN 4096 - ver = (struct hci_rp_read_local_version *)skb->data; - BT_INFO("%s: BCM: patching hci_ver=%02x hci_rev=%04x lmp_ver=%02x " - "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, - ver->lmp_ver, ver->lmp_subver); - kfree_skb(skb); +#define QCA_GET_TARGET_VERSION 0x09 +#define QCA_CHECK_STATUS 0x05 +#define QCA_DFU_DOWNLOAD 0x01 - /* 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); +#define QCA_SYSCFG_UPDATED 0x40 +#define QCA_PATCH_UPDATED 0x80 +#define QCA_DFU_TIMEOUT 3000 - /* 50 msec delay after Download Minidrv completes */ - msleep(50); +struct qca_version { + __le32 rom_version; + __le32 patch_version; + __le32 ram_version; + __le32 ref_clock; + __u8 reserved[4]; +} __packed; - 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; - } +struct qca_rampatch_version { + __le16 rom_version; + __le16 patch_version; +} __packed; - cmd_param = fw_ptr; - fw_ptr += cmd->plen; - fw_size -= cmd->plen; +struct qca_device_info { + u32 rom_version; + u8 rampatch_hdr; /* length of header in rampatch */ + u8 nvm_hdr; /* length of header in NVM */ + u8 ver_offset; /* offset of version structure in rampatch */ +}; - opcode = le16_to_cpu(cmd->opcode); +static const struct qca_device_info qca_devices_table[] = { + { 0x00000100, 20, 4, 10 }, /* Rome 1.0 */ + { 0x00000101, 20, 4, 10 }, /* Rome 1.1 */ + { 0x00000201, 28, 4, 18 }, /* Rome 2.1 */ + { 0x00000300, 28, 4, 18 }, /* Rome 3.0 */ + { 0x00000302, 28, 4, 18 }, /* Rome 3.2 */ +}; - 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); - } +static int btusb_qca_send_vendor_req(struct hci_dev *hdev, u8 request, + void *data, u16 size) +{ + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; + int pipe, err; + u8 *buf; - /* 250 msec delay after Launch Ram completes */ - msleep(250); + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; -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); + /* Found some of USB hosts have IOT issues with ours so that we should + * not wait until HCI layer is ready. + */ + pipe = usb_rcvctrlpipe(udev, 0); + err = usb_control_msg(udev, pipe, request, USB_TYPE_VENDOR | USB_DIR_IN, + 0, 0, buf, size, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to access otp area (%d)", hdev->name, err); goto done; } - kfree_skb(skb); - /* Read Local Version Info */ - skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, - HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", - hdev->name, ret); - goto done; - } + memcpy(data, buf, size); - if (skb->len != sizeof(*ver)) { - BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", - hdev->name); - kfree_skb(skb); - ret = -EIO; - goto done; - } +done: + kfree(buf); - ver = (struct hci_rp_read_local_version *)skb->data; - BT_INFO("%s: BCM: firmware hci_ver=%02x hci_rev=%04x lmp_ver=%02x " - "lmp_subver=%04x", hdev->name, ver->hci_ver, ver->hci_rev, - ver->lmp_ver, ver->lmp_subver); - kfree_skb(skb); + return err; +} - /* 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); +static int btusb_setup_qca_download_fw(struct hci_dev *hdev, + const struct firmware *firmware, + size_t hdr_size) +{ + struct btusb_data *btdata = hci_get_drvdata(hdev); + struct usb_device *udev = btdata->udev; + size_t count, size, sent = 0; + int pipe, len, err; + u8 *buf; + + buf = kmalloc(QCA_DFU_PACKET_LEN, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + count = firmware->size; + + size = min_t(size_t, count, hdr_size); + memcpy(buf, firmware->data, size); + + /* USB patches should go down to controller through USB path + * because binary format fits to go down through USB channel. + * USB control path is for patching headers and USB bulk is for + * patch body. + */ + pipe = usb_sndctrlpipe(udev, 0); + err = usb_control_msg(udev, pipe, QCA_DFU_DOWNLOAD, USB_TYPE_VENDOR, + 0, 0, buf, size, USB_CTRL_SET_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to send headers (%d)", hdev->name, err); 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; + sent += size; + count -= size; + + while (count) { + size = min_t(size_t, count, QCA_DFU_PACKET_LEN); + + memcpy(buf, firmware->data + sent, size); + + pipe = usb_sndbulkpipe(udev, 0x02); + err = usb_bulk_msg(udev, pipe, buf, size, &len, + QCA_DFU_TIMEOUT); + if (err < 0) { + BT_ERR("%s: Failed to send body at %zd of %zd (%d)", + hdev->name, sent, firmware->size, err); + break; + } + + if (size != len) { + BT_ERR("%s: Failed to get bulk buffer", hdev->name); + err = -EILSEQ; + break; + } + + sent += size; + count -= size; } - 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; +done: + kfree(buf); + return err; +} + +static int btusb_setup_qca_load_rampatch(struct hci_dev *hdev, + struct qca_version *ver, + const struct qca_device_info *info) +{ + struct qca_rampatch_version *rver; + const struct firmware *fw; + u32 ver_rom, ver_patch; + u16 rver_rom, rver_patch; + char fwname[64]; + int err; + + ver_rom = le32_to_cpu(ver->rom_version); + ver_patch = le32_to_cpu(ver->patch_version); + + snprintf(fwname, sizeof(fwname), "qca/rampatch_usb_%08x.bin", ver_rom); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err) { + BT_ERR("%s: failed to request rampatch file: %s (%d)", + hdev->name, fwname, err); + return err; } - /* 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); + BT_INFO("%s: using rampatch file: %s", hdev->name, fwname); + + rver = (struct qca_rampatch_version *)(fw->data + info->ver_offset); + rver_rom = le16_to_cpu(rver->rom_version); + rver_patch = le16_to_cpu(rver->patch_version); + + BT_INFO("%s: QCA: patch rome 0x%x build 0x%x, firmware rome 0x%x " + "build 0x%x", hdev->name, rver_rom, rver_patch, ver_rom, + ver_patch); + + if (rver_rom != ver_rom || rver_patch <= ver_patch) { + BT_ERR("%s: rampatch file version did not match with firmware", + hdev->name); + err = -EINVAL; + goto done; } - kfree_skb(skb); + err = btusb_setup_qca_download_fw(hdev, fw, info->rampatch_hdr); done: release_firmware(fw); - return ret; + return err; } -static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr) +static int btusb_setup_qca_load_nvm(struct hci_dev *hdev, + struct qca_version *ver, + const struct qca_device_info *info) { - struct sk_buff *skb; - long ret; + const struct firmware *fw; + char fwname[64]; + int err; - 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; + snprintf(fwname, sizeof(fwname), "qca/nvm_usb_%08x.bin", + le32_to_cpu(ver->rom_version)); + + err = request_firmware(&fw, fwname, &hdev->dev); + if (err) { + BT_ERR("%s: failed to request NVM file: %s (%d)", + hdev->name, fwname, err); + return err; } - kfree_skb(skb); - return 0; + BT_INFO("%s: using NVM file: %s", hdev->name, fwname); + + err = btusb_setup_qca_download_fw(hdev, fw, info->nvm_hdr); + + release_firmware(fw); + + return err; } -static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev, - const bdaddr_t *bdaddr) +static int btusb_setup_qca(struct hci_dev *hdev) { - struct sk_buff *skb; - u8 buf[10]; - long ret; + const struct qca_device_info *info = NULL; + struct qca_version ver; + u32 ver_rom; + u8 status; + int i, err; - buf[0] = 0x01; - buf[1] = 0x01; - buf[2] = 0x00; - buf[3] = sizeof(bdaddr_t); - memcpy(buf + 4, bdaddr, sizeof(bdaddr_t)); + err = btusb_qca_send_vendor_req(hdev, QCA_GET_TARGET_VERSION, &ver, + sizeof(ver)); + if (err < 0) + return err; - skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT); - if (IS_ERR(skb)) { - ret = PTR_ERR(skb); - BT_ERR("%s: Change address command failed (%ld)", - hdev->name, ret); - return ret; + ver_rom = le32_to_cpu(ver.rom_version); + for (i = 0; i < ARRAY_SIZE(qca_devices_table); i++) { + if (ver_rom == qca_devices_table[i].rom_version) + info = &qca_devices_table[i]; + } + if (!info) { + BT_ERR("%s: don't support firmware rome 0x%x", hdev->name, + ver_rom); + return -ENODEV; + } + + err = btusb_qca_send_vendor_req(hdev, QCA_CHECK_STATUS, &status, + sizeof(status)); + if (err < 0) + return err; + + if (!(status & QCA_PATCH_UPDATED)) { + err = btusb_setup_qca_load_rampatch(hdev, &ver, info); + if (err < 0) + return err; + } + + if (!(status & QCA_SYSCFG_UPDATED)) { + err = btusb_setup_qca_load_nvm(hdev, &ver, info); + if (err < 0) + return err; } - kfree_skb(skb); return 0; } @@ -2701,23 +2728,29 @@ 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->set_bdaddr = btusb_set_bdaddr_bcm; - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + hdev->setup = btbcm_setup_patchram; + hdev->set_bdaddr = btbcm_set_bdaddr; } + if (id->driver_info & BTUSB_BCM_APPLE) + hdev->setup = btbcm_setup_apple; +#endif + if (id->driver_info & BTUSB_INTEL) { hdev->setup = btusb_setup_intel; - hdev->set_bdaddr = btusb_set_bdaddr_intel; + hdev->shutdown = btusb_shutdown_intel; + hdev->set_bdaddr = btintel_set_bdaddr; set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); } if (id->driver_info & BTUSB_INTEL_NEW) { 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); } @@ -2734,9 +2767,15 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_ATH3012) { hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); } + if (id->driver_info & BTUSB_QCA_ROME) { + data->setup_on_usb = btusb_setup_qca; + hdev->set_bdaddr = btusb_set_bdaddr_ath3012; + } + if (id->driver_info & BTUSB_AMP) { /* AMP controllers do not support SCO packets */ data->isoc = NULL; @@ -2772,6 +2811,8 @@ static int btusb_probe(struct usb_interface *intf, /* Fake CSR devices with broken commands */ if (bcdDevice <= 0x100) hdev->setup = btusb_setup_csr; + + set_bit(HCI_QUIRK_SIMULTANEOUS_DISCOVERY, &hdev->quirks); } if (id->driver_info & BTUSB_SNIFFER) { diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c index 9c4dcf4c62ea..1b3f8647ea2f 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; @@ -187,40 +190,42 @@ 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, void *data, int count) +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, + 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); + return err; } return count; } -static 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, +static const struct hci_uart_proto athp = { + .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) { - 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_bcm.c b/drivers/bluetooth/hci_bcm.c new file mode 100644 index 000000000000..1ec0b4a5ffa6 --- /dev/null +++ b/drivers/bluetooth/hci_bcm.c @@ -0,0 +1,153 @@ +/* + * + * 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 <linux/kernel.h> +#include <linux/errno.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#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 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; + + if (!test_bit(HCI_UART_REGISTERED, &hu->flags)) + return -EUNATCH; + + 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); + 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_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 21cc45b34f13..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; @@ -554,10 +552,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); @@ -735,8 +733,9 @@ 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, + .name = "BCSP", .open = bcsp_open, .close = bcsp_close, .enqueue = bcsp_enqueue, @@ -747,14 +746,7 @@ static 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 66db9a803373..f7190f01e135 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -40,17 +40,14 @@ #include <linux/signal.h> #include <linux/ioctl.h> #include <linux/skbuff.h> +#include <asm/unaligned.h> #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> #include "hci_uart.h" -#define VERSION "1.2" - struct h4_struct { - unsigned long rx_state; - unsigned long rx_count; struct sk_buff *rx_skb; struct sk_buff_head txq; }; @@ -117,18 +114,26 @@ 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, void *data, int count) +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, + 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); + return err; } return count; @@ -140,8 +145,9 @@ 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, + .name = "H4", .open = h4_open, .close = h4_close, .recv = h4_recv, @@ -152,17 +158,105 @@ static 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) { return hci_uart_unregister_proto(&h4p); } + +struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, + const unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count) +{ + while (count) { + int i, len; + + if (!skb) { + for (i = 0; i < pkts_count; i++) { + if (buffer[0] != (&pkts[i])->type) + continue; + + skb = bt_skb_alloc((&pkts[i])->maxlen, + GFP_ATOMIC); + if (!skb) + return ERR_PTR(-ENOMEM); + + bt_cb(skb)->pkt_type = (&pkts[i])->type; + bt_cb(skb)->expect = (&pkts[i])->hlen; + break; + } + + /* Check for invalid packet type */ + if (!skb) + return ERR_PTR(-EILSEQ); + + count -= 1; + buffer += 1; + } + + len = min_t(uint, bt_cb(skb)->expect - skb->len, count); + memcpy(skb_put(skb, len), buffer, len); + + count -= len; + buffer += len; + + /* Check for partial packet */ + if (skb->len < bt_cb(skb)->expect) + continue; + + for (i = 0; i < pkts_count; i++) { + if (bt_cb(skb)->pkt_type == (&pkts[i])->type) + break; + } + + if (i >= pkts_count) { + kfree_skb(skb); + return ERR_PTR(-EILSEQ); + } + + if (skb->len == (&pkts[i])->hlen) { + u16 dlen; + + switch ((&pkts[i])->lsize) { + case 0: + /* No variable data length */ + (&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 */ + (&pkts[i])->recv(hdev, skb); + skb = NULL; + } + } + + return skb; +} diff --git a/drivers/bluetooth/hci_h5.c b/drivers/bluetooth/hci_h5.c index ec0fa7732c0d..3455cecc9ecf 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); @@ -743,8 +743,9 @@ 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, + .name = "Three-wire (H5)", .open = h5_open, .close = h5_close, .recv = h5_recv, @@ -755,14 +756,7 @@ static 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_intel.c b/drivers/bluetooth/hci_intel.c new file mode 100644 index 000000000000..5dd07bf05236 --- /dev/null +++ b/drivers/bluetooth/hci_intel.c @@ -0,0 +1,31 @@ +/* + * + * 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 <linux/kernel.h> +#include <linux/errno.h> +#include <linux/skbuff.h> + +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/hci_core.h> + +#include "hci_uart.h" diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index dc487b5d1156..5c9a73f02664 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -44,13 +44,15 @@ #include <net/bluetooth/bluetooth.h> #include <net/bluetooth/hci_core.h> +#include "btintel.h" +#include "btbcm.h" #include "hci_uart.h" -#define VERSION "2.2" +#define VERSION "2.3" -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; @@ -60,10 +62,12 @@ int hci_uart_register_proto(struct hci_uart_proto *p) hup[p->id] = p; + BT_INFO("HCI UART protocol %s registered", p->name); + 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 +80,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; @@ -261,6 +265,54 @@ static int hci_uart_send_frame(struct hci_dev *hdev, struct sk_buff *skb) return 0; } +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)) { +#ifdef CONFIG_BT_HCIUART_INTEL + case 2: + hdev->set_bdaddr = btintel_set_bdaddr; + btintel_check_bdaddr(hdev); + break; +#endif +#ifdef CONFIG_BT_HCIUART_BCM + case 15: + hdev->set_bdaddr = btbcm_set_bdaddr; + btbcm_check_bdaddr(hdev); + break; +#endif + } + +done: + kfree_skb(skb); + return 0; +} + /* ------ LDISC part ------ */ /* hci_uart_tty_open * @@ -316,7 +368,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); @@ -355,7 +407,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(""); @@ -383,9 +435,10 @@ 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 = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; if (!hu || tty != hu->tty) return; @@ -394,7 +447,7 @@ static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *f 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; @@ -426,6 +479,7 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->close = hci_uart_close; hdev->flush = hci_uart_flush; hdev->send = hci_uart_send_frame; + hdev->setup = hci_uart_setup; SET_HCIDEV_DEV(hdev, hu->tty->dev); if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags)) @@ -458,7 +512,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); @@ -486,9 +540,10 @@ 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)) + if (flags & ~valid_flags) return -EINVAL; hu->hdev_flags = flags; @@ -509,10 +564,10 @@ 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 = (void *)tty->disc_data; + struct hci_uart *hu = tty->disc_data; int err = 0; BT_DBG(""); @@ -566,19 +621,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; } @@ -626,6 +681,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; } @@ -649,6 +707,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_ll.c b/drivers/bluetooth/hci_ll.c index 69a90b1b5ff5..9ee24b075f79 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; @@ -505,8 +505,9 @@ 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, + .name = "LL", .open = ll_open, .close = ll_close, .recv = ll_recv, @@ -517,14 +518,7 @@ static 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) diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h index 247488edcbf9..72120a5ba13c 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 8 #define HCI_UART_H4 0 #define HCI_UART_BCSP 1 @@ -43,21 +43,26 @@ #define HCI_UART_H4DS 3 #define HCI_UART_LL 4 #define HCI_UART_ATH3K 5 +#define HCI_UART_INTEL 6 +#define HCI_UART_BCM 7 #define HCI_UART_RAW_DEVICE 0 #define HCI_UART_RESET_ON_INIT 1 #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; 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); - int (*recv)(struct hci_uart *hu, void *data, int len); + 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); struct sk_buff *(*dequeue)(struct hci_uart *hu); }; @@ -71,7 +76,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; @@ -87,14 +92,48 @@ 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); #ifdef CONFIG_BT_HCIUART_H4 int h4_init(void); int h4_deinit(void); + +struct h4_recv_pkt { + u8 type; /* Packet type */ + u8 hlen; /* Header length */ + u8 loff; /* Data length offset in header */ + u8 lsize; /* Data length field size */ + u16 maxlen; /* Max overall packet length */ + int (*recv)(struct hci_dev *hdev, struct sk_buff *skb); +}; + +#define H4_RECV_ACL \ + .type = HCI_ACLDATA_PKT, \ + .hlen = HCI_ACL_HDR_SIZE, \ + .loff = 2, \ + .lsize = 2, \ + .maxlen = HCI_MAX_FRAME_SIZE \ + +#define H4_RECV_SCO \ + .type = HCI_SCODATA_PKT, \ + .hlen = HCI_SCO_HDR_SIZE, \ + .loff = 2, \ + .lsize = 1, \ + .maxlen = HCI_MAX_SCO_SIZE + +#define H4_RECV_EVENT \ + .type = HCI_EVENT_PKT, \ + .hlen = HCI_EVENT_HDR_SIZE, \ + .loff = 1, \ + .lsize = 1, \ + .maxlen = HCI_MAX_EVENT_SIZE + +struct sk_buff *h4_recv_buf(struct hci_dev *hdev, struct sk_buff *skb, + const unsigned char *buffer, int count, + const struct h4_recv_pkt *pkts, int pkts_count); #endif #ifdef CONFIG_BT_HCIUART_BCSP @@ -116,3 +155,8 @@ int ath_deinit(void); int h5_init(void); int h5_deinit(void); #endif + +#ifdef CONFIG_BT_HCIUART_BCM +int bcm_init(void); +int bcm_deinit(void); +#endif |