xref: /freebsd/usr.sbin/bluetooth/iwmbtfw/main.c (revision c1643cedbf243424370162febf6d9180bdd1df58)
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
iwmbt_is_supported(struct libusb_device_descriptor * d)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 *
iwmbt_find_device(libusb_context * ctx,int bus_id,int dev_id,enum iwmbt_device * iwmbt_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
iwmbt_dump_version(struct iwmbt_version * ver)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
iwmbt_dump_boot_params(struct iwmbt_boot_params * params)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
iwmbt_dump_version_tlv(struct iwmbt_version_tlv * ver)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 == 0x01 || ver->img_type == 0x03)
219 		iwmbt_info("%s timestamp %u.%u buildtype %u build %u",
220 		    ver->img_type == 0x01 ? "Bootloader" : "Firmware",
221 		    2000 + (ver->timestamp >> 8),
222 		    ver->timestamp & 0xff,
223 		    ver->build_type,
224 		    ver->build_num);
225 }
226 
227 static int
iwmbt_patch_firmware(libusb_device_handle * hdl,const char * firmware_path)228 iwmbt_patch_firmware(libusb_device_handle *hdl, const char *firmware_path)
229 {
230 	struct iwmbt_firmware fw;
231 	int ret;
232 
233 	iwmbt_debug("loading %s", firmware_path);
234 
235 	/* Read in the firmware */
236 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
237 		iwmbt_debug("iwmbt_fw_read() failed");
238 		return (-1);
239 	}
240 
241 	/* Load in the firmware */
242 	ret = iwmbt_patch_fwfile(hdl, &fw);
243 	if (ret < 0)
244 		iwmbt_debug("Loading firmware file failed");
245 
246 	/* free it */
247 	iwmbt_fw_free(&fw);
248 
249 	return (ret);
250 }
251 
252 static int
iwmbt_init_firmware(libusb_device_handle * hdl,const char * firmware_path,uint32_t * boot_param,uint8_t hw_variant,uint8_t sbe_type)253 iwmbt_init_firmware(libusb_device_handle *hdl, const char *firmware_path,
254     uint32_t *boot_param, uint8_t hw_variant, uint8_t sbe_type)
255 {
256 	struct iwmbt_firmware fw;
257 	int header_len, ret = -1;
258 
259 	iwmbt_debug("loading %s", firmware_path);
260 
261 	/* Read in the firmware */
262 	if (iwmbt_fw_read(&fw, firmware_path) <= 0) {
263 		iwmbt_debug("iwmbt_fw_read() failed");
264 		return (-1);
265 	}
266 
267 	iwmbt_debug("Firmware file size=%d", fw.len);
268 
269 	if (hw_variant <= 0x14) {
270 		/*
271 		 * Hardware variants 0x0b, 0x0c, 0x11 - 0x14 .sfi file have
272 		 * a RSA header of 644 bytes followed by Command Buffer.
273 		 */
274 		header_len = RSA_HEADER_LEN;
275 		if (fw.len < header_len) {
276 			iwmbt_err("Invalid size of firmware file (%d)", fw.len);
277 			ret = -1;
278 			goto exit;
279 		}
280 
281 		/* Check if the CSS Header version is RSA(0x00010000) */
282 		if (le32dec(fw.buf + CSS_HEADER_OFFSET) != 0x00010000) {
283 			iwmbt_err("Invalid CSS Header version");
284 			ret = -1;
285 			goto exit;
286 		}
287 
288 		/* Only RSA secure boot engine supported */
289 		if (sbe_type != 0x00) {
290 			iwmbt_err("Invalid SBE type for hardware variant (%d)",
291 			    hw_variant);
292 			ret = -1;
293 			goto exit;
294 		}
295 
296 	} else if (hw_variant >= 0x17) {
297 		/*
298 		 * Hardware variants 0x17, 0x18 onwards support both RSA and
299 		 * ECDSA secure boot engine. As a result, the corresponding sfi
300 		 * file will have RSA header of 644, ECDSA header of 320 bytes
301 		 * followed by Command Buffer.
302 		 */
303 		header_len = ECDSA_OFFSET + ECDSA_HEADER_LEN;
304 		if (fw.len < header_len) {
305 			iwmbt_err("Invalid size of firmware file (%d)", fw.len);
306 			ret = -1;
307 			goto exit;
308 		}
309 
310 		/* Check if CSS header for ECDSA follows the RSA header */
311 		if (fw.buf[ECDSA_OFFSET] != 0x06) {
312 			ret = -1;
313 			goto exit;
314 		}
315 
316 		/* Check if the CSS Header version is ECDSA(0x00020000) */
317 		if (le32dec(fw.buf + ECDSA_OFFSET + CSS_HEADER_OFFSET) != 0x00020000) {
318 			iwmbt_err("Invalid CSS Header version");
319 			ret = -1;
320 			goto exit;
321 		}
322 	}
323 
324 	/* Load in the CSS header */
325 	if (sbe_type == 0x00)
326 		ret = iwmbt_load_rsa_header(hdl, &fw);
327 	else if (sbe_type == 0x01)
328 		ret = iwmbt_load_ecdsa_header(hdl, &fw);
329 	if (ret < 0)
330 		goto exit;
331 
332 	/* Load in the Command Buffer */
333 	ret = iwmbt_load_fwfile(hdl, &fw, boot_param, header_len);
334 
335 exit:
336 	/* free firmware */
337 	iwmbt_fw_free(&fw);
338 
339 	return (ret);
340 }
341 
342 static int
iwmbt_init_ddc(libusb_device_handle * hdl,const char * ddc_path)343 iwmbt_init_ddc(libusb_device_handle *hdl, const char *ddc_path)
344 {
345 	struct iwmbt_firmware ddc;
346 	int ret;
347 
348 	iwmbt_debug("loading %s", ddc_path);
349 
350 	/* Read in the DDC file */
351 	if (iwmbt_fw_read(&ddc, ddc_path) <= 0) {
352 		iwmbt_debug("iwmbt_fw_read() failed");
353 		return (-1);
354 	}
355 
356 	/* Load in the DDC file */
357 	ret = iwmbt_load_ddc(hdl, &ddc);
358 	if (ret < 0)
359 		iwmbt_debug("Loading DDC file failed");
360 
361 	/* free it */
362 	iwmbt_fw_free(&ddc);
363 
364 	return (ret);
365 }
366 
367 /*
368  * Parse ugen name and extract device's bus and address
369  */
370 
371 static int
parse_ugen_name(char const * ugen,uint8_t * bus,uint8_t * addr)372 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
373 {
374 	char *ep;
375 
376 	if (strncmp(ugen, "ugen", 4) != 0)
377 		return (-1);
378 
379 	*bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
380 	if (*ep != '.')
381 		return (-1);
382 
383 	*addr = (uint8_t) strtoul(ep + 1, &ep, 10);
384 	if (*ep != '\0')
385 		return (-1);
386 
387 	return (0);
388 }
389 
390 static void
usage(void)391 usage(void)
392 {
393 	fprintf(stderr,
394 	    "Usage: iwmbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
395 	fprintf(stderr, "    -D: enable debugging\n");
396 	fprintf(stderr, "    -d: device to operate upon\n");
397 	fprintf(stderr, "    -f: firmware path, if not default\n");
398 	fprintf(stderr, "    -I: enable informational output\n");
399 	exit(127);
400 }
401 
402 int
main(int argc,char * argv[])403 main(int argc, char *argv[])
404 {
405 	libusb_context *ctx = NULL;
406 	libusb_device *dev = NULL;
407 	libusb_device_handle *hdl = NULL;
408 	static struct iwmbt_version ver;
409 	static struct iwmbt_version_tlv ver_tlv;
410 	static struct iwmbt_boot_params params;
411 	uint32_t boot_param;
412 	int r;
413 	uint8_t bus_id = 0, dev_id = 0;
414 	int devid_set = 0;
415 	int n;
416 	char *firmware_dir = NULL;
417 	char *firmware_path = NULL;
418 	int retcode = 1;
419 	enum iwmbt_device iwmbt_device;
420 
421 	/* Parse command line arguments */
422 	while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
423 		switch (n) {
424 		case 'd': /* ugen device name */
425 			devid_set = 1;
426 			if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
427 				usage();
428 			break;
429 		case 'D':
430 			iwmbt_do_debug = 1;
431 			break;
432 		case 'f': /* firmware dir */
433 			if (firmware_dir)
434 				free(firmware_dir);
435 			firmware_dir = strdup(optarg);
436 			break;
437 		case 'I':
438 			iwmbt_do_info = 1;
439 			break;
440 		case 'h':
441 		default:
442 			usage();
443 			break;
444 			/* NOT REACHED */
445 		}
446 	}
447 
448 	/* Ensure the devid was given! */
449 	if (devid_set == 0) {
450 		usage();
451 		/* NOTREACHED */
452 	}
453 
454 	/* libusb setup */
455 	r = libusb_init(&ctx);
456 	if (r != 0) {
457 		iwmbt_err("libusb_init failed: code %d", r);
458 		exit(127);
459 	}
460 
461 	iwmbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
462 
463 	/* Find a device based on the bus/dev id */
464 	dev = iwmbt_find_device(ctx, bus_id, dev_id, &iwmbt_device);
465 	if (dev == NULL) {
466 		iwmbt_err("device not found");
467 		goto shutdown;
468 	}
469 
470 	/* XXX enforce that bInterfaceNumber is 0 */
471 
472 	/* XXX enforce the device/product id if they're non-zero */
473 
474 	/* Grab device handle */
475 	r = libusb_open(dev, &hdl);
476 	if (r != 0) {
477 		iwmbt_err("libusb_open() failed: code %d", r);
478 		goto shutdown;
479 	}
480 
481 	/* Check if ng_ubt is attached */
482 	r = libusb_kernel_driver_active(hdl, 0);
483 	if (r < 0) {
484 		iwmbt_err("libusb_kernel_driver_active() failed: code %d", r);
485 		goto shutdown;
486 	}
487 	if (r > 0) {
488 		iwmbt_info("Firmware has already been downloaded");
489 		retcode = 0;
490 		goto shutdown;
491 	}
492 
493 	if (iwmbt_device == IWMBT_DEVICE_7260) {
494 
495 		/* Get Intel version */
496 		r = iwmbt_get_version(hdl, &ver);
497 		if (r < 0) {
498 			iwmbt_debug("iwmbt_get_version() failed code %d", r);
499 			goto shutdown;
500 		}
501 		iwmbt_dump_version(&ver);
502 		iwmbt_debug("fw_patch_num=0x%02x", (int) ver.fw_patch_num);
503 
504 		/* fw_patch_num = >0 operational mode */
505 		if (ver.fw_patch_num > 0x00) {
506 			iwmbt_info("Firmware has already been downloaded");
507 			retcode = 0;
508 			goto reset;
509 		}
510 
511 		/* Default the firmware path */
512 		if (firmware_dir == NULL)
513 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
514 
515 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "bseq");
516 		if (firmware_path == NULL)
517 			goto shutdown;
518 
519 		iwmbt_debug("firmware_path = %s", firmware_path);
520 
521 		/* Enter manufacturer mode */
522 		r = iwmbt_enter_manufacturer(hdl);
523 		if (r < 0) {
524 			iwmbt_debug("iwmbt_enter_manufacturer() failed code %d", r);
525 			goto shutdown;
526 		}
527 
528 		/* Download firmware and parse it for magic Intel Reset parameter */
529 		r = iwmbt_patch_firmware(hdl, firmware_path);
530 		free(firmware_path);
531 		if (r < 0) {
532 			(void)iwmbt_exit_manufacturer(hdl, 0x01);
533 			goto shutdown;
534 		}
535 
536 		iwmbt_info("Firmware download complete");
537 
538 		/* Exit manufacturer mode */
539 		r = iwmbt_exit_manufacturer(hdl, r == 0 ? 0x00 : 0x02);
540 		if (r < 0) {
541 			iwmbt_debug("iwmbt_exit_manufacturer() failed code %d", r);
542 			goto shutdown;
543 		}
544 
545 		/* Once device is running in operational mode we can ignore failures */
546 		retcode = 0;
547 
548 		/* Execute Read Intel Version one more time */
549 		r = iwmbt_get_version(hdl, &ver);
550 		if (r == 0)
551 			iwmbt_dump_version(&ver);
552 
553 		/* Set Intel Event mask */
554 		if (iwmbt_enter_manufacturer(hdl) < 0)
555 			goto reset;
556 		r = iwmbt_set_event_mask(hdl);
557 		if (r == 0)
558 			iwmbt_info("Intel Event Mask is set");
559 		(void)iwmbt_exit_manufacturer(hdl, 0x00);
560 
561 	} else if (iwmbt_device == IWMBT_DEVICE_8260) {
562 
563 		/* Get Intel version */
564 		r = iwmbt_get_version(hdl, &ver);
565 		if (r < 0) {
566 			iwmbt_debug("iwmbt_get_version() failed code %d", r);
567 			goto shutdown;
568 		}
569 		iwmbt_dump_version(&ver);
570 		iwmbt_debug("fw_variant=0x%02x", (int) ver.fw_variant);
571 
572 		/* fw_variant = 0x06 bootloader mode / 0x23 operational mode */
573 		if (ver.fw_variant == 0x23) {
574 			iwmbt_info("Firmware has already been downloaded");
575 			retcode = 0;
576 			goto reset;
577 		}
578 
579 		if (ver.fw_variant != 0x06){
580 			iwmbt_err("unknown fw_variant 0x%02x", (int) ver.fw_variant);
581 			goto shutdown;
582 		}
583 
584 		/* Read Intel Secure Boot Params */
585 		r = iwmbt_get_boot_params(hdl, &params);
586 		if (r < 0) {
587 			iwmbt_debug("iwmbt_get_boot_params() failed!");
588 			goto shutdown;
589 		}
590 		iwmbt_dump_boot_params(&params);
591 
592 		/* Check if firmware fragments are ACKed with a cmd complete event */
593 		if (params.limited_cce != 0x00) {
594 			iwmbt_err("Unsupported Intel firmware loading method (%u)",
595 			   params.limited_cce);
596 			goto shutdown;
597 		}
598 
599 		/* Default the firmware path */
600 		if (firmware_dir == NULL)
601 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
602 
603 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "sfi");
604 		if (firmware_path == NULL)
605 			goto shutdown;
606 
607 		iwmbt_debug("firmware_path = %s", firmware_path);
608 
609 		/* Download firmware and parse it for magic Intel Reset parameter */
610 		r = iwmbt_init_firmware(hdl, firmware_path, &boot_param, 0, 0);
611 		free(firmware_path);
612 		if (r < 0)
613 			goto shutdown;
614 
615 		iwmbt_info("Firmware download complete");
616 
617 		r = iwmbt_intel_reset(hdl, boot_param);
618 		if (r < 0) {
619 			iwmbt_debug("iwmbt_intel_reset() failed!");
620 			goto shutdown;
621 		}
622 
623 		iwmbt_info("Firmware operational");
624 
625 		/* Once device is running in operational mode we can ignore failures */
626 		retcode = 0;
627 
628 		/* Execute Read Intel Version one more time */
629 		r = iwmbt_get_version(hdl, &ver);
630 		if (r == 0)
631 			iwmbt_dump_version(&ver);
632 
633 		/* Apply the device configuration (DDC) parameters */
634 		firmware_path = iwmbt_get_fwname(&ver, &params, firmware_dir, "ddc");
635 		iwmbt_debug("ddc_path = %s", firmware_path);
636 		if (firmware_path != NULL) {
637 			r = iwmbt_init_ddc(hdl, firmware_path);
638 			if (r == 0)
639 				iwmbt_info("DDC download complete");
640 			free(firmware_path);
641 		}
642 
643 		/* Set Intel Event mask */
644 		r = iwmbt_set_event_mask(hdl);
645 		if (r == 0)
646 			iwmbt_info("Intel Event Mask is set");
647 
648 	} else {
649 
650 		/* Get Intel version */
651 		r = iwmbt_get_version_tlv(hdl, &ver_tlv);
652 		if (r < 0) {
653 			iwmbt_debug("iwmbt_get_version_tlv() failed code %d", r);
654 			goto shutdown;
655 		}
656 		iwmbt_dump_version_tlv(&ver_tlv);
657 		iwmbt_debug("img_type=0x%02x", (int) ver_tlv.img_type);
658 
659 		/* img_type = 0x01 bootloader mode / 0x03 operational mode */
660 		if (ver_tlv.img_type == 0x03) {
661 			iwmbt_info("Firmware has already been downloaded");
662 			retcode = 0;
663 			goto reset;
664 		}
665 
666 		if (ver_tlv.img_type != 0x01){
667 			iwmbt_err("unknown img_type 0x%02x", (int) ver_tlv.img_type);
668 			goto shutdown;
669 		}
670 
671 		/* Check if firmware fragments are ACKed with a cmd complete event */
672 		if (ver_tlv.limited_cce != 0x00) {
673 			iwmbt_err("Unsupported Intel firmware loading method (%u)",
674 			   ver_tlv.limited_cce);
675 			goto shutdown;
676 		}
677 
678 		/* Check if secure boot engine is supported: 1 (ECDSA) or 0 (RSA) */
679 		if (ver_tlv.sbe_type > 0x01) {
680 			iwmbt_err("Unsupported secure boot engine (%u)",
681 			   ver_tlv.sbe_type);
682 			goto shutdown;
683 		}
684 
685 		/* Default the firmware path */
686 		if (firmware_dir == NULL)
687 			firmware_dir = strdup(_DEFAULT_IWMBT_FIRMWARE_PATH);
688 
689 		firmware_path = iwmbt_get_fwname_tlv(&ver_tlv, firmware_dir, "sfi");
690 		if (firmware_path == NULL)
691 			goto shutdown;
692 
693 		iwmbt_debug("firmware_path = %s", firmware_path);
694 
695 		/* Download firmware and parse it for magic Intel Reset parameter */
696 		r = iwmbt_init_firmware(hdl, firmware_path, &boot_param,
697 		    ver_tlv.cnvi_bt >> 16 & 0x3f, ver_tlv.sbe_type);
698 		free(firmware_path);
699 		if (r < 0)
700 			goto shutdown;
701 
702 		r = iwmbt_intel_reset(hdl, boot_param);
703 		if (r < 0) {
704 			iwmbt_debug("iwmbt_intel_reset() failed!");
705 			goto shutdown;
706 		}
707 
708 		iwmbt_info("Firmware operational");
709 
710 		/* Once device is running in operational mode we can ignore failures */
711 		retcode = 0;
712 
713 		/* Execute Read Intel Version one more time */
714 		r = iwmbt_get_version(hdl, &ver);
715 		if (r == 0)
716 			iwmbt_dump_version(&ver);
717 
718 		/* Apply the device configuration (DDC) parameters */
719 		firmware_path = iwmbt_get_fwname_tlv(&ver_tlv, firmware_dir, "ddc");
720 		iwmbt_debug("ddc_path = %s", firmware_path);
721 		if (firmware_path != NULL) {
722 			r = iwmbt_init_ddc(hdl, firmware_path);
723 			if (r == 0)
724 				iwmbt_info("DDC download complete");
725 			free(firmware_path);
726 		}
727 
728 		/* Set Intel Event mask */
729 		r = iwmbt_set_event_mask(hdl);
730 		if (r == 0)
731 			iwmbt_info("Intel Event Mask is set");
732 
733 		iwmbt_info("Firmware download complete");
734 	}
735 
736 reset:
737 
738 	/* Ask kernel driver to probe and attach device again */
739 	r = libusb_reset_device(hdl);
740 	if (r != 0)
741 		iwmbt_err("libusb_reset_device() failed: %s",
742 		    libusb_strerror(r));
743 
744 shutdown:
745 
746 	/* Shutdown */
747 
748 	if (hdl != NULL)
749 		libusb_close(hdl);
750 
751 	if (dev != NULL)
752 		libusb_unref_device(dev);
753 
754 	if (ctx != NULL)
755 		libusb_exit(ctx);
756 
757 	if (retcode == 0)
758 		iwmbt_info("Firmware download is successful!");
759 	else
760 		iwmbt_err("Firmware download failed!");
761 
762 	return (retcode);
763 }
764