mirror of
https://github.com/bluekitchen/btstack.git
synced 2025-03-25 16:43:28 +00:00
chipet/intel: support for firmware upload and configuration of Intel Wireless 8260 and 8265
This commit is contained in:
parent
507db03762
commit
8174b66a45
@ -84,6 +84,7 @@ Cypress CYW20704 | Dual mode | H4, H5, USB | Probably |
|
||||
Dialog Semiconductor DA14581, DA14585 | LE | H4, SPI | n.a. | da14581 | Official HCI firmware used
|
||||
Espressif ESP32 | Dual mode | VHCI | Not yet | | SoC with Bluetooth and Wifi
|
||||
EM 9301, 9304 | LE | SPI | n.a. | em9301 | Custom HCI SPI implementation
|
||||
Intel Dual Wireless 8260, 8265 | Dual mode | USB | Probably | intel |
|
||||
Nordic nRF | LE | H4 | n.a. | | Requires custom HCI firmware
|
||||
STM STLC2500D | Classic | H4 | No (didn't try) | stlc2500d | Custom deep sleep management not supported
|
||||
Toshiba TC35661 | Dual mode | H4 | No | tc3566 |
|
||||
|
@ -64,6 +64,7 @@ Dialog DA14585 | LE | H4, SPI | No | n.a.
|
||||
Espressif ESP32 | Dual mode | VHCI | Yes | Not yet | Yes | Yes | | SoC with Bluetooth and Wifi
|
||||
EM 9301 | LE | SPI, H4 | No | n.a. | No | No | em9301 | Custom HCI SPI implementation
|
||||
EM 9304 | LE | SPI, H4 | Yes | n.a. | Yes | Yes | em9301 | Custom HCI SPI implementation
|
||||
Intel Dual Wireless 8260, 8265 | Dual mode | USB | Yes | Probably | Don't know | Don't know | intel |
|
||||
Nordic nRF | LE | H4 | Fixed Random | n.a. | Yes | Yes | | Requires HCI firmware
|
||||
STM STLC2500D | Classic | H4 | No | No (didn't try) | n.a | n.a. | stlc2500d | Custom deep sleep management not supported
|
||||
Toshiba TC35661 | Dual mode | H4 | No | No | No | No | tc3566 | Only -007/009 models provide full HCI. See below
|
||||
@ -173,6 +174,10 @@ EM9304 is used by the 'stm32-l053r8-em9304' port in BTstack. The port.c file als
|
||||
|
||||
**BTstack integration**: The common code for the EM9304 is provided by *btstack_chipset_em9301.c*. During the setup, *btstack_chipset_em9301_instance* function is used to get a *btstack_chipset_t* instance and passed to *hci_init* function. It enables to set the BD Addr during start.
|
||||
|
||||
## Intel Dual Wireless 8260, 8265
|
||||
|
||||
Wifi/Bluetooth combo cards mainly used in mobile computers. The Bluetooth part requires the upload of a firmware file and a configuration file. SCO, DLE, Multiple roles not tested.
|
||||
|
||||
## Nordic nRF5 series
|
||||
|
||||
The Single-Mode LE chipsets from the Nordic nRF5 series chipsets usually do not have an HCI interface. Instead, they provide an LE Bluetooth Stack as a binary library, the so-called *SoftDevices*. Developer can write their Bluetooth application on top of this library. Since the chipset can be programmed, it can also be loaded with a firmware that provides a regular HCI H4 interface for a Host.
|
||||
|
2
chipset/intel/.gitignore
vendored
Normal file
2
chipset/intel/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
*.ddc
|
||||
*.sfi
|
28
chipset/intel/Makefile.inc
Normal file
28
chipset/intel/Makefile.inc
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Makefile to download firmware and config files for Intel Wireless chipsets from Linux firmware tree
|
||||
#
|
||||
# Supported:
|
||||
# - Intel Wireless 8260
|
||||
# - Intel Wireless 8265
|
||||
|
||||
LINUX_FIRMWARE_URL = https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/
|
||||
|
||||
FILES = \
|
||||
ibt-11-5.ddc \
|
||||
ibt-11-5.sfi \
|
||||
ibt-12-16.ddc \
|
||||
ibt-12-16.sfi
|
||||
|
||||
all: $(FILES)
|
||||
|
||||
%.sfi:
|
||||
@echo "Downloading %@"
|
||||
@curl -O -L $(LINUX_FIRMWARE_URL)/intel/$@
|
||||
|
||||
%.ddc:
|
||||
@echo "Downloading %@"
|
||||
@curl -O -L $(LINUX_FIRMWARE_URL)/intel/$@
|
||||
|
||||
clean:
|
||||
rm -f $(FILES)
|
||||
|
417
chipset/intel/btstack_chipset_intel_firmware.c
Normal file
417
chipset/intel/btstack_chipset_intel_firmware.c
Normal file
@ -0,0 +1,417 @@
|
||||
#define __BTSTACK_FILE__ "btstack_chipset_intel_firmware.c"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "btstack_chipset_intel_firmware.h"
|
||||
#include "hci_cmd.h"
|
||||
#include "bluetooth.h"
|
||||
#include "hci_dump.h"
|
||||
#include "btstack_event.h"
|
||||
#include "btstack_debug.h"
|
||||
#include "btstack_util.h"
|
||||
#include "btstack_run_loop.h"
|
||||
|
||||
// Vendor specific structs
|
||||
|
||||
typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t hw_platform;
|
||||
uint8_t hw_variant;
|
||||
uint8_t hw_revision;
|
||||
uint8_t fw_variant;
|
||||
uint8_t fw_revision;
|
||||
uint8_t fw_build_num;
|
||||
uint8_t fw_build_ww;
|
||||
uint8_t fw_build_yy;
|
||||
uint8_t fw_patch_num;
|
||||
} intel_version_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t status;
|
||||
uint8_t otp_format;
|
||||
uint8_t otp_content;
|
||||
uint8_t otp_patch;
|
||||
uint16_t dev_revid;
|
||||
uint8_t secure_boot;
|
||||
uint8_t key_from_hdr;
|
||||
uint8_t key_type;
|
||||
uint8_t otp_lock;
|
||||
uint8_t api_lock;
|
||||
uint8_t debug_lock;
|
||||
bd_addr_t otp_bdaddr;
|
||||
uint8_t min_fw_build_nn;
|
||||
uint8_t min_fw_build_cw;
|
||||
uint8_t min_fw_build_yy;
|
||||
uint8_t limited_cce;
|
||||
uint8_t unlocked_state;
|
||||
} intel_boot_params_t;
|
||||
|
||||
// Vendor sepcific commands
|
||||
|
||||
static const hci_cmd_t hci_intel_read_version = {
|
||||
0xfc05, ""
|
||||
};
|
||||
static const hci_cmd_t hci_intel_read_secure_boot_params = {
|
||||
0xfc0d, ""
|
||||
};
|
||||
|
||||
static const hci_cmd_t hci_intel_reset_param = {
|
||||
0xfc01, "11111111"
|
||||
};
|
||||
|
||||
static const hci_cmd_t hci_intel_set_event_mask = {
|
||||
0xfc52, "11111111"
|
||||
};
|
||||
|
||||
static const hci_cmd_t hci_intel_fc9f = {
|
||||
0xfc9f, "1"
|
||||
};
|
||||
|
||||
// state
|
||||
|
||||
const hci_transport_t * transport;
|
||||
|
||||
static int state = 0;
|
||||
|
||||
static uint8_t hci_outgoing[300];
|
||||
static uint8_t fw_buffer[300];
|
||||
|
||||
static uint8_t hw_variant;
|
||||
static uint16_t dev_revid;
|
||||
|
||||
static FILE * fw_file;
|
||||
static uint32_t fw_offset;
|
||||
|
||||
static void (*done)(int result);
|
||||
|
||||
// functions
|
||||
|
||||
static int transport_send_packet(uint8_t packet_type, const uint8_t * packet, uint16_t size){
|
||||
hci_dump_packet(HCI_COMMAND_DATA_PACKET, 0, (uint8_t*) packet, size);
|
||||
return transport->send_packet(packet_type, (uint8_t *) packet, size);
|
||||
}
|
||||
|
||||
static int transport_send_cmd_va_arg(const hci_cmd_t *cmd, va_list argptr){
|
||||
uint8_t * packet = hci_outgoing;
|
||||
uint16_t size = hci_cmd_create_from_template(packet, cmd, argptr);
|
||||
return transport_send_packet(HCI_COMMAND_DATA_PACKET, packet, size);
|
||||
}
|
||||
|
||||
static int transport_send_cmd(const hci_cmd_t *cmd, ...){
|
||||
va_list argptr;
|
||||
va_start(argptr, cmd);
|
||||
int res = transport_send_cmd_va_arg(cmd, argptr);
|
||||
va_end(argptr);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int transport_send_intel_secure(uint8_t fragment_type, const uint8_t * data, uint16_t len){
|
||||
little_endian_store_16(hci_outgoing, 0, 0xfc09);
|
||||
hci_outgoing[2] = 1 + len;
|
||||
hci_outgoing[3] = fragment_type;
|
||||
memcpy(&hci_outgoing[4], data, len);
|
||||
uint16_t size = 3 + 1 + len;
|
||||
return transport_send_packet(HCI_ACL_DATA_PACKET, hci_outgoing, size);
|
||||
}
|
||||
|
||||
static int transport_send_intel_ddc(const uint8_t * data, uint16_t len){
|
||||
little_endian_store_16(hci_outgoing, 0, 0xfc8b);
|
||||
hci_outgoing[2] = len;
|
||||
memcpy(&hci_outgoing[3], data, len);
|
||||
uint16_t size = 3 + len;
|
||||
return transport_send_packet(HCI_COMMAND_DATA_PACKET, hci_outgoing, size);
|
||||
}
|
||||
|
||||
static void state_machine(uint8_t * packet);
|
||||
|
||||
// read data from fw file and send it via intel_secure + update state
|
||||
static int intel_send_fragment(uint8_t fragment_type, uint16_t len){
|
||||
int res = fread(fw_buffer, 1, len, fw_file);
|
||||
log_info("offset %6u, read %3u -> res %d", fw_offset, len, res);
|
||||
fw_offset += res;
|
||||
state++;
|
||||
return transport_send_intel_secure(fragment_type, fw_buffer, len);
|
||||
}
|
||||
|
||||
// read data from ddc file and send iva intel ddc command
|
||||
// @returns -1 on eof
|
||||
static int intel_send_ddc(void){
|
||||
int res;
|
||||
// read len
|
||||
res = fread(fw_buffer, 1, 1, fw_file);
|
||||
log_info("offset %6u, read 1 -> res %d", fw_offset, res);
|
||||
if (res == 0) return -1;
|
||||
uint8_t len = fw_buffer[0];
|
||||
fw_offset += 1;
|
||||
res = fread(&fw_buffer[1], 1, len, fw_file);
|
||||
log_info("offset %6u, read %u -> res %d", fw_offset, 1, res);
|
||||
return transport_send_intel_ddc(fw_buffer, 1 + len);
|
||||
}
|
||||
|
||||
static void dump_intel_version(intel_version_t * version){
|
||||
log_info("status 0x%02x", version->status);
|
||||
log_info("hw_platform 0x%02x", version->hw_platform);
|
||||
log_info("hw_variant 0x%02x", version->hw_variant);
|
||||
log_info("hw_revision 0x%02x", version->hw_revision);
|
||||
log_info("fw_variant 0x%02x", version->fw_variant);
|
||||
log_info("fw_revision 0x%02x", version->fw_revision);
|
||||
log_info("fw_build_num 0x%02x", version->fw_build_num);
|
||||
log_info("fw_build_ww 0x%02x", version->fw_build_ww);
|
||||
log_info("fw_build_yy 0x%02x", version->fw_build_yy);
|
||||
log_info("fw_patch_num 0x%02x", version->fw_patch_num);
|
||||
}
|
||||
|
||||
static void dump_intel_boot_params(intel_boot_params_t * boot_params){
|
||||
bd_addr_t addr;
|
||||
reverse_bd_addr(boot_params->otp_bdaddr, addr);
|
||||
log_info("Device revision: %u", dev_revid);
|
||||
log_info("Secure Boot: %s", boot_params->secure_boot ? "enabled" : "disabled");
|
||||
log_info("OTP lock: %s", boot_params->otp_lock ? "enabled" : "disabled");
|
||||
log_info("API lock: %s", boot_params->api_lock ? "enabled" : "disabled");
|
||||
log_info("Debug lock: %s", boot_params->debug_lock ? "enabled" : "disabled");
|
||||
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);
|
||||
log_info("OTC BD_ADDR: %s", bd_addr_to_str(addr));
|
||||
}
|
||||
|
||||
static int vendor_firmware_complete_received;
|
||||
static int waiting_for_command_complete;
|
||||
|
||||
static void state_machine(uint8_t * packet){
|
||||
intel_version_t * version;
|
||||
intel_boot_params_t * boot_params;
|
||||
char fw_name[30];
|
||||
int res;
|
||||
uint16_t buffer_offset;
|
||||
bd_addr_t addr;
|
||||
|
||||
if (packet){
|
||||
// firmware upload complete event?
|
||||
if (packet[0] == 0xff && packet[2] == 0x06) {
|
||||
vendor_firmware_complete_received = 1;
|
||||
}
|
||||
|
||||
// command complete
|
||||
if (packet[0] == 0x0e){
|
||||
waiting_for_command_complete = 0;
|
||||
}
|
||||
}
|
||||
|
||||
switch (state){
|
||||
case 0:
|
||||
state++;
|
||||
transport_send_cmd(&hci_reset);
|
||||
break;
|
||||
case 1:
|
||||
// Read Intel Version
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_read_version);
|
||||
break;
|
||||
case 2:
|
||||
version = (intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
|
||||
dump_intel_version(version);
|
||||
|
||||
hw_variant = version->hw_variant;
|
||||
|
||||
// fw_variant = 0x06 bootloader mode / 0x23 operational mode
|
||||
if (version->fw_variant == 0x23) {
|
||||
(*done)(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (version->fw_variant != 0x06){
|
||||
log_error("unknown fw_variant 0x%02x", version->fw_variant);
|
||||
break;
|
||||
}
|
||||
|
||||
// Read Intel Secure Boot Params
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_read_secure_boot_params);
|
||||
break;
|
||||
case 3:
|
||||
boot_params = (intel_boot_params_t *) hci_event_command_complete_get_return_parameters(packet);
|
||||
dump_intel_boot_params(boot_params);
|
||||
|
||||
reverse_bd_addr(boot_params->otp_bdaddr, addr);
|
||||
dev_revid = little_endian_read_16((uint8_t*)&boot_params->dev_revid, 0);
|
||||
|
||||
// assert commmand complete is required
|
||||
if (boot_params->limited_cce != 0) break;
|
||||
|
||||
// firmware file
|
||||
snprintf(fw_name, sizeof(fw_name), "ibt-%u-%u.sfi", hw_variant, dev_revid);
|
||||
log_info("Open firmware %s", fw_name);
|
||||
printf("Firwmare %s\n", fw_name);
|
||||
|
||||
// open firmware file
|
||||
fw_offset = 0;
|
||||
fw_file = fopen(fw_name, "rb");
|
||||
if (!fw_file){
|
||||
log_error("can't open file %s", fw_name);
|
||||
(*done)(1);
|
||||
return;
|
||||
}
|
||||
|
||||
vendor_firmware_complete_received = 0;
|
||||
|
||||
// send CCS segment - offset 0
|
||||
intel_send_fragment(0x00, 128);
|
||||
break;
|
||||
case 4:
|
||||
// send public key / part 1 - offset 128
|
||||
intel_send_fragment(0x03, 128);
|
||||
break;
|
||||
case 5:
|
||||
// send public key / part 2 - offset 384
|
||||
intel_send_fragment(0x03, 128);
|
||||
break;
|
||||
case 6:
|
||||
// skip 4 bytes
|
||||
res = fread(fw_buffer, 1, 4, fw_file);
|
||||
log_info("read res %d", res);
|
||||
fw_offset += res;
|
||||
|
||||
// send signature / part 1 - offset 388
|
||||
intel_send_fragment(0x02, 128);
|
||||
break;
|
||||
case 7:
|
||||
// send signature / part 2 - offset 516
|
||||
intel_send_fragment(0x02, 128);
|
||||
break;
|
||||
case 8:
|
||||
// send firmware chunks - offset 644
|
||||
// chunk len must be 4 byte aligned
|
||||
// multiple commands can be combined
|
||||
buffer_offset = 0;
|
||||
do {
|
||||
res = fread(&fw_buffer[buffer_offset], 1, 3, fw_file);
|
||||
log_info("fw_offset %6u, buffer_offset %u, read %3u -> res %d", fw_offset, buffer_offset, 3, res);
|
||||
fw_offset += res;
|
||||
if (res == 0 ){
|
||||
// EOF
|
||||
log_info("End of file");
|
||||
fclose(fw_file);
|
||||
fw_file = NULL;
|
||||
state++;
|
||||
break;
|
||||
}
|
||||
int param_len = fw_buffer[buffer_offset + 2];
|
||||
buffer_offset += 3;
|
||||
if (param_len){
|
||||
res = fread(&fw_buffer[buffer_offset], 1, param_len, fw_file);
|
||||
fw_offset += res;
|
||||
buffer_offset += res;
|
||||
}
|
||||
} while ((buffer_offset & 3) != 0);
|
||||
|
||||
if (buffer_offset == 0) break;
|
||||
|
||||
waiting_for_command_complete = 1;
|
||||
transport_send_intel_secure(0x01, fw_buffer, buffer_offset);
|
||||
break;
|
||||
|
||||
case 9:
|
||||
// expect Vendor Specific Event 0x06
|
||||
if (!vendor_firmware_complete_received) break;
|
||||
|
||||
printf("Firmware upload complete\n");
|
||||
log_info("Vendor Event 0x06 - firmware complete");
|
||||
|
||||
// Reset Params - constants from Windows Intel driver
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_reset_param, 0x00, 0x00, 0x00, 0x01, 0x00, 0x08, 0x04, 0x00);
|
||||
break;
|
||||
|
||||
case 10:
|
||||
// expect Vendor Specific Event 0x02
|
||||
if (packet[0] != 0xff) break;
|
||||
if (packet[2] != 0x02) break;
|
||||
|
||||
printf("Firmware operational\n");
|
||||
log_info("Vendor Event 0x02 - firmware operational");
|
||||
|
||||
// Read Intel Version
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_read_version);
|
||||
break;
|
||||
|
||||
case 11:
|
||||
version = (intel_version_t*) hci_event_command_complete_get_return_parameters(packet);
|
||||
dump_intel_version(version);
|
||||
|
||||
// ddc config
|
||||
snprintf(fw_name, sizeof(fw_name), "ibt-%u-%u.ddc", hw_variant, dev_revid);
|
||||
log_info("Open DDC %s", fw_name);
|
||||
|
||||
// open ddc file
|
||||
fw_offset = 0;
|
||||
fw_file = fopen(fw_name, "rb");
|
||||
if (!fw_file){
|
||||
log_error("can't open file %s", fw_name);
|
||||
|
||||
(*done)(1);
|
||||
return;
|
||||
}
|
||||
|
||||
// load ddc
|
||||
state++;
|
||||
|
||||
/* fall through */
|
||||
|
||||
case 12:
|
||||
res = intel_send_ddc();
|
||||
if (res == 0) break;
|
||||
|
||||
// DDC download complete
|
||||
state++;
|
||||
log_info("Load DDC Complete");
|
||||
|
||||
|
||||
// Set Intel event mask 0xfc52
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_set_event_mask, 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00);
|
||||
break;
|
||||
|
||||
case 13:
|
||||
// 9F FC 01 00
|
||||
state++;
|
||||
transport_send_cmd(&hci_intel_fc9f, 0x00);
|
||||
break;
|
||||
|
||||
case 14:
|
||||
(*done)(0);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void transport_packet_handler (uint8_t packet_type, uint8_t *packet, uint16_t size){
|
||||
UNUSED(packet_type);
|
||||
// we also get events with packet_type ACL from the controller
|
||||
hci_dump_packet(HCI_EVENT_PACKET, 1, packet, size);
|
||||
switch (hci_event_packet_get_type(packet)){
|
||||
case HCI_EVENT_COMMAND_COMPLETE:
|
||||
case HCI_EVENT_VENDOR_SPECIFIC:
|
||||
state_machine(packet);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void btstack_chipset_intel_download_firmware(const hci_transport_t * hci_transport, void (*callback)(int result)){
|
||||
|
||||
done = callback;
|
||||
|
||||
transport = hci_transport;;
|
||||
// transport->init(NULL);
|
||||
transport->register_packet_handler(&transport_packet_handler);
|
||||
transport->open();
|
||||
|
||||
// get started
|
||||
state = 0;
|
||||
state_machine(NULL);
|
||||
}
|
65
chipset/intel/btstack_chipset_intel_firmware.h
Normal file
65
chipset/intel/btstack_chipset_intel_firmware.h
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2018 BlueKitchen GmbH
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
* 4. Any redistribution, use, or modification is done solely for
|
||||
* personal benefit and not for any commercial purpose or for
|
||||
* monetary gain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY BLUEKITCHEN GMBH AND CONTRIBUTORS
|
||||
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
|
||||
* RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
|
||||
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* Please inquire about commercial licensing options at
|
||||
* contact@bluekitchen-gmbh.com
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* btstack_chipset_intel_firmware.c
|
||||
*
|
||||
* Adapter to use Intel-based chipsets with BTstack
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __BTSTACK_CHIPSET_INTEL_FIRMWARE_H
|
||||
#define __BTSTACK_CHIPSET_INTEL_FIRMWARE_H
|
||||
|
||||
#include "hci_transport.h"
|
||||
|
||||
#if defined __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Download firmware via hci_transport
|
||||
* @param transport
|
||||
* @param done callback. 0 = Success
|
||||
*/
|
||||
void btstack_chipset_intel_download_firmware(const hci_transport_t * hci_transport, void (*done)(int result));
|
||||
|
||||
#if defined __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user