git: c1643cedbf24 - main - iwmbtfw(4): Add support for 9260/9560 bluetooth adaptors
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 06 Nov 2024 23:31:52 UTC
The branch main has been updated by wulf:
URL: https://cgit.FreeBSD.org/src/commit/?id=c1643cedbf243424370162febf6d9180bdd1df58
commit c1643cedbf243424370162febf6d9180bdd1df58
Author: Vladimir Kondratyev <wulf@FreeBSD.org>
AuthorDate: 2024-11-06 23:26:51 +0000
Commit: Vladimir Kondratyev <wulf@FreeBSD.org>
CommitDate: 2024-11-06 23:26:51 +0000
iwmbtfw(4): Add support for 9260/9560 bluetooth adaptors
Required firmware files are already included in to comms/iwmbt-firmware port
Sponsored by: Future Crew LLC
MFC after: 1 month
Reviewed by: bz
Differential Revision: https://reviews.freebsd.org/D46735
---
usr.sbin/bluetooth/iwmbtfw/Makefile | 2 +
usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c | 21 +++
usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h | 71 +++++++
usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c | 183 ++++++++++++++++--
usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h | 12 +-
usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 | 4 +-
usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf | 5 +-
usr.sbin/bluetooth/iwmbtfw/main.c | 323 +++++++++++++++++++++++++-------
8 files changed, 531 insertions(+), 90 deletions(-)
diff --git a/usr.sbin/bluetooth/iwmbtfw/Makefile b/usr.sbin/bluetooth/iwmbtfw/Makefile
index dde586b3aa99..c5cf037eac06 100644
--- a/usr.sbin/bluetooth/iwmbtfw/Makefile
+++ b/usr.sbin/bluetooth/iwmbtfw/Makefile
@@ -4,6 +4,8 @@ CONFSDIR= /etc/devd
PROG= iwmbtfw
MAN= iwmbtfw.8
LIBADD+= usb
+# Not having NDEBUG defined will enable assertions
+CFLAGS+= -DNDEBUG
SRCS= main.c iwmbt_fw.c iwmbt_hw.c
.include <bsd.prog.mk>
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
index 6816b152912d..815b40982d5b 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -170,3 +171,23 @@ iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
return (fwname);
}
+
+char *
+iwmbt_get_fwname_tlv(struct iwmbt_version_tlv *ver, const char *prefix,
+ const char *suffix)
+{
+ char *fwname;
+
+#define IWMBT_PACK_CNVX_TOP(cnvx_top) ((uint16_t)( \
+ ((cnvx_top) & 0x0f000000) >> 16 | \
+ ((cnvx_top) & 0x0000000f) << 12 | \
+ ((cnvx_top) & 0x00000ff0) >> 4))
+
+ asprintf(&fwname, "%s/ibt-%04x-%04x.%s",
+ prefix,
+ IWMBT_PACK_CNVX_TOP(ver->cnvi_top),
+ IWMBT_PACK_CNVX_TOP(ver->cnvr_top),
+ suffix);
+
+ return (fwname);
+}
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
index f737c1c0c2c8..2666d123c8f0 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
@@ -3,6 +3,7 @@
*
* Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,6 +30,15 @@
#ifndef __IWMBT_FW_H__
#define __IWMBT_FW_H__
+#include <sys/types.h>
+#define L2CAP_SOCKET_CHECKED
+#include <bluetooth.h>
+
+#define RSA_HEADER_LEN 644
+#define ECDSA_HEADER_LEN 320
+#define ECDSA_OFFSET RSA_HEADER_LEN
+#define CSS_HEADER_OFFSET 8
+
struct iwmbt_version {
uint8_t status;
uint8_t hw_platform;
@@ -62,6 +72,65 @@ struct iwmbt_boot_params {
uint8_t unlocked_state;
} __attribute__ ((packed));
+enum {
+ IWMBT_TLV_CNVI_TOP = 0x10,
+ IWMBT_TLV_CNVR_TOP,
+ IWMBT_TLV_CNVI_BT,
+ IWMBT_TLV_CNVR_BT,
+ IWMBT_TLV_CNVI_OTP,
+ IWMBT_TLV_CNVR_OTP,
+ IWMBT_TLV_DEV_REV_ID,
+ IWMBT_TLV_USB_VENDOR_ID,
+ IWMBT_TLV_USB_PRODUCT_ID,
+ IWMBT_TLV_PCIE_VENDOR_ID,
+ IWMBT_TLV_PCIE_DEVICE_ID,
+ IWMBT_TLV_PCIE_SUBSYSTEM_ID,
+ IWMBT_TLV_IMAGE_TYPE,
+ IWMBT_TLV_TIME_STAMP,
+ IWMBT_TLV_BUILD_TYPE,
+ IWMBT_TLV_BUILD_NUM,
+ IWMBT_TLV_FW_BUILD_PRODUCT,
+ IWMBT_TLV_FW_BUILD_HW,
+ IWMBT_TLV_FW_STEP,
+ IWMBT_TLV_BT_SPEC,
+ IWMBT_TLV_MFG_NAME,
+ IWMBT_TLV_HCI_REV,
+ IWMBT_TLV_LMP_SUBVER,
+ IWMBT_TLV_OTP_PATCH_VER,
+ IWMBT_TLV_SECURE_BOOT,
+ IWMBT_TLV_KEY_FROM_HDR,
+ IWMBT_TLV_OTP_LOCK,
+ IWMBT_TLV_API_LOCK,
+ IWMBT_TLV_DEBUG_LOCK,
+ IWMBT_TLV_MIN_FW,
+ IWMBT_TLV_LIMITED_CCE,
+ IWMBT_TLV_SBE_TYPE,
+ IWMBT_TLV_OTP_BDADDR,
+ IWMBT_TLV_UNLOCKED_STATE
+};
+
+struct iwmbt_version_tlv {
+ uint32_t cnvi_top;
+ uint32_t cnvr_top;
+ uint32_t cnvi_bt;
+ uint32_t cnvr_bt;
+ uint16_t dev_rev_id;
+ uint8_t img_type;
+ uint16_t timestamp;
+ uint8_t build_type;
+ uint32_t build_num;
+ uint8_t secure_boot;
+ uint8_t otp_lock;
+ uint8_t api_lock;
+ uint8_t debug_lock;
+ uint8_t min_fw_build_nn;
+ uint8_t min_fw_build_cw;
+ uint8_t min_fw_build_yy;
+ uint8_t limited_cce;
+ uint8_t sbe_type;
+ bdaddr_t otp_bd_addr;
+};
+
struct iwmbt_firmware {
char *fwname;
int len;
@@ -73,5 +142,7 @@ extern void iwmbt_fw_free(struct iwmbt_firmware *fw);
extern char *iwmbt_get_fwname(struct iwmbt_version *ver,
struct iwmbt_boot_params *params, const char *prefix,
const char *suffix);
+extern char *iwmbt_get_fwname_tlv(struct iwmbt_version_tlv *ver,
+ const char *prefix, const char *suffix);
#endif
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
index ea732c9925ee..05a851f9d85b 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -29,6 +30,7 @@
#include <sys/endian.h>
#include <sys/stat.h>
+#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stddef.h>
@@ -267,16 +269,6 @@ iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
return (activate_patch);
}
-int
-iwmbt_load_fwfile(struct libusb_device_handle *hdl,
- const struct iwmbt_firmware *fw, uint32_t *boot_param)
-{
- int ready = 0, sent = 0;
- int ret, transferred;
- struct iwmbt_hci_cmd *cmd;
- struct iwmbt_hci_event *event;
- uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
-
#define IWMBT_SEND_FRAGMENT(fragment_type, size, msg) do { \
iwmbt_debug("transferring %d bytes, offset %d", size, sent); \
\
@@ -293,12 +285,11 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
sent += size; \
} while (0)
- if (fw->len < 644) {
- iwmbt_err("Invalid size of firmware file (%d)", fw->len);
- return (-1);
- }
-
- iwmbt_debug("file=%s, size=%d", fw->fwname, fw->len);
+int
+iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
+ const struct iwmbt_firmware *fw)
+{
+ int ret, sent = 0;
IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1");
@@ -310,6 +301,32 @@ iwmbt_load_fwfile(struct libusb_device_handle *hdl,
IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1");
IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2");
+ return (0);
+}
+
+int
+iwmbt_load_ecdsa_header(struct libusb_device_handle *hdl,
+ const struct iwmbt_firmware *fw)
+{
+ int ret, sent = ECDSA_OFFSET;
+
+ IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
+ IWMBT_SEND_FRAGMENT(0x03, 0x60, "public key");
+ IWMBT_SEND_FRAGMENT(0x02, 0x60, "signature");
+
+ return (0);
+}
+
+int
+iwmbt_load_fwfile(struct libusb_device_handle *hdl,
+ const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset)
+{
+ int ready = 0, sent = offset;
+ int ret, transferred;
+ struct iwmbt_hci_cmd *cmd;
+ struct iwmbt_hci_event *event;
+ uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
+
/*
* Send firmware chunks. Chunk len must be 4 byte aligned.
* multiple commands can be combined
@@ -460,6 +477,140 @@ iwmbt_get_version(struct libusb_device_handle *hdl,
return (0);
}
+int
+iwmbt_get_version_tlv(struct libusb_device_handle *hdl,
+ struct iwmbt_version_tlv *version)
+{
+ int ret, transferred;
+ struct iwmbt_hci_event_cmd_compl *event;
+ static struct iwmbt_hci_cmd cmd = {
+ .opcode = htole16(0xfc05),
+ .length = 1,
+ .data = { 0xff },
+ };
+ uint8_t status, datalen, type, len;
+ uint8_t *data;
+ uint8_t buf[255];
+
+ memset(buf, 0, sizeof(buf));
+
+ ret = iwmbt_hci_command(hdl,
+ &cmd,
+ buf,
+ sizeof(buf),
+ &transferred,
+ IWMBT_HCI_CMD_TIMEOUT);
+
+ if (ret < 0 || transferred < (int)IWMBT_HCI_EVT_COMPL_SIZE(uint16_t)) {
+ iwmbt_debug("Can't get version: code=%d, size=%d",
+ ret,
+ transferred);
+ return (-1);
+ }
+
+ event = (struct iwmbt_hci_event_cmd_compl *)buf;
+ memcpy(version, event->data, sizeof(struct iwmbt_version));
+
+ datalen = event->header.length - IWMBT_HCI_EVENT_COMPL_HEAD_SIZE;
+ data = event->data;
+ status = *data++;
+ if (status != 0)
+ return (-1);
+ datalen--;
+
+ while (datalen >= 2) {
+ type = *data++;
+ len = *data++;
+ datalen -= 2;
+
+ if (datalen < len)
+ return (-1);
+
+ switch (type) {
+ case IWMBT_TLV_CNVI_TOP:
+ assert(len == 4);
+ version->cnvi_top = le32dec(data);
+ break;
+ case IWMBT_TLV_CNVR_TOP:
+ assert(len == 4);
+ version->cnvr_top = le32dec(data);
+ break;
+ case IWMBT_TLV_CNVI_BT:
+ assert(len == 4);
+ version->cnvi_bt = le32dec(data);
+ break;
+ case IWMBT_TLV_CNVR_BT:
+ assert(len == 4);
+ version->cnvr_bt = le32dec(data);
+ break;
+ case IWMBT_TLV_DEV_REV_ID:
+ assert(len == 2);
+ version->dev_rev_id = le16dec(data);
+ break;
+ case IWMBT_TLV_IMAGE_TYPE:
+ assert(len == 1);
+ version->img_type = *data;
+ break;
+ case IWMBT_TLV_TIME_STAMP:
+ assert(len == 2);
+ version->min_fw_build_cw = data[0];
+ version->min_fw_build_yy = data[1];
+ version->timestamp = le16dec(data);
+ break;
+ case IWMBT_TLV_BUILD_TYPE:
+ assert(len == 1);
+ version->build_type = *data;
+ break;
+ case IWMBT_TLV_BUILD_NUM:
+ assert(len == 4);
+ version->min_fw_build_nn = *data;
+ version->build_num = le32dec(data);
+ break;
+ case IWMBT_TLV_SECURE_BOOT:
+ assert(len == 1);
+ version->secure_boot = *data;
+ break;
+ case IWMBT_TLV_OTP_LOCK:
+ assert(len == 1);
+ version->otp_lock = *data;
+ break;
+ case IWMBT_TLV_API_LOCK:
+ assert(len == 1);
+ version->api_lock = *data;
+ break;
+ case IWMBT_TLV_DEBUG_LOCK:
+ assert(len == 1);
+ version->debug_lock = *data;
+ break;
+ case IWMBT_TLV_MIN_FW:
+ assert(len == 3);
+ version->min_fw_build_nn = data[0];
+ version->min_fw_build_cw = data[1];
+ version->min_fw_build_yy = data[2];
+ break;
+ case IWMBT_TLV_LIMITED_CCE:
+ assert(len == 1);
+ version->limited_cce = *data;
+ break;
+ case IWMBT_TLV_SBE_TYPE:
+ assert(len == 1);
+ version->sbe_type = *data;
+ break;
+ case IWMBT_TLV_OTP_BDADDR:
+ memcpy(&version->otp_bd_addr, data, sizeof(bdaddr_t));
+ break;
+ default:
+ /* Ignore other types */
+ break;
+ }
+
+ datalen -= len;
+ data += len;
+ }
+
+ return (0);
+}
+
int
iwmbt_get_boot_params(struct libusb_device_handle *hdl,
struct iwmbt_boot_params *params)
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
index eafb2c3f31d8..9467c3807a2a 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
@@ -2,6 +2,7 @@
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -59,6 +60,9 @@ struct iwmbt_hci_event_cmd_compl {
#define IWMBT_HCI_EVT_COMPL_SIZE(payload) \
(offsetof(struct iwmbt_hci_event_cmd_compl, data) + sizeof(payload))
+#define IWMBT_HCI_EVENT_COMPL_HEAD_SIZE \
+ (offsetof(struct iwmbt_hci_event_cmd_compl, data) - \
+ offsetof(struct iwmbt_hci_event_cmd_compl, numpkt))
#define IWMBT_CONTROL_ENDPOINT_ADDR 0x00
#define IWMBT_INTERRUPT_ENDPOINT_ADDR 0x81
@@ -73,13 +77,19 @@ struct iwmbt_hci_event_cmd_compl {
extern int iwmbt_patch_fwfile(struct libusb_device_handle *hdl,
const struct iwmbt_firmware *fw);
+extern int iwmbt_load_rsa_header(struct libusb_device_handle *hdl,
+ const struct iwmbt_firmware *fw);
+extern int iwmbt_load_ecdsa_header(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);
+ const struct iwmbt_firmware *fw, uint32_t *boot_param, int offset);
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_version_tlv(struct libusb_device_handle *hdl,
+ struct iwmbt_version_tlv *version);
extern int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
struct iwmbt_boot_params *params);
extern int iwmbt_intel_reset(struct libusb_device_handle *hdl,
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
index 1924c5f3ce74..2ce828cb5ebe 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 31, 2024
+.Dd September 15, 2024
.Dt IWMBTFW 8
.Os
.Sh NAME
@@ -48,7 +48,7 @@ device.
.Pp
This utility will
.Em only
-work with Intel Wireless 7260/8260/8265 chip based Bluetooth USB devices
+work with Intel Wireless 7260/8260/9260 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
diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
index ef8d5263383b..e30a3c15ccaa 100644
--- a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
@@ -1,11 +1,12 @@
#
-# Download Intel Wireless 8260/8265 bluetooth adaptor firmware
+# Download Intel Wireless bluetooth adaptor firmware
+#
notify 100 {
match "system" "USB";
match "subsystem" "DEVICE";
match "type" "ATTACH";
match "vendor" "0x8087";
- match "product" "(0x07dc|0x0a2a|0x0aa7|0x0a2b|0x0aaa|0x0025|0x0026|0x0029)";
+ match "product" "(0x07dc|0x0a2a|0x0aa7|0x0a2b|0x0aaa|0x0025|0x0026|0x0029|0x0032|0x0033)";
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 9ef31b906b77..c2b67ce01906 100644
--- a/usr.sbin/bluetooth/iwmbtfw/main.c
+++ b/usr.sbin/bluetooth/iwmbtfw/main.c
@@ -3,6 +3,7 @@
*
* Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
* Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
+ * Copyright (c) 2023 Future Crew LLC.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -50,71 +51,63 @@
int iwmbt_do_debug = 0;
int iwmbt_do_info = 0;
+enum iwmbt_device {
+ IWMBT_DEVICE_UNKNOWN,
+ IWMBT_DEVICE_7260,
+ IWMBT_DEVICE_8260,
+ IWMBT_DEVICE_9260,
+};
+
struct iwmbt_devid {
uint16_t product_id;
uint16_t vendor_id;
+ enum iwmbt_device device;
};
-static struct iwmbt_devid iwmbt_list_72xx[] = {
+static struct iwmbt_devid iwmbt_list[] = {
- /* Intel Wireless 7260/7265 and successors */
- { .vendor_id = 0x8087, .product_id = 0x07dc },
- { .vendor_id = 0x8087, .product_id = 0x0a2a },
- { .vendor_id = 0x8087, .product_id = 0x0aa7 },
-};
+ /* Intel Wireless 7260/7265 and successors */
+ { .vendor_id = 0x8087, .product_id = 0x07dc, .device = IWMBT_DEVICE_7260 },
+ { .vendor_id = 0x8087, .product_id = 0x0a2a, .device = IWMBT_DEVICE_7260 },
+ { .vendor_id = 0x8087, .product_id = 0x0aa7, .device = IWMBT_DEVICE_7260 },
-static struct iwmbt_devid iwmbt_list_82xx[] = {
+ /* Intel Wireless 8260/8265 and successors */
+ { .vendor_id = 0x8087, .product_id = 0x0a2b, .device = IWMBT_DEVICE_8260 },
+ { .vendor_id = 0x8087, .product_id = 0x0aaa, .device = IWMBT_DEVICE_8260 },
+ { .vendor_id = 0x8087, .product_id = 0x0025, .device = IWMBT_DEVICE_8260 },
+ { .vendor_id = 0x8087, .product_id = 0x0026, .device = IWMBT_DEVICE_8260 },
+ { .vendor_id = 0x8087, .product_id = 0x0029, .device = IWMBT_DEVICE_8260 },
- /* Intel Wireless 8260/8265 and successors */
- { .vendor_id = 0x8087, .product_id = 0x0a2b },
- { .vendor_id = 0x8087, .product_id = 0x0aaa },
- { .vendor_id = 0x8087, .product_id = 0x0025 },
- { .vendor_id = 0x8087, .product_id = 0x0026 },
- { .vendor_id = 0x8087, .product_id = 0x0029 },
+ /* Intel Wireless 9260/9560 and successors */
+ { .vendor_id = 0x8087, .product_id = 0x0032, .device = IWMBT_DEVICE_9260 },
+ { .vendor_id = 0x8087, .product_id = 0x0033, .device = IWMBT_DEVICE_9260 },
};
-static int
-iwmbt_is_7260(struct libusb_device_descriptor *d)
+static enum iwmbt_device
+iwmbt_is_supported(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_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);
+ for (i = 0; i < (int) nitems(iwmbt_list); i++) {
+ if ((iwmbt_list[i].product_id == d->idProduct) &&
+ (iwmbt_list[i].vendor_id == d->idVendor)) {
+ iwmbt_info("found iwmbtfw compatible");
+ return (iwmbt_list[i].device);
}
}
/* Not found */
- return (0);
+ return (IWMBT_DEVICE_UNKNOWN);
}
static libusb_device *
iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
- int *iwmbt_use_old_method)
+ enum iwmbt_device *iwmbt_device)
{
libusb_device **list, *dev = NULL, *found = NULL;
struct libusb_device_descriptor d;
+ enum iwmbt_device device;
ssize_t cnt, i;
int r;
@@ -141,20 +134,13 @@ iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
}
/* Match on the vendor/product id */
- if (iwmbt_is_7260(&d)) {
+ device = iwmbt_is_supported(&d);
+ if (device != IWMBT_DEVICE_UNKNOWN) {
/*
* 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;
+ *iwmbt_device = device;
break;
}
}
@@ -200,6 +186,44 @@ iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
params->otp_bdaddr[0]);
}
+static void
+iwmbt_dump_version_tlv(struct iwmbt_version_tlv *ver)
+{
+ iwmbt_info("cnvi_top 0x%08x", ver->cnvi_top);
+ iwmbt_info("cnvr_top 0x%08x", ver->cnvr_top);
+ iwmbt_info("cnvi_bt 0x%08x", ver->cnvi_bt);
+ iwmbt_info("cnvr_bt 0x%08x", ver->cnvr_bt);
+ iwmbt_info("dev_rev_id 0x%04x", ver->dev_rev_id);
+ iwmbt_info("img_type 0x%02x", ver->img_type);
+ iwmbt_info("timestamp 0x%04x", ver->timestamp);
+ iwmbt_info("build_type 0x%02x", ver->build_type);
+ iwmbt_info("build_num 0x%08x", ver->build_num);
+ iwmbt_info("Secure Boot: %s", ver->secure_boot ? "on" : "off");
+ iwmbt_info("OTP lock: %s", ver->otp_lock ? "on" : "off");
+ iwmbt_info("API lock: %s", ver->api_lock ? "on" : "off");
+ iwmbt_info("Debug lock: %s", ver->debug_lock ? "on" : "off");
+ iwmbt_info("Minimum firmware build %u week %u year %u",
+ ver->min_fw_build_nn,
+ ver->min_fw_build_cw,
+ 2000 + ver->min_fw_build_yy);
+ iwmbt_info("limited_cce 0x%02x", ver->limited_cce);
+ iwmbt_info("sbe_type 0x%02x", ver->sbe_type);
+ iwmbt_info("OTC BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x",
+ ver->otp_bd_addr.b[5],
+ ver->otp_bd_addr.b[4],
+ ver->otp_bd_addr.b[3],
+ ver->otp_bd_addr.b[2],
+ ver->otp_bd_addr.b[1],
+ ver->otp_bd_addr.b[0]);
+ if (ver->img_type == 0x01 || ver->img_type == 0x03)
+ iwmbt_info("%s timestamp %u.%u buildtype %u build %u",
+ ver->img_type == 0x01 ? "Bootloader" : "Firmware",
+ 2000 + (ver->timestamp >> 8),
+ ver->timestamp & 0xff,
+ ver->build_type,
+ ver->build_num);
+}
+
static int
iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
{
@@ -227,10 +251,10 @@ iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
static int
iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
- uint32_t *boot_param)
+ uint32_t *boot_param, uint8_t hw_variant, uint8_t sbe_type)
{
struct iwmbt_firmware fw;
- int ret;
+ int header_len, ret = -1;
iwmbt_debug("loading %s", firmware_path);
@@ -240,12 +264,76 @@ iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
return (-1);
}
- /* Load in the firmware */
- ret = iwmbt_load_fwfile(hdl, &fw, boot_param);
+ iwmbt_debug("Firmware file size=%d", fw.len);
+
+ if (hw_variant <= 0x14) {
+ /*
+ * Hardware variants 0x0b, 0x0c, 0x11 - 0x14 .sfi file have
+ * a RSA header of 644 bytes followed by Command Buffer.
+ */
+ header_len = RSA_HEADER_LEN;
+ if (fw.len < header_len) {
+ iwmbt_err("Invalid size of firmware file (%d)", fw.len);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Check if the CSS Header version is RSA(0x00010000) */
+ if (le32dec(fw.buf + CSS_HEADER_OFFSET) != 0x00010000) {
+ iwmbt_err("Invalid CSS Header version");
+ ret = -1;
+ goto exit;
+ }
+
+ /* Only RSA secure boot engine supported */
+ if (sbe_type != 0x00) {
+ iwmbt_err("Invalid SBE type for hardware variant (%d)",
+ hw_variant);
+ ret = -1;
+ goto exit;
+ }
+
+ } else if (hw_variant >= 0x17) {
+ /*
+ * Hardware variants 0x17, 0x18 onwards support both RSA and
+ * ECDSA secure boot engine. As a result, the corresponding sfi
+ * file will have RSA header of 644, ECDSA header of 320 bytes
+ * followed by Command Buffer.
+ */
+ header_len = ECDSA_OFFSET + ECDSA_HEADER_LEN;
+ if (fw.len < header_len) {
+ iwmbt_err("Invalid size of firmware file (%d)", fw.len);
+ ret = -1;
+ goto exit;
+ }
+
+ /* Check if CSS header for ECDSA follows the RSA header */
+ if (fw.buf[ECDSA_OFFSET] != 0x06) {
+ ret = -1;
+ goto exit;
+ }
+
+ /* Check if the CSS Header version is ECDSA(0x00020000) */
+ if (le32dec(fw.buf + ECDSA_OFFSET + CSS_HEADER_OFFSET) != 0x00020000) {
+ iwmbt_err("Invalid CSS Header version");
+ ret = -1;
+ goto exit;
+ }
+ }
+
+ /* Load in the CSS header */
+ if (sbe_type == 0x00)
+ ret = iwmbt_load_rsa_header(hdl, &fw);
+ else if (sbe_type == 0x01)
+ ret = iwmbt_load_ecdsa_header(hdl, &fw);
if (ret < 0)
- iwmbt_debug("Loading firmware file failed");
+ goto exit;
- /* free it */
+ /* Load in the Command Buffer */
+ ret = iwmbt_load_fwfile(hdl, &fw, boot_param, header_len);
+
+exit:
+ /* free firmware */
iwmbt_fw_free(&fw);
return (ret);
@@ -318,6 +406,7 @@ main(int argc, char *argv[])
libusb_device *dev = NULL;
libusb_device_handle *hdl = NULL;
static struct iwmbt_version ver;
+ static struct iwmbt_version_tlv ver_tlv;
static struct iwmbt_boot_params params;
uint32_t boot_param;
int r;
@@ -327,7 +416,7 @@ main(int argc, char *argv[])
char *firmware_dir = NULL;
char *firmware_path = NULL;
int retcode = 1;
- int iwmbt_use_old_method = 0;
+ enum iwmbt_device iwmbt_device;
/* Parse command line arguments */
while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
@@ -372,7 +461,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, &iwmbt_use_old_method);
+ dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_device);
if (dev == NULL) {
iwmbt_err("device not found");
goto shutdown;
@@ -401,16 +490,16 @@ main(int argc, char *argv[])
goto shutdown;
}
- /* Get Intel version */
- r = iwmbt_get_version(hdl, &ver);
- if (r < 0) {
- 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);
+ if (iwmbt_device == IWMBT_DEVICE_7260) {
- if (iwmbt_use_old_method) {
+ /* Get Intel version */
+ r = iwmbt_get_version(hdl, &ver);
+ if (r < 0) {
+ iwmbt_debug("iwmbt_get_version() failed code %d", r);
+ goto shutdown;
+ }
+ iwmbt_dump_version(&ver);
+ iwmbt_debug("fw_patch_num=0x%02x", (int) ver.fw_patch_num);
/* fw_patch_num = >0 operational mode */
if (ver.fw_patch_num > 0x00) {
@@ -469,7 +558,16 @@ main(int argc, char *argv[])
iwmbt_info("Intel Event Mask is set");
(void)iwmbt_exit_manufacturer(hdl, 0x00);
- } else {
+ } else if (iwmbt_device == IWMBT_DEVICE_8260) {
+
+ /* Get Intel version */
+ r = iwmbt_get_version(hdl, &ver);
+ if (r < 0) {
+ 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) {
@@ -509,7 +607,7 @@ main(int argc, char *argv[])
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);
+ r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 0, 0);
free(firmware_path);
if (r < 0)
goto shutdown;
@@ -546,6 +644,93 @@ main(int argc, char *argv[])
r = iwmbt_set_event_mask(hdl);
if (r == 0)
iwmbt_info("Intel Event Mask is set");
+
+ } else {
+
+ /* Get Intel version */
+ r = iwmbt_get_version_tlv(hdl, &ver_tlv);
+ if (r < 0) {
+ iwmbt_debug("iwmbt_get_version_tlv() failed code %d", r);
+ goto shutdown;
+ }
+ iwmbt_dump_version_tlv(&ver_tlv);
+ iwmbt_debug("img_type=0x%02x", (int) ver_tlv.img_type);
+
+ /* img_type = 0x01 bootloader mode / 0x03 operational mode */
+ if (ver_tlv.img_type == 0x03) {
+ iwmbt_info("Firmware has already been downloaded");
+ retcode = 0;
+ goto reset;
+ }
+
+ if (ver_tlv.img_type != 0x01){
+ iwmbt_err("unknown img_type 0x%02x", (int) ver_tlv.img_type);
+ goto shutdown;
+ }
+
+ /* Check if firmware fragments are ACKed with a cmd complete event */
+ if (ver_tlv.limited_cce != 0x00) {
+ iwmbt_err("Unsupported Intel firmware loading method (%u)",
+ ver_tlv.limited_cce);
+ goto shutdown;
+ }
+
+ /* Check if secure boot engine is supported: 1 (ECDSA) or 0 (RSA) */
+ if (ver_tlv.sbe_type > 0x01) {
+ iwmbt_err("Unsupported secure boot engine (%u)",
+ ver_tlv.sbe_type);
+ goto shutdown;
+ }
+
+ /* Default the firmware path */
+ if (firmware_dir == NULL)
+ firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
+
+ firmware_path = iwmbt_get_fwname_tlv(&ver_tlv, 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,
+ ver_tlv.cnvi_bt >> 16 & 0x3f, ver_tlv.sbe_type);
+ free(firmware_path);
+ if (r < 0)
+ goto shutdown;
+
+ 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_tlv(&ver_tlv, 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");
+
+ iwmbt_info("Firmware download complete");
}
reset: