REPORT_ID greater than 256?

Status
Not open for further replies.

poxyran

Member
Hi,

I'm trying to reproduce a bug and I want to know if it is possible to have a report_id greater than 256 taking into account that the report_id field is declared as a uint8_t.

Thanks.
 
If report_id field is declared as a uint8_t as you say, then the only valid values for the variable would be 0 - 255. So, if the values 0 to 255 map to report_id 0 to 255, then no larger report_id is possible.
 
I understand that, but my question is: can I declare a report_id as uint16_t or the report_id field MUST be an uint8_t?. If so, then, the patch I posted has no sense because report_id is always uint8_t and the only possible values are 0-255.
 
Ah, yes - I see what you mean.

Looking at the sources, I noticed that:

1. the struct hid_report *report_id_hash[HID_MAX_IDS] is at the end of the struct, so the struct can be extended without disrupting any member offsets.
2. The value being used there in hid_register_report() defines the report id as an unsigned (32 bits at least).

It is curious that the member name is report_id_hash[] (i.e. hash), yet in that hid_register_report() no hash value is calculated. They appear to use the id without hashing it.

Looking through the header file they also store a report id in struct hid_report as an unsigned. So I didn't see any 8-bit limitation in the report_id, unless I missed it.
 
Thanks!.

Then, I have the following USB HID descriptor (taken from https://github.com/johnburkert/YeOldeJoystick/blob/master/ps3_gamepad/usb_gamepad.c) with a slight modification (just added the report_id entry):

static uint8_t PROGMEM gamepad_hid_report_desc[] = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x05, // USAGE (Gamepad)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x01, // REPORT_ID (1)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x35, 0x00, // PHYSICAL_MINIMUM (0)
0x45, 0x01, // PHYSICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x0d, // REPORT_COUNT (13)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x0d, // USAGE_MAXIMUM (Button 13)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x95, 0x03, // REPORT_COUNT (3)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x25, 0x07, // LOGICAL_MAXIMUM (7)
0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x01, // REPORT_COUNT (1)
0x65, 0x14, // UNIT (Eng Rot:Angular Pos)
0x09, 0x39, // USAGE (Hat switch)
0x81, 0x42, // INPUT (Data,Var,Abs,Null)
0x65, 0x00, // UNIT (None)
0x95, 0x01, // REPORT_COUNT (1)
0x81, 0x01, // INPUT (Cnst,Ary,Abs)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x09, 0x32, // USAGE (Z)
0x09, 0x35, // USAGE (Rz)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific)
0x09, 0x20, // Unknown
0x09, 0x21, // Unknown
0x09, 0x22, // Unknown
0x09, 0x23, // Unknown
0x09, 0x24, // Unknown
0x09, 0x25, // Unknown
0x09, 0x26, // Unknown
0x09, 0x27, // Unknown
0x09, 0x28, // Unknown
0x09, 0x29, // Unknown
0x09, 0x2a, // Unknown
0x09, 0x2b, // Unknown
0x95, 0x0c, // REPORT_COUNT (12)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x0a, 0x21, 0x26, // Unknown
0x95, 0x08, // REPORT_COUNT (8)
0xb1, 0x02, // FEATURE (Data,Var,Abs)
0xc0 // END_COLLECTION
};

How should I declare the USB HID descriptor in order to have the value of the report_id declared as a uint16_t/uint32_t?. I mean, I can declare the byte array as "static uint16_t PROGMEM gamepad_hid_report_desc[]" but that would shift some bytes, i.e: 0x85, 0x01 would become 0x0085, 0x0001. Is there any problem with that? I mean because of the report_id byte identifier (0x85).
 
How is this array being used? What I mean is, is the structure gamepad_hid_report_desc[] being passed to a function, or simply iterated through? I ask, because here you really do have a problem, being that the type is uint8_t (back to where we started).

In order for larger report id values to be used, that data type has to be changed. Can you point me to the code that uses this?
 
Well, the gamepad_hid_report_desc[] is referenced in the descriptor_list struct at line 261 in the usb_gamepad.c and then used in the ISR() function at line 443 in the same file.
 
Well, the gamepad_hid_report_desc[] is referenced in the descriptor_list struct at line 261 in the usb_gamepad.c and then used in the ISR() function at line 443 in the same file.

Looking at usb_gamepad.c, I believe you are snookered at several levels. You could change the gamepad_hid_report_desc[] data type, but then the rest of the code will fail. Everything in that module is depending upon byte values for report id. You'd need to completely revise that module, reviewing line by line.

I believe that this piece of code (see ref to desc_addr):

Code:
			do {
				// wait for host ready for IN packet
				do {
					i = UEINTX;
				} while (!(i & ((1<<TXINI)|(1<<RXOUTI))));
				if (i & (1<<RXOUTI)) return;	// abort
				// send IN packet
				n = len < ENDPOINT0_SIZE ? len : ENDPOINT0_SIZE;
				for (i = n; i; i--) {
					UEDATX = pgm_read_byte(desc_addr++);
				}
				len -= n;
				usb_send_in();
			} while (len || n == ENDPOINT0_SIZE);
transmits those report id values. Here it is doing so one byte at a time. But if the other end is expecting byte sized report id's (which I am sure it is), then you're beat.

So if you were to revise this program, the driver at the other end would need revising also. If you have access to that, then this is obviously doable.

On the whole however, this looks like a fair piece of work.
 
Thanks for the answer. As you pointed me in a previous post, there weren't 8-byte limitation at the other end, hid-core.c (the hid driver in linux) so I suppose I must find a way to fix this code or to create a new code from the scratch.

