📄 uhchlp.c
字号:
}
return;
}
VOID
SelfLinkBulkTransferQH (
IN QH_STRUCT *ptrQH
)
{
if (ptrQH == NULL) {
return;
}
//
// Make the QH's horizontal link pointer pointing to itself.
//
ptrQH->ptrNext = ptrQH;
SetQHHorizontalQHorTDSelect(ptrQH,TRUE);
SetQHHorizontalLinkPtr(ptrQH,ptrQH);
SetQHHorizontalValidorInvalid(ptrQH,TRUE);
return;
}
EFI_STATUS
CreateFrameList (
USB_HC_DEV *HcDev,
UINT32 FlBaseAddrReg
)
{
EFI_STATUS Status ;
VOID *CommonBuffer;
EFI_PHYSICAL_ADDRESS MappedAddress;
VOID *Mapping;
UINTN BufferSizeInPages;
UINTN BufferSizeInBytes;
//
// The Frame List is a common buffer that will be
// accessed by both the cpu and the usb bus master
// at the same time.
// The Frame List ocupies 4K bytes,
// and must be aligned on 4-Kbyte boundaries.
//
BufferSizeInBytes = 4096;
BufferSizeInPages = EFI_SIZE_TO_PAGES(BufferSizeInBytes);
Status = HcDev->PciIo->AllocateBuffer (HcDev->PciIo,
AllocateAnyPages,
EfiBootServicesData,
BufferSizeInPages,
&CommonBuffer,
0
);
if(EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
Status = HcDev->PciIo->Map (HcDev->PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
CommonBuffer,
&BufferSizeInBytes,
&MappedAddress,
&Mapping
);
if (EFI_ERROR(Status) || (BufferSizeInBytes != 4096)) {
HcDev->PciIo->FreeBuffer (HcDev->PciIo,BufferSizeInPages,CommonBuffer);
return EFI_UNSUPPORTED;
}
HcDev->FrameListEntry = (FRAMELIST_ENTRY*)((UINTN)MappedAddress);
HcDev->FrameListMapping = Mapping;
InitFrameList (HcDev);
//
// Tell the Host Controller where the Frame List lies,
// by set the Frame List Base Address Register.
//
SetFrameListBaseAddress(
HcDev->PciIo,
FlBaseAddrReg,
(UINT32)((UINTN)HcDev->FrameListEntry)
);
return EFI_SUCCESS;
}
EFI_STATUS
FreeFrameListEntry(
USB_HC_DEV *HcDev
)
{
//
// Unmap the common buffer for framelist entry,
// and free the common buffer.
// Uhci's frame list occupy 4k memory.
//
HcDev->PciIo->Unmap (HcDev->PciIo,HcDev->FrameListMapping);
HcDev->PciIo->FreeBuffer (
HcDev->PciIo,
EFI_SIZE_TO_PAGES(4096),
(VOID*)(HcDev->FrameListEntry)
);
return EFI_SUCCESS;
}
VOID
InitFrameList (
USB_HC_DEV *HcDev
)
{
FRAMELIST_ENTRY *FrameListPtr;
UINTN Index;
//
// Validate each Frame List Entry
//
FrameListPtr = HcDev->FrameListEntry;
for(Index = 0 ; Index < 1024 ; Index ++) {
FrameListPtr->FrameListPtrTerminate = 1 ;
FrameListPtr->FrameListPtr = 0;
FrameListPtr->FrameListPtrQSelect = 0;
FrameListPtr->FrameListRsvd = 0;
FrameListPtr++;
}
}
////////////////////////////////////////////////////////////////
//
// QH TD related Helper Functions
//
////////////////////////////////////////////////////////////////
//
// functions for QH
//
EFI_STATUS
AllocateQHStruct(
USB_HC_DEV *HcDev,
OUT QH_STRUCT **ppQHStruct
)
{
EFI_STATUS Status;
*ppQHStruct = NULL;
//
// QH must align on 16 bytes alignment,
// since the memory allocated by UhciAllocatePool ()
// is aligned on 32 bytes, it is no need to adjust
// the allocated memory returned.
//
Status = UhciAllocatePool (HcDev,(UINT8**)ppQHStruct,sizeof(QH_STRUCT));
if(EFI_ERROR(Status)) {
return Status;
}
EfiZeroMem(*ppQHStruct, sizeof(QH_STRUCT));
return EFI_SUCCESS;
}
VOID
InitQH(
IN QH_STRUCT *ptrQH
)
{
//
// Make QH ready
//
SetQHHorizontalValidorInvalid(ptrQH, FALSE);
SetQHVerticalValidorInvalid(ptrQH, FALSE);
ptrQH->LoopPtr = NULL;
}
EFI_STATUS
CreateQH(
USB_HC_DEV *HcDev,
QH_STRUCT **pptrQH
)
{
EFI_STATUS Status;
//
// allocate align memory for QH_STRUCT
//
Status = AllocateQHStruct(HcDev,pptrQH) ;
if(EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES ;
}
//
// init each field of the QH_STRUCT
//
InitQH(*pptrQH) ;
return EFI_SUCCESS ;
}
void
SetQHHorizontalLinkPtr(
IN QH_STRUCT *ptrQH,
IN VOID *ptrNext
)
{
//
// Since the QH_STRUCT is aligned on 16-byte boundaries,
// Only the highest 28bit of the address is valid
// (take 32bit address as an example).
//
ptrQH->QH.QHHorizontalPtr = (UINT32)((UINTN)ptrNext >> 4);
}
VOID*
GetQHHorizontalLinkPtr(
IN QH_STRUCT *ptrQH
)
{
//
// Restore the 28bit address to 32bit address
//(take 32bit address as an example)
//
return ((VOID*)((UINTN)(ptrQH->QH.QHHorizontalPtr << 4)));
}
VOID
SetQHHorizontalQHorTDSelect(
IN QH_STRUCT *ptrQH,
IN BOOLEAN bQH
)
{
//
// if QH is connected, the specified bit is set,
// if TD is connected, the specified bit is cleared.
//
ptrQH->QH.QHHorizontalQSelect = bQH ? 1 : 0;
}
VOID
SetQHHorizontalValidorInvalid(
IN QH_STRUCT *ptrQH,
IN BOOLEAN bValid
)
{
//
// Valid means the horizontal link pointer is valid,
// else, it's invalid.
//
ptrQH->QH.QHHorizontalTerminate = bValid ? 0 : 1;
}
VOID
SetQHVerticalLinkPtr(
IN QH_STRUCT *ptrQH,
IN VOID *ptrNext
)
{
//
// Since the QH_STRUCT is aligned on 16-byte boundaries,
// Only the highest 28bit of the address is valid
// (take 32bit address as an example).
//
ptrQH->QH.QHVerticalPtr = (UINT32)((UINTN)ptrNext >> 4);
}
VOID*
GetQHVerticalLinkPtr(
IN QH_STRUCT *ptrQH
)
{
//
// Restore the 28bit address to 32bit address
//(take 32bit address as an example)
//
return ((VOID*)((UINTN)(ptrQH->QH.QHVerticalPtr << 4)));
}
VOID
SetQHVerticalQHorTDSelect(
IN QH_STRUCT *ptrQH,
IN BOOLEAN bQH
)
{
//
// Set the specified bit if the Vertical Link Pointer pointing to a QH,
// Clear the specified bit if the Vertical Link Pointer pointing to a TD.
//
ptrQH->QH.QHVerticalQSelect = bQH ? 1 : 0;
}
BOOLEAN
IsQHHorizontalQHSelect(
IN QH_STRUCT *ptrQH
)
{
//
// Retrieve the information about whether the Horizontal Link Pointer
// pointing to a QH or TD.
//
return (BOOLEAN)(ptrQH->QH.QHHorizontalQSelect? TRUE : FALSE);
}
VOID
SetQHVerticalValidorInvalid(
IN QH_STRUCT *ptrQH,
IN BOOLEAN IsValid
)
{
//
// If TRUE, indicates the Vertical Link Pointer field is valid,
// else, the field is invalid.
//
ptrQH->QH.QHVerticalTerminate = IsValid ? 0 : 1;
}
BOOLEAN
GetQHVerticalValidorInvalid(
IN QH_STRUCT *ptrQH
)
{
//
// If TRUE, indicates the Vertical Link Pointer field is valid,
// else, the field is invalid.
//
return (BOOLEAN)(!(ptrQH->QH.QHVerticalTerminate));
}
BOOLEAN
GetQHHorizontalValidorInvalid(
IN QH_STRUCT *ptrQH
)
{
//
// If TRUE, meaning the Horizontal Link Pointer field is valid,
// else, the field is invalid.
//
return (BOOLEAN)(!(ptrQH->QH.QHHorizontalTerminate));
}
//
// functions for TD
//
EFI_STATUS
AllocateTDStruct(
USB_HC_DEV *HcDev,
TD_STRUCT **ppTDStruct
)
{
EFI_STATUS Status;
*ppTDStruct = NULL;
//
// TD must align on 16 bytes alignment,
// since the memory allocated by UhciAllocatePool ()
// is aligned on 32 bytes, it is no need to adjust
// the allocated memory returned.
//
Status = UhciAllocatePool (HcDev,
(UINT8**)ppTDStruct,
sizeof(TD_STRUCT)
);
if(EFI_ERROR(Status)) {
return Status;
}
EfiZeroMem(*ppTDStruct, sizeof (TD_STRUCT));
return EFI_SUCCESS;
}
VOID
InitTD(
IN TD_STRUCT *ptrTD
)
{
//
// Make TD ready.
//
SetTDLinkPtrValidorInvalid(ptrTD, FALSE);
}
EFI_STATUS
CreateTD(
USB_HC_DEV *HcDev,
TD_STRUCT **pptrTD
)
{
EFI_STATUS Status;
//
// create memory for TD_STRUCT, and align the memory.
//
Status = AllocateTDStruct(HcDev,pptrTD) ;
if(EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
InitTD(*pptrTD);
return EFI_SUCCESS ;
}
EFI_STATUS
GenSetupStageTD(
IN USB_HC_DEV *HcDev,
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN BOOLEAN bSlow,
IN UINT8 *pDevReq,
IN UINT8 RequestLen,
OUT TD_STRUCT **ppTD
)
{
EFI_STATUS Status;
TD_STRUCT *pTDStruct;
Status = CreateTD(HcDev,&pTDStruct);
if(EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
SetTDLinkPtr(pTDStruct,NULL);
//
// Depth first fashion
//
SetTDLinkPtrDepthorBreadth(pTDStruct, TRUE);
//SetTDLinkPtrQHorTDSelect(pTDStruct,FALSE) ;
//
// initialize as the last TD in the QH context,
// this field will be updated in the TD linkage process.
//
SetTDLinkPtrValidorInvalid(pTDStruct, FALSE);
//
// Disable Short Packet Detection by default
//
EnableorDisableTDShortPacket (pTDStruct, FALSE) ;
//
// Max error counter is 3, retry 3 times when error encountered.
//
SetTDControlErrorCounter(pTDStruct, 3);
//
// set device speed attribute
// (TRUE - Slow Device; FALSE - Full Speed Device)
//
SetTDLoworFullSpeedDevice (pTDStruct, bSlow);
//
// Non isochronous transfer TD
//
SetTDControlIsochronousorNot(pTDStruct,FALSE) ;
//
// Interrupt On Complete bit be set to zero,
// Disable IOC interrupt.
//
SetorClearTDControlIOC(pTDStruct,FALSE) ;
//
// Set TD Active bit
//
SetTDStatusActiveorInactive(pTDStruct, TRUE);
SetTDTokenMaxLength(pTDStruct, RequestLen) ;
SetTDTokenDataToggle0(pTDStruct);
SetTDTokenEndPoint(pTDStruct, Endpoint);
SetTDTokenDeviceAddress (pTDStruct, DevAddr);
SetTDTokenPacketID(pTDStruct, SETUP_PACKET_ID);
pTDStruct->pTDBuffer = (UINT8*)pDevReq;
pTDStruct->TDBufferLength = RequestLen;
SetTDDataBuffer(pTDStruct);
*ppTD = pTDStruct;
return EFI_SUCCESS;
}
EFI_STATUS
GenDataTD(
IN USB_HC_DEV *HcDev,
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN UINT8 *pData,
IN UINT8 Len,
IN UINT8 PktID,
IN UINT8 Toggle,
IN BOOLEAN bSlow,
OUT TD_STRUCT **ppTD
)
{
TD_STRUCT *pTDStruct;
EFI_STATUS Status;
Status = CreateTD(HcDev,&pTDStruct);
if(EFI_ERROR(Status)) {
return EFI_OUT_OF_RESOURCES;
}
SetTDLinkPtr(pTDStruct,NULL) ;
//
// Depth first fashion
//
SetTDLinkPtrDepthorBreadth(pTDStruct,TRUE);
//
// Link pointer pointing to TD struct
//
SetTDLinkPtrQHorTDSelect(pTDStruct,FALSE);
//
// initialize as the last TD in the QH context,
// this field will be updated in the TD linkage process.
//
SetTDLinkPtrValidorInvalid(pTDStruct, FALSE);
//
// Disable short packet detect
//
EnableorDisableTDShortPacket (pTDStruct, FALSE) ;
//
// Max error counter is 3
//
SetTDControlErrorCounter(pTDStruct, 3);
//
// set device speed attribute
// (TRUE - Slow Device; FALSE - Full Speed Device)
//
SetTDLoworFullSpeedDevice (pTDStruct, bSlow);
//
// Non isochronous transfer TD
//
SetTDControlIsochronousorNot(pTDStruct,FALSE) ;
//
// Disable Interrupt On Complete
// Disable IOC interrupt.
//
SetorClearTDControlIOC(pTDStruct,FALSE) ;
//
// Set Active bit
//
SetTDStatusActiveorInactive(pTDStruct, TRUE);
SetTDTokenMaxLength(pTDStruct, Len) ;
if(Toggle) {
SetTDTokenDataToggle1(pTDStruct);
} else {
SetTDTokenDataToggle0(pTDStruct);
}
SetTDTokenEndPoint(pTDStruct, Endpoint);
SetTDTokenDeviceAddress(pTDStruct, DevAddr);
SetTDTokenPacketID(pTDStruct, PktID);
pTDStruct->pTDBuffer = (UINT8*)pData;
pTDStruct->TDBufferLength = Len;
SetTDDataBuffer(pTDStruct);
*ppTD = pTDStruct;
return EFI_SUCCESS;
}
EFI_STATUS
CreateStatusTD(
IN USB_HC_DEV *HcDev,
IN UINT8 DevAddr,
IN UINT8 Endpoint,
IN UINT8 PktID,
IN BOOLEAN bSlow,
OUT TD_STRUCT **ppTD
)
{
TD_STRUCT *ptrTDStruct;
EFI_STATUS Status;
Status = CreateTD(HcDev,&ptrTDStruct);
if(EFI_ERROR(Status)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -