usbx86-64interruptosdevhci

How to determine on which Root Hub Port is connected a usb device after an Enable Slot Command with the Intel's xHC?


I am writing a small driver for the Intel's xHC in a small hobby OS I boot with UEFI.

After I reset all Root Hub Ports, I get 2 Port Status Change Events which is because I asked QEMU to emulate a usb keyboard and a usb mouse in the command line. One Port Status Change Event for each device seems fair. After this, I follow the initialization steps for a USB device. As stated in the xHCI spec:

After the port successfully reaches the Enabled state, system software shall obtain a Device Slot for the newly attached device using an Enable Slot Command, as described in section 4.3.2.

I thus send an Enable Slot Command to each Root Hub Port for which there was a Port Status Change Event. This seems to work because I get 2 Command Completion Events on the Event Ring which both trigger an interrupt. Both of these events are marked with a completion code of 1 which indicates success.

My problem starts here. In the Port Status Change Event is a Port ID field which allows to determine which port triggered the event. In the Command Completion Event, there is none of that. I can link to the Command TRB which triggered the event but the Command TRB doesn't include the Port ID. My problem is that after an Enable Slot Command I need to create an Input Context including a Slot Context which should contain the Root Hub Port number.

I could keep a list of the ports to which I sent an Enable Slot Command but that opens up to race conditions especially once multiprocessing is enabled.

How do I properly get which Root Hub Port triggered the Command Completion Event?


Solution

  • A similar question has been asked on the linux-usb maillist.
    There, Mathias Nyman, points out that the Enable Slot is misleading because it doesn't enable the slot of a specific port instead the command just returns a free index in the Device Context Base Address Array.
    This index is the Slot ID value.

    The programmer has to set the corresponding entry (i.e. dev_ctx_base_addr[slot_id]) with a pointer to a Device Context structure and fill its Slot Context with whatever Port Number and Route String they deem appropriate.
    It's important to stress out that there is no a priori relationship between the Slot ID and the Port Number/Route String.

    So you can just have a queue of slots to initialize and dequeue them as the Command Completion Events arrive.