FreeBSD Bugzilla – Attachment 205386 Details for
Bug 237083
[ubt] Init fails on Intel Wireless 8260/8265 (Thinkpad t480s and others)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
firmware downloader - userland part. downloader itself
iwmbt-user.diff (text/plain), 40.81 KB, created by
Vladimir Kondratyev
on 2019-06-27 22:05:59 UTC
(
hide
)
Description:
firmware downloader - userland part. downloader itself
Filename:
MIME Type:
Creator:
Vladimir Kondratyev
Created:
2019-06-27 22:05:59 UTC
Size:
40.81 KB
patch
obsolete
>commit 1bae824bbb73e56c978dfdc1149a484669e8cb68 >Author: Vladimir Kondratyev <vladimir@kondratyev.su> >Date: Thu Jun 6 19:44:35 2019 +0300 > > iwmbtfw: Firmware loader for Intel Wireless 8260 based Bluetooth USB devices > > Currently supported models are: 8260, 8265, 9560, 9260 and 22161. > Firmware files can be installed with comms/iwmbt-firmware port. > >diff --git a/sbin/devd/Makefile b/sbin/devd/Makefile >index 0d6c54f24f23..c2459272e104 100644 >--- a/sbin/devd/Makefile >+++ b/sbin/devd/Makefile >@@ -18,6 +18,9 @@ DEVD+= hyperv.conf > > .if ${MK_USB} != "no" > DEVD+= uath.conf ulpt.conf >+.if ${MK_BLUETOOTH} != "no" >+DEVD+= iwmbtfw.conf >+.endif > .endif > > .if ${MACHINE_ARCH} == "powerpc" >diff --git a/sbin/devd/iwmbtfw.conf b/sbin/devd/iwmbtfw.conf >new file mode 100644 >index 000000000000..62c44c013546 >--- /dev/null >+++ b/sbin/devd/iwmbtfw.conf >@@ -0,0 +1,9 @@ >+# Download Intel Wireless 8260/8265 bluetooth adaptor firmware >+notify 100 { >+ match "system" "USB"; >+ match "subsystem" "DEVICE"; >+ match "type" "ATTACH"; >+ match "vendor" "0x8087"; >+ match "product" "(0x0a2b|0x0aaa|0x0025|0x0026|0x0029)"; >+ action "/usr/sbin/iwmbtfw -d $cdev -f /usr/local/share/iwmbt-firmware"; >+}; >diff --git a/targets/pseudo/userland/Makefile.depend b/targets/pseudo/userland/Makefile.depend >index 934d7be54ed7..9d8640d9b2f7 100644 >--- a/targets/pseudo/userland/Makefile.depend >+++ b/targets/pseudo/userland/Makefile.depend >@@ -443,6 +443,7 @@ DIRDEPS+= \ > usr.sbin/bluetooth/hccontrol \ > usr.sbin/bluetooth/hcsecd \ > usr.sbin/bluetooth/hcseriald \ >+ usr.sbin/bluetooth/iwmbtfw \ > usr.sbin/bluetooth/l2control \ > usr.sbin/bluetooth/l2ping \ > usr.sbin/bluetooth/rfcomm_pppd \ >diff --git a/tools/build/mk/OptionalObsoleteFiles.inc b/tools/build/mk/OptionalObsoleteFiles.inc >index 58592329e11d..1f18951aea21 100644 >--- a/tools/build/mk/OptionalObsoleteFiles.inc >+++ b/tools/build/mk/OptionalObsoleteFiles.inc >@@ -523,6 +523,7 @@ OLD_FILES+=usr/sbin/btpand > OLD_FILES+=usr/sbin/hccontrol > OLD_FILES+=usr/sbin/hcsecd > OLD_FILES+=usr/sbin/hcseriald >+OLD_FILES+=usr/sbin/iwmbtfw > OLD_FILES+=usr/sbin/l2control > OLD_FILES+=usr/sbin/l2ping > OLD_FILES+=usr/sbin/rfcomm_pppd >@@ -600,6 +601,7 @@ OLD_FILES+=usr/share/man/man8/btpand.8.gz > OLD_FILES+=usr/share/man/man8/hccontrol.8.gz > OLD_FILES+=usr/share/man/man8/hcsecd.8.gz > OLD_FILES+=usr/share/man/man8/hcseriald.8.gz >+OLD_FILES+=usr/share/man/man8/iwmbtfw.8.gz > OLD_FILES+=usr/share/man/man8/l2control.8.gz > OLD_FILES+=usr/share/man/man8/l2ping.8.gz > OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz >@@ -9988,6 +9990,9 @@ OLD_FILES+=usr/sbin/local-unbound-control > .endif > > .if ${MK_USB} == no >+.if ${MK_BLUETOOTH} == no >+OLD_FILES+=etc/devd/iwmbtfw.conf >+.endif > OLD_FILES+=etc/devd/uath.conf > OLD_FILES+=etc/devd/uauth.conf > OLD_FILES+=etc/devd/ulpt.conf >diff --git a/usr.sbin/bluetooth/Makefile b/usr.sbin/bluetooth/Makefile >index 74900816cb2e..c380fc77d6ec 100644 >--- a/usr.sbin/bluetooth/Makefile >+++ b/usr.sbin/bluetooth/Makefile >@@ -21,6 +21,7 @@ SUBDIR+= ath3kfw > SUBDIR+= bcmfw > SUBDIR+= bthidcontrol > SUBDIR+= bthidd >+SUBDIR+= iwmbtfw > .endif > > .include <bsd.subdir.mk> >diff --git a/usr.sbin/bluetooth/iwmbtfw/Makefile b/usr.sbin/bluetooth/iwmbtfw/Makefile >new file mode 100644 >index 000000000000..23d72303fd8c >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/Makefile >@@ -0,0 +1,8 @@ >+# $FreeBSD$ >+ >+PROG= iwmbtfw >+MAN= iwmbtfw.8 >+LIBADD+= usb >+SRCS= main.c iwmbt_fw.c iwmbt_hw.c >+ >+.include <bsd.prog.mk> >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h >new file mode 100644 >index 000000000000..2a93b306ce5d >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h >@@ -0,0 +1,47 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD >+ * >+ * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org> >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+#ifndef __IWMBT_DEBUG_H__ >+#define __IWMBT_DEBUG_H__ >+ >+extern int iwmbt_do_debug; >+extern int iwmbt_do_info; >+ >+#define iwmbt_err(fmt, ...) \ >+ fprintf(stderr, "iwmbtfw: %s: "fmt"\n", __func__, ##__VA_ARGS__) >+#define iwmbt_info(fmt, ...) do { \ >+ if (iwmbt_do_info) \ >+ fprintf(stderr, "%s: "fmt"\n", __func__, ##__VA_ARGS__);\ >+} while (0) >+#define iwmbt_debug(fmt, ...) do { \ >+ if (iwmbt_do_debug) \ >+ fprintf(stderr, "%s: "fmt"\n", __func__, ##__VA_ARGS__);\ >+} while (0) >+ >+#endif >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c >new file mode 100644 >index 000000000000..7764f8bc4ac3 >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c >@@ -0,0 +1,148 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD >+ * >+ * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org> >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+#include <sys/types.h> >+#include <sys/endian.h> >+#include <sys/stat.h> >+ >+#include <err.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <unistd.h> >+ >+#include "iwmbt_fw.h" >+#include "iwmbt_dbg.h" >+ >+int >+iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname) >+{ >+ int fd; >+ struct stat sb; >+ unsigned char *buf; >+ ssize_t r; >+ int i; >+ >+ fd = open(fwname, O_RDONLY); >+ if (fd < 0) { >+ warn("%s: open: %s", __func__, fwname); >+ return (0); >+ } >+ >+ if (fstat(fd, &sb) != 0) { >+ warn("%s: stat: %s", __func__, fwname); >+ close(fd); >+ return (0); >+ } >+ >+ buf = calloc(1, sb.st_size); >+ if (buf == NULL) { >+ warn("%s: calloc", __func__); >+ close(fd); >+ return (0); >+ } >+ >+ i = 0; >+ /* XXX handle partial reads */ >+ r = read(fd, buf, sb.st_size); >+ if (r < 0) { >+ warn("%s: read", __func__); >+ free(buf); >+ close(fd); >+ return (0); >+ } >+ >+ if (r != sb.st_size) { >+ iwmbt_err("read len %d != file size %d", >+ (int) r, >+ (int) sb.st_size); >+ free(buf); >+ close(fd); >+ return (0); >+ } >+ >+ /* We have everything, so! */ >+ >+ memset(fw, 0, sizeof(*fw)); >+ >+ fw->fwname = strdup(fwname); >+ fw->len = sb.st_size; >+ fw->buf = buf; >+ >+ close(fd); >+ return (1); >+} >+ >+void >+iwmbt_fw_free(struct iwmbt_firmware *fw) >+{ >+ if (fw->fwname) >+ free(fw->fwname); >+ if (fw->buf) >+ free(fw->buf); >+ memset(fw, 0, sizeof(*fw)); >+} >+ >+char * >+iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params, >+ const char *prefix, const char *suffix) >+{ >+ char *fwname; >+ >+ switch (ver->hw_variant) { >+ case 0x0b: /* 8260 */ >+ case 0x0c: /* 8265 */ >+ asprintf(&fwname, "%s/ibt-%u-%u.%s", >+ prefix, >+ le16toh(ver->hw_variant), >+ le16toh(params->dev_revid), >+ suffix); >+ break; >+ >+ case 0x11: /* 9560 */ >+ case 0x12: /* 9260 */ >+ case 0x13: >+ case 0x14: /* 22161 */ >+ asprintf(&fwname, "%s/ibt-%u-%u-%u.%s", >+ prefix, >+ le16toh(ver->hw_variant), >+ le16toh(ver->hw_revision), >+ le16toh(ver->fw_revision), >+ suffix); >+ break; >+ >+ default: >+ fwname = NULL; >+ } >+ >+ return (fwname); >+} >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h >new file mode 100644 >index 000000000000..8291fed427f2 >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h >@@ -0,0 +1,79 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD >+ * >+ * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org> >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+#ifndef __IWMBT_FW_H__ >+#define __IWMBT_FW_H__ >+ >+struct iwmbt_version { >+ 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; >+} __attribute__ ((packed)); >+ >+struct iwmbt_boot_params { >+ 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; >+ uint8_t otp_bdaddr[6]; >+ 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; >+} __attribute__ ((packed)); >+ >+struct iwmbt_firmware { >+ char *fwname; >+ int len; >+ unsigned char *buf; >+}; >+ >+extern int iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname); >+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); >+ >+#endif >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c >new file mode 100644 >index 000000000000..172b4b30f0d0 >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c >@@ -0,0 +1,390 @@ >+/*- >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+#include <sys/types.h> >+#include <sys/endian.h> >+#include <sys/stat.h> >+ >+#include <err.h> >+#include <errno.h> >+#include <stddef.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <unistd.h> >+ >+#include <libusb.h> >+ >+#include "iwmbt_fw.h" >+#include "iwmbt_hw.h" >+#include "iwmbt_dbg.h" >+ >+#define XMIN(x, y) ((x) < (y) ? (x) : (y)) >+ >+static int >+iwmbt_send_fragment(struct libusb_device_handle *hdl, >+ uint8_t fragment_type, const void *data, uint8_t len, int timeout) >+{ >+ int ret, transferred; >+ uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; >+ struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf; >+ >+ memset(buf, 0, sizeof(buf)); >+ cmd->opcode = htole16(0xfc09), >+ cmd->length = len + 1, >+ cmd->data[0] = fragment_type; >+ memcpy(cmd->data + 1, data, len); >+ >+ ret = libusb_bulk_transfer(hdl, >+ IWMBT_BULK_OUT_ENDPOINT_ADDR, >+ (uint8_t *)cmd, >+ IWMBT_HCI_CMD_SIZE(cmd), >+ &transferred, >+ timeout); >+ >+ if (ret < 0 || transferred != IWMBT_HCI_CMD_SIZE(cmd)) { >+ iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu", >+ libusb_strerror(ret), >+ IWMBT_HCI_CMD_SIZE(cmd)); >+ return (-1); >+ } >+ >+ ret = libusb_bulk_transfer(hdl, >+ IWMBT_BULK_IN_ENDPOINT_ADDR, >+ buf, >+ sizeof(buf), >+ &transferred, >+ timeout); >+ >+ if (ret < 0) { >+ iwmbt_err("libusb_bulk_transfer() failed: err=%s", >+ libusb_strerror(ret)); >+ return (-1); >+ } >+ >+ return (0); >+} >+ >+static int >+iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd, >+ void *event, int size, int *transferred, int timeout) >+{ >+ int ret; >+ >+ ret = libusb_control_transfer(hdl, >+ LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE, >+ 0, >+ 0, >+ 0, >+ (uint8_t *)cmd, >+ IWMBT_HCI_CMD_SIZE(cmd), >+ timeout); >+ >+ if (ret < 0) { >+ iwmbt_err("libusb_control_transfer() failed: err=%s", >+ libusb_strerror(ret)); >+ return (ret); >+ } >+ >+ ret = libusb_interrupt_transfer(hdl, >+ IWMBT_INTERRUPT_ENDPOINT_ADDR, >+ event, >+ size, >+ transferred, >+ timeout); >+ >+ if (ret < 0) >+ iwmbt_err("libusb_interrupt_transfer() failed: err=%s", >+ libusb_strerror(ret)); >+ >+ return (ret); >+} >+ >+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); \ >+ \ >+ ret = iwmbt_send_fragment(hdl, \ >+ fragment_type, \ >+ fw->buf + sent, \ >+ XMIN(size, fw->len - sent), \ >+ IWMBT_HCI_CMD_TIMEOUT); \ >+ \ >+ if (ret < 0) { \ >+ iwmbt_debug("Failed to send "msg": code=%d", ret); \ >+ return (-1); \ >+ } \ >+ 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); >+ >+ IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment"); >+ IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1"); >+ IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2"); >+ >+ /* skip 4 bytes */ >+ sent += 4; >+ >+ IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1"); >+ IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2"); >+ >+ /* >+ * Send firmware chunks. Chunk len must be 4 byte aligned. >+ * multiple commands can be combined >+ */ >+ while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) { >+ cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready); >+ /* Parse firmware for Intel Reset HCI command parameter */ >+ if (cmd->opcode == htole16(0xfc0e)) { >+ *boot_param = le32dec(cmd->data); >+ iwmbt_debug("boot_param=0x%08x", *boot_param); >+ } >+ ready += IWMBT_HCI_CMD_SIZE(cmd); >+ while (ready >= 0xFC) { >+ IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk"); >+ ready -= 0xFC; >+ } >+ if (ready > 0 && ready % 4 == 0) { >+ IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk"); >+ ready = 0; >+ } >+ } >+ >+ /* Wait for firmware download completion event */ >+ ret = libusb_interrupt_transfer(hdl, >+ IWMBT_INTERRUPT_ENDPOINT_ADDR, >+ buf, >+ sizeof(buf), >+ &transferred, >+ IWMBT_LOADCMPL_TIMEOUT); >+ >+ if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { >+ iwmbt_err("libusb_interrupt_transfer() failed: " >+ "err=%s, size=%d", >+ libusb_strerror(ret), >+ transferred); >+ return (-1); >+ } >+ >+ /* Expect Vendor Specific Event 0x06 */ >+ event = (struct iwmbt_hci_event *)buf; >+ if (event->header.event != 0xFF || event->data[0] != 0x06) { >+ iwmbt_err("firmware download completion event missed"); >+ return (-1); >+ } >+ >+ return (0); >+} >+ >+int >+iwmbt_get_version(struct libusb_device_handle *hdl, >+ struct iwmbt_version *version) >+{ >+ int ret, transferred; >+ struct iwmbt_hci_event_cmd_compl*event; >+ struct iwmbt_hci_cmd cmd = { >+ .opcode = htole16(0xfc05), >+ .length = 0, >+ }; >+ uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)]; >+ >+ memset(buf, 0, sizeof(buf)); >+ >+ ret = iwmbt_hci_command(hdl, >+ &cmd, >+ buf, >+ sizeof(buf), >+ &transferred, >+ IWMBT_HCI_CMD_TIMEOUT); >+ >+ if (ret < 0 || transferred != sizeof(buf)) { >+ 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)); >+ >+ return (0); >+} >+ >+int >+iwmbt_get_boot_params(struct libusb_device_handle *hdl, >+ struct iwmbt_boot_params *params) >+{ >+ int ret, transferred = 0; >+ struct iwmbt_hci_event_cmd_compl *event; >+ struct iwmbt_hci_cmd cmd = { >+ .opcode = htole16(0xfc0d), >+ .length = 0, >+ }; >+ uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)]; >+ >+ memset(buf, 0, sizeof(buf)); >+ >+ ret = iwmbt_hci_command(hdl, >+ &cmd, >+ buf, >+ sizeof(buf), >+ &transferred, >+ IWMBT_HCI_CMD_TIMEOUT); >+ >+ if (ret < 0 || transferred != sizeof(buf)) { >+ iwmbt_debug("Can't get boot params: code=%d, size=%d", >+ ret, >+ transferred); >+ return (-1); >+ } >+ >+ event = (struct iwmbt_hci_event_cmd_compl *)buf; >+ memcpy(params, event->data, sizeof(struct iwmbt_boot_params)); >+ >+ return (0); >+} >+ >+int >+iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param) >+{ >+ int ret, transferred = 0; >+ struct iwmbt_hci_event *event; >+ static struct iwmbt_hci_cmd cmd = { >+ .opcode = htole16(0xfc01), >+ .length = 8, >+ .data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 }, >+ }; >+ uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE]; >+ >+ le32enc(cmd.data + 4, boot_param); >+ memset(buf, 0, sizeof(buf)); >+ >+ ret = iwmbt_hci_command(hdl, >+ &cmd, >+ buf, >+ sizeof(buf), >+ &transferred, >+ IWMBT_HCI_CMD_TIMEOUT); >+ >+ if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) { >+ iwmbt_debug("Intel Reset command failed: code=%d, size=%d", >+ ret, >+ transferred); >+ return (ret); >+ } >+ >+ /* expect Vendor Specific Event 0x02 */ >+ event = (struct iwmbt_hci_event *)buf; >+ if (event->header.event != 0xFF || event->data[0] != 0x02) { >+ iwmbt_err("Intel Reset completion event missed"); >+ return (-1); >+ } >+ >+ return (0); >+} >+ >+int >+iwmbt_load_ddc(struct libusb_device_handle *hdl, >+ const struct iwmbt_firmware *ddc) >+{ >+ int size, sent = 0; >+ int ret, transferred; >+ uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE]; >+ struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf; >+ >+ size = ddc->len; >+ >+ iwmbt_debug("file=%s, size=%d", ddc->fwname, size); >+ >+ while (size > 0) { >+ >+ memset(buf, 0, sizeof(buf)); >+ cmd->opcode = htole16(0xfc8b); >+ cmd->length = ddc->buf[sent] + 1; >+ memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size)); >+ >+ iwmbt_debug("transferring %d bytes, offset %d", >+ cmd->length, >+ sent); >+ >+ size -= cmd->length; >+ sent += cmd->length; >+ >+ ret = iwmbt_hci_command(hdl, >+ cmd, >+ buf, >+ sizeof(buf), >+ &transferred, >+ IWMBT_HCI_CMD_TIMEOUT); >+ >+ if (ret < 0) { >+ iwmbt_debug("Intel Write DDC failed: code=%d", ret); >+ return (-1); >+ } >+ } >+ >+ return (0); >+} >+ >+int >+iwmbt_set_event_mask(struct libusb_device_handle *hdl) >+{ >+ int ret, transferred = 0; >+ static struct iwmbt_hci_cmd cmd = { >+ .opcode = htole16(0xfc52), >+ .length = 8, >+ .data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 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("Intel Set Event Mask failed: code=%d", ret); >+ >+ return (ret); >+} >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h >new file mode 100644 >index 000000000000..28f6c3ac0e07 >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h >@@ -0,0 +1,89 @@ >+/*- >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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, >+ * without modification. >+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer >+ * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any >+ * redistribution must be conditioned upon including a substantially >+ * similar Disclaimer requirement for further binary redistribution. >+ * >+ * NO WARRANTY >+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS >+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT >+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY >+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL >+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES. >+ * >+ * $FreeBSD$ >+ */ >+#ifndef __IWMBT_HW_H__ >+#define __IWMBT_HW_H__ >+ >+/* USB control request (HCI command) structure */ >+struct iwmbt_hci_cmd { >+ uint16_t opcode; >+ uint8_t length; >+ uint8_t data[]; >+} __attribute__ ((packed)); >+ >+#define IWMBT_HCI_CMD_SIZE(cmd) \ >+ ((cmd)->length + offsetof(struct iwmbt_hci_cmd, data)) >+ >+/* USB interrupt transfer HCI event header structure */ >+struct iwmbt_hci_evhdr { >+ uint8_t event; >+ uint8_t length; >+} __attribute__ ((packed)); >+ >+/* USB interrupt transfer (generic HCI event) structure */ >+struct iwmbt_hci_event { >+ struct iwmbt_hci_evhdr header; >+ uint8_t data[]; >+} __attribute__ ((packed)); >+ >+/* USB interrupt transfer (HCI command completion event) structure */ >+struct iwmbt_hci_event_cmd_compl { >+ struct iwmbt_hci_evhdr header; >+ uint8_t numpkt; >+ uint16_t opcode; >+ uint8_t data[]; >+} __attribute__ ((packed)); >+ >+#define IWMBT_HCI_EVT_COMPL_SIZE(payload) \ >+ (offsetof(struct iwmbt_hci_event_cmd_compl, data) + sizeof(payload)) >+ >+#define IWMBT_CONTROL_ENDPOINT_ADDR 0x00 >+#define IWMBT_INTERRUPT_ENDPOINT_ADDR 0x81 >+#define IWMBT_BULK_IN_ENDPOINT_ADDR 0x82 >+#define IWMBT_BULK_OUT_ENDPOINT_ADDR 0x02 >+ >+#define IWMBT_HCI_MAX_CMD_SIZE 256 >+#define IWMBT_HCI_MAX_EVENT_SIZE 16 >+ >+#define IWMBT_HCI_CMD_TIMEOUT 2000 /* ms */ >+#define IWMBT_LOADCMPL_TIMEOUT 5000 /* ms */ >+ >+extern int iwmbt_load_fwfile(struct libusb_device_handle *hdl, >+ const struct iwmbt_firmware *fw, uint32_t *boot_param); >+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, >+ struct iwmbt_boot_params *params); >+extern int iwmbt_intel_reset(struct libusb_device_handle *hdl, >+ uint32_t boot_param); >+extern int iwmbt_load_ddc(struct libusb_device_handle *hdl, >+ const struct iwmbt_firmware *ddc); >+extern int iwmbt_set_event_mask(struct libusb_device_handle *hdl); >+ >+#endif >diff --git a/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 >new file mode 100644 >index 000000000000..3afbf54793f9 >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 >@@ -0,0 +1,96 @@ >+.\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@freebsd.org> >+.\" Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+.\" >+.\" 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. >+.\" >+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+.\" >+.\" $FreeBSD$ >+.\" >+.Dd June 4, 2019 >+.Dt IWMBTFW 8 >+.Os >+.Sh NAME >+.Nm iwmbtfw >+.Nd firmware download utility for Intel Wireless 8260/8265 chip based Bluetooth >+USB devices >+.Sh SYNOPSIS >+.Nm >+.Fl d Ar device_name >+.Fl f Ar firmware_path >+.Nm >+.Fl h >+.Sh DESCRIPTION >+The >+.Nm >+utility downloads the specified firmware file to the specified >+.Xr ugen 4 >+device. >+.Pp >+This utility will >+.Em only >+work with Intel Wireless 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 >+.Pq Dv USB_VENDOR_INTEL2 >+and the product ID should be one of the supported devices. >+.Pp >+Firmware files are available in the >+.Pa comms/iwmbt-firmware >+port. >+.Pp >+The >+.Nm >+utility will query the device to determine which firmware image and board >+configuration to load in at runtime. >+.Pp >+The options are as follows: >+.Bl -tag -width indent >+.It Fl D >+Enable verbose debugging. >+.It Fl d Ar device_name >+Specify >+.Xr ugen 4 >+device name. >+.It Fl I >+Enable informational debugging. >+.It Fl f Ar firmware_path >+Specify the directory containing the firmware files to search and upload. >+.It Fl h >+Display usage message and exit. >+.El >+.Sh EXIT STATUS >+.Ex -std >+.Sh SEE ALSO >+.Xr libusb 3 , >+.Xr ugen 4 , >+.Xr devd 8 >+.Sh AUTHORS >+.Nm >+is based on >+.Xr ath3kfw 8 >+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 . >+.Sh BUGS >+Most likely. >+Please report if found. >diff --git a/usr.sbin/bluetooth/iwmbtfw/main.c b/usr.sbin/bluetooth/iwmbtfw/main.c >new file mode 100644 >index 000000000000..ecd9d226b91f >--- /dev/null >+++ b/usr.sbin/bluetooth/iwmbtfw/main.c >@@ -0,0 +1,456 @@ >+/*- >+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD >+ * >+ * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org> >+ * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org> >+ * >+ * 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. >+ * >+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 THE AUTHOR 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. >+ * >+ * $FreeBSD$ >+ */ >+ >+#include <sys/param.h> >+#include <sys/stat.h> >+#include <sys/endian.h> >+ >+#include <err.h> >+#include <errno.h> >+#include <fcntl.h> >+#include <libgen.h> >+#include <stdio.h> >+#include <stdlib.h> >+#include <string.h> >+#include <unistd.h> >+ >+#include <libusb.h> >+ >+#include "iwmbt_fw.h" >+#include "iwmbt_hw.h" >+#include "iwmbt_dbg.h" >+ >+#define _DEFAULT_IWMBT_FIRMWARE_PATH "/usr/share/firmware/intel" >+ >+int iwmbt_do_debug = 0; >+int iwmbt_do_info = 0; >+ >+struct iwmbt_devid { >+ uint16_t product_id; >+ uint16_t vendor_id; >+}; >+ >+static struct iwmbt_devid iwmbt_list[] = { >+ >+ /* 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 }, >+}; >+ >+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)) { >+ iwmbt_info("found 8260/8265"); >+ return (1); >+ } >+ } >+ >+ /* Not found */ >+ return (0); >+} >+ >+static libusb_device * >+iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id) >+{ >+ libusb_device **list, *dev = NULL, *found = NULL; >+ struct libusb_device_descriptor d; >+ ssize_t cnt, i; >+ int r; >+ >+ cnt = libusb_get_device_list(ctx, &list); >+ if (cnt < 0) { >+ iwmbt_err("libusb_get_device_list() failed: code %lld", >+ (long long int) cnt); >+ return (NULL); >+ } >+ >+ /* >+ * Scan through USB device list. >+ */ >+ for (i = 0; i < cnt; i++) { >+ dev = list[i]; >+ if (bus_id == libusb_get_bus_number(dev) && >+ dev_id == libusb_get_device_address(dev)) { >+ /* Get the device descriptor for this device entry */ >+ r = libusb_get_device_descriptor(dev, &d); >+ if (r != 0) { >+ iwmbt_err("libusb_get_device_descriptor: %s", >+ libusb_strerror(r)); >+ break; >+ } >+ >+ /* Match on the vendor/product id */ >+ if (iwmbt_is_8260(&d)) { >+ /* >+ * Take a reference so it's not freed later on. >+ */ >+ found = libusb_ref_device(dev); >+ break; >+ } >+ } >+ } >+ >+ libusb_free_device_list(list, 1); >+ return (found); >+} >+ >+static void >+iwmbt_dump_version(struct iwmbt_version *ver) >+{ >+ iwmbt_info("status 0x%02x", ver->status); >+ iwmbt_info("hw_platform 0x%02x", ver->hw_platform); >+ iwmbt_info("hw_variant 0x%02x", ver->hw_variant); >+ iwmbt_info("hw_revision 0x%02x", ver->hw_revision); >+ iwmbt_info("fw_variant 0x%02x", ver->fw_variant); >+ iwmbt_info("fw_revision 0x%02x", ver->fw_revision); >+ iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num); >+ iwmbt_info("fw_build_ww 0x%02x", ver->fw_build_ww); >+ iwmbt_info("fw_build_yy 0x%02x", ver->fw_build_yy); >+ iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num); >+} >+ >+static void >+iwmbt_dump_boot_params(struct iwmbt_boot_params *params) >+{ >+ iwmbt_info("Device revision: %u", le16toh(params->dev_revid)); >+ iwmbt_info("Secure Boot: %s", params->secure_boot ? "on" : "off"); >+ iwmbt_info("OTP lock: %s", params->otp_lock ? "on" : "off"); >+ iwmbt_info("API lock: %s", params->api_lock ? "on" : "off"); >+ iwmbt_info("Debug lock: %s", params->debug_lock ? "on" : "off"); >+ iwmbt_info("Minimum firmware build %u week %u year %u", >+ params->min_fw_build_nn, >+ params->min_fw_build_cw, >+ 2000 + params->min_fw_build_yy); >+ iwmbt_info("OTC BD_ADDR: %02x:%02x:%02x:%02x:%02x:%02x", >+ params->otp_bdaddr[5], >+ params->otp_bdaddr[4], >+ params->otp_bdaddr[3], >+ params->otp_bdaddr[2], >+ params->otp_bdaddr[1], >+ params->otp_bdaddr[0]); >+} >+ >+static int >+iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path, >+ uint32_t *boot_param) >+{ >+ 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_load_fwfile(hdl, &fw, boot_param); >+ if (ret < 0) >+ iwmbt_debug("Loading firmware file failed"); >+ >+ /* free it */ >+ iwmbt_fw_free(&fw); >+ >+ return (ret); >+} >+ >+static int >+iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path) >+{ >+ struct iwmbt_firmware ddc; >+ int ret; >+ >+ iwmbt_debug("loading %s", ddc_path); >+ >+ /* Read in the DDC file */ >+ if (iwmbt_fw_read(&ddc, ddc_path) <= 0) { >+ iwmbt_debug("iwmbt_fw_read() failed"); >+ return (-1); >+ } >+ >+ /* Load in the DDC file */ >+ ret = iwmbt_load_ddc(hdl, &ddc); >+ if (ret < 0) >+ iwmbt_debug("Loading DDC file failed"); >+ >+ /* free it */ >+ iwmbt_fw_free(&ddc); >+ >+ return (ret); >+} >+ >+/* >+ * Parse ugen name and extract device's bus and address >+ */ >+ >+static int >+parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr) >+{ >+ char *ep; >+ >+ if (strncmp(ugen, "ugen", 4) != 0) >+ return (-1); >+ >+ *bus = (uint8_t) strtoul(ugen + 4, &ep, 10); >+ if (*ep != '.') >+ return (-1); >+ >+ *addr = (uint8_t) strtoul(ep + 1, &ep, 10); >+ if (*ep != '\0') >+ return (-1); >+ >+ return (0); >+} >+ >+static void >+usage(void) >+{ >+ fprintf(stderr, >+ "Usage: iwmbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n"); >+ fprintf(stderr, " -D: enable debugging\n"); >+ fprintf(stderr, " -d: device to operate upon\n"); >+ fprintf(stderr, " -f: firmware path, if not default\n"); >+ fprintf(stderr, " -I: enable informational output\n"); >+ exit(127); >+} >+ >+int >+main(int argc, char *argv[]) >+{ >+ libusb_context *ctx = NULL; >+ libusb_device *dev = NULL; >+ libusb_device_handle *hdl = NULL; >+ static struct iwmbt_version ver; >+ static struct iwmbt_boot_params params; >+ uint32_t boot_param; >+ int r; >+ uint8_t bus_id = 0, dev_id = 0; >+ int devid_set = 0; >+ int n; >+ char *firmware_dir = NULL; >+ char *firmware_path = NULL; >+ int retcode = 1; >+ >+ /* Parse command line arguments */ >+ while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) { >+ switch (n) { >+ case 'd': /* ugen device name */ >+ devid_set = 1; >+ if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0) >+ usage(); >+ break; >+ case 'D': >+ iwmbt_do_debug = 1; >+ break; >+ case 'f': /* firmware dir */ >+ if (firmware_dir) >+ free(firmware_dir); >+ firmware_dir = strdup(optarg); >+ break; >+ case 'I': >+ iwmbt_do_info = 1; >+ break; >+ case 'h': >+ default: >+ usage(); >+ break; >+ /* NOT REACHED */ >+ } >+ } >+ >+ /* Ensure the devid was given! */ >+ if (devid_set == 0) { >+ usage(); >+ /* NOTREACHED */ >+ } >+ >+ /* libusb setup */ >+ r = libusb_init(&ctx); >+ if (r != 0) { >+ iwmbt_err("libusb_init failed: code %d", r); >+ exit(127); >+ } >+ >+ 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); >+ if (dev == NULL) { >+ iwmbt_err("device not found"); >+ goto shutdown; >+ } >+ >+ /* XXX enforce that bInterfaceNumber is 0 */ >+ >+ /* XXX enforce the device/product id if they're non-zero */ >+ >+ /* Grab device handle */ >+ r = libusb_open(dev, &hdl); >+ if (r != 0) { >+ iwmbt_err("libusb_open() failed: code %d", r); >+ goto shutdown; >+ } >+ >+ /* Check if ng_ubt is attached */ >+ r = libusb_kernel_driver_active(hdl, 0); >+ if (r < 0) { >+ iwmbt_err("libusb_kernel_driver_active() failed: code %d", r); >+ goto shutdown; >+ } >+ if (r > 0) { >+ iwmbt_info("Firmware has already been downloaded"); >+ retcode = 0; >+ goto shutdown; >+ } >+ >+ /* Get Intel version */ >+ r = iwmbt_get_version(hdl, &ver); >+ if (r < 0) { >+ iwmbt_debug("iwmbt_get_version() failedL 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"); >+ 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: >+ >+ /* Ask kernel driver to probe and attach device again */ >+ r = libusb_reset_device(hdl); >+ if (r != 0) >+ iwmbt_err("libusb_reset_device() failed: %s", >+ libusb_strerror(r)); >+ >+shutdown: >+ >+ /* Shutdown */ >+ >+ if (hdl != NULL) >+ libusb_close(hdl); >+ >+ if (dev != NULL) >+ libusb_unref_device(dev); >+ >+ if (ctx != NULL) >+ libusb_exit(ctx); >+ >+ if (retcode == 0) >+ iwmbt_info("Firmware download is succesful!"); >+ else >+ iwmbt_err("Firmware download failed!"); >+ >+ return (retcode); >+}
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 237083
:
204303
|
205385
| 205386 |
205387
|
205388
|
206565
|
206566