Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Larry Finger and committed by
Marcel Holtmann
1110a2db 83ebb9ec

+95 -12
+95 -12
drivers/bluetooth/btrtl.c
··· 33 33 #define RTL_ROM_LMP_8723B 0x8723 34 34 #define RTL_ROM_LMP_8821A 0x8821 35 35 #define RTL_ROM_LMP_8761A 0x8761 36 + #define RTL_ROM_LMP_8822B 0x8822 36 37 37 38 static int rtl_read_rom_version(struct hci_dev *hdev, u8 *version) 38 39 { ··· 79 78 const unsigned char *patch_length_base, *patch_offset_base; 80 79 u32 patch_offset = 0; 81 80 u16 patch_length, num_patches; 82 - const u16 project_id_to_lmp_subver[] = { 83 - RTL_ROM_LMP_8723A, 84 - RTL_ROM_LMP_8723B, 85 - RTL_ROM_LMP_8821A, 86 - RTL_ROM_LMP_8761A 81 + static const struct { 82 + __u16 lmp_subver; 83 + __u8 id; 84 + } project_id_to_lmp_subver[] = { 85 + { RTL_ROM_LMP_8723A, 0 }, 86 + { RTL_ROM_LMP_8723B, 1 }, 87 + { RTL_ROM_LMP_8821A, 2 }, 88 + { RTL_ROM_LMP_8761A, 3 }, 89 + { RTL_ROM_LMP_8822B, 8 }, 87 90 }; 88 91 89 92 ret = rtl_read_rom_version(hdev, &rom_version); ··· 139 134 return -EINVAL; 140 135 } 141 136 142 - if (project_id >= ARRAY_SIZE(project_id_to_lmp_subver)) { 137 + /* Find project_id in table */ 138 + for (i = 0; i < ARRAY_SIZE(project_id_to_lmp_subver); i++) { 139 + if (project_id == project_id_to_lmp_subver[i].id) 140 + break; 141 + } 142 + 143 + if (i >= ARRAY_SIZE(project_id_to_lmp_subver)) { 143 144 BT_ERR("%s: unknown project id %d", hdev->name, project_id); 144 145 return -EINVAL; 145 146 } 146 147 147 - if (lmp_subver != project_id_to_lmp_subver[project_id]) { 148 + if (lmp_subver != project_id_to_lmp_subver[i].lmp_subver) { 148 149 BT_ERR("%s: firmware is for %x but this is a %x", hdev->name, 149 - project_id_to_lmp_subver[project_id], lmp_subver); 150 + project_id_to_lmp_subver[i].lmp_subver, lmp_subver); 150 151 return -EINVAL; 151 152 } 152 153 ··· 268 257 return ret; 269 258 } 270 259 260 + static int rtl_load_config(struct hci_dev *hdev, const char *name, u8 **buff) 261 + { 262 + const struct firmware *fw; 263 + int ret; 264 + 265 + BT_INFO("%s: rtl: loading %s", hdev->name, name); 266 + ret = request_firmware(&fw, name, &hdev->dev); 267 + if (ret < 0) { 268 + BT_ERR("%s: Failed to load %s", hdev->name, name); 269 + return ret; 270 + } 271 + 272 + ret = fw->size; 273 + *buff = kmemdup(fw->data, ret, GFP_KERNEL); 274 + 275 + release_firmware(fw); 276 + 277 + return ret; 278 + } 279 + 271 280 static int btrtl_setup_rtl8723a(struct hci_dev *hdev) 272 281 { 273 282 const struct firmware *fw; ··· 327 296 unsigned char *fw_data = NULL; 328 297 const struct firmware *fw; 329 298 int ret; 299 + int cfg_sz; 300 + u8 *cfg_buff = NULL; 301 + u8 *tbuff; 302 + char *cfg_name = NULL; 303 + 304 + switch (lmp_subver) { 305 + case RTL_ROM_LMP_8723B: 306 + cfg_name = "rtl_bt/rtl8723b_config.bin"; 307 + break; 308 + case RTL_ROM_LMP_8821A: 309 + cfg_name = "rtl_bt/rtl8821a_config.bin"; 310 + break; 311 + case RTL_ROM_LMP_8761A: 312 + cfg_name = "rtl_bt/rtl8761a_config.bin"; 313 + break; 314 + case RTL_ROM_LMP_8822B: 315 + cfg_name = "rtl_bt/rtl8822b_config.bin"; 316 + break; 317 + default: 318 + BT_ERR("%s: rtl: no config according to lmp_subver %04x", 319 + hdev->name, lmp_subver); 320 + break; 321 + } 322 + 323 + if (cfg_name) { 324 + cfg_sz = rtl_load_config(hdev, cfg_name, &cfg_buff); 325 + if (cfg_sz < 0) 326 + cfg_sz = 0; 327 + } else 328 + cfg_sz = 0; 330 329 331 330 BT_INFO("%s: rtl: loading %s", hdev->name, fw_name); 332 331 ret = request_firmware(&fw, fw_name, &hdev->dev); 333 332 if (ret < 0) { 334 333 BT_ERR("%s: Failed to load %s", hdev->name, fw_name); 335 - return ret; 334 + goto err_req_fw; 336 335 } 337 336 338 337 ret = rtl8723b_parse_firmware(hdev, lmp_subver, fw, &fw_data); 339 338 if (ret < 0) 340 339 goto out; 341 340 341 + if (cfg_sz) { 342 + tbuff = kzalloc(ret + cfg_sz, GFP_KERNEL); 343 + if (!tbuff) { 344 + ret = -ENOMEM; 345 + goto out; 346 + } 347 + 348 + memcpy(tbuff, fw_data, ret); 349 + kfree(fw_data); 350 + 351 + memcpy(tbuff + ret, cfg_buff, cfg_sz); 352 + ret += cfg_sz; 353 + 354 + fw_data = tbuff; 355 + } 356 + 357 + BT_INFO("cfg_sz %d, total size %d", cfg_sz, ret); 358 + 342 359 ret = rtl_download_firmware(hdev, fw_data, ret); 343 - kfree(fw_data); 344 - if (ret < 0) 345 - goto out; 346 360 347 361 out: 348 362 release_firmware(fw); 363 + kfree(fw_data); 364 + err_req_fw: 365 + if (cfg_sz) 366 + kfree(cfg_buff); 349 367 return ret; 350 368 } 351 369 ··· 457 377 case RTL_ROM_LMP_8761A: 458 378 return btrtl_setup_rtl8723b(hdev, lmp_subver, 459 379 "rtl_bt/rtl8761a_fw.bin"); 380 + case RTL_ROM_LMP_8822B: 381 + return btrtl_setup_rtl8723b(hdev, lmp_subver, 382 + "rtl_bt/rtl8822b_fw.bin"); 460 383 default: 461 384 BT_INFO("rtl: assuming no firmware upload needed."); 462 385 return 0;