2019-05-27 09:55:05 +03:00
// SPDX-License-Identifier: GPL-2.0-or-later
2015-04-06 08:52:10 +03:00
/*
*
* Bluetooth support for Broadcom devices
*
* Copyright ( C ) 2015 Intel Corporation
*/
# include <linux/module.h>
2015-04-06 08:52:13 +03:00
# include <linux/firmware.h>
# include <asm/unaligned.h>
2015-04-06 08:52:10 +03:00
# include <net/bluetooth/bluetooth.h>
# include <net/bluetooth/hci_core.h>
# include "btbcm.h"
# define VERSION "0.1"
# define BDADDR_BCM20702A0 (&(bdaddr_t) {{0x00, 0xa0, 0x02, 0x70, 0x20, 0x00}})
2018-12-17 07:04:45 +03:00
# define BDADDR_BCM20702A1 (&(bdaddr_t) {{0x00, 0x00, 0xa0, 0x02, 0x70, 0x20}})
2019-05-01 10:18:23 +03:00
# define BDADDR_BCM2076B1 (&(bdaddr_t) {{0x79, 0x56, 0x00, 0xa0, 0x76, 0x20}})
2018-12-17 07:04:47 +03:00
# define BDADDR_BCM43430A0 (&(bdaddr_t) {{0xac, 0x1f, 0x12, 0xa0, 0x43, 0x43}})
2015-05-28 12:25:02 +03:00
# define BDADDR_BCM4324B3 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb3, 0x24, 0x43}})
2015-07-27 19:02:25 +03:00
# define BDADDR_BCM4330B1 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb1, 0x30, 0x43}})
2019-11-17 23:39:46 +03:00
# define BDADDR_BCM4334B0 (&(bdaddr_t) {{0x00, 0x00, 0x00, 0xb0, 0x34, 0x43}})
2019-08-23 13:31:36 +03:00
# define BDADDR_BCM4345C5 (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0xc5, 0x45, 0x43}})
2019-04-09 17:15:50 +03:00
# define BDADDR_BCM43341B (&(bdaddr_t) {{0xac, 0x1f, 0x00, 0x1b, 0x34, 0x43}})
2015-04-06 08:52:10 +03:00
2020-04-17 20:15:27 +03:00
# define BCM_FW_NAME_LEN 64
2020-04-17 20:15:31 +03:00
# define BCM_FW_NAME_COUNT_MAX 2
/* For kmalloc-ing the fw-name array instead of putting it on the stack */
typedef char bcm_fw_name [ BCM_FW_NAME_LEN ] ;
2020-04-17 20:15:27 +03:00
2015-04-06 08:52:10 +03:00
int btbcm_check_bdaddr ( struct hci_dev * hdev )
{
struct hci_rp_read_bd_addr * bda ;
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , HCI_OP_READ_BD_ADDR , 0 , NULL ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
int err = PTR_ERR ( skb ) ;
2020-01-09 07:40:19 +03:00
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Reading device address failed (%d) " , err ) ;
2015-04-06 08:52:10 +03:00
return err ;
}
if ( skb - > len ! = sizeof ( * bda ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Device address length mismatch " ) ;
2015-04-06 08:52:10 +03:00
kfree_skb ( skb ) ;
return - EIO ;
}
bda = ( struct hci_rp_read_bd_addr * ) skb - > data ;
2015-05-28 12:25:02 +03:00
/* Check if the address indicates a controller with either an
* invalid or default address . In both cases the device needs
* to be marked as not having a valid address .
*
* The address 00 : 20 : 70 : 02 : A0 : 00 indicates a BCM20702A0 controller
2015-04-06 08:52:10 +03:00
* with no configured address .
2015-05-28 12:25:02 +03:00
*
2018-12-17 07:04:45 +03:00
* The address 20 : 70 : 02 : A0 : 00 : 00 indicates a BCM20702A1 controller
* with no configured address .
*
2019-05-01 10:18:23 +03:00
* The address 20 : 76 : A0 : 00 : 56 : 79 indicates a BCM2076B1 controller
* with no configured address .
*
2015-05-28 12:25:02 +03:00
* The address 43 : 24 : B3 : 00 : 00 : 00 indicates a BCM4324B3 controller
* with waiting for configuration state .
2015-07-27 19:02:25 +03:00
*
* The address 43 : 30 : B1 : 00 : 00 : 00 indicates a BCM4330B1 controller
* with waiting for configuration state .
2018-12-17 07:04:47 +03:00
*
* The address 43 : 43 : A0 : 12 : 1F : AC indicates a BCM43430A0 controller
* with no configured address .
2015-04-06 08:52:10 +03:00
*/
2015-05-28 12:25:02 +03:00
if ( ! bacmp ( & bda - > bdaddr , BDADDR_BCM20702A0 ) | |
2018-12-17 07:04:45 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM20702A1 ) | |
2019-05-01 10:18:23 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM2076B1 ) | |
2015-07-27 19:02:25 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM4324B3 ) | |
2018-12-17 07:04:47 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM4330B1 ) | |
2019-11-17 23:39:46 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM4334B0 ) | |
2019-08-23 13:31:36 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM4345C5 ) | |
2019-04-09 17:15:50 +03:00
! bacmp ( & bda - > bdaddr , BDADDR_BCM43430A0 ) | |
! bacmp ( & bda - > bdaddr , BDADDR_BCM43341B ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: Using default device address (%pMR) " ,
& bda - > bdaddr ) ;
2015-04-06 08:52:10 +03:00
set_bit ( HCI_QUIRK_INVALID_BDADDR , & hdev - > quirks ) ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_check_bdaddr ) ;
int btbcm_set_bdaddr ( struct hci_dev * hdev , const bdaddr_t * bdaddr )
{
struct sk_buff * skb ;
int err ;
skb = __hci_cmd_sync ( hdev , 0xfc01 , 6 , bdaddr , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Change address command failed (%d) " , err ) ;
2015-04-06 08:52:10 +03:00
return err ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_set_bdaddr ) ;
2019-11-26 10:17:30 +03:00
int btbcm_read_pcm_int_params ( struct hci_dev * hdev ,
struct bcm_set_pcm_int_params * params )
{
struct sk_buff * skb ;
int err = 0 ;
skb = __hci_cmd_sync ( hdev , 0xfc1d , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
bt_dev_err ( hdev , " BCM: Read PCM int params failed (%d) " , err ) ;
return err ;
}
if ( skb - > len ! = 6 | | skb - > data [ 0 ] ) {
bt_dev_err ( hdev , " BCM: Read PCM int params length mismatch " ) ;
kfree_skb ( skb ) ;
return - EIO ;
}
if ( params )
memcpy ( params , skb - > data + 1 , 5 ) ;
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_read_pcm_int_params ) ;
int btbcm_write_pcm_int_params ( struct hci_dev * hdev ,
const struct bcm_set_pcm_int_params * params )
{
struct sk_buff * skb ;
int err ;
skb = __hci_cmd_sync ( hdev , 0xfc1c , 5 , params , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
bt_dev_err ( hdev , " BCM: Write PCM int params failed (%d) " , err ) ;
return err ;
}
kfree_skb ( skb ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_write_pcm_int_params ) ;
2015-05-28 12:25:01 +03:00
int btbcm_patchram ( struct hci_dev * hdev , const struct firmware * fw )
2015-04-11 00:02:20 +03:00
{
const struct hci_command_hdr * cmd ;
const u8 * fw_ptr ;
size_t fw_size ;
struct sk_buff * skb ;
u16 opcode ;
2015-05-28 12:25:01 +03:00
int err = 0 ;
2015-04-11 00:02:20 +03:00
/* Start Download */
skb = __hci_cmd_sync ( hdev , 0xfc2e , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Download Minidrv command failed (%d) " ,
err ) ;
2015-04-11 00:02:20 +03:00
goto done ;
}
kfree_skb ( skb ) ;
/* 50 msec delay after Download Minidrv completes */
msleep ( 50 ) ;
fw_ptr = fw - > data ;
fw_size = fw - > size ;
while ( fw_size > = sizeof ( * cmd ) ) {
const u8 * cmd_param ;
cmd = ( struct hci_command_hdr * ) fw_ptr ;
fw_ptr + = sizeof ( * cmd ) ;
fw_size - = sizeof ( * cmd ) ;
if ( fw_size < cmd - > plen ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Patch is corrupted " ) ;
2015-04-11 00:02:20 +03:00
err = - EINVAL ;
goto done ;
}
cmd_param = fw_ptr ;
fw_ptr + = cmd - > plen ;
fw_size - = cmd - > plen ;
opcode = le16_to_cpu ( cmd - > opcode ) ;
skb = __hci_cmd_sync ( hdev , opcode , cmd - > plen , cmd_param ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
err = PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Patch command %04x failed (%d) " ,
opcode , err ) ;
2015-04-11 00:02:20 +03:00
goto done ;
}
kfree_skb ( skb ) ;
}
/* 250 msec delay after Launch Ram completes */
msleep ( 250 ) ;
done :
return err ;
}
EXPORT_SYMBOL ( btbcm_patchram ) ;
2015-04-06 08:52:13 +03:00
static int btbcm_reset ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , HCI_OP_RESET , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
int err = PTR_ERR ( skb ) ;
2020-01-09 07:40:19 +03:00
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Reset failed (%d) " , err ) ;
2015-04-06 08:52:13 +03:00
return err ;
}
kfree_skb ( skb ) ;
2017-01-10 06:46:28 +03:00
/* 100 msec delay for module to complete reset process */
msleep ( 100 ) ;
2015-04-06 08:52:13 +03:00
return 0 ;
}
2015-10-05 13:43:57 +03:00
static struct sk_buff * btbcm_read_local_name ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , HCI_OP_READ_LOCAL_NAME , 0 , NULL ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Reading local name failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-10-05 13:43:57 +03:00
return skb ;
}
if ( skb - > len ! = sizeof ( struct hci_rp_read_local_name ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Local name length mismatch " ) ;
2015-10-05 13:43:57 +03:00
kfree_skb ( skb ) ;
return ERR_PTR ( - EIO ) ;
}
return skb ;
}
2015-04-06 08:52:13 +03:00
static struct sk_buff * btbcm_read_local_version ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , HCI_OP_READ_LOCAL_VERSION , 0 , NULL ,
HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Reading local version info failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-04-06 08:52:13 +03:00
return skb ;
}
if ( skb - > len ! = sizeof ( struct hci_rp_read_local_version ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Local version length mismatch " ) ;
2015-04-06 08:52:13 +03:00
kfree_skb ( skb ) ;
return ERR_PTR ( - EIO ) ;
}
return skb ;
}
static struct sk_buff * btbcm_read_verbose_config ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , 0xfc79 , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Read verbose config info failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-04-06 08:52:13 +03:00
return skb ;
}
if ( skb - > len ! = 7 ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Verbose config length mismatch " ) ;
2015-04-06 08:52:13 +03:00
kfree_skb ( skb ) ;
return ERR_PTR ( - EIO ) ;
}
return skb ;
}
2017-06-10 15:33:16 +03:00
static struct sk_buff * btbcm_read_controller_features ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , 0xfc6e , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Read controller features failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2017-06-10 15:33:16 +03:00
return skb ;
}
if ( skb - > len ! = 9 ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Controller features length mismatch " ) ;
2017-06-10 15:33:16 +03:00
kfree_skb ( skb ) ;
return ERR_PTR ( - EIO ) ;
}
return skb ;
}
2015-04-06 08:52:13 +03:00
static struct sk_buff * btbcm_read_usb_product ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
skb = __hci_cmd_sync ( hdev , 0xfc5a , 0 , NULL , HCI_INIT_TIMEOUT ) ;
if ( IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: Read USB product info failed (%ld) " ,
PTR_ERR ( skb ) ) ;
2015-04-06 08:52:13 +03:00
return skb ;
}
if ( skb - > len ! = 5 ) {
2017-10-30 12:42:59 +03:00
bt_dev_err ( hdev , " BCM: USB product length mismatch " ) ;
2015-04-06 08:52:13 +03:00
kfree_skb ( skb ) ;
return ERR_PTR ( - EIO ) ;
}
return skb ;
}
2017-08-17 12:02:40 +03:00
static int btbcm_read_info ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: chip id %u " , skb - > data [ 1 ] ) ;
2017-08-17 12:02:40 +03:00
kfree_skb ( skb ) ;
/* Read Controller Features */
skb = btbcm_read_controller_features ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: features 0x%2.2x " , skb - > data [ 1 ] ) ;
2017-08-17 12:02:40 +03:00
kfree_skb ( skb ) ;
2020-04-17 20:15:28 +03:00
return 0 ;
}
static int btbcm_print_local_name ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
2017-08-17 12:02:40 +03:00
/* Read Local Name */
skb = btbcm_read_local_name ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " %s " , ( char * ) ( skb - > data + 1 ) ) ;
2017-08-17 12:02:40 +03:00
kfree_skb ( skb ) ;
return 0 ;
}
2018-04-20 15:44:03 +03:00
struct bcm_subver_table {
2015-04-06 08:52:13 +03:00
u16 subver ;
const char * name ;
2018-04-20 15:44:03 +03:00
} ;
static const struct bcm_subver_table bcm_uart_subver_table [ ] = {
2021-08-12 19:52:18 +03:00
{ 0x1111 , " BCM4362A2 " } , /* 000.017.017 */
2015-07-27 19:02:25 +03:00
{ 0x4103 , " BCM4330B1 " } , /* 002.001.003 */
2019-11-17 23:39:46 +03:00
{ 0x410d , " BCM4334B0 " } , /* 002.001.013 */
2015-04-06 08:52:19 +03:00
{ 0x410e , " BCM43341B0 " } , /* 002.001.014 */
2019-03-05 16:09:00 +03:00
{ 0x4204 , " BCM2076B1 " } , /* 002.002.004 */
2015-05-28 12:25:02 +03:00
{ 0x4406 , " BCM4324B3 " } , /* 002.004.006 */
2020-04-17 20:15:32 +03:00
{ 0x4606 , " BCM4324B5 " } , /* 002.006.006 */
2018-09-04 20:50:57 +03:00
{ 0x6109 , " BCM4335C0 " } , /* 003.001.009 */
2015-06-17 18:42:46 +03:00
{ 0x610c , " BCM4354 " } , /* 003.001.012 */
2018-01-18 12:21:55 +03:00
{ 0x2122 , " BCM4343A0 " } , /* 001.001.034 */
2017-06-28 22:10:55 +03:00
{ 0x2209 , " BCM43430A1 " } , /* 001.002.009 */
2017-10-06 10:34:18 +03:00
{ 0x6119 , " BCM4345C0 " } , /* 003.001.025 */
2019-08-23 13:31:36 +03:00
{ 0x6606 , " BCM4345C5 " } , /* 003.006.006 */
2017-10-13 18:54:01 +03:00
{ 0x230f , " BCM4356A2 " } , /* 001.003.015 */
2018-12-17 07:04:45 +03:00
{ 0x220e , " BCM20702A1 " } , /* 001.002.014 */
2018-12-19 14:22:46 +03:00
{ 0x4217 , " BCM4329B1 " } , /* 002.002.023 */
2019-05-20 16:41:04 +03:00
{ 0x6106 , " BCM4359C0 " } , /* 003.001.006 */
2019-11-20 14:02:35 +03:00
{ 0x4106 , " BCM4335A0 " } , /* 002.001.006 */
2021-05-10 02:28:37 +03:00
{ 0x410c , " BCM43430B0 " } , /* 002.001.012 */
2015-04-06 08:52:19 +03:00
{ }
} ;
2018-04-20 15:44:04 +03:00
static const struct bcm_subver_table bcm_usb_subver_table [ ] = {
2020-04-17 20:15:32 +03:00
{ 0x2105 , " BCM20703A1 " } , /* 001.001.005 */
2018-04-20 15:44:04 +03:00
{ 0x210b , " BCM43142A0 " } , /* 001.001.011 */
{ 0x2112 , " BCM4314A0 " } , /* 001.001.018 */
{ 0x2118 , " BCM20702A0 " } , /* 001.001.024 */
{ 0x2126 , " BCM4335A0 " } , /* 001.001.038 */
{ 0x220e , " BCM20702A1 " } , /* 001.002.014 */
2020-05-24 20:41:29 +03:00
{ 0x230f , " BCM4356A2 " } , /* 001.003.015 */
2018-04-20 15:44:04 +03:00
{ 0x4106 , " BCM4335B0 " } , /* 002.001.006 */
{ 0x410e , " BCM20702B0 " } , /* 002.001.014 */
{ 0x6109 , " BCM4335C0 " } , /* 003.001.009 */
{ 0x610c , " BCM4354 " } , /* 003.001.012 */
2020-05-24 20:41:29 +03:00
{ 0x6607 , " BCM4350C5 " } , /* 003.006.007 */
2018-04-20 15:44:04 +03:00
{ }
} ;
2020-04-17 20:15:27 +03:00
int btbcm_initialize ( struct hci_dev * hdev , bool * fw_load_done )
2015-05-28 12:25:04 +03:00
{
2018-04-20 15:44:04 +03:00
u16 subver , rev , pid , vid ;
2015-05-28 12:25:04 +03:00
struct sk_buff * skb ;
struct hci_rp_read_local_version * ver ;
2018-04-20 15:44:04 +03:00
const struct bcm_subver_table * bcm_subver_table ;
2020-04-17 20:15:31 +03:00
const char * hw_name = NULL ;
char postfix [ 16 ] = " " ;
int fw_name_count = 0 ;
bcm_fw_name * fw_name ;
2020-04-17 20:15:27 +03:00
const struct firmware * fw ;
2015-05-28 12:25:04 +03:00
int i , err ;
/* Reset */
err = btbcm_reset ( hdev ) ;
if ( err )
return err ;
/* Read Local Version Info */
skb = btbcm_read_local_version ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
ver = ( struct hci_rp_read_local_version * ) skb - > data ;
rev = le16_to_cpu ( ver - > hci_rev ) ;
subver = le16_to_cpu ( ver - > lmp_subver ) ;
kfree_skb ( skb ) ;
2017-08-17 12:02:40 +03:00
/* Read controller information */
2020-04-17 20:15:27 +03:00
if ( ! ( * fw_load_done ) ) {
2018-04-20 15:44:05 +03:00
err = btbcm_read_info ( hdev ) ;
if ( err )
return err ;
}
2020-04-17 20:15:28 +03:00
err = btbcm_print_local_name ( hdev ) ;
if ( err )
return err ;
2015-05-28 12:25:04 +03:00
2018-04-20 15:44:04 +03:00
bcm_subver_table = ( hdev - > bus = = HCI_USB ) ? bcm_usb_subver_table :
bcm_uart_subver_table ;
for ( i = 0 ; bcm_subver_table [ i ] . name ; i + + ) {
if ( subver = = bcm_subver_table [ i ] . subver ) {
hw_name = bcm_subver_table [ i ] . name ;
break ;
2015-05-28 12:25:04 +03:00
}
2018-04-20 15:44:04 +03:00
}
2015-05-28 12:25:04 +03:00
2020-04-17 20:15:30 +03:00
bt_dev_info ( hdev , " %s (%3.3u.%3.3u.%3.3u) build %4.4u " ,
2020-04-17 20:15:31 +03:00
hw_name ? hw_name : " BCM " , ( subver & 0xe000 ) > > 13 ,
2020-04-17 20:15:30 +03:00
( subver & 0x1f00 ) > > 8 , ( subver & 0x00ff ) , rev & 0x0fff ) ;
if ( * fw_load_done )
return 0 ;
2018-04-20 15:44:04 +03:00
if ( hdev - > bus = = HCI_USB ) {
/* Read USB Product Info */
skb = btbcm_read_usb_product ( hdev ) ;
if ( IS_ERR ( skb ) )
return PTR_ERR ( skb ) ;
vid = get_unaligned_le16 ( skb - > data + 1 ) ;
pid = get_unaligned_le16 ( skb - > data + 3 ) ;
kfree_skb ( skb ) ;
2020-04-17 20:15:31 +03:00
snprintf ( postfix , sizeof ( postfix ) , " -%4.4x-%4.4x " , vid , pid ) ;
2015-05-28 12:25:04 +03:00
}
2020-04-17 20:15:31 +03:00
fw_name = kmalloc ( BCM_FW_NAME_COUNT_MAX * BCM_FW_NAME_LEN , GFP_KERNEL ) ;
if ( ! fw_name )
return - ENOMEM ;
if ( hw_name ) {
snprintf ( fw_name [ fw_name_count ] , BCM_FW_NAME_LEN ,
" brcm/%s%s.hcd " , hw_name , postfix ) ;
fw_name_count + + ;
2020-04-17 20:15:27 +03:00
}
2020-04-17 20:15:31 +03:00
snprintf ( fw_name [ fw_name_count ] , BCM_FW_NAME_LEN ,
" brcm/BCM%s.hcd " , postfix ) ;
fw_name_count + + ;
for ( i = 0 ; i < fw_name_count ; i + + ) {
err = firmware_request_nowarn ( & fw , fw_name [ i ] , & hdev - > dev ) ;
if ( err = = 0 ) {
bt_dev_info ( hdev , " %s '%s' Patch " ,
hw_name ? hw_name : " BCM " , fw_name [ i ] ) ;
* fw_load_done = true ;
break ;
}
}
if ( * fw_load_done ) {
err = btbcm_patchram ( hdev , fw ) ;
if ( err )
bt_dev_info ( hdev , " BCM: Patch failed (%d) " , err ) ;
release_firmware ( fw ) ;
} else {
bt_dev_err ( hdev , " BCM: firmware Patch file not found, tried: " ) ;
for ( i = 0 ; i < fw_name_count ; i + + )
bt_dev_err ( hdev , " BCM: '%s' " , fw_name [ i ] ) ;
}
2020-04-17 20:15:27 +03:00
2020-04-17 20:15:31 +03:00
kfree ( fw_name ) ;
2015-05-28 12:25:04 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_initialize ) ;
2020-04-17 20:15:29 +03:00
int btbcm_finalize ( struct hci_dev * hdev , bool * fw_load_done )
2015-05-28 12:25:04 +03:00
{
int err ;
2020-04-17 20:15:29 +03:00
/* Re-initialize if necessary */
if ( * fw_load_done ) {
err = btbcm_initialize ( hdev , fw_load_done ) ;
if ( err )
return err ;
}
2015-05-28 12:25:04 +03:00
btbcm_check_bdaddr ( hdev ) ;
set_bit ( HCI_QUIRK_STRICT_DUPLICATE_FILTER , & hdev - > quirks ) ;
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_finalize ) ;
2015-04-06 08:52:13 +03:00
int btbcm_setup_patchram ( struct hci_dev * hdev )
{
2020-04-17 20:15:27 +03:00
bool fw_load_done = false ;
2018-04-20 15:44:06 +03:00
int err ;
2015-04-06 08:52:13 +03:00
2018-04-20 15:44:06 +03:00
/* Initialize */
2020-04-17 20:15:27 +03:00
err = btbcm_initialize ( hdev , & fw_load_done ) ;
2017-08-17 12:02:40 +03:00
if ( err )
return err ;
2015-10-05 13:43:57 +03:00
2020-04-17 20:15:27 +03:00
/* Re-initialize after loading Patch */
2020-04-17 20:15:29 +03:00
return btbcm_finalize ( hdev , & fw_load_done ) ;
2015-04-06 08:52:13 +03:00
}
EXPORT_SYMBOL_GPL ( btbcm_setup_patchram ) ;
int btbcm_setup_apple ( struct hci_dev * hdev )
{
struct sk_buff * skb ;
2015-10-03 13:01:08 +03:00
int err ;
/* Reset */
err = btbcm_reset ( hdev ) ;
if ( err )
return err ;
2015-04-06 08:52:13 +03:00
/* Read Verbose Config Version Info */
skb = btbcm_read_verbose_config ( hdev ) ;
2015-07-14 23:25:30 +03:00
if ( ! IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: chip id %u build %4.4u " ,
skb - > data [ 1 ] , get_unaligned_le16 ( skb - > data + 5 ) ) ;
2015-07-14 23:25:30 +03:00
kfree_skb ( skb ) ;
}
2015-04-06 08:52:13 +03:00
2015-10-18 23:48:28 +03:00
/* Read USB Product Info */
skb = btbcm_read_usb_product ( hdev ) ;
if ( ! IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: product %4.4x:%4.4x " ,
get_unaligned_le16 ( skb - > data + 1 ) ,
get_unaligned_le16 ( skb - > data + 3 ) ) ;
2015-10-18 23:48:28 +03:00
kfree_skb ( skb ) ;
}
2017-06-10 15:33:16 +03:00
/* Read Controller Features */
skb = btbcm_read_controller_features ( hdev ) ;
if ( ! IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " BCM: features 0x%2.2x " , skb - > data [ 1 ] ) ;
2017-06-10 15:33:16 +03:00
kfree_skb ( skb ) ;
}
2015-10-05 13:43:57 +03:00
/* Read Local Name */
skb = btbcm_read_local_name ( hdev ) ;
if ( ! IS_ERR ( skb ) ) {
2017-10-30 12:42:59 +03:00
bt_dev_info ( hdev , " %s " , ( char * ) ( skb - > data + 1 ) ) ;
2015-10-05 13:43:57 +03:00
kfree_skb ( skb ) ;
}
2015-04-06 08:52:15 +03:00
set_bit ( HCI_QUIRK_STRICT_DUPLICATE_FILTER , & hdev - > quirks ) ;
2015-04-06 08:52:13 +03:00
return 0 ;
}
EXPORT_SYMBOL_GPL ( btbcm_setup_apple ) ;
2015-04-06 08:52:10 +03:00
MODULE_AUTHOR ( " Marcel Holtmann <marcel@holtmann.org> " ) ;
MODULE_DESCRIPTION ( " Bluetooth support for Broadcom devices ver " VERSION ) ;
MODULE_VERSION ( VERSION ) ;
MODULE_LICENSE ( " GPL " ) ;