xref: /btstack/chipset/intel/btstack_chipset_intel_firmware.c (revision addebe7f9f70e3d69518093706c20ea7d59e949d)
1e501bae0SMatthias Ringwald /*
2e501bae0SMatthias Ringwald  * Copyright (C) 2018 BlueKitchen GmbH
3e501bae0SMatthias Ringwald  *
4e501bae0SMatthias Ringwald  * Redistribution and use in source and binary forms, with or without
5e501bae0SMatthias Ringwald  * modification, are permitted provided that the following conditions
6e501bae0SMatthias Ringwald  * are met:
7e501bae0SMatthias Ringwald  *
8e501bae0SMatthias Ringwald  * 1. Redistributions of source code must retain the above copyright
9e501bae0SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer.
10e501bae0SMatthias Ringwald  * 2. Redistributions in binary form must reproduce the above copyright
11e501bae0SMatthias Ringwald  *    notice, this list of conditions and the following disclaimer in the
12e501bae0SMatthias Ringwald  *    documentation and/or other materials provided with the distribution.
13e501bae0SMatthias Ringwald  * 3. Neither the name of the copyright holders nor the names of
14e501bae0SMatthias Ringwald  *    contributors may be used to endorse or promote products derived
15e501bae0SMatthias Ringwald  *    from this software without specific prior written permission.
16e501bae0SMatthias Ringwald  * 4. Any redistribution, use, or modification is done solely for
17e501bae0SMatthias Ringwald  *    personal benefit and not for any commercial purpose or for
18e501bae0SMatthias Ringwald  *    monetary gain.
19e501bae0SMatthias Ringwald  *
20e501bae0SMatthias Ringwald  * THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
21e501bae0SMatthias Ringwald  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22e501bae0SMatthias Ringwald  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
232fca4dadSMilanka Ringwald  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BLUEKITCHEN
242fca4dadSMilanka Ringwald  * GMBH OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25e501bae0SMatthias Ringwald  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26e501bae0SMatthias Ringwald  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27e501bae0SMatthias Ringwald  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28e501bae0SMatthias Ringwald  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29e501bae0SMatthias Ringwald  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30e501bae0SMatthias Ringwald  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31e501bae0SMatthias Ringwald  * SUCH DAMAGE.
32e501bae0SMatthias Ringwald  *
33e501bae0SMatthias Ringwald  * Please inquire about commercial licensing options at
34e501bae0SMatthias Ringwald  * [email protected]
35e501bae0SMatthias Ringwald  *
36e501bae0SMatthias Ringwald  */
37e501bae0SMatthias Ringwald 
38e501bae0SMatthias Ringwald #define BTSTACK_FILE__ "btstack_chipset_intel_firmware.c"
398174b66aSMatthias Ringwald 
408174b66aSMatthias Ringwald #include <fcntl.h>
418174b66aSMatthias Ringwald #include <stdio.h>
425965dbb8SMatthias Ringwald #include <inttypes.h>
438174b66aSMatthias Ringwald 
448174b66aSMatthias Ringwald #include "btstack_chipset_intel_firmware.h"
457a4d61a3SMatthias Ringwald 
468174b66aSMatthias Ringwald #include "bluetooth.h"
478174b66aSMatthias Ringwald #include "btstack_debug.h"
487a4d61a3SMatthias Ringwald #include "btstack_event.h"
498174b66aSMatthias Ringwald #include "btstack_run_loop.h"
507a4d61a3SMatthias Ringwald #include "btstack_util.h"
517a4d61a3SMatthias Ringwald #include "hci.h"
527a4d61a3SMatthias Ringwald #include "hci_cmd.h"
537a4d61a3SMatthias Ringwald #include "hci_dump.h"
547a4d61a3SMatthias Ringwald 
55ce9d10fbSMatthias Ringwald #ifdef _MSC_VER
56ce9d10fbSMatthias Ringwald  // ignore deprecated warning for fopen
57ce9d10fbSMatthias Ringwald #pragma warning(disable : 4996)
58ce9d10fbSMatthias Ringwald #endif
59ce9d10fbSMatthias Ringwald 
607a4d61a3SMatthias Ringwald // assert outgoing and incoming hci packet buffers can hold max hci command resp. event packet
617a4d61a3SMatthias Ringwald #if HCI_OUTGOING_PACKET_BUFFER_SIZE < (HCI_CMD_HEADER_SIZE + 255)
627a4d61a3SMatthias Ringwald #error "HCI_OUTGOING_PACKET_BUFFER_SIZE to small. Outgoing HCI packet buffer to small for largest HCI Command packet. Please set HCI_ACL_PAYLOAD_SIZE to 258 or higher."
637a4d61a3SMatthias Ringwald #endif
647a4d61a3SMatthias Ringwald #if HCI_INCOMING_PACKET_BUFFER_SIZE < (HCI_EVENT_HEADER_SIZE_HEADER_SIZE + 255)
657a4d61a3SMatthias Ringwald #error "HCI_INCOMING_PACKET_BUFFER_SIZE to small. Incoming HCI packet buffer to small for largest HCI Event packet. Please set HCI_ACL_PAYLOAD_SIZE to 257 or higher."
667a4d61a3SMatthias Ringwald #endif
678174b66aSMatthias Ringwald 
688174b66aSMatthias Ringwald // Vendor specific structs
698174b66aSMatthias Ringwald 
708174b66aSMatthias Ringwald typedef struct {
718174b66aSMatthias Ringwald     uint8_t status;
728174b66aSMatthias Ringwald     uint8_t hw_platform;
738174b66aSMatthias Ringwald     uint8_t hw_variant;
748174b66aSMatthias Ringwald     uint8_t hw_revision;
758174b66aSMatthias Ringwald     uint8_t fw_variant;
768174b66aSMatthias Ringwald     uint8_t fw_revision;
778174b66aSMatthias Ringwald     uint8_t fw_build_num;
788174b66aSMatthias Ringwald     uint8_t fw_build_ww;
798174b66aSMatthias Ringwald     uint8_t fw_build_yy;
808174b66aSMatthias Ringwald     uint8_t fw_patch_num;
818174b66aSMatthias Ringwald } intel_version_t;
828174b66aSMatthias Ringwald 
838174b66aSMatthias Ringwald typedef struct {
848174b66aSMatthias Ringwald     uint8_t     status;
858174b66aSMatthias Ringwald     uint8_t     otp_format;
868174b66aSMatthias Ringwald     uint8_t     otp_content;
878174b66aSMatthias Ringwald     uint8_t     otp_patch;
888174b66aSMatthias Ringwald     uint16_t    dev_revid;
898174b66aSMatthias Ringwald     uint8_t     secure_boot;
908174b66aSMatthias Ringwald     uint8_t     key_from_hdr;
918174b66aSMatthias Ringwald     uint8_t     key_type;
928174b66aSMatthias Ringwald     uint8_t     otp_lock;
938174b66aSMatthias Ringwald     uint8_t     api_lock;
948174b66aSMatthias Ringwald     uint8_t     debug_lock;
958174b66aSMatthias Ringwald     bd_addr_t   otp_bdaddr;
968174b66aSMatthias Ringwald     uint8_t     min_fw_build_nn;
978174b66aSMatthias Ringwald     uint8_t     min_fw_build_cw;
988174b66aSMatthias Ringwald     uint8_t     min_fw_build_yy;
998174b66aSMatthias Ringwald     uint8_t     limited_cce;
1008174b66aSMatthias Ringwald     uint8_t     unlocked_state;
1018174b66aSMatthias Ringwald } intel_boot_params_t;
1028174b66aSMatthias Ringwald 
103f4b0d900SMatthias Ringwald typedef enum {
104f4b0d900SMatthias Ringwald     INTEL_CONTROLLER_LEGACY,
105f4b0d900SMatthias Ringwald     INTEL_CONTROLLER_TLV,
106f4b0d900SMatthias Ringwald } intel_controller_mode_t;
107f4b0d900SMatthias Ringwald 
108bca4e2d9SMatthias Ringwald typedef enum {
109bca4e2d9SMatthias Ringwald     STATE_INITIAL = 0,
110bca4e2d9SMatthias Ringwald     STATE_HANDLE_HCI_RESET = 1,
111bca4e2d9SMatthias Ringwald     STATE_HANDLE_READ_VERSION_1 = 2,
112bca4e2d9SMatthias Ringwald     STATE_HANDLE_READ_SECURE_BOOT_PARAMS = 3,
113bca4e2d9SMatthias Ringwald     STATE_SEND_PUBLIC_KEY_1 = 4,
114bca4e2d9SMatthias Ringwald     STATE_SEND_PUBLIC_KEY_2 = 5,
115bca4e2d9SMatthias Ringwald     STATE_SEND_SIGNATURE_PART_1 = 6,
116bca4e2d9SMatthias Ringwald     STATE_SEND_SIGNATURE_PART_2 = 7,
117bca4e2d9SMatthias Ringwald     STATE_SEND_FIRMWARE_CHUNK = 8,
118bca4e2d9SMatthias Ringwald     STATE_HANDLE_FIRMWARE_CHUNKS_SENT = 9,
119bca4e2d9SMatthias Ringwald     STATE_HANDLE_VENDOR_SPECIFIC_EVENT_02 = 10,
120bca4e2d9SMatthias Ringwald     STATE_HANDLE_READ_VERSION_2 = 11,
121bca4e2d9SMatthias Ringwald     STATE_SEND_DDC = 12,
122bca4e2d9SMatthias Ringwald     STATE_DONE = 15
123bca4e2d9SMatthias Ringwald } state_t;
124bca4e2d9SMatthias Ringwald 
125f4b0d900SMatthias Ringwald // Vendor specific commands
1268174b66aSMatthias Ringwald 
1278174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_read_version = {
128db2cdd6dSMatthias Ringwald     0xfc05, "1"
1298174b66aSMatthias Ringwald };
1308174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_read_secure_boot_params = {
1318174b66aSMatthias Ringwald     0xfc0d, ""
1328174b66aSMatthias Ringwald };
1338174b66aSMatthias Ringwald 
1348174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_reset_param = {
1358174b66aSMatthias Ringwald     0xfc01, "11111111"
1368174b66aSMatthias Ringwald };
1378174b66aSMatthias Ringwald 
1388174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_set_event_mask = {
1398174b66aSMatthias Ringwald     0xfc52, "11111111"
1408174b66aSMatthias Ringwald };
1418174b66aSMatthias Ringwald 
1428174b66aSMatthias Ringwald // state
1438174b66aSMatthias Ringwald 
144bca4e2d9SMatthias Ringwald const char * firmware_folder_path = ".";
145bca4e2d9SMatthias Ringwald 
146bca4e2d9SMatthias Ringwald static intel_version_t     intel_version;
147bca4e2d9SMatthias Ringwald static intel_boot_params_t intel_boot_params;
14829c6772bSMatthias Ringwald 
149f4b0d900SMatthias Ringwald static intel_controller_mode_t controller_mode;
150f4b0d900SMatthias Ringwald 
1518174b66aSMatthias Ringwald const hci_transport_t * transport;
1528174b66aSMatthias Ringwald 
1535c04b733SMatthias Ringwald static state_t state;
1548174b66aSMatthias Ringwald 
155bca4e2d9SMatthias Ringwald static int vendor_firmware_complete_received;
156bca4e2d9SMatthias Ringwald static int waiting_for_command_complete;
157bca4e2d9SMatthias Ringwald 
1588174b66aSMatthias Ringwald static uint8_t hci_outgoing[300];
1598174b66aSMatthias Ringwald static uint8_t fw_buffer[300];
1608174b66aSMatthias Ringwald 
1618174b66aSMatthias Ringwald static FILE *   fw_file;
162ce9d10fbSMatthias Ringwald static size_t   fw_offset;
1638174b66aSMatthias Ringwald 
1648174b66aSMatthias Ringwald static void (*done)(int result);
1658174b66aSMatthias Ringwald 
166*addebe7fSMatthias Ringwald // protogtypes
167*addebe7fSMatthias Ringwald 
168*addebe7fSMatthias Ringwald static void state_machine(uint8_t *packet, uint16_t size);
169*addebe7fSMatthias Ringwald 
1708174b66aSMatthias Ringwald // functions
1718174b66aSMatthias Ringwald 
intel_get_dev_revid(intel_boot_params_t * boot_params)172*addebe7fSMatthias Ringwald static uint16_t intel_get_dev_revid(intel_boot_params_t * boot_params){
173*addebe7fSMatthias Ringwald     return little_endian_read_16((uint8_t*)&intel_boot_params.dev_revid, 0);
174*addebe7fSMatthias Ringwald }
175*addebe7fSMatthias Ringwald 
dump_intel_version(intel_version_t * version)176*addebe7fSMatthias Ringwald static void dump_intel_version(intel_version_t     * version){
177*addebe7fSMatthias Ringwald     log_info("status       0x%02x", version->status);
178*addebe7fSMatthias Ringwald     log_info("hw_platform  0x%02x", version->hw_platform);
179*addebe7fSMatthias Ringwald     log_info("hw_variant   0x%02x", version->hw_variant);
180*addebe7fSMatthias Ringwald     log_info("hw_revision  0x%02x", version->hw_revision);
181*addebe7fSMatthias Ringwald     log_info("fw_variant   0x%02x", version->fw_variant);
182*addebe7fSMatthias Ringwald     log_info("fw_revision  0x%02x", version->fw_revision);
183*addebe7fSMatthias Ringwald     log_info("fw_build_num 0x%02x", version->fw_build_num);
184*addebe7fSMatthias Ringwald     log_info("fw_build_ww  0x%02x", version->fw_build_ww);
185*addebe7fSMatthias Ringwald     log_info("fw_build_yy  0x%02x", version->fw_build_yy);
186*addebe7fSMatthias Ringwald     log_info("fw_patch_num 0x%02x", version->fw_patch_num);
187*addebe7fSMatthias Ringwald }
188*addebe7fSMatthias Ringwald 
dump_intel_boot_params(intel_boot_params_t * boot_params)189*addebe7fSMatthias Ringwald static void dump_intel_boot_params(intel_boot_params_t * boot_params){
190*addebe7fSMatthias Ringwald     bd_addr_t addr;
191*addebe7fSMatthias Ringwald     reverse_bd_addr(boot_params->otp_bdaddr, addr);
192*addebe7fSMatthias Ringwald     log_info("Device revision: %u", intel_get_dev_revid(boot_params));
193*addebe7fSMatthias Ringwald     log_info("Secure Boot:  %s", boot_params->secure_boot ? "enabled" : "disabled");
194*addebe7fSMatthias Ringwald     log_info("OTP lock:     %s", boot_params->otp_lock    ? "enabled" : "disabled");
195*addebe7fSMatthias Ringwald     log_info("API lock:     %s", boot_params->api_lock    ? "enabled" : "disabled");
196*addebe7fSMatthias Ringwald     log_info("Debug lock:   %s", boot_params->debug_lock  ? "enabled" : "disabled");
197*addebe7fSMatthias Ringwald     log_info("Minimum firmware build %u week %u %u", boot_params->min_fw_build_nn, boot_params->min_fw_build_cw, 2000 + boot_params->min_fw_build_yy);
198*addebe7fSMatthias Ringwald     log_info("OTC BD_ADDR:  %s", bd_addr_to_str(addr));
199*addebe7fSMatthias Ringwald }
200*addebe7fSMatthias Ringwald 
intel_get_firmware_name(intel_version_t * version,intel_boot_params_t * boot_params,const char * folder_path,const char * suffix,char * firmware_path,size_t firmware_path_len)201*addebe7fSMatthias Ringwald static int intel_get_firmware_name(intel_version_t *version, intel_boot_params_t *boot_params, const char *folder_path,
202e9d8f008SMatthias Ringwald                                    const char *suffix, char *firmware_path, size_t firmware_path_len) {
203e9d8f008SMatthias Ringwald     switch (version->hw_variant)
204e9d8f008SMatthias Ringwald     {
205e9d8f008SMatthias Ringwald         case 0x0b: /* SfP */
206e9d8f008SMatthias Ringwald         case 0x0c: /* WsP */
207e9d8f008SMatthias Ringwald             snprintf(firmware_path, firmware_path_len, "%s/ibt-%u-%u.%s",
208e9d8f008SMatthias Ringwald                      folder_path,
209e9d8f008SMatthias Ringwald                      version->hw_variant,
210*addebe7fSMatthias Ringwald                      intel_get_dev_revid(boot_params),
211e9d8f008SMatthias Ringwald                      suffix);
212e9d8f008SMatthias Ringwald             break;
213e9d8f008SMatthias Ringwald         case 0x11: /* JfP */
214e9d8f008SMatthias Ringwald         case 0x12: /* ThP */
215e9d8f008SMatthias Ringwald         case 0x13: /* HrP */
216e9d8f008SMatthias Ringwald         case 0x14: /* CcP */
217e9d8f008SMatthias Ringwald             snprintf(firmware_path, firmware_path_len, "%s/ibt-%u-%u-%u.%s",
218e9d8f008SMatthias Ringwald                      folder_path,
219e9d8f008SMatthias Ringwald                      version->hw_variant,
220e9d8f008SMatthias Ringwald                      version->hw_revision,
221e9d8f008SMatthias Ringwald                      version->fw_revision,
222e9d8f008SMatthias Ringwald                      suffix);
223e9d8f008SMatthias Ringwald             break;
224e9d8f008SMatthias Ringwald         default:
225e9d8f008SMatthias Ringwald             printf("Unsupported Intel hardware variant (%u)\n", version->hw_variant);
226e9d8f008SMatthias Ringwald             break;
227e9d8f008SMatthias Ringwald     }
228e9d8f008SMatthias Ringwald 
229e9d8f008SMatthias Ringwald     return 0;
230e9d8f008SMatthias Ringwald }
231e9d8f008SMatthias Ringwald 
transport_send_packet(uint8_t packet_type,const uint8_t * packet,uint16_t size)2328174b66aSMatthias Ringwald static int transport_send_packet(uint8_t packet_type, const uint8_t * packet, uint16_t size){
2338174b66aSMatthias Ringwald     hci_dump_packet(HCI_COMMAND_DATA_PACKET, 0, (uint8_t*) packet, size);
2348174b66aSMatthias Ringwald     return transport->send_packet(packet_type, (uint8_t *) packet, size);
2358174b66aSMatthias Ringwald }
2368174b66aSMatthias Ringwald 
transport_send_cmd_va_arg(const hci_cmd_t * cmd,va_list argptr)2378174b66aSMatthias Ringwald static int transport_send_cmd_va_arg(const hci_cmd_t *cmd, va_list argptr){
2388174b66aSMatthias Ringwald     uint8_t * packet = hci_outgoing;
2398174b66aSMatthias Ringwald     uint16_t size = hci_cmd_create_from_template(packet, cmd, argptr);
2408174b66aSMatthias Ringwald     return transport_send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
2418174b66aSMatthias Ringwald }
2428174b66aSMatthias Ringwald 
transport_send_cmd(const hci_cmd_t * cmd,...)2438174b66aSMatthias Ringwald static int transport_send_cmd(const hci_cmd_t *cmd, ...){
2448174b66aSMatthias Ringwald     va_list argptr;
2458174b66aSMatthias Ringwald     va_start(argptr, cmd);
2468174b66aSMatthias Ringwald     int res = transport_send_cmd_va_arg(cmd, argptr);
2478174b66aSMatthias Ringwald     va_end(argptr);
2488174b66aSMatthias Ringwald     return res;
2498174b66aSMatthias Ringwald }
2508174b66aSMatthias Ringwald 
transport_send_intel_secure(uint8_t fragment_type,const uint8_t * data,uint8_t len)251ce9d10fbSMatthias Ringwald static int transport_send_intel_secure(uint8_t fragment_type, const uint8_t * data, uint8_t len){
2528174b66aSMatthias Ringwald     little_endian_store_16(hci_outgoing, 0, 0xfc09);
2538174b66aSMatthias Ringwald     hci_outgoing[2] = 1 + len;
2548174b66aSMatthias Ringwald     hci_outgoing[3] = fragment_type;
2558174b66aSMatthias Ringwald     memcpy(&hci_outgoing[4], data, len);
2568174b66aSMatthias Ringwald     uint16_t size = 3 +  1 + len;
2578174b66aSMatthias Ringwald     return transport_send_packet(HCI_ACL_DATA_PACKET, hci_outgoing, size);
2588174b66aSMatthias Ringwald }
2598174b66aSMatthias Ringwald 
transport_send_intel_ddc(const uint8_t * data,uint8_t len)260ce9d10fbSMatthias Ringwald static int transport_send_intel_ddc(const uint8_t * data, uint8_t len){
2618174b66aSMatthias Ringwald     little_endian_store_16(hci_outgoing, 0, 0xfc8b);
2628174b66aSMatthias Ringwald     hci_outgoing[2] = len;
2638174b66aSMatthias Ringwald     memcpy(&hci_outgoing[3], data, len);
2648174b66aSMatthias Ringwald     uint16_t size = 3 +  len;
2658174b66aSMatthias Ringwald     return transport_send_packet(HCI_COMMAND_DATA_PACKET, hci_outgoing, size);
2668174b66aSMatthias Ringwald }
2678174b66aSMatthias Ringwald 
2688174b66aSMatthias Ringwald // read data from fw file and send it via intel_secure + update state
intel_send_fragment(uint8_t fragment_type,uint8_t len)269ce9d10fbSMatthias Ringwald static int intel_send_fragment(uint8_t fragment_type, uint8_t len){
270ce9d10fbSMatthias Ringwald     size_t res = fread(fw_buffer, 1, len, fw_file);
2715965dbb8SMatthias Ringwald     log_info("offset %6" PRId32 ", read %3u -> res %" PRId32 "", (int32_t)fw_offset, len, (int32_t)res);
2728174b66aSMatthias Ringwald     fw_offset += res;
2738174b66aSMatthias Ringwald     return transport_send_intel_secure(fragment_type, fw_buffer, len);
2748174b66aSMatthias Ringwald }
2758174b66aSMatthias Ringwald 
2768174b66aSMatthias Ringwald // read data from  ddc file and send iva intel ddc command
2778174b66aSMatthias Ringwald // @returns -1 on eof
intel_send_ddc(void)2788174b66aSMatthias Ringwald static int intel_send_ddc(void){
279ce9d10fbSMatthias Ringwald     size_t res;
2808174b66aSMatthias Ringwald     // read len
2818174b66aSMatthias Ringwald     res = fread(fw_buffer, 1, 1, fw_file);
2825965dbb8SMatthias Ringwald     log_info("offset %6" PRId32 ", read 1 -> res %" PRId32 "", (int32_t)fw_offset, (int32_t)res);
2838174b66aSMatthias Ringwald     if (res == 0) return -1;
2848174b66aSMatthias Ringwald     uint8_t len = fw_buffer[0];
2858174b66aSMatthias Ringwald     fw_offset += 1;
2868174b66aSMatthias Ringwald     res = fread(&fw_buffer[1], 1, len, fw_file);
2875965dbb8SMatthias Ringwald     log_info("offset %6" PRId32 ", read %u -> res %" PRId32 "", (int32_t)fw_offset, 1, (int32_t)res);
2888174b66aSMatthias Ringwald     return transport_send_intel_ddc(fw_buffer, 1 + len);
2898174b66aSMatthias Ringwald }
2908174b66aSMatthias Ringwald 
state_machine(uint8_t * packet,uint16_t size)2915b4c35aeSMatthias Ringwald static void state_machine(uint8_t *packet, uint16_t size) {
292ce9d10fbSMatthias Ringwald     size_t res;
293ce9d10fbSMatthias Ringwald     size_t buffer_offset;
2948174b66aSMatthias Ringwald     bd_addr_t addr;
29529c6772bSMatthias Ringwald     char    fw_path[300];
2968174b66aSMatthias Ringwald 
2978174b66aSMatthias Ringwald     if (packet){
2988174b66aSMatthias Ringwald         // firmware upload complete event?
2998174b66aSMatthias Ringwald         if (packet[0] == 0xff && packet[2] == 0x06) {
3008174b66aSMatthias Ringwald             vendor_firmware_complete_received = 1;
3018174b66aSMatthias Ringwald         }
3028174b66aSMatthias Ringwald 
3038174b66aSMatthias Ringwald         // command complete
3048174b66aSMatthias Ringwald         if (packet[0] == 0x0e){
3058174b66aSMatthias Ringwald             waiting_for_command_complete = 0;
3068174b66aSMatthias Ringwald         }
3078174b66aSMatthias Ringwald     }
3088174b66aSMatthias Ringwald 
3098174b66aSMatthias Ringwald     switch (state){
3105c04b733SMatthias Ringwald         case STATE_INITIAL:
311f4b0d900SMatthias Ringwald             controller_mode = INTEL_CONTROLLER_LEGACY;
3125c04b733SMatthias Ringwald             state = STATE_HANDLE_HCI_RESET;
3138174b66aSMatthias Ringwald             transport_send_cmd(&hci_reset);
3148174b66aSMatthias Ringwald             break;
3155c04b733SMatthias Ringwald         case STATE_HANDLE_HCI_RESET:
31688362d5eSMatthias Ringwald             // check if HCI Reset was supported
31788362d5eSMatthias Ringwald             if (packet[0] == 0x0e && packet[1] == 0x04 && packet[3] == 0x03 && packet[4] == 0x0c && packet[5] == 0x00){
31888362d5eSMatthias Ringwald                 log_info("HCI Reset was successful, no need for firmware upload / or not an Intel chipset");
31988362d5eSMatthias Ringwald                 (*done)(0);
32088362d5eSMatthias Ringwald                 break;
32188362d5eSMatthias Ringwald             }
32288362d5eSMatthias Ringwald 
3238174b66aSMatthias Ringwald             // Read Intel Version
3245c04b733SMatthias Ringwald             state = STATE_HANDLE_READ_VERSION_1;
325db2cdd6dSMatthias Ringwald             transport_send_cmd(&hci_intel_read_version, 0xff);
3268174b66aSMatthias Ringwald             break;
3275c04b733SMatthias Ringwald         case STATE_HANDLE_READ_VERSION_1:
3285c04b733SMatthias Ringwald             // detect legacy vs. new TLV mode based on Read Version response
329f4b0d900SMatthias Ringwald             if ((size == sizeof(intel_version_t)) || (packet[1] != 0x037)){
330f4b0d900SMatthias Ringwald                 controller_mode = INTEL_CONTROLLER_TLV;
331f4b0d900SMatthias Ringwald                 printf("\nERROR: Intel Controller uses new TLV mode. TLV mode is not supported yet\n");
332f4b0d900SMatthias Ringwald                 printf("Details: https://github.com/torvalds/linux/blob/master/drivers/bluetooth/btintel.c\n\n");
333f4b0d900SMatthias Ringwald                 log_error("TLV mode not supported");
334f4b0d900SMatthias Ringwald                 (*done)(1);
335f4b0d900SMatthias Ringwald                 break;
336f4b0d900SMatthias Ringwald             }
337f4b0d900SMatthias Ringwald 
338f4b0d900SMatthias Ringwald             // legacy mode
339bca4e2d9SMatthias Ringwald             intel_version =  *(intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
340bca4e2d9SMatthias Ringwald             dump_intel_version(&intel_version);
3418174b66aSMatthias Ringwald 
3428174b66aSMatthias Ringwald             // fw_variant = 0x06 bootloader mode / 0x23 operational mode
343bca4e2d9SMatthias Ringwald             if (intel_version.fw_variant == 0x23) {
3448174b66aSMatthias Ringwald                 (*done)(0);
3458174b66aSMatthias Ringwald                 break;
3468174b66aSMatthias Ringwald             }
3478174b66aSMatthias Ringwald 
348bca4e2d9SMatthias Ringwald             if (intel_version.fw_variant != 0x06){
349bca4e2d9SMatthias Ringwald                 log_error("unknown fw_variant 0x%02x", intel_version.fw_variant);
3508174b66aSMatthias Ringwald                 break;
3518174b66aSMatthias Ringwald             }
3528174b66aSMatthias Ringwald 
3538174b66aSMatthias Ringwald             // Read Intel Secure Boot Params
3545c04b733SMatthias Ringwald             state = STATE_HANDLE_READ_SECURE_BOOT_PARAMS;
3558174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_read_secure_boot_params);
3568174b66aSMatthias Ringwald             break;
3575c04b733SMatthias Ringwald         case STATE_HANDLE_READ_SECURE_BOOT_PARAMS:
358bca4e2d9SMatthias Ringwald             intel_boot_params = *(intel_boot_params_t *) hci_event_command_complete_get_return_parameters(packet);
359bca4e2d9SMatthias Ringwald             dump_intel_boot_params(&intel_boot_params);
3608174b66aSMatthias Ringwald 
361bca4e2d9SMatthias Ringwald             reverse_bd_addr(intel_boot_params.otp_bdaddr, addr);
3628174b66aSMatthias Ringwald 
3635c04b733SMatthias Ringwald             // assert command complete is required
364bca4e2d9SMatthias Ringwald             if (intel_boot_params.limited_cce != 0) break;
3658174b66aSMatthias Ringwald 
3668174b66aSMatthias Ringwald             // firmware file
367e9d8f008SMatthias Ringwald             intel_get_firmware_name(&intel_version, &intel_boot_params, firmware_folder_path,
368e9d8f008SMatthias Ringwald                                     "sfi", fw_path, sizeof(fw_path));
36929c6772bSMatthias Ringwald             log_info("Open firmware %s", fw_path);
3705c04b733SMatthias Ringwald             printf("Firmware %s\n", fw_path);
3718174b66aSMatthias Ringwald 
3728174b66aSMatthias Ringwald             // open firmware file
3738174b66aSMatthias Ringwald             fw_offset = 0;
37429c6772bSMatthias Ringwald             fw_file = fopen(fw_path, "rb");
3758174b66aSMatthias Ringwald             if (!fw_file){
37629c6772bSMatthias Ringwald                 log_error("can't open file %s", fw_path);
3778174b66aSMatthias Ringwald                 (*done)(1);
3788174b66aSMatthias Ringwald                 return;
3798174b66aSMatthias Ringwald             }
3808174b66aSMatthias Ringwald 
3818174b66aSMatthias Ringwald             vendor_firmware_complete_received = 0;
3828174b66aSMatthias Ringwald 
3838174b66aSMatthias Ringwald             // send CCS segment - offset 0
3845c04b733SMatthias Ringwald             state = STATE_SEND_PUBLIC_KEY_1;
3858174b66aSMatthias Ringwald             intel_send_fragment(0x00, 128);
3868174b66aSMatthias Ringwald             break;
3875c04b733SMatthias Ringwald         case STATE_SEND_PUBLIC_KEY_1:
3888174b66aSMatthias Ringwald             // send public key / part 1 - offset 128
3895c04b733SMatthias Ringwald             state = STATE_SEND_PUBLIC_KEY_2;
3908174b66aSMatthias Ringwald             intel_send_fragment(0x03, 128);
3918174b66aSMatthias Ringwald             break;
3925c04b733SMatthias Ringwald         case STATE_SEND_PUBLIC_KEY_2:
3938174b66aSMatthias Ringwald             // send public key / part 2 - offset 384
3945c04b733SMatthias Ringwald             state = STATE_SEND_SIGNATURE_PART_1;
3958174b66aSMatthias Ringwald             intel_send_fragment(0x03, 128);
3968174b66aSMatthias Ringwald             break;
3975c04b733SMatthias Ringwald         case STATE_SEND_SIGNATURE_PART_1:
3988174b66aSMatthias Ringwald             // skip 4 bytes
3998174b66aSMatthias Ringwald             res = fread(fw_buffer, 1, 4, fw_file);
4005965dbb8SMatthias Ringwald             log_info("read res %d", (int)res);
4018174b66aSMatthias Ringwald             fw_offset += res;
4028174b66aSMatthias Ringwald 
4038174b66aSMatthias Ringwald             // send signature / part 1 - offset 388
4045c04b733SMatthias Ringwald             state = STATE_SEND_SIGNATURE_PART_2;
4058174b66aSMatthias Ringwald             intel_send_fragment(0x02, 128);
4068174b66aSMatthias Ringwald             break;
4075c04b733SMatthias Ringwald         case STATE_SEND_SIGNATURE_PART_2:
4088174b66aSMatthias Ringwald             // send signature / part 2 - offset 516
4095c04b733SMatthias Ringwald             state = STATE_SEND_FIRMWARE_CHUNK;
4108174b66aSMatthias Ringwald             intel_send_fragment(0x02, 128);
4118174b66aSMatthias Ringwald             break;
4125c04b733SMatthias Ringwald         case STATE_SEND_FIRMWARE_CHUNK:
4138174b66aSMatthias Ringwald             // send firmware chunks - offset 644
4148174b66aSMatthias Ringwald             // chunk len must be 4 byte aligned
4158174b66aSMatthias Ringwald             // multiple commands can be combined
4168174b66aSMatthias Ringwald             buffer_offset = 0;
4178174b66aSMatthias Ringwald             do {
4188174b66aSMatthias Ringwald                 res = fread(&fw_buffer[buffer_offset], 1, 3, fw_file);
4195965dbb8SMatthias Ringwald                 log_info("fw_offset %6" PRId32 ", buffer_offset %" PRId32 ", read %3u -> res %" PRId32 "", (int32_t)fw_offset, (int32_t)buffer_offset, 3, (int32_t)res);
4208174b66aSMatthias Ringwald                 fw_offset += res;
4218174b66aSMatthias Ringwald                 if (res == 0 ){
4228174b66aSMatthias Ringwald                     // EOF
4238174b66aSMatthias Ringwald                     log_info("End of file");
4248174b66aSMatthias Ringwald                     fclose(fw_file);
4258174b66aSMatthias Ringwald                     fw_file = NULL;
4265c04b733SMatthias Ringwald                     state = STATE_HANDLE_FIRMWARE_CHUNKS_SENT;
4278174b66aSMatthias Ringwald                     break;
4288174b66aSMatthias Ringwald                 }
4298174b66aSMatthias Ringwald                 int param_len = fw_buffer[buffer_offset + 2];
4308174b66aSMatthias Ringwald                 buffer_offset += 3;
4318174b66aSMatthias Ringwald                 if (param_len){
4328174b66aSMatthias Ringwald                     res = fread(&fw_buffer[buffer_offset], 1, param_len, fw_file);
4338174b66aSMatthias Ringwald                     fw_offset     += res;
4348174b66aSMatthias Ringwald                     buffer_offset += res;
4358174b66aSMatthias Ringwald                 }
4368174b66aSMatthias Ringwald             } while ((buffer_offset & 3) != 0);
4378174b66aSMatthias Ringwald 
4388174b66aSMatthias Ringwald             if (buffer_offset == 0) break;
4398174b66aSMatthias Ringwald 
4408174b66aSMatthias Ringwald             waiting_for_command_complete = 1;
441ce9d10fbSMatthias Ringwald             transport_send_intel_secure(0x01, fw_buffer, (uint8_t) buffer_offset);
4428174b66aSMatthias Ringwald             break;
4438174b66aSMatthias Ringwald 
4445c04b733SMatthias Ringwald         case STATE_HANDLE_FIRMWARE_CHUNKS_SENT:
4458174b66aSMatthias Ringwald             // expect Vendor Specific Event 0x06
4468174b66aSMatthias Ringwald             if (!vendor_firmware_complete_received) break;
4478174b66aSMatthias Ringwald 
4488174b66aSMatthias Ringwald             printf("Firmware upload complete\n");
4498174b66aSMatthias Ringwald             log_info("Vendor Event 0x06 - firmware complete");
4508174b66aSMatthias Ringwald 
4518174b66aSMatthias Ringwald             // Reset Params - constants from Windows Intel driver
4525c04b733SMatthias Ringwald             state = STATE_HANDLE_VENDOR_SPECIFIC_EVENT_02;
4538174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_reset_param, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x04, 0x00);
4548174b66aSMatthias Ringwald             break;
4558174b66aSMatthias Ringwald 
4565c04b733SMatthias Ringwald         case STATE_HANDLE_VENDOR_SPECIFIC_EVENT_02:
4578174b66aSMatthias Ringwald             // expect Vendor Specific Event 0x02
4588174b66aSMatthias Ringwald             if (packet[0] != 0xff) break;
4598174b66aSMatthias Ringwald             if (packet[2] != 0x02) break;
4608174b66aSMatthias Ringwald 
4618174b66aSMatthias Ringwald             printf("Firmware operational\n");
4628174b66aSMatthias Ringwald             log_info("Vendor Event 0x02 - firmware operational");
4638174b66aSMatthias Ringwald 
4648174b66aSMatthias Ringwald             // Read Intel Version
4655c04b733SMatthias Ringwald             state = STATE_HANDLE_READ_VERSION_2;
4668174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_read_version);
4678174b66aSMatthias Ringwald             break;
4688174b66aSMatthias Ringwald 
4695c04b733SMatthias Ringwald         case STATE_HANDLE_READ_VERSION_2:
470bca4e2d9SMatthias Ringwald             intel_version = *(intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
471bca4e2d9SMatthias Ringwald             dump_intel_version(&intel_version);
4728174b66aSMatthias Ringwald 
4738174b66aSMatthias Ringwald             // ddc config
474e9d8f008SMatthias Ringwald             intel_get_firmware_name(&intel_version, &intel_boot_params, firmware_folder_path,
475e9d8f008SMatthias Ringwald                                     "ddc", fw_path, sizeof(fw_path));
47629c6772bSMatthias Ringwald             log_info("Open DDC %s", fw_path);
4778174b66aSMatthias Ringwald 
4788174b66aSMatthias Ringwald             // open ddc file
4798174b66aSMatthias Ringwald             fw_offset = 0;
48029c6772bSMatthias Ringwald             fw_file = fopen(fw_path, "rb");
4818174b66aSMatthias Ringwald             if (!fw_file){
48229c6772bSMatthias Ringwald                 log_error("can't open file %s", fw_path);
4838174b66aSMatthias Ringwald 
4848174b66aSMatthias Ringwald                 (*done)(1);
4858174b66aSMatthias Ringwald                 return;
4868174b66aSMatthias Ringwald             }
4878174b66aSMatthias Ringwald 
4888174b66aSMatthias Ringwald             // load ddc
4895c04b733SMatthias Ringwald             state = STATE_SEND_DDC;
4908174b66aSMatthias Ringwald 
4918174b66aSMatthias Ringwald             /* fall through */
4928174b66aSMatthias Ringwald 
4935c04b733SMatthias Ringwald         case STATE_SEND_DDC:
4948174b66aSMatthias Ringwald             res = intel_send_ddc();
4958174b66aSMatthias Ringwald             if (res == 0) break;
4968174b66aSMatthias Ringwald 
4978174b66aSMatthias Ringwald             // DDC download complete
4988174b66aSMatthias Ringwald             log_info("Load DDC Complete");
4998174b66aSMatthias Ringwald 
5005c04b733SMatthias Ringwald             // TODO: check if we need to wait for HCI Command Complete, resp. add another state here
5018174b66aSMatthias Ringwald 
5028174b66aSMatthias Ringwald             // Set Intel event mask 0xfc52
5035c04b733SMatthias Ringwald             state = STATE_DONE;
5048174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_set_event_mask, 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
5058174b66aSMatthias Ringwald             break;
5068174b66aSMatthias Ringwald 
5075c04b733SMatthias Ringwald         case STATE_DONE:
5088174b66aSMatthias Ringwald             (*done)(0);
5098174b66aSMatthias Ringwald             break;
5108174b66aSMatthias Ringwald 
5118174b66aSMatthias Ringwald         default:
5128174b66aSMatthias Ringwald             break;
5138174b66aSMatthias Ringwald     }
5148174b66aSMatthias Ringwald }
5158174b66aSMatthias Ringwald 
transport_packet_handler(uint8_t packet_type,uint8_t * packet,uint16_t size)5168174b66aSMatthias Ringwald static void transport_packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
5178174b66aSMatthias Ringwald     UNUSED(packet_type);
5188174b66aSMatthias Ringwald     // we also get events with packet_type ACL from the controller
5198174b66aSMatthias Ringwald     hci_dump_packet(HCI_EVENT_PACKET, 1, packet, size);
5208174b66aSMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
5218174b66aSMatthias Ringwald         case HCI_EVENT_COMMAND_COMPLETE:
5228174b66aSMatthias Ringwald         case HCI_EVENT_VENDOR_SPECIFIC:
5235b4c35aeSMatthias Ringwald             state_machine(packet, size);
5248174b66aSMatthias Ringwald             break;
5258174b66aSMatthias Ringwald         default:
5268174b66aSMatthias Ringwald             break;
5278174b66aSMatthias Ringwald     }
5288174b66aSMatthias Ringwald }
5298174b66aSMatthias Ringwald 
btstack_chipset_intel_set_firmware_path(const char * path)53029c6772bSMatthias Ringwald void btstack_chipset_intel_set_firmware_path(const char * path){
531bca4e2d9SMatthias Ringwald     firmware_folder_path = path;
53229c6772bSMatthias Ringwald }
53329c6772bSMatthias Ringwald 
btstack_chipset_intel_download_firmware(const hci_transport_t * hci_transport,void (* callback)(int result))5348174b66aSMatthias Ringwald void btstack_chipset_intel_download_firmware(const hci_transport_t * hci_transport, void (*callback)(int result)){
5358174b66aSMatthias Ringwald 
5368174b66aSMatthias Ringwald     done = callback;
5378174b66aSMatthias Ringwald 
5388174b66aSMatthias Ringwald 	transport = hci_transport;;
5398174b66aSMatthias Ringwald     transport->register_packet_handler(&transport_packet_handler);
5408174b66aSMatthias Ringwald     transport->open();
5418174b66aSMatthias Ringwald 
5428174b66aSMatthias Ringwald     // get started
5435c04b733SMatthias Ringwald     state = STATE_INITIAL;
5445b4c35aeSMatthias Ringwald     state_machine(NULL, 0);
5458174b66aSMatthias Ringwald }
546