18bb555aaSBjoern Hartmann /* 274f83314SMatthias Ringwald * Copyright (C) 2022 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 5974f83314SMatthias Ringwald #ifdef _MSC_VER 6074f83314SMatthias Ringwald // ignore deprecated warning for fopen 6174f83314SMatthias Ringwald #pragma warning(disable : 4996) 6274f83314SMatthias Ringwald #endif 6374f83314SMatthias Ringwald 648bb555aaSBjoern Hartmann #define ROM_LMP_NONE 0x0000 658bb555aaSBjoern Hartmann #define ROM_LMP_8723a 0x1200 668bb555aaSBjoern Hartmann #define ROM_LMP_8723b 0x8723 678bb555aaSBjoern Hartmann #define ROM_LMP_8821a 0X8821 688bb555aaSBjoern Hartmann #define ROM_LMP_8761a 0X8761 698bb555aaSBjoern Hartmann #define ROM_LMP_8822b 0X8822 708bb555aaSBjoern Hartmann 718bb555aaSBjoern Hartmann #define HCI_DOWNLOAD_FW 0xFC20 728bb555aaSBjoern Hartmann #define HCI_READ_ROM_VERSION 0xFC6D 738bb555aaSBjoern Hartmann #define HCI_READ_LMP_VERSION 0x1001 748bb555aaSBjoern Hartmann #define HCI_RESET 0x0C03 758bb555aaSBjoern Hartmann 768bb555aaSBjoern Hartmann #define FILL_COMMAND(buf, command) ((int16_t *)buf)[0] = command 778bb555aaSBjoern Hartmann #define FILL_LENGTH(buf, length) buf[2] = length 788bb555aaSBjoern Hartmann #define FILL_INDEX(buf, index) buf[3] = index 798bb555aaSBjoern Hartmann #define FILL_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 808bb555aaSBjoern Hartmann 818bb555aaSBjoern Hartmann enum { 828bb555aaSBjoern Hartmann STATE_READ_ROM_VERSION, 838bb555aaSBjoern Hartmann STATE_LOAD_FIRMWARE, 848bb555aaSBjoern Hartmann STATE_RESET, 858bb555aaSBjoern Hartmann STATE_DONE, 868bb555aaSBjoern Hartmann }; 878bb555aaSBjoern Hartmann 888bb555aaSBjoern Hartmann enum { FW_DONE, FW_MORE_TO_DO }; 898bb555aaSBjoern Hartmann 908bb555aaSBjoern Hartmann typedef struct { 918bb555aaSBjoern Hartmann uint16_t prod_id; 928bb555aaSBjoern Hartmann uint16_t lmp_sub; 938bb555aaSBjoern Hartmann char * mp_patch_name; 948bb555aaSBjoern Hartmann char * patch_name; 958bb555aaSBjoern Hartmann char * config_name; 968bb555aaSBjoern Hartmann 978bb555aaSBjoern Hartmann uint8_t *fw_cache1; 988bb555aaSBjoern Hartmann int fw_len1; 998bb555aaSBjoern Hartmann } patch_info; 1008bb555aaSBjoern Hartmann 1018bb555aaSBjoern Hartmann static patch_info fw_patch_table[] = { 1028bb555aaSBjoern Hartmann /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, fw_cache, fw_len } */ 1038bb555aaSBjoern Hartmann {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* RTL8723A */ 1048bb555aaSBjoern Hartmann {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 1058bb555aaSBjoern Hartmann {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for LI */ 1068bb555aaSBjoern Hartmann {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */ 1078bb555aaSBjoern Hartmann {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for Azurewave */ 1088bb555aaSBjoern Hartmann 1098bb555aaSBjoern Hartmann {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1108bb555aaSBjoern Hartmann {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1118bb555aaSBjoern Hartmann {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1128bb555aaSBjoern Hartmann {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */ 1138bb555aaSBjoern Hartmann 1148bb555aaSBjoern Hartmann {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 1158bb555aaSBjoern Hartmann {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */ 1168bb555aaSBjoern Hartmann {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for LC */ 1178bb555aaSBjoern Hartmann {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1188bb555aaSBjoern Hartmann {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1198bb555aaSBjoern Hartmann {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for HP */ 1208bb555aaSBjoern Hartmann {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1218bb555aaSBjoern Hartmann {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1228bb555aaSBjoern Hartmann {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1238bb555aaSBjoern Hartmann {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1248bb555aaSBjoern Hartmann 1258bb555aaSBjoern Hartmann {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1268bb555aaSBjoern Hartmann {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1278bb555aaSBjoern Hartmann {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */ 1288bb555aaSBjoern Hartmann {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1298bb555aaSBjoern Hartmann {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1308bb555aaSBjoern Hartmann {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */ 1318bb555aaSBjoern Hartmann 1328bb555aaSBjoern Hartmann {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU only */ 1338bb555aaSBjoern Hartmann {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 1348bb555aaSBjoern Hartmann {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 1358bb555aaSBjoern Hartmann {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 1368bb555aaSBjoern Hartmann {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 1378bb555aaSBjoern Hartmann {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE for LI */ 1388bb555aaSBjoern Hartmann {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8812AE */ 1398bb555aaSBjoern Hartmann {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8814AE */ 1408bb555aaSBjoern Hartmann 1418bb555aaSBjoern Hartmann {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1428bb555aaSBjoern Hartmann {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1438bb555aaSBjoern Hartmann {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */ 1448bb555aaSBjoern Hartmann {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1458bb555aaSBjoern Hartmann {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1468bb555aaSBjoern Hartmann {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1478bb555aaSBjoern Hartmann {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1488bb555aaSBjoern Hartmann 1498bb555aaSBjoern Hartmann {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */ 1508bb555aaSBjoern Hartmann {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 1518bb555aaSBjoern Hartmann {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 1528bb555aaSBjoern Hartmann {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 1538bb555aaSBjoern Hartmann 1548bb555aaSBjoern Hartmann {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 1558bb555aaSBjoern Hartmann {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1568bb555aaSBjoern Hartmann {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1578bb555aaSBjoern Hartmann {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 1588bb555aaSBjoern Hartmann {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 1598bb555aaSBjoern Hartmann 1608bb555aaSBjoern Hartmann {0x8771, 0x8761, "mp_rtl8761bu_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */ 1618bb555aaSBjoern Hartmann 1628bb555aaSBjoern Hartmann /* NOTE: must append patch entries above the null entry */ 1638bb555aaSBjoern Hartmann {0, 0, NULL, NULL, NULL, NULL, 0}}; 1648bb555aaSBjoern Hartmann 1658bb555aaSBjoern Hartmann uint16_t project_id[] = { 1668bb555aaSBjoern Hartmann ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 1678bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 1688bb555aaSBjoern Hartmann ROM_LMP_8821a, /* RTL8821CU */ 1698bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 1708bb555aaSBjoern Hartmann ROM_LMP_8761a, /* index 14 for 8761BU */ 1718bb555aaSBjoern Hartmann }; 1728bb555aaSBjoern Hartmann 1738bb555aaSBjoern Hartmann static btstack_packet_callback_registration_t hci_event_callback_registration; 1748bb555aaSBjoern Hartmann static uint8_t state = STATE_READ_ROM_VERSION; 1758bb555aaSBjoern Hartmann static uint8_t rom_version; 1768bb555aaSBjoern Hartmann static uint16_t lmp_subversion; 1778bb555aaSBjoern Hartmann static uint16_t product_id; 1788bb555aaSBjoern Hartmann static patch_info * patch; 1798bb555aaSBjoern Hartmann 1808bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 1818bb555aaSBjoern Hartmann static const char *firmware_folder_path = "."; 1828bb555aaSBjoern Hartmann static const char *firmware_file_path; 1838bb555aaSBjoern Hartmann static const char *config_folder_path = "."; 1848bb555aaSBjoern Hartmann static const char *config_file_path; 1858bb555aaSBjoern Hartmann static char firmware_file[1000]; 1868bb555aaSBjoern Hartmann static char config_file[1000]; 1878bb555aaSBjoern Hartmann #endif 1888bb555aaSBjoern Hartmann 1898bb555aaSBjoern Hartmann const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 1908bb555aaSBjoern Hartmann const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 1918bb555aaSBjoern Hartmann 1928bb555aaSBjoern Hartmann static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 1938bb555aaSBjoern Hartmann UNUSED(channel); 1948bb555aaSBjoern Hartmann UNUSED(size); 1958bb555aaSBjoern Hartmann if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 1968bb555aaSBjoern Hartmann return; 1978bb555aaSBjoern Hartmann } 1988bb555aaSBjoern Hartmann uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 1998bb555aaSBjoern Hartmann 2008bb555aaSBjoern Hartmann switch (opcode) { 2018bb555aaSBjoern Hartmann case HCI_READ_ROM_VERSION: 2028bb555aaSBjoern Hartmann rom_version = hci_event_command_complete_get_return_parameters(packet)[1]; 2038bb555aaSBjoern Hartmann log_info("Received ROM version 0x%02x", rom_version); 2048bb555aaSBjoern Hartmann break; 2058bb555aaSBjoern Hartmann default: 2068bb555aaSBjoern Hartmann break; 2078bb555aaSBjoern Hartmann } 2088bb555aaSBjoern Hartmann } 2098bb555aaSBjoern Hartmann 2108bb555aaSBjoern Hartmann static void chipset_init(const void *config) { 2118bb555aaSBjoern Hartmann UNUSED(config); 2128bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 2138bb555aaSBjoern Hartmann // determine file path 2148bb555aaSBjoern Hartmann if (firmware_file_path == NULL || config_file_path == NULL) { 2158bb555aaSBjoern Hartmann log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 2168bb555aaSBjoern Hartmann patch = NULL; 21792728706SMatthias Ringwald for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 2188bb555aaSBjoern Hartmann if (fw_patch_table[i].prod_id == product_id) { 2198bb555aaSBjoern Hartmann patch = &fw_patch_table[i]; 2208bb555aaSBjoern Hartmann break; 2218bb555aaSBjoern Hartmann } 2228bb555aaSBjoern Hartmann } 2238bb555aaSBjoern Hartmann if (patch == NULL) { 2248bb555aaSBjoern Hartmann log_info("Product id 0x%04x is unknown", product_id); 2258bb555aaSBjoern Hartmann state = STATE_DONE; 2268bb555aaSBjoern Hartmann return; 2278bb555aaSBjoern Hartmann } 22874f83314SMatthias Ringwald snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 22974f83314SMatthias Ringwald snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 2308bb555aaSBjoern Hartmann firmware_file_path = &firmware_file[0]; 2318bb555aaSBjoern Hartmann config_file_path = &config_file[0]; 2328bb555aaSBjoern Hartmann lmp_subversion = patch->lmp_sub; 2338bb555aaSBjoern Hartmann } 2348bb555aaSBjoern Hartmann log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 2358bb555aaSBjoern Hartmann 2368bb555aaSBjoern Hartmann // activate hci callback 2378bb555aaSBjoern Hartmann hci_event_callback_registration.callback = &hci_packet_handler; 2388bb555aaSBjoern Hartmann hci_add_event_handler(&hci_event_callback_registration); 2398bb555aaSBjoern Hartmann state = STATE_READ_ROM_VERSION; 2408bb555aaSBjoern Hartmann #endif 2418bb555aaSBjoern Hartmann } 2428bb555aaSBjoern Hartmann 2438bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 2448bb555aaSBjoern Hartmann 2458bb555aaSBjoern Hartmann /** 2468bb555aaSBjoern Hartmann * @brief Opens the specified file and stores content to an allocated buffer 2478bb555aaSBjoern Hartmann * 2488bb555aaSBjoern Hartmann * @param file 2498bb555aaSBjoern Hartmann * @param buf 2508bb555aaSBjoern Hartmann * @param name 2518bb555aaSBjoern Hartmann * @return uint32_t Length of file 2528bb555aaSBjoern Hartmann */ 2538bb555aaSBjoern Hartmann static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 2548bb555aaSBjoern Hartmann uint32_t size; 2558bb555aaSBjoern Hartmann 2568bb555aaSBjoern Hartmann // open file 2578bb555aaSBjoern Hartmann *file = fopen(name, "rb"); 2588bb555aaSBjoern Hartmann if (*file == NULL) { 2598bb555aaSBjoern Hartmann log_info("Failed to open file %s", name); 2608bb555aaSBjoern Hartmann return 0; 2618bb555aaSBjoern Hartmann } 2628bb555aaSBjoern Hartmann 2638bb555aaSBjoern Hartmann // determine length of file 2648bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_END); 2658bb555aaSBjoern Hartmann size = ftell(*file); 2668bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_SET); 2678bb555aaSBjoern Hartmann if (size <= 0) { 2688bb555aaSBjoern Hartmann return 0; 2698bb555aaSBjoern Hartmann } 2708bb555aaSBjoern Hartmann 2718bb555aaSBjoern Hartmann // allocate memory 2728bb555aaSBjoern Hartmann *buf = malloc(size); 2738bb555aaSBjoern Hartmann if (*buf == NULL) { 2748bb555aaSBjoern Hartmann fclose(*file); 2758bb555aaSBjoern Hartmann *file = NULL; 2768bb555aaSBjoern Hartmann log_info("Failed to allocate %u bytes for file %s", size, name); 2778bb555aaSBjoern Hartmann return 0; 2788bb555aaSBjoern Hartmann } 2798bb555aaSBjoern Hartmann 2808bb555aaSBjoern Hartmann // read file 28158080ea6SMatthias Ringwald size_t ret = fread(*buf, size, 1, *file); 2828bb555aaSBjoern Hartmann if (ret != 1) { 283*09fffc16SMatthias Ringwald log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 2848bb555aaSBjoern Hartmann fclose(*file); 2858bb555aaSBjoern Hartmann free(*buf); 2868bb555aaSBjoern Hartmann *file = NULL; 2878bb555aaSBjoern Hartmann *buf = NULL; 2888bb555aaSBjoern Hartmann return 0; 2898bb555aaSBjoern Hartmann } 2908bb555aaSBjoern Hartmann 2918bb555aaSBjoern Hartmann log_info("Opened file %s and read %u bytes", name, size); 2928bb555aaSBjoern Hartmann return size; 2938bb555aaSBjoern Hartmann } 2948bb555aaSBjoern Hartmann 2958bb555aaSBjoern Hartmann static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 2968bb555aaSBjoern Hartmann fclose(*file); 2978bb555aaSBjoern Hartmann free(*buffer); 2988bb555aaSBjoern Hartmann *buffer = NULL; 2998bb555aaSBjoern Hartmann *file = NULL; 3008bb555aaSBjoern Hartmann } 3018bb555aaSBjoern Hartmann 3028bb555aaSBjoern Hartmann static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 3038bb555aaSBjoern Hartmann static uint8_t *patch_buf = NULL; 3048bb555aaSBjoern Hartmann static uint32_t fw_total_len; 3058bb555aaSBjoern Hartmann static uint32_t fw_ptr; 3068bb555aaSBjoern Hartmann static uint8_t index; 3078bb555aaSBjoern Hartmann 3088bb555aaSBjoern Hartmann // read firmware and config 3098bb555aaSBjoern Hartmann if (patch_buf == NULL) { 3108bb555aaSBjoern Hartmann uint16_t patch_length = 0; 3118bb555aaSBjoern Hartmann uint32_t offset; 3128bb555aaSBjoern Hartmann FILE * fw = NULL; 3138bb555aaSBjoern Hartmann uint32_t fw_size; 3148bb555aaSBjoern Hartmann uint8_t *fw_buf = NULL; 3158bb555aaSBjoern Hartmann 3168bb555aaSBjoern Hartmann FILE * conf = NULL; 3178bb555aaSBjoern Hartmann uint32_t conf_size; 3188bb555aaSBjoern Hartmann uint8_t *conf_buf = NULL; 3198bb555aaSBjoern Hartmann 3208bb555aaSBjoern Hartmann if (firmware == NULL || config == NULL) { 3218bb555aaSBjoern Hartmann log_info("Please specify realtek firmware and config file paths"); 3228bb555aaSBjoern Hartmann return FW_DONE; 3238bb555aaSBjoern Hartmann } 3248bb555aaSBjoern Hartmann 3258bb555aaSBjoern Hartmann // read firmware 3268bb555aaSBjoern Hartmann fw_size = read_file(&fw, &fw_buf, firmware); 3278bb555aaSBjoern Hartmann if (fw_size == 0) { 3288bb555aaSBjoern Hartmann log_info("Firmware size is 0. Quit!"); 3298bb555aaSBjoern Hartmann return FW_DONE; 3308bb555aaSBjoern Hartmann } 3318bb555aaSBjoern Hartmann 3328bb555aaSBjoern Hartmann // read config 3338bb555aaSBjoern Hartmann conf_size = read_file(&conf, &conf_buf, config); 3348bb555aaSBjoern Hartmann if (conf_size == 0) { 3358bb555aaSBjoern Hartmann log_info("Config size is 0. Quit!"); 3368bb555aaSBjoern Hartmann fclose(fw); 3378bb555aaSBjoern Hartmann free(fw_buf); 3388bb555aaSBjoern Hartmann fw_buf = NULL; 3398bb555aaSBjoern Hartmann fw = NULL; 3408bb555aaSBjoern Hartmann return FW_DONE; 3418bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3428bb555aaSBjoern Hartmann } 3438bb555aaSBjoern Hartmann 3448bb555aaSBjoern Hartmann // check signature 3458bb555aaSBjoern Hartmann if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 3468bb555aaSBjoern Hartmann log_info("Wrong signature. Quit!"); 3478bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3488bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3498bb555aaSBjoern Hartmann return FW_DONE; 3508bb555aaSBjoern Hartmann } 3518bb555aaSBjoern Hartmann 3528bb555aaSBjoern Hartmann // check project id 3538bb555aaSBjoern Hartmann if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) { 3548bb555aaSBjoern Hartmann log_info("Wrong project id. Quit!"); 3558bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3568bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3578bb555aaSBjoern Hartmann return FW_DONE; 3588bb555aaSBjoern Hartmann } 3598bb555aaSBjoern Hartmann 3608bb555aaSBjoern Hartmann // read firmware version 3618bb555aaSBjoern Hartmann uint32_t fw_version = little_endian_read_32(fw_buf, 8); 3628bb555aaSBjoern Hartmann log_info("Firmware version: 0x%x", fw_version); 3638bb555aaSBjoern Hartmann 3648bb555aaSBjoern Hartmann // read number of patches 3658bb555aaSBjoern Hartmann uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12); 3668bb555aaSBjoern Hartmann log_info("Number of patches: %d", fw_num_patches); 3678bb555aaSBjoern Hartmann 3688bb555aaSBjoern Hartmann // find correct entry 3698bb555aaSBjoern Hartmann for (uint16_t i = 0; i < fw_num_patches; i++) { 3708bb555aaSBjoern Hartmann if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 3718bb555aaSBjoern Hartmann patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 3728bb555aaSBjoern Hartmann offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 3738bb555aaSBjoern Hartmann log_info("patch_length %u, offset %u", patch_length, offset); 3748bb555aaSBjoern Hartmann break; 3758bb555aaSBjoern Hartmann } 3768bb555aaSBjoern Hartmann } 3778bb555aaSBjoern Hartmann if (patch_length == 0) { 3788bb555aaSBjoern Hartmann log_debug("Failed to find valid patch"); 3798bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3808bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3818bb555aaSBjoern Hartmann return FW_DONE; 3828bb555aaSBjoern Hartmann } 3838bb555aaSBjoern Hartmann 3848bb555aaSBjoern Hartmann // allocate patch buffer 3858bb555aaSBjoern Hartmann fw_total_len = patch_length + conf_size; 3868bb555aaSBjoern Hartmann patch_buf = malloc(fw_total_len); 3878bb555aaSBjoern Hartmann if (patch_buf == NULL) { 3888bb555aaSBjoern Hartmann log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 3898bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 3908bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 3918bb555aaSBjoern Hartmann return FW_DONE; 3928bb555aaSBjoern Hartmann } 3938bb555aaSBjoern Hartmann 3948bb555aaSBjoern Hartmann // copy patch 3958bb555aaSBjoern Hartmann memcpy(patch_buf, fw_buf + offset, patch_length); 3968bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length - 4, &fw_version, 4); 3978bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length, conf_buf, conf_size); 3988bb555aaSBjoern Hartmann fw_ptr = 0; 3998bb555aaSBjoern Hartmann index = 0; 4008bb555aaSBjoern Hartmann 4018bb555aaSBjoern Hartmann // close files 4028bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 4038bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 4048bb555aaSBjoern Hartmann } 4058bb555aaSBjoern Hartmann 4068bb555aaSBjoern Hartmann uint8_t len; 4078bb555aaSBjoern Hartmann if (fw_total_len - fw_ptr > 252) { 4088bb555aaSBjoern Hartmann len = 252; 4098bb555aaSBjoern Hartmann } else { 4108bb555aaSBjoern Hartmann len = fw_total_len - fw_ptr; 4118bb555aaSBjoern Hartmann index |= 0x80; // end 4128bb555aaSBjoern Hartmann } 4138bb555aaSBjoern Hartmann 4148bb555aaSBjoern Hartmann if (len) { 4158bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW); 4168bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, len + 1); 4178bb555aaSBjoern Hartmann FILL_INDEX(hci_cmd_buffer, index); 4188bb555aaSBjoern Hartmann FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 4198bb555aaSBjoern Hartmann index++; 4208bb555aaSBjoern Hartmann fw_ptr += len; 4218bb555aaSBjoern Hartmann return FW_MORE_TO_DO; 4228bb555aaSBjoern Hartmann } 4238bb555aaSBjoern Hartmann 4248bb555aaSBjoern Hartmann // cleanup and return 4258bb555aaSBjoern Hartmann free(patch_buf); 4268bb555aaSBjoern Hartmann patch_buf = NULL; 4278bb555aaSBjoern Hartmann return FW_DONE; 4288bb555aaSBjoern Hartmann } 4298bb555aaSBjoern Hartmann 4308bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 4318bb555aaSBjoern Hartmann 4328bb555aaSBjoern Hartmann static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 4338bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4348bb555aaSBjoern Hartmann uint8_t ret; 4358bb555aaSBjoern Hartmann while (true) { 4368bb555aaSBjoern Hartmann switch (state) { 4378bb555aaSBjoern Hartmann case STATE_READ_ROM_VERSION: 4388bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION); 4398bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 4408bb555aaSBjoern Hartmann state = STATE_LOAD_FIRMWARE; 4418bb555aaSBjoern Hartmann break; 4428bb555aaSBjoern Hartmann case STATE_LOAD_FIRMWARE: 4438bb555aaSBjoern Hartmann if (lmp_subversion != ROM_LMP_8723a) { 4448bb555aaSBjoern Hartmann ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 4458bb555aaSBjoern Hartmann } else { 4468bb555aaSBjoern Hartmann log_info("Realtek firmware for old patch style not implemented"); 4478bb555aaSBjoern Hartmann ret = FW_DONE; 4488bb555aaSBjoern Hartmann } 4498bb555aaSBjoern Hartmann if (ret != FW_DONE) { 4508bb555aaSBjoern Hartmann break; 4518bb555aaSBjoern Hartmann } 4528bb555aaSBjoern Hartmann // we are done fall through 4538bb555aaSBjoern Hartmann state = STATE_RESET; 4548bb555aaSBjoern Hartmann case STATE_RESET: 4558bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_RESET); 4568bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 4578bb555aaSBjoern Hartmann state = STATE_DONE; 4588bb555aaSBjoern Hartmann break; 4598bb555aaSBjoern Hartmann case STATE_DONE: 4608bb555aaSBjoern Hartmann hci_remove_event_handler(&hci_event_callback_registration); 4618bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 4628bb555aaSBjoern Hartmann break; 4638bb555aaSBjoern Hartmann default: 4648bb555aaSBjoern Hartmann log_info("Invalid state %d", state); 4658bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 4668bb555aaSBjoern Hartmann break; 4678bb555aaSBjoern Hartmann } 4688bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_VALID_COMMAND; 4698bb555aaSBjoern Hartmann } 4708bb555aaSBjoern Hartmann #else // HAVE_POSIX_FILE_IO 4718bb555aaSBjoern Hartmann log_info("Realtek without File IO is not implemented yet"); 4728bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 4738bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 4748bb555aaSBjoern Hartmann } 4758bb555aaSBjoern Hartmann 4768bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 4778bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4788bb555aaSBjoern Hartmann firmware_file_path = path; 4798bb555aaSBjoern Hartmann #endif 4808bb555aaSBjoern Hartmann } 4818bb555aaSBjoern Hartmann 4828bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 4838bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4848bb555aaSBjoern Hartmann firmware_folder_path = path; 4858bb555aaSBjoern Hartmann #endif 4868bb555aaSBjoern Hartmann } 4878bb555aaSBjoern Hartmann 4888bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_file_path(const char *path) { 4898bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4908bb555aaSBjoern Hartmann config_file_path = path; 4918bb555aaSBjoern Hartmann #endif 4928bb555aaSBjoern Hartmann } 4938bb555aaSBjoern Hartmann 4948bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_folder_path(const char *path) { 4958bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4968bb555aaSBjoern Hartmann config_folder_path = path; 4978bb555aaSBjoern Hartmann #endif 4988bb555aaSBjoern Hartmann } 4998bb555aaSBjoern Hartmann 5005a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) { 5015a4c0fdaSMatthias Ringwald lmp_subversion = version; 5025a4c0fdaSMatthias Ringwald } 5038bb555aaSBjoern Hartmann 5045a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_product_id(uint16_t id) { 5055a4c0fdaSMatthias Ringwald product_id = id; 5065a4c0fdaSMatthias Ringwald } 5075a4c0fdaSMatthias Ringwald 5085a4c0fdaSMatthias Ringwald uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 5095a4c0fdaSMatthias Ringwald return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 5105a4c0fdaSMatthias Ringwald } 5115a4c0fdaSMatthias Ringwald 5125a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 5135a4c0fdaSMatthias Ringwald btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 5145a4c0fdaSMatthias Ringwald *out_vendor_id = 0xbda; 5155a4c0fdaSMatthias Ringwald *out_product_id = fw_patch_table[index].prod_id; 5165a4c0fdaSMatthias Ringwald } 5178bb555aaSBjoern Hartmann 5188bb555aaSBjoern Hartmann static const btstack_chipset_t btstack_chipset_realtek = { 5198bb555aaSBjoern Hartmann "REALTEK", chipset_init, chipset_next_command, 5208bb555aaSBjoern Hartmann NULL, // chipset_set_baudrate_command, 5218bb555aaSBjoern Hartmann NULL, // chipset_set_bd_addr_command not supported or implemented 5228bb555aaSBjoern Hartmann }; 5238bb555aaSBjoern Hartmann 5248bb555aaSBjoern Hartmann // MARK: public API 5258bb555aaSBjoern Hartmann const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 526