git: f16c39e7fe64 - stable/12 - iwmbtfw(8): Add support for Intel 7260/7265 bluetooth adapter firmwares

From: Vladimir Kondratyev <wulf_at_FreeBSD.org>
Date: Thu, 24 Nov 2022 23:17:41 UTC
The branch stable/12 has been updated by wulf:

URL: https://cgit.FreeBSD.org/src/commit/?id=f16c39e7fe641cf9e6f17cfc177d2300b218bf45

commit f16c39e7fe641cf9e6f17cfc177d2300b218bf45
Author:     Philippe Michaud-Boudreault <pitwuu@gmail.com>
AuthorDate: 2021-05-04 23:48:21 +0000
Commit:     Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2022-11-24 23:15:54 +0000

    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
    
    (cherry picked from commit fe70d7b26d7a98b17e315bc3455bee267c618b4e)
---
 usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c   |  14 ++
 usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c   | 189 +++++++++++++++++++++++-
 usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h   |   5 +
 usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8    |  10 +-
 usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf |   2 +-
 usr.sbin/bluetooth/iwmbtfw/main.c       | 253 +++++++++++++++++++++++---------
 6 files changed, 401 insertions(+), 72 deletions(-)

diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
index 7764f8bc4ac3..fc93ce094adc 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
@@ -119,6 +119,20 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
 	char *fwname;
 
 	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 0x0c:	/* 8265 */
 		asprintf(&fwname, "%s/ibt-%u-%u.%s",
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index af48e038340f..f4272548d560 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -27,7 +27,7 @@
  * $FreeBSD$
  */
 
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/endian.h>
 #include <sys/stat.h>
 
@@ -126,6 +126,125 @@ iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd,
 	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
 iwmbt_load_fwfile(struct libusb_device_handle *hdl,
     const struct iwmbt_firmware *fw, uint32_t *boot_param)
@@ -217,6 +336,74 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
 	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
 iwmbt_get_version(struct libusb_device_handle *hdl,
     struct iwmbt_version *version)
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
index 6a87f499fa26..5bc1d15181cd 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
@@ -73,8 +73,13 @@ struct iwmbt_hci_event_cmd_compl {
 #define	IWMBT_HCI_CMD_TIMEOUT		2000	/* 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,
 	    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,
 	    struct iwmbt_version *version);
 extern	int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
index 3afbf54793f9..10e68040e0e4 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
@@ -1,5 +1,6 @@
 .\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@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
 .\" modification, are permitted provided that the following conditions
@@ -24,12 +25,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd June 4, 2019
+.Dd May 3, 2021
 .Dt IWMBTFW 8
 .Os
 .Sh NAME
 .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
 .Sh SYNOPSIS
 .Nm
@@ -46,7 +47,7 @@ device.
 .Pp
 This utility will
 .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.
 The identification is currently based on USB vendor ID/product ID pair.
 The vendor ID should be 0x8087
@@ -91,6 +92,9 @@ utility used as firmware downloader template and on Linux btintel driver
 source code.
 It is written by
 .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
 Most likely.
 Please report if found.
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
index 4bd1f020237c..6b417089c68b 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
@@ -7,6 +7,6 @@ notify 100 {
 	match "subsystem"	"DEVICE";
 	match "type"		"ATTACH";
 	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";
 };
diff --git a/usr.sbin/bluetooth/iwmbtfw/main.c b/usr.sbin/bluetooth/iwmbtfw/main.c
index ecd9d226b91f..3476e3fcd613 100644
--- a/usr.sbin/bluetooth/iwmbtfw/main.c
+++ b/usr.sbin/bluetooth/iwmbtfw/main.c
@@ -57,7 +57,15 @@ struct iwmbt_devid {
 	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 */
 	{ .vendor_id = 0x8087, .product_id = 0x0a2b },
@@ -67,15 +75,33 @@ static struct iwmbt_devid iwmbt_list[] = {
 	{ .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
 iwmbt_is_8260(struct libusb_device_descriptor *d)
 {
 	int i;
 
 	/* Search looking for whether it's an 8260/8265 */
-	for (i = 0; i < (int) nitems(iwmbt_list); i++) {
-		if ((iwmbt_list[i].product_id == d->idProduct) &&
-		    (iwmbt_list[i].vendor_id == d->idVendor)) {
+	for (i = 0; i < (int) nitems(iwmbt_list_82xx); i++) {
+		if ((iwmbt_list_82xx[i].product_id == d->idProduct) &&
+		    (iwmbt_list_82xx[i].vendor_id == d->idVendor)) {
 			iwmbt_info("found 8260/8265");
 			return (1);
 		}
@@ -86,7 +112,8 @@ iwmbt_is_8260(struct libusb_device_descriptor *d)
 }
 
 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;
 	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 */
+			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)) {
 				/*
 				 * Take a reference so it's not freed later on.
 				 */
 				found = libusb_ref_device(dev);
+				*iwmbt_use_old_method = 0;
 				break;
 			}
 		}
@@ -166,6 +202,31 @@ iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
 	    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
 iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
     uint32_t *boot_param)
@@ -268,6 +329,7 @@ main(int argc, char *argv[])
 	char *firmware_dir = NULL;
 	char *firmware_path = NULL;
 	int retcode = 1;
+	int iwmbt_use_old_method = 0;
 
 	/* Parse command line arguments */
 	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);
 
 	/* 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) {
 		iwmbt_err("device not found");
 		goto shutdown;
@@ -344,87 +406,144 @@ main(int argc, char *argv[])
 	/* Get Intel version */
 	r = iwmbt_get_version(hdl, &ver);
 	if (r < 0) {
-		iwmbt_debug("iwmbt_get_version() failedL code %d", r);
+		iwmbt_debug("iwmbt_get_version() failed code %d", r);
 		goto shutdown;
 	}
 	iwmbt_dump_version(&ver);
 	iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
 
-	/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
-	if (ver.fw_variant == 0x23) {
-		iwmbt_info("Firmware has already been downloaded");
+	if (iwmbt_use_old_method) {
+
+		/* fw_patch_num = >0 operational mode */
+		if (ver.fw_patch_num > 0x00) {
+			iwmbt_info("Firmware has already been downloaded");
+			retcode = 0;
+			goto reset;
+		}
+
+		/* Default the firmware path */
+		if (firmware_dir == NULL)
+			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
+
+		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "bseq");
+		if (firmware_path == NULL)
+			goto shutdown;
+
+		iwmbt_debug("firmware_path = %s", firmware_path);
+
+		/* Enter manufacturer mode */
+		r = iwmbt_enter_manufacturer(hdl);
+		if (r < 0) {
+			iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
+			goto shutdown;
+		}
+
+		/* Download firmware and parse it for magic Intel Reset parameter */
+		r = iwmbt_patch_firmware(hdl, firmware_path);
+		free(firmware_path);
+		if (r < 0)
+			goto shutdown;
+
+		iwmbt_info("Firmware download complete");
+
+		/* Exit manufacturer mode */
+		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;
-		goto reset;
-	}
 
-	if (ver.fw_variant != 0x06){
-		iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
-		goto shutdown;
-	}
+		/* Execute Read Intel Version one more time */
+		r = iwmbt_get_version(hdl, &ver);
+		if (r == 0)
+			iwmbt_dump_version(&ver);
 
-	/* Read Intel Secure Boot Params */
-	r = iwmbt_get_boot_params(hdl, &params);
-	if (r < 0) {
-		iwmbt_debug("iwmbt_get_boot_params() failed!");
-		goto shutdown;
-	}
-	iwmbt_dump_boot_params(&params);
+		/* Set Intel Event mask */
+		r = iwmbt_set_event_mask(hdl);
+		if (r == 0)
+			iwmbt_info("Intel Event Mask is set");
 
-	/* 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;
-	}
+	} else {
 
-	/* Default the firmware path */
-	if (firmware_dir == NULL)
-		firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
+		/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
+		if (ver.fw_variant == 0x23) {
+			iwmbt_info("Firmware has already been downloaded");
+			retcode = 0;
+			goto reset;
+		}
 
-	firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
-	if (firmware_path == NULL)
-		goto shutdown;
+		if (ver.fw_variant != 0x06){
+			iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
+			goto shutdown;
+		}
 
-	iwmbt_debug("firmware_path = %s", firmware_path);
+		/* Read Intel Secure Boot Params */
+		r = iwmbt_get_boot_params(hdl, &params);
+		if (r < 0) {
+			iwmbt_debug("iwmbt_get_boot_params() failed!");
+			goto shutdown;
+		}
+		iwmbt_dump_boot_params(&params);
 
-	/* 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;
+		/* 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;
+		}
 
-	iwmbt_info("Firmware download complete");
+		/* Default the firmware path */
+		if (firmware_dir == NULL)
+			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
 
-	r = iwmbt_intel_reset(hdl, boot_param);
-	if (r < 0) {
-		iwmbt_debug("iwmbt_intel_reset() failed!");
-		goto shutdown;
-	}
+		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
+		if (firmware_path == NULL)
+			goto shutdown;
 
-	iwmbt_info("Firmware operational");
+		iwmbt_debug("firmware_path = %s", firmware_path);
 
-	/* Once device is running in operational mode we can ignore failures */
-	retcode = 0;
+		/* 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;
 
-	/* 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, &params, firmware_dir, "ddc");
-	iwmbt_debug("ddc_path = %s", firmware_path);
-	if (firmware_path != NULL) {
-		r = iwmbt_init_ddc(hdl, firmware_path);
+		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_info("DDC download complete");
-		free(firmware_path);
-	}
+			iwmbt_dump_version(&ver);
+
+		/* Apply the device configuration (DDC) parameters */
+		firmware_path = iwmbt_get_fwname(&ver, &params, 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");
+		/* Set Intel Event mask */
+		r = iwmbt_set_event_mask(hdl);
+		if (r == 0)
+			iwmbt_info("Intel Event Mask is set");
+	}
 
 reset: