📄 uhci.c
字号:
return EFI_SUCCESS ;
}
EFI_STATUS
UHCIControlTransfer (
IN EFI_USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN BOOLEAN IsSlowDevice,
IN UINT8 MaximumPacketLength,
IN EFI_USB_DEVICE_REQUEST *Request,
IN EFI_USB_DATA_DIRECTION TransferDirection,
IN OUT VOID *Data OPTIONAL,
IN OUT UINTN *DataLength OPTIONAL,
IN UINTN TimeOut,
OUT UINT32 *TransferResult
)
/*++
Routine Description:
Submits control transfer to a target USB device.
Arguments:
This A pointer to the EFI_USB_HC_PROTOCOL instance.
DeviceAddress Represents the address of the target device on the USB,
which is assigned during USB enumeration.
IsSlowDevice Indicates whether the target device is slow device
or full-speed device.
MaximumPacketLength Indicates the maximum packet size that the
default control transfer endpoint is capable of
sending or receiving.
Request A pointer to the USB device request that will be sent
to the USB device.
TransferDirection Specifies the data direction for the transfer.
There are three values available, DataIn, DataOut
and NoData.
Data A pointer to the buffer of data that will be transmitted
to USB device or received from USB device.
DataLength Indicates the size, in bytes, of the data buffer
specified by Data.
TimeOut Indicates the maximum time, in microseconds,
which the transfer is allowed to complete.
TransferResult A pointer to the detailed result information generated
by this control transfer.
Returns:
EFI_SUCCESS
The control transfer was completed successfully.
EFI_OUT_OF_RESOURCES
The control transfer could not be completed due to a lack of resources.
EFI_INVALID_PARAMETER
Some parameters are invalid.
EFI_TIMEOUT
The control transfer failed due to timeout.
EFI_DEVICE_ERROR
The control transfer failed due to host controller or device error.
Caller should check TranferResult for detailed error information.
--*/
{
USB_HC_DEV *HcDev;
UINT32 StatusReg;
UINT32 FrameNumReg;
UINT8 PktID;
QH_STRUCT *ptrQH;
TD_STRUCT *ptrTD;
TD_STRUCT *ptrPreTD;
TD_STRUCT *ptrSetupTD;
TD_STRUCT *ptrStatusTD;
EFI_STATUS Status;
UINTN i;
UINTN DataLen;
UINT8 *ptrDataSource;
UINT8 *ptr;
UINT8 DataToggle;
UINT16 LoadFrameListIndex;
UINT8 pktsize;
UINT8 *RequestMappedAddress = NULL;
VOID *RequestMapping = NULL;
UINTN RequestLen;
EFI_PHYSICAL_ADDRESS TempPtr;
VOID *Mapping = NULL;
TD_STRUCT *ptrFirstDataTD = NULL;
TD_STRUCT *ptrLastDataTD = NULL;
BOOLEAN FirstTD = FALSE;
PktID = INPUT_PACKET_ID;
Mapping = NULL;
HcDev = USB_HC_DEV_FROM_THIS(This);
StatusReg = (UINT32)(USBSTS);
FrameNumReg = (UINT32)(USBFRNUM);
ptrPreTD = NULL;
ptrTD = NULL;
//
// Parameters Checking
//
if (Request == NULL || TransferResult == NULL) {
return EFI_INVALID_PARAMETER;
}
//
// if errors exist that cause host controller halt,
// then return EFI_DEVICE_ERROR.
//
if(IsHCHalted(HcDev->PciIo,StatusReg) ||
IsHCProcessErr(HcDev->PciIo,StatusReg) ||
IsHostSysErr(HcDev->PciIo,StatusReg)) {
ClearStatusReg(HcDev->PciIo,StatusReg);
*TransferResult = EFI_USB_ERR_SYSTEM;
return EFI_DEVICE_ERROR;
}
//
// low speed usb devices are limited to only an eight-byte
// maximum data payload size
//
if (IsSlowDevice && (MaximumPacketLength != 8)) {
return EFI_INVALID_PARAMETER;
}
if (MaximumPacketLength != 8 && MaximumPacketLength != 16
&& MaximumPacketLength != 32 && MaximumPacketLength != 64) {
return EFI_INVALID_PARAMETER;
}
if ((TransferDirection != EfiUsbNoData) && (DataLength == NULL)) {
return EFI_INVALID_PARAMETER;
}
switch(TransferDirection) {
case EfiUsbDataIn:
PktID = INPUT_PACKET_ID;
ptrDataSource = Data;
DataLen = *DataLength;
//
// map the source data buffer for bus master access.
// BusMasterWrite means cpu read
//
Status = HcDev->PciIo->Map (
HcDev->PciIo,
EfiPciIoOperationBusMasterWrite,
ptrDataSource,
&DataLen,
&TempPtr,
&Mapping
);
if (EFI_ERROR(Status)) {
return Status;
}
ptr = (UINT8*)((UINTN)TempPtr);
break;
case EfiUsbDataOut:
PktID = OUTPUT_PACKET_ID;
ptrDataSource = Data;
DataLen = *DataLength;
//
// map the source data buffer for bus master access.
// BusMasterRead means cpu write
//
Status = HcDev->PciIo->Map (HcDev->PciIo,
EfiPciIoOperationBusMasterRead,
ptrDataSource,
&DataLen,
&TempPtr,
&Mapping
);
if (EFI_ERROR(Status)) {
return Status;
}
ptr = (UINT8*)((UINTN)TempPtr);
break;
//
// no data stage
//
case EfiUsbNoData:
if ((DataLength != NULL) && (*DataLength != 0) ) {
return EFI_INVALID_PARAMETER;
}
PktID = OUTPUT_PACKET_ID;
ptrDataSource = NULL;
DataLen = 0;
ptr = NULL;
break;
default:
return EFI_INVALID_PARAMETER;
}
ClearStatusReg(HcDev->PciIo,StatusReg);
//
// create QH structure and init
//
Status = CreateQH(HcDev,&ptrQH);
if(EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
return Status;
}
//
// map the Request for bus master access.
// BusMasterRead means cpu write
//
RequestLen = sizeof (EFI_USB_DEVICE_REQUEST);
Status = HcDev->PciIo->Map (HcDev->PciIo,
EfiPciIoOperationBusMasterRead,
(UINT8*)Request,
&RequestLen,
&TempPtr,
&RequestMapping
);
if (EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
return Status;
}
RequestMappedAddress = (UINT8*)((UINTN)TempPtr);
//
// generate Setup Stage TD
//
Status = GenSetupStageTD(HcDev,DeviceAddress,0,
IsSlowDevice, (UINT8*)RequestMappedAddress,
sizeof(EFI_USB_DEVICE_REQUEST), &ptrSetupTD);
if (EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
return Status;
}
//
// Data Stage of Control Transfer
//
DataToggle = 1;
FirstTD = TRUE;
while(DataLen > 0) {
//
// create TD structures and link together
//
//
// pktsize is the data load size that each TD carries.
//
pktsize = (UINT8)DataLen;
if (DataLen > MaximumPacketLength) {
pktsize = MaximumPacketLength;
}
Status = GenDataTD(HcDev,DeviceAddress, 0, ptr, pktsize, PktID, DataToggle, IsSlowDevice,&ptrTD);
if (EFI_ERROR(Status)) {
//
// free all resources occupied
//
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
DeleteQueuedTDs (HcDev, ptrSetupTD);
DeleteQueuedTDs (HcDev,ptrFirstDataTD);
return Status;
}
//
// Link two TDs in vertical depth
//
if (FirstTD) {
ptrFirstDataTD = ptrTD ;
ptrFirstDataTD->ptrNextTD = NULL;
FirstTD = FALSE;
} else {
LinkTDToTD(ptrPreTD,ptrTD);
}
ptrPreTD = ptrTD;
DataToggle ^= 1;
ptr += pktsize;
DataLen -= pktsize;
}
ptrLastDataTD = ptrTD;
//
// Status Stage of Control Transfer
//
if(PktID == OUTPUT_PACKET_ID) {
PktID = INPUT_PACKET_ID;
} else {
PktID = OUTPUT_PACKET_ID;
}
//
// create Status Stage TD structure
//
Status = CreateStatusTD(HcDev,DeviceAddress,0,PktID,IsSlowDevice,&ptrStatusTD);
if (EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
DeleteQueuedTDs (HcDev, ptrSetupTD);
DeleteQueuedTDs (HcDev,ptrFirstDataTD);
return Status;
}
if (IsSlowDevice) {
//
// link setup TD structures to QH structure
//
LinkTDToQH(ptrQH,ptrSetupTD);
LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
//
// link QH-TDs to total 50 frame list entry to speed up the execution.
//
for(i = 0; i < 100; i ++) {
LinkQHToFrameList(HcDev->FrameListEntry,
(UINT16)((LoadFrameListIndex + i) % 1024),
ptrQH) ;
}
//
// Poll QH-TDs execution and get result.
// detail status is returned
//
Status = ExecuteControlTransfer (HcDev,ptrSetupTD,
LoadFrameListIndex,DataLength,
TimeOut,TransferResult);
//
// Remove Control Transfer QH-TDs structure from the frame list
// and update the pointers in the Frame List
// and other pointers in other related QH structures.
//
for (i = 0; i < 100; i ++) {
DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
}
//
// delete setup stage TD; the QH is reserved for the next stages.
//
DeleteQueuedTDs (HcDev,ptrSetupTD);
//
// some control transfers do not have Data Stage
//
if (ptrFirstDataTD != NULL) {
LinkTDToQH (ptrQH,ptrFirstDataTD);
LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
for(i = 0; i < 500; i ++) {
LinkQHToFrameList(HcDev->FrameListEntry,
(UINT16)((LoadFrameListIndex + i) % 1024),
ptrQH) ;
}
Status = ExecuteControlTransfer (HcDev,ptrFirstDataTD,
LoadFrameListIndex,DataLength,
TimeOut,TransferResult);
for (i = 0; i < 500; i ++) {
DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
}
//
// delete data stage TD; the QH is reserved for the next stage.
//
DeleteQueuedTDs (HcDev,ptrFirstDataTD);
}
LinkTDToQH(ptrQH,ptrStatusTD);
//
// get the frame list index that the QH-TDs will be linked to.
//
LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
for(i = 0; i < 100; i ++) {
//
// put the QH-TDs directly or indirectly into the proper place
// in the Frame List
//
LinkQHToFrameList(HcDev->FrameListEntry,
(UINT16)((LoadFrameListIndex + i) % 1024),
ptrQH) ;
}
//
// Poll QH-TDs execution and get result.
// detail status is returned
//
Status = ExecuteControlTransfer (HcDev,ptrStatusTD,
LoadFrameListIndex,DataLength,
TimeOut,TransferResult);
//
// Delete Control Transfer QH-TDs structure
// and update the pointers in the Frame List
// and other pointers in other related QH structures.
//
// TRUE means must search other framelistindex
//
for (i = 0; i < 100; i ++) {
DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
}
DeleteQueuedTDs (HcDev,ptrStatusTD);
} else {
//
// link setup stage TD with data stage TD
//
ptrPreTD = ptrSetupTD;
if (ptrFirstDataTD != NULL) {
LinkTDToTD (ptrSetupTD, ptrFirstDataTD);
ptrPreTD = ptrLastDataTD;
}
//
// link status TD with previous TD
//
LinkTDToTD (ptrPreTD, ptrStatusTD);
//
// link QH with TD
//
LinkTDToQH (ptrQH, ptrSetupTD);
LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
for(i = 0; i < 500; i ++) {
//
// put the QH-TDs directly or indirectly into the proper place
// in the Frame List
//
LinkQHToFrameList(HcDev->FrameListEntry,
(UINT16)((LoadFrameListIndex + i) % 1024),
ptrQH) ;
}
//
// Poll QH-TDs execution and get result.
// detail status is returned
//
Status = ExecuteControlTransfer (HcDev,ptrSetupTD,
LoadFrameListIndex,DataLength,
TimeOut,TransferResult);
//
// Remove Control Transfer QH-TDs structure from the frame list
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -