Merge branch 'for-upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetoot...
authorJohn W. Linville <linville@tuxdriver.com>
Thu, 29 May 2014 17:03:47 +0000 (13:03 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Thu, 29 May 2014 17:03:47 +0000 (13:03 -0400)
Conflicts:
drivers/bluetooth/btusb.c

1  2 
drivers/bluetooth/btusb.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_event.c
net/bluetooth/rfcomm/core.c

index a7dfbf9a3afb6be53e372f78d9ee8202bdb17d08,8f579cd9bbaf398489764ea3e78ecca2146d818d..a1c80b0c7663d25baf2224bae0513b3bb29c6543
@@@ -49,6 -49,7 +49,7 @@@ static struct usb_driver btusb_driver
  #define BTUSB_WRONG_SCO_MTU   0x40
  #define BTUSB_ATH3012         0x80
  #define BTUSB_INTEL           0x100
+ #define BTUSB_BCM_PATCHRAM    0x200
  
  static const struct usb_device_id btusb_table[] = {
        /* Generic Bluetooth USB device */
        { USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01) },
  
        /* Broadcom devices with vendor specific id */
-       { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01) },
+       { USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
+         .driver_info = BTUSB_BCM_PATCHRAM },
  
        /* Belkin F8065bf - Broadcom based */
        { USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
@@@ -152,7 -154,6 +154,7 @@@ static const struct usb_device_id black
        { USB_DEVICE(0x04ca, 0x3004), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3005), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3006), .driver_info = BTUSB_ATH3012 },
 +      { USB_DEVICE(0x04ca, 0x3007), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x3008), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x04ca, 0x300b), .driver_info = BTUSB_ATH3012 },
        { USB_DEVICE(0x0930, 0x0219), .driver_info = BTUSB_ATH3012 },
@@@ -1381,6 -1382,154 +1383,154 @@@ exit_mfg_deactivate
        return 0;
  }
  
+ static int btusb_setup_bcm_patchram(struct hci_dev *hdev)
+ {
+       struct btusb_data *data = hci_get_drvdata(hdev);
+       struct usb_device *udev = data->udev;
+       char fw_name[64];
+       const struct firmware *fw;
+       const u8 *fw_ptr;
+       size_t fw_size;
+       const struct hci_command_hdr *cmd;
+       const u8 *cmd_param;
+       u16 opcode;
+       struct sk_buff *skb;
+       struct hci_rp_read_local_version *ver;
+       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;
+       }
+       /* Reset */
+       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               ret = PTR_ERR(skb);
+               BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
+               goto done;
+       }
+       kfree_skb(skb);
+       /* Read Local Version Info */
+       skb = __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;
+       }
+       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;
+       }
+       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);
+       /* Start Download */
+       skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               ret = PTR_ERR(skb);
+               BT_ERR("%s: BCM: Download Minidrv command failed (%ld)",
+                       hdev->name, ret);
+               goto reset_fw;
+       }
+       kfree_skb(skb);
+       /* 50 msec delay after Download Minidrv completes */
+       msleep(50);
+       fw_ptr = fw->data;
+       fw_size = fw->size;
+       while (fw_size >= sizeof(*cmd)) {
+               cmd = (struct hci_command_hdr *) fw_ptr;
+               fw_ptr += sizeof(*cmd);
+               fw_size -= sizeof(*cmd);
+               if (fw_size < cmd->plen) {
+                       BT_ERR("%s: BCM: patch %s is corrupted",
+                               hdev->name, fw_name);
+                       ret = -EINVAL;
+                       goto reset_fw;
+               }
+               cmd_param = fw_ptr;
+               fw_ptr += cmd->plen;
+               fw_size -= cmd->plen;
+               opcode = le16_to_cpu(cmd->opcode);
+               skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param,
+                                    HCI_INIT_TIMEOUT);
+               if (IS_ERR(skb)) {
+                       ret = PTR_ERR(skb);
+                       BT_ERR("%s: BCM: patch command %04x failed (%ld)",
+                               hdev->name, opcode, ret);
+                       goto reset_fw;
+               }
+               kfree_skb(skb);
+       }
+       /* 250 msec delay after Launch Ram completes */
+       msleep(250);
+ reset_fw:
+       /* Reset */
+       skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+       if (IS_ERR(skb)) {
+               ret = PTR_ERR(skb);
+               BT_ERR("%s: HCI_OP_RESET failed (%ld)", hdev->name, ret);
+               goto done;
+       }
+       kfree_skb(skb);
+       /* Read Local Version Info */
+       skb = __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;
+       }
+       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;
+       }
+       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);
+ done:
+       release_firmware(fw);
+       return ret;
+ }
  static int btusb_probe(struct usb_interface *intf,
                                const struct usb_device_id *id)
  {
        if (id->driver_info & BTUSB_BCM92035)
                hdev->setup = btusb_setup_bcm92035;
  
 -      if (id->driver_info & BTUSB_INTEL) {
 -              usb_enable_autosuspend(data->udev);
+       if (id->driver_info & BTUSB_BCM_PATCHRAM)
+               hdev->setup = btusb_setup_bcm_patchram;
 +      if (id->driver_info & BTUSB_INTEL)
                hdev->setup = btusb_setup_intel;
 -      }
  
        /* Interface numbers are hardcoded in the specification */
        data->isoc = usb_ifnum_to_if(data->udev, 1);
diff --combined net/bluetooth/hci_conn.c
index 095943c02d6e4ae9643cd1099e7e648ef8de6488,1bb8900086ddb2489970f25d0c03a384aaed4982..8671bc79a35bebe23a2f6b269c582bfcfc4add37
@@@ -28,6 -28,7 +28,7 @@@
  
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
+ #include <net/bluetooth/l2cap.h>
  
  #include "smp.h"
  #include "a2mp.h"
@@@ -407,6 -408,8 +408,8 @@@ struct hci_conn *hci_conn_add(struct hc
        conn->io_capability = hdev->io_capability;
        conn->remote_auth = 0xff;
        conn->key_type = 0xff;
+       conn->tx_power = HCI_TX_POWER_INVALID;
+       conn->max_tx_power = HCI_TX_POWER_INVALID;
  
        set_bit(HCI_CONN_POWER_SAVE, &conn->flags);
        conn->disc_timeout = HCI_DISCONN_TIMEOUT;
@@@ -884,17 -887,14 +887,17 @@@ static int hci_conn_auth(struct hci_con
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->flags)) {
                struct hci_cp_auth_requested cp;
  
 -              /* encrypt must be pending if auth is also pending */
 -              set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
 -
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
                             sizeof(cp), &cp);
 +
 +              /* If we're already encrypted set the REAUTH_PEND flag,
 +               * otherwise set the ENCRYPT_PEND.
 +               */
                if (conn->key_type != 0xff)
                        set_bit(HCI_CONN_REAUTH_PEND, &conn->flags);
 +              else
 +                      set_bit(HCI_CONN_ENCRYPT_PEND, &conn->flags);
        }
  
        return 0;
