networking: introduce and use skb_put_data()
[linux-block.git] / net / bluetooth / hci_core.c
index 05686776a5fb78d67dd38b22632ccfd1355b857e..d860e3cc23cf151583e5d455edce572328e2168f 100644 (file)
@@ -148,13 +148,13 @@ static ssize_t vendor_diag_write(struct file *file, const char __user *user_buf,
                return -EINVAL;
 
        /* When the diagnostic flags are not persistent and the transport
-        * is not active, then there is no need for the vendor callback.
-        *
-        * Instead just store the desired value. If needed the setting
-        * will be programmed when the controller gets powered on.
+        * is not active or in user channel operation, then there is no need
+        * for the vendor callback. Instead just store the desired value and
+        * the setting will be programmed when the controller gets powered on.
         */
        if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
-           !test_bit(HCI_RUNNING, &hdev->flags))
+           (!test_bit(HCI_RUNNING, &hdev->flags) ||
+            hci_dev_test_flag(hdev, HCI_USER_CHANNEL)))
                goto done;
 
        hci_req_sync_lock(hdev);
@@ -548,6 +548,7 @@ 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 };
+       bool changed = false;
 
        /* If Connectionless Slave Broadcast master role is supported
         * enable all necessary events for it.
@@ -557,6 +558,7 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
                events[1] |= 0x80;      /* Synchronization Train Complete */
                events[2] |= 0x10;      /* Slave Page Response Timeout */
                events[2] |= 0x20;      /* CSB Channel Map Change */
+               changed = true;
        }
 
        /* If Connectionless Slave Broadcast slave role is supported
@@ -567,13 +569,24 @@ static void hci_set_event_mask_page_2(struct hci_request *req)
                events[2] |= 0x02;      /* CSB Receive */
                events[2] |= 0x04;      /* CSB Timeout */
                events[2] |= 0x08;      /* Truncated Page Complete */
+               changed = true;
        }
 
        /* Enable Authenticated Payload Timeout Expired event if supported */
-       if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING)
+       if (lmp_ping_capable(hdev) || hdev->le_features[0] & HCI_LE_PING) {
                events[2] |= 0x80;
+               changed = true;
+       }
 
-       hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2, sizeof(events), events);
+       /* Some Broadcom based controllers indicate support for Set Event
+        * Mask Page 2 command, but then actually do not support it. Since
+        * the default value is all bits set to zero, the command is only
+        * required if the event mask has to be changed. In case no change
+        * to the event mask is needed, skip this command.
+        */
+       if (changed)
+               hci_req_add(req, HCI_OP_SET_EVENT_MASK_PAGE_2,
+                           sizeof(events), events);
 }
 
 static int hci_init3_req(struct hci_request *req, unsigned long opt)
@@ -635,6 +648,14 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
                                                 * Report
                                                 */
 
+               /* If the controller supports Channel Selection Algorithm #2
+                * feature, enable the corresponding event.
+                */
+               if (hdev->le_features[1] & HCI_LE_CHAN_SEL_ALG2)
+                       events[2] |= 0x08;      /* LE Channel Selection
+                                                * Algorithm
+                                                */
+
                /* If the controller supports the LE Set Scan Enable command,
                 * enable the corresponding advertising report event.
                 */
@@ -677,6 +698,12 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
                if (hdev->commands[34] & 0x04)
                        events[1] |= 0x01;      /* LE Generate DHKey Complete */
 
+               /* If the controller supports the LE Set Default PHY or
+                * LE Set PHY commands, enable the corresponding event.
+                */
+               if (hdev->commands[35] & (0x20 | 0x40))
+                       events[1] |= 0x08;        /* LE PHY Update Complete */
+
                hci_req_add(req, HCI_OP_LE_SET_EVENT_MASK, sizeof(events),
                            events);
 
@@ -771,6 +798,27 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
                            sizeof(support), &support);
        }
 
+       /* Set Suggested Default Data Length to maximum if supported */
+       if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
+               struct hci_cp_le_write_def_data_len cp;
+
+               cp.tx_len = hdev->le_max_tx_len;
+               cp.tx_time = hdev->le_max_tx_time;
+               hci_req_add(req, HCI_OP_LE_WRITE_DEF_DATA_LEN, sizeof(cp), &cp);
+       }
+
+       /* Set Default PHY parameters if command is supported */
+       if (hdev->commands[35] & 0x20) {
+               struct hci_cp_le_set_default_phy cp;
+
+               /* No transmitter PHY or receiver PHY preferences */
+               cp.all_phys = 0x03;
+               cp.tx_phys = 0;
+               cp.rx_phys = 0;
+
+               hci_req_add(req, HCI_OP_LE_SET_DEFAULT_PHY, sizeof(cp), &cp);
+       }
+
        return 0;
 }
 
@@ -1384,6 +1432,7 @@ static int hci_dev_do_open(struct hci_dev *hdev)
         * completed.
         */
        if (test_bit(HCI_QUIRK_NON_PERSISTENT_DIAG, &hdev->quirks) &&
+           !hci_dev_test_flag(hdev, HCI_USER_CHANNEL) &&
            hci_dev_test_flag(hdev, HCI_VENDOR_DIAG) && hdev->set_diag)
                ret = hdev->set_diag(hdev, true);
 
@@ -3217,7 +3266,7 @@ int hci_reset_dev(struct hci_dev *hdev)
                return -ENOMEM;
 
        hci_skb_pkt_type(skb) = HCI_EVENT_PKT;
-       memcpy(skb_put(skb, 3), hw_err, 3);
+       skb_put_data(skb, hw_err, 3);
 
        /* Send Hardware Error to upper stack */
        return hci_recv_frame(hdev, skb);