aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLarry Finger <Larry.Finger@lwfinger.net>2016-09-09 11:02:05 -0400
committerMarcel Holtmann <marcel@holtmann.org>2016-09-19 14:19:34 -0400
commit1110a2dbe69831abdcf119c3a9a4c4ef2d0905f8 (patch)
tree893ef264aa26af5488d6cd6056d239889b198e60
parent83ebb9ec734e9e768a9fae469e4a7ed1762ef43a (diff)
Bluetooth: btrtl: Add RTL8822BE Bluetooth device
The RTL8822BE is a new Realtek wifi and BT device. Support for the BT part is hereby added. As this device is similar to most of the other Realtek BT devices, the changes are minimal. The main difference is that the 8822BE needs a configuration file for enabling and disabling features. Thus code is added to select and load this configuration file. Although not needed at the moment, hooks are added for the other devices that might need such configuration files. One additional change is to the routine that tests that the project ID contained in the firmware matches the hardware. As the project IDs are not sequential, continuing to use the position in the array as the expected value of the ID would require adding extra unused entries in the table, and any subsequant rearrangment of the array would break the code. To fix these problems, the array elements now contain both the hardware ID and the expected value for the project ID. Signed-off-by: 陆朱伟 <alex_lu@realsil.com.cn> Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--drivers/bluetooth/btrtl.c107
1 files changed, 95 insertions, 12 deletions
diff --git a/drivers/bluetooth/btrtl.c b/drivers/bluetooth/btrtl.c
index 84288938f7f2..fc9b25703c67 100644
--- a/drivers/bluetooth/btrtl.c
+++ b/drivers/bluetooth/btrtl.c
@@ -33,6 +33,7 @@
33#define RTL_ROM_LMP_8723B 0x8723 33#define RTL_ROM_LMP_8723B 0x8723
34#define RTL_ROM_LMP_8821A 0x8821 34#define RTL_ROM_LMP_8821A 0x8821
35#define RTL_ROM_LMP_8761A 0x8761 35#define RTL_ROM_LMP_8761A 0x8761
36#define RTL_ROM_LMP_8822B 0x8822
36 37
37static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) 38static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version)
38{ 39{
@@ -78,11 +79,15 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
78 const unsigned char *patch_length_base, *patch_offset_base; 79 const unsigned char *patch_length_base, *patch_offset_base;
79 u32 patch_offset = 0; 80 u32 patch_offset = 0;
80 u16 patch_length, num_patches; 81 u16 patch_length, num_patches;
81 const u16 project_id_to_lmp_subver[] = { 82 static const struct {
82 RTL_ROM_LMP_8723A, 83 __u16 lmp_subver;
83 RTL_ROM_LMP_8723B, 84 __u8 id;
84 RTL_ROM_LMP_8821A, 85 } project_id_to_lmp_subver[] = {
85 RTL_ROM_LMP_8761A 86 { RTL_ROM_LMP_8723A, 0 },
87 { RTL_ROM_LMP_8723B, 1 },
88 { RTL_ROM_LMP_8821A, 2 },
89 { RTL_ROM_LMP_8761A, 3 },
90 { RTL_ROM_LMP_8822B, 8 },
86 }; 91 };
87 92
88 ret = rtl_read_rom_version(hdev, &rom_version); 93 ret = rtl_read_rom_version(hdev, &rom_version);
@@ -134,14 +139,20 @@ static int rtl8723b_parse_firmware(struct hci_dev *hdev, u16 lmp_subver,
134 return -EINVAL; 139 return -EINVAL;
135 } 140 }
136 141
137 if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { 142 /* Find project_id in table */
143 for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) {
144 if (project_id == project_id_to_lmp_subver[i].id)
145 break;
146 }
147
148 if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) {
138 BT_ERR("%s: unknown project id %d", hdev->name, project_id); 149 BT_ERR("%s: unknown project id %d", hdev->name, project_id);
139 return -EINVAL; 150 return -EINVAL;
140 } 151 }
141 152
142 if (lmp_subver != project_id_to_lmp_subver[project_id]) { 153 if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) {
143 BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, 154 BT_ERR("%s: firmware is for %x but this is a %x", hdev->name,
144 project_id_to_lmp_subver[project_id], lmp_subver); 155 project_id_to_lmp_subver[i].lmp_subver, lmp_subver);
145 return -EINVAL; 156 return -EINVAL;
146 } 157 }
147 158
@@ -257,6 +268,26 @@ out:
257 return ret; 268 return ret;
258} 269}
259 270
271static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff)
272{
273 const struct firmware *fw;
274 int ret;
275
276 BT_INFO("%s: rtl: loading %s", hdev->name, name);
277 ret = request_firmware(&fw, name, &hdev->dev);
278 if (ret < 0) {
279 BT_ERR("%s: Failed to load %s", hdev->name, name);
280 return ret;
281 }
282
283 ret = fw->size;
284 *buff = kmemdup(fw->data, ret, GFP_KERNEL);
285
286 release_firmware(fw);
287
288 return ret;
289}
290
260static int btrtl_setup_rtl8723a(struct hci_dev *hdev) 291static int btrtl_setup_rtl8723a(struct hci_dev *hdev)
261{ 292{
262 const struct firmware *fw; 293 const struct firmware *fw;
@@ -296,25 +327,74 @@ static int btrtl_setup_rtl8723b(struct hci_dev *hdev, u16 lmp_subver,
296 unsigned char *fw_data = NULL; 327 unsigned char *fw_data = NULL;
297 const struct firmware *fw; 328 const struct firmware *fw;
298 int ret; 329 int ret;
330 int cfg_sz;
331 u8 *cfg_buff = NULL;
332 u8 *tbuff;
333 char *cfg_name = NULL;
334
335 switch (lmp_subver) {
336 case RTL_ROM_LMP_8723B:
337 cfg_name = "rtl_bt/rtl8723b_config.bin";
338 break;
339 case RTL_ROM_LMP_8821A:
340 cfg_name = "rtl_bt/rtl8821a_config.bin";
341 break;
342 case RTL_ROM_LMP_8761A:
343 cfg_name = "rtl_bt/rtl8761a_config.bin";
344 break;
345 case RTL_ROM_LMP_8822B:
346 cfg_name = "rtl_bt/rtl8822b_config.bin";
347 break;
348 default:
349 BT_ERR("%s: rtl: no config according to lmp_subver %04x",
350 hdev->name, lmp_subver);
351 break;
352 }
353
354 if (cfg_name) {
355 cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff);
356 if (cfg_sz < 0)
357 cfg_sz = 0;
358 } else
359 cfg_sz = 0;
299 360
300 BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); 361 BT_INFO("%s: rtl: loading %s", hdev->name, fw_name);
301 ret = request_firmware(&fw, fw_name, &hdev->dev); 362 ret = request_firmware(&fw, fw_name, &hdev->dev);
302 if (ret < 0) { 363 if (ret < 0) {
303 BT_ERR("%s: Failed to load %s", hdev->name, fw_name); 364 BT_ERR("%s: Failed to load %s", hdev->name, fw_name);
304 return ret; 365 goto err_req_fw;
305 } 366 }
306 367
307 ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); 368 ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data);
308 if (ret < 0) 369 if (ret < 0)
309 goto out; 370 goto out;
310 371
372 if (cfg_sz) {
373 tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL);
374 if (!tbuff) {
375 ret = -ENOMEM;
376 goto out;
377 }
378
379 memcpy(tbuff, fw_data, ret);
380 kfree(fw_data);
381
382 memcpy(tbuff + ret, cfg_buff, cfg_sz);
383 ret += cfg_sz;
384
385 fw_data = tbuff;
386 }
387
388 BT_INFO("cfg_sz %d, total size %d", cfg_sz, ret);
389
311 ret = rtl_download_firmware(hdev, fw_data, ret); 390 ret = rtl_download_firmware(hdev, fw_data, ret);
312 kfree(fw_data);
313 if (ret < 0)
314 goto out;
315 391
316out: 392out:
317 release_firmware(fw); 393 release_firmware(fw);
394 kfree(fw_data);
395err_req_fw:
396 if (cfg_sz)
397 kfree(cfg_buff);
318 return ret; 398 return ret;
319} 399}
320 400
@@ -377,6 +457,9 @@ int btrtl_setup_realtek(struct hci_dev *hdev)
377 case RTL_ROM_LMP_8761A: 457 case RTL_ROM_LMP_8761A:
378 return btrtl_setup_rtl8723b(hdev, lmp_subver, 458 return btrtl_setup_rtl8723b(hdev, lmp_subver,
379 "rtl_bt/rtl8761a_fw.bin"); 459 "rtl_bt/rtl8761a_fw.bin");
460 case RTL_ROM_LMP_8822B:
461 return btrtl_setup_rtl8723b(hdev, lmp_subver,
462 "rtl_bt/rtl8822b_fw.bin");
380 default: 463 default:
381 BT_INFO("rtl: assuming no firmware upload needed."); 464 BT_INFO("rtl: assuming no firmware upload needed.");
382 return 0; 465 return 0;