-
Notifications
You must be signed in to change notification settings - Fork 79
Add new read_setup() for control endpoints #153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
@9names ran some tests of this with Raspberry Pi 5 host and SAMD21, confirming the problem (enumeration being unreliable) and that this appears to resolve it. While confirming the problem, 9names saw the new test case error out in an unexpected way - reporting |
Sorry, I've not had an opportunity to look at the test code changes here, and probably won't be able to test Rust USB stuff until mid December at earliest. Since the test stuff isn't really critical, I'd like to proceed with this PR so that implementors can do their part. |
Out of interest, what is blocking this PR? As it is required to get USB functioning on the ATSAMD platform properly. |
@eldruin @ryan-summers - Apologies for my sporadic involvement with this, I'd like to get it over the line but it's not clear to me what the next step should be. The important change is about the API change, but in order to demonstrate the problem I made some fairly large changes to the testing infrastructure, maybe those should be separated? Also, I'm hesitant to offer as I've not been doing much programming lately, but I could try to help out with maintaining usb-device by reviewing other PRs/issues if that might help share the load a bit. Would prefer to not accept my own PRs of course! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for your work on this.
- Have you looked deeper into the
Entity not found
test error? I hesitate to merge a test that may fail for unrelated and unclear reasons when another PR is submitted. - IIUC, this is a breaking change, so we would need to release a 0.4 version, which will lead to a lot of friction across the ecosystem given the position of this crate. Do you have an impression of the breakage and solutions when attempting to mix
usb-device
versions in applications and HALs? - One thing missing here is an entry to the changelog.
- I would welcome you to the org if you are interested to join. Mostly we do 4-eye principle so that at least one more person has a look at the changes. This is not a formal policy, though. Have a look here for further info.
Need to support a test that hard resets the device and ensures that it re-enumerates. The current model supplies a device handle to the test case, but this case will require a handle to the rusb context so that it can determine when the device has enumerated.
This reduces log noise for tests that reset the device under test
Needed for testing enumeration time
|
One thing I'm curious about: have other UsbBus implementations than the Microchip SAM HAL got some clever solution for this, with the existing usb-device? My hunch is that it isn't possible to make a correctly-behaving device without some way to distinguish between reads of SETUP and OUT data, but my usb-device experience is limited to SAMD devices. |
I had some troubles with zlp followed by setup while implementing it on rp2040. EDIT: And if a ZLP got discarded by the hardware/software, we ignore it here. |
Interesting, thanks @ithinuel ! That is a clever workaround, and I think the need for it shows that the usb-device API has a bit of a gap in this area. I'll rework this PR a little so it doesn't talk about the SAMD target, because your example shows the same underlying issue. Presuming that the RP2040 USB peripheral works like the SAMD one, I'd note that the workaround leaves a possibly-large timing hole - if poll() is called after the ZLP, poll() returns, SETUP appears, then ep_read() is called. |
True, I realize that as I was looking at the code & thinking of your use case:
That being said, I never experienced any issue with it so far. I’m using the rp2040 as my keyboard through a KVM causing the usb to re-enumerate everytime I switch computer. |
When that happened in the SAMD case, the read() would fail (silently, IIRC) and the host would retry the SETUP unless it had failed too many times. With most hosts, it was reliable enough to just be an annoyance (enumeration would take a second or two longer) but some never worked. |
This change aims to resolve issues where an expected OUT Zero Length Packet (ZLP) was overwritten by a subsequent SETUP transaction. The USB spec requires that devices accept SETUP transactions, this behaviour is implemented directly in some USB hardware. To allow the control pipe implementation to distinguish between OUT data and SETUP data, the read() method was changed to return an error if SETUP data was present, and a new read_setup() was added that expects SETUP data not OUT data.
Just a nudge on this - maybe good to integrate a couple outstanding PRs (eg #147) and cut a release. My feeling is that, although it's a pain to update all the other crates, this is as the documentation states a work-in-progress and this PR allows the HAL implementations to fix incorrect behaviour. |
Background can be found at atsamd-rs/atsamd#738 .
The USB spec says that the SETUP transactions used with control endpoints must always be accepted by the device [1], and at least in the Microchip SAMD21's USB peripheral that behaviour is handled in hardware [2]. We've observed that some hosts will send an OUT ZLP, followed very shortly by a SETUP for a new transaction - on the SAMD21 parts this results in the OUT data (none, in this case) being overwritten by SETUP, which in the existing implementation results in an overflow error (since
read()
was called with a zero length slice for the OUT ZLP, but >0 bytes are available from the SETUP that overwrote it). The user-observable result is that the device fails to enumerate at all on some hosts, or sporadically on others.In light of this, it seems the control pipe code needs some way to differentiate reads of OUT data from reads of SETUP data. This PR changes the existing
read()
methods to return an error if SETUP data is present, making it specific to OUT data, and adds a newread_setup()
method specifically for reading SETUP data.Most of the commits/diff here are work on the test framework, to add a new test that resets the device and times how long it takes to re-enumerate. The test is a bit crude, but seems to validate the changes to the read methods.
[1] USB 2.0 spec section 5.5.5 Control Transfer Data Sequences:
[2] SAMD21 datasheet DS40001882H section 32.6.2.6 Management of SETUP Transactions. The key thing here is that the data is copied in to the buffer regardless of BK0RDY.