14fba30f0SMarcel Holtmann /* 24fba30f0SMarcel Holtmann * 34fba30f0SMarcel Holtmann * Bluetooth support for Broadcom devices 44fba30f0SMarcel Holtmann * 54fba30f0SMarcel Holtmann * Copyright (C) 2015 Intel Corporation 64fba30f0SMarcel Holtmann * 74fba30f0SMarcel Holtmann * 84fba30f0SMarcel Holtmann * This program is free software; you can redistribute it and/or modify 94fba30f0SMarcel Holtmann * it under the terms of the GNU General Public License as published by 104fba30f0SMarcel Holtmann * the Free Software Foundation; either version 2 of the License, or 114fba30f0SMarcel Holtmann * (at your option) any later version. 124fba30f0SMarcel Holtmann * 134fba30f0SMarcel Holtmann * This program is distributed in the hope that it will be useful, 144fba30f0SMarcel Holtmann * but WITHOUT ANY WARRANTY; without even the implied warranty of 154fba30f0SMarcel Holtmann * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 164fba30f0SMarcel Holtmann * GNU General Public License for more details. 174fba30f0SMarcel Holtmann * 184fba30f0SMarcel Holtmann * You should have received a copy of the GNU General Public License 194fba30f0SMarcel Holtmann * along with this program; if not, write to the Free Software 204fba30f0SMarcel Holtmann * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 214fba30f0SMarcel Holtmann * 224fba30f0SMarcel Holtmann */ 234fba30f0SMarcel Holtmann 244fba30f0SMarcel Holtmann #include <linux/module.h> 251c8ba6d0SMarcel Holtmann #include <linux/firmware.h> 261c8ba6d0SMarcel Holtmann #include <asm/unaligned.h> 274fba30f0SMarcel Holtmann 284fba30f0SMarcel Holtmann #include <net/bluetooth/bluetooth.h> 294fba30f0SMarcel Holtmann #include <net/bluetooth/hci_core.h> 304fba30f0SMarcel Holtmann 314fba30f0SMarcel Holtmann #include "btbcm.h" 324fba30f0SMarcel Holtmann 334fba30f0SMarcel Holtmann #define VERSION "0.1" 344fba30f0SMarcel Holtmann 354fba30f0SMarcel Holtmann #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) 36a8f3b941SFrederic Danis #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) 374a546ec3SFrederic Danis #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) 384fba30f0SMarcel Holtmann 394fba30f0SMarcel Holtmann int btbcm_check_bdaddr(struct hci_dev *hdev) 404fba30f0SMarcel Holtmann { 414fba30f0SMarcel Holtmann struct hci_rp_read_bd_addr *bda; 424fba30f0SMarcel Holtmann struct sk_buff *skb; 434fba30f0SMarcel Holtmann 444fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_BD_ADDR, 0, NULL, 454fba30f0SMarcel Holtmann HCI_INIT_TIMEOUT); 464fba30f0SMarcel Holtmann if (IS_ERR(skb)) { 474fba30f0SMarcel Holtmann int err = PTR_ERR(skb); 482064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err); 494fba30f0SMarcel Holtmann return err; 504fba30f0SMarcel Holtmann } 514fba30f0SMarcel Holtmann 524fba30f0SMarcel Holtmann if (skb->len != sizeof(*bda)) { 532064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Device address length mismatch"); 544fba30f0SMarcel Holtmann kfree_skb(skb); 554fba30f0SMarcel Holtmann return -EIO; 564fba30f0SMarcel Holtmann } 574fba30f0SMarcel Holtmann 584fba30f0SMarcel Holtmann bda = (struct hci_rp_read_bd_addr *)skb->data; 594fba30f0SMarcel Holtmann 60a8f3b941SFrederic Danis /* Check if the address indicates a controller with either an 61a8f3b941SFrederic Danis * invalid or default address. In both cases the device needs 62a8f3b941SFrederic Danis * to be marked as not having a valid address. 63a8f3b941SFrederic Danis * 64a8f3b941SFrederic Danis * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller 654fba30f0SMarcel Holtmann * with no configured address. 66a8f3b941SFrederic Danis * 67a8f3b941SFrederic Danis * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller 68a8f3b941SFrederic Danis * with waiting for configuration state. 694a546ec3SFrederic Danis * 704a546ec3SFrederic Danis * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller 714a546ec3SFrederic Danis * with waiting for configuration state. 724fba30f0SMarcel Holtmann */ 73a8f3b941SFrederic Danis if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || 744a546ec3SFrederic Danis !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || 754a546ec3SFrederic Danis !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { 762064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: Using default device address (%pMR)", 772064ee33SMarcel Holtmann &bda->bdaddr); 784fba30f0SMarcel Holtmann set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); 794fba30f0SMarcel Holtmann } 804fba30f0SMarcel Holtmann 814fba30f0SMarcel Holtmann kfree_skb(skb); 824fba30f0SMarcel Holtmann 834fba30f0SMarcel Holtmann return 0; 844fba30f0SMarcel Holtmann } 854fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_check_bdaddr); 864fba30f0SMarcel Holtmann 874fba30f0SMarcel Holtmann int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) 884fba30f0SMarcel Holtmann { 894fba30f0SMarcel Holtmann struct sk_buff *skb; 904fba30f0SMarcel Holtmann int err; 914fba30f0SMarcel Holtmann 924fba30f0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc01, 6, bdaddr, HCI_INIT_TIMEOUT); 934fba30f0SMarcel Holtmann if (IS_ERR(skb)) { 944fba30f0SMarcel Holtmann err = PTR_ERR(skb); 952064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Change address command failed (%d)", err); 964fba30f0SMarcel Holtmann return err; 974fba30f0SMarcel Holtmann } 984fba30f0SMarcel Holtmann kfree_skb(skb); 994fba30f0SMarcel Holtmann 1004fba30f0SMarcel Holtmann return 0; 1014fba30f0SMarcel Holtmann } 1024fba30f0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); 1034fba30f0SMarcel Holtmann 10418aeb444SFrederic Danis int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) 10550862ee5SMarcel Holtmann { 10650862ee5SMarcel Holtmann const struct hci_command_hdr *cmd; 10750862ee5SMarcel Holtmann const u8 *fw_ptr; 10850862ee5SMarcel Holtmann size_t fw_size; 10950862ee5SMarcel Holtmann struct sk_buff *skb; 11050862ee5SMarcel Holtmann u16 opcode; 11118aeb444SFrederic Danis int err = 0; 11250862ee5SMarcel Holtmann 11350862ee5SMarcel Holtmann /* Start Download */ 11450862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); 11550862ee5SMarcel Holtmann if (IS_ERR(skb)) { 11650862ee5SMarcel Holtmann err = PTR_ERR(skb); 1172064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Download Minidrv command failed (%d)", 1182064ee33SMarcel Holtmann err); 11950862ee5SMarcel Holtmann goto done; 12050862ee5SMarcel Holtmann } 12150862ee5SMarcel Holtmann kfree_skb(skb); 12250862ee5SMarcel Holtmann 12350862ee5SMarcel Holtmann /* 50 msec delay after Download Minidrv completes */ 12450862ee5SMarcel Holtmann msleep(50); 12550862ee5SMarcel Holtmann 12650862ee5SMarcel Holtmann fw_ptr = fw->data; 12750862ee5SMarcel Holtmann fw_size = fw->size; 12850862ee5SMarcel Holtmann 12950862ee5SMarcel Holtmann while (fw_size >= sizeof(*cmd)) { 13050862ee5SMarcel Holtmann const u8 *cmd_param; 13150862ee5SMarcel Holtmann 13250862ee5SMarcel Holtmann cmd = (struct hci_command_hdr *)fw_ptr; 13350862ee5SMarcel Holtmann fw_ptr += sizeof(*cmd); 13450862ee5SMarcel Holtmann fw_size -= sizeof(*cmd); 13550862ee5SMarcel Holtmann 13650862ee5SMarcel Holtmann if (fw_size < cmd->plen) { 1372064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch is corrupted"); 13850862ee5SMarcel Holtmann err = -EINVAL; 13950862ee5SMarcel Holtmann goto done; 14050862ee5SMarcel Holtmann } 14150862ee5SMarcel Holtmann 14250862ee5SMarcel Holtmann cmd_param = fw_ptr; 14350862ee5SMarcel Holtmann fw_ptr += cmd->plen; 14450862ee5SMarcel Holtmann fw_size -= cmd->plen; 14550862ee5SMarcel Holtmann 14650862ee5SMarcel Holtmann opcode = le16_to_cpu(cmd->opcode); 14750862ee5SMarcel Holtmann 14850862ee5SMarcel Holtmann skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, 14950862ee5SMarcel Holtmann HCI_INIT_TIMEOUT); 15050862ee5SMarcel Holtmann if (IS_ERR(skb)) { 15150862ee5SMarcel Holtmann err = PTR_ERR(skb); 1522064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Patch command %04x failed (%d)", 1532064ee33SMarcel Holtmann opcode, err); 15450862ee5SMarcel Holtmann goto done; 15550862ee5SMarcel Holtmann } 15650862ee5SMarcel Holtmann kfree_skb(skb); 15750862ee5SMarcel Holtmann } 15850862ee5SMarcel Holtmann 15950862ee5SMarcel Holtmann /* 250 msec delay after Launch Ram completes */ 16050862ee5SMarcel Holtmann msleep(250); 16150862ee5SMarcel Holtmann 16250862ee5SMarcel Holtmann done: 16350862ee5SMarcel Holtmann return err; 16450862ee5SMarcel Holtmann } 16550862ee5SMarcel Holtmann EXPORT_SYMBOL(btbcm_patchram); 16650862ee5SMarcel Holtmann 1671c8ba6d0SMarcel Holtmann static int btbcm_reset(struct hci_dev *hdev) 1681c8ba6d0SMarcel Holtmann { 1691c8ba6d0SMarcel Holtmann struct sk_buff *skb; 1701c8ba6d0SMarcel Holtmann 1711c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); 1721c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 1731c8ba6d0SMarcel Holtmann int err = PTR_ERR(skb); 1742064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reset failed (%d)", err); 1751c8ba6d0SMarcel Holtmann return err; 1761c8ba6d0SMarcel Holtmann } 1771c8ba6d0SMarcel Holtmann kfree_skb(skb); 1781c8ba6d0SMarcel Holtmann 1793af3a594SWen-chien Jesse Sung /* 100 msec delay for module to complete reset process */ 1803af3a594SWen-chien Jesse Sung msleep(100); 1813af3a594SWen-chien Jesse Sung 1821c8ba6d0SMarcel Holtmann return 0; 1831c8ba6d0SMarcel Holtmann } 1841c8ba6d0SMarcel Holtmann 1859bc63ca0SMarcel Holtmann static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev) 1869bc63ca0SMarcel Holtmann { 1879bc63ca0SMarcel Holtmann struct sk_buff *skb; 1889bc63ca0SMarcel Holtmann 1899bc63ca0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL, 1909bc63ca0SMarcel Holtmann HCI_INIT_TIMEOUT); 1919bc63ca0SMarcel Holtmann if (IS_ERR(skb)) { 1922064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local name failed (%ld)", 1932064ee33SMarcel Holtmann PTR_ERR(skb)); 1949bc63ca0SMarcel Holtmann return skb; 1959bc63ca0SMarcel Holtmann } 1969bc63ca0SMarcel Holtmann 1979bc63ca0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_name)) { 1982064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local name length mismatch"); 1999bc63ca0SMarcel Holtmann kfree_skb(skb); 2009bc63ca0SMarcel Holtmann return ERR_PTR(-EIO); 2019bc63ca0SMarcel Holtmann } 2029bc63ca0SMarcel Holtmann 2039bc63ca0SMarcel Holtmann return skb; 2049bc63ca0SMarcel Holtmann } 2059bc63ca0SMarcel Holtmann 2061c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev) 2071c8ba6d0SMarcel Holtmann { 2081c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2091c8ba6d0SMarcel Holtmann 2101c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, 2111c8ba6d0SMarcel Holtmann HCI_INIT_TIMEOUT); 2121c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2132064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Reading local version info failed (%ld)", 2142064ee33SMarcel Holtmann PTR_ERR(skb)); 2151c8ba6d0SMarcel Holtmann return skb; 2161c8ba6d0SMarcel Holtmann } 2171c8ba6d0SMarcel Holtmann 2181c8ba6d0SMarcel Holtmann if (skb->len != sizeof(struct hci_rp_read_local_version)) { 2192064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Local version length mismatch"); 2201c8ba6d0SMarcel Holtmann kfree_skb(skb); 2211c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 2221c8ba6d0SMarcel Holtmann } 2231c8ba6d0SMarcel Holtmann 2241c8ba6d0SMarcel Holtmann return skb; 2251c8ba6d0SMarcel Holtmann } 2261c8ba6d0SMarcel Holtmann 2271c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_verbose_config(struct hci_dev *hdev) 2281c8ba6d0SMarcel Holtmann { 2291c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2301c8ba6d0SMarcel Holtmann 2311c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc79, 0, NULL, HCI_INIT_TIMEOUT); 2321c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2332064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read verbose config info failed (%ld)", 2342064ee33SMarcel Holtmann PTR_ERR(skb)); 2351c8ba6d0SMarcel Holtmann return skb; 2361c8ba6d0SMarcel Holtmann } 2371c8ba6d0SMarcel Holtmann 2381c8ba6d0SMarcel Holtmann if (skb->len != 7) { 2392064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Verbose config length mismatch"); 2401c8ba6d0SMarcel Holtmann kfree_skb(skb); 2411c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 2421c8ba6d0SMarcel Holtmann } 2431c8ba6d0SMarcel Holtmann 2441c8ba6d0SMarcel Holtmann return skb; 2451c8ba6d0SMarcel Holtmann } 2461c8ba6d0SMarcel Holtmann 2474284ecbeSMarcel Holtmann static struct sk_buff *btbcm_read_controller_features(struct hci_dev *hdev) 2484284ecbeSMarcel Holtmann { 2494284ecbeSMarcel Holtmann struct sk_buff *skb; 2504284ecbeSMarcel Holtmann 2514284ecbeSMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc6e, 0, NULL, HCI_INIT_TIMEOUT); 2524284ecbeSMarcel Holtmann if (IS_ERR(skb)) { 2532064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read controller features failed (%ld)", 2542064ee33SMarcel Holtmann PTR_ERR(skb)); 2554284ecbeSMarcel Holtmann return skb; 2564284ecbeSMarcel Holtmann } 2574284ecbeSMarcel Holtmann 2584284ecbeSMarcel Holtmann if (skb->len != 9) { 2592064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Controller features length mismatch"); 2604284ecbeSMarcel Holtmann kfree_skb(skb); 2614284ecbeSMarcel Holtmann return ERR_PTR(-EIO); 2624284ecbeSMarcel Holtmann } 2634284ecbeSMarcel Holtmann 2644284ecbeSMarcel Holtmann return skb; 2654284ecbeSMarcel Holtmann } 2664284ecbeSMarcel Holtmann 2671c8ba6d0SMarcel Holtmann static struct sk_buff *btbcm_read_usb_product(struct hci_dev *hdev) 2681c8ba6d0SMarcel Holtmann { 2691c8ba6d0SMarcel Holtmann struct sk_buff *skb; 2701c8ba6d0SMarcel Holtmann 2711c8ba6d0SMarcel Holtmann skb = __hci_cmd_sync(hdev, 0xfc5a, 0, NULL, HCI_INIT_TIMEOUT); 2721c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) { 2732064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: Read USB product info failed (%ld)", 2742064ee33SMarcel Holtmann PTR_ERR(skb)); 2751c8ba6d0SMarcel Holtmann return skb; 2761c8ba6d0SMarcel Holtmann } 2771c8ba6d0SMarcel Holtmann 2781c8ba6d0SMarcel Holtmann if (skb->len != 5) { 2792064ee33SMarcel Holtmann bt_dev_err(hdev, "BCM: USB product length mismatch"); 2801c8ba6d0SMarcel Holtmann kfree_skb(skb); 2811c8ba6d0SMarcel Holtmann return ERR_PTR(-EIO); 2821c8ba6d0SMarcel Holtmann } 2831c8ba6d0SMarcel Holtmann 2841c8ba6d0SMarcel Holtmann return skb; 2851c8ba6d0SMarcel Holtmann } 2861c8ba6d0SMarcel Holtmann 287e76dc1ddSMarcel Holtmann static int btbcm_read_info(struct hci_dev *hdev) 288e76dc1ddSMarcel Holtmann { 289e76dc1ddSMarcel Holtmann struct sk_buff *skb; 290e76dc1ddSMarcel Holtmann 291e76dc1ddSMarcel Holtmann /* Read Verbose Config Version Info */ 292e76dc1ddSMarcel Holtmann skb = btbcm_read_verbose_config(hdev); 293e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 294e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 295e76dc1ddSMarcel Holtmann 2962064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u", skb->data[1]); 297e76dc1ddSMarcel Holtmann kfree_skb(skb); 298e76dc1ddSMarcel Holtmann 299e76dc1ddSMarcel Holtmann /* Read Controller Features */ 300e76dc1ddSMarcel Holtmann skb = btbcm_read_controller_features(hdev); 301e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 302e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 303e76dc1ddSMarcel Holtmann 3042064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); 305e76dc1ddSMarcel Holtmann kfree_skb(skb); 306e76dc1ddSMarcel Holtmann 307e76dc1ddSMarcel Holtmann /* Read Local Name */ 308e76dc1ddSMarcel Holtmann skb = btbcm_read_local_name(hdev); 309e76dc1ddSMarcel Holtmann if (IS_ERR(skb)) 310e76dc1ddSMarcel Holtmann return PTR_ERR(skb); 311e76dc1ddSMarcel Holtmann 3122064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); 313e76dc1ddSMarcel Holtmann kfree_skb(skb); 314e76dc1ddSMarcel Holtmann 315e76dc1ddSMarcel Holtmann return 0; 316e76dc1ddSMarcel Holtmann } 317e76dc1ddSMarcel Holtmann 318f7328381SHans de Goede struct bcm_subver_table { 3191c8ba6d0SMarcel Holtmann u16 subver; 3201c8ba6d0SMarcel Holtmann const char *name; 321f7328381SHans de Goede }; 322f7328381SHans de Goede 323f7328381SHans de Goede static const struct bcm_subver_table bcm_uart_subver_table[] = { 3244a546ec3SFrederic Danis { 0x4103, "BCM4330B1" }, /* 002.001.003 */ 3259a0bb57dSMarcel Holtmann { 0x410e, "BCM43341B0" }, /* 002.001.014 */ 326a8f3b941SFrederic Danis { 0x4406, "BCM4324B3" }, /* 002.004.006 */ 32740db5f0eSIlya Faenson { 0x610c, "BCM4354" }, /* 003.001.012 */ 328d456f678SJörg Krause { 0x2122, "BCM4343A0" }, /* 001.001.034 */ 329feb16722SIan Molton { 0x2209, "BCM43430A1" }, /* 001.002.009 */ 33018a39b9aSIan W MORRISON { 0x6119, "BCM4345C0" }, /* 003.001.025 */ 331b133e0c4SHans de Goede { 0x230f, "BCM4356A2" }, /* 001.003.015 */ 3329a0bb57dSMarcel Holtmann { } 3339a0bb57dSMarcel Holtmann }; 3349a0bb57dSMarcel Holtmann 335fec0de23SHans de Goede static const struct bcm_subver_table bcm_usb_subver_table[] = { 336fec0de23SHans de Goede { 0x210b, "BCM43142A0" }, /* 001.001.011 */ 337fec0de23SHans de Goede { 0x2112, "BCM4314A0" }, /* 001.001.018 */ 338fec0de23SHans de Goede { 0x2118, "BCM20702A0" }, /* 001.001.024 */ 339fec0de23SHans de Goede { 0x2126, "BCM4335A0" }, /* 001.001.038 */ 340fec0de23SHans de Goede { 0x220e, "BCM20702A1" }, /* 001.002.014 */ 341fec0de23SHans de Goede { 0x230f, "BCM4354A2" }, /* 001.003.015 */ 342fec0de23SHans de Goede { 0x4106, "BCM4335B0" }, /* 002.001.006 */ 343fec0de23SHans de Goede { 0x410e, "BCM20702B0" }, /* 002.001.014 */ 344fec0de23SHans de Goede { 0x6109, "BCM4335C0" }, /* 003.001.009 */ 345fec0de23SHans de Goede { 0x610c, "BCM4354" }, /* 003.001.012 */ 346fec0de23SHans de Goede { } 347fec0de23SHans de Goede }; 348fec0de23SHans de Goede 34975e167e6SFrederic Danis int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len) 35075e167e6SFrederic Danis { 351fec0de23SHans de Goede u16 subver, rev, pid, vid; 35275e167e6SFrederic Danis const char *hw_name = NULL; 35375e167e6SFrederic Danis struct sk_buff *skb; 35475e167e6SFrederic Danis struct hci_rp_read_local_version *ver; 355fec0de23SHans de Goede const struct bcm_subver_table *bcm_subver_table; 35675e167e6SFrederic Danis int i, err; 35775e167e6SFrederic Danis 35875e167e6SFrederic Danis /* Reset */ 35975e167e6SFrederic Danis err = btbcm_reset(hdev); 36075e167e6SFrederic Danis if (err) 36175e167e6SFrederic Danis return err; 36275e167e6SFrederic Danis 36375e167e6SFrederic Danis /* Read Local Version Info */ 36475e167e6SFrederic Danis skb = btbcm_read_local_version(hdev); 36575e167e6SFrederic Danis if (IS_ERR(skb)) 36675e167e6SFrederic Danis return PTR_ERR(skb); 36775e167e6SFrederic Danis 36875e167e6SFrederic Danis ver = (struct hci_rp_read_local_version *)skb->data; 36975e167e6SFrederic Danis rev = le16_to_cpu(ver->hci_rev); 37075e167e6SFrederic Danis subver = le16_to_cpu(ver->lmp_subver); 37175e167e6SFrederic Danis kfree_skb(skb); 37275e167e6SFrederic Danis 373e76dc1ddSMarcel Holtmann /* Read controller information */ 374e76dc1ddSMarcel Holtmann err = btbcm_read_info(hdev); 375e76dc1ddSMarcel Holtmann if (err) 376e76dc1ddSMarcel Holtmann return err; 37775e167e6SFrederic Danis 378fec0de23SHans de Goede /* Upper nibble of rev should be between 0 and 3? */ 379fec0de23SHans de Goede if (((rev & 0xf000) >> 12) > 3) 380fec0de23SHans de Goede return 0; 381fec0de23SHans de Goede 382fec0de23SHans de Goede bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : 383fec0de23SHans de Goede bcm_uart_subver_table; 384fec0de23SHans de Goede 385fec0de23SHans de Goede for (i = 0; bcm_subver_table[i].name; i++) { 386fec0de23SHans de Goede if (subver == bcm_subver_table[i].subver) { 387fec0de23SHans de Goede hw_name = bcm_subver_table[i].name; 38875e167e6SFrederic Danis break; 38975e167e6SFrederic Danis } 39075e167e6SFrederic Danis } 39175e167e6SFrederic Danis 392fec0de23SHans de Goede if (hdev->bus == HCI_USB) { 393fec0de23SHans de Goede /* Read USB Product Info */ 394fec0de23SHans de Goede skb = btbcm_read_usb_product(hdev); 395fec0de23SHans de Goede if (IS_ERR(skb)) 396fec0de23SHans de Goede return PTR_ERR(skb); 397fec0de23SHans de Goede 398fec0de23SHans de Goede vid = get_unaligned_le16(skb->data + 1); 399fec0de23SHans de Goede pid = get_unaligned_le16(skb->data + 3); 400fec0de23SHans de Goede kfree_skb(skb); 401fec0de23SHans de Goede 402fec0de23SHans de Goede snprintf(fw_name, len, "brcm/%s-%4.4x-%4.4x.hcd", 403fec0de23SHans de Goede hw_name ? : "BCM", vid, pid); 404fec0de23SHans de Goede } else { 405fec0de23SHans de Goede snprintf(fw_name, len, "brcm/%s.hcd", 406fec0de23SHans de Goede hw_name ? : "BCM"); 40775e167e6SFrederic Danis } 40875e167e6SFrederic Danis 4092064ee33SMarcel Holtmann bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", 4108045ce21SMarcel Holtmann hw_name ? : "BCM", (subver & 0xe000) >> 13, 41175e167e6SFrederic Danis (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); 41275e167e6SFrederic Danis 41375e167e6SFrederic Danis return 0; 41475e167e6SFrederic Danis } 41575e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_initialize); 41675e167e6SFrederic Danis 41775e167e6SFrederic Danis int btbcm_finalize(struct hci_dev *hdev) 41875e167e6SFrederic Danis { 41975e167e6SFrederic Danis struct sk_buff *skb; 42075e167e6SFrederic Danis struct hci_rp_read_local_version *ver; 42175e167e6SFrederic Danis u16 subver, rev; 42275e167e6SFrederic Danis int err; 42375e167e6SFrederic Danis 42475e167e6SFrederic Danis /* Reset */ 42575e167e6SFrederic Danis err = btbcm_reset(hdev); 42675e167e6SFrederic Danis if (err) 42775e167e6SFrederic Danis return err; 42875e167e6SFrederic Danis 42975e167e6SFrederic Danis /* Read Local Version Info */ 43075e167e6SFrederic Danis skb = btbcm_read_local_version(hdev); 43175e167e6SFrederic Danis if (IS_ERR(skb)) 43275e167e6SFrederic Danis return PTR_ERR(skb); 43375e167e6SFrederic Danis 43475e167e6SFrederic Danis ver = (struct hci_rp_read_local_version *)skb->data; 43575e167e6SFrederic Danis rev = le16_to_cpu(ver->hci_rev); 43675e167e6SFrederic Danis subver = le16_to_cpu(ver->lmp_subver); 43775e167e6SFrederic Danis kfree_skb(skb); 43875e167e6SFrederic Danis 4392064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM (%3.3u.%3.3u.%3.3u) build %4.4u", 4408045ce21SMarcel Holtmann (subver & 0xe000) >> 13, (subver & 0x1f00) >> 8, 44175e167e6SFrederic Danis (subver & 0x00ff), rev & 0x0fff); 44275e167e6SFrederic Danis 44375e167e6SFrederic Danis btbcm_check_bdaddr(hdev); 44475e167e6SFrederic Danis 44575e167e6SFrederic Danis set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 44675e167e6SFrederic Danis 44775e167e6SFrederic Danis return 0; 44875e167e6SFrederic Danis } 44975e167e6SFrederic Danis EXPORT_SYMBOL_GPL(btbcm_finalize); 45075e167e6SFrederic Danis 4511c8ba6d0SMarcel Holtmann int btbcm_setup_patchram(struct hci_dev *hdev) 4521c8ba6d0SMarcel Holtmann { 4531c8ba6d0SMarcel Holtmann char fw_name[64]; 45418aeb444SFrederic Danis const struct firmware *fw; 45550862ee5SMarcel Holtmann u16 subver, rev, pid, vid; 4561c8ba6d0SMarcel Holtmann const char *hw_name = NULL; 4571c8ba6d0SMarcel Holtmann struct sk_buff *skb; 4581c8ba6d0SMarcel Holtmann struct hci_rp_read_local_version *ver; 459f7328381SHans de Goede const struct bcm_subver_table *bcm_subver_table; 4601c8ba6d0SMarcel Holtmann int i, err; 4611c8ba6d0SMarcel Holtmann 4621c8ba6d0SMarcel Holtmann /* Reset */ 4631c8ba6d0SMarcel Holtmann err = btbcm_reset(hdev); 4641c8ba6d0SMarcel Holtmann if (err) 4651c8ba6d0SMarcel Holtmann return err; 4661c8ba6d0SMarcel Holtmann 4671c8ba6d0SMarcel Holtmann /* Read Local Version Info */ 4681c8ba6d0SMarcel Holtmann skb = btbcm_read_local_version(hdev); 4691c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) 4701c8ba6d0SMarcel Holtmann return PTR_ERR(skb); 4711c8ba6d0SMarcel Holtmann 4721c8ba6d0SMarcel Holtmann ver = (struct hci_rp_read_local_version *)skb->data; 4731c8ba6d0SMarcel Holtmann rev = le16_to_cpu(ver->hci_rev); 4741c8ba6d0SMarcel Holtmann subver = le16_to_cpu(ver->lmp_subver); 4751c8ba6d0SMarcel Holtmann kfree_skb(skb); 4761c8ba6d0SMarcel Holtmann 477e76dc1ddSMarcel Holtmann /* Read controller information */ 478e76dc1ddSMarcel Holtmann err = btbcm_read_info(hdev); 479e76dc1ddSMarcel Holtmann if (err) 480e76dc1ddSMarcel Holtmann return err; 4819bc63ca0SMarcel Holtmann 4821b2525c0SHans de Goede /* Upper nibble of rev should be between 0 and 3? */ 4831b2525c0SHans de Goede if (((rev & 0xf000) >> 12) > 3) 4841b2525c0SHans de Goede return 0; 4851b2525c0SHans de Goede 486f7328381SHans de Goede bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : 487f7328381SHans de Goede bcm_uart_subver_table; 488f7328381SHans de Goede 489f7328381SHans de Goede for (i = 0; bcm_subver_table[i].name; i++) { 490f7328381SHans de Goede if (subver == bcm_subver_table[i].subver) { 491f7328381SHans de Goede hw_name = bcm_subver_table[i].name; 4929a0bb57dSMarcel Holtmann break; 4939a0bb57dSMarcel Holtmann } 4949a0bb57dSMarcel Holtmann } 4959a0bb57dSMarcel Holtmann 496f7328381SHans de Goede if (hdev->bus == HCI_USB) { 4971c8ba6d0SMarcel Holtmann /* Read USB Product Info */ 4981c8ba6d0SMarcel Holtmann skb = btbcm_read_usb_product(hdev); 4991c8ba6d0SMarcel Holtmann if (IS_ERR(skb)) 5001c8ba6d0SMarcel Holtmann return PTR_ERR(skb); 5011c8ba6d0SMarcel Holtmann 5021c8ba6d0SMarcel Holtmann vid = get_unaligned_le16(skb->data + 1); 5031c8ba6d0SMarcel Holtmann pid = get_unaligned_le16(skb->data + 3); 5041c8ba6d0SMarcel Holtmann kfree_skb(skb); 5051c8ba6d0SMarcel Holtmann 5069a0bb57dSMarcel Holtmann snprintf(fw_name, sizeof(fw_name), "brcm/%s-%4.4x-%4.4x.hcd", 5079a0bb57dSMarcel Holtmann hw_name ? : "BCM", vid, pid); 508f7328381SHans de Goede } else { 509f7328381SHans de Goede snprintf(fw_name, sizeof(fw_name), "brcm/%s.hcd", 510f7328381SHans de Goede hw_name ? : "BCM"); 5119a0bb57dSMarcel Holtmann } 5129a0bb57dSMarcel Holtmann 5132064ee33SMarcel Holtmann bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", 5148045ce21SMarcel Holtmann hw_name ? : "BCM", (subver & 0xe000) >> 13, 5151c8ba6d0SMarcel Holtmann (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); 5161c8ba6d0SMarcel Holtmann 51718aeb444SFrederic Danis err = request_firmware(&fw, fw_name, &hdev->dev); 51818aeb444SFrederic Danis if (err < 0) { 5192064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: Patch %s not found", fw_name); 520ad750fa1SPetri Gynther goto done; 52118aeb444SFrederic Danis } 52218aeb444SFrederic Danis 52318aeb444SFrederic Danis btbcm_patchram(hdev, fw); 52418aeb444SFrederic Danis 52518aeb444SFrederic Danis release_firmware(fw); 5261c8ba6d0SMarcel Holtmann 5271c8ba6d0SMarcel Holtmann /* Reset */ 5281c8ba6d0SMarcel Holtmann err = btbcm_reset(hdev); 5291c8ba6d0SMarcel Holtmann if (err) 53050862ee5SMarcel Holtmann return err; 5311c8ba6d0SMarcel Holtmann 5321c8ba6d0SMarcel Holtmann /* Read Local Version Info */ 5331c8ba6d0SMarcel Holtmann skb = btbcm_read_local_version(hdev); 53450862ee5SMarcel Holtmann if (IS_ERR(skb)) 53550862ee5SMarcel Holtmann return PTR_ERR(skb); 5361c8ba6d0SMarcel Holtmann 5371c8ba6d0SMarcel Holtmann ver = (struct hci_rp_read_local_version *)skb->data; 5381c8ba6d0SMarcel Holtmann rev = le16_to_cpu(ver->hci_rev); 5391c8ba6d0SMarcel Holtmann subver = le16_to_cpu(ver->lmp_subver); 5401c8ba6d0SMarcel Holtmann kfree_skb(skb); 5411c8ba6d0SMarcel Holtmann 5422064ee33SMarcel Holtmann bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", 5438045ce21SMarcel Holtmann hw_name ? : "BCM", (subver & 0xe000) >> 13, 5441c8ba6d0SMarcel Holtmann (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); 5451c8ba6d0SMarcel Holtmann 5469bc63ca0SMarcel Holtmann /* Read Local Name */ 5479bc63ca0SMarcel Holtmann skb = btbcm_read_local_name(hdev); 5489bc63ca0SMarcel Holtmann if (IS_ERR(skb)) 5499bc63ca0SMarcel Holtmann return PTR_ERR(skb); 5509bc63ca0SMarcel Holtmann 5512064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); 5529bc63ca0SMarcel Holtmann kfree_skb(skb); 5539bc63ca0SMarcel Holtmann 554ad750fa1SPetri Gynther done: 5551c8ba6d0SMarcel Holtmann btbcm_check_bdaddr(hdev); 5561c8ba6d0SMarcel Holtmann 557941521e2SMarcel Holtmann set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 558941521e2SMarcel Holtmann 55950862ee5SMarcel Holtmann return 0; 5601c8ba6d0SMarcel Holtmann } 5611c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_patchram); 5621c8ba6d0SMarcel Holtmann 5631c8ba6d0SMarcel Holtmann int btbcm_setup_apple(struct hci_dev *hdev) 5641c8ba6d0SMarcel Holtmann { 5651c8ba6d0SMarcel Holtmann struct sk_buff *skb; 566b224d3ffSMarcel Holtmann int err; 567b224d3ffSMarcel Holtmann 568b224d3ffSMarcel Holtmann /* Reset */ 569b224d3ffSMarcel Holtmann err = btbcm_reset(hdev); 570b224d3ffSMarcel Holtmann if (err) 571b224d3ffSMarcel Holtmann return err; 5721c8ba6d0SMarcel Holtmann 5731c8ba6d0SMarcel Holtmann /* Read Verbose Config Version Info */ 5741c8ba6d0SMarcel Holtmann skb = btbcm_read_verbose_config(hdev); 5757bee8b08SChris Mason if (!IS_ERR(skb)) { 5762064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: chip id %u build %4.4u", 577b224d3ffSMarcel Holtmann skb->data[1], get_unaligned_le16(skb->data + 5)); 5781c8ba6d0SMarcel Holtmann kfree_skb(skb); 5797bee8b08SChris Mason } 5801c8ba6d0SMarcel Holtmann 58134cea41eSMarcel Holtmann /* Read USB Product Info */ 58234cea41eSMarcel Holtmann skb = btbcm_read_usb_product(hdev); 58334cea41eSMarcel Holtmann if (!IS_ERR(skb)) { 5842064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: product %4.4x:%4.4x", 58534cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 1), 58634cea41eSMarcel Holtmann get_unaligned_le16(skb->data + 3)); 58734cea41eSMarcel Holtmann kfree_skb(skb); 58834cea41eSMarcel Holtmann } 58934cea41eSMarcel Holtmann 5904284ecbeSMarcel Holtmann /* Read Controller Features */ 5914284ecbeSMarcel Holtmann skb = btbcm_read_controller_features(hdev); 5924284ecbeSMarcel Holtmann if (!IS_ERR(skb)) { 5932064ee33SMarcel Holtmann bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); 5944284ecbeSMarcel Holtmann kfree_skb(skb); 5954284ecbeSMarcel Holtmann } 5964284ecbeSMarcel Holtmann 5979bc63ca0SMarcel Holtmann /* Read Local Name */ 5989bc63ca0SMarcel Holtmann skb = btbcm_read_local_name(hdev); 5999bc63ca0SMarcel Holtmann if (!IS_ERR(skb)) { 6002064ee33SMarcel Holtmann bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); 6019bc63ca0SMarcel Holtmann kfree_skb(skb); 6029bc63ca0SMarcel Holtmann } 6039bc63ca0SMarcel Holtmann 604941521e2SMarcel Holtmann set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); 605941521e2SMarcel Holtmann 6061c8ba6d0SMarcel Holtmann return 0; 6071c8ba6d0SMarcel Holtmann } 6081c8ba6d0SMarcel Holtmann EXPORT_SYMBOL_GPL(btbcm_setup_apple); 6091c8ba6d0SMarcel Holtmann 6104fba30f0SMarcel Holtmann MODULE_AUTHOR("Marcel Holtmann <marcel@holtmann.org>"); 6114fba30f0SMarcel Holtmann MODULE_DESCRIPTION("Bluetooth support for Broadcom devices ver " VERSION); 6124fba30f0SMarcel Holtmann MODULE_VERSION(VERSION); 6134fba30f0SMarcel Holtmann MODULE_LICENSE("GPL"); 614