iwmbtfw(8): Add support for Intel 7260/7265 bluetooth adapter firmwares
To use it comms/iwmbt-firmware port should be updated to 20210315 version. Submitted by: Philippe Michaud-Boudreault <pitwuu@gmail.com> Tested by: Helge Oldach <freebsd@oldach.net> Reviewed by: wulf PR: 228787 MFC after: 2 weeks
This commit is contained in:
parent
15c0aaf517
commit
fe70d7b26d
@ -119,6 +119,20 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
|
|||||||
char *fwname;
|
char *fwname;
|
||||||
|
|
||||||
switch (ver->hw_variant) {
|
switch (ver->hw_variant) {
|
||||||
|
case 0x07: /* 7260 */
|
||||||
|
asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s",
|
||||||
|
prefix,
|
||||||
|
le16toh(ver->hw_platform),
|
||||||
|
le16toh(ver->hw_variant),
|
||||||
|
le16toh(ver->hw_revision),
|
||||||
|
le16toh(ver->fw_variant),
|
||||||
|
le16toh(ver->fw_revision),
|
||||||
|
le16toh(ver->fw_build_num),
|
||||||
|
le16toh(ver->fw_build_ww),
|
||||||
|
le16toh(ver->fw_build_yy),
|
||||||
|
suffix);
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x0b: /* 8260 */
|
case 0x0b: /* 8260 */
|
||||||
case 0x0c: /* 8265 */
|
case 0x0c: /* 8265 */
|
||||||
asprintf(&fwname, "%s/ibt-%u-%u.%s",
|
asprintf(&fwname, "%s/ibt-%u-%u.%s",
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
* $FreeBSD$
|
* $FreeBSD$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/param.h>
|
||||||
#include <sys/endian.h>
|
#include <sys/endian.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@ -126,6 +126,125 @@ iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd,
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
|
||||||
|
const struct iwmbt_firmware *fw)
|
||||||
|
{
|
||||||
|
int ret, transferred;
|
||||||
|
struct iwmbt_firmware fw_job = *fw;
|
||||||
|
uint16_t cmd_opcode;
|
||||||
|
uint8_t cmd_length;
|
||||||
|
uint8_t cmd_buf[IWMBT_HCI_MAX_CMD_SIZE];
|
||||||
|
uint8_t evt_code;
|
||||||
|
uint8_t evt_length;
|
||||||
|
uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE];
|
||||||
|
int skip_patch = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
skip_patch = 0;
|
||||||
|
|
||||||
|
if (fw_job.len < 4)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fw_job.buf[0] != 0x01) {
|
||||||
|
iwmbt_err("Invalid firmware, expected HCI command (%d)",
|
||||||
|
fw_job.buf[0]);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Advance by one. */
|
||||||
|
fw_job.buf++;
|
||||||
|
fw_job.len--;
|
||||||
|
|
||||||
|
/* Load in the HCI command to perform. */
|
||||||
|
cmd_opcode = le16dec(fw_job.buf);
|
||||||
|
cmd_length = fw_job.buf[2];
|
||||||
|
memcpy(cmd_buf, fw_job.buf, 3);
|
||||||
|
|
||||||
|
iwmbt_debug("opcode=%04x, len=%02x", cmd_opcode, cmd_length);
|
||||||
|
|
||||||
|
/* For some reason the command 0xfc2f hangs up my card. */
|
||||||
|
if (cmd_opcode == 0xfc2f)
|
||||||
|
skip_patch = 1;
|
||||||
|
|
||||||
|
/* Advance by three. */
|
||||||
|
fw_job.buf += 3;
|
||||||
|
fw_job.len -= 3;
|
||||||
|
|
||||||
|
if (fw_job.len < cmd_length)
|
||||||
|
cmd_length = fw_job.len;
|
||||||
|
|
||||||
|
/* Copy data to HCI command buffer. */
|
||||||
|
memcpy(cmd_buf + 3, fw_job.buf,
|
||||||
|
MIN(cmd_length, IWMBT_HCI_MAX_CMD_SIZE - 3));
|
||||||
|
|
||||||
|
/* Advance by data length. */
|
||||||
|
fw_job.buf += cmd_length;
|
||||||
|
fw_job.len -= cmd_length;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Every command has its associated event: data must match
|
||||||
|
* what is recorded in the firmware file. Perform that check
|
||||||
|
* now.
|
||||||
|
*
|
||||||
|
* Some commands are mapped to more than one event sequence,
|
||||||
|
* in that case we can drop the non-patch commands, as we
|
||||||
|
* probably don't need them for operation of the card.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* Is this the end of the file? */
|
||||||
|
if (fw_job.len < 3)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (fw_job.buf[0] != 0x02)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Advance by one. */
|
||||||
|
fw_job.buf++;
|
||||||
|
fw_job.len--;
|
||||||
|
|
||||||
|
/* Load in the HCI event. */
|
||||||
|
evt_code = fw_job.buf[0];
|
||||||
|
evt_length = fw_job.buf[1];
|
||||||
|
|
||||||
|
/* Advance by two. */
|
||||||
|
fw_job.buf += 2;
|
||||||
|
fw_job.len -= 2;
|
||||||
|
|
||||||
|
/* Prepare HCI event buffer. */
|
||||||
|
memset(evt_buf, 0, IWMBT_HCI_MAX_EVENT_SIZE);
|
||||||
|
|
||||||
|
iwmbt_debug("event=%04x, len=%02x",
|
||||||
|
evt_code, evt_length);
|
||||||
|
|
||||||
|
/* Advance by data length. */
|
||||||
|
fw_job.buf += evt_length;
|
||||||
|
fw_job.len -= evt_length;
|
||||||
|
|
||||||
|
if (skip_patch == 0) {
|
||||||
|
ret = iwmbt_hci_command(hdl,
|
||||||
|
(struct iwmbt_hci_cmd *)cmd_buf,
|
||||||
|
evt_buf,
|
||||||
|
IWMBT_HCI_MAX_EVENT_SIZE,
|
||||||
|
&transferred,
|
||||||
|
IWMBT_HCI_CMD_TIMEOUT);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
iwmbt_debug("Can't send patch: "
|
||||||
|
"code=%d, size=%d",
|
||||||
|
ret,
|
||||||
|
transferred);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
iwmbt_load_fwfile(struct libusb_device_handle *hdl,
|
iwmbt_load_fwfile(struct libusb_device_handle *hdl,
|
||||||
const struct iwmbt_firmware *fw, uint32_t *boot_param)
|
const struct iwmbt_firmware *fw, uint32_t *boot_param)
|
||||||
@ -217,6 +336,74 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iwmbt_enter_manufacturer(struct libusb_device_handle *hdl)
|
||||||
|
{
|
||||||
|
int ret, transferred;
|
||||||
|
static struct iwmbt_hci_cmd cmd = {
|
||||||
|
.opcode = htole16(0xfc11),
|
||||||
|
.length = 2,
|
||||||
|
.data = { 0x01, 0x00 },
|
||||||
|
};
|
||||||
|
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
|
||||||
|
|
||||||
|
ret = iwmbt_hci_command(hdl,
|
||||||
|
&cmd,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
&transferred,
|
||||||
|
IWMBT_HCI_CMD_TIMEOUT);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
iwmbt_debug("Can't enter manufacturer mode: code=%d, size=%d",
|
||||||
|
ret,
|
||||||
|
transferred);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iwmbt_exit_manufacturer(struct libusb_device_handle *hdl, int mode)
|
||||||
|
{
|
||||||
|
int ret, transferred;
|
||||||
|
static struct iwmbt_hci_cmd cmd = {
|
||||||
|
.opcode = htole16(0xfc11),
|
||||||
|
.length = 2,
|
||||||
|
.data = { 0x00, 0x00 },
|
||||||
|
};
|
||||||
|
uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The mode sets the type of reset we want to perform:
|
||||||
|
* 0x00: simply exit manufacturer mode without a reset.
|
||||||
|
* 0x01: exit manufacturer mode with a reset and patches disabled
|
||||||
|
* 0x02: exit manufacturer mode with a reset and patches enabled
|
||||||
|
*/
|
||||||
|
if (mode > 2) {
|
||||||
|
iwmbt_debug("iwmbt_exit_manufacturer(): unknown mode (%d)",
|
||||||
|
mode);
|
||||||
|
}
|
||||||
|
cmd.data[1] = mode;
|
||||||
|
|
||||||
|
ret = iwmbt_hci_command(hdl,
|
||||||
|
&cmd,
|
||||||
|
buf,
|
||||||
|
sizeof(buf),
|
||||||
|
&transferred,
|
||||||
|
IWMBT_HCI_CMD_TIMEOUT);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
iwmbt_debug("Can't exit manufacturer mode: code=%d, size=%d",
|
||||||
|
ret,
|
||||||
|
transferred);
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
iwmbt_get_version(struct libusb_device_handle *hdl,
|
iwmbt_get_version(struct libusb_device_handle *hdl,
|
||||||
struct iwmbt_version *version)
|
struct iwmbt_version *version)
|
||||||
|
@ -73,8 +73,13 @@ struct iwmbt_hci_event_cmd_compl {
|
|||||||
#define IWMBT_HCI_CMD_TIMEOUT 2000 /* ms */
|
#define IWMBT_HCI_CMD_TIMEOUT 2000 /* ms */
|
||||||
#define IWMBT_LOADCMPL_TIMEOUT 5000 /* ms */
|
#define IWMBT_LOADCMPL_TIMEOUT 5000 /* ms */
|
||||||
|
|
||||||
|
extern int iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
|
||||||
|
const struct iwmbt_firmware *fw);
|
||||||
extern int iwmbt_load_fwfile(struct libusb_device_handle *hdl,
|
extern int iwmbt_load_fwfile(struct libusb_device_handle *hdl,
|
||||||
const struct iwmbt_firmware *fw, uint32_t *boot_param);
|
const struct iwmbt_firmware *fw, uint32_t *boot_param);
|
||||||
|
extern int iwmbt_enter_manufacturer(struct libusb_device_handle *hdl);
|
||||||
|
extern int iwmbt_exit_manufacturer(struct libusb_device_handle *hdl,
|
||||||
|
int mode);
|
||||||
extern int iwmbt_get_version(struct libusb_device_handle *hdl,
|
extern int iwmbt_get_version(struct libusb_device_handle *hdl,
|
||||||
struct iwmbt_version *version);
|
struct iwmbt_version *version);
|
||||||
extern int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
|
extern int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
.\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@freebsd.org>
|
.\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@freebsd.org>
|
||||||
.\" Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
|
.\" Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
|
||||||
|
.\" Copyright (c) 2021 Philippe Michaud-Boudreault <pitwuu@gmail.com>
|
||||||
.\"
|
.\"
|
||||||
.\" Redistribution and use in source and binary forms, with or without
|
.\" Redistribution and use in source and binary forms, with or without
|
||||||
.\" modification, are permitted provided that the following conditions
|
.\" modification, are permitted provided that the following conditions
|
||||||
@ -24,12 +25,12 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd June 4, 2019
|
.Dd May 3, 2021
|
||||||
.Dt IWMBTFW 8
|
.Dt IWMBTFW 8
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm iwmbtfw
|
.Nm iwmbtfw
|
||||||
.Nd firmware download utility for Intel Wireless 8260/8265 chip based Bluetooth
|
.Nd firmware download utility for Intel Wireless 7260/8260/8265 chip based Bluetooth
|
||||||
USB devices
|
USB devices
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm
|
.Nm
|
||||||
@ -46,7 +47,7 @@ device.
|
|||||||
.Pp
|
.Pp
|
||||||
This utility will
|
This utility will
|
||||||
.Em only
|
.Em only
|
||||||
work with Intel Wireless 8260/8265 chip based Bluetooth USB devices and some of
|
work with Intel Wireless 7260/8260/8265 chip based Bluetooth USB devices and some of
|
||||||
their successors.
|
their successors.
|
||||||
The identification is currently based on USB vendor ID/product ID pair.
|
The identification is currently based on USB vendor ID/product ID pair.
|
||||||
The vendor ID should be 0x8087
|
The vendor ID should be 0x8087
|
||||||
@ -91,6 +92,9 @@ utility used as firmware downloader template and on Linux btintel driver
|
|||||||
source code.
|
source code.
|
||||||
It is written by
|
It is written by
|
||||||
.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
|
.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
|
||||||
|
.Pp
|
||||||
|
Support for the 7260 card added by
|
||||||
|
.An Philippe Michaud-Boudreault Aq Mt pitwuu@gmail.com .
|
||||||
.Sh BUGS
|
.Sh BUGS
|
||||||
Most likely.
|
Most likely.
|
||||||
Please report if found.
|
Please report if found.
|
||||||
|
@ -7,6 +7,6 @@ notify 100 {
|
|||||||
match "subsystem" "DEVICE";
|
match "subsystem" "DEVICE";
|
||||||
match "type" "ATTACH";
|
match "type" "ATTACH";
|
||||||
match "vendor" "0x8087";
|
match "vendor" "0x8087";
|
||||||
match "product" "(0x0a2b|0x0aaa|0x0025|0x0026|0x0029)";
|
match "product" "(0x07dc|0x0a2a|0x0aa7|0x0a2b|0x0aaa|0x0025|0x0026|0x0029)";
|
||||||
action "/usr/sbin/iwmbtfw -d $cdev -f /usr/local/share/iwmbt-firmware";
|
action "/usr/sbin/iwmbtfw -d $cdev -f /usr/local/share/iwmbt-firmware";
|
||||||
};
|
};
|
||||||
|
@ -57,7 +57,15 @@ struct iwmbt_devid {
|
|||||||
uint16_t vendor_id;
|
uint16_t vendor_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct iwmbt_devid iwmbt_list[] = {
|
static struct iwmbt_devid iwmbt_list_72xx[] = {
|
||||||
|
|
||||||
|
/* Intel Wireless 7260/7265 and successors */
|
||||||
|
{ .vendor_id = 0x8087, .product_id = 0x07dc },
|
||||||
|
{ .vendor_id = 0x8087, .product_id = 0x0a2a },
|
||||||
|
{ .vendor_id = 0x8087, .product_id = 0x0aa7 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct iwmbt_devid iwmbt_list_82xx[] = {
|
||||||
|
|
||||||
/* Intel Wireless 8260/8265 and successors */
|
/* Intel Wireless 8260/8265 and successors */
|
||||||
{ .vendor_id = 0x8087, .product_id = 0x0a2b },
|
{ .vendor_id = 0x8087, .product_id = 0x0a2b },
|
||||||
@ -67,15 +75,33 @@ static struct iwmbt_devid iwmbt_list[] = {
|
|||||||
{ .vendor_id = 0x8087, .product_id = 0x0029 },
|
{ .vendor_id = 0x8087, .product_id = 0x0029 },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
iwmbt_is_7260(struct libusb_device_descriptor *d)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Search looking for whether it's an 7260/7265 */
|
||||||
|
for (i = 0; i < (int) nitems(iwmbt_list_72xx); i++) {
|
||||||
|
if ((iwmbt_list_72xx[i].product_id == d->idProduct) &&
|
||||||
|
(iwmbt_list_72xx[i].vendor_id == d->idVendor)) {
|
||||||
|
iwmbt_info("found 7260/7265");
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Not found */
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iwmbt_is_8260(struct libusb_device_descriptor *d)
|
iwmbt_is_8260(struct libusb_device_descriptor *d)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/* Search looking for whether it's an 8260/8265 */
|
/* Search looking for whether it's an 8260/8265 */
|
||||||
for (i = 0; i < (int) nitems(iwmbt_list); i++) {
|
for (i = 0; i < (int) nitems(iwmbt_list_82xx); i++) {
|
||||||
if ((iwmbt_list[i].product_id == d->idProduct) &&
|
if ((iwmbt_list_82xx[i].product_id == d->idProduct) &&
|
||||||
(iwmbt_list[i].vendor_id == d->idVendor)) {
|
(iwmbt_list_82xx[i].vendor_id == d->idVendor)) {
|
||||||
iwmbt_info("found 8260/8265");
|
iwmbt_info("found 8260/8265");
|
||||||
return (1);
|
return (1);
|
||||||
}
|
}
|
||||||
@ -86,7 +112,8 @@ iwmbt_is_8260(struct libusb_device_descriptor *d)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static libusb_device *
|
static libusb_device *
|
||||||
iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id)
|
iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
|
||||||
|
int *iwmbt_use_old_method)
|
||||||
{
|
{
|
||||||
libusb_device **list, *dev = NULL, *found = NULL;
|
libusb_device **list, *dev = NULL, *found = NULL;
|
||||||
struct libusb_device_descriptor d;
|
struct libusb_device_descriptor d;
|
||||||
@ -116,11 +143,20 @@ iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Match on the vendor/product id */
|
/* Match on the vendor/product id */
|
||||||
|
if (iwmbt_is_7260(&d)) {
|
||||||
|
/*
|
||||||
|
* Take a reference so it's not freed later on.
|
||||||
|
*/
|
||||||
|
found = libusb_ref_device(dev);
|
||||||
|
*iwmbt_use_old_method = 1;
|
||||||
|
break;
|
||||||
|
} else
|
||||||
if (iwmbt_is_8260(&d)) {
|
if (iwmbt_is_8260(&d)) {
|
||||||
/*
|
/*
|
||||||
* Take a reference so it's not freed later on.
|
* Take a reference so it's not freed later on.
|
||||||
*/
|
*/
|
||||||
found = libusb_ref_device(dev);
|
found = libusb_ref_device(dev);
|
||||||
|
*iwmbt_use_old_method = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -166,6 +202,31 @@ iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
|
|||||||
params->otp_bdaddr[0]);
|
params->otp_bdaddr[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
|
||||||
|
{
|
||||||
|
struct iwmbt_firmware fw;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
iwmbt_debug("loading %s", firmware_path);
|
||||||
|
|
||||||
|
/* Read in the firmware */
|
||||||
|
if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
|
||||||
|
iwmbt_debug("iwmbt_fw_read() failed");
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load in the firmware */
|
||||||
|
ret = iwmbt_patch_fwfile(hdl, &fw);
|
||||||
|
if (ret < 0)
|
||||||
|
iwmbt_debug("Loading firmware file failed");
|
||||||
|
|
||||||
|
/* free it */
|
||||||
|
iwmbt_fw_free(&fw);
|
||||||
|
|
||||||
|
return (ret);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
|
iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
|
||||||
uint32_t *boot_param)
|
uint32_t *boot_param)
|
||||||
@ -268,6 +329,7 @@ main(int argc, char *argv[])
|
|||||||
char *firmware_dir = NULL;
|
char *firmware_dir = NULL;
|
||||||
char *firmware_path = NULL;
|
char *firmware_path = NULL;
|
||||||
int retcode = 1;
|
int retcode = 1;
|
||||||
|
int iwmbt_use_old_method = 0;
|
||||||
|
|
||||||
/* Parse command line arguments */
|
/* Parse command line arguments */
|
||||||
while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
|
while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
|
||||||
@ -312,7 +374,7 @@ main(int argc, char *argv[])
|
|||||||
iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
|
iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
|
||||||
|
|
||||||
/* Find a device based on the bus/dev id */
|
/* Find a device based on the bus/dev id */
|
||||||
dev = iwmbt_find_device(ctx, bus_id, dev_id);
|
dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_use_old_method);
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
iwmbt_err("device not found");
|
iwmbt_err("device not found");
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
@ -344,87 +406,144 @@ main(int argc, char *argv[])
|
|||||||
/* Get Intel version */
|
/* Get Intel version */
|
||||||
r = iwmbt_get_version(hdl, &ver);
|
r = iwmbt_get_version(hdl, &ver);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
iwmbt_debug("iwmbt_get_version() failedL code %d", r);
|
iwmbt_debug("iwmbt_get_version() failed code %d", r);
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
}
|
}
|
||||||
iwmbt_dump_version(&ver);
|
iwmbt_dump_version(&ver);
|
||||||
iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
|
iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
|
||||||
|
|
||||||
/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
|
if (iwmbt_use_old_method) {
|
||||||
if (ver.fw_variant == 0x23) {
|
|
||||||
iwmbt_info("Firmware has already been downloaded");
|
|
||||||
retcode = 0;
|
|
||||||
goto reset;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ver.fw_variant != 0x06){
|
/* fw_patch_num = >0 operational mode */
|
||||||
iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
|
if (ver.fw_patch_num > 0x00) {
|
||||||
goto shutdown;
|
iwmbt_info("Firmware has already been downloaded");
|
||||||
}
|
retcode = 0;
|
||||||
|
goto reset;
|
||||||
|
}
|
||||||
|
|
||||||
/* Read Intel Secure Boot Params */
|
/* Default the firmware path */
|
||||||
r = iwmbt_get_boot_params(hdl, ¶ms);
|
if (firmware_dir == NULL)
|
||||||
if (r < 0) {
|
firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
|
||||||
iwmbt_debug("iwmbt_get_boot_params() failed!");
|
|
||||||
goto shutdown;
|
|
||||||
}
|
|
||||||
iwmbt_dump_boot_params(¶ms);
|
|
||||||
|
|
||||||
/* Check if firmware fragments are ACKed with a cmd complete event */
|
firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "bseq");
|
||||||
if (params.limited_cce != 0x00) {
|
if (firmware_path == NULL)
|
||||||
iwmbt_err("Unsupported Intel firmware loading method (%u)",
|
goto shutdown;
|
||||||
params.limited_cce);
|
|
||||||
goto shutdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Default the firmware path */
|
iwmbt_debug("firmware_path = %s", firmware_path);
|
||||||
if (firmware_dir == NULL)
|
|
||||||
firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
|
|
||||||
|
|
||||||
firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "sfi");
|
/* Enter manufacturer mode */
|
||||||
if (firmware_path == NULL)
|
r = iwmbt_enter_manufacturer(hdl);
|
||||||
goto shutdown;
|
if (r < 0) {
|
||||||
|
iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
iwmbt_debug("firmware_path = %s", firmware_path);
|
/* Download firmware and parse it for magic Intel Reset parameter */
|
||||||
|
r = iwmbt_patch_firmware(hdl, firmware_path);
|
||||||
/* Download firmware and parse it for magic Intel Reset parameter */
|
|
||||||
r = iwmbt_init_firmware(hdl, firmware_path, &boot_param);
|
|
||||||
free(firmware_path);
|
|
||||||
if (r < 0)
|
|
||||||
goto shutdown;
|
|
||||||
|
|
||||||
iwmbt_info("Firmware download complete");
|
|
||||||
|
|
||||||
r = iwmbt_intel_reset(hdl, boot_param);
|
|
||||||
if (r < 0) {
|
|
||||||
iwmbt_debug("iwmbt_intel_reset() failed!");
|
|
||||||
goto shutdown;
|
|
||||||
}
|
|
||||||
|
|
||||||
iwmbt_info("Firmware operational");
|
|
||||||
|
|
||||||
/* Once device is running in operational mode we can ignore failures */
|
|
||||||
retcode = 0;
|
|
||||||
|
|
||||||
/* Execute Read Intel Version one more time */
|
|
||||||
r = iwmbt_get_version(hdl, &ver);
|
|
||||||
if (r == 0)
|
|
||||||
iwmbt_dump_version(&ver);
|
|
||||||
|
|
||||||
/* Apply the device configuration (DDC) parameters */
|
|
||||||
firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "ddc");
|
|
||||||
iwmbt_debug("ddc_path = %s", firmware_path);
|
|
||||||
if (firmware_path != NULL) {
|
|
||||||
r = iwmbt_init_ddc(hdl, firmware_path);
|
|
||||||
if (r == 0)
|
|
||||||
iwmbt_info("DDC download complete");
|
|
||||||
free(firmware_path);
|
free(firmware_path);
|
||||||
}
|
if (r < 0)
|
||||||
|
goto shutdown;
|
||||||
|
|
||||||
/* Set Intel Event mask */
|
iwmbt_info("Firmware download complete");
|
||||||
r = iwmbt_set_event_mask(hdl);
|
|
||||||
if (r == 0)
|
/* Exit manufacturer mode */
|
||||||
iwmbt_info("Intel Event Mask is set");
|
r = iwmbt_exit_manufacturer(hdl, 0x02);
|
||||||
|
if (r < 0) {
|
||||||
|
iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Once device is running in operational mode we can ignore failures */
|
||||||
|
retcode = 0;
|
||||||
|
|
||||||
|
/* Execute Read Intel Version one more time */
|
||||||
|
r = iwmbt_get_version(hdl, &ver);
|
||||||
|
if (r == 0)
|
||||||
|
iwmbt_dump_version(&ver);
|
||||||
|
|
||||||
|
/* Set Intel Event mask */
|
||||||
|
r = iwmbt_set_event_mask(hdl);
|
||||||
|
if (r == 0)
|
||||||
|
iwmbt_info("Intel Event Mask is set");
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
|
||||||
|
if (ver.fw_variant == 0x23) {
|
||||||
|
iwmbt_info("Firmware has already been downloaded");
|
||||||
|
retcode = 0;
|
||||||
|
goto reset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ver.fw_variant != 0x06){
|
||||||
|
iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read Intel Secure Boot Params */
|
||||||
|
r = iwmbt_get_boot_params(hdl, ¶ms);
|
||||||
|
if (r < 0) {
|
||||||
|
iwmbt_debug("iwmbt_get_boot_params() failed!");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
iwmbt_dump_boot_params(¶ms);
|
||||||
|
|
||||||
|
/* Check if firmware fragments are ACKed with a cmd complete event */
|
||||||
|
if (params.limited_cce != 0x00) {
|
||||||
|
iwmbt_err("Unsupported Intel firmware loading method (%u)",
|
||||||
|
params.limited_cce);
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Default the firmware path */
|
||||||
|
if (firmware_dir == NULL)
|
||||||
|
firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
|
||||||
|
|
||||||
|
firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "sfi");
|
||||||
|
if (firmware_path == NULL)
|
||||||
|
goto shutdown;
|
||||||
|
|
||||||
|
iwmbt_debug("firmware_path = %s", firmware_path);
|
||||||
|
|
||||||
|
/* Download firmware and parse it for magic Intel Reset parameter */
|
||||||
|
r = iwmbt_init_firmware(hdl, firmware_path, &boot_param);
|
||||||
|
free(firmware_path);
|
||||||
|
if (r < 0)
|
||||||
|
goto shutdown;
|
||||||
|
|
||||||
|
iwmbt_info("Firmware download complete");
|
||||||
|
|
||||||
|
r = iwmbt_intel_reset(hdl, boot_param);
|
||||||
|
if (r < 0) {
|
||||||
|
iwmbt_debug("iwmbt_intel_reset() failed!");
|
||||||
|
goto shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
iwmbt_info("Firmware operational");
|
||||||
|
|
||||||
|
/* Once device is running in operational mode we can ignore failures */
|
||||||
|
retcode = 0;
|
||||||
|
|
||||||
|
/* Execute Read Intel Version one more time */
|
||||||
|
r = iwmbt_get_version(hdl, &ver);
|
||||||
|
if (r == 0)
|
||||||
|
iwmbt_dump_version(&ver);
|
||||||
|
|
||||||
|
/* Apply the device configuration (DDC) parameters */
|
||||||
|
firmware_path = iwmbt_get_fwname(&ver, ¶ms, firmware_dir, "ddc");
|
||||||
|
iwmbt_debug("ddc_path = %s", firmware_path);
|
||||||
|
if (firmware_path != NULL) {
|
||||||
|
r = iwmbt_init_ddc(hdl, firmware_path);
|
||||||
|
if (r == 0)
|
||||||
|
iwmbt_info("DDC download complete");
|
||||||
|
free(firmware_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set Intel Event mask */
|
||||||
|
r = iwmbt_set_event_mask(hdl);
|
||||||
|
if (r == 0)
|
||||||
|
iwmbt_info("Intel Event Mask is set");
|
||||||
|
}
|
||||||
|
|
||||||
reset:
|
reset:
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user