These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / drivers / bluetooth / btbcm.c
index 3f146c9..0b69794 100644 (file)
@@ -33,6 +33,8 @@
 #define VERSION "0.1"
 
 #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
+#define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
+#define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
 
 int btbcm_check_bdaddr(struct hci_dev *hdev)
 {
@@ -55,17 +57,23 @@ int btbcm_check_bdaddr(struct hci_dev *hdev)
        }
 
        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
+       /* Check if the address indicates a controller with either an
+        * invalid or default address. In both cases the device needs
+        * to be marked as not having a valid address.
+        *
+        * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller
         * with no configured address.
+        *
+        * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller
+        * with waiting for configuration state.
+        *
+        * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller
+        * with waiting for configuration state.
         */
-       if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0)) {
+       if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) ||
+           !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) ||
+           !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) {
                BT_INFO("%s: BCM: Using default device address (%pMR)",
                        hdev->name, &bda->bdaddr);
                set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
@@ -95,21 +103,14 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 }
 EXPORT_SYMBOL_GPL(btbcm_set_bdaddr);
 
-int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
+int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw)
 {
        const struct hci_command_hdr *cmd;
-       const struct firmware *fw;
        const u8 *fw_ptr;
        size_t fw_size;
        struct sk_buff *skb;
        u16 opcode;
-       int err;
-
-       err = request_firmware(&fw, firmware, &hdev->dev);
-       if (err < 0) {
-               BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware);
-               return err;
-       }
+       int err = 0;
 
        /* Start Download */
        skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
@@ -135,8 +136,7 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
                fw_size -= sizeof(*cmd);
 
                if (fw_size < cmd->plen) {
-                       BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name,
-                              firmware);
+                       BT_ERR("%s: BCM: Patch is corrupted", hdev->name);
                        err = -EINVAL;
                        goto done;
                }
@@ -162,7 +162,6 @@ int btbcm_patchram(struct hci_dev *hdev, const char *firmware)
        msleep(250);
 
 done:
-       release_firmware(fw);
        return err;
 }
 EXPORT_SYMBOL(btbcm_patchram);
@@ -182,6 +181,27 @@ static int btbcm_reset(struct hci_dev *hdev)
        return 0;
 }
 
+static struct sk_buff *btbcm_read_local_name(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+
+       skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL,
+                            HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               BT_ERR("%s: BCM: Reading local name failed (%ld)",
+                      hdev->name, PTR_ERR(skb));
+               return skb;
+       }
+
+       if (skb->len != sizeof(struct hci_rp_read_local_name)) {
+               BT_ERR("%s: BCM: Local name length mismatch", hdev->name);
+               kfree_skb(skb);
+               return ERR_PTR(-EIO);
+       }
+
+       return skb;
+}
+
 static struct sk_buff *btbcm_read_local_version(struct hci_dev *hdev)
 {
        struct sk_buff *skb;
@@ -247,10 +267,103 @@ static const struct {
        u16 subver;
        const char *name;
 } bcm_uart_subver_table[] = {
+       { 0x4103, "BCM4330B1"   },      /* 002.001.003 */
        { 0x410e, "BCM43341B0"  },      /* 002.001.014 */
+       { 0x4406, "BCM4324B3"   },      /* 002.004.006 */
+       { 0x610c, "BCM4354"     },      /* 003.001.012 */
        { }
 };
 
+int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len)
+{
+       u16 subver, rev;
+       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:
+       case 1:
+       case 3:
+               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, len, "brcm/%s.hcd", hw_name ? : "BCM");
+               break;
+       default:
+               return 0;
+       }
+
+       BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+               hw_name ? : "BCM", (subver & 0xe000) >> 13,
+               (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_initialize);
+
+int btbcm_finalize(struct hci_dev *hdev)
+{
+       struct sk_buff *skb;
+       struct hci_rp_read_local_version *ver;
+       u16 subver, rev;
+       int 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);
+
+       BT_INFO("%s: BCM (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
+               (subver & 0xe000) >> 13, (subver & 0x1f00) >> 8,
+               (subver & 0x00ff), rev & 0x0fff);
+
+       btbcm_check_bdaddr(hdev);
+
+       set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btbcm_finalize);
+
 static const struct {
        u16 subver;
        const char *name;
@@ -271,6 +384,7 @@ static const struct {
 int btbcm_setup_patchram(struct hci_dev *hdev)
 {
        char fw_name[64];
+       const struct firmware *fw;
        u16 subver, rev, pid, vid;
        const char *hw_name = NULL;
        struct sk_buff *skb;
@@ -300,8 +414,17 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
        BT_INFO("%s: BCM: chip id %u", hdev->name, skb->data[1]);
        kfree_skb(skb);
 
+       /* Read Local Name */
+       skb = btbcm_read_local_name(hdev);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
+       kfree_skb(skb);
+
        switch ((rev & 0xf000) >> 12) {
        case 0:
+       case 3:
                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;
@@ -338,12 +461,18 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
        }
 
        BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
-               hw_name ? : "BCM", (subver & 0x7000) >> 13,
+               hw_name ? : "BCM", (subver & 0xe000) >> 13,
                (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
 
-       err = btbcm_patchram(hdev, fw_name);
-       if (err == -ENOENT)
+       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;
+       }
+
+       btbcm_patchram(hdev, fw);
+
+       release_firmware(fw);
 
        /* Reset */
        err = btbcm_reset(hdev);
@@ -361,9 +490,17 @@ int btbcm_setup_patchram(struct hci_dev *hdev)
        kfree_skb(skb);
 
        BT_INFO("%s: %s (%3.3u.%3.3u.%3.3u) build %4.4u", hdev->name,
-               hw_name ? : "BCM", (subver & 0x7000) >> 13,
+               hw_name ? : "BCM", (subver & 0xe000) >> 13,
                (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff);
 
+       /* Read Local Name */
+       skb = btbcm_read_local_name(hdev);
+       if (IS_ERR(skb))
+               return PTR_ERR(skb);
+
+       BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
+       kfree_skb(skb);
+
        btbcm_check_bdaddr(hdev);
 
        set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
@@ -375,12 +512,34 @@ EXPORT_SYMBOL_GPL(btbcm_setup_patchram);
 int btbcm_setup_apple(struct hci_dev *hdev)
 {
        struct sk_buff *skb;
+       int err;
+
+       /* Reset */
+       err = btbcm_reset(hdev);
+       if (err)
+               return err;
 
        /* Read Verbose Config Version Info */
        skb = btbcm_read_verbose_config(hdev);
        if (!IS_ERR(skb)) {
-               BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name, skb->data[1],
-                       get_unaligned_le16(skb->data + 5));
+               BT_INFO("%s: BCM: chip id %u build %4.4u", hdev->name,
+                       skb->data[1], get_unaligned_le16(skb->data + 5));
+               kfree_skb(skb);
+       }
+
+       /* Read USB Product Info */
+       skb = btbcm_read_usb_product(hdev);
+       if (!IS_ERR(skb)) {
+               BT_INFO("%s: BCM: product %4.4x:%4.4x", hdev->name,
+                       get_unaligned_le16(skb->data + 1),
+                       get_unaligned_le16(skb->data + 3));
+               kfree_skb(skb);
+       }
+
+       /* Read Local Name */
+       skb = btbcm_read_local_name(hdev);
+       if (!IS_ERR(skb)) {
+               BT_INFO("%s: %s", hdev->name, (char *)(skb->data + 1));
                kfree_skb(skb);
        }