18bb555aaSBjoern Hartmann /* 28bb555aaSBjoern Hartmann * Copyright (C) 2014 BlueKitchen GmbH 38bb555aaSBjoern Hartmann * 48bb555aaSBjoern Hartmann * Redistribution and use in source and binary forms, with or without 58bb555aaSBjoern Hartmann * modification, are permitted provided that the following conditions 68bb555aaSBjoern Hartmann * are met: 78bb555aaSBjoern Hartmann * 88bb555aaSBjoern Hartmann * 1. Redistributions of source code must retain the above copyright 98bb555aaSBjoern Hartmann * notice, this list of conditions and the following disclaimer. 108bb555aaSBjoern Hartmann * 2. Redistributions in binary form must reproduce the above copyright 118bb555aaSBjoern Hartmann * notice, this list of conditions and the following disclaimer in the 128bb555aaSBjoern Hartmann * documentation and/or other materials provided with the distribution. 138bb555aaSBjoern Hartmann * 3. Neither the name of the copyright holders nor the names of 148bb555aaSBjoern Hartmann * contributors may be used to endorse or promote products derived 158bb555aaSBjoern Hartmann * from this software without specific prior written permission. 168bb555aaSBjoern Hartmann * 4. Any redistribution, use, or modification is done solely for 178bb555aaSBjoern Hartmann * personal benefit and not for any commercial purpose or for 188bb555aaSBjoern Hartmann * monetary gain. 198bb555aaSBjoern Hartmann * 208bb555aaSBjoern Hartmann * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 218bb555aaSBjoern Hartmann * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 228bb555aaSBjoern Hartmann * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 238bb555aaSBjoern Hartmann * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 248bb555aaSBjoern Hartmann * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 258bb555aaSBjoern Hartmann * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 268bb555aaSBjoern Hartmann * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 278bb555aaSBjoern Hartmann * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 288bb555aaSBjoern Hartmann * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 298bb555aaSBjoern Hartmann * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 308bb555aaSBjoern Hartmann * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 318bb555aaSBjoern Hartmann * SUCH DAMAGE. 328bb555aaSBjoern Hartmann * 338bb555aaSBjoern Hartmann * Please inquire about commercial licensing options at 348bb555aaSBjoern Hartmann * [email protected] 358bb555aaSBjoern Hartmann * 368bb555aaSBjoern Hartmann */ 378bb555aaSBjoern Hartmann 388bb555aaSBjoern Hartmann #define BTSTACK_FILE__ "btstack_chipset_realtek.c" 398bb555aaSBjoern Hartmann 408bb555aaSBjoern Hartmann /* 418bb555aaSBjoern Hartmann * btstack_chipset_realtek.c 428bb555aaSBjoern Hartmann * 438bb555aaSBjoern Hartmann * Adapter to use REALTEK-based chipsets with BTstack 448bb555aaSBjoern Hartmann */ 458bb555aaSBjoern Hartmann 468bb555aaSBjoern Hartmann #include "btstack_chipset_realtek.h" 478bb555aaSBjoern Hartmann 488bb555aaSBjoern Hartmann #include <stddef.h> /* NULL */ 498bb555aaSBjoern Hartmann #include <stdio.h> 508bb555aaSBjoern Hartmann #include <string.h> /* memcpy */ 518bb555aaSBjoern Hartmann 528bb555aaSBjoern Hartmann #include "btstack_control.h" 538bb555aaSBjoern Hartmann #include "btstack_debug.h" 548bb555aaSBjoern Hartmann #include "btstack_event.h" 558bb555aaSBjoern Hartmann #include "btstack_util.h" 568bb555aaSBjoern Hartmann #include "hci.h" 578bb555aaSBjoern Hartmann #include "hci_transport.h" 588bb555aaSBjoern Hartmann 598bb555aaSBjoern Hartmann #define ROM_LMP_NONE 0x0000 608bb555aaSBjoern Hartmann #define ROM_LMP_8723a 0x1200 618bb555aaSBjoern Hartmann #define ROM_LMP_8723b 0x8723 628bb555aaSBjoern Hartmann #define ROM_LMP_8821a 0X8821 638bb555aaSBjoern Hartmann #define ROM_LMP_8761a 0X8761 648bb555aaSBjoern Hartmann #define ROM_LMP_8822b 0X8822 658bb555aaSBjoern Hartmann 668bb555aaSBjoern Hartmann #define HCI_DOWNLOAD_FW 0xFC20 678bb555aaSBjoern Hartmann #define HCI_READ_ROM_VERSION 0xFC6D 688bb555aaSBjoern Hartmann #define HCI_READ_LMP_VERSION 0x1001 698bb555aaSBjoern Hartmann #define HCI_RESET 0x0C03 708bb555aaSBjoern Hartmann 718bb555aaSBjoern Hartmann #define FILL_COMMAND(buf, command) ((int16_t *)buf)[0] = command 728bb555aaSBjoern Hartmann #define FILL_LENGTH(buf, length) buf[2] = length 738bb555aaSBjoern Hartmann #define FILL_INDEX(buf, index) buf[3] = index 748bb555aaSBjoern Hartmann #define FILL_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 758bb555aaSBjoern Hartmann 768bb555aaSBjoern Hartmann enum { 778bb555aaSBjoern Hartmann STATE_READ_ROM_VERSION, 788bb555aaSBjoern Hartmann STATE_LOAD_FIRMWARE, 798bb555aaSBjoern Hartmann STATE_RESET, 808bb555aaSBjoern Hartmann STATE_DONE, 818bb555aaSBjoern Hartmann }; 828bb555aaSBjoern Hartmann 838bb555aaSBjoern Hartmann enum { FW_DONE, FW_MORE_TO_DO }; 848bb555aaSBjoern Hartmann 858bb555aaSBjoern Hartmann typedef struct { 868bb555aaSBjoern Hartmann uint16_t prod_id; 878bb555aaSBjoern Hartmann uint16_t lmp_sub; 888bb555aaSBjoern Hartmann char * mp_patch_name; 898bb555aaSBjoern Hartmann char * patch_name; 908bb555aaSBjoern Hartmann char * config_name; 918bb555aaSBjoern Hartmann 928bb555aaSBjoern Hartmann uint8_t *fw_cache1; 938bb555aaSBjoern Hartmann int fw_len1; 948bb555aaSBjoern Hartmann } patch_info; 958bb555aaSBjoern Hartmann 968bb555aaSBjoern Hartmann static patch_info fw_patch_table[] = { 978bb555aaSBjoern Hartmann /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, fw_cache, fw_len } */ 988bb555aaSBjoern Hartmann {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* RTL8723A */ 998bb555aaSBjoern Hartmann {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 1008bb555aaSBjoern Hartmann {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for LI */ 1018bb555aaSBjoern Hartmann {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 1028bb555aaSBjoern Hartmann {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for Azurewave */ 1038bb555aaSBjoern Hartmann 1048bb555aaSBjoern Hartmann {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1058bb555aaSBjoern Hartmann {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1068bb555aaSBjoern Hartmann {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1078bb555aaSBjoern Hartmann {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1088bb555aaSBjoern Hartmann 1098bb555aaSBjoern Hartmann {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 1108bb555aaSBjoern Hartmann {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 1118bb555aaSBjoern Hartmann {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for LC */ 1128bb555aaSBjoern Hartmann {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1138bb555aaSBjoern Hartmann {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1148bb555aaSBjoern Hartmann {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for HP */ 1158bb555aaSBjoern Hartmann {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1168bb555aaSBjoern Hartmann {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1178bb555aaSBjoern Hartmann {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1188bb555aaSBjoern Hartmann {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1198bb555aaSBjoern Hartmann 1208bb555aaSBjoern Hartmann {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1218bb555aaSBjoern Hartmann {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1228bb555aaSBjoern Hartmann {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1238bb555aaSBjoern Hartmann {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1248bb555aaSBjoern Hartmann {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1258bb555aaSBjoern Hartmann {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1268bb555aaSBjoern Hartmann 1278bb555aaSBjoern Hartmann {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU only */ 1288bb555aaSBjoern Hartmann {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 1298bb555aaSBjoern Hartmann {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 1308bb555aaSBjoern Hartmann {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 1318bb555aaSBjoern Hartmann {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 1328bb555aaSBjoern Hartmann {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE for LI */ 1338bb555aaSBjoern Hartmann {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8812AE */ 1348bb555aaSBjoern Hartmann {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8814AE */ 1358bb555aaSBjoern Hartmann 1368bb555aaSBjoern Hartmann {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1378bb555aaSBjoern Hartmann {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1388bb555aaSBjoern Hartmann {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */ 1398bb555aaSBjoern Hartmann {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1408bb555aaSBjoern Hartmann {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1418bb555aaSBjoern Hartmann {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1428bb555aaSBjoern Hartmann {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1438bb555aaSBjoern Hartmann 1448bb555aaSBjoern Hartmann {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */ 1458bb555aaSBjoern Hartmann {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 1468bb555aaSBjoern Hartmann {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 1478bb555aaSBjoern Hartmann {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 1488bb555aaSBjoern Hartmann 1498bb555aaSBjoern Hartmann {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 1508bb555aaSBjoern Hartmann {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1518bb555aaSBjoern Hartmann {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1528bb555aaSBjoern Hartmann {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1538bb555aaSBjoern Hartmann {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 1548bb555aaSBjoern Hartmann 1558bb555aaSBjoern Hartmann {0x8771, 0x8761, "mp_rtl8761bu_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */ 1568bb555aaSBjoern Hartmann 1578bb555aaSBjoern Hartmann /* NOTE: must append patch entries above the null entry */ 1588bb555aaSBjoern Hartmann {0, 0, NULL, NULL, NULL, NULL, 0}}; 1598bb555aaSBjoern Hartmann 1608bb555aaSBjoern Hartmann uint16_t project_id[] = { 1618bb555aaSBjoern Hartmann ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 1628bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 1638bb555aaSBjoern Hartmann ROM_LMP_8821a, /* RTL8821CU */ 1648bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 1658bb555aaSBjoern Hartmann ROM_LMP_8761a, /* index 14 for 8761BU */ 1668bb555aaSBjoern Hartmann }; 1678bb555aaSBjoern Hartmann 1688bb555aaSBjoern Hartmann static btstack_packet_callback_registration_t hci_event_callback_registration; 1698bb555aaSBjoern Hartmann static uint8_t state = STATE_READ_ROM_VERSION; 1708bb555aaSBjoern Hartmann static uint8_t rom_version; 1718bb555aaSBjoern Hartmann static uint16_t lmp_subversion; 1728bb555aaSBjoern Hartmann static uint16_t product_id; 1738bb555aaSBjoern Hartmann static patch_info * patch; 1748bb555aaSBjoern Hartmann 1758bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 1768bb555aaSBjoern Hartmann static const char *firmware_folder_path = "."; 1778bb555aaSBjoern Hartmann static const char *firmware_file_path; 1788bb555aaSBjoern Hartmann static const char *config_folder_path = "."; 1798bb555aaSBjoern Hartmann static const char *config_file_path; 1808bb555aaSBjoern Hartmann static char firmware_file[1000]; 1818bb555aaSBjoern Hartmann static char config_file[1000]; 1828bb555aaSBjoern Hartmann #endif 1838bb555aaSBjoern Hartmann 1848bb555aaSBjoern Hartmann const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 1858bb555aaSBjoern Hartmann const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 1868bb555aaSBjoern Hartmann 1878bb555aaSBjoern Hartmann static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 1888bb555aaSBjoern Hartmann UNUSED(channel); 1898bb555aaSBjoern Hartmann UNUSED(size); 1908bb555aaSBjoern Hartmann if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 1918bb555aaSBjoern Hartmann return; 1928bb555aaSBjoern Hartmann } 1938bb555aaSBjoern Hartmann uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 1948bb555aaSBjoern Hartmann 1958bb555aaSBjoern Hartmann switch (opcode) { 1968bb555aaSBjoern Hartmann case HCI_READ_ROM_VERSION: 1978bb555aaSBjoern Hartmann rom_version = hci_event_command_complete_get_return_parameters(packet)[1]; 1988bb555aaSBjoern Hartmann log_info("Received ROM version 0x%02x", rom_version); 1998bb555aaSBjoern Hartmann break; 2008bb555aaSBjoern Hartmann default: 2018bb555aaSBjoern Hartmann break; 2028bb555aaSBjoern Hartmann } 2038bb555aaSBjoern Hartmann } 2048bb555aaSBjoern Hartmann 2058bb555aaSBjoern Hartmann static void chipset_init(const void *config) { 2068bb555aaSBjoern Hartmann UNUSED(config); 2078bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 2088bb555aaSBjoern Hartmann // determine file path 2098bb555aaSBjoern Hartmann if (firmware_file_path == NULL || config_file_path == NULL) { 2108bb555aaSBjoern Hartmann log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 2118bb555aaSBjoern Hartmann patch = NULL; 2128bb555aaSBjoern Hartmann for (int i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 2138bb555aaSBjoern Hartmann if (fw_patch_table[i].prod_id == product_id) { 2148bb555aaSBjoern Hartmann patch = &fw_patch_table[i]; 2158bb555aaSBjoern Hartmann break; 2168bb555aaSBjoern Hartmann } 2178bb555aaSBjoern Hartmann } 2188bb555aaSBjoern Hartmann if (patch == NULL) { 2198bb555aaSBjoern Hartmann log_info("Product id 0x%04x is unknown", product_id); 2208bb555aaSBjoern Hartmann state = STATE_DONE; 2218bb555aaSBjoern Hartmann return; 2228bb555aaSBjoern Hartmann } 2238bb555aaSBjoern Hartmann sprintf(firmware_file, "%s/%s", firmware_folder_path, patch->patch_name); 2248bb555aaSBjoern Hartmann sprintf(config_file, "%s/%s", config_folder_path, patch->config_name); 2258bb555aaSBjoern Hartmann firmware_file_path = &firmware_file[0]; 2268bb555aaSBjoern Hartmann config_file_path = &config_file[0]; 2278bb555aaSBjoern Hartmann lmp_subversion = patch->lmp_sub; 2288bb555aaSBjoern Hartmann } 2298bb555aaSBjoern Hartmann log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 2308bb555aaSBjoern Hartmann 2318bb555aaSBjoern Hartmann // activate hci callback 2328bb555aaSBjoern Hartmann hci_event_callback_registration.callback = &hci_packet_handler; 2338bb555aaSBjoern Hartmann hci_add_event_handler(&hci_event_callback_registration); 2348bb555aaSBjoern Hartmann state = STATE_READ_ROM_VERSION; 2358bb555aaSBjoern Hartmann #endif 2368bb555aaSBjoern Hartmann } 2378bb555aaSBjoern Hartmann 2388bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 2398bb555aaSBjoern Hartmann 2408bb555aaSBjoern Hartmann /** 2418bb555aaSBjoern Hartmann * @brief Opens the specified file and stores content to an allocated buffer 2428bb555aaSBjoern Hartmann * 2438bb555aaSBjoern Hartmann * @param file 2448bb555aaSBjoern Hartmann * @param buf 2458bb555aaSBjoern Hartmann * @param name 2468bb555aaSBjoern Hartmann * @return uint32_t Length of file 2478bb555aaSBjoern Hartmann */ 2488bb555aaSBjoern Hartmann static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 2498bb555aaSBjoern Hartmann uint32_t size; 2508bb555aaSBjoern Hartmann 2518bb555aaSBjoern Hartmann // open file 2528bb555aaSBjoern Hartmann *file = fopen(name, "rb"); 2538bb555aaSBjoern Hartmann if (*file == NULL) { 2548bb555aaSBjoern Hartmann log_info("Failed to open file %s", name); 2558bb555aaSBjoern Hartmann return 0; 2568bb555aaSBjoern Hartmann } 2578bb555aaSBjoern Hartmann 2588bb555aaSBjoern Hartmann // determine length of file 2598bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_END); 2608bb555aaSBjoern Hartmann size = ftell(*file); 2618bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_SET); 2628bb555aaSBjoern Hartmann if (size <= 0) { 2638bb555aaSBjoern Hartmann return 0; 2648bb555aaSBjoern Hartmann } 2658bb555aaSBjoern Hartmann 2668bb555aaSBjoern Hartmann // allocate memory 2678bb555aaSBjoern Hartmann *buf = malloc(size); 2688bb555aaSBjoern Hartmann if (*buf == NULL) { 2698bb555aaSBjoern Hartmann fclose(*file); 2708bb555aaSBjoern Hartmann *file = NULL; 2718bb555aaSBjoern Hartmann log_info("Failed to allocate %u bytes for file %s", size, name); 2728bb555aaSBjoern Hartmann return 0; 2738bb555aaSBjoern Hartmann } 2748bb555aaSBjoern Hartmann 2758bb555aaSBjoern Hartmann // read file 2768bb555aaSBjoern Hartmann uint8_t ret = fread(*buf, size, 1, *file); 2778bb555aaSBjoern Hartmann if (ret != 1) { 2788bb555aaSBjoern Hartmann log_info("Failed to read %u bytes from file %s (ret = %u)", size, name, ret); 2798bb555aaSBjoern Hartmann fclose(*file); 2808bb555aaSBjoern Hartmann free(*buf); 2818bb555aaSBjoern Hartmann *file = NULL; 2828bb555aaSBjoern Hartmann *buf = NULL; 2838bb555aaSBjoern Hartmann return 0; 2848bb555aaSBjoern Hartmann } 2858bb555aaSBjoern Hartmann 2868bb555aaSBjoern Hartmann log_info("Opened file %s and read %u bytes", name, size); 2878bb555aaSBjoern Hartmann return size; 2888bb555aaSBjoern Hartmann } 2898bb555aaSBjoern Hartmann 2908bb555aaSBjoern Hartmann static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 2918bb555aaSBjoern Hartmann fclose(*file); 2928bb555aaSBjoern Hartmann free(*buffer); 2938bb555aaSBjoern Hartmann *buffer = NULL; 2948bb555aaSBjoern Hartmann *file = NULL; 2958bb555aaSBjoern Hartmann } 2968bb555aaSBjoern Hartmann 2978bb555aaSBjoern Hartmann static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 2988bb555aaSBjoern Hartmann static uint8_t *patch_buf = NULL; 2998bb555aaSBjoern Hartmann static uint32_t fw_total_len; 3008bb555aaSBjoern Hartmann static uint32_t fw_ptr; 3018bb555aaSBjoern Hartmann static uint8_t index; 3028bb555aaSBjoern Hartmann 3038bb555aaSBjoern Hartmann // read firmware and config 3048bb555aaSBjoern Hartmann if (patch_buf == NULL) { 3058bb555aaSBjoern Hartmann uint16_t patch_length = 0; 3068bb555aaSBjoern Hartmann uint32_t offset; 3078bb555aaSBjoern Hartmann FILE * fw = NULL; 3088bb555aaSBjoern Hartmann uint32_t fw_size; 3098bb555aaSBjoern Hartmann uint8_t *fw_buf = NULL; 3108bb555aaSBjoern Hartmann 3118bb555aaSBjoern Hartmann FILE * conf = NULL; 3128bb555aaSBjoern Hartmann uint32_t conf_size; 3138bb555aaSBjoern Hartmann uint8_t *conf_buf = NULL; 3148bb555aaSBjoern Hartmann 3158bb555aaSBjoern Hartmann if (firmware == NULL || config == NULL) { 3168bb555aaSBjoern Hartmann log_info("Please specify realtek firmware and config file paths"); 3178bb555aaSBjoern Hartmann return FW_DONE; 3188bb555aaSBjoern Hartmann } 3198bb555aaSBjoern Hartmann 3208bb555aaSBjoern Hartmann // read firmware 3218bb555aaSBjoern Hartmann fw_size = read_file(&fw, &fw_buf, firmware); 3228bb555aaSBjoern Hartmann if (fw_size == 0) { 3238bb555aaSBjoern Hartmann log_info("Firmware size is 0. Quit!"); 3248bb555aaSBjoern Hartmann return FW_DONE; 3258bb555aaSBjoern Hartmann } 3268bb555aaSBjoern Hartmann 3278bb555aaSBjoern Hartmann // read config 3288bb555aaSBjoern Hartmann conf_size = read_file(&conf, &conf_buf, config); 3298bb555aaSBjoern Hartmann if (conf_size == 0) { 3308bb555aaSBjoern Hartmann log_info("Config size is 0. Quit!"); 3318bb555aaSBjoern Hartmann fclose(fw); 3328bb555aaSBjoern Hartmann free(fw_buf); 3338bb555aaSBjoern Hartmann fw_buf = NULL; 3348bb555aaSBjoern Hartmann fw = NULL; 3358bb555aaSBjoern Hartmann return FW_DONE; 3368bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3378bb555aaSBjoern Hartmann } 3388bb555aaSBjoern Hartmann 3398bb555aaSBjoern Hartmann // check signature 3408bb555aaSBjoern Hartmann if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 3418bb555aaSBjoern Hartmann log_info("Wrong signature. Quit!"); 3428bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3438bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3448bb555aaSBjoern Hartmann return FW_DONE; 3458bb555aaSBjoern Hartmann } 3468bb555aaSBjoern Hartmann 3478bb555aaSBjoern Hartmann // check project id 3488bb555aaSBjoern Hartmann if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) { 3498bb555aaSBjoern Hartmann log_info("Wrong project id. Quit!"); 3508bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3518bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3528bb555aaSBjoern Hartmann return FW_DONE; 3538bb555aaSBjoern Hartmann } 3548bb555aaSBjoern Hartmann 3558bb555aaSBjoern Hartmann // read firmware version 3568bb555aaSBjoern Hartmann uint32_t fw_version = little_endian_read_32(fw_buf, 8); 3578bb555aaSBjoern Hartmann log_info("Firmware version: 0x%x", fw_version); 3588bb555aaSBjoern Hartmann 3598bb555aaSBjoern Hartmann // read number of patches 3608bb555aaSBjoern Hartmann uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12); 3618bb555aaSBjoern Hartmann log_info("Number of patches: %d", fw_num_patches); 3628bb555aaSBjoern Hartmann 3638bb555aaSBjoern Hartmann // find correct entry 3648bb555aaSBjoern Hartmann for (uint16_t i = 0; i < fw_num_patches; i++) { 3658bb555aaSBjoern Hartmann if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 3668bb555aaSBjoern Hartmann patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 3678bb555aaSBjoern Hartmann offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 3688bb555aaSBjoern Hartmann log_info("patch_length %u, offset %u", patch_length, offset); 3698bb555aaSBjoern Hartmann break; 3708bb555aaSBjoern Hartmann } 3718bb555aaSBjoern Hartmann } 3728bb555aaSBjoern Hartmann if (patch_length == 0) { 3738bb555aaSBjoern Hartmann log_debug("Failed to find valid patch"); 3748bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3758bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3768bb555aaSBjoern Hartmann return FW_DONE; 3778bb555aaSBjoern Hartmann } 3788bb555aaSBjoern Hartmann 3798bb555aaSBjoern Hartmann // allocate patch buffer 3808bb555aaSBjoern Hartmann fw_total_len = patch_length + conf_size; 3818bb555aaSBjoern Hartmann patch_buf = malloc(fw_total_len); 3828bb555aaSBjoern Hartmann if (patch_buf == NULL) { 3838bb555aaSBjoern Hartmann log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 3848bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3858bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3868bb555aaSBjoern Hartmann return FW_DONE; 3878bb555aaSBjoern Hartmann } 3888bb555aaSBjoern Hartmann 3898bb555aaSBjoern Hartmann // copy patch 3908bb555aaSBjoern Hartmann memcpy(patch_buf, fw_buf + offset, patch_length); 3918bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length - 4, &fw_version, 4); 3928bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length, conf_buf, conf_size); 3938bb555aaSBjoern Hartmann fw_ptr = 0; 3948bb555aaSBjoern Hartmann index = 0; 3958bb555aaSBjoern Hartmann 3968bb555aaSBjoern Hartmann // close files 3978bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3988bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3998bb555aaSBjoern Hartmann } 4008bb555aaSBjoern Hartmann 4018bb555aaSBjoern Hartmann uint8_t len; 4028bb555aaSBjoern Hartmann if (fw_total_len - fw_ptr > 252) { 4038bb555aaSBjoern Hartmann len = 252; 4048bb555aaSBjoern Hartmann } else { 4058bb555aaSBjoern Hartmann len = fw_total_len - fw_ptr; 4068bb555aaSBjoern Hartmann index |= 0x80; // end 4078bb555aaSBjoern Hartmann } 4088bb555aaSBjoern Hartmann 4098bb555aaSBjoern Hartmann if (len) { 4108bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW); 4118bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, len + 1); 4128bb555aaSBjoern Hartmann FILL_INDEX(hci_cmd_buffer, index); 4138bb555aaSBjoern Hartmann FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 4148bb555aaSBjoern Hartmann index++; 4158bb555aaSBjoern Hartmann fw_ptr += len; 4168bb555aaSBjoern Hartmann return FW_MORE_TO_DO; 4178bb555aaSBjoern Hartmann } 4188bb555aaSBjoern Hartmann 4198bb555aaSBjoern Hartmann // cleanup and return 4208bb555aaSBjoern Hartmann free(patch_buf); 4218bb555aaSBjoern Hartmann patch_buf = NULL; 4228bb555aaSBjoern Hartmann return FW_DONE; 4238bb555aaSBjoern Hartmann } 4248bb555aaSBjoern Hartmann 4258bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 4268bb555aaSBjoern Hartmann 4278bb555aaSBjoern Hartmann static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 4288bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4298bb555aaSBjoern Hartmann uint8_t ret; 4308bb555aaSBjoern Hartmann while (true) { 4318bb555aaSBjoern Hartmann switch (state) { 4328bb555aaSBjoern Hartmann case STATE_READ_ROM_VERSION: 4338bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION); 4348bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 4358bb555aaSBjoern Hartmann state = STATE_LOAD_FIRMWARE; 4368bb555aaSBjoern Hartmann break; 4378bb555aaSBjoern Hartmann case STATE_LOAD_FIRMWARE: 4388bb555aaSBjoern Hartmann if (lmp_subversion != ROM_LMP_8723a) { 4398bb555aaSBjoern Hartmann ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 4408bb555aaSBjoern Hartmann } else { 4418bb555aaSBjoern Hartmann log_info("Realtek firmware for old patch style not implemented"); 4428bb555aaSBjoern Hartmann ret = FW_DONE; 4438bb555aaSBjoern Hartmann } 4448bb555aaSBjoern Hartmann if (ret != FW_DONE) { 4458bb555aaSBjoern Hartmann break; 4468bb555aaSBjoern Hartmann } 4478bb555aaSBjoern Hartmann // we are done fall through 4488bb555aaSBjoern Hartmann state = STATE_RESET; 4498bb555aaSBjoern Hartmann case STATE_RESET: 4508bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_RESET); 4518bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 4528bb555aaSBjoern Hartmann state = STATE_DONE; 4538bb555aaSBjoern Hartmann break; 4548bb555aaSBjoern Hartmann case STATE_DONE: 4558bb555aaSBjoern Hartmann hci_remove_event_handler(&hci_event_callback_registration); 4568bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 4578bb555aaSBjoern Hartmann break; 4588bb555aaSBjoern Hartmann default: 4598bb555aaSBjoern Hartmann log_info("Invalid state %d", state); 4608bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 4618bb555aaSBjoern Hartmann break; 4628bb555aaSBjoern Hartmann } 4638bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_VALID_COMMAND; 4648bb555aaSBjoern Hartmann } 4658bb555aaSBjoern Hartmann #else // HAVE_POSIX_FILE_IO 4668bb555aaSBjoern Hartmann log_info("Realtek without File IO is not implemented yet"); 4678bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 4688bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 4698bb555aaSBjoern Hartmann } 4708bb555aaSBjoern Hartmann 4718bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 4728bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4738bb555aaSBjoern Hartmann firmware_file_path = path; 4748bb555aaSBjoern Hartmann #endif 4758bb555aaSBjoern Hartmann } 4768bb555aaSBjoern Hartmann 4778bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 4788bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4798bb555aaSBjoern Hartmann firmware_folder_path = path; 4808bb555aaSBjoern Hartmann #endif 4818bb555aaSBjoern Hartmann } 4828bb555aaSBjoern Hartmann 4838bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_file_path(const char *path) { 4848bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4858bb555aaSBjoern Hartmann config_file_path = path; 4868bb555aaSBjoern Hartmann #endif 4878bb555aaSBjoern Hartmann } 4888bb555aaSBjoern Hartmann 4898bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_folder_path(const char *path) { 4908bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4918bb555aaSBjoern Hartmann config_folder_path = path; 4928bb555aaSBjoern Hartmann #endif 4938bb555aaSBjoern Hartmann } 4948bb555aaSBjoern Hartmann 495*5a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) { 496*5a4c0fdaSMatthias Ringwald lmp_subversion = version; 497*5a4c0fdaSMatthias Ringwald } 4988bb555aaSBjoern Hartmann 499*5a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_product_id(uint16_t id) { 500*5a4c0fdaSMatthias Ringwald product_id = id; 501*5a4c0fdaSMatthias Ringwald } 502*5a4c0fdaSMatthias Ringwald 503*5a4c0fdaSMatthias Ringwald uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 504*5a4c0fdaSMatthias Ringwald return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 505*5a4c0fdaSMatthias Ringwald } 506*5a4c0fdaSMatthias Ringwald 507*5a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 508*5a4c0fdaSMatthias Ringwald btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 509*5a4c0fdaSMatthias Ringwald *out_vendor_id = 0xbda; 510*5a4c0fdaSMatthias Ringwald *out_product_id = fw_patch_table[index].prod_id; 511*5a4c0fdaSMatthias Ringwald } 5128bb555aaSBjoern Hartmann 5138bb555aaSBjoern Hartmann static const btstack_chipset_t btstack_chipset_realtek = { 5148bb555aaSBjoern Hartmann "REALTEK", chipset_init, chipset_next_command, 5158bb555aaSBjoern Hartmann NULL, // chipset_set_baudrate_command, 5168bb555aaSBjoern Hartmann NULL, // chipset_set_bd_addr_command not supported or implemented 5178bb555aaSBjoern Hartmann }; 5188bb555aaSBjoern Hartmann 5198bb555aaSBjoern Hartmann // MARK: public API 5208bb555aaSBjoern Hartmann const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 521