UINT32 CheckEDStatus ( IN ED_DESCRIPTOR *Ed, IN TD_DESCRIPTOR *HeadTd ) { while(HeadTd != NULL) { if (HeadTd->Word0.ConditionCode != 0) { return HeadTd->Word0.ConditionCode; } HeadTd = HeadTd->NextTDPointer; } if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) { return TD_TOBE_PROCESSED; } return TD_NO_ERROR; }
UINT32 CheckEDStatus ( IN ED_DESCRIPTOR *Ed, IN TD_DESCRIPTOR *HeadTd, OUT OHCI_ED_RESULT *EdResult ) { while(HeadTd != NULL) { if (HeadTd->NextTDPointer == 0) { return TD_NO_ERROR; } if (HeadTd->Word0.ConditionCode != 0) { return HeadTd->Word0.ConditionCode; } EdResult->NextToggle = ((UINT8)(HeadTd->Word0.DataToggle) & BIT0) ^ BIT0; HeadTd = (TD_DESCRIPTOR *)(UINTN)(HeadTd->NextTDPointer); } if (OhciGetEDField (Ed, ED_TDHEAD_PTR) != OhciGetEDField (Ed, ED_TDTAIL_PTR)) { return TD_TOBE_PROCESSED; } return TD_NO_ERROR; }
VOID EFIAPI OhciHouseKeeper ( IN EFI_EVENT Event, IN VOID *Context ) { USB_OHCI_HC_DEV *Ohc; INTERRUPT_CONTEXT_ENTRY *Entry; INTERRUPT_CONTEXT_ENTRY *PreEntry; ED_DESCRIPTOR *Ed; TD_DESCRIPTOR *DataTd; TD_DESCRIPTOR *HeadTd; UINT8 Toggle; EFI_TPL OriginalTPL; UINT32 Result; Ohc = (USB_OHCI_HC_DEV *) Context; OriginalTPL = gBS->RaiseTPL(TPL_NOTIFY); Entry = Ohc->InterruptContextList; PreEntry = NULL; while(Entry != NULL) { OhciCheckTDsResults(Ohc, Entry->DataTd, &Result ); if (((Result & EFI_USB_ERR_STALL) == EFI_USB_ERR_STALL) || ((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)) { PreEntry = Entry; Entry = Entry->NextEntry; continue; } if (Entry->CallBackFunction != NULL) { OhciInvokeInterruptCallBack (Entry, Result); if (Ohc->InterruptContextList == NULL) { gBS->RestoreTPL (OriginalTPL); return; } } if (Entry->IsPeriodic) { Ed = Entry->Ed; HeadTd = Entry->DataTd; DataTd = HeadTd; Toggle = 0; if (Result == EFI_USB_NOERROR) { // // Update toggle if there is no error, and re-submit the interrupt Ed&Tds // if ((Ed != NULL) && (DataTd != NULL)) { Ed->Word0.Skip = 1; } // // From hcir1_0a.pdf 4.2.2 // ToggleCarry:This bit is the data toggle carry bit, // Whenever a TD is retired, this bit is written to // contain the last data toggle value(LSb of data Toggel // file) from the retired TD. // This field is not used for Isochronous Endpoints // if (Ed == NULL) { return; } Toggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); while(DataTd != NULL) { if (DataTd->NextTDPointer == 0) { DataTd->Word0.DataToggle = 0; break; } else { OhciSetTDField (DataTd, TD_DT_TOGGLE, Toggle); } DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); Toggle ^= 1; } // // HC will only update DataToggle, ErrorCount, ConditionCode // CurrentBufferPointer & NextTD, so we only need to update // them once we want to active them again // DataTd = HeadTd; while (DataTd != NULL) { if (DataTd->NextTDPointer == 0) { OhciSetTDField (DataTd, TD_ERROR_CNT | TD_COND_CODE | TD_CURR_BUFFER_PTR | TD_NEXT_PTR, 0); break; } OhciSetTDField (DataTd, TD_ERROR_CNT, 0); OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); DataTd->NextTD = DataTd->NextTDPointer; DataTd->CurrBufferPointer = DataTd->DataBuffer; DataTd = (TD_DESCRIPTOR *)(UINTN)(DataTd->NextTDPointer); } // // Active current Ed,Td // // HC will only update Halted, ToggleCarry & TDQueueHeadPointer, // So we only need to update them once we want to active them again. // if ((Ed != NULL) && (DataTd != NULL)) { Ed->Word2.TdHeadPointer = (UINT32)((UINTN)HeadTd>>4); OhciSetEDField (Ed, ED_HALTED | ED_DTTOGGLE, 0); Ed->Word0.Skip = 0; } } } else {
/** Submits bulk transfer to a bulk endpoint of a USB device. @param PeiServices The pointer of EFI_PEI_SERVICES. @param This The pointer of PEI_USB_HOST_CONTROLLER_PPI. @param DeviceAddress Target device address. @param EndPointAddress Endpoint number and its direction in bit 7. @param MaxiPacketLength Maximum packet size the endpoint is capable of sending or receiving. @param Data A pointers to the buffers of data to transmit from or receive into. @param DataLength The lenght of the data buffer. @param DataToggle On input, the initial data toggle for the transfer; On output, it is updated to to next data toggle to use of the subsequent bulk transfer. @param TimeOut Indicates the maximum time, in millisecond, which the transfer is allowed to complete. @param TransferResult A pointer to the detailed result information of the bulk transfer. @retval EFI_SUCCESS The transfer was completed successfully. @retval EFI_OUT_OF_RESOURCES The transfer failed due to lack of resource. @retval EFI_INVALID_PARAMETER Parameters are invalid. @retval EFI_TIMEOUT The transfer failed due to timeout. @retval EFI_DEVICE_ERROR The transfer failed due to host controller error. **/ EFI_STATUS EFIAPI OhciBulkTransfer ( IN EFI_PEI_SERVICES **PeiServices, IN PEI_USB_HOST_CONTROLLER_PPI *This, IN UINT8 DeviceAddress, IN UINT8 EndPointAddress, IN UINT8 MaxPacketLength, IN OUT VOID *Data, IN OUT UINTN *DataLength, IN OUT UINT8 *DataToggle, IN UINTN TimeOut, OUT UINT32 *TransferResult ) { USB_OHCI_HC_DEV *Ohc; ED_DESCRIPTOR *Ed; UINT32 DataPidDir; TD_DESCRIPTOR *HeadTd; TD_DESCRIPTOR *DataTd; TD_DESCRIPTOR *EmptyTd; EFI_STATUS Status; UINT8 EndPointNum; UINTN TimeCount; UINT32 ErrorCode; UINT8 CurrentToggle; UINTN MapLength; EFI_PHYSICAL_ADDRESS MapPyhAddr; UINTN LeftLength; UINTN ActualSendLength; BOOLEAN FirstTD; MapLength = 0; MapPyhAddr = 0; LeftLength = 0; Status = EFI_SUCCESS; if (Data == NULL || DataLength == NULL || DataToggle == NULL || TransferResult == NULL || *DataLength == 0 || (*DataToggle != 0 && *DataToggle != 1) || (MaxPacketLength != 8 && MaxPacketLength != 16 && MaxPacketLength != 32 && MaxPacketLength != 64)) { return EFI_INVALID_PARAMETER; } Ohc = PEI_RECOVERY_USB_OHC_DEV_FROM_EHCI_THIS (This); if ((EndPointAddress & 0x80) != 0) { DataPidDir = TD_IN_PID; } else { DataPidDir = TD_OUT_PID; } EndPointNum = (EndPointAddress & 0xF); OhciSetHcControl (Ohc, BULK_ENABLE, 0); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 0) { *TransferResult = EFI_USB_ERR_SYSTEM; return EFI_DEVICE_ERROR; } } OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, NULL); Ed = OhciCreateED (Ohc); if (Ed == NULL) { DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate ED buffer\r\n")); return EFI_OUT_OF_RESOURCES; } OhciSetEDField (Ed, ED_SKIP, 1); OhciSetEDField (Ed, ED_FUNC_ADD, DeviceAddress); OhciSetEDField (Ed, ED_ENDPT_NUM, EndPointNum); OhciSetEDField (Ed, ED_DIR, ED_FROM_TD_DIR); OhciSetEDField (Ed, ED_SPEED, HI_SPEED); OhciSetEDField (Ed, ED_FORMAT | ED_HALTED | ED_DTTOGGLE, 0); OhciSetEDField (Ed, ED_MAX_PACKET, MaxPacketLength); OhciSetEDField (Ed, ED_PDATA, 0); OhciSetEDField (Ed, ED_ZERO, 0); OhciSetEDField (Ed, ED_TDHEAD_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_TDTAIL_PTR, (UINT32) NULL); OhciSetEDField (Ed, ED_NEXT_EDPTR, (UINT32) NULL); OhciAttachEDToList (Ohc, BULK_LIST, Ed, NULL); if(Data != NULL) { MapLength = *DataLength; MapPyhAddr = (EFI_PHYSICAL_ADDRESS)(UINTN)Data; } // //Data Stage // LeftLength = MapLength; ActualSendLength = MapLength; CurrentToggle = *DataToggle; HeadTd = NULL; FirstTD = TRUE; while (LeftLength > 0) { ActualSendLength = LeftLength; if (LeftLength > MaxPacketLength) { ActualSendLength = MaxPacketLength; } DataTd = OhciCreateTD (Ohc); if (DataTd == NULL) { DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Data TD buffer\r\n")); Status = EFI_OUT_OF_RESOURCES; goto FREE_TD_BUFF; } OhciSetTDField (DataTd, TD_PDATA, 0); OhciSetTDField (DataTd, TD_BUFFER_ROUND, 1); OhciSetTDField (DataTd, TD_DIR_PID, DataPidDir); OhciSetTDField (DataTd, TD_DELAY_INT, TD_NO_DELAY); OhciSetTDField (DataTd, TD_DT_TOGGLE, CurrentToggle); OhciSetTDField (DataTd, TD_ERROR_CNT, 0); OhciSetTDField (DataTd, TD_COND_CODE, TD_TOBE_PROCESSED); OhciSetTDField (DataTd, TD_CURR_BUFFER_PTR, (UINT32) MapPyhAddr); OhciSetTDField (DataTd, TD_BUFFER_END_PTR, (UINT32) MapPyhAddr + ActualSendLength - 1); OhciSetTDField (DataTd, TD_NEXT_PTR, (UINT32) NULL); DataTd->ActualSendLength = ActualSendLength; DataTd->DataBuffer = (UINT8 *)(UINTN)MapPyhAddr; DataTd->NextTDPointer = 0; if (FirstTD) { HeadTd = DataTd; FirstTD = FALSE; } else { OhciLinkTD (HeadTd, DataTd); } CurrentToggle ^= 1; MapPyhAddr += ActualSendLength; LeftLength -= ActualSendLength; } // // Empty Stage // EmptyTd = OhciCreateTD (Ohc); if (EmptyTd == NULL) { Status = EFI_OUT_OF_RESOURCES; DEBUG ((EFI_D_INFO, "OhcBulkTransfer: Fail to allocate Empty TD buffer\r\n")); goto FREE_TD_BUFF; } OhciSetTDField (EmptyTd, TD_PDATA, 0); OhciSetTDField (EmptyTd, TD_BUFFER_ROUND, 0); OhciSetTDField (EmptyTd, TD_DIR_PID, 0); OhciSetTDField (EmptyTd, TD_DELAY_INT, 0); //OhciSetTDField (EmptyTd, TD_DT_TOGGLE, CurrentToggle); EmptyTd->Word0.DataToggle = 0; OhciSetTDField (EmptyTd, TD_ERROR_CNT, 0); OhciSetTDField (EmptyTd, TD_COND_CODE, 0); OhciSetTDField (EmptyTd, TD_CURR_BUFFER_PTR, 0); OhciSetTDField (EmptyTd, TD_BUFFER_END_PTR, 0); OhciSetTDField (EmptyTd, TD_NEXT_PTR, 0); EmptyTd->ActualSendLength = 0; EmptyTd->DataBuffer = NULL; EmptyTd->NextTDPointer = NULL; OhciLinkTD (HeadTd, EmptyTd); Ed->TdTailPointer = EmptyTd; OhciAttachTDListToED (Ed, HeadTd); OhciSetEDField (Ed, ED_SKIP, 0); OhciSetHcCommandStatus (Ohc, BULK_LIST_FILLED, 1); OhciSetHcControl (Ohc, BULK_ENABLE, 1); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { MicroSecondDelay (HC_1_MILLISECOND); if (OhciGetHcControl (Ohc, BULK_ENABLE) != 1) { *TransferResult = EFI_USB_ERR_SYSTEM; goto FREE_TD_BUFF; } } TimeCount = 0; Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); while (Status == EFI_NOT_READY && TimeCount <= TimeOut) { MicroSecondDelay (HC_1_MILLISECOND); TimeCount++; Status = CheckIfDone (Ohc, BULK_LIST, Ed, HeadTd, &ErrorCode); } *TransferResult = ConvertErrorCode (ErrorCode); if (ErrorCode != TD_NO_ERROR) { if (ErrorCode == TD_TOBE_PROCESSED) { DEBUG ((EFI_D_INFO, "Bulk pipe timeout, > %d mS\r\n", TimeOut)); } else { DEBUG ((EFI_D_INFO, "Bulk pipe broken\r\n")); } *DataLength = 0; } *DataToggle = (UINT8) OhciGetEDField (Ed, ED_DTTOGGLE); FREE_TD_BUFF: while (HeadTd) { DataTd = HeadTd; HeadTd = HeadTd->NextTDPointer; UsbHcFreeMem(Ohc->MemPool, DataTd, sizeof(TD_DESCRIPTOR)); } UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR)); return Status; }