Discussion:
[Libusb-devel] String descriptor index
Axel Rohde
2010-06-13 11:03:12 UTC
Permalink
Hi everybody!

I've observed the following weird behaviour when obtaining the string
descriptors via libusb_get_string_descriptor_ascii( ):

I'm using usblib-1.0 on windows to communicate with a ATmega32U2 HID
device based on LUFA.

That device's firmware implements three string descriptors with the
following indices:
0x01: Manufacturer descriptor string
0x02: Product descriptor string
0xDC: SerialNumber descriptor string

All three are successfully retrieved by the standard Windows HID driver.

The unusual value for the SN descriptor string index is because of the
way LUFA implements the automatic generation of that string based on the
internal unique ID of the microcontroller.
http://www.fourwalledcubicle.com/files/MyUSB/Doc/100513/html/group___group___descriptors.html#gae91cf5b90df788954090bcbd8bf1bece

The problem arises when my software on the host tries to obtain the
serial number string by calling:
r=libusb_get_string_descriptor_ascii(pHandle,
oDeviceDescriptor.iSerialNumber, (unsigned char*) szSN, 255 );
... it returns with error code -2 (LIBUSB_ERROR_INVALID_PARAM).

I ran the xusb example on my device and it successfully manages to
obtain the SN-string, so I had a look at the xusb source to see what I
am doing wrong.
Here is an excerpt from line 688 of:
http://git.libusb.org/?p=libusb-pbatard.git;a=blob;f=examples/xusb.c;h=4ebd37a15977ef48a728658db02c7751c1a094b6;hb=HEAD

for (i=1; i<nb_strings; i++) {
if (libusb_get_string_descriptor_ascii(handle, (uint8_t)i,
string, 128) >= 0) {
printf(" String (%d/%d): \"%s\"\n", i, nb_strings-1,
string);
}
}

As you can see, it doesn't use the string index reported by the
device-descriptor (0xDC) , but a sequentially incremented counter i, so
it successfully manages to obtain the SN-string with index=3;
The funny thing, is that the device descriptor obtained by xusb states
that the SN-string-decriptor-index indeed is 220 (=0xDC).

I modified my host software accordingly and it now succeeds retrieving
the SN-string by requesting index=3 instead of index=0xDC.

Since the Windows HID driver manages to obtain the SN string, I first
thought it might be a bug in libusb-1.0, so I dived into the source of
libusb, but everything looks as it should and I can't come up with a
plausible explanation for that LIBUSB_ERROR_INVALID_PARAM error code.

Did I misunderstand the documentation of
libusb_get_string_descriptor_ascii()?
http://libusb.sourceforge.net/api-1.0/group__desc.html#gaf3f92d0a7465d49a5e61eb3f8689fae4
I assumed the descriptor index is the one reported by the device-descriptor.



Regards,
Axel.
Xiaofan Chen
2010-06-13 12:44:03 UTC
Permalink
Post by Axel Rohde
Since the Windows HID driver manages to obtain the SN string, I first
thought it might be a bug in libusb-1.0, so I dived into the source of
libusb, but everything looks as it should and I can't come up with a
plausible explanation for that LIBUSB_ERROR_INVALID_PARAM error code.
I tend to think it is a bug.

http://git.libusb.org/?p=libusb-pbatard.git;a=blob;f=libusb/os/windows_usb.c;h=8b9408422f60a28017de561fc99af280e9637b21;hb=HEAD

2938 d.iManufacturer = _hid_wcslen(dev->man_string) ? 1 : 0;
2939 d.iProduct = _hid_wcslen(dev->prod_string) ? 2 : 0;
2940 d.iSerialNumber = _hid_wcslen(dev->ser_string) ? 3 : 0;

3025 static int _hid_get_string_descriptor(struct hid_device_priv*
dev, int index,
3026
void *data, size_t *size)
3027 {
3028 void *tmp = NULL;
3029 size_t tmp_size = 0;
3030
3031 /* language ID, EN-US */
3032 char string_langid[] = {
3033 0x09,
3034 0x04
3035 };
3036
3037 if ((*size < 2) || (*size > 255)) {
3038 return LIBUSB_ERROR_OVERFLOW;
3039 }
3041 switch(index) {
3042 case 0:
3043 tmp = string_langid;
3044 tmp_size = sizeof(string_langid)+2;
3045 break;
3046 case 1:
3047 tmp = dev->man_string;
3048 tmp_size = (_hid_wcslen(dev->man_string)+1) *
sizeof(WCHAR);
3049 break;
3050 case 2:
3051 tmp = dev->prod_string;
3052 tmp_size = (_hid_wcslen(dev->prod_string)+1) *
sizeof(WCHAR);
3053 break;
3054 case 3:
3055 tmp = dev->ser_string;
3056 tmp_size = (_hid_wcslen(dev->ser_string)+1) *
sizeof(WCHAR);
3057 break;
3058 default:
3059 return LIBUSB_ERROR_INVALID_PARAM;
3060 }

The index are hard-coded to be 1/2/3 (or 0 if not existed). I think
this is not correct.
--
Xiaofan http://mcuee.blogspot.com
Pete Batard
2010-06-13 14:34:19 UTC
Permalink
Yeah, this is a bug.

This comes from using the Windows API's HidD_GetManufacturerString,
HidD_GetProductString, HidD_GetSerialNumberString calls, that don't
care about string index, and overlooking the fact that Manufacturer,
Product and S/N don't necessarily use 1, 2, 3, unlike language ID,
which is always set to 0.

I'll fix that.

Regards,

/Pete
Axel Rohde
2010-06-13 18:53:41 UTC
Permalink
Thanks Xiaofan for pointing at the right spot of the source code. I
somehow got lost and looked in the wrong files.

And thank you Pete for your restless fight with the Windows APIs.

I hope you don't get tired of me and my unusual USB device
implementations. :-/


Cheers,
Axel.
Peter Stuge
2010-06-13 19:39:53 UTC
Permalink
Post by Axel Rohde
I hope you don't get tired of me and my unusual USB device
implementations. :-/
It is clearly very important that the Windows code, maybe in
particular the niched HID driver on Windows, is tested with all
sorts of devices, and the more unusual they are the better it is.


//Peter
Pete Batard
2010-06-13 20:29:34 UTC
Permalink
Post by Axel Rohde
I hope you don't get tired of me and my unusual USB device
implementations. :-/
Not at all. If anything, just like Peter, I think we haven't had enough
testers for the Windows code yet.

The more we get the new backend tested against unusual devices, or in
unusual situations, the better. So please keep it up, and don't hesitate
to submit reports about any oddity you see.

Regards,

/Pete
Xiaofan Chen
2010-06-14 01:37:05 UTC
Permalink
I hope you don't get tired of me and my unusual USB device implementations.
:-/
Actually LUFA seems to be quite good even though I am not using USB
AVRs. I am mainly using USB PICs. I have an Olimex LPC-P2148 board
(with lpcusb stack) but I am not that familiar with it. Then I have
also an ADI USB DAC demo board with Cypress EZUSB-FX2 (not FX2LP)
but again I am not that familiar with it.

And I think your HID device implementation is not unusual at all but
rather quite compliant.;-)

My main HID testbed is the Generic HID Firmware from Jan Axelson
and the PICkit 2. Both are using USB stack from Microchip (V2.x and
V1.x). Pete also has access to them. I think it is very
good that you are using a different device and a different stack.
--
Xiaofan http://mcuee.blogspot.com
Peter Stuge
2010-06-14 03:35:56 UTC
Permalink
I have an Olimex LPC-P2148 board (with lpcusb stack) but I am not
that familiar with it.
I'm also using lpcusb on the LPC-2148 MCU with libusb-1.0. It works
perfectly. I will be using it in a Windows app fairly soon, with
vendor-specific interface and WinUSB.sys.


//Peter
Xiaofan Chen
2010-06-14 05:02:47 UTC
Permalink
Post by Peter Stuge
I have an Olimex LPC-P2148 board (with lpcusb stack) but I am not
that familiar with it.
I'm also using lpcusb on the LPC-2148 MCU with libusb-1.0. It works
perfectly. I will be using it in a Windows app fairly soon, with
vendor-specific interface and WinUSB.sys.
Glad to know that. I have not looked in depth of the lpcusb stack.
But I want to do one test with it: I would like to port the Linux
usbfs based host example to libusb-1.0 to test out isochronous
transfer under Linux. Probably I will also try it out with the
asynchronous API of libusb-win32, just to compare the results.
It could be the test device for future libusb0.sys integration as well.
http://lpcusb.svn.sourceforge.net/viewvc/lpcusb/trunk/host/linux_isoc_sample/src/linux_usbfs_isoc_io_test.c?revision=178&view=markup
--
Xiaofan http://mcuee.blogspot.com
Pete Batard
2010-06-14 21:16:55 UTC
Permalink
Should be fixed in pbr283.

Regards,

/Pete
Axel Rohde
2010-06-15 07:53:18 UTC
Permalink
Post by Pete Batard
Should be fixed in pbr283.
It works!

Thank you.

Axel.

Loading...