programs should now use the usb-cramium crate for a USB
stack. It preserves the `lib` API, so you /should/ be able to
integrate it seamlessly by just renaming crates between
the two.
we're going to strip out the USB cramium support from this crate
eventually because it has migrated to a stand-alone crate
the hardware model is just too different to keep the two branches
in sync: one allows interrupts to be delegated to userspace, the other
requires the interrupts to happen all in the locked handler context
due to timing assumptions of the core.
the problem with the interrupt handler context is that panics
are really hard to debug - you can't actually send a panic message
from an interrupt context, because there is no IPC when the
handler is running. Normally we try to keep the handlers as
minimal as possible, but in this case we can't due to hardware
assumptions.
realizing a bunch of stuff like the stack expects you to enqueue
the OUT receiver with calls to read() that happen to block, fixing
max packet size that can be different for in and out end points,
and handling quirks of the core when sending setup packets longer than
64 bytes.
the UsbBus implementation is being totally rewritten for the
inside-out IRQ protected scheme.
we can now get past some preliminaries in the link protocol
(i.e., address setting and the first config descriptor), but
a long way to go still in debugging.
the uart in the shared library is claimed by the first process
that touches it, so prints in the shared library at early boot have
to be carefully configured
- disable IRQs on departure
- put EV enable outside of the HAL function
this is necessary because we need all HAL calls to be finished
before an interrupt happens to avoid locking problems
The approach here turns the usb-device crate "inside out". The
working hypothesis for the unreliability of the previous implementation
is that we try to do all the IRQ-handling in userspace, where
the operation can be pre-empted. Unfortunately, this doesn't set well
with the corigine USB hardware driver, as it assumes that it has
the full CPU attention while its state is being manipulated (and
some things must be responded to in basically real time otherwise
you get protocol inconsistencies).
In this implementation, we use the Xous subsystem to do the
API-level exchanges of information to a USB handler that, for the
most part, runs directly inside an IRQ context.
There's some trickiness in terms of sharing the hardware state
across the boundary between IRQ and userland, but most of it
got handled I think fairly cleanly in this implemnetation by
using the xous-native server queuing mechanism to shuttle data
in between the two domains. The main spot where I think panics
can creep in is in data transmission, where the Tx data is
shoved into a RefCell and then the IRQ is invoked to pull the
data from a RefCell. As long as we don't invoke the IRQ to
pull data from the RefCell while it's borrowed mutably, we should
be OK.
Wrapping the structure in a Mutex actually doesn't help here
because the IRQ context can't do a "wait" to get a lock - it
would never get it, because it's in an uninterruptable context.
Thus we skip the complexity of a Mutex and let Rust panic if
we mesesd up the data hand-off.