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
hci_packet_handler(uint8_t packet_type,uint16_t channel,uint8_t * packet,uint16_t size)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
chipset_init(const void * config)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 btstack_snprintf_assert_complete(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name);
466 btstack_snprintf_assert_complete(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 */
read_file(FILE ** file,uint8_t ** buf,const char * name)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
finalize_file_and_buffer(FILE ** file,uint8_t ** buffer)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
rtk_get_fw_project_id(uint8_t * p_buf)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. */
insert_queue_sort(btstack_linked_list_t * list,struct patch_node * node)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
insert_patch(btstack_linked_list_t * patch_list,uint8_t * section_pos,uint32_t opcode,uint32_t * patch_len,uint8_t * sec_flag)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 }
rtb_get_patch_header(uint32_t * len,btstack_linked_list_t * patch_list,uint8_t * epatch_buf,uint8_t key_id)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 UNUSED(key_id);
657 uint16_t i, j;
658 struct rtb_new_patch_hdr *new_patch;
659 uint8_t sec_flag = 0;
660 uint32_t number_of_ota_flag;
661 uint32_t patch_len = 0;
662 uint8_t *section_pos;
663 uint8_t *ota_flag_pos;
664 uint32_t number_of_section;
665
666 struct rtb_section_hdr section_hdr;
667 struct rtb_ota_flag ota_flag;
668
669 new_patch = (struct rtb_new_patch_hdr *)epatch_buf;
670 number_of_section = new_patch->number_of_section;
671
672 log_info("FW version 0x%02x,%02x,%02x,%02x,%02x,%02x,%02x,%02x",
673 *(epatch_buf + 8), *(epatch_buf + 9), *(epatch_buf + 10),
674 *(epatch_buf + 11),*(epatch_buf + 12), *(epatch_buf + 13),
675 *(epatch_buf + 14), *(epatch_buf + 15));
676
677 section_pos = epatch_buf + 20;
678
679 for (i = 0; i < number_of_section; i++) {
680 section_hdr.opcode = little_endian_read_32(section_pos, 0);
681 section_hdr.section_len = little_endian_read_32(section_pos, 4);
682 log_info("opcode 0x%04x", section_hdr.opcode);
683 switch (section_hdr.opcode) {
684 case PATCH_SNIPPETS:
685 insert_patch(patch_list, section_pos, PATCH_SNIPPETS, &patch_len, NULL);
686 printf("Realtek: patch len is %d\n",patch_len);
687 break;
688 case PATCH_SECURITY_HEADER:
689 if(!g_key_id)
690 break;
691
692 sec_flag = 0;
693 insert_patch(patch_list, section_pos, PATCH_SECURITY_HEADER, &patch_len, &sec_flag);
694 if(sec_flag)
695 break;
696
697 for (i = 0; i < number_of_section; i++) {
698 section_hdr.opcode = little_endian_read_32(section_pos, 0);
699 section_hdr.section_len = little_endian_read_32(section_pos, 4);
700 if(section_hdr.opcode == PATCH_DUMMY_HEADER) {
701 insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL);
702 }
703 section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
704 }
705 break;
706 case PATCH_DUMMY_HEADER:
707 if(g_key_id) {
708 break;
709 }
710 insert_patch(patch_list, section_pos, PATCH_DUMMY_HEADER, &patch_len, NULL);
711 break;
712 case PATCH_OTA_FLAG:
713 ota_flag_pos = section_pos + 4;
714 number_of_ota_flag = little_endian_read_32(ota_flag_pos, 0);
715 ota_flag.eco = (uint8_t)*(ota_flag_pos + 1);
716 if (ota_flag.eco == rom_version + 1) {
717 for (j = 0; j < number_of_ota_flag; j++) {
718 if (ota_flag.eco == rom_version + 1) {
719 ota_flag.enable = little_endian_read_32(ota_flag_pos, 4);
720 }
721 }
722 }
723 break;
724 default:
725 log_error("Unknown Opcode");
726 break;
727 }
728 section_pos += (SECTION_HEADER_SIZE + section_hdr.section_len);
729 }
730 *len = patch_len;
731
732 return NULL;
733 }
734
get_max_patch_size(uint8_t chip_type)735 static inline int get_max_patch_size(uint8_t chip_type)
736 {
737 int max_patch_size = 0;
738
739 switch (chip_type) {
740 case RTLPREVIOUS:
741 max_patch_size = 24 * 1024;
742 break;
743 case RTL8822BU:
744 max_patch_size = 25 * 1024;
745 break;
746 case RTL8723DU:
747 case RTL8822CU:
748 case RTL8761BU:
749 case RTL8821CU:
750 max_patch_size = 40 * 1024;
751 break;
752 case RTL8852AU:
753 max_patch_size = 0x114D0 + 529; /* 69.2KB */
754 break;
755 case RTL8723FU:
756 max_patch_size = 0xC4Cf + 529; /* 49.2KB */
757 break;
758 case RTL8852BU:
759 case RTL8851BU:
760 max_patch_size = 0x104D0 + 529; /* 65KB */
761 break;
762 case RTL8852CU:
763 max_patch_size = 0x130D0 + 529; /* 76.2KB */
764 break;
765 case RTL8822EU:
766 max_patch_size = 0x24620 + 529; /* 145KB */
767 break;
768 default:
769 max_patch_size = 40 * 1024;
770 break;
771 }
772
773 return max_patch_size;
774 }
775
update_firmware(const char * firmware,const char * config,uint8_t * hci_cmd_buffer)776 static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) {
777 static uint8_t *patch_buf = NULL;
778 static uint32_t fw_total_len;
779 static uint32_t fw_ptr;
780 static uint8_t index;
781
782 // read firmware and config
783 if (patch_buf == NULL) {
784 uint16_t patch_length = 0;
785 uint32_t offset = 0;
786 FILE * fw = NULL;
787 uint32_t fw_size;
788 uint8_t *fw_buf = NULL;
789
790 FILE * conf = NULL;
791 uint32_t conf_size;
792 uint8_t *conf_buf = NULL;
793
794 uint32_t fw_version;
795 uint16_t fw_num_patches;
796
797 struct patch_node *tmp;
798 unsigned max_patch_size = 0;
799
800 if (firmware == NULL || config == NULL) {
801 log_info("Please specify realtek firmware and config file paths");
802 return FW_DONE;
803 }
804 // read config
805 conf_size = read_file(&conf, &conf_buf, config);
806 if (conf_size == 0) {
807 log_info("Config size is 0, using efuse settings!");
808 }
809 // read firmware
810 fw_size = read_file(&fw, &fw_buf, firmware);
811 if (fw_size == 0) {
812 log_info("Firmware size is 0. Quit!");
813 if (conf_size != 0){
814 finalize_file_and_buffer(&conf, &conf_buf);
815 }
816 return FW_DONE;
817 }
818 // check signature
819 if (((memcmp(fw_buf, FW_SIGNATURE, 8) != 0) && (memcmp(fw_buf, FW_SIGNATURE_NEW, 8) != 0))
820 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) {
821 log_info("Wrong signature. Quit!");
822 finalize_file_and_buffer(&fw, &fw_buf);
823 finalize_file_and_buffer(&conf, &conf_buf);
824 return FW_DONE;
825 }
826 // check project id
827 if (lmp_subversion != project_id[rtk_get_fw_project_id(fw_buf + fw_size - 5)]) {
828 log_info("Wrong project id. Quit!");
829 finalize_file_and_buffer(&fw, &fw_buf);
830 finalize_file_and_buffer(&conf, &conf_buf);
831 return FW_DONE;
832 }
833 // init ordered list for new firmware signature
834 btstack_linked_list_t patch_list = NULL;
835 bool have_new_firmware_signature = memcmp(fw_buf, FW_SIGNATURE_NEW, 8) == 0;
836 if (have_new_firmware_signature){
837 printf("Realtek: Using new signature\n");
838 uint8_t key_id = g_key_id;
839 if (key_id == 0) {
840 log_info("Wrong key id. Quit!");
841 finalize_file_and_buffer(&fw, &fw_buf);
842 finalize_file_and_buffer(&conf, &conf_buf);
843 return FW_DONE;
844 }
845
846 rtb_get_patch_header(&fw_total_len, &patch_list, fw_buf, key_id);
847 if (fw_total_len == 0) {
848 finalize_file_and_buffer(&fw, &fw_buf);
849 finalize_file_and_buffer(&conf, &conf_buf);
850 return FW_DONE;
851 }
852 fw_total_len += conf_size;
853 } else {
854 printf("Realtek: Using old signature\n");
855 // read firmware version
856 fw_version = little_endian_read_32(fw_buf, 8);
857 log_info("Firmware version: 0x%x", fw_version);
858
859 // read number of patches
860 fw_num_patches = little_endian_read_16(fw_buf, 12);
861 log_info("Number of patches: %d", fw_num_patches);
862
863 // find correct entry
864 for (uint16_t i = 0; i < fw_num_patches; i++) {
865 if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) {
866 patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i);
867 offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i);
868 log_info("patch_length %u, offset %u", patch_length, offset);
869 break;
870 }
871 }
872 if (patch_length == 0) {
873 log_debug("Failed to find valid patch");
874 finalize_file_and_buffer(&fw, &fw_buf);
875 finalize_file_and_buffer(&conf, &conf_buf);
876 return FW_DONE;
877 }
878 fw_total_len = patch_length + conf_size;
879 }
880
881 max_patch_size = get_max_patch_size(patch->chip_type);
882 printf("Realtek: FW/CONFIG total length is %d, max patch size id %d\n", fw_total_len, max_patch_size);
883 if (fw_total_len > max_patch_size) {
884 printf("FRealtek: W/CONFIG total length larger than allowed %d\n", max_patch_size);
885 finalize_file_and_buffer(&fw, &fw_buf);
886 finalize_file_and_buffer(&conf, &conf_buf);
887 return FW_DONE;
888 }
889 // allocate patch buffer
890 patch_buf = malloc(fw_total_len);
891 if (patch_buf == NULL) {
892 log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len);
893 finalize_file_and_buffer(&fw, &fw_buf);
894 finalize_file_and_buffer(&conf, &conf_buf);
895 return FW_DONE;
896 }
897 if (have_new_firmware_signature) {
898 int tmp_len = 0;
899 // append patches based on priority and free
900 while (patch_list) {
901 tmp = (struct patch_node *) patch_list;
902 log_info("len = 0x%x", tmp->len);
903 memcpy(patch_buf + tmp_len, tmp->payload, tmp->len);
904 tmp_len += tmp->len;
905 patch_list = patch_list->next;
906 free(tmp);
907 }
908 if (conf_size) {
909 memcpy(&patch_buf[fw_total_len - conf_size], conf_buf, conf_size);
910 }
911 } else {
912 // copy patch
913 memcpy(patch_buf, fw_buf + offset, patch_length);
914 memcpy(patch_buf + patch_length - 4, &fw_version, 4);
915 memcpy(patch_buf + patch_length, conf_buf, conf_size);
916 }
917 fw_ptr = 0;
918 index = 0;
919
920 // close files
921 finalize_file_and_buffer(&fw, &fw_buf);
922 finalize_file_and_buffer(&conf, &conf_buf);
923 }
924
925 uint8_t len;
926 if (fw_total_len - fw_ptr > 252) {
927 len = 252;
928 } else {
929 len = fw_total_len - fw_ptr;
930 index |= 0x80; // end
931 }
932
933 if (len) {
934 little_endian_store_16(hci_cmd_buffer, 0, HCI_OPCODE_HCI_RTK_DOWNLOAD_FW);
935 HCI_CMD_SET_LENGTH(hci_cmd_buffer, len + 1);
936 HCI_CMD_DOWNLOAD_SET_INDEX(hci_cmd_buffer, index);
937 HCI_CMD_DOWNLOAD_COPY_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len);
938 index++;
939 if (index > 0x7f) {
940 index = (index & 0x7f) +1;
941 }
942 fw_ptr += len;
943 return FW_MORE_TO_DO;
944 }
945
946 // cleanup and return
947 free(patch_buf);
948 patch_buf = NULL;
949 printf("Realtek: Init process finished\n");
950 return FW_DONE;
951 }
952
953 #endif // HAVE_POSIX_FILE_IO
954
955 static const uint8_t hci_realtek_read_sec_proj[] = {0x61, 0xfc, 0x05, 0x10, 0xA4, 0x0D, 0x00, 0xb0 };
956 static const uint8_t hci_realtek_read_lmp_subversion[] = {0x61, 0xfc, 0x05, 0x10, 0x38, 0x04, 0x28, 0x80 };
957 static const uint8_t hci_realtek_read_hci_revision[] = {0x61, 0xfc, 0x05, 0x10, 0x3A, 0x04, 0x28, 0x80 };
958
chipset_next_command(uint8_t * hci_cmd_buffer)959 static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) {
960 #ifdef HAVE_POSIX_FILE_IO
961 uint8_t ret;
962 while (true) {
963 switch (state) {
964 case STATE_PHASE_1_READ_LMP_SUBVERSION:
965 memcpy(hci_cmd_buffer, hci_realtek_read_lmp_subversion, sizeof(hci_realtek_read_lmp_subversion));
966 state = STATE_PHASE_1_W4_READ_LMP_SUBVERSION;
967 break;
968 case STATE_PHASE_1_READ_HCI_REVISION:
969 memcpy(hci_cmd_buffer, hci_realtek_read_hci_revision, sizeof(hci_realtek_read_hci_revision));
970 state = STATE_PHASE_1_W4_READ_HCI_REVISION;
971 break;
972 case STATE_PHASE_1_DONE:
973 // custom pre-init done, continue with read ROM version in main custom init
974 state = STATE_PHASE_2_READ_ROM_VERSION;
975 return BTSTACK_CHIPSET_DONE;
976 case STATE_PHASE_2_READ_ROM_VERSION:
977 HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RTK_READ_ROM_VERSION);
978 HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0);
979 state = STATE_PHASE_2_READ_SEC_PROJ;
980 break;
981 case STATE_PHASE_2_READ_SEC_PROJ:
982 memcpy(hci_cmd_buffer, hci_realtek_read_sec_proj, sizeof(hci_realtek_read_sec_proj));
983 state = STATE_PHASE_2_W4_SEC_PROJ;
984 break;
985 case STATE_PHASE_2_LOAD_FIRMWARE:
986 if (lmp_subversion != ROM_LMP_8723a) {
987 ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer);
988 } else {
989 log_info("Realtek firmware for old patch style not implemented");
990 ret = FW_DONE;
991 }
992 if (ret != FW_DONE) {
993 break;
994 }
995 // we are done
996 state = STATE_PHASE_2_RESET;
997
998 /* fall through */
999
1000 case STATE_PHASE_2_RESET:
1001 HCI_CMD_SET_OPCODE(hci_cmd_buffer, HCI_OPCODE_HCI_RESET);
1002 HCI_CMD_SET_LENGTH(hci_cmd_buffer, 0);
1003 state = STATE_PHASE_2_DONE;
1004 break;
1005 case STATE_PHASE_2_DONE:
1006 hci_remove_event_handler(&hci_event_callback_registration);
1007 return BTSTACK_CHIPSET_DONE;
1008 default:
1009 log_info("Invalid state %d", state);
1010 return BTSTACK_CHIPSET_DONE;
1011 }
1012 return BTSTACK_CHIPSET_VALID_COMMAND;
1013 }
1014 #else // HAVE_POSIX_FILE_IO
1015 log_info("Realtek without File IO is not implemented yet");
1016 return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
1017 #endif // HAVE_POSIX_FILE_IO
1018 }
1019
btstack_chipset_realtek_set_firmware_file_path(const char * path)1020 void btstack_chipset_realtek_set_firmware_file_path(const char *path) {
1021 #ifdef HAVE_POSIX_FILE_IO
1022 firmware_file_path = path;
1023 #endif
1024 }
1025
btstack_chipset_realtek_set_firmware_folder_path(const char * path)1026 void btstack_chipset_realtek_set_firmware_folder_path(const char *path) {
1027 #ifdef HAVE_POSIX_FILE_IO
1028 firmware_folder_path = path;
1029 #endif
1030 }
1031
btstack_chipset_realtek_set_config_file_path(const char * path)1032 void btstack_chipset_realtek_set_config_file_path(const char *path) {
1033 #ifdef HAVE_POSIX_FILE_IO
1034 config_file_path = path;
1035 #endif
1036 }
1037
btstack_chipset_realtek_set_config_folder_path(const char * path)1038 void btstack_chipset_realtek_set_config_folder_path(const char *path) {
1039 #ifdef HAVE_POSIX_FILE_IO
1040 config_folder_path = path;
1041 #endif
1042 }
1043
btstack_chipset_realtek_set_product_id(uint16_t id)1044 void btstack_chipset_realtek_set_product_id(uint16_t id) {
1045 product_id = id;
1046 }
1047
btstack_chipset_realtek_get_num_usb_controllers(void)1048 uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){
1049 return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel
1050 }
1051
btstack_chipset_realtek_get_vendor_product_id(uint16_t index,uint16_t * out_vendor_id,uint16_t * out_product_id)1052 void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){
1053 btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1));
1054 *out_vendor_id = 0xbda;
1055 *out_product_id = fw_patch_table[index].prod_id;
1056 }
1057
1058 static const btstack_chipset_t btstack_chipset_realtek = {
1059 "REALTEK", chipset_init, chipset_next_command,
1060 NULL, // chipset_set_baudrate_command,
1061 NULL, // chipset_set_bd_addr_command not supported or implemented
1062 };
1063
btstack_chipset_realtek_instance(void)1064 const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; }
1065