summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Warren <swarren@nvidia.com>2015-10-08 10:43:07 -0600
committerStephen Warren <swarren@nvidia.com>2015-10-08 10:47:49 -0600
commit42f282565f8dd8fe9fb51bc5c0f5eb9adf813f67 (patch)
treef9b1aeaa37f0982b49fe1fdb17aa85846547c23c
parentd8eb1cef0885d936df271e8f96b8a036bc8a7411 (diff)
downloadtegrarcm-42f282565f8dd8fe9fb51bc5c0f5eb9adf813f67.tar.gz
Match USB port ID on re-enumeration
When executing the RCM process, the Tegra device will be re-enumerated on the USB bus once the miniloader is booted. This requires tegrarcm to search for it again. In a system with multiple attached Tegra boards, all being booted/shutdown in parallel, it is possible that the second call to usb_open() will find a different Tegra device. Solve this issue by having usb_open() record the exact physical USB port path of the device, and match only that path on subsequent searches. This will be robust except in the case where the device being operated on is physically unplugged and replaced (not simply power-cycled) while tegrarcm is executing. This is much less likely that the previous failure modes. This feature also enables the next patch in this series. Signed-off-by: Stephen Warren <swarren@nvidia.com>
-rw-r--r--src/main.c18
-rw-r--r--src/usb.c76
-rw-r--r--src/usb.h14
3 files changed, 102 insertions, 6 deletions
diff --git a/src/main.c b/src/main.c
index 50adc14..4936d02 100644
--- a/src/main.c
+++ b/src/main.c
@@ -136,6 +136,12 @@ int main(int argc, char **argv)
int do_read = 0;
char *mlfile = NULL;
uint32_t mlentry = 0;
+#ifdef HAVE_USB_PORT_MATCH
+ bool match_port = false;
+ uint8_t match_bus;
+ uint8_t match_ports[PORT_MATCH_MAX_PORTS];
+ int match_ports_len;
+#endif
static struct option long_options[] = {
[OPT_BCT] = {"bct", 1, 0, 0},
@@ -232,7 +238,11 @@ int main(int argc, char **argv)
printf("entry addr 0x%x\n", entryaddr);
}
- usb = usb_open(USB_VENID_NVIDIA, &devid);
+ usb = usb_open(USB_VENID_NVIDIA, &devid
+#ifdef HAVE_USB_PORT_MATCH
+ , &match_port, &match_bus, match_ports, &match_ports_len
+#endif
+ );
if (!usb)
error(1, errno, "could not open USB device");
printf("device id: 0x%x\n", devid);
@@ -259,7 +269,11 @@ int main(int argc, char **argv)
// device may have re-enumerated, so reopen USB
usb_close(usb);
- usb = usb_open(USB_VENID_NVIDIA, &devid);
+ usb = usb_open(USB_VENID_NVIDIA, &devid
+#ifdef HAVE_USB_PORT_MATCH
+ , &match_port, &match_bus, match_ports, &match_ports_len
+#endif
+ );
if (!usb)
error(1, errno, "could not open USB device");
}
diff --git a/src/usb.c b/src/usb.c
index 71234d7..8a36742 100644
--- a/src/usb.c
+++ b/src/usb.c
@@ -42,9 +42,27 @@
//
// returns 1 if the specified usb device matches the vendor id
//
-static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid)
+static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+ ,
+ bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+ int *match_ports_len
+#endif
+)
{
struct libusb_device_descriptor desc;
+#ifdef HAVE_USB_PORT_MATCH
+ uint8_t dev_bus;
+ uint8_t dev_ports[PORT_MATCH_MAX_PORTS];
+ int dev_ports_len;
+#ifdef DEBUG
+ int i;
+ char portstr[(PORT_MATCH_MAX_PORTS * 4)];
+ char *portstrp;
+ size_t portstr_lenleft;
+ int printed;
+#endif
+#endif
if (libusb_get_device_descriptor(dev, &desc)) {
dprintf("libusb_get_device_descriptor\n");
@@ -66,6 +84,47 @@ static int usb_match(libusb_device *dev, uint16_t venid, uint16_t *devid)
desc.idVendor, desc.idProduct);
return 0;
}
+#ifdef HAVE_USB_PORT_MATCH
+ dev_bus = libusb_get_bus_number(dev);
+ dev_ports_len = libusb_get_port_numbers(dev, dev_ports,
+ PORT_MATCH_MAX_PORTS);
+ if (dev_ports_len < 0) {
+ dprintf("libusb_get_port_numbers failed: %d\n", dev_ports_len);
+ return 0;
+ }
+ if (*match_port) {
+ if (dev_bus != *match_bus) {
+ dprintf("bus mismatch dev:%d match:%d\n", dev_bus,
+ *match_bus);
+ return 0;
+ }
+ if (memcmp(dev_ports, match_ports, dev_ports_len)) {
+ dprintf("ports mismatch\n");
+ return 0;
+ }
+ }
+ if (!*match_port) {
+ *match_port = true;
+ *match_bus = dev_bus;
+ memcpy(match_ports, dev_ports, dev_ports_len);
+ *match_ports_len = dev_ports_len;
+#ifdef DEBUG
+ portstrp = portstr;
+ portstr_lenleft = sizeof(portstr);
+ printed = snprintf(portstrp, portstr_lenleft, "%d-%d",
+ dev_bus, dev_ports[0]);
+ portstrp += printed;
+ portstr_lenleft -= printed;
+ for (i = 1; i < dev_ports_len; i++) {
+ printed = snprintf(portstrp, portstr_lenleft, ".%d",
+ (int)dev_ports[i]);
+ portstrp += printed;
+ portstr_lenleft -= printed;
+ }
+ dprintf("Enabling future match %s\n", portstr);
+#endif
+ }
+#endif
dprintf("device matches\n");
*devid = desc.idProduct;
@@ -151,7 +210,13 @@ static int usb_get_interface(libusb_device_handle *handle,
return 0;
}
-usb_device_t *usb_open(uint16_t venid, uint16_t *devid)
+usb_device_t *usb_open(uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+ ,
+ bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+ int *match_ports_len
+#endif
+)
{
libusb_device **list = NULL;
libusb_device *found = NULL;
@@ -172,7 +237,12 @@ usb_device_t *usb_open(uint16_t venid, uint16_t *devid)
for (i = 0; i < cnt; i++) {
libusb_device *device = list[i];
- if (usb_match(device, venid, devid)) {
+ if (usb_match(device, venid, devid
+#ifdef HAVE_USB_PORT_MATCH
+ , match_port, match_bus, match_ports,
+ match_ports_len
+#endif
+ )) {
found = device;
break;
}
diff --git a/src/usb.h b/src/usb.h
index a7b36af..e8fcd67 100644
--- a/src/usb.h
+++ b/src/usb.h
@@ -29,8 +29,14 @@
#ifndef USB_H
#define USB_H
+#include <stdbool.h>
#include <libusb.h>
+#if defined(LIBUSBX_API_VERSION) && (LIBUSBX_API_VERSION >= 0x01000102)
+#define HAVE_USB_PORT_MATCH
+#define PORT_MATCH_MAX_PORTS 7
+#endif
+
#define USB_VENID_NVIDIA 0x955
#define USB_DEVID_NVIDIA_TEGRA20 0x20
#define USB_DEVID_NVIDIA_TEGRA30 0x30
@@ -45,7 +51,13 @@ typedef struct {
int initialized;
} usb_device_t;
-usb_device_t *usb_open(uint16_t venid, uint16_t *devid);
+usb_device_t *usb_open(uint16_t venid, uint16_t *devid
+#ifdef HAVE_USB_PORT_MATCH
+ ,
+ bool *match_port, uint8_t *match_bus, uint8_t *match_ports,
+ int *match_ports_len
+#endif
+);
void usb_close(usb_device_t *usb);
int usb_write(usb_device_t *usb, uint8_t *buf, int len);
int usb_read(usb_device_t *usb, uint8_t *buf, int len, int *actual_len);