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 "rtlbt_fw.h"
46 #include "rtlbt_hw.h"
47 #include "rtlbt_dbg.h"
48
49 #define _DEFAULT_RTLBT_FIRMWARE_PATH "/usr/share/firmware/rtlbt"
50
51 int rtlbt_do_debug = 0;
52 int rtlbt_do_info = 0;
53
54 struct rtlbt_devid {
55 uint16_t product_id;
56 uint16_t vendor_id;
57 };
58
59 static struct rtlbt_devid rtlbt_list[] = {
60 /*
61 * Non-Realtek vendors using Realtek Bluetooth chipsets.
62 * Devices with vendor 0x0bda are already matched by the
63 * generic check in rtlbt_find_device().
64 */
65
66 /* Realtek 8821CE Bluetooth devices */
67 { .vendor_id = 0x13d3, .product_id = 0x3529 },
68
69 /* Realtek 8851BE Bluetooth devices */
70 { .vendor_id = 0x13d3, .product_id = 0x3600 },
71
72 /* Realtek 8852AE Bluetooth devices */
73 { .vendor_id = 0x04c5, .product_id = 0x165c },
74 { .vendor_id = 0x04ca, .product_id = 0x4006 },
75 { .vendor_id = 0x0cb8, .product_id = 0xc549 },
76
77 /* Realtek 8852CE Bluetooth devices */
78 { .vendor_id = 0x04ca, .product_id = 0x4007 },
79 { .vendor_id = 0x04c5, .product_id = 0x1675 },
80 { .vendor_id = 0x0cb8, .product_id = 0xc558 },
81 { .vendor_id = 0x13d3, .product_id = 0x3587 },
82 { .vendor_id = 0x13d3, .product_id = 0x3586 },
83 { .vendor_id = 0x13d3, .product_id = 0x3592 },
84 { .vendor_id = 0x13d3, .product_id = 0x3612 },
85 { .vendor_id = 0x0489, .product_id = 0xe122 },
86
87 /* Realtek 8852BE Bluetooth devices */
88 { .vendor_id = 0x0cb8, .product_id = 0xc559 },
89 { .vendor_id = 0x13d3, .product_id = 0x3570 },
90 { .vendor_id = 0x13d3, .product_id = 0x3571 },
91 { .vendor_id = 0x13d3, .product_id = 0x3572 },
92 { .vendor_id = 0x13d3, .product_id = 0x3591 },
93 { .vendor_id = 0x0489, .product_id = 0xe123 },
94 { .vendor_id = 0x0489, .product_id = 0xe125 },
95
96 /* Realtek 8922AE Bluetooth devices */
97 { .vendor_id = 0x13d3, .product_id = 0x3617 },
98 { .vendor_id = 0x13d3, .product_id = 0x3616 },
99 { .vendor_id = 0x0489, .product_id = 0xe130 },
100
101 /* Realtek 8723AE Bluetooth devices */
102 { .vendor_id = 0x0930, .product_id = 0x021d },
103 { .vendor_id = 0x13d3, .product_id = 0x3394 },
104
105 /* Realtek 8723BE Bluetooth devices */
106 { .vendor_id = 0x0489, .product_id = 0xe085 },
107 { .vendor_id = 0x0489, .product_id = 0xe08b },
108 { .vendor_id = 0x04f2, .product_id = 0xb49f },
109 { .vendor_id = 0x13d3, .product_id = 0x3410 },
110 { .vendor_id = 0x13d3, .product_id = 0x3416 },
111 { .vendor_id = 0x13d3, .product_id = 0x3459 },
112 { .vendor_id = 0x13d3, .product_id = 0x3494 },
113
114 /* Realtek 8723BU Bluetooth devices */
115 { .vendor_id = 0x7392, .product_id = 0xa611 },
116
117 /* Realtek 8723DE Bluetooth devices */
118 { .vendor_id = 0x2ff8, .product_id = 0xb011 },
119
120 /* Realtek 8761BUV Bluetooth devices */
121 { .vendor_id = 0x2c4e, .product_id = 0x0115 },
122 { .vendor_id = 0x2357, .product_id = 0x0604 },
123 { .vendor_id = 0x0b05, .product_id = 0x190e },
124 { .vendor_id = 0x2550, .product_id = 0x8761 },
125 { .vendor_id = 0x6655, .product_id = 0x8771 },
126 { .vendor_id = 0x7392, .product_id = 0xc611 },
127 { .vendor_id = 0x2b89, .product_id = 0x8761 },
128
129 /* Realtek 8821AE Bluetooth devices */
130 { .vendor_id = 0x0b05, .product_id = 0x17dc },
131 { .vendor_id = 0x13d3, .product_id = 0x3414 },
132 { .vendor_id = 0x13d3, .product_id = 0x3458 },
133 { .vendor_id = 0x13d3, .product_id = 0x3461 },
134 { .vendor_id = 0x13d3, .product_id = 0x3462 },
135
136 /* Realtek 8822BE Bluetooth devices */
137 { .vendor_id = 0x13d3, .product_id = 0x3526 },
138 { .vendor_id = 0x0b05, .product_id = 0x185c },
139
140 /* Realtek 8822CE Bluetooth devices */
141 { .vendor_id = 0x04ca, .product_id = 0x4005 },
142 { .vendor_id = 0x04c5, .product_id = 0x161f },
143 { .vendor_id = 0x0b05, .product_id = 0x18ef },
144 { .vendor_id = 0x13d3, .product_id = 0x3548 },
145 { .vendor_id = 0x13d3, .product_id = 0x3549 },
146 { .vendor_id = 0x13d3, .product_id = 0x3553 },
147 { .vendor_id = 0x13d3, .product_id = 0x3555 },
148 { .vendor_id = 0x2ff8, .product_id = 0x3051 },
149 { .vendor_id = 0x1358, .product_id = 0xc123 },
150 { .vendor_id = 0x0cb5, .product_id = 0xc547 },
151 };
152
153 static int
rtlbt_is_realtek(struct libusb_device_descriptor * d)154 rtlbt_is_realtek(struct libusb_device_descriptor *d)
155 {
156 int i;
157
158 /* Search looking for whether it's a Realtek-based device */
159 for (i = 0; i < (int) nitems(rtlbt_list); i++) {
160 if ((rtlbt_list[i].product_id == d->idProduct) &&
161 (rtlbt_list[i].vendor_id == d->idVendor)) {
162 rtlbt_info("found USB Realtek");
163 return (1);
164 }
165 }
166
167 /* Not found */
168 return (0);
169 }
170
171 static int
rtlbt_is_bluetooth(struct libusb_device * dev)172 rtlbt_is_bluetooth(struct libusb_device *dev)
173 {
174 struct libusb_config_descriptor *cfg;
175 const struct libusb_interface *ifc;
176 const struct libusb_interface_descriptor *d;
177 int r;
178
179 r = libusb_get_active_config_descriptor(dev, &cfg);
180 if (r < 0) {
181 rtlbt_err("Cannot retrieve config descriptor: %s",
182 libusb_error_name(r));
183 return (0);
184 }
185
186 if (cfg->bNumInterfaces != 0) {
187 /* Only 0-th HCI/ACL interface is supported by downloader */
188 ifc = &cfg->interface[0];
189 if (ifc->num_altsetting != 0) {
190 /* BT HCI/ACL interface has no altsettings */
191 d = &ifc->altsetting[0];
192 /* Check if interface is a bluetooth */
193 if (d->bInterfaceClass == LIBUSB_CLASS_WIRELESS &&
194 d->bInterfaceSubClass == 0x01 &&
195 d->bInterfaceProtocol == 0x01) {
196 rtlbt_info("found USB Realtek");
197 libusb_free_config_descriptor(cfg);
198 return (1);
199 }
200 }
201 }
202 libusb_free_config_descriptor(cfg);
203
204 /* Not found */
205 return (0);
206 }
207
208 static libusb_device *
rtlbt_find_device(libusb_context * ctx,int bus_id,int dev_id)209 rtlbt_find_device(libusb_context *ctx, int bus_id, int dev_id)
210 {
211 libusb_device **list, *dev = NULL, *found = NULL;
212 struct libusb_device_descriptor d;
213 ssize_t cnt, i;
214 int r;
215
216 cnt = libusb_get_device_list(ctx, &list);
217 if (cnt < 0) {
218 rtlbt_err("libusb_get_device_list() failed: code %lld",
219 (long long int) cnt);
220 return (NULL);
221 }
222
223 /*
224 * Scan through USB device list.
225 */
226 for (i = 0; i < cnt; i++) {
227 dev = list[i];
228 if (bus_id == libusb_get_bus_number(dev) &&
229 dev_id == libusb_get_device_address(dev)) {
230 /* Get the device descriptor for this device entry */
231 r = libusb_get_device_descriptor(dev, &d);
232 if (r != 0) {
233 rtlbt_err("libusb_get_device_descriptor: %s",
234 libusb_strerror(r));
235 break;
236 }
237
238 /* For non-Realtek match on the vendor/product id */
239 if (rtlbt_is_realtek(&d)) {
240 /*
241 * Take a reference so it's not freed later on.
242 */
243 found = libusb_ref_device(dev);
244 break;
245 }
246 /* For Realtek vendor match on the interface class */
247 if (d.idVendor == 0x0bda && rtlbt_is_bluetooth(dev)) {
248 /*
249 * Take a reference so it's not freed later on.
250 */
251 found = libusb_ref_device(dev);
252 break;
253 }
254 }
255 }
256
257 libusb_free_device_list(list, 1);
258 return (found);
259 }
260
261 static void
rtlbt_dump_version(ng_hci_read_local_ver_rp * ver)262 rtlbt_dump_version(ng_hci_read_local_ver_rp *ver)
263 {
264 rtlbt_info("hci_version 0x%02x", ver->hci_version);
265 rtlbt_info("hci_revision 0x%04x", le16toh(ver->hci_revision));
266 rtlbt_info("lmp_version 0x%02x", ver->lmp_version);
267 rtlbt_info("lmp_subversion 0x%04x", le16toh(ver->lmp_subversion));
268 }
269
270 /*
271 * Parse ugen name and extract device's bus and address
272 */
273
274 static int
parse_ugen_name(char const * ugen,uint8_t * bus,uint8_t * addr)275 parse_ugen_name(char const *ugen, uint8_t *bus, uint8_t *addr)
276 {
277 char *ep;
278
279 if (strncmp(ugen, "ugen", 4) != 0)
280 return (-1);
281
282 *bus = (uint8_t) strtoul(ugen + 4, &ep, 10);
283 if (*ep != '.')
284 return (-1);
285
286 *addr = (uint8_t) strtoul(ep + 1, &ep, 10);
287 if (*ep != '\0')
288 return (-1);
289
290 return (0);
291 }
292
293 static void
usage(void)294 usage(void)
295 {
296 fprintf(stderr,
297 "Usage: rtlbtfw (-D) -d ugenX.Y (-f firmware path) (-I)\n");
298 fprintf(stderr, " -D: enable debugging\n");
299 fprintf(stderr, " -d: device to operate upon\n");
300 fprintf(stderr, " -f: firmware path, if not default\n");
301 fprintf(stderr, " -I: enable informational output\n");
302 exit(127);
303 }
304
305 int
main(int argc,char * argv[])306 main(int argc, char *argv[])
307 {
308 libusb_context *ctx = NULL;
309 libusb_device *dev = NULL;
310 libusb_device_handle *hdl = NULL;
311 ng_hci_read_local_ver_rp ver;
312 int r;
313 uint8_t bus_id = 0, dev_id = 0;
314 int devid_set = 0;
315 int n;
316 char *firmware_dir = NULL;
317 char *firmware_path = NULL;
318 char *config_path = NULL;
319 const char *fw_suffix;
320 int retcode = 1;
321 const struct rtlbt_id_table *ic;
322 uint8_t rom_version;
323 struct rtlbt_firmware fw, cfg;
324 enum rtlbt_fw_type fw_type;
325 uint16_t fw_lmp_subversion;
326
327 /* Parse command line arguments */
328 while ((n = getopt(argc, argv, "Dd:f:hIm:p:v:")) != -1) {
329 switch (n) {
330 case 'd': /* ugen device name */
331 devid_set = 1;
332 if (parse_ugen_name(optarg, &bus_id, &dev_id) < 0)
333 usage();
334 break;
335 case 'D':
336 rtlbt_do_debug = 1;
337 break;
338 case 'f': /* firmware dir */
339 if (firmware_dir)
340 free(firmware_dir);
341 firmware_dir = strdup(optarg);
342 break;
343 case 'I':
344 rtlbt_do_info = 1;
345 break;
346 case 'h':
347 default:
348 usage();
349 break;
350 /* NOT REACHED */
351 }
352 }
353
354 /* Ensure the devid was given! */
355 if (devid_set == 0) {
356 usage();
357 /* NOTREACHED */
358 }
359
360 /* libusb setup */
361 r = libusb_init(&ctx);
362 if (r != 0) {
363 rtlbt_err("libusb_init failed: code %d", r);
364 exit(127);
365 }
366
367 rtlbt_debug("opening dev %d.%d", (int) bus_id, (int) dev_id);
368
369 /* Find a device based on the bus/dev id */
370 dev = rtlbt_find_device(ctx, bus_id, dev_id);
371 if (dev == NULL) {
372 rtlbt_err("device not found");
373 goto shutdown;
374 }
375
376 /* XXX enforce that bInterfaceNumber is 0 */
377
378 /* XXX enforce the device/product id if they're non-zero */
379
380 /* Grab device handle */
381 r = libusb_open(dev, &hdl);
382 if (r != 0) {
383 rtlbt_err("libusb_open() failed: code %d", r);
384 goto shutdown;
385 }
386
387 /* Check if ng_ubt is attached */
388 r = libusb_kernel_driver_active(hdl, 0);
389 if (r < 0) {
390 rtlbt_err("libusb_kernel_driver_active() failed: code %d", r);
391 goto shutdown;
392 }
393 if (r > 0) {
394 rtlbt_info("Firmware has already been downloaded");
395 retcode = 0;
396 goto shutdown;
397 }
398
399 /* Get local version */
400 r = rtlbt_read_local_ver(hdl, &ver);
401 if (r < 0) {
402 rtlbt_err("rtlbt_read_local_ver() failed code %d", r);
403 goto shutdown;
404 }
405 rtlbt_dump_version(&ver);
406
407 ic = rtlbt_get_ic(ver.lmp_subversion, ver.hci_revision,
408 ver.hci_version);
409 if (ic == NULL) {
410 rtlbt_err("rtlbt_get_ic() failed: Unknown IC");
411 goto shutdown;
412 }
413
414 /* Default the firmware path */
415 if (firmware_dir == NULL)
416 firmware_dir = strdup(_DEFAULT_RTLBT_FIRMWARE_PATH);
417
418 fw_suffix = ic->fw_suffix == NULL ? "_fw.bin" : ic->fw_suffix;
419 firmware_path = rtlbt_get_fwname(ic->fw_name, firmware_dir, fw_suffix);
420 if (firmware_path == NULL)
421 goto shutdown;
422
423 rtlbt_debug("firmware_path = %s", firmware_path);
424
425 rtlbt_info("loading firmware %s", firmware_path);
426
427 /* Read in the firmware */
428 if (rtlbt_fw_read(&fw, firmware_path) <= 0) {
429 rtlbt_debug("rtlbt_fw_read() failed");
430 return (-1);
431 }
432
433 fw_type = rtlbt_get_fw_type(&fw, &fw_lmp_subversion);
434 if (fw_type == RTLBT_FW_TYPE_UNKNOWN &&
435 (ic->flags & RTLBT_IC_FLAG_SIMPLE) == 0) {
436 rtlbt_debug("Unknown firmware type");
437 goto shutdown;
438 }
439
440 if (fw_type != RTLBT_FW_TYPE_UNKNOWN) {
441
442 /* Match hardware and firmware lmp_subversion */
443 if (fw_lmp_subversion != ver.lmp_subversion) {
444 rtlbt_err("firmware is for %x but this is a %x",
445 fw_lmp_subversion, ver.lmp_subversion);
446 goto shutdown;
447 }
448
449 /* Query a ROM version */
450 r = rtlbt_read_rom_ver(hdl, &rom_version);
451 if (r < 0) {
452 rtlbt_err("rtlbt_read_rom_ver() failed code %d", r);
453 goto shutdown;
454 }
455 rtlbt_debug("rom_version = %d", rom_version);
456
457 /* Load in the firmware */
458 if (fw_type == RTLBT_FW_TYPE_V2) {
459 uint8_t key_id, reg_val[2];
460 r = rtlbt_read_reg16(hdl, RTLBT_SEC_PROJ, reg_val);
461 if (r < 0) {
462 rtlbt_err("rtlbt_read_reg16() failed code %d", r);
463 goto shutdown;
464 }
465 key_id = reg_val[0];
466 rtlbt_debug("key_id = %d", key_id);
467 r = rtlbt_parse_fwfile_v2(&fw, rom_version, key_id);
468 } else
469 r = rtlbt_parse_fwfile_v1(&fw, rom_version);
470 if (r < 0) {
471 rtlbt_err("Parsing firmware file failed");
472 goto shutdown;
473 }
474
475 config_path = rtlbt_get_fwname(ic->fw_name, firmware_dir,
476 "_config.bin");
477 if (config_path == NULL)
478 goto shutdown;
479
480 rtlbt_info("loading config %s", config_path);
481
482 /* Read in the config file */
483 if (rtlbt_fw_read(&cfg, config_path) <= 0) {
484 rtlbt_err("rtlbt_fw_read() failed");
485 if ((ic->flags & RTLBT_IC_FLAG_CONFIG) != 0)
486 goto shutdown;
487 } else {
488 r = rtlbt_append_fwfile(&fw, &cfg);
489 rtlbt_fw_free(&cfg);
490 if (r < 0) {
491 rtlbt_err("Appending config file failed");
492 goto shutdown;
493 }
494 }
495 }
496
497 r = rtlbt_load_fwfile(hdl, &fw);
498 if (r < 0) {
499 rtlbt_debug("Loading firmware file failed");
500 goto shutdown;
501 }
502
503 /* free it */
504 rtlbt_fw_free(&fw);
505
506 rtlbt_info("Firmware download complete");
507
508 /* Execute Read Local Version one more time */
509 r = rtlbt_read_local_ver(hdl, &ver);
510 if (r < 0) {
511 rtlbt_err("rtlbt_read_local_ver() failed code %d", r);
512 goto shutdown;
513 }
514 rtlbt_dump_version(&ver);
515
516 retcode = 0;
517
518 /* Ask kernel driver to probe and attach device again */
519 r = libusb_reset_device(hdl);
520 if (r != 0)
521 rtlbt_err("libusb_reset_device() failed: %s",
522 libusb_strerror(r));
523
524 shutdown:
525
526 /* Shutdown */
527
528 if (hdl != NULL)
529 libusb_close(hdl);
530
531 if (dev != NULL)
532 libusb_unref_device(dev);
533
534 if (ctx != NULL)
535 libusb_exit(ctx);
536
537 if (retcode == 0)
538 rtlbt_info("Firmware download is successful!");
539 else
540 rtlbt_err("Firmware download failed!");
541
542 return (retcode);
543 }
544