USB Host Mouse Driver

Status
Not open for further replies.
Yeah, caching the offset for the most recently used report ID is a great idea. In the common case of a device repeatedly sending the same report, we can just skip right to it.

Code to bail out when another report ID is found would also cut down the wasted parsing.

Maybe it'd also be ok to just delete all the bytes for unclaimed top level collections? If nobody claims it, we never offer it again. Then again, devices with more than 1 top level collection aren't very common, are they?
 
Back to playing a little with PS3, to see how the data is being overwritten for Right joystick.

It has to do with this section:
Code:
        Usage Page (Desktop),       ; Generic desktop controls (01h)
        Report Size (8),
        Report Count (39),
        Usage (Pointer),            ; Pointer (01h, physical collection)
        Input (Variable),
So it creates 39 bytes of input... You see the Usage page command for desktop 0x01
You then see the Usage: 01 (pointer) and so you assume ID is 0x10001
Which you do for the first one... Not sure about the other 38...

However looking at the USB HID Usage document: http://www.usb.org/developers/hidpage/Hut1_12v2.pdf
Section 3.1 - looks like ID 0 is reserved and 0x00-0x1f are reserved for top level collections 1 -> Pointer...

So not sure the best thing to set as an ID back to the user, for these items... I am going to try a hack where if less than 0x20 ignores it and see what that does.
Again Big Rabbit Hole ;)

Edit: Put in Pull request that simply ignores any USAGE: < 0x20

This appears to make the right joystick work on PS3 controller.
 
Last edited:
@Paul (and others) I am thinking of adding a few new methods to some of these classes.
For example I might want to know when there is a device connected, like do I have a mouse connected, or joystick or keyboard...

So was thinking of adding a connected() method - I had this in my Rabbit hole branch.

Two main branches of code for this: NON hid implemented devices like keyboard and HID devices currently Joystick and Mouse

First pass: HID...

Wondering if it makes sense to add members directly to the USBHIDInput class?

If so would it make sense to move the: Device_t *mydevice = NULL;
out of the JoystickController and MouseController classes and make a protected variable in USBHidinput. Maybe add some of the support code like the collections_claimed to inside the USBHidInput
class as well?

Also wondering about: exposing the idProduct and idVendor as member calls as well? Again probably part of the USBHidInput class.

Example: If I have code that is using Joystick, I would probably have code in place that would check for PS3 vs PS4 vs other Joysticks I have. Why? Their order of buttons are different. The Hat buttons are different... Also maybe I have the ability to monitor some other non-standard axes. Example I still want to rig up Teensy as Joystick, so may want to monitor additional Axes.

Also with my pending fix #77 currently all 39 additional axes are reported as id 0x10000 - may want some other mechanism for these... Where maybe they need some other index...
May also want to add the ability to the joysticks hid_input_data method, to be able to save additional Axes. That is maybe we define axes as having N items. Maybe default to 8 or 10, but have array maybe like 32 items... Then maybe if I detect PS3, I could say, pleas monitor these items (....) and then have our axis method(s) be able to return these. Maybe by index or by ID...

Make sense?

Right now probably will go out and enjoy another day
 
For example I might want to know when there is a device connected, like do I have a mouse connected, or joystick or keyboard...

So was thinking of adding a connected() method - I had this in my Rabbit hole branch.

I want this to happen in the driver base class, so it applies consistently to all device drivers.

Perhaps consistency with how Arduino uses the bool operator for Serial would be good? Or maybe the fake-bool approach from String, if operator bool is problematic? Or is an explicity connected() function best? I'm not sure. But I do feel pretty strongly about implementing this sort of functionality in the base class.

But drivers using only HID don't inherit the driver base class. I put the dev == driver compare logic into the driver, but maybe it really belongs in the HID parser, similar to how the regular driver base class is managed by emuneration.cpp.

Another possible complication is the possibility for a driver to have multiple inheritance, like the keyboard driver using the HID parser for media & power keys and the regular driver for the boot protocol. I've got to admit, this is kinda stretching my C++ a bit. Maybe tni will see this and comment?

Sorry to be so vague and undecided on some of this stuff. It really will make a huge long term difference to get it done well in a consistent way. Future Teensy boards likely all will have USB host, and I'd imagine eventually nearly all Arduino boards will too. Long-term, I'm guessing EHCI will become the norm, so this code is likely to get reused across the entire Arduino world in 10+ years time frame......

Also wondering about: exposing the idProduct and idVendor as member calls as well?

Yes, these too should be in the base class. I had also intended allocate a buffer in the base class for storing the string descriptors (or a truncated version if they're longer than the buffer) which could be queried as const char *.

Then maybe if I detect PS3, I could say, pleas monitor these items (....) and then have our axis method(s) be able to return these. Maybe by index or by ID...

For very common devices with wrong HID report descriptors, with the PS3 controller being the main example, it probably makes sense to just create a dedicated driver that claims based on vendor and product ID. Then it can just use hard coded bit offsets.
 
Thanks Paul,

I assumed also that things like connected should be done at the base class, which is why mentioned HID vs non-HID as the non-Hid did not inherit from the base class. Again was thinking these methods should also work from the base HID input class. But I don't believe it has any information to help with this. Like a pointer to the device object, which is why I thought about moving it there instead of both Mouse and Joystick having their own...

I also was thinking the idea of vendor ID and Product ID should be at the base class. They already have member variables for these, but should maybe have methods to return them.

Again if the base HID input class holds onto a pointer/handle to current device object, it can then return that data through that pointer.

I was going to ask about String descriptors as well. Thought I would experiment to see how hard it is to retrieve them... Again at base class then hopefully though HID class...

As for method names, yes we should take a pass... As you mentioned connected could work like if (Serial), but I would like it to work better. That is Serial at least used to only handle that the Serial port was connected but not that it later disconnected. Once we get the functionality working reasonably, would like to take pass through and cleanup APIS as well.

As I mentioned earlier we don't probably want it like: myMouse.getMouseButtons(), but probably just myMouse.buttons().

And then take a pass at adding Events.

As for Multiple Inheritance, these days I usually try to avoid it like the plague, as then it often leads to dynamic casting....

I hopefully will have a chance in a little while to play with some of this.
 
Quick update:

I added some of the stuff mentioned above. That is added query for available() to both top level devices and HID devices. Likewise added query to got vendor ID and product ID. And started doing some testing.

They appear to be working, but I am running into an issue with connecting and unconnecting devices. I first saw it when I was testing Mice, that the Microsoft Wireless mouse/keyboard combo. Works fine when I plug it in, but when I unplug it, things stop working... Then tried with simple mouse and I could go through at least several iterations. Then tried simple keyboard and ran into issue worked when plugged in and had problems if I disconnect it. So this morning turned on debug output:

Code:
USB Host Testing
sizeof Device = 32
sizeof Pipe = 96
sizeof Transfer = 64
power up USBHS PHY

ISR: 408C
 Port Change
port change: 14001403
    connect

ISR: 1004088
 Timer0
  begin reset

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

ISR: 1004088
 Timer0
  end recovery
new_Device: 1.5 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 1FFF3520    token=80120180
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF3520    token=100
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  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 1FFF3520    token=80280
  Followup 1FFF53A0    token=80FC0180
  Followup 1FFF53E0    token=80008080

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

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5420    token=80000200
  Followup 1FFF5360    token=CC0100
  Followup 1FFF3520    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=80000100
  Followup 1FFF5420    token=8000
enumeration:
Config data length = 59
new_Control_Transfer
  Followup 1FFF5360    token=80280
  Followup 1FFF3520    token=803B0180
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF3520    token=80000100
  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=1FFF3560
USBHub memory usage = 864
USBHub claim_device this=1FFF38C0
USBHub memory usage = 864
USBHub claim_device this=1FFF2D60
KeyboardController claim this=1FFF2020
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF3C60
HIDParser claim this=1FFF4140
HIDParser claim this=1FFF2420
HIDParser claim this=1FFF28C0
HIDParser claim this=1FFF30C0
Descriptor 4 = INTERFACE
KeyboardController claim this=1FFF2020
ep = 81
packet size = 8
polling interval = 24
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 0, shift= 0
add_qh_to_periodic_schedule: 1FFF3400
  interval = 16
  offset =   0
    old slot 0: (empty)
  add to slot 0
    new slot 0: 1FFF3400
    old slot 16: (empty)
  add to slot 16
    new slot 16: 1FFF3400
Periodic Schedule:
 0: 1FFF3400
 1: (empty)
 2: (empty)
 3: (empty)
 4: (empty)
 5: (empty)
 6: (empty)
 7: (empty)
 8: (empty)
 9: (empty)
10: (empty)
11: (empty)
12: (empty)
13: (empty)
14: (empty)
15: (empty)
16: 1FFF3400
17: (empty)
18: (empty)
19: (empty)
20: (empty)
21: (empty)
22: (empty)
23: (empty)
24: (empty)
25: (empty)
26: (empty)
27: (empty)
28: (empty)
29: (empty)
30: (empty)
31: (empty)
new_Data_Transfer
new_Control_Transfer
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF3C60
 bInterfaceClass =    3
 bInterfaceSubClass = 0
 bInterfaceProtocol = 0
report descriptor size = 159
Single endpoint HID:
  endpoint = 82
   size = 8
   interval = 10
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 8, shift= 0
add_qh_to_periodic_schedule: 1FFF33A0
  interval = 8
  offset =   8
    old slot 8: (empty)
  add to slot 8
    new slot 8: 1FFF33A0
    old slot 16: 1FFF3400
  traverse list 16
  num 1FFF3402  node 1FFF3400->1
  adding at node 1FFF3400, num=1FFF3402, node->qh.horizontal_link=1
    new slot 16: 1FFF3400 -> 1FFF33A0
    old slot 24: (empty)
  add to slot 24
    new slot 24: 1FFF33A0
Periodic Schedule:
 0: 1FFF3400 -> 1FFF33A0
 1: (empty)
 2: (empty)
 3: (empty)
 4: (empty)
 5: (empty)
 6: (empty)
 7: (empty)
 8: 1FFF33A0
 9: (empty)
10: (empty)
11: (empty)
12: (empty)
13: (empty)
14: (empty)
15: (empty)
16: 1FFF3400 -> 1FFF33A0
17: (empty)
18: (empty)
19: (empty)
20: (empty)
21: (empty)
22: (empty)
23: (empty)
24: 1FFF33A0
25: (empty)
26: (empty)
27: (empty)
28: (empty)
29: (empty)
30: (empty)
31: (empty)
new_Control_Transfer
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
  Followup 1FFF3520    token=80000200
  Followup 1FFF34E0    token=8100
  Followup 1FFF5420    token=80000200
  Followup 1FFF2CE0    token=809F0180
  Followup 1FFF2D20    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2CE0    token=809F0180
  Followup 1FFF2D20    token=80008080

ISR: 4E089
 USB Async
Async Followup
  Followup 1FFF2CE0    token=80000100
  Followup 1FFF2D20    token=8000
control callback (hid)
05 01 09 80 A1 01 85 01 05 01 19 81 29 88 15 00 25 01 95 08 75 01 81 02 C0 05 0C 09 01 A1 01 85 02 15 00 25 01 0A 83 01 0A CD 00 0A B7 00 0A E9 00 0A EA 00 0A E2 00 0A B6 00 0A B5 00 0A 8A 01 0A 92 01 0A 94 01 0A 21 02 0A 23 02 0A 24 02 0A 25 02 0A 26 02 0A 27 02 0A 2A 02 95 12 75 01 81 02 95 01 75 06 81 01 C0 05 09 09 01 A1 01 85 03 15 00 25 01 0A 2C 00 0A 18 00 0A 20 00 0A 1F 00 0A 1C 00 0A 3D 00 0A 41 00 0A 42 00 0A 43 00 0A 46 00 95 0A 75 01 81 02 95 01 75 06 81 01 C0 
  mesg = 22000681
  got report descriptor
Found top level collection 10080
find_driver
  driver 1FFF4100
  driver 1FFF3C20
Found top level collection C0001
find_driver
  driver 1FFF4100
  driver 1FFF3C20
Found top level collection 90001
find_driver
  driver 1FFF4100
  driver 1FFF3C20
new_Data_Transfer

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF53E0    token=80008100
KeyboardController Callback (member)
  KB Data: 00 00 04 00 00 00 00 00 
  press, key=4
  unicode = 97
key 'a'  97
new_Data_Transfer
  Followup 1FFF34A0    token=88180
  Followup 1FFF53A0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF53A0    token=8100
KeyboardController Callback (member)
  KB Data: 00 00 00 00 00 00 00 00 
  release, key=4
new_Data_Transfer
  Followup 1FFF2D20    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF2D20    token=80008100
KeyboardController Callback (member)
  KB Data: 00 00 05 00 00 00 00 00 
  press, key=5
  unicode = 98
key 'b'  98
new_Data_Transfer
  Followup 1FFF53E0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF53E0    token=8100
KeyboardController Callback (member)
  KB Data: 00 00 00 00 00 00 00 00 
  release, key=5
new_Data_Transfer
  Followup 1FFF53A0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF53A0    token=80008100
KeyboardController Callback (member)
  KB Data: 00 00 06 00 00 00 00 00 
  press, key=6
  unicode = 99
key 'c'  99
new_Data_Transfer
  Followup 1FFF2D20    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF2D20    token=8100
KeyboardController Callback (member)
  KB Data: 00 00 00 00 00 00 00 00 
  release, key=6
new_Data_Transfer
  Followup 1FFF53E0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF53E0    token=80008100
KeyboardController Callback (member)
  KB Data: 00 00 07 00 00 00 00 00 
  press, key=7
  unicode = 100
key 'd'  100
new_Data_Transfer
  Followup 1FFF53A0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF34A0    token=88180
  Followup 1FFF53A0    token=8100
KeyboardController Callback (member)
  KB Data: 00 00 00 00 00 00 00 00 
  release, key=7
new_Data_Transfer
  Followup 1FFF2D20    token=88180

[COLOR="#FF0000"]ISR: C08C
 Port Change
port change: 1C00100A
    disconnect
disconnect_Device:
USBDriver (available_drivers) list: 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2220 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
USBDriver (dev->drivers) list: 1FFF3C60
disconnect driver 1FFF3C60
USBDriver (available_drivers) list: 1FFF3C60 -> 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2220 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
delete_Pipe 1FFF3400
delete_Pipe 1FFF33A0
delete_Pipe 1FFF5300
  shut down async schedule
removed Device_t from devlist
  disable
[/COLOR]
ISR: 408C
 Port Change
port change: 14001403
    connect

ISR: 1004088
 Timer0
  begin reset

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

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

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF3460    token=80000200
  Followup 1FFF53E0    token=100
  Followup 1FFF34A0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF2CE0    token=80280
  Followup 1FFF3460    token=80008180

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2CE0    token=80000200
  Followup 1FFF3460    token=8100
enumeration:
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF2D20    token=80120180
  Followup 1FFF34A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF2D20    token=100
  Followup 1FFF34A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF34A0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF2CE0    token=80280
  Followup 1FFF3460    token=80FC0180
  Followup 1FFF53E0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2CE0    token=80000200
  Followup 1FFF3460    token=F80100
  Followup 1FFF53E0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF2D20    token=80280
  Followup 1FFF34A0    token=80FC0180
  Followup 1FFF2CE0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2D20    token=80000200
  Followup 1FFF34A0    token=CA0100
  Followup 1FFF2CE0    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF3460    token=80280
  Followup 1FFF53E0    token=80FC0180
  Followup 1FFF2D20    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF3460    token=80000200
  Followup 1FFF53E0    token=CC0100
  Followup 1FFF2D20    token=8000
enumeration:
new_Control_Transfer
  Followup 1FFF34A0    token=80280
  Followup 1FFF2CE0    token=80090180
  Followup 1FFF3460    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF34A0    token=80000200
  Followup 1FFF2CE0    token=80000100
  Followup 1FFF3460    token=8000
enumeration:
Config data length = 59
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF2D20    token=803B0180
  Followup 1FFF34A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF2D20    token=80000100
  Followup 1FFF34A0    token=8000
enumeration:
bNumInterfaces = 2
bConfigurationValue = 1
new_Control_Transfer
  Followup 1FFF2CE0    token=80280
  Followup 1FFF53E0    token=80008180

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF2CE0    token=80000200
  Followup 1FFF53E0    token=8100
enumeration:
HIDParser claim this=1FFF3C60
USBHub memory usage = 864
USBHub claim_device this=1FFF3560
USBHub memory usage = 864
USBHub claim_device this=1FFF38C0
USBHub memory usage = 864
USBHub claim_device this=1FFF2D60
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF4140
HIDParser claim this=1FFF2420
HIDParser claim this=1FFF28C0
HIDParser claim this=1FFF30C0
Descriptor 4 = INTERFACE
HIDParser claim this=1FFF3C60
 bInterfaceClass =    3
 bInterfaceSubClass = 1
 bInterfaceProtocol = 1
report descriptor size = 65
Single endpoint HID:
  endpoint = 81
   size = 8
   interval = 24
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 1, shift= 0
add_qh_to_periodic_schedule: 1FFF33A0
  interval = 16
  offset =   1
    old slot 1: (empty)
  add to slot 1
    new slot 1: 1FFF33A0
    old slot 17: (empty)
  add to slot 17
    new slot 17: 1FFF33A0
Periodic Schedule:
 0: (empty)
 1: 1FFF33A0
 2: (empty)
 3: (empty)
 4: (empty)
 5: (empty)
 6: (empty)
 7: (empty)
 8: (empty)
 9: (empty)
10: (empty)
11: (empty)
12: (empty)
13: (empty)
14: (empty)
15: (empty)
16: (empty)
17: 1FFF33A0
18: (empty)
19: (empty)
20: (empty)
21: (empty)
22: (empty)
23: (empty)
24: (empty)
25: (empty)
26: (empty)
27: (empty)
28: (empty)
29: (empty)
30: (empty)
31: (empty)
new_Control_Transfer
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
Descriptor 4 = INTERFACE
KeyboardController claim this=1FFF2220
HIDParser claim this=1FFF4140
 bInterfaceClass =    3
 bInterfaceSubClass = 0
 bInterfaceProtocol = 0
report descriptor size = 159
Single endpoint HID:
  endpoint = 82
   size = 8
   interval = 10
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 9, shift= 0
add_qh_to_periodic_schedule: 1FFF3400
  interval = 8
  offset =   9
    old slot 9: (empty)
  add to slot 9
    new slot 9: 1FFF3400
    old slot 17: 1FFF33A0
  traverse list 17
  num 1FFF33A2  node 1FFF33A0->1
  adding at node 1FFF33A0, num=1FFF33A2, node->qh.horizontal_link=1
    new slot 17: 1FFF33A0 -> 1FFF3400
    old slot 25: (empty)
  add to slot 25
    new slot 25: 1FFF3400
Periodic Schedule:
 0: (empty)
 1: 1FFF33A0 -> 1FFF3400
 2: (empty)
 3: (empty)
 4: (empty)
 5: (empty)
 6: (empty)
 7: (empty)
 8: (empty)
 9: 1FFF3400
10: (empty)
11: (empty)
12: (empty)
13: (empty)
14: (empty)
15: (empty)
16: (empty)
17: 1FFF33A0 -> 1FFF3400
18: (empty)
19: (empty)
20: (empty)
21: (empty)
22: (empty)
23: (empty)
24: (empty)
25: 1FFF3400
26: (empty)
27: (empty)
28: (empty)
29: (empty)
30: (empty)
31: (empty)
new_Control_Transfer
Descriptor 33 = HID
Descriptor 5 = ENDPOINT
  Followup 1FFF2D20    token=80000200
  Followup 1FFF53A0    token=80410180
  Followup 1FFF3460    token=80008080
  Followup 1FFF34A0    token=80280
  Followup 1FFF5360    token=809F0180
  Followup 1FFF3520    token=80008080

ISR: 4C089
 USB Async
Async Followup
  Followup 1FFF53A0    token=100
  Followup 1FFF3460    token=8000
control callback (hid)
05 01 09 06 A1 01 05 07 19 E0 29 E7 15 00 25 01 95 08 75 01 81 02 95 08 75 01 81 01 05 08 19 01 29 03 95 03 75 01 91 02 95 01 75 05 91 01 05 07 19 00 2A FF 00 15 00 26 FF 00 95 06 75 08 81 00 C0 
  mesg = 22000681
  got report descriptor
Found top level collection 10006
find_driver
  driver 1FFF4100
  driver 1FFF3C20
new_Data_Transfer
  Followup 1FFF34A0    token=80000200
  Followup 1FFF5360    token=809F0180
  Followup 1FFF3520    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000100
  Followup 1FFF3520    token=8000
control callback (hid)
05 01 09 80 A1 01 85 01 05 01 19 81 29 88 15 00 25 01 95 08 75 01 81 02 C0 05 0C 09 01 A1 01 85 02 15 00 25 01 0A 83 01 0A CD 00 0A B7 00 0A E9 00 0A EA 00 0A E2 00 0A B6 00 0A B5 00 0A 8A 01 0A 92 01 0A 94 01 0A 21 02 0A 23 02 0A 24 02 0A 25 02 0A 26 02 0A 27 02 0A 2A 02 95 12 75 01 81 02 95 01 75 06 81 01 C0 05 09 09 01 A1 01 85 03 15 00 25 01 0A 2C 00 0A 18 00 0A 20 00 0A 1F 00 0A 1C 00 0A 3D 00 0A 41 00 0A 42 00 0A 43 00 0A 46 00 95 0A 75 01 81 02 95 01 75 06 81 01 C0 
  mesg = 22000681
  got report descriptor
Found top level collection 10080
find_driver
  driver 1FFF4100
  driver 1FFF3C20
Found top level collection C0001
find_driver
  driver 1FFF4100
  driver 1FFF3C20
Found top level collection 90001
find_driver
  driver 1FFF4100
  driver 1FFF3C20
new_Data_Transfer

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF2CE0    token=80008100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF5420    token=88180
  Followup 1FFF53A0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF5420    token=88180
  Followup 1FFF53A0    token=8100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF3520    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF5420    token=88180
  Followup 1FFF3520    token=80008100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF2CE0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF5420    token=88180
  Followup 1FFF2CE0    token=8100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF53A0    token=88180

ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF5420    token=88180
  Followup 1FFF53A0    token=80008100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF3520    token=88180

ISR: C08C
 Port Change
port change: 1C00100A
    disconnect
disconnect_Device:
USBDriver (available_drivers) list: 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2220 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
USBDriver (dev->drivers) list: 1FFF4140
disconnect driver 1FFF4140
USBDriver (available_drivers) list: 1FFF4140 -> 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2220 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
delete_Pipe 1FFF33A0
delete_Pipe 1FFF3400
delete_Pipe 1FFF5300
  shut down async schedule
removed Device_t from devlist
  disable
In the above I marked where the device was disconnected in RED. After that point I plugged it back in... From some of this I could not tell if Keyboard or HID driver claimed this device. But it then started showing lots of the USB periodic messages like:
Code:
ISR: 8E089
 USB Periodic
Periodic Followup
  Followup 1FFF5420    token=88180
  Followup 1FFF53A0    token=80008100
HID: 00 00 00 00 00 00 00 00 
new_Data_Transfer
  Followup 1FFF3520    token=88180
Which keeps repeating... Note: I also ran into this with DS4 controller. Where with it, I could connect it, disconnect it, connect it, on the 2nd disconnect it would stop working. Almost like we included 5 HID parsers and it has two logical hid devices and they were not fully shutdown so took up 2 each time and on the third failed? ...

Investigating. Maybe like the devices are not fully releasing? Or maybe they go to the end of the list? That is for example a Keyboard is a HID device, but as it is first created, it has priority? ...

Edit: I have edited the enumeration code. to try doing the claim of interfaces in two parts. I first call all of the devices with enumeration type 1, if not claimed, I loop again calling with enumeration type 2 and edited the HID Input class to only process #2. This allows the code to choose a more specific driver like Keyboard first, before the HID decides to grab it. This appears to be working now with my Microsoft Mouse/Keyboard code...

Still investigating the PS4 controller, which still is working like I saw before... Also trying to see why I am only doing the Connect messages in my test app and not the disconnect... Maybe the device pointer is not being reset to NULL, but I think it is...

Update: I pushed up the enumeration change as well current state of adding APIs to: https://github.com/KurtE/USBHost_t36/tree/HID-Device-API-Additions

I have been investigating Hang on 2nd removal of DS4, actually it may take a few attempts to hang... Maybe timing issue.
The code is hanging in: USBHost::delete_Pipe in the section at the end which is free all the transfers still attached... Not sure if chain is bad or hang in free_transfer yet.

Looks like hang in the loop - I added some more debug messages:
Code:
	//
	// TODO: do we need to look at pipe->qh.current ??
	//
	// free all the transfers still attached to the QH
	println("  free all transfers still attached");
	Transfer_t *tr = (Transfer_t *)(pipe->qh.next);
	while ((uint32_t)tr & 0xFFFFFFE0) {
		println("    TR: ", (uint32_t)tr, HEX);
		Transfer_t *next = (Transfer_t *)(tr->qtd.next);
		free_Transfer(tr);
		tr = next;
	}
	// hopefully we found everything...
	println("  free_Pipe");
	free_Pipe(pipe);
First disconnect I received one TR: message...

2nd disconnect: It hung:
Code:
ISR: C084
 Port Change
port change: 1C00100A
    disconnect
disconnect_Device:
USBDriver (available_drivers) list: 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2020 -> 1FFF2220 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
USBDriver (dev->drivers) list: 1FFF3C60
disconnect driver 1FFF3C60
*** Joystick - disconnect_collection claim count 0
USBDriver (available_drivers) list: 1FFF3C60 -> 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2020 -> 1FFF2220 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
delete_Pipe 1FFF3400
  remove from periodic schedule
  free all transfers still attached
    TR: 1FFF3720
    TR: 1FFF53A0
    TR: 1FFF37E0
    TR: 1FFF37A0
    TR: 1FFF3AC0
    TR: 1FFF3B00
    TR: 1FFF3B40
    TR: 1FFF2F20
    TR: 1FFF2F60
    TR: 1FFF2FA0
    TR: 1FFF2FE0
    TR: 1FFF2120
    TR: 1FFF2160
    TR: 1FFF21A0
    TR: 1FFF21E0
    TR: 1FFF2320
    TR: 1FFF2360
    TR: 1FFF23A0
    TR: 1FFF23E0
    TR: 1FFF4000
    TR: 1FFF4040
    TR: 1FFF4080
    TR: 1FFF40C0
    TR: 1FFF44E0
...
 
Last edited:
Not sure if I should post it here or in another thread about USB Keyboards...

I drug out a Dell USB keyboard, from maybe 2 or 3 computers ago that is not working with the USB Host code. What is different about this Keyboard is that it has a built in USB hub.

Debug output from USB host with debug turned on:
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: 1004088
 Timer0
  begin reset

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

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

ISR: 4C081
 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 1FFF3520    token=80120180
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF3520    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 1FFF3520    token=80280
  Followup 1FFF53A0    token=80FC0180
  Followup 1FFF53E0    token=80008080

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

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5420    token=80000200
  Followup 1FFF5360    token=80D00100
  Followup 1FFF3520    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=80000100
  Followup 1FFF5420    token=8000
enumeration:
Config data length = 25
new_Control_Transfer
  Followup 1FFF5360    token=80280
  Followup 1FFF3520    token=80190180
  Followup 1FFF53A0    token=80008080

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF5360    token=80000200
  Followup 1FFF3520    token=80000100
  Followup 1FFF53A0    token=8000
enumeration:
bNumInterfaces = 1
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=1FFF3560
  polling interval = 24
7
5
81
1
bDeviceClass = 9
bDeviceSubClass = 0
bDeviceProtocol = 0
new_Control_Transfer
  Followup 1FFF3520    token=80280
  Followup 1FFF5420    token=80100180
  Followup 1FFF53A0    token=80008080

ISR: 4C081
 USB Async
Async Followup
  Followup 1FFF3520    token=80000200
  Followup 1FFF5420    token=80070100
  Followup 1FFF53A0    token=8000
USBHub control callback
09 29 03 0D 00 16 64 02 FF 00 00 00 00 00 00 00 
Hub ports = 3
new_Control_Transfer
new_Control_Transfer
  Followup 1FFF53E0    token=80280
  Followup 1FFF3520    token=80008180
  Followup 1FFF5420    token=80280
  Followup 1FFF34E0    token=80008180

ISR: 4E081
 USB Async
Async Followup
  Followup 1FFF53E0    token=80000200
  Followup 1FFF3520    token=8100
USBHub control callback
new_Control_Transfer
  Followup 1FFF5420    token=80000200
  Followup 1FFF34E0    token=8100
USBHub control callback
power turned on to all ports
device addr = 1
new_Pipe
allocate_interrupt_pipe_bandwidth
 best_bandwidth = 3
, at offset = 0, shift= 0
add_qh_to_periodic_schedule: 1FFF3400
  interval = 16
  offset =   0
    old slot 0: (empty)
  add to slot 0
    new slot 0: 1FFF3400
    old slot 16: (empty)
  add to slot 16
    new slot 16: 1FFF3400
Periodic Schedule:
 0: 1FFF3400
 1: (empty)
 2: (empty)
 3: (empty)
 4: (empty)
 5: (empty)
 6: (empty)
 7: (empty)
 8: (empty)
 9: (empty)
10: (empty)
11: (empty)
12: (empty)
13: (empty)
14: (empty)
15: (empty)
16: 1FFF3400
17: (empty)
18: (empty)
19: (empty)
20: (empty)
21: (empty)
22: (empty)
23: (empty)
24: (empty)
25: (empty)
26: (empty)
27: (empty)
28: (empty)
29: (empty)
30: (empty)
31: (empty)
pipe cap1 = F0010101
new_Data_Transfer
  Followup 1FFF5360    token=80000200
  Followup 1FFF53A0    token=8100
USBHub control callback

ISR: 4C081
 USB Async
Async Followup

ISR: C08C
 Port Change
port change: 1C00100A
    disconnect
disconnect_Device:
USBDriver (available_drivers) list: 1FFF38C0 -> 1FFF2D60 -> 1FFF2020 -> 1FFF2220 -> 1FFF3C60 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
USBDriver (dev->drivers) list: 1FFF3560
disconnect driver 1FFF3560
USBDriver (available_drivers) list: 1FFF3560 -> 1FFF38C0 -> 1FFF2D60 -> 1FFF2020 -> 1FFF2220 -> 1FFF3C60 -> 1FFF4140 -> 1FFF2420 -> 1FFF28C0 -> 1FFF30C0
delete_Pipe 1FFF3400
delete_Pipe 1FFF5300
  shut down async schedule
removed Device_t from devlist
  disable

Information from Linux machine:
From dmesg:
Code:
[   86.913131] usb 1-4: new full-speed USB device number 6 using xhci_hcd
[   87.041916] usb 1-4: New USB device found, idVendor=413c, idProduct=1004
[   87.041940] usb 1-4: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[   87.041961] usb 1-4: Product: Dell USB Keyboard Hub
[   87.041969] usb 1-4: Manufacturer: Dell
[   87.043730] usb 1-4: ep 0x81 - rounding interval to 128 microframes, ep desc says 192 mic                                             roframes
[   87.045226] hub 1-4:1.0: USB hub found
[   87.045352] hub 1-4:1.0: 3 ports detected
[   87.317034] usb 1-4.1: new low-speed USB device number 7 using xhci_hcd
[   87.410590] usb 1-4.1: New USB device found, idVendor=413c, idProduct=2006
[   87.410601] usb 1-4.1: New USB device strings: Mfr=1, Product=2, SerialNumber=0
[   87.410608] usb 1-4.1: Product: Dell USB Keyboard Hub
[   87.410614] usb 1-4.1: Manufacturer: Dell
[   87.410968] usb 1-4.1: ep 0x81 - rounding interval to 64 microframes, ep desc says 80 mic                                             roframes
[   87.410993] usb 1-4.1: ep 0x82 - rounding interval to 1024 microframes, ep desc says 2040                                              microframes
[   87.454092] usbcore: registered new interface driver usbhid
[   87.454100] usbhid: USB HID core driver
[   87.461300] input: Dell Dell USB Keyboard Hub as /devices/pci0000:00/0000:00:14.0/usb1/1-                                             4/1-4.1/1-4.1:1.0/0003:413C:2006.0001/input/input4
[   87.518218] hid-generic 0003:413C:2006.0001: input,hidraw0: USB HID v1.10 Keyboard [Dell                                              Dell USB Keyboard Hub] on usb-0000:00:14.0-4.1/input0
[   87.520363] input: Dell Dell USB Keyboard Hub as /devices/pci0000:00/0000:00:14.0/usb1/1-                                             4/1-4.1/1-4.1:1.1/0003:413C:2006.0002/input/input5
[   87.573775] hid-generic 0003:413C:2006.0002: input,hidraw1: USB HID v1.10 Device [Dell De                                             ll USB Keyboard Hub] on usb-0000:00:14.0-4.1/input1

from LSUSB:
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 413c:2006 Dell Computer Corp.
Bus 001 Device 006: ID 413c:1004 Dell Computer 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:~$
Could print out more stuff if it would help.

Again not sure one can get this keyboard specifically, but have you tested with any keyboards with hubs built in?
Like maybe something like: https://smile.amazon.com/Perixx-PER...5489220&sr=8-5&keywords=keyboard+with+usb+hub
 
Paul (and others), More questions about maybe API's(methods) for the USB Host code.

As you mentioned earlier and in code. There are cases, where I may want to print out the Vendor name, or product name or Serial #.

The current enumeration code is actually setup to query the data (if the device supports it), but the code does nothing with the data after receiving it.

Like case 6: in the enumeration code:
Code:
		case 6: // parse Manufacturer string
			// TODO: receive the string...
			if (enumbuf[1]) dev->enum_state = 7;
			else if (enumbuf[2]) dev->enum_state = 9;
			else dev->enum_state = 11;
			break;

There are a few different ways I see to handle this.

a) Allocate memory (new or malloc or...) a string for the data - I know that is probably not an option.
b) Allocate space in the USB objects to hold these strings... Not sure we would always want to waste memory, and setup some large buffers.
c) Have a way for the user code to supply buffer(s) for this. Would probably need to be on constructor as may be done before user code is running?

