I got my hands on a rt2800usb device. Mine differs slightly in which vendor/product it shows (it's sold by Belkin) and in which firmware it requests (rt2870.bin), but I suppose the issues will be similar.

Josef wrote:
So far the RT2800USB driver is non-working and the next step is figuring
out why. For that I will take a closer look at your USB back-end work
and its integration into the kernel.

I have done some investigation into this (see [1]), there is a simple issue and a harder issue.

The simple issue is that for ath9k all control transfers were outgoing, so I simply neglected to support incoming control transfers. That was easily fixed, but exposed the other issue.

The harder issue is that Usb::Packet_handler::submit can block, allowing IO (including timer) signals to be handled. Timer signals in turn can use Lx_kit::Scheduler::schedule to try to run the kernel. Hence, it is a risk to submit any USB transaction from the kernel emulation stack, since this will be a re-entrant call to schedule if it does block and a timer fires. For whatever reason this never happened with ath9k, but seems to happen with rt2800usb. Therefore what I plan to try is to make every emulated USB transaction post to an emulator-maintained queue [2], and send an application-level signal to trigger later processing by a function on the main stack. You could imagine short-cutting this for cases where you were sure it wouldn't block, but there does not seem to be an easily exposed way to check this (it's private to the implementation). Alternatively lx_kit could use the IO-level timer handler to trigger a second application-level handler, which in turn performs the scheduling (this is what I am doing to handle completions). In this way the USB submit can be called from the kernel stack, perhaps. But that requires changes to lx_kit and may possibly break other things.

[1] https://github.com/cvparker/genode-world/tree/ath9k_driver_support-2023-01-22

[2] P.S. I already had to implement this partially in order to throttle the rate of incoming URBs submitted, otherwise the queue fills with pending incoming URBs but there's no room for the outgoing URB that's necessary to initiate the incoming transactions - so it deadlocks.