xref: /btstack/chipset/realtek/btstack_chipset_realtek.c (revision 25d5427a345779b159b63c0d8b197d2dee40cf37)
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         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  */
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