|
@@ -35,6 +35,60 @@
|
|
|
#define RTL_ROM_LMP_8761A 0x8761
|
|
|
#define RTL_ROM_LMP_8822B 0x8822
|
|
|
|
|
|
+#define IC_MATCH_FL_LMPSUBV (1 << 0)
|
|
|
+#define IC_MATCH_FL_HCIREV (1 << 1)
|
|
|
+#define IC_INFO(lmps, hcir) \
|
|
|
+ .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \
|
|
|
+ .lmp_subver = (lmps), \
|
|
|
+ .hci_rev = (hcir)
|
|
|
+
|
|
|
+struct id_table {
|
|
|
+ __u16 match_flags;
|
|
|
+ __u16 lmp_subver;
|
|
|
+ __u16 hci_rev;
|
|
|
+ bool config_needed;
|
|
|
+ char *fw_name;
|
|
|
+ char *cfg_name;
|
|
|
+};
|
|
|
+
|
|
|
+static const struct id_table ic_id_table[] = {
|
|
|
+ /* 8723B */
|
|
|
+ { IC_INFO(RTL_ROM_LMP_8723B, 0xb),
|
|
|
+ .config_needed = false,
|
|
|
+ .fw_name = "rtl_bt/rtl8723b_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8723b_config.bin" },
|
|
|
+
|
|
|
+ /* 8723D */
|
|
|
+ { IC_INFO(RTL_ROM_LMP_8723B, 0xd),
|
|
|
+ .config_needed = true,
|
|
|
+ .fw_name = "rtl_bt/rtl8723d_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8723d_config.bin" },
|
|
|
+
|
|
|
+ /* 8821A */
|
|
|
+ { IC_INFO(RTL_ROM_LMP_8821A, 0xa),
|
|
|
+ .config_needed = false,
|
|
|
+ .fw_name = "rtl_bt/rtl8821a_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8821a_config.bin" },
|
|
|
+
|
|
|
+ /* 8821C */
|
|
|
+ { IC_INFO(RTL_ROM_LMP_8821A, 0xc),
|
|
|
+ .config_needed = false,
|
|
|
+ .fw_name = "rtl_bt/rtl8821c_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8821c_config.bin" },
|
|
|
+
|
|
|
+ /* 8761A */
|
|
|
+ { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0,
|
|
|
+ .config_needed = false,
|
|
|
+ .fw_name = "rtl_bt/rtl8761a_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8761a_config.bin" },
|
|
|
+
|
|
|
+ /* 8822B */
|
|
|
+ { IC_INFO(RTL_ROM_LMP_8822B, 0xb),
|
|
|
+ .config_needed = true,
|
|
|
+ .fw_name = "rtl_bt/rtl8822b_fw.bin",
|
|
|
+ .cfg_name = "rtl_bt/rtl8822b_config.bin" },
|
|
|
+ };
|
|
|
+
|
|
|
static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
|
|
|
{
|
|
|
struct rtl_rom_version_evt *rom_version;
|
|
@@ -64,9 +118,9 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
- const struct firmware *fw,
|
|
|
- unsigned char **_buf)
|
|
|
+static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
+ const struct firmware *fw,
|
|
|
+ unsigned char **_buf)
|
|
|
{
|
|
|
const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
|
|
|
struct rtl_epatch_header *epatch_info;
|
|
@@ -88,6 +142,8 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
{ RTL_ROM_LMP_8821A, 2 },
|
|
|
{ RTL_ROM_LMP_8761A, 3 },
|
|
|
{ RTL_ROM_LMP_8822B, 8 },
|
|
|
+ { RTL_ROM_LMP_8723B, 9 }, /* 8723D */
|
|
|
+ { RTL_ROM_LMP_8821A, 10 }, /* 8821C */
|
|
|
};
|
|
|
|
|
|
ret = rtl_read_rom_version(hdev, &rom_version);
|
|
@@ -320,8 +376,8 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
- const char *fw_name)
|
|
|
+static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev,
|
|
|
+ u16 lmp_subver)
|
|
|
{
|
|
|
unsigned char *fw_data = NULL;
|
|
|
const struct firmware *fw;
|
|
@@ -330,39 +386,40 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
u8 *cfg_buff = NULL;
|
|
|
u8 *tbuff;
|
|
|
char *cfg_name = NULL;
|
|
|
- bool config_needed = false;
|
|
|
+ char *fw_name = NULL;
|
|
|
+ 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;
|
|
|
|
|
|
- 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 (i >= ARRAY_SIZE(ic_id_table)) {
|
|
|
+ BT_ERR("%s: unknown IC info, lmp subver %04x, hci rev %04x",
|
|
|
+ hdev->name, lmp_subver, hci_rev);
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+
|
|
|
+ cfg_name = ic_id_table[i].cfg_name;
|
|
|
+
|
|
|
if (cfg_name) {
|
|
|
cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
|
|
|
if (cfg_sz < 0) {
|
|
|
cfg_sz = 0;
|
|
|
- if (config_needed)
|
|
|
+ if (ic_id_table[i].config_needed)
|
|
|
BT_ERR("Necessary config file %s not found\n",
|
|
|
cfg_name);
|
|
|
}
|
|
|
} else
|
|
|
cfg_sz = 0;
|
|
|
|
|
|
+ fw_name = ic_id_table[i].fw_name;
|
|
|
bt_dev_info(hdev, "rtl: loading %s", fw_name);
|
|
|
ret = request_firmware(&fw, fw_name, &hdev->dev);
|
|
|
if (ret < 0) {
|
|
@@ -370,7 +427,7 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
|
|
|
goto err_req_fw;
|
|
|
}
|
|
|
|
|
|
- ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
|
|
|
+ ret = rtlbt_parse_firmware(hdev, lmp_subver, fw, &fw_data);
|
|
|
if (ret < 0)
|
|
|
goto out;
|
|
|
|
|
@@ -429,7 +486,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
|
|
|
{
|
|
|
struct sk_buff *skb;
|
|
|
struct hci_rp_read_local_version *resp;
|
|
|
- u16 lmp_subver;
|
|
|
+ u16 hci_rev, lmp_subver;
|
|
|
|
|
|
skb = btrtl_read_local_version(hdev);
|
|
|
if (IS_ERR(skb))
|
|
@@ -441,6 +498,7 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
|
|
|
resp->hci_ver, resp->hci_rev,
|
|
|
resp->lmp_ver, resp->lmp_subver);
|
|
|
|
|
|
+ hci_rev = le16_to_cpu(resp->hci_rev);
|
|
|
lmp_subver = le16_to_cpu(resp->lmp_subver);
|
|
|
kfree_skb(skb);
|
|
|
|
|
@@ -455,17 +513,10 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
|
|
|
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");
|
|
|
+ return btrtl_setup_rtl8723b(hdev, hci_rev, lmp_subver);
|
|
|
default:
|
|
|
bt_dev_info(hdev, "rtl: assuming no firmware upload needed");
|
|
|
return 0;
|