diff options
author | Marcel Holtmann <marcel@holtmann.org> | 2015-04-10 17:02:20 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2015-04-29 19:05:29 -0400 |
commit | 50862ee5578efa342a25c8b86f0080494736057f (patch) | |
tree | 21ee10200e8eb8c9440a739a4b1990d15c298c52 | |
parent | 16e5c47a0f90a37cf8b8d50b5eaf3cd3f7ed9530 (diff) |
Bluetooth: btbcm: Export patchram download as separate function
This isolates the Broadcom patchram download procedure as separate
function so that it can be easily used from USB and UART based drivers.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
-rw-r--r-- | drivers/bluetooth/btbcm.c | 148 | ||||
-rw-r--r-- | drivers/bluetooth/btbcm.h | 6 |
2 files changed, 85 insertions, 69 deletions
diff --git a/drivers/bluetooth/btbcm.c b/drivers/bluetooth/btbcm.c index d0741f3ed7ec..4bba86677adc 100644 --- a/drivers/bluetooth/btbcm.c +++ b/drivers/bluetooth/btbcm.c | |||
@@ -95,6 +95,78 @@ int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | |||
95 | } | 95 | } |
96 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); | 96 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); |
97 | 97 | ||
98 | int btbcm_patchram(struct hci_dev *hdev, const char *firmware) | ||
99 | { | ||
100 | const struct hci_command_hdr *cmd; | ||
101 | const struct firmware *fw; | ||
102 | const u8 *fw_ptr; | ||
103 | size_t fw_size; | ||
104 | struct sk_buff *skb; | ||
105 | u16 opcode; | ||
106 | int err; | ||
107 | |||
108 | err = request_firmware(&fw, firmware, &hdev->dev); | ||
109 | if (err < 0) { | ||
110 | BT_INFO("%s: BCM: Patch %s not found", hdev->name, firmware); | ||
111 | return err; | ||
112 | } | ||
113 | |||
114 | /* Start Download */ | ||
115 | skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); | ||
116 | if (IS_ERR(skb)) { | ||
117 | err = PTR_ERR(skb); | ||
118 | BT_ERR("%s: BCM: Download Minidrv command failed (%d)", | ||
119 | hdev->name, err); | ||
120 | goto done; | ||
121 | } | ||
122 | kfree_skb(skb); | ||
123 | |||
124 | /* 50 msec delay after Download Minidrv completes */ | ||
125 | msleep(50); | ||
126 | |||
127 | fw_ptr = fw->data; | ||
128 | fw_size = fw->size; | ||
129 | |||
130 | while (fw_size >= sizeof(*cmd)) { | ||
131 | const u8 *cmd_param; | ||
132 | |||
133 | cmd = (struct hci_command_hdr *)fw_ptr; | ||
134 | fw_ptr += sizeof(*cmd); | ||
135 | fw_size -= sizeof(*cmd); | ||
136 | |||
137 | if (fw_size < cmd->plen) { | ||
138 | BT_ERR("%s: BCM: Patch %s is corrupted", hdev->name, | ||
139 | firmware); | ||
140 | err = -EINVAL; | ||
141 | goto done; | ||
142 | } | ||
143 | |||
144 | cmd_param = fw_ptr; | ||
145 | fw_ptr += cmd->plen; | ||
146 | fw_size -= cmd->plen; | ||
147 | |||
148 | opcode = le16_to_cpu(cmd->opcode); | ||
149 | |||
150 | skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, | ||
151 | HCI_INIT_TIMEOUT); | ||
152 | if (IS_ERR(skb)) { | ||
153 | err = PTR_ERR(skb); | ||
154 | BT_ERR("%s: BCM: Patch command %04x failed (%d)", | ||
155 | hdev->name, opcode, err); | ||
156 | goto done; | ||
157 | } | ||
158 | kfree_skb(skb); | ||
159 | } | ||
160 | |||
161 | /* 250 msec delay after Launch Ram completes */ | ||
162 | msleep(250); | ||
163 | |||
164 | done: | ||
165 | release_firmware(fw); | ||
166 | return err; | ||
167 | } | ||
168 | EXPORT_SYMBOL(btbcm_patchram); | ||
169 | |||
98 | static int btbcm_reset(struct hci_dev *hdev) | 170 | static int btbcm_reset(struct hci_dev *hdev) |
99 | { | 171 | { |
100 | struct sk_buff *skb; | 172 | struct sk_buff *skb; |
@@ -198,12 +270,8 @@ static const struct { | |||
198 | 270 | ||
199 | int btbcm_setup_patchram(struct hci_dev *hdev) | 271 | int btbcm_setup_patchram(struct hci_dev *hdev) |
200 | { | 272 | { |
201 | const struct hci_command_hdr *cmd; | ||
202 | const struct firmware *fw; | ||
203 | const u8 *fw_ptr; | ||
204 | size_t fw_size; | ||
205 | char fw_name[64]; | 273 | char fw_name[64]; |
206 | u16 opcode, subver, rev, pid, vid; | 274 | u16 subver, rev, pid, vid; |
207 | const char *hw_name = NULL; | 275 | const char *hw_name = NULL; |
208 | struct sk_buff *skb; | 276 | struct sk_buff *skb; |
209 | struct hci_rp_read_local_version *ver; | 277 | struct hci_rp_read_local_version *ver; |
@@ -273,74 +341,19 @@ int btbcm_setup_patchram(struct hci_dev *hdev) | |||
273 | hw_name ? : "BCM", (subver & 0x7000) >> 13, | 341 | hw_name ? : "BCM", (subver & 0x7000) >> 13, |
274 | (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); | 342 | (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); |
275 | 343 | ||
276 | err = request_firmware(&fw, fw_name, &hdev->dev); | 344 | err = btbcm_patchram(hdev, fw_name); |
277 | if (err < 0) { | 345 | if (err == -ENOENT) |
278 | BT_INFO("%s: BCM: patch %s not found", hdev->name, fw_name); | ||
279 | return 0; | 346 | return 0; |
280 | } | ||
281 | |||
282 | /* Start Download */ | ||
283 | skb = __hci_cmd_sync(hdev, 0xfc2e, 0, NULL, HCI_INIT_TIMEOUT); | ||
284 | if (IS_ERR(skb)) { | ||
285 | err = PTR_ERR(skb); | ||
286 | BT_ERR("%s: BCM: Download Minidrv command failed (%d)", | ||
287 | hdev->name, err); | ||
288 | goto reset; | ||
289 | } | ||
290 | kfree_skb(skb); | ||
291 | |||
292 | /* 50 msec delay after Download Minidrv completes */ | ||
293 | msleep(50); | ||
294 | |||
295 | fw_ptr = fw->data; | ||
296 | fw_size = fw->size; | ||
297 | |||
298 | while (fw_size >= sizeof(*cmd)) { | ||
299 | const u8 *cmd_param; | ||
300 | |||
301 | cmd = (struct hci_command_hdr *)fw_ptr; | ||
302 | fw_ptr += sizeof(*cmd); | ||
303 | fw_size -= sizeof(*cmd); | ||
304 | |||
305 | if (fw_size < cmd->plen) { | ||
306 | BT_ERR("%s: BCM: patch %s is corrupted", hdev->name, | ||
307 | fw_name); | ||
308 | err = -EINVAL; | ||
309 | goto reset; | ||
310 | } | ||
311 | 347 | ||
312 | cmd_param = fw_ptr; | ||
313 | fw_ptr += cmd->plen; | ||
314 | fw_size -= cmd->plen; | ||
315 | |||
316 | opcode = le16_to_cpu(cmd->opcode); | ||
317 | |||
318 | skb = __hci_cmd_sync(hdev, opcode, cmd->plen, cmd_param, | ||
319 | HCI_INIT_TIMEOUT); | ||
320 | if (IS_ERR(skb)) { | ||
321 | err = PTR_ERR(skb); | ||
322 | BT_ERR("%s: BCM: patch command %04x failed (%d)", | ||
323 | hdev->name, opcode, err); | ||
324 | goto reset; | ||
325 | } | ||
326 | kfree_skb(skb); | ||
327 | } | ||
328 | |||
329 | /* 250 msec delay after Launch Ram completes */ | ||
330 | msleep(250); | ||
331 | |||
332 | reset: | ||
333 | /* Reset */ | 348 | /* Reset */ |
334 | err = btbcm_reset(hdev); | 349 | err = btbcm_reset(hdev); |
335 | if (err) | 350 | if (err) |
336 | goto done; | 351 | return err; |
337 | 352 | ||
338 | /* Read Local Version Info */ | 353 | /* Read Local Version Info */ |
339 | skb = btbcm_read_local_version(hdev); | 354 | skb = btbcm_read_local_version(hdev); |
340 | if (IS_ERR(skb)) { | 355 | if (IS_ERR(skb)) |
341 | err = PTR_ERR(skb); | 356 | return PTR_ERR(skb); |
342 | goto done; | ||
343 | } | ||
344 | 357 | ||
345 | ver = (struct hci_rp_read_local_version *)skb->data; | 358 | ver = (struct hci_rp_read_local_version *)skb->data; |
346 | rev = le16_to_cpu(ver->hci_rev); | 359 | rev = le16_to_cpu(ver->hci_rev); |
@@ -355,10 +368,7 @@ reset: | |||
355 | 368 | ||
356 | set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); | 369 | set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); |
357 | 370 | ||
358 | done: | 371 | return 0; |
359 | release_firmware(fw); | ||
360 | |||
361 | return err; | ||
362 | } | 372 | } |
363 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); | 373 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); |
364 | 374 | ||
diff --git a/drivers/bluetooth/btbcm.h b/drivers/bluetooth/btbcm.h index 34268ae3eb46..eb6ab5f9483d 100644 --- a/drivers/bluetooth/btbcm.h +++ b/drivers/bluetooth/btbcm.h | |||
@@ -25,6 +25,7 @@ | |||
25 | 25 | ||
26 | int btbcm_check_bdaddr(struct hci_dev *hdev); | 26 | int btbcm_check_bdaddr(struct hci_dev *hdev); |
27 | int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); | 27 | int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr); |
28 | int btbcm_patchram(struct hci_dev *hdev, const char *firmware); | ||
28 | 29 | ||
29 | int btbcm_setup_patchram(struct hci_dev *hdev); | 30 | int btbcm_setup_patchram(struct hci_dev *hdev); |
30 | int btbcm_setup_apple(struct hci_dev *hdev); | 31 | int btbcm_setup_apple(struct hci_dev *hdev); |
@@ -41,6 +42,11 @@ static inline int btbcm_set_bdaddr(struct hci_dev *hdev, const bdaddr_t *bdaddr) | |||
41 | return -EOPNOTSUPP; | 42 | return -EOPNOTSUPP; |
42 | } | 43 | } |
43 | 44 | ||
45 | static inline int btbcm_patchram(struct hci_dev *hdev, const char *firmware) | ||
46 | { | ||
47 | return -EOPNOTSUPP; | ||
48 | } | ||
49 | |||
44 | static inline int btbcm_setup_patchram(struct hci_dev *hdev) | 50 | static inline int btbcm_setup_patchram(struct hci_dev *hdev) |
45 | { | 51 | { |
46 | return 0; | 52 | return 0; |