USB Host Mouse Driver

Status
Not open for further replies.
Thanks @defragster and @tni!

I am looking at trying to handle the Teensy configured as an USB mouse as a mouse to the T3.6...

The first issue, is the USBHost code is not currently claiming the Mouse. This is because it is not marked as a Boot device nor as mouse.

From ...cores\teensy3\usb_desc.c
Code:
#ifdef MOUSE_INTERFACE
        // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
        9,                                      // bLength
        4,                                      // bDescriptorType
        MOUSE_INTERFACE,                        // bInterfaceNumber
        0,                                      // bAlternateSetting
        1,                                      // bNumEndpoints
[COLOR="#FF0000"]        0x03,                                   // bInterfaceClass (0x03 = HID)
        0x00,                                   // bInterfaceSubClass (0x01 = Boot)
        0x00,                                   // bInterfaceProtocol (0x02 = Mouse)[/COLOR]
        0,                                      // iInterface
        // HID interface descriptor, HID 1.11 spec, section 6.2.1
        9,                                      // bLength
        0x21,                                   // bDescriptorType
        0x11, 0x01,                             // bcdHID
        0,                                      // bCountryCode
        1,                                      // bNumDescriptors
        0x22,                                   // bDescriptorType
        LSB(sizeof(mouse_report_desc)),         // wDescriptorLength
        MSB(sizeof(mouse_report_desc)),
        // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
        7,                                      // bLength
        5,                                      // bDescriptorType
        MOUSE_ENDPOINT | 0x80,                  // bEndpointAddress
        0x03,                                   // bmAttributes (0x03=intr)
        MOUSE_SIZE, 0,                          // wMaxPacketSize
        MOUSE_INTERVAL,                         // bInterval
#endif // MOUSE_INTERFACE
Again as you can see it is not setup as boot device...

Currently the USBHost mouse claim code checks these values:
Code:
	if (descriptors[5] != 3) return false; // bInterfaceClass, 3 = HID
	if (descriptors[6] != 1) return false; // bInterfaceSubClass, 1 = Boot Device
	if (descriptors[7] != 2) return false; // bInterfaceProtocol, 2 = Mouse
And bails from trying to claim it... So the mouse does not work...

I obviously may know enough here... But how does Windows know that this is a mouse? As I can plug it in to my PC and with the Triangle example sketch, my mouse moves itself around in a triangle pattern.

Suggestions?
 
I don't think you are supposed to use the interface subclass to identify the device type. Per USB HID spec (Device Class Definition for Human Interface Devices (HID) Version 1.11):
4.2 Subclass
...
The HID committee agreed on the improbability that subclass protocols for all
possible (and yet to be conceived) devices could be defined. In addition, many
known devices seemed to straddle multiple classifications—for example,
keyboards with locators, or locators that provided keystrokes. Consequently, the
HID class does not use subclasses to define most protocols. Instead, a HID class
device identifies its data protocol and the type of data provided within its Report
descriptor.
...


The Teensy mouse device is somewhat unusual anyway and combines mouse and touchpad. The Teensy mouse report descriptor has mouse usage.
 
Thanks @tni,

I read that also.

So far the Keyboard and Mouse code looks at the subclass for boot device and works with that.

What I am trying to figure out, is what is the more generic way (at least for mouse).

The USB Claim code is walking through the Descriptors trying to decide if any of them should be claimed by the Mouse.

Loops through each section asking the Mouse if it wants to claim it: So it calls it with ...
Code:
 Actual whole data : 08 0B 00 02 02 02 01 04 09 04 00 00 01 02 02 01 00 05 24 00 10 01 05 24 01 01 01 04 24 02 06 05 24 06 00 01 07 05 82 03 10 00 40 09 04 01 00 02 0A 00 00 00 07 05 03 02 40 00 00 07 05 84 02 40 00 00 09 04 02 00 01 03 01 01 00 09 21 11 01 00 01 22 3F 00 07 05 81 03 08 00 01 09 04 03 00 01 03 00 00 00 09 21 11 01 00 01 22 54 00 07 05 85 03 08 00 02 09 04 04 00 01 03 00 00 00 09 21 11 01 00 01 22 55 00 07 05 86 03 0C 00 01 09 04 05 00 01 03 00 00 00 09 21 11 01 00 01 22 28 00 07 05 87 03 08 00 04 

... Loops a few times
Probably Keyboard entry which has the Boot subclass
  : 09 04 02 00 01 03 01 01 00 09 21 11 01 00 01 22 3F 00 07 05 81 03 08 00 01 

Probably Mouse entry which in this case does not have Boot sublass
 : 09 04 03 00 01 03 00 00 00 09 21 11 01 00 01 22 54 00 07 05 85 03 08 00 02
I am sort of talking this out, out-laud, so pardon the ramblings.

So I need to keep reading some parts of the HID stuff to hopefully sink in. But I wonder if I might need to do something like:
See the entry above - Since it is not marked as subclass or like, do I maybe see the beginning of the data:
Code:
#ifdef MOUSE_INTERFACE
        // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
        9,                                      // bLength
        4,                                      // bDescriptorType
        MOUSE_INTERFACE,                        // bInterfaceNumber
        0,                                      // bAlternateSetting
        1,                                      // bNumEndpoints
        0x03,                                   // bInterfaceClass (0x03 = HID)
        0x00,                                   // bInterfaceSubClass (0x01 = Boot)
        0x00,                                   // bInterfaceProtocol (0x02 = Mouse)
So We see the interface number And retrieve the HID report descriptor. I do this to process later. Currently I start reading index 0 and if it is not the right one increment until I find it, but
should maybe check if the bInterfaceNumber has the right one?

Currently reading in starting with index 0 like:
Code:
	mk_setup(descriptor_setup, 0x81, 6, 0x2200, 0, descriptors[16]);  // bugbug... need to get the right one... 
	queue_Control_Transfer(dev, &descriptor_setup, mouse_report_desc, this);
But assuming the data above has the actual correct index. If I would then check the start of the report descriptor, which for all of the mice I have seen start off with:
Code:
static uint8_t mouse_report_desc[] = {
        0x05, 0x01,                     // Usage Page (Generic Desktop)
        0x09, 0x02,                     // Usage (Mouse)

If this is the more generic approach, wonder if that implies that we should change the enumeration step# state table that gets to case 14, which calls claim_drivers, that we may need to go through multiple steps (waiting for next USB packet to be processed). ...

Still investigating
 
Another update:

I modified the claim code: first I split out the code that a driver can claim a whole device, as it's own method.

Then setup the claim for Interface code to allow the code to be called multiple times. Then the code is setup that this function can now return 3 values:
Does not claim, Does Claim, or needs HID descriptor...

If the device returns needs HID descriptor, the main enum sets up to retrieve it. When data is returned, it re-enters into the Claim code. So the mouse code now checks to see if everything is else is OK for it to maybe claim... If so and the HID descriptor had not been returned it will ask for it... When it reenters, it looks at the beginning of this data and if correct continues else bails... Then parses the HID data...

So with this: I tested again with the 4 mice I mentioned earlier. It also now appears to work with T-LC running as Mouse (Triangle test app).
I also updated test app to simply print out Raw mouse data (like the Mouse/Keyboard app) and not try the scaling stuff...

So again would be great if any has other mice to try...

Github updated

Kurt

Update: fixed a problem with a Dell mouse I found sitting around
 
Last edited:
Hi KurtE, I downloaded your latest work on the mouse driver. I've got some time this weekend so I can't wait to go through it!

Awesome stuff:)
 
Warning: WIP - But playing around right now with Joystick plugged into USB.. Actually currently playing with Sony PS4 controller (DS4).

I started off from my Mouse code reading in HID information and then try to extract data. It is getting most of the data now. Need to fix my extract field from stream code to handle more of the issues with signed vs unsigned, plus how I handle where it says mouse is 12 bits...

I decided to upload the WIP to Github as I don't think Paul would take a Pull request until current IDE is released...

