diff options
29 files changed, 3236 insertions, 574 deletions
diff --git a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt index 0ea18a53cc29..824c0e23c544 100644 --- a/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt +++ b/Documentation/devicetree/bindings/net/qualcomm-bluetooth.txt @@ -10,12 +10,25 @@ device the slave device is attached to. Required properties: - compatible: should contain one of the following: * "qcom,qca6174-bt" + * "qcom,wcn3990-bt" + +Optional properties for compatible string qcom,qca6174-bt: -Optional properties: - enable-gpios: gpio specifier used to enable chip - clocks: clock provided to the controller (SUSCLK_32KHZ) -Example: +Required properties for compatible string qcom,wcn3990-bt: + + - vddio-supply: VDD_IO supply regulator handle. + - vddxo-supply: VDD_XO supply regulator handle. + - vddrf-supply: VDD_RF supply regulator handle. + - vddch0-supply: VDD_CH0 supply regulator handle. + +Optional properties for compatible string qcom,wcn3990-bt: + + - max-speed: see Documentation/devicetree/bindings/serial/slave-device.txt + +Examples: serial@7570000 { label = "BT-UART"; @@ -28,3 +41,15 @@ serial@7570000 { clocks = <&divclk4>; }; }; + +serial@898000 { + bluetooth { + compatible = "qcom,wcn3990-bt"; + + vddio-supply = <&vreg_s4a_1p8>; + vddxo-supply = <&vreg_l7a_1p8>; + vddrf-supply = <&vreg_l17a_1p3>; + vddch0-supply = <&vreg_l25a_3p3>; + max-speed = <3200000>; + }; +}; diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index f3c643a0473c..5f953ca8ac5b 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -159,6 +159,7 @@ config BT_HCIUART_LL config BT_HCIUART_3WIRE bool "Three-wire UART (H5) protocol support" depends on BT_HCIUART + depends on BT_HCIUART_SERDEV help The HCI Three-wire UART Transport Layer makes it possible to user the Bluetooth HCI over a serial port interface. The HCI diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index ab090a313a5f..0588639b899a 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -490,7 +490,7 @@ static int bfusb_send_frame(struct hci_dev *hdev, struct sk_buff *skb) count = skb->len; /* Max HCI frame size seems to be 1511 + 1 */ - nskb = bt_skb_alloc(count + 32, GFP_ATOMIC); + nskb = bt_skb_alloc(count + 32, GFP_KERNEL); if (!nskb) { BT_ERR("Can't allocate memory for new packet"); return -ENOMEM; diff --git a/drivers/bluetooth/bluecard_cs.c b/drivers/bluetooth/bluecard_cs.c index 82437a69f99c..cc6e56223656 100644 --- a/drivers/bluetooth/bluecard_cs.c +++ b/drivers/bluetooth/bluecard_cs.c @@ -565,7 +565,7 @@ static int bluecard_hci_set_baud_rate(struct hci_dev *hdev, int baud) /* Ericsson baud rate command */ unsigned char cmd[] = { HCI_COMMAND_PKT, 0x09, 0xfc, 0x01, 0x03 }; - skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC); + skb = bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_KERNEL); if (!skb) { BT_ERR("Can't allocate mem for new packet"); return -1; diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index c6f7cc57db14..d1c2adf08576 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -289,7 +289,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb) skb->dev = (void *) hdev; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, GFP_KERNEL); if (!urb) return -ENOMEM; @@ -298,7 +298,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb) switch (hci_skb_pkt_type(skb)) { case HCI_COMMAND_PKT: - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); + dr = kmalloc(sizeof(*dr), GFP_KERNEL); if (!dr) { usb_free_urb(urb); return -ENOMEM; @@ -343,7 +343,7 @@ static int bpa10x_send_frame(struct hci_dev *hdev, struct sk_buff *skb) usb_anchor_urb(urb, &data->tx_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, GFP_KERNEL); if (err < 0) { bt_dev_err(hdev, "urb %p submission failed", urb); kfree(urb->setup_packet); diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c index 888bac49a87b..fb3d03928460 100644 --- a/drivers/bluetooth/btmrvl_sdio.c +++ b/drivers/bluetooth/btmrvl_sdio.c @@ -718,7 +718,7 @@ static int btmrvl_sdio_card_to_host(struct btmrvl_private *priv) } /* Allocate buffer */ - skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_ATOMIC); + skb = bt_skb_alloc(num_blocks * blksz + BTSDIO_DMA_ALIGN, GFP_KERNEL); if (!skb) { BT_ERR("No free skb"); ret = -ENOMEM; diff --git a/drivers/bluetooth/btqca.c b/drivers/bluetooth/btqca.c index 8219816c54a0..488f5e7521dd 100644 --- a/drivers/bluetooth/btqca.c +++ b/drivers/bluetooth/btqca.c @@ -27,7 +27,7 @@ #define VERSION "0.1" -static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) +int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) { struct sk_buff *skb; struct edl_event_hdr *edl; @@ -35,36 +35,35 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) char cmd; int err = 0; - BT_DBG("%s: ROME Patch Version Request", hdev->name); + bt_dev_dbg(hdev, "QCA Version Request"); cmd = EDL_PATCH_VER_REQ_CMD; skb = __hci_cmd_sync_ev(hdev, EDL_PATCH_CMD_OPCODE, EDL_PATCH_CMD_LEN, &cmd, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Failed to read version of ROME (%d)", hdev->name, - err); + bt_dev_err(hdev, "Reading QCA version information failed (%d)", + err); return err; } if (skb->len != sizeof(*edl) + sizeof(*ver)) { - BT_ERR("%s: Version size mismatch len %d", hdev->name, - skb->len); + bt_dev_err(hdev, "QCA Version size mismatch len %d", skb->len); err = -EILSEQ; goto out; } edl = (struct edl_event_hdr *)(skb->data); if (!edl) { - BT_ERR("%s: TLV with no header", hdev->name); + bt_dev_err(hdev, "QCA TLV with no header"); err = -EILSEQ; goto out; } if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != EDL_APP_VER_RES_EVT) { - BT_ERR("%s: Wrong packet received %d %d", hdev->name, - edl->cresp, edl->rtype); + bt_dev_err(hdev, "QCA Wrong packet received %d %d", edl->cresp, + edl->rtype); err = -EIO; goto out; } @@ -76,30 +75,35 @@ static int rome_patch_ver_req(struct hci_dev *hdev, u32 *rome_version) BT_DBG("%s: ROM :0x%08x", hdev->name, le16_to_cpu(ver->rome_ver)); BT_DBG("%s: SOC :0x%08x", hdev->name, le32_to_cpu(ver->soc_id)); - /* ROME chipset version can be decided by patch and SoC + /* QCA chipset version can be decided by patch and SoC * version, combination with upper 2 bytes from SoC * and lower 2 bytes from patch will be used. */ - *rome_version = (le32_to_cpu(ver->soc_id) << 16) | + *soc_version = (le32_to_cpu(ver->soc_id) << 16) | (le16_to_cpu(ver->rome_ver) & 0x0000ffff); + if (*soc_version == 0) + err = -EILSEQ; out: kfree_skb(skb); + if (err) + bt_dev_err(hdev, "QCA Failed to get version (%d)", err); return err; } +EXPORT_SYMBOL_GPL(qca_read_soc_version); -static int rome_reset(struct hci_dev *hdev) +static int qca_send_reset(struct hci_dev *hdev) { struct sk_buff *skb; int err; - BT_DBG("%s: ROME HCI_RESET", hdev->name); + bt_dev_dbg(hdev, "QCA HCI_RESET"); skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Reset failed (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Reset failed (%d)", err); return err; } @@ -108,7 +112,7 @@ static int rome_reset(struct hci_dev *hdev) return 0; } -static void rome_tlv_check_data(struct rome_config *config, +static void qca_tlv_check_data(struct rome_config *config, const struct firmware *fw) { const u8 *data; @@ -207,7 +211,7 @@ static void rome_tlv_check_data(struct rome_config *config, } } -static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, +static int qca_tlv_send_segment(struct hci_dev *hdev, int seg_size, const u8 *data, enum rome_tlv_dnld_mode mode) { struct sk_buff *skb; @@ -228,19 +232,19 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Failed to send TLV segment (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to send TLV segment (%d)", err); return err; } if (skb->len != sizeof(*edl) + sizeof(*tlv_resp)) { - BT_ERR("%s: TLV response size mismatch", hdev->name); + bt_dev_err(hdev, "QCA TLV response size mismatch"); err = -EILSEQ; goto out; } edl = (struct edl_event_hdr *)(skb->data); if (!edl) { - BT_ERR("%s: TLV with no header", hdev->name); + bt_dev_err(hdev, "TLV with no header"); err = -EILSEQ; goto out; } @@ -249,8 +253,8 @@ static int rome_tlv_send_segment(struct hci_dev *hdev, int seg_size, if (edl->cresp != EDL_CMD_REQ_RES_EVT || edl->rtype != EDL_TVL_DNLD_RES_EVT || tlv_resp->result != 0x00) { - BT_ERR("%s: TLV with error stat 0x%x rtype 0x%x (0x%x)", - hdev->name, edl->cresp, edl->rtype, tlv_resp->result); + bt_dev_err(hdev, "QCA TLV with error stat 0x%x rtype 0x%x (0x%x)", + edl->cresp, edl->rtype, tlv_resp->result); err = -EIO; } @@ -260,23 +264,23 @@ out: return err; } -static int rome_download_firmware(struct hci_dev *hdev, +static int qca_download_firmware(struct hci_dev *hdev, struct rome_config *config) { const struct firmware *fw; const u8 *segment; int ret, remain, i = 0; - bt_dev_info(hdev, "ROME Downloading %s", config->fwname); + bt_dev_info(hdev, "QCA Downloading %s", config->fwname); ret = request_firmware(&fw, config->fwname, &hdev->dev); if (ret) { - BT_ERR("%s: Failed to request file: %s (%d)", hdev->name, - config->fwname, ret); + bt_dev_err(hdev, "QCA Failed to request file: %s (%d)", + config->fwname, ret); return ret; } - rome_tlv_check_data(config, fw); + qca_tlv_check_data(config, fw); segment = fw->data; remain = fw->size; @@ -290,7 +294,7 @@ static int rome_download_firmware(struct hci_dev *hdev, if (!remain || segsize < MAX_SIZE_PER_TLV_SEGMENT) config->dnld_mode = ROME_SKIP_EVT_NONE; - ret = rome_tlv_send_segment(hdev, segsize, segment, + ret = qca_tlv_send_segment(hdev, segsize, segment, config->dnld_mode); if (ret) break; @@ -317,8 +321,7 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) HCI_VENDOR_PKT, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { err = PTR_ERR(skb); - BT_ERR("%s: Change address command failed (%d)", - hdev->name, err); + bt_dev_err(hdev, "QCA Change address command failed (%d)", err); return err; } @@ -328,57 +331,65 @@ int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr) } EXPORT_SYMBOL_GPL(qca_set_bdaddr_rome); -int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate) +int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + enum qca_btsoc_type soc_type, u32 soc_ver) { - u32 rome_ver = 0; struct rome_config config; int err; + u8 rom_ver; - BT_DBG("%s: ROME setup on UART", hdev->name); + bt_dev_dbg(hdev, "QCA setup on UART"); config.user_baud_rate = baudrate; - /* Get ROME version information */ - err = rome_patch_ver_req(hdev, &rome_ver); - if (err < 0 || rome_ver == 0) { - BT_ERR("%s: Failed to get version 0x%x", hdev->name, err); - return err; - } - - bt_dev_info(hdev, "ROME controller version 0x%08x", rome_ver); - /* Download rampatch file */ config.type = TLV_TYPE_PATCH; - snprintf(config.fwname, sizeof(config.fwname), "qca/rampatch_%08x.bin", - rome_ver); - err = rome_download_firmware(hdev, &config); + if (soc_type == QCA_WCN3990) { + /* Firmware files to download are based on ROM version. + * ROM version is derived from last two bytes of soc_ver. + */ + rom_ver = ((soc_ver & 0x00000f00) >> 0x04) | + (soc_ver & 0x0000000f); + snprintf(config.fwname, sizeof(config.fwname), + "qca/crbtfw%02x.tlv", rom_ver); + } else { + snprintf(config.fwname, sizeof(config.fwname), + "qca/rampatch_%08x.bin", soc_ver); + } + + err = qca_download_firmware(hdev, &config); if (err < 0) { - BT_ERR("%s: Failed to download patch (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to download patch (%d)", err); return err; } /* Download NVM configuration */ config.type = TLV_TYPE_NVM; - snprintf(config.fwname, sizeof(config.fwname), "qca/nvm_%08x.bin", - rome_ver); - err = rome_download_firmware(hdev, &config); + if (soc_type == QCA_WCN3990) + snprintf(config.fwname, sizeof(config.fwname), + "qca/crnv%02x.bin", rom_ver); + else + snprintf(config.fwname, sizeof(config.fwname), + "qca/nvm_%08x.bin", soc_ver); + + err = qca_download_firmware(hdev, &config); if (err < 0) { - BT_ERR("%s: Failed to download NVM (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to download NVM (%d)", err); return err; } /* Perform HCI reset */ - err = rome_reset(hdev); + err = qca_send_reset(hdev); if (err < 0) { - BT_ERR("%s: Failed to run HCI_RESET (%d)", hdev->name, err); + bt_dev_err(hdev, "QCA Failed to run HCI_RESET (%d)", err); return err; } - bt_dev_info(hdev, "ROME setup on UART is completed"); + bt_dev_info(hdev, "QCA setup on UART is completed"); return 0; } -EXPORT_SYMBOL_GPL(qca_uart_setup_rome); +EXPORT_SYMBOL_GPL(qca_uart_setup); MODULE_AUTHOR("Ben Young Tae Kim <ytkim@qca.qualcomm.com>"); MODULE_DESCRIPTION("Bluetooth support for Qualcomm Atheros family ver " VERSION); diff --git a/drivers/bluetooth/btqca.h b/drivers/bluetooth/btqca.h index 13d77fd873b6..0c01f375fe83 100644 --- a/drivers/bluetooth/btqca.h +++ b/drivers/bluetooth/btqca.h @@ -37,6 +37,9 @@ #define EDL_TAG_ID_HCI (17) #define EDL_TAG_ID_DEEP_SLEEP (27) +#define QCA_WCN3990_POWERON_PULSE 0xFC +#define QCA_WCN3990_POWEROFF_PULSE 0xC0 + enum qca_bardrate { QCA_BAUDRATE_115200 = 0, QCA_BAUDRATE_57600, @@ -124,10 +127,19 @@ struct tlv_type_hdr { __u8 data[0]; } __packed; +enum qca_btsoc_type { + QCA_INVALID = -1, + QCA_AR3002, + QCA_ROME, + QCA_WCN3990 +}; + #if IS_ENABLED(CONFIG_BT_QCA) int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdaddr); -int qca_uart_setup_rome(struct hci_dev *hdev, uint8_t baudrate); +int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + enum qca_btsoc_type soc_type, u32 soc_ver); +int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version); #else @@ -136,7 +148,13 @@ static inline int qca_set_bdaddr_rome(struct hci_dev *hdev, const bdaddr_t *bdad return -EOPNOTSUPP; } -static inline int qca_uart_setup_rome(struct hci_dev *hdev, int speed) +static inline int qca_uart_setup(struct hci_dev *hdev, uint8_t baudrate, + enum qca_btsoc_type soc_type, u32 soc_ver) +{ + return -EOPNOTSUPP; +} + +static inline int qca_read_soc_version(struct hci_dev *hdev, u32 *soc_version) { return -EOPNOTSUPP; } diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c index 437f080deaab..7f9ea8e4c1b2 100644 --- a/drivers/bluetooth/btrtl.c +++ b/drivers/bluetooth/btrtl.c @@ -34,9 +34,12 @@ #define RTL_ROM_LMP_8821A 0x8821 #define RTL_ROM_LMP_8761A 0x8761 #define RTL_ROM_LMP_8822B 0x8822 +#define RTL_CONFIG_MAGIC 0x8723ab55 #define IC_MATCH_FL_LMPSUBV (1 << 0) #define IC_MATCH_FL_HCIREV (1 << 1) +#define IC_MATCH_FL_HCIVER (1 << 2) +#define IC_MATCH_FL_HCIBUS (1 << 3) #define IC_INFO(lmps, hcir) \ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \ .lmp_subver = (lmps), \ @@ -46,49 +49,130 @@ struct id_table { __u16 match_flags; __u16 lmp_subver; __u16 hci_rev; + __u8 hci_ver; + __u8 hci_bus; bool config_needed; + bool has_rom_version; char *fw_name; char *cfg_name; }; +struct btrtl_device_info { + const struct id_table *ic_info; + u8 rom_version; + u8 *fw_data; + int fw_len; + u8 *cfg_data; + int cfg_len; +}; + static const struct id_table ic_id_table[] = { + { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8723A, 0x0, + .config_needed = false, + .has_rom_version = false, + .fw_name = "rtl_bt/rtl8723a_fw.bin", + .cfg_name = NULL }, + + { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_3499, 0x0, + .config_needed = false, + .has_rom_version = false, + .fw_name = "rtl_bt/rtl8723a_fw.bin", + .cfg_name = NULL }, + + /* 8723BS */ + { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | + IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, + .lmp_subver = RTL_ROM_LMP_8723B, + .hci_rev = 0xb, + .hci_ver = 6, + .hci_bus = HCI_UART, + .config_needed = true, + .has_rom_version = true, + .fw_name = "rtl_bt/rtl8723bs_fw.bin", + .cfg_name = "rtl_bt/rtl8723bs_config" }, + /* 8723B */ { IC_INFO(RTL_ROM_LMP_8723B, 0xb), .config_needed = false, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8723b_fw.bin", - .cfg_name = "rtl_bt/rtl8723b_config.bin" }, + .cfg_name = "rtl_bt/rtl8723b_config" }, /* 8723D */ { IC_INFO(RTL_ROM_LMP_8723B, 0xd), .config_needed = true, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8723d_fw.bin", - .cfg_name = "rtl_bt/rtl8723d_config.bin" }, + .cfg_name = "rtl_bt/rtl8723d_config" }, + + /* 8723DS */ + { .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV | + IC_MATCH_FL_HCIVER | IC_MATCH_FL_HCIBUS, + .lmp_subver = RTL_ROM_LMP_8723B, + .hci_rev = 0xd, + .hci_ver = 8, + .hci_bus = HCI_UART, + .config_needed = true, + .has_rom_version = true, + .fw_name = "rtl_bt/rtl8723ds_fw.bin", + .cfg_name = "rtl_bt/rtl8723ds_config" }, /* 8821A */ { IC_INFO(RTL_ROM_LMP_8821A, 0xa), .config_needed = false, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8821a_fw.bin", - .cfg_name = "rtl_bt/rtl8821a_config.bin" }, + .cfg_name = "rtl_bt/rtl8821a_config" }, /* 8821C */ { IC_INFO(RTL_ROM_LMP_8821A, 0xc), .config_needed = false, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8821c_fw.bin", - .cfg_name = "rtl_bt/rtl8821c_config.bin" }, + .cfg_name = "rtl_bt/rtl8821c_config" }, /* 8761A */ { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0, .config_needed = false, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8761a_fw.bin", - .cfg_name = "rtl_bt/rtl8761a_config.bin" }, + .cfg_name = "rtl_bt/rtl8761a_config" }, /* 8822B */ { IC_INFO(RTL_ROM_LMP_8822B, 0xb), .config_needed = true, + .has_rom_version = true, .fw_name = "rtl_bt/rtl8822b_fw.bin", - .cfg_name = "rtl_bt/rtl8822b_config.bin" }, + .cfg_name = "rtl_bt/rtl8822b_config" }, }; +static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev, + u8 hci_ver, u8 hci_bus) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) { + if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) && + (ic_id_table[i].lmp_subver != lmp_subver)) + continue; + if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) && + (ic_id_table[i].hci_rev != hci_rev)) + continue; + if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIVER) && + (ic_id_table[i].hci_ver != hci_ver)) + continue; + if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIBUS) && + (ic_id_table[i].hci_bus != hci_bus)) + continue; + + break; + } + if (i >= ARRAY_SIZE(ic_id_table)) + return NULL; + + return &ic_id_table[i]; +} + static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) { struct rtl_rom_version_evt *rom_version; @@ -97,20 +181,20 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) /* Read RTL ROM version command */ skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - BT_ERR("%s: Read ROM version failed (%ld)", - hdev->name, PTR_ERR(skb)); + rtl_dev_err(hdev, "Read ROM version failed (%ld)\n", + PTR_ERR(skb)); return PTR_ERR(skb); } if (skb->len != sizeof(*rom_version)) { - BT_ERR("%s: RTL version event length mismatch", hdev->name); + rtl_dev_err(hdev, "RTL version event length mismatch\n"); kfree_skb(skb); return -EIO; } rom_version = (struct rtl_rom_version_evt *)skb->data; - bt_dev_info(hdev, "rom_version status=%x version=%x", - rom_version->status, rom_version->version); + rtl_dev_info(hdev, "rom_version status=%x version=%x\n", + rom_version->status, rom_version->version); *version = rom_version->version; @@ -118,16 +202,16 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) return 0; } -static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, - const struct firmware *fw, +static int rtlbt_parse_firmware(struct hci_dev *hdev, + struct btrtl_device_info *btrtl_dev, unsigned char **_buf) { const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; struct rtl_epatch_header *epatch_info; unsigned char *buf; - int i, ret, len; + int i, len; size_t min_size; - u8 opcode, length, data, rom_version = 0; + u8 opcode, length, data; int project_id = -1; const unsigned char *fwptr, *chip_id_base; const unsigned char *patch_length_base, *patch_offset_base; @@ -146,17 +230,13 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ }; - ret = rtl_read_rom_version(hdev, &rom_version); - if (ret) - return ret; - min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; - if (fw->size < min_size) + if (btrtl_dev->fw_len < min_size) return -EINVAL; - fwptr = fw->data + fw->size - sizeof(extension_sig); + fwptr = btrtl_dev->fw_data + btrtl_dev->fw_len - sizeof(extension_sig); if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { - BT_ERR("%s: extension section signature mismatch", hdev->name); + rtl_dev_err(hdev, "extension section signature mismatch\n"); return -EINVAL; } @@ -166,7 +246,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, * Once we have that, we double-check that that project_id is suitable * for the hardware we are working with. */ - while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { + while (fwptr >= btrtl_dev->fw_data + (sizeof(*epatch_info) + 3)) { opcode = *--fwptr; length = *--fwptr; data = *--fwptr; @@ -177,8 +257,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, break; if (length == 0) { - BT_ERR("%s: found instruction with length 0", - hdev->name); + rtl_dev_err(hdev, "found instruction with length 0\n"); return -EINVAL; } @@ -191,7 +270,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, } if (project_id < 0) { - BT_ERR("%s: failed to find version instruction", hdev->name); + rtl_dev_err(hdev, "failed to find version instruction\n"); return -EINVAL; } @@ -202,19 +281,21 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, } if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) { - BT_ERR("%s: unknown project id %d", hdev->name, project_id); + rtl_dev_err(hdev, "unknown project id %d\n", project_id); return -EINVAL; } - if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) { - BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, - project_id_to_lmp_subver[i].lmp_subver, lmp_subver); + if (btrtl_dev->ic_info->lmp_subver != + project_id_to_lmp_subver[i].lmp_subver) { + rtl_dev_err(hdev, "firmware is for %x but this is a %x\n", + project_id_to_lmp_subver[i].lmp_subver, + btrtl_dev->ic_info->lmp_subver); return -EINVAL; } - epatch_info = (struct rtl_epatch_header *)fw->data; + epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data; if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { - BT_ERR("%s: bad EPATCH signature", hdev->name); + rtl_dev_err(hdev, "bad EPATCH signature\n"); return -EINVAL; } @@ -229,16 +310,16 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, * Find the right patch for this chip. */ min_size += 8 * num_patches; - if (fw->size < min_size) + if (btrtl_dev->fw_len < min_size) return -EINVAL; - chip_id_base = fw->data + sizeof(struct rtl_epatch_header); + chip_id_base = btrtl_dev->fw_data + sizeof(struct rtl_epatch_header); patch_length_base = chip_id_base + (sizeof(u16) * num_patches); patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); for (i = 0; i < num_patches; i++) { u16 chip_id = get_unaligned_le16(chip_id_base + (i * sizeof(u16))); - if (chip_id == rom_version + 1) { + if (chip_id == btrtl_dev->rom_version + 1) { patch_length = get_unaligned_le16(patch_length_base + (i * sizeof(u16))); patch_offset = get_unaligned_le32(patch_offset_base + @@ -248,21 +329,22 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, } if (!patch_offset) { - BT_ERR("%s: didn't find patch for chip id %d", - hdev->name, rom_version); + rtl_dev_err(hdev, "didn't find patch for chip id %d", + btrtl_dev->rom_version); return -EINVAL; } BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); min_size = patch_offset + patch_length; - if (fw->size < min_size) + if (btrtl_dev->fw_len < min_size) return -EINVAL; /* Copy the firmware into a new buffer and write the version at * the end. */ len = patch_length; - buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); + buf = kmemdup(btrtl_dev->fw_data + patch_offset, patch_length, + GFP_KERNEL); if (!buf) return -ENOMEM; @@ -301,15 +383,14 @@ static int rtl_download_firmware(struct hci_dev *hdev, skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { - BT_ERR("%s: download fw command failed (%ld)", - hdev->name, PTR_ERR(skb)); + rtl_dev_err(hdev, "download fw command failed (%ld)\n", + PTR_ERR(skb)); ret = -PTR_ERR(skb); goto out; } if (skb->len != sizeof(struct rtl_download_response)) { - BT_ERR("%s: download fw event length mismatch", - hdev->name); + rtl_dev_err(hdev, "download fw event length mismatch\n"); kfree_skb(skb); ret = -EIO; goto out; @@ -324,12 +405,12 @@ out: return ret; } -static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) +static int rtl_load_file(struct hci_dev *hdev, const char *name, u8 **buff) { const struct firmware *fw; int ret; - bt_dev_info(hdev, "rtl: loading %s", name); + rtl_dev_info(hdev, "rtl: loading %s\n", name); ret = request_firmware(&fw, name, &hdev->dev); if (ret < 0) return ret; @@ -343,96 +424,37 @@ static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) return ret; } -static int btrtl_setup_rtl8723a(struct hci_dev *hdev) +static int btrtl_setup_rtl8723a(struct hci_dev *hdev, + struct btrtl_device_info *btrtl_dev) { - const struct firmware *fw; - int ret; - - bt_dev_info(hdev, "rtl: loading rtl_bt/rtl8723a_fw.bin"); - ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev); - if (ret < 0) { - BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); - return ret; - } - - if (fw->size < 8) { - ret = -EINVAL; - goto out; - } + if (btrtl_dev->fw_len < 8) + return -EINVAL; /* Check that the firmware doesn't have the epatch signature * (which is only for RTL8723B and newer). */ - if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { - BT_ERR("%s: unexpected EPATCH signature!", hdev->name); - ret = -EINVAL; - goto out; + if (!memcmp(btrtl_dev->fw_data, RTL_EPATCH_SIGNATURE, 8)) { + rtl_dev_err(hdev, "unexpected EPATCH signature!\n"); + return -EINVAL; } - ret = rtl_download_firmware(hdev, fw->data, fw->size); - -out: - release_firmware(fw); - return ret; + return rtl_download_firmware(hdev, btrtl_dev->fw_data, + btrtl_dev->fw_len); } -static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev, - u16 lmp_subver) +static int btrtl_setup_rtl8723b(struct hci_dev |