📄 uhchlp.c
字号:
//
// 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
)
{
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,
OUT UINT32 *Result,
OUT UINTN *ErrTDPos,
OUT UINTN *ActualTransferSize
)
{
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;
}
//
// Accumulate actual transferred data length in each TD.
//
Len = GetTDStatusActualLength (ptrTD) % 0x800;
*ActualTransferSize += Len;
//
// if any error encountered, stop processing the left TDs.
//
if(*Result) {
return FALSE;
}
ptrTD = (TD_STRUCT*)(ptrTD->ptrNextTD);
//
// Record the first Error TD's position in the queue,
// this value is zero-based.
//
(*ErrTDPos) ++ ;
}
return TRUE ;
}
VOID
ExecuteAsyncINTTDs(
IN USB_HC_DEV *HcDev,
IN INTERRUPT_LIST *ptrList,
OUT UINT32 *Result,
OUT UINTN *ErrTDPos,
OUT UINTN *ActualLen
)
{
//
// *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.
//
CheckTDsResults(ptrList->ptrFirstTD,Result,ErrTDPos,ActualLen) ;
return ;
}
VOID
UpdateAsyncINTQHTDs(
IN INTERRUPT_LIST *ptrList,
IN UINT32 Result,
IN UINT32 ErrTDPos
)
{
QH_STRUCT *ptrFirstQH;
QH_STRUCT *ptrQH;
TD_STRUCT *ptrFirstTD;
TD_STRUCT *ptrTD;
UINT8 DataToggle;
UINT32 i;
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.
//
if(DataToggle == GetTDTokenDataToggle(ptrFirstTD)) {
ptrTD = ptrFirstTD ;
while(ptrTD) {
DataToggle ^= 1 ;
if(DataToggle) {
SetTDTokenDataToggle1(ptrTD);
} else {
SetTDTokenDataToggle0(ptrTD);
}
ptrTD = ptrTD->ptrNextTD ;
}
}
//
// restore Link Pointer of QH to First TD
// (because QH's Link Pointer will change during TD execution)
//
ptrQH = ptrFirstQH;
while(ptrQH) {
LinkTDToQH(ptrQH,ptrFirstTD) ;
ptrQH = ptrQH->ptrNextIntQH;
}
//
// set all the TDs active
//
ptrTD = ptrFirstTD;
while(ptrTD) {
SetTDStatusActiveorInactive(ptrTD, TRUE);
ptrTD = ptrTD->ptrNextTD ;
}
return ;
}
else if(((Result & EFI_USB_ERR_NOTEXECUTE) == EFI_USB_ERR_NOTEXECUTE)
|| ((Result & EFI_USB_ERR_NAK) == EFI_USB_ERR_NAK))
{
// no update
return;
}
// Have Errors
else
{
ptrTD = ptrFirstTD ;
if(ErrTDPos != 0) // not first TD error
{
//
// get the last success TD
//
for( i = 1 ; i < ErrTDPos ; i ++) {
ptrTD = ptrTD->ptrNextTD ;
}
//
// update Data Toggle in the interrupt list node
//
ptrList->DataToggle = GetTDTokenDataToggle(ptrTD);
//
// get the error TD
//
ptrTD = ptrTD->ptrNextTD ;
} else {
ptrList->DataToggle = GetTDTokenDataToggle(ptrTD);
}
//
// do not restore the QH's vertical link pointer,
// let the callback function do the rest of error handling.
//
return;
}
}
VOID
ClearTDStatus(
IN TD_STRUCT *ptrTD
)
{
//
// clear all the status bit in TD.
//
if(!ptrTD) {
return ;
}
ptrTD->TDData.TDStatus = 0 ;
return ;
}
VOID
ReleaseInterruptList(
IN USB_HC_DEV *HcDev,
IN EFI_LIST_ENTRY *ListHead
)
{
EFI_LIST_ENTRY *Link;
EFI_LIST_ENTRY *SavedLink;
INTERRUPT_LIST *pNode;
TD_STRUCT *ptrTD;
TD_STRUCT *ptrNextTD;
QH_STRUCT *ptrQH;
QH_STRUCT *SavedQH;
if (ListHead == NULL) {
return;
}
Link = ListHead;
//
// Free all the resources in the interrupt list
//
SavedLink = Link->ForwardLink;
while (!IsListEmpty (ListHead)) {
Link = SavedLink;
SavedLink = Link->ForwardLink;
pNode = INTERRUPT_LIST_FROM_LINK(Link);
RemoveEntryList (&pNode->Link);
SavedQH = pNode->ptrQH;
for (ptrQH = SavedQH;ptrQH != NULL;ptrQH = SavedQH) {
SavedQH = ptrQH->ptrNextIntQH;
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
}
ptrTD = pNode->ptrFirstTD ;
while (!ptrTD) {
ptrNextTD = ptrTD->ptrNextTD ;
UhciFreePool(HcDev,(UINT8*)ptrTD,sizeof(TD_STRUCT));
ptrTD = ptrNextTD ;
}
gBS->FreePool(pNode);
}
}
EFI_STATUS
InitializeMemoryManagement (
USB_HC_DEV *HcDev
)
{
MEMORY_MANAGE_HEADER *MemoryHeader;
EFI_STATUS Status;
UINTN MemPages;
MemPages = NORMAL_MEMORY_BLOCK_UNIT_IN_PAGES;
Status = CreateMemoryBlock (HcDev,&MemoryHeader,MemPages);
if (EFI_ERROR(Status)) {
return Status;
}
HcDev->MemoryHeader = MemoryHeader;
return EFI_SUCCESS;
}
EFI_STATUS
CreateMemoryBlock (
USB_HC_DEV *HcDev,
MEMORY_MANAGE_HEADER **MemoryHeader,
UINTN MemoryBlockSizeInPages
)
/*
Use PciIo->AllocateBuffer to allocate common buffer for the memory block,
and use PciIo->Map to map the common buffer for Bus Master Read/Write.
*/
{
EFI_STATUS Status;
VOID *CommonBuffer;
EFI_PHYSICAL_ADDRESS MappedAddress;
UINTN MemoryBlockSizeInBytes;
void *Mapping;
//
// Allocate memory for MemoryHeader
//
Status = gBS->AllocatePool (EfiBootServicesData, sizeof(MEMORY_MANAGE_HEADER),MemoryHeader);
if (EFI_ERROR(Status)) {
return Status;
}
EfiZeroMem (*MemoryHeader,sizeof(MEMORY_MANAGE_HEADER));
(*MemoryHeader)->Next = NULL;
//
// set Memory block size
//
(*MemoryHeader)->MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE (MemoryBlockSizeInPages);
//
// each bit in Bit Array will manage 32 bytes memory in memory block
//
(*MemoryHeader)->BitArraySizeInBytes = ((*MemoryHeader)->MemoryBlockSizeInBytes / 32) / 8;
//
// Allocate memory for BitArray
//
Status = gBS->AllocatePool (EfiBootServicesData,
(*MemoryHeader)->BitArraySizeInBytes,
&((*MemoryHeader)->BitArrayPtr)
);
if (EFI_ERROR(Status)) {
gBS->FreePool (*MemoryHeader);
return Status;
}
EfiZeroMem ((*MemoryHeader)->BitArrayPtr,(*MemoryHeader)->BitArraySizeInBytes);
//
// Memory Block uses MemoryBlockSizeInPages pages,
// and it is allocated as common buffer use.
//
Status = HcDev->PciIo->AllocateBuffer (
HcDev->PciIo,
AllocateAnyPages,
EfiBootServicesData,
MemoryBlockSizeInPages,
&CommonBuffer,
0
);
if (EFI_ERROR(Status)) {
gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
gBS->FreePool (*MemoryHeader);
return Status;
}
MemoryBlockSizeInBytes = EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages);
Status = HcDev->PciIo->Map (HcDev->PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
CommonBuffer,
&MemoryBlockSizeInBytes,
&MappedAddress,
&Mapping
);
//
// if returned Mapped size is less than the size we request,do not support.
//
if (EFI_ERROR(Status) || (MemoryBlockSizeInBytes != EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages))) {
HcDev->PciIo->FreeBuffer (HcDev->PciIo,MemoryBlockSizeInPages,CommonBuffer);
gBS->FreePool ((*MemoryHeader)->BitArrayPtr);
gBS->FreePool (*MemoryHeader);
return EFI_UNSUPPORTED;
}
//
// Set Memory block initial address
//
(*MemoryHeader)->MemoryBlockPtr = (UINT8*)((UINTN)MappedAddress);
(*MemoryHeader)->Mapping = Mapping;
EfiZeroMem (
(*MemoryHeader)->MemoryBlockPtr,
EFI_PAGES_TO_SIZE(MemoryBlockSizeInPages)
);
return EFI_SUCCESS;
}
EFI_STATUS
FreeMemoryHeader (
USB_HC_DEV *HcDev,
MEMORY_MANAGE_HEADER *MemoryHeader
)
{
if ((MemoryHeader == NULL) || (HcDev == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// unmap the common buffer used by the memory block
//
HcDev->PciIo->Unmap (HcDev->PciIo,MemoryHeader->Mapping);
//
// free common buffer
//
HcDev->PciIo->FreeBuffer (
HcDev->PciIo,
EFI_SIZE_TO_PAGES (MemoryHeader->MemoryBlockSizeInBytes),
MemoryHeader->MemoryBlockPtr
);
//
// free bit array
//
gBS->FreePool (MemoryHeader->BitArrayPtr);
//
// free memory header
//
gBS->FreePool (MemoryHeader);
return EFI_SUCCESS;
}
EFI_STATUS
UhciAllocatePool (
USB_HC_DEV *HcDev,
UINT8 **Pool,
UINTN AllocSize
)
{
MEMORY_MANAGE_HEADER *MemoryHeader;
MEMORY_MANAGE_HEADER *TempHeaderPtr;
MEMORY_MANAGE_HEADER *NewMemoryHeader;
UINTN RealAllocSize;
UINTN MemoryBlockSizeInPages;
EFI_STATUS Status;
*Pool = NULL;
MemoryHeader = HcDev->MemoryHeader;
//
// allocate unit is 32 bytes (align on 32 byte)
//
if (AllocSize % 32) {
RealAllocSize = (AllocSize / 32 + 1) * 32;
} else {
RealAllocSize = AllocSize;
}
//
// There may be linked MemoryHeaders.
// To allocate a free pool in Memory blocks,
// must search in the MemoryHeader link list
// until enough free pool is found.
//
Status = EFI_NOT_FOUND;
for (TempHeaderPtr = MemoryHeader;TempHeaderPtr != NULL;
TempHeaderPtr = TempHeaderPtr->Next) {
Status
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -