View | Details | Raw Unified | Return to bug 237083 | Differences between
and this patch

Collapse All | Expand All

(-)b/sbin/devd/Makefile (+3 lines)
Lines 18-23 DEVD+= hyperv.conf Link Here
18
18
19
.if ${MK_USB} != "no"
19
.if ${MK_USB} != "no"
20
DEVD+=	uath.conf ulpt.conf
20
DEVD+=	uath.conf ulpt.conf
21
.if ${MK_BLUETOOTH} != "no"
22
DEVD+=	iwmbtfw.conf
23
.endif
21
.endif
24
.endif
22
25
23
.if ${MACHINE_ARCH} == "powerpc"
26
.if ${MACHINE_ARCH} == "powerpc"
(-)b/sbin/devd/iwmbtfw.conf (+9 lines)
Added Link Here
1
# Download Intel Wireless 8260/8265 bluetooth adaptor firmware
2
notify 100 {
3
	match "system"		"USB";
4
	match "subsystem"	"DEVICE";
5
	match "type"		"ATTACH";
6
	match "vendor"		"0x8087";
7
	match "product"		"(0x0a2b|0x0aaa|0x0025|0x0026|0x0029)";
8
	action "/usr/sbin/iwmbtfw -d $cdev -f /usr/local/share/iwmbt-firmware";
9
};
(-)b/targets/pseudo/userland/Makefile.depend (+1 lines)
Lines 443-448 DIRDEPS+= \ Link Here
443
	usr.sbin/bluetooth/hccontrol \
443
	usr.sbin/bluetooth/hccontrol \
444
	usr.sbin/bluetooth/hcsecd \
444
	usr.sbin/bluetooth/hcsecd \
445
	usr.sbin/bluetooth/hcseriald \
445
	usr.sbin/bluetooth/hcseriald \
446
	usr.sbin/bluetooth/iwmbtfw \
446
	usr.sbin/bluetooth/l2control \
447
	usr.sbin/bluetooth/l2control \
447
	usr.sbin/bluetooth/l2ping \
448
	usr.sbin/bluetooth/l2ping \
448
	usr.sbin/bluetooth/rfcomm_pppd \
449
	usr.sbin/bluetooth/rfcomm_pppd \
(-)b/tools/build/mk/OptionalObsoleteFiles.inc (+5 lines)
Lines 523-528 OLD_FILES+=usr/sbin/btpand Link Here
523
OLD_FILES+=usr/sbin/hccontrol
523
OLD_FILES+=usr/sbin/hccontrol
524
OLD_FILES+=usr/sbin/hcsecd
524
OLD_FILES+=usr/sbin/hcsecd
525
OLD_FILES+=usr/sbin/hcseriald
525
OLD_FILES+=usr/sbin/hcseriald
526
OLD_FILES+=usr/sbin/iwmbtfw
526
OLD_FILES+=usr/sbin/l2control
527
OLD_FILES+=usr/sbin/l2control
527
OLD_FILES+=usr/sbin/l2ping
528
OLD_FILES+=usr/sbin/l2ping
528
OLD_FILES+=usr/sbin/rfcomm_pppd
529
OLD_FILES+=usr/sbin/rfcomm_pppd
Lines 600-605 OLD_FILES+=usr/share/man/man8/btpand.8.gz Link Here
600
OLD_FILES+=usr/share/man/man8/hccontrol.8.gz
601
OLD_FILES+=usr/share/man/man8/hccontrol.8.gz
601
OLD_FILES+=usr/share/man/man8/hcsecd.8.gz
602
OLD_FILES+=usr/share/man/man8/hcsecd.8.gz
602
OLD_FILES+=usr/share/man/man8/hcseriald.8.gz
603
OLD_FILES+=usr/share/man/man8/hcseriald.8.gz
604
OLD_FILES+=usr/share/man/man8/iwmbtfw.8.gz
603
OLD_FILES+=usr/share/man/man8/l2control.8.gz
605
OLD_FILES+=usr/share/man/man8/l2control.8.gz
604
OLD_FILES+=usr/share/man/man8/l2ping.8.gz
606
OLD_FILES+=usr/share/man/man8/l2ping.8.gz
605
OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz
607
OLD_FILES+=usr/share/man/man8/rfcomm_pppd.8.gz
Lines 9988-9993 OLD_FILES+=usr/sbin/local-unbound-control Link Here
9988
.endif
9990
.endif
9989
9991
9990
.if ${MK_USB} == no
9992
.if ${MK_USB} == no
9993
.if ${MK_BLUETOOTH} == no
9994
OLD_FILES+=etc/devd/iwmbtfw.conf
9995
.endif
9991
OLD_FILES+=etc/devd/uath.conf
9996
OLD_FILES+=etc/devd/uath.conf
9992
OLD_FILES+=etc/devd/uauth.conf
9997
OLD_FILES+=etc/devd/uauth.conf
9993
OLD_FILES+=etc/devd/ulpt.conf
9998
OLD_FILES+=etc/devd/ulpt.conf
(-)b/usr.sbin/bluetooth/Makefile (+1 lines)
Lines 21-26 SUBDIR+= ath3kfw Link Here
21
SUBDIR+=	bcmfw
21
SUBDIR+=	bcmfw
22
SUBDIR+=	bthidcontrol
22
SUBDIR+=	bthidcontrol
23
SUBDIR+=	bthidd
23
SUBDIR+=	bthidd
24
SUBDIR+=	iwmbtfw
24
.endif
25
.endif
25
26
26
.include <bsd.subdir.mk>
27
.include <bsd.subdir.mk>
(-)b/usr.sbin/bluetooth/iwmbtfw/Makefile (+8 lines)
Added Link Here
1
# $FreeBSD$
2
3
PROG=		iwmbtfw
4
MAN=		iwmbtfw.8
5
LIBADD+=	usb
6
SRCS=		main.c iwmbt_fw.c iwmbt_hw.c
7
8
.include <bsd.prog.mk>
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbt_dbg.h (+47 lines)
Added Link Here
1
/*-
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * $FreeBSD$
29
 */
30
#ifndef	__IWMBT_DEBUG_H__
31
#define	__IWMBT_DEBUG_H__
32
33
extern	int iwmbt_do_debug;
34
extern	int iwmbt_do_info;
35
36
#define	iwmbt_err(fmt, ...)						\
37
	fprintf(stderr, "iwmbtfw: %s: "fmt"\n", __func__, ##__VA_ARGS__)
38
#define	iwmbt_info(fmt, ...)	do {					\
39
	if (iwmbt_do_info)						\
40
		fprintf(stderr, "%s: "fmt"\n", __func__, ##__VA_ARGS__);\
41
} while (0)
42
#define	iwmbt_debug(fmt, ...)	do {					\
43
	if (iwmbt_do_debug)						\
44
		fprintf(stderr, "%s: "fmt"\n", __func__, ##__VA_ARGS__);\
45
} while (0)
46
47
#endif
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.c (+148 lines)
Added Link Here
1
/*-
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * $FreeBSD$
29
 */
30
31
#include <sys/types.h>
32
#include <sys/endian.h>
33
#include <sys/stat.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <stdio.h>
39
#include <stdlib.h>
40
#include <string.h>
41
#include <unistd.h>
42
43
#include "iwmbt_fw.h"
44
#include "iwmbt_dbg.h"
45
46
int
47
iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname)
48
{
49
	int fd;
50
	struct stat sb;
51
	unsigned char *buf;
52
	ssize_t r;
53
	int i;
54
55
	fd = open(fwname, O_RDONLY);
56
	if (fd < 0) {
57
		warn("%s: open: %s", __func__, fwname);
58
		return (0);
59
	}
60
61
	if (fstat(fd, &sb) != 0) {
62
		warn("%s: stat: %s", __func__, fwname);
63
		close(fd);
64
		return (0);
65
	}
66
67
	buf = calloc(1, sb.st_size);
68
	if (buf == NULL) {
69
		warn("%s: calloc", __func__);
70
		close(fd);
71
		return (0);
72
	}
73
74
	i = 0;
75
	/* XXX handle partial reads */
76
	r = read(fd, buf, sb.st_size);
77
	if (r < 0) {
78
		warn("%s: read", __func__);
79
		free(buf);
80
		close(fd);
81
		return (0);
82
	}
83
84
	if (r != sb.st_size) {
85
		iwmbt_err("read len %d != file size %d",
86
		    (int) r,
87
		    (int) sb.st_size);
88
		free(buf);
89
		close(fd);
90
		return (0);
91
	}
92
93
	/* We have everything, so! */
94
95
	memset(fw, 0, sizeof(*fw));
96
97
	fw->fwname = strdup(fwname);
98
	fw->len = sb.st_size;
99
	fw->buf = buf;
100
101
	close(fd);
102
	return (1);
103
}
104
105
void
106
iwmbt_fw_free(struct iwmbt_firmware *fw)
107
{
108
	if (fw->fwname)
109
		free(fw->fwname);
110
	if (fw->buf)
111
		free(fw->buf);
112
	memset(fw, 0, sizeof(*fw));
113
}
114
115
char *
116
iwmbt_get_fwname(struct iwmbt_version *ver, struct iwmbt_boot_params *params,
117
    const char *prefix, const char *suffix)
118
{
119
	char *fwname;
120
121
	switch (ver->hw_variant) {
122
	case 0x0b:	/* 8260 */
123
	case 0x0c:	/* 8265 */
124
		asprintf(&fwname, "%s/ibt-%u-%u.%s",
125
		    prefix,
126
		    le16toh(ver->hw_variant),
127
		    le16toh(params->dev_revid),
128
		    suffix);
129
		break;
130
131
	case 0x11:	/* 9560 */
132
	case 0x12:	/* 9260 */
133
	case 0x13:
134
	case 0x14:	/* 22161 */
135
		asprintf(&fwname, "%s/ibt-%u-%u-%u.%s",
136
		    prefix,
137
		    le16toh(ver->hw_variant),
138
		    le16toh(ver->hw_revision),
139
		    le16toh(ver->fw_revision),
140
		    suffix);
141
		break;
142
143
	default:
144
		fwname = NULL;
145
	}
146
147
	return (fwname);
148
}
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbt_fw.h (+79 lines)
Added Link Here
1
/*-
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * $FreeBSD$
29
 */
30
31
#ifndef	__IWMBT_FW_H__
32
#define	__IWMBT_FW_H__
33
34
struct iwmbt_version {
35
	uint8_t status;
36
	uint8_t hw_platform;
37
	uint8_t hw_variant;
38
	uint8_t hw_revision;
39
	uint8_t fw_variant;
40
	uint8_t fw_revision;
41
	uint8_t fw_build_num;
42
	uint8_t fw_build_ww;
43
	uint8_t fw_build_yy;
44
	uint8_t fw_patch_num;
45
} __attribute__ ((packed));
46
47
struct iwmbt_boot_params {
48
	uint8_t status;
49
	uint8_t otp_format;
50
	uint8_t otp_content;
51
	uint8_t otp_patch;
52
	uint16_t dev_revid;
53
	uint8_t secure_boot;
54
	uint8_t key_from_hdr;
55
	uint8_t key_type;
56
	uint8_t otp_lock;
57
	uint8_t api_lock;
58
	uint8_t debug_lock;
59
	uint8_t otp_bdaddr[6];
60
	uint8_t min_fw_build_nn;
61
	uint8_t min_fw_build_cw;
62
	uint8_t min_fw_build_yy;
63
	uint8_t limited_cce;
64
	uint8_t unlocked_state;
65
} __attribute__ ((packed));
66
67
struct iwmbt_firmware {
68
	char *fwname;
69
	int len;
70
	unsigned char *buf;
71
};
72
73
extern	int iwmbt_fw_read(struct iwmbt_firmware *fw, const char *fwname);
74
extern	void iwmbt_fw_free(struct iwmbt_firmware *fw);
75
extern	char *iwmbt_get_fwname(struct iwmbt_version *ver,
76
	struct iwmbt_boot_params *params, const char *prefix,
77
	const char *suffix);
