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