From 25ce7fad2281082e3e6684392b53b4674df51ec2 Mon Sep 17 00:00:00 2001 From: Bjorn Andersson Date: Tue, 7 May 2024 15:08:57 -0500 Subject: [PATCH] usb: Allow selecting board by serial number When working on a host with multiple boards attached being able to select a specific board by serial number becomes necessary. In the EDL USB descriptors a device serial number is available as part of the iProduct string, so this can be used for comparison. As libusb requires a handle the libusb_open() needs to be moved into the loop. Signed-off-by: Bjorn Andersson --- qdl.c | 9 +++++-- qdl.h | 2 +- ramdump.c | 9 +++++-- usb.c | 80 ++++++++++++++++++++++++++++++++++++++----------------- 4 files changed, 71 insertions(+), 29 deletions(-) diff --git a/qdl.c b/qdl.c index df84401..e15dcbd 100644 --- a/qdl.c +++ b/qdl.c @@ -105,6 +105,7 @@ int main(int argc, char **argv) { char *prog_mbn, *storage="ufs"; char *incdir = NULL; + char *serial = NULL; int type; int ret; int opt; @@ -115,11 +116,12 @@ int main(int argc, char **argv) {"debug", no_argument, 0, 'd'}, {"include", required_argument, 0, 'i'}, {"finalize-provisioning", no_argument, 0, 'l'}, + {"serial", required_argument, 0, 'S'}, {"storage", required_argument, 0, 's'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "di:", options, NULL )) != -1) { + while ((opt = getopt_long(argc, argv, "di:S:", options, NULL )) != -1) { switch (opt) { case 'd': qdl_debug = true; @@ -133,6 +135,9 @@ int main(int argc, char **argv) case 's': storage = optarg; break; + case 'S': + serial = optarg; + break; default: print_usage(); return 1; @@ -174,7 +179,7 @@ int main(int argc, char **argv) } } while (++optind < argc); - ret = qdl_open(&qdl); + ret = qdl_open(&qdl, serial); if (ret) return 1; diff --git a/qdl.h b/qdl.h index 7d2fb75..0bb310a 100644 --- a/qdl.h +++ b/qdl.h @@ -24,7 +24,7 @@ struct qdl_device { char *mappings[MAPPING_SZ]; // array index is the id from the device }; -int qdl_open(struct qdl_device *qdl); +int qdl_open(struct qdl_device *qdl, const char *serial); int qdl_read(struct qdl_device *qdl, void *buf, size_t len, unsigned int timeout); int qdl_write(struct qdl_device *qdl, const void *buf, size_t len); diff --git a/ramdump.c b/ramdump.c index d06cdb9..c094c5f 100644 --- a/ramdump.c +++ b/ramdump.c @@ -21,16 +21,18 @@ int main(int argc, char **argv) struct qdl_device qdl; char *ramdump_path = "."; char *filter = NULL; + char *serial = NULL; int ret; int opt; static struct option options[] = { {"debug", no_argument, 0, 'd'}, {"output", required_argument, 0, 'o'}, + {"serial", required_argument, 0, 'S'}, {0, 0, 0, 0} }; - while ((opt = getopt_long(argc, argv, "do:", options, NULL )) != -1) { + while ((opt = getopt_long(argc, argv, "do:S:", options, NULL )) != -1) { switch (opt) { case 'd': qdl_debug = true; @@ -38,6 +40,9 @@ int main(int argc, char **argv) case 'o': ramdump_path = optarg; break; + case 'S': + serial = optarg; + break; default: print_usage(); } @@ -49,7 +54,7 @@ int main(int argc, char **argv) if (optind != argc) print_usage(); - ret = qdl_open(&qdl); + ret = qdl_open(&qdl, serial); if (ret) return 1; diff --git a/usb.c b/usb.c index 0737db6..35a1c1e 100644 --- a/usb.c +++ b/usb.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -9,12 +10,40 @@ #include "qdl.h" -static int qdl_parse_usb_descriptors(libusb_device *dev, struct qdl_device *qdl, int *intf) +static bool qdl_match_usb_serial(struct libusb_device_handle *handle, const char *serial, + const struct libusb_device_descriptor *desc) +{ + char buf[128]; + char *p; + int ret; + + /* If no serial is requested, consider everything a match */ + if (!serial) + return true; + + ret = libusb_get_string_descriptor_ascii(handle, desc->iProduct, (unsigned char *)buf, sizeof(buf)); + if (ret < 0) { + warnx("failed to read iProduct descriptor: %s", libusb_strerror(ret)); + return false; + } + + p = strstr(buf, "_SN:"); + if (!p) + return false; + + p += strlen("_SN:"); + p[strcspn(p, " _")] = '\0'; + + return strcmp(p, serial) == 0; +} + +static int qdl_try_open(libusb_device *dev, struct qdl_device *qdl, const char *serial) { const struct libusb_endpoint_descriptor *endpoint; const struct libusb_interface_descriptor *ifc; struct libusb_config_descriptor *config; struct libusb_device_descriptor desc; + struct libusb_device_handle *handle; size_t out_size; size_t in_size; uint8_t type; @@ -76,26 +105,42 @@ static int qdl_parse_usb_descriptors(libusb_device *dev, struct qdl_device *qdl, ifc->bInterfaceProtocol != 17) continue; + ret = libusb_open(dev, &handle); + if (ret < 0) { + warnx("unable to open USB device"); + continue; + } + + if (!qdl_match_usb_serial(handle, serial, &desc)) { + libusb_close(handle); + continue; + } + + ret = libusb_claim_interface(handle, ifc->bInterfaceNumber); + if (ret < 0) { + warnx("failed to claim USB interface"); + libusb_close(handle); + continue; + } + + qdl->usb_handle = handle; qdl->in_ep = in; qdl->out_ep = out; qdl->in_maxpktsize = in_size; qdl->out_maxpktsize = out_size; - *intf = ifc->bInterfaceNumber; - return 1; } return 0; } -int qdl_open(struct qdl_device *qdl) +int qdl_open(struct qdl_device *qdl, const char *serial) { - struct libusb_device_handle *handle; struct libusb_device **devs; struct libusb_device *dev; bool wait_printed = false; - int intf_num; + bool found = false; ssize_t n; int ret; int i; @@ -112,29 +157,16 @@ int qdl_open(struct qdl_device *qdl) for (i = 0; devs[i]; i++) { dev = devs[i]; - ret = qdl_parse_usb_descriptors(dev, qdl, &intf_num); - if (ret != 1) - continue; - - ret = libusb_open(dev, &handle); - if (ret < 0) { - warnx("unable to open USB device"); - continue; + ret = qdl_try_open(dev, qdl, serial); + if (ret == 1) { + found = true; + break; } - - ret = libusb_claim_interface(handle, intf_num); - if (ret < 0) { - warnx("failed to claim USB interface"); - libusb_close(handle); - } - - qdl->usb_handle = handle; - break; } libusb_free_device_list(devs, 1); - if (qdl->usb_handle) + if (found) return 0; if (!wait_printed) {