.. | .. |
---|
| 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 | |
---|
24 | 9 | #include <linux/module.h> |
---|
.. | .. |
---|
33 | 18 | #define VERSION "0.1" |
---|
34 | 19 | |
---|
35 | 20 | #define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}}) |
---|
| 21 | +#define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}}) |
---|
| 22 | +#define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}}) |
---|
| 23 | +#define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}}) |
---|
36 | 24 | #define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}}) |
---|
37 | 25 | #define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}}) |
---|
| 26 | +#define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}}) |
---|
| 27 | +#define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}}) |
---|
| 28 | +#define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}}) |
---|
| 29 | + |
---|
| 30 | +#define BCM_FW_NAME_LEN 64 |
---|
| 31 | +#define BCM_FW_NAME_COUNT_MAX 2 |
---|
| 32 | +/* For kmalloc-ing the fw-name array instead of putting it on the stack */ |
---|
| 33 | +typedef char bcm_fw_name[BCM_FW_NAME_LEN]; |
---|
38 | 34 | |
---|
39 | 35 | int btbcm_check_bdaddr(struct hci_dev *hdev) |
---|
40 | 36 | { |
---|
.. | .. |
---|
45 | 41 | HCI_INIT_TIMEOUT); |
---|
46 | 42 | if (IS_ERR(skb)) { |
---|
47 | 43 | int err = PTR_ERR(skb); |
---|
| 44 | + |
---|
48 | 45 | bt_dev_err(hdev, "BCM: Reading device address failed (%d)", err); |
---|
49 | 46 | return err; |
---|
50 | 47 | } |
---|
.. | .. |
---|
64 | 61 | * The address 00:20:70:02:A0:00 indicates a BCM20702A0 controller |
---|
65 | 62 | * with no configured address. |
---|
66 | 63 | * |
---|
| 64 | + * The address 20:70:02:A0:00:00 indicates a BCM20702A1 controller |
---|
| 65 | + * with no configured address. |
---|
| 66 | + * |
---|
| 67 | + * The address 20:76:A0:00:56:79 indicates a BCM2076B1 controller |
---|
| 68 | + * with no configured address. |
---|
| 69 | + * |
---|
67 | 70 | * The address 43:24:B3:00:00:00 indicates a BCM4324B3 controller |
---|
68 | 71 | * with waiting for configuration state. |
---|
69 | 72 | * |
---|
70 | 73 | * The address 43:30:B1:00:00:00 indicates a BCM4330B1 controller |
---|
71 | 74 | * with waiting for configuration state. |
---|
| 75 | + * |
---|
| 76 | + * The address 43:43:A0:12:1F:AC indicates a BCM43430A0 controller |
---|
| 77 | + * with no configured address. |
---|
72 | 78 | */ |
---|
73 | 79 | if (!bacmp(&bda->bdaddr, BDADDR_BCM20702A0) || |
---|
| 80 | + !bacmp(&bda->bdaddr, BDADDR_BCM20702A1) || |
---|
| 81 | + !bacmp(&bda->bdaddr, BDADDR_BCM2076B1) || |
---|
74 | 82 | !bacmp(&bda->bdaddr, BDADDR_BCM4324B3) || |
---|
75 | | - !bacmp(&bda->bdaddr, BDADDR_BCM4330B1)) { |
---|
| 83 | + !bacmp(&bda->bdaddr, BDADDR_BCM4330B1) || |
---|
| 84 | + !bacmp(&bda->bdaddr, BDADDR_BCM4334B0) || |
---|
| 85 | + !bacmp(&bda->bdaddr, BDADDR_BCM4345C5) || |
---|
| 86 | + !bacmp(&bda->bdaddr, BDADDR_BCM43430A0) || |
---|
| 87 | + !bacmp(&bda->bdaddr, BDADDR_BCM43341B)) { |
---|
76 | 88 | bt_dev_info(hdev, "BCM: Using default device address (%pMR)", |
---|
77 | 89 | &bda->bdaddr); |
---|
78 | 90 | set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks); |
---|
.. | .. |
---|
100 | 112 | return 0; |
---|
101 | 113 | } |
---|
102 | 114 | EXPORT_SYMBOL_GPL(btbcm_set_bdaddr); |
---|
| 115 | + |
---|
| 116 | +int btbcm_read_pcm_int_params(struct hci_dev *hdev, |
---|
| 117 | + struct bcm_set_pcm_int_params *params) |
---|
| 118 | +{ |
---|
| 119 | + struct sk_buff *skb; |
---|
| 120 | + int err = 0; |
---|
| 121 | + |
---|
| 122 | + skb = __hci_cmd_sync(hdev, 0xfc1d, 0, NULL, HCI_INIT_TIMEOUT); |
---|
| 123 | + if (IS_ERR(skb)) { |
---|
| 124 | + err = PTR_ERR(skb); |
---|
| 125 | + bt_dev_err(hdev, "BCM: Read PCM int params failed (%d)", err); |
---|
| 126 | + return err; |
---|
| 127 | + } |
---|
| 128 | + |
---|
| 129 | + if (skb->len != 6 || skb->data[0]) { |
---|
| 130 | + bt_dev_err(hdev, "BCM: Read PCM int params length mismatch"); |
---|
| 131 | + kfree_skb(skb); |
---|
| 132 | + return -EIO; |
---|
| 133 | + } |
---|
| 134 | + |
---|
| 135 | + if (params) |
---|
| 136 | + memcpy(params, skb->data + 1, 5); |
---|
| 137 | + |
---|
| 138 | + kfree_skb(skb); |
---|
| 139 | + |
---|
| 140 | + return 0; |
---|
| 141 | +} |
---|
| 142 | +EXPORT_SYMBOL_GPL(btbcm_read_pcm_int_params); |
---|
| 143 | + |
---|
| 144 | +int btbcm_write_pcm_int_params(struct hci_dev *hdev, |
---|
| 145 | + const struct bcm_set_pcm_int_params *params) |
---|
| 146 | +{ |
---|
| 147 | + struct sk_buff *skb; |
---|
| 148 | + int err; |
---|
| 149 | + |
---|
| 150 | + skb = __hci_cmd_sync(hdev, 0xfc1c, 5, params, HCI_INIT_TIMEOUT); |
---|
| 151 | + if (IS_ERR(skb)) { |
---|
| 152 | + err = PTR_ERR(skb); |
---|
| 153 | + bt_dev_err(hdev, "BCM: Write PCM int params failed (%d)", err); |
---|
| 154 | + return err; |
---|
| 155 | + } |
---|
| 156 | + kfree_skb(skb); |
---|
| 157 | + |
---|
| 158 | + return 0; |
---|
| 159 | +} |
---|
| 160 | +EXPORT_SYMBOL_GPL(btbcm_write_pcm_int_params); |
---|
103 | 161 | |
---|
104 | 162 | int btbcm_patchram(struct hci_dev *hdev, const struct firmware *fw) |
---|
105 | 163 | { |
---|
.. | .. |
---|
171 | 229 | skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); |
---|
172 | 230 | if (IS_ERR(skb)) { |
---|
173 | 231 | int err = PTR_ERR(skb); |
---|
| 232 | + |
---|
174 | 233 | bt_dev_err(hdev, "BCM: Reset failed (%d)", err); |
---|
175 | 234 | return err; |
---|
176 | 235 | } |
---|
.. | .. |
---|
304 | 363 | bt_dev_info(hdev, "BCM: features 0x%2.2x", skb->data[1]); |
---|
305 | 364 | kfree_skb(skb); |
---|
306 | 365 | |
---|
| 366 | + return 0; |
---|
| 367 | +} |
---|
| 368 | + |
---|
| 369 | +static int btbcm_print_local_name(struct hci_dev *hdev) |
---|
| 370 | +{ |
---|
| 371 | + struct sk_buff *skb; |
---|
| 372 | + |
---|
307 | 373 | /* Read Local Name */ |
---|
308 | 374 | skb = btbcm_read_local_name(hdev); |
---|
309 | 375 | if (IS_ERR(skb)) |
---|
.. | .. |
---|
322 | 388 | |
---|
323 | 389 | static const struct bcm_subver_table bcm_uart_subver_table[] = { |
---|
324 | 390 | { 0x4103, "BCM4330B1" }, /* 002.001.003 */ |
---|
| 391 | + { 0x410d, "BCM4334B0" }, /* 002.001.013 */ |
---|
325 | 392 | { 0x410e, "BCM43341B0" }, /* 002.001.014 */ |
---|
| 393 | + { 0x4204, "BCM2076B1" }, /* 002.002.004 */ |
---|
326 | 394 | { 0x4406, "BCM4324B3" }, /* 002.004.006 */ |
---|
327 | 395 | { 0x4606, "BCM4324B5" }, /* 002.006.006 */ |
---|
328 | 396 | { 0x6109, "BCM4335C0" }, /* 003.001.009 */ |
---|
.. | .. |
---|
330 | 398 | { 0x2122, "BCM4343A0" }, /* 001.001.034 */ |
---|
331 | 399 | { 0x2209, "BCM43430A1" }, /* 001.002.009 */ |
---|
332 | 400 | { 0x6119, "BCM4345C0" }, /* 003.001.025 */ |
---|
| 401 | + { 0x6606, "BCM4345C5" }, /* 003.006.006 */ |
---|
333 | 402 | { 0x230f, "BCM4356A2" }, /* 001.003.015 */ |
---|
| 403 | + { 0x220e, "BCM20702A1" }, /* 001.002.014 */ |
---|
| 404 | + { 0x420d, "BCM4349B1" }, /* 002.002.013 */ |
---|
| 405 | + { 0x420e, "BCM4349B1" }, /* 002.002.014 */ |
---|
| 406 | + { 0x4217, "BCM4329B1" }, /* 002.002.023 */ |
---|
| 407 | + { 0x6106, "BCM4359C0" }, /* 003.001.006 */ |
---|
| 408 | + { 0x4106, "BCM4335A0" }, /* 002.001.006 */ |
---|
334 | 409 | { } |
---|
335 | 410 | }; |
---|
336 | 411 | |
---|
.. | .. |
---|
341 | 416 | { 0x2118, "BCM20702A0" }, /* 001.001.024 */ |
---|
342 | 417 | { 0x2126, "BCM4335A0" }, /* 001.001.038 */ |
---|
343 | 418 | { 0x220e, "BCM20702A1" }, /* 001.002.014 */ |
---|
344 | | - { 0x230f, "BCM4354A2" }, /* 001.003.015 */ |
---|
| 419 | + { 0x230f, "BCM4356A2" }, /* 001.003.015 */ |
---|
345 | 420 | { 0x4106, "BCM4335B0" }, /* 002.001.006 */ |
---|
346 | 421 | { 0x410e, "BCM20702B0" }, /* 002.001.014 */ |
---|
347 | 422 | { 0x6109, "BCM4335C0" }, /* 003.001.009 */ |
---|
348 | 423 | { 0x610c, "BCM4354" }, /* 003.001.012 */ |
---|
| 424 | + { 0x6607, "BCM4350C5" }, /* 003.006.007 */ |
---|
349 | 425 | { } |
---|
350 | 426 | }; |
---|
351 | 427 | |
---|
352 | | -int btbcm_initialize(struct hci_dev *hdev, char *fw_name, size_t len, |
---|
353 | | - bool reinit) |
---|
| 428 | +int btbcm_initialize(struct hci_dev *hdev, bool *fw_load_done) |
---|
354 | 429 | { |
---|
355 | 430 | u16 subver, rev, pid, vid; |
---|
356 | | - const char *hw_name = "BCM"; |
---|
357 | 431 | struct sk_buff *skb; |
---|
358 | 432 | struct hci_rp_read_local_version *ver; |
---|
359 | 433 | const struct bcm_subver_table *bcm_subver_table; |
---|
| 434 | + const char *hw_name = NULL; |
---|
| 435 | + char postfix[16] = ""; |
---|
| 436 | + int fw_name_count = 0; |
---|
| 437 | + bcm_fw_name *fw_name; |
---|
| 438 | + const struct firmware *fw; |
---|
360 | 439 | int i, err; |
---|
361 | 440 | |
---|
362 | 441 | /* Reset */ |
---|
.. | .. |
---|
375 | 454 | kfree_skb(skb); |
---|
376 | 455 | |
---|
377 | 456 | /* Read controller information */ |
---|
378 | | - if (!reinit) { |
---|
| 457 | + if (!(*fw_load_done)) { |
---|
379 | 458 | err = btbcm_read_info(hdev); |
---|
380 | 459 | if (err) |
---|
381 | 460 | return err; |
---|
382 | 461 | } |
---|
383 | | - |
---|
384 | | - /* Upper nibble of rev should be between 0 and 3? */ |
---|
385 | | - if (((rev & 0xf000) >> 12) > 3) |
---|
386 | | - return 0; |
---|
| 462 | + err = btbcm_print_local_name(hdev); |
---|
| 463 | + if (err) |
---|
| 464 | + return err; |
---|
387 | 465 | |
---|
388 | 466 | bcm_subver_table = (hdev->bus == HCI_USB) ? bcm_usb_subver_table : |
---|
389 | 467 | bcm_uart_subver_table; |
---|
.. | .. |
---|
395 | 473 | } |
---|
396 | 474 | } |
---|
397 | 475 | |
---|
| 476 | + bt_dev_info(hdev, "%s (%3.3u.%3.3u.%3.3u) build %4.4u", |
---|
| 477 | + hw_name ? hw_name : "BCM", (subver & 0xe000) >> 13, |
---|
| 478 | + (subver & 0x1f00) >> 8, (subver & 0x00ff), rev & 0x0fff); |
---|
| 479 | + |
---|
| 480 | + if (*fw_load_done) |
---|
| 481 | + return 0; |
---|
| 482 | + |
---|
398 | 483 | if (hdev->bus == HCI_USB) { |
---|
399 | 484 | /* Read USB Product Info */ |
---|
400 | 485 | skb = btbcm_read_usb_product(hdev); |
---|
.. | .. |
---|
405 | 490 | pid = get_unaligned_le16(skb->data + 3); |
---|
406 | 491 | kfree_skb(skb); |
---|
407 | 492 | |
---|
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); |
---|
| 493 | + snprintf(postfix, sizeof(postfix), "-%4.4x-%4.4x", vid, pid); |
---|
412 | 494 | } |
---|
413 | 495 | |
---|
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); |
---|
| 496 | + fw_name = kmalloc(BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN, GFP_KERNEL); |
---|
| 497 | + if (!fw_name) |
---|
| 498 | + return -ENOMEM; |
---|
417 | 499 | |
---|
| 500 | + if (hw_name) { |
---|
| 501 | + snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, |
---|
| 502 | + "brcm/%s%s.hcd", hw_name, postfix); |
---|
| 503 | + fw_name_count++; |
---|
| 504 | + } |
---|
| 505 | + |
---|
| 506 | + snprintf(fw_name[fw_name_count], BCM_FW_NAME_LEN, |
---|
| 507 | + "brcm/BCM%s.hcd", postfix); |
---|
| 508 | + fw_name_count++; |
---|
| 509 | + |
---|
| 510 | + for (i = 0; i < fw_name_count; i++) { |
---|
| 511 | + err = firmware_request_nowarn(&fw, fw_name[i], &hdev->dev); |
---|
| 512 | + if (err == 0) { |
---|
| 513 | + bt_dev_info(hdev, "%s '%s' Patch", |
---|
| 514 | + hw_name ? hw_name : "BCM", fw_name[i]); |
---|
| 515 | + *fw_load_done = true; |
---|
| 516 | + break; |
---|
| 517 | + } |
---|
| 518 | + } |
---|
| 519 | + |
---|
| 520 | + if (*fw_load_done) { |
---|
| 521 | + err = btbcm_patchram(hdev, fw); |
---|
| 522 | + if (err) |
---|
| 523 | + bt_dev_info(hdev, "BCM: Patch failed (%d)", err); |
---|
| 524 | + |
---|
| 525 | + release_firmware(fw); |
---|
| 526 | + } else { |
---|
| 527 | + bt_dev_err(hdev, "BCM: firmware Patch file not found, tried:"); |
---|
| 528 | + for (i = 0; i < fw_name_count; i++) |
---|
| 529 | + bt_dev_err(hdev, "BCM: '%s'", fw_name[i]); |
---|
| 530 | + } |
---|
| 531 | + |
---|
| 532 | + kfree(fw_name); |
---|
418 | 533 | return 0; |
---|
419 | 534 | } |
---|
420 | 535 | EXPORT_SYMBOL_GPL(btbcm_initialize); |
---|
421 | 536 | |
---|
422 | | -int btbcm_finalize(struct hci_dev *hdev) |
---|
| 537 | +int btbcm_finalize(struct hci_dev *hdev, bool *fw_load_done) |
---|
423 | 538 | { |
---|
424 | | - char fw_name[64]; |
---|
425 | 539 | int err; |
---|
426 | 540 | |
---|
427 | | - /* Re-initialize */ |
---|
428 | | - err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), true); |
---|
429 | | - if (err) |
---|
430 | | - return err; |
---|
| 541 | + /* Re-initialize if necessary */ |
---|
| 542 | + if (*fw_load_done) { |
---|
| 543 | + err = btbcm_initialize(hdev, fw_load_done); |
---|
| 544 | + if (err) |
---|
| 545 | + return err; |
---|
| 546 | + } |
---|
431 | 547 | |
---|
432 | 548 | btbcm_check_bdaddr(hdev); |
---|
433 | 549 | |
---|
.. | .. |
---|
439 | 555 | |
---|
440 | 556 | int btbcm_setup_patchram(struct hci_dev *hdev) |
---|
441 | 557 | { |
---|
442 | | - char fw_name[64]; |
---|
443 | | - const struct firmware *fw; |
---|
444 | | - struct sk_buff *skb; |
---|
| 558 | + bool fw_load_done = false; |
---|
445 | 559 | int err; |
---|
446 | 560 | |
---|
447 | 561 | /* Initialize */ |
---|
448 | | - err = btbcm_initialize(hdev, fw_name, sizeof(fw_name), false); |
---|
| 562 | + err = btbcm_initialize(hdev, &fw_load_done); |
---|
449 | 563 | if (err) |
---|
450 | 564 | return err; |
---|
451 | 565 | |
---|
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; |
---|
| 566 | + /* Re-initialize after loading Patch */ |
---|
| 567 | + return btbcm_finalize(hdev, &fw_load_done); |
---|
481 | 568 | } |
---|
482 | 569 | EXPORT_SYMBOL_GPL(btbcm_setup_patchram); |
---|
483 | 570 | |
---|