d) Don't do it as part of the enumeration - But as part of a method call. Maybe something like:
myButton.manufactureString(buffer, len, event_object);

This would probably require that the enumeration code: stash the string ids into memory variables instead of enumbuf 0-3 and would probably still do the work to get the language ID, or maybe have this part of the query code. That if we have not yet done the query for it, do it now... (case 3)

Also wondering, these strings I believe are stored as Unicode. Is this what we should return to the caller, or should these be converted to Ascii or UTF-8? If converted are there some standard functions for doing this?

Edit - I have started playing with the idea of having API(s) to retrieve the strings and as such, would like to get it to work with normal devices and as well as Mouse and Joystick. But trying to figure out how to do this with these HID objects as they have no handle or pointer to the USBHidParser that is controlling their Pipes and the ike. Wonder if maybe the claim function should pass in handle to this object. So then methods like I mentioned would simply call off to the version that is part of the top level object.
 
Last edited:
Paul and Others:

Update: I have a WIP version up in the branch: https://github.com/KurtE/USBHost_t36/tree/HID-Device-API-Additions

Right now I have three new APIS to query the product name, manufacturer name and Serial number, which is starting to limp along.
But they are Async, so needed a callback to enable them to notify caller code when done. So I used EventResponder.

The USBHid input class, now is passed a pointer to the Device object during claim, which I hold onto. I use this to have the device query for the the HID objects.

