Revise magic numbers in USB codebase #1236
Labels
CI
Entries related to continuous integration infrastructure (historically also recipes like Makefiles)
refactor/fightwarn
PR or issue proposal to improve code maintainability without functional changes, or to fix warnings
USB non-zero interface numbers
Most UPSes serve USB interactions on interface 0 which is default. Recent "composite devices" differ
USB
Milestone
Reflecting a helpful answering comment, originally posted by @marcan in #300 (comment)
If you see 0x80, that's an IN endpoint number, not an interface number.
What the right way to deal with endpoint numbers is depends on the devices involved. Often you can get away with hardcoding endpoint numbers if they never change between device variants. Sometimes it's better to look at the descriptors and identify the endpoints by their position inside an interface, which itself can be identified by index or by its class or in some other way.
That's IN endpoint 1.
Same, IN endpoint 1 (which must be of interrupt type in this case). The 8 later is the buffer length and 1000 is a timeout.
This is actually wrong; USB_ENDPOINT_IN should be equal to 0x80. It should be
1 | USB_ENDPOINT_IN
to denote IN endpoint 1.(note that IN 1 (0x81) and OUT 1 (0x01) are distinct, separate endpoints)
Same story again, IN endpoint 1, length 8, timeout 1000.
In this case the HID input endpoint is, presumably, dynamically determined based on descriptors or some other way, so it comes from a structure, but it presumably lacks the IN bit so that gets added here (ORed would be more appropriate though).
I'm pretty sure the libusb0 code is written incorrectly (but works by accident). The prototype for that function is:
So the first parameter is the request type. But
USB_ENDPOINT_IN + 1
reads like it's trying to specify that the control request should be sent to IN endpoint 1, which doesn't make much sense (sending control requests to non-zero endpoints is exceedingly rare and not even supported by this API), and isn't what that parameter does. However, if you evaluateLIBUSB_ENDPOINT_IN|LIBUSB_REQUEST_TYPE_STANDARD|LIBUSB_RECIPIENT_INTERFACE
, you'll see it is 0x81 indeed (which does not mean IN 1 here, rather it's a bitfield describing the control request type). So in the end both versions do the same thing, but the libusb0 one is written in a confusing way and the author may not have understood it properly.That's a length.
The 0x81 stuff can be replaced with
LIBUSB_ENDPOINT_IN|1
in most cases. That said, endpoint numbers are such a fundamental part of USB that I think anyone working on this stuff probably understands that 0x81 means IN 1 and 0x01 means OUT 1. It would be more useful to have a define specific to each driver, e.g. something like:Which makes it clear that these are hardcoded endpoint numbers for that given device.
Addition should almost always be a logical OR instead; it doesn't make a difference for combining bitfields, but addition will break if e.g. one component already had the IN bit set, and OR is more idiomatic.
Endpoint zero is magical and used for control transfers almost always (and nothing else). For simple devices with only two data endpoints, those are often going to be either IN 1 (0x81) and OUT 1 (0x01), or something like IN 1 (0x81) and OUT 2 (0x02) (some devices prefer to use separate endpoint numbers for IN/OUT; this could be a USB device controller hardware limitation, or just caused by confused embedded engineers thinking they can't do that even though it's fully allowed). For a device with one interface, they would be part of interface 0, and you can usually get away with hardcoding them in that case. Devices with multiple interfaces though could end up having endpoint numbers change between device revisions / hardware; in that case it's a better idea to get the endpoint numbers from the interface descriptor.
HID is a particularly special case, because it's a standard and often implemented alongside other things. Since many devices implement HID, you can't hardcode interface or endpoint numbers. The correct way to do this is to look through all interface descriptors and find the one that claims to have the HID class; then use that interface number and get the endpoint descriptors from that interface descriptor. That way you don't have to hardcode anything for specific devices.
UPDATE: Partially related to #2149 subject area and USB non-zero interface numbersMost UPSes serve USB interactions on interface 0 which is default. Recent "composite devices" differ
labelled issues.
The text was updated successfully, but these errors were encountered: