libusb: introduce jtag_libusb_choose_interface() and use it for JLink

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>
This commit is contained in:
Paul Fertser 2014-10-01 10:36:02 +04:00 committed by Spencer Oliver
parent b631e78b25
commit 487c57d9a2
6 changed files with 77 additions and 47 deletions

View File

@ -2136,13 +2136,11 @@ static int aice_usb_open(struct aice_port_param_s *param)
#endif #endif
/* usb_set_configuration required under win32 */ /* usb_set_configuration required under win32 */
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
jtag_libusb_set_configuration(devh, 0); jtag_libusb_set_configuration(devh, 0);
jtag_libusb_claim_interface(devh, 0);
unsigned int aice_read_ep; unsigned int aice_read_ep;
unsigned int aice_write_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_read_ep = aice_read_ep;
aice_handler.usb_write_ep = aice_write_ep; aice_handler.usb_write_ep = aice_write_ep;

View File

@ -47,16 +47,12 @@
* pid = ( usb_address > 0x4) ? 0x0101 : (0x101 + usb_address) * 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 static unsigned int jlink_write_ep;
#define JLINK_READ_ENDPOINT 0x81 static unsigned int jlink_read_ep;
#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_hw_jtag_version = 2; static unsigned int jlink_hw_jtag_version = 2;
#define JLINK_USB_TIMEOUT 1000 #define JLINK_USB_TIMEOUT 1000
@ -1746,20 +1742,12 @@ static struct jlink *jlink_usb_open()
/* usb_set_configuration is only required under win32 /* usb_set_configuration is only required under win32
* with libusb 0.1 and libusb0.sys. For libusb 1.0 it is a no-op * with libusb 0.1 and libusb0.sys. For libusb 1.0 it is a no-op
* since the configuration is already set. */ * since the configuration is already set. */
struct jtag_libusb_device *udev = jtag_libusb_get_device(devh);
jtag_libusb_set_configuration(devh, 0); 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 */ jtag_libusb_choose_interface(devh, &jlink_read_ep, &jlink_write_ep,
uint16_t matched_pid; JLINK_USB_INTERFACE_CLASS,
if (jtag_libusb_get_pid(udev, &matched_pid) == ERROR_OK) { JLINK_USB_INTERFACE_SUBCLASS,
if (matched_pid == JLINK_OB_PID) { JLINK_USB_INTERFACE_PROTOCOL);
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);
struct jlink *result = malloc(sizeof(struct jlink)); struct jlink *result = malloc(sizeof(struct jlink));
result->usb_handle = devh; result->usb_handle = devh;

View File

@ -145,14 +145,23 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
udev->config[configuration].bConfigurationValue); 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_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 *iface = udev->config->interface;
struct usb_interface_descriptor *desc = iface->altsetting; struct usb_interface_descriptor *desc = iface->altsetting;
*usb_read_ep = *usb_write_ep = 0;
for (int i = 0; i < desc->bNumEndpoints; i++) { 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; uint8_t epnum = desc->endpoint[i].bEndpointAddress;
bool is_input = epnum & 0x80; bool is_input = epnum & 0x80;
LOG_DEBUG("usb ep %s %02x", is_input ? "in" : "out", epnum); 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; *usb_read_ep = epnum;
else else
*usb_write_ep = epnum; *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) int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)

View File

@ -66,9 +66,10 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout); char *bytes, int size, int timeout);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration); 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_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); int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
#endif /* JTAG_USB_COMMON_H */ #endif /* JTAG_USB_COMMON_H */

View File

@ -186,23 +186,31 @@ int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
return retCode; 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_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 *inter;
const struct libusb_interface_descriptor *interdesc; const struct libusb_interface_descriptor *interdesc;
const struct libusb_endpoint_descriptor *epdesc; const struct libusb_endpoint_descriptor *epdesc;
struct libusb_config_descriptor *config; struct libusb_config_descriptor *config;
*usb_read_ep = *usb_write_ep = 0;
libusb_get_config_descriptor(udev, 0, &config); libusb_get_config_descriptor(udev, 0, &config);
for (int i = 0; i < (int)config->bNumInterfaces; i++) { for (int i = 0; i < (int)config->bNumInterfaces; i++) {
inter = &config->interface[i]; inter = &config->interface[i];
for (int j = 0; j < inter->num_altsetting; j++) { interdesc = &inter->altsetting[0];
interdesc = &inter->altsetting[j];
for (int k = 0; for (int k = 0;
k < (int)interdesc->bNumEndpoints; k++) { 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]; epdesc = &interdesc->endpoint[k];
uint8_t epnum = epdesc->bEndpointAddress; uint8_t epnum = epdesc->bEndpointAddress;
@ -214,12 +222,18 @@ int jtag_libusb_get_endpoints(struct jtag_libusb_device *udev,
*usb_read_ep = epnum; *usb_read_ep = epnum;
else else
*usb_write_ep = epnum; *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); libusb_free_config_descriptor(config);
return 0; return ERROR_FAIL;
} }
int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid) int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid)

View File

@ -60,9 +60,23 @@ int jtag_libusb_bulk_read(struct jtag_libusb_device_handle *dev, int ep,
char *bytes, int size, int timeout); char *bytes, int size, int timeout);
int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh, int jtag_libusb_set_configuration(jtag_libusb_device_handle *devh,
int configuration); 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_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); int jtag_libusb_get_pid(struct jtag_libusb_device *dev, uint16_t *pid);
#endif /* JTAG_USB_COMMON_H */ #endif /* JTAG_USB_COMMON_H */