78
79
#endif
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.c (+390 lines)
Added Link Here
1
/*-
2
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer.
9
 * 2. Redistributions in binary form must reproduce the above copyright
10
 *    notice, this list of conditions and the following disclaimer in the
11
 *    documentation and/or other materials provided with the distribution.
12
 *
13
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
 * SUCH DAMAGE.
24
 *
25
 * $FreeBSD$
26
 */
27
28
#include <sys/types.h>
29
#include <sys/endian.h>
30
#include <sys/stat.h>
31
32
#include <err.h>
33
#include <errno.h>
34
#include <stddef.h>
35
#include <stdio.h>
36
#include <stdlib.h>
37
#include <string.h>
38
#include <unistd.h>
39
40
#include <libusb.h>
41
42
#include "iwmbt_fw.h"
43
#include "iwmbt_hw.h"
44
#include "iwmbt_dbg.h"
45
46
#define	XMIN(x, y)	((x) < (y) ? (x) : (y))
47
48
static int
49
iwmbt_send_fragment(struct libusb_device_handle *hdl,
50
    uint8_t fragment_type, const void *data, uint8_t len, int timeout)
51
{
52
	int ret, transferred;
53
	uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
54
	struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *) buf;
55
56
	memset(buf, 0, sizeof(buf));
57
	cmd->opcode = htole16(0xfc09),
58
	cmd->length = len + 1,
59
	cmd->data[0] = fragment_type;
60
	memcpy(cmd->data + 1, data, len);
61
62
	ret = libusb_bulk_transfer(hdl,
63
	    IWMBT_BULK_OUT_ENDPOINT_ADDR,
64
	    (uint8_t *)cmd,
65
	    IWMBT_HCI_CMD_SIZE(cmd),
66
	    &transferred,
67
	    timeout);
68
69
	if (ret < 0 || transferred != IWMBT_HCI_CMD_SIZE(cmd)) {
70
		iwmbt_err("libusb_bulk_transfer() failed: err=%s, size=%zu",
71
		    libusb_strerror(ret),
72
		    IWMBT_HCI_CMD_SIZE(cmd));
73
		return (-1);
74
	}
75
76
	ret = libusb_bulk_transfer(hdl,
77
	    IWMBT_BULK_IN_ENDPOINT_ADDR,
78
	    buf,
79
	    sizeof(buf),
80
	    &transferred,
81
	    timeout);
82
83
	if (ret < 0) {
84
		iwmbt_err("libusb_bulk_transfer() failed: err=%s",
85
		    libusb_strerror(ret));
86
		return (-1);
87
	}
88
89
	return (0);
90
}
91
92
static int
93
iwmbt_hci_command(struct libusb_device_handle *hdl, struct iwmbt_hci_cmd *cmd,
94
    void *event, int size, int *transferred, int timeout)
95
{
96
	int ret;
97
98
	ret = libusb_control_transfer(hdl,
99
	    LIBUSB_REQUEST_TYPE_CLASS | LIBUSB_RECIPIENT_DEVICE,
100
	    0,
101
	    0,
102
	    0,
103
	    (uint8_t *)cmd,
104
	    IWMBT_HCI_CMD_SIZE(cmd),
105
	    timeout);
106
107
	if (ret < 0) {
108
		iwmbt_err("libusb_control_transfer() failed: err=%s",
109
		    libusb_strerror(ret));
110
		return (ret);
111
	}
112
113
	ret = libusb_interrupt_transfer(hdl,
114
	    IWMBT_INTERRUPT_ENDPOINT_ADDR,
115
	    event,
116
	    size,
117
	    transferred,
118
	    timeout);
119
120
	if (ret < 0)
121
		iwmbt_err("libusb_interrupt_transfer() failed: err=%s",
122
		    libusb_strerror(ret));
123
124
	return (ret);
125
}
126
127
int
128
iwmbt_load_fwfile(struct libusb_device_handle *hdl,
129
    const struct iwmbt_firmware *fw, uint32_t *boot_param)
130
{
131
	int ready = 0, sent = 0;
132
	int ret, transferred;
133
	struct iwmbt_hci_cmd *cmd;
134
	struct iwmbt_hci_event *event;
135
	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
136
137
#define	IWMBT_SEND_FRAGMENT(fragment_type, size, msg)	do {		\
138
	iwmbt_debug("transferring %d bytes, offset %d", size, sent);	\
139
									\
140
	ret = iwmbt_send_fragment(hdl,					\
141
	    fragment_type,						\
142
	    fw->buf + sent,						\
143
	    XMIN(size, fw->len - sent),					\
144
	    IWMBT_HCI_CMD_TIMEOUT);					\
145
									\
146
	if (ret < 0) {							\
147
		iwmbt_debug("Failed to send "msg": code=%d", ret);	\
148
		return (-1);						\
149
	}								\
150
	sent += size;							\
151
} while (0)
152
153
	if (fw->len < 644) {
154
		iwmbt_err("Invalid size of firmware file (%d)", fw->len);
155
		return (-1);
156
	}
157
158
	iwmbt_debug("file=%s, size=%d", fw->fwname, fw->len);
