libusb: introduce jtag_libusb_choose_interface() and use it for JLink 27/2327/3
authorPaul Fertser <fercerpav@gmail.com>
Wed, 1 Oct 2014 06:36:02 +0000 (10:36 +0400)
committerSpencer Oliver <spen@spen-soft.co.uk>
Mon, 6 Oct 2014 18:40:39 +0000 (18:40 +0000)
This introduces a new common function that allows auto-discovery of a
suitable USB interface based on class, subclass and protocol
matching. It claims the interface and returns the corresponding
endpoints number to the caller.

The need for this arised due to nRF51822 USB dongle which comes with
an "on-board Segger J-link debugger" having 3 interfaces, so the
current code can't work at all with it (in this particular case the
last interface needs to be choosen). This also removes special
handling of JLink-OB endpoint numbers as it's now possible to
autodetect them as well as the standard JLink endpoints.

Change-Id: I4d990a7a3b373efdd2949a394b32d855a168e138
Signed-off-by: Paul Fertser <fercerpav@gmail.com>
Reviewed-on: http://openocd.zylin.com/2327
Tested-by: jenkins
Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
src/jtag/aice/aice_usb.c
src/jtag/drivers/jlink.c
src/jtag/drivers/libusb0_common.c
src/jtag/drivers/libusb0_common.h
src/jtag/drivers/libusb1_common.c
src/jtag/drivers/libusb1_common.h

index d933845c50844bfa56267fd066d8bd29f6804ce2..50b3b9a22388fd70e0767246bf896937e27fc7ac 100644 (file)
@@ -2136,13 +2136,11 @@ static int aice_usb_open(struct aice_port_param_s *param)
 #endif
 
        /* usb_set_configuration required under win32 */
-       struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
        jtag_libusb_set_configuration(devh, 0);
-       jtag_libusb_claim_interface(devh, 0);
 
        unsigned int aice_read_ep;
        unsigned int aice_write_ep;
-       jtag_libusb_get_endpoints(udev, &aice_read_ep, &aice_write_ep);
+       jtag_libusb_choose_interface(devh, &aice_read_ep, &aice_write_ep, -1, -1, -1);
 
        aice_handler.usb_read_ep = aice_read_ep;
        aice_handler.usb_write_ep = aice_write_ep;
index 2177b08e04b04628a617f3c17c7d8b466d8cd53a..57eea64d192ba352aa49d7d8cefe1df88ae53b5c 100644 (file)
  * pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address)
  */
 
-#define JLINK_OB_PID  0x0105
+#define JLINK_USB_INTERFACE_CLASS 0xff
+#define JLINK_USB_INTERFACE_SUBCLASS 0xff
+#define JLINK_USB_INTERFACE_PROTOCOL 0xff
 
-#define JLINK_WRITE_ENDPOINT   0x02
-#define JLINK_READ_ENDPOINT            0x81
-
-#define JLINK_OB_WRITE_ENDPOINT        0x06
-#define JLINK_OB_READ_ENDPOINT 0x85
-
-static unsigned int jlink_write_ep = JLINK_WRITE_ENDPOINT;
-static unsigned int jlink_read_ep = JLINK_READ_ENDPOINT;
+static unsigned int jlink_write_ep;
+static unsigned int jlink_read_ep;
 static unsigned int jlink_hw_jtag_version = 2;
 
 #define JLINK_USB_TIMEOUT 1000
@@ -1746,20 +1742,12 @@ static struct jlink *jlink_usb_open()
        /* usb_set_configuration is only required under win32
         * with libusb 0.1 and libusb0.sys. For libusb 1.0 it is a no-op
         * since the configuration is already set. */
-       struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
        jtag_libusb_set_configuration(devh, 0);
-       jtag_libusb_claim_interface(devh, 0);
-
-       /* Use the OB endpoints if the JLink we matched is a Jlink-OB adapter */
-       uint16_t matched_pid;
-       if (jtag_libusb_get_pid(udev, &matched_pid) == ERROR_OK) {
-               if (matched_pid == JLINK_OB_PID) {
-                       jlink_read_ep = JLINK_OB_WRITE_ENDPOINT;
-                       jlink_write_ep = JLINK_OB_READ_ENDPOINT;
-               }
-       }
 
-       jtag_libusb_get_endpoints(udev, &jlink_read_ep, &jlink_write_ep);
+       jtag_libusb_choose_interface(devh, &jlink_read_ep, &jlink_write_ep,
+                                    JLINK_USB_INTERFACE_CLASS,
+                                    JLINK_USB_INTERFACE_SUBCLASS,
+                                    JLINK_USB_INTERFACE_PROTOCOL);
 
        struct jlink *result = malloc(sizeof(struct jlink));
        result->usb_handle = devh;
index b44b7861b7b70f20747430d453a5eaded02d8764..5b1248d2635b1faaa1840bd6145ecfa3c6ef8d87 100644 (file)
@@ -145,14 +145,23 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
                        udev->config[configuration].bConfigurationValue);
 }
 
-int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
+int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
                unsigned int *usb_read_ep,
