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", "rtl8723b_config", NULL, 0}, /* RTL8723BU */ 115 {0xb72A, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BU */ 116 117 {0xb728, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for LC */ 118 {0xb723, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 119 {0xb72B, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 120 {0xb001, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE for HP */ 121 {0xb002, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 122 {0xb003, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 123 {0xb004, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 124 {0xb005, 0x8723, "mp_rtl8723b_fw", "rtl8723b_fw", "rtl8723b_config", NULL, 0}, /* RTL8723BE */ 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 {0xd720, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 133 {0xd723, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 134 {0xd739, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 135 {0xb009, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU */ 136 {0x0231, 0x8723, "mp_rtl8723du_fw", "rtl8723du_fw", "rtl8723du_config", NULL, 0}, /* RTL8723DU for LiteOn */ 137 138 {0xb733, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 139 {0xb73a, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 140 {0xf72b, 0x8723, "mp_rtl8723fu_fw", "rtl8723fu_fw", "rtl8723fu_config", NULL, 0}, /* RTL8723FU */ 141 142 {0xA761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU only */ 143 {0x818B, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 144 {0x818C, 0x8761, "mp_rtl8761a_fw", "rtl8761aw_fw", "rtl8761aw_config", NULL, 0}, /* RTL8761AW + 8192EU */ 145 {0x8760, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE */ 146 {0xB761, 0x8761, "mp_rtl8761a_fw", "rtl8761au_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AUV only */ 147 {0x8761, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8192EE for LI */ 148 {0x8A60, 0x8761, "mp_rtl8761a_fw", "rtl8761au8812ae_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8812AE */ 149 {0x3527, 0x8761, "mp_rtl8761a_fw", "rtl8761au8192ee_fw", "rtl8761a_config", NULL, 0}, /* RTL8761AU + 8814AE */ 150 151 {0x8771, 0x8761, "mp_rtl8761b_fw", "rtl8761bu_fw", "rtl8761bu_config", NULL, 0}, /* RTL8761BU only */ 152 {0xa725, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0}, /* RTL8725AU */ 153 {0xa72A, 0x8761, "mp_rtl8761b_fw", "rtl8725au_fw", "rtl8725au_config", NULL, 0}, /* RTL8725AU BT only */ 154 155 {0x8821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 156 {0x0821, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 157 {0x0823, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AU */ 158 {0x3414, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 159 {0x3458, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 160 {0x3461, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 161 {0x3462, 0x8821, "mp_rtl8821a_fw", "rtl8821a_fw", "rtl8821a_config", NULL, 0}, /* RTL8821AE */ 162 163 {0xb820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 164 {0xc820, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CU */ 165 {0xc821, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 166 {0xc823, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 167 {0xc824, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 168 {0xc825, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 169 {0xc827, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 170 {0xc025, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 171 {0xc024, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 172 {0xc030, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 173 {0xb00a, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 174 {0xb00e, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 175 {0xc032, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 176 {0x4000, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for LiteOn */ 177 {0x4001, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for LiteOn */ 178 {0x3529, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 179 {0x3530, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 180 {0x3532, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 181 {0x3533, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 182 {0x3538, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 183 {0x3539, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 184 {0x3558, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 185 {0x3559, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 186 {0x3581, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for Azurewave */ 187 {0x3540, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE */ 188 {0x3541, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for GSD */ 189 {0x3543, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CE for GSD */ 190 {0xc80c, 0x8821, "mp_rtl8821cu_fw", "rtl8821cu_fw", "rtl8821cu_config", NULL, 0}, /* RTL8821CUH */ 191 192 {0xd820, 0x8822, "mp_rtl8821du_fw", "rtl8821du_fw", "rtl8821du_config", NULL, 0}, /* RTL8821DU */ 193 194 {0xb82c, 0x8822, "mp_rtl8822bu_fw", "rtl8822bu_fw", "rtl8822bu_config", NULL, 0}, /* RTL8822BU */ 195 196 {0xc82c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 197 {0xc82e, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 198 {0xc81d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CU */ 199 200 {0xc822, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 201 {0xc82b, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 202 {0xb00c, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 203 {0xb00d, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 204 {0xc123, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 205 {0xc126, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 206 {0xc127, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 207 {0xc128, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 208 {0xc129, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 209 {0xc131, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 210 {0xc136, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 211 {0x3549, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 212 {0x3548, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for Azurewave */ 213 {0xc125, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 214 {0x4005, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for LiteOn */ 215 {0x3051, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE for LiteOn */ 216 {0x18ef, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 217 {0x161f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 218 {0x3053, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 219 {0xc547, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 220 {0x3553, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 221 {0x3555, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE */ 222 {0xc82f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 223 {0xc02f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 224 {0xc03f, 0x8822, "mp_rtl8822cu_fw", "rtl8822cu_fw", "rtl8822cu_config", NULL, 0}, /* RTL8822CE-VS */ 225 226 {0x8851, 0x8852, "mp_rtl8851au_fw", "rtl8851au_fw", "rtl8851au_config", NULL, 0}, /* RTL8851AU */ 227 228 {0xb851, 0x8851, "mp_rtl8851bu_fw", "rtl8851bu_fw", "rtl8851bu_config", NULL, 0}, /* RTL8851BU */ 229 230 {0x885a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AU */ 231 {0x8852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 232 {0xa852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 233 {0x2852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 234 {0x385a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 235 {0x3852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 236 {0x1852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 237 {0x4852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 238 {0x4006, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 239 {0x3561, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 240 {0x3562, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 241 {0x588a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 242 {0x589a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 243 {0x590a, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 244 {0xc125, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 245 {0xe852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 246 {0xb852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 247 {0xc852, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 248 {0xc549, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 249 {0xc127, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 250 {0x3565, 0x8852, "mp_rtl8852au_fw", "rtl8852au_fw", "rtl8852au_config", NULL, 0}, /* RTL8852AE */ 251 252 {0xa85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BU */ 253 {0xb85b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 254 {0xb85c, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 255 {0x3571, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 256 {0x3570, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 257 {0x3572, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 258 {0x4b06, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 259 {0x885b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 260 {0x886b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 261 {0x887b, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 262 {0xc559, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 263 {0xb052, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 264 {0xb152, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 265 {0xb252, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 266 {0x4853, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 267 {0x1670, 0x8852, "mp_rtl8852bu_fw", "rtl8852bu_fw", "rtl8852bu_config", NULL, 0}, /* RTL8852BE */ 268 269 {0xc85a, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CU */ 270 {0x0852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 271 {0x5852, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 272 {0xc85c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 273 {0x885c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 274 {0x886c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 275 {0x887c, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 276 {0x4007, 0x8852, "mp_rtl8852cu_fw", "rtl8852cu_fw", "rtl8852cu_config", NULL, 0}, /* RTL8852CE */ 277 278 {0xe822, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0}, /* RTL8822EU */ 279 {0xa82a, 0x8822, "mp_rtl8822eu_fw", "rtl8822eu_fw", "rtl8822eu_config", NULL, 0}, /* RTL8822EU */ 280 281 /* NOTE: must append patch entries above the null entry */ 282 {0, 0, NULL, NULL, NULL, NULL, 0}}; 283 284 uint16_t project_id[] = { 285 ROM_LMP_8723a, ROM_LMP_8723b, ROM_LMP_8821a, ROM_LMP_8761a, ROM_LMP_NONE, 286 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, ROM_LMP_8723b, /* RTL8723DU */ 287 ROM_LMP_8821a, /* RTL8821CU */ 288 ROM_LMP_NONE, ROM_LMP_NONE, ROM_LMP_8822b, /* RTL8822CU */ 289 ROM_LMP_8761a, /* index 14 for 8761BU */ 290 }; 291 292 static btstack_packet_callback_registration_t hci_event_callback_registration; 293 static uint8_t state = STATE_READ_ROM_VERSION; 294 static uint8_t rom_version; 295 static uint16_t lmp_subversion; 296 static uint16_t product_id; 297 static patch_info * patch; 298 299 #ifdef HAVE_POSIX_FILE_IO 300 static const char *firmware_folder_path = "."; 301 static const char *firmware_file_path; 302 static const char *config_folder_path = "."; 303 static const char *config_file_path; 304 static char firmware_file[1000]; 305 static char config_file[1000]; 306 #endif 307 308 const uint8_t FW_SIGNATURE[8] = {0x52, 0x65, 0x61, 0x6C, 0x74, 0x65, 0x63, 0x68}; 309 const uint8_t EXTENSION_SIGNATURE[4] = {0x51, 0x04, 0xFD, 0x77}; 310 311 static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size) { 312 UNUSED(channel); 313 UNUSED(size); 314 if (packet_type != HCI_EVENT_PACKET || hci_event_packet_get_type(packet) != HCI_EVENT_COMMAND_COMPLETE) { 315 return; 316 } 317 uint16_t opcode = hci_event_command_complete_get_command_opcode(packet); 318 319 switch (opcode) { 320 case HCI_READ_ROM_VERSION: 321 rom_version = hci_event_command_complete_get_return_parameters(packet)[1]; 322 log_info("Received ROM version 0x%02x", rom_version); 323 break; 324 default: 325 break; 326 } 327 } 328 329 static void chipset_init(const void *config) { 330 UNUSED(config); 331 #ifdef HAVE_POSIX_FILE_IO 332 // determine file path 333 if (firmware_file_path == NULL || config_file_path == NULL) { 334 log_info("firmware or config file path is empty. Using product id 0x%04x!", product_id); 335 patch = NULL; 336 for (uint16_t i = 0; i < sizeof(fw_patch_table) / sizeof(patch_info); i++) { 337 if (fw_patch_table[i].prod_id == product_id) { 338 patch = &fw_patch_table[i]; 339 break; 340 } 341 } 342 if (patch == NULL) { 343 log_info("Product id 0x%04x is unknown", product_id); 344 state = STATE_DONE; 345 return; 346 } 347 snprintf(firmware_file, sizeof(firmware_file), "%s/%s", firmware_folder_path, patch->patch_name); 348 snprintf(config_file, sizeof(config_file), "%s/%s", config_folder_path, patch->config_name); 349 firmware_file_path = &firmware_file[0]; 350 config_file_path = &config_file[0]; 351 lmp_subversion = patch->lmp_sub; 352 } 353 log_info("Using firmware '%s' and config '%s'", firmware_file_path, config_file_path); 354 355 // activate hci callback 356 hci_event_callback_registration.callback = &hci_packet_handler; 357 hci_add_event_handler(&hci_event_callback_registration); 358 state = STATE_READ_ROM_VERSION; 359 #endif 360 } 361 362 #ifdef HAVE_POSIX_FILE_IO 363 364 /** 365 * @brief Opens the specified file and stores content to an allocated buffer 366 * 367 * @param file 368 * @param buf 369 * @param name 370 * @return uint32_t Length of file 371 */ 372 static uint32_t read_file(FILE **file, uint8_t **buf, const char *name) { 373 uint32_t size; 374 375 // open file 376 *file = fopen(name, "rb"); 377 if (*file == NULL) { 378 log_info("Failed to open file %s", name); 379 return 0; 380 } 381 382 // determine length of file 383 fseek(*file, 0, SEEK_END); 384 size = ftell(*file); 385 fseek(*file, 0, SEEK_SET); 386 if (size <= 0) { 387 return 0; 388 } 389 390 // allocate memory 391 *buf = malloc(size); 392 if (*buf == NULL) { 393 fclose(*file); 394 *file = NULL; 395 log_info("Failed to allocate %u bytes for file %s", size, name); 396 return 0; 397 } 398 399 // read file 400 size_t ret = fread(*buf, size, 1, *file); 401 if (ret != 1) { 402 log_info("Failed to read %u bytes from file %s (ret = %d)", size, name, (int) ret); 403 fclose(*file); 404 free(*buf); 405 *file = NULL; 406 *buf = NULL; 407 return 0; 408 } 409 410 log_info("Opened file %s and read %u bytes", name, size); 411 return size; 412 } 413 414 static void finalize_file_and_buffer(FILE **file, uint8_t **buffer) { 415 fclose(*file); 416 free(*buffer); 417 *buffer = NULL; 418 *file = NULL; 419 } 420 421 static uint8_t update_firmware(const char *firmware, const char *config, uint8_t *hci_cmd_buffer) { 422 static uint8_t *patch_buf = NULL; 423 static uint32_t fw_total_len; 424 static uint32_t fw_ptr; 425 static uint8_t index; 426 427 // read firmware and config 428 if (patch_buf == NULL) { 429 uint16_t patch_length = 0; 430 uint32_t offset; 431 FILE * fw = NULL; 432 uint32_t fw_size; 433 uint8_t *fw_buf = NULL; 434 435 FILE * conf = NULL; 436 uint32_t conf_size; 437 uint8_t *conf_buf = NULL; 438 439 if (firmware == NULL || config == NULL) { 440 log_info("Please specify realtek firmware and config file paths"); 441 return FW_DONE; 442 } 443 444 // read firmware 445 fw_size = read_file(&fw, &fw_buf, firmware); 446 if (fw_size == 0) { 447 log_info("Firmware size is 0. Quit!"); 448 return FW_DONE; 449 } 450 451 // read config 452 conf_size = read_file(&conf, &conf_buf, config); 453 if (conf_size == 0) { 454 log_info("Config size is 0. Quit!"); 455 fclose(fw); 456 free(fw_buf); 457 fw_buf = NULL; 458 fw = NULL; 459 return FW_DONE; 460 finalize_file_and_buffer(&fw, &fw_buf); 461 } 462 463 // check signature 464 if (memcmp(fw_buf, FW_SIGNATURE, 8) != 0 || memcmp(fw_buf + fw_size - 4, EXTENSION_SIGNATURE, 4) != 0) { 465 log_info("Wrong signature. Quit!"); 466 finalize_file_and_buffer(&fw, &fw_buf); 467 finalize_file_and_buffer(&conf, &conf_buf); 468 return FW_DONE; 469 } 470 471 // check project id 472 if (lmp_subversion != project_id[*(fw_buf + fw_size - 7)]) { 473 log_info("Wrong project id. Quit!"); 474 finalize_file_and_buffer(&fw, &fw_buf); 475 finalize_file_and_buffer(&conf, &conf_buf); 476 return FW_DONE; 477 } 478 479 // read firmware version 480 uint32_t fw_version = little_endian_read_32(fw_buf, 8); 481 log_info("Firmware version: 0x%x", fw_version); 482 483 // read number of patches 484 uint16_t fw_num_patches = little_endian_read_16(fw_buf, 12); 485 log_info("Number of patches: %d", fw_num_patches); 486 487 // find correct entry 488 for (uint16_t i = 0; i < fw_num_patches; i++) { 489 if (little_endian_read_16(fw_buf, 14 + 2 * i) == rom_version + 1) { 490 patch_length = little_endian_read_16(fw_buf, 14 + 2 * fw_num_patches + 2 * i); 491 offset = little_endian_read_32(fw_buf, 14 + 4 * fw_num_patches + 4 * i); 492 log_info("patch_length %u, offset %u", patch_length, offset); 493 break; 494 } 495 } 496 if (patch_length == 0) { 497 log_debug("Failed to find valid patch"); 498 finalize_file_and_buffer(&fw, &fw_buf); 499 finalize_file_and_buffer(&conf, &conf_buf); 500 return FW_DONE; 501 } 502 503 // allocate patch buffer 504 fw_total_len = patch_length + conf_size; 505 patch_buf = malloc(fw_total_len); 506 if (patch_buf == NULL) { 507 log_debug("Failed to allocate %u bytes for patch buffer", fw_total_len); 508 finalize_file_and_buffer(&fw, &fw_buf); 509 finalize_file_and_buffer(&conf, &conf_buf); 510 return FW_DONE; 511 } 512 513 // copy patch 514 memcpy(patch_buf, fw_buf + offset, patch_length); 515 memcpy(patch_buf + patch_length - 4, &fw_version, 4); 516 memcpy(patch_buf + patch_length, conf_buf, conf_size); 517 fw_ptr = 0; 518 index = 0; 519 520 // close files 521 finalize_file_and_buffer(&fw, &fw_buf); 522 finalize_file_and_buffer(&conf, &conf_buf); 523 } 524 525 uint8_t len; 526 if (fw_total_len - fw_ptr > 252) { 527 len = 252; 528 } else { 529 len = fw_total_len - fw_ptr; 530 index |= 0x80; // end 531 } 532 533 if (len) { 534 FILL_COMMAND(hci_cmd_buffer, HCI_DOWNLOAD_FW); 535 FILL_LENGTH(hci_cmd_buffer, len + 1); 536 FILL_INDEX(hci_cmd_buffer, index); 537 FILL_FW_DATA(hci_cmd_buffer, patch_buf, fw_ptr, len); 538 index++; 539 fw_ptr += len; 540 return FW_MORE_TO_DO; 541 } 542 543 // cleanup and return 544 free(patch_buf); 545 patch_buf = NULL; 546 return FW_DONE; 547 } 548 549 #endif // HAVE_POSIX_FILE_IO 550 551 static btstack_chipset_result_t chipset_next_command(uint8_t *hci_cmd_buffer) { 552 #ifdef HAVE_POSIX_FILE_IO 553 uint8_t ret; 554 while (true) { 555 switch (state) { 556 case STATE_READ_ROM_VERSION: 557 FILL_COMMAND(hci_cmd_buffer, HCI_READ_ROM_VERSION); 558 FILL_LENGTH(hci_cmd_buffer, 0); 559 state = STATE_LOAD_FIRMWARE; 560 break; 561 case STATE_LOAD_FIRMWARE: 562 if (lmp_subversion != ROM_LMP_8723a) { 563 ret = update_firmware(firmware_file_path, config_file_path, hci_cmd_buffer); 564 } else { 565 log_info("Realtek firmware for old patch style not implemented"); 566 ret = FW_DONE; 567 } 568 if (ret != FW_DONE) { 569 break; 570 } 571 // we are done fall through 572 state = STATE_RESET; 573 case STATE_RESET: 574 FILL_COMMAND(hci_cmd_buffer, HCI_RESET); 575 FILL_LENGTH(hci_cmd_buffer, 0); 576 state = STATE_DONE; 577 break; 578 case STATE_DONE: 579 hci_remove_event_handler(&hci_event_callback_registration); 580 return BTSTACK_CHIPSET_DONE; 581 break; 582 default: 583 log_info("Invalid state %d", state); 584 return BTSTACK_CHIPSET_DONE; 585 break; 586 } 587 return BTSTACK_CHIPSET_VALID_COMMAND; 588 } 589 #else // HAVE_POSIX_FILE_IO 590 log_info("Realtek without File IO is not implemented yet"); 591 return BTSTACK_CHIPSET_NO_INIT_SCRIPT; 592 #endif // HAVE_POSIX_FILE_IO 593 } 594 595 void btstack_chipset_realtek_set_firmware_file_path(const char *path) { 596 #ifdef HAVE_POSIX_FILE_IO 597 firmware_file_path = path; 598 #endif 599 } 600 601 void btstack_chipset_realtek_set_firmware_folder_path(const char *path) { 602 #ifdef HAVE_POSIX_FILE_IO 603 firmware_folder_path = path; 604 #endif 605 } 606 607 void btstack_chipset_realtek_set_config_file_path(const char *path) { 608 #ifdef HAVE_POSIX_FILE_IO 609 config_file_path = path; 610 #endif 611 } 612 613 void btstack_chipset_realtek_set_config_folder_path(const char *path) { 614 #ifdef HAVE_POSIX_FILE_IO 615 config_folder_path = path; 616 #endif 617 } 618 619 void btstack_chipset_realtek_set_lmp_subversion(uint16_t version) { 620 lmp_subversion = version; 621 } 622 623 void btstack_chipset_realtek_set_product_id(uint16_t id) { 624 product_id = id; 625 } 626 627 uint16_t btstack_chipset_realtek_get_num_usb_controllers(void){ 628 return (sizeof(fw_patch_table) / sizeof(patch_info)) - 1; // sentinel 629 } 630 631 void btstack_chipset_realtek_get_vendor_product_id(uint16_t index, uint16_t * out_vendor_id, uint16_t * out_product_id){ 632 btstack_assert(index < ((sizeof(fw_patch_table) / sizeof(patch_info)) - 1)); 633 *out_vendor_id = 0xbda; 634 *out_product_id = fw_patch_table[index].prod_id; 635 } 636 637 static const btstack_chipset_t btstack_chipset_realtek = { 638 "REALTEK", chipset_init, chipset_next_command, 639 NULL, // chipset_set_baudrate_command, 640 NULL, // chipset_set_bd_addr_command not supported or implemented 641 }; 642 643 // MARK: public API 644 const btstack_chipset_t *btstack_chipset_realtek_instance(void) { return &btstack_chipset_realtek; } 645