uhchlp.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 3,348 行 · 第 1/5 页
C
3,348 行
//
ScrollNum = CountTDsNumber (PtrTD) - ErrTDPos;
if (ScrollNum & 0x1) {
*DataToggle ^= 1;
}
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
VOID
DelLinkSingleQH (
IN USB_HC_DEV *HcDev,
IN QH_STRUCT *PtrQH,
IN UINT16 FrameListIndex,
IN BOOLEAN SearchOther,
IN BOOLEAN Delete
)
/*++
Routine Description:
Unlink from frame list and delete single QH
Arguments:
HcDev - USB_HC_DEV
PtrQH - QH_STRUCT
FrameListIndex - Frame List Index
SearchOther - Search Other QH
Delete - TRUE is to delete the QH
Returns:
VOID
--*/
{
FRAMELIST_ENTRY *pCurFrame;
UINTN Index;
UINTN BeginFrame;
UINTN EndFrame;
QH_STRUCT *CurrentQH;
QH_STRUCT *NextQH;
TD_STRUCT *CurrentTD;
VOID *PtrPreQH;
BOOLEAN Found;
NextQH = NULL;
PtrPreQH = NULL;
Found = FALSE;
if (PtrQH == NULL) {
return ;
}
if (SearchOther) {
BeginFrame = 0;
EndFrame = 1024;
} else {
BeginFrame = FrameListIndex;
EndFrame = FrameListIndex + 1;
}
for (Index = BeginFrame; Index < EndFrame; Index++) {
pCurFrame = HcDev->FrameListEntry + (Index & 0x3FF);
if (GetCurFrameListTerminate (pCurFrame)) {
//
// current frame list is empty,search next frame list entry
//
continue;
}
if (!IsCurFrameListQHorTD (pCurFrame)) {
//
// TD linked to current framelist
//
CurrentTD = (TD_STRUCT *) GetCurFrameListPointer (pCurFrame);
while (GetTDLinkPtrValidorInvalid (CurrentTD)) {
if (IsTDLinkPtrQHOrTD (CurrentTD)) {
//
// QH linked next to the TD,break while ()
//
break;
}
CurrentTD = (TD_STRUCT *) GetTDLinkPtr (CurrentTD);
}
if (!GetTDLinkPtrValidorInvalid (CurrentTD)) {
//
// no QH linked next to the last TD,
// search next frame list
//
continue;
}
//
// a QH linked next to the last TD
//
CurrentQH = (QH_STRUCT *) GetTDLinkPtr (CurrentTD);
PtrPreQH = CurrentTD;
} else {
//
// a QH linked to current framelist
//
CurrentQH = (QH_STRUCT *) GetCurFrameListPointer (pCurFrame);
PtrPreQH = NULL;
}
if (CurrentQH == PtrQH) {
if (GetQHHorizontalValidorInvalid (PtrQH)) {
//
// there is QH connected after the QH found
//
//
// retrieve nex qh pointer of the qh found.
//
NextQH = GetQHHorizontalLinkPtr (PtrQH);
} else {
NextQH = NULL;
}
if (PtrPreQH) {
//
// QH linked to a TD struct
//
CurrentTD = (TD_STRUCT *) PtrPreQH;
SetTDLinkPtrValidorInvalid (CurrentTD, (BOOLEAN) ((NextQH == NULL) ? FALSE : TRUE));
SetTDLinkPtr (CurrentTD, NextQH);
CurrentTD->ptrNextQH = NextQH;
} else {
//
// QH linked directly to current framelist entry
//
SetorClearCurFrameListTerminate (pCurFrame, (BOOLEAN) ((NextQH == NULL) ? TRUE : FALSE));
SetCurFrameListPointer (pCurFrame, (UINT8 *) NextQH);
}
Found = TRUE;
//
// search next framelist entry
//
continue;
}
while (GetQHHorizontalValidorInvalid (CurrentQH)) {
PtrPreQH = CurrentQH;
//
// Get next horizontal linked QH
//
CurrentQH = (QH_STRUCT *) GetQHHorizontalLinkPtr (CurrentQH);
//
// the qh is found
//
if (CurrentQH == PtrQH) {
break;
}
}
//
// search next frame list entry
//
if (CurrentQH != PtrQH) {
//
// Not find the QH
//
continue;
}
//
// find the specified qh, then delink it from
// the horizontal QH list in the frame entry.
//
if (GetQHHorizontalValidorInvalid (PtrQH)) {
//
// there is QH connected after the QH found
//
//
// retrieve nex qh pointer of the qh found.
//
NextQH = GetQHHorizontalLinkPtr (PtrQH);
} else {
//
// NO QH connected after the QH found
//
NextQH = NULL;
//
// NULL the previous QH's link ptr and set Terminate field.
//
SetQHHorizontalValidorInvalid ((QH_STRUCT *) PtrPreQH, FALSE);
}
SetQHHorizontalLinkPtr ((QH_STRUCT *) PtrPreQH, NextQH);
((QH_STRUCT *) PtrPreQH)->ptrNext = NextQH;
Found = TRUE;
}
if (Found && Delete) {
//
// free memory once used by the specific QH
//
UhciFreePool (HcDev, (UINT8 *) PtrQH, sizeof (QH_STRUCT));
}
return ;
}
VOID
DeleteQueuedTDs (
IN USB_HC_DEV *HcDev,
IN TD_STRUCT *PtrFirstTD
)
/*++
Routine Description:
Delete Queued TDs
Arguments:
HcDev - USB_HC_DEV
PtrFirstTD - TD link list head
Returns:
VOID
--*/
{
TD_STRUCT *Tptr1;
TD_STRUCT *Tptr2;
Tptr1 = PtrFirstTD;
//
// Delete all the TDs in a queue.
//
while (Tptr1) {
Tptr2 = Tptr1;
if (!GetTDLinkPtrValidorInvalid (Tptr2)) {
Tptr1 = NULL;
} else {
Tptr1 = GetTDLinkPtr (Tptr2);
//
// TD link to itself
//
if (Tptr1 == Tptr2) {
Tptr1 = NULL;
}
}
UhciFreePool (HcDev, (UINT8 *) Tptr2, sizeof (TD_STRUCT));
}
return ;
}
VOID
InsertQHTDToINTList (
IN USB_HC_DEV *HcDev,
IN QH_STRUCT *PtrQH,
IN TD_STRUCT *PtrFirstTD,
IN UINT8 DeviceAddress,
IN UINT8 EndPointAddress,
IN UINT8 DataToggle,
IN UINTN DataLength,
IN UINTN PollingInterval,
IN VOID *Mapping,
IN UINT8 *DataBuffer,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction,
IN VOID *Context
)
/*++
Routine Description:
Insert QH and TD To Interrupt List
Arguments:
HcDev - USB_HC_DEV
PtrQH - QH_STRUCT
PtrFirstTD - First TD_STRUCT
DeviceAddress - Device Address
EndPointAddress - EndPoint Address
DataToggle - Data Toggle
DataLength - Data length
PollingInterval - Polling Interval when inserted to frame list
Mapping - Mapping alue
DataBuffer - Data buffer
CallBackFunction- CallBackFunction after interrupt transfeer
Context - CallBackFunction Context passed as function parameter
Returns:
EFI_SUCCESS - Sucess
EFI_INVALID_PARAMETER - Paremeter is error
--*/
{
INTERRUPT_LIST *Node;
Node = EfiLibAllocatePool (sizeof (INTERRUPT_LIST));
if (Node == NULL) {
return ;
}
//
// Fill Node field
//
Node->Signature = INTERRUPT_LIST_SIGNATURE;
Node->DevAddr = DeviceAddress;
Node->EndPoint = EndPointAddress;
Node->PtrQH = PtrQH;
Node->PtrFirstTD = PtrFirstTD;
Node->DataToggle = DataToggle;
Node->DataLen = DataLength;
Node->PollInterval = PollingInterval;
Node->Mapping = Mapping;
//
// DataBuffer is allocated host memory, not mapped memory
//
Node->DataBuffer = DataBuffer;
Node->InterruptCallBack = CallBackFunction;
Node->InterruptContext = Context;
//
// insert the new interrupt transfer to the head of the list.
// The interrupt transfer's monitor function scans the whole list from head
// to tail. The new interrupt transfer MUST be added to the head of the list
// for the sake of error recovery.
//
InsertHeadList (&(HcDev->InterruptListHead), &(Node->Link));
return ;
}
EFI_STATUS
DeleteAsyncINTQHTDs (
IN USB_HC_DEV *HcDev,
IN UINT8 DeviceAddress,
IN UINT8 EndPointAddress,
OUT UINT8 *DataToggle
)
/*++
Routine Description:
Delete Async INT QH and TDs
Arguments:
HcDev - USB_HC_DEV
DeviceAddress - Device Address
EndPointAddress - EndPoint Address
DataToggle - Data Toggle
Returns:
EFI_SUCCESS - Sucess
EFI_INVALID_PARAMETER - Paremeter is error
--*/
{
QH_STRUCT *MatchQH;
QH_STRUCT *ptrNextQH;
TD_STRUCT *MatchTD;
EFI_LIST_ENTRY *Link;
INTERRUPT_LIST *MatchList;
INTERRUPT_LIST *PtrList;
BOOLEAN Found;
UINT32 Result;
UINTN ErrTDPos;
UINTN ActualLen;
MatchQH = NULL;
MatchTD = NULL;
MatchList = NULL;
//
// no interrupt transaction exists
//
if (IsListEmpty (&(HcDev->InterruptListHead))) {
return EFI_INVALID_PARAMETER;
}
//
// find the correct QH-TD that need to delete
// (by matching Device address and EndPoint number to match QH-TD )
//
Found = FALSE;
Link = &(HcDev->InterruptListHead);
do {
Link = Link->ForwardLink;
PtrList = INTERRUPT_LIST_FROM_LINK (Link);
if ((PtrList->DevAddr == DeviceAddress) && ((PtrList->EndPoint & 0x0f) == (EndPointAddress & 0x0f))) {
MatchList = PtrList;
Found = TRUE;
break;
}
} while (Link->ForwardLink != &(HcDev->InterruptListHead));
if (!Found) {
return EFI_INVALID_PARAMETER;
}
//
// get current endpoint's data toggle bit and save.
//
ExecuteAsyncINTTDs (HcDev, MatchList, &Result, &ErrTDPos, &ActualLen);
UpdateAsyncINTQHTDs (MatchList, Result, (UINT32) ErrTDPos);
*DataToggle = MatchList->DataToggle;
MatchTD = MatchList->PtrFirstTD;
MatchQH = MatchList->PtrQH;
//
// find the first matching QH position in the FrameList
//
while (MatchQH) {
ptrNextQH = MatchQH->ptrNextIntQH;
//
// Search all the entries
//
DelLinkSingleQH (HcDev, MatchQH, 0, TRUE, TRUE);
MatchQH = ptrNextQH;
}
//
// Call PciIo->Unmap() to unmap the busmaster read/write
//
HcDev->PciIo->Unmap (HcDev->PciIo, MatchList->Mapping);
//
// free host data buffer allocated,
// mapped data buffer is freed by Unmap
//
if (MatchList->DataBuffer != NULL) {
gBS->FreePool (MatchList->DataBuffer);
}
//
// at last delete the TDs, to aVOID problems
//
DeleteQueuedTDs (HcDev, MatchTD);
//
// remove Match node from interrupt list
//
RemoveEntryList (&(MatchList->Link));
gBS->FreePool (MatchList);
return EFI_SUCCESS;
}
BOOLEAN
CheckTDsResults (
IN TD_STRUCT *PtrTD,
IN UINTN RequiredLen,
OUT UINT32 *Result,
OUT UINTN *ErrTDPos,
OUT UINTN *ActualTransferSize
)
/*++
Routine Description:
Check TDs Results
Arguments:
PtrTD - TD_STRUCT to check
RequiredLen - Required Len
Result - Transfer result
ErrTDPos - Error TD Position
ActualTransferSize - Actual Transfer Size
Returns:
TRUE - Sucess
FALSE - Fail
--*/
{
UINTN Len;
*Result = EFI_USB_NOERROR;
*ErrTDPos = 0;
//
// Init to zero.
//
*ActualTransferSize = 0;
while (PtrTD) {
if (IsTDStatusActive (PtrTD)) {
*Result |= EFI_USB_ERR_NOTEXECUTE;
}
if (IsTDStatusStalled (PtrTD)) {
*Result |= EFI_USB_ERR_STALL;
}
if (IsTDStatusBufferError (PtrTD)) {
*Result |= EFI_USB_ERR_BUFFER;
}
if (IsTDStatusBabbleError (PtrTD)) {
*Result |= EFI_USB_ERR_BABBLE;
}
if (IsTDStatusNAKReceived (PtrTD)) {
*Result |= EFI_USB_ERR_NAK;
}
if (IsTDStatusCRCTimeOutError (PtrTD)) {
*Result |= EFI_USB_ERR_TIMEOUT;
}
if (IsTDStatusBitStuffError (PtrTD)) {
*Result |= EFI_USB_ERR_BITSTUFF;
}
//
// if any error encountered, stop processing the left TDs.
//
if (*Result) {
return FALSE;
}
Len = GetTDStatusActualLength (PtrTD) & 0x7FF;
*ActualTransferSize += Len;
if (*ActualTransferSize <= RequiredLen && Len < PtrTD->TDData.TDTokenMaxLen) {
//
// transter finished and actural length less than required length
//
goto Done;
}
//
// Accumulate actual transferred data length in each TD.
//
PtrTD = (TD_STRUCT *) (PtrTD->ptrNextTD);
//
// Record the first Error TD's position in the queue,
// this value is zero-based.
//
(*ErrTDPos)++;
}
Done:
return TRUE;
}
VOID
ExecuteAsyncINTTDs (
IN USB_HC_DEV *HcDev,
IN INTERRUPT_LIST *PtrList,
OUT UINT32 *Result,
OUT UINTN *ErrTDPos,
OUT UINTN *ActualLen
)
/*++
Routine Description:
Execute Async Interrupt TDs
Arguments:
HcDev - USB_HC_DEV
PtrList - INTERRUPT_LIST
Result - Transfer result
ErrTDPos - Error TD Position
ActualTransferSize - Actual Transfer Size
Returns:
VOID
--*/
{
//
// *ErrTDPos is zero-based value, indicating the first error TD's position
// in the TDs' sequence.
// *ErrTDPos value is only valid when *Result is not equal NOERROR.
//
UINTN RequiredLen;
RequiredLen = *ActualLen;
CheckTDsResults (PtrList->PtrFirstTD, RequiredLen, Result, ErrTDPos, ActualLen);
return ;
}
VOID
UpdateAsyncINTQHTDs (
IN INTERRUPT_LIST *PtrList,
IN UINT32 Result,
IN UINT32 ErrTDPos
)
/*++
Routine Description:
Update Async Interrupt QH and TDs
Arguments:
PtrList - INTERRUPT_LIST
Result - Transfer reslut
ErrTDPos - Error TD Position
Returns:
VOID
--*/
{
QH_STRUCT *PtrFirstQH;
QH_STRUCT *PtrQH;
TD_STRUCT *PtrFirstTD;
TD_STRUCT *PtrTD;
UINT8 DataToggle;
UINT32 Index;
PtrFirstQH = PtrList->PtrQH;
PtrFirstTD = PtrList->PtrFirstTD;
DataToggle = 0;
if (Result == EFI_USB_NOERROR) {
PtrTD = PtrFirstTD;
while (PtrTD) {
DataToggle = GetTDTokenDataToggle (PtrTD);
PtrTD = PtrTD->ptrNextTD;
}
//
// save current DataToggle value to interrupt list.
// this value is used for tracing the interrupt endpoint DataToggle.
// when this interrupt transfer is deleted, the last DataToggle is saved
//
PtrList->DataToggle = DataToggle;
PtrTD = PtrFirstTD;
//
// Since DataToggle bit should toggle after each success transaction,
// the First TD's DataToggle bit will be updated to XOR of Last TD's
// DataToggle bit. If the First TD's DataToggle bit is not equal Last
// TD's DataToggle bit, that means it already be the XOR of Last TD's,
// so no update is needed.
/
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?