-               unsigned int *usb_write_ep)
+               unsigned int *usb_write_ep,
+               int bclass, int subclass, int protocol)
 {
+       struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
        struct usb_interface *iface = udev->config->interface;
        struct usb_interface_descriptor *desc = iface->altsetting;
 
+       *usb_read_ep = *usb_write_ep = 0;
+
        for (int i = 0; i < desc->bNumEndpoints; i++) {
+               if ((bclass > 0 && desc->bInterfaceClass != bclass) ||
+                   (subclass > 0 && desc->bInterfaceSubClass != subclass) ||
+                   (protocol > 0 && desc->bInterfaceProtocol != protocol))
+                       continue;
+
                uint8_t epnum = desc->endpoint[i].bEndpointAddress;
                bool is_input = epnum & 0x80;
                LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum);
@@ -160,9 +169,15 @@ int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
                        *usb_read_ep = epnum;
                else
                        *usb_write_ep = epnum;
+
+               if (*usb_read_ep && *usb_write_ep) {
+                       LOG_DEBUG("Claiming interface %d", (int)desc->bInterfaceNumber);
+                       usb_claim_interface(devh, (int)desc->bInterfaceNumber);
+                       return ERROR_OK;
+               }
        }
 
-       return 0;
+       return ERROR_FAIL;
 }
 
 int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
index 370954fd377528d3f9a10517355439e5cb5b4370..ca372a080af796f7601fa609a721cf1ceb2beb96 100644 (file)
@@ -66,9 +66,10 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
                char *bytes, int size, int timeout);
 int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
                int configuration);
-int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
+int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
                unsigned int *usb_read_ep,
-               unsigned int *usb_write_ep);
+               unsigned int *usb_write_ep,
+               int bclass, int subclass, int protocol);
 int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
 
 #endif /* JTAG_USB_COMMON_H */
index 07d9f9512ce9aed6f3947198591f2586e2fdc2d7..bda91ffbc0a811157d1c8eb970fe39ffa46c0843 100644 (file)
@@ -186,40 +186,54 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
        return retCode;
 }
 
-int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
+int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
                unsigned int *usb_read_ep,
-               unsigned int *usb_write_ep)
+               unsigned int *usb_write_ep,
+               int bclass, int subclass, int protocol)
 {
+       struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
        const struct libusb_interface *inter;
        const struct libusb_interface_descriptor *interdesc;
        const struct libusb_endpoint_descriptor *epdesc;
        struct libusb_config_descriptor *config;
 
+       *usb_read_ep = *usb_write_ep = 0;
+
        libusb_get_config_descriptor(udev, 0, &config);
        for (int i = 0; i < (int)config->bNumInterfaces; i++) {
                inter = &config->interface[i];
 
-               for (int j = 0; j < inter->num_altsetting; j++) {
-                       interdesc = &inter->altsetting[j];
-                       for (int k = 0;
-                               k < (int)interdesc->bNumEndpoints; k++) {
-                               epdesc = &interdesc->endpoint[k];
-
-                               uint8_t epnum = epdesc->bEndpointAddress;
-                               bool is_input = epnum & 0x80;
-                               LOG_DEBUG("usb ep %s %02x",
-                                       is_input ? "in" : "out", epnum);
-
-                               if (is_input)
-                                       *usb_read_ep = epnum;
-                               else
-                                       *usb_write_ep = epnum;
+               interdesc = &inter->altsetting[0];
+               for (int k = 0;
+                    k < (int)interdesc->bNumEndpoints; k++) {
+                       if ((bclass > 0 && interdesc->bInterfaceClass != bclass) ||
+                           (subclass > 0 && interdesc->bInterfaceSubClass != subclass) ||
+                           (protocol > 0 && interdesc->bInterfaceProtocol != protocol))
+                               continue;
+
+                       epdesc = &interdesc->endpoint[k];
+
+                       uint8_t epnum = epdesc->bEndpointAddress;
+                       bool is_input = epnum & 0x80;
+                       LOG_DEBUG("usb ep %s %02x",
+                                 is_input ? "in" : "out", epnum);
+
+                       if (is_input)
+                               *usb_read_ep = epnum;
+                       else
+                               *usb_write_ep = epnum;
+
+                       if (*usb_read_ep && *usb_write_ep) {
+                               LOG_DEBUG("Claiming interface %d", (int)interdesc->bInterfaceNumber);
+                               libusb_claim_interface(devh, (int)interdesc->bInterfaceNumber);
+                               libusb_free_config_descriptor(config);
+                               return ERROR_OK;
                        }
                }
        }
        libusb_free_config_descriptor(config);
 
-       return 0;
+       return ERROR_FAIL;
 }
 
 int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)
index a4447ca9baec3bb3103af8e421ed9ec9879d2cff..4ef6bf730d0faf14c4a62cd259f49f1ea6ebf85a 100644 (file)
@@ -60,9 +60,23 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
                char *bytes, int size, int timeout);
 int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
                int configuration);
-int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
+/**
+ * Find the first interface optionally matching class, subclass and
+ * protocol and claim it.
+ * @param devh _libusb_ device handle.
+ * @param usb_read_ep A pointer to a variable where the _IN_ endpoint
+ *     number will be stored.
+ * @param usb_write_ep A pointer to a variable where the _OUT_ endpoint
+ *     number will be stored.
+ * @param bclass `bInterfaceClass` to match, or -1 to ignore this field.
+ * @param subclass `bInterfaceSubClass` to match, or -1 to ignore this field.
+ * @param protocol `bInterfaceProtocol` to match, or -1 to ignore this field.
+ * @returns Returns ERROR_OK on success, ERROR_FAIL otherwise.
+ */
+int jtag_libusb_choose_interface(struct jtag_libusb_device_handle *devh,
                unsigned int *usb_read_ep,
-               unsigned int *usb_write_ep);
+               unsigned int *usb_write_ep,
+               int bclass, int subclass, int protocol);
 int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
 
 #endif /* JTAG_USB_COMMON_H */

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)