mirror of https://github.com/acidanthera/audk.git
567 lines
11 KiB
C
567 lines
11 KiB
C
/** @file
|
|
This file contains URB request, each request is warpped in a
|
|
URB (Usb Request Block).
|
|
|
|
Copyright (c) 2013-2015 Intel Corporation.
|
|
|
|
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.
|
|
|
|
**/
|
|
|
|
|
|
|
|
#include "OhcPeim.h"
|
|
|
|
|
|
/**
|
|
|
|
Create a TD
|
|
|
|
@Param Ohc UHC private data
|
|
|
|
@retval TD structure pointer
|
|
|
|
**/
|
|
TD_DESCRIPTOR *
|
|
OhciCreateTD (
|
|
IN USB_OHCI_HC_DEV *Ohc
|
|
)
|
|
{
|
|
TD_DESCRIPTOR *Td;
|
|
|
|
Td = UsbHcAllocateMem(Ohc->MemPool, sizeof(TD_DESCRIPTOR));
|
|
if (Td == NULL) {
|
|
return NULL;
|
|
}
|
|
Td->CurrBufferPointer = NULL;
|
|
Td->NextTD = NULL;
|
|
Td->BufferEndPointer = NULL;
|
|
Td->NextTDPointer = NULL;
|
|
|
|
return Td;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Free a TD
|
|
|
|
@Param Ohc UHC private data
|
|
@Param Td Pointer to a TD to free
|
|
|
|
@retval EFI_SUCCESS TD freed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciFreeTD (
|
|
IN USB_OHCI_HC_DEV *Ohc,
|
|
IN TD_DESCRIPTOR *Td
|
|
)
|
|
{
|
|
if (Td == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
UsbHcFreeMem(Ohc->MemPool, Td, sizeof(TD_DESCRIPTOR));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Create a ED
|
|
|
|
@Param Ohc Device private data
|
|
|
|
@retval ED descriptor pointer
|
|
|
|
**/
|
|
ED_DESCRIPTOR *
|
|
OhciCreateED (
|
|
USB_OHCI_HC_DEV *Ohc
|
|
)
|
|
{
|
|
ED_DESCRIPTOR *Ed;
|
|
Ed = UsbHcAllocateMem(Ohc->MemPool, sizeof (ED_DESCRIPTOR));
|
|
if (Ed == NULL) {
|
|
return NULL;
|
|
}
|
|
Ed->Word0.Skip = 1;
|
|
Ed->TdTailPointer = NULL;
|
|
Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) NULL);
|
|
Ed->NextED = NULL;
|
|
|
|
return Ed;
|
|
}
|
|
|
|
/**
|
|
|
|
Free a ED
|
|
|
|
@Param Ohc UHC private data
|
|
@Param Ed Pointer to a ED to free
|
|
|
|
@retval EFI_SUCCESS ED freed
|
|
|
|
**/
|
|
|
|
EFI_STATUS
|
|
OhciFreeED (
|
|
IN USB_OHCI_HC_DEV *Ohc,
|
|
IN ED_DESCRIPTOR *Ed
|
|
)
|
|
{
|
|
if (Ed == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
UsbHcFreeMem(Ohc->MemPool, Ed, sizeof(ED_DESCRIPTOR));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Free ED
|
|
|
|
@Param Ohc Device private data
|
|
@Param Ed Pointer to a ED to free
|
|
|
|
@retval EFI_SUCCESS ED freed
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciFreeAllTDFromED (
|
|
IN USB_OHCI_HC_DEV *Ohc,
|
|
IN ED_DESCRIPTOR *Ed
|
|
)
|
|
{
|
|
TD_DESCRIPTOR *HeadTd;
|
|
TD_DESCRIPTOR *TailTd;
|
|
TD_DESCRIPTOR *Td;
|
|
TD_DESCRIPTOR *TempTd;
|
|
|
|
if (Ed == NULL) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
HeadTd = TD_PTR (Ed->Word2.TdHeadPointer);
|
|
TailTd = Ed->TdTailPointer;
|
|
|
|
Td = HeadTd;
|
|
while (Td != TailTd) {
|
|
TempTd = Td;
|
|
Td = Td->NextTDPointer;
|
|
OhciFreeTD (Ohc, TempTd);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Attach an ED
|
|
|
|
@Param Ed Ed to be attached
|
|
@Param NewEd Ed to attach
|
|
|
|
@retval EFI_SUCCESS NewEd attached to Ed
|
|
@retval EFI_INVALID_PARAMETER Ed is NULL
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciAttachED (
|
|
IN ED_DESCRIPTOR *Ed,
|
|
IN ED_DESCRIPTOR *NewEd
|
|
)
|
|
{
|
|
ED_DESCRIPTOR *Temp;
|
|
|
|
if (Ed == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Ed->NextED == NULL){
|
|
Ed->NextED = NewEd;
|
|
} else {
|
|
Temp = Ed->NextED;
|
|
Ed->NextED = NewEd;
|
|
NewEd->NextED = Temp;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
/**
|
|
|
|
Attach an ED to an ED list
|
|
|
|
@Param OHC UHC private data
|
|
@Param ListType Type of the ED list
|
|
@Param Ed ED to attach
|
|
@Param EdList ED list to be attached
|
|
|
|
@retval EFI_SUCCESS ED attached to ED list
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciAttachEDToList (
|
|
IN USB_OHCI_HC_DEV *Ohc,
|
|
IN DESCRIPTOR_LIST_TYPE ListType,
|
|
IN ED_DESCRIPTOR *Ed,
|
|
IN ED_DESCRIPTOR *EdList
|
|
)
|
|
{
|
|
ED_DESCRIPTOR *HeadEd;
|
|
|
|
switch(ListType) {
|
|
case CONTROL_LIST:
|
|
HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_CONTROL_HEAD);
|
|
if (HeadEd == NULL) {
|
|
OhciSetMemoryPointer (Ohc, HC_CONTROL_HEAD, Ed);
|
|
} else {
|
|
OhciAttachED (HeadEd, Ed);
|
|
}
|
|
break;
|
|
|
|
case BULK_LIST:
|
|
HeadEd = (ED_DESCRIPTOR *) OhciGetMemoryPointer (Ohc, HC_BULK_HEAD);
|
|
if (HeadEd == NULL) {
|
|
OhciSetMemoryPointer (Ohc, HC_BULK_HEAD, Ed);
|
|
} else {
|
|
OhciAttachED (HeadEd, Ed);
|
|
}
|
|
break;
|
|
|
|
case INTERRUPT_LIST:
|
|
OhciAttachED (EdList, Ed);
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
/**
|
|
|
|
Link Td2 to the end of Td1
|
|
|
|
@Param Td1 TD to be linked
|
|
@Param Td2 TD to link
|
|
|
|
@retval EFI_SUCCESS TD successfully linked
|
|
@retval EFI_INVALID_PARAMETER Td1 is NULL
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciLinkTD (
|
|
IN TD_DESCRIPTOR *Td1,
|
|
IN TD_DESCRIPTOR *Td2
|
|
)
|
|
{
|
|
TD_DESCRIPTOR *TempTd;
|
|
|
|
if (Td1 == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (Td1 == Td2) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
TempTd = Td1;
|
|
while (TempTd->NextTD != NULL) {
|
|
TempTd = TempTd->NextTD;
|
|
}
|
|
|
|
TempTd->NextTD = Td2;
|
|
TempTd->NextTDPointer = Td2;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Attach TD list to ED
|
|
|
|
@Param Ed ED which TD list attach on
|
|
@Param HeadTd Head of the TD list to attach
|
|
|
|
@retval EFI_SUCCESS TD list attached on the ED
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciAttachTDListToED (
|
|
IN ED_DESCRIPTOR *Ed,
|
|
IN TD_DESCRIPTOR *HeadTd
|
|
)
|
|
{
|
|
TD_DESCRIPTOR *TempTd;
|
|
|
|
TempTd = TD_PTR (Ed->Word2.TdHeadPointer);
|
|
|
|
if (TempTd != NULL) {
|
|
while (TempTd->NextTD != NULL) {
|
|
TempTd = TempTd->NextTD;
|
|
}
|
|
TempTd->NextTD = HeadTd;
|
|
TempTd->NextTDPointer = HeadTd;
|
|
} else {
|
|
Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 ((UINT32) HeadTd);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Set value to ED specific field
|
|
|
|
@Param Ed ED to be set
|
|
@Param Field Field to be set
|
|
@Param Value Value to set
|
|
|
|
@retval EFI_SUCCESS Value set
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciSetEDField (
|
|
IN ED_DESCRIPTOR *Ed,
|
|
IN UINT32 Field,
|
|
IN UINT32 Value
|
|
)
|
|
{
|
|
if (Field & ED_FUNC_ADD) {
|
|
Ed->Word0.FunctionAddress = Value;
|
|
}
|
|
if (Field & ED_ENDPT_NUM) {
|
|
Ed->Word0.EndPointNum = Value;
|
|
}
|
|
if (Field & ED_DIR) {
|
|
Ed->Word0.Direction = Value;
|
|
}
|
|
if (Field & ED_SPEED) {
|
|
Ed->Word0.Speed = Value;
|
|
}
|
|
if (Field & ED_SKIP) {
|
|
Ed->Word0.Skip = Value;
|
|
}
|
|
if (Field & ED_FORMAT) {
|
|
Ed->Word0.Format = Value;
|
|
}
|
|
if (Field & ED_MAX_PACKET) {
|
|
Ed->Word0.MaxPacketSize = Value;
|
|
}
|
|
if (Field & ED_PDATA) {
|
|
Ed->Word0.FreeSpace = Value;
|
|
}
|
|
if (Field & ED_ZERO) {
|
|
Ed->Word2.Zero = Value;
|
|
}
|
|
if (Field & ED_TDTAIL_PTR) {
|
|
Ed->TdTailPointer = (VOID *) Value;
|
|
}
|
|
|
|
if (Field & ED_HALTED) {
|
|
Ed->Word2.Halted = Value;
|
|
}
|
|
if (Field & ED_DTTOGGLE) {
|
|
Ed->Word2.ToggleCarry = Value;
|
|
}
|
|
if (Field & ED_TDHEAD_PTR) {
|
|
Ed->Word2.TdHeadPointer = RIGHT_SHIFT_4 (Value);
|
|
}
|
|
|
|
if (Field & ED_NEXT_EDPTR) {
|
|
Ed->NextED = (VOID *) Value;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Get value from an ED's specific field
|
|
|
|
@Param Ed ED pointer
|
|
@Param Field Field to get value from
|
|
|
|
@retval Value of the field
|
|
|
|
**/
|
|
UINT32
|
|
OhciGetEDField (
|
|
IN ED_DESCRIPTOR *Ed,
|
|
IN UINT32 Field
|
|
)
|
|
{
|
|
switch (Field) {
|
|
case ED_FUNC_ADD:
|
|
return Ed->Word0.FunctionAddress;
|
|
break;
|
|
case ED_ENDPT_NUM:
|
|
return Ed->Word0.EndPointNum;
|
|
break;
|
|
case ED_DIR:
|
|
return Ed->Word0.Direction;
|
|
break;
|
|
case ED_SPEED:
|
|
return Ed->Word0.Speed;
|
|
break;
|
|
case ED_SKIP:
|
|
return Ed->Word0.Skip;
|
|
break;
|
|
case ED_FORMAT:
|
|
return Ed->Word0.Format;
|
|
break;
|
|
case ED_MAX_PACKET:
|
|
return Ed->Word0.MaxPacketSize;
|
|
break;
|
|
|
|
case ED_TDTAIL_PTR:
|
|
return (UINT32) Ed->TdTailPointer;
|
|
break;
|
|
|
|
case ED_HALTED:
|
|
return Ed->Word2.Halted;
|
|
break;
|
|
|
|
case ED_DTTOGGLE:
|
|
return Ed->Word2.ToggleCarry;
|
|
break;
|
|
|
|
case ED_TDHEAD_PTR:
|
|
return Ed->Word2.TdHeadPointer << 4;
|
|
break;
|
|
|
|
case ED_NEXT_EDPTR:
|
|
return (UINT32) Ed->NextED;
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Set value to TD specific field
|
|
|
|
@Param Td TD to be set
|
|
@Param Field Field to be set
|
|
@Param Value Value to set
|
|
|
|
@retval EFI_SUCCESS Value set
|
|
|
|
**/
|
|
EFI_STATUS
|
|
OhciSetTDField (
|
|
IN TD_DESCRIPTOR *Td,
|
|
IN UINT32 Field,
|
|
IN UINT32 Value
|
|
)
|
|
{
|
|
if (Field & TD_PDATA) {
|
|
Td->Word0.Reserved = Value;
|
|
}
|
|
if (Field & TD_BUFFER_ROUND) {
|
|
Td->Word0.BufferRounding = Value;
|
|
}
|
|
if (Field & TD_DIR_PID) {
|
|
Td->Word0.DirPID = Value;
|
|
}
|
|
if (Field & TD_DELAY_INT) {
|
|
Td->Word0.DelayInterrupt = Value;
|
|
}
|
|
if (Field & TD_DT_TOGGLE) {
|
|
Td->Word0.DataToggle = Value | 0x2;
|
|
}
|
|
if (Field & TD_ERROR_CNT) {
|
|
Td->Word0.ErrorCount = Value;
|
|
}
|
|
if (Field & TD_COND_CODE) {
|
|
Td->Word0.ConditionCode = Value;
|
|
}
|
|
|
|
if (Field & TD_CURR_BUFFER_PTR) {
|
|
Td->CurrBufferPointer = (VOID *) Value;
|
|
}
|
|
|
|
|
|
if (Field & TD_NEXT_PTR) {
|
|
Td->NextTD = (VOID *) Value;
|
|
}
|
|
|
|
if (Field & TD_BUFFER_END_PTR) {
|
|
Td->BufferEndPointer = (VOID *) Value;
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
|
|
/**
|
|
|
|
Get value from ED specific field
|
|
|
|
@Param Td TD pointer
|
|
@Param Field Field to get value from
|
|
|
|
@retval Value of the field
|
|
|
|
**/
|
|
|
|
UINT32
|
|
OhciGetTDField (
|
|
IN TD_DESCRIPTOR *Td,
|
|
IN UINT32 Field
|
|
)
|
|
{
|
|
switch (Field){
|
|
case TD_BUFFER_ROUND:
|
|
return Td->Word0.BufferRounding;
|
|
break;
|
|
case TD_DIR_PID:
|
|
return Td->Word0.DirPID;
|
|
break;
|
|
case TD_DELAY_INT:
|
|
return Td->Word0.DelayInterrupt;
|
|
break;
|
|
case TD_DT_TOGGLE:
|
|
return Td->Word0.DataToggle;
|
|
break;
|
|
case TD_ERROR_CNT:
|
|
return Td->Word0.ErrorCount;
|
|
break;
|
|
case TD_COND_CODE:
|
|
return Td->Word0.ConditionCode;
|
|
break;
|
|
case TD_CURR_BUFFER_PTR:
|
|
return (UINT32) Td->CurrBufferPointer;
|
|
break;
|
|
|
|
case TD_NEXT_PTR:
|
|
return (UINT32) Td->NextTD;
|
|
break;
|
|
|
|
case TD_BUFFER_END_PTR:
|
|
return (UINT32) Td->BufferEndPointer;
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
}
|
|
|
|
return 0;
|
|
}
|