Previously, the USB async process implemented its own worker and event handling. This design allowed all USB code to hold the mutex while events were being processed. However, the async process is not used directly: transfer, enumeration, and initilization are all wrapped internally, so driver developers do not need to manage it themselves.
This change decouples the mutex from the USB sync thread, reducing the size of critical sections. The tradeoff is that any custom async thread implementation must now handle locking explicitly.
The implementation is also clearer by using taskqueue.