The API currently has the user pass in a buffer to use for it and I don't do any post processing of the data.
What this implies: is the buffer will have: <count of bytes> <03> ... unicode characters for the string...

Would like to convert the Unicode back to Ascii or UTF-8... Not sure the easiest way yet. Also may at some point combine the three function into one where you pass in what string you want...

So test app tries to print out these strings... Pretty quick and dirty right now... But for example here is Sony PS4 controller

Code:
USB Host Testing


*** Joystick 054c:05c4 Connected ***
Joystick Manufacturer: 38 03 53 00 6f 00 6e 00 79 00 20 00 43 00 6f 00 6d 00 70 00 75 00 74 00 65 00 72 00 20 00 45 00 6e 00 74 00 65 00 72 00 74 00 61 00 69 00 6e 00 6d 00 65 00 6e 00 74 00 = 'Sony Computer Entertainment'
Joystick Product: 28 03 57 00 69 00 72 00 65 00 6c 00 65 00 73 00 73 00 20 00 43 00 6f 00 6e 00 74 00 72 00 6f 00 6c 00 6c 00 65 00 72 00 = 'Wireless Controller'
Joystick no Serial number string
Joystick: buttons = 0, X = 126, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 125, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 124, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 123, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 122, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 121, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 120, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 119, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 118, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 117, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 116, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 115, Y = 129, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 115, Y = 128, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
Joystick: buttons = 0, X = 114, Y = 128, Z = 127, Rz = 128, Rx = 0, Ry = 0, Hat = 8
 
