I have a USB MIDI controller that USBHost_t36 connects to only some of the time, and
I have collected logs of what happens when it fails. I think they point at two small
gaps in enumeration, and I would be glad to test or write a patch if that is welcome.
Setup
- Teensy 4.1, device plugged directly into the USB host port
- Donner StarryCtrl. It reports as "Jieli Technology" / "SINCO", VID 4353 PID 4B4D,
full speed, EP0 max packet 64. It is battery powered and was switched on throughout.
- USBHost_t36 master at 0463fc1, with USBHOST_PRINT_DEBUG defined
- Other devices are fine on the same port. An IK Multimedia iRig Keys 25 enumerates
first time, every time.
Result
Four plug-ins on current master, hands off the cable after each:
1. First request sent, then the device disconnects and reconnects BY ITSELF.
Second pass enumerates completely and MIDIDevice claims it. Works.
2. First request sent (state 0), then nothing. No error, no port change.
Silent for more than 10 seconds, until I unplug.
3. Disconnect/reconnect by itself, second pass reads the device descriptor,
then stalls at state 3 (language ID string request).
4. Disconnect/reconnect twice, third pass reads the device descriptor, language ID
and manufacturer string, then stalls at state 5 (product string request).
So one success in four. The library bundled with Teensyduino 1.59 behaves like run 2:
it stalls after new_Pipe and only a replug helps.
Run 2, the silent stall:
Run 4, the end of the third pass:
I have attached the full logs for all four runs.
The device is clearly at fault. But in every failure the port stays enabled and no
error is raised, so as far as I can tell the device is simply not answering (NAKing)
and the request waits forever. The recovery added in December (enumeration_error,
retry up to 25 times) never runs, because it is driven by the error callback and there
is no error.
Every pass that reached the device descriptor read it correctly. Both stalls that came
after a good start were on a string descriptor.
One more data point. I'm working on Rust libraries for the Teensy. On the same Teensy and the same port,
I was able to get imxrt-usbh with cotton-usb-host to work by resetting the port after failure and retrying
enumeration. I got ten plug ins in a row succeeding with that code - USBHost_t36 works about 20% of the
time. The Rust stack never asks for string descriptors.
TWO SUGGESTIONS
1. Time out a string descriptor request and move on. The strings are only used for
display, so a device that will not serve one could still enumerate.
2. A watchdog on enumeration progress. If no state advances within about a second,
reset the port and start again, up to a few times. This would cover the stall on
the first request, which cannot be skipped.
I have not built either, so I cannot say they cure this device on USBHost_t36. I am
happy to try, or to test anything you would rather do instead. Would a patch along
these lines be welcome, and do you have a preference between the two?
I have collected logs of what happens when it fails. I think they point at two small
gaps in enumeration, and I would be glad to test or write a patch if that is welcome.
Setup
- Teensy 4.1, device plugged directly into the USB host port
- Donner StarryCtrl. It reports as "Jieli Technology" / "SINCO", VID 4353 PID 4B4D,
full speed, EP0 max packet 64. It is battery powered and was switched on throughout.
- USBHost_t36 master at 0463fc1, with USBHOST_PRINT_DEBUG defined
- Other devices are fine on the same port. An IK Multimedia iRig Keys 25 enumerates
first time, every time.
Result
Four plug-ins on current master, hands off the cable after each:
1. First request sent, then the device disconnects and reconnects BY ITSELF.
Second pass enumerates completely and MIDIDevice claims it. Works.
2. First request sent (state 0), then nothing. No error, no port change.
Silent for more than 10 seconds, until I unplug.
3. Disconnect/reconnect by itself, second pass reads the device descriptor,
then stalls at state 3 (language ID string request).
4. Disconnect/reconnect twice, third pass reads the device descriptor, language ID
and manufacturer string, then stalls at state 5 (product string request).
So one success in four. The library bundled with Teensyduino 1.59 behaves like run 2:
it stalls after new_Pipe and only a replug helps.
Run 2, the silent stall:
Code:
port change: 10001803
connect
begin reset
port change: 10001805
port enabled
end recovery
new_Device: 12 Mbit/sec
new_Pipe
enumeration_transmit, state 0
[ 127s] no USB-MIDI device on the host port
[ 132s] no USB-MIDI device on the host port
Run 4, the end of the third pass:
Code:
enumeration_receive, state 2
Device Descriptor:
12 01 10 01 00 00 00 40 53 43 4D 4B 00 01 01 02 03 01
VendorID = 4353, ProductID = 4B4D, Version = 0100
enumeration_transmit, state 3
enumeration_receive, state 3
enumeration_transmit, state 4
enumeration_receive, state 4
Manufacturer: Jieli Technology
enumeration_transmit, state 5
[ 207s] no USB-MIDI device on the host port
I have attached the full logs for all four runs.
The device is clearly at fault. But in every failure the port stays enabled and no
error is raised, so as far as I can tell the device is simply not answering (NAKing)
and the request waits forever. The recovery added in December (enumeration_error,
retry up to 25 times) never runs, because it is driven by the error callback and there
is no error.
Every pass that reached the device descriptor read it correctly. Both stalls that came
after a good start were on a string descriptor.
One more data point. I'm working on Rust libraries for the Teensy. On the same Teensy and the same port,
I was able to get imxrt-usbh with cotton-usb-host to work by resetting the port after failure and retrying
enumeration. I got ten plug ins in a row succeeding with that code - USBHost_t36 works about 20% of the
time. The Rust stack never asks for string descriptors.
TWO SUGGESTIONS
1. Time out a string descriptor request and move on. The strings are only used for
display, so a device that will not serve one could still enumerate.
2. A watchdog on enumeration progress. If no state advances within about a second,
reset the port and start again, up to a few times. This would cover the stall on
the first request, which cannot be skipped.
I have not built either, so I cannot say they cure this device on USBHost_t36. I am
happy to try, or to test anything you would rather do instead. Would a patch along
these lines be welcome, and do you have a preference between the two?