]> Pileus Git - ~andy/linux/blobdiff - net/bluetooth/hci_core.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/bluetooth/bluetooth
[~andy/linux] / net / bluetooth / hci_core.c
index 0976eabdafb040e83e7a64f5f7d30c36be7c5fea..4549b5cbfac5aa5eaad080961ce29bb4803e6e0f 100644 (file)
@@ -607,6 +607,34 @@ static void hci_set_le_support(struct hci_request *req)
                            &cp);
 }
 
+static void hci_set_event_mask_page_2(struct hci_request *req)
+{
+       struct hci_dev *hdev = req->hdev;
+       u8 events[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+
+       /* If Connectionless Slave Broadcast master role is supported
+        * enable all necessary events for it.
+        */
+       if (hdev->features[2][0] & 0x01) {
+               events[1] |= 0x40;      /* Triggered Clock Capture */
+               events[1] |= 0x80;      /* Synchronization Train Complete */
+               events[2] |= 0x10;      /* Slave Page Response Timeout */
+               events[2] |= 0x20;      /* CSB Channel Map Change */
+       }
+
+       /* If Connectionless Slave Broadcast slave role is supported
+        * enable all necessary events for it.
+        */
+       if (hdev->features[2][0] & 0x02) {
+               events[2] |= 0x01;      /* Synchronization Train Received */
+               events[2] |= 0x02;      /* CSB Receive */
+               events[2] |= 0x04;      /* CSB Timeout */
+               events[2] |= 0x08;      /* Truncated Page Complete */
+       }
+
+       hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
+}
+
 static void hci_init3_req(struct hci_request *req, unsigned long opt)
 {
        struct hci_dev *hdev = req->hdev;
@@ -648,6 +676,19 @@ static void hci_init3_req(struct hci_request *req, unsigned long opt)
        }
 }
 
+static void hci_init4_req(struct hci_request *req, unsigned long opt)
+{
+       struct hci_dev *hdev = req->hdev;
+
+       /* Set event mask page 2 if the HCI command for it is supported */
+       if (hdev->commands[22] & 0x04)
+               hci_set_event_mask_page_2(req);
+
+       /* Check for Synchronization Train support */
+       if (hdev->features[2][0] & 0x04)
+               hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
+}
+
 static int __hci_init(struct hci_dev *hdev)
 {
        int err;
@@ -667,7 +708,11 @@ static int __hci_init(struct hci_dev *hdev)
        if (err < 0)
                return err;
 
-       return __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
+       err = __hci_req_sync(hdev, hci_init3_req, 0, HCI_INIT_TIMEOUT);
+       if (err < 0)
+               return err;
+
+       return __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
 }
 
 static void hci_scan_req(struct hci_request *req, unsigned long opt)
@@ -984,6 +1029,11 @@ int hci_inquiry(void __user *arg)
        if (!hdev)
                return -ENODEV;
 
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               err = -EBUSY;
+               goto done;
+       }
+
        hci_dev_lock(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
            inquiry_cache_empty(hdev) || ir.flags & IREQ_CACHE_FLUSH) {
@@ -1146,7 +1196,11 @@ int hci_dev_open(__u16 dev)
                goto done;
        }
 
-       if (hdev->rfkill && rfkill_blocked(hdev->rfkill)) {
+       /* Check for rfkill but allow the HCI setup stage to proceed
+        * (which in itself doesn't cause any RF activity).
+        */
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags) &&
+           !test_bit(HCI_SETUP, &hdev->dev_flags)) {
                ret = -ERFKILL;
                goto done;
        }
@@ -1177,7 +1231,8 @@ int hci_dev_open(__u16 dev)
                if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
                        set_bit(HCI_RAW, &hdev->flags);
 
-               if (!test_bit(HCI_RAW, &hdev->flags))
+               if (!test_bit(HCI_RAW, &hdev->flags) &&
+                   !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
                        ret = __hci_init(hdev);
        }
 
@@ -1188,6 +1243,7 @@ int hci_dev_open(__u16 dev)
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
                if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
+                   !test_bit(HCI_USER_CHANNEL, &hdev->dev_flags) &&
                    mgmt_valid_hdev(hdev)) {
                        hci_dev_lock(hdev);
                        mgmt_powered(hdev, 1);
@@ -1324,11 +1380,17 @@ int hci_dev_close(__u16 dev)
        if (!hdev)
                return -ENODEV;
 
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               err = -EBUSY;
+               goto done;
+       }
+
        if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
                cancel_delayed_work(&hdev->power_off);
 
        err = hci_dev_do_close(hdev);
 
+done:
        hci_dev_put(hdev);
        return err;
 }
@@ -1349,6 +1411,11 @@ int hci_dev_reset(__u16 dev)
                goto done;
        }
 
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               ret = -EBUSY;
+               goto done;
+       }
+
        /* Drop queues */
        skb_queue_purge(&hdev->rx_q);
        skb_queue_purge(&hdev->cmd_q);
@@ -1382,10 +1449,15 @@ int hci_dev_reset_stat(__u16 dev)
        if (!hdev)
                return -ENODEV;
 
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               ret = -EBUSY;
+               goto done;
+       }
+
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
 
+done:
        hci_dev_put(hdev);
-
        return ret;
 }
 
@@ -1402,6 +1474,11 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
        if (!hdev)
                return -ENODEV;
 
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               err = -EBUSY;
+               goto done;
+       }
+
        switch (cmd) {
        case HCISETAUTH:
                err = hci_req_sync(hdev, hci_auth_req, dr.dev_opt,
@@ -1460,6 +1537,7 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
                break;
        }
 
+done:
        hci_dev_put(hdev);
        return err;
 }
@@ -1568,10 +1646,16 @@ static int hci_rfkill_set_block(void *data, bool blocked)
 
        BT_DBG("%p name %s blocked %d", hdev, hdev->name, blocked);
 
-       if (!blocked)
-               return 0;
+       if (test_bit(HCI_USER_CHANNEL, &hdev->dev_flags))
+               return -EBUSY;
 
-       hci_dev_do_close(hdev);
+       if (blocked) {
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+               if (!test_bit(HCI_SETUP, &hdev->dev_flags))
+                       hci_dev_do_close(hdev);
+       } else {
+               clear_bit(HCI_RFKILLED, &hdev->dev_flags);
+       }
 
        return 0;
 }
@@ -1593,9 +1677,13 @@ static void hci_power_on(struct work_struct *work)
                return;
        }
 
-       if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
+       if (test_bit(HCI_RFKILLED, &hdev->dev_flags)) {
+               clear_bit(HCI_AUTO_OFF, &hdev->dev_flags);
+               hci_dev_do_close(hdev);
+       } else if (test_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
                queue_delayed_work(hdev->req_workqueue, &hdev->power_off,
                                   HCI_AUTO_OFF_TIMEOUT);
+       }
 
        if (test_and_clear_bit(HCI_SETUP, &hdev->dev_flags))
                mgmt_index_added(hdev);
@@ -2211,6 +2299,9 @@ int hci_register_dev(struct hci_dev *hdev)
                }
        }
 
+       if (hdev->rfkill && rfkill_blocked(hdev->rfkill))
+               set_bit(HCI_RFKILLED, &hdev->dev_flags);
+
        set_bit(HCI_SETUP, &hdev->dev_flags);
 
        if (hdev->dev_type != HCI_AMP)
@@ -3260,15 +3351,13 @@ static void hci_tx_work(struct work_struct *work)
        BT_DBG("%s acl %d sco %d le %d", hdev->name, hdev->acl_cnt,
               hdev->sco_cnt, hdev->le_cnt);
 
-       /* Schedule queues and send stuff to HCI driver */
-
-       hci_sched_acl(hdev);
-
-       hci_sched_sco(hdev);
-
-       hci_sched_esco(hdev);
-
-       hci_sched_le(hdev);
+       if (!test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
+               /* Schedule queues and send stuff to HCI driver */
+               hci_sched_acl(hdev);
+               hci_sched_sco(hdev);
+               hci_sched_esco(hdev);
+               hci_sched_le(hdev);
+       }
 
        /* Send next queued raw (unknown type) packet */
        while ((skb = skb_dequeue(&hdev->raw_q)))
@@ -3459,7 +3548,8 @@ static void hci_rx_work(struct work_struct *work)
                        hci_send_to_sock(hdev, skb);
                }
 
-               if (test_bit(HCI_RAW, &hdev->flags)) {
+               if (test_bit(HCI_RAW, &hdev->flags) ||
+                   test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
                        kfree_skb(skb);
                        continue;
                }
@@ -3514,7 +3604,7 @@ static void hci_cmd_work(struct work_struct *work)
 
                kfree_skb(hdev->sent_cmd);
 
-               hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
+               hdev->sent_cmd = skb_clone(skb, GFP_KERNEL);
                if (hdev->sent_cmd) {
                        atomic_dec(&hdev->cmd_cnt);
                        hci_send_frame(skb);