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" 55*7977fdcaSMatthias Ringwald #include "btstack_linked_list.h" 568bb555aaSBjoern Hartmann #include "btstack_util.h" 578bb555aaSBjoern Hartmann #include "hci.h" 588bb555aaSBjoern Hartmann #include "hci_transport.h" 598bb555aaSBjoern Hartmann 6074f83314SMatthias Ringwald #ifdef _MSC_VER 6174f83314SMatthias Ringwald // ignore deprecated warning for fopen 6274f83314SMatthias Ringwald #pragma warning(disable : 4996) 6374f83314SMatthias Ringwald #endif 6474f83314SMatthias Ringwald 658bb555aaSBjoern Hartmann #define ROM_LMP_NONE 0x0000 668bb555aaSBjoern Hartmann #define ROM_LMP_8723a 0x1200 678bb555aaSBjoern Hartmann #define ROM_LMP_8723b 0x8723 68*7977fdcaSMatthias Ringwald #define ROM_LMP_8821a 0x8821 69*7977fdcaSMatthias Ringwald #define ROM_LMP_8761a 0x8761 70*7977fdcaSMatthias Ringwald #define ROM_LMP_8822b 0x8822 71*7977fdcaSMatthias Ringwald #define ROM_LMP_8852a 0x8852 72*7977fdcaSMatthias Ringwald #define ROM_LMP_8851b 0x8851 738bb555aaSBjoern Hartmann 74*7977fdcaSMatthias Ringwald #define HCI_OPCODE_HCI_RTK_DOWNLOAD_FW 0xFC20 75*7977fdcaSMatthias Ringwald #define HCI_OPCODE_HCI_RTK_READ_ROM_VERSION 0xFC6D 768bb555aaSBjoern Hartmann 77*7977fdcaSMatthias Ringwald #define READ_SEC_PROJ 4 78*7977fdcaSMatthias Ringwald 79*7977fdcaSMatthias Ringwald #define HCI_CMD_SET_OPCODE(buf, opcode) little_endian_store_16(buf, 0, opcode) 80*7977fdcaSMatthias Ringwald #define HCI_CMD_SET_LENGTH(buf, length) buf[2] = length 81*7977fdcaSMatthias Ringwald #define HCI_CMD_DOWNLOAD_SET_INDEX(buf, index) buf[3] = index 82*7977fdcaSMatthias Ringwald #define HCI_CMD_DOWNLOAD_COPY_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 83*7977fdcaSMatthias Ringwald 84*7977fdcaSMatthias Ringwald #define PATCH_SNIPPETS 0x01 85*7977fdcaSMatthias Ringwald #define PATCH_DUMMY_HEADER 0x02 86*7977fdcaSMatthias Ringwald #define PATCH_SECURITY_HEADER 0x03 87*7977fdcaSMatthias Ringwald #define PATCH_OTA_FLAG 0x04 88*7977fdcaSMatthias Ringwald #define SECTION_HEADER_SIZE 8 89*7977fdcaSMatthias Ringwald 90*7977fdcaSMatthias Ringwald /* software id */ 91*7977fdcaSMatthias Ringwald #define RTLPREVIOUS 0x00 92*7977fdcaSMatthias Ringwald #define RTL8822BU 0x70 93*7977fdcaSMatthias Ringwald #define RTL8723DU 0x71 94*7977fdcaSMatthias Ringwald #define RTL8821CU 0x72 95*7977fdcaSMatthias Ringwald #define RTL8822CU 0x73 96*7977fdcaSMatthias Ringwald #define RTL8761BU 0x74 97*7977fdcaSMatthias Ringwald #define RTL8852AU 0x75 98*7977fdcaSMatthias Ringwald #define RTL8723FU 0x76 99*7977fdcaSMatthias Ringwald #define RTL8852BU 0x77 100*7977fdcaSMatthias Ringwald #define RTL8852CU 0x78 101*7977fdcaSMatthias Ringwald #define RTL8822EU 0x79 102*7977fdcaSMatthias Ringwald #define RTL8851BU 0x7A 103*7977fdcaSMatthias Ringwald 104*7977fdcaSMatthias Ringwald struct rtk_epatch_entry { 105*7977fdcaSMatthias Ringwald uint16_t chipID; 106*7977fdcaSMatthias Ringwald uint16_t patch_length; 107*7977fdcaSMatthias Ringwald uint32_t start_offset; 108*7977fdcaSMatthias Ringwald } __attribute__ ((packed)); 109*7977fdcaSMatthias Ringwald 110*7977fdcaSMatthias Ringwald struct rtk_epatch { 111*7977fdcaSMatthias Ringwald uint8_t signature[8]; 112*7977fdcaSMatthias Ringwald uint32_t fw_version; 113*7977fdcaSMatthias Ringwald uint16_t number_of_total_patch; 114*7977fdcaSMatthias Ringwald struct rtk_epatch_entry entry[0]; 115*7977fdcaSMatthias Ringwald } __attribute__ ((packed)); 116*7977fdcaSMatthias Ringwald 117*7977fdcaSMatthias Ringwald struct rtk_extension_entry { 118*7977fdcaSMatthias Ringwald uint8_t opcode; 119*7977fdcaSMatthias Ringwald uint8_t length; 120*7977fdcaSMatthias Ringwald uint8_t *data; 121*7977fdcaSMatthias Ringwald } __attribute__ ((packed)); 122*7977fdcaSMatthias Ringwald 123*7977fdcaSMatthias Ringwald struct rtb_section_hdr { 124*7977fdcaSMatthias Ringwald uint32_t opcode; 125*7977fdcaSMatthias Ringwald uint32_t section_len; 126*7977fdcaSMatthias Ringwald uint32_t soffset; 127*7977fdcaSMatthias Ringwald } __attribute__ ((packed)); 128*7977fdcaSMatthias Ringwald 129*7977fdcaSMatthias Ringwald struct rtb_new_patch_hdr { 130*7977fdcaSMatthias Ringwald uint8_t signature[8]; 131*7977fdcaSMatthias Ringwald uint8_t fw_version[8]; 132*7977fdcaSMatthias Ringwald uint32_t number_of_section; 133*7977fdcaSMatthias Ringwald } __attribute__ ((packed)); 1348bb555aaSBjoern Hartmann 1358bb555aaSBjoern Hartmann enum { 136*7977fdcaSMatthias Ringwald // Pre-Init: runs before HCI Reset 137*7977fdcaSMatthias Ringwald STATE_PHASE_1_READ_LMP_SUBVERSION, 138*7977fdcaSMatthias Ringwald STATE_PHASE_1_W4_READ_LMP_SUBVERSION, 139*7977fdcaSMatthias Ringwald STATE_PHASE_1_READ_HCI_REVISION, 140*7977fdcaSMatthias Ringwald STATE_PHASE_1_W4_READ_HCI_REVISION, 141*7977fdcaSMatthias Ringwald STATE_PHASE_1_DONE, 142*7977fdcaSMatthias Ringwald // Custom Init: runs after HCI Reset 143*7977fdcaSMatthias Ringwald STATE_PHASE_2_READ_ROM_VERSION, 144*7977fdcaSMatthias Ringwald STATE_PHASE_2_READ_SEC_PROJ, 145*7977fdcaSMatthias Ringwald STATE_PHASE_2_W4_SEC_PROJ, 146*7977fdcaSMatthias Ringwald STATE_PHASE_2_LOAD_FIRMWARE, 147*7977fdcaSMatthias Ringwald STATE_PHASE_2_RESET, 148*7977fdcaSMatthias Ringwald STATE_PHASE_2_DONE, 1498bb555aaSBjoern Hartmann }; 1508bb555aaSBjoern Hartmann enum { FW_DONE, FW_MORE_TO_DO }; 1518bb555aaSBjoern Hartmann 1528bb555aaSBjoern Hartmann typedef struct { 1538bb555aaSBjoern Hartmann uint16_t prod_id; 1548bb555aaSBjoern Hartmann uint16_t lmp_sub; 1558bb555aaSBjoern Hartmann char * mp_patch_name; 1568bb555aaSBjoern Hartmann char * patch_name; 1578bb555aaSBjoern Hartmann char * config_name; 1588bb555aaSBjoern Hartmann 1598bb555aaSBjoern Hartmann uint8_t *fw_cache1; 1608bb555aaSBjoern Hartmann int fw_len1; 161*7977fdcaSMatthias Ringwald uint8_t chip_type; 1628bb555aaSBjoern Hartmann } patch_info; 1638bb555aaSBjoern Hartmann 164*7977fdcaSMatthias Ringwald static const patch_info fw_patch_table[] = { 165*7977fdcaSMatthias Ringwald /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, chip_type } */ 166*7977fdcaSMatthias Ringwald {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* RTL8723A */ 167*7977fdcaSMatthias Ringwald {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 168*7977fdcaSMatthias Ringwald {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for LI */ 169*7977fdcaSMatthias Ringwald {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 170*7977fdcaSMatthias Ringwald {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for Azurewave */ 1718bb555aaSBjoern Hartmann 172*7977fdcaSMatthias Ringwald {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 173*7977fdcaSMatthias Ringwald {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 174*7977fdcaSMatthias Ringwald {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 175*7977fdcaSMatthias Ringwald {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 1768bb555aaSBjoern Hartmann 177*7977fdcaSMatthias Ringwald {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 178*7977fdcaSMatthias Ringwald {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 179*7977fdcaSMatthias Ringwald {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for LC */ 180*7977fdcaSMatthias Ringwald {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 181*7977fdcaSMatthias Ringwald {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 182*7977fdcaSMatthias Ringwald {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for HP */ 183*7977fdcaSMatthias Ringwald {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 184*7977fdcaSMatthias Ringwald {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 185*7977fdcaSMatthias Ringwald {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 186*7977fdcaSMatthias Ringwald {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1873366b4c1SMatthias Ringwald 188*7977fdcaSMatthias Ringwald {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 189*7977fdcaSMatthias Ringwald {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 190*7977fdcaSMatthias Ringwald {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 191*7977fdcaSMatthias Ringwald {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 192*7977fdcaSMatthias Ringwald {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 193*7977fdcaSMatthias Ringwald {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 1948bb555aaSBjoern Hartmann 195*7977fdcaSMatthias Ringwald {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU only */ 196*7977fdcaSMatthias Ringwald {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 197*7977fdcaSMatthias Ringwald {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 198*7977fdcaSMatthias Ringwald {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE */ 199*7977fdcaSMatthias Ringwald {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AUV only */ 200*7977fdcaSMatthias Ringwald {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE for LI */ 201*7977fdcaSMatthias Ringwald {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8812AE */ 202*7977fdcaSMatthias Ringwald {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8814AE */ 2033366b4c1SMatthias Ringwald 204*7977fdcaSMatthias Ringwald {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 205*7977fdcaSMatthias Ringwald {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 206*7977fdcaSMatthias Ringwald {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AU */ 207*7977fdcaSMatthias Ringwald {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 208*7977fdcaSMatthias Ringwald {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 209*7977fdcaSMatthias Ringwald {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 210*7977fdcaSMatthias Ringwald {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2113366b4c1SMatthias Ringwald 212*7977fdcaSMatthias Ringwald {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0, RTL8822BU}, /* RTL8822BU */ 2133366b4c1SMatthias Ringwald 214*7977fdcaSMatthias Ringwald {0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 215*7977fdcaSMatthias Ringwald {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 216*7977fdcaSMatthias Ringwald {0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 217*7977fdcaSMatthias Ringwald {0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 218*7977fdcaSMatthias Ringwald {0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU for LiteOn */ 2198bb555aaSBjoern Hartmann 220*7977fdcaSMatthias Ringwald {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 221*7977fdcaSMatthias Ringwald {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 222*7977fdcaSMatthias Ringwald {0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 223*7977fdcaSMatthias Ringwald {0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 224*7977fdcaSMatthias Ringwald {0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 225*7977fdcaSMatthias Ringwald {0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 226*7977fdcaSMatthias Ringwald {0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 227*7977fdcaSMatthias Ringwald {0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 228*7977fdcaSMatthias Ringwald {0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 229*7977fdcaSMatthias Ringwald {0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 230*7977fdcaSMatthias Ringwald {0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 231*7977fdcaSMatthias Ringwald {0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 232*7977fdcaSMatthias Ringwald {0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 233*7977fdcaSMatthias Ringwald {0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 234*7977fdcaSMatthias Ringwald {0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 235*7977fdcaSMatthias Ringwald {0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 236*7977fdcaSMatthias Ringwald {0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 237*7977fdcaSMatthias Ringwald {0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 238*7977fdcaSMatthias Ringwald {0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 239*7977fdcaSMatthias Ringwald {0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 240*7977fdcaSMatthias Ringwald {0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 241*7977fdcaSMatthias Ringwald {0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 242*7977fdcaSMatthias Ringwald {0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 243*7977fdcaSMatthias Ringwald {0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 244*7977fdcaSMatthias Ringwald {0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 245*7977fdcaSMatthias Ringwald {0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 246*7977fdcaSMatthias Ringwald {0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 247*7977fdcaSMatthias Ringwald {0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CUH */ 2488bb555aaSBjoern Hartmann 249*7977fdcaSMatthias Ringwald {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 250*7977fdcaSMatthias Ringwald {0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 251*7977fdcaSMatthias Ringwald {0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 252*7977fdcaSMatthias Ringwald {0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", NULL, 0, RTL8822CU}, /* RTL8821DU */ 2533366b4c1SMatthias Ringwald 254*7977fdcaSMatthias Ringwald {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 255*7977fdcaSMatthias Ringwald {0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 256*7977fdcaSMatthias Ringwald {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 257*7977fdcaSMatthias Ringwald {0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 258*7977fdcaSMatthias Ringwald {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 259*7977fdcaSMatthias Ringwald {0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 260*7977fdcaSMatthias Ringwald {0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 261*7977fdcaSMatthias Ringwald {0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 262*7977fdcaSMatthias Ringwald {0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 263*7977fdcaSMatthias Ringwald {0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 264*7977fdcaSMatthias Ringwald {0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 265*7977fdcaSMatthias Ringwald {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 266*7977fdcaSMatthias Ringwald {0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 267*7977fdcaSMatthias Ringwald {0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 268*7977fdcaSMatthias Ringwald {0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 269*7977fdcaSMatthias Ringwald {0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 270*7977fdcaSMatthias Ringwald {0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 271*7977fdcaSMatthias Ringwald {0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 272*7977fdcaSMatthias Ringwald {0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 273*7977fdcaSMatthias Ringwald {0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 274*7977fdcaSMatthias Ringwald {0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 275*7977fdcaSMatthias Ringwald {0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 276*7977fdcaSMatthias Ringwald {0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 277*7977fdcaSMatthias Ringwald {0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 278*7977fdcaSMatthias Ringwald {0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 2793366b4c1SMatthias Ringwald 280*7977fdcaSMatthias Ringwald {0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0, RTL8761BU}, /* RTL8761BU only */ 281*7977fdcaSMatthias Ringwald {0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU */ 282*7977fdcaSMatthias Ringwald {0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU BT only */ 2838bb555aaSBjoern Hartmann 284*7977fdcaSMatthias Ringwald {0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AU */ 285*7977fdcaSMatthias Ringwald {0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 286*7977fdcaSMatthias Ringwald {0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 287*7977fdcaSMatthias Ringwald {0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 288*7977fdcaSMatthias Ringwald {0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 289*7977fdcaSMatthias Ringwald {0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 290*7977fdcaSMatthias Ringwald {0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 291*7977fdcaSMatthias Ringwald {0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 292*7977fdcaSMatthias Ringwald {0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 293*7977fdcaSMatthias Ringwald {0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 294*7977fdcaSMatthias Ringwald {0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 295*7977fdcaSMatthias Ringwald {0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 296*7977fdcaSMatthias Ringwald {0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 297*7977fdcaSMatthias Ringwald {0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 298*7977fdcaSMatthias Ringwald {0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 299*7977fdcaSMatthias Ringwald {0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 300*7977fdcaSMatthias Ringwald {0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 301*7977fdcaSMatthias Ringwald {0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 302*7977fdcaSMatthias Ringwald {0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 303*7977fdcaSMatthias Ringwald {0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 304*7977fdcaSMatthias Ringwald {0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3058bb555aaSBjoern Hartmann 306*7977fdcaSMatthias Ringwald {0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 307*7977fdcaSMatthias Ringwald {0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 308*7977fdcaSMatthias Ringwald {0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 3093366b4c1SMatthias Ringwald 310*7977fdcaSMatthias Ringwald {0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", NULL, 0, RTL8852BU}, /* RTL8851AU */ 311*7977fdcaSMatthias Ringwald {0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BU */ 312*7977fdcaSMatthias Ringwald {0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 313*7977fdcaSMatthias Ringwald {0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 314*7977fdcaSMatthias Ringwald {0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 315*7977fdcaSMatthias Ringwald {0x3570, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 316*7977fdcaSMatthias Ringwald {0x3572, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 317*7977fdcaSMatthias Ringwald {0x4b06, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 318*7977fdcaSMatthias Ringwald {0x885b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 319*7977fdcaSMatthias Ringwald {0x886b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 320*7977fdcaSMatthias Ringwald {0x887b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 321*7977fdcaSMatthias Ringwald {0xc559, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 322*7977fdcaSMatthias Ringwald {0xb052, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 323*7977fdcaSMatthias Ringwald {0xb152, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 324*7977fdcaSMatthias Ringwald {0xb252, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 325*7977fdcaSMatthias Ringwald {0x4853, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 326*7977fdcaSMatthias Ringwald {0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3273366b4c1SMatthias Ringwald 328*7977fdcaSMatthias Ringwald {0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CU */ 329*7977fdcaSMatthias Ringwald {0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 330*7977fdcaSMatthias Ringwald {0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 331*7977fdcaSMatthias Ringwald {0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 332*7977fdcaSMatthias Ringwald {0x885c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 333*7977fdcaSMatthias Ringwald {0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 334*7977fdcaSMatthias Ringwald {0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 335*7977fdcaSMatthias Ringwald {0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3363366b4c1SMatthias Ringwald 337*7977fdcaSMatthias Ringwald {0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 338*7977fdcaSMatthias Ringwald {0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 3393366b4c1SMatthias Ringwald 340*7977fdcaSMatthias Ringwald {0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", NULL, 0, RTL8851BU}, /* RTL8851BU */ 3418bb555aaSBjoern Hartmann 3428bb555aaSBjoern Hartmann /* NOTE: must append patch entries above the null entry */ 343*7977fdcaSMatthias Ringwald {0, 0, NULL, NULL, NULL, NULL, 0, 0} 344*7977fdcaSMatthias Ringwald }; 3458bb555aaSBjoern Hartmann 346*7977fdcaSMatthias Ringwald static uint16_t project_id[] = { 3478bb555aaSBjoern Hartmann ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 3488bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 3498bb555aaSBjoern Hartmann ROM_LMP_8821a, /* RTL8821CU */ 3508bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 3518bb555aaSBjoern Hartmann ROM_LMP_8761a, /* index 14 for 8761BU */ 352*7977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 18 for 8852AU */ 353*7977fdcaSMatthias Ringwald ROM_LMP_8723b, /* index 19 for 8723FU */ 354*7977fdcaSMatthias Ringwald ROM_LMP_8852a, /* index 20 for 8852BU */ 355*7977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 25 for 8852CU */ 356*7977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, 357*7977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* index 33 for 8822EU */ 358*7977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8851b, /* index 36 for 8851BU */ 3598bb555aaSBjoern Hartmann }; 3608bb555aaSBjoern Hartmann 3618bb555aaSBjoern Hartmann static btstack_packet_callback_registration_t hci_event_callback_registration; 362*7977fdcaSMatthias Ringwald static uint8_t state; 3638bb555aaSBjoern Hartmann static uint8_t rom_version; 3648bb555aaSBjoern Hartmann static uint16_t lmp_subversion; 3658bb555aaSBjoern Hartmann static uint16_t product_id; 366*7977fdcaSMatthias Ringwald static const patch_info * patch; 367*7977fdcaSMatthias Ringwald static uint8_t g_key_id = 0; 3688bb555aaSBjoern Hartmann 3698bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 3708bb555aaSBjoern Hartmann static const char *firmware_folder_path = "."; 3718bb555aaSBjoern Hartmann static const char *firmware_file_path; 3728bb555aaSBjoern Hartmann static const char *config_folder_path = "."; 3738bb555aaSBjoern Hartmann static const char *config_file_path; 3748bb555aaSBjoern Hartmann static char firmware_file[1000]; 3758bb555aaSBjoern Hartmann static char config_file[1000]; 3768bb555aaSBjoern Hartmann #endif 3778bb555aaSBjoern Hartmann 378*7977fdcaSMatthias Ringwald static const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 379*7977fdcaSMatthias Ringwald static const uint8_t FW_SIGNATURE_NEW[8] = {0x52, 0x54, 0x42, 0x54, 0x43, 0x6F, 0x72, 0x65}; 380*7977fdcaSMatthias Ringwald static const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 3818bb555aaSBjoern Hartmann 3828bb555aaSBjoern Hartmann static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 3838bb555aaSBjoern Hartmann UNUSED(channel); 3848bb555aaSBjoern Hartmann UNUSED(size); 385*7977fdcaSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) { 3868bb555aaSBjoern Hartmann return; 3878bb555aaSBjoern Hartmann } 388*7977fdcaSMatthias Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 389*7977fdcaSMatthias Ringwald return; 390*7977fdcaSMatthias Ringwald } 3918bb555aaSBjoern Hartmann 392*7977fdcaSMatthias Ringwald uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 393*7977fdcaSMatthias Ringwald const uint8_t * return_para = hci_event_command_complete_get_return_parameters(packet); 3948bb555aaSBjoern Hartmann switch (opcode) { 395*7977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION: 396*7977fdcaSMatthias Ringwald lmp_subversion = little_endian_read_16(packet, 12); 397*7977fdcaSMatthias Ringwald break; 398*7977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_RTK_READ_ROM_VERSION: 399*7977fdcaSMatthias Ringwald rom_version = return_para[1]; 4008bb555aaSBjoern Hartmann log_info("Received ROM version 0x%02x", rom_version); 401*7977fdcaSMatthias Ringwald printf("Realtek: Received ROM version 0x%02x\n", rom_version); 402*7977fdcaSMatthias Ringwald if (patch->lmp_sub != lmp_subversion) { 403*7977fdcaSMatthias Ringwald printf("Realtek: Firmware already exists\n"); 404*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 405*7977fdcaSMatthias Ringwald } 406*7977fdcaSMatthias Ringwald break; 407*7977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_RTK_READ_CARD_INFO: 408*7977fdcaSMatthias Ringwald switch (state){ 409*7977fdcaSMatthias Ringwald case STATE_PHASE_1_W4_READ_LMP_SUBVERSION: 410*7977fdcaSMatthias Ringwald log_info("Read Card: LMP Subversion"); 411*7977fdcaSMatthias Ringwald if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x8822){ 412*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_READ_HCI_REVISION; 413*7977fdcaSMatthias Ringwald } else { 414*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_DONE; 415*7977fdcaSMatthias Ringwald } 416*7977fdcaSMatthias Ringwald break; 417*7977fdcaSMatthias Ringwald case STATE_PHASE_1_W4_READ_HCI_REVISION: 418*7977fdcaSMatthias Ringwald log_info("Read Card: HCI Revision"); 419*7977fdcaSMatthias Ringwald if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x000e){ 420*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_ROM_VERSION; 421*7977fdcaSMatthias Ringwald } else { 422*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_DONE; 423*7977fdcaSMatthias Ringwald } 424*7977fdcaSMatthias Ringwald break; 425*7977fdcaSMatthias Ringwald case STATE_PHASE_2_W4_SEC_PROJ: 426*7977fdcaSMatthias Ringwald g_key_id = return_para[1]; 427*7977fdcaSMatthias Ringwald printf("Realtek: Received key id 0x%02x\n", g_key_id); 428*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_LOAD_FIRMWARE; 429*7977fdcaSMatthias Ringwald break; 430*7977fdcaSMatthias Ringwald default: 431*7977fdcaSMatthias Ringwald btstack_assert(false); 432*7977fdcaSMatthias Ringwald break; 433*7977fdcaSMatthias Ringwald } 4348bb555aaSBjoern Hartmann break; 4358bb555aaSBjoern Hartmann default: 4368bb555aaSBjoern Hartmann break; 4378bb555aaSBjoern Hartmann } 4388bb555aaSBjoern Hartmann } 4398bb555aaSBjoern Hartmann 4408bb555aaSBjoern Hartmann static void chipset_init(const void *config) { 4418bb555aaSBjoern Hartmann UNUSED(config); 442*7977fdcaSMatthias Ringwald 443*7977fdcaSMatthias Ringwald // pre-set lmp subversion: HCI starts custom download only if HCI Version = 0x00e, and LMP Subversion = 0x8822 444*7977fdcaSMatthias Ringwald lmp_subversion = 0x8822; 445*7977fdcaSMatthias Ringwald 4468bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4478bb555aaSBjoern Hartmann // determine file path 4488bb555aaSBjoern Hartmann if (firmware_file_path == NULL || config_file_path == NULL) { 4498bb555aaSBjoern Hartmann log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 4508bb555aaSBjoern Hartmann patch = NULL; 45192728706SMatthias Ringwald for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 4528bb555aaSBjoern Hartmann if (fw_patch_table[i].prod_id == product_id) { 4538bb555aaSBjoern Hartmann patch = &fw_patch_table[i]; 4548bb555aaSBjoern Hartmann break; 4558bb555aaSBjoern Hartmann } 4568bb555aaSBjoern Hartmann } 4578bb555aaSBjoern Hartmann if (patch == NULL) { 4588bb555aaSBjoern Hartmann log_info("Product id 0x%04x is unknown", product_id); 459*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 4608bb555aaSBjoern Hartmann return; 4618bb555aaSBjoern Hartmann } 46274f83314SMatthias Ringwald snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 46374f83314SMatthias Ringwald snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 4648bb555aaSBjoern Hartmann firmware_file_path = &firmware_file[0]; 4658bb555aaSBjoern Hartmann config_file_path = &config_file[0]; 466*7977fdcaSMatthias Ringwald //lmp_subversion = patch->lmp_sub; 4678bb555aaSBjoern Hartmann } 4688bb555aaSBjoern Hartmann log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 469*7977fdcaSMatthias Ringwald printf("Realtek: Using firmware '%s' and config '%s'\n", firmware_file_path, config_file_path); 4708bb555aaSBjoern Hartmann 4718bb555aaSBjoern Hartmann // activate hci callback 4728bb555aaSBjoern Hartmann hci_event_callback_registration.callback = &hci_packet_handler; 4738bb555aaSBjoern Hartmann hci_add_event_handler(&hci_event_callback_registration); 474*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_READ_LMP_SUBVERSION; 4758bb555aaSBjoern Hartmann #endif 4768bb555aaSBjoern Hartmann } 4778bb555aaSBjoern Hartmann 4788bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4798bb555aaSBjoern Hartmann 4808bb555aaSBjoern Hartmann /** 4818bb555aaSBjoern Hartmann * @brief Opens the specified file and stores content to an allocated buffer 4828bb555aaSBjoern Hartmann * 4838bb555aaSBjoern Hartmann * @param file 4848bb555aaSBjoern Hartmann * @param buf 4858bb555aaSBjoern Hartmann * @param name 4868bb555aaSBjoern Hartmann * @return uint32_t Length of file 4878bb555aaSBjoern Hartmann */ 4888bb555aaSBjoern Hartmann static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 4898bb555aaSBjoern Hartmann uint32_t size; 4908bb555aaSBjoern Hartmann 4918bb555aaSBjoern Hartmann // open file 4928bb555aaSBjoern Hartmann *file = fopen(name, "rb"); 4938bb555aaSBjoern Hartmann if (*file == NULL) { 4948bb555aaSBjoern Hartmann log_info("Failed to open file %s", name); 4958bb555aaSBjoern Hartmann return 0; 4968bb555aaSBjoern Hartmann } 4978bb555aaSBjoern Hartmann 4988bb555aaSBjoern Hartmann // determine length of file 4998bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_END); 5008bb555aaSBjoern Hartmann size = ftell(*file); 5018bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_SET); 5028bb555aaSBjoern Hartmann if (size <= 0) { 5038bb555aaSBjoern Hartmann return 0; 5048bb555aaSBjoern Hartmann } 5058bb555aaSBjoern Hartmann 5068bb555aaSBjoern Hartmann // allocate memory 5078bb555aaSBjoern Hartmann *buf = malloc(size); 5088bb555aaSBjoern Hartmann if (*buf == NULL) { 5098bb555aaSBjoern Hartmann fclose(*file); 5108bb555aaSBjoern Hartmann *file = NULL; 5118bb555aaSBjoern Hartmann log_info("Failed to allocate %u bytes for file %s", size, name); 5128bb555aaSBjoern Hartmann return 0; 5138bb555aaSBjoern Hartmann } 5148bb555aaSBjoern Hartmann 5158bb555aaSBjoern Hartmann // read file 51658080ea6SMatthias Ringwald size_t ret = fread(*buf, size, 1, *file); 5178bb555aaSBjoern Hartmann if (ret != 1) { 51809fffc16SMatthias Ringwald log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 5198bb555aaSBjoern Hartmann fclose(*file); 5208bb555aaSBjoern Hartmann free(*buf); 5218bb555aaSBjoern Hartmann *file = NULL; 5228bb555aaSBjoern Hartmann *buf = NULL; 5238bb555aaSBjoern Hartmann return 0; 5248bb555aaSBjoern Hartmann } 5258bb555aaSBjoern Hartmann 5268bb555aaSBjoern Hartmann log_info("Opened file %s and read %u bytes", name, size); 5278bb555aaSBjoern Hartmann return size; 5288bb555aaSBjoern Hartmann } 5298bb555aaSBjoern Hartmann 5308bb555aaSBjoern Hartmann static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 5318bb555aaSBjoern Hartmann fclose(*file); 5328bb555aaSBjoern Hartmann free(*buffer); 5338bb555aaSBjoern Hartmann *buffer = NULL; 5348bb555aaSBjoern Hartmann *file = NULL; 5358bb555aaSBjoern Hartmann } 5368bb555aaSBjoern Hartmann 537*7977fdcaSMatthias Ringwald static uint8_t rtk_get_fw_project_id(uint8_t * p_buf) 538*7977fdcaSMatthias Ringwald { 539*7977fdcaSMatthias Ringwald uint8_t opcode; 540*7977fdcaSMatthias Ringwald uint8_t len; 541*7977fdcaSMatthias Ringwald uint8_t data = 0; 542*7977fdcaSMatthias Ringwald 543*7977fdcaSMatthias Ringwald do { 544*7977fdcaSMatthias Ringwald opcode = *p_buf; 545*7977fdcaSMatthias Ringwald len = *(p_buf - 1); 546*7977fdcaSMatthias Ringwald if (opcode == 0x00) { 547*7977fdcaSMatthias Ringwald if (len == 1) { 548*7977fdcaSMatthias Ringwald data = *(p_buf - 2); 549*7977fdcaSMatthias Ringwald log_info 550*7977fdcaSMatthias Ringwald ("rtk_get_fw_project_id: opcode %d, len %d, data %d", 551*7977fdcaSMatthias Ringwald opcode, len, data); 552*7977fdcaSMatthias Ringwald break; 553*7977fdcaSMatthias Ringwald } else { 554*7977fdcaSMatthias Ringwald log_error 555*7977fdcaSMatthias Ringwald ("rtk_get_fw_project_id: invalid len %d", 556*7977fdcaSMatthias Ringwald len); 557*7977fdcaSMatthias Ringwald } 558*7977fdcaSMatthias Ringwald } 559*7977fdcaSMatthias Ringwald p_buf -= len + 2; 560*7977fdcaSMatthias Ringwald } while (*p_buf != 0xFF); 561*7977fdcaSMatthias Ringwald 562*7977fdcaSMatthias Ringwald return data; 563*7977fdcaSMatthias Ringwald } 564*7977fdcaSMatthias Ringwald 565*7977fdcaSMatthias Ringwald struct rtb_ota_flag { 566*7977fdcaSMatthias Ringwald uint8_t eco; 567*7977fdcaSMatthias Ringwald uint8_t enable; 568*7977fdcaSMatthias Ringwald uint16_t reserve; 569*7977fdcaSMatthias Ringwald }; 570*7977fdcaSMatthias Ringwald 571*7977fdcaSMatthias Ringwald struct patch_node { 572*7977fdcaSMatthias Ringwald btstack_linked_item_t item; 573*7977fdcaSMatthias Ringwald uint8_t eco; 574*7977fdcaSMatthias Ringwald uint8_t pri; 575*7977fdcaSMatthias Ringwald uint8_t key_id; 576*7977fdcaSMatthias Ringwald uint8_t reserve; 577*7977fdcaSMatthias Ringwald uint32_t len; 578*7977fdcaSMatthias Ringwald uint8_t *payload; 579*7977fdcaSMatthias Ringwald }; 580*7977fdcaSMatthias Ringwald 581*7977fdcaSMatthias Ringwald /* Add a node to alist that is in ascending order. */ 582*7977fdcaSMatthias Ringwald static void insert_queue_sort(btstack_linked_list_t * list, struct patch_node *node) 583*7977fdcaSMatthias Ringwald { 584*7977fdcaSMatthias Ringwald btstack_assert(list != NULL); 585*7977fdcaSMatthias Ringwald btstack_assert(node != NULL); 586*7977fdcaSMatthias Ringwald 587*7977fdcaSMatthias Ringwald struct patch_node *next; 588*7977fdcaSMatthias Ringwald btstack_linked_item_t *it; 589*7977fdcaSMatthias Ringwald 590*7977fdcaSMatthias Ringwald for (it = (btstack_linked_item_t *) list; it->next ; it = it->next){ 591*7977fdcaSMatthias Ringwald next = (struct patch_node *) it->next; 592*7977fdcaSMatthias Ringwald if(next->pri >= node->pri) { 593*7977fdcaSMatthias Ringwald break; 594*7977fdcaSMatthias Ringwald } 595*7977fdcaSMatthias Ringwald } 596*7977fdcaSMatthias Ringwald node->item.next = it->next; 597*7977fdcaSMatthias Ringwald it->next = (btstack_linked_item_t *) node; 598*7977fdcaSMatthias Ringwald } 599*7977fdcaSMatthias Ringwald 600*7977fdcaSMatthias Ringwald static int insert_patch(btstack_linked_list_t * patch_list, uint8_t *section_pos, 601*7977fdcaSMatthias Ringwald uint32_t opcode, uint32_t *patch_len, uint8_t *sec_flag) 602*7977fdcaSMatthias Ringwald { 603*7977fdcaSMatthias Ringwald struct patch_node *tmp; 604*7977fdcaSMatthias Ringwald uint32_t i; 605*7977fdcaSMatthias Ringwald uint32_t numbers; 606*7977fdcaSMatthias Ringwald uint32_t section_len = 0; 607*7977fdcaSMatthias Ringwald uint8_t eco = 0; 608*7977fdcaSMatthias Ringwald uint8_t *pos = section_pos + 8; 609*7977fdcaSMatthias Ringwald 610*7977fdcaSMatthias Ringwald numbers = little_endian_read_16(pos, 0); 611*7977fdcaSMatthias Ringwald log_info("number 0x%04x", numbers); 612*7977fdcaSMatthias Ringwald 613*7977fdcaSMatthias Ringwald pos += 4; 614*7977fdcaSMatthias Ringwald for (i = 0; i < numbers; i++) { 615*7977fdcaSMatthias Ringwald eco = (uint8_t)*(pos); 616*7977fdcaSMatthias Ringwald log_info("eco 0x%02x, Eversion:%02x", eco, rom_version); 617*7977fdcaSMatthias Ringwald if (eco == rom_version + 1) { 618*7977fdcaSMatthias Ringwald //tmp = (struct patch_node*)kzalloc(sizeof(struct patch_node), GFP_KERNEL); 619*7977fdcaSMatthias Ringwald tmp = (struct patch_node*)malloc(sizeof(struct patch_node)); 620*7977fdcaSMatthias Ringwald tmp->pri = (uint8_t)*(pos + 1); 621*7977fdcaSMatthias Ringwald if(opcode == PATCH_SECURITY_HEADER) 622*7977fdcaSMatthias Ringwald tmp->key_id = (uint8_t)*(pos + 1); 623*7977fdcaSMatthias Ringwald 624*7977fdcaSMatthias Ringwald section_len = little_endian_read_32(pos, 4); 625*7977fdcaSMatthias Ringwald tmp->len = section_len; 626*7977fdcaSMatthias Ringwald *patch_len += section_len; 627*7977fdcaSMatthias Ringwald log_info("Pri:%d, Patch length 0x%04x", tmp->pri, tmp->len); 628*7977fdcaSMatthias Ringwald tmp->payload = pos + 8; 629*7977fdcaSMatthias Ringwald if(opcode != PATCH_SECURITY_HEADER) { 630*7977fdcaSMatthias Ringwald insert_queue_sort(patch_list, tmp); 631*7977fdcaSMatthias Ringwald } else { 632*7977fdcaSMatthias Ringwald if((g_key_id == tmp->key_id) && (g_key_id > 0)) { 633*7977fdcaSMatthias Ringwald insert_queue_sort(patch_list, tmp); 634*7977fdcaSMatthias Ringwald *sec_flag = 1; 635*7977fdcaSMatthias Ringwald } else { 636*7977fdcaSMatthias Ringwald pos += (8 + section_len); 637*7977fdcaSMatthias Ringwald free(tmp); 638*7977fdcaSMatthias Ringwald continue; 639*7977fdcaSMatthias Ringwald } 640*7977fdcaSMatthias Ringwald } 641*7977fdcaSMatthias Ringwald } else { 642*7977fdcaSMatthias Ringwald section_len = little_endian_read_32(pos, 4); 643*7977fdcaSMatthias Ringwald log_info("Patch length 0x%04x", section_len); 644*7977fdcaSMatthias Ringwald } 645*7977fdcaSMatthias Ringwald pos += (8 + section_len); 646*7977fdcaSMatthias Ringwald } 647*7977fdcaSMatthias Ringwald return 0; 648*7977fdcaSMatthias Ringwald } 649*7977fdcaSMatthias Ringwald static uint8_t *rtb_get_patch_header(uint32_t *len, 650*7977fdcaSMatthias Ringwald btstack_linked_list_t * patch_list, uint8_t * epatch_buf, 651*7977fdcaSMatthias Ringwald uint8_t key_id) 652*7977fdcaSMatthias Ringwald { 653*7977fdcaSMatthias Ringwald uint16_t i, j; 654*7977fdcaSMatthias Ringwald struct rtb_new_patch_hdr *new_patch; 655*7977fdcaSMatthias Ringwald uint8_t sec_flag = 0; 656*7977fdcaSMatthias Ringwald uint32_t number_of_ota_flag; 657*7977fdcaSMatthias Ringwald uint32_t patch_len = 0; 658*7977fdcaSMatthias Ringwald uint8_t *section_pos; 659*7977fdcaSMatthias Ringwald uint8_t *ota_flag_pos; 660*7977fdcaSMatthias Ringwald uint32_t number_of_section; 661*7977fdcaSMatthias Ringwald 662*7977fdcaSMatthias Ringwald struct rtb_section_hdr section_hdr; 663*7977fdcaSMatthias Ringwald struct rtb_ota_flag ota_flag; 664*7977fdcaSMatthias Ringwald 665*7977fdcaSMatthias Ringwald new_patch = (struct rtb_new_patch_hdr *)epatch_buf; 666*7977fdcaSMatthias Ringwald number_of_section = new_patch->number_of_section; 667*7977fdcaSMatthias Ringwald 668*7977fdcaSMatthias Ringwald log_info("FW version 0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", 669*7977fdcaSMatthias Ringwald *(epatch_buf + 8), *(epatch_buf + 9), *(epatch_buf + 10), 670*7977fdcaSMatthias Ringwald *(epatch_buf + 11),*(epatch_buf + 12), *(epatch_buf + 13), 671*7977fdcaSMatthias Ringwald *(epatch_buf + 14), *(epatch_buf + 15)); 672*7977fdcaSMatthias Ringwald 673*7977fdcaSMatthias Ringwald section_pos = epatch_buf + 20; 674*7977fdcaSMatthias Ringwald 675*7977fdcaSMatthias Ringwald for (i = 0; i < number_of_section; i++) { 676*7977fdcaSMatthias Ringwald section_hdr.opcode = little_endian_read_32(section_pos, 0); 677*7977fdcaSMatthias Ringwald section_hdr.section_len = little_endian_read_32(section_pos, 4); 678*7977fdcaSMatthias Ringwald log_info("opcode 0x%04x", section_hdr.opcode); 679*7977fdcaSMatthias Ringwald switch (section_hdr.opcode) { 680*7977fdcaSMatthias Ringwald case PATCH_SNIPPETS: 681*7977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_SNIPPETS, &patch_len, NULL); 682*7977fdcaSMatthias Ringwald printf("Realtek: patch len is %d\n",patch_len); 683*7977fdcaSMatthias Ringwald break; 684*7977fdcaSMatthias Ringwald case PATCH_SECURITY_HEADER: 685*7977fdcaSMatthias Ringwald if(!g_key_id) 686*7977fdcaSMatthias Ringwald break; 687*7977fdcaSMatthias Ringwald 688*7977fdcaSMatthias Ringwald sec_flag = 0; 689*7977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_SECURITY_HEADER, &patch_len, &sec_flag); 690*7977fdcaSMatthias Ringwald if(sec_flag) 691*7977fdcaSMatthias Ringwald break; 692*7977fdcaSMatthias Ringwald 693*7977fdcaSMatthias Ringwald for (i = 0; i < number_of_section; i++) { 694*7977fdcaSMatthias Ringwald section_hdr.opcode = little_endian_read_32(section_pos, 0); 695*7977fdcaSMatthias Ringwald section_hdr.section_len = little_endian_read_32(section_pos, 4); 696*7977fdcaSMatthias Ringwald if(section_hdr.opcode == PATCH_DUMMY_HEADER) { 697*7977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 698*7977fdcaSMatthias Ringwald } 699*7977fdcaSMatthias Ringwald section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 700*7977fdcaSMatthias Ringwald } 701*7977fdcaSMatthias Ringwald break; 702*7977fdcaSMatthias Ringwald case PATCH_DUMMY_HEADER: 703*7977fdcaSMatthias Ringwald if(g_key_id) { 704*7977fdcaSMatthias Ringwald break; 705*7977fdcaSMatthias Ringwald } 706*7977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 707*7977fdcaSMatthias Ringwald break; 708*7977fdcaSMatthias Ringwald case PATCH_OTA_FLAG: 709*7977fdcaSMatthias Ringwald ota_flag_pos = section_pos + 4; 710*7977fdcaSMatthias Ringwald number_of_ota_flag = little_endian_read_32(ota_flag_pos, 0); 711*7977fdcaSMatthias Ringwald ota_flag.eco = (uint8_t)*(ota_flag_pos + 1); 712*7977fdcaSMatthias Ringwald if (ota_flag.eco == rom_version + 1) { 713*7977fdcaSMatthias Ringwald for (j = 0; j < number_of_ota_flag; j++) { 714*7977fdcaSMatthias Ringwald if (ota_flag.eco == rom_version + 1) { 715*7977fdcaSMatthias Ringwald ota_flag.enable = little_endian_read_32(ota_flag_pos, 4); 716*7977fdcaSMatthias Ringwald } 717*7977fdcaSMatthias Ringwald } 718*7977fdcaSMatthias Ringwald } 719*7977fdcaSMatthias Ringwald break; 720*7977fdcaSMatthias Ringwald default: 721*7977fdcaSMatthias Ringwald log_error("Unknown Opcode"); 722*7977fdcaSMatthias Ringwald break; 723*7977fdcaSMatthias Ringwald } 724*7977fdcaSMatthias Ringwald section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 725*7977fdcaSMatthias Ringwald } 726*7977fdcaSMatthias Ringwald *len = patch_len; 727*7977fdcaSMatthias Ringwald 728*7977fdcaSMatthias Ringwald return NULL; 729*7977fdcaSMatthias Ringwald } 730*7977fdcaSMatthias Ringwald 731*7977fdcaSMatthias Ringwald static inline int get_max_patch_size(uint8_t chip_type) 732*7977fdcaSMatthias Ringwald { 733*7977fdcaSMatthias Ringwald int max_patch_size = 0; 734*7977fdcaSMatthias Ringwald 735*7977fdcaSMatthias Ringwald switch (chip_type) { 736*7977fdcaSMatthias Ringwald case RTLPREVIOUS: 737*7977fdcaSMatthias Ringwald max_patch_size = 24 * 1024; 738*7977fdcaSMatthias Ringwald break; 739*7977fdcaSMatthias Ringwald case RTL8822BU: 740*7977fdcaSMatthias Ringwald max_patch_size = 25 * 1024; 741*7977fdcaSMatthias Ringwald break; 742*7977fdcaSMatthias Ringwald case RTL8723DU: 743*7977fdcaSMatthias Ringwald case RTL8822CU: 744*7977fdcaSMatthias Ringwald case RTL8761BU: 745*7977fdcaSMatthias Ringwald case RTL8821CU: 746*7977fdcaSMatthias Ringwald max_patch_size = 40 * 1024; 747*7977fdcaSMatthias Ringwald break; 748*7977fdcaSMatthias Ringwald case RTL8852AU: 749*7977fdcaSMatthias Ringwald max_patch_size = 0x114D0 + 529; /* 69.2KB */ 750*7977fdcaSMatthias Ringwald break; 751*7977fdcaSMatthias Ringwald case RTL8723FU: 752*7977fdcaSMatthias Ringwald max_patch_size = 0xC4Cf + 529; /* 49.2KB */ 753*7977fdcaSMatthias Ringwald break; 754*7977fdcaSMatthias Ringwald case RTL8852BU: 755*7977fdcaSMatthias Ringwald case RTL8851BU: 756*7977fdcaSMatthias Ringwald max_patch_size = 0x104D0 + 529; /* 65KB */ 757*7977fdcaSMatthias Ringwald break; 758*7977fdcaSMatthias Ringwald case RTL8852CU: 759*7977fdcaSMatthias Ringwald max_patch_size = 0x130D0 + 529; /* 76.2KB */ 760*7977fdcaSMatthias Ringwald break; 761*7977fdcaSMatthias Ringwald case RTL8822EU: 762*7977fdcaSMatthias Ringwald max_patch_size = 0x24620 + 529; /* 145KB */ 763*7977fdcaSMatthias Ringwald break; 764*7977fdcaSMatthias Ringwald default: 765*7977fdcaSMatthias Ringwald max_patch_size = 40 * 1024; 766*7977fdcaSMatthias Ringwald break; 767*7977fdcaSMatthias Ringwald } 768*7977fdcaSMatthias Ringwald 769*7977fdcaSMatthias Ringwald return max_patch_size; 770*7977fdcaSMatthias Ringwald } 771*7977fdcaSMatthias Ringwald 7728bb555aaSBjoern Hartmann static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 7738bb555aaSBjoern Hartmann static uint8_t *patch_buf = NULL; 7748bb555aaSBjoern Hartmann static uint32_t fw_total_len; 7758bb555aaSBjoern Hartmann static uint32_t fw_ptr; 7768bb555aaSBjoern Hartmann static uint8_t index; 7778bb555aaSBjoern Hartmann 7788bb555aaSBjoern Hartmann // read firmware and config 7798bb555aaSBjoern Hartmann if (patch_buf == NULL) { 7808bb555aaSBjoern Hartmann uint16_t patch_length = 0; 7818bb555aaSBjoern Hartmann uint32_t offset; 7828bb555aaSBjoern Hartmann FILE * fw = NULL; 7838bb555aaSBjoern Hartmann uint32_t fw_size; 7848bb555aaSBjoern Hartmann uint8_t *fw_buf = NULL; 7858bb555aaSBjoern Hartmann 7868bb555aaSBjoern Hartmann FILE * conf = NULL; 7878bb555aaSBjoern Hartmann uint32_t conf_size; 7888bb555aaSBjoern Hartmann uint8_t *conf_buf = NULL; 7898bb555aaSBjoern Hartmann 790*7977fdcaSMatthias Ringwald uint32_t fw_version; 791*7977fdcaSMatthias Ringwald uint16_t fw_num_patches; 792*7977fdcaSMatthias Ringwald 793*7977fdcaSMatthias Ringwald struct patch_node *tmp; 794*7977fdcaSMatthias Ringwald int max_patch_size = 0; 795*7977fdcaSMatthias Ringwald 7968bb555aaSBjoern Hartmann if (firmware == NULL || config == NULL) { 7978bb555aaSBjoern Hartmann log_info("Please specify realtek firmware and config file paths"); 7988bb555aaSBjoern Hartmann return FW_DONE; 7998bb555aaSBjoern Hartmann } 800*7977fdcaSMatthias Ringwald // read config 801*7977fdcaSMatthias Ringwald conf_size = read_file(&conf, &conf_buf, config); 802*7977fdcaSMatthias Ringwald if (conf_size == 0) { 803*7977fdcaSMatthias Ringwald log_info("Config size is 0, using efuse settings!"); 804*7977fdcaSMatthias Ringwald } 8058bb555aaSBjoern Hartmann // read firmware 8068bb555aaSBjoern Hartmann fw_size = read_file(&fw, &fw_buf, firmware); 8078bb555aaSBjoern Hartmann if (fw_size == 0) { 8088bb555aaSBjoern Hartmann log_info("Firmware size is 0. Quit!"); 809*7977fdcaSMatthias Ringwald if (conf_size != 0){ 810*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 811*7977fdcaSMatthias Ringwald } 8128bb555aaSBjoern Hartmann return FW_DONE; 8138bb555aaSBjoern Hartmann } 8148bb555aaSBjoern Hartmann // check signature 815*7977fdcaSMatthias Ringwald if (((memcmp(fw_buf, FW_SIGNATURE, 8) != 0) && (memcmp(fw_buf, FW_SIGNATURE_NEW, 8) != 0)) 816*7977fdcaSMatthias Ringwald || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 8178bb555aaSBjoern Hartmann log_info("Wrong signature. Quit!"); 8188bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8198bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8208bb555aaSBjoern Hartmann return FW_DONE; 8218bb555aaSBjoern Hartmann } 8228bb555aaSBjoern Hartmann // check project id 823*7977fdcaSMatthias Ringwald if (lmp_subversion != project_id[rtk_get_fw_project_id(fw_buf + fw_size - 5)]) { 8248bb555aaSBjoern Hartmann log_info("Wrong project id. Quit!"); 8258bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8268bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8278bb555aaSBjoern Hartmann return FW_DONE; 8288bb555aaSBjoern Hartmann } 829*7977fdcaSMatthias Ringwald // init ordered list for new firmware signature 830*7977fdcaSMatthias Ringwald btstack_linked_list_t patch_list = NULL; 831*7977fdcaSMatthias Ringwald bool have_new_firmware_signature = memcmp(fw_buf, FW_SIGNATURE_NEW, 8) == 0; 832*7977fdcaSMatthias Ringwald if (have_new_firmware_signature){ 833*7977fdcaSMatthias Ringwald printf("Realtek: Using new signature\n"); 834*7977fdcaSMatthias Ringwald uint8_t key_id = g_key_id; 835*7977fdcaSMatthias Ringwald if (key_id < 0) { 836*7977fdcaSMatthias Ringwald log_info("Wrong key id. Quit!"); 837*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 838*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 839*7977fdcaSMatthias Ringwald return FW_DONE; 840*7977fdcaSMatthias Ringwald } 8418bb555aaSBjoern Hartmann 842*7977fdcaSMatthias Ringwald rtb_get_patch_header(&fw_total_len, &patch_list, fw_buf, key_id); 843*7977fdcaSMatthias Ringwald if (fw_total_len == 0) { 844*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 845*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 846*7977fdcaSMatthias Ringwald return FW_DONE; 847*7977fdcaSMatthias Ringwald } 848*7977fdcaSMatthias Ringwald fw_total_len += conf_size; 849*7977fdcaSMatthias Ringwald } else { 850*7977fdcaSMatthias Ringwald printf("Realtek: Using old signature\n"); 8518bb555aaSBjoern Hartmann // read firmware version 852*7977fdcaSMatthias Ringwald fw_version = little_endian_read_32(fw_buf, 8); 8538bb555aaSBjoern Hartmann log_info("Firmware version: 0x%x", fw_version); 8548bb555aaSBjoern Hartmann 8558bb555aaSBjoern Hartmann // read number of patches 856*7977fdcaSMatthias Ringwald fw_num_patches = little_endian_read_16(fw_buf, 12); 8578bb555aaSBjoern Hartmann log_info("Number of patches: %d", fw_num_patches); 8588bb555aaSBjoern Hartmann 8598bb555aaSBjoern Hartmann // find correct entry 8608bb555aaSBjoern Hartmann for (uint16_t i = 0; i < fw_num_patches; i++) { 8618bb555aaSBjoern Hartmann if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 8628bb555aaSBjoern Hartmann patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 8638bb555aaSBjoern Hartmann offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 8648bb555aaSBjoern Hartmann log_info("patch_length %u, offset %u", patch_length, offset); 8658bb555aaSBjoern Hartmann break; 8668bb555aaSBjoern Hartmann } 8678bb555aaSBjoern Hartmann } 8688bb555aaSBjoern Hartmann if (patch_length == 0) { 8698bb555aaSBjoern Hartmann log_debug("Failed to find valid patch"); 8708bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8718bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8728bb555aaSBjoern Hartmann return FW_DONE; 8738bb555aaSBjoern Hartmann } 8748bb555aaSBjoern Hartmann fw_total_len = patch_length + conf_size; 875*7977fdcaSMatthias Ringwald } 876*7977fdcaSMatthias Ringwald 877*7977fdcaSMatthias Ringwald max_patch_size = get_max_patch_size(patch->chip_type); 878*7977fdcaSMatthias Ringwald printf("Realtek: FW/CONFIG total length is %d, max patch size id %d\n", fw_total_len, max_patch_size); 879*7977fdcaSMatthias Ringwald if (fw_total_len > max_patch_size) { 880*7977fdcaSMatthias Ringwald printf("FRealtek: W/CONFIG total length larger than allowed %d\n", max_patch_size); 881*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 882*7977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 883*7977fdcaSMatthias Ringwald return FW_DONE; 884*7977fdcaSMatthias Ringwald } 885*7977fdcaSMatthias Ringwald // allocate patch buffer 8868bb555aaSBjoern Hartmann patch_buf = malloc(fw_total_len); 8878bb555aaSBjoern Hartmann if (patch_buf == NULL) { 8888bb555aaSBjoern Hartmann log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 8898bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8908bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8918bb555aaSBjoern Hartmann return FW_DONE; 8928bb555aaSBjoern Hartmann } 893*7977fdcaSMatthias Ringwald if (have_new_firmware_signature) { 894*7977fdcaSMatthias Ringwald int tmp_len = 0; 895*7977fdcaSMatthias Ringwald // append patches based on priority and free 896*7977fdcaSMatthias Ringwald while (patch_list) { 897*7977fdcaSMatthias Ringwald tmp = (struct patch_node *) patch_list; 898*7977fdcaSMatthias Ringwald log_info("len = 0x%x", tmp->len); 899*7977fdcaSMatthias Ringwald memcpy(patch_buf + tmp_len, tmp->payload, tmp->len); 900*7977fdcaSMatthias Ringwald tmp_len += tmp->len; 901*7977fdcaSMatthias Ringwald patch_list = patch_list->next; 902*7977fdcaSMatthias Ringwald free(tmp); 903*7977fdcaSMatthias Ringwald } 904*7977fdcaSMatthias Ringwald if (conf_size) { 905*7977fdcaSMatthias Ringwald memcpy(&patch_buf[fw_total_len - conf_size], conf_buf, conf_size); 906*7977fdcaSMatthias Ringwald } 907*7977fdcaSMatthias Ringwald } else { 9088bb555aaSBjoern Hartmann // copy patch 9098bb555aaSBjoern Hartmann memcpy(patch_buf, fw_buf + offset, patch_length); 9108bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length - 4, &fw_version, 4); 9118bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length, conf_buf, conf_size); 912*7977fdcaSMatthias Ringwald } 9138bb555aaSBjoern Hartmann fw_ptr = 0; 9148bb555aaSBjoern Hartmann index = 0; 9158bb555aaSBjoern Hartmann 9168bb555aaSBjoern Hartmann // close files 9178bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 9188bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 9198bb555aaSBjoern Hartmann } 9208bb555aaSBjoern Hartmann 9218bb555aaSBjoern Hartmann uint8_t len; 9228bb555aaSBjoern Hartmann if (fw_total_len - fw_ptr > 252) { 9238bb555aaSBjoern Hartmann len = 252; 9248bb555aaSBjoern Hartmann } else { 9258bb555aaSBjoern Hartmann len = fw_total_len - fw_ptr; 9268bb555aaSBjoern Hartmann index |= 0x80; // end 9278bb555aaSBjoern Hartmann } 9288bb555aaSBjoern Hartmann 9298bb555aaSBjoern Hartmann if (len) { 930*7977fdcaSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_HCI_RTK_DOWNLOAD_FW); 931*7977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, len + 1); 932*7977fdcaSMatthias Ringwald HCI_CMD_DOWNLOAD_SET_INDEX(hci_cmd_buffer, index); 933*7977fdcaSMatthias Ringwald HCI_CMD_DOWNLOAD_COPY_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 9348bb555aaSBjoern Hartmann index++; 935*7977fdcaSMatthias Ringwald if (index > 0x7f) { 936*7977fdcaSMatthias Ringwald index = (index & 0x7f) +1; 937*7977fdcaSMatthias Ringwald } 9388bb555aaSBjoern Hartmann fw_ptr += len; 9398bb555aaSBjoern Hartmann return FW_MORE_TO_DO; 9408bb555aaSBjoern Hartmann } 9418bb555aaSBjoern Hartmann 9428bb555aaSBjoern Hartmann // cleanup and return 9438bb555aaSBjoern Hartmann free(patch_buf); 9448bb555aaSBjoern Hartmann patch_buf = NULL; 945*7977fdcaSMatthias Ringwald printf("Realtek: Init process finished\n"); 9468bb555aaSBjoern Hartmann return FW_DONE; 9478bb555aaSBjoern Hartmann } 9488bb555aaSBjoern Hartmann 9498bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 9508bb555aaSBjoern Hartmann 951*7977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_sec_proj[] = {0x61, 0xfc, 0x05, 0x10, 0xA4, 0x0D, 0x00, 0xb0 }; 952*7977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_lmp_subversion[] = {0x61, 0xfc, 0x05, 0x10, 0x38, 0x04, 0x28, 0x80 }; 953*7977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_hci_revision[] = {0x61, 0xfc, 0x05, 0x10, 0x3A, 0x04, 0x28, 0x80 }; 954*7977fdcaSMatthias Ringwald 9558bb555aaSBjoern Hartmann static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 9568bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 9578bb555aaSBjoern Hartmann uint8_t ret; 9588bb555aaSBjoern Hartmann while (true) { 9598bb555aaSBjoern Hartmann switch (state) { 960*7977fdcaSMatthias Ringwald case STATE_PHASE_1_READ_LMP_SUBVERSION: 961*7977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_lmp_subversion, sizeof(hci_realtek_read_lmp_subversion)); 962*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_W4_READ_LMP_SUBVERSION; 9638bb555aaSBjoern Hartmann break; 964*7977fdcaSMatthias Ringwald case STATE_PHASE_1_READ_HCI_REVISION: 965*7977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_hci_revision, sizeof(hci_realtek_read_hci_revision)); 966*7977fdcaSMatthias Ringwald state = STATE_PHASE_1_W4_READ_HCI_REVISION; 967*7977fdcaSMatthias Ringwald break; 968*7977fdcaSMatthias Ringwald case STATE_PHASE_1_DONE: 969*7977fdcaSMatthias Ringwald // custom pre-init done, continue with read ROM version in main custom init 970*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_ROM_VERSION; 971*7977fdcaSMatthias Ringwald return BTSTACK_CHIPSET_DONE; 972*7977fdcaSMatthias Ringwald case STATE_PHASE_2_READ_ROM_VERSION: 973*7977fdcaSMatthias Ringwald HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RTK_READ_ROM_VERSION); 974*7977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 975*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_SEC_PROJ; 976*7977fdcaSMatthias Ringwald break; 977*7977fdcaSMatthias Ringwald case STATE_PHASE_2_READ_SEC_PROJ: 978*7977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_sec_proj, sizeof(hci_realtek_read_sec_proj)); 979*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_W4_SEC_PROJ; 980*7977fdcaSMatthias Ringwald break; 981*7977fdcaSMatthias Ringwald case STATE_PHASE_2_LOAD_FIRMWARE: 9828bb555aaSBjoern Hartmann if (lmp_subversion != ROM_LMP_8723a) { 9838bb555aaSBjoern Hartmann ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 9848bb555aaSBjoern Hartmann } else { 9858bb555aaSBjoern Hartmann log_info("Realtek firmware for old patch style not implemented"); 9868bb555aaSBjoern Hartmann ret = FW_DONE; 9878bb555aaSBjoern Hartmann } 9888bb555aaSBjoern Hartmann if (ret != FW_DONE) { 9898bb555aaSBjoern Hartmann break; 9908bb555aaSBjoern Hartmann } 991*7977fdcaSMatthias Ringwald // we are done 992*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_RESET; 993*7977fdcaSMatthias Ringwald 994*7977fdcaSMatthias Ringwald /* fall through */ 995*7977fdcaSMatthias Ringwald 996*7977fdcaSMatthias Ringwald case STATE_PHASE_2_RESET: 997*7977fdcaSMatthias Ringwald HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RESET); 998*7977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 999*7977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 10008bb555aaSBjoern Hartmann break; 1001*7977fdcaSMatthias Ringwald case STATE_PHASE_2_DONE: 10028bb555aaSBjoern Hartmann hci_remove_event_handler(&hci_event_callback_registration); 10038bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 10048bb555aaSBjoern Hartmann default: 10058bb555aaSBjoern Hartmann log_info("Invalid state %d", state); 10068bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 10078bb555aaSBjoern Hartmann } 10088bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_VALID_COMMAND; 10098bb555aaSBjoern Hartmann } 10108bb555aaSBjoern Hartmann #else // HAVE_POSIX_FILE_IO 10118bb555aaSBjoern Hartmann log_info("Realtek without File IO is not implemented yet"); 10128bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 10138bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 10148bb555aaSBjoern Hartmann } 10158bb555aaSBjoern Hartmann 10168bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 10178bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10188bb555aaSBjoern Hartmann firmware_file_path = path; 10198bb555aaSBjoern Hartmann #endif 10208bb555aaSBjoern Hartmann } 10218bb555aaSBjoern Hartmann 10228bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 10238bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10248bb555aaSBjoern Hartmann firmware_folder_path = path; 10258bb555aaSBjoern Hartmann #endif 10268bb555aaSBjoern Hartmann } 10278bb555aaSBjoern Hartmann 10288bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_file_path(const char *path) { 10298bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10308bb555aaSBjoern Hartmann config_file_path = path; 10318bb555aaSBjoern Hartmann #endif 10328bb555aaSBjoern Hartmann } 10338bb555aaSBjoern Hartmann 10348bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_folder_path(const char *path) { 10358bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10368bb555aaSBjoern Hartmann config_folder_path = path; 10378bb555aaSBjoern Hartmann #endif 10388bb555aaSBjoern Hartmann } 10398bb555aaSBjoern Hartmann 10405a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_product_id(uint16_t id) { 10415a4c0fdaSMatthias Ringwald product_id = id; 10425a4c0fdaSMatthias Ringwald } 10435a4c0fdaSMatthias Ringwald 10445a4c0fdaSMatthias Ringwald uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 10455a4c0fdaSMatthias Ringwald return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 10465a4c0fdaSMatthias Ringwald } 10475a4c0fdaSMatthias Ringwald 10485a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 10495a4c0fdaSMatthias Ringwald btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 10505a4c0fdaSMatthias Ringwald *out_vendor_id = 0xbda; 10515a4c0fdaSMatthias Ringwald *out_product_id = fw_patch_table[index].prod_id; 10525a4c0fdaSMatthias Ringwald } 10538bb555aaSBjoern Hartmann 10548bb555aaSBjoern Hartmann static const btstack_chipset_t btstack_chipset_realtek = { 10558bb555aaSBjoern Hartmann "REALTEK", chipset_init, chipset_next_command, 10568bb555aaSBjoern Hartmann NULL, // chipset_set_baudrate_command, 10578bb555aaSBjoern Hartmann NULL, // chipset_set_bd_addr_command not supported or implemented 10588bb555aaSBjoern Hartmann }; 10598bb555aaSBjoern Hartmann 10608bb555aaSBjoern Hartmann const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 1061