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 + -
显示快捷键?