1 /* 2 * Copyright (C) 2014 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_chipset_realtek.c" 39 40 /* 41 * btstack_chipset_realtek.c 42 * 43 * Adapter to use REALTEK-based chipsets with BTstack 44 */ 45 46 #include "btstack_chipset_realtek.h" 47 48 #include <stddef.h> /* NULL */ 49 #include <stdio.h> 50 #include <string.h> /* memcpy */ 51 52 #include "btstack_control.h" 53 #include "btstack_debug.h" 54 #include "btstack_event.h" 55 #include "btstack_util.h" 56 #include "hci.h" 57 #include "hci_transport.h" 58 59 #define ROM_LMP_NONE 0x0000 60 #define ROM_LMP_8723a 0x1200 61 #define ROM_LMP_8723b 0x8723 62 #define ROM_LMP_8821a 0X8821 63 #define ROM_LMP_8761a 0X8761 64 #define ROM_LMP_8822b 0X8822 65 66 #define HCI_DOWNLOAD_FW 0xFC20 67 #define HCI_READ_ROM_VERSION 0xFC6D 68 #define HCI_READ_LMP_VERSION 0x1001 69 #define HCI_RESET 0x0C03 70 71 #define FILL_COMMAND(buf, command) ((int16_t *)buf)[0] = command 72 #define FILL_LENGTH(buf, length) buf[2] = length 73 #define FILL_INDEX(buf, index) buf[3] = index 74 #define FILL_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 75 76 enum { 77 STATE_READ_ROM_VERSION, 78 STATE_LOAD_FIRMWARE, 79 STATE_RESET, 80 STATE_DONE, 81 }; 82 83 enum { FW_DONE, FW_MORE_TO_DO }; 84 85 typedef struct { 86 uint16_t prod_id; 87 uint16_t lmp_sub; 88 char * mp_patch_name; 89 char * patch_name; 90 char * config_name; 91 92 uint8_t *fw_cache1; 93 int fw_len1; 94 } patch_info; 95 96 static patch_info fw_patch_table[] = { 97 /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, fw_cache, fw_len } */ 98 {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* RTL8723A */ 99 {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 100 {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for LI */ 101 {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 102 {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for Azurewave */ 103 104 {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 105 {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 106 {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 107 {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 108 109 {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 110 {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 111 {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for LC */ 112 {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 113 {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 114 {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for HP */ 115 {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 116 {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 117 {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 118 {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 119 120 {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 121 {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 122 {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 123 {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 124 {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 125 {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 126 127 {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU only */ 128 {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 129 {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 130 {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 131 {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 132 {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE for LI */ 133 {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8812AE */ 134 {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8814AE */ 135 136 {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 137 {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 138 {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */ 139 {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 140 {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 141 {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 142 {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 143 144 {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */ 145 {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 146 {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 147 {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 148 149 {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 150 {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 151 {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 152 {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 153 {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 154 155 {0x8771, 0x8761, "mp_rtl8761bu_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */ 156 157 /* NOTE: must append patch entries above the null entry */ 158 {0, 0, NULL, NULL, NULL, NULL, 0}}; 159 160 uint16_t project_id[] = { 161 ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 162 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 163 ROM_LMP_8821a, /* RTL8821CU */ 164 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 165 ROM_LMP_8761a, /* index 14 for 8761BU */ 166 }; 167 168 static btstack_packet_callback_registration_t hci_event_callback_registration; 169 static uint8_t state = STATE_READ_ROM_VERSION; 170 static uint8_t rom_version; 171 static uint16_t lmp_subversion; 172 static uint16_t product_id; 173 static patch_info * patch; 174 175 #ifdef HAVE_POSIX_FILE_IO 176 static const char *firmware_folder_path = "."; 177 static const char *firmware_file_path; 178 static const char *config_folder_path = "."; 179 static const char *config_file_path; 180 static char firmware_file[1000]; 181 static char config_file[1000]; 182 #endif 183 184 const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 185 const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 186 187 static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 188 UNUSED(channel); 189 UNUSED(size); 190 if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 191 return; 192 } 193 uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 194 195 switch (opcode) { 196 case HCI_READ_ROM_VERSION: 197 rom_version = hci_event_command_complete_get_return_parameters(packet)[1]; 198 log_info("Received ROM version 0x%02x", rom_version); 199 break; 200 default: 201 break; 202 } 203 } 204 205 static void chipset_init(const void *config) { 206 UNUSED(config); 207 #ifdef HAVE_POSIX_FILE_IO 208 // determine file path 209 if (firmware_file_path == NULL || config_file_path == NULL) { 210 log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 211 patch = NULL; 212 for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 213 if (fw_patch_table[i].prod_id == product_id) { 214 patch = &fw_patch_table[i]; 215 break; 216 } 217 } 218 if (patch == NULL) { 219 log_info("Product id 0x%04x is unknown", product_id); 220 state = STATE_DONE; 221 return; 222 } 223 sprintf(firmware_file, "%s/%s", firmware_folder_path, patch->patch_name); 224 sprintf(config_file, "%s/%s", config_folder_path, patch->config_name); 225 firmware_file_path = &firmware_file[0]; 226 config_file_path = &config_file[0]; 227 lmp_subversion = patch->lmp_sub; 228 } 229 log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 230 231 // activate hci callback 232 hci_event_callback_registration.callback = &hci_packet_handler; 233 hci_add_event_handler(&hci_event_callback_registration); 234 state = STATE_READ_ROM_VERSION; 235 #endif 236 } 237 238 #ifdef HAVE_POSIX_FILE_IO 239 240 /** 241 * @brief Opens the specified file and stores content to an allocated buffer 242 * 243 * @param file 244 * @param buf 245 * @param name 246 * @return uint32_t Length of file 247 */ 248 static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 249 uint32_t size; 250 251 // open file 252 *file = fopen(name, "rb"); 253 if (*file == NULL) { 254 log_info("Failed to open file %s", name); 255 return 0; 256 } 257 258 // determine length of file 259 fseek(*file, 0, SEEK_END); 260 size = ftell(*file); 261 fseek(*file, 0, SEEK_SET); 262 if (size <= 0) { 263 return 0; 264 } 265 266 // allocate memory 267 *buf = malloc(size); 268 if (*buf == NULL) { 269 fclose(*file); 270 *file = NULL; 271 log_info("Failed to allocate %u bytes for file %s", size, name); 272 return 0; 273 } 274 275 // read file 276 uint8_t ret = fread(*buf, size, 1, *file); 277 if (ret != 1) { 278 log_info("Failed to read %u bytes from file %s (ret = %u)", size, name, ret); 279 fclose(*file); 280 free(*buf); 281 *file = NULL; 282 *buf = NULL; 283 return 0; 284 } 285 286 log_info("Opened file %s and read %u bytes", name, size); 287 return size; 288 } 289 290 static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 291 fclose(*file); 292 free(*buffer); 293 *buffer = NULL; 294 *file = NULL; 295 } 296 297 static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 298 static uint8_t *patch_buf = NULL; 299 static uint32_t fw_total_len; 300 static uint32_t fw_ptr; 301 static uint8_t index; 302 303 // read firmware and config 304 if (patch_buf == NULL) { 305 uint16_t patch_length = 0; 306 uint32_t offset; 307 FILE * fw = NULL; 308 uint32_t fw_size; 309 uint8_t *fw_buf = NULL; 310 311 FILE * conf = NULL; 312 uint32_t conf_size; 313 uint8_t *conf_buf = NULL; 314 315 if (firmware == NULL || config == NULL) { 316 log_info("Please specify realtek firmware and config file paths"); 317 return FW_DONE; 318 } 319 320 // read firmware 321 fw_size = read_file(&fw, &fw_buf, firmware); 322 if (fw_size == 0) { 323 log_info("Firmware size is 0. Quit!"); 324 return FW_DONE; 325 } 326 327 // read config 328 conf_size = read_file(&conf, &conf_buf, config); 329 if (conf_size == 0) { 330 log_info("Config size is 0. Quit!"); 331 fclose(fw); 332 free(fw_buf); 333 fw_buf = NULL; 334 fw = NULL; 335 return FW_DONE; 336 finalize_file_and_buffer(&fw, &fw_buf); 337 } 338 339 // check signature 340 if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 341 log_info("Wrong signature. Quit!"); 342 finalize_file_and_buffer(&fw, &fw_buf); 343 finalize_file_and_buffer(&conf, &conf_buf); 344 return FW_DONE; 345 } 346 347 // check project id 348 if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) { 349 log_info("Wrong project id. Quit!"); 350 finalize_file_and_buffer(&fw, &fw_buf); 351 finalize_file_and_buffer(&conf, &conf_buf); 352 return FW_DONE; 353 } 354 355 // read firmware version 356 uint32_t fw_version = little_endian_read_32(fw_buf, 8); 357 log_info("Firmware version: 0x%x", fw_version); 358 359 // read number of patches 360 uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12); 361 log_info("Number of patches: %d", fw_num_patches); 362 363 // find correct entry 364 for (uint16_t i = 0; i < fw_num_patches; i++) { 365 if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 366 patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 367 offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 368 log_info("patch_length %u, offset %u", patch_length, offset); 369 break; 370 } 371 } 372 if (patch_length == 0) { 373 log_debug("Failed to find valid patch"); 374 finalize_file_and_buffer(&fw, &fw_buf); 375 finalize_file_and_buffer(&conf, &conf_buf); 376 return FW_DONE; 377 } 378 379 // allocate patch buffer 380 fw_total_len = patch_length + conf_size; 381 patch_buf = malloc(fw_total_len); 382 if (patch_buf == NULL) { 383 log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 384 finalize_file_and_buffer(&fw, &fw_buf); 385 finalize_file_and_buffer(&conf, &conf_buf); 386 return FW_DONE; 387 } 388 389 // copy patch 390 memcpy(patch_buf, fw_buf + offset, patch_length); 391 memcpy(patch_buf + patch_length - 4, &fw_version, 4); 392 memcpy(patch_buf + patch_length, conf_buf, conf_size); 393 fw_ptr = 0; 394 index = 0; 395 396 // close files 397 finalize_file_and_buffer(&fw, &fw_buf); 398 finalize_file_and_buffer(&conf, &conf_buf); 399 } 400 401 uint8_t len; 402 if (fw_total_len - fw_ptr > 252) { 403 len = 252; 404 } else { 405 len = fw_total_len - fw_ptr; 406 index |= 0x80; // end 407 } 408 409 if (len) { 410 FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW); 411 FILL_LENGTH(hci_cmd_buffer, len + 1); 412 FILL_INDEX(hci_cmd_buffer, index); 413 FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 414 index++; 415 fw_ptr += len; 416 return FW_MORE_TO_DO; 417 } 418 419 // cleanup and return 420 free(patch_buf); 421 patch_buf = NULL; 422 return FW_DONE; 423 } 424 425 #endif // HAVE_POSIX_FILE_IO 426 427 static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 428 #ifdef HAVE_POSIX_FILE_IO 429 uint8_t ret; 430 while (true) { 431 switch (state) { 432 case STATE_READ_ROM_VERSION: 433 FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION); 434 FILL_LENGTH(hci_cmd_buffer, 0); 435 state = STATE_LOAD_FIRMWARE; 436 break; 437 case STATE_LOAD_FIRMWARE: 438 if (lmp_subversion != ROM_LMP_8723a) { 439 ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 440 } else { 441 log_info("Realtek firmware for old patch style not implemented"); 442 ret = FW_DONE; 443 } 444 if (ret != FW_DONE) { 445 break; 446 } 447 // we are done fall through 448 state = STATE_RESET; 449 case STATE_RESET: 450 FILL_COMMAND(hci_cmd_buffer, HCI_RESET); 451 FILL_LENGTH(hci_cmd_buffer, 0); 452 state = STATE_DONE; 453 break; 454 case STATE_DONE: 455 hci_remove_event_handler(&hci_event_callback_registration); 456 return BTSTACK_CHIPSET_DONE; 457 break; 458 default: 459 log_info("Invalid state %d", state); 460 return BTSTACK_CHIPSET_DONE; 461 break; 462 } 463 return BTSTACK_CHIPSET_VALID_COMMAND; 464 } 465 #else // HAVE_POSIX_FILE_IO 466 log_info("Realtek without File IO is not implemented yet"); 467 return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 468 #endif // HAVE_POSIX_FILE_IO 469 } 470 471 void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 472 #ifdef HAVE_POSIX_FILE_IO 473 firmware_file_path = path; 474 #endif 475 } 476 477 void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 478 #ifdef HAVE_POSIX_FILE_IO 479 firmware_folder_path = path; 480 #endif 481 } 482 483 void btstack_chipset_realtek_set_config_file_path(const char *path) { 484 #ifdef HAVE_POSIX_FILE_IO 485 config_file_path = path; 486 #endif 487 } 488 489 void btstack_chipset_realtek_set_config_folder_path(const char *path) { 490 #ifdef HAVE_POSIX_FILE_IO 491 config_folder_path = path; 492 #endif 493 } 494 495 void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) { 496 lmp_subversion = version; 497 } 498 499 void btstack_chipset_realtek_set_product_id(uint16_t id) { 500 product_id = id; 501 } 502 503 uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 504 return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 505 } 506 507 void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 508 btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 509 *out_vendor_id = 0xbda; 510 *out_product_id = fw_patch_table[index].prod_id; 511 } 512 513 static const btstack_chipset_t btstack_chipset_realtek = { 514 "REALTEK", chipset_init, chipset_next_command, 515 NULL, // chipset_set_baudrate_command, 516 NULL, // chipset_set_bd_addr_command not supported or implemented 517 }; 518 519 // MARK: public API 520 const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 521