159
160
	IWMBT_SEND_FRAGMENT(0x00, 0x80, "CCS segment");
161
	IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 1");
162
	IWMBT_SEND_FRAGMENT(0x03, 0x80, "public key / part 2");
163
164
	/* skip 4 bytes */
165
	sent += 4;
166
167
	IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 1");
168
	IWMBT_SEND_FRAGMENT(0x02, 0x80, "signature / part 2");
169
170
	/*
171
	 * Send firmware chunks. Chunk len must be 4 byte aligned.
172
	 * multiple commands can be combined
173
	 */
174
	while (fw->len - sent - ready >= (int) sizeof(struct iwmbt_hci_cmd)) {
175
		cmd = (struct iwmbt_hci_cmd *)(fw->buf + sent + ready);
176
		/* Parse firmware for Intel Reset HCI command parameter */
177
		if (cmd->opcode == htole16(0xfc0e)) {
178
			*boot_param = le32dec(cmd->data);
179
			iwmbt_debug("boot_param=0x%08x", *boot_param);
180
		}
181
		ready += IWMBT_HCI_CMD_SIZE(cmd);
182
		while (ready >= 0xFC) {
183
			IWMBT_SEND_FRAGMENT(0x01, 0xFC, "firmware chunk");
184
			ready -= 0xFC;
185
		}
186
		if (ready > 0 && ready % 4 == 0) {
187
			IWMBT_SEND_FRAGMENT(0x01, ready, "firmware chunk");
188
			ready = 0;
189
		}
190
	}
191
192
	/* Wait for firmware download completion event */
193
	ret = libusb_interrupt_transfer(hdl,
194
	    IWMBT_INTERRUPT_ENDPOINT_ADDR,
195
	    buf,
196
	    sizeof(buf),
197
	    &transferred,
198
	    IWMBT_LOADCMPL_TIMEOUT);
199
200
	if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
201
		iwmbt_err("libusb_interrupt_transfer() failed: "
202
		    "err=%s, size=%d",
203
		    libusb_strerror(ret),
204
		    transferred);
205
		return (-1);
206
	}
207
208
	/* Expect Vendor Specific Event 0x06 */
209
	event = (struct iwmbt_hci_event *)buf;
210
	if (event->header.event != 0xFF || event->data[0] != 0x06) {
211
		iwmbt_err("firmware download completion event missed");
212
		return (-1);
213
	}
214
215
	return (0);
216
}
217
218
int
219
iwmbt_get_version(struct libusb_device_handle *hdl,
220
    struct iwmbt_version *version)
221
{
222
	int ret, transferred;
223
	struct iwmbt_hci_event_cmd_compl*event;
224
	struct iwmbt_hci_cmd cmd = {
225
		.opcode = htole16(0xfc05),
226
		.length = 0,
227
	};
228
	uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_version)];
229
230
	memset(buf, 0, sizeof(buf));
231
232
	ret = iwmbt_hci_command(hdl,
233
	    &cmd,
234
	    buf,
235
	    sizeof(buf),
236
	    &transferred,
237
	    IWMBT_HCI_CMD_TIMEOUT);
238
239
	if (ret < 0 || transferred != sizeof(buf)) {
240
		 iwmbt_debug("Can't get version: : code=%d, size=%d",
241
		     ret,
242
		     transferred);
243
		 return (-1);
244
	}
245
246
	event = (struct iwmbt_hci_event_cmd_compl *)buf;
247
	memcpy(version, event->data, sizeof(struct iwmbt_version));
248
249
	return (0);
250
}
251
252
int
253
iwmbt_get_boot_params(struct libusb_device_handle *hdl,
254
    struct iwmbt_boot_params *params)
255
{
256
	int ret, transferred = 0;
257
	struct iwmbt_hci_event_cmd_compl *event;
258
	struct iwmbt_hci_cmd cmd = {
259
		.opcode = htole16(0xfc0d),
260
		.length = 0,
261
	};
262
	uint8_t buf[IWMBT_HCI_EVT_COMPL_SIZE(struct iwmbt_boot_params)];
263
264
	memset(buf, 0, sizeof(buf));
265
266
	ret = iwmbt_hci_command(hdl,
267
	    &cmd,
268
	    buf,
269
	    sizeof(buf),
270
	    &transferred,
271
	    IWMBT_HCI_CMD_TIMEOUT);
272
273
	if (ret < 0 || transferred != sizeof(buf)) {
274
		 iwmbt_debug("Can't get boot params: code=%d, size=%d",
275
		     ret,
276
		     transferred);
277
		 return (-1);
278
	}
279
280
	event = (struct iwmbt_hci_event_cmd_compl *)buf;
281
	memcpy(params, event->data, sizeof(struct iwmbt_boot_params));
282
283
	return (0);
284
}
285
286
int
287
iwmbt_intel_reset(struct libusb_device_handle *hdl, uint32_t boot_param)
288
{
289
	int ret, transferred = 0;
290
	struct iwmbt_hci_event *event;
291
	static struct iwmbt_hci_cmd cmd = {
292
		.opcode = htole16(0xfc01),
293
		.length = 8,
294
		.data = { 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00 },
295
	};
296
	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
297
298
	le32enc(cmd.data + 4, boot_param);
299
	memset(buf, 0, sizeof(buf));
300
301
	ret = iwmbt_hci_command(hdl,
302
	    &cmd,
303
	    buf,
304
	    sizeof(buf),
305
	    &transferred,
306
	    IWMBT_HCI_CMD_TIMEOUT);
307
308
	if (ret < 0 || transferred < (int)sizeof(struct iwmbt_hci_event) + 1) {
309
		 iwmbt_debug("Intel Reset command failed: code=%d, size=%d",
310
		    ret,
311
		    transferred);
312
		 return (ret);
313
	}
314
315
	/* expect Vendor Specific Event 0x02 */
316
	event = (struct iwmbt_hci_event *)buf;
317
	if (event->header.event != 0xFF || event->data[0] != 0x02) {
318
		iwmbt_err("Intel Reset completion event missed");
319
		return (-1);
320
	}
321
322
	return (0);
323
}
324
325
int
326
iwmbt_load_ddc(struct libusb_device_handle *hdl,
327
    const struct iwmbt_firmware *ddc)
