aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorVladimir Kondratyev <wulf@FreeBSD.org>2021-05-31 19:32:08 +0000
committerVladimir Kondratyev <wulf@FreeBSD.org>2021-05-31 19:32:08 +0000
commitda93a73f834612b659b37b513c8296e1178d249b (patch)
treefc1812807807f0205c03ae4b6205fa64e71a7fb3 /usr.sbin
parent8505eb5dd8f743f29e9c93b6814a34f1890e6c41 (diff)
downloadsrc-da93a73f834612b659b37b513c8296e1178d249b.tar.gz
src-da93a73f834612b659b37b513c8296e1178d249b.zip
iwmbtfw(8): Improve Intel 7260/7265 adaptors handling
- Allow firmware downloading for hw_variant #8; - Enter manufacturer mode for setting of event mask; - Handle multi-event response on HCI commands for 7260; This allows to remove kludge with skipping of 0xfc2f opcode. - Disable patch and exit manufacturer mode on downloading failure; - Use default firmware if correct firmware file is not found; Reviewed by: Philippe Michaud-Boudreault <pitwuu_AT_gmail_DOT_com> MFC after: 1 week Tested by: arrowd Differential revision: https://reviews.freebsd.org/D30543
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c14
-rw-r--r--usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c116
-rw-r--r--usr.sbin/bluetooth/iwmbtfw/main.c9
3 files changed, 91 insertions, 48 deletions
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
index fc93ce094adc..963d5d5d9008 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
@@ -116,10 +116,12 @@ char *
iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
const char *prefix, const char *suffix)
{
+ struct stat sb;
char *fwname;
switch (ver->hw_variant) {
case 0x07: /* 7260 */
+ case 0x08: /* 7265 */
asprintf(&fwname, "%s/ibt-hw-%x.%x.%x-fw-%x.%x.%x.%x.%x.%s",
prefix,
le16toh(ver->hw_platform),
@@ -131,6 +133,18 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
le16toh(ver->fw_build_ww),
le16toh(ver->fw_build_yy),
suffix);
+ /*
+ * Fallback to the default firmware patch if
+ * the correct firmware patch file is not found.
+ */
+ if (stat(fwname, &sb) != 0 && errno == ENOENT) {
+ free(fwname);
+ asprintf(&fwname, "%s/ibt-hw-%x.%x.%s",
+ prefix,
+ le16toh(ver->hw_platform),
+ le16toh(ver->hw_variant),
+ suffix);
+ }
break;
case 0x0b: /* 8260 */
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index f4272548d560..218fd28b74a2 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -134,17 +134,18 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
struct iwmbt_firmware fw_job = *fw;
uint16_t cmd_opcode;
uint8_t cmd_length;
- uint8_t cmd_buf[IWMBT_HCI_MAX_CMD_SIZE];
+ struct iwmbt_hci_cmd *cmd_buf;
uint8_t evt_code;
uint8_t evt_length;
uint8_t evt_buf[IWMBT_HCI_MAX_EVENT_SIZE];
- int skip_patch = 0;
+ int activate_patch = 0;
- for (;;) {
- skip_patch = 0;
-
- if (fw_job.len < 4)
- break;
+ while (fw_job.len > 0) {
+ if (fw_job.len < 4) {
+ iwmbt_err("Invalid firmware, unexpected EOF in HCI "
+ "command header. Remains=%d", fw_job.len);
+ return (-1);
+ }
if (fw_job.buf[0] != 0x01) {
iwmbt_err("Invalid firmware, expected HCI command (%d)",
@@ -159,47 +160,61 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
/* 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);
+ cmd_buf = (struct iwmbt_hci_cmd *)fw_job.buf;
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;
+ /*
+ * If there is a command that loads a patch in the
+ * firmware file, then activate the patch upon success,
+ * otherwise just disable the manufacturer mode.
+ */
+ if (cmd_opcode == 0xfc8e)
+ activate_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));
+ if (fw_job.len < cmd_length) {
+ iwmbt_err("Invalid firmware, unexpected EOF in HCI "
+ "command data. len=%d, remains=%d",
+ cmd_length, fw_job.len);
+ return (-1);
+ }
/* Advance by data length. */
fw_job.buf += cmd_length;
fw_job.len -= cmd_length;
+ ret = libusb_control_transfer(hdl,
+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
+ 0,
+ 0,
+ 0,
+ (uint8_t *)cmd_buf,
+ IWMBT_HCI_CMD_SIZE(cmd_buf),
+ IWMBT_HCI_CMD_TIMEOUT);
+
+ if (ret < 0) {
+ iwmbt_err("libusb_control_transfer() failed: err=%s",
+ libusb_strerror(ret));
+ return (-1);
+ }
+
/*
* 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 (;;) {
+ while (fw_job.len > 0 && fw_job.buf[0] == 0x02) {
/* Is this the end of the file? */
- if (fw_job.len < 3)
- break;
-
- if (fw_job.buf[0] != 0x02)
- break;
+ if (fw_job.len < 3) {
+ iwmbt_err("Invalid firmware, unexpected EOF in"
+ "event header. remains=%d", fw_job.len);
+ return (-1);
+ }
/* Advance by one. */
fw_job.buf++;
@@ -219,30 +234,39 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
iwmbt_debug("event=%04x, len=%02x",
evt_code, evt_length);
+ if (fw_job.len < evt_length) {
+ iwmbt_err("Invalid firmware, unexpected EOF in"
+ " event data. len=%d, remains=%d",
+ evt_length, fw_job.len);
+ return (-1);
+ }
+
+ ret = libusb_interrupt_transfer(hdl,
+ IWMBT_INTERRUPT_ENDPOINT_ADDR,
+ evt_buf,
+ IWMBT_HCI_MAX_EVENT_SIZE,
+ &transferred,
+ IWMBT_HCI_CMD_TIMEOUT);
+
+ if (ret < 0) {
+ iwmbt_err("libusb_interrupt_transfer() failed:"
+ " err=%s", libusb_strerror(ret));
+ return (-1);
+ }
+
+ if ((int)evt_length + 2 != transferred ||
+ memcmp(evt_buf + 2, fw_job.buf, evt_length) != 0) {
+ iwmbt_err("event does not match firmware");
+ return (-1);
+ }
+
/* 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);
+ return (activate_patch);
}
int
diff --git a/usr.sbin/bluetooth/iwmbtfw/main.c b/usr.sbin/bluetooth/iwmbtfw/main.c
index 3476e3fcd613..202894740805 100644
--- a/usr.sbin/bluetooth/iwmbtfw/main.c
+++ b/usr.sbin/bluetooth/iwmbtfw/main.c
@@ -441,13 +441,15 @@ main(int argc, char *argv[])
/* Download firmware and parse it for magic Intel Reset parameter */
r = iwmbt_patch_firmware(hdl, firmware_path);
free(firmware_path);
- if (r < 0)
+ if (r < 0) {
+ (void)iwmbt_exit_manufacturer(hdl, 0x01);
goto shutdown;
+ }
iwmbt_info("Firmware download complete");
/* Exit manufacturer mode */
- r = iwmbt_exit_manufacturer(hdl, 0x02);
+ r = iwmbt_exit_manufacturer(hdl, r == 0 ? 0x00 : 0x02);
if (r < 0) {
iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
goto shutdown;
@@ -462,9 +464,12 @@ main(int argc, char *argv[])
iwmbt_dump_version(&ver);
/* Set Intel Event mask */
+ if (iwmbt_enter_manufacturer(hdl) < 0)
+ goto reset;
r = iwmbt_set_event_mask(hdl);
if (r == 0)
iwmbt_info("Intel Event Mask is set");
+ (void)iwmbt_exit_manufacturer(hdl, 0x00);
} else {