USB HID Enumeration - Page 1
Forum section: electronics / general

author: Bambur
author_rank: Regular Contributor
timestamp: January 13, 2017, 02:48:37 pm
content: Hello to everyone!Is there USB HID enumeration experts on this forum? I am stuck and would appreciate help

author: ataradov
author_rank: Super Contributor
timestamp: January 13, 2017, 05:35:43 pm
content: So do we need to pull information from you? What is the problem?

author: Bambur
author_rank: Regular Contributor
timestamp: January 13, 2017, 09:28:30 pm
content: Thanks for the reply, Alex!I am trying to implement a HID with Microchip PIC. I want to implement USB code myself, so I do not use any library or third-party framework. I have studied USB transactions and higher level control transfers. I am able to enumerate till Windows requests the HID report descriptor. I transfer mine and get... the reset. I have tried differrent HID report descriptors -- the result is either a blue screen, or USB reset.The request for HID report descriptor by Windows XP host looks very suspitious to me. Here is the setup data I receive:81 06 00 22 00 00 5d 00The length is 0x005d, where as my HID report descriptor is of 29 byte only. Why? I have no idea at the moment.I attach the log of my enumeration as seen by the device, and my descriptors. Do you see any problems? What to check else and where?

author: ataradov
author_rank: Super Contributor
timestamp: January 13, 2017, 09:50:34 pm
content: Thishttps://github.com/ataradov/dgw/tree/master/embeddedhas a simple working implementation of a HID device for SAM D21. You can take a descriptor from there, it works under Windows, Linux and OS X for sure.I don't know if your descriptors are correct, since I don't want to decode binary data, it is not 1970 anymore.Quote from: Bambur on January 13, 2017, 09:28:30 pmHost does not know how big your descriptor is, so it requests a big number. You should respond with the actual number of bytes you have. My Win7 requests 97 (0x61) bytes, for example.

author: ataradov
author_rank: Super Contributor
timestamp: January 13, 2017, 10:04:10 pm
content: Your descriptors appear to be correct (or at least parsable), so it must be something in a way you are sending them.I'm attaching a handy USB descriptor parser. It is an HTML page that works offline. It parses your thing to this:Quote

author: Bambur
author_rank: Regular Contributor
timestamp: January 18, 2017, 09:36:35 pm
content: Alex, could you kindly tell me the idea of clear/set feature, e.g. udc_endpoint_clear_feature in udc.c? I do not know the chip you used and cannot see what it does. I get Clear Feature request now from the host, but do not know what it is supposed to do. Where is it specified?

author: ataradov
author_rank: Super Contributor
timestamp: January 18, 2017, 09:46:23 pm
content: Quote from: Bambur on January 18, 2017, 09:36:35 pmFor endpoints, Clear Feature request must clear stall state of the corresponding endpoint. This is a part of the USB spec, although I don't know if hosts ever send this request. EDIT: apparently they doIn theory Set Feature for endpoint puts endpoint into the stall state, so this lets host to pause traffic from the endpoint. Clear Feature is used to reverse this process and enable the traffic.

author: Bambur
author_rank: Regular Contributor
timestamp: January 18, 2017, 10:25:36 pm
content: Thanks, Alex!Now I get Clear Feature request. I enable endpoint 1 IN and arm endpoint 0 IN for the status ZLP. I see the status stage completes fine and then... reset and code 43 in Windows Device Manager. What am I missing?UADDR=0aPIR2.USBIF=1UIE=00101011UIR=01011100UIR.TRNIF=1, usb transaction completedUSTAT=000000000400 34 08 00 050500 02 01 00 00 81 00 00 00endpoint 0 setupclear featureUADDR=0aPIR2.USBIF=1UIE=00101011UIR=01011100UIR.TRNIF=1, usb transaction completedUSTAT=000001000404 64 00 40 050540endpoint 0 inUADDR=00PIR2.USBIF=1UIE=00101011UIR=01010101UIR.URSTIF=1, usb reset detected

author: ataradov
author_rank: Super Contributor
timestamp: January 18, 2017, 10:31:42 pm
content: I have no idea. I would strongly suggest to use Linux for debugging USB devices. Linux is way more descriptive with what's wrong with the device.

author: Bambur
author_rank: Regular Contributor
timestamp: January 18, 2017, 11:59:09 pm
content: Alex, if I change bNumEndpoints to zero in the interface descriptor, it enumerates OK. However, I see 2 devices: HID-compliant device and USB Human Interface Device. Why?..

author: ataradov
author_rank: Super Contributor
timestamp: January 19, 2017, 12:03:24 am
content: Quote from: Bambur on January 18, 2017, 11:59:09 pmYou are doing something non-standard, so absolutely any behavior is normal. I have no idea what windows does on the inside when it sees malformed descriptors.

author: John_ITIC
author_rank: Frequent Contributor
timestamp: January 20, 2017, 03:19:08 am
content: Normally a hardware USB analyzer is needed when software analyzers can not be used due to system crashes. PM me if you need to buy one and I can give you a good price./John.

author: Bambur
author_rank: Regular Contributor
timestamp: January 23, 2017, 10:32:07 am
content: I agree the analyser would be great to have, but I do not have one.I have found the problem. It was the way I controlled the endpoint 1 for interrupts IN and OUT transfers. It looks like Windows built-in HID driver expects the endpoints defined in the interface to reply with NAK's or data after SetConfiguration is done. I did not do that properly initially, hence the reset.I attach the enumeration log I see in a successful case.Could somebody tell me the idea with HID reports? Does host buffer them once it receives some? When does host send a report? Basically, I want to transfer some data to and from my HID running on the microcontroller.

author: ataradov
author_rank: Super Contributor
timestamp: January 23, 2017, 05:13:43 pm
content: Quote from: Bambur on January 23, 2017, 10:32:07 amDuring the configuration stage only control endpoint needs to send ZLP. In general, all endpoints must send NACK or STALL in response to request if they don't have data. This should be done by the hardware, since software can't be fast enough.Quote from: Bambur on January 23, 2017, 10:32:07 amDepends on a report configuration. If it looks like a keyboard or a mouse, then they become corresponding devices.Quote from: Bambur on January 23, 2017, 10:32:07 amIf it is just an arbitrary data, then noting is buffered unless there is a client attached, in which case requests are forwarded to that client.Quote from: Bambur on January 23, 2017, 10:32:07 amOnly when requested by the client.Quote from: Bambur on January 23, 2017, 10:32:07 amHere is example of PC side of things for Windows and Linux -https://github.com/ataradov/dgw/tree/master/cli

author: Bambur
author_rank: Regular Contributor
timestamp: January 23, 2017, 06:59:17 pm
content: Thanks, Alex! I appreciate you helping me.In my case, endpoint 1 was declared for both IN and OUT interrupt transfers. However, I simply forgot to enable it. Host receives nothing polling the endpoint IN, desides the device malfunctions and resets it.I could enumerate when I removed the descriptors of endpoint 1 in the interface. Then, I realized I forgot to enable the endpoint 1. I also forgot to initialize the buffer descriptors of endpoint 1 properly for a couple of tries and got a bit confused. Anyway, finally it all looks logic and expected. Now I want to continue with the application for Windows. That's why I asked about the reports. I will study your code, Alex, as well as Windows documentation on HID.

