📄 uhci.c
字号:
// and update the pointers in the Frame List
// and other pointers in other related QH structures.
//
for (i = 0; i < 500; i ++) {
DelLinkSingleQH (HcDev,ptrQH,(UINT16)((LoadFrameListIndex + i) % 1024),FALSE,FALSE);
}
DeleteQueuedTDs (HcDev,ptrSetupTD);
}
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
if (Mapping != NULL) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
}
if (RequestMapping != NULL) {
HcDev->PciIo->Unmap (HcDev->PciIo,RequestMapping);
}
//
// if has errors that cause host controller halt,
// then return EFI_DEVICE_ERROR directly.
//
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;
}
ClearStatusReg(HcDev->PciIo,StatusReg);
return Status ;
}
EFI_STATUS
UHCIBulkTransfer (
IN EFI_USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPointAddress,
IN UINT8 MaximumPacketLength,
IN OUT VOID *Data,
IN OUT UINTN *DataLength,
IN OUT UINT8 *DataToggle,
IN UINTN TimeOut,
OUT UINT32 *TransferResult
)
/*++
Routine Description:
Submits bulk transfer to a bulk endpoint of a 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.
EndPointAddress The combination of an endpoint number and an
endpoint direction of the target USB device.
Each endpoint address supports data transfer in
one direction except the control endpoint
(whose default endpoint address is 0).
It is the caller's responsibility to make sure that
the EndPointAddress represents a bulk endpoint.
MaximumPacketLength Indicates the maximum packet size the target endpoint
is capable of sending or receiving.
Data A pointer to the buffer of data that will be transmitted
to USB device or received from USB device.
DataLength When input, indicates the size, in bytes, of the data buffer
specified by Data. When output, indicates the actually
transferred data size.
DataToggle A pointer to the data toggle value. On input, it indicates
the initial data toggle value the bulk transfer should adopt;
on output, it is updated to indicate the data toggle value
of the subsequent bulk transfer.
TimeOut Indicates the maximum time, in microseconds, which the
transfer is allowed to complete.
TransferResult A pointer to the detailed result information of the
bulk transfer.
Returns:
EFI_SUCCESS
The bulk transfer was completed successfully.
EFI_OUT_OF_RESOURCES
The bulk transfer could not be submitted due to lack of resource.
EFI_INVALID_PARAMETER
Some parameters are invalid.
EFI_TIMEOUT
The bulk transfer failed due to timeout.
EFI_DEVICE_ERROR
The bulk 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;
UINTN DataLen;
QH_STRUCT *ptrQH ;
TD_STRUCT *ptrFirstTD;
TD_STRUCT *ptrTD;
TD_STRUCT *ptrPreTD;
UINT16 LoadFrameListIndex;
UINT16 SavedFrameListIndex;
UINT8 PktID;
UINT8 *ptrDataSource;
UINT8 *ptr;
BOOLEAN IsFirstTD;
EFI_STATUS Status ;
UINT32 i;
UINT8 pktsize;
EFI_USB_DATA_DIRECTION TransferDirection;
//
// Used to calculate how many entries are linked to the
// specified bulk transfer QH-TDs
//
UINT32 LinkTimes;
BOOLEAN ShortPacketEnable;
EFI_PHYSICAL_ADDRESS TempPtr;
VOID *Mapping;
HcDev = USB_HC_DEV_FROM_THIS(This);
StatusReg = (UINT32)(USBSTS);
FrameNumReg = (UINT32)(USBFRNUM);
PktID = INPUT_PACKET_ID;
ptrTD = NULL;
ptrFirstTD = NULL;
ptrPreTD = NULL;
LinkTimes = 1;
DataLen = 0;
ptr = NULL;
ShortPacketEnable = FALSE;
Mapping = NULL;
//
// Parameters Checking
//
if ((DataLength == NULL) || (Data == NULL)
|| (TransferResult == NULL)) {
return EFI_INVALID_PARAMETER;
}
//
// if has errors that cause host controller halt,
// then return EFI_DEVICE_ERROR directly.
//
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;
}
if (*DataLength == 0) {
return EFI_INVALID_PARAMETER;
}
if ((*DataToggle != 1) && (*DataToggle != 0)) {
return EFI_INVALID_PARAMETER;
}
if(MaximumPacketLength != 8 && MaximumPacketLength != 16
&& MaximumPacketLength != 32 && MaximumPacketLength != 64) {
return EFI_INVALID_PARAMETER;
}
//
// Enable the maximum packet size (64bytes)
// that can be used for full speed bandwidth reclamation
// at the end of a frame.
//
EnableMaxPacketSize (HcDev);
ClearStatusReg(HcDev->PciIo,StatusReg);
//
// construct QH and TD data structures,
// and link them together
//
if (EndPointAddress & 0x80) {
TransferDirection = EfiUsbDataIn;
} else {
TransferDirection = EfiUsbDataOut;
}
switch(TransferDirection) {
case EfiUsbDataIn:
ShortPacketEnable = TRUE;
PktID = INPUT_PACKET_ID;
ptrDataSource = Data;
DataLen = *DataLength;
//
// 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;
//
// 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;
default:
return EFI_INVALID_PARAMETER;
}
//
// create QH structure and init
//
Status = CreateQH(HcDev,&ptrQH);
if(EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
return Status;
}
//
// i is used to calculate the total number of TDs.
//
i = 0;
IsFirstTD = TRUE ;
while(DataLen > 0) {
//
// create TD structures and link together
//
pktsize = (UINT8)DataLen;
if(DataLen > MaximumPacketLength) {
pktsize = MaximumPacketLength;
}
Status = GenDataTD(HcDev,DeviceAddress,EndPointAddress, ptr,
pktsize, PktID, *DataToggle, FALSE,&ptrTD);
if (EFI_ERROR(Status)) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
DeleteQueuedTDs (HcDev,ptrFirstTD);
return Status;
}
//
// Enable short packet detection.
// (default action is disabling short packet detection)
//
if(ShortPacketEnable) {
EnableorDisableTDShortPacket (ptrTD, TRUE) ;
}
if(IsFirstTD) {
ptrFirstTD = ptrTD ;
ptrFirstTD->ptrNextTD = NULL;
IsFirstTD = FALSE ;
} else {
//
// Link two TDs in vertical depth
//
LinkTDToTD(ptrPreTD,ptrTD) ;
}
i ++ ;
ptrPreTD = ptrTD ;
*DataToggle ^= 1;
ptr += pktsize;
DataLen -= pktsize;
}
//
// link TD structures to QH structure
//
LinkTDToQH(ptrQH,ptrFirstTD);
//
// calculate how many entries are linked to the specified bulk transfer QH-TDs
// the below values are referred to the USB spec revision1.1.
//
switch(MaximumPacketLength) {
case 8:
LinkTimes = i / 71 + 1;
break;
case 16:
LinkTimes = i / 51 + 1;
break;
case 32:
LinkTimes = i / 33 + 1;
break;
case 64:
LinkTimes = i / 19 + 1;
break;
}
LinkTimes += 500; // redundant
//
// put QH-TDs into Frame list
//
LoadFrameListIndex = (UINT16)((GetCurrentFrameNumber(HcDev->PciIo,FrameNumReg)) % 1024);
SavedFrameListIndex = LoadFrameListIndex;
for(i = 0; i <= LinkTimes ; i ++) {
//
// put the QH-TD directly or indirectly into the proper place
// in the Frame List
//
LinkQHToFrameList(HcDev->FrameListEntry,LoadFrameListIndex,ptrQH) ;
LoadFrameListIndex += 1 ;
LoadFrameListIndex %= 1024 ;
}
LoadFrameListIndex = SavedFrameListIndex;
//
// Execute QH-TD and get result
//
//
// detail status is put into the Result field in the pIRP
// the Data Toggle value is also re-updated to the value
// of the last successful TD
//
Status = ExecBulkorSyncInterruptTransfer (HcDev,ptrFirstTD,
LoadFrameListIndex,DataLength,
DataToggle,TimeOut,TransferResult);
//
// Delete Bulk transfer QH-TD structure
// and maitain the pointers in the Frame List
// and other pointers in related QH structure
//
// TRUE means must search other framelistindex
//
for(i = 0; i <= LinkTimes ; i ++) {
DelLinkSingleQH (HcDev,ptrQH,LoadFrameListIndex,FALSE,FALSE);
LoadFrameListIndex += 1;
LoadFrameListIndex %= 1024 ;
}
UhciFreePool(HcDev,(UINT8*)ptrQH,sizeof(QH_STRUCT));
DeleteQueuedTDs (HcDev,ptrFirstTD);
if (Mapping != NULL) {
HcDev->PciIo->Unmap (HcDev->PciIo,Mapping);
}
//
// if has errors that cause host controller halt,
// then return EFI_DEVICE_ERROR directly.
//
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;
}
ClearStatusReg(HcDev->PciIo,StatusReg);
return Status ;
}
EFI_STATUS
UHCIAsyncInterruptTransfer (
IN EFI_USB_HC_PROTOCOL *This,
IN UINT8 DeviceAddress,
IN UINT8 EndPointAddress,
IN BOOLEAN IsSlowDevice,
IN UINT8 MaxiumPacketLength,
IN BOOLEAN IsNewTransfer,
IN OUT UINT8 *DataToggle,
IN UINTN PollingInterval OPTIONAL,
IN UINTN DataLength OPTIONAL,
IN EFI_ASYNC_USB_TRANSFER_CALLBACK CallBackFunction OPTIONAL,
IN VOID *Context OPTIONAL
)
/*++
Routine Description:
Submits an asynchronous interrupt transfer to an
interrupt endpoint of a 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.
EndPointAddress The combination of an endpoint number and an endpoint
direction of the target USB device. Each endpoint address
supports data transfer in one direction except the
control endpoint (whose default endpoint address is 0).
It is the caller's responsibility to make sure that
the EndPointAddress represents an interrupt endpoint.
IsSlowDevice Indicates whether the target device is slow device
or full-speed device.
MaxiumPacketLength Indicates the maximum packet size the target endpoint
is capable of sending or receiving.
IsNewTransfer If TRUE, an asynchronous interrupt pipe is built between
the host and the target interrupt endpoint.
If FALSE, the specified asynchronous interrupt pipe
is canceled.
DataToggle A pointer to the data toggle value. On input, it is valid
when IsNewTransfer is TRUE, and it indicates the initial
data toggle value the asynchronous interrupt transfer
should adopt.
On output, it is valid when IsNewTransfer is FALSE,
and it is updated to indicate the data toggle value of
the subsequent asynchronous interrupt transfer.
PollingInterval Indicates the interval, in milliseconds, that the
asynchronous interrupt transfer is polled.
This parameter is required when IsNewTransfer is TRUE.
DataLength Indicates the length of data to be r
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -