2015-12-02 14:37:48

by Loic Poulain

[permalink] [raw]
Subject: [PATCH v2] Bluetooth: btintel: Add manufacturing enter/exit helpers

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.

Signed-off-by: Loic Poulain <[email protected]>
---
v2: add static definition if !CONFIG_BT_INTEL

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

diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
index 1f13e61..e9f26eb 100644
--- a/drivers/bluetooth/btintel.c
+++ b/drivers/bluetooth/btintel.c
@@ -73,6 +73,43 @@ 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;
+
+ 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 +163,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;
+ int err, ret;

- 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_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 +328,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;
-
- 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_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



2015-12-02 17:52:05

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH v2] Bluetooth: btintel: Add manufacturing enter/exit helpers

Hi Loic,

> 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.
>
> Signed-off-by: Loic Poulain <[email protected]>
> ---
> v2: add static definition if !CONFIG_BT_INTEL
>
> drivers/bluetooth/btintel.c | 109 ++++++++++++++++++++++----------------------
> drivers/bluetooth/btintel.h | 12 +++++
> drivers/bluetooth/btusb.c | 54 ++++++----------------
> 3 files changed, 81 insertions(+), 94 deletions(-)
>
> diff --git a/drivers/bluetooth/btintel.c b/drivers/bluetooth/btintel.c
> index 1f13e61..e9f26eb 100644
> --- a/drivers/bluetooth/btintel.c
> +++ b/drivers/bluetooth/btintel.c
> @@ -73,6 +73,43 @@ 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;
> +

please add a comment above this that talks about activating / deactivating patches. From the original code this was obvious since it was in the command buffer name.

The 0x02 means reset and activate patches while 0x01 means reset and deactivate patches. So a comment spelling this out in plain English would help here to understand what the patched parameter means.

And of course reset == false means that we just disable manufacturer mode. So mentioning that would be useful as well.

> + 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);

Regards

Marcel