Page 1 of 1

usb hub: ohci interrupt for port, port GET_STATUS

Posted: Sat Jun 03, 2023 4:54 pm
by sounds
Briefly: I'm using qemu to emulate a usb hub. The interrupt endpoint is set up using the OHCI controller. The interrupt transfer is posted by the OHCI controller, so I immediately send a setup TD to send GET_STATUS to the port. To my surprise, I get a second interrupt transfer posted before the GET_STATUS response, which makes it impossible to send a CLEAR_FEATURE to the port to stop the interrupt from firing.

2 x interrupts? Something feels off.

Yes, it kind of makes sense. I can live with it. But I wanted to check if there is no better solution than what I currently have. I ignore all interrupts from the interrupt endpoint until I've completed GET_STATUS and done a CLEAR_FEATURE to clear the set bits that triggered the interrupt. Or, alternatively I could block the interrupt transfer in the controller, but that would prevent interrupts from the other ports on the hub so I think that's incorrect.

Any suggestions for a way to respond to the interrupt TD with successful GET_STATUS and CLEAR_FEATURE TD's before getting additional interrupt TD's?

Re: usb hub: ohci interrupt for port, port GET_STATUS

Posted: Sat Jun 03, 2023 7:30 pm
by BenLunt
If I understand you correctly, you have set up the Periodic List to return a 1-byte (7 ports or less) change status. Once you have received this byte, if a change is detected, you then use the Control Pipe to request the 4-byte status of the hub. Once you have done this, you then send a Clear Feature request (on the Control Pipe) to clear the change status.

Is this correct?

What interrupt are you talking about? A hardware interrupt? Is it because the DoneHead value is being written after the Periodic list is executed?
If you are taking about a new Interrupt TD being executed, this could happen depending on the rate of the check. Your Periodic list could be using a 16ms check and your HubGetPortStatus() routine could be taking more than 16ms to process the change. An external hub usually indicates a 0xFFms interval (or round up to 256ms).

The second (hardware) interrupt may have nothing to do with the external hub port status event. It could be something else, simply that the controller is again, done with the list.

When you get the initial interrupt, at the start of your "HubGetPortStatus" routine check to see if you are already processing the change. If so, simply return. Once you are done with the Change Event (indicate an enumeration of new device or a removal of a device), get the status one more time to see if there was a change between the first initial call and now the end of the process. If so, repeat for a different port change event. If no other change was found, clear the "InThisRoutine" flag and return.

Code: Select all

HubGetPortStatus() {
  if (InThisRoutine)
    return;
  InThisRoutine = 1;
  do {
    HubStatus = GetHubStatus();
    .
    . Do Something because of the change event (enumerate new device, removal of device, etc.)
    .
  while (HubStatus != GetHubStatus());
  ClearFeature();
  InThisRoutine = 0;
  return;
}
Of course this is simply a mock-up example, but you may get the point.

Hope this helps,
Ben
- https://www.fysnet.net/the_universal_serial_bus.htm

Re: usb hub: ohci interrupt for port, port GET_STATUS

Posted: Sat Jun 03, 2023 11:21 pm
by sounds
Thanks, Ben. Very helpful. I ran out of time to post a detailed response, but will follow up with a detailed dump. I'm guessing I'm not properly interpreting the endpoint descriptor with interval = 0xff for the qemu emulated hub.