📄 uhchlp.c
字号:
SetCurFrameListQHorTD(
IN FRAMELIST_ENTRY *pCurEntry,
IN BOOLEAN IsQH
)
{
//
// This bit indicates to the hardware whether the item referenced by the
// link pointer is a TD or a QH.
//
pCurEntry-> FrameListPtrQSelect = (IsQH ? 1 : 0) ;
}
BOOLEAN
IsCurFrameListQHorTD(
IN FRAMELIST_ENTRY *pCurEntry
)
{
//
//TRUE is QH
//FALSE is TD
//
return (BOOLEAN)(pCurEntry->FrameListPtrQSelect);
}
BOOLEAN
GetCurFrameListTerminate(
IN FRAMELIST_ENTRY *pCurEntry
)
{
//
// TRUE means the frame is empty,
// FALSE means the link pointer field is valid.
//
return (BOOLEAN)(pCurEntry->FrameListPtrTerminate) ;
}
VOID
SetCurFrameListPointer(
IN FRAMELIST_ENTRY *pCurEntry,
IN UINT8 *ptr
)
{
//
// Set the pointer field of the frame.
//
pCurEntry-> FrameListPtr = (UINT32)((UINTN)ptr >> 4);
}
VOID*
GetCurFrameListPointer(
IN FRAMELIST_ENTRY *pCurEntry
)
{
VOID *ptr ;
//
// Get the link pointer of the frame.
//
ptr = (VOID*)((UINTN)(pCurEntry-> FrameListPtr << 4));
return ptr;
}
VOID
LinkQHToFrameList(
IN FRAMELIST_ENTRY *pEntry,
IN UINT16 FrameListIndex,
IN QH_STRUCT *ptrQH
)
{
FRAMELIST_ENTRY *pCurFrame ;
QH_STRUCT *TempQH;
QH_STRUCT *NextTempQH;
TD_STRUCT *TempTD;
BOOLEAN LINK;
//
// Get frame list entry that the link process will begin from.
//
pCurFrame = pEntry + FrameListIndex ;
//
// if current frame is empty
// then link the specified QH directly to the Frame List.
//
if (GetCurFrameListTerminate (pCurFrame)) {
//
// Link new QH to the frame list entry.
//
SetCurFrameListQHorTD (pCurFrame, TRUE) ;
SetCurFrameListPointer (pCurFrame, (UINT8 *)ptrQH) ;
//
// clear T bit in the Frame List, indicating that the frame list entry
// is no longer empty.
//
SetorClearCurFrameListTerminate(pCurFrame, FALSE) ;
return;
} else {
//
// current frame list has link pointer
//
if (!IsCurFrameListQHorTD (pCurFrame)) {
//
// a TD is linked to the framelist entry
//
TempTD = (TD_STRUCT*)GetCurFrameListPointer (pCurFrame);
while (GetTDLinkPtrValidorInvalid (TempTD)) {
if (IsTDLinkPtrQHOrTD (TempTD)) { // QH linked next to the TD
break;
}
TempTD = (TD_STRUCT*)GetTDLinkPtr (TempTD);
}
//
// either no ptr linked next to the TD or QH is linked next to the TD
//
if (!GetTDLinkPtrValidorInvalid (TempTD)) {
//
// no ptr linked next to the TD
//
TempTD->ptrNextQH = ptrQH;
SetTDLinkPtrQHorTDSelect (TempTD,TRUE);
SetTDLinkPtr (TempTD,ptrQH);
SetTDLinkPtrValidorInvalid(TempTD,TRUE) ;
//ptrQH->ptrNext = NULL;
return;
} else {
//
// QH is linked next to the TD
//
TempQH = (QH_STRUCT*)GetTDLinkPtr (TempTD) ;
}
} else {
//
// a QH is linked to the framelist entry
//
TempQH = (QH_STRUCT*)GetCurFrameListPointer(pCurFrame) ;
}
//
// Set up Flag
//
LINK = TRUE;
//
// avoid the same qh repeated linking in one frame entry
//
if (TempQH == ptrQH) {
LINK = FALSE;
}
//
// if current QH has next QH connected
//
while (GetQHHorizontalValidorInvalid (TempQH)) {
//
// Get next QH pointer
//
NextTempQH = (QH_STRUCT*)GetQHHorizontalLinkPtr (TempQH);
//
// Bulk transfer qh may be self-linked,
// so, the code below is to avoid dead-loop when meeting self-linked qh
//
if (NextTempQH == TempQH) {
LINK = FALSE;
break;
}
TempQH = NextTempQH;
//
// avoid the same qh repeated linking in one frame entry
//
if (TempQH == ptrQH) {
LINK = FALSE;
}
}
if (LINK) {
// Link
TempQH->ptrNext = ptrQH;
SetQHHorizontalQHorTDSelect(TempQH,TRUE) ;
SetQHHorizontalLinkPtr(TempQH,ptrQH) ;
SetQHHorizontalValidorInvalid(TempQH,TRUE) ;
//ptrQH->ptrNext = NULL;
}
return;
}
}
EFI_STATUS
ExecuteControlTransfer (
IN USB_HC_DEV *HcDev,
IN TD_STRUCT *ptrTD,
IN UINT32 wIndex,
OUT UINTN *ActualLen,
IN UINTN TimeOut,
OUT UINT32 *TransferResult
)
{
UINTN ErrTDPos;
UINTN Delay;
ErrTDPos = 0 ;
*TransferResult = EFI_USB_NOERROR;
*ActualLen = 0;
Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
do {
CheckTDsResults(ptrTD,TransferResult,&ErrTDPos,ActualLen);
//
// TD is inactive, means the control transfer is end.
//
if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
break;
}
gBS->Stall(50);
} while(Delay--);
if(*TransferResult != EFI_USB_NOERROR) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
EFI_STATUS
ExecBulkorSyncInterruptTransfer (
IN USB_HC_DEV *HcDev,
IN TD_STRUCT *ptrTD,
IN UINT32 wIndex,
OUT UINTN *ActualLen,
OUT UINT8 *DataToggle,
IN UINTN TimeOut,
OUT UINT32 *TransferResult
)
{
UINTN ErrTDPos;
UINTN ScrollNum;
UINTN Delay;
ErrTDPos = 0;
*TransferResult = EFI_USB_NOERROR;
*ActualLen = 0;
Delay = (TimeOut * STALL_1_MILLI_SECOND / 50) + 1;
do {
CheckTDsResults (ptrTD,TransferResult,&ErrTDPos,ActualLen);
//
// TD is inactive, thus meaning bulk transfer's end.
//
if ((*TransferResult & EFI_USB_ERR_NOTEXECUTE) != EFI_USB_ERR_NOTEXECUTE) {
break;
}
gBS->Stall(50); // Stall for 50 us
} while (Delay--);
//
// has error
//
if(*TransferResult != EFI_USB_NOERROR) {
//
// scroll the Data Toggle back to the last success TD
//
ScrollNum = CountTDsNumber(ptrTD) - ErrTDPos;
if(ScrollNum % 2) {
*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
)
{
FRAMELIST_ENTRY *pCurFrame;
UINTN i;
UINTN BeginFrame;
UINTN EndFrame;
QH_STRUCT *CurrentQH;
QH_STRUCT *NextQH;
QH_STRUCT *LastLoopQH;
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 ( i = BeginFrame; i < EndFrame; i ++) {
pCurFrame = HcDev->FrameListEntry + (i % 1024);
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) {
//
// tell whether CurrentQH is in QH loop and is one of the ends of the
// loop,
// if yes, break the QH loop.
//
if (IsQHsLooped (CurrentQH,&LastLoopQH)) {
if ((CurrentQH == LastLoopQH) || (CurrentQH == LastLoopQH->LoopPtr)) {
LastLoopQH->LoopPtr = NULL;
SetQHHorizontalValidorInvalid(LastLoopQH,FALSE);
SetQHHorizontalLinkPtr(LastLoopQH,NULL);
LastLoopQH->ptrNext = NULL;
}
}
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;
}
//
// retrieve the Last QH in the Loop,
// if no Loop, LastLoopQH = NULL
//
IsQHsLooped (CurrentQH,&LastLoopQH);
while (CurrentQH != LastLoopQH) {
PtrPreQH = CurrentQH;
//
// Get next horizontal linked QH
//
CurrentQH = (QH_STRUCT*)GetQHHorizontalLinkPtr (CurrentQH);
//
// the qh is found
//
if (CurrentQH == ptrQH) {
break;
}
}
if (CurrentQH != ptrQH) {
//
// search next frame list entry
//
continue;
}
//
// find the specified qh, then delink it from
// the horizontal QH list in the frame entry.
//
if (LastLoopQH != NULL) {
//
// break the qh loop
// if exists and the specified qh is one of the ends of the loop
//
if ((CurrentQH == LastLoopQH) || (CurrentQH == LastLoopQH->LoopPtr)) {
LastLoopQH->LoopPtr = NULL;
SetQHHorizontalValidorInvalid(LastLoopQH,FALSE);
SetQHHorizontalLinkPtr(LastLoopQH,NULL);
LastLoopQH->ptrNext = NULL;
}
}
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
)
/*
The last TD in the queue may be linked to itself.
Must take this condition into account.
*/
{
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
)
{
EFI_STATUS Status;
INTERRUPT_LIST *Node ;
Status = gBS->AllocatePool (EfiBootServicesData,sizeof(INTERRUPT_LIST),&Node);
if(EFI_ERROR(Status)) {
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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -