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