@Paul (and others),

Made a few more changes:

The most important was a fix to the enumeration, when a device was added that had multiple interfaces which used different driver objects. The code to link these together was broken and last driver won. The main place you would notice the failure is on the removal of the device. Only the last one enumerated would be removed.

The other change, associated with getting the the strings above, is I put in a post processes to convert the string objects into an ASCII null terminated string. The code is pretty limited in that it ignores the high bytes of the unicode characters.

Probably needs additional work/testing, but might be interesting to try out...

Code:
*** Keyboard 1 046d:c517 Connected ***


*** Mouse 046d:c517 Connected ***
Keyboard 1 Manufacturer: Logitech
Keyboard 1 Product: USB Receiver
Keyboard 1 no Serial number string
Mouse Manufacturer: Logitech
Mouse Product: USB Receiver
Mouse no Serial number string

or with a Teensy programmed as Mouse Triangle move ;)
Code:
USB Host Testing


*** Keyboard 1 16c0:0482 Connected ***


*** Mouse 16c0:0482 Connected ***


*** Joystick 16c0:0482 Connected ***
Keyboard 1 Manufacturer: Teensyduino
Keyboard 1 Product: Keyboard/Mouse/Joystick
Keyboard 1 serial: 1701970
Mouse Manufacturer: Teensyduino
Mouse Product: Keyboard/Mouse/Joystick
Mouse serial: 1701970
Joystick Manufacturer: Teensyduino
Joystick Product: Keyboard/Mouse/Joystick
Joystick serial: 1701970
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
Mouse: buttons = 0,  mouseX = 2,  mouseY = -1,  wheel = 0,  wheelH = 0
*** Joystick - disconnect_collection claim count 0

