Browse Source

libztex: Work around ZTEX USB firmware bug exposed by the FreeBSD libusb

The ZTEX USB firmware doesn't correctly support GET_DESCRIPTOR requests
for string descriptors, specifically the device always returns the full
string descriptor, even if the request wLength is shorter. The FreeBSD
implementation of libusb_get_string_descriptor_ascii() first requests 4
(four) bytes to validate the start of the string descriptor, and since
the device sends back too many bytes the USB host controller signals an
error to FreeBSD which returns the error to us.

In order to avoid this mess the libusb_get_string_descriptor_ascii()
call is replaced with the way libusb-1.0 works; which makes only a
single request to read the entire string descriptor.
nfactor-troky
Peter Stuge 12 years ago
parent
commit
972ddf74c7
  1. 32
      libztex.c

32
libztex.c

@ -409,6 +409,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt @@ -409,6 +409,7 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
struct libztex_device *newdev;
int i, cnt, err;
unsigned char buf[64];
uint16_t langid;
newdev = malloc(sizeof(struct libztex_device));
newdev->bitFileName = NULL;
@ -436,13 +437,40 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt @@ -436,13 +437,40 @@ int libztex_prepare_device(struct libusb_device *dev, struct libztex_device** zt
return err;
}
cnt = libusb_get_string_descriptor_ascii (newdev->hndl, newdev->descriptor.iSerialNumber, newdev->snString,
LIBZTEX_SNSTRING_LEN + 1);
/* We open code string descriptor retrieval and ASCII decoding here
* in order to work around that libusb_get_string_descriptor_ascii()
* in the FreeBSD libusb implementation hits a bug in ZTEX firmware,
* where the device returns more bytes than requested, causing babble,
* which makes FreeBSD return an error to us.
*
* Avoid the mess by doing it manually the same way as libusb-1.0.
*/
cnt = libusb_control_transfer(newdev->hndl, LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_DESCRIPTOR, (LIBUSB_DT_STRING << 8) | 0,
0x0000, buf, sizeof(buf), 1000);
if (unlikely(cnt < 0)) {
applog(LOG_ERR, "Ztex check device: Failed to read device LANGIDs with err %d", cnt);
return cnt;
}
langid = libusb_le16_to_cpu(((uint16_t *)buf)[1]);
cnt = libusb_control_transfer(newdev->hndl, LIBUSB_ENDPOINT_IN,
LIBUSB_REQUEST_GET_DESCRIPTOR,
(LIBUSB_DT_STRING << 8) | newdev->descriptor.iSerialNumber,
langid, buf, sizeof(buf), 1000);
if (unlikely(cnt < 0)) {
applog(LOG_ERR, "Ztex check device: Failed to read device snString with err %d", cnt);
return cnt;
}
/* num chars = (all bytes except bLength and bDescriptorType) / 2 */
for (i = 0; i <= (cnt - 2) / 2 && i < sizeof(newdev->snString)-1; i++)
newdev->snString[i] = buf[2 + i*2];
newdev->snString[i] = 0;
cnt = libusb_control_transfer(newdev->hndl, 0xc0, 0x22, 0, 0, buf, 40, 500);
if (unlikely(cnt < 0)) {
applog(LOG_ERR, "Ztex check device: Failed to read ztex descriptor with err %d", cnt);

Loading…
Cancel
Save