This is an automated email from Gerrit. "Erhan Kurubas <erhan.kuru...@espressif.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7079
-- gerrit commit d3b717bb6a5b6eb932cecdc38c15d51e1ae3aa34 Author: Erhan Kurubas <erhan.kuru...@espressif.com> Date: Tue Jul 5 00:14:09 2022 +0300 esp_usb_jtag: device reinit after bulk write error Reinit sequence(reset + init) will be needed when external reset is asserted or when the usb cable is unplugged/replugged. Signed-off-by: Erhan Kurubas <erhan.kuru...@espressif.com> Change-Id: I20e66bf186939afe4098f80a62ad6c1b9f88f5fe diff --git a/src/jtag/drivers/esp_usb_jtag.c b/src/jtag/drivers/esp_usb_jtag.c index a73984a3a1..78d361eb77 100644 --- a/src/jtag/drivers/esp_usb_jtag.c +++ b/src/jtag/drivers/esp_usb_jtag.c @@ -197,7 +197,14 @@ struct jtag_proto_caps_speed_apb { *to be read, we have multiple buffers to store those before the bitq interface reads them out. */ #define IN_BUF_CT 8 -#define ESP_USB_INTERFACE 1 +/* + * comment from libusb: + * As per the USB 3.0 specs, the current maximum limit for the depth is 7. + */ +#define MAX_USB_PORTS 7 +#define ESP_USB_JTAG_RST_DELAY 100000 /* us */ + +#define ESP_USB_INTERFACE 1 /* Private data */ struct esp_usb_jtag { @@ -231,6 +238,7 @@ struct esp_usb_jtag { * OpenOCD supports multiple JTAG adapters anyway. */ static struct esp_usb_jtag esp_usb_jtag_priv; static struct esp_usb_jtag *priv = &esp_usb_jtag_priv; +static const char *esp_usb_jtag_serial; static int esp_usb_vid; static int esp_usb_pid; @@ -240,13 +248,99 @@ static int esp_usb_target_chip_id; static int esp_usb_jtag_init(void); static int esp_usb_jtag_quit(void); +static bool esp_usb_jtag_libusb_location_equal(libusb_device *dev1, libusb_device *dev2) +{ + if (libusb_get_bus_number(dev1) != libusb_get_bus_number(dev2)) + return false; + +#ifdef HAVE_LIBUSB_GET_PORT_NUMBERS + uint8_t port_path1[MAX_USB_PORTS], port_path2[MAX_USB_PORTS]; + + int path_len1 = libusb_get_port_numbers(dev1, port_path1, MAX_USB_PORTS); + if (path_len1 == LIBUSB_ERROR_OVERFLOW) { + LOG_WARNING("cannot determine path to usb device! (more than %i ports in path)\n", + MAX_USB_PORTS); + return false; + } + + int path_len2 = libusb_get_port_numbers(dev2, port_path2, MAX_USB_PORTS); + if (path_len2 == LIBUSB_ERROR_OVERFLOW) { + LOG_WARNING("cannot determine path to usb device! (more than %i ports in path)\n", + MAX_USB_PORTS); + return false; + } + + if (path_len1 != path_len2) + return false; + + for (int i = 0; i < path_len1; i++) { + if (port_path1[i] != port_path2[i]) + return false; + } +#endif /* HAVE_LIBUSB_GET_PORT_NUMBERS */ + + if (libusb_get_device_address(dev1) != libusb_get_device_address(dev2)) + return false; + return true; +} + +static int esp_usb_jtag_reinit_device(struct libusb_device_handle *usb_device) +{ + const uint16_t vids[] = { esp_usb_vid, 0 }; /* must be null terminated */ + const uint16_t pids[] = { esp_usb_pid, 0 }; /* must be null terminated */ + libusb_device *cur_dev = libusb_get_device(usb_device); + libusb_device *new_dev = NULL; + int ret, tries = 5; + + while (tries-- >= 0) { + new_dev = jtag_libusb_find_device(vids, pids, esp_usb_jtag_serial); + if (new_dev) { + if (esp_usb_jtag_libusb_location_equal(cur_dev, new_dev)) { + /* device is still at the same location on bus and with the same address, try to reset it */ + int rc = libusb_reset_device(usb_device); + if (rc == LIBUSB_ERROR_NOT_FOUND || rc == LIBUSB_ERROR_NO_DEVICE) { + /* re-enumeration is necessary */ + break; + } + libusb_unref_device(new_dev); + return rc == 0 ? ERROR_OK : ERROR_WAIT; + } + break; + } + jtag_sleep(ESP_USB_JTAG_RST_DELAY); + } + if (!new_dev) { + LOG_ERROR("esp_usb_jtag: device not found!"); + return ERROR_FAIL; + } + libusb_unref_device(new_dev); + ret = esp_usb_jtag_quit(); + if (ret != ERROR_OK) { + LOG_ERROR("esp_usb_jtag: failed to deinit (%d)", ret); + return ret; + } + tries = 5; + while (tries-- >= 0) { + ret = esp_usb_jtag_init(); + if (ret == ERROR_OK) + break; + jtag_sleep(ESP_USB_JTAG_RST_DELAY); + } + if (ret != ERROR_OK) { + LOG_ERROR("esp_usb_jtag: failed to init (%d)", ret); + return ret; + } + return ERROR_OK; +} + /* Try to receive from USB endpoint into the current priv->in_buf */ static int esp_usb_jtag_recv_buf(void) { - if (priv->in_buf_size_bits[priv->cur_in_buf_wr] != 0) + if (priv->in_buf_size_bits[priv->cur_in_buf_wr] != 0) { LOG_ERROR("esp_usb_jtag: IN buffer overflow! (%d, size %d)", priv->cur_in_buf_wr, priv->in_buf_size_bits[priv->cur_in_buf_wr]); + } unsigned int recvd = 0, ct = (priv->pending_in_bits + 7) / 8; if (ct > IN_BUF_SZ) @@ -313,8 +407,12 @@ static int esp_usb_jtag_send_buf(void) written + tr, ct); } - if (ret != ERROR_OK) + if (ret != ERROR_OK) { + int reset_ret = esp_usb_jtag_reinit_device(priv->usb_device); + if (reset_ret != ERROR_OK) + LOG_ERROR("esp_usb_jtag: failed to reinit USB device!"); return ret; + } written += tr; } priv->out_buf_pos_nibbles = 0; @@ -507,6 +605,19 @@ static int esp_usb_jtag_init(void) goto out; } + /* serial number may have been set by `adapter serial` command */ + if (adapter_get_required_serial()) { + free((void *)esp_usb_jtag_serial); + esp_usb_jtag_serial = strdup(adapter_get_required_serial()); + } + + if (!esp_usb_jtag_serial) { + r = jtag_libusb_get_serial(priv->usb_device, &esp_usb_jtag_serial); + if (r != ERROR_OK) + goto out; + } + LOG_INFO("esp_usb_jtag: serial (%s)", esp_usb_jtag_serial); + jtag_libusb_set_configuration(priv->usb_device, USB_CONFIGURATION); r = jtag_libusb_choose_interface(priv->usb_device, &priv->read_ep, &priv->write_ep, @@ -599,6 +710,8 @@ static int esp_usb_jtag_init(void) return ERROR_OK; out: + free((void *)esp_usb_jtag_serial); + esp_usb_jtag_serial = NULL; if (priv->usb_device) jtag_libusb_close(priv->usb_device); bitq_interface = NULL; @@ -608,6 +721,8 @@ out: static int esp_usb_jtag_quit(void) { + free((void *)esp_usb_jtag_serial); + esp_usb_jtag_serial = NULL; if (!priv->usb_device) return ERROR_OK; jtag_libusb_close(priv->usb_device); --