Skip to content
Jakub Jermář edited this page Dec 28, 2017 · 2 revisions

The XHCI stack is capable of handling scenarios when USB devices are physically disconnected from the bus. When such an event occurs, the Device Manager ought to be notified in order to relay gone message to other drivers, which may be communiating with the disconnected device at that moment, and execute overall process of deinitialization and memory deallocation associated with the detachment of the device.

Disconnection Routine

In XHCI, the xHC abstracts the physical topology of the USB bus to the host controller driver. For that reason, all devices appear to the HCD as if they were connected to some port of the xHC's root hub. This results in great simplification of the disconnection process.

When a device is physically disconnected from the bus, a port change event is generated by the root hub on the respective port. Such event informs the HCD that the connected state has changed (using the CSC bit) and that there is no device physically connected to the port anymore (using the CCS bit). Upon receiving such an update, the HCD initiates the removal of the device from the XHCI bus.

The device is first marked as offline (i.e. incapable of initiating any new transfers). This is followed by the immediate abortion of all in-flight transfers to all of its endpoints.

At this point, any USB drivers operating on the disconnected device usually start receiving I/O errors. A common driver policy in such situation is to retry the failed transfers several times before giving up (especially when polling). This approach however yields no success since the creation of new transfers has been inhibited prior to the abortion of the existing ones. This design results in the USB drivers reporting failure to any child drivers or user software before disengaging their previous communication with the device and deallocating their data structures.

The HCD continues the routine by unbinding the DDF function of the disconnected device, effectively triggering the gone callback in all drivers bound onto the function's subtree. It is at this point when most deadlocks may occur since the Device Manager relies on user space drivers to efficiently propagate the gone signal to all of their child functions (and drivers) before removing them.

In the end, the HCD instructs the xHC to disable the slot of the disconnected device and unregisters all of the its endpoints along with all of their transfer data structures.

Expected Disconnection

The HelenOS Device Driver Framework includes a user-initiated signal which informs active drivers that their managed device may be removed in the near future. Named fun_offline, this callback is a good opportunity for drivers to flush their buffers and terminate all in-flight communications, resulting in a consistent state before the physical detachment happens.

The USB host controller library has been appropriately extended to relay this signal to the implementation of the USB bus. In the XHCI bus, this signal is simply handled by marking the DDF function corresponding to the device as offline, triggering the device_remove callback in all drivers bound onto its subtree (and their possible removal by the Device Manager). The device itself is then transitioned to the offline state, inhibiting any new transfers from taking place, and all of its endpoints are removed with the exception of the endpoint zero, which is used for configuration control messages from the HCD. Lastly, the xHC is instructed to deconfigure the device.

If a physical detachment occurs in this state, the beginning of the disconnection routine, which inhibts and aborts in-flight transfers is rendered unnecessary, and can be skipped up to the point when the DDF function is removed from the Device Manager tree, greatly reducing the amount of work to be done as well as the probability that the detached device will be left in an inconsistent state.

The user can initiate the fun_offline signal for instance by executing the following command in the shell:

# devctl offline <device path>

Rolling back

The Device Driver Framework also includes the fun_online signal, which is a counterpart to fun_offline. This signal is understood as the user changing their mind about the imminent disconnection of a device, and asking the OS to reestablish all communications with the device, so that it can be accessed and used again.

For due dilligence, fun_online is propagated through the USB host controller library to the bus implementation in the same way as fun_offline. The XHCI bus responds to this signal by executing the exact inverse of the sequence described in the previous section, eventually marking the device as online, notifying the Device Manager, which then activates the respective drivers and calls their device_add callbacks.

The user can initiate the fun_online signal for instance by executing the following command in the shell:

# devctl online <device path>

Propagating the offline/online calls

The USB device driver library has been extended to accept the fun_offline and fun_online signals from DDF and unpack and relay them to proprietary device drivers in an appropriate callbacks.

While this feature is not expected to be used often, it may prove useful when implementing drivers for USB devices, which connect the host to other buses (e.g. Ethernet), and might thus need the capability to notify various drivers bound onto their functions.