xref: /btstack/chipset/realtek/btstack_chipset_realtek.c (revision c824d78c0a34df89b57d535abafcc7dacf30bb06)
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_util.h"
56 #include "hci.h"
57 #include "hci_transport.h"
58 
59 #ifdef _MSC_VER
60 // ignore deprecated warning for fopen
61 #pragma warning(disable : 4996)
62 #endif
63 
64 #define ROM_LMP_NONE 0x0000
65 #define ROM_LMP_8723a 0x1200
66 #define ROM_LMP_8723b 0x8723
67 #define ROM_LMP_8821a 0X8821
68 #define ROM_LMP_8761a 0X8761
69 #define ROM_LMP_8822b 0X8822
70 
71 #define HCI_DOWNLOAD_FW 0xFC20
72 #define HCI_READ_ROM_VERSION 0xFC6D
73 #define HCI_READ_LMP_VERSION 0x1001
74 #define HCI_RESET 0x0C03
75 
76 #define FILL_COMMAND(buf, command) ((int16_t *)buf)[0] = command
77 #define FILL_LENGTH(buf, length) buf[2] = length
78 #define FILL_INDEX(buf, index) buf[3] = index
79 #define FILL_FW_DATA(buf, firmware, ptr, len) memcpy(buf + 4, firmware + ptr, len)
80 
81 enum {
82     STATE_READ_ROM_VERSION,
83     STATE_LOAD_FIRMWARE,
84     STATE_RESET,
85     STATE_DONE,
86 };
87 
88 enum { FW_DONE, FW_MORE_TO_DO };
89 
90 typedef struct {
91     uint16_t prod_id;
92     uint16_t lmp_sub;
93     char *   mp_patch_name;
94     char *   patch_name;
95     char *   config_name;
96 
97     uint8_t *fw_cache1;
98     int      fw_len1;
99 } patch_info;
100 
101 static patch_info fw_patch_table[] = {
102     /* { pid, lmp_sub, mp_fw_name, fw_name, config_name, fw_cache, fw_len } */
103     {0x1724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* RTL8723A */
104     {0x8723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */
105     {0xA723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for LI */
106     {0x0723, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE */
107     {0x3394, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AE for Azurewave */
108 
109     {0x0724, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */
110     {0x8725, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */
111     {0x872A, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */
112     {0x872B, 0x1200, "mp_rtl8723a_fw", "rtl8723a_fw", "rtl8723a_config", NULL, 0}, /* 8723AU */
113 
114     {0xb720, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */
115     {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723bu_config", NULL, 0}, /* RTL8723BU */
116     {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE for LC */
117     {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
118     {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
119     {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE for HP */
120     {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
121     {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
122     {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
123     {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0},  /* RTL8723BE */
124 
125     {0x3410, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */
126     {0x3416, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */
127     {0x3459, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Azurewave */
128     {0xE085, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */
129     {0xE08B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */
130     {0xE09E, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for Foxconn */
131 
132     {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU only */
133     {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */
134     {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */
135     {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU + 8192EE */
136     {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU + 8192EE */
137     {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU + 8192EE for LI */
138     {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU + 8812AE */
139     {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0},  /* RTL8761AU + 8814AE */
140 
141     {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
142     {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
143     {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */
144     {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
145     {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
146     {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
147     {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */
148 
149     {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */
150     {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */
151     {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */
152     {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */
153 
154     {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */
155     {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */
156     {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */
157     {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */
158     {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */
159 
160     {0x8771, 0x8761, "mp_rtl8761bu_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */
161 
162     /* NOTE: must append patch entries above the null entry */
163     {0, 0, NULL, NULL, NULL, NULL, 0}};
164 
165 uint16_t project_id[] = {
166     ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE,
167     ROM_LMP_NONE,  ROM_LMP_NONE,  ROM_LMP_NONE,  ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */
168     ROM_LMP_8821a,                                                             /* RTL8821CU */
169     ROM_LMP_NONE,  ROM_LMP_NONE,  ROM_LMP_8822b,                               /* RTL8822CU */
170     ROM_LMP_8761a,                                                             /* index 14 for 8761BU */
171 };
172 
173 static btstack_packet_callback_registration_t hci_event_callback_registration;
174 static uint8_t                                state = STATE_READ_ROM_VERSION;
175 static uint8_t                                rom_version;
176 static uint16_t                               lmp_subversion;
177 static uint16_t                               product_id;
178 static patch_info *                           patch;
179 
180 #ifdef HAVE_POSIX_FILE_IO
181 static const char *firmware_folder_path = ".";
182 static const char *firmware_file_path;
183 static const char *config_folder_path = ".";
184 static const char *config_file_path;
185 static char        firmware_file[1000];
186 static char        config_file[1000];
187 #endif
188 
189 const uint8_t FW_SIGNATURE[8]        = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68};
190 const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77};
191 
192 static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) {
193     UNUSED(channel);
194     UNUSED(size);
195     if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) {
196         return;
197     }
198     uint16_t opcode = hci_event_command_complete_get_command_opcode(packet);
199 
200     switch (opcode) {
201     case HCI_READ_ROM_VERSION:
202         rom_version = hci_event_command_complete_get_return_parameters(packet)[1];
203         log_info("Received ROM version 0x%02x", rom_version);
204         break;
205     default:
206         break;
207     }
208 }
209 
210 static void chipset_init(const void *config) {
211     UNUSED(config);
212 #ifdef HAVE_POSIX_FILE_IO
213     // determine file path
214     if (firmware_file_path == NULL || config_file_path == NULL) {
215         log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id);
216         patch = NULL;
217         for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) {
218             if (fw_patch_table[i].prod_id == product_id) {
219                 patch = &fw_patch_table[i];
220                 break;
221             }
222         }
223         if (patch == NULL) {
224             log_info("Product id 0x%04x is unknown", product_id);
225             state = STATE_DONE;
226             return;
227         }
228         snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name);
229         snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name);
230         firmware_file_path = &firmware_file[0];
231         config_file_path   = &config_file[0];
232         lmp_subversion     = patch->lmp_sub;
233     }
234     log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path);
235 
236     // activate hci callback
237     hci_event_callback_registration.callback = &hci_packet_handler;
238     hci_add_event_handler(&hci_event_callback_registration);
239     state = STATE_READ_ROM_VERSION;
240 #endif
241 }
242 
243 #ifdef HAVE_POSIX_FILE_IO
244 
245 /**
246  * @brief Opens the specified file and stores content to an allocated buffer
247  *
248  * @param file
249  * @param buf
250  * @param name
251  * @return uint32_t Length of file
252  */
253 static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) {
254     uint32_t size;
255 
256     // open file
257     *file = fopen(name, "rb");
258     if (*file == NULL) {
259         log_info("Failed to open file %s", name);
260         return 0;
261     }
262 
263     // determine length of file
264     fseek(*file, 0, SEEK_END);
265     size = ftell(*file);
266     fseek(*file, 0, SEEK_SET);
267     if (size <= 0) {
268         return 0;
269     }
270 
271     // allocate memory
272     *buf = malloc(size);
273     if (*buf == NULL) {
274         fclose(*file);
275         *file = NULL;
276         log_info("Failed to allocate %u bytes for file %s", size, name);
277         return 0;
278     }
279 
280     // read file
281     size_t ret = fread(*buf, size, 1, *file);
282     if (ret != 1) {
283         log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret);
284         fclose(*file);
285         free(*buf);
286         *file = NULL;
287         *buf  = NULL;
288         return 0;
289     }
290 
291     log_info("Opened file %s and read %u bytes", name, size);
292     return size;
293 }
294 
295 static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) {
296     fclose(*file);
297     free(*buffer);
298     *buffer = NULL;
299     *file   = NULL;
300 }
301 
302 static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) {
303     static uint8_t *patch_buf = NULL;
304     static uint32_t fw_total_len;
305     static uint32_t fw_ptr;
306     static uint8_t  index;
307 
308     // read firmware and config
309     if (patch_buf == NULL) {
310         uint16_t patch_length = 0;
311         uint32_t offset;
312         FILE *   fw = NULL;
313         uint32_t fw_size;
314         uint8_t *fw_buf = NULL;
315 
316         FILE *   conf = NULL;
317         uint32_t conf_size;
318         uint8_t *conf_buf = NULL;
319 
320         if (firmware == NULL || config == NULL) {
321             log_info("Please specify realtek firmware and config file paths");
322             return FW_DONE;
323         }
324 
325         // read firmware
326         fw_size = read_file(&fw, &fw_buf, firmware);
327         if (fw_size == 0) {
328             log_info("Firmware size is 0. Quit!");
329             return FW_DONE;
330         }
331 
332         // read config
333         conf_size = read_file(&conf, &conf_buf, config);
334         if (conf_size == 0) {
335             log_info("Config size is 0. Quit!");
336             fclose(fw);
337             free(fw_buf);
338             fw_buf = NULL;
339             fw     = NULL;
340             return FW_DONE;
341             finalize_file_and_buffer(&fw, &fw_buf);
342         }
343 
344         // check signature
345         if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) {
346             log_info("Wrong signature. Quit!");
347             finalize_file_and_buffer(&fw, &fw_buf);
348             finalize_file_and_buffer(&conf, &conf_buf);
349             return FW_DONE;
350         }
351 
352         // check project id
353         if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) {
354             log_info("Wrong project id. Quit!");
355             finalize_file_and_buffer(&fw, &fw_buf);
356             finalize_file_and_buffer(&conf, &conf_buf);
357             return FW_DONE;
358         }
359 
360         // read firmware version
361         uint32_t fw_version = little_endian_read_32(fw_buf, 8);
362         log_info("Firmware version: 0x%x", fw_version);
363 
364         // read number of patches
365         uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12);
366         log_info("Number of patches: %d", fw_num_patches);
367 
368         // find correct entry
369         for (uint16_t i = 0; i < fw_num_patches; i++) {
370             if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) {
371                 patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i);
372                 offset       = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i);
373                 log_info("patch_length %u, offset %u", patch_length, offset);
374                 break;
375             }
376         }
377         if (patch_length == 0) {
378             log_debug("Failed to find valid patch");
379             finalize_file_and_buffer(&fw, &fw_buf);
380             finalize_file_and_buffer(&conf, &conf_buf);
381             return FW_DONE;
382         }
383 
384         // allocate patch buffer
385         fw_total_len = patch_length + conf_size;
386         patch_buf    = malloc(fw_total_len);
387         if (patch_buf == NULL) {
388             log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len);
389             finalize_file_and_buffer(&fw, &fw_buf);
390             finalize_file_and_buffer(&conf, &conf_buf);
391             return FW_DONE;
392         }
393 
394         // copy patch
395         memcpy(patch_buf, fw_buf + offset, patch_length);
396         memcpy(patch_buf + patch_length - 4, &fw_version, 4);
397         memcpy(patch_buf + patch_length, conf_buf, conf_size);
398         fw_ptr = 0;
399         index  = 0;
400 
401         // close files
402         finalize_file_and_buffer(&fw, &fw_buf);
403         finalize_file_and_buffer(&conf, &conf_buf);
404     }
405 
406     uint8_t len;
407     if (fw_total_len - fw_ptr > 252) {
408         len = 252;
409     } else {
410         len = fw_total_len - fw_ptr;
411         index |= 0x80;  // end
412     }
413 
414     if (len) {
415         FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW);
416         FILL_LENGTH(hci_cmd_buffer, len + 1);
417         FILL_INDEX(hci_cmd_buffer, index);
418         FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len);
419         index++;
420         fw_ptr += len;
421         return FW_MORE_TO_DO;
422     }
423 
424     // cleanup and return
425     free(patch_buf);
426     patch_buf = NULL;
427     return FW_DONE;
428 }
429 
430 #endif  // HAVE_POSIX_FILE_IO
431 
432 static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) {
433 #ifdef HAVE_POSIX_FILE_IO
434     uint8_t ret;
435     while (true) {
436         switch (state) {
437         case STATE_READ_ROM_VERSION:
438             FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION);
439             FILL_LENGTH(hci_cmd_buffer, 0);
440             state = STATE_LOAD_FIRMWARE;
441             break;
442         case STATE_LOAD_FIRMWARE:
443             if (lmp_subversion != ROM_LMP_8723a) {
444                 ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer);
445             } else {
446                 log_info("Realtek firmware for old patch style not implemented");
447                 ret = FW_DONE;
448             }
449             if (ret != FW_DONE) {
450                 break;
451             }
452             // we are done fall through
453             state = STATE_RESET;
454         case STATE_RESET:
455             FILL_COMMAND(hci_cmd_buffer, HCI_RESET);
456             FILL_LENGTH(hci_cmd_buffer, 0);
457             state = STATE_DONE;
458             break;
459         case STATE_DONE:
460             hci_remove_event_handler(&hci_event_callback_registration);
461             return BTSTACK_CHIPSET_DONE;
462             break;
463         default:
464             log_info("Invalid state %d", state);
465             return BTSTACK_CHIPSET_DONE;
466             break;
467         }
468         return BTSTACK_CHIPSET_VALID_COMMAND;
469     }
470 #else   // HAVE_POSIX_FILE_IO
471     log_info("Realtek without File IO is not implemented yet");
472     return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
473 #endif  // HAVE_POSIX_FILE_IO
474 }
475 
476 void btstack_chipset_realtek_set_firmware_file_path(const char *path) {
477 #ifdef HAVE_POSIX_FILE_IO
478     firmware_file_path = path;
479 #endif
480 }
481 
482 void btstack_chipset_realtek_set_firmware_folder_path(const char *path) {
483 #ifdef HAVE_POSIX_FILE_IO
484     firmware_folder_path = path;
485 #endif
486 }
487 
488 void btstack_chipset_realtek_set_config_file_path(const char *path) {
489 #ifdef HAVE_POSIX_FILE_IO
490     config_file_path = path;
491 #endif
492 }
493 
494 void btstack_chipset_realtek_set_config_folder_path(const char *path) {
495 #ifdef HAVE_POSIX_FILE_IO
496     config_folder_path = path;
497 #endif
498 }
499 
500 void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) {
501     lmp_subversion = version;
502 }
503 
504 void btstack_chipset_realtek_set_product_id(uint16_t id) {
505     product_id = id;
506 }
507 
508 uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){
509     return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel
510 }
511 
512 void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){
513     btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1));
514     *out_vendor_id = 0xbda;
515     *out_product_id = fw_patch_table[index].prod_id;
516 }
517 
518 static const btstack_chipset_t btstack_chipset_realtek = {
519     "REALTEK", chipset_init, chipset_next_command,
520     NULL,  // chipset_set_baudrate_command,
521     NULL,  // chipset_set_bd_addr_command not supported or implemented
522 };
523 
524 // MARK: public API
525 const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; }
526