*** Keyboard 1 disconnected ***

*** Mouse disconnected ***

*** Joystick disconnected ***
 
FWIW
I was just checking on status of USB Host. I tested with old K66 proto (has USB host connector) and with mouse example from
https://github.com/PaulStoffregen/USBHost_t36.
Everything looked good. USB keyboard and USB wired-mouse and wireless mouse all good. Logitech joystick good with movement, buttons, and hat.
All is well.;)
 
Just a quick note that my Lenovo Keyboard KU-1255 only worked as a mouse (no KB) until I made this small change

Code:
	// Had to delete below to get Lenovo Keyboard & mouse to work....
	//if (size != 8) return false; // must be 8 bytes for Keyboard Boot Protocol

It was returning 63 for packet size on Keyboard claim, not 8. I know this is not too helpful and surely has downstream issues for other keyboards, but if anyone has issues with something similar, look there. Thanks for the great work on this project, it's saving me a lot of time and effort.
 
@Paul (or others): Is there any way to change the timing of the USB transfers ? - or do them on request (triggered by software or a timer) only ? I'd accept any trick.. ;) I really want to make it more VGA compatible. During H or V-Sync is some time where - I hope - it does not influence VGA so badly - and for a keyboard or mouse less frequent transfers are still OK. In addition, i have some black lines where is plenty of time, and it would not hurt to do the transfers during these lines.
I use a fork anyway, so any changes to the usb-code are OK. :)
 
