1 /* 2 * Copyright (C) 2022 BlueKitchen GmbH 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the copyright holders nor the names of 14 * contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 4. Any redistribution, use, or modification is done solely for 17 * personal benefit and not for any commercial purpose or for 18 * monetary gain. 19 * 20 * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN 24 * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * Please inquire about commercial licensing options at 34 * [email protected] 35 * 36 */ 37 38 #define BTSTACK_FILE__ "btstack_chipset_realtek.c" 39 40 /* 41 * btstack_chipset_realtek.c 42 * 43 * Adapter to use REALTEK-based chipsets with BTstack 44 */ 45 46 #include "btstack_chipset_realtek.h" 47 48 #include <stddef.h> /* NULL */ 49 #include <stdio.h> 50 #include <string.h> /* memcpy */ 51 52 #include "btstack_control.h" 53 #include "btstack_debug.h" 54 #include "btstack_event.h" 55 #include "btstack_linked_list.h" 56 #include "btstack_util.h" 57 #include "hci.h" 58 #include "hci_transport.h" 59 60 #ifdef _MSC_VER 61 // ignore deprecated warning for fopen 62 #pragma warning(disable : 4996) 63 #endif 64 65 #define ROM_LMP_NONE 0x0000 66 #define ROM_LMP_8723a 0x1200 67 #define ROM_LMP_8723b 0x8723 68 #define ROM_LMP_8821a 0x8821 69 #define ROM_LMP_8761a 0x8761 70 #define ROM_LMP_8822b 0x8822 71 #define ROM_LMP_8852a 0x8852 72 #define ROM_LMP_8851b 0x8851 73 74 #define HCI_OPCODE_HCI_RTK_DOWNLOAD_FW 0xFC20 75 #define HCI_OPCODE_HCI_RTK_READ_ROM_VERSION 0xFC6D 76 77 #define READ_SEC_PROJ 4 78 79 #define HCI_CMD_SET_OPCODE(buf, opcode) little_endian_store_16(buf, 0, opcode) 80 #define HCI_CMD_SET_LENGTH(buf, length) buf[2] = length 81 #define HCI_CMD_DOWNLOAD_SET_INDEX(buf, index) buf[3] = index 82 #define HCI_CMD_DOWNLOAD_COPY_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len) 83 84 #define PATCH_SNIPPETS 0x01 85 #define PATCH_DUMMY_HEADER 0x02 86 #define PATCH_SECURITY_HEADER 0x03 87 #define PATCH_OTA_FLAG 0x04 88 #define SECTION_HEADER_SIZE 8 89 90 /* software id */ 91 #define RTLPREVIOUS 0x00 92 #define RTL8822BU 0x70 93 #define RTL8723DU 0x71 94 #define RTL8821CU 0x72 95 #define RTL8822CU 0x73 96 #define RTL8761BU 0x74 97 #define RTL8852AU 0x75 98 #define RTL8723FU 0x76 99 #define RTL8852BU 0x77 100 #define RTL8852CU 0x78 101 #define RTL8822EU 0x79 102 #define RTL8851BU 0x7A 103 104 #pragma pack(push, 1) 105 struct rtk_epatch_entry { 106 uint16_t chipID; 107 uint16_t patch_length; 108 uint32_t start_offset; 109 }; 110 111 struct rtk_epatch { 112 uint8_t signature[8]; 113 uint32_t fw_version; 114 uint16_t number_of_total_patch; 115 struct rtk_epatch_entry entry[0]; 116 }; 117 118 struct rtk_extension_entry { 119 uint8_t opcode; 120 uint8_t length; 121 uint8_t *data; 122 }; 123 124 struct rtb_section_hdr { 125 uint32_t opcode; 126 uint32_t section_len; 127 uint32_t soffset; 128 }; 129 130 struct rtb_new_patch_hdr { 131 uint8_t signature[8]; 132 uint8_t fw_version[8]; 133 uint32_t number_of_section; 134 }; 135 #pragma pack(pop) 136 137 138 enum { 139 // Pre-Init: runs before HCI Reset 140 STATE_PHASE_1_READ_LMP_SUBVERSION, 141 STATE_PHASE_1_W4_READ_LMP_SUBVERSION, 142 STATE_PHASE_1_READ_HCI_REVISION, 143 STATE_PHASE_1_W4_READ_HCI_REVISION, 144 STATE_PHASE_1_DONE, 145 // Custom Init: runs after HCI Reset 146 STATE_PHASE_2_READ_ROM_VERSION, 147 STATE_PHASE_2_READ_SEC_PROJ, 148 STATE_PHASE_2_W4_SEC_PROJ, 149 STATE_PHASE_2_LOAD_FIRMWARE, 150 STATE_PHASE_2_RESET, 151 STATE_PHASE_2_DONE, 152 }; 153 enum { FW_DONE, FW_MORE_TO_DO }; 154 155 typedef struct { 156 uint16_t prod_id; 157 uint16_t lmp_sub; 158 char * mp_patch_name; 159 char * patch_name; 160 char * config_name; 161 162 uint8_t *fw_cache1; 163 int fw_len1; 164 uint8_t chip_type; 165 } patch_info; 166 167 static const patch_info fw_patch_table[] = { 168 /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, chip_type } */ 169 {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* RTL8723A */ 170 {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 171 {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for LI */ 172 {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE */ 173 {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AE for Azurewave */ 174 175 {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 176 {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 177 {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 178 {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0, RTLPREVIOUS}, /* 8723AU */ 179 180 {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 181 {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BU */ 182 {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for LC */ 183 {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 184 {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 185 {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for HP */ 186 {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 187 {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 188 {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 189 {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE */ 190 191 {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 192 {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 193 {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Azurewave */ 194 {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 195 {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 196 {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0, RTLPREVIOUS}, /* RTL8723BE for Foxconn */ 197 198 {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU only */ 199 {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 200 {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AW + 8192EU */ 201 {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE */ 202 {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AUV only */ 203 {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8192EE for LI */ 204 {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8812AE */ 205 {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0, RTLPREVIOUS}, /* RTL8761AU + 8814AE */ 206 207 {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 208 {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 209 {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AU */ 210 {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 211 {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 212 {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 213 {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0, RTLPREVIOUS}, /* RTL8821AE */ 214 215 {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0, RTL8822BU}, /* RTL8822BU */ 216 217 {0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 218 {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 219 {0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 220 {0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU */ 221 {0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0, RTL8723DU}, /* RTL8723DU for LiteOn */ 222 223 {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 224 {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CU */ 225 {0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 226 {0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 227 {0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 228 {0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 229 {0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 230 {0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 231 {0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 232 {0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 233 {0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 234 {0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 235 {0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 236 {0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 237 {0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for LiteOn */ 238 {0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 239 {0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 240 {0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 241 {0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 242 {0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 243 {0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 244 {0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 245 {0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 246 {0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for Azurewave */ 247 {0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE */ 248 {0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 249 {0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CE for GSD */ 250 {0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0, RTL8821CU}, /* RTL8821CUH */ 251 252 {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 253 {0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 254 {0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CU */ 255 {0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", NULL, 0, RTL8822CU}, /* RTL8821DU */ 256 257 {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 258 {0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 259 {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 260 {0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 261 {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 262 {0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 263 {0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 264 {0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 265 {0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 266 {0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 267 {0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 268 {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 269 {0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for Azurewave */ 270 {0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 271 {0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 272 {0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE for LiteOn */ 273 {0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 274 {0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 275 {0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 276 {0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 277 {0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 278 {0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE */ 279 {0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 280 {0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 281 {0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0, RTL8822CU}, /* RTL8822CE-VS */ 282 283 {0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0, RTL8761BU}, /* RTL8761BU only */ 284 {0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU */ 285 {0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0, RTL8761BU}, /* RTL8725AU BT only */ 286 287 {0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AU */ 288 {0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 289 {0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 290 {0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 291 {0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 292 {0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 293 {0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 294 {0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 295 {0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 296 {0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 297 {0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 298 {0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 299 {0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 300 {0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 301 {0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 302 {0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 303 {0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 304 {0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 305 {0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 306 {0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 307 {0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0, RTL8852AU}, /* RTL8852AE */ 308 309 {0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 310 {0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 311 {0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0, RTL8723FU}, /* RTL8723FU */ 312 313 {0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", NULL, 0, RTL8852BU}, /* RTL8851AU */ 314 {0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BU */ 315 {0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 316 {0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 317 {0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 318 {0x3570, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 319 {0x3572, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 320 {0x4b06, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 321 {0x885b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 322 {0x886b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 323 {0x887b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 324 {0xc559, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 325 {0xb052, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 326 {0xb152, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 327 {0xb252, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 328 {0x4853, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 329 {0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0, RTL8852BU}, /* RTL8852BE */ 330 331 {0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CU */ 332 {0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 333 {0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 334 {0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 335 {0x885c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 336 {0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 337 {0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 338 {0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0, RTL8852CU}, /* RTL8852CE */ 339 340 {0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 341 {0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0, RTL8822EU}, /* RTL8822EU */ 342 343 {0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", NULL, 0, RTL8851BU}, /* RTL8851BU */ 344 345 /* NOTE: must append patch entries above the null entry */ 346 {0, 0, NULL, NULL, NULL, NULL, 0, 0} 347 }; 348 349 static uint16_t project_id[] = { 350 ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 351 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 352 ROM_LMP_8821a, /* RTL8821CU */ 353 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 354 ROM_LMP_8761a, /* index 14 for 8761BU */ 355 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 18 for 8852AU */ 356 ROM_LMP_8723b, /* index 19 for 8723FU */ 357 ROM_LMP_8852a, /* index 20 for 8852BU */ 358 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8852a, /* index 25 for 8852CU */ 359 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, 360 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* index 33 for 8822EU */ 361 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8851b, /* index 36 for 8851BU */ 362 }; 363 364 static btstack_packet_callback_registration_t hci_event_callback_registration; 365 static uint8_t state; 366 static uint8_t rom_version; 367 static uint16_t lmp_subversion; 368 static uint16_t product_id; 369 static const patch_info * patch; 370 static uint8_t g_key_id = 0; 371 372 #ifdef HAVE_POSIX_FILE_IO 373 static const char *firmware_folder_path = "."; 374 static const char *firmware_file_path; 375 static const char *config_folder_path = "."; 376 static const char *config_file_path; 377 static char firmware_file[1000]; 378 static char config_file[1000]; 379 #endif 380 381 static const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 382 static const uint8_t FW_SIGNATURE_NEW[8] = {0x52, 0x54, 0x42, 0x54, 0x43, 0x6F, 0x72, 0x65}; 383 static const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 384 385 static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 386 UNUSED(channel); 387 UNUSED(size); 388 if (packet_type != HCI_EVENT_PACKET) { 389 return; 390 } 391 if (hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 392 return; 393 } 394 395 uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 396 const uint8_t * return_para = hci_event_command_complete_get_return_parameters(packet); 397 switch (opcode) { 398 case HCI_OPCODE_HCI_READ_LOCAL_VERSION_INFORMATION: 399 lmp_subversion = little_endian_read_16(packet, 12); 400 break; 401 case HCI_OPCODE_HCI_RTK_READ_ROM_VERSION: 402 rom_version = return_para[1]; 403 log_info("Received ROM version 0x%02x", rom_version); 404 printf("Realtek: Received ROM version 0x%02x\n", rom_version); 405 if (patch->lmp_sub != lmp_subversion) { 406 printf("Realtek: Firmware already exists\n"); 407 state = STATE_PHASE_2_DONE; 408 } 409 break; 410 case HCI_OPCODE_HCI_RTK_READ_CARD_INFO: 411 switch (state){ 412 case STATE_PHASE_1_W4_READ_LMP_SUBVERSION: 413 log_info("Read Card: LMP Subversion"); 414 if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x8822){ 415 state = STATE_PHASE_1_READ_HCI_REVISION; 416 } else { 417 state = STATE_PHASE_1_DONE; 418 } 419 break; 420 case STATE_PHASE_1_W4_READ_HCI_REVISION: 421 log_info("Read Card: HCI Revision"); 422 if (little_endian_read_16(hci_event_command_complete_get_return_parameters(packet), 1) == 0x000e){ 423 state = STATE_PHASE_2_READ_ROM_VERSION; 424 } else { 425 state = STATE_PHASE_1_DONE; 426 } 427 break; 428 case STATE_PHASE_2_W4_SEC_PROJ: 429 g_key_id = return_para[1]; 430 printf("Realtek: Received key id 0x%02x\n", g_key_id); 431 state = STATE_PHASE_2_LOAD_FIRMWARE; 432 break; 433 default: 434 btstack_assert(false); 435 break; 436 } 437 break; 438 default: 439 break; 440 } 441 } 442 443 static void chipset_init(const void *config) { 444 UNUSED(config); 445 446 // pre-set lmp subversion: HCI starts custom download only if HCI Version = 0x00e, and LMP Subversion = 0x8822 447 lmp_subversion = 0x8822; 448 449 #ifdef HAVE_POSIX_FILE_IO 450 // determine file path 451 if (firmware_file_path == NULL || config_file_path == NULL) { 452 log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 453 patch = NULL; 454 for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 455 if (fw_patch_table[i].prod_id == product_id) { 456 patch = &fw_patch_table[i]; 457 break; 458 } 459 } 460 if (patch == NULL) { 461 log_info("Product id 0x%04x is unknown", product_id); 462 state = STATE_PHASE_2_DONE; 463 return; 464 } 465 snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 466 snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 467 firmware_file_path = &firmware_file[0]; 468 config_file_path = &config_file[0]; 469 //lmp_subversion = patch->lmp_sub; 470 } 471 log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 472 printf("Realtek: Using firmware '%s' and config '%s'\n", firmware_file_path, config_file_path); 473 474 // activate hci callback 475 hci_event_callback_registration.callback = &hci_packet_handler; 476 hci_add_event_handler(&hci_event_callback_registration); 477 state = STATE_PHASE_1_READ_LMP_SUBVERSION; 478 #endif 479 } 480 481 #ifdef HAVE_POSIX_FILE_IO 482 483 /** 484 * @brief Opens the specified file and stores content to an allocated buffer 485 * 486 * @param file 487 * @param buf 488 * @param name 489 * @return uint32_t Length of file 490 */ 491 static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 492 uint32_t size; 493 494 // open file 495 *file = fopen(name, "rb"); 496 if (*file == NULL) { 497 log_info("Failed to open file %s", name); 498 return 0; 499 } 500 501 // determine length of file 502 fseek(*file, 0, SEEK_END); 503 size = ftell(*file); 504 fseek(*file, 0, SEEK_SET); 505 if (size <= 0) { 506 return 0; 507 } 508 509 // allocate memory 510 *buf = malloc(size); 511 if (*buf == NULL) { 512 fclose(*file); 513 *file = NULL; 514 log_info("Failed to allocate %u bytes for file %s", size, name); 515 return 0; 516 } 517 518 // read file 519 size_t ret = fread(*buf, size, 1, *file); 520 if (ret != 1) { 521 log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 522 fclose(*file); 523 free(*buf); 524 *file = NULL; 525 *buf = NULL; 526 return 0; 527 } 528 529 log_info("Opened file %s and read %u bytes", name, size); 530 return size; 531 } 532 533 static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 534 fclose(*file); 535 free(*buffer); 536 *buffer = NULL; 537 *file = NULL; 538 } 539 540 static uint8_t rtk_get_fw_project_id(uint8_t * p_buf) 541 { 542 uint8_t opcode; 543 uint8_t len; 544 uint8_t data = 0; 545 546 do { 547 opcode = *p_buf; 548 len = *(p_buf - 1); 549 if (opcode == 0x00) { 550 if (len == 1) { 551 data = *(p_buf - 2); 552 log_info 553 ("rtk_get_fw_project_id: opcode %d, len %d, data %d", 554 opcode, len, data); 555 break; 556 } else { 557 log_error 558 ("rtk_get_fw_project_id: invalid len %d", 559 len); 560 } 561 } 562 p_buf -= len + 2; 563 } while (*p_buf != 0xFF); 564 565 return data; 566 } 567 568 struct rtb_ota_flag { 569 uint8_t eco; 570 uint8_t enable; 571 uint16_t reserve; 572 }; 573 574 struct patch_node { 575 btstack_linked_item_t item; 576 uint8_t eco; 577 uint8_t pri; 578 uint8_t key_id; 579 uint8_t reserve; 580 uint32_t len; 581 uint8_t *payload; 582 }; 583 584 /* Add a node to alist that is in ascending order. */ 585 static void insert_queue_sort(btstack_linked_list_t * list, struct patch_node *node) 586 { 587 btstack_assert(list != NULL); 588 btstack_assert(node != NULL); 589 590 struct patch_node *next; 591 btstack_linked_item_t *it; 592 593 for (it = (btstack_linked_item_t *) list; it->next ; it = it->next){ 594 next = (struct patch_node *) it->next; 595 if(next->pri >= node->pri) { 596 break; 597 } 598 } 599 node->item.next = it->next; 600 it->next = (btstack_linked_item_t *) node; 601 } 602 603 static int insert_patch(btstack_linked_list_t * patch_list, uint8_t *section_pos, 604 uint32_t opcode, uint32_t *patch_len, uint8_t *sec_flag) 605 { 606 struct patch_node *tmp; 607 uint32_t i; 608 uint32_t numbers; 609 uint32_t section_len = 0; 610 uint8_t eco = 0; 611 uint8_t *pos = section_pos + 8; 612 613 numbers = little_endian_read_16(pos, 0); 614 log_info("number 0x%04x", numbers); 615 616 pos += 4; 617 for (i = 0; i < numbers; i++) { 618 eco = (uint8_t)*(pos); 619 log_info("eco 0x%02x, Eversion:%02x", eco, rom_version); 620 if (eco == rom_version + 1) { 621 //tmp = (struct patch_node*)kzalloc(sizeof(struct patch_node), GFP_KERNEL); 622 tmp = (struct patch_node*)malloc(sizeof(struct patch_node)); 623 tmp->pri = (uint8_t)*(pos + 1); 624 if(opcode == PATCH_SECURITY_HEADER) 625 tmp->key_id = (uint8_t)*(pos + 1); 626 627 section_len = little_endian_read_32(pos, 4); 628 tmp->len = section_len; 629 *patch_len += section_len; 630 log_info("Pri:%d, Patch length 0x%04x", tmp->pri, tmp->len); 631 tmp->payload = pos + 8; 632 if(opcode != PATCH_SECURITY_HEADER) { 633 insert_queue_sort(patch_list, tmp); 634 } else { 635 if((g_key_id == tmp->key_id) && (g_key_id > 0)) { 636 insert_queue_sort(patch_list, tmp); 637 *sec_flag = 1; 638 } else { 639 pos += (8 + section_len); 640 free(tmp); 641 continue; 642 } 643 } 644 } else { 645 section_len = little_endian_read_32(pos, 4); 646 log_info("Patch length 0x%04x", section_len); 647 } 648 pos += (8 + section_len); 649 } 650 return 0; 651 } 652 static uint8_t *rtb_get_patch_header(uint32_t *len, 653 btstack_linked_list_t * patch_list, uint8_t * epatch_buf, 654 uint8_t key_id) 655 { 656 uint16_t i, j; 657 struct rtb_new_patch_hdr *new_patch; 658 uint8_t sec_flag = 0; 659 uint32_t number_of_ota_flag; 660 uint32_t patch_len = 0; 661 uint8_t *section_pos; 662 uint8_t *ota_flag_pos; 663 uint32_t number_of_section; 664 665 struct rtb_section_hdr section_hdr; 666 struct rtb_ota_flag ota_flag; 667 668 new_patch = (struct rtb_new_patch_hdr *)epatch_buf; 669 number_of_section = new_patch->number_of_section; 670 671 log_info("FW version 0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x", 672 *(epatch_buf + 8), *(epatch_buf + 9), *(epatch_buf + 10), 673 *(epatch_buf + 11),*(epatch_buf + 12), *(epatch_buf + 13), 674 *(epatch_buf + 14), *(epatch_buf + 15)); 675 676 section_pos = epatch_buf + 20; 677 678 for (i = 0; i < number_of_section; i++) { 679 section_hdr.opcode = little_endian_read_32(section_pos, 0); 680 section_hdr.section_len = little_endian_read_32(section_pos, 4); 681 log_info("opcode 0x%04x", section_hdr.opcode); 682 switch (section_hdr.opcode) { 683 case PATCH_SNIPPETS: 684 insert_patch(patch_list, section_pos, PATCH_SNIPPETS, &patch_len, NULL); 685 printf("Realtek: patch len is %d\n",patch_len); 686 break; 687 case PATCH_SECURITY_HEADER: 688 if(!g_key_id) 689 break; 690 691 sec_flag = 0; 692 insert_patch(patch_list, section_pos, PATCH_SECURITY_HEADER, &patch_len, &sec_flag); 693 if(sec_flag) 694 break; 695 696 for (i = 0; i < number_of_section; i++) { 697 section_hdr.opcode = little_endian_read_32(section_pos, 0); 698 section_hdr.section_len = little_endian_read_32(section_pos, 4); 699 if(section_hdr.opcode == PATCH_DUMMY_HEADER) { 700 insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 701 } 702 section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 703 } 704 break; 705 case PATCH_DUMMY_HEADER: 706 if(g_key_id) { 707 break; 708 } 709 insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL); 710 break; 711 case PATCH_OTA_FLAG: 712 ota_flag_pos = section_pos + 4; 713 number_of_ota_flag = little_endian_read_32(ota_flag_pos, 0); 714 ota_flag.eco = (uint8_t)*(ota_flag_pos + 1); 715 if (ota_flag.eco == rom_version + 1) { 716 for (j = 0; j < number_of_ota_flag; j++) { 717 if (ota_flag.eco == rom_version + 1) { 718 ota_flag.enable = little_endian_read_32(ota_flag_pos, 4); 719 } 720 } 721 } 722 break; 723 default: 724 log_error("Unknown Opcode"); 725 break; 726 } 727 section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len); 728 } 729 *len = patch_len; 730 731 return NULL; 732 } 733 734 static inline int get_max_patch_size(uint8_t chip_type) 735 { 736 int max_patch_size = 0; 737 738 switch (chip_type) { 739 case RTLPREVIOUS: 740 max_patch_size = 24 * 1024; 741 break; 742 case RTL8822BU: 743 max_patch_size = 25 * 1024; 744 break; 745 case RTL8723DU: 746 case RTL8822CU: 747 case RTL8761BU: 748 case RTL8821CU: 749 max_patch_size = 40 * 1024; 750 break; 751 case RTL8852AU: 752 max_patch_size = 0x114D0 + 529; /* 69.2KB */ 753 break; 754 case RTL8723FU: 755 max_patch_size = 0xC4Cf + 529; /* 49.2KB */ 756 break; 757 case RTL8852BU: 758 case RTL8851BU: 759 max_patch_size = 0x104D0 + 529; /* 65KB */ 760 break; 761 case RTL8852CU: 762 max_patch_size = 0x130D0 + 529; /* 76.2KB */ 763 break; 764 case RTL8822EU: 765 max_patch_size = 0x24620 + 529; /* 145KB */ 766 break; 767 default: 768 max_patch_size = 40 * 1024; 769 break; 770 } 771 772 return max_patch_size; 773 } 774 775 static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 776 static uint8_t *patch_buf = NULL; 777 static uint32_t fw_total_len; 778 static uint32_t fw_ptr; 779 static uint8_t index; 780 781 // read firmware and config 782 if (patch_buf == NULL) { 783 uint16_t patch_length = 0; 784 uint32_t offset; 785 FILE * fw = NULL; 786 uint32_t fw_size; 787 uint8_t *fw_buf = NULL; 788 789 FILE * conf = NULL; 790 uint32_t conf_size; 791 uint8_t *conf_buf = NULL; 792 793 uint32_t fw_version; 794 uint16_t fw_num_patches; 795 796 struct patch_node *tmp; 797 int max_patch_size = 0; 798 799 if (firmware == NULL || config == NULL) { 800 log_info("Please specify realtek firmware and config file paths"); 801 return FW_DONE; 802 } 803 // read config 804 conf_size = read_file(&conf, &conf_buf, config); 805 if (conf_size == 0) { 806 log_info("Config size is 0, using efuse settings!"); 807 } 808 // read firmware 809 fw_size = read_file(&fw, &fw_buf, firmware); 810 if (fw_size == 0) { 811 log_info("Firmware size is 0. Quit!"); 812 if (conf_size != 0){ 813 finalize_file_and_buffer(&conf, &conf_buf); 814 } 815 return FW_DONE; 816 } 817 // check signature 818 if (((memcmp(fw_buf, FW_SIGNATURE, 8) != 0) && (memcmp(fw_buf, FW_SIGNATURE_NEW, 8) != 0)) 819 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 820 log_info("Wrong signature. Quit!"); 821 finalize_file_and_buffer(&fw, &fw_buf); 822 finalize_file_and_buffer(&conf, &conf_buf); 823 return FW_DONE; 824 } 825 // check project id 826 if (lmp_subversion != project_id[rtk_get_fw_project_id(fw_buf + fw_size - 5)]) { 827 log_info("Wrong project id. Quit!"); 828 finalize_file_and_buffer(&fw, &fw_buf); 829 finalize_file_and_buffer(&conf, &conf_buf); 830 return FW_DONE; 831 } 832 // init ordered list for new firmware signature 833 btstack_linked_list_t patch_list = NULL; 834 bool have_new_firmware_signature = memcmp(fw_buf, FW_SIGNATURE_NEW, 8) == 0; 835 if (have_new_firmware_signature){ 836 printf("Realtek: Using new signature\n"); 837 uint8_t key_id = g_key_id; 838 if (key_id < 0) { 839 log_info("Wrong key id. Quit!"); 840 finalize_file_and_buffer(&fw, &fw_buf); 841 finalize_file_and_buffer(&conf, &conf_buf); 842 return FW_DONE; 843 } 844 845 rtb_get_patch_header(&fw_total_len, &patch_list, fw_buf, key_id); 846 if (fw_total_len == 0) { 847 finalize_file_and_buffer(&fw, &fw_buf); 848 finalize_file_and_buffer(&conf, &conf_buf); 849 return FW_DONE; 850 } 851 fw_total_len += conf_size; 852 } else { 853 printf("Realtek: Using old signature\n"); 854 // read firmware version 855 fw_version = little_endian_read_32(fw_buf, 8); 856 log_info("Firmware version: 0x%x", fw_version); 857 858 // read number of patches 859 fw_num_patches = little_endian_read_16(fw_buf, 12); 860 log_info("Number of patches: %d", fw_num_patches); 861 862 // find correct entry 863 for (uint16_t i = 0; i < fw_num_patches; i++) { 864 if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 865 patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 866 offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 867 log_info("patch_length %u, offset %u", patch_length, offset); 868 break; 869 } 870 } 871 if (patch_length == 0) { 872 log_debug("Failed to find valid patch"); 873 finalize_file_and_buffer(&fw, &fw_buf); 874 finalize_file_and_buffer(&conf, &conf_buf); 875 return FW_DONE; 876 } 877 fw_total_len = patch_length + conf_size; 878 } 879 880 max_patch_size = get_max_patch_size(patch->chip_type); 881 printf("Realtek: FW/CONFIG total length is %d, max patch size id %d\n", fw_total_len, max_patch_size); 882 if (fw_total_len > max_patch_size) { 883 printf("FRealtek: W/CONFIG total length larger than allowed %d\n", max_patch_size); 884 finalize_file_and_buffer(&fw, &fw_buf); 885 finalize_file_and_buffer(&conf, &conf_buf); 886 return FW_DONE; 887 } 888 // allocate patch buffer 889 patch_buf = malloc(fw_total_len); 890 if (patch_buf == NULL) { 891 log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 892 finalize_file_and_buffer(&fw, &fw_buf); 893 finalize_file_and_buffer(&conf, &conf_buf); 894 return FW_DONE; 895 } 896 if (have_new_firmware_signature) { 897 int tmp_len = 0; 898 // append patches based on priority and free 899 while (patch_list) { 900 tmp = (struct patch_node *) patch_list; 901 log_info("len = 0x%x", tmp->len); 902 memcpy(patch_buf + tmp_len, tmp->payload, tmp->len); 903 tmp_len += tmp->len; 904 patch_list = patch_list->next; 905 free(tmp); 906 } 907 if (conf_size) { 908 memcpy(&patch_buf[fw_total_len - conf_size], conf_buf, conf_size); 909 } 910 } else { 911 // copy patch 912 memcpy(patch_buf, fw_buf + offset, patch_length); 913 memcpy(patch_buf + patch_length - 4, &fw_version, 4); 914 memcpy(patch_buf + patch_length, conf_buf, conf_size); 915 } 916 fw_ptr = 0; 917 index = 0; 918 919 // close files 920 finalize_file_and_buffer(&fw, &fw_buf); 921 finalize_file_and_buffer(&conf, &conf_buf); 922 } 923 924 uint8_t len; 925 if (fw_total_len - fw_ptr > 252) { 926 len = 252; 927 } else { 928 len = fw_total_len - fw_ptr; 929 index |= 0x80; // end 930 } 931 932 if (len) { 933 little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_HCI_RTK_DOWNLOAD_FW); 934 HCI_CMD_SET_LENGTH(hci_cmd_buffer, len + 1); 935 HCI_CMD_DOWNLOAD_SET_INDEX(hci_cmd_buffer, index); 936 HCI_CMD_DOWNLOAD_COPY_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 937 index++; 938 if (index > 0x7f) { 939 index = (index & 0x7f) +1; 940 } 941 fw_ptr += len; 942 return FW_MORE_TO_DO; 943 } 944 945 // cleanup and return 946 free(patch_buf); 947 patch_buf = NULL; 948 printf("Realtek: Init process finished\n"); 949 return FW_DONE; 950 } 951 952 #endif // HAVE_POSIX_FILE_IO 953 954 static const uint8_t hci_realtek_read_sec_proj[] = {0x61, 0xfc, 0x05, 0x10, 0xA4, 0x0D, 0x00, 0xb0 }; 955 static const uint8_t hci_realtek_read_lmp_subversion[] = {0x61, 0xfc, 0x05, 0x10, 0x38, 0x04, 0x28, 0x80 }; 956 static const uint8_t hci_realtek_read_hci_revision[] = {0x61, 0xfc, 0x05, 0x10, 0x3A, 0x04, 0x28, 0x80 }; 957 958 static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 959 #ifdef HAVE_POSIX_FILE_IO 960 uint8_t ret; 961 while (true) { 962 switch (state) { 963 case STATE_PHASE_1_READ_LMP_SUBVERSION: 964 memcpy(hci_cmd_buffer, hci_realtek_read_lmp_subversion, sizeof(hci_realtek_read_lmp_subversion)); 965 state = STATE_PHASE_1_W4_READ_LMP_SUBVERSION; 966 break; 967 case STATE_PHASE_1_READ_HCI_REVISION: 968 memcpy(hci_cmd_buffer, hci_realtek_read_hci_revision, sizeof(hci_realtek_read_hci_revision)); 969 state = STATE_PHASE_1_W4_READ_HCI_REVISION; 970 break; 971 case STATE_PHASE_1_DONE: 972 // custom pre-init done, continue with read ROM version in main custom init 973 state = STATE_PHASE_2_READ_ROM_VERSION; 974 return BTSTACK_CHIPSET_DONE; 975 case STATE_PHASE_2_READ_ROM_VERSION: 976 HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RTK_READ_ROM_VERSION); 977 HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 978 state = STATE_PHASE_2_READ_SEC_PROJ; 979 break; 980 case STATE_PHASE_2_READ_SEC_PROJ: 981 memcpy(hci_cmd_buffer, hci_realtek_read_sec_proj, sizeof(hci_realtek_read_sec_proj)); 982 state = STATE_PHASE_2_W4_SEC_PROJ; 983 break; 984 case STATE_PHASE_2_LOAD_FIRMWARE: 985 if (lmp_subversion != ROM_LMP_8723a) { 986 ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 987 } else { 988 log_info("Realtek firmware for old patch style not implemented"); 989 ret = FW_DONE; 990 } 991 if (ret != FW_DONE) { 992 break; 993 } 994 // we are done 995 state = STATE_PHASE_2_RESET; 996 997 /* fall through */ 998 999 case STATE_PHASE_2_RESET: 1000 HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RESET); 1001 HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0); 1002 state = STATE_PHASE_2_DONE; 1003 break; 1004 case STATE_PHASE_2_DONE: 1005 hci_remove_event_handler(&hci_event_callback_registration); 1006 return BTSTACK_CHIPSET_DONE; 1007 default: 1008 log_info("Invalid state %d", state); 1009 return BTSTACK_CHIPSET_DONE; 1010 } 1011 return BTSTACK_CHIPSET_VALID_COMMAND; 1012 } 1013 #else // HAVE_POSIX_FILE_IO 1014 log_info("Realtek without File IO is not implemented yet"); 1015 return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 1016 #endif // HAVE_POSIX_FILE_IO 1017 } 1018 1019 void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 1020 #ifdef HAVE_POSIX_FILE_IO 1021 firmware_file_path = path; 1022 #endif 1023 } 1024 1025 void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 1026 #ifdef HAVE_POSIX_FILE_IO 1027 firmware_folder_path = path; 1028 #endif 1029 } 1030 1031 void btstack_chipset_realtek_set_config_file_path(const char *path) { 1032 #ifdef HAVE_POSIX_FILE_IO 1033 config_file_path = path; 1034 #endif 1035 } 1036 1037 void btstack_chipset_realtek_set_config_folder_path(const char *path) { 1038 #ifdef HAVE_POSIX_FILE_IO 1039 config_folder_path = path; 1040 #endif 1041 } 1042 1043 void btstack_chipset_realtek_set_product_id(uint16_t id) { 1044 product_id = id; 1045 } 1046 1047 uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 1048 return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 1049 } 1050 1051 void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 1052 btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 1053 *out_vendor_id = 0xbda; 1054 *out_product_id = fw_patch_table[index].prod_id; 1055 } 1056 1057 static const btstack_chipset_t btstack_chipset_realtek = { 1058 "REALTEK", chipset_init, chipset_next_command, 1059 NULL, // chipset_set_baudrate_command, 1060 NULL, // chipset_set_bd_addr_command not supported or implemented 1061 }; 1062 1063 const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 1064