svn commit: r351197 - in head: targets/pseudo/userland tools/build/mk usr.sbin/bluetooth usr.sbin/bluetooth/iwmbtfw

Vladimir Kondratyev wulf at FreeBSD.org
Sun Aug 18 22:20:31 UTC 2019


Author: wulf
Date: Sun Aug 18 22:20:28 2019
New Revision: 351197
URL: https://svnweb.freebsd.org/changeset/base/351197

Log:
  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.
  
  PR:			237083
  Reviewed by:		hps, emax
  X-MFC with:		r351196
  Differential Revision:	https://reviews.freebsd.org/D21071

Added:
  head/usr.sbin/bluetooth/iwmbtfw/
  head/usr.sbin/bluetooth/iwmbtfw/Makefile   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf   (contents, props changed)
  head/usr.sbin/bluetooth/iwmbtfw/main.c   (contents, props changed)
Modified:
  head/targets/pseudo/userland/Makefile.depend
  head/tools/build/mk/OptionalObsoleteFiles.inc
  head/usr.sbin/bluetooth/Makefile

Modified: head/targets/pseudo/userland/Makefile.depend
==============================================================================
--- head/targets/pseudo/userland/Makefile.depend	Sun Aug 18 22:11:42 2019	(r351196)
+++ head/targets/pseudo/userland/Makefile.depend	Sun Aug 18 22:20:28 2019	(r351197)
@@ -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 \

Modified: head/tools/build/mk/OptionalObsoleteFiles.inc
==============================================================================
--- head/tools/build/mk/OptionalObsoleteFiles.inc	Sun Aug 18 22:11:42 2019	(r351196)
+++ head/tools/build/mk/OptionalObsoleteFiles.inc	Sun Aug 18 22:20:28 2019	(r351197)
@@ -471,6 +471,7 @@ OLD_FILES+=etc/bluetooth/hcsecd.conf
 OLD_FILES+=etc/bluetooth/hosts
 OLD_FILES+=etc/bluetooth/protocols
 OLD_FILES+=etc/defaults/bluetooth.device.conf
+OLD_FILES+=etc/devd/iwmbtfw.conf
 OLD_DIRS+=etc/bluetooth
 OLD_FILES+=etc/rc.d/bluetooth
 OLD_FILES+=etc/rc.d/bthidd
@@ -524,6 +525,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
@@ -601,6 +603,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

Modified: head/usr.sbin/bluetooth/Makefile
==============================================================================
--- head/usr.sbin/bluetooth/Makefile	Sun Aug 18 22:11:42 2019	(r351196)
+++ head/usr.sbin/bluetooth/Makefile	Sun Aug 18 22:20:28 2019	(r351197)
@@ -21,6 +21,7 @@ SUBDIR+=	ath3kfw
 SUBDIR+=	bcmfw
 SUBDIR+=	bthidcontrol
 SUBDIR+=	bthidd
+SUBDIR+=	iwmbtfw
 .endif
 
 .include <bsd.subdir.mk>

Added: head/usr.sbin/bluetooth/iwmbtfw/Makefile
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/Makefile	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+PACKAGE=	bluetooth
+CONFS=		iwmbtfw.conf
+CONFSDIR=       /etc/devd
+PROG=		iwmbtfw
+MAN=		iwmbtfw.8
+LIBADD+=	usb
+SRCS=		main.c iwmbt_fw.c iwmbt_hw.c
+
+.include <bsd.prog.mk>

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,47 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Adrian Chadd <adrian at freebsd.org>
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,148 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Adrian Chadd <adrian at freebsd.org>
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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);
+}

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,79 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Adrian Chadd <adrian at freebsd.org>
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,392 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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);
+}

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,88 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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_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

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,96 @@
+.\" Copyright (c) 2013, 2016 Adrian Chadd <adrian at freebsd.org>
+.\" Copyright (c) 2019 Vladimir Kondratyev <wulf at 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 at FreeBSD.org .
+.Sh BUGS
+Most likely.
+Please report if found.

Added: head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.conf	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,12 @@
+# $FreeBSD$
+#
+# 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";
+};

Added: head/usr.sbin/bluetooth/iwmbtfw/main.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/usr.sbin/bluetooth/iwmbtfw/main.c	Sun Aug 18 22:20:28 2019	(r351197)
@@ -0,0 +1,456 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2013 Adrian Chadd <adrian at freebsd.org>
+ * Copyright (c) 2019 Vladimir Kondratyev <wulf at 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;
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-head mailing list