author: Bambur
author_rank: Regular Contributor
timestamp: February 20, 2017, 10:13:22 pm
content: I am puzzled again. Please help.I have the followig HID report descriptor:06 00 ff 09 01 a1 01 15 00 26 ff 00 75 08 95 40 09 01 81 02 95 40 09 01 9102 95 01 09 01 b1 02 c00x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)0x09, 0x01, // Usage (0x01)0xA1, 0x01, // Collection (Application)0x15, 0x00, // Logical Minimum (0)0x26, 0xFF, 0x00, // Logical Maximum (255)0x75, 0x08, // Report Size (8 )0x95, 0x40, // Report Count (64)0x09, 0x01, // Usage (0x01)0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)0x95, 0x40, // Report Count (64)0x09, 0x01, // Usage (0x01)0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)0x95, 0x01, // Report Count (1)0x09, 0x01, // Usage (0x01)0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)0xC0, // End Collection// 33 bytesIt defines the input and output reports of 64 bytes.Why do I get Windows returning 65 in HIDP_CAPS.InputReportByteLength and HIDP_CAPS.OutputReportByteLength?Where does HIDP_CAPS.FeatureReportByteLength = 2 come from?Any ideas?

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2017, 10:17:22 pm
content: Quote from: Bambur on February 20, 2017, 10:13:22 pmThis is normal. Those values indicate the size of the chunk you need to write into a file corresponding to the device. The first byte is always "Report ID" and the rest is an actual payload. Same goes for reading, the first read byte is report ID.Quote from: Bambur on February 20, 2017, 10:13:22 pmNo idea on this one.

author: Bambur
author_rank: Regular Contributor
timestamp: February 20, 2017, 10:19:27 pm
content: Alex, thanks a lot! I am glad you are around here and helping.How do I know the report ID value? Where does it come from?

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2017, 10:20:57 pm
content: If you only have one report (as you do in this case), then it is always 0. And then it just increments by one for each report type supported by the device.

author: Bambur
author_rank: Regular Contributor
timestamp: February 20, 2017, 10:23:55 pm
content: OK. Zero it is.Now, if report length is of 65 bytes, does it come in 2 USB transactions? First of 64 bytes and second of 1 byte?

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2017, 10:29:04 pm
content: No, the report itself is 64 bytes. Added 1 byte is an OS abstraction. So you need to add 1 byte (0) in front of your data when you do WriteFile() and discard the first byte after ReadFile().And you need to specify 65 bytes length for reading/writing.Example:https://github.com/ataradov/edbg/blob/master/dbg_win.c

author: Bambur
author_rank: Regular Contributor
timestamp: February 20, 2017, 10:32:53 pm
content: H-m, that's unexpected and very interesting. How do you know all that, Alex? Is there a good documentation or source of information?I'll continue and see how it goes.Thanks!

author: ataradov
author_rank: Super Contributor
timestamp: February 20, 2017, 10:37:12 pm
content: Quote from: Bambur on February 20, 2017, 10:32:53 pmI originally implemented this stuff on Linux, and there are some good examples with explanations for that.Later, when I did a Windows port, I just assumed that things are similar. So I just tried the same thing, and it worked. I originally just had a fixed report size, so detecting was not an issue.Later, when I got to reading CAPS, I saw that it returns 1 byte more than needed, and I just assumed that it included that report ID byte.So a lot of assumptions and experimenting.

author: Bambur
author_rank: Regular Contributor
timestamp: February 23, 2017, 09:14:29 pm
content: I got sending and receiving reports working.UADDR=05PIR2.USBIF=1UIE=00101011UIR=01011100UIR.TRNIF=1, usb transaction completedUSTAT=000010000408 04 40 80 050580 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 191a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 3435 36 37 38 39 3a 3b 3c 3d 3e 3f 40endpoint 1 outUADDR=05PIR2.USBIF=1UIE=00101011UIR=01011100UIR.TRNIF=1, usb transaction completedUSTAT=00001100040c 24 40 80 050580 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 191a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 32 33 3435 36 37 38 39 3a 3b 3c 3d 3e 3f 40endpoint 1 inAs Alex said, I need to provide a buffer one byte longer than the report length:BYTE out; for (BYTE i = 0; i < 65; i += 1) out[ i ] = i;HID receives 64 bytes only, though. What a messIs it OK to have endpoint 1 bidirectional? It works, but is it inline with the spec?

