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:
parent
b631e78b25
commit
487c57d9a2
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
Loading…
Reference in New Issue