Thanks again for all your help!
 
Be careful about assumptions-- while the Linux data structures don't impose an 8-bit limit on the report_id, the driver data marshaling might. If that usb_gamepad.c code has been known to work with linux, then this suggests that the linux driver is also expecting byte sized report_id values from the usb pipe.

So again, both sides will need to be amended to make a larger report_id to work, as far as I can see.
 
In the USB HID spec, version 1.11 (dated 6/27/01), section 5.6 on pages 17-18 says:

...... Report ID
items are used to indicate which data fields are represented in each report
structure. A Report ID item tag assigns a 1-byte identification prefix to each
report transfer. If no Report ID item tags are present in the Report descriptor, it
can be assumed that only one Input, Output, and Feature report structure exists
and together they represent all of the device's data.

Note Only Input reports are sent via the Interrupt In pipe. Feature and
Output reports must be initiated by the host via the Control pipe or an optional
Interrupt Out pipe.

If a device has multiple report structures, all data transfers start with a 1-byte
identifier prefix that indicates which report structure applies to the transfer. This
allows the class driver to distinguish incoming pointer data from keyboard data by
examining the transfer prefix.

I have no idea whether or how the Linux kernel implements or checks report ID numbers. But it seems pretty clear from the HID spec that they're only 1 byte.
 
Yes, that's what I thought at the very beginning. All the sample codes I saw treated the report id as a uint8_t but then I saw that patch in the linux kernel and I got lost. So, then, that patch in the linux kernel seems useless for me unless they handled the report_id as a WORD o DWORD instead of a byte.
 
What you can do is cheat, if you are willing to bend the driver on the Linux side.

For erxample, if you don't need every possible 8-bit report_id value, pick one or more that can be re-used (i.e. bent). For example, on both sides (where applicable) say id 0x1D is not used. Remap that 0x1D on both ends to the 16-bit ID value that you need. You'll just have to map back to the 8-bit ID whenever it needs to pass through the usb pipe.
 
@wwg: can you give me an example of how to do it? I don't get it. On the linux side I can't touch anything, the only thing I can do is to fake usb device (using teensy) with a report_id greater than 256.
 
That requires downloading the kernel software and making some changes, and then installing it. That procedure is a bit much to explain by email/forum. But there are web resources available for rebuilding your kernel etc., which you might be able to use.

Once you learn how to rebuild and install a kernel, then the next step is to locate the linux source module to be modified (find command is your friend), modify that and repeat (the kernel build/install).
 
Oh! ok. But, as I said, I can't modify the host, just to fake a device. I already did that but just for debugging purposes.
 
@posyran - I'd like to ask for your help on improving this forum, if you have a moment to offer a fresh "new forum user" perspective.

First of all, I don't want to accuse you of doing anything wrong or breaking the rules here, so please don't take this the wrong way. My interest is figuring out innovative ways to improve forums in general. The problem, which happen here every day (and continuously across all forums dedicated to tech subjects) involves just-registered users posting vague questions. The trouble with such questions is twofold. First, good answers are pretty much impossible when questions lack necessary details or context. Second, the resulting conversation asking for details & context consumes the time and energy of everyone who wants to help.

Human time and enthusiasm are the most precious and limited of resources. Anything we can do to get brand new users to post better questions with details and context will save everyone a lot of time and frustration, and of course lead to better help.

Obviously the traditional stuff, like forum rules when you sign up and posting guidelines aren't highly effective. We have those here, pretty like like all forums do. Some people read them, but obviously many people don't. Again, I'm not trying to accuse you of anything. This happens every day, here and across all forums on the internet.

If you can think back to a couple days ago when you started this thread, please try to recall what you saw on the screen and what your thought process was. You clicked "Post New Thread", then typed the message, then clicked "Submit New Thread".

What could a forum do differently? For example, you wrote "trying to reproduce a bug". What text, pixels, or interactive elements could a forum like this have used to get you to think that people reading your question wouldn't necessarily know you were talking at the Linux kernel? How could something on the screen have made you think that people reading your question wouldn't know that you're trying to cause the bug to occur only by external stimulus by USB?

I know these are tough, perhaps impossible issues. But it's a common problem here and across all internet forums. Anything we can do to improve, to get brand new users who haven't read any guidelines to post more detailed questions with more context can really help everyone. If you can recall anything about your thought process and what you saw on the screen and didn't realize at the time, I'd really like to hear. Even if we can make a tiny improvement, over the long run it'll be incredibly helpful.
 
@PaulStoffregen: Sorry for revisiting this thread after a long time. I want to give you an answer about what you wrote just because you took time to write and intend to give me something to think.

I think there is nothing wrong with the forum but I'm sure that there are things to improve, as always, however, it was my fault this thread take too many answers trying to understand what I was trying to do simply because I didn't explain enough my idea at the first place, just that, I assume the responsibility :)

In my defense, I have to say that I'm a newbie with the USB protocol and Teensy board so I was trying to trigger something with just a tiny knowledge and I think that was the reason I couldn't explain my self well at the very beginning. I knew that I needed a report_id greater than 256 but not too much. Also, it was my error to assume that everyone in this forum will understand what I was trying to do simply just because we are in a USB/Teensy related forum, again, my bad.

I know that every person in the forum spend time answering posts without asking anything in return and I appreciate that.

I'll try to give more details the next time I post in this forum.

BR,
poxyran
 
Status
Not open for further replies.
Back
Top