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 114*3366b4c1SMatthias Ringwald {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BU */ 115*3366b4c1SMatthias Ringwald {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BU */ 116*3366b4c1SMatthias Ringwald 1178bb555aaSBjoern Hartmann {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for LC */ 1188bb555aaSBjoern Hartmann {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1198bb555aaSBjoern Hartmann {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1208bb555aaSBjoern Hartmann {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for HP */ 1218bb555aaSBjoern Hartmann {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1228bb555aaSBjoern Hartmann {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1238bb555aaSBjoern Hartmann {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 1248bb555aaSBjoern Hartmann {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 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 132*3366b4c1SMatthias Ringwald {0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 133*3366b4c1SMatthias Ringwald {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 134*3366b4c1SMatthias Ringwald {0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 135*3366b4c1SMatthias Ringwald {0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 136*3366b4c1SMatthias Ringwald {0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU for LiteOn */ 137*3366b4c1SMatthias Ringwald 138*3366b4c1SMatthias Ringwald {0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 139*3366b4c1SMatthias Ringwald {0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 140*3366b4c1SMatthias Ringwald {0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 141*3366b4c1SMatthias Ringwald 1428bb555aaSBjoern Hartmann {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU only */ 1438bb555aaSBjoern Hartmann {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 1448bb555aaSBjoern Hartmann {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 145*3366b4c1SMatthias Ringwald {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 146*3366b4c1SMatthias Ringwald {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AUV only */ 147*3366b4c1SMatthias Ringwald {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE for LI */ 148*3366b4c1SMatthias Ringwald {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8812AE */ 149*3366b4c1SMatthias Ringwald {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8814AE */ 150*3366b4c1SMatthias Ringwald 151*3366b4c1SMatthias Ringwald {0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */ 152*3366b4c1SMatthias Ringwald {0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0}, /* RTL8725AU */ 153*3366b4c1SMatthias Ringwald {0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0}, /* RTL8725AU BT only */ 1548bb555aaSBjoern Hartmann 1558bb555aaSBjoern Hartmann {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1568bb555aaSBjoern Hartmann {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1578bb555aaSBjoern Hartmann {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */ 1588bb555aaSBjoern Hartmann {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1598bb555aaSBjoern Hartmann {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1608bb555aaSBjoern Hartmann {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1618bb555aaSBjoern Hartmann {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 1628bb555aaSBjoern Hartmann 1638bb555aaSBjoern Hartmann {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 1648bb555aaSBjoern Hartmann {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 165*3366b4c1SMatthias Ringwald {0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 166*3366b4c1SMatthias Ringwald {0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 167*3366b4c1SMatthias Ringwald {0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 168*3366b4c1SMatthias Ringwald {0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 169*3366b4c1SMatthias Ringwald {0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 170*3366b4c1SMatthias Ringwald {0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 171*3366b4c1SMatthias Ringwald {0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 172*3366b4c1SMatthias Ringwald {0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 173*3366b4c1SMatthias Ringwald {0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 174*3366b4c1SMatthias Ringwald {0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 175*3366b4c1SMatthias Ringwald {0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 176*3366b4c1SMatthias Ringwald {0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for LiteOn */ 177*3366b4c1SMatthias Ringwald {0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for LiteOn */ 178*3366b4c1SMatthias Ringwald {0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 179*3366b4c1SMatthias Ringwald {0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 180*3366b4c1SMatthias Ringwald {0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 181*3366b4c1SMatthias Ringwald {0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 182*3366b4c1SMatthias Ringwald {0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 183*3366b4c1SMatthias Ringwald {0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 184*3366b4c1SMatthias Ringwald {0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 185*3366b4c1SMatthias Ringwald {0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 186*3366b4c1SMatthias Ringwald {0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 187*3366b4c1SMatthias Ringwald {0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 188*3366b4c1SMatthias Ringwald {0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for GSD */ 189*3366b4c1SMatthias Ringwald {0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for GSD */ 190*3366b4c1SMatthias Ringwald {0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CUH */ 191*3366b4c1SMatthias Ringwald 192*3366b4c1SMatthias Ringwald {0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", NULL, 0}, /* RTL8821DU */ 193*3366b4c1SMatthias Ringwald 194*3366b4c1SMatthias Ringwald {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */ 1958bb555aaSBjoern Hartmann 1968bb555aaSBjoern Hartmann {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 197*3366b4c1SMatthias Ringwald {0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 198*3366b4c1SMatthias Ringwald {0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 1998bb555aaSBjoern Hartmann 200*3366b4c1SMatthias Ringwald {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 201*3366b4c1SMatthias Ringwald {0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 202*3366b4c1SMatthias Ringwald {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 203*3366b4c1SMatthias Ringwald {0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 204*3366b4c1SMatthias Ringwald {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 205*3366b4c1SMatthias Ringwald {0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 206*3366b4c1SMatthias Ringwald {0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 207*3366b4c1SMatthias Ringwald {0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 208*3366b4c1SMatthias Ringwald {0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 209*3366b4c1SMatthias Ringwald {0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 210*3366b4c1SMatthias Ringwald {0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 211*3366b4c1SMatthias Ringwald {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 212*3366b4c1SMatthias Ringwald {0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 213*3366b4c1SMatthias Ringwald {0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 214*3366b4c1SMatthias Ringwald {0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for LiteOn */ 215*3366b4c1SMatthias Ringwald {0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for LiteOn */ 216*3366b4c1SMatthias Ringwald {0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 217*3366b4c1SMatthias Ringwald {0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 218*3366b4c1SMatthias Ringwald {0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 219*3366b4c1SMatthias Ringwald {0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 220*3366b4c1SMatthias Ringwald {0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 221*3366b4c1SMatthias Ringwald {0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 222*3366b4c1SMatthias Ringwald {0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 223*3366b4c1SMatthias Ringwald {0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 224*3366b4c1SMatthias Ringwald {0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 225*3366b4c1SMatthias Ringwald 226*3366b4c1SMatthias Ringwald {0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", NULL, 0}, /* RTL8851AU */ 227*3366b4c1SMatthias Ringwald 228*3366b4c1SMatthias Ringwald {0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", NULL, 0}, /* RTL8851BU */ 229*3366b4c1SMatthias Ringwald 230*3366b4c1SMatthias Ringwald {0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AU */ 231*3366b4c1SMatthias Ringwald {0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 232*3366b4c1SMatthias Ringwald {0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 233*3366b4c1SMatthias Ringwald {0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 234*3366b4c1SMatthias Ringwald {0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 235*3366b4c1SMatthias Ringwald {0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 236*3366b4c1SMatthias Ringwald {0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 237*3366b4c1SMatthias Ringwald {0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 238*3366b4c1SMatthias Ringwald {0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 239*3366b4c1SMatthias Ringwald {0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 240*3366b4c1SMatthias Ringwald {0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 241*3366b4c1SMatthias Ringwald {0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 242*3366b4c1SMatthias Ringwald {0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 243*3366b4c1SMatthias Ringwald {0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 244*3366b4c1SMatthias Ringwald {0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 245*3366b4c1SMatthias Ringwald {0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 246*3366b4c1SMatthias Ringwald {0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 247*3366b4c1SMatthias Ringwald {0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 248*3366b4c1SMatthias Ringwald {0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 249*3366b4c1SMatthias Ringwald {0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 250*3366b4c1SMatthias Ringwald {0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 251*3366b4c1SMatthias Ringwald 252*3366b4c1SMatthias Ringwald {0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BU */ 253*3366b4c1SMatthias Ringwald {0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 254*3366b4c1SMatthias Ringwald {0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 255*3366b4c1SMatthias Ringwald {0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 256*3366b4c1SMatthias Ringwald {0x3570, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 257*3366b4c1SMatthias Ringwald {0x3572, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 258*3366b4c1SMatthias Ringwald {0x4b06, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 259*3366b4c1SMatthias Ringwald {0x885b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 260*3366b4c1SMatthias Ringwald {0x886b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 261*3366b4c1SMatthias Ringwald {0x887b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 262*3366b4c1SMatthias Ringwald {0xc559, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 263*3366b4c1SMatthias Ringwald {0xb052, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 264*3366b4c1SMatthias Ringwald {0xb152, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 265*3366b4c1SMatthias Ringwald {0xb252, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 266*3366b4c1SMatthias Ringwald {0x4853, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 267*3366b4c1SMatthias Ringwald {0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 268*3366b4c1SMatthias Ringwald 269*3366b4c1SMatthias Ringwald {0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CU */ 270*3366b4c1SMatthias Ringwald {0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 271*3366b4c1SMatthias Ringwald {0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 272*3366b4c1SMatthias Ringwald {0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 273*3366b4c1SMatthias Ringwald {0x885c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 274*3366b4c1SMatthias Ringwald {0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 275*3366b4c1SMatthias Ringwald {0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 276*3366b4c1SMatthias Ringwald {0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 277*3366b4c1SMatthias Ringwald 278*3366b4c1SMatthias Ringwald {0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0}, /* RTL8822EU */ 279*3366b4c1SMatthias Ringwald {0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0}, /* RTL8822EU */ 2808bb555aaSBjoern Hartmann 2818bb555aaSBjoern Hartmann /* NOTE: must append patch entries above the null entry */ 2828bb555aaSBjoern Hartmann {0, 0, NULL, NULL, NULL, NULL, 0}}; 2838bb555aaSBjoern Hartmann 2848bb555aaSBjoern Hartmann uint16_t project_id[] = { 2858bb555aaSBjoern Hartmann ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 2868bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 2878bb555aaSBjoern Hartmann ROM_LMP_8821a, /* RTL8821CU */ 2888bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 2898bb555aaSBjoern Hartmann ROM_LMP_8761a, /* index 14 for 8761BU */ 2908bb555aaSBjoern Hartmann }; 2918bb555aaSBjoern Hartmann 2928bb555aaSBjoern Hartmann static btstack_packet_callback_registration_t hci_event_callback_registration; 2938bb555aaSBjoern Hartmann static uint8_t state = STATE_READ_ROM_VERSION; 2948bb555aaSBjoern Hartmann static uint8_t rom_version; 2958bb555aaSBjoern Hartmann static uint16_t lmp_subversion; 2968bb555aaSBjoern Hartmann static uint16_t product_id; 2978bb555aaSBjoern Hartmann static patch_info * patch; 2988bb555aaSBjoern Hartmann 2998bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 3008bb555aaSBjoern Hartmann static const char *firmware_folder_path = "."; 3018bb555aaSBjoern Hartmann static const char *firmware_file_path; 3028bb555aaSBjoern Hartmann static const char *config_folder_path = "."; 3038bb555aaSBjoern Hartmann static const char *config_file_path; 3048bb555aaSBjoern Hartmann static char firmware_file[1000]; 3058bb555aaSBjoern Hartmann static char config_file[1000]; 3068bb555aaSBjoern Hartmann #endif 3078bb555aaSBjoern Hartmann 3088bb555aaSBjoern Hartmann const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 3098bb555aaSBjoern Hartmann const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 3108bb555aaSBjoern Hartmann 3118bb555aaSBjoern Hartmann static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 3128bb555aaSBjoern Hartmann UNUSED(channel); 3138bb555aaSBjoern Hartmann UNUSED(size); 3148bb555aaSBjoern Hartmann if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 3158bb555aaSBjoern Hartmann return; 3168bb555aaSBjoern Hartmann } 3178bb555aaSBjoern Hartmann uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 3188bb555aaSBjoern Hartmann 3198bb555aaSBjoern Hartmann switch (opcode) { 3208bb555aaSBjoern Hartmann case HCI_READ_ROM_VERSION: 3218bb555aaSBjoern Hartmann rom_version = hci_event_command_complete_get_return_parameters(packet)[1]; 3228bb555aaSBjoern Hartmann log_info("Received ROM version 0x%02x", rom_version); 3238bb555aaSBjoern Hartmann break; 3248bb555aaSBjoern Hartmann default: 3258bb555aaSBjoern Hartmann break; 3268bb555aaSBjoern Hartmann } 3278bb555aaSBjoern Hartmann } 3288bb555aaSBjoern Hartmann 3298bb555aaSBjoern Hartmann static void chipset_init(const void *config) { 3308bb555aaSBjoern Hartmann UNUSED(config); 3318bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 3328bb555aaSBjoern Hartmann // determine file path 3338bb555aaSBjoern Hartmann if (firmware_file_path == NULL || config_file_path == NULL) { 3348bb555aaSBjoern Hartmann log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 3358bb555aaSBjoern Hartmann patch = NULL; 33692728706SMatthias Ringwald for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 3378bb555aaSBjoern Hartmann if (fw_patch_table[i].prod_id == product_id) { 3388bb555aaSBjoern Hartmann patch = &fw_patch_table[i]; 3398bb555aaSBjoern Hartmann break; 3408bb555aaSBjoern Hartmann } 3418bb555aaSBjoern Hartmann } 3428bb555aaSBjoern Hartmann if (patch == NULL) { 3438bb555aaSBjoern Hartmann log_info("Product id 0x%04x is unknown", product_id); 3448bb555aaSBjoern Hartmann state = STATE_DONE; 3458bb555aaSBjoern Hartmann return; 3468bb555aaSBjoern Hartmann } 34774f83314SMatthias Ringwald snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 34874f83314SMatthias Ringwald snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 3498bb555aaSBjoern Hartmann firmware_file_path = &firmware_file[0]; 3508bb555aaSBjoern Hartmann config_file_path = &config_file[0]; 3518bb555aaSBjoern Hartmann lmp_subversion = patch->lmp_sub; 3528bb555aaSBjoern Hartmann } 3538bb555aaSBjoern Hartmann log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 3548bb555aaSBjoern Hartmann 3558bb555aaSBjoern Hartmann // activate hci callback 3568bb555aaSBjoern Hartmann hci_event_callback_registration.callback = &hci_packet_handler; 3578bb555aaSBjoern Hartmann hci_add_event_handler(&hci_event_callback_registration); 3588bb555aaSBjoern Hartmann state = STATE_READ_ROM_VERSION; 3598bb555aaSBjoern Hartmann #endif 3608bb555aaSBjoern Hartmann } 3618bb555aaSBjoern Hartmann 3628bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 3638bb555aaSBjoern Hartmann 3648bb555aaSBjoern Hartmann /** 3658bb555aaSBjoern Hartmann * @brief Opens the specified file and stores content to an allocated buffer 3668bb555aaSBjoern Hartmann * 3678bb555aaSBjoern Hartmann * @param file 3688bb555aaSBjoern Hartmann * @param buf 3698bb555aaSBjoern Hartmann * @param name 3708bb555aaSBjoern Hartmann * @return uint32_t Length of file 3718bb555aaSBjoern Hartmann */ 3728bb555aaSBjoern Hartmann static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 3738bb555aaSBjoern Hartmann uint32_t size; 3748bb555aaSBjoern Hartmann 3758bb555aaSBjoern Hartmann // open file 3768bb555aaSBjoern Hartmann *file = fopen(name, "rb"); 3778bb555aaSBjoern Hartmann if (*file == NULL) { 3788bb555aaSBjoern Hartmann log_info("Failed to open file %s", name); 3798bb555aaSBjoern Hartmann return 0; 3808bb555aaSBjoern Hartmann } 3818bb555aaSBjoern Hartmann 3828bb555aaSBjoern Hartmann // determine length of file 3838bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_END); 3848bb555aaSBjoern Hartmann size = ftell(*file); 3858bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_SET); 3868bb555aaSBjoern Hartmann if (size <= 0) { 3878bb555aaSBjoern Hartmann return 0; 3888bb555aaSBjoern Hartmann } 3898bb555aaSBjoern Hartmann 3908bb555aaSBjoern Hartmann // allocate memory 3918bb555aaSBjoern Hartmann *buf = malloc(size); 3928bb555aaSBjoern Hartmann if (*buf == NULL) { 3938bb555aaSBjoern Hartmann fclose(*file); 3948bb555aaSBjoern Hartmann *file = NULL; 3958bb555aaSBjoern Hartmann log_info("Failed to allocate %u bytes for file %s", size, name); 3968bb555aaSBjoern Hartmann return 0; 3978bb555aaSBjoern Hartmann } 3988bb555aaSBjoern Hartmann 3998bb555aaSBjoern Hartmann // read file 40058080ea6SMatthias Ringwald size_t ret = fread(*buf, size, 1, *file); 4018bb555aaSBjoern Hartmann if (ret != 1) { 40209fffc16SMatthias Ringwald log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 4038bb555aaSBjoern Hartmann fclose(*file); 4048bb555aaSBjoern Hartmann free(*buf); 4058bb555aaSBjoern Hartmann *file = NULL; 4068bb555aaSBjoern Hartmann *buf = NULL; 4078bb555aaSBjoern Hartmann return 0; 4088bb555aaSBjoern Hartmann } 4098bb555aaSBjoern Hartmann 4108bb555aaSBjoern Hartmann log_info("Opened file %s and read %u bytes", name, size); 4118bb555aaSBjoern Hartmann return size; 4128bb555aaSBjoern Hartmann } 4138bb555aaSBjoern Hartmann 4148bb555aaSBjoern Hartmann static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 4158bb555aaSBjoern Hartmann fclose(*file); 4168bb555aaSBjoern Hartmann free(*buffer); 4178bb555aaSBjoern Hartmann *buffer = NULL; 4188bb555aaSBjoern Hartmann *file = NULL; 4198bb555aaSBjoern Hartmann } 4208bb555aaSBjoern Hartmann 4218bb555aaSBjoern Hartmann static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 4228bb555aaSBjoern Hartmann static uint8_t *patch_buf = NULL; 4238bb555aaSBjoern Hartmann static uint32_t fw_total_len; 4248bb555aaSBjoern Hartmann static uint32_t fw_ptr; 4258bb555aaSBjoern Hartmann static uint8_t index; 4268bb555aaSBjoern Hartmann 4278bb555aaSBjoern Hartmann // read firmware and config 4288bb555aaSBjoern Hartmann if (patch_buf == NULL) { 4298bb555aaSBjoern Hartmann uint16_t patch_length = 0; 4308bb555aaSBjoern Hartmann uint32_t offset; 4318bb555aaSBjoern Hartmann FILE * fw = NULL; 4328bb555aaSBjoern Hartmann uint32_t fw_size; 4338bb555aaSBjoern Hartmann uint8_t *fw_buf = NULL; 4348bb555aaSBjoern Hartmann 4358bb555aaSBjoern Hartmann FILE * conf = NULL; 4368bb555aaSBjoern Hartmann uint32_t conf_size; 4378bb555aaSBjoern Hartmann uint8_t *conf_buf = NULL; 4388bb555aaSBjoern Hartmann 4398bb555aaSBjoern Hartmann if (firmware == NULL || config == NULL) { 4408bb555aaSBjoern Hartmann log_info("Please specify realtek firmware and config file paths"); 4418bb555aaSBjoern Hartmann return FW_DONE; 4428bb555aaSBjoern Hartmann } 4438bb555aaSBjoern Hartmann 4448bb555aaSBjoern Hartmann // read firmware 4458bb555aaSBjoern Hartmann fw_size = read_file(&fw, &fw_buf, firmware); 4468bb555aaSBjoern Hartmann if (fw_size == 0) { 4478bb555aaSBjoern Hartmann log_info("Firmware size is 0. Quit!"); 4488bb555aaSBjoern Hartmann return FW_DONE; 4498bb555aaSBjoern Hartmann } 4508bb555aaSBjoern Hartmann 4518bb555aaSBjoern Hartmann // read config 4528bb555aaSBjoern Hartmann conf_size = read_file(&conf, &conf_buf, config); 4538bb555aaSBjoern Hartmann if (conf_size == 0) { 4548bb555aaSBjoern Hartmann log_info("Config size is 0. Quit!"); 4558bb555aaSBjoern Hartmann fclose(fw); 4568bb555aaSBjoern Hartmann free(fw_buf); 4578bb555aaSBjoern Hartmann fw_buf = NULL; 4588bb555aaSBjoern Hartmann fw = NULL; 4598bb555aaSBjoern Hartmann return FW_DONE; 4608bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 4618bb555aaSBjoern Hartmann } 4628bb555aaSBjoern Hartmann 4638bb555aaSBjoern Hartmann // check signature 4648bb555aaSBjoern Hartmann if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 4658bb555aaSBjoern Hartmann log_info("Wrong signature. Quit!"); 4668bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 4678bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 4688bb555aaSBjoern Hartmann return FW_DONE; 4698bb555aaSBjoern Hartmann } 4708bb555aaSBjoern Hartmann 4718bb555aaSBjoern Hartmann // check project id 4728bb555aaSBjoern Hartmann if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) { 4738bb555aaSBjoern Hartmann log_info("Wrong project id. Quit!"); 4748bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 4758bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 4768bb555aaSBjoern Hartmann return FW_DONE; 4778bb555aaSBjoern Hartmann } 4788bb555aaSBjoern Hartmann 4798bb555aaSBjoern Hartmann // read firmware version 4808bb555aaSBjoern Hartmann uint32_t fw_version = little_endian_read_32(fw_buf, 8); 4818bb555aaSBjoern Hartmann log_info("Firmware version: 0x%x", fw_version); 4828bb555aaSBjoern Hartmann 4838bb555aaSBjoern Hartmann // read number of patches 4848bb555aaSBjoern Hartmann uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12); 4858bb555aaSBjoern Hartmann log_info("Number of patches: %d", fw_num_patches); 4868bb555aaSBjoern Hartmann 4878bb555aaSBjoern Hartmann // find correct entry 4888bb555aaSBjoern Hartmann for (uint16_t i = 0; i < fw_num_patches; i++) { 4898bb555aaSBjoern Hartmann if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 4908bb555aaSBjoern Hartmann patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 4918bb555aaSBjoern Hartmann offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 4928bb555aaSBjoern Hartmann log_info("patch_length %u, offset %u", patch_length, offset); 4938bb555aaSBjoern Hartmann break; 4948bb555aaSBjoern Hartmann } 4958bb555aaSBjoern Hartmann } 4968bb555aaSBjoern Hartmann if (patch_length == 0) { 4978bb555aaSBjoern Hartmann log_debug("Failed to find valid patch"); 4988bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 4998bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 5008bb555aaSBjoern Hartmann return FW_DONE; 5018bb555aaSBjoern Hartmann } 5028bb555aaSBjoern Hartmann 5038bb555aaSBjoern Hartmann // allocate patch buffer 5048bb555aaSBjoern Hartmann fw_total_len = patch_length + conf_size; 5058bb555aaSBjoern Hartmann patch_buf = malloc(fw_total_len); 5068bb555aaSBjoern Hartmann if (patch_buf == NULL) { 5078bb555aaSBjoern Hartmann log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 5088bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 5098bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 5108bb555aaSBjoern Hartmann return FW_DONE; 5118bb555aaSBjoern Hartmann } 5128bb555aaSBjoern Hartmann 5138bb555aaSBjoern Hartmann // copy patch 5148bb555aaSBjoern Hartmann memcpy(patch_buf, fw_buf + offset, patch_length); 5158bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length - 4, &fw_version, 4); 5168bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length, conf_buf, conf_size); 5178bb555aaSBjoern Hartmann fw_ptr = 0; 5188bb555aaSBjoern Hartmann index = 0; 5198bb555aaSBjoern Hartmann 5208bb555aaSBjoern Hartmann // close files 5218bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 5228bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 5238bb555aaSBjoern Hartmann } 5248bb555aaSBjoern Hartmann 5258bb555aaSBjoern Hartmann uint8_t len; 5268bb555aaSBjoern Hartmann if (fw_total_len - fw_ptr > 252) { 5278bb555aaSBjoern Hartmann len = 252; 5288bb555aaSBjoern Hartmann } else { 5298bb555aaSBjoern Hartmann len = fw_total_len - fw_ptr; 5308bb555aaSBjoern Hartmann index |= 0x80; // end 5318bb555aaSBjoern Hartmann } 5328bb555aaSBjoern Hartmann 5338bb555aaSBjoern Hartmann if (len) { 5348bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW); 5358bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, len + 1); 5368bb555aaSBjoern Hartmann FILL_INDEX(hci_cmd_buffer, index); 5378bb555aaSBjoern Hartmann FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 5388bb555aaSBjoern Hartmann index++; 5398bb555aaSBjoern Hartmann fw_ptr += len; 5408bb555aaSBjoern Hartmann return FW_MORE_TO_DO; 5418bb555aaSBjoern Hartmann } 5428bb555aaSBjoern Hartmann 5438bb555aaSBjoern Hartmann // cleanup and return 5448bb555aaSBjoern Hartmann free(patch_buf); 5458bb555aaSBjoern Hartmann patch_buf = NULL; 5468bb555aaSBjoern Hartmann return FW_DONE; 5478bb555aaSBjoern Hartmann } 5488bb555aaSBjoern Hartmann 5498bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 5508bb555aaSBjoern Hartmann 5518bb555aaSBjoern Hartmann static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 5528bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 5538bb555aaSBjoern Hartmann uint8_t ret; 5548bb555aaSBjoern Hartmann while (true) { 5558bb555aaSBjoern Hartmann switch (state) { 5568bb555aaSBjoern Hartmann case STATE_READ_ROM_VERSION: 5578bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION); 5588bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 5598bb555aaSBjoern Hartmann state = STATE_LOAD_FIRMWARE; 5608bb555aaSBjoern Hartmann break; 5618bb555aaSBjoern Hartmann case STATE_LOAD_FIRMWARE: 5628bb555aaSBjoern Hartmann if (lmp_subversion != ROM_LMP_8723a) { 5638bb555aaSBjoern Hartmann ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 5648bb555aaSBjoern Hartmann } else { 5658bb555aaSBjoern Hartmann log_info("Realtek firmware for old patch style not implemented"); 5668bb555aaSBjoern Hartmann ret = FW_DONE; 5678bb555aaSBjoern Hartmann } 5688bb555aaSBjoern Hartmann if (ret != FW_DONE) { 5698bb555aaSBjoern Hartmann break; 5708bb555aaSBjoern Hartmann } 5718bb555aaSBjoern Hartmann // we are done fall through 5728bb555aaSBjoern Hartmann state = STATE_RESET; 5738bb555aaSBjoern Hartmann case STATE_RESET: 5748bb555aaSBjoern Hartmann FILL_COMMAND(hci_cmd_buffer, HCI_RESET); 5758bb555aaSBjoern Hartmann FILL_LENGTH(hci_cmd_buffer, 0); 5768bb555aaSBjoern Hartmann state = STATE_DONE; 5778bb555aaSBjoern Hartmann break; 5788bb555aaSBjoern Hartmann case STATE_DONE: 5798bb555aaSBjoern Hartmann hci_remove_event_handler(&hci_event_callback_registration); 5808bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 5818bb555aaSBjoern Hartmann break; 5828bb555aaSBjoern Hartmann default: 5838bb555aaSBjoern Hartmann log_info("Invalid state %d", state); 5848bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 5858bb555aaSBjoern Hartmann break; 5868bb555aaSBjoern Hartmann } 5878bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_VALID_COMMAND; 5888bb555aaSBjoern Hartmann } 5898bb555aaSBjoern Hartmann #else // HAVE_POSIX_FILE_IO 5908bb555aaSBjoern Hartmann log_info("Realtek without File IO is not implemented yet"); 5918bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 5928bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 5938bb555aaSBjoern Hartmann } 5948bb555aaSBjoern Hartmann 5958bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 5968bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 5978bb555aaSBjoern Hartmann firmware_file_path = path; 5988bb555aaSBjoern Hartmann #endif 5998bb555aaSBjoern Hartmann } 6008bb555aaSBjoern Hartmann 6018bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 6028bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 6038bb555aaSBjoern Hartmann firmware_folder_path = path; 6048bb555aaSBjoern Hartmann #endif 6058bb555aaSBjoern Hartmann } 6068bb555aaSBjoern Hartmann 6078bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_file_path(const char *path) { 6088bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 6098bb555aaSBjoern Hartmann config_file_path = path; 6108bb555aaSBjoern Hartmann #endif 6118bb555aaSBjoern Hartmann } 6128bb555aaSBjoern Hartmann 6138bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_folder_path(const char *path) { 6148bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 6158bb555aaSBjoern Hartmann config_folder_path = path; 6168bb555aaSBjoern Hartmann #endif 6178bb555aaSBjoern Hartmann } 6188bb555aaSBjoern Hartmann 6195a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) { 6205a4c0fdaSMatthias Ringwald lmp_subversion = version; 6215a4c0fdaSMatthias Ringwald } 6228bb555aaSBjoern Hartmann 6235a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_product_id(uint16_t id) { 6245a4c0fdaSMatthias Ringwald product_id = id; 6255a4c0fdaSMatthias Ringwald } 6265a4c0fdaSMatthias Ringwald 6275a4c0fdaSMatthias Ringwald uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 6285a4c0fdaSMatthias Ringwald return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 6295a4c0fdaSMatthias Ringwald } 6305a4c0fdaSMatthias Ringwald 6315a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 6325a4c0fdaSMatthias Ringwald btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 6335a4c0fdaSMatthias Ringwald *out_vendor_id = 0xbda; 6345a4c0fdaSMatthias Ringwald *out_product_id = fw_patch_table[index].prod_id; 6355a4c0fdaSMatthias Ringwald } 6368bb555aaSBjoern Hartmann 6378bb555aaSBjoern Hartmann static const btstack_chipset_t btstack_chipset_realtek = { 6388bb555aaSBjoern Hartmann "REALTEK", chipset_init, chipset_next_command, 6398bb555aaSBjoern Hartmann NULL, // chipset_set_baudrate_command, 6408bb555aaSBjoern Hartmann NULL, // chipset_set_bd_addr_command not supported or implemented 6418bb555aaSBjoern Hartmann }; 6428bb555aaSBjoern Hartmann 6438bb555aaSBjoern Hartmann // MARK: public API 6448bb555aaSBjoern Hartmann const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 645