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" 557977fdcaSMatthias 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 687977fdcaSMatthias Ringwald #define ROM_LMP_8821a 0x8821 697977fdcaSMatthias Ringwald #define ROM_LMP_8761a 0x8761 707977fdcaSMatthias Ringwald #define ROM_LMP_8822b 0x8822 717977fdcaSMatthias Ringwald #define ROM_LMP_8852a 0x8852 727977fdcaSMatthias Ringwald #define ROM_LMP_8851b 0x8851 738bb555aaSBjoern Hartmann 747977fdcaSMatthias Ringwald #define HCI_OPCODE_HCI_RTK_DOWNLOAD_FW 0xFC20 757977fdcaSMatthias Ringwald #define HCI_OPCODE_HCI_RTK_READ_ROM_VERSION 0xFC6D 768bb555aaSBjoern Hartmann 777977fdcaSMatthias Ringwald #define READ_SEC_PROJ 4 787977fdcaSMatthias Ringwald 797977fdcaSMatthias Ringwald #define HCI_CMD_SET_OPCODE(buf, opcode) little_endian_store_16(buf, 0, opcode) 807977fdcaSMatthias Ringwald #define HCI_CMD_SET_LENGTH(buf, length) buf[2] = length 817977fdcaSMatthias Ringwald #define HCI_CMD_DOWNLOAD_SET_INDEX(buf, index) buf[3] = index 827977fdcaSMatthias Ringwald #define HCI_CMD_DOWNLOAD_COPY_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 837977fdcaSMatthias Ringwald 847977fdcaSMatthias Ringwald #define PATCH_SNIPPETS 0x01 857977fdcaSMatthias Ringwald #define PATCH_DUMMY_HEADER 0x02 867977fdcaSMatthias Ringwald #define PATCH_SECURITY_HEADER 0x03 877977fdcaSMatthias Ringwald #define PATCH_OTA_FLAG 0x04 887977fdcaSMatthias Ringwald #define SECTION_HEADER_SIZE 8 897977fdcaSMatthias Ringwald 907977fdcaSMatthias Ringwald /* software id */ 917977fdcaSMatthias Ringwald #define RTLPREVIOUS 0x00 927977fdcaSMatthias Ringwald #define RTL8822BU 0x70 937977fdcaSMatthias Ringwald #define RTL8723DU 0x71 947977fdcaSMatthias Ringwald #define RTL8821CU 0x72 957977fdcaSMatthias Ringwald #define RTL8822CU 0x73 967977fdcaSMatthias Ringwald #define RTL8761BU 0x74 977977fdcaSMatthias Ringwald #define RTL8852AU 0x75 987977fdcaSMatthias Ringwald #define RTL8723FU 0x76 997977fdcaSMatthias Ringwald #define RTL8852BU 0x77 1007977fdcaSMatthias Ringwald #define RTL8852CU 0x78 1017977fdcaSMatthias Ringwald #define RTL8822EU 0x79 1027977fdcaSMatthias Ringwald #define RTL8851BU 0x7A 1037977fdcaSMatthias Ringwald 1041747cbabSMatthias Ringwald #pragma pack(push, 1) 1057977fdcaSMatthias Ringwald struct rtk_epatch_entry { 1067977fdcaSMatthias Ringwald uint16_t chipID; 1077977fdcaSMatthias Ringwald uint16_t patch_length; 1087977fdcaSMatthias Ringwald uint32_t start_offset; 1091747cbabSMatthias Ringwald }; 1107977fdcaSMatthias Ringwald 1117977fdcaSMatthias Ringwald struct rtk_epatch { 1127977fdcaSMatthias Ringwald uint8_t signature[8]; 1137977fdcaSMatthias Ringwald uint32_t fw_version; 1147977fdcaSMatthias Ringwald uint16_t number_of_total_patch; 1157977fdcaSMatthias Ringwald struct rtk_epatch_entry entry[0]; 1161747cbabSMatthias Ringwald }; 1177977fdcaSMatthias Ringwald 1187977fdcaSMatthias Ringwald struct rtk_extension_entry { 1197977fdcaSMatthias Ringwald uint8_t opcode; 1207977fdcaSMatthias Ringwald uint8_t length; 1217977fdcaSMatthias Ringwald uint8_t *data; 1221747cbabSMatthias Ringwald }; 1237977fdcaSMatthias Ringwald 1247977fdcaSMatthias Ringwald struct rtb_section_hdr { 1257977fdcaSMatthias Ringwald uint32_t opcode; 1267977fdcaSMatthias Ringwald uint32_t section_len; 1277977fdcaSMatthias Ringwald uint32_t soffset; 1281747cbabSMatthias Ringwald }; 1297977fdcaSMatthias Ringwald 1307977fdcaSMatthias Ringwald struct rtb_new_patch_hdr { 1317977fdcaSMatthias Ringwald uint8_t signature[8]; 1327977fdcaSMatthias Ringwald uint8_t fw_version[8]; 1337977fdcaSMatthias Ringwald uint32_t number_of_section; 1341747cbabSMatthias Ringwald }; 1351747cbabSMatthias Ringwald #pragma pack(pop) 1361747cbabSMatthias Ringwald 1378bb555aaSBjoern Hartmann 1388bb555aaSBjoern Hartmann enum { 1397977fdcaSMatthias Ringwald // Pre-Init: runs before HCI Reset 1407977fdcaSMatthias Ringwald STATE_PHASE_1_READ_LMP_SUBVERSION, 1417977fdcaSMatthias Ringwald STATE_PHASE_1_W4_READ_LMP_SUBVERSION, 1427977fdcaSMatthias Ringwald STATE_PHASE_1_READ_HCI_REVISION, 1437977fdcaSMatthias Ringwald STATE_PHASE_1_W4_READ_HCI_REVISION, 1447977fdcaSMatthias Ringwald STATE_PHASE_1_DONE, 1457977fdcaSMatthias Ringwald // Custom Init: runs after HCI Reset 1467977fdcaSMatthias Ringwald STATE_PHASE_2_READ_ROM_VERSION, 1477977fdcaSMatthias Ringwald STATE_PHASE_2_READ_SEC_PROJ, 1487977fdcaSMatthias Ringwald STATE_PHASE_2_W4_SEC_PROJ, 1497977fdcaSMatthias Ringwald STATE_PHASE_2_LOAD_FIRMWARE, 1507977fdcaSMatthias Ringwald STATE_PHASE_2_RESET, 1517977fdcaSMatthias Ringwald STATE_PHASE_2_DONE, 1528bb555aaSBjoern Hartmann }; 1538bb555aaSBjoern Hartmann enum { FW_DONE, FW_MORE_TO_DO }; 1548bb555aaSBjoern Hartmann 1558bb555aaSBjoern Hartmann typedef struct { 1568bb555aaSBjoern Hartmann uint16_t prod_id; 1578bb555aaSBjoern Hartmann uint16_t lmp_sub; 1588bb555aaSBjoern Hartmann char * mp_patch_name; 1598bb555aaSBjoern Hartmann char * patch_name; 1608bb555aaSBjoern Hartmann char * config_name; 1618bb555aaSBjoern Hartmann 1628bb555aaSBjoern Hartmann uint8_t *fw_cache1; 1638bb555aaSBjoern Hartmann int fw_len1; 1647977fdcaSMatthias Ringwald uint8_t chip_type; 1658bb555aaSBjoern Hartmann } patch_info; 1668bb555aaSBjoern Hartmann 1677977fdcaSMatthias Ringwald static const patch_info fw_patch_table[] = { 1687977fdcaSMatthias Ringwald /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, chip_type } */ 1697977fdcaSMatthias Ringwald {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* RTL8723A */ 1707977fdcaSMatthias Ringwald {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 1717977fdcaSMatthias Ringwald {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for LI */ 1727977fdcaSMatthias Ringwald {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 1737977fdcaSMatthias Ringwald {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for Azurewave */ 1748bb555aaSBjoern Hartmann 1757977fdcaSMatthias Ringwald {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 1767977fdcaSMatthias Ringwald {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 1777977fdcaSMatthias Ringwald {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 1787977fdcaSMatthias Ringwald {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 1798bb555aaSBjoern Hartmann 1807977fdcaSMatthias Ringwald {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 1817977fdcaSMatthias Ringwald {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 1827977fdcaSMatthias Ringwald {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for LC */ 1837977fdcaSMatthias Ringwald {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1847977fdcaSMatthias Ringwald {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1857977fdcaSMatthias Ringwald {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for HP */ 1867977fdcaSMatthias Ringwald {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1877977fdcaSMatthias Ringwald {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1887977fdcaSMatthias Ringwald {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1897977fdcaSMatthias Ringwald {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 1903366b4c1SMatthias Ringwald 1917977fdcaSMatthias Ringwald {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 1927977fdcaSMatthias Ringwald {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 1937977fdcaSMatthias Ringwald {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 1947977fdcaSMatthias Ringwald {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 1957977fdcaSMatthias Ringwald {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 1967977fdcaSMatthias Ringwald {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 1978bb555aaSBjoern Hartmann 1987977fdcaSMatthias Ringwald {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU only */ 1997977fdcaSMatthias Ringwald {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 2007977fdcaSMatthias Ringwald {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 2017977fdcaSMatthias Ringwald {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE */ 2027977fdcaSMatthias Ringwald {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AUV only */ 2037977fdcaSMatthias Ringwald {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE for LI */ 2047977fdcaSMatthias Ringwald {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8812AE */ 2057977fdcaSMatthias Ringwald {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8814AE */ 2063366b4c1SMatthias Ringwald 2077977fdcaSMatthias Ringwald {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2087977fdcaSMatthias Ringwald {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2097977fdcaSMatthias Ringwald {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AU */ 2107977fdcaSMatthias Ringwald {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2117977fdcaSMatthias Ringwald {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2127977fdcaSMatthias Ringwald {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2137977fdcaSMatthias Ringwald {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 2143366b4c1SMatthias Ringwald 2157977fdcaSMatthias Ringwald {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0, RTL8822BU}, /* RTL8822BU */ 2163366b4c1SMatthias Ringwald 2177977fdcaSMatthias Ringwald {0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 2187977fdcaSMatthias Ringwald {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 2197977fdcaSMatthias Ringwald {0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 2207977fdcaSMatthias Ringwald {0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 2217977fdcaSMatthias Ringwald {0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU for LiteOn */ 2228bb555aaSBjoern Hartmann 2237977fdcaSMatthias Ringwald {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 2247977fdcaSMatthias Ringwald {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 2257977fdcaSMatthias Ringwald {0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2267977fdcaSMatthias Ringwald {0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2277977fdcaSMatthias Ringwald {0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2287977fdcaSMatthias Ringwald {0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2297977fdcaSMatthias Ringwald {0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2307977fdcaSMatthias Ringwald {0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2317977fdcaSMatthias Ringwald {0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2327977fdcaSMatthias Ringwald {0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2337977fdcaSMatthias Ringwald {0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2347977fdcaSMatthias Ringwald {0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2357977fdcaSMatthias Ringwald {0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2367977fdcaSMatthias Ringwald {0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 2377977fdcaSMatthias Ringwald {0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 2387977fdcaSMatthias Ringwald {0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2397977fdcaSMatthias Ringwald {0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2407977fdcaSMatthias Ringwald {0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2417977fdcaSMatthias Ringwald {0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2427977fdcaSMatthias Ringwald {0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2437977fdcaSMatthias Ringwald {0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2447977fdcaSMatthias Ringwald {0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2457977fdcaSMatthias Ringwald {0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2467977fdcaSMatthias Ringwald {0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 2477977fdcaSMatthias Ringwald {0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 2487977fdcaSMatthias Ringwald {0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 2497977fdcaSMatthias Ringwald {0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 2507977fdcaSMatthias Ringwald {0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CUH */ 2518bb555aaSBjoern Hartmann 2527977fdcaSMatthias Ringwald {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 2537977fdcaSMatthias Ringwald {0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 2547977fdcaSMatthias Ringwald {0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 2557977fdcaSMatthias Ringwald {0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", NULL, 0, RTL8822CU}, /* RTL8821DU */ 2563366b4c1SMatthias Ringwald 2577977fdcaSMatthias Ringwald {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2587977fdcaSMatthias Ringwald {0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2597977fdcaSMatthias Ringwald {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2607977fdcaSMatthias Ringwald {0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2617977fdcaSMatthias Ringwald {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2627977fdcaSMatthias Ringwald {0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2637977fdcaSMatthias Ringwald {0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2647977fdcaSMatthias Ringwald {0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2657977fdcaSMatthias Ringwald {0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2667977fdcaSMatthias Ringwald {0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2677977fdcaSMatthias Ringwald {0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2687977fdcaSMatthias Ringwald {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 2697977fdcaSMatthias Ringwald {0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 2707977fdcaSMatthias Ringwald {0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2717977fdcaSMatthias Ringwald {0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 2727977fdcaSMatthias Ringwald {0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 2737977fdcaSMatthias Ringwald {0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2747977fdcaSMatthias Ringwald {0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2757977fdcaSMatthias Ringwald {0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2767977fdcaSMatthias Ringwald {0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2777977fdcaSMatthias Ringwald {0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2787977fdcaSMatthias Ringwald {0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 2797977fdcaSMatthias Ringwald {0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 2807977fdcaSMatthias Ringwald {0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 2817977fdcaSMatthias Ringwald {0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 2823366b4c1SMatthias Ringwald 2837977fdcaSMatthias Ringwald {0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0, RTL8761BU}, /* RTL8761BU only */ 2847977fdcaSMatthias Ringwald {0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU */ 2857977fdcaSMatthias Ringwald {0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU BT only */ 2868bb555aaSBjoern Hartmann 2877977fdcaSMatthias Ringwald {0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AU */ 2887977fdcaSMatthias Ringwald {0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2897977fdcaSMatthias Ringwald {0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2907977fdcaSMatthias Ringwald {0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2917977fdcaSMatthias Ringwald {0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2927977fdcaSMatthias Ringwald {0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2937977fdcaSMatthias Ringwald {0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2947977fdcaSMatthias Ringwald {0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2957977fdcaSMatthias Ringwald {0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2967977fdcaSMatthias Ringwald {0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2977977fdcaSMatthias Ringwald {0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2987977fdcaSMatthias Ringwald {0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 2997977fdcaSMatthias Ringwald {0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3007977fdcaSMatthias Ringwald {0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3017977fdcaSMatthias Ringwald {0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3027977fdcaSMatthias Ringwald {0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3037977fdcaSMatthias Ringwald {0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3047977fdcaSMatthias Ringwald {0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3057977fdcaSMatthias Ringwald {0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3067977fdcaSMatthias Ringwald {0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3077977fdcaSMatthias Ringwald {0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 3088bb555aaSBjoern Hartmann 3097977fdcaSMatthias Ringwald {0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 3107977fdcaSMatthias Ringwald {0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 3117977fdcaSMatthias Ringwald {0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 3123366b4c1SMatthias Ringwald 3137977fdcaSMatthias Ringwald {0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", NULL, 0, RTL8852BU}, /* RTL8851AU */ 3147977fdcaSMatthias Ringwald {0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BU */ 3157977fdcaSMatthias Ringwald {0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3167977fdcaSMatthias Ringwald {0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3177977fdcaSMatthias Ringwald {0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3187977fdcaSMatthias Ringwald {0x3570, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3197977fdcaSMatthias Ringwald {0x3572, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3207977fdcaSMatthias Ringwald {0x4b06, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3217977fdcaSMatthias Ringwald {0x885b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3227977fdcaSMatthias Ringwald {0x886b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3237977fdcaSMatthias Ringwald {0x887b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3247977fdcaSMatthias Ringwald {0xc559, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3257977fdcaSMatthias Ringwald {0xb052, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3267977fdcaSMatthias Ringwald {0xb152, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3277977fdcaSMatthias Ringwald {0xb252, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3287977fdcaSMatthias Ringwald {0x4853, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3297977fdcaSMatthias Ringwald {0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 3303366b4c1SMatthias Ringwald 3317977fdcaSMatthias Ringwald {0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CU */ 3327977fdcaSMatthias Ringwald {0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3337977fdcaSMatthias Ringwald {0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3347977fdcaSMatthias Ringwald {0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3357977fdcaSMatthias Ringwald {0x885c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3367977fdcaSMatthias Ringwald {0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3377977fdcaSMatthias Ringwald {0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3387977fdcaSMatthias Ringwald {0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 3393366b4c1SMatthias Ringwald 3407977fdcaSMatthias Ringwald {0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 3417977fdcaSMatthias Ringwald {0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 3423366b4c1SMatthias Ringwald 3437977fdcaSMatthias Ringwald {0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", NULL, 0, RTL8851BU}, /* RTL8851BU */ 3448bb555aaSBjoern Hartmann 3458bb555aaSBjoern Hartmann /* NOTE: must append patch entries above the null entry */ 3467977fdcaSMatthias Ringwald {0, 0, NULL, NULL, NULL, NULL, 0, 0} 3477977fdcaSMatthias Ringwald }; 3488bb555aaSBjoern Hartmann 3497977fdcaSMatthias Ringwald static uint16_t project_id[] = { 3508bb555aaSBjoern Hartmann ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 3518bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 3528bb555aaSBjoern Hartmann ROM_LMP_8821a, /* RTL8821CU */ 3538bb555aaSBjoern Hartmann ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 3548bb555aaSBjoern Hartmann ROM_LMP_8761a, /* index 14 for 8761BU */ 3557977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 18 for 8852AU */ 3567977fdcaSMatthias Ringwald ROM_LMP_8723b, /* index 19 for 8723FU */ 3577977fdcaSMatthias Ringwald ROM_LMP_8852a, /* index 20 for 8852BU */ 3587977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 25 for 8852CU */ 3597977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, 3607977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* index 33 for 8822EU */ 3617977fdcaSMatthias Ringwald ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8851b, /* index 36 for 8851BU */ 3628bb555aaSBjoern Hartmann }; 3638bb555aaSBjoern Hartmann 3648bb555aaSBjoern Hartmann static btstack_packet_callback_registration_t hci_event_callback_registration; 3657977fdcaSMatthias Ringwald static uint8_t state; 3668bb555aaSBjoern Hartmann static uint8_t rom_version; 3678bb555aaSBjoern Hartmann static uint16_t lmp_subversion; 3688bb555aaSBjoern Hartmann static uint16_t product_id; 3697977fdcaSMatthias Ringwald static const patch_info * patch; 3707977fdcaSMatthias Ringwald static uint8_t g_key_id = 0; 3718bb555aaSBjoern Hartmann 3728bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 3738bb555aaSBjoern Hartmann static const char *firmware_folder_path = "."; 3748bb555aaSBjoern Hartmann static const char *firmware_file_path; 3758bb555aaSBjoern Hartmann static const char *config_folder_path = "."; 3768bb555aaSBjoern Hartmann static const char *config_file_path; 3778bb555aaSBjoern Hartmann static char firmware_file[1000]; 3788bb555aaSBjoern Hartmann static char config_file[1000]; 3798bb555aaSBjoern Hartmann #endif 3808bb555aaSBjoern Hartmann 3817977fdcaSMatthias Ringwald static const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 3827977fdcaSMatthias Ringwald static const uint8_t FW_SIGNATURE_NEW[8] = {0x52, 0x54, 0x42, 0x54, 0x43, 0x6F, 0x72, 0x65}; 3837977fdcaSMatthias Ringwald static const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 3848bb555aaSBjoern Hartmann 3858bb555aaSBjoern Hartmann static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 3868bb555aaSBjoern Hartmann UNUSED(channel); 3878bb555aaSBjoern Hartmann UNUSED(size); 3887977fdcaSMatthias Ringwald if (packet_type != HCI_EVENT_PACKET) { 3898bb555aaSBjoern Hartmann return; 3908bb555aaSBjoern Hartmann } 3917977fdcaSMatthias Ringwald if (hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 3927977fdcaSMatthias Ringwald return; 3937977fdcaSMatthias Ringwald } 3948bb555aaSBjoern Hartmann 3957977fdcaSMatthias Ringwald uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 3967977fdcaSMatthias Ringwald const uint8_t * return_para = hci_event_command_complete_get_return_parameters(packet); 3978bb555aaSBjoern Hartmann switch (opcode) { 3987977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION: 3997977fdcaSMatthias Ringwald lmp_subversion = little_endian_read_16(packet, 12); 4007977fdcaSMatthias Ringwald break; 4017977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_RTK_READ_ROM_VERSION: 4027977fdcaSMatthias Ringwald rom_version = return_para[1]; 4038bb555aaSBjoern Hartmann log_info("Received ROM version 0x%02x", rom_version); 4047977fdcaSMatthias Ringwald printf("Realtek: Received ROM version 0x%02x\n", rom_version); 4057977fdcaSMatthias Ringwald if (patch->lmp_sub != lmp_subversion) { 4067977fdcaSMatthias Ringwald printf("Realtek: Firmware already exists\n"); 4077977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 4087977fdcaSMatthias Ringwald } 4097977fdcaSMatthias Ringwald break; 4107977fdcaSMatthias Ringwald case HCI_OPCODE_HCI_RTK_READ_CARD_INFO: 4117977fdcaSMatthias Ringwald switch (state){ 4127977fdcaSMatthias Ringwald case STATE_PHASE_1_W4_READ_LMP_SUBVERSION: 4137977fdcaSMatthias Ringwald log_info("Read Card: LMP Subversion"); 4147977fdcaSMatthias Ringwald if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x8822){ 4157977fdcaSMatthias Ringwald state = STATE_PHASE_1_READ_HCI_REVISION; 4167977fdcaSMatthias Ringwald } else { 4177977fdcaSMatthias Ringwald state = STATE_PHASE_1_DONE; 4187977fdcaSMatthias Ringwald } 4197977fdcaSMatthias Ringwald break; 4207977fdcaSMatthias Ringwald case STATE_PHASE_1_W4_READ_HCI_REVISION: 4217977fdcaSMatthias Ringwald log_info("Read Card: HCI Revision"); 4227977fdcaSMatthias Ringwald if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x000e){ 4237977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_ROM_VERSION; 4247977fdcaSMatthias Ringwald } else { 4257977fdcaSMatthias Ringwald state = STATE_PHASE_1_DONE; 4267977fdcaSMatthias Ringwald } 4277977fdcaSMatthias Ringwald break; 4287977fdcaSMatthias Ringwald case STATE_PHASE_2_W4_SEC_PROJ: 4297977fdcaSMatthias Ringwald g_key_id = return_para[1]; 4307977fdcaSMatthias Ringwald printf("Realtek: Received key id 0x%02x\n", g_key_id); 4317977fdcaSMatthias Ringwald state = STATE_PHASE_2_LOAD_FIRMWARE; 4327977fdcaSMatthias Ringwald break; 4337977fdcaSMatthias Ringwald default: 4347977fdcaSMatthias Ringwald btstack_assert(false); 4357977fdcaSMatthias Ringwald break; 4367977fdcaSMatthias Ringwald } 4378bb555aaSBjoern Hartmann break; 4388bb555aaSBjoern Hartmann default: 4398bb555aaSBjoern Hartmann break; 4408bb555aaSBjoern Hartmann } 4418bb555aaSBjoern Hartmann } 4428bb555aaSBjoern Hartmann 4438bb555aaSBjoern Hartmann static void chipset_init(const void *config) { 4448bb555aaSBjoern Hartmann UNUSED(config); 4457977fdcaSMatthias Ringwald 4467977fdcaSMatthias Ringwald // pre-set lmp subversion: HCI starts custom download only if HCI Version = 0x00e, and LMP Subversion = 0x8822 4477977fdcaSMatthias Ringwald lmp_subversion = 0x8822; 4487977fdcaSMatthias Ringwald 4498bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4508bb555aaSBjoern Hartmann // determine file path 4518bb555aaSBjoern Hartmann if (firmware_file_path == NULL || config_file_path == NULL) { 4528bb555aaSBjoern Hartmann log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 4538bb555aaSBjoern Hartmann patch = NULL; 45492728706SMatthias Ringwald for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 4558bb555aaSBjoern Hartmann if (fw_patch_table[i].prod_id == product_id) { 4568bb555aaSBjoern Hartmann patch = &fw_patch_table[i]; 4578bb555aaSBjoern Hartmann break; 4588bb555aaSBjoern Hartmann } 4598bb555aaSBjoern Hartmann } 4608bb555aaSBjoern Hartmann if (patch == NULL) { 4618bb555aaSBjoern Hartmann log_info("Product id 0x%04x is unknown", product_id); 4627977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 4638bb555aaSBjoern Hartmann return; 4648bb555aaSBjoern Hartmann } 465*c75b474dSMatthias Ringwald btstack_snprintf_assert_complete(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 466*c75b474dSMatthias Ringwald btstack_snprintf_assert_complete(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 4678bb555aaSBjoern Hartmann firmware_file_path = &firmware_file[0]; 4688bb555aaSBjoern Hartmann config_file_path = &config_file[0]; 4697977fdcaSMatthias Ringwald //lmp_subversion = patch->lmp_sub; 4708bb555aaSBjoern Hartmann } 4718bb555aaSBjoern Hartmann log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 4727977fdcaSMatthias Ringwald printf("Realtek: Using firmware '%s' and config '%s'\n", firmware_file_path, config_file_path); 4738bb555aaSBjoern Hartmann 4748bb555aaSBjoern Hartmann // activate hci callback 4758bb555aaSBjoern Hartmann hci_event_callback_registration.callback = &hci_packet_handler; 4768bb555aaSBjoern Hartmann hci_add_event_handler(&hci_event_callback_registration); 4777977fdcaSMatthias Ringwald state = STATE_PHASE_1_READ_LMP_SUBVERSION; 4788bb555aaSBjoern Hartmann #endif 4798bb555aaSBjoern Hartmann } 4808bb555aaSBjoern Hartmann 4818bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 4828bb555aaSBjoern Hartmann 4838bb555aaSBjoern Hartmann /** 4848bb555aaSBjoern Hartmann * @brief Opens the specified file and stores content to an allocated buffer 4858bb555aaSBjoern Hartmann * 4868bb555aaSBjoern Hartmann * @param file 4878bb555aaSBjoern Hartmann * @param buf 4888bb555aaSBjoern Hartmann * @param name 4898bb555aaSBjoern Hartmann * @return uint32_t Length of file 4908bb555aaSBjoern Hartmann */ 4918bb555aaSBjoern Hartmann static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 4928bb555aaSBjoern Hartmann uint32_t size; 4938bb555aaSBjoern Hartmann 4948bb555aaSBjoern Hartmann // open file 4958bb555aaSBjoern Hartmann *file = fopen(name, "rb"); 4968bb555aaSBjoern Hartmann if (*file == NULL) { 4978bb555aaSBjoern Hartmann log_info("Failed to open file %s", name); 4988bb555aaSBjoern Hartmann return 0; 4998bb555aaSBjoern Hartmann } 5008bb555aaSBjoern Hartmann 5018bb555aaSBjoern Hartmann // determine length of file 5028bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_END); 5038bb555aaSBjoern Hartmann size = ftell(*file); 5048bb555aaSBjoern Hartmann fseek(*file, 0, SEEK_SET); 5058bb555aaSBjoern Hartmann if (size <= 0) { 5068bb555aaSBjoern Hartmann return 0; 5078bb555aaSBjoern Hartmann } 5088bb555aaSBjoern Hartmann 5098bb555aaSBjoern Hartmann // allocate memory 5108bb555aaSBjoern Hartmann *buf = malloc(size); 5118bb555aaSBjoern Hartmann if (*buf == NULL) { 5128bb555aaSBjoern Hartmann fclose(*file); 5138bb555aaSBjoern Hartmann *file = NULL; 5148bb555aaSBjoern Hartmann log_info("Failed to allocate %u bytes for file %s", size, name); 5158bb555aaSBjoern Hartmann return 0; 5168bb555aaSBjoern Hartmann } 5178bb555aaSBjoern Hartmann 5188bb555aaSBjoern Hartmann // read file 51958080ea6SMatthias Ringwald size_t ret = fread(*buf, size, 1, *file); 5208bb555aaSBjoern Hartmann if (ret != 1) { 52109fffc16SMatthias Ringwald log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 5228bb555aaSBjoern Hartmann fclose(*file); 5238bb555aaSBjoern Hartmann free(*buf); 5248bb555aaSBjoern Hartmann *file = NULL; 5258bb555aaSBjoern Hartmann *buf = NULL; 5268bb555aaSBjoern Hartmann return 0; 5278bb555aaSBjoern Hartmann } 5288bb555aaSBjoern Hartmann 5298bb555aaSBjoern Hartmann log_info("Opened file %s and read %u bytes", name, size); 5308bb555aaSBjoern Hartmann return size; 5318bb555aaSBjoern Hartmann } 5328bb555aaSBjoern Hartmann 5338bb555aaSBjoern Hartmann static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 5348bb555aaSBjoern Hartmann fclose(*file); 5358bb555aaSBjoern Hartmann free(*buffer); 5368bb555aaSBjoern Hartmann *buffer = NULL; 5378bb555aaSBjoern Hartmann *file = NULL; 5388bb555aaSBjoern Hartmann } 5398bb555aaSBjoern Hartmann 5407977fdcaSMatthias Ringwald static uint8_t rtk_get_fw_project_id(uint8_t * p_buf) 5417977fdcaSMatthias Ringwald { 5427977fdcaSMatthias Ringwald uint8_t opcode; 5437977fdcaSMatthias Ringwald uint8_t len; 5447977fdcaSMatthias Ringwald uint8_t data = 0; 5457977fdcaSMatthias Ringwald 5467977fdcaSMatthias Ringwald do { 5477977fdcaSMatthias Ringwald opcode = *p_buf; 5487977fdcaSMatthias Ringwald len = *(p_buf - 1); 5497977fdcaSMatthias Ringwald if (opcode == 0x00) { 5507977fdcaSMatthias Ringwald if (len == 1) { 5517977fdcaSMatthias Ringwald data = *(p_buf - 2); 5527977fdcaSMatthias Ringwald log_info 5537977fdcaSMatthias Ringwald ("rtk_get_fw_project_id: opcode %d, len %d, data %d", 5547977fdcaSMatthias Ringwald opcode, len, data); 5557977fdcaSMatthias Ringwald break; 5567977fdcaSMatthias Ringwald } else { 5577977fdcaSMatthias Ringwald log_error 5587977fdcaSMatthias Ringwald ("rtk_get_fw_project_id: invalid len %d", 5597977fdcaSMatthias Ringwald len); 5607977fdcaSMatthias Ringwald } 5617977fdcaSMatthias Ringwald } 5627977fdcaSMatthias Ringwald p_buf -= len + 2; 5637977fdcaSMatthias Ringwald } while (*p_buf != 0xFF); 5647977fdcaSMatthias Ringwald 5657977fdcaSMatthias Ringwald return data; 5667977fdcaSMatthias Ringwald } 5677977fdcaSMatthias Ringwald 5687977fdcaSMatthias Ringwald struct rtb_ota_flag { 5697977fdcaSMatthias Ringwald uint8_t eco; 5707977fdcaSMatthias Ringwald uint8_t enable; 5717977fdcaSMatthias Ringwald uint16_t reserve; 5727977fdcaSMatthias Ringwald }; 5737977fdcaSMatthias Ringwald 5747977fdcaSMatthias Ringwald struct patch_node { 5757977fdcaSMatthias Ringwald btstack_linked_item_t item; 5767977fdcaSMatthias Ringwald uint8_t eco; 5777977fdcaSMatthias Ringwald uint8_t pri; 5787977fdcaSMatthias Ringwald uint8_t key_id; 5797977fdcaSMatthias Ringwald uint8_t reserve; 5807977fdcaSMatthias Ringwald uint32_t len; 5817977fdcaSMatthias Ringwald uint8_t *payload; 5827977fdcaSMatthias Ringwald }; 5837977fdcaSMatthias Ringwald 5847977fdcaSMatthias Ringwald /* Add a node to alist that is in ascending order. */ 5857977fdcaSMatthias Ringwald static void insert_queue_sort(btstack_linked_list_t * list, struct patch_node *node) 5867977fdcaSMatthias Ringwald { 5877977fdcaSMatthias Ringwald btstack_assert(list != NULL); 5887977fdcaSMatthias Ringwald btstack_assert(node != NULL); 5897977fdcaSMatthias Ringwald 5907977fdcaSMatthias Ringwald struct patch_node *next; 5917977fdcaSMatthias Ringwald btstack_linked_item_t *it; 5927977fdcaSMatthias Ringwald 5937977fdcaSMatthias Ringwald for (it = (btstack_linked_item_t *) list; it->next ; it = it->next){ 5947977fdcaSMatthias Ringwald next = (struct patch_node *) it->next; 5957977fdcaSMatthias Ringwald if(next->pri >= node->pri) { 5967977fdcaSMatthias Ringwald break; 5977977fdcaSMatthias Ringwald } 5987977fdcaSMatthias Ringwald } 5997977fdcaSMatthias Ringwald node->item.next = it->next; 6007977fdcaSMatthias Ringwald it->next = (btstack_linked_item_t *) node; 6017977fdcaSMatthias Ringwald } 6027977fdcaSMatthias Ringwald 6037977fdcaSMatthias Ringwald static int insert_patch(btstack_linked_list_t * patch_list, uint8_t *section_pos, 6047977fdcaSMatthias Ringwald uint32_t opcode, uint32_t *patch_len, uint8_t *sec_flag) 6057977fdcaSMatthias Ringwald { 6067977fdcaSMatthias Ringwald struct patch_node *tmp; 6077977fdcaSMatthias Ringwald uint32_t i; 6087977fdcaSMatthias Ringwald uint32_t numbers; 6097977fdcaSMatthias Ringwald uint32_t section_len = 0; 6107977fdcaSMatthias Ringwald uint8_t eco = 0; 6117977fdcaSMatthias Ringwald uint8_t *pos = section_pos + 8; 6127977fdcaSMatthias Ringwald 6137977fdcaSMatthias Ringwald numbers = little_endian_read_16(pos, 0); 6147977fdcaSMatthias Ringwald log_info("number 0x%04x", numbers); 6157977fdcaSMatthias Ringwald 6167977fdcaSMatthias Ringwald pos += 4; 6177977fdcaSMatthias Ringwald for (i = 0; i < numbers; i++) { 6187977fdcaSMatthias Ringwald eco = (uint8_t)*(pos); 6197977fdcaSMatthias Ringwald log_info("eco 0x%02x, Eversion:%02x", eco, rom_version); 6207977fdcaSMatthias Ringwald if (eco == rom_version + 1) { 6217977fdcaSMatthias Ringwald //tmp = (struct patch_node*)kzalloc(sizeof(struct patch_node), GFP_KERNEL); 6227977fdcaSMatthias Ringwald tmp = (struct patch_node*)malloc(sizeof(struct patch_node)); 6237977fdcaSMatthias Ringwald tmp->pri = (uint8_t)*(pos + 1); 6247977fdcaSMatthias Ringwald if(opcode == PATCH_SECURITY_HEADER) 6257977fdcaSMatthias Ringwald tmp->key_id = (uint8_t)*(pos + 1); 6267977fdcaSMatthias Ringwald 6277977fdcaSMatthias Ringwald section_len = little_endian_read_32(pos, 4); 6287977fdcaSMatthias Ringwald tmp->len = section_len; 6297977fdcaSMatthias Ringwald *patch_len += section_len; 6307977fdcaSMatthias Ringwald log_info("Pri:%d, Patch length 0x%04x", tmp->pri, tmp->len); 6317977fdcaSMatthias Ringwald tmp->payload = pos + 8; 6327977fdcaSMatthias Ringwald if(opcode != PATCH_SECURITY_HEADER) { 6337977fdcaSMatthias Ringwald insert_queue_sort(patch_list, tmp); 6347977fdcaSMatthias Ringwald } else { 6357977fdcaSMatthias Ringwald if((g_key_id == tmp->key_id) && (g_key_id > 0)) { 6367977fdcaSMatthias Ringwald insert_queue_sort(patch_list, tmp); 6377977fdcaSMatthias Ringwald *sec_flag = 1; 6387977fdcaSMatthias Ringwald } else { 6397977fdcaSMatthias Ringwald pos += (8 + section_len); 6407977fdcaSMatthias Ringwald free(tmp); 6417977fdcaSMatthias Ringwald continue; 6427977fdcaSMatthias Ringwald } 6437977fdcaSMatthias Ringwald } 6447977fdcaSMatthias Ringwald } else { 6457977fdcaSMatthias Ringwald section_len = little_endian_read_32(pos, 4); 6467977fdcaSMatthias Ringwald log_info("Patch length 0x%04x", section_len); 6477977fdcaSMatthias Ringwald } 6487977fdcaSMatthias Ringwald pos += (8 + section_len); 6497977fdcaSMatthias Ringwald } 6507977fdcaSMatthias Ringwald return 0; 6517977fdcaSMatthias Ringwald } 6527977fdcaSMatthias Ringwald static uint8_t *rtb_get_patch_header(uint32_t *len, 6537977fdcaSMatthias Ringwald btstack_linked_list_t * patch_list, uint8_t * epatch_buf, 6547977fdcaSMatthias Ringwald uint8_t key_id) 6557977fdcaSMatthias Ringwald { 6567977fdcaSMatthias Ringwald uint16_t i, j; 6577977fdcaSMatthias Ringwald struct rtb_new_patch_hdr *new_patch; 6587977fdcaSMatthias Ringwald uint8_t sec_flag = 0; 6597977fdcaSMatthias Ringwald uint32_t number_of_ota_flag; 6607977fdcaSMatthias Ringwald uint32_t patch_len = 0; 6617977fdcaSMatthias Ringwald uint8_t *section_pos; 6627977fdcaSMatthias Ringwald uint8_t *ota_flag_pos; 6637977fdcaSMatthias Ringwald uint32_t number_of_section; 6647977fdcaSMatthias Ringwald 6657977fdcaSMatthias Ringwald struct rtb_section_hdr section_hdr; 6667977fdcaSMatthias Ringwald struct rtb_ota_flag ota_flag; 6677977fdcaSMatthias Ringwald 6687977fdcaSMatthias Ringwald new_patch = (struct rtb_new_patch_hdr *)epatch_buf; 6697977fdcaSMatthias Ringwald number_of_section = new_patch->number_of_section; 6707977fdcaSMatthias Ringwald 6717977fdcaSMatthias Ringwald log_info("FW version 0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", 6727977fdcaSMatthias Ringwald *(epatch_buf + 8), *(epatch_buf + 9), *(epatch_buf + 10), 6737977fdcaSMatthias Ringwald *(epatch_buf + 11),*(epatch_buf + 12), *(epatch_buf + 13), 6747977fdcaSMatthias Ringwald *(epatch_buf + 14), *(epatch_buf + 15)); 6757977fdcaSMatthias Ringwald 6767977fdcaSMatthias Ringwald section_pos = epatch_buf + 20; 6777977fdcaSMatthias Ringwald 6787977fdcaSMatthias Ringwald for (i = 0; i < number_of_section; i++) { 6797977fdcaSMatthias Ringwald section_hdr.opcode = little_endian_read_32(section_pos, 0); 6807977fdcaSMatthias Ringwald section_hdr.section_len = little_endian_read_32(section_pos, 4); 6817977fdcaSMatthias Ringwald log_info("opcode 0x%04x", section_hdr.opcode); 6827977fdcaSMatthias Ringwald switch (section_hdr.opcode) { 6837977fdcaSMatthias Ringwald case PATCH_SNIPPETS: 6847977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_SNIPPETS, &patch_len, NULL); 6857977fdcaSMatthias Ringwald printf("Realtek: patch len is %d\n",patch_len); 6867977fdcaSMatthias Ringwald break; 6877977fdcaSMatthias Ringwald case PATCH_SECURITY_HEADER: 6887977fdcaSMatthias Ringwald if(!g_key_id) 6897977fdcaSMatthias Ringwald break; 6907977fdcaSMatthias Ringwald 6917977fdcaSMatthias Ringwald sec_flag = 0; 6927977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_SECURITY_HEADER, &patch_len, &sec_flag); 6937977fdcaSMatthias Ringwald if(sec_flag) 6947977fdcaSMatthias Ringwald break; 6957977fdcaSMatthias Ringwald 6967977fdcaSMatthias Ringwald for (i = 0; i < number_of_section; i++) { 6977977fdcaSMatthias Ringwald section_hdr.opcode = little_endian_read_32(section_pos, 0); 6987977fdcaSMatthias Ringwald section_hdr.section_len = little_endian_read_32(section_pos, 4); 6997977fdcaSMatthias Ringwald if(section_hdr.opcode == PATCH_DUMMY_HEADER) { 7007977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 7017977fdcaSMatthias Ringwald } 7027977fdcaSMatthias Ringwald section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 7037977fdcaSMatthias Ringwald } 7047977fdcaSMatthias Ringwald break; 7057977fdcaSMatthias Ringwald case PATCH_DUMMY_HEADER: 7067977fdcaSMatthias Ringwald if(g_key_id) { 7077977fdcaSMatthias Ringwald break; 7087977fdcaSMatthias Ringwald } 7097977fdcaSMatthias Ringwald insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 7107977fdcaSMatthias Ringwald break; 7117977fdcaSMatthias Ringwald case PATCH_OTA_FLAG: 7127977fdcaSMatthias Ringwald ota_flag_pos = section_pos + 4; 7137977fdcaSMatthias Ringwald number_of_ota_flag = little_endian_read_32(ota_flag_pos, 0); 7147977fdcaSMatthias Ringwald ota_flag.eco = (uint8_t)*(ota_flag_pos + 1); 7157977fdcaSMatthias Ringwald if (ota_flag.eco == rom_version + 1) { 7167977fdcaSMatthias Ringwald for (j = 0; j < number_of_ota_flag; j++) { 7177977fdcaSMatthias Ringwald if (ota_flag.eco == rom_version + 1) { 7187977fdcaSMatthias Ringwald ota_flag.enable = little_endian_read_32(ota_flag_pos, 4); 7197977fdcaSMatthias Ringwald } 7207977fdcaSMatthias Ringwald } 7217977fdcaSMatthias Ringwald } 7227977fdcaSMatthias Ringwald break; 7237977fdcaSMatthias Ringwald default: 7247977fdcaSMatthias Ringwald log_error("Unknown Opcode"); 7257977fdcaSMatthias Ringwald break; 7267977fdcaSMatthias Ringwald } 7277977fdcaSMatthias Ringwald section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 7287977fdcaSMatthias Ringwald } 7297977fdcaSMatthias Ringwald *len = patch_len; 7307977fdcaSMatthias Ringwald 7317977fdcaSMatthias Ringwald return NULL; 7327977fdcaSMatthias Ringwald } 7337977fdcaSMatthias Ringwald 7347977fdcaSMatthias Ringwald static inline int get_max_patch_size(uint8_t chip_type) 7357977fdcaSMatthias Ringwald { 7367977fdcaSMatthias Ringwald int max_patch_size = 0; 7377977fdcaSMatthias Ringwald 7387977fdcaSMatthias Ringwald switch (chip_type) { 7397977fdcaSMatthias Ringwald case RTLPREVIOUS: 7407977fdcaSMatthias Ringwald max_patch_size = 24 * 1024; 7417977fdcaSMatthias Ringwald break; 7427977fdcaSMatthias Ringwald case RTL8822BU: 7437977fdcaSMatthias Ringwald max_patch_size = 25 * 1024; 7447977fdcaSMatthias Ringwald break; 7457977fdcaSMatthias Ringwald case RTL8723DU: 7467977fdcaSMatthias Ringwald case RTL8822CU: 7477977fdcaSMatthias Ringwald case RTL8761BU: 7487977fdcaSMatthias Ringwald case RTL8821CU: 7497977fdcaSMatthias Ringwald max_patch_size = 40 * 1024; 7507977fdcaSMatthias Ringwald break; 7517977fdcaSMatthias Ringwald case RTL8852AU: 7527977fdcaSMatthias Ringwald max_patch_size = 0x114D0 + 529; /* 69.2KB */ 7537977fdcaSMatthias Ringwald break; 7547977fdcaSMatthias Ringwald case RTL8723FU: 7557977fdcaSMatthias Ringwald max_patch_size = 0xC4Cf + 529; /* 49.2KB */ 7567977fdcaSMatthias Ringwald break; 7577977fdcaSMatthias Ringwald case RTL8852BU: 7587977fdcaSMatthias Ringwald case RTL8851BU: 7597977fdcaSMatthias Ringwald max_patch_size = 0x104D0 + 529; /* 65KB */ 7607977fdcaSMatthias Ringwald break; 7617977fdcaSMatthias Ringwald case RTL8852CU: 7627977fdcaSMatthias Ringwald max_patch_size = 0x130D0 + 529; /* 76.2KB */ 7637977fdcaSMatthias Ringwald break; 7647977fdcaSMatthias Ringwald case RTL8822EU: 7657977fdcaSMatthias Ringwald max_patch_size = 0x24620 + 529; /* 145KB */ 7667977fdcaSMatthias Ringwald break; 7677977fdcaSMatthias Ringwald default: 7687977fdcaSMatthias Ringwald max_patch_size = 40 * 1024; 7697977fdcaSMatthias Ringwald break; 7707977fdcaSMatthias Ringwald } 7717977fdcaSMatthias Ringwald 7727977fdcaSMatthias Ringwald return max_patch_size; 7737977fdcaSMatthias Ringwald } 7747977fdcaSMatthias Ringwald 7758bb555aaSBjoern Hartmann static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 7768bb555aaSBjoern Hartmann static uint8_t *patch_buf = NULL; 7778bb555aaSBjoern Hartmann static uint32_t fw_total_len; 7788bb555aaSBjoern Hartmann static uint32_t fw_ptr; 7798bb555aaSBjoern Hartmann static uint8_t index; 7808bb555aaSBjoern Hartmann 7818bb555aaSBjoern Hartmann // read firmware and config 7828bb555aaSBjoern Hartmann if (patch_buf == NULL) { 7838bb555aaSBjoern Hartmann uint16_t patch_length = 0; 7848bb555aaSBjoern Hartmann uint32_t offset; 7858bb555aaSBjoern Hartmann FILE * fw = NULL; 7868bb555aaSBjoern Hartmann uint32_t fw_size; 7878bb555aaSBjoern Hartmann uint8_t *fw_buf = NULL; 7888bb555aaSBjoern Hartmann 7898bb555aaSBjoern Hartmann FILE * conf = NULL; 7908bb555aaSBjoern Hartmann uint32_t conf_size; 7918bb555aaSBjoern Hartmann uint8_t *conf_buf = NULL; 7928bb555aaSBjoern Hartmann 7937977fdcaSMatthias Ringwald uint32_t fw_version; 7947977fdcaSMatthias Ringwald uint16_t fw_num_patches; 7957977fdcaSMatthias Ringwald 7967977fdcaSMatthias Ringwald struct patch_node *tmp; 7977977fdcaSMatthias Ringwald int max_patch_size = 0; 7987977fdcaSMatthias Ringwald 7998bb555aaSBjoern Hartmann if (firmware == NULL || config == NULL) { 8008bb555aaSBjoern Hartmann log_info("Please specify realtek firmware and config file paths"); 8018bb555aaSBjoern Hartmann return FW_DONE; 8028bb555aaSBjoern Hartmann } 8037977fdcaSMatthias Ringwald // read config 8047977fdcaSMatthias Ringwald conf_size = read_file(&conf, &conf_buf, config); 8057977fdcaSMatthias Ringwald if (conf_size == 0) { 8067977fdcaSMatthias Ringwald log_info("Config size is 0, using efuse settings!"); 8077977fdcaSMatthias Ringwald } 8088bb555aaSBjoern Hartmann // read firmware 8098bb555aaSBjoern Hartmann fw_size = read_file(&fw, &fw_buf, firmware); 8108bb555aaSBjoern Hartmann if (fw_size == 0) { 8118bb555aaSBjoern Hartmann log_info("Firmware size is 0. Quit!"); 8127977fdcaSMatthias Ringwald if (conf_size != 0){ 8137977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 8147977fdcaSMatthias Ringwald } 8158bb555aaSBjoern Hartmann return FW_DONE; 8168bb555aaSBjoern Hartmann } 8178bb555aaSBjoern Hartmann // check signature 8187977fdcaSMatthias Ringwald if (((memcmp(fw_buf, FW_SIGNATURE, 8) != 0) && (memcmp(fw_buf, FW_SIGNATURE_NEW, 8) != 0)) 8197977fdcaSMatthias Ringwald || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 8208bb555aaSBjoern Hartmann log_info("Wrong signature. Quit!"); 8218bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8228bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8238bb555aaSBjoern Hartmann return FW_DONE; 8248bb555aaSBjoern Hartmann } 8258bb555aaSBjoern Hartmann // check project id 8267977fdcaSMatthias Ringwald if (lmp_subversion != project_id[rtk_get_fw_project_id(fw_buf + fw_size - 5)]) { 8278bb555aaSBjoern Hartmann log_info("Wrong project id. Quit!"); 8288bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8298bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8308bb555aaSBjoern Hartmann return FW_DONE; 8318bb555aaSBjoern Hartmann } 8327977fdcaSMatthias Ringwald // init ordered list for new firmware signature 8337977fdcaSMatthias Ringwald btstack_linked_list_t patch_list = NULL; 8347977fdcaSMatthias Ringwald bool have_new_firmware_signature = memcmp(fw_buf, FW_SIGNATURE_NEW, 8) == 0; 8357977fdcaSMatthias Ringwald if (have_new_firmware_signature){ 8367977fdcaSMatthias Ringwald printf("Realtek: Using new signature\n"); 8377977fdcaSMatthias Ringwald uint8_t key_id = g_key_id; 8387977fdcaSMatthias Ringwald if (key_id < 0) { 8397977fdcaSMatthias Ringwald log_info("Wrong key id. Quit!"); 8407977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 8417977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 8427977fdcaSMatthias Ringwald return FW_DONE; 8437977fdcaSMatthias Ringwald } 8448bb555aaSBjoern Hartmann 8457977fdcaSMatthias Ringwald rtb_get_patch_header(&fw_total_len, &patch_list, fw_buf, key_id); 8467977fdcaSMatthias Ringwald if (fw_total_len == 0) { 8477977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 8487977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 8497977fdcaSMatthias Ringwald return FW_DONE; 8507977fdcaSMatthias Ringwald } 8517977fdcaSMatthias Ringwald fw_total_len += conf_size; 8527977fdcaSMatthias Ringwald } else { 8537977fdcaSMatthias Ringwald printf("Realtek: Using old signature\n"); 8548bb555aaSBjoern Hartmann // read firmware version 8557977fdcaSMatthias Ringwald fw_version = little_endian_read_32(fw_buf, 8); 8568bb555aaSBjoern Hartmann log_info("Firmware version: 0x%x", fw_version); 8578bb555aaSBjoern Hartmann 8588bb555aaSBjoern Hartmann // read number of patches 8597977fdcaSMatthias Ringwald fw_num_patches = little_endian_read_16(fw_buf, 12); 8608bb555aaSBjoern Hartmann log_info("Number of patches: %d", fw_num_patches); 8618bb555aaSBjoern Hartmann 8628bb555aaSBjoern Hartmann // find correct entry 8638bb555aaSBjoern Hartmann for (uint16_t i = 0; i < fw_num_patches; i++) { 8648bb555aaSBjoern Hartmann if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 8658bb555aaSBjoern Hartmann patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 8668bb555aaSBjoern Hartmann offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 8678bb555aaSBjoern Hartmann log_info("patch_length %u, offset %u", patch_length, offset); 8688bb555aaSBjoern Hartmann break; 8698bb555aaSBjoern Hartmann } 8708bb555aaSBjoern Hartmann } 8718bb555aaSBjoern Hartmann if (patch_length == 0) { 8728bb555aaSBjoern Hartmann log_debug("Failed to find valid patch"); 8738bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8748bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8758bb555aaSBjoern Hartmann return FW_DONE; 8768bb555aaSBjoern Hartmann } 8778bb555aaSBjoern Hartmann fw_total_len = patch_length + conf_size; 8787977fdcaSMatthias Ringwald } 8797977fdcaSMatthias Ringwald 8807977fdcaSMatthias Ringwald max_patch_size = get_max_patch_size(patch->chip_type); 8817977fdcaSMatthias Ringwald printf("Realtek: FW/CONFIG total length is %d, max patch size id %d\n", fw_total_len, max_patch_size); 8827977fdcaSMatthias Ringwald if (fw_total_len > max_patch_size) { 8837977fdcaSMatthias Ringwald printf("FRealtek: W/CONFIG total length larger than allowed %d\n", max_patch_size); 8847977fdcaSMatthias Ringwald finalize_file_and_buffer(&fw, &fw_buf); 8857977fdcaSMatthias Ringwald finalize_file_and_buffer(&conf, &conf_buf); 8867977fdcaSMatthias Ringwald return FW_DONE; 8877977fdcaSMatthias Ringwald } 8887977fdcaSMatthias Ringwald // allocate patch buffer 8898bb555aaSBjoern Hartmann patch_buf = malloc(fw_total_len); 8908bb555aaSBjoern Hartmann if (patch_buf == NULL) { 8918bb555aaSBjoern Hartmann log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 8928bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 8938bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 8948bb555aaSBjoern Hartmann return FW_DONE; 8958bb555aaSBjoern Hartmann } 8967977fdcaSMatthias Ringwald if (have_new_firmware_signature) { 8977977fdcaSMatthias Ringwald int tmp_len = 0; 8987977fdcaSMatthias Ringwald // append patches based on priority and free 8997977fdcaSMatthias Ringwald while (patch_list) { 9007977fdcaSMatthias Ringwald tmp = (struct patch_node *) patch_list; 9017977fdcaSMatthias Ringwald log_info("len = 0x%x", tmp->len); 9027977fdcaSMatthias Ringwald memcpy(patch_buf + tmp_len, tmp->payload, tmp->len); 9037977fdcaSMatthias Ringwald tmp_len += tmp->len; 9047977fdcaSMatthias Ringwald patch_list = patch_list->next; 9057977fdcaSMatthias Ringwald free(tmp); 9067977fdcaSMatthias Ringwald } 9077977fdcaSMatthias Ringwald if (conf_size) { 9087977fdcaSMatthias Ringwald memcpy(&patch_buf[fw_total_len - conf_size], conf_buf, conf_size); 9097977fdcaSMatthias Ringwald } 9107977fdcaSMatthias Ringwald } else { 9118bb555aaSBjoern Hartmann // copy patch 9128bb555aaSBjoern Hartmann memcpy(patch_buf, fw_buf + offset, patch_length); 9138bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length - 4, &fw_version, 4); 9148bb555aaSBjoern Hartmann memcpy(patch_buf + patch_length, conf_buf, conf_size); 9157977fdcaSMatthias Ringwald } 9168bb555aaSBjoern Hartmann fw_ptr = 0; 9178bb555aaSBjoern Hartmann index = 0; 9188bb555aaSBjoern Hartmann 9198bb555aaSBjoern Hartmann // close files 9208bb555aaSBjoern Hartmann finalize_file_and_buffer(&fw, &fw_buf); 9218bb555aaSBjoern Hartmann finalize_file_and_buffer(&conf, &conf_buf); 9228bb555aaSBjoern Hartmann } 9238bb555aaSBjoern Hartmann 9248bb555aaSBjoern Hartmann uint8_t len; 9258bb555aaSBjoern Hartmann if (fw_total_len - fw_ptr > 252) { 9268bb555aaSBjoern Hartmann len = 252; 9278bb555aaSBjoern Hartmann } else { 9288bb555aaSBjoern Hartmann len = fw_total_len - fw_ptr; 9298bb555aaSBjoern Hartmann index |= 0x80; // end 9308bb555aaSBjoern Hartmann } 9318bb555aaSBjoern Hartmann 9328bb555aaSBjoern Hartmann if (len) { 9337977fdcaSMatthias Ringwald little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_HCI_RTK_DOWNLOAD_FW); 9347977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, len + 1); 9357977fdcaSMatthias Ringwald HCI_CMD_DOWNLOAD_SET_INDEX(hci_cmd_buffer, index); 9367977fdcaSMatthias Ringwald HCI_CMD_DOWNLOAD_COPY_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 9378bb555aaSBjoern Hartmann index++; 9387977fdcaSMatthias Ringwald if (index > 0x7f) { 9397977fdcaSMatthias Ringwald index = (index & 0x7f) +1; 9407977fdcaSMatthias Ringwald } 9418bb555aaSBjoern Hartmann fw_ptr += len; 9428bb555aaSBjoern Hartmann return FW_MORE_TO_DO; 9438bb555aaSBjoern Hartmann } 9448bb555aaSBjoern Hartmann 9458bb555aaSBjoern Hartmann // cleanup and return 9468bb555aaSBjoern Hartmann free(patch_buf); 9478bb555aaSBjoern Hartmann patch_buf = NULL; 9487977fdcaSMatthias Ringwald printf("Realtek: Init process finished\n"); 9498bb555aaSBjoern Hartmann return FW_DONE; 9508bb555aaSBjoern Hartmann } 9518bb555aaSBjoern Hartmann 9528bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 9538bb555aaSBjoern Hartmann 9547977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_sec_proj[] = {0x61, 0xfc, 0x05, 0x10, 0xA4, 0x0D, 0x00, 0xb0 }; 9557977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_lmp_subversion[] = {0x61, 0xfc, 0x05, 0x10, 0x38, 0x04, 0x28, 0x80 }; 9567977fdcaSMatthias Ringwald static const uint8_t hci_realtek_read_hci_revision[] = {0x61, 0xfc, 0x05, 0x10, 0x3A, 0x04, 0x28, 0x80 }; 9577977fdcaSMatthias Ringwald 9588bb555aaSBjoern Hartmann static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 9598bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 9608bb555aaSBjoern Hartmann uint8_t ret; 9618bb555aaSBjoern Hartmann while (true) { 9628bb555aaSBjoern Hartmann switch (state) { 9637977fdcaSMatthias Ringwald case STATE_PHASE_1_READ_LMP_SUBVERSION: 9647977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_lmp_subversion, sizeof(hci_realtek_read_lmp_subversion)); 9657977fdcaSMatthias Ringwald state = STATE_PHASE_1_W4_READ_LMP_SUBVERSION; 9668bb555aaSBjoern Hartmann break; 9677977fdcaSMatthias Ringwald case STATE_PHASE_1_READ_HCI_REVISION: 9687977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_hci_revision, sizeof(hci_realtek_read_hci_revision)); 9697977fdcaSMatthias Ringwald state = STATE_PHASE_1_W4_READ_HCI_REVISION; 9707977fdcaSMatthias Ringwald break; 9717977fdcaSMatthias Ringwald case STATE_PHASE_1_DONE: 9727977fdcaSMatthias Ringwald // custom pre-init done, continue with read ROM version in main custom init 9737977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_ROM_VERSION; 9747977fdcaSMatthias Ringwald return BTSTACK_CHIPSET_DONE; 9757977fdcaSMatthias Ringwald case STATE_PHASE_2_READ_ROM_VERSION: 9767977fdcaSMatthias Ringwald HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RTK_READ_ROM_VERSION); 9777977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 9787977fdcaSMatthias Ringwald state = STATE_PHASE_2_READ_SEC_PROJ; 9797977fdcaSMatthias Ringwald break; 9807977fdcaSMatthias Ringwald case STATE_PHASE_2_READ_SEC_PROJ: 9817977fdcaSMatthias Ringwald memcpy(hci_cmd_buffer, hci_realtek_read_sec_proj, sizeof(hci_realtek_read_sec_proj)); 9827977fdcaSMatthias Ringwald state = STATE_PHASE_2_W4_SEC_PROJ; 9837977fdcaSMatthias Ringwald break; 9847977fdcaSMatthias Ringwald case STATE_PHASE_2_LOAD_FIRMWARE: 9858bb555aaSBjoern Hartmann if (lmp_subversion != ROM_LMP_8723a) { 9868bb555aaSBjoern Hartmann ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 9878bb555aaSBjoern Hartmann } else { 9888bb555aaSBjoern Hartmann log_info("Realtek firmware for old patch style not implemented"); 9898bb555aaSBjoern Hartmann ret = FW_DONE; 9908bb555aaSBjoern Hartmann } 9918bb555aaSBjoern Hartmann if (ret != FW_DONE) { 9928bb555aaSBjoern Hartmann break; 9938bb555aaSBjoern Hartmann } 9947977fdcaSMatthias Ringwald // we are done 9957977fdcaSMatthias Ringwald state = STATE_PHASE_2_RESET; 9967977fdcaSMatthias Ringwald 9977977fdcaSMatthias Ringwald /* fall through */ 9987977fdcaSMatthias Ringwald 9997977fdcaSMatthias Ringwald case STATE_PHASE_2_RESET: 10007977fdcaSMatthias Ringwald HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RESET); 10017977fdcaSMatthias Ringwald HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 10027977fdcaSMatthias Ringwald state = STATE_PHASE_2_DONE; 10038bb555aaSBjoern Hartmann break; 10047977fdcaSMatthias Ringwald case STATE_PHASE_2_DONE: 10058bb555aaSBjoern Hartmann hci_remove_event_handler(&hci_event_callback_registration); 10068bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 10078bb555aaSBjoern Hartmann default: 10088bb555aaSBjoern Hartmann log_info("Invalid state %d", state); 10098bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_DONE; 10108bb555aaSBjoern Hartmann } 10118bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_VALID_COMMAND; 10128bb555aaSBjoern Hartmann } 10138bb555aaSBjoern Hartmann #else // HAVE_POSIX_FILE_IO 10148bb555aaSBjoern Hartmann log_info("Realtek without File IO is not implemented yet"); 10158bb555aaSBjoern Hartmann return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 10168bb555aaSBjoern Hartmann #endif // HAVE_POSIX_FILE_IO 10178bb555aaSBjoern Hartmann } 10188bb555aaSBjoern Hartmann 10198bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 10208bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10218bb555aaSBjoern Hartmann firmware_file_path = path; 10228bb555aaSBjoern Hartmann #endif 10238bb555aaSBjoern Hartmann } 10248bb555aaSBjoern Hartmann 10258bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 10268bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10278bb555aaSBjoern Hartmann firmware_folder_path = path; 10288bb555aaSBjoern Hartmann #endif 10298bb555aaSBjoern Hartmann } 10308bb555aaSBjoern Hartmann 10318bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_file_path(const char *path) { 10328bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10338bb555aaSBjoern Hartmann config_file_path = path; 10348bb555aaSBjoern Hartmann #endif 10358bb555aaSBjoern Hartmann } 10368bb555aaSBjoern Hartmann 10378bb555aaSBjoern Hartmann void btstack_chipset_realtek_set_config_folder_path(const char *path) { 10388bb555aaSBjoern Hartmann #ifdef HAVE_POSIX_FILE_IO 10398bb555aaSBjoern Hartmann config_folder_path = path; 10408bb555aaSBjoern Hartmann #endif 10418bb555aaSBjoern Hartmann } 10428bb555aaSBjoern Hartmann 10435a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_set_product_id(uint16_t id) { 10445a4c0fdaSMatthias Ringwald product_id = id; 10455a4c0fdaSMatthias Ringwald } 10465a4c0fdaSMatthias Ringwald 10475a4c0fdaSMatthias Ringwald uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 10485a4c0fdaSMatthias Ringwald return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 10495a4c0fdaSMatthias Ringwald } 10505a4c0fdaSMatthias Ringwald 10515a4c0fdaSMatthias Ringwald void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 10525a4c0fdaSMatthias Ringwald btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 10535a4c0fdaSMatthias Ringwald *out_vendor_id = 0xbda; 10545a4c0fdaSMatthias Ringwald *out_product_id = fw_patch_table[index].prod_id; 10555a4c0fdaSMatthias Ringwald } 10568bb555aaSBjoern Hartmann 10578bb555aaSBjoern Hartmann static const btstack_chipset_t btstack_chipset_realtek = { 10588bb555aaSBjoern Hartmann "REALTEK", chipset_init, chipset_next_command, 10598bb555aaSBjoern Hartmann NULL, // chipset_set_baudrate_command, 10608bb555aaSBjoern Hartmann NULL, // chipset_set_bd_addr_command not supported or implemented 10618bb555aaSBjoern Hartmann }; 10628bb555aaSBjoern Hartmann 10638bb555aaSBjoern Hartmann const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 1064