aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Blumenstingl <martin.blumenstingl@googlemail.com>2018-08-02 10:57:13 -0400
committerMarcel Holtmann <marcel@holtmann.org>2018-08-03 07:27:46 -0400
commit26503ad25de8c7c93a2037f919c2e49a62cf65f1 (patch)
treea865ea0478c026862822a78e35dbc46113b3b361
parentf96dbd322a8f1368dc663c48c7dc3c66a086ec9f (diff)
Bluetooth: btrtl: split the device initialization into smaller parts
This prepares the btrtl code so it can be used to initialize Bluetooth modules connected via UART (these are found for example on the RTL8723BS and RTL8723DS SDIO chips, which come with an embedded UART Bluetooth module). The Realtek "rtl8723bs_bt" and "rtl8723ds_bt" userspace Bluetooth UART initialization tools (rtk_hciattach) use the following sequence: 1) send H5 sync pattern (already supported by hci_h5) 2) get LMP version (already supported by btrtl) 3) get ROM version (already supported by btrtl) 4) load the firmware and config for the current chipset (already supported by btrtl) 5) read UART settings from the config blob (currently not supported) 6) send UART settings via a vendor command to the device (which changes the baudrate of the device and enables or disables flow control depending on the config) 7) change the baudrate and flow control settings on the host 8) send the firmware and config blob to the device (already supported by btrtl) The main reason why the initialization has to be split is step #7. This requires changes to the underlying "bus", which should be kept outside of the "generic" btrtl driver. The idea for this split is borrowed from the btbcm driver but adjusted where needed (the btrtl driver for example needs two blobs: firmware and config, while the btbcm only needs one). This also prepares the code for step #5 (parsing the config blob) by centralizing the code which loads the firmware and config blobs and storing the result in the new struct btrtl_device_info. Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com> Signed-off-by: Jeremy Cline <jeremy@jcline.org> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--drivers/bluetooth/btrtl.c279
-rw-r--r--drivers/bluetooth/btrtl.h26
2 files changed, 199 insertions, 106 deletions
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index c08f63e3bc14..bb6c138b47cc 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -47,48 +47,96 @@ struct id_table {
47 __u16 lmp_subver; 47 __u16 lmp_subver;
48 __u16 hci_rev; 48 __u16 hci_rev;
49 bool config_needed; 49 bool config_needed;
50 bool has_rom_version;
50 char *fw_name; 51 char *fw_name;
51 char *cfg_name; 52 char *cfg_name;
52}; 53};
53 54
55struct btrtl_device_info {
56 const struct id_table *ic_info;
57 u8 rom_version;
58 u8 *fw_data;
59 int fw_len;
60 u8 *cfg_data;
61 int cfg_len;
62};
63
54static const struct id_table ic_id_table[] = { 64static const struct id_table ic_id_table[] = {
65 { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8723A, 0x0,
66 .config_needed = false,
67 .has_rom_version = false,
68 .fw_name = "rtl_bt/rtl8723a_fw.bin",
69 .cfg_name = NULL },
70
71 { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_3499, 0x0,
72 .config_needed = false,
73 .has_rom_version = false,
74 .fw_name = "rtl_bt/rtl8723a_fw.bin",
75 .cfg_name = NULL },
76
55 /* 8723B */ 77 /* 8723B */
56 { IC_INFO(RTL_ROM_LMP_8723B, 0xb), 78 { IC_INFO(RTL_ROM_LMP_8723B, 0xb),
57 .config_needed = false, 79 .config_needed = false,
80 .has_rom_version = true,
58 .fw_name = "rtl_bt/rtl8723b_fw.bin", 81 .fw_name = "rtl_bt/rtl8723b_fw.bin",
59 .cfg_name = "rtl_bt/rtl8723b_config.bin" }, 82 .cfg_name = "rtl_bt/rtl8723b_config.bin" },
60 83
61 /* 8723D */ 84 /* 8723D */
62 { IC_INFO(RTL_ROM_LMP_8723B, 0xd), 85 { IC_INFO(RTL_ROM_LMP_8723B, 0xd),
63 .config_needed = true, 86 .config_needed = true,
87 .has_rom_version = true,
64 .fw_name = "rtl_bt/rtl8723d_fw.bin", 88 .fw_name = "rtl_bt/rtl8723d_fw.bin",
65 .cfg_name = "rtl_bt/rtl8723d_config.bin" }, 89 .cfg_name = "rtl_bt/rtl8723d_config.bin" },
66 90
67 /* 8821A */ 91 /* 8821A */
68 { IC_INFO(RTL_ROM_LMP_8821A, 0xa), 92 { IC_INFO(RTL_ROM_LMP_8821A, 0xa),
69 .config_needed = false, 93 .config_needed = false,
94 .has_rom_version = true,
70 .fw_name = "rtl_bt/rtl8821a_fw.bin", 95 .fw_name = "rtl_bt/rtl8821a_fw.bin",
71 .cfg_name = "rtl_bt/rtl8821a_config.bin" }, 96 .cfg_name = "rtl_bt/rtl8821a_config.bin" },
72 97
73 /* 8821C */ 98 /* 8821C */
74 { IC_INFO(RTL_ROM_LMP_8821A, 0xc), 99 { IC_INFO(RTL_ROM_LMP_8821A, 0xc),
75 .config_needed = false, 100 .config_needed = false,
101 .has_rom_version = true,
76 .fw_name = "rtl_bt/rtl8821c_fw.bin", 102 .fw_name = "rtl_bt/rtl8821c_fw.bin",
77 .cfg_name = "rtl_bt/rtl8821c_config.bin" }, 103 .cfg_name = "rtl_bt/rtl8821c_config.bin" },
78 104
79 /* 8761A */ 105 /* 8761A */
80 { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0, 106 { IC_MATCH_FL_LMPSUBV, RTL_ROM_LMP_8761A, 0x0,
81 .config_needed = false, 107 .config_needed = false,
108 .has_rom_version = true,
82 .fw_name = "rtl_bt/rtl8761a_fw.bin", 109 .fw_name = "rtl_bt/rtl8761a_fw.bin",
83 .cfg_name = "rtl_bt/rtl8761a_config.bin" }, 110 .cfg_name = "rtl_bt/rtl8761a_config.bin" },
84 111
85 /* 8822B */ 112 /* 8822B */
86 { IC_INFO(RTL_ROM_LMP_8822B, 0xb), 113 { IC_INFO(RTL_ROM_LMP_8822B, 0xb),
87 .config_needed = true, 114 .config_needed = true,
115 .has_rom_version = true,
88 .fw_name = "rtl_bt/rtl8822b_fw.bin", 116 .fw_name = "rtl_bt/rtl8822b_fw.bin",
89 .cfg_name = "rtl_bt/rtl8822b_config.bin" }, 117 .cfg_name = "rtl_bt/rtl8822b_config.bin" },
90 }; 118 };
91 119
120static const struct id_table *btrtl_match_ic(u16 lmp_subver, u16 hci_rev)
121{
122 int i;
123
124 for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) {
125 if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) &&
126 (ic_id_table[i].lmp_subver != lmp_subver))
127 continue;
128 if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) &&
129 (ic_id_table[i].hci_rev != hci_rev))
130 continue;
131
132 break;
133 }
134 if (i >= ARRAY_SIZE(ic_id_table))
135 return NULL;
136
137 return &ic_id_table[i];
138}
139
92static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) 140static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
93{ 141{
94 struct rtl_rom_version_evt *rom_version; 142 struct rtl_rom_version_evt *rom_version;
@@ -118,16 +166,16 @@ static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
118 return 0; 166 return 0;
119} 167}
120 168
121static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver, 169static int rtlbt_parse_firmware(struct hci_dev *hdev,
122 const struct firmware *fw, 170 struct btrtl_device_info *btrtl_dev,
123 unsigned char **_buf) 171 unsigned char **_buf)
124{ 172{
125 const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 }; 173 const u8 extension_sig[] = { 0x51, 0x04, 0xfd, 0x77 };
126 struct rtl_epatch_header *epatch_info; 174 struct rtl_epatch_header *epatch_info;
127 unsigned char *buf; 175 unsigned char *buf;
128 int i, ret, len; 176 int i, len;
129 size_t min_size; 177 size_t min_size;
130 u8 opcode, length, data, rom_version = 0; 178 u8 opcode, length, data;
131 int project_id = -1; 179 int project_id = -1;
132 const unsigned char *fwptr, *chip_id_base; 180 const unsigned char *fwptr, *chip_id_base;
133 const unsigned char *patch_length_base, *patch_offset_base; 181 const unsigned char *patch_length_base, *patch_offset_base;
@@ -146,15 +194,11 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
146 { RTL_ROM_LMP_8821A, 10 }, /* 8821C */ 194 { RTL_ROM_LMP_8821A, 10 }, /* 8821C */
147 }; 195 };
148 196
149 ret = rtl_read_rom_version(hdev, &rom_version);
150 if (ret)
151 return ret;
152
153 min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3; 197 min_size = sizeof(struct rtl_epatch_header) + sizeof(extension_sig) + 3;
154 if (fw->size < min_size) 198 if (btrtl_dev->fw_len < min_size)
155 return -EINVAL; 199 return -EINVAL;
156 200
157 fwptr = fw->data + fw->size - sizeof(extension_sig); 201 fwptr = btrtl_dev->fw_data + btrtl_dev->fw_len - sizeof(extension_sig);
158 if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) { 202 if (memcmp(fwptr, extension_sig, sizeof(extension_sig)) != 0) {
159 BT_ERR("%s: extension section signature mismatch", hdev->name); 203 BT_ERR("%s: extension section signature mismatch", hdev->name);
160 return -EINVAL; 204 return -EINVAL;
@@ -166,7 +210,7 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
166 * Once we have that, we double-check that that project_id is suitable 210 * Once we have that, we double-check that that project_id is suitable
167 * for the hardware we are working with. 211 * for the hardware we are working with.
168 */ 212 */
169 while (fwptr >= fw->data + (sizeof(struct rtl_epatch_header) + 3)) { 213 while (fwptr >= btrtl_dev->fw_data + (sizeof(*epatch_info) + 3)) {
170 opcode = *--fwptr; 214 opcode = *--fwptr;
171 length = *--fwptr; 215 length = *--fwptr;
172 data = *--fwptr; 216 data = *--fwptr;
@@ -206,13 +250,15 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
206 return -EINVAL; 250 return -EINVAL;
207 } 251 }
208 252
209 if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) { 253 if (btrtl_dev->ic_info->lmp_subver !=
254 project_id_to_lmp_subver[i].lmp_subver) {
210 BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, 255 BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
211 project_id_to_lmp_subver[i].lmp_subver, lmp_subver); 256 project_id_to_lmp_subver[i].lmp_subver,
257 btrtl_dev->ic_info->lmp_subver);
212 return -EINVAL; 258 return -EINVAL;
213 } 259 }
214 260
215 epatch_info = (struct rtl_epatch_header *)fw->data; 261 epatch_info = (struct rtl_epatch_header *)btrtl_dev->fw_data;
216 if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) { 262 if (memcmp(epatch_info->signature, RTL_EPATCH_SIGNATURE, 8) != 0) {
217 BT_ERR("%s: bad EPATCH signature", hdev->name); 263 BT_ERR("%s: bad EPATCH signature", hdev->name);
218 return -EINVAL; 264 return -EINVAL;
@@ -229,16 +275,16 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
229 * Find the right patch for this chip. 275 * Find the right patch for this chip.
230 */ 276 */
231 min_size += 8 * num_patches; 277 min_size += 8 * num_patches;
232 if (fw->size < min_size) 278 if (btrtl_dev->fw_len < min_size)
233 return -EINVAL; 279 return -EINVAL;
234 280
235 chip_id_base = fw->data + sizeof(struct rtl_epatch_header); 281 chip_id_base = btrtl_dev->fw_data + sizeof(struct rtl_epatch_header);
236 patch_length_base = chip_id_base + (sizeof(u16) * num_patches); 282 patch_length_base = chip_id_base + (sizeof(u16) * num_patches);
237 patch_offset_base = patch_length_base + (sizeof(u16) * num_patches); 283 patch_offset_base = patch_length_base + (sizeof(u16) * num_patches);
238 for (i = 0; i < num_patches; i++) { 284 for (i = 0; i < num_patches; i++) {
239 u16 chip_id = get_unaligned_le16(chip_id_base + 285 u16 chip_id = get_unaligned_le16(chip_id_base +
240 (i * sizeof(u16))); 286 (i * sizeof(u16)));
241 if (chip_id == rom_version + 1) { 287 if (chip_id == btrtl_dev->rom_version + 1) {
242 patch_length = get_unaligned_le16(patch_length_base + 288 patch_length = get_unaligned_le16(patch_length_base +
243 (i * sizeof(u16))); 289 (i * sizeof(u16)));
244 patch_offset = get_unaligned_le32(patch_offset_base + 290 patch_offset = get_unaligned_le32(patch_offset_base +
@@ -249,20 +295,21 @@ static int rtlbt_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
249 295
250 if (!patch_offset) { 296 if (!patch_offset) {
251 BT_ERR("%s: didn't find patch for chip id %d", 297 BT_ERR("%s: didn't find patch for chip id %d",
252 hdev->name, rom_version); 298 hdev->name, btrtl_dev->rom_version);
253 return -EINVAL; 299 return -EINVAL;
254 } 300 }
255 301
256 BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i); 302 BT_DBG("length=%x offset=%x index %d", patch_length, patch_offset, i);
257 min_size = patch_offset + patch_length; 303 min_size = patch_offset + patch_length;
258 if (fw->size < min_size) 304 if (btrtl_dev->fw_len < min_size)
259 return -EINVAL; 305 return -EINVAL;
260 306
261 /* Copy the firmware into a new buffer and write the version at 307 /* Copy the firmware into a new buffer and write the version at
262 * the end. 308 * the end.
263 */ 309 */
264 len = patch_length; 310 len = patch_length;
265 buf = kmemdup(fw->data + patch_offset, patch_length, GFP_KERNEL); 311 buf = kmemdup(btrtl_dev->fw_data + patch_offset, patch_length,
312 GFP_KERNEL);
266 if (!buf) 313 if (!buf)
267 return -ENOMEM; 314 return -ENOMEM;
268 315
@@ -324,7 +371,7 @@ out:
324 return ret; 371 return ret;
325} 372}
326 373
327static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) 374static int rtl_load_file(struct hci_dev *hdev, const char *name, u8 **buff)
328{ 375{
329 const struct firmware *fw; 376 const struct firmware *fw;
330 int ret; 377 int ret;
@@ -343,96 +390,37 @@ static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff)
343 return ret; 390 return ret;
344} 391}
345 392
346static int btrtl_setup_rtl8723a(struct hci_dev *hdev) 393static int btrtl_setup_rtl8723a(struct hci_dev *hdev,
394 struct btrtl_device_info *btrtl_dev)
347{ 395{
348 const struct firmware *fw; 396 if (btrtl_dev->fw_len < 8)
349 int ret; 397 return -EINVAL;
350
351 bt_dev_info(hdev, "rtl: loading rtl_bt/rtl8723a_fw.bin");
352 ret = request_firmware(&fw, "rtl_bt/rtl8723a_fw.bin", &hdev->dev);
353 if (ret < 0) {
354 BT_ERR("%s: Failed to load rtl_bt/rtl8723a_fw.bin", hdev->name);
355 return ret;
356 }
357
358 if (fw->size < 8) {
359 ret = -EINVAL;
360 goto out;
361 }
362 398
363 /* Check that the firmware doesn't have the epatch signature 399 /* Check that the firmware doesn't have the epatch signature
364 * (which is only for RTL8723B and newer). 400 * (which is only for RTL8723B and newer).
365 */ 401 */
366 if (!memcmp(fw->data, RTL_EPATCH_SIGNATURE, 8)) { 402 if (!memcmp(btrtl_dev->fw_data, RTL_EPATCH_SIGNATURE, 8)) {
367 BT_ERR("%s: unexpected EPATCH signature!", hdev->name); 403 BT_ERR("%s: unexpected EPATCH signature!", hdev->name);
368 ret = -EINVAL; 404 return -EINVAL;
369 goto out;
370 } 405 }
371 406
372 ret = rtl_download_firmware(hdev, fw->data, fw->size); 407 return rtl_download_firmware(hdev, btrtl_dev->fw_data,
373 408 btrtl_dev->fw_len);
374out:
375 release_firmware(fw);
376 return ret;
377} 409}
378 410
379static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev, 411static int btrtl_setup_rtl8723b(struct hci_dev *hdev,
380 u16 lmp_subver) 412 struct btrtl_device_info *btrtl_dev)
381{ 413{
382 unsigned char *fw_data = NULL; 414 unsigned char *fw_data = NULL;
383 const struct firmware *fw;
384 int ret; 415 int ret;
385 int cfg_sz;
386 u8 *cfg_buff = NULL;
387 u8 *tbuff; 416 u8 *tbuff;
388 char *cfg_name = NULL;
389 char *fw_name = NULL;
390 int i;
391
392 for (i = 0; i < ARRAY_SIZE(ic_id_table); i++) {
393 if ((ic_id_table[i].match_flags & IC_MATCH_FL_LMPSUBV) &&
394 (ic_id_table[i].lmp_subver != lmp_subver))
395 continue;
396 if ((ic_id_table[i].match_flags & IC_MATCH_FL_HCIREV) &&
397 (ic_id_table[i].hci_rev != hci_rev))
398 continue;
399
400 break;
401 }
402
403 if (i >= ARRAY_SIZE(ic_id_table)) {
404 BT_ERR("%s: unknown IC info, lmp subver %04x, hci rev %04x",
405 hdev->name, lmp_subver, hci_rev);
406 return -EINVAL;
407 }
408
409 cfg_name = ic_id_table[i].cfg_name;
410
411 if (cfg_name) {
412 cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
413 if (cfg_sz < 0) {
414 cfg_sz = 0;
415 if (ic_id_table[i].config_needed)
416 BT_ERR("Necessary config file %s not found\n",
417 cfg_name);
418 }
419 } else
420 cfg_sz = 0;
421
422 fw_name = ic_id_table[i].fw_name;
423 bt_dev_info(hdev, "rtl: loading %s", fw_name);
424 ret = request_firmware(&fw, fw_name, &hdev->dev);
425 if (ret < 0) {
426 BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
427 goto err_req_fw;
428 }
429 417
430 ret = rtlbt_parse_firmware(hdev, lmp_subver, fw, &fw_data); 418 ret = rtlbt_parse_firmware(hdev, btrtl_dev, &fw_data);
431 if (ret < 0) 419 if (ret < 0)
432 goto out; 420 goto out;
433 421
434 if (cfg_sz) { 422 if (btrtl_dev->cfg_len > 0) {
435 tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL); 423 tbuff = kzalloc(ret + btrtl_dev->cfg_len, GFP_KERNEL);
436 if (!tbuff) { 424 if (!tbuff) {
437 ret = -ENOMEM; 425 ret = -ENOMEM;
438 goto out; 426 goto out;
@@ -441,22 +429,18 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 hci_rev,
441 memcpy(tbuff, fw_data, ret); 429 memcpy(tbuff, fw_data, ret);
442 kfree(fw_data); 430 kfree(fw_data);
443 431
444 memcpy(tbuff + ret, cfg_buff, cfg_sz); 432 memcpy(tbuff + ret, btrtl_dev->cfg_data, btrtl_dev->cfg_len);
445 ret += cfg_sz; 433 ret += btrtl_dev->cfg_len;
446 434
447 fw_data = tbuff; 435 fw_data = tbuff;
448 } 436 }
449 437
450 bt_dev_info(hdev, "cfg_sz %d, total size %d", cfg_sz, ret); 438 rtl_dev_info(hdev, "cfg_sz %d, total sz %d\n", btrtl_dev->cfg_len, ret);
451 439
452 ret = rtl_download_firmware(hdev, fw_data, ret); 440 ret = rtl_download_firmware(hdev, fw_data, ret);
453 441
454out: 442out:
455 release_firmware(fw);
456 kfree(fw_data); 443 kfree(fw_data);
457err_req_fw:
458 if (cfg_sz)
459 kfree(cfg_buff);
460 return ret; 444 return ret;
461} 445}
462 446
@@ -482,15 +466,33 @@ static struct sk_buff *btrtl_read_local_version(struct hci_dev *hdev)
482 return skb; 466 return skb;
483} 467}
484 468
485int btrtl_setup_realtek(struct hci_dev *hdev) 469void btrtl_free(struct btrtl_device_info *btrtl_dev)
470{
471 kfree(btrtl_dev->fw_data);
472 kfree(btrtl_dev->cfg_data);
473 kfree(btrtl_dev);
474}
475EXPORT_SYMBOL_GPL(btrtl_free);
476
477struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev)
486{ 478{
479 struct btrtl_device_info *btrtl_dev;
487 struct sk_buff *skb; 480 struct sk_buff *skb;
488 struct hci_rp_read_local_version *resp; 481 struct hci_rp_read_local_version *resp;
489 u16 hci_rev, lmp_subver; 482 u16 hci_rev, lmp_subver;
483 int ret;
484
485 btrtl_dev = kzalloc(sizeof(*btrtl_dev), GFP_KERNEL);
486 if (!btrtl_dev) {
487 ret = -ENOMEM;
488 goto err_alloc;
489 }
490 490
491 skb = btrtl_read_local_version(hdev); 491 skb = btrtl_read_local_version(hdev);
492 if (IS_ERR(skb)) 492 if (IS_ERR(skb)) {
493 return -PTR_ERR(skb); 493 ret = PTR_ERR(skb);
494 goto err_free;
495 }
494 496
495 resp = (struct hci_rp_read_local_version *)skb->data; 497 resp = (struct hci_rp_read_local_version *)skb->data;
496 bt_dev_info(hdev, "rtl: examining hci_ver=%02x hci_rev=%04x " 498 bt_dev_info(hdev, "rtl: examining hci_ver=%02x hci_rev=%04x "
@@ -502,26 +504,91 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
502 lmp_subver = le16_to_cpu(resp->lmp_subver); 504 lmp_subver = le16_to_cpu(resp->lmp_subver);
503 kfree_skb(skb); 505 kfree_skb(skb);
504 506
507 btrtl_dev->ic_info = btrtl_match_ic(lmp_subver, hci_rev);
508 if (!btrtl_dev->ic_info) {
509 rtl_dev_err(hdev, "unknown IC info, lmp subver %04x, hci rev %04x\n",
510 lmp_subver, hci_rev);
511 ret = -EINVAL;
512 goto err_free;
513 }
514
515 if (btrtl_dev->ic_info->has_rom_version) {
516 ret = rtl_read_rom_version(hdev, &btrtl_dev->rom_version);
517 if (ret)
518 goto err_free;
519 }
520
521 btrtl_dev->fw_len = rtl_load_file(hdev, btrtl_dev->ic_info->fw_name,
522 &btrtl_dev->fw_data);
523 if (btrtl_dev->fw_len < 0) {
524 rtl_dev_err(hdev, "firmware file %s not found\n",
525 btrtl_dev->ic_info->fw_name);
526 ret = btrtl_dev->fw_len;
527 goto err_free;
528 }
529
530 if (btrtl_dev->ic_info->cfg_name) {
531 btrtl_dev->cfg_len = rtl_load_file(hdev,
532 btrtl_dev->ic_info->cfg_name,
533 &btrtl_dev->cfg_data);
534 if (btrtl_dev->ic_info->config_needed &&
535 btrtl_dev->cfg_len <= 0) {
536 rtl_dev_err(hdev, "mandatory config file %s not found\n",
537 btrtl_dev->ic_info->cfg_name);
538 ret = btrtl_dev->cfg_len;
539 goto err_free;
540 }
541 }
542
543 return btrtl_dev;
544
545err_free:
546 btrtl_free(btrtl_dev);
547err_alloc:
548 return ERR_PTR(ret);
549}
550EXPORT_SYMBOL_GPL(btrtl_initialize);
551
552int btrtl_download_firmware(struct hci_dev *hdev,
553 struct btrtl_device_info *btrtl_dev)
554{
505 /* Match a set of subver values that correspond to stock firmware, 555 /* Match a set of subver values that correspond to stock firmware,
506 * which is not compatible with standard btusb. 556 * which is not compatible with standard btusb.
507 * If matched, upload an alternative firmware that does conform to 557 * If matched, upload an alternative firmware that does conform to
508 * standard btusb. Once that firmware is uploaded, the subver changes 558 * standard btusb. Once that firmware is uploaded, the subver changes
509 * to a different value. 559 * to a different value.
510 */ 560 */
511 switch (lmp_subver) { 561 switch (btrtl_dev->ic_info->lmp_subver) {
512 case RTL_ROM_LMP_8723A: 562 case RTL_ROM_LMP_8723A:
513 case RTL_ROM_LMP_3499: 563 case RTL_ROM_LMP_3499:
514 return btrtl_setup_rtl8723a(hdev); 564 return btrtl_setup_rtl8723a(hdev, btrtl_dev);
515 case RTL_ROM_LMP_8723B: 565 case RTL_ROM_LMP_8723B:
516 case RTL_ROM_LMP_8821A: 566 case RTL_ROM_LMP_8821A:
517 case RTL_ROM_LMP_8761A: 567 case RTL_ROM_LMP_8761A:
518 case RTL_ROM_LMP_8822B: 568 case RTL_ROM_LMP_8822B:
519 return btrtl_setup_rtl8723b(hdev, hci_rev, lmp_subver); 569 return btrtl_setup_rtl8723b(hdev, btrtl_dev);
520 default: 570 default:
521 bt_dev_info(hdev, "rtl: assuming no firmware upload needed"); 571 bt_dev_info(hdev, "rtl: assuming no firmware upload needed");
522 return 0; 572 return 0;
523 } 573 }
524} 574}
575EXPORT_SYMBOL_GPL(btrtl_download_firmware);
576
577int btrtl_setup_realtek(struct hci_dev *hdev)
578{
579 struct btrtl_device_info *btrtl_dev;
580 int ret;
581
582 btrtl_dev = btrtl_initialize(hdev);
583 if (IS_ERR(btrtl_dev))
584 return PTR_ERR(btrtl_dev);
585
586 ret = btrtl_download_firmware(hdev, btrtl_dev);
587
588 btrtl_free(btrtl_dev);
589
590 return ret;
591}
525EXPORT_SYMBOL_GPL(btrtl_setup_realtek); 592EXPORT_SYMBOL_GPL(btrtl_setup_realtek);
526 593
527MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>"); 594MODULE_AUTHOR("Daniel Drake <drake@endlessm.com>");
diff --git a/drivers/bluetooth/btrtl.h b/drivers/bluetooth/btrtl.h
index 38ffe4890cd1..e41974f8af40 100644
--- a/drivers/bluetooth/btrtl.h
+++ b/drivers/bluetooth/btrtl.h
@@ -17,6 +17,13 @@
17 17
18#define RTL_FRAG_LEN 252 18#define RTL_FRAG_LEN 252
19 19
20#define rtl_dev_err(dev, fmt, ...) bt_dev_err(dev, "RTL: " fmt, ##__VA_ARGS__)
21#define rtl_dev_warn(dev, fmt, ...) bt_dev_warn(dev, "RTL: " fmt, ##__VA_ARGS__)
22#define rtl_dev_info(dev, fmt, ...) bt_dev_info(dev, "RTL: " fmt, ##__VA_ARGS__)
23#define rtl_dev_dbg(dev, fmt, ...) bt_dev_dbg(dev, "RTL: " fmt, ##__VA_ARGS__)
24
25struct btrtl_device_info;
26
20struct rtl_download_cmd { 27struct rtl_download_cmd {
21 __u8 index; 28 __u8 index;
22 __u8 data[RTL_FRAG_LEN]; 29 __u8 data[RTL_FRAG_LEN];
@@ -40,10 +47,29 @@ struct rtl_epatch_header {
40 47
41#if IS_ENABLED(CONFIG_BT_RTL) 48#if IS_ENABLED(CONFIG_BT_RTL)
42 49
50struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev);
51void btrtl_free(struct btrtl_device_info *btrtl_dev);
52int btrtl_download_firmware(struct hci_dev *hdev,
53 struct btrtl_device_info *btrtl_dev);
43int btrtl_setup_realtek(struct hci_dev *hdev); 54int btrtl_setup_realtek(struct hci_dev *hdev);
44 55
45#else 56#else
46 57
58static inline struct btrtl_device_info *btrtl_initialize(struct hci_dev *hdev)
59{
60 return ERR_PTR(-EOPNOTSUPP);
61}
62
63static inline void btrtl_free(struct btrtl_device_info *btrtl_dev)
64{
65}
66
67static inline int btrtl_download_firmware(struct hci_dev *hdev,
68 struct btrtl_device_info *btrtl_dev)
69{
70 return -EOPNOTSUPP;
71}
72
47static inline int btrtl_setup_realtek(struct hci_dev *hdev) 73static inline int btrtl_setup_realtek(struct hci_dev *hdev)
48{ 74{
49 return -EOPNOTSUPP; 75 return -EOPNOTSUPP;