static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) { struct rtl_rom_version_evt *rom_version; struct sk_buff *skb; /* 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)); return PTR_ERR(skb); } if (skb->len != sizeof(*rom_version)) { BT_ERR("%s: RTL version event length mismatch", hdev->name); 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); *version = rom_version->version; kfree_skb(skb); return 0; }
static int btrtl_setup_rtl8723a(struct hci_dev *hdev) { 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; } /* 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; } ret = rtl_download_firmware(hdev, fw->data, fw->size); out: release_firmware(fw); return ret; }
int btrtl_setup_realtek(struct hci_dev *hdev) { struct sk_buff *skb; struct hci_rp_read_local_version *resp; u16 lmp_subver; skb = btrtl_read_local_version(hdev); if (IS_ERR(skb)) return -PTR_ERR(skb); resp = (struct hci_rp_read_local_version *)skb->data; bt_dev_info(hdev, "rtl: examining hci_ver=%02x hci_rev=%04x " "lmp_ver=%02x lmp_subver=%04x", resp->hci_ver, resp->hci_rev, resp->lmp_ver, resp->lmp_subver); lmp_subver = le16_to_cpu(resp->lmp_subver); kfree_skb(skb); /* Match a set of subver values that correspond to stock firmware, * which is not compatible with standard btusb. * If matched, upload an alternative firmware that does conform to * standard btusb. Once that firmware is uploaded, the subver changes * to a different value. */ switch (lmp_subver) { case RTL_ROM_LMP_8723A: case RTL_ROM_LMP_3499: return btrtl_setup_rtl8723a(hdev); case RTL_ROM_LMP_8723B: return btrtl_setup_rtl8723b(hdev, lmp_subver, "rtl_bt/rtl8723b_fw.bin"); case RTL_ROM_LMP_8821A: return btrtl_setup_rtl8723b(hdev, lmp_subver, "rtl_bt/rtl8821a_fw.bin"); case RTL_ROM_LMP_8761A: return btrtl_setup_rtl8723b(hdev, lmp_subver, "rtl_bt/rtl8761a_fw.bin"); case RTL_ROM_LMP_8822B: return btrtl_setup_rtl8723b(hdev, lmp_subver, "rtl_bt/rtl8822b_fw.bin"); default: bt_dev_info(hdev, "rtl: assuming no firmware upload needed"); return 0; } }
int btintel_load_ddc_config(struct hci_dev *hdev, const char *ddc_name) { const struct firmware *fw; struct sk_buff *skb; const u8 *fw_ptr; int err; err = request_firmware(&fw, ddc_name, &hdev->dev); if (err < 0) { bt_dev_err(hdev, "Failed to load Intel DDC file %s (%d)", ddc_name, err); return err; } bt_dev_info(hdev, "Found Intel DDC parameters: %s", ddc_name); fw_ptr = fw->data; /* DDC file contains one or more DDC structure which has * Length (1 byte), DDC ID (2 bytes), and DDC value (Length - 2). */ while (fw->size > fw_ptr - fw->data) { u8 cmd_plen = fw_ptr[0] + sizeof(u8); skb = __hci_cmd_sync(hdev, 0xfc8b, cmd_plen, fw_ptr, HCI_INIT_TIMEOUT); if (IS_ERR(skb)) { bt_dev_err(hdev, "Failed to send Intel_Write_DDC (%ld)", PTR_ERR(skb)); release_firmware(fw); return PTR_ERR(skb); } fw_ptr += cmd_plen; kfree_skb(skb); } release_firmware(fw); bt_dev_info(hdev, "Applying Intel DDC parameters completed"); return 0; }
struct regmap *btintel_regmap_init(struct hci_dev *hdev, u16 opcode_read, u16 opcode_write) { struct regmap_ibt_context *ctx; bt_dev_info(hdev, "regmap: Init R%x-W%x region", opcode_read, opcode_write); ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); ctx->op_read = opcode_read; ctx->op_write = opcode_write; ctx->hdev = hdev; return regmap_init(&hdev->dev, ®map_ibt, ctx, ®map_ibt_cfg); }
static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) { const struct firmware *fw; int ret; bt_dev_info(hdev, "rtl: loading %s", name); ret = request_firmware(&fw, name, &hdev->dev); if (ret < 0) return ret; ret = fw->size; *buff = kmemdup(fw->data, ret, GFP_KERNEL); if (!*buff) ret = -ENOMEM; release_firmware(fw); return ret; }
static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver, const char *fw_name) { unsigned char *fw_data = NULL; const struct firmware *fw; int ret; int cfg_sz; u8 *cfg_buff = NULL; u8 *tbuff; char *cfg_name = NULL; bool config_needed = false; switch (lmp_subver) { case RTL_ROM_LMP_8723B: cfg_name = "rtl_bt/rtl8723b_config.bin"; break; case RTL_ROM_LMP_8821A: cfg_name = "rtl_bt/rtl8821a_config.bin"; break; case RTL_ROM_LMP_8761A: cfg_name = "rtl_bt/rtl8761a_config.bin"; break; case RTL_ROM_LMP_8822B: cfg_name = "rtl_bt/rtl8822b_config.bin"; config_needed = true; break; default: BT_ERR("%s: rtl: no config according to lmp_subver %04x", hdev->name, lmp_subver); break; } if (cfg_name) { cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff); if (cfg_sz < 0) { cfg_sz = 0; if (config_needed) BT_ERR("Necessary config file %s not found\n", cfg_name); } } else cfg_sz = 0; bt_dev_info(hdev, "rtl: loading %s", fw_name); ret = request_firmware(&fw, fw_name, &hdev->dev); if (ret < 0) { BT_ERR("%s: Failed to load %s", hdev->name, fw_name); goto err_req_fw; } ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); if (ret < 0) goto out; if (cfg_sz) { tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL); if (!tbuff) { ret = -ENOMEM; goto out; } memcpy(tbuff, fw_data, ret); kfree(fw_data); memcpy(tbuff + ret, cfg_buff, cfg_sz); ret += cfg_sz; fw_data = tbuff; } bt_dev_info(hdev, "cfg_sz %d, total size %d", cfg_sz, ret); ret = rtl_download_firmware(hdev, fw_data, ret); out: release_firmware(fw); kfree(fw_data); err_req_fw: if (cfg_sz) kfree(cfg_buff); return ret; }
static int qca_setup(struct hci_uart *hu) { struct hci_dev *hdev = hu->hdev; struct qca_data *qca = hu->priv; unsigned int speed, qca_baudrate = QCA_BAUDRATE_115200; struct qca_serdev *qcadev; int ret; int soc_ver = 0; qcadev = serdev_device_get_drvdata(hu->serdev); ret = qca_check_speeds(hu); if (ret) return ret; /* Patch downloading has to be done without IBS mode */ clear_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); if (qcadev->btsoc_type == QCA_WCN3990) { bt_dev_info(hdev, "setting up wcn3990"); /* Enable NON_PERSISTENT_SETUP QUIRK to ensure to execute * setup for every hci up. */ set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks); set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks); hu->hdev->shutdown = qca_power_off; ret = qca_wcn3990_init(hu); if (ret) return ret; ret = qca_read_soc_version(hdev, &soc_ver); if (ret) return ret; } else { bt_dev_info(hdev, "ROME setup"); qca_set_speed(hu, QCA_INIT_SPEED); } /* Setup user speed if needed */ speed = qca_get_speed(hu, QCA_OPER_SPEED); if (speed) { ret = qca_set_speed(hu, QCA_OPER_SPEED); if (ret) return ret; qca_baudrate = qca_get_baudrate_value(speed); } if (qcadev->btsoc_type != QCA_WCN3990) { /* Get QCA version information */ ret = qca_read_soc_version(hdev, &soc_ver); if (ret) return ret; } bt_dev_info(hdev, "QCA controller version 0x%08x", soc_ver); /* Setup patch / NVM configurations */ ret = qca_uart_setup(hdev, qca_baudrate, qcadev->btsoc_type, soc_ver); if (!ret) { set_bit(STATE_IN_BAND_SLEEP_ENABLED, &qca->flags); qca_debugfs_init(hdev); } else if (ret == -ENOENT) { /* No patch/nvm-config found, run with original fw/config */ ret = 0; } else if (ret == -EAGAIN) { /* * Userspace firmware loader will return -EAGAIN in case no * patch/nvm-config is found, so run with original fw/config. */ ret = 0; } /* Setup bdaddr */ if (qcadev->btsoc_type == QCA_WCN3990) hu->hdev->set_bdaddr = qca_set_bdaddr; else hu->hdev->set_bdaddr = qca_set_bdaddr_rome; return ret; }