xref: /freebsd/usr.sbin/bluetooth/iwmbtfw/main.c (revision 0feaf865ce8e333f834177a5656e57b5e32ad5cf)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2013 Adrian Chadd <adrian@freebsd.org>
5  * Copyright (c) 2019 Vladimir Kondratyev <wulf@FreeBSD.org>
6  * Copyright (c) 2023 Future Crew LLC.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <sys/endian.h>
33 
34 #include <err.h>
35 #include <errno.h>
36 #include <fcntl.h>
37 #include <libgen.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
42 
43 #include <libusb.h>
44 
45 #include "iwmbt_fw.h"
46 #include "iwmbt_hw.h"
47 #include "iwmbt_dbg.h"
48 
49 #define	_DEFAULT_IWMBT_FIRMWARE_PATH	"/usr/share/firmware/intel"
50 
51 int	iwmbt_do_debug = 0;
52 int	iwmbt_do_info = 0;
53 
54 enum iwmbt_device {
55 	IWMBT_DEVICE_UNKNOWN,
56 	IWMBT_DEVICE_7260,
57 	IWMBT_DEVICE_8260,
58 	IWMBT_DEVICE_9260,
59 };
60 
61 struct iwmbt_devid {
62 	uint16_t product_id;
63 	uint16_t vendor_id;
64 	enum iwmbt_device device;
65 };
66 
67 static struct iwmbt_devid iwmbt_list[] = {
68 
69     /* Intel Wireless 7260/7265 and successors */
70     { .vendor_id = 0x8087, .product_id = 0x07dc, .device = IWMBT_DEVICE_7260 },
71     { .vendor_id = 0x8087, .product_id = 0x0a2a, .device = IWMBT_DEVICE_7260 },
72     { .vendor_id = 0x8087, .product_id = 0x0aa7, .device = IWMBT_DEVICE_7260 },
73 
74     /* Intel Wireless 8260/8265 and successors */
75     { .vendor_id = 0x8087, .product_id = 0x0a2b, .device = IWMBT_DEVICE_8260 },
76     { .vendor_id = 0x8087, .product_id = 0x0aaa, .device = IWMBT_DEVICE_8260 },
77     { .vendor_id = 0x8087, .product_id = 0x0025, .device = IWMBT_DEVICE_8260 },
78     { .vendor_id = 0x8087, .product_id = 0x0026, .device = IWMBT_DEVICE_8260 },
79     { .vendor_id = 0x8087, .product_id = 0x0029, .device = IWMBT_DEVICE_8260 },
80 
81     /* Intel Wireless 9260/9560 and successors */
82     { .vendor_id = 0x8087, .product_id = 0x0032, .device = IWMBT_DEVICE_9260 },
83     { .vendor_id = 0x8087, .product_id = 0x0033, .device = IWMBT_DEVICE_9260 },
84 };
85 
86 static enum iwmbt_device
87 iwmbt_is_supported(struct libusb_device_descriptor *d)
88 {
89 	int i;
90 
91 	/* Search looking for whether it's an 7260/7265 */
92 	for (i = 0; i < (int) nitems(iwmbt_list); i++) {
93 		if ((iwmbt_list[i].product_id == d->idProduct) &&
94 		    (iwmbt_list[i].vendor_id == d->idVendor)) {
95 			iwmbt_info("found iwmbtfw compatible");
96 			return (iwmbt_list[i].device);
97 		}
98 	}
99 
100 	/* Not found */
101 	return (IWMBT_DEVICE_UNKNOWN);
102 }
103 
104 static libusb_device *
105 iwmbt_find_device(libusb_context *ctx, int bus_id, int dev_id,
106     enum iwmbt_device *iwmbt_device)
107 {
108 	libusb_device **list, *dev = NULL, *found = NULL;
109 	struct libusb_device_descriptor d;
110 	enum iwmbt_device device;
111 	ssize_t cnt, i;
112 	int r;
113 
114 	cnt = libusb_get_device_list(ctx, &list);
115 	if (cnt < 0) {
116 		iwmbt_err("libusb_get_device_list() failed: code %lld",
117 		    (long long int) cnt);
118 		return (NULL);
119 	}
120 
121 	/*
122 	 * Scan through USB device list.
123 	 */
124 	for (i = 0; i < cnt; i++) {
125 		dev = list[i];
126 		if (bus_id == libusb_get_bus_number(dev) &&
127 		    dev_id == libusb_get_device_address(dev)) {
128 			/* Get the device descriptor for this device entry */
129 			r = libusb_get_device_descriptor(dev, &d);
130 			if (r != 0) {
131 				iwmbt_err("libusb_get_device_descriptor: %s",
132 				    libusb_strerror(r));
133 				break;
134 			}
135 
136 			/* Match on the vendor/product id */
137 			device = iwmbt_is_supported(&d);
138 			if (device != IWMBT_DEVICE_UNKNOWN) {
139 				/*
140 				 * Take a reference so it's not freed later on.
141 				 */
142 				found = libusb_ref_device(dev);
143 				*iwmbt_device = device;
144 				break;
145 			}
146 		}
147 	}
148 
149 	libusb_free_device_list(list, 1);
150 	return (found);
151 }
152 
153 static void
154 iwmbt_dump_version(struct iwmbt_version *ver)
155 {
156 	iwmbt_info("status       0x%02x", ver->status);
157 	iwmbt_info("hw_platform  0x%02x", ver->hw_platform);
158 	iwmbt_info("hw_variant   0x%02x", ver->hw_variant);
159 	iwmbt_info("hw_revision  0x%02x", ver->hw_revision);
160 	iwmbt_info("fw_variant   0x%02x", ver->fw_variant);
161 	iwmbt_info("fw_revision  0x%02x", ver->fw_revision);
162 	iwmbt_info("fw_build_num 0x%02x", ver->fw_build_num);
163 	iwmbt_info("fw_build_ww  0x%02x", ver->fw_build_ww);
164 	iwmbt_info("fw_build_yy  0x%02x", ver->fw_build_yy);
165 	iwmbt_info("fw_patch_num 0x%02x", ver->fw_patch_num);
166 }
167 
168 static void
169 iwmbt_dump_boot_params(struct iwmbt_boot_params *params)
170 {
171 	iwmbt_info("Device revision: %u", le16toh(params->dev_revid));
172 	iwmbt_info("Secure Boot:  %s", params->secure_boot ? "on" : "off");
173 	iwmbt_info("OTP lock:     %s", params->otp_lock    ? "on" : "off");
174 	iwmbt_info("API lock:     %s", params->api_lock    ? "on" : "off");
175 	iwmbt_info("Debug lock:   %s", params->debug_lock  ? "on" : "off");
176 	iwmbt_info("Minimum firmware build %u week %u year %u",
177 	    params->min_fw_build_nn,
178 	    params->min_fw_build_cw,
179 	    2000 + params->min_fw_build_yy);
180 	iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
181 	    params->otp_bdaddr[5],
182 	    params->otp_bdaddr[4],
183 	    params->otp_bdaddr[3],
184 	    params->otp_bdaddr[2],
185 	    params->otp_bdaddr[1],
186 	    params->otp_bdaddr[0]);
187 }
188 
189 static void
190 iwmbt_dump_version_tlv(struct iwmbt_version_tlv *ver)
191 {
192 	iwmbt_info("cnvi_top     0x%08x", ver->cnvi_top);
193 	iwmbt_info("cnvr_top     0x%08x", ver->cnvr_top);
194 	iwmbt_info("cnvi_bt      0x%08x", ver->cnvi_bt);
195 	iwmbt_info("cnvr_bt      0x%08x", ver->cnvr_bt);
196 	iwmbt_info("dev_rev_id   0x%04x", ver->dev_rev_id);
197 	iwmbt_info("img_type     0x%02x", ver->img_type);
198 	iwmbt_info("timestamp    0x%04x", ver->timestamp);
199 	iwmbt_info("build_type   0x%02x", ver->build_type);
200 	iwmbt_info("build_num    0x%08x", ver->build_num);
201 	iwmbt_info("Secure Boot:  %s", ver->secure_boot ? "on" : "off");
202 	iwmbt_info("OTP lock:     %s", ver->otp_lock    ? "on" : "off");
203 	iwmbt_info("API lock:     %s", ver->api_lock    ? "on" : "off");
204 	iwmbt_info("Debug lock:   %s", ver->debug_lock  ? "on" : "off");
205 	iwmbt_info("Minimum firmware build %u week %u year %u",
206 	    ver->min_fw_build_nn,
207 	    ver->min_fw_build_cw,
208 	    2000 + ver->min_fw_build_yy);
209 	iwmbt_info("limited_cce  0x%02x", ver->limited_cce);
210 	iwmbt_info("sbe_type     0x%02x", ver->sbe_type);
211 	iwmbt_info("OTC BD_ADDR:  %02x:%02x:%02x:%02x:%02x:%02x",
212 	    ver->otp_bd_addr.b[5],
213 	    ver->otp_bd_addr.b[4],
214 	    ver->otp_bd_addr.b[3],
215 	    ver->otp_bd_addr.b[2],
216 	    ver->otp_bd_addr.b[1],
217 	    ver->otp_bd_addr.b[0]);
218 	if (ver->img_type == TLV_IMG_TYPE_BOOTLOADER ||
219 	    ver->img_type == TLV_IMG_TYPE_OPERATIONAL)
220 		iwmbt_info("%s timestamp %u.%u buildtype %u build %u",
221 		    (ver->img_type == TLV_IMG_TYPE_BOOTLOADER ?
222 		    "Bootloader" : "Firmware"),
223 		    2000 + (ver->timestamp >> 8),
224 		    ver->timestamp & 0xff,
225 		    ver->build_type,
226 		    ver->build_num);
227 }
228 
229 
230 static int
231 iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
232     uint32_t *boot_param, uint8_t hw_variant, uint8_t sbe_type)
233 {
234 	struct iwmbt_firmware fw;
235 	int header_len, ret = -1;
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 	iwmbt_debug("Firmware file size=%d", fw.len);
246 
247 	if (hw_variant <= 0x14) {
248 		/*
249 		 * Hardware variants 0x0b, 0x0c, 0x11 - 0x14 .sfi file have
250 		 * a RSA header of 644 bytes followed by Command Buffer.
251 		 */
252 		header_len = RSA_HEADER_LEN;
253 		if (fw.len < header_len) {
254 			iwmbt_err("Invalid size of firmware file (%d)", fw.len);
255 			ret = -1;
256 			goto exit;
257 		}
258 
259 		/* Check if the CSS Header version is RSA(0x00010000) */
260 		if (le32dec(fw.buf + CSS_HEADER_OFFSET) != 0x00010000) {
261 			iwmbt_err("Invalid CSS Header version");
262 			ret = -1;
263 			goto exit;
264 		}
265 
266 		/* Only RSA secure boot engine supported */
267 		if (sbe_type != 0x00) {
268 			iwmbt_err("Invalid SBE type for hardware variant (%d)",
269 			    hw_variant);
270 			ret = -1;
271 			goto exit;
272 		}
273 
274 	} else if (hw_variant >= 0x17) {
275 		/*
276 		 * Hardware variants 0x17, 0x18 onwards support both RSA and
277 		 * ECDSA secure boot engine. As a result, the corresponding sfi
278 		 * file will have RSA header of 644, ECDSA header of 320 bytes
279 		 * followed by Command Buffer.
280 		 */
281 		header_len = ECDSA_OFFSET + ECDSA_HEADER_LEN;
282 		if (fw.len < header_len) {
283 			iwmbt_err("Invalid size of firmware file (%d)", fw.len);
284 			ret = -1;
285 			goto exit;
286 		}
287 
288 		/* Check if CSS header for ECDSA follows the RSA header */
289 		if (fw.buf[ECDSA_OFFSET] != 0x06) {
290 			ret = -1;
291 			goto exit;
292 		}
293 
294 		/* Check if the CSS Header version is ECDSA(0x00020000) */
295 		if (le32dec(fw.buf + ECDSA_OFFSET + CSS_HEADER_OFFSET) != 0x00020000) {
296 			iwmbt_err("Invalid CSS Header version");
297 			ret = -1;
298 			goto exit;
299 		}
300 	}
301 
302 	/* Load in the CSS header */
303 	if (sbe_type == 0x00)
304 		ret = iwmbt_load_rsa_header(hdl, &fw);
305 	else if (sbe_type == 0x01)
306 		ret = iwmbt_load_ecdsa_header(hdl, &fw);
307 	if (ret < 0)
308 		goto exit;
309 
310 	/* Load in the Command Buffer */
311 	ret = iwmbt_load_fwfile(hdl, &fw, boot_param, header_len);
312 
313 exit:
314 	/* free firmware */
315 	iwmbt_fw_free(&fw);
316 
317 	return (ret);
318 }
319 
320 static int
321 iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path)
322 {
323 	struct iwmbt_firmware ddc;
324 	int ret;
325 
326 	iwmbt_debug("loading %s", ddc_path);
327 
328 	/* Read in the DDC file */
329 	if (iwmbt_fw_read(&ddc, ddc_path) <= 0) {
330 		iwmbt_debug("iwmbt_fw_read() failed");
331 		return (-1);
332 	}
333 
334 	/* Load in the DDC file */
335 	ret = iwmbt_load_ddc(hdl, &ddc);
336 	if (ret < 0)
337 		iwmbt_debug("Loading DDC file failed");
338 
339 	/* free it */
340 	iwmbt_fw_free(&ddc);
341 
342 	return (ret);
343 }
344 
345 /*
346  * Parse ugen name and extract device's bus and address
347  */
348 
349 static int
350 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
351 {
352 	char *ep;
353 
354 	if (strncmp(ugen, "ugen", 4) != 0)
355 		return (-1);
356 
357 	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
358 	if (*ep != '.')
359 		return (-1);
360 
361 	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
362 	if (*ep != '\0')
363 		return (-1);
364 
365 	return (0);
366 }
367 
368 static void
369 usage(void)
370 {
371 	fprintf(stderr,
372 	    "Usage: iwmbtfw [-DI] -d ugenX.Y [-f firmware path]\n");
373 	fprintf(stderr, "    -D: enable debugging\n");
374 	fprintf(stderr, "    -d: device to operate upon\n");
375 	fprintf(stderr, "    -f: firmware path (defaults to %s)\n",
376 	    _DEFAULT_IWMBT_FIRMWARE_PATH);
377 	fprintf(stderr, "    -I: enable informational output\n");
378 	exit(127);
379 }
380 
381 
382 
383 /*
384  * Returns 0 on success.
385  */
386 static int
387 handle_7260(libusb_device_handle *hdl, char *firmware_dir)
388 {
389 	int r;
390 	char *firmware_path;
391 	struct iwmbt_version ver;
392 	struct iwmbt_firmware fw;
393 
394 	r = iwmbt_get_version(hdl, &ver);
395 	if (r < 0) {
396 		iwmbt_debug("iwmbt_get_version() failed code %d", r);
397 		return 1;
398 	}
399 	iwmbt_dump_version(&ver);
400 	iwmbt_debug("fw_patch_num=0x%02x", (int) ver.fw_patch_num);
401 
402 	/* fw_patch_num = >0 operational mode */
403 	if (ver.fw_patch_num > 0x00) {
404 		iwmbt_info("Firmware has already been downloaded");
405 		return 0;
406 	}
407 
408 	firmware_path = iwmbt_get_fwname(&ver, NULL, firmware_dir, "bseq");
409 	if (firmware_path == NULL)
410 		return 1;
411 	iwmbt_debug("firmware_path = %s", firmware_path);
412 
413 	r = iwmbt_fw_read(&fw, firmware_path);
414 	free(firmware_path);
415 	if (r <= 0) {
416 		iwmbt_debug("iwmbt_fw_read() failed");
417 		return 1;
418 	}
419 
420 	r = iwmbt_enter_manufacturer(hdl);
421 	if (r < 0) {
422 		iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
423 		iwmbt_fw_free(&fw);
424 		return 1;
425 	}
426 
427 	/* Download firmware */
428 	r = iwmbt_patch_fwfile(hdl, &fw);
429 	iwmbt_fw_free(&fw);
430 	if (r < 0) {
431 		iwmbt_debug("Loading firmware file failed");
432 		(void)iwmbt_exit_manufacturer(hdl, IWMBT_MM_EXIT_COLD_RESET);
433 		return 1;
434 	}
435 
436 	iwmbt_info("Firmware download complete");
437 
438 	r = iwmbt_exit_manufacturer(hdl,
439 	    (r == 0 ? IWMBT_MM_EXIT_ONLY : IWMBT_MM_EXIT_WARM_RESET));
440 	if (r < 0) {
441 		iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
442 		return 1;
443 	}
444 
445 	/* Once device is running in operational mode we can ignore failures */
446 
447 	/* Dump actual controller version */
448 	r = iwmbt_get_version(hdl, &ver);
449 	if (r == 0)
450 		iwmbt_dump_version(&ver);
451 
452 	if (iwmbt_enter_manufacturer(hdl) < 0)
453 		return 0;
454 	r = iwmbt_set_event_mask(hdl);
455 	if (r == 0)
456 		iwmbt_info("Intel Event Mask is set");
457 	(void)iwmbt_exit_manufacturer(hdl, IWMBT_MM_EXIT_ONLY);
458 
459 	return 0;
460 }
461 
462 
463 /*
464  * Returns 0 on success.
465  */
466 static int
467 handle_8260(libusb_device_handle *hdl, char *firmware_dir)
468 {
469 	int r;
470 	uint32_t boot_param;
471 	struct iwmbt_version ver;
472 	struct iwmbt_boot_params params;
473 	char *firmware_path = NULL;
474 
475 	r = iwmbt_get_version(hdl, &ver);
476 	if (r < 0) {
477 		iwmbt_debug("iwmbt_get_version() failed code %d", r);
478 		return 1;
479 	}
480 	iwmbt_dump_version(&ver);
481 	iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
482 
483 	if (ver.fw_variant == FW_VARIANT_OPERATIONAL) {
484 		iwmbt_info("Firmware has already been downloaded");
485 		return 0;
486 	}
487 
488 	if (ver.fw_variant != FW_VARIANT_BOOTLOADER){
489 		iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
490 		return 1;
491 	}
492 
493 	/* Read Intel Secure Boot Params */
494 	r = iwmbt_get_boot_params(hdl, &params);
495 	if (r < 0) {
496 		iwmbt_debug("iwmbt_get_boot_params() failed!");
497 		return 1;
498 	}
499 	iwmbt_dump_boot_params(&params);
500 
501 	/* Check if firmware fragments are ACKed with a cmd complete event */
502 	if (params.limited_cce != 0x00) {
503 		iwmbt_err("Unsupported Intel firmware loading method (%u)",
504 		   params.limited_cce);
505 		return 1;
506 	}
507 
508 	firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
509 	if (firmware_path == NULL)
510 		return 1;
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, 0, 0);
515 	free(firmware_path);
516 	if (r < 0)
517 		return 1;
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 		return 1;
525 	}
526 
527 	iwmbt_info("Firmware operational");
528 
529 	/* Once device is running in operational mode we can ignore failures */
530 
531 	/* Dump actual controller version */
532 	r = iwmbt_get_version(hdl, &ver);
533 	if (r == 0)
534 		iwmbt_dump_version(&ver);
535 
536 	/* Apply the device configuration (DDC) parameters */
537 	firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "ddc");
538 	iwmbt_debug("ddc_path = %s", firmware_path);
539 	if (firmware_path != NULL) {
540 		r = iwmbt_init_ddc(hdl, firmware_path);
541 		if (r == 0)
542 			iwmbt_info("DDC download complete");
543 		free(firmware_path);
544 	}
545 
546 	r = iwmbt_set_event_mask(hdl);
547 	if (r == 0)
548 		iwmbt_info("Intel Event Mask is set");
549 
550 	return 0;
551 }
552 
553 
554 static int
555 handle_9260(libusb_device_handle *hdl, char *firmware_dir)
556 {
557 	int r;
558 	uint32_t boot_param;
559 	struct iwmbt_version vl;
560 	struct iwmbt_version_tlv vt;
561 	char *firmware_path = NULL;
562 
563 	r = iwmbt_get_version_tlv(hdl, &vt);
564 	if (r < 0) {
565 		iwmbt_debug("iwmbt_get_version_tlv() failed code %d", r);
566 		return 1;
567 	}
568 	iwmbt_dump_version_tlv(&vt);
569 	iwmbt_debug("img_type=0x%02x", (int) vt.img_type);
570 
571 	if (vt.img_type == TLV_IMG_TYPE_OPERATIONAL) {
572 		iwmbt_info("Firmware has already been downloaded");
573 		return 0;
574 	}
575 
576 	if (vt.img_type != TLV_IMG_TYPE_BOOTLOADER) {
577 		iwmbt_err("unknown img_type 0x%02x", (int) vt.img_type);
578 		return 1;
579 	}
580 
581 	/* Check if firmware fragments are ACKed with a cmd complete event */
582 	if (vt.limited_cce != 0x00) {
583 		iwmbt_err("Unsupported Intel firmware loading method (%u)",
584 		   vt.limited_cce);
585 		return 1;
586 	}
587 
588 	/* Check if secure boot engine is supported: 1 (ECDSA) or 0 (RSA) */
589 	if (vt.sbe_type > 0x01) {
590 		iwmbt_err("Unsupported secure boot engine (%u)",
591 		   vt.sbe_type);
592 		return 1;
593 	}
594 
595 	firmware_path = iwmbt_get_fwname_tlv(&vt, firmware_dir, "sfi");
596 	if (firmware_path == NULL)
597 		return 1;
598 	iwmbt_debug("firmware_path = %s", firmware_path);
599 
600 	/* Download firmware and parse it for magic Intel Reset parameter */
601 	r = iwmbt_init_firmware(hdl, firmware_path, &boot_param,
602 	    vt.cnvi_bt >> 16 & 0x3f, vt.sbe_type);
603 	free(firmware_path);
604 	if (r < 0)
605 		return 1;
606 
607 	iwmbt_info("Firmware download complete");
608 
609 	r = iwmbt_intel_reset(hdl, boot_param);
610 	if (r < 0) {
611 		iwmbt_debug("iwmbt_intel_reset() failed!");
612 		return 1;
613 	}
614 
615 	iwmbt_info("Firmware operational");
616 
617 	/* Once device is running in operational mode we can ignore failures */
618 
619 	r = iwmbt_get_version(hdl, &vl);
620 	if (r == 0)
621 		iwmbt_dump_version(&vl);
622 
623 	/* Apply the device configuration (DDC) parameters */
624 	firmware_path = iwmbt_get_fwname_tlv(&vt, firmware_dir, "ddc");
625 	iwmbt_debug("ddc_path = %s", firmware_path);
626 	if (firmware_path != NULL) {
627 		r = iwmbt_init_ddc(hdl, firmware_path);
628 		if (r == 0)
629 			iwmbt_info("DDC download complete");
630 		free(firmware_path);
631 	}
632 
633 	r = iwmbt_set_event_mask(hdl);
634 	if (r == 0)
635 		iwmbt_info("Intel Event Mask is set");
636 
637 	return 0;
638 }
639 
640 
641 int
642 main(int argc, char *argv[])
643 {
644 	libusb_context *ctx = NULL;
645 	libusb_device *dev = NULL;
646 	libusb_device_handle *hdl = NULL;
647 	int r;
648 	uint8_t bus_id = 0, dev_id = 0;
649 	int devid_set = 0;
650 	int n;
651 	char *firmware_dir = NULL;
652 	int retcode = 1;
653 	enum iwmbt_device iwmbt_device;
654 
655 	/* Parse command line arguments */
656 	while ((n = getopt(argc, argv, "Dd:f:hI")) != -1) {
657 		switch (n) {
658 		case 'd': /* ugen device name */
659 			devid_set = 1;
660 			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
661 				usage();
662 			break;
663 		case 'D':
664 			iwmbt_do_debug = 1;
665 			break;
666 		case 'f': /* firmware dir */
667 			if (firmware_dir)
668 				free(firmware_dir);
669 			firmware_dir = strdup(optarg);
670 			break;
671 		case 'I':
672 			iwmbt_do_info = 1;
673 			break;
674 		case 'h':
675 		default:
676 			usage();
677 			break;
678 			/* NOT REACHED */
679 		}
680 	}
681 
682 	/* Ensure the devid was given! */
683 	if (devid_set == 0) {
684 		usage();
685 		/* NOTREACHED */
686 	}
687 
688 	/* Default the firmware path */
689 	if (firmware_dir == NULL)
690 		firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
691 
692 	/* libusb setup */
693 	r = libusb_init(&ctx);
694 	if (r != 0) {
695 		iwmbt_err("libusb_init failed: code %d", r);
696 		exit(127);
697 	}
698 
699 	iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
700 
701 	/* Find a device based on the bus/dev id */
702 	dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_device);
703 	if (dev == NULL) {
704 		iwmbt_err("device not found");
705 		goto shutdown;
706 	}
707 
708 	/* XXX enforce that bInterfaceNumber is 0 */
709 
710 	/* XXX enforce the device/product id if they're non-zero */
711 
712 	/* Grab device handle */
713 	r = libusb_open(dev, &hdl);
714 	if (r != 0) {
715 		iwmbt_err("libusb_open() failed: code %d", r);
716 		goto shutdown;
717 	}
718 
719 	/* Check if ng_ubt is attached */
720 	r = libusb_kernel_driver_active(hdl, 0);
721 	if (r < 0) {
722 		iwmbt_err("libusb_kernel_driver_active() failed: code %d", r);
723 		goto shutdown;
724 	}
725 	if (r > 0) {
726 		iwmbt_info("Firmware has already been downloaded");
727 		retcode = 0;
728 		goto shutdown;
729 	}
730 
731 	switch(iwmbt_device) {
732 	case IWMBT_DEVICE_7260:
733 		retcode = handle_7260(hdl, firmware_dir);
734 		break;
735 	case IWMBT_DEVICE_8260:
736 		retcode = handle_8260(hdl, firmware_dir);
737 		break;
738 	case IWMBT_DEVICE_9260:
739 		retcode = handle_9260(hdl, firmware_dir);
740 		break;
741 	default:
742 		iwmbt_err("FIXME: unknown iwmbt type %d", (int)iwmbt_device);
743 		retcode = 1;
744 	}
745 
746 	if (retcode == 0) {
747 		/* Ask kernel driver to probe and attach device again */
748 		r = libusb_reset_device(hdl);
749 		if (r != 0)
750 			iwmbt_err("libusb_reset_device() failed: %s",
751 			    libusb_strerror(r));
752 	}
753 
754 shutdown:
755 	if (hdl != NULL)
756 		libusb_close(hdl);
757 
758 	if (dev != NULL)
759 		libusb_unref_device(dev);
760 
761 	if (ctx != NULL)
762 		libusb_exit(ctx);
763 
764 	if (retcode == 0)
765 		iwmbt_info("Firmware download is successful!");
766 	else
767 		iwmbt_err("Firmware download failed!");
768 
769 	return (retcode);
770 }
771