Start of hacked up test program (from mouse only... Currently has mouse and joystick...)

Code:
// Simple test of USB Host Mouse
//
// This example is in the public domain
//
// Information on this driver can be found in mouse.cpp
// and USBHost_t36.h.
// It is an initial attempt.
//
#include "USBHost_t36.h"

USBHost myusb;
USBHub hub1(myusb);
USBHub hub2(myusb);
USBHub hub3(myusb);

MouseController mouse1(myusb);
JoystickController joystick1(myusb);
bool mouse_connected = false;
bool joystick_connected = false; 

void setup()
{
  while (!Serial) ; // wait for Arduino Serial Monitor
  Serial.println("USB Host Mouse Testing");
  myusb.begin();
}

void loop()
{
  myusb.Task();

  // See if a mouse is now connected?
  bool mouse_currently_connected = mouse1.connected();
  if (mouse_currently_connected != mouse_connected) {
    mouse_connected = mouse_currently_connected;
    if (mouse_connected) {
      Serial.println("\n\n*** Mouse Connected ***");
      mouse1.printDeviceInfo();
    } else {
      Serial.println("\n\n*** Mouse Disconnected ***");
    }
  }

  bool joystick_currently_connected = joystick1.connected();
  if (joystick_currently_connected != joystick_connected) {
    joystick_connected = joystick_currently_connected;
    if (joystick_connected) {
      Serial.println("\n\n*** joystick Connected ***");
      joystick1.printDeviceInfo();
    } else {
      Serial.println("\n\n*** joystick Disconnected ***");
    }
  }

  if (mouse1.available()) {
    Serial.print("buttons = ");
    Serial.print(mouse1.getButtons(), DEC);
    Serial.print(",  wheel = ");
    Serial.print(mouse1.getWheel(), DEC);
    Serial.print(",  mouseX = ");
    Serial.print(mouse1.getMouseX(), DEC);
    Serial.print(",  mouseY = ");
    Serial.println(mouse1.getMouseY(), DEC);
    mouse1.mouseDataClear();
  }
  if (joystick1.available()) {
    uint8_t count_axes = joystick1.countAxes();
    Serial.print("Joy buttons = ");
    Serial.print(joystick1.buttons(), DEC);

    for (uint8_t i = 0; i < count_axes; i++) {
      Serial.print(" ");
      Serial.print(joystick1.axes(i), DEC);
    }
    Serial.println();
    joystick1.dataClear();
  }

  
  delay(5);
}
Some Debug output:
Code:
*** joystick Connected ***

Mouse Information
  Packet Size: 64
  Report: 1
  Buttons:  Bit offset:44 Bit Size:14
0 - X(10030):  Bit offset:8 Bit Size:8
1 - Y(10031):  Bit offset:16 Bit Size:8
2 - Z(10032):  Bit offset:24 Bit Size:8
3 - Rz(10035):  Bit offset:32 Bit Size:8
4 - Hat(10039):  Bit offset:40 Bit Size:4
5 - <user>(20):  Bit offset:58 Bit Size:6
6 - Rx(10033):  Bit offset:64 Bit Size:8
7 - Ry(10034):  Bit offset:72 Bit Size:8
8 - <user>(21):  Bit offset:80 Bit Size:8
9 - <user>(0):  Bit offset:88 Bit Size:8
10 - <user>(0):  Bit offset:96 Bit Size:8
11 - <user>(0):  Bit offset:104 Bit Size:8
12 - <user>(0):  Bit offset:112 Bit Size:8
13 - <user>(0):  Bit offset:120 Bit Size:8
14 - <user>(0):  Bit offset:128 Bit Size:8
15 - <user>(0):  Bit offset:136 Bit Size:8
Joy buttons = 8 126 123 126 127 8 0 0 0 78 95 13 27 0 4 0 2
Joy buttons = 8 126 122 126 127 8 8 0 0 95 223 14 27 0 5 0 2
Joy buttons = 8 126 122 126 127 8 12 0 0 76 226 14 29 0 5 0 1
Joy buttons = 8 126 123 126 127 8 16 0 0 57 229 14 27 0 3 0 1
Joy buttons = 8 126 123 126 127 8 20 0 0 39 232 14 23 0 4 0 4
Joy buttons = 8 126 123 126 127 8 28 0 0 2 238 14 29 0 5 0 1
Joy buttons = 8 126 123 126 127 8 32 0 0 239 240 14 27 0 7 0 2
Joy buttons = 8 126 122 126 127 8 36 0 0 220 243 14 28 0 5 0 5
Joy buttons = 8 126 122 126 127 8 44 0 0 183 249 14 25 0 4 0 2
Joy buttons = 8 126 123 126 127 8 48 0 0 164 252 14 28 0 5 0 4
Joy buttons = 8 126 123 126 127 8 52 0 0 146 255 14 28 0 5 0 4
Joy buttons = 8 126 123 126 127 8 56 0 0 127 2 14 26 0 5 0 3
Joy buttons = 8 126 123 126 127 8 64 0 0 90 8 14 29 0 4 0 3
Joy buttons = 8 126 122 126 127 8 68 0 0 71 11 14 27 0 4 0 3
Joy buttons = 8 126 123 126 127 8 72 0 0 53 14 14 27 0 5 0 3
Joy buttons = 8 126 123 126 127 8 76 0 0 34 17 14 27 0
Again WIP Buttons should be 8 not 8... encoding of other data... Also the joysticks should probably be signed... Will fix tomorrow or the next day...

--------------------------------------------

Also wondering about how all of these classes should work for user to get the new data...

That is currently the Keyboard class, has the user attach functions: attachPress() and attachRelease()... With function pointers.

Currently Mouse and Joystick are setup are Polled. Do you have data for me... If so ask for it...

Wondering if all of these should optionally transition over to using Events?
 
Quick update: I think I have the PS4 joystick (plugged into USB host) working pretty well. I reworked the code to extract the fields when they are off byte boundaries. Also now look for logical Min/Max values for field(s) to deduce that the field is signed or not. At some point soon may try to merge some of this code with the Mouse code base. Updated github if anyone wants to try with PS4 or other USB joystick (please)

Maybe generate a HIDUSB sub class that both derive from...

I tried plugging in a PS3 controller, but it is not Liking it: I believe it has to due with the order of the ENDPOINTS in the descriptions:
For example if you look at a hex dump of the data passed to the claim function for PS4 and PS3 you see:
Code:
        00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
PS4: 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 E3 01 07 05 84 03 40 00 05 07 05 03 03 40 00 05 
PS3: 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 94 00 07 05 02 03 40 00 01 07 05 81 03 40 00 01 
         |                                        |                                        |                               |
Swapped the end points
PS3: 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 94 00 07 05 81 03 40 00 01 07 05 02 03 40 00 01
The two end points are starting at bytes 18 and 25. The code verifies that byte 19 is a 5 (end point) and that byte 20 has the high bit set to mark it as input... Which PS4 does PS3 does not.
But if you look where I swapped the end points in the data than it would...

So will see what happens if I have the code check both end points and work off of them...
 
Kurt, been busy - would like to run all my mice for you. If you could open an SD file and save WHATEVER you want to a file for each device I could carry my Teensy around on a battery pack plug it in and plug each mouse or whatever I find? How about an Xbox controller?

Then I could return to my PC and zip the files and upload without as much cut and paste overhead and error and not have to drag out all the mice from where they sit at various workstations.

Offhand my K66 Proto doesn't show me battery terminal to run RTC - but with USB battery the MILLIS would stay increasing. I could plug in a keyboard between mice and supply a text name for each device and the USB data could be ordered by timestamp.
 
Hi defragster... Yes I should try an xbox plugged in and see if it works...
Will see about setting up other test that stores results.

Right now still trying to figure out PS3... I figured out that I think I need to use the 2nd end point as that one has the 0x80 bit set for which endpoint. So I use that and try to then base everything else off of using data out of that end point and not the first...

I have the code then read in the HID description report and parse it... I think I have it understanding the data, from the trace. (USB print data...)...

