Hi guys,
By no means do I want to sound confrontational, but I have to agree and disagree with some of these comments. Also, though I think I am quite versed in this subject, I do not know all things about it, so please take my comments as my opinion, not fact.
Klakap wrote:
It looks like you are not reading speed of connected device. But it is vitally important thing. If you have connected full speed device, you have to request all 18 bytes at once. Otherwise there is hardware that will do all kind of strange things. For example, on one of my testing computer such piece of hardware resets whole computer just because I requested 8 bytes, not 18 bytes from descriptor. And when you will read other descriptors from full speed device, also make sure you are requesting maximum possible bytes - 64.
First, I agree with the speed verification. As the first request, if you detect a full-speed device, you should request 64 bytes, expecting a short packet on a short return. If you detect a low-speed device, you should request only 8 bytes, not necessarily expecting a short packet. The port's register set will indicate the speed.
However, I disagree with the "make sure you are requesting maximum possible bytes - 64". A device must adhere to your request. If you request only 8 bytes, the device must not send more than 8 bytes. It can send less, but it must not send more. A TD that requests only one byte is a valid request. If a TD requests more than the max_packet_size previously retrieved, all but the last DATA packet of the TD (which the last could be the one and only) should be of max_packet_size, while the last can and usually is less than the max_packet_size. However, again, a TD containing only one DATA packet, can request less than max_packet_size. It is allowed.
With that being said, I again agree, that when requesting the Device Descriptor for the first time, you should request the assumed Max Packet Size, 8 bytes for a low-speed device, and 64 bytes for a full-speed device. However, after that, the device must respond with any size packet requested, from a single byte to the max allowed by the hardware (8, 64, 512, 4096, etc.), per TD.
A note: When I use the term TD here, this is considered a Transfer Descriptor. A Transfer Descriptor is a count of one or more packets requesting a transfer. A Control TD is a SETUP packet, zero or more DATA packets, and a single STATUS packet. Unfortunately, the UHCI specs also name a single packet transfer as a TD. Therefore, don't confuse the term TD here with a single UHCI transfer TD. In all USB terms, a TD (a Transfer Descriptor) is considered one or more packet requests consisting of a complete transfer.
USB 2.0, section 5.3.2 states:
Quote:
The data payloads for such a multiple data payload IRP are expected to be of the maximum packet size until the last data payload that contains the remainder of the overall IRP.
You must first get the max packet size from the Device Descriptor, which may be much less than 64 bytes on a full-speed device. Once retrieved, you should use this value for every sequential packet, expecting a possible short-packet on the last request.
If the hardware does "all kind of strange things", this is not due to your request, this is due to something else. Again, please don't take this as confrontational, but if your computer reset the whole system because you requested only 8 bytes instead of 18, I believe you have more problems than you think. Either your USB stack is faulty, the HC is faulty, the device attached is faulty, or any or all the above.
Klakap wrote:
I mean that through every IN TD you have to transfer as much bytes as possible. Low speed devices allow you to transfer maximum of 8 bytes per one IN TD. But full speed devices allow you to transfer 64 bytes per one IN TD. So when you are requesting descriptor that return 18 bytes, for full speed devices you have to transfer them all in one IN TD. For low speed devices you need to use three IN TDs. Of course, do not forget to check how many bytes are you requesting in SETUP packet. Try to request all 18 bytes, and transfer them in one IN TD.
Because of bad choices by manufacturers testing their products only on a well-known well-used operating system that incorrectly interpreted a statement about a device in early development, the first request after a reset must be for the Device Descriptor *and* it must be a request for 8 bytes on low-speed devices, and 64-bytes on full speed devices. However, after that, this is no longer the case. You do not have to request as much as possible. It is preferred that you do, but it is not a requirement. Also, not all full-speed devices allow you to transfer 64-bytes per IN request. A full-speed mouse may only allow 8 bytes at a time, or less. This is why you request the Device Descriptor as the first descriptor so that you can retrieve the max packet size the device can transfer. From there, you only request a max size of this retrieved value, which can be less than 64.
For example, what happens when you plug a high-speed device into a full-speed Host Controller (HC)? Even though the high-speed device, when connected to a high-speed capable HC, might transfer more than 64-bytes at a time, the device *must* act as a full-speed device transferring no more than 64-bytes at a time. A device must adhere to the HC it is attached to as well as never sending more than requested. On the other side of that, a high-speed device, when plugged into a full-speed only HC, is only required to enumerate the Control pipe. It is not required to enumerate further. i.e.: it only has to respond to the Control pipe. Most high-speed devices will enumerate as a full-speed device, functioning as a full-speed device, but this is not a requirement.
Again, it is recommended and preferred that you transfer MAX_PACKET sized packets, usually 64 bytes at a time for full-speed devices, but it is not a requirement. A properly functioning device must respect the size requested. If the size a TD requests is a single byte, it must respect that and only send one byte. i.e.: It must only write one byte to the buffer you specify. If it writes more, you have a faulty Host Controller and/or Device. Remember that a TD is one or more max_packet_size packets. A Control TD is a single SETUP, zero or more DATA, and a single STATUS packet. It is perfectly acceptable to request a single byte of data, which would consist of one and only one DATA packet. It is all DATA packets before the last that should (in most cases *must*) contain max_packet_size'd packets.
Klakap wrote:
For full speed device, you need one IN TD with maxlen 9, for low speed device, you need two IN TD, first with maxlen 8 and second with maxlen 1.
This is correct. For (most) full-speed devices, you only need one IN TD. For low-speed devices, you need at least two. However, again, you must adhere to the max_packet_size, not the speed of the device. A full-speed device can have a max_packet_size of 8 bytes.
Klakap wrote:
When you read device descriptor, you have to assume size by speed and then you should use value from device descriptor. For example if I recall correctly, QEMU handle mouse and keyboard in way that it emulates them as full speed device, so device descriptor should be readed in one 18 bytes IN TD, however max control endpoint size in descriptor is 8, so you should read all other descriptors by 8 bytes long IN TD.
My notes agree that QEMU does emulate a mouse at both full- and high-speed. However, with that being said, may I reiterate, only the first request of the Device Descriptor should be a 64-byte request. Once you know the max_packet_size due to this request, all further requests must not be more than this max_packet_size, which in this example you give, must not be more than 8 bytes for this particular full speed device. (
https://gitlab.com/qemu-project/qemu/-/ ... hid.c#L265)
To reiterate, on the UHCI/OHCI, the first request after the first reset must be an 8-byte request for low-speed devices and a 64-byte request for full-speed devices. All residual requests, even the request after the second reset, must be the size of the max_packet_size found, not including the last packet of the TD. (On a super-speed controller, when a super-speed device is found, you initially request 512 bytes. However, the super-speed controller will indicate if the device is high-speed or less, or a super-speed device before you request the Device Descriptor.)
1) send reset
2) send GET_DESCRIPTOR(USB_DT_DEVICE) request. (8 bytes for low-speed, 64-bytes for full-speed. There *must* be only one DATA packet within the TD. No more.)
3) send reset
4) send GET_DESCRIPTOR(USB_DT_DEVICE) request. (max_packet_size requests only. There can be more than one DATA packet in the TD.)
5) continue with retrieving requests and further enumeration
Hope this helps,
Ben
-
https://www.fysnet.net/osdesign_book_series.htm