1db33c77dSCarlo Caione /* 2db33c77dSCarlo Caione * Bluetooth support for Realtek devices 3db33c77dSCarlo Caione * 4db33c77dSCarlo Caione * Copyright (C) 2015 Endless Mobile, Inc. 5db33c77dSCarlo Caione * 6db33c77dSCarlo Caione * This program is free software; you can redistribute it and/or modify 7db33c77dSCarlo Caione * it under the terms of the GNU General Public License as published by 8db33c77dSCarlo Caione * the Free Software Foundation; either version 2 of the License, or 9db33c77dSCarlo Caione * (at your option) any later version. 10db33c77dSCarlo Caione * 11db33c77dSCarlo Caione * This program is distributed in the hope that it will be useful, 12db33c77dSCarlo Caione * but WITHOUT ANY WARRANTY; without even the implied warranty of 13db33c77dSCarlo Caione * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14db33c77dSCarlo Caione * GNU General Public License for more details. 15db33c77dSCarlo Caione * 16db33c77dSCarlo Caione */ 17db33c77dSCarlo Caione 18db33c77dSCarlo Caione #include <linux/module.h> 19db33c77dSCarlo Caione #include <linux/firmware.h> 20db33c77dSCarlo Caione #include <asm/unaligned.h> 21db33c77dSCarlo Caione #include <linux/usb.h> 22db33c77dSCarlo Caione 23db33c77dSCarlo Caione #include <net/bluetooth/bluetooth.h> 24db33c77dSCarlo Caione #include <net/bluetooth/hci_core.h> 25db33c77dSCarlo Caione 26db33c77dSCarlo Caione #include "btrtl.h" 27db33c77dSCarlo Caione 28db33c77dSCarlo Caione #define VERSION "0.1" 29db33c77dSCarlo Caione 30db33c77dSCarlo Caione #define RTL_EPATCH_SIGNATURE "Realtech" 31db33c77dSCarlo Caione #define RTL_ROM_LMP_3499 0x3499 32db33c77dSCarlo Caione #define RTL_ROM_LMP_8723A 0x1200 33db33c77dSCarlo Caione #define RTL_ROM_LMP_8723B 0x8723 34db33c77dSCarlo Caione #define RTL_ROM_LMP_8821A 0x8821 35db33c77dSCarlo Caione #define RTL_ROM_LMP_8761A 0x8761 361110a2dbSLarry Finger #define RTL_ROM_LMP_8822B 0x8822 37db33c77dSCarlo Caione 38*907f8499SAlex Lu #define IC_MATCH_FL_LMPSUBV (1 << 0) 39*907f8499SAlex Lu #define IC_MATCH_FL_HCIREV (1 << 1) 40*907f8499SAlex Lu #define IC_INFO(lmps, hcir) \ 41*907f8499SAlex Lu .match_flags = IC_MATCH_FL_LMPSUBV | IC_MATCH_FL_HCIREV, \ 42*907f8499SAlex Lu .lmp_subver = (lmps), \ 43*907f8499SAlex Lu .hci_rev = (hcir) 44*907f8499SAlex Lu 45*907f8499SAlex Lu struct id_table { 46*907f8499SAlex Lu __u16 match_flags; 47*907f8499SAlex Lu __u16 lmp_subver; 48*907f8499SAlex Lu __u16 hci_rev; 49*907f8499SAlex Lu bool config_needed; 50*907f8499SAlex Lu char *fw_name; 51*907f8499SAlex Lu char *cfg_name; 52*907f8499SAlex Lu }; 53*907f8499SAlex Lu 54*907f8499SAlex Lu static const struct id_table ic_id_table[] = { 55*907f8499SAlex Lu /* 8723B */ 56*907f8499SAlex Lu { IC_INFO(RTL_ROM_LMP_8723B, 0xb), 57*907f8499SAlex Lu .config_needed = false, 58*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8723b_fw.bin", 59*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8723b_config.bin" }, 60*907f8499SAlex Lu 61*907f8499SAlex Lu /* 8723D */ 62*907f8499SAlex Lu { IC_INFO(RTL_ROM_LMP_8723B, 0xd), 63*907f8499SAlex Lu .config_needed = true, 64*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8723d_fw.bin", 65*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8723d_config.bin" }, 66*907f8499SAlex Lu 67*907f8499SAlex Lu /* 8821A */ 68*907f8499SAlex Lu { IC_INFO(RTL_ROM_LMP_8821A, 0xa), 69*907f8499SAlex Lu .config_needed = false, 70*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8821a_fw.bin", 71*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8821a_config.bin" }, 72*907f8499SAlex Lu 73*907f8499SAlex Lu /* 8821C */ 74*907f8499SAlex Lu { IC_INFO(RTL_ROM_LMP_8821A, 0xc), 75*907f8499SAlex Lu .config_needed = false, 76*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8821c_fw.bin", 77*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8821c_config.bin" }, 78*907f8499SAlex Lu 79*907f8499SAlex Lu /* 8761A */ 80*907f8499SAlex Lu { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0, 81*907f8499SAlex Lu .config_needed = false, 82*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8761a_fw.bin", 83*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8761a_config.bin" }, 84*907f8499SAlex Lu 85*907f8499SAlex Lu /* 8822B */ 86*907f8499SAlex Lu { IC_INFO(RTL_ROM_LMP_8822B, 0xb), 87*907f8499SAlex Lu .config_needed = true, 88*907f8499SAlex Lu .fw_name = "rtl_bt/rtl8822b_fw.bin", 89*907f8499SAlex Lu .cfg_name = "rtl_bt/rtl8822b_config.bin" }, 90*907f8499SAlex Lu }; 91*907f8499SAlex Lu 92db33c77dSCarlo Caione static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) 93db33c77dSCarlo Caione { 94db33c77dSCarlo Caione struct rtl_rom_version_evt *rom_version; 95db33c77dSCarlo Caione struct sk_buff *skb; 96db33c77dSCarlo Caione 97db33c77dSCarlo Caione /* Read RTL ROM version command */ 98db33c77dSCarlo Caione skb = __hci_cmd_sync(hdev, 0xfc6d, 0, NULL, HCI_INIT_TIMEOUT); 99db33c77dSCarlo Caione if (IS_ERR(skb)) { 100db33c77dSCarlo Caione BT_ERR("%s: Read ROM version failed (%ld)", 101db33c77dSCarlo Caione hdev->name, PTR_ERR(skb)); 102db33c77dSCarlo Caione return PTR_ERR(skb); 103db33c77dSCarlo Caione } 104db33c77dSCarlo Caione 105db33c77dSCarlo Caione if (skb->len != sizeof(*rom_version)) { 106db33c77dSCarlo Caione BT_ERR("%s: RTL version event length mismatch", hdev->name); 107db33c77dSCarlo Caione kfree_skb(skb); 108db33c77dSCarlo Caione return -EIO; 109db33c77dSCarlo Caione } 110db33c77dSCarlo Caione 111db33c77dSCarlo Caione rom_version = (struct rtl_rom_version_evt *)skb->data; 1122064ee33SMarcel Holtmann bt_dev_info(hdev, "rom_version status=%x version=%x", 1132064ee33SMarcel Holtmann rom_version->status, rom_version->version); 114db33c77dSCarlo Caione 115db33c77dSCarlo Caione *version = rom_version->version; 116db33c77dSCarlo Caione 117db33c77dSCarlo Caione kfree_skb(skb); 118db33c77dSCarlo Caione return 0; 119db33c77dSCarlo Caione } 120db33c77dSCarlo Caione 121*907f8499SAlex Lu static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, 122db33c77dSCarlo Caione const struct firmware *fw, 123db33c77dSCarlo Caione unsigned char **_buf) 124db33c77dSCarlo Caione { 125db33c77dSCarlo Caione const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; 126db33c77dSCarlo Caione struct rtl_epatch_header *epatch_info; 127db33c77dSCarlo Caione unsigned char *buf; 128db33c77dSCarlo Caione int i, ret, len; 129db33c77dSCarlo Caione size_t min_size; 130db33c77dSCarlo Caione u8 opcode, length, data, rom_version = 0; 131db33c77dSCarlo Caione int project_id = -1; 132db33c77dSCarlo Caione const unsigned char *fwptr, *chip_id_base; 133db33c77dSCarlo Caione const unsigned char *patch_length_base, *patch_offset_base; 134db33c77dSCarlo Caione u32 patch_offset = 0; 135db33c77dSCarlo Caione u16 patch_length, num_patches; 1361110a2dbSLarry Finger static const struct { 1371110a2dbSLarry Finger __u16 lmp_subver; 1381110a2dbSLarry Finger __u8 id; 1391110a2dbSLarry Finger } project_id_to_lmp_subver[] = { 1401110a2dbSLarry Finger { RTL_ROM_LMP_8723A, 0 }, 1411110a2dbSLarry Finger { RTL_ROM_LMP_8723B, 1 }, 1421110a2dbSLarry Finger { RTL_ROM_LMP_8821A, 2 }, 1431110a2dbSLarry Finger { RTL_ROM_LMP_8761A, 3 }, 1441110a2dbSLarry Finger { RTL_ROM_LMP_8822B, 8 }, 145*907f8499SAlex Lu { RTL_ROM_LMP_8723B, 9 }, /* 8723D */ 146*907f8499SAlex Lu { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ 147db33c77dSCarlo Caione }; 148db33c77dSCarlo Caione 149db33c77dSCarlo Caione ret = rtl_read_rom_version(hdev, &rom_version); 150db33c77dSCarlo Caione if (ret) 151db33c77dSCarlo Caione return ret; 152db33c77dSCarlo Caione 153db33c77dSCarlo Caione min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; 154db33c77dSCarlo Caione if (fw->size < min_size) 155db33c77dSCarlo Caione return -EINVAL; 156db33c77dSCarlo Caione 157db33c77dSCarlo Caione fwptr = fw->data + fw->size - sizeof(extension_sig); 158db33c77dSCarlo Caione if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { 159db33c77dSCarlo Caione BT_ERR("%s: extension section signature mismatch", hdev->name); 160db33c77dSCarlo Caione return -EINVAL; 161db33c77dSCarlo Caione } 162db33c77dSCarlo Caione 163db33c77dSCarlo Caione /* Loop from the end of the firmware parsing instructions, until 164db33c77dSCarlo Caione * we find an instruction that identifies the "project ID" for the 165db33c77dSCarlo Caione * hardware supported by this firwmare file. 166db33c77dSCarlo Caione * Once we have that, we double-check that that project_id is suitable 167db33c77dSCarlo Caione * for the hardware we are working with. 168db33c77dSCarlo Caione */ 169db33c77dSCarlo Caione while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { 170db33c77dSCarlo Caione opcode = *--fwptr; 171db33c77dSCarlo Caione length = *--fwptr; 172db33c77dSCarlo Caione data = *--fwptr; 173db33c77dSCarlo Caione 174db33c77dSCarlo Caione BT_DBG("check op=%x len=%x data=%x", opcode, length, data); 175db33c77dSCarlo Caione 176db33c77dSCarlo Caione if (opcode == 0xff) /* EOF */ 177db33c77dSCarlo Caione break; 178db33c77dSCarlo Caione 179db33c77dSCarlo Caione if (length == 0) { 180db33c77dSCarlo Caione BT_ERR("%s: found instruction with length 0", 181db33c77dSCarlo Caione hdev->name); 182db33c77dSCarlo Caione return -EINVAL; 183db33c77dSCarlo Caione } 184db33c77dSCarlo Caione 185db33c77dSCarlo Caione if (opcode == 0 && length == 1) { 186db33c77dSCarlo Caione project_id = data; 187db33c77dSCarlo Caione break; 188db33c77dSCarlo Caione } 189db33c77dSCarlo Caione 190db33c77dSCarlo Caione fwptr -= length; 191db33c77dSCarlo Caione } 192db33c77dSCarlo Caione 193db33c77dSCarlo Caione if (project_id < 0) { 194db33c77dSCarlo Caione BT_ERR("%s: failed to find version instruction", hdev->name); 195db33c77dSCarlo Caione return -EINVAL; 196db33c77dSCarlo Caione } 197db33c77dSCarlo Caione 1981110a2dbSLarry Finger /* Find project_id in table */ 1991110a2dbSLarry Finger for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) { 2001110a2dbSLarry Finger if (project_id == project_id_to_lmp_subver[i].id) 2011110a2dbSLarry Finger break; 2021110a2dbSLarry Finger } 2031110a2dbSLarry Finger 2041110a2dbSLarry Finger if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) { 205db33c77dSCarlo Caione BT_ERR("%s: unknown project id %d", hdev->name, project_id); 206db33c77dSCarlo Caione return -EINVAL; 207db33c77dSCarlo Caione } 208db33c77dSCarlo Caione 2091110a2dbSLarry Finger if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) { 210db33c77dSCarlo Caione BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, 2111110a2dbSLarry Finger project_id_to_lmp_subver[i].lmp_subver, lmp_subver); 212db33c77dSCarlo Caione return -EINVAL; 213db33c77dSCarlo Caione } 214db33c77dSCarlo Caione 215db33c77dSCarlo Caione epatch_info = (struct rtl_epatch_header *)fw->data; 216db33c77dSCarlo Caione if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { 217db33c77dSCarlo Caione BT_ERR("%s: bad EPATCH signature", hdev->name); 218db33c77dSCarlo Caione return -EINVAL; 219db33c77dSCarlo Caione } 220db33c77dSCarlo Caione 221db33c77dSCarlo Caione num_patches = le16_to_cpu(epatch_info->num_patches); 222db33c77dSCarlo Caione BT_DBG("fw_version=%x, num_patches=%d", 223db33c77dSCarlo Caione le32_to_cpu(epatch_info->fw_version), num_patches); 224db33c77dSCarlo Caione 225db33c77dSCarlo Caione /* After the rtl_epatch_header there is a funky patch metadata section. 226db33c77dSCarlo Caione * Assuming 2 patches, the layout is: 227db33c77dSCarlo Caione * ChipID1 ChipID2 PatchLength1 PatchLength2 PatchOffset1 PatchOffset2 228db33c77dSCarlo Caione * 229db33c77dSCarlo Caione * Find the right patch for this chip. 230db33c77dSCarlo Caione */ 231db33c77dSCarlo Caione min_size += 8 * num_patches; 232db33c77dSCarlo Caione if (fw->size < min_size) 233db33c77dSCarlo Caione return -EINVAL; 234db33c77dSCarlo Caione 235db33c77dSCarlo Caione chip_id_base = fw->data + sizeof(struct rtl_epatch_header); 236db33c77dSCarlo Caione patch_length_base = chip_id_base + (sizeof(u16) * num_patches); 237db33c77dSCarlo Caione patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); 238db33c77dSCarlo Caione for (i = 0; i < num_patches; i++) { 239db33c77dSCarlo Caione u16 chip_id = get_unaligned_le16(chip_id_base + 240db33c77dSCarlo Caione (i * sizeof(u16))); 241db33c77dSCarlo Caione if (chip_id == rom_version + 1) { 242db33c77dSCarlo Caione patch_length = get_unaligned_le16(patch_length_base + 243db33c77dSCarlo Caione (i * sizeof(u16))); 244db33c77dSCarlo Caione patch_offset = get_unaligned_le32(patch_offset_base + 245db33c77dSCarlo Caione (i * sizeof(u32))); 246db33c77dSCarlo Caione break; 247db33c77dSCarlo Caione } 248db33c77dSCarlo Caione } 249db33c77dSCarlo Caione 250db33c77dSCarlo Caione if (!patch_offset) { 251db33c77dSCarlo Caione BT_ERR("%s: didn't find patch for chip id %d", 252db33c77dSCarlo Caione hdev->name, rom_version); 253db33c77dSCarlo Caione return -EINVAL; 254db33c77dSCarlo Caione } 255db33c77dSCarlo Caione 256db33c77dSCarlo Caione BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); 257db33c77dSCarlo Caione min_size = patch_offset + patch_length; 258db33c77dSCarlo Caione if (fw->size < min_size) 259db33c77dSCarlo Caione return -EINVAL; 260db33c77dSCarlo Caione 261db33c77dSCarlo Caione /* Copy the firmware into a new buffer and write the version at 262db33c77dSCarlo Caione * the end. 263db33c77dSCarlo Caione */ 264db33c77dSCarlo Caione len = patch_length; 265db33c77dSCarlo Caione buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); 266db33c77dSCarlo Caione if (!buf) 267db33c77dSCarlo Caione return -ENOMEM; 268db33c77dSCarlo Caione 269db33c77dSCarlo Caione memcpy(buf + patch_length - 4, &epatch_info->fw_version, 4); 270db33c77dSCarlo Caione 271db33c77dSCarlo Caione *_buf = buf; 272db33c77dSCarlo Caione return len; 273db33c77dSCarlo Caione } 274db33c77dSCarlo Caione 275db33c77dSCarlo Caione static int rtl_download_firmware(struct hci_dev *hdev, 276db33c77dSCarlo Caione const unsigned char *data, int fw_len) 277db33c77dSCarlo Caione { 278db33c77dSCarlo Caione struct rtl_download_cmd *dl_cmd; 279db33c77dSCarlo Caione int frag_num = fw_len / RTL_FRAG_LEN + 1; 280db33c77dSCarlo Caione int frag_len = RTL_FRAG_LEN; 281db33c77dSCarlo Caione int ret = 0; 282db33c77dSCarlo Caione int i; 283db33c77dSCarlo Caione 284db33c77dSCarlo Caione dl_cmd = kmalloc(sizeof(struct rtl_download_cmd), GFP_KERNEL); 285db33c77dSCarlo Caione if (!dl_cmd) 286db33c77dSCarlo Caione return -ENOMEM; 287db33c77dSCarlo Caione 288db33c77dSCarlo Caione for (i = 0; i < frag_num; i++) { 289db33c77dSCarlo Caione struct sk_buff *skb; 290db33c77dSCarlo Caione 291db33c77dSCarlo Caione BT_DBG("download fw (%d/%d)", i, frag_num); 292db33c77dSCarlo Caione 293db33c77dSCarlo Caione dl_cmd->index = i; 294db33c77dSCarlo Caione if (i == (frag_num - 1)) { 295db33c77dSCarlo Caione dl_cmd->index |= 0x80; /* data end */ 296db33c77dSCarlo Caione frag_len = fw_len % RTL_FRAG_LEN; 297db33c77dSCarlo Caione } 298db33c77dSCarlo Caione memcpy(dl_cmd->data, data, frag_len); 299db33c77dSCarlo Caione 300db33c77dSCarlo Caione /* Send download command */ 301db33c77dSCarlo Caione skb = __hci_cmd_sync(hdev, 0xfc20, frag_len + 1, dl_cmd, 302db33c77dSCarlo Caione HCI_INIT_TIMEOUT); 303db33c77dSCarlo Caione if (IS_ERR(skb)) { 304db33c77dSCarlo Caione BT_ERR("%s: download fw command failed (%ld)", 305db33c77dSCarlo Caione hdev->name, PTR_ERR(skb)); 306db33c77dSCarlo Caione ret = -PTR_ERR(skb); 307db33c77dSCarlo Caione goto out; 308db33c77dSCarlo Caione } 309db33c77dSCarlo Caione 310db33c77dSCarlo Caione if (skb->len != sizeof(struct rtl_download_response)) { 311db33c77dSCarlo Caione BT_ERR("%s: download fw event length mismatch", 312db33c77dSCarlo Caione hdev->name); 313db33c77dSCarlo Caione kfree_skb(skb); 314db33c77dSCarlo Caione ret = -EIO; 315db33c77dSCarlo Caione goto out; 316db33c77dSCarlo Caione } 317db33c77dSCarlo Caione 318db33c77dSCarlo Caione kfree_skb(skb); 319db33c77dSCarlo Caione data += RTL_FRAG_LEN; 320db33c77dSCarlo Caione } 321db33c77dSCarlo Caione 322db33c77dSCarlo Caione out: 323db33c77dSCarlo Caione kfree(dl_cmd); 324db33c77dSCarlo Caione return ret; 325db33c77dSCarlo Caione } 326db33c77dSCarlo Caione 3271110a2dbSLarry Finger static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) 3281110a2dbSLarry Finger { 3291110a2dbSLarry Finger const struct firmware *fw; 3301110a2dbSLarry Finger int ret; 3311110a2dbSLarry Finger 3322064ee33SMarcel Holtmann bt_dev_info(hdev, "rtl: loading %s", name); 3331110a2dbSLarry Finger ret = request_firmware(&fw, name, &hdev->dev); 334abed84a0SLarry Finger if (ret < 0) 3351110a2dbSLarry Finger return ret; 3361110a2dbSLarry Finger ret = fw->size; 3371110a2dbSLarry Finger *buff = kmemdup(fw->data, ret, GFP_KERNEL); 338c3327bdeSDan Carpenter if (!*buff) 339c3327bdeSDan Carpenter ret = -ENOMEM; 3401110a2dbSLarry Finger 3411110a2dbSLarry Finger release_firmware(fw); 3421110a2dbSLarry Finger 3431110a2dbSLarry Finger return ret; 3441110a2dbSLarry Finger } 3451110a2dbSLarry Finger 346db33c77dSCarlo Caione static int btrtl_setup_rtl8723a(struct hci_dev *hdev) 347db33c77dSCarlo Caione { 348db33c77dSCarlo Caione const struct firmware *fw; 349db33c77dSCarlo Caione int ret; 350db33c77dSCarlo Caione 3512064ee33SMarcel Holtmann bt_dev_info(hdev, "rtl: loading rtl_bt/rtl8723a_fw.bin"); 352db33c77dSCarlo Caione ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev); 353db33c77dSCarlo Caione if (ret < 0) { 354db33c77dSCarlo Caione BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name); 355db33c77dSCarlo Caione return ret; 356db33c77dSCarlo Caione } 357db33c77dSCarlo Caione 358db33c77dSCarlo Caione if (fw->size < 8) { 359db33c77dSCarlo Caione ret = -EINVAL; 360db33c77dSCarlo Caione goto out; 361db33c77dSCarlo Caione } 362db33c77dSCarlo Caione 363db33c77dSCarlo Caione /* Check that the firmware doesn't have the epatch signature 364db33c77dSCarlo Caione * (which is only for RTL8723B and newer). 365db33c77dSCarlo Caione */ 366db33c77dSCarlo Caione if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { 367db33c77dSCarlo Caione BT_ERR("%s: unexpected EPATCH signature!", hdev->name); 368db33c77dSCarlo Caione ret = -EINVAL; 369db33c77dSCarlo Caione goto out; 370db33c77dSCarlo Caione } 371db33c77dSCarlo Caione 372db33c77dSCarlo Caione ret = rtl_download_firmware(hdev, fw->data, fw->size); 373db33c77dSCarlo Caione 374db33c77dSCarlo Caione out: 375db33c77dSCarlo Caione release_firmware(fw); 376db33c77dSCarlo Caione return ret; 377db33c77dSCarlo Caione } 378db33c77dSCarlo Caione 379*907f8499SAlex Lu static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev, 380*907f8499SAlex Lu u16 lmp_subver) 381db33c77dSCarlo Caione { 382db33c77dSCarlo Caione unsigned char *fw_data = NULL; 383db33c77dSCarlo Caione const struct firmware *fw; 384db33c77dSCarlo Caione int ret; 3851110a2dbSLarry Finger int cfg_sz; 3861110a2dbSLarry Finger u8 *cfg_buff = NULL; 3871110a2dbSLarry Finger u8 *tbuff; 3881110a2dbSLarry Finger char *cfg_name = NULL; 389*907f8499SAlex Lu char *fw_name = NULL; 390*907f8499SAlex Lu int i; 3911110a2dbSLarry Finger 392*907f8499SAlex Lu for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) { 393*907f8499SAlex Lu if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) && 394*907f8499SAlex Lu (ic_id_table[i].lmp_subver != lmp_subver)) 395*907f8499SAlex Lu continue; 396*907f8499SAlex Lu if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) && 397*907f8499SAlex Lu (ic_id_table[i].hci_rev != hci_rev)) 398*907f8499SAlex Lu continue; 399*907f8499SAlex Lu 4001110a2dbSLarry Finger break; 4011110a2dbSLarry Finger } 4021110a2dbSLarry Finger 403*907f8499SAlex Lu if (i >= ARRAY_SIZE(ic_id_table)) { 404*907f8499SAlex Lu BT_ERR("%s: unknown IC info, lmp subver %04x, hci rev %04x", 405*907f8499SAlex Lu hdev->name, lmp_subver, hci_rev); 406*907f8499SAlex Lu return -EINVAL; 407*907f8499SAlex Lu } 408*907f8499SAlex Lu 409*907f8499SAlex Lu cfg_name = ic_id_table[i].cfg_name; 410*907f8499SAlex Lu 4111110a2dbSLarry Finger if (cfg_name) { 4121110a2dbSLarry Finger cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff); 413abed84a0SLarry Finger if (cfg_sz < 0) { 4141110a2dbSLarry Finger cfg_sz = 0; 415*907f8499SAlex Lu if (ic_id_table[i].config_needed) 416abed84a0SLarry Finger BT_ERR("Necessary config file %s not found\n", 417abed84a0SLarry Finger cfg_name); 418abed84a0SLarry Finger } 4191110a2dbSLarry Finger } else 4201110a2dbSLarry Finger cfg_sz = 0; 421db33c77dSCarlo Caione 422*907f8499SAlex Lu fw_name = ic_id_table[i].fw_name; 4232064ee33SMarcel Holtmann bt_dev_info(hdev, "rtl: loading %s", fw_name); 424db33c77dSCarlo Caione ret = request_firmware(&fw, fw_name, &hdev->dev); 425db33c77dSCarlo Caione if (ret < 0) { 426db33c77dSCarlo Caione BT_ERR("%s: Failed to load %s", hdev->name, fw_name); 4271110a2dbSLarry Finger goto err_req_fw; 428db33c77dSCarlo Caione } 429db33c77dSCarlo Caione 430*907f8499SAlex Lu ret = rtlbt_parse_firmware(hdev, lmp_subver, fw, &fw_data); 431db33c77dSCarlo Caione if (ret < 0) 432db33c77dSCarlo Caione goto out; 433db33c77dSCarlo Caione 4341110a2dbSLarry Finger if (cfg_sz) { 4351110a2dbSLarry Finger tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL); 4361110a2dbSLarry Finger if (!tbuff) { 4371110a2dbSLarry Finger ret = -ENOMEM; 438db33c77dSCarlo Caione goto out; 4391110a2dbSLarry Finger } 4401110a2dbSLarry Finger 4411110a2dbSLarry Finger memcpy(tbuff, fw_data, ret); 4421110a2dbSLarry Finger kfree(fw_data); 4431110a2dbSLarry Finger 4441110a2dbSLarry Finger memcpy(tbuff + ret, cfg_buff, cfg_sz); 4451110a2dbSLarry Finger ret += cfg_sz; 4461110a2dbSLarry Finger 4471110a2dbSLarry Finger fw_data = tbuff; 4481110a2dbSLarry Finger } 4491110a2dbSLarry Finger 4502064ee33SMarcel Holtmann bt_dev_info(hdev, "cfg_sz %d, total size %d", cfg_sz, ret); 4511110a2dbSLarry Finger 4521110a2dbSLarry Finger ret = rtl_download_firmware(hdev, fw_data, ret); 453db33c77dSCarlo Caione 454db33c77dSCarlo Caione out: 455db33c77dSCarlo Caione release_firmware(fw); 4561110a2dbSLarry Finger kfree(fw_data); 4571110a2dbSLarry Finger err_req_fw: 4581110a2dbSLarry Finger if (cfg_sz) 4591110a2dbSLarry Finger kfree(cfg_buff); 460db33c77dSCarlo Caione return ret; 461db33c77dSCarlo Caione } 462db33c77dSCarlo Caione 463db33c77dSCarlo Caione static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev) 464db33c77dSCarlo Caione { 465db33c77dSCarlo Caione struct sk_buff *skb; 466db33c77dSCarlo Caione 467db33c77dSCarlo Caione skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL, 468db33c77dSCarlo Caione HCI_INIT_TIMEOUT); 469db33c77dSCarlo Caione if (IS_ERR(skb)) { 470db33c77dSCarlo Caione BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION failed (%ld)", 471db33c77dSCarlo Caione hdev->name, PTR_ERR(skb)); 472db33c77dSCarlo Caione return skb; 473db33c77dSCarlo Caione } 474db33c77dSCarlo Caione 475db33c77dSCarlo Caione if (skb->len != sizeof(struct hci_rp_read_local_version)) { 476db33c77dSCarlo Caione BT_ERR("%s: HCI_OP_READ_LOCAL_VERSION event length mismatch", 477db33c77dSCarlo Caione hdev->name); 478db33c77dSCarlo Caione kfree_skb(skb); 479db33c77dSCarlo Caione return ERR_PTR(-EIO); 480db33c77dSCarlo Caione } 481db33c77dSCarlo Caione 482db33c77dSCarlo Caione return skb; 483db33c77dSCarlo Caione } 484db33c77dSCarlo Caione 485db33c77dSCarlo Caione int btrtl_setup_realtek(struct hci_dev *hdev) 486db33c77dSCarlo Caione { 487db33c77dSCarlo Caione struct sk_buff *skb; 488db33c77dSCarlo Caione struct hci_rp_read_local_version *resp; 489*907f8499SAlex Lu u16 hci_rev, lmp_subver; 490db33c77dSCarlo Caione 491db33c77dSCarlo Caione skb = btrtl_read_local_version(hdev); 492db33c77dSCarlo Caione if (IS_ERR(skb)) 493db33c77dSCarlo Caione return -PTR_ERR(skb); 494db33c77dSCarlo Caione 495db33c77dSCarlo Caione resp = (struct hci_rp_read_local_version *)skb->data; 4962064ee33SMarcel Holtmann bt_dev_info(hdev, "rtl: examining hci_ver=%02x hci_rev=%04x " 4972064ee33SMarcel Holtmann "lmp_ver=%02x lmp_subver=%04x", 4982064ee33SMarcel Holtmann resp->hci_ver, resp->hci_rev, 499db33c77dSCarlo Caione resp->lmp_ver, resp->lmp_subver); 500db33c77dSCarlo Caione 501*907f8499SAlex Lu hci_rev = le16_to_cpu(resp->hci_rev); 502db33c77dSCarlo Caione lmp_subver = le16_to_cpu(resp->lmp_subver); 503db33c77dSCarlo Caione kfree_skb(skb); 504db33c77dSCarlo Caione 505db33c77dSCarlo Caione /* Match a set of subver values that correspond to stock firmware, 506db33c77dSCarlo Caione * which is not compatible with standard btusb. 507db33c77dSCarlo Caione * If matched, upload an alternative firmware that does conform to 508db33c77dSCarlo Caione * standard btusb. Once that firmware is uploaded, the subver changes 509db33c77dSCarlo Caione * to a different value. 510db33c77dSCarlo Caione */ 511db33c77dSCarlo Caione switch (lmp_subver) { 512db33c77dSCarlo Caione case RTL_ROM_LMP_8723A: 513db33c77dSCarlo Caione case RTL_ROM_LMP_3499: 514db33c77dSCarlo Caione return btrtl_setup_rtl8723a(hdev); 515db33c77dSCarlo Caione case RTL_ROM_LMP_8723B: 516db33c77dSCarlo Caione case RTL_ROM_LMP_8821A: 517db33c77dSCarlo Caione case RTL_ROM_LMP_8761A: 5181110a2dbSLarry Finger case RTL_ROM_LMP_8822B: 519*907f8499SAlex Lu return btrtl_setup_rtl8723b(hdev, hci_rev, lmp_subver); 520db33c77dSCarlo Caione default: 5212064ee33SMarcel Holtmann bt_dev_info(hdev, "rtl: assuming no firmware upload needed"); 522db33c77dSCarlo Caione return 0; 523db33c77dSCarlo Caione } 524db33c77dSCarlo Caione } 525db33c77dSCarlo Caione EXPORT_SYMBOL_GPL(btrtl_setup_realtek); 526db33c77dSCarlo Caione 527db33c77dSCarlo Caione MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>"); 528db33c77dSCarlo Caione MODULE_DESCRIPTION("Bluetooth support for Realtek devices ver " VERSION); 529db33c77dSCarlo Caione MODULE_VERSION(VERSION); 530db33c77dSCarlo Caione MODULE_LICENSE("GPL"); 531