But then the last thing we do is set idle, which fails. And I am not getting anything back... Still investigating.

But my Up2 kickstarter board arrived today :D

Code:
JoystickController claim descriptors
  : 09 04 00 00 02 03 00 00 00 09 21 11 01 00 01 22 94 00 07 05 02 03 40 00 01 07 05 81 03 40 00 01 
ep(joystick) = 1
Joystick Parse HID Descriptor: Size:148
05 01 09 04 A1 01 A1 02 85 01 75 08 95 01 15 00 26 FF 00 81 03 75 01 95 13 15 00 25 01 35 00 45 01 05 09 19 01 29 13 81 02 75 01 95 0D 06 00 FF 81 03 15 00 26 FF 00 05 01 09 01 A1 00 75 08 95 04 35 00 46 FF 00 09 30 09 31 09 32 09 35 81 02 C0 05 01 75 08 95 27 09 01 81 02 75 08 95 30 09 01 91 02 75 08 95 30 09 01 B1 02 C0 A1 02 85 02 75 08 95 30 09 01 B1 02 C0 A1 02 85 EE 75 08 95 30 09 01 B1 02 C0 A1 02 85 EF 75 08 95 30 09 01 B1 02 C0 C0 
  Collection: Application
    Collection: Logical
      Report ID: 1 0  *** Main Report ***
      Report size: 8
      Report count: 1
      Logical Min: 0
      Logical Max: FF
      Input: Constant Variable 2B
      Report size: 1
      Report count: 13
      Logical Min: 0
      Logical Max: 1
      Other:35 0
      Other:45 1
      Usage page: 9
      Other:19 1
      Other:29 13
      Input: Variable 2A
      ### Button: 16 1
      Report size: 1
      Report count: D
      Usage page: FF00
      Input: Constant Variable 2B
      Logical Min: 0
      Logical Max: FF
      Usage page: 1
      Usage: 1 +
      Collection: Physical
        Report size: 8
        Report count: 4
        Other:35 0
        Other:46 FF
        Usage: 30 +
        Usage: 31 +
        Usage: 32 +
        Usage: 35 +
        Input: Variable 2A
        0 - #X(10030): 48 8
        1 - #Y(10031): 56 8
        2 - #Z(10032): 64 8
        3 - #Rz(10035): 72 8
        End Collection
      Usage page: 1
      Report size: 8
      Report count: 27
      Usage: 1 +
      Input: Variable 2A
      4 - #<user>(10001): 80 8
      5 - #<user>(10000): 88 8
      6 - #<user>(10000): 96 8
      7 - #<user>(10000): 104 8
      8 - #<user>(10000): 112 8
      9 - #<user>(10000): 120 8
      10 - #<user>(10000): 128 8
      11 - #<user>(10000): 136 8
      12 - #<user>(10000): 144 8
      13 - #<user>(10000): 152 8
      14 - #<user>(10000): 160 8
      15 - #<user>(10000): 168 8
      Report size: 8
      Report count: 30
      Usage: 1 +
      Other:91 2
      Report size: 8
      Report count: 30
      Usage: 1 +
      Other:B1 2
      End Collection
    Collection: Logical
      Report ID: 2 --- Secondary ---
      Report size: 8
      Report count: 30
      Usage: 1 -
      Other:B1 2
      End Collection
    Collection: Logical
      Report ID: EE --- Secondary ---
      Report size: 8
      Report count: 30
      Usage: 1 -
      Other:B1 2
      End Collection
    Collection: Logical
      Report ID: EF --- Secondary ---
      Report size: 8
      Report count: 30
      Usage: 1 -
      Other:B1 2
      End Collection
    End Collection
packet size(Joystick) = 64
polling interval = 1
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 5
, at offset = 0, shift= 0
add_qh_to_periodic_schedule:
  interval = 1
  offset =   0
  add to slot 0
  add to slot 1
  add to slot 2
  add to slot 3
  add to slot 4
  add to slot 5
  add to slot 6
  add to slot 7
  add to slot 8
  add to slot 9
  add to slot 10
  add to slot 11
  add to slot 12
  add to slot 13
  add to slot 14
  add to slot 15
  add to slot 16
  add to slot 17
  add to slot 18
  add to slot 19
  add to slot 20
  add to slot 21
  add to slot 22
  add to slot 23
  add to slot 24
  add to slot 25
  add to slot 26
  add to slot 27
  add to slot 28
  add to slot 29
  add to slot 30
  add to slot 31
Periodic Schedule:
 0: 1FFF2C00
 1: 1FFF2C00
 2: 1FFF2C00
 3: 1FFF2C00
 4: 1FFF2C00
 5: 1FFF2C00
 6: 1FFF2C00
 7: 1FFF2C00
 8: 1FFF2C00
 9: 1FFF2C00
10: 1FFF2C00
11: 1FFF2C00
12: 1FFF2C00
13: 1FFF2C00
14: 1FFF2C00
15: 1FFF2C00
16: 1FFF2C00
17: 1FFF2C00
18: 1FFF2C00
19: 1FFF2C00
20: 1FFF2C00
21: 1FFF2C00
22: 1FFF2C00
23: 1FFF2C00
24: 1FFF2C00
25: 1FFF2C00
26: 1FFF2C00
27: 1FFF2C00
28: 1FFF2C00
29: 1FFF2C00
30: 1FFF2C00
31: 1FFF2C00
new_Data_Transfer
new_Control_Transfer
************** Joystick Claim Connected ******************
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
Descriptor 5 = ENDPOINT
  Followup 1FFF3500    token=80000200
  Followup 1FFF2DA0    token=80008180
[COLOR="#FF0000"]
ISR: 4C08B
 USB Error
 USB Async
Async Followup
  Followup 1FFF2DA0    token=80008140
JoystickController control (static)
1FFF2A40
  Setup: A21 0 0 0
ERROR Followup
[/COLOR]

*** joystick Connected ***

Joystick Information
  Packet Size: 64
  Report: 1
  Buttons:  Bit offset:16 Bit Size:19
0 - X(10030):  Bit offset:48 Bit Size:8
1 - Y(10031):  Bit offset:56 Bit Size:8
2 - Z(10032):  Bit offset:64 Bit Size:8
3 - Rz(10035):  Bit offset:72 Bit Size:8
4 - <user>(10001):  Bit offset:80 Bit Size:8
5 - <user>(10000):  Bit offset:88 Bit Size:8
6 - <user>(10000):  Bit offset:96 Bit Size:8
7 - <user>(10000):  Bit offset:104 Bit Size:8
8 - <user>(10000):  Bit offset:112 Bit Size:8
9 - <user>(10000):  Bit offset:120 Bit Size:8
10 - <user>(10000):  Bit offset:128 Bit Size:8
11 - <user>(10000):  Bit offset:136 Bit Size:8
12 - <user>(10000):  Bit offset:144 Bit Size:8
13 - <user>(10000):  Bit offset:152 Bit Size:8
14 - <user>(10000):  Bit offset:160 Bit Size:8
15 - <user>(10000):  Bit offset:168 Bit Size:8
 
This morning for the fun of it I tried plugging in an XBOX one controller into my USB Host to see if the USB Joystick hid code would work...

Turns out the XBox one is not a HID setup... So currently the joystick code does not try to claim it...
Here is an edited output showing the descriptors passed into the claim code.
Code:
USBHub claim_device this=1FFF2020
JoystickController claim this=1FFF2A40
JoystickController claim descriptors
  : 09 04 00 00 02 FF 47 D0 00 07 05 02 03 40 00 04 07 05 82 03 40 00 04 09 04 01 00 00 FF 47 D0 00 
  : 09 04 01 01 02 FF 47 D0 00 07 05 03 01 E4 00 01 07 05 83 01 40 00 01 09 04 02 00 00 FF 47 D0 00 
  : 09 04 02 01 02 FF 47 D0 00 07 05 04 02 40 00 00 07 05 84 02 40 00 00
