diff options
author | Loic Poulain <loic.poulain@intel.com> | 2015-12-03 10:10:22 -0500 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-12-09 18:51:50 -0500 |
commit | 28dc4b92e20e0fd18be2d8356abf959d58c7346a (patch) | |
tree | 38967870eb36b45e689755e08ebedc93d8beec0a /drivers/bluetooth | |
parent | 1623d0bf847d3b38d8cf24367b3689ba0e3fe2aa (diff) |
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.
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>
Diffstat (limited to 'drivers/bluetooth')
-rw-r--r-- | drivers/bluetooth/btintel.c | 114 | ||||
-rw-r--r-- | drivers/bluetooth/btintel.h | 12 | ||||
-rw-r--r-- | 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 1f13e617bf56..54410479f2f5 100644 --- a/drivers/bluetooth/btintel.c +++ b/drivers/bluetooth/btintel.c | |||
@@ -73,6 +73,48 @@ int btintel_check_bdaddr(struct hci_dev *hdev) | |||
73 | } | 73 | } |
74 | EXPORT_SYMBOL_GPL(btintel_check_bdaddr); | 74 | EXPORT_SYMBOL_GPL(btintel_check_bdaddr); |
75 | 75 | ||
76 | int btintel_enter_mfg(struct hci_dev *hdev) | ||
77 | { | ||
78 | const u8 param[] = { 0x01, 0x00 }; | ||
79 | struct sk_buff *skb; | ||
80 | |||
81 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); | ||
82 | if (IS_ERR(skb)) { | ||
83 | bt_dev_err(hdev, "Entering manufacturer mode failed (%ld)", | ||
84 | PTR_ERR(skb)); | ||
85 | return PTR_ERR(skb); | ||
86 | } | ||
87 | kfree_skb(skb); | ||
88 | |||
89 | return 0; | ||
90 | } | ||
91 | EXPORT_SYMBOL_GPL(btintel_enter_mfg); | ||
92 | |||
93 | int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched) | ||
94 | { | ||
95 | u8 param[] = { 0x00, 0x00 }; | ||
96 | struct sk_buff *skb; | ||
97 | |||
98 | /* The 2nd command parameter specifies the manufacturing exit method: | ||
99 | * 0x00: Just disable the manufacturing mode (0x00). | ||
100 | * 0x01: Disable manufacturing mode and reset with patches deactivated. | ||
101 | * 0x02: Disable manufacturing mode and reset with patches activated. | ||
102 | */ | ||
103 | if (reset) | ||
104 | param[1] |= patched ? 0x02 : 0x01; | ||
105 | |||
106 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_CMD_TIMEOUT); | ||
107 | if (IS_ERR(skb)) { | ||
108 | bt_dev_err(hdev, "Exiting manufacturer mode failed (%ld)", | ||
109 | PTR_ERR(skb)); | ||
110 | return PTR_ERR(skb); | ||
111 | } | ||
112 | kfree_skb(skb); | ||
113 | |||
114 | return 0; | ||
115 | } | ||
116 | EXPORT_SYMBOL_GPL(btintel_exit_mfg); | ||
117 | |||
76 | int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | 118 | int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
77 | { | 119 | { |
78 | struct sk_buff *skb; | 120 | struct sk_buff *skb; |
@@ -126,37 +168,19 @@ EXPORT_SYMBOL_GPL(btintel_set_diag); | |||
126 | 168 | ||
127 | int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) | 169 | int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable) |
128 | { | 170 | { |
129 | struct sk_buff *skb; | 171 | int err, ret; |
130 | u8 param[2]; | ||
131 | int err; | ||
132 | |||
133 | param[0] = 0x01; | ||
134 | param[1] = 0x00; | ||
135 | |||
136 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); | ||
137 | if (IS_ERR(skb)) { | ||
138 | err = PTR_ERR(skb); | ||
139 | BT_ERR("%s: Entering Intel manufacturer mode failed (%d)", | ||
140 | hdev->name, err); | ||
141 | return PTR_ERR(skb); | ||
142 | } | ||
143 | kfree_skb(skb); | ||
144 | 172 | ||
145 | err = btintel_set_diag(hdev, enable); | 173 | err = btintel_enter_mfg(hdev); |
174 | if (err) | ||
175 | return err; | ||
146 | 176 | ||
147 | param[0] = 0x00; | 177 | ret = btintel_set_diag(hdev, enable); |
148 | param[1] = 0x00; | ||
149 | 178 | ||
150 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); | 179 | err = btintel_exit_mfg(hdev, false, false); |
151 | if (IS_ERR(skb)) { | 180 | if (err) |
152 | err = PTR_ERR(skb); | 181 | return err; |
153 | BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)", | ||
154 | hdev->name, err); | ||
155 | return PTR_ERR(skb); | ||
156 | } | ||
157 | kfree_skb(skb); | ||
158 | 182 | ||
159 | return err; | 183 | return ret; |
160 | } | 184 | } |
161 | EXPORT_SYMBOL_GPL(btintel_set_diag_mfg); | 185 | EXPORT_SYMBOL_GPL(btintel_set_diag_mfg); |
162 | 186 | ||
@@ -309,37 +333,19 @@ EXPORT_SYMBOL_GPL(btintel_set_event_mask); | |||
309 | 333 | ||
310 | int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug) | 334 | int btintel_set_event_mask_mfg(struct hci_dev *hdev, bool debug) |
311 | { | 335 | { |
312 | struct sk_buff *skb; | 336 | int err, ret; |
313 | u8 param[2]; | ||
314 | int err; | ||
315 | 337 | ||
316 | param[0] = 0x01; | 338 | err = btintel_enter_mfg(hdev); |
317 | param[1] = 0x00; | 339 | if (err) |
318 | 340 | return err; | |
319 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); | ||
320 | if (IS_ERR(skb)) { | ||
321 | err = PTR_ERR(skb); | ||
322 | BT_ERR("%s: Entering Intel manufacturer mode failed (%d)", | ||
323 | hdev->name, err); | ||
324 | return PTR_ERR(skb); | ||
325 | } | ||
326 | kfree_skb(skb); | ||
327 | |||
328 | err = btintel_set_event_mask(hdev, debug); | ||
329 | 341 | ||
330 | param[0] = 0x00; | 342 | ret = btintel_set_event_mask(hdev, debug); |
331 | param[1] = 0x00; | ||
332 | 343 | ||
333 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, param, HCI_INIT_TIMEOUT); | 344 | err = btintel_exit_mfg(hdev, false, false); |
334 | if (IS_ERR(skb)) { | 345 | if (err) |
335 | err = PTR_ERR(skb); | 346 | return err; |
336 | BT_ERR("%s: Leaving Intel manufacturer mode failed (%d)", | ||
337 | hdev->name, err); | ||
338 | return PTR_ERR(skb); | ||
339 | } | ||
340 | kfree_skb(skb); | ||
341 | 347 | ||
342 | return err; | 348 | return ret; |
343 | } | 349 | } |
344 | EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg); | 350 | EXPORT_SYMBOL_GPL(btintel_set_event_mask_mfg); |
345 | 351 | ||
diff --git a/drivers/bluetooth/btintel.h b/drivers/bluetooth/btintel.h index 07e58e05a7fa..fa72eaec3461 100644 --- a/drivers/bluetooth/btintel.h +++ b/drivers/bluetooth/btintel.h | |||
@@ -72,6 +72,8 @@ struct intel_secure_send_result { | |||
72 | #if IS_ENABLED(CONFIG_BT_INTEL) | 72 | #if IS_ENABLED(CONFIG_BT_INTEL) |
73 | 73 | ||
74 | int btintel_check_bdaddr(struct hci_dev *hdev); | 74 | int btintel_check_bdaddr(struct hci_dev *hdev); |
75 | int btintel_enter_mfg(struct hci_dev *hdev); | ||
76 | int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched); | ||
75 | int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); | 77 | int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); |
76 | int btintel_set_diag(struct hci_dev *hdev, bool enable); | 78 | int btintel_set_diag(struct hci_dev *hdev, bool enable); |
77 | int btintel_set_diag_mfg(struct hci_dev *hdev, bool enable); | 79 | 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) | |||
94 | return -EOPNOTSUPP; | 96 | return -EOPNOTSUPP; |
95 | } | 97 | } |
96 | 98 | ||
99 | static inline int btintel_enter_mfg(struct hci_dev *hdev) | ||
100 | { | ||
101 | return -EOPNOTSUPP; | ||
102 | } | ||
103 | |||
104 | static inline int btintel_exit_mfg(struct hci_dev *hdev, bool reset, bool patched) | ||
105 | { | ||
106 | return -EOPNOTSUPP; | ||
107 | } | ||
108 | |||
97 | static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | 109 | static inline int btintel_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) |
98 | { | 110 | { |
99 | return -EOPNOTSUPP; | 111 | return -EOPNOTSUPP; |
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index 25beb3a28eee..6e141cdb98a4 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c | |||
@@ -1646,14 +1646,9 @@ static int btusb_setup_intel(struct hci_dev *hdev) | |||
1646 | struct sk_buff *skb; | 1646 | struct sk_buff *skb; |
1647 | const struct firmware *fw; | 1647 | const struct firmware *fw; |
1648 | const u8 *fw_ptr; | 1648 | const u8 *fw_ptr; |
1649 | int disable_patch; | 1649 | int disable_patch, err; |
1650 | struct intel_version *ver; | 1650 | struct intel_version *ver; |
1651 | 1651 | ||
1652 | const u8 mfg_enable[] = { 0x01, 0x00 }; | ||
1653 | const u8 mfg_disable[] = { 0x00, 0x00 }; | ||
1654 | const u8 mfg_reset_deactivate[] = { 0x00, 0x01 }; | ||
1655 | const u8 mfg_reset_activate[] = { 0x00, 0x02 }; | ||
1656 | |||
1657 | BT_DBG("%s", hdev->name); | 1652 | BT_DBG("%s", hdev->name); |
1658 | 1653 | ||
1659 | /* The controller has a bug with the first HCI command sent to it | 1654 | /* 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) | |||
1725 | 1720 | ||
1726 | kfree_skb(skb); | 1721 | kfree_skb(skb); |
1727 | 1722 | ||
1728 | /* This Intel specific command enables the manufacturer mode of the | 1723 | /* Enable the manufacturer mode of the controller. |
1729 | * controller. | ||
1730 | * | ||
1731 | * Only while this mode is enabled, the driver can download the | 1724 | * Only while this mode is enabled, the driver can download the |
1732 | * firmware patch data and configuration parameters. | 1725 | * firmware patch data and configuration parameters. |
1733 | */ | 1726 | */ |
1734 | skb = __hci_cmd_sync(hdev, 0xfc11, 2, mfg_enable, HCI_INIT_TIMEOUT); | 1727 | err = btintel_enter_mfg(hdev); |
1735 | if (IS_ERR(skb)) { | 1728 | if (err) { |
1736 | BT_ERR("%s entering Intel manufacturer mode failed (%ld)", | ||
1737 | hdev->name, PTR_ERR(skb)); | ||
1738 | release_firmware(fw); | 1729 | release_firmware(fw); |
1739 | return PTR_ERR(skb); | 1730 | return err; |
1740 | } | 1731 | } |
1741 | 1732 | ||
1742 | kfree_skb(skb); | ||
1743 | |||
1744 | disable_patch = 1; | 1733 | disable_patch = 1; |
1745 | 1734 | ||
1746 | /* The firmware data file consists of list of Intel specific HCI | 1735 | /* The firmware data file consists of list of Intel specific HCI |
@@ -1780,14 +1769,9 @@ static int btusb_setup_intel(struct hci_dev *hdev) | |||
1780 | /* Patching completed successfully and disable the manufacturer mode | 1769 | /* Patching completed successfully and disable the manufacturer mode |
1781 | * with reset and activate the downloaded firmware patches. | 1770 | * with reset and activate the downloaded firmware patches. |
1782 | */ | 1771 | */ |
1783 | skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_activate), | 1772 | err = btintel_exit_mfg(hdev, true, true); |
1784 | mfg_reset_activate, HCI_INIT_TIMEOUT); | 1773 | if (err) |
1785 | if (IS_ERR(skb)) { | 1774 | return err; |
1786 | BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", | ||
1787 | hdev->name, PTR_ERR(skb)); | ||
1788 | return PTR_ERR(skb); | ||
1789 | } | ||
1790 | kfree_skb(skb); | ||
1791 | 1775 | ||
1792 | BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", | 1776 | BT_INFO("%s: Intel Bluetooth firmware patch completed and activated", |
1793 | hdev->name); | 1777 | hdev->name); |
@@ -1796,14 +1780,9 @@ static int btusb_setup_intel(struct hci_dev *hdev) | |||
1796 | 1780 | ||
1797 | exit_mfg_disable: | 1781 | exit_mfg_disable: |
1798 | /* Disable the manufacturer mode without reset */ | 1782 | /* Disable the manufacturer mode without reset */ |
1799 | skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_disable), mfg_disable, | 1783 | err = btintel_exit_mfg(hdev, false, false); |
1800 | HCI_INIT_TIMEOUT); | 1784 | if (err) |
1801 | if (IS_ERR(skb)) { | 1785 | return err; |
1802 | BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", | ||
1803 | hdev->name, PTR_ERR(skb)); | ||
1804 | return PTR_ERR(skb); | ||
1805 | } | ||
1806 | kfree_skb(skb); | ||
1807 | 1786 | ||
1808 | BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); | 1787 | BT_INFO("%s: Intel Bluetooth firmware patch completed", hdev->name); |
1809 | 1788 | ||
@@ -1815,14 +1794,9 @@ exit_mfg_deactivate: | |||
1815 | /* Patching failed. Disable the manufacturer mode with reset and | 1794 | /* Patching failed. Disable the manufacturer mode with reset and |
1816 | * deactivate the downloaded firmware patches. | 1795 | * deactivate the downloaded firmware patches. |
1817 | */ | 1796 | */ |
1818 | skb = __hci_cmd_sync(hdev, 0xfc11, sizeof(mfg_reset_deactivate), | 1797 | err = btintel_exit_mfg(hdev, true, false); |
1819 | mfg_reset_deactivate, HCI_INIT_TIMEOUT); | 1798 | if (err) |
1820 | if (IS_ERR(skb)) { | 1799 | return err; |
1821 | BT_ERR("%s exiting Intel manufacturer mode failed (%ld)", | ||
1822 | hdev->name, PTR_ERR(skb)); | ||
1823 | return PTR_ERR(skb); | ||
1824 | } | ||
1825 | kfree_skb(skb); | ||
1826 | 1800 | ||
1827 | BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", | 1801 | BT_INFO("%s: Intel Bluetooth firmware patch completed and deactivated", |
1828 | hdev->name); | 1802 | hdev->name); |