Last edited:
Sure. You can disable and enable the periodic (interrupt pipes) and asynchronous (control & bulk pipes) schedules. When disabled, the host controller simply won't do that communication, and it will (or should) even stop hitting the bus for reading the lists.

For asynchronous timing should be much simpler to control. It should start scanning for QHs needing service pretty much immediately after you enable.

But periodic only runs at the beginning of each 125 us microframe. If you happen to enable right after the beginning of a microframe, it could possibly wait just under 125 us. Interrupt pipes communicating at 1.5 or 12 Mbit/sec through a TT in a hub, or through the built in TT probably won't work unless the periodic schedule remains enabled for a few microframes. The split start token has to be scheduled in the microframe before the TT actually talks to the slower device, and then split completes are scheduled in later microframes. If the periodic schedule isn't left enabled over all those microframes, you probably won't be able to get a successful transfer from any low speed endpoint.
 
Paul - do HID or BOOT devices get on a different schedule by default? As this relates to the VGA - T_3.6 Serial HID to PC Host stops the jitter from timing collisions. If the T_3.6 HOST could do that as well it might solve the problem.
 
Defragster - I think the default scheduling is setup by the device. In particular: If you look at the keyboard code.

If you look at the library in the keyboard code, at the claim function...

Code:
	uint32_t interval = descriptors[24];
	println("polling interval = ", interval);
	datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval);
	datapipe->callback_function = callback;
