]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - drivers/bluetooth/btrtl.c
s390/crypto: fix gcm-aes-s390 selftest failures
[mirror_ubuntu-bionic-kernel.git] / drivers / bluetooth / btrtl.c
index 6e2ad748abbae27686f9de4dd024dd1605168236..437f080deaab293f08f92aaff55c4ec5be69fb91 100644 (file)
 #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;