author: ataradov
author_rank: Super Contributor
timestamp: February 23, 2017, 09:23:18 pm
content: Quote from: Bambur on February 23, 2017, 09:14:29 pmWell, this is a consequence of using a 'file' as an abstraction for everything and the need to communicate more than one piece of information.Quote from: Bambur on February 23, 2017, 09:14:29 pmAbsolutely.Some hardware implementations only support one way communication on a particular endpoint index, so I just pick different numbers even on the ones that support bidirectional operation. This way all my descriptors on all hardware platforms are the same.

author: aandrew
author_rank: Frequent Contributor
timestamp: February 23, 2017, 11:38:05 pm
content: Quote from: ataradov on January 18, 2017, 10:31:42 pmNot to mention it has a *great* built-in USB traffic logging and debugging system:https://www.kernel.org/doc/Documentation/usb/usbmon.txt(Wireshare also works with this interface, although I've not used it myself.)

author: Bambur
author_rank: Regular Contributor
timestamp: February 24, 2017, 04:10:30 pm
content: H-m, we might take our words back on bidirectional data endpoints:Data endpoints are optional and used for transferring data. They areunidirectional, has a type (control, interrupt, bulk, isochronous) and other properties.https://msdn.microsoft.com/en-us/library/windows/hardware/dn303353(v=vs.85).aspx

author: ataradov
author_rank: Super Contributor
timestamp: February 24, 2017, 04:44:00 pm
content: Quote from: Bambur on February 24, 2017, 04:10:30 pmI think they just used the wrong words. Technically, for endpoint 5, IN direction will have address 0x85, and OUT direction will be just 0x05, so they are unique in a way.Otherwise, I see no reason to not support the same index for IN and OUT endpoints.

author: Bambur
author_rank: Regular Contributor
timestamp: March 08, 2017, 02:17:36 pm
content: Alex, thanks again! I see your point.Next I would like to ask about the considerations on a protocol over interrupt IN and OUT endpoints.I have understood host polls an IN endpoint periodically and has an internal ring buffer where it stores fetched HID reports. Hence, there is HidD_SetNumInputBuffers on Windows, for instance. Nevertheless, there is no guarantee no report(s) will be lost.Have you thought about that? Any solution?

author: ataradov
author_rank: Super Contributor
timestamp: March 08, 2017, 04:43:20 pm
content: Quote from: Bambur on March 08, 2017, 02:17:36 pmNot really. PCs are much faster than any USB device out there. Just organize your program in a way that reads the data fast enough.With USB FS it is not a problem at all, since your maximum throughput is 65 KB/s. With USB HS I was getting something like 6 MB/s, which is also close to theoretical maximum, ans I had no problems with that.

author: janoc
author_rank: Super Contributor
timestamp: March 08, 2017, 05:09:54 pm
content: BTW, careful with the HID descriptors - the Windows HID parser is notorious for crashing and randomly barfing on otherwise perfectly valid descriptors that Linux or Mac will work fine with (for example). The best way that I have found to avoid this issue is to "steal" a descriptor from a device implementing similar functionality to what you are after and adapt it - that will give you a known working starting point.If you don't have an USB analyzer, then Wireshark (https://www.wireshark.org/) can capture and analyze USB transactions too if you install the USBCap drivers during installation. That is a huge timesaver for debugging problems like this.For interfacing with HID devices in a portable way without having to deal with the messy Win32 APIs I have found the HIDAPI lib (http://www.signal11.us/oss/hidapi/) indispensable. That makes talking to a HID device a lot easier.

author: janoc
author_rank: Super Contributor
timestamp: March 08, 2017, 05:17:43 pm
content: Quote from: ataradov on January 18, 2017, 10:31:42 pmI second this. Even if you put Linux in a VirtualBox image, it will save you a ton of headaches.