aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTarek BOCHKATI <tarek.bouchkati@gmail.com>2020-03-07 17:20:24 +0100
committerOleksij Rempel <linux@rempel-privat.de>2020-03-22 08:17:14 +0000
commit4b4389a2d69d96e08d2b417e47c24cad6b50a5c5 (patch)
tree419e5db25022af6d9da01064afe4b992083e07a7 /src
parent6ecccc88955ead6283bfa9da123e120a73d4cab8 (diff)
downloadriscv-openocd-4b4389a2d69d96e08d2b417e47c24cad6b50a5c5.zip
riscv-openocd-4b4389a2d69d96e08d2b417e47c24cad6b50a5c5.tar.gz
riscv-openocd-4b4389a2d69d96e08d2b417e47c24cad6b50a5c5.tar.bz2
stlink: workaround serial bug with old ST-Link DFU
Old ST-LINK DFU returns an incorrect serial in the USB descriptor example for the following serial "57FF72067265575742132067" - the correct descriptor serial is: 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00 ... this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format. the serial part is: 0x0035, 0x0037, 0x0046, 0x0046 ... >> 57FF ... this format could be read correctly by 'libusb_get_string_descriptor_ascii' so this case is managed by libusb_helper::string_descriptor_equal - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor: 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ... >> 57 FF 72 ... based on the length (0x1a = 26) we could easily decide if we have to fixup the serial and then we have just to convert the raw data into printable characters using sprintf example for an old ST-LINK/V2 standalone: before : 'W?rreWWB g' after : '57FF72067265575742132067' => same as the displayed value in STM32CubeProgrammer tested using these commands using the buggy serial -c "hla_serial \x57\x3f\x72\x06\x72\x65\x57\x57\x42\x13\x20\x67" using the computed serial -c "hla_serial 57FF72067265575742132067" Change-Id: I1213818257663eeb8e76f419087d3127d0524842 Signed-off-by: Tarek BOCHKATI <tarek.bouchkati@gmail.com> Reviewed-on: http://openocd.zylin.com/5396 Reviewed-by: Oleksij Rempel <linux@rempel-privat.de> Tested-by: jenkins Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
Diffstat (limited to 'src')
-rw-r--r--src/jtag/drivers/stlink_usb.c83
1 files changed, 82 insertions, 1 deletions
diff --git a/src/jtag/drivers/stlink_usb.c b/src/jtag/drivers/stlink_usb.c
index d8d8d67..6ab979f 100644
--- a/src/jtag/drivers/stlink_usb.c
+++ b/src/jtag/drivers/stlink_usb.c
@@ -47,6 +47,8 @@
#define USE_LIBUSB_ASYNCIO
#endif
+#define STLINK_SERIAL_LEN 24
+
#define ENDPOINT_IN 0x80
#define ENDPOINT_OUT 0x00
@@ -2745,6 +2747,85 @@ static int stlink_usb_close(void *handle)
return ERROR_OK;
}
+/* Compute ST-Link serial number from the device descriptor
+ * this function will help to work-around a bug in old ST-Link/V2 DFU
+ * the buggy DFU returns an incorrect serial in the USB descriptor
+ * example for the following serial "57FF72067265575742132067"
+ * - the correct descriptor serial is:
+ * 0x32, 0x03, 0x35, 0x00, 0x37, 0x00, 0x46, 0x00, 0x46, 0x00, 0x37, 0x00, 0x32, 0x00 ...
+ * this contains the length (0x32 = 50), the type (0x3 = DT_STRING) and the serial in unicode format
+ * the serial part is: 0x0035, 0x0037, 0x0046, 0x0046, 0x0037, 0x0032 ... >> 57FF72 ...
+ * this format could be read correctly by 'libusb_get_string_descriptor_ascii'
+ * so this case is managed by libusb_helper::string_descriptor_equal
+ * - the buggy DFU is not doing any unicode conversion and returns a raw serial data in the descriptor
+ * 0x1a, 0x03, 0x57, 0x00, 0xFF, 0x00, 0x72, 0x00 ...
+ * >> 57 FF 72 ...
+ * based on the length (0x1a = 26) we could easily decide if we have to fixup the serial
+ * and then we have just to convert the raw data into printable characters using sprintf
+ */
+char *stlink_usb_get_alternate_serial(libusb_device_handle *device,
+ struct libusb_device_descriptor *dev_desc)
+{
+ int usb_retval;
+ unsigned char desc_serial[(STLINK_SERIAL_LEN + 1) * 2];
+
+ if (dev_desc->iSerialNumber == 0)
+ return NULL;
+
+ /* get the LANGID from String Descriptor Zero */
+ usb_retval = libusb_get_string_descriptor(device, 0, 0, desc_serial,
+ sizeof(desc_serial));
+
+ if (usb_retval < LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+ libusb_error_name(usb_retval), usb_retval);
+ return NULL;
+ } else if (usb_retval < 4) {
+ /* the size should be least 4 bytes to contain a minimum of 1 supported LANGID */
+ LOG_ERROR("could not get the LANGID");
+ return NULL;
+ }
+
+ uint32_t langid = desc_serial[2] | (desc_serial[3] << 8);
+
+ /* get the serial */
+ usb_retval = libusb_get_string_descriptor(device, dev_desc->iSerialNumber,
+ langid, desc_serial, sizeof(desc_serial));
+
+ unsigned char len = desc_serial[0];
+
+ if (usb_retval < LIBUSB_SUCCESS) {
+ LOG_ERROR("libusb_get_string_descriptor() failed: %s(%d)",
+ libusb_error_name(usb_retval), usb_retval);
+ return NULL;
+ } else if (desc_serial[1] != LIBUSB_DT_STRING || len > usb_retval) {
+ LOG_ERROR("invalid string in ST-LINK USB serial descriptor");
+ return NULL;
+ }
+
+ if (len == ((STLINK_SERIAL_LEN + 1) * 2)) {
+ /* good ST-Link adapter, this case is managed by
+ * libusb::libusb_get_string_descriptor_ascii */
+ return NULL;
+ } else if (len != ((STLINK_SERIAL_LEN / 2 + 1) * 2)) {
+ LOG_ERROR("unexpected serial length (%d) in descriptor", len);
+ return NULL;
+ }
+
+ /* else (len == 26) => buggy ST-Link */
+
+ char *alternate_serial = malloc((STLINK_SERIAL_LEN + 1) * sizeof(char));
+ if (alternate_serial == NULL)
+ return NULL;
+
+ for (unsigned int i = 0; i < STLINK_SERIAL_LEN; i += 2)
+ sprintf(alternate_serial + i, "%02X", desc_serial[i + 2]);
+
+ alternate_serial[STLINK_SERIAL_LEN] = '\0';
+
+ return alternate_serial;
+}
+
/** */
static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
{
@@ -2779,7 +2860,7 @@ static int stlink_usb_open(struct hl_interface_param_s *param, void **fd)
*/
do {
if (jtag_libusb_open(param->vid, param->pid, param->serial,
- &h->fd, NULL) != ERROR_OK) {
+ &h->fd, stlink_usb_get_alternate_serial) != ERROR_OK) {
LOG_ERROR("open failed");
goto error_open;
}