Code checks byte index 5 for value 3 (HID) and in this case they are 0xFF so no match.

To verify this I plugged it into my UP board with Linux and tried to do HID dump and the like which fails.
Here is some of DMESG and lsusb output
Code:
[   99.745378] usb 1-3: USB disconnect, device number 6
[  202.033842] usb 1-3: new full-speed USB device number 7 using xhci_hcd
[  202.163342] usb 1-3: New USB device found, idVendor=045e, idProduct=02ea
[  202.163356] usb 1-3: New USB device strings: Mfr=1, Product=2, SerialNumber=3
[  202.163364] usb 1-3: Product: Controller
[  202.163372] usb 1-3: Manufacturer: Microsoft
[  202.163379] usb 1-3: SerialNumber: 3033363030303332393035363234
[  202.165003] input: Generic X-Box pad as /devices/pci0000:00/0000:00:14.0/usb1/1-3/1-3:1.0/input/input5

kurt@kurt-UP-CHT01:~$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 0424:2530 Standard Microsystems Corp.
Bus 001 Device 004: ID 0bda:8178 Realtek Semiconductor Corp. RTL8192CU 802.11n WLAN Adapter
Bus 001 Device 003: ID 0424:4603 Standard Microsystems Corp.
Bus 001 Device 007: ID 045e:02ea Microsoft Corp.
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

kurt@kurt-UP-CHT01:~$ sudo usbhid-dump
No matching HID interfaces

kurt@kurt-UP-CHT01:~$ ls /dev/input
by-id  by-path  event0  event1  event2  event3  event4  js0  mice
So not HID, but still creates Joystick...
 
I decided to upload the WIP to Github as I don't think Paul would take a Pull request until current IDE is released...

Start of hacked up test program (from mouse only... Currently has mouse and joystick...)

Sorry, I really should have looked at this earlier. I'm only just now getting to it, after releasing 1.39.

I probably should have explained how I'd planned to address the "rabbit hole". I see you've started going down the path of deferring the interface claim, until the extra descriptor can be read. That's not the way I want to approach this. I really should have written an explanation days ago before you started this work... but only just now getting the time.

The long-term solution I'd like to see involves a special HID driver which always unconditionally claims any interface with bInterfaceClass = 3, unless of course one of the other drivers has claimed it first because it had bInterfaceSubClass = 1. The idea is a tricky mix of C++ object-scope functionality for each HID interface claimed, and static scope functionality with linked lists of active drivers where it's sending the HID events. Did I mention this is a deep rabbit hole?

Also wondering about how all of these classes should work for user to get the new data...

That is currently the Keyboard class, has the user attach functions: attachPress() and attachRelease()... With function pointers.

Currently Mouse and Joystick are setup are Polled. Do you have data for me... If so ask for it...

Wondering if all of these should optionally transition over to using Events?

Yes, my long-term goal is for all of this stuff to use (still experimental) EventResponder. In fact, that's the main reason I paused on USB host. Well, that and writing the EHCI driver was pretty exhausting. I'm still not looking forward to someday adding isochronous pipe support.

This HID stuff was something I kinda swept under the rug, kinda hoping boot protocol devices would be good enough for a while. That's probably true for keyboards, but mice and joysticks & gamepads vary way too much.
 
Thanks Paul,

I think I have been slowly converging over to a common driver for Joystick and Mouse and ???. I already figured and sort of mentioned, that I thought the two drivers (Mouse and Joystick) could converge as most of the code is the same. The mouse is sort of a sub-set...

I have not played much with the keyboard stuff, but with the mouse quickly decided the boot information was probably not enough as I saw several mice that all said they reported 8 bytes back, but they all had different formats. Some had a report ID, others did not. Some reported 8 bit values some 12 bit, and some 16 bit for X, Y...

As you mentioned, very deep Rabbit Hole! Was just still trying to figure out why the PS3 errors out... Still need to learn more about USB errors and the like. Also need to learn things like:
the PS3: has two end points, 1 is input and the other output? When do you use them? the PS4 also has two, but the input and output ones are reversed in order...

As I sort of deduced, it seemed to be logical to convert all of this to use the EventResponder.

So the question is, does my experimentation and prototyping here help, or would you rather have the fun?

Edit: Also with the HID, at times wondering how much of the information to keep and use.
Example: Should we keep the logical Min/Max values? Likewise should we keep the Physical Min/Max values and then do the conversions?
 
I've got your parseHIDDescriptor code on my screen right now. Let me play with this for a couple days....

Some of the seldom used HID stuff like physical units, long format items, push/pop may never get implemented.
 
Sounds good... Note: the joystick parse code is probably in better state than the mouse one currently...

Also I punted so far on things like multiple reports, I assume first one. And not really sure how to properly handle collections...

So I will play with some other things for now.
 
Here's the HID report descriptors from all the non-keyboard devices I have here for testing.

Coda (small/cheap) mouse:
05 01 09 02 A1 01 05 09 19 01 29 03 15 00 25 01 95 03 75 01 81 02 95 01 75 05 81 03 05 01 09 01 A1 00 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 C0 C0

Apple Mighty Mouse:
05 01 09 02 A1 01 05 09 19 01 29 04 15 00 25 01 95 04 75 01 81 02 95 01 75 04 81 01 05 01 09 01 A1 00 09 30 09 31 09 32 09 38 15 81 25 7F 75 08 95 04 81 06 C0 05 FF 09 C0 75 08 95 01 81 02 C0

Logitech Wireless Trackball, interface #0 (keyboard)
05 01 09 06 A1 01 95 08 75 01 15 00 25 01 05 07 19 E0 29 E7 81 02 81 03 95 05 05 08 19 01 29 05 91 02 95 01 75 03 91 01 95 06 75 08 15 00 26 FF 00 05 07 19 00 2A FF 00 81 00 C0

Logitech Wireless Trackball, interface #1 (mouse)
05 01 09 02 A1 01 85 02 09 01 A1 00 95 10 75 01 15 00 25 01 05 09 19 01 29 10 81 02 95 02 75 0C 16 01 F8 26 FF 07 05 01 09 30 09 31 81 06 95 01 75 08 15 81 25 7F 09 38 81 06 95 01 05 0C 0A 38 02 81 06 C0 C0 05 0C 09 01 A1 01 85 03 95 02 75 10 15 01 26 FF 02 19 01 2A FF 02 81 00 C0 05 01 09 80 A1 01 85 04 95 01 75 02 15 01 25 03 09 82 09 81 09 83 81 00 75 06 81 03 C0 06 BC FF 09 88 A1 01 85 08 95 01 75 08 15 01 26 FF 00 19 01 29 FF 81 00 C0

Logitech Wireless Trackball, interface #2 (unknown)
06 00 FF 09 01 A1 01 85 10 95 06 75 08 15 00 26 FF 00 09 01 81 00 09 01 91 00 C0 06 00 FF 09 02 A1 01 85 11 95 13 75 08 15 00 26 FF 00 09 02 81 00 09 02 91 00 C0 06 00 FF 09 04 A1 01 85 20 95 0E 75 08 15 00 26 FF 00 09 41 81 00 09 41 91 00 85 21 95 1F 09 42 81 00 09 42 91 00 C0

Microsoft Intellimouse
05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 05 15 00 25 01 75 01 95 05 81 02 75 03 95 01 81 01 05 01 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 C0 05 FF 09 02 15 00 25 01 75 01 95 01 B1 22 75 07 95 01 B1 01 C0

Logitech M100
05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 03 15 00 25 01 95 08 75 01 81 02 05 01 09 30 09 31 09 38 15 81 25 7F 75 08 95 03 81 06 C0 C0

Logitech M-U0007
05 01 09 02 A1 01 09 01 A1 00 05 09 19 01 29 08 15 00 25 01 95 08 75 01 81 02 95 00 81 03 05 01 09 30 09 31 16 01 F8 26 FF 07 75 0C 95 02 81 06 09 38 15 81 25 7F 75 08 95 01 81 06 05 0C 0A 38 02 95 01 81 06 C0 C0