You will see that the descriptor contains an interval value which we pass into the create the new pipe...
 
Code:
    datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval);
..already been there and seen it - it does not help to increase "interval". Or maybe, it's an other issue due to the very old USB-HOST code I use..
 
do HID or BOOT devices get on a different schedule by default?

Their control endpoint zero will be serviced by the asynchronous schedule, and their interrupt endpoint(s) will be serviced by the periodic schedule.

It doesn't matter what other descriptors the device uses to identify itself. The endpoint types are what matters. Control and bulk are always on the asynchronous schedule. Interrupt type is always done with the periodic schedule. So far, USBHost_t36 has no support for isochronous. But when/if it's ever added, isochronous can only be done with the periodic schedule.

Might also be worth mentioning the endpoints only get serviced if the device driver calls new_Pipe().

Regardless of whether a pipe exists (QH structures have been linked into the schedules), the host controller will regularly access memory to poll the schedules. The periodic schedule is accessed every 125 us. The async schedule is accessed until no QHs needing work are found, and then it goes into a timeout mode before it scans the QH list again. The timeout isn't documented anywhere by Freescale... you have to read the EHCI spec for that level of detail (and the EHCI document is quite a challenging read....)

The enable bits for both schedules are in the USBHS_USBCMD register, documented on pages 1599 to 1601. The recommended procedure for changing these bits involves writing to USBHS_USBCMD and then polling the corresponding status bit in USBHS_USBSTS. The host controller does many operations that take substantial time, so your change doesn't necessarily take effect until it completes whatever operation was in progress at the moment you write to USBHS_USBCMD.
 
Might also be worth mentioning Freescale's controller has two non-EHCI tuning registers.

USBHS_BURSTSIZE gives you control over how long it takes control over the bus. Maybe trying smaller values will help?

USBHS_TXFILLTUNING is one of the parts of the host controller I don't understand. Curious to hear if it has any impact. So far we don't really have much in the way of benchmarks for testing the impact of this stuff, so I've been leaving it alone in hopes the defaults are sane.
 
Wow. OK,..thank you very much for the help. I understand max. 50% - but weekend is near, and I hope I find some time to try some things - at least USBHS_USBCMD.
 
Thanks Paul and Kurt - after seeing the VGA clean with HID SPEW I was hoping to elicit such info as to keep Frank busy this next weekend - good luck Frank.
Do I remember (a post I saw) correctly that a 'Teensy' (as 'keyboard'?) doesn't register on T_3.6 Host because it is a BOOT device?
 
Do I remember (a post I saw) correctly that a 'Teensy' (as 'keyboard'?) doesn't register on T_3.6 Host because it is a BOOT device?

No. You're confusing the fairly high-level work of generic HID report descriptor parsing with this very low-level stuff about how the hardware actually uses DMA to implement the pipes and their service schedules.

Boot protocol keyboards and mice communicate use a fixed data format (or the first part of their data is the simple fixed format - the rest could be anything). They still have the same endpoints and so the same pipes are used. All the actual low-level communication is identical (well, except they tend to have smaller data sizes than feature-packed products which can't use the very limited fixed format).

The only difference is you (or the author of the boot protocol device driver) can write very simple code to assume the meaning of the bits and bytes. If the device sends more than just the fixed-definition bytes, as nearly all mice do for their scroll wheel and other features, the only reliable way to know what those other bits mean is by parsing the HID report descriptor. That's all fairly high level work you do (or the parser driver does) in software. It's not technically any part of the USB host controller. It's "only" work done on the driver level to actually use the data after it's been communicated by the pipe.
 
Last edited:
Thanks Paul - I should have left off 'correctly' :) I didn't find it again to see the context. I was hoping there was a simple type/portion of the descriptor that would lead to a usable keyboard without triggering polling - the way 'Raw HID' from Teensy does that would lead to specific use versions to work with VGA with HOST on Teensy64.
 
The other interesting thing about marked as boot at least as far as mice is concerned, is that many of the mice I have all are marked as boot, but they don't appear to have a fixed data output... Some start with a report id, some do not. Some have 8 bit values for axes, others 12 and still others 16...

Again I am just fumbling along with some of the USB stuff. Need to reread some of the sections in PDF...

If it were me and I was just hacking... I would experiment and see, if I played with void KeyboardController::new_data(const Transfer_t *transfer)

function and see what happens if I don't do the call: queue_Data_Transfer(datapipe, report, 8, this);
At the end some of the time... Does that stop the polling/Interrupts? Do they resume if I later queue the transfer?

I would also wonder if looking at the wrong end? That is Why is the keyboard interrupt screwing up the VGA? Can something be done at that end? Is it DMA? Interrupts? If interrupt, is it high enough priority...
 
Does that stop the polling/Interrupts? Do they resume if I later queue the transfer?

Yes and yes, from the perspective of communication on the USB cable.

From as far as accessing the memory bus, the host controller will keep reading from the RAM every 125 us. It doesn't know whether you queued another transfer. It has to use the bus to read the QH data structure, because reading the RAM is how it find out if you've queued another transfer. If you have, then it will send the IN token on the cable, and if the device responds with an ACK and DATA tokens, it writes the bytes into RAM.

But even if the device always answers NAK, and even you don't queue any transfer, the controller is periodically reading the RAM. That's how it does almost everything. It's not like conventional peripherals where its I/O registers are used. The registers are limited to very basic stuff, like interrupt enable/status, notifying of a cable connect status, and configuring where in memory the async and periodic schedules are located. Everything else is done by a complex arrangement of arrays and linked lists in RAM. When the schedules are enabled, it's pretty regularly reading RAM to monitor those schedules to find out what you want it to do. You (or the lower level code I spent 4 months writing) give it work to do by linking more structs into those lists, and reap the results by finding the structs & buffers in RAM after its done the work.
 
Status
Not open for further replies.
Back
Top