328
{
329
	int size, sent = 0;
330
	int ret, transferred;
331
	uint8_t buf[IWMBT_HCI_MAX_CMD_SIZE];
332
	struct iwmbt_hci_cmd *cmd = (struct iwmbt_hci_cmd *)buf;
333
334
	size = ddc->len;
335
336
	iwmbt_debug("file=%s, size=%d", ddc->fwname, size);
337
338
	while (size > 0) {
339
340
		memset(buf, 0, sizeof(buf));
341
		cmd->opcode = htole16(0xfc8b);
342
		cmd->length = ddc->buf[sent] + 1;
343
		memcpy(cmd->data, ddc->buf + sent, XMIN(ddc->buf[sent], size));
344
345
		iwmbt_debug("transferring %d bytes, offset %d",
346
		    cmd->length,
347
		    sent);
348
349
		size -= cmd->length;
350
		sent += cmd->length;
351
352
		ret = iwmbt_hci_command(hdl,
353
		    cmd,
354
		    buf,
355
		    sizeof(buf),
356
		    &transferred,
357
		    IWMBT_HCI_CMD_TIMEOUT);
358
359
		if (ret < 0) {
360
			 iwmbt_debug("Intel Write DDC failed: code=%d", ret);
361
			 return (-1);
362
		}
363
	}
364
365
	return (0);
366
}
367
368
int
369
iwmbt_set_event_mask(struct libusb_device_handle *hdl)
370
{
371
	int ret, transferred = 0;
372
	static struct iwmbt_hci_cmd cmd = {
373
		.opcode = htole16(0xfc52),
374
		.length = 8,
375
		.data = { 0x87, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
376
	};
377
	uint8_t buf[IWMBT_HCI_MAX_EVENT_SIZE];
378
379
	ret = iwmbt_hci_command(hdl,
380
	    &cmd,
381
	    buf,
382
	    sizeof(buf),
383
	    &transferred,
384
	    IWMBT_HCI_CMD_TIMEOUT);
385
386
	if (ret < 0)
387
		 iwmbt_debug("Intel Set Event Mask failed: code=%d", ret);
388
389
	return (ret);
390
}
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbt_hw.h (+89 lines)
Added Link Here
1
/*-
2
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
3
 *
4
 * Redistribution and use in source and binary forms, with or without
5
 * modification, are permitted provided that the following conditions
6
 * are met:
7
 * 1. Redistributions of source code must retain the above copyright
8
 *    notice, this list of conditions and the following disclaimer,
9
 *    without modification.
10
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
11
 *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
12
 *    redistribution must be conditioned upon including a substantially
13
 *    similar Disclaimer requirement for further binary redistribution.
14
 *
15
 * NO WARRANTY
16
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
 * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
19
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
20
 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY,
21
 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24
 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26
 * THE POSSIBILITY OF SUCH DAMAGES.
27
 *
28
 * $FreeBSD$
29
 */
30
#ifndef	__IWMBT_HW_H__
31
#define	__IWMBT_HW_H__
32
33
/* USB control request (HCI command) structure */
34
struct iwmbt_hci_cmd {
35
	uint16_t	opcode;
36
	uint8_t		length;
37
	uint8_t		data[];
38
} __attribute__ ((packed));
39
40
#define IWMBT_HCI_CMD_SIZE(cmd) \
41
	((cmd)->length + offsetof(struct iwmbt_hci_cmd, data))
42
43
/* USB interrupt transfer HCI event header structure */
44
struct iwmbt_hci_evhdr {
45
	uint8_t		event;
46
	uint8_t		length;
47
} __attribute__ ((packed));
48
49
/* USB interrupt transfer (generic HCI event) structure */
50
struct iwmbt_hci_event {
51
	struct iwmbt_hci_evhdr	header;
52
	uint8_t			data[];
53
} __attribute__ ((packed));
54
55
/* USB interrupt transfer (HCI command completion event) structure */
56
struct iwmbt_hci_event_cmd_compl {
57
	struct iwmbt_hci_evhdr	header;
58
	uint8_t			numpkt;
59
	uint16_t		opcode;
60
	uint8_t			data[];
61
} __attribute__ ((packed));
62
63
#define IWMBT_HCI_EVT_COMPL_SIZE(payload) \
64
	(offsetof(struct iwmbt_hci_event_cmd_compl, data) + sizeof(payload))
65
66
#define	IWMBT_CONTROL_ENDPOINT_ADDR	0x00
67
#define	IWMBT_INTERRUPT_ENDPOINT_ADDR	0x81
68
#define	IWMBT_BULK_IN_ENDPOINT_ADDR	0x82
69
#define	IWMBT_BULK_OUT_ENDPOINT_ADDR	0x02
70
71
#define	IWMBT_HCI_MAX_CMD_SIZE		256
72
#define	IWMBT_HCI_MAX_EVENT_SIZE	16
73
74
#define	IWMBT_HCI_CMD_TIMEOUT		2000	/* ms */
75
#define	IWMBT_LOADCMPL_TIMEOUT		5000	/* ms */
76
77
extern	int iwmbt_load_fwfile(struct libusb_device_handle *hdl,
78
	    const struct iwmbt_firmware *fw, uint32_t *boot_param);
79
extern	int iwmbt_get_version(struct libusb_device_handle *hdl,
80
	    struct iwmbt_version *version);
81
extern	int iwmbt_get_boot_params(struct libusb_device_handle *hdl,
82
	    struct iwmbt_boot_params *params);
83
extern	int iwmbt_intel_reset(struct libusb_device_handle *hdl,
84
	    uint32_t boot_param);
85
extern	int iwmbt_load_ddc(struct libusb_device_handle *hdl,
86
	    const struct iwmbt_firmware *ddc);
87
extern	int iwmbt_set_event_mask(struct libusb_device_handle *hdl);
88
89
#endif
(-)b/usr.sbin/bluetooth/iwmbtfw/iwmbtfw.8 (+96 lines)
Added Link Here
1
.\" Copyright (c) 2013, 2016 Adrian Chadd <adrian@freebsd.org>
2
.\" Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
3
.\"
4
.\" Redistribution and use in source and binary forms, with or without
5
.\" modification, are permitted provided that the following conditions
6
.\" are met:
7
.\" 1. Redistributions of source code must retain the above copyright
8
.\"    notice, this list of conditions and the following disclaimer.
9
.\" 2. Redistributions in binary form must reproduce the above copyright
10
.\"    notice, this list of conditions and the following disclaimer in the
11
.\"    documentation and/or other materials provided with the distribution.
12
.\"
13
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23
.\" SUCH DAMAGE.
24
.\"
25
.\" $FreeBSD$
26
.\"
27
.Dd June 4, 2019
28
.Dt IWMBTFW 8
29
.Os
30
.Sh NAME
31
.Nm iwmbtfw
32
.Nd firmware download utility for Intel Wireless 8260/8265 chip based Bluetooth
33
USB devices
34
.Sh SYNOPSIS
35
.Nm
36
.Fl d Ar device_name
37
.Fl f Ar firmware_path
38
.Nm
39
.Fl h
40
.Sh DESCRIPTION
41
The
42
.Nm
43
utility downloads the specified firmware file to the specified
44
.Xr ugen 4
45
device.
46
.Pp
47
This utility will
48
.Em only
49
work with Intel Wireless 8260/8265 chip based Bluetooth USB devices and some of
50
their successors.
51
The identification is currently based on USB vendor ID/product ID pair.
52
The vendor ID should be 0x8087
53
.Pq Dv USB_VENDOR_INTEL2
54
and the product ID should be one of the supported devices.
55
.Pp
56
Firmware files are available in the
57
.Pa comms/iwmbt-firmware
58
port.
59
.Pp
60
The
61
.Nm
62
utility will query the device to determine which firmware image and board
63
configuration to load in at runtime.
64
.Pp
65
The options are as follows:
66
.Bl -tag -width indent
67
.It Fl D
68
Enable verbose debugging.
69
.It Fl d Ar device_name
70
Specify
71
.Xr ugen 4
72
device name.
73
.It Fl I
74
Enable informational debugging.
75
.It Fl f Ar firmware_path
76
Specify the directory containing the firmware files to search and upload.
77
.It Fl h
78
Display usage message and exit.
79
.El
80
.Sh EXIT STATUS
81
.Ex -std
82
.Sh SEE ALSO
83
.Xr libusb 3 ,
84
.Xr ugen 4 ,
85
.Xr devd 8
86
.Sh AUTHORS
87
.Nm
88
is based on
89
.Xr ath3kfw 8
90
utility used as firmware downloader template and on Linux btintel driver
91
source code.
92
It is written by
93
.An Vladimir Kondratyev Aq Mt wulf@FreeBSD.org .
94
.Sh BUGS
95
Most likely.
96
Please report if found.
(-)b/usr.sbin/bluetooth/iwmbtfw/main.c (+456 lines)
Added Link Here
1
/*-
2
 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3
 *
4
 * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5
 * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 * $FreeBSD$
29
 */
30
31
#include <sys/param.h>
32
#include <sys/stat.h>
33
#include <sys/endian.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <fcntl.h>
38
#include <libgen.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <unistd.h>
43
44
#include <libusb.h>
45
46
#include "iwmbt_fw.h"
47
#include "iwmbt_hw.h"
48
#include "iwmbt_dbg.h"
49
50
#define	_DEFAULT_IWMBT_FIRMWARE_PATH	"/usr/share/firmware/intel"
51
52
int	iwmbt_do_debug = 0;
53
int	iwmbt_do_info = 0;
54
55
struct iwmbt_devid {
56
	uint16_t product_id;
57
	uint16_t vendor_id;
58
};
59
60
static struct iwmbt_devid iwmbt_list[] = {
61
62
	/* Intel Wireless 8260/8265 and successors */
63
	{ .vendor_id = 0x8087, .product_id = 0x0a2b },
64
	{ .vendor_id = 0x8087, .product_id = 0x0aaa },
65
	{ .vendor_id = 0x8087, .product_id = 0x0025 },
66
	{ .vendor_id = 0x8087, .product_id = 0x0026 },
67
	{ .vendor_id = 0x8087, .product_id = 0x0029 },
68
};
69
70
static int
71
iwmbt_is_8260(struct libusb_device_descriptor *d)
72
{
73
	int i;
74
75
	/* Search looking for whether it's an 8260/8265 */
76
	for (i = 0; i < (int) nitems(iwmbt_list); i++) {
77
		if ((iwmbt_list[i].product_id == d->idProduct) &&
78
		    (iwmbt_list[i].vendor_id == d->idVendor)) {
79
			iwmbt_info("found 8260/8265");
80
			return (1);
81
		}
82
	}
83
84
	/* Not found */
85
	return (0);
86
}
87
88
static libusb_device *
89
iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id)
90
{
91
	libusb_device **list, *dev = NULL, *found = NULL;
92
	struct libusb_device_descriptor d;
93
	ssize_t cnt, i;
94
	int r;
95
96
	cnt = libusb_get_device_list(ctx, &list);
97
	if (cnt < 0) {
98
		iwmbt_err("libusb_get_device_list() failed: code %lld",
99
		    (long long int) cnt);
100
		return (NULL);
101
	}
102
103
	/*
104
	 * Scan through USB device list.
105
	 */
106
	for (i = 0; i < cnt; i++) {
107
		dev = list[i];
108
		if (bus_id == libusb_get_bus_number(dev) &&
109
		    dev_id == libusb_get_device_address(dev)) {
110
			/* Get the device descriptor for this device entry */
111
			r = libusb_get_device_descriptor(dev, &d);
112
			if (r != 0) {
113
				iwmbt_err("libusb_get_device_descriptor: %s",
114
				    libusb_strerror(r));
115
				break;
116
			}
117
118
			/* Match on the vendor/product id */
119
			if (iwmbt_is_8260(&d)) {
120
				/*
121
				 * Take a reference so it's not freed later on.
122
				 */
123
				found = libusb_ref_device(dev);
124
				break;
125
			}
126
		}
127
	}
128
129
	libusb_free_device_list(list, 1);
130
	return (found);
131
}
132
133
static void
134
iwmbt_dump_version(struct iwmbt_version *ver)
135
{
136
	iwmbt_info("status       0x%02x", ver->status);
137
	iwmbt_info("hw_platform  0x%02x", ver->hw_platform);
138
	iwmbt_info("hw_variant   0x%02x", ver->hw_variant);
139
	iwmbt_info("hw_revision  0x%02x", ver->hw_revision);
140
	iwmbt_info("fw_variant   0x%02x", ver->fw_variant);
141
	iwmbt_info("fw_revision  0x%02x", ver->fw_revision);
142
	iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num);
