xref: /btstack/chipset/intel/btstack_chipset_intel_firmware.c (revision 29c6772bc68e470e5e7fd6a129b9ce19f63bdd8a)
18174b66aSMatthias Ringwald #define __BTSTACK_FILE__ "btstack_chipset_intel_firmware.c"
28174b66aSMatthias Ringwald 
38174b66aSMatthias Ringwald #include <fcntl.h>
48174b66aSMatthias Ringwald #include <unistd.h>
58174b66aSMatthias Ringwald #include <stdio.h>
68174b66aSMatthias Ringwald 
78174b66aSMatthias Ringwald #include "btstack_chipset_intel_firmware.h"
88174b66aSMatthias Ringwald #include "hci_cmd.h"
98174b66aSMatthias Ringwald #include "bluetooth.h"
108174b66aSMatthias Ringwald #include "hci_dump.h"
118174b66aSMatthias Ringwald #include "btstack_event.h"
128174b66aSMatthias Ringwald #include "btstack_debug.h"
138174b66aSMatthias Ringwald #include "btstack_util.h"
148174b66aSMatthias Ringwald #include "btstack_run_loop.h"
158174b66aSMatthias Ringwald 
168174b66aSMatthias Ringwald // Vendor specific structs
178174b66aSMatthias Ringwald 
188174b66aSMatthias Ringwald typedef struct {
198174b66aSMatthias Ringwald     uint8_t status;
208174b66aSMatthias Ringwald     uint8_t hw_platform;
218174b66aSMatthias Ringwald     uint8_t hw_variant;
228174b66aSMatthias Ringwald     uint8_t hw_revision;
238174b66aSMatthias Ringwald     uint8_t fw_variant;
248174b66aSMatthias Ringwald     uint8_t fw_revision;
258174b66aSMatthias Ringwald     uint8_t fw_build_num;
268174b66aSMatthias Ringwald     uint8_t fw_build_ww;
278174b66aSMatthias Ringwald     uint8_t fw_build_yy;
288174b66aSMatthias Ringwald     uint8_t fw_patch_num;
298174b66aSMatthias Ringwald } intel_version_t;
308174b66aSMatthias Ringwald 
318174b66aSMatthias Ringwald typedef struct {
328174b66aSMatthias Ringwald     uint8_t     status;
338174b66aSMatthias Ringwald     uint8_t     otp_format;
348174b66aSMatthias Ringwald     uint8_t     otp_content;
358174b66aSMatthias Ringwald     uint8_t     otp_patch;
368174b66aSMatthias Ringwald     uint16_t    dev_revid;
378174b66aSMatthias Ringwald     uint8_t     secure_boot;
388174b66aSMatthias Ringwald     uint8_t     key_from_hdr;
398174b66aSMatthias Ringwald     uint8_t     key_type;
408174b66aSMatthias Ringwald     uint8_t     otp_lock;
418174b66aSMatthias Ringwald     uint8_t     api_lock;
428174b66aSMatthias Ringwald     uint8_t     debug_lock;
438174b66aSMatthias Ringwald     bd_addr_t   otp_bdaddr;
448174b66aSMatthias Ringwald     uint8_t     min_fw_build_nn;
458174b66aSMatthias Ringwald     uint8_t     min_fw_build_cw;
468174b66aSMatthias Ringwald     uint8_t     min_fw_build_yy;
478174b66aSMatthias Ringwald     uint8_t     limited_cce;
488174b66aSMatthias Ringwald     uint8_t     unlocked_state;
498174b66aSMatthias Ringwald } intel_boot_params_t;
508174b66aSMatthias Ringwald 
518174b66aSMatthias Ringwald // Vendor sepcific commands
528174b66aSMatthias Ringwald 
538174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_read_version = {
548174b66aSMatthias Ringwald     0xfc05, ""
558174b66aSMatthias Ringwald };
568174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_read_secure_boot_params = {
578174b66aSMatthias Ringwald     0xfc0d, ""
588174b66aSMatthias Ringwald };
598174b66aSMatthias Ringwald 
608174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_reset_param = {
618174b66aSMatthias Ringwald     0xfc01, "11111111"
628174b66aSMatthias Ringwald };
638174b66aSMatthias Ringwald 
648174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_set_event_mask = {
658174b66aSMatthias Ringwald     0xfc52, "11111111"
668174b66aSMatthias Ringwald };
678174b66aSMatthias Ringwald 
688174b66aSMatthias Ringwald static const hci_cmd_t hci_intel_fc9f = {
698174b66aSMatthias Ringwald     0xfc9f, "1"
708174b66aSMatthias Ringwald };
718174b66aSMatthias Ringwald 
728174b66aSMatthias Ringwald // state
738174b66aSMatthias Ringwald 
74*29c6772bSMatthias Ringwald const char * firmware_path = ".";
75*29c6772bSMatthias Ringwald 
768174b66aSMatthias Ringwald const hci_transport_t * transport;
778174b66aSMatthias Ringwald 
788174b66aSMatthias Ringwald static int state = 0;
798174b66aSMatthias Ringwald 
808174b66aSMatthias Ringwald static uint8_t hci_outgoing[300];
818174b66aSMatthias Ringwald static uint8_t fw_buffer[300];
828174b66aSMatthias Ringwald 
838174b66aSMatthias Ringwald static uint8_t  hw_variant;
848174b66aSMatthias Ringwald static uint16_t dev_revid;
858174b66aSMatthias Ringwald 
868174b66aSMatthias Ringwald static FILE *   fw_file;
878174b66aSMatthias Ringwald static uint32_t fw_offset;
888174b66aSMatthias Ringwald 
898174b66aSMatthias Ringwald static void (*done)(int result);
908174b66aSMatthias Ringwald 
918174b66aSMatthias Ringwald // functions
928174b66aSMatthias Ringwald 
938174b66aSMatthias Ringwald static int transport_send_packet(uint8_t packet_type, const uint8_t * packet, uint16_t size){
948174b66aSMatthias Ringwald     hci_dump_packet(HCI_COMMAND_DATA_PACKET, 0, (uint8_t*) packet, size);
958174b66aSMatthias Ringwald     return transport->send_packet(packet_type, (uint8_t *) packet, size);
968174b66aSMatthias Ringwald }
978174b66aSMatthias Ringwald 
988174b66aSMatthias Ringwald static int transport_send_cmd_va_arg(const hci_cmd_t *cmd, va_list argptr){
998174b66aSMatthias Ringwald     uint8_t * packet = hci_outgoing;
1008174b66aSMatthias Ringwald     uint16_t size = hci_cmd_create_from_template(packet, cmd, argptr);
1018174b66aSMatthias Ringwald     return transport_send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
1028174b66aSMatthias Ringwald }
1038174b66aSMatthias Ringwald 
1048174b66aSMatthias Ringwald static int transport_send_cmd(const hci_cmd_t *cmd, ...){
1058174b66aSMatthias Ringwald     va_list argptr;
1068174b66aSMatthias Ringwald     va_start(argptr, cmd);
1078174b66aSMatthias Ringwald     int res = transport_send_cmd_va_arg(cmd, argptr);
1088174b66aSMatthias Ringwald     va_end(argptr);
1098174b66aSMatthias Ringwald     return res;
1108174b66aSMatthias Ringwald }
1118174b66aSMatthias Ringwald 
1128174b66aSMatthias Ringwald static int transport_send_intel_secure(uint8_t fragment_type, const uint8_t * data, uint16_t len){
1138174b66aSMatthias Ringwald     little_endian_store_16(hci_outgoing, 0, 0xfc09);
1148174b66aSMatthias Ringwald     hci_outgoing[2] = 1 + len;
1158174b66aSMatthias Ringwald     hci_outgoing[3] = fragment_type;
1168174b66aSMatthias Ringwald     memcpy(&hci_outgoing[4], data, len);
1178174b66aSMatthias Ringwald     uint16_t size = 3 +  1 + len;
1188174b66aSMatthias Ringwald     return transport_send_packet(HCI_ACL_DATA_PACKET, hci_outgoing, size);
1198174b66aSMatthias Ringwald }
1208174b66aSMatthias Ringwald 
1218174b66aSMatthias Ringwald static int transport_send_intel_ddc(const uint8_t * data, uint16_t len){
1228174b66aSMatthias Ringwald     little_endian_store_16(hci_outgoing, 0, 0xfc8b);
1238174b66aSMatthias Ringwald     hci_outgoing[2] = len;
1248174b66aSMatthias Ringwald     memcpy(&hci_outgoing[3], data, len);
1258174b66aSMatthias Ringwald     uint16_t size = 3 +  len;
1268174b66aSMatthias Ringwald     return transport_send_packet(HCI_COMMAND_DATA_PACKET, hci_outgoing, size);
1278174b66aSMatthias Ringwald }
1288174b66aSMatthias Ringwald 
1298174b66aSMatthias Ringwald static void state_machine(uint8_t * packet);
1308174b66aSMatthias Ringwald 
1318174b66aSMatthias Ringwald // read data from fw file and send it via intel_secure + update state
1328174b66aSMatthias Ringwald static int intel_send_fragment(uint8_t fragment_type, uint16_t len){
1338174b66aSMatthias Ringwald     int res = fread(fw_buffer, 1, len, fw_file);
1348174b66aSMatthias Ringwald     log_info("offset %6u, read %3u -> res %d", fw_offset, len, res);
1358174b66aSMatthias Ringwald     fw_offset += res;
1368174b66aSMatthias Ringwald     state++;
1378174b66aSMatthias Ringwald     return transport_send_intel_secure(fragment_type, fw_buffer, len);
1388174b66aSMatthias Ringwald }
1398174b66aSMatthias Ringwald 
1408174b66aSMatthias Ringwald // read data from  ddc file and send iva intel ddc command
1418174b66aSMatthias Ringwald // @returns -1 on eof
1428174b66aSMatthias Ringwald static int intel_send_ddc(void){
1438174b66aSMatthias Ringwald     int res;
1448174b66aSMatthias Ringwald     // read len
1458174b66aSMatthias Ringwald     res = fread(fw_buffer, 1, 1, fw_file);
1468174b66aSMatthias Ringwald     log_info("offset %6u, read 1 -> res %d", fw_offset, res);
1478174b66aSMatthias Ringwald     if (res == 0) return -1;
1488174b66aSMatthias Ringwald     uint8_t len = fw_buffer[0];
1498174b66aSMatthias Ringwald     fw_offset += 1;
1508174b66aSMatthias Ringwald     res = fread(&fw_buffer[1], 1, len, fw_file);
1518174b66aSMatthias Ringwald     log_info("offset %6u, read %u -> res %d", fw_offset, 1, res);
1528174b66aSMatthias Ringwald     return transport_send_intel_ddc(fw_buffer, 1 + len);
1538174b66aSMatthias Ringwald }
1548174b66aSMatthias Ringwald 
1558174b66aSMatthias Ringwald static void dump_intel_version(intel_version_t     * version){
1568174b66aSMatthias Ringwald     log_info("status       0x%02x", version->status);
1578174b66aSMatthias Ringwald     log_info("hw_platform  0x%02x", version->hw_platform);
1588174b66aSMatthias Ringwald     log_info("hw_variant   0x%02x", version->hw_variant);
1598174b66aSMatthias Ringwald     log_info("hw_revision  0x%02x", version->hw_revision);
1608174b66aSMatthias Ringwald     log_info("fw_variant   0x%02x", version->fw_variant);
1618174b66aSMatthias Ringwald     log_info("fw_revision  0x%02x", version->fw_revision);
1628174b66aSMatthias Ringwald     log_info("fw_build_num 0x%02x", version->fw_build_num);
1638174b66aSMatthias Ringwald     log_info("fw_build_ww  0x%02x", version->fw_build_ww);
1648174b66aSMatthias Ringwald     log_info("fw_build_yy  0x%02x", version->fw_build_yy);
1658174b66aSMatthias Ringwald     log_info("fw_patch_num 0x%02x", version->fw_patch_num);
1668174b66aSMatthias Ringwald }
1678174b66aSMatthias Ringwald 
1688174b66aSMatthias Ringwald static void dump_intel_boot_params(intel_boot_params_t * boot_params){
1698174b66aSMatthias Ringwald     bd_addr_t addr;
1708174b66aSMatthias Ringwald     reverse_bd_addr(boot_params->otp_bdaddr, addr);
1718174b66aSMatthias Ringwald     log_info("Device revision: %u", dev_revid);
1728174b66aSMatthias Ringwald     log_info("Secure Boot:  %s", boot_params->secure_boot ? "enabled" : "disabled");
1738174b66aSMatthias Ringwald     log_info("OTP lock:     %s", boot_params->otp_lock    ? "enabled" : "disabled");
1748174b66aSMatthias Ringwald     log_info("API lock:     %s", boot_params->api_lock    ? "enabled" : "disabled");
1758174b66aSMatthias Ringwald     log_info("Debug lock:   %s", boot_params->debug_lock  ? "enabled" : "disabled");
1768174b66aSMatthias 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);
1778174b66aSMatthias Ringwald     log_info("OTC BD_ADDR:  %s", bd_addr_to_str(addr));
1788174b66aSMatthias Ringwald }
1798174b66aSMatthias Ringwald 
1808174b66aSMatthias Ringwald static int vendor_firmware_complete_received;
1818174b66aSMatthias Ringwald static int waiting_for_command_complete;
1828174b66aSMatthias Ringwald 
1838174b66aSMatthias Ringwald static void state_machine(uint8_t * packet){
1848174b66aSMatthias Ringwald     intel_version_t     * version;
1858174b66aSMatthias Ringwald     intel_boot_params_t * boot_params;
1868174b66aSMatthias Ringwald     int res;
1878174b66aSMatthias Ringwald     uint16_t buffer_offset;
1888174b66aSMatthias Ringwald     bd_addr_t addr;
189*29c6772bSMatthias Ringwald     char    fw_path[300];
1908174b66aSMatthias Ringwald 
1918174b66aSMatthias Ringwald     if (packet){
1928174b66aSMatthias Ringwald         // firmware upload complete event?
1938174b66aSMatthias Ringwald         if (packet[0] == 0xff && packet[2] == 0x06) {
1948174b66aSMatthias Ringwald             vendor_firmware_complete_received = 1;
1958174b66aSMatthias Ringwald         }
1968174b66aSMatthias Ringwald 
1978174b66aSMatthias Ringwald         // command complete
1988174b66aSMatthias Ringwald         if (packet[0] == 0x0e){
1998174b66aSMatthias Ringwald             waiting_for_command_complete = 0;
2008174b66aSMatthias Ringwald         }
2018174b66aSMatthias Ringwald     }
2028174b66aSMatthias Ringwald 
2038174b66aSMatthias Ringwald     switch (state){
2048174b66aSMatthias Ringwald         case 0:
2058174b66aSMatthias Ringwald             state++;
2068174b66aSMatthias Ringwald             transport_send_cmd(&hci_reset);
2078174b66aSMatthias Ringwald             break;
2088174b66aSMatthias Ringwald         case 1:
2098174b66aSMatthias Ringwald             // Read Intel Version
2108174b66aSMatthias Ringwald             state++;
2118174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_read_version);
2128174b66aSMatthias Ringwald             break;
2138174b66aSMatthias Ringwald         case 2:
2148174b66aSMatthias Ringwald             version = (intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
2158174b66aSMatthias Ringwald             dump_intel_version(version);
2168174b66aSMatthias Ringwald 
2178174b66aSMatthias Ringwald             hw_variant = version->hw_variant;
2188174b66aSMatthias Ringwald 
2198174b66aSMatthias Ringwald             // fw_variant = 0x06 bootloader mode / 0x23 operational mode
2208174b66aSMatthias Ringwald             if (version->fw_variant == 0x23) {
2218174b66aSMatthias Ringwald                 (*done)(0);
2228174b66aSMatthias Ringwald                 break;
2238174b66aSMatthias Ringwald             }
2248174b66aSMatthias Ringwald 
2258174b66aSMatthias Ringwald             if (version->fw_variant != 0x06){
2268174b66aSMatthias Ringwald                 log_error("unknown fw_variant 0x%02x", version->fw_variant);
2278174b66aSMatthias Ringwald                 break;
2288174b66aSMatthias Ringwald             }
2298174b66aSMatthias Ringwald 
2308174b66aSMatthias Ringwald             // Read Intel Secure Boot Params
2318174b66aSMatthias Ringwald             state++;
2328174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_read_secure_boot_params);
2338174b66aSMatthias Ringwald             break;
2348174b66aSMatthias Ringwald         case 3:
2358174b66aSMatthias Ringwald             boot_params = (intel_boot_params_t *) hci_event_command_complete_get_return_parameters(packet);
2368174b66aSMatthias Ringwald             dump_intel_boot_params(boot_params);
2378174b66aSMatthias Ringwald 
2388174b66aSMatthias Ringwald             reverse_bd_addr(boot_params->otp_bdaddr, addr);
2398174b66aSMatthias Ringwald             dev_revid = little_endian_read_16((uint8_t*)&boot_params->dev_revid, 0);
2408174b66aSMatthias Ringwald 
2418174b66aSMatthias Ringwald             // assert commmand complete is required
2428174b66aSMatthias Ringwald             if (boot_params->limited_cce != 0) break;
2438174b66aSMatthias Ringwald 
2448174b66aSMatthias Ringwald             // firmware file
245*29c6772bSMatthias Ringwald             snprintf(fw_path, sizeof(fw_path), "%s/ibt-%u-%u.sfi", firmware_path, hw_variant, dev_revid);
246*29c6772bSMatthias Ringwald             log_info("Open firmware %s", fw_path);
247*29c6772bSMatthias Ringwald             printf("Firwmare %s\n", fw_path);
2488174b66aSMatthias Ringwald 
2498174b66aSMatthias Ringwald             // open firmware file
2508174b66aSMatthias Ringwald             fw_offset = 0;
251*29c6772bSMatthias Ringwald             fw_file = fopen(fw_path, "rb");
2528174b66aSMatthias Ringwald             if (!fw_file){
253*29c6772bSMatthias Ringwald                 log_error("can't open file %s", fw_path);
2548174b66aSMatthias Ringwald                 (*done)(1);
2558174b66aSMatthias Ringwald                 return;
2568174b66aSMatthias Ringwald             }
2578174b66aSMatthias Ringwald 
2588174b66aSMatthias Ringwald             vendor_firmware_complete_received = 0;
2598174b66aSMatthias Ringwald 
2608174b66aSMatthias Ringwald             // send CCS segment - offset 0
2618174b66aSMatthias Ringwald             intel_send_fragment(0x00, 128);
2628174b66aSMatthias Ringwald             break;
2638174b66aSMatthias Ringwald         case 4:
2648174b66aSMatthias Ringwald             // send public key / part 1 - offset 128
2658174b66aSMatthias Ringwald             intel_send_fragment(0x03, 128);
2668174b66aSMatthias Ringwald             break;
2678174b66aSMatthias Ringwald         case 5:
2688174b66aSMatthias Ringwald             // send public key / part 2 - offset 384
2698174b66aSMatthias Ringwald             intel_send_fragment(0x03, 128);
2708174b66aSMatthias Ringwald             break;
2718174b66aSMatthias Ringwald         case 6:
2728174b66aSMatthias Ringwald             // skip 4 bytes
2738174b66aSMatthias Ringwald             res = fread(fw_buffer, 1, 4, fw_file);
2748174b66aSMatthias Ringwald             log_info("read res %d", res);
2758174b66aSMatthias Ringwald             fw_offset += res;
2768174b66aSMatthias Ringwald 
2778174b66aSMatthias Ringwald             // send signature / part 1 - offset 388
2788174b66aSMatthias Ringwald             intel_send_fragment(0x02, 128);
2798174b66aSMatthias Ringwald             break;
2808174b66aSMatthias Ringwald         case 7:
2818174b66aSMatthias Ringwald             // send signature / part 2 - offset 516
2828174b66aSMatthias Ringwald             intel_send_fragment(0x02, 128);
2838174b66aSMatthias Ringwald             break;
2848174b66aSMatthias Ringwald         case 8:
2858174b66aSMatthias Ringwald             // send firmware chunks - offset 644
2868174b66aSMatthias Ringwald             // chunk len must be 4 byte aligned
2878174b66aSMatthias Ringwald             // multiple commands can be combined
2888174b66aSMatthias Ringwald             buffer_offset = 0;
2898174b66aSMatthias Ringwald             do {
2908174b66aSMatthias Ringwald                 res = fread(&fw_buffer[buffer_offset], 1, 3, fw_file);
2918174b66aSMatthias Ringwald                 log_info("fw_offset %6u, buffer_offset %u, read %3u -> res %d", fw_offset, buffer_offset, 3, res);
2928174b66aSMatthias Ringwald                 fw_offset += res;
2938174b66aSMatthias Ringwald                 if (res == 0 ){
2948174b66aSMatthias Ringwald                     // EOF
2958174b66aSMatthias Ringwald                     log_info("End of file");
2968174b66aSMatthias Ringwald                     fclose(fw_file);
2978174b66aSMatthias Ringwald                     fw_file = NULL;
2988174b66aSMatthias Ringwald                     state++;
2998174b66aSMatthias Ringwald                     break;
3008174b66aSMatthias Ringwald                 }
3018174b66aSMatthias Ringwald                 int param_len = fw_buffer[buffer_offset + 2];
3028174b66aSMatthias Ringwald                 buffer_offset += 3;
3038174b66aSMatthias Ringwald                 if (param_len){
3048174b66aSMatthias Ringwald                     res = fread(&fw_buffer[buffer_offset], 1, param_len, fw_file);
3058174b66aSMatthias Ringwald                     fw_offset     += res;
3068174b66aSMatthias Ringwald                     buffer_offset += res;
3078174b66aSMatthias Ringwald                 }
3088174b66aSMatthias Ringwald             } while ((buffer_offset & 3) != 0);
3098174b66aSMatthias Ringwald 
3108174b66aSMatthias Ringwald             if (buffer_offset == 0) break;
3118174b66aSMatthias Ringwald 
3128174b66aSMatthias Ringwald             waiting_for_command_complete = 1;
3138174b66aSMatthias Ringwald             transport_send_intel_secure(0x01, fw_buffer, buffer_offset);
3148174b66aSMatthias Ringwald             break;
3158174b66aSMatthias Ringwald 
3168174b66aSMatthias Ringwald         case 9:
3178174b66aSMatthias Ringwald             // expect Vendor Specific Event 0x06
3188174b66aSMatthias Ringwald             if (!vendor_firmware_complete_received) break;
3198174b66aSMatthias Ringwald 
3208174b66aSMatthias Ringwald             printf("Firmware upload complete\n");
3218174b66aSMatthias Ringwald             log_info("Vendor Event 0x06 - firmware complete");
3228174b66aSMatthias Ringwald 
3238174b66aSMatthias Ringwald             // Reset Params - constants from Windows Intel driver
3248174b66aSMatthias Ringwald             state++;
3258174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_reset_param, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x04, 0x00);
3268174b66aSMatthias Ringwald             break;
3278174b66aSMatthias Ringwald 
3288174b66aSMatthias Ringwald         case 10:
3298174b66aSMatthias Ringwald             // expect Vendor Specific Event 0x02
3308174b66aSMatthias Ringwald             if (packet[0] != 0xff) break;
3318174b66aSMatthias Ringwald             if (packet[2] != 0x02) break;
3328174b66aSMatthias Ringwald 
3338174b66aSMatthias Ringwald             printf("Firmware operational\n");
3348174b66aSMatthias Ringwald             log_info("Vendor Event 0x02 - firmware operational");
3358174b66aSMatthias Ringwald 
3368174b66aSMatthias Ringwald             // Read Intel Version
3378174b66aSMatthias Ringwald             state++;
3388174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_read_version);
3398174b66aSMatthias Ringwald             break;
3408174b66aSMatthias Ringwald 
3418174b66aSMatthias Ringwald         case 11:
3428174b66aSMatthias Ringwald             version = (intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
3438174b66aSMatthias Ringwald             dump_intel_version(version);
3448174b66aSMatthias Ringwald 
3458174b66aSMatthias Ringwald             // ddc config
346*29c6772bSMatthias Ringwald             snprintf(fw_path, sizeof(fw_path), "%s/ibt-%u-%u.ddc", firmware_path, hw_variant, dev_revid);
347*29c6772bSMatthias Ringwald             log_info("Open DDC %s", fw_path);
3488174b66aSMatthias Ringwald 
3498174b66aSMatthias Ringwald             // open ddc file
3508174b66aSMatthias Ringwald             fw_offset = 0;
351*29c6772bSMatthias Ringwald             fw_file = fopen(fw_path, "rb");
3528174b66aSMatthias Ringwald             if (!fw_file){
353*29c6772bSMatthias Ringwald                 log_error("can't open file %s", fw_path);
3548174b66aSMatthias Ringwald 
3558174b66aSMatthias Ringwald                 (*done)(1);
3568174b66aSMatthias Ringwald                 return;
3578174b66aSMatthias Ringwald             }
3588174b66aSMatthias Ringwald 
3598174b66aSMatthias Ringwald             // load ddc
3608174b66aSMatthias Ringwald             state++;
3618174b66aSMatthias Ringwald 
3628174b66aSMatthias Ringwald             /* fall through */
3638174b66aSMatthias Ringwald 
3648174b66aSMatthias Ringwald         case 12:
3658174b66aSMatthias Ringwald             res = intel_send_ddc();
3668174b66aSMatthias Ringwald             if (res == 0) break;
3678174b66aSMatthias Ringwald 
3688174b66aSMatthias Ringwald             // DDC download complete
3698174b66aSMatthias Ringwald             state++;
3708174b66aSMatthias Ringwald             log_info("Load DDC Complete");
3718174b66aSMatthias Ringwald 
3728174b66aSMatthias Ringwald 
3738174b66aSMatthias Ringwald             // Set Intel event mask 0xfc52
3748174b66aSMatthias Ringwald             state++;
3758174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_set_event_mask, 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
3768174b66aSMatthias Ringwald             break;
3778174b66aSMatthias Ringwald 
3788174b66aSMatthias Ringwald         case 13:
3798174b66aSMatthias Ringwald             // 9F FC 01 00
3808174b66aSMatthias Ringwald             state++;
3818174b66aSMatthias Ringwald             transport_send_cmd(&hci_intel_fc9f, 0x00);
3828174b66aSMatthias Ringwald             break;
3838174b66aSMatthias Ringwald 
3848174b66aSMatthias Ringwald         case 14:
3858174b66aSMatthias Ringwald             (*done)(0);
3868174b66aSMatthias Ringwald             break;
3878174b66aSMatthias Ringwald 
3888174b66aSMatthias Ringwald         default:
3898174b66aSMatthias Ringwald             break;
3908174b66aSMatthias Ringwald     }
3918174b66aSMatthias Ringwald }
3928174b66aSMatthias Ringwald 
3938174b66aSMatthias Ringwald static void transport_packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
3948174b66aSMatthias Ringwald     UNUSED(packet_type);
3958174b66aSMatthias Ringwald     // we also get events with packet_type ACL from the controller
3968174b66aSMatthias Ringwald     hci_dump_packet(HCI_EVENT_PACKET, 1, packet, size);
3978174b66aSMatthias Ringwald     switch (hci_event_packet_get_type(packet)){
3988174b66aSMatthias Ringwald         case HCI_EVENT_COMMAND_COMPLETE:
3998174b66aSMatthias Ringwald         case HCI_EVENT_VENDOR_SPECIFIC:
4008174b66aSMatthias Ringwald             state_machine(packet);
4018174b66aSMatthias Ringwald             break;
4028174b66aSMatthias Ringwald         default:
4038174b66aSMatthias Ringwald             break;
4048174b66aSMatthias Ringwald     }
4058174b66aSMatthias Ringwald }
4068174b66aSMatthias Ringwald 
407*29c6772bSMatthias Ringwald void btstack_chipset_intel_set_firmware_path(const char * path){
408*29c6772bSMatthias Ringwald     firmware_path = path;
409*29c6772bSMatthias Ringwald }
410*29c6772bSMatthias Ringwald 
4118174b66aSMatthias Ringwald void btstack_chipset_intel_download_firmware(const hci_transport_t * hci_transport, void (*callback)(int result)){
4128174b66aSMatthias Ringwald 
4138174b66aSMatthias Ringwald     done = callback;
4148174b66aSMatthias Ringwald 
4158174b66aSMatthias Ringwald 	transport = hci_transport;;
4168174b66aSMatthias Ringwald     // transport->init(NULL);
4178174b66aSMatthias Ringwald     transport->register_packet_handler(&transport_packet_handler);
4188174b66aSMatthias Ringwald     transport->open();
4198174b66aSMatthias Ringwald 
4208174b66aSMatthias Ringwald     // get started
4218174b66aSMatthias Ringwald     state = 0;
4228174b66aSMatthias Ringwald     state_machine(NULL);
4238174b66aSMatthias Ringwald }
424