[PATCH v3] Bluetooth: btintel: Add manufacturing enter/exit helpers

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxxxxx>
---
 v2: add static definition if !CONFIG_BT_INTEL
 v3: add comment on manufaturing exit behavior

 drivers/bluetooth/btintel.c | 114 +++++++++++++++++++++++---------------------
 drivers/bluetooth/btintel.h |  12 +++++
 drivers/bluetooth/btusb.c   |  54 ++++++---------------
 3 files changed, 86 insertions(+), 94 deletions(-)

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 1f13e61..5441047 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -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);
 
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h
index 07e58e0..fa72eae 100644
--- a/drivers/bluetooth/btintel.h
+++ b/drivers/bluetooth/btintel.h
@@ -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;
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 8063534..890ee52 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -1642,14 +1642,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
@@ -1721,22 +1716,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
@@ -1776,14 +1765,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);
@@ -1792,14 +1776,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);
 
@@ -1811,14 +1790,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);
-- 
1.9.1

--
To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Bluez Devel]     [Linux Wireless Networking]     [Linux Wireless Personal Area Networking]     [Linux ATH6KL]     [Linux USB Devel]     [Linux Media Drivers]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Big List of Linux Books]

  Powered by Linux