/** Clear all the interrutp status bits, these bits are Write-Clean. @param Uhc The UHCI device. **/ VOID UhciAckAllInterrupt ( IN USB_HC_DEV *Uhc ) { UhciWriteReg (Uhc->PciIo, USBSTS_OFFSET, 0x3F); // // If current HC is halted, re-enable it. Host Controller Process Error // is a temporary error status. // if (!UhciIsHcWorking (Uhc->PciIo)) { DEBUG ((EFI_D_ERROR, "UhciAckAllInterrupt: re-enable the UHCI from system error\n")); Uhc->Usb2Hc.SetState (&Uhc->Usb2Hc, EfiUsbHcStateOperational); } }
/** Check TDs Results. @param Uhc This UHCI device. @param Td UHCI_TD_SW to check. @param IsLow Is Low Speed Device. @param QhResult Return the result of this TD list. @return Whether the TD's result is finialized. **/ BOOLEAN UhciCheckTdStatus ( IN USB_HC_DEV *Uhc, IN UHCI_TD_SW *Td, IN BOOLEAN IsLow, OUT UHCI_QH_RESULT *QhResult ) { UINTN Len; UINT8 State; UHCI_TD_HW *TdHw; BOOLEAN Finished; Finished = TRUE; // // Initialize the data toggle to that of the first // TD. The next toggle to use is either: // 1. first TD's toggle if no TD is executed OK // 2. the next toggle of last executed-OK TD // QhResult->Result = EFI_USB_NOERROR; QhResult->NextToggle = (UINT8)Td->TdHw.DataToggle; QhResult->Complete = 0; while (Td != NULL) { TdHw = &Td->TdHw; State = (UINT8)TdHw->Status; // // UHCI will set STALLED bit when it abort the execution // of TD list. There are several reasons: // 1. BABBLE error happened // 2. Received a STALL response // 3. Error count decreased to zero. // // It also set CRC/Timeout/NAK/Buffer Error/BitStuff Error // bits when corresponding conditions happen. But these // conditions are not deadly, that is a TD can successfully // completes even these bits are set. But it is likely that // upper layer won't distinguish these condtions. So, only // set these bits when TD is actually halted. // if ((State & USBTD_STALLED) != 0) { if ((State & USBTD_BABBLE) != 0) { QhResult->Result |= EFI_USB_ERR_BABBLE; } else if (TdHw->ErrorCount != 0) { QhResult->Result |= EFI_USB_ERR_STALL; } if ((State & USBTD_CRC) != 0) { QhResult->Result |= EFI_USB_ERR_CRC; } if ((State & USBTD_BUFFERR) != 0) { QhResult->Result |= EFI_USB_ERR_BUFFER; } if ((Td->TdHw.Status & USBTD_BITSTUFF) != 0) { QhResult->Result |= EFI_USB_ERR_BITSTUFF; } if (TdHw->ErrorCount == 0) { QhResult->Result |= EFI_USB_ERR_TIMEOUT; } Finished = TRUE; goto ON_EXIT; } else if ((State & USBTD_ACTIVE) != 0) { // // The TD is still active, no need to check further. // QhResult->Result |= EFI_USB_ERR_NOTEXECUTE; Finished = FALSE; goto ON_EXIT; } else { // // Update the next data toggle, it is always the // next to the last known-good TD's data toggle if // any TD is executed OK // QhResult->NextToggle = (UINT8) (1 - (UINT8)TdHw->DataToggle); // // This TD is finished OK or met short packet read. Update the // transfer length if it isn't a SETUP. // Len = (TdHw->ActualLen + 1) & 0x7FF; if (TdHw->PidCode != SETUP_PACKET_ID) { QhResult->Complete += Len; } // // Short packet condition for full speed input TD, also // terminate the transfer // if (!IsLow && (TdHw->ShortPacket == 1) && (Len < Td->DataLen)) { DEBUG ((EFI_D_VERBOSE, "UhciCheckTdStatus: short packet read occured\n")); Finished = TRUE; goto ON_EXIT; } } Td = Td->NextTd; } ON_EXIT: // // Check whether HC is halted. Don't move this up. It must be // called after data toggle is successfully updated. // if (!UhciIsHcWorking (Uhc->PciIo)) { QhResult->Result |= EFI_USB_ERR_SYSTEM; Finished = TRUE; } if (Finished) { Uhc->PciIo->Flush (Uhc->PciIo); } UhciAckAllInterrupt (Uhc); return Finished; }