143
	iwmbt_info("fw_build_ww  0x%02x", ver->fw_build_ww);
144
	iwmbt_info("fw_build_yy  0x%02x", ver->fw_build_yy);
145
	iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num);
146
}
147
148
static void
149
iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
150
{
151
	iwmbt_info("Device revision: %u", le16toh(params->dev_revid));
152
	iwmbt_info("Secure Boot:  %s", params->secure_boot ? "on" : "off");
153
	iwmbt_info("OTP lock:     %s", params->otp_lock    ? "on" : "off");
154
	iwmbt_info("API lock:     %s", params->api_lock    ? "on" : "off");
155
	iwmbt_info("Debug lock:   %s", params->debug_lock  ? "on" : "off");
156
	iwmbt_info("Minimum firmware build %u week %u year %u",
157
	    params->min_fw_build_nn,
158
	    params->min_fw_build_cw,
159
	    2000 + params->min_fw_build_yy);
160
	iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
161
	    params->otp_bdaddr[5],
162
	    params->otp_bdaddr[4],
163
	    params->otp_bdaddr[3],
164
	    params->otp_bdaddr[2],
165
	    params->otp_bdaddr[1],
166
	    params->otp_bdaddr[0]);
167
}
168
169
static int
170
iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
171
    uint32_t *boot_param)
