]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bluetooth/iwmbtfw/main.c
MFV: zlib: examples: define functions as static ones. (PR #855)
[FreeBSD/FreeBSD.git] / usr.sbin / bluetooth / iwmbtfw / main.c
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
50 int     iwmbt_do_debug = 0;
51 int     iwmbt_do_info = 0;
52
53 struct iwmbt_devid {
54         uint16_t product_id;
55         uint16_t vendor_id;
56 };
57
58 static 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
66 static 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
76 static int
77 iwmbt_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
94 static int
95 iwmbt_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
112 static libusb_device *
113 iwmbt_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
167 static void
168 iwmbt_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
182 static void
183 iwmbt_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
203 static int
204 iwmbt_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
228 static int
229 iwmbt_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
254 static int
255 iwmbt_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
283 static int
284 parse_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
302 static void
303 usage(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
314 int
315 main(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
551 reset:
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
559 shutdown:
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 }