Sony Dualshock3 Sixaxis (gamepad):
05 01 09 04 A1 01 A1 02 85 01 75 08 95 01 15 00 26 FF 00 81 03 75 01 95 13 15 00 25 01 35 00 45 01 05 09 19 01 29 13 81 02 75 01 95 0D 06 00 FF 81 03 15 00 26 FF 00 05 01 09 01 A1 00 75 08 95 04 35 00 46 FF 00 09 30 09 31 09 32 09 35 81 02 C0 05 01 75 08 95 27 09 01 81 02 75 08 95 30 09 01 91 02 75 08 95 30 09 01 B1 02 C0 A1 02 85 02 75 08 95 30 09 01 B1 02 C0 A1 02 85 EE 75 08 95 30 09 01 B1 02 C0 A1 02 85 EF 75 08 95 30 09 01 B1 02 C0 C0
 
Looks good, I have a few of the same ones as I mentioned throughout the thread. Also have for example Sony DualShock 4:
Code:
001:006:000:DESCRIPTOR         1504880944.787596
 05 01 09 05 A1 01 85 01 09 30 09 31 09 32 09 35 
 15 00 26 FF 00 75 08 95 04 81 02 09 39 15 00 25
 07 35 00 46 3B 01 65 14 75 04 95 01 81 42 65 00
 05 09 19 01 29 0E 15 00 25 01 75 01 95 0E 81 02
 06 00 FF 09 20 75 06 95 01 15 00 25 7F 81 02 05
 01 09 33 09 34 15 00 26 FF 00 75 08 95 02 81 02
 06 00 FF 09 21 95 36 81 02 85 05 09 22 95 1F 91
 02 85 04 09 23 95 24 B1 02 85 02 09 24 95 24 B1
 02 85 08 09 25 95 03 B1 02 85 10 09 26 95 04 B1
 02 85 11 09 27 95 02 B1 02 85 12 06 02 FF 09 21
 95 0F B1 02 85 13 09 22 95 16 B1 02 85 14 06 05
 FF 09 20 95 10 B1 02 85 15 09 21 95 2C B1 02 06
 80 FF 85 80 09 20 95 06 B1 02 85 81 09 21 95 06
 B1 02 85 82 09 22 95 05 B1 02 85 83 09 23 95 01
 B1 02 85 84 09 24 95 04 B1 02 85 85 09 25 95 06
 B1 02 85 86 09 26 95 06 B1 02 85 87 09 27 95 23
 B1 02 85 88 09 28 95 22 B1 02 85 89 09 29 95 02
 B1 02 85 90 09 30 95 05 B1 02 85 91 09 31 95 03
 B1 02 85 92 09 32 95 03 B1 02 85 93 09 33 95 0C
 B1 02 85 A0 09 40 95 06 B1 02 85 A1 09 41 95 01
 B1 02 85 A2 09 42 95 01 B1 02 85 A3 09 43 95 30
 B1 02 85 A4 09 44 95 0D B1 02 85 A5 09 45 95 15
 B1 02 85 A6 09 46 95 15 B1 02 85 F0 09 47 95 3F
 B1 02 85 F1 09 48 95 3F B1 02 85 F2 09 49 95 0F
 B1 02 85 A7 09 4A 95 01 B1 02 85 A8 09 4B 95 01
 B1 02 85 A9 09 4C 95 08 B1 02 85 AA 09 4E 95 01
 B1 02 85 AB 09 4F 95 39 B1 02 85 AC 09 50 95 39
 B1 02 85 AD 09 51 95 0B B1 02 85 AE 09 52 95 01
 B1 02 85 AF 09 53 95 02 B1 02 85 B0 09 54 95 3F
 B1 02 85 B1 09 55 95 02 B1 02 85 B2 09 56 95 02
 B1 02 C0

And it helps me to use the linux tools to visually see what all of this is:
Code:
kurt@kurt-UP-CHT01:~$ sudo usbhid-dump  -i0 | grep -v : | xxd -r -p | hidrd-convert -o spec
Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Gamepad),                    ; Gamepad (05h, application collection)
Collection (Application),
    Report ID (1),
    Usage (X),                      ; X (30h, dynamic value)
    Usage (Y),                      ; Y (31h, dynamic value)
    Usage (Z),                      ; Z (32h, dynamic value)
    Usage (Rz),                     ; Rz (35h, dynamic value)
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (4),
    Input (Variable),
    Usage (Hat Switch),             ; Hat switch (39h, dynamic value)
    Logical Minimum (0),
    Logical Maximum (7),
    Physical Minimum (0),
    Physical Maximum (315),
    Unit (Degrees),
    Report Size (4),
    Report Count (1),
    Input (Variable, Null State),
    Unit,
    Usage Page (Button),            ; Button (09h)
    Usage Minimum (01h),
    Usage Maximum (0Eh),
    Logical Minimum (0),
    Logical Maximum (1),
    Report Size (1),
    Report Count (14),
    Input (Variable),
    Usage Page (FF00h),             ; FF00h, vendor-defined
    Usage (20h),
    Report Size (6),
    Report Count (1),
    Logical Minimum (0),
    Logical Maximum (127),
    Input (Variable),
    Usage Page (Desktop),           ; Generic desktop controls (01h)
    Usage (Rx),                     ; Rx (33h, dynamic value)
    Usage (Ry),                     ; Ry (34h, dynamic value)
    Logical Minimum (0),
    Logical Maximum (255),
    Report Size (8),
    Report Count (2),
    Input (Variable),
    Usage Page (FF00h),             ; FF00h, vendor-defined
    Usage (21h),
    Report Count (54),
    Input (Variable),
   [COLOR="#FF0000"] Report ID (5),[/COLOR]
    Usage (22h),
    Report Count (31),
    Output (Variable),
    [COLOR="#FF0000"]Report ID (4),[/COLOR]
    Usage (23h),
    Report Count (36),
    Feature (Variable),
   [COLOR="#FF0000"] Report ID (2),[/COLOR]
    Usage (24h),
    Report Count (36),
    Feature (Variable),
   [COLOR="#FF0000"] Report ID (8),[/COLOR]
    Usage (25h),
    Report Count (3),
    Feature (Variable),
    Report ID (16),
    Usage (26h),
    Report Count (4),
    Feature (Variable),
    Report ID (17),
    Usage (27h),
    Report Count (2),
    Feature (Variable),
    Report ID (18),
    Usage Page (FF02h),             ; FF02h, vendor-defined
    Usage (21h),
    Report Count (15),
    Feature (Variable),
    Report ID (19),
    Usage (22h),
    Report Count (22),
    Feature (Variable),
    Report ID (20),
    Usage Page (FF05h),             ; FF05h, vendor-defined
    Usage (20h),
    Report Count (16),
    Feature (Variable),
    Report ID (21),
    Usage (21h),
    Report Count (44),
    Feature (Variable),
    Usage Page (FF80h),             ; FF80h, vendor-defined
    Report ID (128),
    Usage (20h),
    Report Count (6),
    Feature (Variable),
    Report ID (129),
    Usage (21h),
    Report Count (6),
    Feature (Variable),
    Report ID (130),
    Usage (22h),
    Report Count (5),
    Feature (Variable),
    Report ID (131),
    Usage (23h),
    Report Count (1),
    Feature (Variable),
    Report ID (132),
    Usage (24h),
    Report Count (4),
    Feature (Variable),
    Report ID (133),
    Usage (25h),
    Report Count (6),
    Feature (Variable),
    Report ID (134),
    Usage (26h),
    Report Count (6),
    Feature (Variable),
    Report ID (135),
    Usage (27h),
    Report Count (35),
    Feature (Variable),
    Report ID (136),
    Usage (28h),
    Report Count (34),
    Feature (Variable),
    Report ID (137),
    Usage (29h),
    Report Count (2),
    Feature (Variable),
    Report ID (144),
    Usage (30h),
    Report Count (5),
    Feature (Variable),
    Report ID (145),
    Usage (31h),
    Report Count (3),
    Feature (Variable),
    Report ID (146),
    Usage (32h),
    Report Count (3),
    Feature (Variable),
    Report ID (147),
    Usage (33h),
    Report Count (12),
    Feature (Variable),
    Report ID (160),
    Usage (40h),
    Report Count (6),
    Feature (Variable),
    Report ID (161),
    Usage (41h),
    Report Count (1),
    Feature (Variable),
    Report ID (162),
    Usage (42h),
    Report Count (1),
    Feature (Variable),
    Report ID (163),
    Usage (43h),
    Report Count (48),
    Feature (Variable),
    Report ID (164),
    Usage (44h),
    Report Count (13),
    Feature (Variable),
    Report ID (165),
    Usage (45h),
    Report Count (21),
    Feature (Variable),
    Report ID (166),
    Usage (46h),
    Report Count (21),
    Feature (Variable),
    Report ID (240),
    Usage (47h),
    Report Count (63),
    Feature (Variable),
    Report ID (241),
    Usage (48h),
    Report Count (63),
    Feature (Variable),
    Report ID (242),
    Usage (49h),
    Report Count (15),
    Feature (Variable),
    Report ID (167),
    Usage (4Ah),
    Report Count (1),
    Feature (Variable),
    Report ID (168),
    Usage (4Bh),
    Report Count (1),
    Feature (Variable),
    Report ID (169),
    Usage (4Ch),
    Report Count (8),
    Feature (Variable),
    Report ID (170),
    Usage (4Eh),
    Report Count (1),
    Feature (Variable),
    Report ID (171),
    Usage (4Fh),
    Report Count (57),
    Feature (Variable),
    Report ID (172),
    Usage (50h),
    Report Count (57),
    Feature (Variable),
    Report ID (173),
    Usage (51h),
    Report Count (11),
    Feature (Variable),
    Report ID (174),
    Usage (52h),
    Report Count (1),
    Feature (Variable),
    Report ID (175),
    Usage (53h),
    Report Count (2),
    Feature (Variable),
    Report ID (176),
    Usage (54h),
    Report Count (63),
    Feature (Variable),
    Report ID (177),
    Usage (55h),
    Report Count (2),
    Feature (Variable),
    Report ID (178),
    Usage (56h),
    Report Count (2),
    Feature (Variable),
End Collection
kurt@kurt-UP-CHT01:~$
Which my debug code sort of outputs a subset of this...
Note: I highlighted in RED in the above where it appears like it generates multiple different reports... I stopped marking after the first few... Currently the code ignores data for reports that don't match the first one... But for some devices may need multiple? That is currently my Mouse version handles the Teensy as Mouse, again only for the first report, but I think using a teensy for mouse, there is a 2nd usage, where you can set absolute position and it probably outputs report 2...

As I mentioned earlier the Microsoft wireless one I have, is a little more complicated as it looks like it intermixed stuff from multiple reports. That is is started the main report, went into some form of collection, output some other report and then went back to the first report to add more fields.

So for the fun of it I took your wireless trackball data saved to a file on my linux machine (up board) and then used the hiddump with it...
Code:
kurt@kurt-UP-CHT01:~$ vi foo
kurt@kurt-UP-CHT01:~$ cat foo |  xxd -r -p | hidrd-convert -o spec                          Usage Page (Desktop),                   ; Generic desktop controls (01h)
Usage (Mouse),                          ; Mouse (02h, application collection)
Collection (Application),
    Report ID (2),
    Usage (Pointer),                    ; Pointer (01h, physical collection)
    Collection (Physical),
        Report Count (16),
        Report Size (1),
        Logical Minimum (0),
        Logical Maximum (1),
        Usage Page (Button),            ; Button (09h)
        Usage Minimum (01h),
        Usage Maximum (10h),
        Input (Variable),
        Report Count (2),
        Report Size (12),
        Logical Minimum (-2047),
        Logical Maximum (2047),
        Usage Page (Desktop),           ; Generic desktop controls (01h)
        Usage (X),                      ; X (30h, dynamic value)
        Usage (Y),                      ; Y (31h, dynamic value)
        Input (Variable, Relative),
        Report Count (1),
        Report Size (8),
        Logical Minimum (-127),
        Logical Maximum (127),
        Usage (Wheel),                  ; Wheel (38h, dynamic value)
        Input (Variable, Relative),
        Report Count (1),
        Usage Page (Consumer),          ; Consumer (0Ch)
        Usage (AC Pan),                 ; AC pan (0238h, linear control)
        Input (Variable, Relative),
    End Collection,
End Collection,
Usage Page (Consumer),                  ; Consumer (0Ch)
Usage (Consumer Control),               ; Consumer control (01h, application collection)
Collection (Application),
    Report ID (3),
    Report Count (2),
    Report Size (16),
    Logical Minimum (1),
    Logical Maximum (767),
    Usage Minimum (Consumer Control),   ; Consumer control (01h, application collection)
    Usage Maximum (02FFh),
    Input,
End Collection,
Usage Page (Desktop),                   ; Generic desktop controls (01h)
Usage (Sys Control),                    ; System control (80h, application collection)
Collection (Application),
    Report ID (4),
    Report Count (1),
    Report Size (2),
    Logical Minimum (1),
    Logical Maximum (3),
    Usage (Sys Sleep),                  ; System sleep (82h, one-shot control)
    Usage (Sys Power Down),             ; System power down (81h, one-shot control)
    Usage (Sys Wake Up),                ; System wake up (83h, one-shot control)
    Input,
    Report Size (6),
    Input (Constant, Variable),
End Collection,
Usage Page (FFBCh),                     ; FFBCh, vendor-defined
Usage (88h),
Collection (Application),
    Report ID (8),
    Report Count (1),
    Report Size (8),
    Logical Minimum (1),
    Logical Maximum (255),
    Usage Minimum (01h),
    Usage Maximum (FFh),
    Input,
End Collection
kurt@kurt-UP-CHT01:~$
 
Found another device to test out. I have a Watcom Bamboo fun tablet.
Mouse descriptor:
Code:
 : 09 04 00 00 01 03 01 02 00 09 21 00 01 00 01 22 B0 00 07 05 81 03 09 00 04 09 04 01 00 01 03 00 00 00 09 21 00 01 00 01 22 4B 00 07 05 82 03 40 00 04

HID Report descriptor:
Code:
05 01 09 02 A1 01 85 01 09 01 A1 00 05 09 19 01 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31 15 81 25 7F 75 08 95 02 81 06 C0 C0 05 0D 09 01 A1 01 85 02 A1 00 06 00 FF 09 01 15 00 26 FF 00 75 08 95 08 81 02 C0 09 01 85 02 95 01 B1 02 09 01 85 03 95 01 B1 02 09 01 85 04 95 01 B1 02 09 01 85 05 95 01 B1 02 09 01 85 10 95 02 B1 02 09 01 85 11 95 10 B1 02 09 01 85 13 95 01 B1 02 09 01 85 20 95 01 B1 02 09 01 85 21 95 01 B1 02 09 01 85 06 95 01 B1 02 09 01 85 07 95 01 B1 02 09 01 85 14 95 01 B1 02 C0

Some of the debug decoding:
Code:
  Collection: Application
    Report ID: 1 0  *** Main Report ***
    Usage: 1 +
    Collection: Physical
      Usage page: 9
      Other:19 1
      Other:29 5
      Other:15 0
      Other:25 1
      Report count: 5
      Report size: 1
      Input: Variable 2
      ### Button: 8 1
      Report count: 1
      Report size: 3
      Input: Constant 1
      Usage page: 1
      Usage: 30 +
      Usage: 31 +
      Other:15 81
      Other:25 7F
      Report size: 8
      Report count: 2
      Input: Variable Relative 6
      ### X: 16 8
      ### Y: 24 8
      End Collection
    End Collection
  Usage page: D
  Usage: 1 +
  Collection: Application
    Report ID: 2 --- Secondary ---
    Collection: Physical
      Usage page: FF00
      Usage: 1 -
      Other:15 0
