.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * |
---|
3 | 4 | * Bluetooth support for Broadcom devices |
---|
4 | 5 | * |
---|
5 | 6 | * Copyright (C) 2015 Intel Corporation |
---|
6 | | - * |
---|
7 | | - * |
---|
8 | | - * This program is free software; you can redistribute it and/or modify |
---|
9 | | - * it under the terms of the GNU General Public License as published by |
---|
10 | | - * the Free Software Foundation; either version 2 of the License, or |
---|
11 | | - * (at your option) any later version. |
---|
12 | | - * |
---|
13 | | - * This program is distributed in the hope that it will be useful, |
---|
14 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
15 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
16 | | - * GNU General Public License for more details. |
---|
17 | | - * |
---|
18 | | - * You should have received a copy of the GNU General Public License |
---|
19 | | - * along with this program; if not, write to the Free Software |
---|
20 | | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
---|
21 | | - * |
---|
22 | 7 | */ |
---|
23 | 8 | |
---|
| 9 | +#ifndef __GENKSYMS__ // ANDROID CRC kabi preservation hack due to commit 76dd7893bd10 |
---|
| 10 | +#include <linux/efi.h> |
---|
| 11 | +#endif |
---|
24 | 12 | #include <linux/module.h> |
---|
25 | 13 | #include <linux/firmware.h> |
---|
26 | 14 | #include <asm/unaligned.h> |
---|
.. | .. |
---|
33 | 21 | #define VERSION "0.1" |
---|
34 | 22 | |
---|
35 | 23 | #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) |
---|
| 24 | +#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) |
---|
| 25 | +#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) |
---|
| 26 | +#define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) |
---|
36 | 27 | #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) |
---|
37 | 28 | #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) |
---|
| 29 | +#define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}}) |
---|
| 30 | +#define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}}) |
---|
| 31 | +#define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}}) |
---|
| 32 | + |
---|
| 33 | +#define BCM_FW_NAME_LEN 64 |
---|
| 34 | +#define BCM_FW_NAME_COUNT_MAX 2 |
---|
| 35 | +/* For kmalloc-ing the fw-name array instead of putting it on the stack */ |
---|
| 36 | +typedef char bcm_fw_name[BCM_FW_NAME_LEN]; |
---|
| 37 | + |
---|
| 38 | +#ifdef CONFIG_EFI |
---|
| 39 | +static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev) |
---|
| 40 | +{ |
---|
| 41 | + efi_guid_t guid = EFI_GUID(0x74b00bd9, 0x805a, 0x4d61, 0xb5, 0x1f, |
---|
| 42 | + 0x43, 0x26, 0x81, 0x23, 0xd1, 0x13); |
---|
| 43 | + bdaddr_t efi_bdaddr, bdaddr; |
---|
| 44 | + efi_status_t status; |
---|
| 45 | + unsigned long len; |
---|
| 46 | + int ret; |
---|
| 47 | + |
---|
| 48 | + if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) |
---|
| 49 | + return -EOPNOTSUPP; |
---|
| 50 | + |
---|
| 51 | + len = sizeof(efi_bdaddr); |
---|
| 52 | + status = efi.get_variable(L"BDADDR", &guid, NULL, &len, &efi_bdaddr); |
---|
| 53 | + if (status != EFI_SUCCESS) |
---|
| 54 | + return -ENXIO; |
---|
| 55 | + |
---|
| 56 | + if (len != sizeof(efi_bdaddr)) |
---|
| 57 | + return -EIO; |
---|
| 58 | + |
---|
| 59 | + baswap(&bdaddr, &efi_bdaddr); |
---|
| 60 | + |
---|
| 61 | + ret = btbcm_set_bdaddr(hdev, &bdaddr); |
---|
| 62 | + if (ret) |
---|
| 63 | + return ret; |
---|
| 64 | + |
---|
| 65 | + bt_dev_info(hdev, "BCM: Using EFI device address (%pMR)", &bdaddr); |
---|
| 66 | + return 0; |
---|
| 67 | +} |
---|
| 68 | +#else |
---|
| 69 | +static int btbcm_set_bdaddr_from_efi(struct hci_dev *hdev) |
---|
| 70 | +{ |
---|
| 71 | + return -EOPNOTSUPP; |
---|
| 72 | +} |
---|
| 73 | +#endif |
---|
38 | 74 | |
---|
39 | 75 | int btbcm_check_bdaddr(struct hci_dev *hdev) |
---|
40 | 76 | { |
---|
.. | .. |
---|
45 | 81 | HCI_INIT_TIMEOUT); |
---|
46 | 82 | if (IS_ERR(skb)) { |
---|
47 | 83 | int err = PTR_ERR(skb); |
---|
| 84 | + |
---|
48 | 85 | bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err); |
---|
49 | 86 | return err; |
---|
50 | 87 | } |
---|
.. | .. |
---|
64 | 101 | * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller |
---|
65 | 102 | * with no configured address. |
---|
66 | 103 | * |
---|
| 104 | + * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller |
---|
| 105 | + * with no configured address. |
---|
| 106 | + * |
---|
| 107 | + * The address 20:76:A0:00:56:79 indicates a BCM2076B1 controller |
---|
| 108 | + * with no configured address. |
---|
| 109 | + * |
---|
67 | 110 | * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller |
---|
68 | 111 | * with waiting for configuration state. |
---|
69 | 112 | * |
---|
70 | 113 | * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller |
---|
71 | 114 | * with waiting for configuration state. |
---|
| 115 | + * |
---|
| 116 | + * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller |
---|
| 117 | + * with no configured address. |
---|
72 | 118 | */ |
---|
73 | 119 | if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || |
---|
| 120 | + !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || |
---|
| 121 | + !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) || |
---|
74 | 122 | !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || |
---|
75 | | - !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { |
---|
76 | | - bt_dev_info(hdev, "BCM: Using default device address (%pMR)", |
---|
77 | | - &bda->bdaddr); |
---|
78 | | - set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); |
---|
| 123 | + !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || |
---|
| 124 | + !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) || |
---|
| 125 | + !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || |
---|
| 126 | + !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || |
---|
| 127 | + !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { |
---|
| 128 | + /* Try falling back to BDADDR EFI variable */ |
---|
| 129 | + if (btbcm_set_bdaddr_from_efi(hdev) != 0) { |
---|
| 130 | + bt_dev_info(hdev, "BCM: Using default device address (%pMR)", |
---|
| 131 | + &bda->bdaddr); |
---|
| 132 | + set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); |
---|
| 133 | + } |
---|
79 | 134 | } |
---|
80 | 135 | |
---|
81 | 136 | kfree_skb(skb); |
---|
.. | .. |
---|
100 | 155 | return 0; |
---|
101 | 156 | } |
---|
102 | 157 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); |
---|
| 158 | + |
---|
| 159 | +int btbcm_read_pcm_int_params(struct hci_dev *hdev, |
---|
| 160 | + struct bcm_set_pcm_int_params *params) |
---|
| 161 | +{ |
---|
| 162 | + struct sk_buff *skb; |
---|
| 163 | + int err = 0; |
---|
| 164 | + |
---|
| 165 | + skb = __hci_cmd_sync(hdev, 0xfc1d, 0, NULL, HCI_INIT_TIMEOUT); |
---|
| 166 | + if (IS_ERR(skb)) { |
---|
| 167 | + err = PTR_ERR(skb); |
---|
| 168 | + bt_dev_err(hdev, "BCM: Read PCM int params failed (%d)", err); |
---|
| 169 | + return err; |
---|
| 170 | + } |
---|
| 171 | + |
---|
| 172 | + if (skb->len != 6 || skb->data[0]) { |
---|
| 173 | + bt_dev_err(hdev, "BCM: Read PCM int params length mismatch"); |
---|
| 174 | + kfree_skb(skb); |
---|
| 175 | + return -EIO; |
---|
| 176 | + } |
---|
| 177 | + |
---|
| 178 | + if (params) |
---|
| 179 | + memcpy(params, skb->data + 1, 5); |
---|
| 180 | + |
---|
| 181 | + kfree_skb(skb); |
---|
| 182 | + |
---|
| 183 | + return 0; |
---|
| 184 | +} |
---|
| 185 | +EXPORT_SYMBOL_GPL(btbcm_read_pcm_int_params); |
---|
| 186 | + |
---|
| 187 | +int btbcm_write_pcm_int_params(struct hci_dev *hdev, |
---|
| 188 | + const struct bcm_set_pcm_int_params *params) |
---|
| 189 | +{ |
---|
| 190 | + struct sk_buff *skb; |
---|
| 191 | + int err; |
---|
| 192 | + |
---|
| 193 | + skb = __hci_cmd_sync(hdev, 0xfc1c, 5, params, HCI_INIT_TIMEOUT); |
---|
| 194 | + if (IS_ERR(skb)) { |
---|
| 195 | + err = PTR_ERR(skb); |
---|
| 196 | + bt_dev_err(hdev, "BCM: Write PCM int params failed (%d)", err); |
---|
| 197 | + return err; |
---|
| 198 | + } |
---|
| 199 | + kfree_skb(skb); |
---|
| 200 | + |
---|
| 201 | + return 0; |
---|
| 202 | +} |
---|
| 203 | +EXPORT_SYMBOL_GPL(btbcm_write_pcm_int_params); |
---|
103 | 204 | |
---|
104 | 205 | int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) |
---|
105 | 206 | { |
---|
.. | .. |
---|
171 | 272 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); |
---|
172 | 273 | if (IS_ERR(skb)) { |
---|
173 | 274 | int err = PTR_ERR(skb); |
---|
| 275 | + |
---|
174 | 276 | bt_dev_err(hdev, "BCM: Reset failed (%d)", err); |
---|
175 | 277 | return err; |
---|
176 | 278 | } |
---|
.. | .. |
---|
304 | 406 | bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); |
---|
305 | 407 | kfree_skb(skb); |
---|
306 | 408 | |
---|
| 409 | + return 0; |
---|
| 410 | +} |
---|
| 411 | + |
---|
| 412 | +static int btbcm_print_local_name(struct hci_dev *hdev) |
---|
| 413 | +{ |
---|
| 414 | + struct sk_buff *skb; |
---|
| 415 | + |
---|
307 | 416 | /* Read Local Name */ |
---|
308 | 417 | skb = btbcm_read_local_name(hdev); |
---|
309 | 418 | if (IS_ERR(skb)) |
---|
.. | .. |
---|
322 | 431 | |
---|
323 | 432 | static const struct bcm_subver_table bcm_uart_subver_table[] = { |
---|
324 | 433 | { 0x4103, "BCM4330B1" }, /* 002.001.003 */ |
---|
| 434 | + { 0x410d, "BCM4334B0" }, /* 002.001.013 */ |
---|
325 | 435 | { 0x410e, "BCM43341B0" }, /* 002.001.014 */ |
---|
| 436 | + { 0x4204, "BCM2076B1" }, /* 002.002.004 */ |
---|
326 | 437 | { 0x4406, "BCM4324B3" }, /* 002.004.006 */ |
---|
327 | 438 | { 0x4606, "BCM4324B5" }, /* 002.006.006 */ |
---|
328 | 439 | { 0x6109, "BCM4335C0" }, /* 003.001.009 */ |
---|
.. | .. |
---|
330 | 441 | { 0x2122, "BCM4343A0" }, /* 001.001.034 */ |
---|
331 | 442 | { 0x2209, "BCM43430A1" }, /* 001.002.009 */ |
---|
332 | 443 | { 0x6119, "BCM4345C0" }, /* 003.001.025 */ |
---|
| 444 | + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ |
---|
333 | 445 | { 0x230f, "BCM4356A2" }, /* 001.003.015 */ |
---|
| 446 | + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ |
---|
| 447 | + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ |
---|
| 448 | + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ |
---|
| 449 | + { 0x4217, "BCM4329B1" }, /* 002.002.023 */ |
---|
| 450 | + { 0x6106, "BCM4359C0" }, /* 003.001.006 */ |
---|
| 451 | + { 0x4106, "BCM4335A0" }, /* 002.001.006 */ |
---|
334 | 452 | { } |
---|
335 | 453 | }; |
---|
336 | 454 | |
---|
.. | .. |
---|
341 | 459 | { 0x2118, "BCM20702A0" }, /* 001.001.024 */ |
---|
342 | 460 | { 0x2126, "BCM4335A0" }, /* 001.001.038 */ |
---|
343 | 461 | { 0x220e, "BCM20702A1" }, /* 001.002.014 */ |
---|
344 | | - { 0x230f, "BCM4354A2" }, /* 001.003.015 */ |
---|
| 462 | + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ |
---|
345 | 463 | { 0x4106, "BCM4335B0" }, /* 002.001.006 */ |
---|
346 | 464 | { 0x410e, "BCM20702B0" }, /* 002.001.014 */ |
---|
347 | 465 | { 0x6109, "BCM4335C0" }, /* 003.001.009 */ |
---|
348 | 466 | { 0x610c, "BCM4354" }, /* 003.001.012 */ |
---|
| 467 | + { 0x6607, "BCM4350C5" }, /* 003.006.007 */ |
---|
349 | 468 | { } |
---|
350 | 469 | }; |
---|
351 | 470 | |
---|
352 | | -int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len, |
---|
353 | | - bool reinit) |
---|
| 471 | +int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) |
---|
354 | 472 | { |
---|
355 | 473 | u16 subver, rev, pid, vid; |
---|
356 | | - const char *hw_name = "BCM"; |
---|
357 | 474 | struct sk_buff *skb; |
---|
358 | 475 | struct hci_rp_read_local_version *ver; |
---|
359 | 476 | const struct bcm_subver_table *bcm_subver_table; |
---|
| 477 | + const char *hw_name = NULL; |
---|
| 478 | + char postfix[16] = ""; |
---|
| 479 | + int fw_name_count = 0; |
---|
| 480 | + bcm_fw_name *fw_name; |
---|
| 481 | + const struct firmware *fw; |
---|
360 | 482 | int i, err; |
---|
361 | 483 | |
---|
362 | 484 | /* Reset */ |
---|
.. | .. |
---|
375 | 497 | kfree_skb(skb); |
---|
376 | 498 | |
---|
377 | 499 | /* Read controller information */ |
---|
378 | | - if (!reinit) { |
---|
| 500 | + if (!(*fw_load_done)) { |
---|
379 | 501 | err = btbcm_read_info(hdev); |
---|
380 | 502 | if (err) |
---|
381 | 503 | return err; |
---|
382 | 504 | } |
---|
383 | | - |
---|
384 | | - /* Upper nibble of rev should be between 0 and 3? */ |
---|
385 | | - if (((rev & 0xf000) >> 12) > 3) |
---|
386 | | - return 0; |
---|
| 505 | + err = btbcm_print_local_name(hdev); |
---|
| 506 | + if (err) |
---|
| 507 | + return err; |
---|
387 | 508 | |
---|
388 | 509 | bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : |
---|
389 | 510 | bcm_uart_subver_table; |
---|
.. | .. |
---|
395 | 516 | } |
---|
396 | 517 | } |
---|
397 | 518 | |
---|
| 519 | + bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", |
---|
| 520 | + hw_name ? hw_name : "BCM", (subver & 0xe000) >> 13, |
---|
| 521 | + (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); |
---|
| 522 | + |
---|
| 523 | + if (*fw_load_done) |
---|
| 524 | + return 0; |
---|
| 525 | + |
---|
398 | 526 | if (hdev->bus == HCI_USB) { |
---|
399 | 527 | /* Read USB Product Info */ |
---|
400 | 528 | skb = btbcm_read_usb_product(hdev); |
---|
.. | .. |
---|
405 | 533 | pid = get_unaligned_le16(skb->data + 3); |
---|
406 | 534 | kfree_skb(skb); |
---|
407 | 535 | |
---|
408 | | - snprintf(fw_name, len, "brcm/%s-%4.4x-%4.4x.hcd", |
---|
409 | | - hw_name, vid, pid); |
---|
410 | | - } else { |
---|
411 | | - snprintf(fw_name, len, "brcm/%s.hcd", hw_name); |
---|
| 536 | + snprintf(postfix, sizeof(postfix), "-%4.4x-%4.4x", vid, pid); |
---|
412 | 537 | } |
---|
413 | 538 | |
---|
414 | | - bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", |
---|
415 | | - hw_name, (subver & 0xe000) >> 13, |
---|
416 | | - (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); |
---|
| 539 | + fw_name = kmalloc(BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN, GFP_KERNEL); |
---|
| 540 | + if (!fw_name) |
---|
| 541 | + return -ENOMEM; |
---|
417 | 542 | |
---|
| 543 | + if (hw_name) { |
---|
| 544 | + snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, |
---|
| 545 | + "brcm/%s%s.hcd", hw_name, postfix); |
---|
| 546 | + fw_name_count++; |
---|
| 547 | + } |
---|
| 548 | + |
---|
| 549 | + snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, |
---|
| 550 | + "brcm/BCM%s.hcd", postfix); |
---|
| 551 | + fw_name_count++; |
---|
| 552 | + |
---|
| 553 | + for (i = 0; i < fw_name_count; i++) { |
---|
| 554 | + err = firmware_request_nowarn(&fw, fw_name[i], &hdev->dev); |
---|
| 555 | + if (err == 0) { |
---|
| 556 | + bt_dev_info(hdev, "%s '%s' Patch", |
---|
| 557 | + hw_name ? hw_name : "BCM", fw_name[i]); |
---|
| 558 | + *fw_load_done = true; |
---|
| 559 | + break; |
---|
| 560 | + } |
---|
| 561 | + } |
---|
| 562 | + |
---|
| 563 | + if (*fw_load_done) { |
---|
| 564 | + err = btbcm_patchram(hdev, fw); |
---|
| 565 | + if (err) |
---|
| 566 | + bt_dev_info(hdev, "BCM: Patch failed (%d)", err); |
---|
| 567 | + |
---|
| 568 | + release_firmware(fw); |
---|
| 569 | + } else { |
---|
| 570 | + bt_dev_err(hdev, "BCM: firmware Patch file not found, tried:"); |
---|
| 571 | + for (i = 0; i < fw_name_count; i++) |
---|
| 572 | + bt_dev_err(hdev, "BCM: '%s'", fw_name[i]); |
---|
| 573 | + } |
---|
| 574 | + |
---|
| 575 | + kfree(fw_name); |
---|
418 | 576 | return 0; |
---|
419 | 577 | } |
---|
420 | 578 | EXPORT_SYMBOL_GPL(btbcm_initialize); |
---|
421 | 579 | |
---|
422 | | -int btbcm_finalize(struct hci_dev *hdev) |
---|
| 580 | +int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done) |
---|
423 | 581 | { |
---|
424 | | - char fw_name[64]; |
---|
425 | 582 | int err; |
---|
426 | 583 | |
---|
427 | | - /* Re-initialize */ |
---|
428 | | - err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true); |
---|
429 | | - if (err) |
---|
430 | | - return err; |
---|
| 584 | + /* Re-initialize if necessary */ |
---|
| 585 | + if (*fw_load_done) { |
---|
| 586 | + err = btbcm_initialize(hdev, fw_load_done); |
---|
| 587 | + if (err) |
---|
| 588 | + return err; |
---|
| 589 | + } |
---|
431 | 590 | |
---|
432 | 591 | btbcm_check_bdaddr(hdev); |
---|
433 | 592 | |
---|
.. | .. |
---|
439 | 598 | |
---|
440 | 599 | int btbcm_setup_patchram(struct hci_dev *hdev) |
---|
441 | 600 | { |
---|
442 | | - char fw_name[64]; |
---|
443 | | - const struct firmware *fw; |
---|
444 | | - struct sk_buff *skb; |
---|
| 601 | + bool fw_load_done = false; |
---|
445 | 602 | int err; |
---|
446 | 603 | |
---|
447 | 604 | /* Initialize */ |
---|
448 | | - err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), false); |
---|
| 605 | + err = btbcm_initialize(hdev, &fw_load_done); |
---|
449 | 606 | if (err) |
---|
450 | 607 | return err; |
---|
451 | 608 | |
---|
452 | | - err = request_firmware(&fw, fw_name, &hdev->dev); |
---|
453 | | - if (err < 0) { |
---|
454 | | - bt_dev_info(hdev, "BCM: Patch %s not found", fw_name); |
---|
455 | | - goto done; |
---|
456 | | - } |
---|
457 | | - |
---|
458 | | - btbcm_patchram(hdev, fw); |
---|
459 | | - |
---|
460 | | - release_firmware(fw); |
---|
461 | | - |
---|
462 | | - /* Re-initialize */ |
---|
463 | | - err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true); |
---|
464 | | - if (err) |
---|
465 | | - return err; |
---|
466 | | - |
---|
467 | | - /* Read Local Name */ |
---|
468 | | - skb = btbcm_read_local_name(hdev); |
---|
469 | | - if (IS_ERR(skb)) |
---|
470 | | - return PTR_ERR(skb); |
---|
471 | | - |
---|
472 | | - bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); |
---|
473 | | - kfree_skb(skb); |
---|
474 | | - |
---|
475 | | -done: |
---|
476 | | - btbcm_check_bdaddr(hdev); |
---|
477 | | - |
---|
478 | | - set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks); |
---|
479 | | - |
---|
480 | | - return 0; |
---|
| 609 | + /* Re-initialize after loading Patch */ |
---|
| 610 | + return btbcm_finalize(hdev, &fw_load_done); |
---|
481 | 611 | } |
---|
482 | 612 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); |
---|
483 | 613 | |
---|