ehcisched.c
来自「EFI BIOS是Intel提出的下一代的BIOS标准。这里上传的Edk源代码是」· C语言 代码 · 共 2,975 行 · 第 1/5 页
C
2,975 行
/*++
Copyright (c) 2006, Intel Corporation
All rights reserved. This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EhciSched.c
Abstract:
Revision History
--*/
#include "Tiano.h"
#include "EfiDriverLib.h"
#include "Ehci.h"
EFI_STATUS
SetAndWaitDoorBell (
IN USB2_HC_DEV *HcDev,
IN UINTN Timeout
)
/*++
Routine Description:
Set DoorBell and wait it to complete
Arguments:
HcDev - USB2_HC_DEV
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
EFI_STATUS Status;
UINT32 Data;
UINTN Delay;
Status = ReadEhcOperationalReg (
HcDev,
USBCMD,
&Data
);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto exit;
}
Data |= USBCMD_IAAD;
Status = WriteEhcOperationalReg (
HcDev,
USBCMD,
Data
);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
}
//
// Timeout is in US unit
//
Delay = (Timeout / 50) + 1;
do {
Status = ReadEhcOperationalReg (
HcDev,
USBSTS,
&Data
);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto exit;
}
if ((Data & USBSTS_IAA) == USBSTS_IAA) {
break;
}
gBS->Stall (EHCI_GENERIC_RECOVERY_TIME);
} while (Delay--);
Data = Data & 0xFFFFFFC0;
Data |= USBSTS_IAA;
Status = WriteEhcOperationalReg (
HcDev,
USBSTS,
Data
);
exit:
return Status;
}
EFI_STATUS
CreateNULLQH (
IN USB2_HC_DEV *HcDev
)
/*++
Routine Description:
Create the NULL QH to make it as the Async QH header
Arguments:
HcDev - USB2_HC_DEV
Returns:
EFI_SUCCESS Success
--*/
{
EFI_STATUS Status;
EHCI_QH_ENTITY *NULLQhPtr;
//
// Allocate memory for Qh structure
//
Status = EhciAllocatePool (
HcDev,
(UINT8 **) &NULLQhPtr,
sizeof (EHCI_QH_ENTITY)
);
if (EFI_ERROR (Status)) {
return Status;
}
NULLQhPtr->Qh.Status = QTD_STATUS_HALTED;
NULLQhPtr->Qh.HeadReclamationFlag = 1;
NULLQhPtr->Qh.QhHorizontalPointer = (UINT32) (GET_0B_TO_31B (&(NULLQhPtr->Qh) >> 5));
NULLQhPtr->Qh.SelectType = QH_SELECT_TYPE;
NULLQhPtr->Qh.NextQtdTerminate = 1;
NULLQhPtr->Next = NULLQhPtr;
NULLQhPtr->Prev = NULLQhPtr;
HcDev->NULLQH = NULLQhPtr;
return Status;
}
VOID
DestroyNULLQH (
IN USB2_HC_DEV *HcDev
)
{
if (HcDev->NULLQH != NULL) {
EhciFreePool (HcDev, (UINT8 *)HcDev->NULLQH, sizeof (EHCI_QH_ENTITY));
HcDev->NULLQH = NULL;
}
}
EFI_STATUS
InitialPeriodicFrameList (
IN USB2_HC_DEV *HcDev,
IN UINTN Length
)
/*++
Routine Description:
Initialize Periodic Schedule Frame List
Arguments:
HcDev - USB2_HC_DEV
Length - Frame List Length
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
EFI_STATUS Status;
VOID *CommonBuffer;
EFI_PHYSICAL_ADDRESS FrameBuffer;
VOID *Map;
UINTN BufferSizeInPages;
UINTN BufferSizeInBytes;
UINTN FrameIndex;
FRAME_LIST_ENTRY *FrameEntryPtr;
//
// 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.
//
if (EHCI_MAX_FRAME_LIST_LENGTH != Length && IsFrameListProgrammable (HcDev)) {
Status = SetFrameListLen (HcDev, Length);
if (EFI_ERROR (Status)) {
Status = EFI_INVALID_PARAMETER;
goto exit;
}
}
BufferSizeInBytes = EFI_PAGE_SIZE;
BufferSizeInPages = EFI_SIZE_TO_PAGES (BufferSizeInBytes);
Status = HcDev->PciIo->AllocateBuffer (
HcDev->PciIo,
AllocateAnyPages,
EfiBootServicesData,
BufferSizeInPages,
&CommonBuffer,
0
);
if (EFI_ERROR (Status)) {
DEBUG ((gEHCErrorLevel, "EHCI: PciIo->AllocateBuffer Failed\n"));
Status = EFI_OUT_OF_RESOURCES;
goto exit;
}
Status = HcDev->PciIo->Map (
HcDev->PciIo,
EfiPciIoOperationBusMasterCommonBuffer,
CommonBuffer,
&BufferSizeInBytes,
&FrameBuffer,
&Map
);
if (EFI_ERROR (Status) || (BufferSizeInBytes != EFI_PAGE_SIZE)) {
DEBUG ((gEHCErrorLevel, "EHCI: PciIo->MapBuffer Failed\n"));
Status = EFI_OUT_OF_RESOURCES;
goto free_buffer;
}
//
// Put high 32bit into CtrlDataStructSeg reg
// when 64bit addressing range capability
//
if (HcDev->Is64BitCapable != 0) {
HcDev->High32BitAddr = (UINT32) GET_32B_TO_63B (FrameBuffer);
Status = SetCtrlDataStructSeg (HcDev);
if (EFI_ERROR (Status)) {
DEBUG ((gEHCErrorLevel, "EHCI: SetCtrlDataStructSeg Failed\n"));
Status = EFI_DEVICE_ERROR;
goto unmap_buffer;
}
}
//
// Tell the Host Controller where the Frame List lies,
// by set the Frame List Base Address Register.
//
Status = SetFrameListBaseAddr (HcDev, (UINT32) FrameBuffer);
if (EFI_ERROR (Status)) {
Status = EFI_DEVICE_ERROR;
goto unmap_buffer;
}
HcDev->PeriodicFrameListLength = Length;
HcDev->PeriodicFrameListBuffer = (VOID *) ((UINTN) FrameBuffer);
HcDev->PeriodicFrameListMap = Map;
//
// Init Frame List Array fields
//
FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {
FrameEntryPtr->LinkPointer = 0;
FrameEntryPtr->Rsvd = 0;
FrameEntryPtr->SelectType = 0;
FrameEntryPtr->LinkTerminate = TRUE;
FrameEntryPtr++;
}
goto exit;
unmap_buffer:
HcDev->PciIo->Unmap (HcDev->PciIo, Map);
free_buffer:
HcDev->PciIo->FreeBuffer (HcDev->PciIo, BufferSizeInPages, CommonBuffer);
exit:
return Status;
}
VOID
DeinitialPeriodicFrameList (
IN USB2_HC_DEV *HcDev
)
/*++
Routine Description:
Deinitialize Periodic Schedule Frame List
Arguments:
HcDev - USB2_HC_DEV
Returns:
VOID
--*/
{
HcDev->PciIo->Unmap (HcDev->PciIo, HcDev->PeriodicFrameListMap);
HcDev->PciIo->FreeBuffer (HcDev->PciIo, EFI_SIZE_TO_PAGES (EFI_PAGE_SIZE), HcDev->PeriodicFrameListBuffer);
return ;
}
EFI_STATUS
CreatePollingTimer (
IN USB2_HC_DEV *HcDev,
IN EFI_EVENT_NOTIFY NotifyFunction
)
/*++
Routine Description:
Create Async Request Polling Timer
Arguments:
HcDev - USB2_HC_DEV
NotifyFunction - Timer Notify Function
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
return gBS->CreateEvent (
EFI_EVENT_TIMER | EFI_EVENT_NOTIFY_SIGNAL,
EFI_TPL_NOTIFY,
NotifyFunction,
HcDev,
&HcDev->AsyncRequestEvent
);
}
EFI_STATUS
DestoryPollingTimer (
IN USB2_HC_DEV *HcDev
)
/*++
Routine Description:
Destory Async Request Polling Timer
Arguments:
HcDev - USB2_HC_DEV
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
return gBS->CloseEvent (HcDev->AsyncRequestEvent);
}
EFI_STATUS
StartPollingTimer (
IN USB2_HC_DEV *HcDev
)
/*++
Routine Description:
Start Async Request Polling Timer
Arguments:
HcDev - USB2_HC_DEV
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
return gBS->SetTimer (
HcDev->AsyncRequestEvent,
TimerPeriodic,
EHCI_ASYNC_REQUEST_POLLING_TIME
);
}
EFI_STATUS
StopPollingTimer (
IN USB2_HC_DEV *HcDev
)
/*++
Routine Description:
Stop Async Request Polling Timer
Arguments:
HcDev - USB2_HC_DEV
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
return gBS->SetTimer (
HcDev->AsyncRequestEvent,
TimerCancel,
EHCI_ASYNC_REQUEST_POLLING_TIME
);
}
EFI_STATUS
CreateQh (
IN USB2_HC_DEV *HcDev,
IN UINT8 DeviceAddr,
IN UINT8 Endpoint,
IN UINT8 DeviceSpeed,
IN UINTN MaxPacketLen,
OUT EHCI_QH_ENTITY **QhPtrPtr
)
/*++
Routine Description:
Create Qh Structure and Pre-Initialize
Arguments:
HcDev - USB2_HC_DEV
DeviceAddr - Address of Device
Endpoint - Endpoint Number
DeviceSpeed - Device Speed
MaxPacketLen - Max Length of one Packet
QhPtrPtr - A pointer of pointer to Qh for return
Returns:
EFI_SUCCESS Success
EFI_OUT_OF_RESOURCES Cannot allocate resources
--*/
{
EFI_STATUS Status;
EHCI_QH_HW *QhHwPtr;
ASSERT (HcDev);
ASSERT (QhPtrPtr);
*QhPtrPtr = NULL;
//
// Allocate memory for Qh structure
//
Status = EhciAllocatePool (
HcDev,
(UINT8 **) QhPtrPtr,
sizeof (EHCI_QH_ENTITY)
);
if (EFI_ERROR (Status)) {
Status = EFI_OUT_OF_RESOURCES;
goto exit;
}
//
// Software field
//
(*QhPtrPtr)->Next = NULL;
(*QhPtrPtr)->Prev = NULL;
(*QhPtrPtr)->FirstQtdPtr = NULL;
(*QhPtrPtr)->AltQtdPtr = NULL;
(*QhPtrPtr)->LastQtdPtr = NULL;
//
// Hardware field
//
QhHwPtr = &((*QhPtrPtr)->Qh);
QhHwPtr->QhHorizontalPointer = 0;
QhHwPtr->SelectType = 0;
QhHwPtr->MaxPacketLen = (UINT32) MaxPacketLen;
QhHwPtr->EndpointSpeed = (DeviceSpeed & 0x3);
QhHwPtr->EndpointNum = (Endpoint & 0x0F);
QhHwPtr->DeviceAddr = (DeviceAddr & 0x7F);
QhHwPtr->Multiplier = HIGH_BANDWIDTH_PIPE_MULTIPLIER;
QhHwPtr->Rsvd1 = 0;
QhHwPtr->Rsvd2 = 0;
QhHwPtr->Rsvd3 = 0;
QhHwPtr->Rsvd4 = 0;
QhHwPtr->Rsvd5 = 0;
QhHwPtr->Rsvd6 = 0;
exit:
return Status;
}
VOID
DestoryQh (
IN USB2_HC_DEV *HcDev,
IN EHCI_QH_ENTITY *QhPtr
)
/*++
Routine Description:
Destory Qh Structure
Arguments:
HcDev - USB2_HC_DEV
QhPtr - A pointer to Qh
Returns:
EFI_SUCCESS Success
EFI_DEVICE_ERROR Fail
--*/
{
ASSERT (HcDev);
ASSERT (QhPtr);
EhciFreePool (HcDev, (UINT8 *) QhPtr, sizeof (EHCI_QH_ENTITY));
return ;
}
EFI_STATUS
CreateControlQh (
IN USB2_HC_DEV *HcDev,
IN UINT8 DeviceAddr,
IN UINT8 DeviceSpeed,
IN UINTN MaxPacketLen,
IN EFI_USB2_HC_TRANSACTION_TRANSLATOR *Translator,
OUT EHCI_QH_ENTITY **QhPtrPtr
)
/*++
Routine Description:
Create Qh for Control Transfer
Arguments:
HcDev - USB2_HC_DEV
DeviceAddr - Address of Device
DeviceSpeed - Device Speed
MaxPacketLen - Max Length of one Packet
Translator - Translator Transaction for SplitX
QhPtrPtr - A pointer of pointer to Qh for return
Returns:
EFI_SUCCESS Success
EFI_OUT_OF_RESOURCES Cannot allocate resources
--*/
{
EFI_STATUS Status;
//
// Create and init Control Qh
//
Status = CreateQh (
HcDev,
DeviceAddr,
0,
DeviceSpeed,
MaxPacketLen,
QhPtrPtr
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?