Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth...
[cascardo/linux.git] / net / bluetooth / hci_core.c
index 48e1e04..cc27297 100644 (file)
@@ -600,7 +600,15 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
        struct hci_dev *hdev = req->hdev;
        u8 p;
 
-       /* Only send HCI_Delete_Stored_Link_Key if it is supported */
+       /* Some Broadcom based Bluetooth controllers do not support the
+        * Delete Stored Link Key command. They are clearly indicating its
+        * absence in the bit mask of supported commands.
+        *
+        * Check the supported commands and only if the the command is marked
+        * as supported send it. If not supported assume that the controller
+        * does not have actual support for stored link keys which makes this
+        * command redundant anyway.
+         */
        if (hdev->commands[6] & 0x80) {
                struct hci_cp_delete_stored_link_key cp;
 
@@ -754,7 +762,7 @@ void hci_discovery_set_state(struct hci_dev *hdev, int state)
        hdev->discovery.state = state;
 }
 
-static void inquiry_cache_flush(struct hci_dev *hdev)
+void hci_inquiry_cache_flush(struct hci_dev *hdev)
 {
        struct discovery_state *cache = &hdev->discovery;
        struct inquiry_entry *p, *n;
@@ -967,7 +975,7 @@ int hci_inquiry(void __user *arg)
        hci_dev_lock(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
            inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
-               inquiry_cache_flush(hdev);
+               hci_inquiry_cache_flush(hdev);
                do_inquiry = 1;
        }
        hci_dev_unlock(hdev);
@@ -1204,8 +1212,6 @@ static int hci_dev_do_close(struct hci_dev *hdev)
 {
        BT_DBG("%s %p", hdev->name, hdev);
 
-       cancel_work_sync(&hdev->le_scan);
-
        cancel_delayed_work(&hdev->power_off);
 
        hci_req_cancel(hdev, ENODEV);
@@ -1233,7 +1239,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        cancel_delayed_work_sync(&hdev->le_scan_disable);
 
        hci_dev_lock(hdev);
-       inquiry_cache_flush(hdev);
+       hci_inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
        hci_dev_unlock(hdev);
 
@@ -1334,7 +1340,7 @@ int hci_dev_reset(__u16 dev)
        skb_queue_purge(&hdev->cmd_q);
 
        hci_dev_lock(hdev);
-       inquiry_cache_flush(hdev);
+       hci_inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
        hci_dev_unlock(hdev);
 
@@ -1994,80 +2000,59 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
        return mgmt_device_unblocked(hdev, bdaddr, type);
 }
 
-static void le_scan_param_req(struct hci_request *req, unsigned long opt)
+static void inquiry_complete(struct hci_dev *hdev, u8 status)
 {
-       struct le_scan_params *param =  (struct le_scan_params *) opt;
-       struct hci_cp_le_set_scan_param cp;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.type = param->type;
-       cp.interval = cpu_to_le16(param->interval);
-       cp.window = cpu_to_le16(param->window);
+       if (status) {
+               BT_ERR("Failed to start inquiry: status %d", status);
 
-       hci_req_add(req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(cp), &cp);
-}
-
-static void le_scan_enable_req(struct hci_request *req, unsigned long opt)
-{
-       struct hci_cp_le_set_scan_enable cp;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.enable = LE_SCAN_ENABLE;
-       cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
-
-       hci_req_add(req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+               hci_dev_lock(hdev);
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               hci_dev_unlock(hdev);
+               return;
+       }
 }
 
-static int hci_do_le_scan(struct hci_dev *hdev, u8 type, u16 interval,
-                         u16 window, int timeout)
+static void le_scan_disable_work_complete(struct hci_dev *hdev, u8 status)
 {
-       long timeo = msecs_to_jiffies(3000);
-       struct le_scan_params param;
+       /* General inquiry access code (GIAC) */
+       u8 lap[3] = { 0x33, 0x8b, 0x9e };
+       struct hci_request req;
+       struct hci_cp_inquiry cp;
        int err;
 
-       BT_DBG("%s", hdev->name);
-
-       if (test_bit(HCI_LE_SCAN, &hdev->dev_flags))
-               return -EINPROGRESS;
-
-       param.type = type;
-       param.interval = interval;
-       param.window = window;
-
-       hci_req_lock(hdev);
-
-       err = __hci_req_sync(hdev, le_scan_param_req, (unsigned long) &param,
-                            timeo);
-       if (!err)
-               err = __hci_req_sync(hdev, le_scan_enable_req, 0, timeo);
-
-       hci_req_unlock(hdev);
+       if (status) {
+               BT_ERR("Failed to disable LE scanning: status %d", status);
+               return;
+       }
 
-       if (err < 0)
-               return err;
+       switch (hdev->discovery.type) {
+       case DISCOV_TYPE_LE:
+               hci_dev_lock(hdev);
+               hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               hci_dev_unlock(hdev);
+               break;
 
-       queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
-                          timeout);
+       case DISCOV_TYPE_INTERLEAVED:
+               hci_req_init(&req, hdev);
 
-       return 0;
-}
+               memset(&cp, 0, sizeof(cp));
+               memcpy(&cp.lap, lap, sizeof(cp.lap));
+               cp.length = DISCOV_INTERLEAVED_INQUIRY_LEN;
+               hci_req_add(&req, HCI_OP_INQUIRY, sizeof(cp), &cp);
 
-int hci_cancel_le_scan(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
+               hci_dev_lock(hdev);
 
-       if (!test_bit(HCI_LE_SCAN, &hdev->dev_flags))
-               return -EALREADY;
+               hci_inquiry_cache_flush(hdev);
 
-       if (cancel_delayed_work(&hdev->le_scan_disable)) {
-               struct hci_cp_le_set_scan_enable cp;
+               err = hci_req_run(&req, inquiry_complete);
+               if (err) {
+                       BT_ERR("Inquiry request failed: err %d", err);
+                       hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
+               }
 
-               /* Send HCI command to disable LE Scan */
-               memset(&cp, 0, sizeof(cp));
-               hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+               hci_dev_unlock(hdev);
+               break;
        }
-
-       return 0;
 }
 
 static void le_scan_disable_work(struct work_struct *work)
@@ -2075,46 +2060,20 @@ static void le_scan_disable_work(struct work_struct *work)
        struct hci_dev *hdev = container_of(work, struct hci_dev,
                                            le_scan_disable.work);
        struct hci_cp_le_set_scan_enable cp;
+       struct hci_request req;
+       int err;
 
        BT_DBG("%s", hdev->name);
 
-       memset(&cp, 0, sizeof(cp));
-
-       hci_send_cmd(hdev, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
-}
-
-static void le_scan_work(struct work_struct *work)
-{
-       struct hci_dev *hdev = container_of(work, struct hci_dev, le_scan);
-       struct le_scan_params *param = &hdev->le_scan_params;
+       hci_req_init(&req, hdev);
 
-       BT_DBG("%s", hdev->name);
+       memset(&cp, 0, sizeof(cp));
+       cp.enable = LE_SCAN_DISABLE;
+       hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
 
-       hci_do_le_scan(hdev, param->type, param->interval, param->window,
-                      param->timeout);
-}
-
-int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
-               int timeout)
-{
-       struct le_scan_params *param = &hdev->le_scan_params;
-
-       BT_DBG("%s", hdev->name);
-
-       if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
-               return -ENOTSUPP;
-
-       if (work_busy(&hdev->le_scan))
-               return -EINPROGRESS;
-
-       param->type = type;
-       param->interval = interval;
-       param->window = window;
-       param->timeout = timeout;
-
-       queue_work(system_long_wq, &hdev->le_scan);
-
-       return 0;
+       err = hci_req_run(&req, le_scan_disable_work_complete);
+       if (err)
+               BT_ERR("Disable LE scanning request failed: err %d", err);
 }
 
 /* Alloc HCI device */
@@ -2151,7 +2110,6 @@ struct hci_dev *hci_alloc_dev(void)
        INIT_WORK(&hdev->cmd_work, hci_cmd_work);
        INIT_WORK(&hdev->tx_work, hci_tx_work);
        INIT_WORK(&hdev->power_on, hci_power_on);
-       INIT_WORK(&hdev->le_scan, le_scan_work);
 
        INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
        INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
@@ -2210,16 +2168,15 @@ int hci_register_dev(struct hci_dev *hdev)
 
        BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
 
-       hdev->workqueue = alloc_workqueue(hdev->name, WQ_HIGHPRI | WQ_UNBOUND |
-                                         WQ_MEM_RECLAIM, 1);
+       hdev->workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
+                                         WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->workqueue) {
                error = -ENOMEM;
                goto err;
        }
 
-       hdev->req_workqueue = alloc_workqueue(hdev->name,
-                                             WQ_HIGHPRI | WQ_UNBOUND |
-                                             WQ_MEM_RECLAIM, 1);
+       hdev->req_workqueue = alloc_workqueue("%s", WQ_HIGHPRI | WQ_UNBOUND |
+                                             WQ_MEM_RECLAIM, 1, hdev->name);
        if (!hdev->req_workqueue) {
                destroy_workqueue(hdev->workqueue);
                error = -ENOMEM;
@@ -3559,36 +3516,6 @@ static void hci_cmd_work(struct work_struct *work)
        }
 }
 
-int hci_do_inquiry(struct hci_dev *hdev, u8 length)
-{
-       /* General inquiry access code (GIAC) */
-       u8 lap[3] = { 0x33, 0x8b, 0x9e };
-       struct hci_cp_inquiry cp;
-
-       BT_DBG("%s", hdev->name);
-
-       if (test_bit(HCI_INQUIRY, &hdev->flags))
-               return -EINPROGRESS;
-
-       inquiry_cache_flush(hdev);
-
-       memset(&cp, 0, sizeof(cp));
-       memcpy(&cp.lap, lap, sizeof(cp.lap));
-       cp.length  = length;
-
-       return hci_send_cmd(hdev, HCI_OP_INQUIRY, sizeof(cp), &cp);
-}
-
-int hci_cancel_inquiry(struct hci_dev *hdev)
-{
-       BT_DBG("%s", hdev->name);
-
-       if (!test_bit(HCI_INQUIRY, &hdev->flags))
-               return -EALREADY;
-
-       return hci_send_cmd(hdev, HCI_OP_INQUIRY_CANCEL, 0, NULL);
-}
-
 u8 bdaddr_to_le(u8 bdaddr_type)
 {
        switch (bdaddr_type) {