172
{
173
	struct iwmbt_firmware fw;
174
	int ret;
175
176
	iwmbt_debug("loading %s", firmware_path);
177
178
	/* Read in the firmware */
179
	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
180
		iwmbt_debug("iwmbt_fw_read() failed");
181
		return (-1);
182
	}
183
184
	/* Load in the firmware */
185
	ret = iwmbt_load_fwfile(hdl, &fw, boot_param);
186
	if (ret < 0)
187
		iwmbt_debug("Loading firmware file failed");
188
189
	/* free it */
190
	iwmbt_fw_free(&fw);
191
192
	return (ret);
193
}
194
195
static int
196
iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path)
197
{
198
	struct iwmbt_firmware ddc;
199
	int ret;
200
201
	iwmbt_debug("loading %s", ddc_path);
202
203
	/* Read in the DDC file */
204
	if (iwmbt_fw_read(&ddc, ddc_path) <= 0) {
205
		iwmbt_debug("iwmbt_fw_read() failed");
206
		return (-1);
207
	}
208
209
	/* Load in the DDC file */
210
	ret = iwmbt_load_ddc(hdl, &ddc);
211
	if (ret < 0)
212
		iwmbt_debug("Loading DDC file failed");
213
214
	/* free it */
215
	iwmbt_fw_free(&ddc);
216
217
	return (ret);
218
}
219
220
/*
221
 * Parse ugen name and extract device's bus and address
222
 */
223
224
static int
225
parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
226
{
227
	char *ep;
228
229
	if (strncmp(ugen, "ugen", 4) != 0)
230
		return (-1);
231
232
	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
233
	if (*ep != '.')
234
		return (-1);
235
236
	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
237
	if (*ep != '\0')
238
		return (-1);
239
240
	return (0);
241
}
242
243
static void
244
usage(void)
245
{
246
	fprintf(stderr,
247
	    "Usage: iwmbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
248
	fprintf(stderr, "    -D: enable debugging\n");
249
	fprintf(stderr, "    -d: device to operate upon\n");
250
	fprintf(stderr, "    -f: firmware path, if not default\n");
251
	fprintf(stderr, "    -I: enable informational output\n");
252
	exit(127);
253
}
254
255
int
256
main(int argc, char *argv[])
257
{
258
	libusb_context *ctx = NULL;
259
	libusb_device *dev = NULL;
260
	libusb_device_handle *hdl = NULL;
261
	static struct iwmbt_version ver;
262
	static struct iwmbt_boot_params params;
263
	uint32_t boot_param;
264
	int r;
265
	uint8_t bus_id = 0, dev_id = 0;
266
	int devid_set = 0;
267
	int n;
268
	char *firmware_dir = NULL;
269
	char *firmware_path = NULL;
270
	int retcode = 1;
271
272
	/* Parse command line arguments */
273
	while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
274
		switch (n) {
275
		case 'd': /* ugen device name */
276
			devid_set = 1;
277
			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
278
				usage();
279
			break;
280
		case 'D':
281
			iwmbt_do_debug = 1;
282
			break;
283
		case 'f': /* firmware dir */
284
			if (firmware_dir)
285
				free(firmware_dir);
286
			firmware_dir = strdup(optarg);
287
			break;
288
		case 'I':
289
			iwmbt_do_info = 1;
290
			break;
291
		case 'h':
292
		default:
293
			usage();
294
			break;
295
			/* NOT REACHED */
296
		}
297
	}
298
299
	/* Ensure the devid was given! */
300
	if (devid_set == 0) {
301
		usage();
302
		/* NOTREACHED */
303
	}
304
305
	/* libusb setup */
306
	r = libusb_init(&ctx);
307
	if (r != 0) {
308
		iwmbt_err("libusb_init failed: code %d", r);
309
		exit(127);
310
	}
311
312
	iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
313
314
	/* Find a device based on the bus/dev id */
315
	dev = iwmbt_find_device(ctx, bus_id, dev_id);
316
	if (dev == NULL) {
317
		iwmbt_err("device not found");
318
		goto shutdown;
319
	}
320
321
	/* XXX enforce that bInterfaceNumber is 0 */
322
323
	/* XXX enforce the device/product id if they're non-zero */
324
325
	/* Grab device handle */
326
	r = libusb_open(dev, &hdl);
327
	if (r != 0) {
328
		iwmbt_err("libusb_open() failed: code %d", r);
329
		goto shutdown;
330
	}
331
332
	/* Check if ng_ubt is attached */
333
	r = libusb_kernel_driver_active(hdl, 0);
334
	if (r < 0) {
335
		iwmbt_err("libusb_kernel_driver_active() failed: code %d", r);
336
		goto shutdown;
337
	}
338
	if (r > 0) {
339
		iwmbt_info("Firmware has already been downloaded");
340
		retcode = 0;
341
		goto shutdown;
342
	}
343
344
	/* Get Intel version */
345
	r = iwmbt_get_version(hdl, &ver);
346
	if (r < 0) {
347
		iwmbt_debug("iwmbt_get_version() failedL code %d", r);
348
		goto shutdown;
349
	}
350
	iwmbt_dump_version(&ver);
351
	iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
352
353
	/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
354
	if (ver.fw_variant == 0x23) {
355
		iwmbt_info("Firmware has already been downloaded");
356
		retcode = 0;
357
		goto reset;
358
	}
359
360
	if (ver.fw_variant != 0x06){
361
		iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
362
		goto shutdown;
363
	}
364
365
	/* Read Intel Secure Boot Params */
366
	r = iwmbt_get_boot_params(hdl, &params);
367
	if (r < 0) {
368
		iwmbt_debug("iwmbt_get_boot_params() failed!");
369
		goto shutdown;
370
	}
371
	iwmbt_dump_boot_params(&params);
372
373
	/* Check if firmware fragments are ACKed with a cmd complete event */
374
	if (params.limited_cce != 0x00) {
375
		iwmbt_err("Unsupported Intel firmware loading method (%u)",
376
		   params.limited_cce);
377
		goto shutdown;
378
	}
379
380
	/* Default the firmware path */
381
	if (firmware_dir == NULL)
382
		firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
383
384
	firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
385
	if (firmware_path == NULL)
386
		goto shutdown;
387
388
	iwmbt_debug("firmware_path = %s", firmware_path);
389
390
	/* Download firmware and parse it for magic Intel Reset parameter */
391
	r = iwmbt_init_firmware(hdl, firmware_path, &boot_param);
392
	free(firmware_path);
393
	if (r < 0)
394
		goto shutdown;
395
396
	iwmbt_info("Firmware download complete");
397
398
	r = iwmbt_intel_reset(hdl, boot_param);
399
	if (r < 0) {
400
		iwmbt_debug("iwmbt_intel_reset() failed!");
401
		goto shutdown;
402
	}
403
404
	iwmbt_info("Firmware operational");
405
406
	/* Once device is running in operational mode we can ignore failures */
407
	retcode = 0;
408
409
	/* Execute Read Intel Version one more time */
410
	r = iwmbt_get_version(hdl, &ver);
411
	if (r == 0)
412
		iwmbt_dump_version(&ver);
413
414
	/* Apply the device configuration (DDC) parameters */
415
	firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "ddc");
416
	iwmbt_debug("ddc_path = %s", firmware_path);
417
	if (firmware_path != NULL) {
418
		r = iwmbt_init_ddc(hdl, firmware_path);
419
		if (r == 0)
420
			iwmbt_info("DDC download complete");
421
		free(firmware_path);
422
	}
423
424
	/* Set Intel Event mask */
425
	r = iwmbt_set_event_mask(hdl);
426
	if (r == 0)
427
		iwmbt_info("Intel Event Mask is set");
428
429
reset:
430
431
	/* Ask kernel driver to probe and attach device again */
432
	r = libusb_reset_device(hdl);
433
	if (r != 0)
434
		iwmbt_err("libusb_reset_device() failed: %s",
435
		    libusb_strerror(r));
436
437
shutdown:
438
439
	/* Shutdown */
440
441
	if (hdl != NULL)
442
		libusb_close(hdl);
443
444
	if (dev != NULL)
445
		libusb_unref_device(dev);
446
447
	if (ctx != NULL)
448
		libusb_exit(ctx);
449
450
	if (retcode == 0)
451
		iwmbt_info("Firmware download is succesful!");
452
	else
453
		iwmbt_err("Firmware download failed!");
454
455
	return (retcode);
456
}

Return to bug 237083