index ca19fd4bbb8f198ed5d3a3b959c35aceb3a1e54e,492d8d5071c79e5783a0ad9defebc334a1377730..3454807a40c53df7e720543e90ab4208d9e0afc2
@@@ -1245,6 -1245,59 +1245,59 @@@ static void hci_cc_write_remote_amp_ass
        amp_write_rem_assoc_continue(hdev, rp->phy_handle);
  }
  
+ static void hci_cc_read_rssi(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+       struct hci_rp_read_rssi *rp = (void *) skb->data;
+       struct hci_conn *conn;
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+       if (rp->status)
+               return;
+       hci_dev_lock(hdev);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (conn)
+               conn->rssi = rp->rssi;
+       hci_dev_unlock(hdev);
+ }
+ static void hci_cc_read_tx_power(struct hci_dev *hdev, struct sk_buff *skb)
+ {
+       struct hci_cp_read_tx_power *sent;
+       struct hci_rp_read_tx_power *rp = (void *) skb->data;
+       struct hci_conn *conn;
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+       if (rp->status)
+               return;
+       sent = hci_sent_cmd_data(hdev, HCI_OP_READ_TX_POWER);
+       if (!sent)
+               return;
+       hci_dev_lock(hdev);
+       conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(rp->handle));
+       if (!conn)
+               goto unlock;
+       switch (sent->type) {
+       case 0x00:
+               conn->tx_power = rp->tx_power;
+               break;
+       case 0x01:
+               conn->max_tx_power = rp->tx_power;
+               break;
+       }
+ unlock:
+       hci_dev_unlock(hdev);
+ }
  static void hci_cs_inquiry(struct hci_dev *hdev, __u8 status)
  {
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
@@@ -2637,6 -2690,14 +2690,14 @@@ static void hci_cmd_complete_evt(struc
                hci_cc_write_remote_amp_assoc(hdev, skb);
                break;
  
+       case HCI_OP_READ_RSSI:
+               hci_cc_read_rssi(hdev, skb);
+               break;
+       case HCI_OP_READ_TX_POWER:
+               hci_cc_read_tx_power(hdev, skb);
+               break;
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@@ -3387,12 -3448,6 +3448,12 @@@ static void hci_key_refresh_complete_ev
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
        if (!conn)
                goto unlock;
 +
 +      /* For BR/EDR the necessary steps are taken through the
 +       * auth_complete event.
 +       */
 +      if (conn->type != LE_LINK)
 +              goto unlock;
  
        if (!ev->status)
                conn->sec_level = conn->pending_sec_level;
index cf620260affaea75c4c1e9875ca338afb04f7b2e,05c609b12a1d7007a811f3176ed546e2b6a64d1e..754b6fe4f742af8ce4662a25065c6caba242295b
@@@ -186,9 -186,9 +186,9 @@@ static void rfcomm_l2state_change(struc
        rfcomm_schedule();
  }
  
 -static void rfcomm_l2data_ready(struct sock *sk, int bytes)
 +static void rfcomm_l2data_ready(struct sock *sk)
  {
 -      BT_DBG("%p bytes %d", sk, bytes);
 +      BT_DBG("%p", sk);
        rfcomm_schedule();
  }
  
@@@ -307,7 -307,7 +307,7 @@@ struct rfcomm_dlc *rfcomm_dlc_alloc(gfp
        setup_timer(&d->timer, rfcomm_dlc_timeout, (unsigned long)d);
  
        skb_queue_head_init(&d->tx_queue);
-       spin_lock_init(&d->lock);
+       mutex_init(&d->lock);
        atomic_set(&d->refcnt, 1);
  
        rfcomm_dlc_clear_state(d);