Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bluetooth/iwmbtfw/main.c
105642 views
1
/*-
2
* SPDX-License-Identifier: BSD-2-Clause
3
*
4
* Copyright (c) 2013 Adrian Chadd <[email protected]>
5
* Copyright (c) 2019 Vladimir Kondratyev <[email protected]>
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
772