Instead of using GetKeyWait(), we directly call into an internal OS
function, which avoids the need to press a key before we can redraw over
the OS banner and VRAM when coming back. The disassembly to locate the
function was developed by Dr-Carlos.
We still have to redraw when coming back; getkey() will do it by
dupdate() by default, and it that's not a possibility for the
application an option to receive a special event and handle it manually
is provided.
This looks like it could work in the long term. The only issue that
really hasn't been addressed is how to use packet counters to cut
transactions when there's no ZLP, but we can leave that for later.
The previous scheme was really unclear. Now, an endpoint_t carries all
of the endpoint info (instead of the global address being implicitly
its array index, which couldn't be returned).
An _endpoint address_ is the 8-bit value consisting of an endpoint
number (bits 0x0f) and a direction (bit 0x80).
The _global address_ of an endpoint is the address used to communicate
with the host, and it is unique. The _local address_ of an endpoint is
the interface-specific numbering that gint provides to allow interfaces
to compose without risks of address collisions.
The complete data for an endpoint can be queried with the new functions
usb_get_endpoint_by_*() which accept global addresses, local addresses,
and pipe numbers.
* Clear pipes and FIFOs during world switches to avoid interference
with the OS. LINK uses pipes 3 and 4, and attempts to add a second
pipe to the fxlink interface (thus using pipe 4) would interfere with
LINK and somehow prevent the pipe from being used (Wireshark captures
showed no responses on that pipe). Forcing a blank state is a valid
move because that state occurs naturally after a RESET, thus LINK and
other add-ins must support it as well.
* Delay the application of configuration to the USB configuration stage
(specifically, the DVST configured interrupt, even though technically
we should do that in SET_CONFIGURATION 0). This is because we
previously relied on world switches preserving pipe settings (by not
changing them) to reconnect the gint driver after a world switch.
This is no longer possible as the world switch now clears the pipes.
The new timing makes the driver automatically re-configure as the
connection restarts.
* Move logic around tracking transfers to asyncio.c.
* Add a "short buffer" holding 0-3 bytes between writes, so that the
driver performs only 4-byte writes in the FIFO and a short write in
the commit, if needed.
- This is partially due to me thinking at some point that degrading
writing size was impossible, but it might actually be possible by
writing to FIFO/FIFO+2 or FIFO/FIFO+1/FIFO+2/FIFO+3.
- In any case I think this new approach wins on performance.
* Get rid of unit_size since we now always use 4 bytes.
* Add a waiting function which is used in usb_close() (and once tested
should be used in world switches too).
* Eliminate some of the special cases for the DCP, though not all (in
particular I can't get the commit to rely on the BEMP interrupt yet,
nor can I properly clear PID to NAK when unbinding).
* Finish updating the register list
* Use RTC-based timeouts to not involve more interrupts
* Be a lot more conservative about PID=BUF
* Start setting up parameters and checking invariants for future
bidirectional communications
* Add options to RESET, go to menu, or abort()
* Define weak symbols for driver functions so that low-level debugging
add-ins can be linked with minimal drivers (CPU/INTC/MMU)