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