Bluetooth: btintel: Add manufacturing enter/exit helpers
authorLoic Poulain <loic.poulain@intel.com>
Thu, 3 Dec 2015 15:10:22 +0000 (16:10 +0100)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 9 Dec 2015 23:51:50 +0000 (00:51 +0100)
Older Intel controllers need to enter manufacturing mode to perform
some vendor specific operations (patching, configuration...).
Add enter/exit manufaturing methods and refactor existing
manufacturing code.
Exit can be configured to perform a reset. Reset can be performed
either with patches activated or deactivated.

Signed-off-by: Loic Poulain <loic.poulain@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/bluetooth/btintel.c
drivers/bluetooth/btintel.h
drivers/bluetooth/btusb.c

index 1f13e617bf560d7dde4c30af30e7b6ded180f1c4..54410479f2f596250889a7dccbc89fe228d8150e 100644 (file)
@@ -73,6 +73,48 @@ int btintel_check_bdaddr(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL_GPL(btintel_check_bdaddr);
 
+int btintel_enter_mfg(struct hci_dev *hdev)
+{
+       const u8 param[] = { 0x01, 0x00 };
+       struct sk_buff *skb;
+
+       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_enter_mfg);
+
+int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched)
+{
+       u8 param[] = { 0x00, 0x00 };
+       struct sk_buff *skb;
+
+       /* The 2nd command parameter specifies the manufacturing exit method:
+        * 0x00: Just disable the manufacturing mode (0x00).
+        * 0x01: Disable manufacturing mode and reset with patches deactivated.
+        * 0x02: Disable manufacturing mode and reset with patches activated.
+        */
+       if (reset)
+               param[1] |= patched ? 0x02 : 0x01;
+
+       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT);
+       if (IS_ERR(skb)) {
+               bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)",
+                          PTR_ERR(skb));
+               return PTR_ERR(skb);
+       }
+       kfree_skb(skb);
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(btintel_exit_mfg);
+
 int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 {
        struct sk_buff *skb;
@@ -126,37 +168,19 @@ EXPORT_SYMBOL_GPL(btintel_set_diag);
 
 int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable)
 {
-       struct sk_buff *skb;
-       u8 param[2];
-       int err;
-
-       param[0] = 0x01;
-       param[1] = 0x00;
-
-       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
-                      hdev->name, err);
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       int err, ret;
 
-       err = btintel_set_diag(hdev, enable);
+       err = btintel_enter_mfg(hdev);
+       if (err)
+               return err;
 
-       param[0] = 0x00;
-       param[1] = 0x00;
+       ret = btintel_set_diag(hdev, enable);
 
-       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
-                      hdev->name, err);
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       err = btintel_exit_mfg(hdev, false, false);
+       if (err)
+               return err;
 
-       return err;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(btintel_set_diag_mfg);
 
@@ -309,37 +333,19 @@ EXPORT_SYMBOL_GPL(btintel_set_event_mask);
 
 int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug)
 {
-       struct sk_buff *skb;
-       u8 param[2];
-       int err;
+       int err, ret;
 
-       param[0] = 0x01;
-       param[1] = 0x00;
-
-       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Entering Intel manufacturer mode failed (%d)",
-                      hdev->name, err);
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
-
-       err = btintel_set_event_mask(hdev, debug);
+       err = btintel_enter_mfg(hdev);
+       if (err)
+               return err;
 
-       param[0] = 0x00;
-       param[1] = 0x00;
+       ret = btintel_set_event_mask(hdev, debug);
 
-       skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               err = PTR_ERR(skb);
-               BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)",
-                      hdev->name, err);
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       err = btintel_exit_mfg(hdev, false, false);
+       if (err)
+               return err;
 
-       return err;
+       return ret;
 }
 EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg);
 