...
So looks pretty standard: Except it does not have wheel... (my current code will probably five bogus value here... Should probably init the offset to
something and check it when the user does a query for the data. Actually I do init to 0xff and assume that the X, Y, wheel and buttons will be within 256 bits of the report. Which for Mouse probably all reports will probably be less than 256/8= 32 bytes long so probably not an issue.

My info output shows:
Code:
Mouse Information
  Packet Size: 9
  Report: 1
  Buttons: Bit offset:8 Bit Size:8
  X: Bit offset:16 Bit Size:8 Relative 
  Y: Bit offset:24 Bit Size:8 Relative 
  Wheel: Bit offset:255 Bit Size:0
Edit:
Should mention looking at this device on Linux I see it creates two interfaces:
Code:
[CODE]kurt@kurt-UP-CHT01:~$ lsusb
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 005: ID 0424:2530 Standard Microsystems Corp.
Bus 001 Device 004: ID 0bda:8178 Realtek Semiconductor Corp. RTL8192CU 802.11n WLAN Adapter
Bus 001 Device 003: ID 0424:4603 Standard Microsystems Corp.
Bus 001 Device 007: ID 056a:00d8 Wacom Co., Ltd
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
kurt@kurt-UP-CHT01:~$ sudo usbhid-dump
001:007:001:DESCRIPTOR         1504887181.952739
 06 00 FF 09 01 A1 01 85 02 05 0D 09 22 A1 00 06
 00 FF 09 01 15 00 26 FF 00 75 08 95 02 81 02 05
 01 09 30 35 00 46 44 48 26 E4 02 75 10 95 01 81
 02 09 31 46 D4 30 26 F4 01 81 02 06 00 FF 09 01
 26 FF 00 75 08 95 0D 81 02 C0 C0

001:007:000:DESCRIPTOR         1504887181.956943
 05 01 09 02 A1 01 85 01 09 01 A1 00 05 09 19 01
 29 05 15 00 25 01 95 05 75 01 81 02 95 01 75 03
 81 01 05 01 09 30 09 31 15 81 25 7F 75 08 95 02
 81 06 C0 C0 05 0D 09 01 A1 01 85 02 A1 00 06 00
 FF 09 01 15 00 26 FF 00 75 08 95 08 81 02 C0 09
 01 85 02 95 01 B1 02 09 01 85 03 95 01 B1 02 09
 01 85 04 95 01 B1 02 09 01 85 05 95 01 B1 02 09
 01 85 10 95 02 B1 02 09 01 85 11 95 10 B1 02 09
 01 85 13 95 01 B1 02 09 01 85 20 95 01 B1 02 09
 01 85 21 95 01 B1 02 09 01 85 06 95 01 B1 02 09
 01 85 07 95 01 B1 02 09 01 85 14 95 01 B1 02 C0

kurt@kurt-UP-CHT01:~$ sudo usbhid-dump  -i0 | grep -v : | xxd -r -p | hidrd-convert -o spec
Usage Page (Desktop),               ; Generic desktop controls (01h)
Usage (Mouse),                      ; Mouse (02h, application collection)
Collection (Application),
    Report ID (1),
    Usage (Pointer),                ; Pointer (01h, physical collection)
    Collection (Physical),
        Usage Page (Button),        ; Button (09h)
        Usage Minimum (01h),
        Usage Maximum (05h),
        Logical Minimum (0),
        Logical Maximum (1),
        Report Count (5),
        Report Size (1),
        Input (Variable),
        Report Count (1),
        Report Size (3),
        Input (Constant),
        Usage Page (Desktop),       ; Generic desktop controls (01h)
        Usage (X),                  ; X (30h, dynamic value)
        Usage (Y),                  ; Y (31h, dynamic value)
        Logical Minimum (-127),
        Logical Maximum (127),
        Report Size (8),
        Report Count (2),
        Input (Variable, Relative),
    End Collection,
End Collection,
Usage Page (Digitizer),             ; Digitizer (0Dh)
Usage (Digitizer),                  ; Digitizer (01h, application collection)
Collection (Application),
    Report ID (2),
    Collection (Physical),
        Usage Page (FF00h),         ; FF00h, vendor-defined
        Usage (01h),
        Logical Minimum (0),
        Logical Maximum (255),
        Report Size (8),
        Report Count (8),
        Input (Variable),
    End Collection,
    Usage (01h),
    Report ID (2),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (3),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (4),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (5),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (16),
    Report Count (2),
    Feature (Variable),
    Usage (01h),
    Report ID (17),
    Report Count (16),
    Feature (Variable),
    Usage (01h),
    Report ID (19),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (32),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (33),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (6),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (7),
    Report Count (1),
    Feature (Variable),
    Usage (01h),
    Report ID (20),
    Report Count (1),
    Feature (Variable),
End Collection
kurt@kurt-UP-CHT01:~$ sudo usbhid-dump  -i1 | grep -v : | xxd -r -p | hidrd-convert -o spec Usage Page (FF00h),                 ; FF00h, vendor-defined
Usage (01h),
Collection (Application),
    Report ID (2),
    Usage Page (Digitizer),         ; Digitizer (0Dh)
    Usage (Finger),                 ; Finger (22h, logical collection)
    Collection (Physical),
        Usage Page (FF00h),         ; FF00h, vendor-defined
        Usage (01h),
        Logical Minimum (0),
        Logical Maximum (255),
        Report Size (8),
        Report Count (2),
        Input (Variable),
        Usage Page (Desktop),       ; Generic desktop controls (01h)
        Usage (X),                  ; X (30h, dynamic value)
        Physical Minimum (0),
        Physical Maximum (18500),
        Logical Maximum (740),
        Report Size (16),
        Report Count (1),
        Input (Variable),
        Usage (Y),                  ; Y (31h, dynamic value)
        Physical Maximum (12500),
        Logical Maximum (500),
        Input (Variable),
        Usage Page (FF00h),         ; FF00h, vendor-defined
        Usage (01h),
        Logical Maximum (255),
        Report Size (8),
        Report Count (13),
        Input (Variable),
    End Collection,
End Collection
kurt@kurt-UP-CHT01:~$
[/CODE]
 
Last edited:
I've been falling down the HID rabbit hole for the last few days. It is deep indeed.

My goal has been a single generic HID parser that lets the drivers claim top-level collections, and delivers the data as value/usage pairs. I think I'm getting pretty close, but today I'm starting to get a little concerned about performance. A callback for each item, and walking the report descriptor data every time might be too much overhead. Or maybe Teensy 3.6 is plenty fast enough? Haven't done benchmarking yet, and the code is still filled with tons of slow printing.

Going to commit this stuff to github today, so everyone can look at it. Kurt, your code was extremely helpful to get me started. I must admit, I've been kinda procrastinating even starting to work in this HID parser stuff.
 
Sounds great!

Will look for it later today, to see what all you have done.

The HID stuff is interesting. It will be fun to see how to use it, especially with some different devices.

Example the Watcom tablet has two Interfaces.
The first one acts like mouse and the second a digitizer.

It will also be interesting to see how your value usage pairs work, That is for a mouse would I ask for
something like: 0x10030 to get the X value for the mouse, 0x10031 for Y and 0x90000 for Buttons....

If so and worried about performance, might want to introduce some shortcuts, where I can ask for index for some key and then have extract by index...

Also any luck with PS3?
 
Example the Watcom tablet has two Interfaces.
The first one acts like mouse and the second a digitizer.

Yup. The HID drivers in Windows and Linux allow top level collections to appear as if they were separate devices. That's why I tried to do something similar, allowing drivers to claim only a part of the report based on the top level collections.

Also any luck with PS3?

Nope. Looks like it's triggering a bug deep within the EHCI or periodic bandwidth scheduling code. :(
 
Do you have a test app with the current stuff?

Will tryout the different stuff I have.

Also trying to figure out XBox one, but I am still learning stuff, like how to send it a command... I believe you need to send it a command to tell it to go into sending reports with buttons and axes... One source on this (https://github.com/JRHeaton/XboxOneControllerDev) ... There was another with conflicting commands...
Mine is a XBox one S controller so the PID is 0x2ea and not 0x2d1...

With PS3 - I believe I read that you also need to tell the PS3 to start sending Report 1 to get it to work...
I think the command bytes is:
Code:
static const uint8_t ps3_feature_F4_report[]  = {0x42, 0x0c, 0x00, 0x00};

I tried a few different things like:
Code:
	if ((dev->idVendor == 0x54c) && (dev->idProduct == 0x268)) {
		println("*** Sony PS3");
		mk_setup(setup, 0x21, 9, 0x3f4, 0, 4); // ps3 tell it to send report 1?
		print_hexbytes((uint8_t*)&setup, 8);
		queue_Control_Transfer(dev, &setup, (void*)ps3_feature_F4_report, this);		
	}
But that appears to crash the USB, so probably wrong...

Will look more at your stuff to see if you have stuff that sends out command data like this...
 
Great,

I just synced up. Now trying with my mice, let me know if you want more details on each device... I think I have most of the information in previous posts.

Belkin wired - Appears to work

Dell wired - Appears to work, but shows WheelH, but I am not seeing any mouse H data coming out

HP wired - Like Dell. (fewer buttons)

Logitech wireless combo - appears to work - again not sure about wheelH

Microsoft wireless combo - works and I gett wheelH :D

Wacom Bambo tablet - appears to have issues. It worked once I think, but tried again and hangs... Also appears to hang USB...

Teensy 3.2 with Mouse triangle move - does not output...

Also maybe having some init issues (maybe some race condition). That sometimes if I reset the Teensy, the mouse does not work. It may work again if I unplug it and plug it back in... Maybe time to turn debug back on...
 
Wacom Bambo:
Debug info:
Code:
USB Host Testing
sizeof Device = 32
sizeof Pipe = 96
sizeof Transfer = 64
power up USBHS PHY

ISR: 408C
 Port Change
port change: 10001803
    connect

ISR: 4084
 Port Change
port change: 1C001002
    disconnect

ISR: 1004088
 Timer0

ISR: 408C
 Port Change
port change: 10001803
    connect

ISR: 4084
 Port Change
port change: 1C001002
    disconnect

ISR: 1004088
 Timer0

ISR: 408C
 Port Change
port change: 10001803
    connect

ISR: 4084
 Port Change
port change: 1C001002
    disconnect

ISR: 1004088
 Timer0

ISR: 408C
 Port Change
port change: 10001803
    connect

ISR: 4084
 Port Change
port change: 1C001002
    disconnect

ISR: 1004088
 Timer0

ISR: 408C
 Port Change
port change: 10001803
    connect

ISR: 1004088
 Timer0
  begin reset

ISR: 408C
 Port Change
port change: 10001805
  port enabled

ISR: 1004080
 Timer0
  end recovery
new_Device: 12 Mbit/sec
new_Pipe
new_Control_Transfer

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5420    token=80000200
  Followup 1FFF5360    token=100
  Followup 1FFF53A0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF5420    token=80008180

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF5420    token=8100
enumeration:
new_Control_Transfer
  Followup 1FFF5360    token=80280
  Followup 1FFF2EC0    token=80120180
  Followup 1FFF53A0    token=80008080

ISR: 4E089
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF2EC0    token=100
  Followup 1FFF53A0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF5420    token=80FC0180
  Followup 1FFF5360    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF5420    token=F80100
  Followup 1FFF5360    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF2EC0    token=80280
  Followup 1FFF53A0    token=80FC0180
  Followup 1FFF53E0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2EC0    token=80000200
  Followup 1FFF53A0    token=DE0100
  Followup 1FFF53E0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF5420    token=80280
  Followup 1FFF5360    token=80FC0180
  Followup 1FFF2EC0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5420    token=80000200
  Followup 1FFF5360    token=EC0100
  Followup 1FFF2EC0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF53A0    token=80280
  Followup 1FFF53E0    token=80090180
  Followup 1FFF5420    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53A0    token=80000200
  Followup 1FFF53E0    token=100
  Followup 1FFF5420    token=8000
enumeration:
Config data length = 59
new_Control_Transfer
  Followup 1FFF5360    token=80280
  Followup 1FFF2EC0    token=803B0180
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF2EC0    token=100
  Followup 1FFF53A0    token=8000
enumeration:
bNumInterfaces = 2
bConfigurationValue = 1
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF5360    token=80008180

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF5360    token=8100
enumeration:
USBHub memory usage = 864
USBHub claim_device this=1FFF2F00
USBHub memory usage = 864
USBHub claim_device this=1FFF3260
USBHub memory usage = 864
USBHub claim_device this=1FFF35C0
KeyboardController claim this=1FFF2020
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF3940
HIDParser claim this=1FFF3CE0
HIDParser claim this=1FFF2420
HIDParser claim this=1FFF27C0
HIDParser claim this=1FFF2B60
Descriptor 4 = INTERFACE
KeyboardController claim this=1FFF2020
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF3940
 bInterfaceClass =    3
 bInterfaceSubClass = 1
 bInterfaceProtocol = 2
report descriptor size = 176
Single endpoint HID:
  endpoint = 81
   size = 9
   interval = 4
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 0, shift= 0
add_qh_to_periodic_schedule:
  interval = 4
  offset =   0
  add to slot 0
  add to slot 4
  add to slot 8
  add to slot 12
  add to slot 16
  add to slot 20
  add to slot 24
  add to slot 28
Periodic Schedule:
 0: 1FFF2DA0
 1: (empty)
 2: (empty)
 3: (empty)
 4: 1FFF2DA0
 5: (empty)
 6: (empty)
 7: (empty)
 8: 1FFF2DA0
 9: (empty)
10: (empty)
11: (empty)
12: 1FFF2DA0
13: (empty)
14: (empty)
15: (empty)
16: 1FFF2DA0
17: (empty)
18: (empty)
19: (empty)
20: 1FFF2DA0
21: (empty)
22: (empty)
23: (empty)
24: 1FFF2DA0
25: (empty)
26: (empty)
27: (empty)
28: 1FFF2DA0
29: (empty)
30: (empty)
31: (empty)
new_Control_Transfer
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE
KeyboardController claim this=1FFF2020
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF3CE0
 bInterfaceClass =    3
 bInterfaceSubClass = 0
 bInterfaceProtocol = 0
report descriptor size = 75
Single endpoint HID:
  endpoint = 82
   size = 64
   interval = 4
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 5
, at offset = 0, shift= 3
add_qh_to_periodic_schedule:
  interval = 4
  offset =   0
  traverse list 0
  traverse list 4
More details about this device up in #43. Now to start debugging.

Update: looks like, it is dying in the second Hid Interface for this device. That is there are two Interfaces,
The first is for MOUSE, second is for DIGITIZER, looks like both report single End point.

The first one looks like it completes, the new pipe call. That is I have prints on both sides:
Code:
		println(" *** before new pipe ***");
		in_pipe = new_Pipe(dev, 3, endpoint & 0x0F, 1, size, interval);
		out_pipe = NULL;
		in_size = size;
		println("    pipe =", (uint32_t)in_pipe, HEX);
And not getting the println with the Pipe = ...

2nd Edit: It is hanging in: void USBHost::add_qh_to_periodic_schedule(Pipe_t *pipe).

I am thinking it uses the pointer to Pipe with the knowledge that the pointers are aligned on 32 bit boundary, so that the lower 5 bits will always be zero... So you can maybe encode information into these bits. Wondering how that works with the
horizontal_link variable in the Pipe_struct. That is if this is a linked list? If so how does it work with the different time slots.
That is at Timer 0 slot it finds that it needs to link... So maybe it encodes that data, but what happens when it needs to link again at Slot 4... Again need to see how this all works.
 
Last edited:
Status
Not open for further replies.
Back
Top