xref: /freebsd/usr.sbin/bluetooth/iwmbtfw/main.c (revision f4f56ff43dbd30930f4b018e39ba2b9abf84551f)
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_72xx[] = {
61 
62 	/* Intel Wireless 7260/7265 and successors */
63 	{ .vendor_id = 0x8087, .product_id = 0x07dc },
64 	{ .vendor_id = 0x8087, .product_id = 0x0a2a },
65 	{ .vendor_id = 0x8087, .product_id = 0x0aa7 },
66 };
67 
68 static struct iwmbt_devid iwmbt_list_82xx[] = {
69 
70 	/* Intel Wireless 8260/8265 and successors */
71 	{ .vendor_id = 0x8087, .product_id = 0x0a2b },
72 	{ .vendor_id = 0x8087, .product_id = 0x0aaa },
73 	{ .vendor_id = 0x8087, .product_id = 0x0025 },
74 	{ .vendor_id = 0x8087, .product_id = 0x0026 },
75 	{ .vendor_id = 0x8087, .product_id = 0x0029 },
76 };
77 
78 static int
79 iwmbt_is_7260(struct libusb_device_descriptor *d)
80 {
81 	int i;
82 
83 	/* Search looking for whether it's an 7260/7265 */
84 	for (i = 0; i < (int) nitems(iwmbt_list_72xx); i++) {
85 		if ((iwmbt_list_72xx[i].product_id == d->idProduct) &&
86 		    (iwmbt_list_72xx[i].vendor_id == d->idVendor)) {
87 			iwmbt_info("found 7260/7265");
88 			return (1);
89 		}
90 	}
91 
92 	/* Not found */
93 	return (0);
94 }
95 
96 static int
97 iwmbt_is_8260(struct libusb_device_descriptor *d)
98 {
99 	int i;
100 
101 	/* Search looking for whether it's an 8260/8265 */
102 	for (i = 0; i < (int) nitems(iwmbt_list_82xx); i++) {
103 		if ((iwmbt_list_82xx[i].product_id == d->idProduct) &&
104 		    (iwmbt_list_82xx[i].vendor_id == d->idVendor)) {
105 			iwmbt_info("found 8260/8265");
106 			return (1);
107 		}
108 	}
109 
110 	/* Not found */
111 	return (0);
112 }
113 
114 static libusb_device *
115 iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
116     int *iwmbt_use_old_method)
117 {
118 	libusb_device **list, *dev = NULL, *found = NULL;
119 	struct libusb_device_descriptor d;
120 	ssize_t cnt, i;
121 	int r;
122 
123 	cnt = libusb_get_device_list(ctx, &list);
124 	if (cnt < 0) {
125 		iwmbt_err("libusb_get_device_list() failed: code %lld",
126 		    (long long int) cnt);
127 		return (NULL);
128 	}
129 
130 	/*
131 	 * Scan through USB device list.
132 	 */
133 	for (i = 0; i < cnt; i++) {
134 		dev = list[i];
135 		if (bus_id == libusb_get_bus_number(dev) &&
136 		    dev_id == libusb_get_device_address(dev)) {
137 			/* Get the device descriptor for this device entry */
138 			r = libusb_get_device_descriptor(dev, &d);
139 			if (r != 0) {
140 				iwmbt_err("libusb_get_device_descriptor: %s",
141 				    libusb_strerror(r));
142 				break;
143 			}
144 
145 			/* Match on the vendor/product id */
146 			if (iwmbt_is_7260(&d)) {
147 				/*
148 				 * Take a reference so it's not freed later on.
149 				 */
150 				found = libusb_ref_device(dev);
151 				*iwmbt_use_old_method = 1;
152 				break;
153 			} else
154 			if (iwmbt_is_8260(&d)) {
155 				/*
156 				 * Take a reference so it's not freed later on.
157 				 */
158 				found = libusb_ref_device(dev);
159 				*iwmbt_use_old_method = 0;
160 				break;
161 			}
162 		}
163 	}
164 
165 	libusb_free_device_list(list, 1);
166 	return (found);
167 }
168 
169 static void
170 iwmbt_dump_version(struct iwmbt_version *ver)
171 {
172 	iwmbt_info("status       0x%02x", ver->status);
173 	iwmbt_info("hw_platform  0x%02x", ver->hw_platform);
174 	iwmbt_info("hw_variant   0x%02x", ver->hw_variant);
175 	iwmbt_info("hw_revision  0x%02x", ver->hw_revision);
176 	iwmbt_info("fw_variant   0x%02x", ver->fw_variant);
177 	iwmbt_info("fw_revision  0x%02x", ver->fw_revision);
178 	iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num);
179 	iwmbt_info("fw_build_ww  0x%02x", ver->fw_build_ww);
180 	iwmbt_info("fw_build_yy  0x%02x", ver->fw_build_yy);
181 	iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num);
182 }
183 
184 static void
185 iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
186 {
187 	iwmbt_info("Device revision: %u", le16toh(params->dev_revid));
188 	iwmbt_info("Secure Boot:  %s", params->secure_boot ? "on" : "off");
189 	iwmbt_info("OTP lock:     %s", params->otp_lock    ? "on" : "off");
190 	iwmbt_info("API lock:     %s", params->api_lock    ? "on" : "off");
191 	iwmbt_info("Debug lock:   %s", params->debug_lock  ? "on" : "off");
192 	iwmbt_info("Minimum firmware build %u week %u year %u",
193 	    params->min_fw_build_nn,
194 	    params->min_fw_build_cw,
195 	    2000 + params->min_fw_build_yy);
196 	iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
197 	    params->otp_bdaddr[5],
198 	    params->otp_bdaddr[4],
199 	    params->otp_bdaddr[3],
200 	    params->otp_bdaddr[2],
201 	    params->otp_bdaddr[1],
202 	    params->otp_bdaddr[0]);
203 }
204 
205 static int
206 iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
207 {
208 	struct iwmbt_firmware fw;
209 	int ret;
210 
211 	iwmbt_debug("loading %s", firmware_path);
212 
213 	/* Read in the firmware */
214 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
215 		iwmbt_debug("iwmbt_fw_read() failed");
216 		return (-1);
217 	}
218 
219 	/* Load in the firmware */
220 	ret = iwmbt_patch_fwfile(hdl, &fw);
221 	if (ret < 0)
222 		iwmbt_debug("Loading firmware file failed");
223 
224 	/* free it */
225 	iwmbt_fw_free(&fw);
226 
227 	return (ret);
228 }
229 
230 static int
231 iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
232     uint32_t *boot_param)
233 {
234 	struct iwmbt_firmware fw;
235 	int ret;
236 
237 	iwmbt_debug("loading %s", firmware_path);
238 
239 	/* Read in the firmware */
240 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
241 		iwmbt_debug("iwmbt_fw_read() failed");
242 		return (-1);
243 	}
244 
245 	/* Load in the firmware */
246 	ret = iwmbt_load_fwfile(hdl, &fw, boot_param);
247 	if (ret < 0)
248 		iwmbt_debug("Loading firmware file failed");
249 
250 	/* free it */
251 	iwmbt_fw_free(&fw);
252 
253 	return (ret);
254 }
255 
256 static int
257 iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path)
258 {
259 	struct iwmbt_firmware ddc;
260 	int ret;
261 
262 	iwmbt_debug("loading %s", ddc_path);
263 
264 	/* Read in the DDC file */
265 	if (iwmbt_fw_read(&ddc, ddc_path) <= 0) {
266 		iwmbt_debug("iwmbt_fw_read() failed");
267 		return (-1);
268 	}
269 
270 	/* Load in the DDC file */
271 	ret = iwmbt_load_ddc(hdl, &ddc);
272 	if (ret < 0)
273 		iwmbt_debug("Loading DDC file failed");
274 
275 	/* free it */
276 	iwmbt_fw_free(&ddc);
277 
278 	return (ret);
279 }
280 
281 /*
282  * Parse ugen name and extract device's bus and address
283  */
284 
285 static int
286 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
287 {
288 	char *ep;
289 
290 	if (strncmp(ugen, "ugen", 4) != 0)
291 		return (-1);
292 
293 	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
294 	if (*ep != '.')
295 		return (-1);
296 
297 	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
298 	if (*ep != '\0')
299 		return (-1);
300 
301 	return (0);
302 }
303 
304 static void
305 usage(void)
306 {
307 	fprintf(stderr,
308 	    "Usage: iwmbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
309 	fprintf(stderr, "    -D: enable debugging\n");
310 	fprintf(stderr, "    -d: device to operate upon\n");
311 	fprintf(stderr, "    -f: firmware path, if not default\n");
312 	fprintf(stderr, "    -I: enable informational output\n");
313 	exit(127);
314 }
315 
316 int
317 main(int argc, char *argv[])
318 {
319 	libusb_context *ctx = NULL;
320 	libusb_device *dev = NULL;
321 	libusb_device_handle *hdl = NULL;
322 	static struct iwmbt_version ver;
323 	static struct iwmbt_boot_params params;
324 	uint32_t boot_param;
325 	int r;
326 	uint8_t bus_id = 0, dev_id = 0;
327 	int devid_set = 0;
328 	int n;
329 	char *firmware_dir = NULL;
330 	char *firmware_path = NULL;
331 	int retcode = 1;
332 	int iwmbt_use_old_method = 0;
333 
334 	/* Parse command line arguments */
335 	while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
336 		switch (n) {
337 		case 'd': /* ugen device name */
338 			devid_set = 1;
339 			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
340 				usage();
341 			break;
342 		case 'D':
343 			iwmbt_do_debug = 1;
344 			break;
345 		case 'f': /* firmware dir */
346 			if (firmware_dir)
347 				free(firmware_dir);
348 			firmware_dir = strdup(optarg);
349 			break;
350 		case 'I':
351 			iwmbt_do_info = 1;
352 			break;
353 		case 'h':
354 		default:
355 			usage();
356 			break;
357 			/* NOT REACHED */
358 		}
359 	}
360 
361 	/* Ensure the devid was given! */
362 	if (devid_set == 0) {
363 		usage();
364 		/* NOTREACHED */
365 	}
366 
367 	/* libusb setup */
368 	r = libusb_init(&ctx);
369 	if (r != 0) {
370 		iwmbt_err("libusb_init failed: code %d", r);
371 		exit(127);
372 	}
373 
374 	iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
375 
376 	/* Find a device based on the bus/dev id */
377 	dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_use_old_method);
378 	if (dev == NULL) {
379 		iwmbt_err("device not found");
380 		goto shutdown;
381 	}
382 
383 	/* XXX enforce that bInterfaceNumber is 0 */
384 
385 	/* XXX enforce the device/product id if they're non-zero */
386 
387 	/* Grab device handle */
388 	r = libusb_open(dev, &hdl);
389 	if (r != 0) {
390 		iwmbt_err("libusb_open() failed: code %d", r);
391 		goto shutdown;
392 	}
393 
394 	/* Check if ng_ubt is attached */
395 	r = libusb_kernel_driver_active(hdl, 0);
396 	if (r < 0) {
397 		iwmbt_err("libusb_kernel_driver_active() failed: code %d", r);
398 		goto shutdown;
399 	}
400 	if (r > 0) {
401 		iwmbt_info("Firmware has already been downloaded");
402 		retcode = 0;
403 		goto shutdown;
404 	}
405 
406 	/* Get Intel version */
407 	r = iwmbt_get_version(hdl, &ver);
408 	if (r < 0) {
409 		iwmbt_debug("iwmbt_get_version() failed code %d", r);
410 		goto shutdown;
411 	}
412 	iwmbt_dump_version(&ver);
413 	iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
414 
415 	if (iwmbt_use_old_method) {
416 
417 		/* fw_patch_num = >0 operational mode */
418 		if (ver.fw_patch_num > 0x00) {
419 			iwmbt_info("Firmware has already been downloaded");
420 			retcode = 0;
421 			goto reset;
422 		}
423 
424 		/* Default the firmware path */
425 		if (firmware_dir == NULL)
426 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
427 
428 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "bseq");
429 		if (firmware_path == NULL)
430 			goto shutdown;
431 
432 		iwmbt_debug("firmware_path = %s", firmware_path);
433 
434 		/* Enter manufacturer mode */
435 		r = iwmbt_enter_manufacturer(hdl);
436 		if (r < 0) {
437 			iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
438 			goto shutdown;
439 		}
440 
441 		/* Download firmware and parse it for magic Intel Reset parameter */
442 		r = iwmbt_patch_firmware(hdl, firmware_path);
443 		free(firmware_path);
444 		if (r < 0) {
445 			(void)iwmbt_exit_manufacturer(hdl, 0x01);
446 			goto shutdown;
447 		}
448 
449 		iwmbt_info("Firmware download complete");
450 
451 		/* Exit manufacturer mode */
452 		r = iwmbt_exit_manufacturer(hdl, r == 0 ? 0x00 : 0x02);
453 		if (r < 0) {
454 			iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
455 			goto shutdown;
456 		}
457 
458 		/* Once device is running in operational mode we can ignore failures */
459 		retcode = 0;
460 
461 		/* Execute Read Intel Version one more time */
462 		r = iwmbt_get_version(hdl, &ver);
463 		if (r == 0)
464 			iwmbt_dump_version(&ver);
465 
466 		/* Set Intel Event mask */
467 		if (iwmbt_enter_manufacturer(hdl) < 0)
468 			goto reset;
469 		r = iwmbt_set_event_mask(hdl);
470 		if (r == 0)
471 			iwmbt_info("Intel Event Mask is set");
472 		(void)iwmbt_exit_manufacturer(hdl, 0x00);
473 
474 	} else {
475 
476 		/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
477 		if (ver.fw_variant == 0x23) {
478 			iwmbt_info("Firmware has already been downloaded");
479 			retcode = 0;
480 			goto reset;
481 		}
482 
483 		if (ver.fw_variant != 0x06){
484 			iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
485 			goto shutdown;
486 		}
487 
488 		/* Read Intel Secure Boot Params */
489 		r = iwmbt_get_boot_params(hdl, &params);
490 		if (r < 0) {
491 			iwmbt_debug("iwmbt_get_boot_params() failed!");
492 			goto shutdown;
493 		}
494 		iwmbt_dump_boot_params(&params);
495 
496 		/* Check if firmware fragments are ACKed with a cmd complete event */
497 		if (params.limited_cce != 0x00) {
498 			iwmbt_err("Unsupported Intel firmware loading method (%u)",
499 			   params.limited_cce);
500 			goto shutdown;
501 		}
502 
503 		/* Default the firmware path */
504 		if (firmware_dir == NULL)
505 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
506 
507 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
508 		if (firmware_path == NULL)
509 			goto shutdown;
510 
511 		iwmbt_debug("firmware_path = %s", firmware_path);
512 
513 		/* Download firmware and parse it for magic Intel Reset parameter */
514 		r = iwmbt_init_firmware(hdl, firmware_path, &boot_param);
515 		free(firmware_path);
516 		if (r < 0)
517 			goto shutdown;
518 
519 		iwmbt_info("Firmware download complete");
520 
521 		r = iwmbt_intel_reset(hdl, boot_param);
522 		if (r < 0) {
523 			iwmbt_debug("iwmbt_intel_reset() failed!");
524 			goto shutdown;
525 		}
526 
527 		iwmbt_info("Firmware operational");
528 
529 		/* Once device is running in operational mode we can ignore failures */
530 		retcode = 0;
531 
532 		/* Execute Read Intel Version one more time */
533 		r = iwmbt_get_version(hdl, &ver);
534 		if (r == 0)
535 			iwmbt_dump_version(&ver);
536 
537 		/* Apply the device configuration (DDC) parameters */
538 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "ddc");
539 		iwmbt_debug("ddc_path = %s", firmware_path);
540 		if (firmware_path != NULL) {
541 			r = iwmbt_init_ddc(hdl, firmware_path);
542 			if (r == 0)
543 				iwmbt_info("DDC download complete");
544 			free(firmware_path);
545 		}
546 
547 		/* Set Intel Event mask */
548 		r = iwmbt_set_event_mask(hdl);
549 		if (r == 0)
550 			iwmbt_info("Intel Event Mask is set");
551 	}
552 
553 reset:
554 
555 	/* Ask kernel driver to probe and attach device again */
556 	r = libusb_reset_device(hdl);
557 	if (r != 0)
558 		iwmbt_err("libusb_reset_device() failed: %s",
559 		    libusb_strerror(r));
560 
561 shutdown:
562 
563 	/* Shutdown */
564 
565 	if (hdl != NULL)
566 		libusb_close(hdl);
567 
568 	if (dev != NULL)
569 		libusb_unref_device(dev);
570 
571 	if (ctx != NULL)
572 		libusb_exit(ctx);
573 
574 	if (retcode == 0)
575 		iwmbt_info("Firmware download is succesful!");
576 	else
577 		iwmbt_err("Firmware download failed!");
578 
579 	return (retcode);
580 }
581