index 07e58e05a7fa6771c128c3965632d97413b2ff15..fa72eaec3461d30ae59132ba9d4e55e8ce34a344 100644 (file)
@@ -72,6 +72,8 @@ struct intel_secure_send_result {
 #if IS_ENABLED(CONFIG_BT_INTEL)
 
 int btintel_check_bdaddr(struct hci_dev *hdev);
+int btintel_enter_mfg(struct hci_dev *hdev);
+int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched);
 int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr);
 int btintel_set_diag(struct hci_dev *hdev, bool enable);
 int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable);
@@ -94,6 +96,16 @@ static inline int btintel_check_bdaddr(struct hci_dev *hdev)
        return -EOPNOTSUPP;
 }
 
+static inline int btintel_enter_mfg(struct hci_dev *hdev)
+{
+       return -EOPNOTSUPP;
+}
+
+static inline int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched)
+{
+       return -EOPNOTSUPP;
+}
+
 static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr)
 {
        return -EOPNOTSUPP;
index 25beb3a28eee1a7d11efbfeeebdcdac13f1ee5ad..6e141cdb98a4495baafd48d6cf4b9662ccb891cc 100644 (file)
@@ -1646,14 +1646,9 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        struct sk_buff *skb;
        const struct firmware *fw;
        const u8 *fw_ptr;
-       int disable_patch;
+       int disable_patch, err;
        struct intel_version *ver;
 
-       const u8 mfg_enable[] = { 0x01, 0x00 };
-       const u8 mfg_disable[] = { 0x00, 0x00 };
-       const u8 mfg_reset_deactivate[] = { 0x00, 0x01 };
-       const u8 mfg_reset_activate[] = { 0x00, 0x02 };
-
        BT_DBG("%s", hdev->name);
 
        /* The controller has a bug with the first HCI command sent to it
@@ -1725,22 +1720,16 @@ static int btusb_setup_intel(struct hci_dev *hdev)
 
        kfree_skb(skb);
 
-       /* This Intel specific command enables the manufacturer mode of the
-        * controller.
-        *
+       /* Enable the manufacturer mode of the controller.
         * Only while this mode is enabled, the driver can download the
         * firmware patch data and configuration parameters.
         */
-       skb = __hci_cmd_sync(hdev, 0xfc11, 2, mfg_enable, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s entering Intel manufacturer mode failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
+       err = btintel_enter_mfg(hdev);
+       if (err) {
                release_firmware(fw);
-               return PTR_ERR(skb);
+               return err;
        }
 
-       kfree_skb(skb);
-
        disable_patch = 1;
 
        /* The firmware data file consists of list of Intel specific HCI
@@ -1780,14 +1769,9 @@ static int btusb_setup_intel(struct hci_dev *hdev)
        /* Patching completed successfully and disable the manufacturer mode
         * with reset and activate the downloaded firmware patches.
         */
-       skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_activate),
-                            mfg_reset_activate, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       err = btintel_exit_mfg(hdev, true, true);
+       if (err)
+               return err;
 
        BT_INFO("%s: Intel Bluetooth firmware patch completed and activated",
                hdev->name);
@@ -1796,14 +1780,9 @@ static int btusb_setup_intel(struct hci_dev *hdev)
 
 exit_mfg_disable:
        /* Disable the manufacturer mode without reset */
-       skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_disable), mfg_disable,
-                            HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       err = btintel_exit_mfg(hdev, false, false);
+       if (err)
+               return err;
 
        BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name);
 
@@ -1815,14 +1794,9 @@ exit_mfg_deactivate:
        /* Patching failed. Disable the manufacturer mode with reset and
         * deactivate the downloaded firmware patches.
         */
-       skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_deactivate),
-                            mfg_reset_deactivate, HCI_INIT_TIMEOUT);
-       if (IS_ERR(skb)) {
-               BT_ERR("%s exiting Intel manufacturer mode failed (%ld)",
-                      hdev->name, PTR_ERR(skb));
-               return PTR_ERR(skb);
-       }
-       kfree_skb(skb);
+       err = btintel_exit_mfg(hdev, true, false);
+       if (err)
+               return err;
 
        BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated",
                hdev->name);