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>
__archive__
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
/* 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;

View File

@ -47,16 +47,12 @@
* 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;

View 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)

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);
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 */

View 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];
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;
uint8_t epnum = epdesc->bEndpointAddress;
bool is_input = epnum & 0x80;
LOG_DEBUG("usb ep %s %02x",
is_input ? "in" : "out", epnum);
epdesc = &interdesc->endpoint[k];
if (is_input)
*usb_read_ep = epnum;
else
*usb_write_ep = epnum;
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)

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);
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 */