git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1117 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2826 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2826 lines
		
	
	
		
			78 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| 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:
 | |
| 
 | |
|     Ehci.c
 | |
|     
 | |
| Abstract: 
 | |
|     
 | |
| 
 | |
| Revision History
 | |
| --*/
 | |
| 
 | |
| 
 | |
| #include "Ehci.h"
 | |
| 
 | |
| UINTN                       gEHCDebugLevel  = EFI_D_INFO;
 | |
| UINTN                       gEHCErrorLevel  = EFI_D_ERROR;
 | |
| 
 | |
| //
 | |
| // Prototypes
 | |
| // Driver model protocol interface
 | |
| //
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN EFI_HANDLE                      Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN EFI_HANDLE                      Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingStop (
 | |
|   IN  EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN  EFI_HANDLE                      Controller,
 | |
|   IN  UINTN                           NumberOfChildren,
 | |
|   IN  EFI_HANDLE                      *ChildHandleBuffer
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Ehci protocol interface
 | |
| //
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetCapability (
 | |
|   IN  EFI_USB2_HC_PROTOCOL   *This,
 | |
|   OUT UINT8                  *MaxSpeed,
 | |
|   OUT UINT8                  *PortNumber,
 | |
|   OUT UINT8                  *Is64BitCapable
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciReset (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT16                   Attributes
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetState (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   OUT EFI_USB_HC_STATE         *State
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSetState (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  EFI_USB_HC_STATE         State
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciControlTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                 *This,
 | |
|   IN  UINT8                                DeviceAddress,
 | |
|   IN  UINT8                                DeviceSpeed,
 | |
|   IN  UINTN                                MaximumPacketLength,
 | |
|   IN  EFI_USB_DEVICE_REQUEST               *Request,
 | |
|   IN  EFI_USB_DATA_DIRECTION               TransferDirection,
 | |
|   IN  OUT VOID                             *Data,
 | |
|   IN  OUT UINTN                            *DataLength,
 | |
|   IN  UINTN                                TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,
 | |
|   OUT UINT32                               *TransferResult
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciBulkTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                *This,
 | |
|   IN  UINT8                               DeviceAddress,
 | |
|   IN  UINT8                               EndPointAddress,
 | |
|   IN  UINT8                               DeviceSpeed,
 | |
|   IN  UINTN                               MaximumPacketLength,
 | |
|   IN  UINT8                               DataBuffersNumber,
 | |
|   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
 | |
|   IN  OUT UINTN                           *DataLength,
 | |
|   IN  OUT UINT8                           *DataToggle,
 | |
|   IN  UINTN                               TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | |
|   OUT UINT32                              *TransferResult
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciAsyncInterruptTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  * This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaxiumPacketLength,
 | |
|   IN  BOOLEAN                               IsNewTransfer,
 | |
|   IN  OUT UINT8                             *DataToggle,
 | |
|   IN  UINTN                                 PollingInterval,
 | |
|   IN  UINTN                                 DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | |
|   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,
 | |
|   IN  VOID                                  *Context OPTIONAL
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSyncInterruptTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  *This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaximumPacketLength,
 | |
|   IN  OUT VOID                              *Data,
 | |
|   IN  OUT UINTN                             *DataLength,
 | |
|   IN  OUT UINT8                             *DataToggle,
 | |
|   IN  UINTN                                 TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | |
|   OUT UINT32                                *TransferResult
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciIsochronousTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  *This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaximumPacketLength,
 | |
|   IN  UINT8                                 DataBuffersNumber,
 | |
|   IN  OUT VOID                              *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | |
|   IN  UINTN                                 DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | |
|   OUT UINT32                                *TransferResult
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciAsyncIsochronousTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                *This,
 | |
|   IN  UINT8                               DeviceAddress,
 | |
|   IN  UINT8                               EndPointAddress,
 | |
|   IN  UINT8                               DeviceSpeed,
 | |
|   IN  UINTN                               MaximumPacketLength,
 | |
|   IN  UINT8                               DataBuffersNumber,
 | |
|   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | |
|   IN  UINTN                               DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | |
|   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
 | |
|   IN  VOID                                *Context
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetRootHubPortStatus (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT8                    PortNumber,
 | |
|   OUT EFI_USB_PORT_STATUS      *PortStatus
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSetRootHubPortFeature (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT8                    PortNumber,
 | |
|   IN  EFI_USB_PORT_FEATURE     PortFeature
 | |
|   );
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciClearRootHubPortFeature (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT8                    PortNumber,
 | |
|   IN  EFI_USB_PORT_FEATURE     PortFeature
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Ehci Driver Global Variables
 | |
| //
 | |
| EFI_DRIVER_BINDING_PROTOCOL gEhciDriverBinding = {
 | |
|   EhciDriverBindingSupported,
 | |
|   EhciDriverBindingStart,
 | |
|   EhciDriverBindingStop,
 | |
|   0x10,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| UINT32                      mUsbCapabilityLen;
 | |
| UINT32                      mDeviceSpeed[16];
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL *This,
 | |
|   IN EFI_HANDLE                  Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|   
 | |
|     Test to see if this driver supports ControllerHandle. Any ControllerHandle
 | |
|     that has Usb2HcProtocol installed will be supported.
 | |
| 
 | |
|   Arguments:
 | |
|   
 | |
|     This                - Protocol instance pointer.
 | |
|     Controlle           - Handle of device to test
 | |
|     RemainingDevicePath - Not used
 | |
| 
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS       This driver supports this device.
 | |
|     EFI_UNSUPPORTED   This driver does not support this device.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   USB_CLASSC          UsbClassCReg;
 | |
| 
 | |
|   
 | |
|   //
 | |
|   // Test whether there is PCI IO Protocol attached on the controller handle.
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = PciIo->Pci.Read (
 | |
|                         PciIo,
 | |
|                         EfiPciIoWidthUint8,
 | |
|                         CLASSC,
 | |
|                         sizeof (USB_CLASSC) / sizeof (UINT8),
 | |
|                         &UsbClassCReg
 | |
|                         );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->CloseProtocol (
 | |
|           Controller,
 | |
|           &gEfiPciIoProtocolGuid,
 | |
|           This->DriverBindingHandle,
 | |
|           Controller
 | |
|           );
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Test whether the controller belongs to Ehci type
 | |
|   //
 | |
|   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
 | |
|       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
 | |
|       (UsbClassCReg.PI != PCI_CLASSC_PI_EHCI)
 | |
|       ) {
 | |
| 
 | |
|     gBS->CloseProtocol (
 | |
|            Controller,
 | |
|            &gEfiPciIoProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            Controller
 | |
|            );
 | |
| 
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL *This,
 | |
|   IN EFI_HANDLE                  Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL    *RemainingDevicePath
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|   
 | |
|     Starting the Usb EHCI Driver
 | |
| 
 | |
|   Arguments:
 | |
|   
 | |
|     This                - Protocol instance pointer.
 | |
|     Controller          - Handle of device to test
 | |
|     RemainingDevicePath - Not used
 | |
| 
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS           supports this device.
 | |
|     EFI_UNSUPPORTED       do not support this device.
 | |
|     EFI_DEVICE_ERROR      cannot be started due to device Error
 | |
|     EFI_OUT_OF_RESOURCES  cannot allocate resources
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   USB2_HC_DEV           *HcDev;
 | |
|   EFI_PCI_IO_PROTOCOL   *PciIo;
 | |
|   UINT8                 MaxSpeed;
 | |
|   UINT8                 PortNumber;
 | |
|   UINT8                 Is64BitCapable;
 | |
|   
 | |
|   //
 | |
|   // Open the PciIo Protocol
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Enable the USB Host Controller
 | |
|   //
 | |
|   Status = PciIo->Attributes (
 | |
|                     PciIo,
 | |
|                     EfiPciIoAttributeOperationEnable,
 | |
|                     EFI_PCI_DEVICE_ENABLE,
 | |
|                     NULL
 | |
|                     );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto close_pciio_protocol;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Allocate memory for EHC private data structure
 | |
|   //
 | |
|   HcDev = AllocateZeroPool (sizeof (USB2_HC_DEV));
 | |
|   if (NULL == HcDev) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto close_pciio_protocol;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Init EFI_USB2_HC_PROTOCOL interface and private data structure
 | |
|   //
 | |
|   HcDev->Usb2Hc.GetCapability             = EhciGetCapability;
 | |
|   HcDev->Usb2Hc.Reset                     = EhciReset;
 | |
|   HcDev->Usb2Hc.GetState                  = EhciGetState;
 | |
|   HcDev->Usb2Hc.SetState                  = EhciSetState;
 | |
|   HcDev->Usb2Hc.ControlTransfer           = EhciControlTransfer;
 | |
|   HcDev->Usb2Hc.BulkTransfer              = EhciBulkTransfer;
 | |
|   HcDev->Usb2Hc.AsyncInterruptTransfer    = EhciAsyncInterruptTransfer;
 | |
|   HcDev->Usb2Hc.SyncInterruptTransfer     = EhciSyncInterruptTransfer;
 | |
|   HcDev->Usb2Hc.IsochronousTransfer       = EhciIsochronousTransfer;
 | |
|   HcDev->Usb2Hc.AsyncIsochronousTransfer  = EhciAsyncIsochronousTransfer;
 | |
|   HcDev->Usb2Hc.GetRootHubPortStatus      = EhciGetRootHubPortStatus;
 | |
|   HcDev->Usb2Hc.SetRootHubPortFeature     = EhciSetRootHubPortFeature;
 | |
|   HcDev->Usb2Hc.ClearRootHubPortFeature   = EhciClearRootHubPortFeature;
 | |
|   HcDev->Usb2Hc.MajorRevision             = 0x1;
 | |
|   HcDev->Usb2Hc.MinorRevision             = 0x1;
 | |
| 
 | |
|   HcDev->AsyncRequestList                 = NULL;
 | |
|   HcDev->ControllerNameTable              = NULL;
 | |
|   HcDev->Signature                        = USB2_HC_DEV_SIGNATURE;
 | |
|   HcDev->PciIo = PciIo;
 | |
| 
 | |
|   //
 | |
|   // Install USB2_HC_PROTOCOL
 | |
|   //
 | |
|   Status = gBS->InstallProtocolInterface (
 | |
|                   &Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   EFI_NATIVE_INTERFACE,
 | |
|                   &HcDev->Usb2Hc
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto free_pool;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Get Capability Register Length
 | |
|   //
 | |
|   Status = GetCapabilityLen (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto uninstall_usb2hc_protocol;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and Init Perodic Frame List
 | |
|   //
 | |
|   Status = EhciGetCapability (
 | |
|              &HcDev->Usb2Hc, 
 | |
|              &MaxSpeed, 
 | |
|              &PortNumber, 
 | |
|              &Is64BitCapable
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto uninstall_usb2hc_protocol;
 | |
|   }
 | |
|   HcDev->Is64BitCapable = Is64BitCapable;
 | |
|   
 | |
|   //
 | |
|   // Create and Init Perodic Frame List
 | |
|   //
 | |
|   Status = InitialPeriodicFrameList (
 | |
|              HcDev, 
 | |
|              EHCI_MAX_FRAME_LIST_LENGTH
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto uninstall_usb2hc_protocol;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Init memory pool management
 | |
|   //
 | |
|   Status = InitialMemoryManagement (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto deinit_perodic_frame_list;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create AsyncRequest Polling Timer
 | |
|   //
 | |
|   Status = CreatePollingTimer (HcDev, (EFI_EVENT_NOTIFY) AsyncRequestMoniter);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto deinit_memory_management;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Default Maxximum Interrupt Interval is 8, 
 | |
|   // it means that 8 micro frame = 1ms
 | |
|   //
 | |
|   
 | |
|   //
 | |
|   // Start the Host Controller
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev)) {
 | |
|     Status = StartScheduleExecution (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto deinit_timer;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Set all ports routing to EHC
 | |
|   //
 | |
|   Status = SetPortRoutingEhc (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto deinit_timer;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Component name protocol
 | |
|   //
 | |
|   Status = AddUnicodeString (
 | |
|              "eng",
 | |
|              gEhciComponentName.SupportedLanguages,
 | |
|              &HcDev->ControllerNameTable,
 | |
|              L"Usb Enhanced Host Controller"
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto deinit_timer;
 | |
|   }
 | |
| 
 | |
|   goto exit;
 | |
| 
 | |
|   //
 | |
|   // Error handle process
 | |
|   //
 | |
| deinit_timer:
 | |
|   DestoryPollingTimer (HcDev);
 | |
| deinit_memory_management:
 | |
|   DeinitialMemoryManagement (HcDev);
 | |
| deinit_perodic_frame_list:
 | |
|   DeinitialPeriodicFrameList (HcDev);
 | |
| uninstall_usb2hc_protocol:
 | |
|   gBS->UninstallProtocolInterface (
 | |
|          Controller,
 | |
|          &gEfiUsb2HcProtocolGuid,
 | |
|          &HcDev->Usb2Hc
 | |
|          );
 | |
| free_pool:
 | |
|   gBS->FreePool (HcDev);
 | |
| close_pciio_protocol:
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciDriverBindingStop (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL *This,
 | |
|   IN EFI_HANDLE                  Controller,
 | |
|   IN UINTN                       NumberOfChildren,
 | |
|   IN EFI_HANDLE                  *ChildHandleBuffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
|   Routine Description:
 | |
|   
 | |
|     Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|     created by this driver.
 | |
| 
 | |
|   Arguments:
 | |
|   
 | |
|     This              - Protocol instance pointer.
 | |
|     Controller        - Handle of device to stop driver on
 | |
|     NumberOfChildren  - Number of Children in the ChildHandleBuffer
 | |
|     ChildHandleBuffer - List of handles for the children we need to stop.
 | |
| 
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS         Success
 | |
|     EFI_DEVICE_ERROR    Fail
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_USB2_HC_PROTOCOL  *Usb2Hc;
 | |
|   USB2_HC_DEV           *HcDev;
 | |
| 
 | |
|   //
 | |
|   // Test whether the Controller handler passed in is a valid
 | |
|   // Usb controller handle that should be supported, if not,
 | |
|   // return the error status directly
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   (VOID **) &Usb2Hc,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   HcDev = USB2_HC_DEV_FROM_THIS (Usb2Hc);
 | |
| 
 | |
|   //
 | |
|   // free all the controller related memory and uninstall UHCI Protocol.
 | |
|   //
 | |
|   Status = gBS->UninstallProtocolInterface (
 | |
|                   Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   Usb2Hc
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Set Host Controller state as halt
 | |
|   //
 | |
|   Status = Usb2Hc->SetState (
 | |
|                      Usb2Hc, 
 | |
|                      EfiUsbHcStateHalt
 | |
|                      );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Stop AsyncRequest Polling Timer
 | |
|   //
 | |
|   Status = StopPollingTimer (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Destroy Asynchronous Request Event
 | |
|   //
 | |
|   DestoryPollingTimer (HcDev);
 | |
| 
 | |
|   //
 | |
|   // Destroy Perodic Frame List
 | |
|   //
 | |
|   DeinitialPeriodicFrameList (HcDev);
 | |
| 
 | |
|   //
 | |
|   // Deinit Ehci pool memory management
 | |
|   //
 | |
|   DeinitialMemoryManagement (HcDev);
 | |
| 
 | |
|   //
 | |
|   // Denint Unicode String Table
 | |
|   //
 | |
|   FreeUnicodeStringTable (HcDev->ControllerNameTable);
 | |
| 
 | |
|   //
 | |
|   // Disable the USB Host Controller
 | |
|   //
 | |
|   Status = HcDev->PciIo->Attributes (
 | |
|                            HcDev->PciIo,
 | |
|                            EfiPciIoAttributeOperationDisable,
 | |
|                            EFI_PCI_DEVICE_ENABLE,
 | |
|                            NULL
 | |
|                            );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   gBS->FreePool (HcDev);
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         Controller,
 | |
|         &gEfiPciIoProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Controller
 | |
|         );
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetCapability (
 | |
|   IN  EFI_USB2_HC_PROTOCOL *This,
 | |
|   OUT UINT8                *MaxSpeed,
 | |
|   OUT UINT8                *PortNumber,
 | |
|   OUT UINT8                *Is64BitCapable
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Retrieves the capablility of root hub ports.
 | |
|     
 | |
|   Arguments:
 | |
|   
 | |
|     This            - A pointer to the EFI_USB_HC_PROTOCOL instance.
 | |
|     MaxSpeed        - A pointer to the number of the host controller.
 | |
|     PortNumber      - A pointer to the number of the root hub ports.
 | |
|     Is64BitCapable  - A pointer to the flag for whether controller supports 
 | |
|                       64-bit memory addressing.
 | |
|     
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS            host controller capability were retrieved successfully.
 | |
|     EFI_INVALID_PARAMETER  MaxSpeed or PortNumber or Is64BitCapable is NULL.
 | |
|     EFI_DEVICE_ERROR       An error was encountered while attempting to retrieve the capabilities.  
 | |
|           
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   USB2_HC_DEV *HcDev;
 | |
|   UINT32      HcStructParamsAddr;
 | |
|   UINT32      HcStructParamsReg;
 | |
|   UINT32      HcCapParamsAddr;
 | |
|   UINT32      HcCapParamsReg;
 | |
| 
 | |
|   if (MaxSpeed == NULL || PortNumber == NULL || Is64BitCapable == NULL) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   HcStructParamsAddr  = HCSPARAMS;
 | |
|   HcCapParamsAddr     = HCCPARAMS;
 | |
|   HcDev               = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   Status = ReadEhcCapabiltiyReg (
 | |
|              HcDev,
 | |
|              HcStructParamsAddr,
 | |
|              &HcStructParamsReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = ReadEhcCapabiltiyReg (
 | |
|              HcDev,
 | |
|              HcCapParamsAddr,
 | |
|              &HcCapParamsReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   *MaxSpeed       = EFI_USB_SPEED_HIGH;
 | |
|   *PortNumber     = (UINT8) (HcStructParamsReg & HCSP_NPORTS);
 | |
|   *Is64BitCapable = (UINT8) (HcCapParamsReg & HCCP_64BIT);
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciReset (
 | |
|   IN EFI_USB2_HC_PROTOCOL *This,
 | |
|   IN UINT16               Attributes
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Provides software reset for the USB host controller.
 | |
|   
 | |
|   Arguments:
 | |
|   
 | |
|   This        - A pointer to the EFI_USB2_HC_PROTOCOL instance.  
 | |
|   Attributes  - A bit mask of the reset operation to perform. 
 | |
|                 See below for a list of the supported bit mask values.
 | |
|   
 | |
|   #define EFI_USB_HC_RESET_GLOBAL  0x0001
 | |
|   #define EFI_USB_HC_RESET_HOST_CONTROLLER  0x0002
 | |
|   #define EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG  0x0004
 | |
|   #define EFI_USB_HC_RESET_HOST_WITH_DEBUG  0x0008
 | |
| 
 | |
|   EFI_USB_HC_RESET_GLOBAL 
 | |
|         If this bit is set, a global reset signal will be sent to the USB bus.
 | |
|         This resets all of the USB bus logic, including the USB host 
 | |
|         controller hardware and all the devices attached on the USB bus.
 | |
|   EFI_USB_HC_RESET_HOST_CONTROLLER  
 | |
|         If this bit is set, the USB host controller hardware will be reset. 
 | |
|         No reset signal will be sent to the USB bus.
 | |
|   EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG
 | |
|         If this bit is set, a global reset signal will be sent to the USB bus.
 | |
|         This resets all of the USB bus logic, including the USB host 
 | |
|         controller hardware and all the devices attached on the USB bus. 
 | |
|         If this is an EHCI controller and the debug port has configured, then 
 | |
|         this is will still reset the host controller.
 | |
|   EFI_USB_HC_RESET_HOST_WITH_DEBUG
 | |
|         If this bit is set, the USB host controller hardware will be reset. 
 | |
|         If this is an EHCI controller and the debug port has been configured,
 | |
|         then this will still reset the host controller.
 | |
|         
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|         The reset operation succeeded.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|         Attributes is not valid.
 | |
|     EFI_UNSUPPOURTED
 | |
|         The type of reset specified by Attributes is not currently supported by
 | |
|         the host controller hardware.
 | |
|     EFI_ACCESS_DENIED
 | |
|         Reset operation is rejected due to the debug port being configured and 
 | |
|         active; only EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG or 
 | |
|         EFI_USB_HC_RESET_HOST_WITH_DEBUG reset Atrributes can be used to
 | |
|         perform reset operation for this host controller.
 | |
|     EFI_DEVICE_ERROR  
 | |
|         An error was encountered while attempting to perform 
 | |
|         the reset operation.
 | |
|         
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   USB2_HC_DEV       *HcDev;
 | |
|   UINTN             FrameIndex;
 | |
|   FRAME_LIST_ENTRY  *FrameEntryPtr;
 | |
| 
 | |
|   HcDev = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   switch (Attributes) {
 | |
| 
 | |
|   case EFI_USB_HC_RESET_GLOBAL:
 | |
|     
 | |
|     //
 | |
|     // Same behavior as Host Controller Reset
 | |
|     //
 | |
| 
 | |
|   case EFI_USB_HC_RESET_HOST_CONTROLLER:
 | |
|   	
 | |
|     //
 | |
|     // Host Controller must be Halt when Reset it
 | |
|     //
 | |
|     if (IsEhcHalted (HcDev)) {
 | |
|       Status = ResetEhc (HcDev);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|       //
 | |
|       // Set to zero by Host Controller when reset process completes
 | |
|       //
 | |
|       Status = WaitForEhcReset (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_TIMEOUT;
 | |
|         goto exit;
 | |
|       }
 | |
|     } else {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // only asynchronous interrupt transfers are always alive on the bus, need to cleanup
 | |
|     //
 | |
|     CleanUpAllAsyncRequestTransfer (HcDev);
 | |
|     Status = ClearEhcAllStatus (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Set appropriate 4G Segment Selector
 | |
|     //
 | |
|     Status = SetCtrlDataStructSeg (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Init Perodic List Base Addr and Frame List
 | |
|     //
 | |
|     Status = SetFrameListBaseAddr (
 | |
|                HcDev, 
 | |
|                GET_0B_TO_31B (HcDev->PeriodicFrameListBuffer)
 | |
|                );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
|     FrameEntryPtr = (FRAME_LIST_ENTRY *) HcDev->PeriodicFrameListBuffer;
 | |
|     for (FrameIndex = 0; FrameIndex < HcDev->PeriodicFrameListLength; FrameIndex++) {
 | |
|       FrameEntryPtr->LinkTerminate = TRUE;
 | |
|       FrameEntryPtr++;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Start the Host Controller
 | |
|     //
 | |
|     if (IsEhcHalted (HcDev)) {
 | |
|       Status = StartScheduleExecution (HcDev);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Set all ports routing to EHC
 | |
|     //
 | |
|     Status = SetPortRoutingEhc (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG:
 | |
|   	
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     break;
 | |
| 
 | |
|   case EFI_USB_HC_RESET_HOST_WITH_DEBUG:
 | |
|   	
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetState (
 | |
|   IN  EFI_USB2_HC_PROTOCOL *This,
 | |
|   OUT EFI_USB_HC_STATE     *State
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Retrieves current state of the USB host controller.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This      A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|     State     A pointer to the EFI_USB_HC_STATE data structure that 
 | |
|               indicates current state of the USB host controller.  
 | |
|               Type EFI_USB_HC_STATE is defined below.
 | |
|               
 | |
|     typedef enum {
 | |
|       EfiUsbHcStateHalt,
 | |
|       EfiUsbHcStateOperational,
 | |
|       EfiUsbHcStateSuspend,
 | |
|       EfiUsbHcStateMaximum
 | |
|     } EFI_USB_HC_STATE;
 | |
|   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|             The state information of the host controller was returned in State.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|             State is NULL.
 | |
|     EFI_DEVICE_ERROR  
 | |
|             An error was encountered while attempting to retrieve the 
 | |
|             host controller's current state.  
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   USB2_HC_DEV *HcDev;
 | |
|   UINT32      UsbStatusAddr;
 | |
|   UINT32      UsbStatusReg;
 | |
| 
 | |
|   if (State == NULL) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   UsbStatusAddr = USBSTS;
 | |
|   HcDev         = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   Status = ReadEhcOperationalReg (
 | |
|              HcDev,
 | |
|              UsbStatusAddr,
 | |
|              &UsbStatusReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (UsbStatusReg & USBSTS_HCH) {
 | |
|     *State = EfiUsbHcStateHalt;
 | |
|   } else {
 | |
|     *State = EfiUsbHcStateOperational;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSetState (
 | |
|   IN EFI_USB2_HC_PROTOCOL *This,
 | |
|   IN EFI_USB_HC_STATE     State
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Sets the USB host controller to a specific state.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This     - A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|     State    - Indicates the state of the host controller that will be set.
 | |
|   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|           The USB host controller was successfully placed in the state 
 | |
|           specified by State.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|           State is invalid.
 | |
|     EFI_DEVICE_ERROR  
 | |
|           Failed to set the state specified by State due to device error.  
 | |
|           
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS        Status;
 | |
|   USB2_HC_DEV       *HcDev;
 | |
|   UINT32            UsbCommandAddr;
 | |
|   UINT32            UsbCommandReg;
 | |
|   EFI_USB_HC_STATE  CurrentState;
 | |
| 
 | |
|   UsbCommandAddr  = USBCMD;
 | |
|   HcDev           = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   Status          = EhciGetState (This, &CurrentState);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   switch (State) {
 | |
| 
 | |
|   case EfiUsbHcStateHalt:
 | |
| 
 | |
|     if (EfiUsbHcStateHalt == CurrentState) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto exit;
 | |
|     } else if (EfiUsbHcStateOperational == CurrentState) {
 | |
|       Status = ReadEhcOperationalReg (
 | |
|                  HcDev,
 | |
|                  UsbCommandAddr,
 | |
|                  &UsbCommandReg
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
| 
 | |
|       UsbCommandReg &= ~USBCMD_RS;
 | |
|       Status = WriteEhcOperationalReg (
 | |
|                  HcDev,
 | |
|                  UsbCommandAddr,
 | |
|                  UsbCommandReg
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|       //
 | |
|       // Ensure the HC is in halt status after send the stop command
 | |
|       //
 | |
|       Status = WaitForEhcHalt (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_TIMEOUT;
 | |
|         goto exit;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbHcStateOperational:
 | |
|   	
 | |
|     if (IsEhcSysError (HcDev)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
|     if (EfiUsbHcStateOperational == CurrentState) {
 | |
|       Status = EFI_SUCCESS;
 | |
|       goto exit;
 | |
|     } else if (EfiUsbHcStateHalt == CurrentState) {
 | |
|       //
 | |
|       // Set Host Controller Run
 | |
|       //
 | |
|       Status = ReadEhcOperationalReg (
 | |
|                  HcDev,
 | |
|                  UsbCommandAddr,
 | |
|                  &UsbCommandReg
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return EFI_DEVICE_ERROR;
 | |
|       }
 | |
| 
 | |
|       UsbCommandReg |= USBCMD_RS;
 | |
|       Status = WriteEhcOperationalReg (
 | |
|                  HcDev,
 | |
|                  UsbCommandAddr,
 | |
|                  UsbCommandReg
 | |
|                  );
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbHcStateSuspend:
 | |
|   	
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|   	
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciGetRootHubPortStatus (
 | |
|   IN  EFI_USB2_HC_PROTOCOL *This,
 | |
|   IN  UINT8                PortNumber,
 | |
|   OUT EFI_USB_PORT_STATUS  *PortStatus
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Retrieves the current status of a USB root hub port.
 | |
|   
 | |
|   Arguments:
 | |
|   
 | |
|     This        - A pointer to the EFI_USB2_HC_PROTOCOL.
 | |
|     PortNumber  - Specifies the root hub port from which the status 
 | |
|                   is to be retrieved.  This value is zero-based. For example, 
 | |
|                   if a root hub has two ports, then the first port is numbered 0,
 | |
|                   and the second port is numbered 1.
 | |
|     PortStatus  - A pointer to the current port status bits and 
 | |
|                   port status change bits.  
 | |
|   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS           The status of the USB root hub port specified 
 | |
|                           by PortNumber was returned in PortStatus.
 | |
|     EFI_INVALID_PARAMETER PortNumber is invalid. 
 | |
|     EFI_DEVICE_ERROR      Can't read register     
 | |
|     
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   USB2_HC_DEV *HcDev;
 | |
|   UINT32      PortStatusControlAddr;
 | |
|   UINT32      PortStatusControlReg;
 | |
|   UINT8       MaxSpeed;
 | |
|   UINT8       TotalPortNumber;
 | |
|   UINT8       Is64BitCapable;
 | |
| 
 | |
|   if (PortStatus == NULL) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   EhciGetCapability (
 | |
|     This, 
 | |
|     &MaxSpeed, 
 | |
|     &TotalPortNumber, 
 | |
|     &Is64BitCapable
 | |
|     );
 | |
|   
 | |
|   if (PortNumber >= TotalPortNumber) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   HcDev                 = USB2_HC_DEV_FROM_THIS (This);
 | |
|   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));
 | |
| 
 | |
|   //
 | |
|   // Clear port status
 | |
|   //
 | |
|   PortStatus->PortStatus        = 0;
 | |
|   PortStatus->PortChangeStatus  = 0;
 | |
| 
 | |
|   Status = ReadEhcOperationalReg (
 | |
|              HcDev,
 | |
|              PortStatusControlAddr,
 | |
|              &PortStatusControlReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   //    Fill Port Status bits
 | |
|   //
 | |
|   
 | |
|   //
 | |
|   // Current Connect Status
 | |
|   //
 | |
|   if (PORTSC_CCS & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
 | |
|   }
 | |
|   //
 | |
|   // Port Enabled/Disabled
 | |
|   //
 | |
|   if (PORTSC_PED & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
 | |
|   }
 | |
|   //
 | |
|   // Port Suspend
 | |
|   //
 | |
|   if (PORTSC_SUSP & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
 | |
|   }
 | |
|   //
 | |
|   // Over-current Active
 | |
|   //
 | |
|   if (PORTSC_OCA & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_OVERCURRENT;
 | |
|   }
 | |
|   //
 | |
|   // Port Reset
 | |
|   //
 | |
|   if (PORTSC_PR & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_RESET;
 | |
|   }
 | |
|   //
 | |
|   // Port Power
 | |
|   //
 | |
|   if (PORTSC_PP & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_POWER;
 | |
|   }
 | |
|   //
 | |
|   // Port Owner
 | |
|   //
 | |
|   if (PORTSC_PO & PortStatusControlReg) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
 | |
|   }
 | |
|   //
 | |
|   // Identify device speed
 | |
|   //
 | |
|   if (PORTSC_LS_KSTATE & PortStatusControlReg) {
 | |
|     //
 | |
|     // Low Speed Device Attached
 | |
|     //
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
 | |
|   } else {
 | |
|     //
 | |
|     // Not Low Speed Device Attached
 | |
|     //
 | |
|     if ((PORTSC_CCS & PortStatusControlReg) && (PORTSC_CSC & PortStatusControlReg)) {
 | |
|       mDeviceSpeed[PortNumber] = IsHighSpeedDevice (This, PortNumber) ? USB_PORT_STAT_HIGH_SPEED : 0;
 | |
|     }
 | |
|     PortStatus->PortStatus |= mDeviceSpeed[PortNumber];
 | |
|   }
 | |
|   //
 | |
|   // Fill Port Status Change bits
 | |
|   //
 | |
|   //
 | |
|   // Connect Status Change
 | |
|   //
 | |
|   if (PORTSC_CSC & PortStatusControlReg) {
 | |
|     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
 | |
|   }
 | |
|   //
 | |
|   // Port Enabled/Disabled Change
 | |
|   //
 | |
|   if (PORTSC_PEDC & PortStatusControlReg) {
 | |
|     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
 | |
|   }
 | |
|   //
 | |
|   // Port Over Current Change
 | |
|   //
 | |
|   if (PORTSC_OCC & PortStatusControlReg) {
 | |
|     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_OVERCURRENT;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSetRootHubPortFeature (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT8                    PortNumber,
 | |
|   IN  EFI_USB_PORT_FEATURE     PortFeature
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Sets a feature for the specified root hub port.
 | |
|   
 | |
|   Arguments:
 | |
|   
 | |
|     This        - A pointer to the EFI_USB2_HC_PROTOCOL.
 | |
|     PortNumber  - Specifies the root hub port whose feature 
 | |
|                   is requested to be set.
 | |
|     PortFeature - Indicates the feature selector associated 
 | |
|                   with the feature set request. 
 | |
|   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|         The feature specified by PortFeature was set for the 
 | |
|         USB root hub port specified by PortNumber.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|         PortNumber is invalid or PortFeature is invalid.
 | |
|     EFI_DEVICE_ERROR
 | |
|         Can't read register
 | |
|         
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   USB2_HC_DEV *HcDev;
 | |
|   UINT32      PortStatusControlAddr;
 | |
|   UINT32      PortStatusControlReg;
 | |
|   UINT8       MaxSpeed;
 | |
|   UINT8       TotalPortNumber;
 | |
|   UINT8       Is64BitCapable;
 | |
| 
 | |
|   EhciGetCapability (
 | |
|     This, 
 | |
|     &MaxSpeed, 
 | |
|     &TotalPortNumber, 
 | |
|     &Is64BitCapable
 | |
|     );
 | |
| 
 | |
|   if (PortNumber >= TotalPortNumber) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   HcDev                 = USB2_HC_DEV_FROM_THIS (This);
 | |
|   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));
 | |
| 
 | |
|   Status = ReadEhcOperationalReg (
 | |
|              HcDev,
 | |
|              PortStatusControlAddr,
 | |
|              &PortStatusControlReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   switch (PortFeature) {
 | |
| 
 | |
|   case EfiUsbPortEnable:
 | |
|   
 | |
|     //
 | |
|     // Sofeware can't set this bit, Port can only be enable by the Host Controller
 | |
|     // as a part of the reset and enable
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_PED;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortSuspend:
 | |
|   
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_SUSP;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortReset:
 | |
|   
 | |
|     //
 | |
|     // Make sure Host Controller not halt before reset it
 | |
|     //
 | |
|     if (IsEhcHalted (HcDev)) {
 | |
|       Status = StartScheduleExecution (HcDev);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|       Status = WaitForEhcNotHalt (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         DEBUG ((gEHCDebugLevel, "WaitForEhcNotHalt TimeOut\n"));
 | |
|         Status = EFI_DEVICE_ERROR;
 | |
|         goto exit;
 | |
|       }
 | |
|     }
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_PR;
 | |
|     //
 | |
|     // Set one to PortReset bit must also set zero to PortEnable bit
 | |
|     //
 | |
|     PortStatusControlReg &= ~PORTSC_PED;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortPower:
 | |
|     
 | |
|     //
 | |
|     // No support, no operation
 | |
|     //
 | |
|     goto exit;
 | |
| 
 | |
|   case EfiUsbPortOwner:
 | |
|   
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_PO;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|   	
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WriteEhcOperationalReg (
 | |
|              HcDev,
 | |
|              PortStatusControlAddr,
 | |
|              PortStatusControlReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciClearRootHubPortFeature (
 | |
|   IN  EFI_USB2_HC_PROTOCOL     *This,
 | |
|   IN  UINT8                    PortNumber,
 | |
|   IN  EFI_USB_PORT_FEATURE     PortFeature
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Clears a feature for the specified root hub port.
 | |
|   
 | |
|   Arguments:
 | |
|   
 | |
|     This        - A pointer to the EFI_USB2_HC_PROTOCOL instance. 
 | |
|     PortNumber  - Specifies the root hub port whose feature 
 | |
|                   is requested to be cleared.
 | |
|     PortFeature - Indicates the feature selector associated with the 
 | |
|                   feature clear request.
 | |
|                   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|         The feature specified by PortFeature was cleared for the 
 | |
|         USB root hub port specified by PortNumber.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|         PortNumber is invalid or PortFeature is invalid.
 | |
|     EFI_DEVICE_ERROR
 | |
|         Can't read register
 | |
|         
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   USB2_HC_DEV *HcDev;
 | |
|   UINT32      PortStatusControlAddr;
 | |
|   UINT32      PortStatusControlReg;
 | |
|   UINT8       MaxSpeed;
 | |
|   UINT8       TotalPortNumber;
 | |
|   UINT8       Is64BitCapable;
 | |
| 
 | |
|   EhciGetCapability (
 | |
|     This, 
 | |
|     &MaxSpeed, 
 | |
|     &TotalPortNumber, 
 | |
|     &Is64BitCapable
 | |
|     );
 | |
| 
 | |
|   if (PortNumber >= TotalPortNumber) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   HcDev                 = USB2_HC_DEV_FROM_THIS (This);
 | |
|   PortStatusControlAddr = (UINT32) (PORTSC + (4 * PortNumber));
 | |
| 
 | |
|   Status = ReadEhcOperationalReg (
 | |
|              HcDev,
 | |
|              PortStatusControlAddr,
 | |
|              &PortStatusControlReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   switch (PortFeature) {
 | |
| 
 | |
|   case EfiUsbPortEnable:
 | |
|   
 | |
|     //
 | |
|     // Clear PORT_ENABLE feature means disable port.
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg &= ~PORTSC_PED;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortSuspend:
 | |
|   
 | |
|     //
 | |
|     // A write of zero to this bit is ignored by the host controller.
 | |
|     // The host controller will unconditionally set this bit to a zero when:
 | |
|     //   1. software sets the Forct Port Resume bit to a zero from a one.
 | |
|     //   2. software sets the Port Reset bit to a one frome a zero.
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg &= ~PORTSC_FPR;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortReset:
 | |
|   
 | |
|     //
 | |
|     // Clear PORT_RESET means clear the reset signal.
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg &= ~PORTSC_PR;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortPower:
 | |
|   
 | |
|     //
 | |
|     // No support, no operation
 | |
|     //
 | |
|     goto exit;
 | |
| 
 | |
|   case EfiUsbPortOwner:
 | |
|   
 | |
|     //
 | |
|     // Clear port owner means this port owned by EHC
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg &= ~PORTSC_PO;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortConnectChange:
 | |
|   
 | |
|     //
 | |
|     // Clear connect status change
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_CSC;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortEnableChange:
 | |
|   
 | |
|     //
 | |
|     // Clear enable status change
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_PEDC;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortSuspendChange:
 | |
|   
 | |
|     //
 | |
|     // No related bit, no operation
 | |
|     //
 | |
|     goto exit;
 | |
| 
 | |
|   case EfiUsbPortOverCurrentChange:
 | |
|   
 | |
|     //
 | |
|     // Clear PortOverCurrent change
 | |
|     //
 | |
|     PortStatusControlReg &= 0xffffffd5;
 | |
|     PortStatusControlReg |= PORTSC_OCC;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortResetChange:
 | |
|   
 | |
|     //
 | |
|     // No related bit, no operation
 | |
|     //
 | |
|     goto exit;
 | |
| 
 | |
|   default:
 | |
|   	
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WriteEhcOperationalReg (
 | |
|              HcDev,
 | |
|              PortStatusControlAddr,
 | |
|              PortStatusControlReg
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciControlTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                 *This,
 | |
|   IN  UINT8                                DeviceAddress,
 | |
|   IN  UINT8                                DeviceSpeed,
 | |
|   IN  UINTN                                MaximumPacketLength,
 | |
|   IN  EFI_USB_DEVICE_REQUEST               *Request,
 | |
|   IN  EFI_USB_DATA_DIRECTION               TransferDirection,
 | |
|   IN  OUT VOID                             *Data,
 | |
|   IN  OUT UINTN                            *DataLength,
 | |
|   IN  UINTN                                TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR   *Translator,
 | |
|   OUT UINT32                               *TransferResult
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits control transfer to a target USB device.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This            - A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|     DeviceAddress   - Represents the address of the target device on the USB,
 | |
|                       which is assigned during USB enumeration.
 | |
|     DeviceSpeed     - Indicates target device speed.
 | |
|     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.
 | |
|     Translator      - A pointr to the transaction translator data.
 | |
|     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.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   USB2_HC_DEV     *HcDev;
 | |
|   UINT8           PktId;
 | |
|   EHCI_QH_ENTITY  *QhPtr;
 | |
|   EHCI_QTD_ENTITY *ControlQtdsPtr;
 | |
|   UINT8           *DataCursor;
 | |
|   VOID            *DataMap;
 | |
|   UINT8           *RequestCursor;
 | |
|   VOID            *RequestMap;
 | |
| 
 | |
|   QhPtr           = NULL;
 | |
|   ControlQtdsPtr  = NULL;
 | |
|   DataCursor      = NULL;
 | |
|   DataMap         = NULL;
 | |
|   RequestCursor   = NULL;
 | |
|   RequestMap      = NULL;
 | |
|   HcDev           = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Parameters Checking
 | |
|   //
 | |
|   if (TransferDirection != EfiUsbDataIn &&
 | |
|   	TransferDirection != EfiUsbDataOut &&
 | |
|   	TransferDirection != EfiUsbNoData
 | |
|   	) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EfiUsbNoData == TransferDirection) {
 | |
|     if (NULL != Data || 0 != *DataLength) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   } else {
 | |
|     if (NULL == Data || 0 == *DataLength) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (Request == NULL || TransferResult == NULL) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_LOW == DeviceSpeed) {
 | |
|     if (MaximumPacketLength != 8) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   } else if (MaximumPacketLength != 8 &&
 | |
|            MaximumPacketLength != 16 &&
 | |
|            MaximumPacketLength != 32 &&
 | |
|            MaximumPacketLength != 64
 | |
|           ) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // If errors exist that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     ClearEhcAllStatus (HcDev);
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Map the Request for bus master access.
 | |
|   // BusMasterRead means cpu write
 | |
|   //
 | |
|   Status = MapRequestBuffer (
 | |
|              HcDev,
 | |
|              Request,
 | |
|              &RequestCursor,
 | |
|              &RequestMap
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Map the source data buffer for bus master access.
 | |
|   //
 | |
|   Status = MapDataBuffer (
 | |
|              HcDev,
 | |
|              TransferDirection,
 | |
|              Data,
 | |
|              DataLength,
 | |
|              &PktId,
 | |
|              &DataCursor,
 | |
|              &DataMap
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto unmap_request;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init control Qh
 | |
|   //
 | |
|   Status = CreateControlQh (
 | |
|              HcDev,
 | |
|              DeviceAddress,
 | |
|              DeviceSpeed,
 | |
|              MaximumPacketLength,
 | |
|              Translator,
 | |
|              &QhPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_OUT_OF_RESOURCES;
 | |
|     goto unmap_data;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init control Qtds
 | |
|   //
 | |
|   Status = CreateControlQtds (
 | |
|              HcDev,
 | |
|              PktId,
 | |
|              RequestCursor,
 | |
|              DataCursor,
 | |
|              *DataLength,
 | |
|              Translator,
 | |
|              &ControlQtdsPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_OUT_OF_RESOURCES;
 | |
|     goto destory_qh;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qtds to Qh
 | |
|   //
 | |
|   LinkQtdToQh (QhPtr, ControlQtdsPtr);
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
|   //
 | |
|   // Link Qh and Qtds to Async Schedule List
 | |
|   //
 | |
|   Status = LinkQhToAsyncList (HcDev, QhPtr);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto destory_qtds;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Poll Qh-Qtds execution and get result.
 | |
|   // detail status is returned
 | |
|   //
 | |
|   Status = ExecuteTransfer (
 | |
|              HcDev,
 | |
|              TRUE,
 | |
|              QhPtr,
 | |
|              DataLength,
 | |
|              0,
 | |
|              TimeOut,
 | |
|              TransferResult
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto destory_qtds;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // If has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     *TransferResult |= EFI_USB_ERR_SYSTEM;
 | |
|   }
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
| destory_qtds:
 | |
|   UnlinkQhFromAsyncList (HcDev, QhPtr);
 | |
|   DestoryQtds (HcDev, ControlQtdsPtr);
 | |
| destory_qh:
 | |
|   DestoryQh (HcDev, QhPtr);
 | |
| unmap_data:
 | |
|   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);
 | |
| unmap_request:
 | |
|   HcDev->PciIo->Unmap (HcDev->PciIo, RequestMap);
 | |
| exit:
 | |
|   HcDev->PciIo->Flush (HcDev->PciIo);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciBulkTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                *This,
 | |
|   IN  UINT8                               DeviceAddress,
 | |
|   IN  UINT8                               EndPointAddress,
 | |
|   IN  UINT8                               DeviceSpeed,
 | |
|   IN  UINTN                               MaximumPacketLength,
 | |
|   IN  UINT8                               DataBuffersNumber,
 | |
|   IN  OUT VOID                            *Data[EFI_USB_MAX_BULK_BUFFER_NUM],
 | |
|   IN  OUT UINTN                           *DataLength,
 | |
|   IN  OUT UINT8                           *DataToggle,
 | |
|   IN  UINTN                               TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | |
|   OUT UINT32                              *TransferResult
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits bulk transfer to a bulk endpoint of a USB device.
 | |
|     
 | |
|   Arguments:
 | |
|     
 | |
|     This              - A pointer to the EFI_USB2_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.                  
 | |
|     DeviceSpeed       - Indicates device speed. The supported values are EFI_USB_SPEED_FULL
 | |
|                         and EFI_USB_SPEED_HIGH.
 | |
|     MaximumPacketLength - Indicates the maximum packet size the target endpoint
 | |
|                           is capable of sending or receiving.                 
 | |
|     DataBuffersNumber - Number of data buffers prepared for the transfer.
 | |
|     Data              - Array of pointers to the buffers 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. 
 | |
|     Translator        - A pointr to the transaction translator data. 
 | |
|     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.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   USB2_HC_DEV             *HcDev;
 | |
|   UINT8                   PktId;
 | |
|   EHCI_QH_ENTITY          *QhPtr;
 | |
|   EHCI_QTD_ENTITY         *BulkQtdsPtr;
 | |
|   UINT8                   *DataCursor;
 | |
|   VOID                    *DataMap;
 | |
|   EFI_USB_DATA_DIRECTION  TransferDirection;
 | |
| 
 | |
|   QhPtr       = NULL;
 | |
|   BulkQtdsPtr = NULL;
 | |
|   DataCursor  = NULL;
 | |
|   DataMap     = NULL;
 | |
|   HcDev       = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Parameters Checking
 | |
|   //
 | |
|   if (NULL == DataLength ||
 | |
|   	NULL == Data || 
 | |
|   	NULL == Data[0] || 
 | |
|   	NULL == TransferResult
 | |
|   	) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (*DataLength == 0) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (1 != *DataToggle && 0 != *DataToggle) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_LOW == DeviceSpeed) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_FULL == DeviceSpeed) {
 | |
|     if (MaximumPacketLength > 64) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_HIGH == DeviceSpeed) {
 | |
|     if (MaximumPacketLength > 512) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // if has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     ClearEhcAllStatus (HcDev);
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = ClearEhcAllStatus (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // construct QH and TD data structures,
 | |
|   // and link them together
 | |
|   //
 | |
|   if (EndPointAddress & 0x80) {
 | |
|     TransferDirection = EfiUsbDataIn;
 | |
|   } else {
 | |
|     TransferDirection = EfiUsbDataOut;
 | |
|   }
 | |
| 
 | |
|   Status = MapDataBuffer (
 | |
|              HcDev,
 | |
|              TransferDirection,
 | |
|              Data[0],
 | |
|              DataLength,
 | |
|              &PktId,
 | |
|              &DataCursor,
 | |
|              &DataMap
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Bulk Qh
 | |
|   //
 | |
|   Status = CreateBulkQh (
 | |
|              HcDev,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              DeviceSpeed,
 | |
|              *DataToggle,
 | |
|              MaximumPacketLength,
 | |
|              Translator,
 | |
|              &QhPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_OUT_OF_RESOURCES;
 | |
|     goto unmap_data;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Bulk Qtds
 | |
|   //
 | |
|   Status = CreateBulkOrInterruptQtds (
 | |
|              HcDev,
 | |
|              PktId,
 | |
|              DataCursor,
 | |
|              *DataLength,
 | |
|              Translator,
 | |
|              &BulkQtdsPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_OUT_OF_RESOURCES;
 | |
|     goto destory_qh;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qtds to Qh
 | |
|   //
 | |
|   LinkQtdToQh (QhPtr, BulkQtdsPtr);
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
|   //
 | |
|   // Link Qh and qtds to Async Schedule List
 | |
|   //
 | |
|   Status = LinkQhToAsyncList (HcDev, QhPtr);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto destory_qtds;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Poll QH-TDs execution and get result.
 | |
|   // detail status is returned
 | |
|   //
 | |
|   Status = ExecuteTransfer (
 | |
|              HcDev,
 | |
|              FALSE,
 | |
|              QhPtr,
 | |
|              DataLength,
 | |
|              DataToggle,
 | |
|              TimeOut,
 | |
|              TransferResult
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto destory_qtds;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // if has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     *TransferResult |= EFI_USB_ERR_SYSTEM;
 | |
|   }
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
| destory_qtds:
 | |
|   UnlinkQhFromAsyncList (HcDev, QhPtr);
 | |
|   DestoryQtds (HcDev, BulkQtdsPtr);
 | |
| destory_qh:
 | |
|   DestoryQh (HcDev, QhPtr);
 | |
| unmap_data:
 | |
|   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);
 | |
| exit:
 | |
|   HcDev->PciIo->Flush (HcDev->PciIo);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciAsyncInterruptTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  * This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaximumPacketLength,
 | |
|   IN  BOOLEAN                               IsNewTransfer,
 | |
|   IN  OUT UINT8                             *DataToggle,
 | |
|   IN  UINTN                                 PollingInterval,
 | |
|   IN  UINTN                                 DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    * Translator,
 | |
|   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK       CallBackFunction,
 | |
|   IN  VOID                                  *Context OPTIONAL
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits an asynchronous interrupt transfer to an 
 | |
|     interrupt endpoint of a USB device.
 | |
|     Translator parameter doesn't exist in UEFI2.0 spec, but it will be updated 
 | |
|     in the following specification version.
 | |
|     
 | |
|   Arguments:
 | |
|     
 | |
|     This            - A pointer to the EFI_USB2_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.              
 | |
|     DeviceSpeed     - Indicates device speed.
 | |
|     MaximumPacketLength  - 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 received at the 
 | |
|                       rate specified by PollingInterval from the target 
 | |
|                       asynchronous interrupt endpoint.  This parameter 
 | |
|                       is only required when IsNewTransfer is TRUE.             
 | |
|     Translator      - A pointr to the transaction translator data.
 | |
|     CallBackFunction  - The Callback function.This function is called at the 
 | |
|                         rate specified by PollingInterval.This parameter is 
 | |
|                         only required when IsNewTransfer is TRUE.               
 | |
|     Context         - The context that is passed to the CallBackFunction.
 | |
|                     - This is an optional parameter and may be NULL.
 | |
|   
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|         The asynchronous interrupt transfer request has been successfully 
 | |
|         submitted or canceled.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|         Some parameters are invalid.
 | |
|     EFI_OUT_OF_RESOURCES  
 | |
|         The request could not be completed due to a lack of resources.  
 | |
|     EFI_DEVICE_ERROR
 | |
|         Can't read register
 | |
|         
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   USB2_HC_DEV         *HcDev;
 | |
|   UINT8               PktId;
 | |
|   EHCI_QH_ENTITY      *QhPtr;
 | |
|   EHCI_QTD_ENTITY     *InterruptQtdsPtr;
 | |
|   UINT8               *DataPtr;
 | |
|   UINT8               *DataCursor;
 | |
|   VOID                *DataMap;
 | |
|   UINTN               MappedLength;
 | |
|   EHCI_ASYNC_REQUEST  *AsyncRequestPtr;
 | |
|   EFI_TPL             OldTpl;
 | |
| 
 | |
|   QhPtr             = NULL;
 | |
|   InterruptQtdsPtr  = NULL;
 | |
|   DataPtr           = NULL;
 | |
|   DataCursor        = NULL;
 | |
|   DataMap           = NULL;
 | |
|   AsyncRequestPtr   = NULL;
 | |
|   HcDev             = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Parameters Checking
 | |
|   //
 | |
|   if (!IsDataInTransfer (EndPointAddress)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (IsNewTransfer) {
 | |
|     if (0 == DataLength) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
| 
 | |
|     if (*DataToggle != 1 && *DataToggle != 0) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
| 
 | |
|     if (PollingInterval > 255 || PollingInterval < 1) {
 | |
|       Status = EFI_INVALID_PARAMETER;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // if has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     ClearEhcAllStatus (HcDev);
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = ClearEhcAllStatus (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Delete Async interrupt transfer request
 | |
|   //
 | |
|   if (!IsNewTransfer) {
 | |
| 
 | |
|     OldTpl = gBS->RaiseTPL (EFI_TPL_NOTIFY);
 | |
| 
 | |
|     Status = DeleteAsyncRequestTransfer (
 | |
|                HcDev,
 | |
|                DeviceAddress,
 | |
|                EndPointAddress,
 | |
|                DataToggle
 | |
|                );
 | |
| 
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = EhciAllocatePool (
 | |
|   	         HcDev, 
 | |
|   	         (UINT8 **) &AsyncRequestPtr, 
 | |
|   	         sizeof (EHCI_ASYNC_REQUEST)
 | |
|   	         );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = EhciAllocatePool (HcDev, &DataPtr, DataLength);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto free_request;
 | |
|   }
 | |
| 
 | |
|   MappedLength = DataLength;
 | |
|   Status = MapDataBuffer (
 | |
|              HcDev,
 | |
|              EfiUsbDataIn,
 | |
|              DataPtr,
 | |
|              &MappedLength,
 | |
|              &PktId,
 | |
|              &DataCursor,
 | |
|              &DataMap
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto free_data;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Interrupt Qh
 | |
|   //
 | |
|   Status = CreateInterruptQh (
 | |
|              HcDev,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              DeviceSpeed,
 | |
|              *DataToggle,
 | |
|              MaximumPacketLength,
 | |
|              PollingInterval,
 | |
|              Translator,
 | |
|              &QhPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto unmap_data;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Interrupt Qtds
 | |
|   //
 | |
|   Status = CreateBulkOrInterruptQtds (
 | |
|              HcDev,
 | |
|              PktId,
 | |
|              DataCursor,
 | |
|              MappedLength,
 | |
|              Translator,
 | |
|              &InterruptQtdsPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto destory_qh;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qtds to Qh
 | |
|   //
 | |
|   LinkQtdToQh (QhPtr, InterruptQtdsPtr);
 | |
| 
 | |
|   //
 | |
|   // Init AsyncRequest Entry
 | |
|   //
 | |
|   AsyncRequestPtr->Context      = Context;
 | |
|   AsyncRequestPtr->CallBackFunc = CallBackFunction;
 | |
|   AsyncRequestPtr->TransferType = ASYNC_INTERRUPT_TRANSFER;
 | |
|   AsyncRequestPtr->QhPtr        = QhPtr;
 | |
|   AsyncRequestPtr->Prev         = NULL;
 | |
|   AsyncRequestPtr->Next         = NULL;
 | |
| 
 | |
|   if (NULL == HcDev->AsyncRequestList) {
 | |
|     Status = StartPollingTimer (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       CleanUpAllAsyncRequestTransfer (HcDev);
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Entry to AsyncRequest List
 | |
|   //
 | |
|   LinkToAsyncReqeust (HcDev, AsyncRequestPtr);
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
|   Status = DisablePeriodicSchedule (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qh and Qtds to Periodic Schedule List
 | |
|   //
 | |
|   LinkQhToPeriodicList (HcDev, QhPtr);
 | |
| 
 | |
|   Status = EnablePeriodicSchedule (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (IsEhcHalted (HcDev)) {
 | |
|     Status = StartScheduleExecution (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   HcDev->PciIo->Flush (HcDev->PciIo);
 | |
|   goto exit;
 | |
| 
 | |
| destory_qh:
 | |
|   DestoryQh (HcDev, QhPtr);
 | |
| free_data:
 | |
|   EhciFreePool (HcDev, DataPtr, DataLength);
 | |
| free_request:
 | |
|   EhciFreePool (
 | |
|   	HcDev, 
 | |
|   	(UINT8 *) AsyncRequestPtr, 
 | |
|   	sizeof (EHCI_ASYNC_REQUEST)
 | |
|   	);
 | |
| unmap_data:
 | |
|   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);
 | |
| exit:
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciSyncInterruptTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  *This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaximumPacketLength,
 | |
|   IN  OUT VOID                              *Data,
 | |
|   IN  OUT UINTN                             *DataLength,
 | |
|   IN  OUT UINT8                             *DataToggle,
 | |
|   IN  UINTN                                 TimeOut,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | |
|   OUT UINT32                                *TransferResult
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits synchronous interrupt transfer to an interrupt endpoint 
 | |
|     of a USB device. 
 | |
|     Translator parameter doesn't exist in UEFI2.0 spec, but it will be updated 
 | |
|     in the following specification version.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This            - A pointer to the EFI_USB2_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. 
 | |
|     DeviceSpeed     - Indicates device speed.
 | |
|     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      - On input, the size, in bytes, of the data buffer specified 
 | |
|                       by Data. On output, the number of bytes transferred.
 | |
|     DataToggle      - A pointer to the data toggle value. On input, it indicates
 | |
|                       the initial data toggle value the synchronous interrupt 
 | |
|                       transfer should adopt; 
 | |
|                       on output, it is updated to indicate the data toggle value 
 | |
|                       of the subsequent synchronous interrupt transfer. 
 | |
|     TimeOut         - Indicates the maximum time, in microseconds, which the 
 | |
|                       transfer is allowed to complete.
 | |
|     Translator      - A pointr to the transaction translator data.
 | |
|     TransferResult  - A pointer to the detailed result information from 
 | |
|                       the synchronous interrupt transfer.  
 | |
| 
 | |
|   Returns:
 | |
|   
 | |
|     EFI_SUCCESS 
 | |
|         The synchronous interrupt transfer was completed successfully.
 | |
|     EFI_OUT_OF_RESOURCES  
 | |
|         The synchronous interrupt transfer could not be submitted due 
 | |
|         to lack of resource.
 | |
|     EFI_INVALID_PARAMETER 
 | |
|         Some parameters are invalid.
 | |
|     EFI_TIMEOUT 
 | |
|         The synchronous interrupt transfer failed due to timeout.
 | |
|     EFI_DEVICE_ERROR  
 | |
|         The synchronous interrupt transfer failed due to host controller 
 | |
|         or device error. Caller should check TranferResult for detailed 
 | |
|         error information.  
 | |
|         
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS      Status;
 | |
|   USB2_HC_DEV     *HcDev;
 | |
|   UINT8           PktId;
 | |
|   EHCI_QH_ENTITY  *QhPtr;
 | |
|   EHCI_QTD_ENTITY *InterruptQtdsPtr;
 | |
|   UINT8           *DataCursor;
 | |
|   VOID            *DataMap;
 | |
| 
 | |
|   QhPtr             = NULL;
 | |
|   InterruptQtdsPtr  = NULL;
 | |
|   DataCursor        = NULL;
 | |
|   DataMap           = NULL;
 | |
|   HcDev             = USB2_HC_DEV_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Parameters Checking
 | |
|   //
 | |
|   if (DataLength == NULL ||
 | |
|   	Data == NULL || 
 | |
|   	TransferResult == NULL
 | |
|   	) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (!IsDataInTransfer (EndPointAddress)) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (0 == *DataLength) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (*DataToggle != 1 && *DataToggle != 0) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_LOW == DeviceSpeed && 8 != MaximumPacketLength) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_FULL == DeviceSpeed && MaximumPacketLength > 64) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (EFI_USB_SPEED_HIGH == DeviceSpeed && MaximumPacketLength > 3072) {
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // if has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     ClearEhcAllStatus (HcDev);
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = ClearEhcAllStatus (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = MapDataBuffer (
 | |
|              HcDev,
 | |
|              EfiUsbDataIn,
 | |
|              Data,
 | |
|              DataLength,
 | |
|              &PktId,
 | |
|              &DataCursor,
 | |
|              &DataMap
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Interrupt Qh
 | |
|   //
 | |
|   Status = CreateInterruptQh (
 | |
|              HcDev,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              DeviceSpeed,
 | |
|              *DataToggle,
 | |
|              MaximumPacketLength,
 | |
|              0,
 | |
|              Translator,
 | |
|              &QhPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto unmap_data;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Create and init Interrupt Qtds
 | |
|   //
 | |
|   Status = CreateBulkOrInterruptQtds (
 | |
|              HcDev,
 | |
|              PktId,
 | |
|              DataCursor,
 | |
|              *DataLength,
 | |
|              Translator,
 | |
|              &InterruptQtdsPtr
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|     Status          = EFI_OUT_OF_RESOURCES;
 | |
|     goto destory_qh;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qtds to Qh
 | |
|   //
 | |
|   LinkQtdToQh (QhPtr, InterruptQtdsPtr);
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
|   Status = DisablePeriodicSchedule (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WaitForPeriodicScheduleDisable (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|     goto exit;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Link Qh and Qtds to Periodic Schedule List
 | |
|   //
 | |
|   LinkQhToPeriodicList (HcDev, QhPtr);
 | |
| 
 | |
|   Status = EnablePeriodicSchedule (HcDev);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_DEVICE_ERROR;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   Status = WaitForPeriodicScheduleEnable (HcDev, EHCI_GENERIC_TIMEOUT);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_TIMEOUT;
 | |
|     goto exit;
 | |
|   }
 | |
| 
 | |
|   if (IsEhcHalted (HcDev)) {
 | |
|     Status = StartScheduleExecution (HcDev);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto exit;
 | |
|     }
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // Poll QH-TDs execution and get result.
 | |
|   // detail status is returned
 | |
|   //
 | |
|   Status = ExecuteTransfer (
 | |
|              HcDev,
 | |
|              FALSE,
 | |
|              QhPtr,
 | |
|              DataLength,
 | |
|              DataToggle,
 | |
|              TimeOut,
 | |
|              TransferResult
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto destory_qtds;
 | |
|   }
 | |
|   
 | |
|   //
 | |
|   // if has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   if (IsEhcHalted (HcDev) || IsEhcSysError (HcDev)) {
 | |
|     *TransferResult |= EFI_USB_ERR_SYSTEM;
 | |
|   }
 | |
| 
 | |
|   ClearEhcAllStatus (HcDev);
 | |
| 
 | |
| destory_qtds:
 | |
|   UnlinkQhFromPeriodicList (HcDev, QhPtr, 0);
 | |
|   DestoryQtds (HcDev, InterruptQtdsPtr);
 | |
| destory_qh:
 | |
|   DestoryQh (HcDev, QhPtr);
 | |
| unmap_data:
 | |
|   HcDev->PciIo->Unmap (HcDev->PciIo, DataMap);
 | |
| exit:
 | |
|   HcDev->PciIo->Flush (HcDev->PciIo);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciIsochronousTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                  *This,
 | |
|   IN  UINT8                                 DeviceAddress,
 | |
|   IN  UINT8                                 EndPointAddress,
 | |
|   IN  UINT8                                 DeviceSpeed,
 | |
|   IN  UINTN                                 MaximumPacketLength,
 | |
|   IN  UINT8                                 DataBuffersNumber,
 | |
|   IN  OUT VOID                              *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | |
|   IN  UINTN                                 DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR    *Translator,
 | |
|   OUT UINT32                                *TransferResult
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits isochronous transfer to a target USB device.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This             - A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|     DeviceAddress    - Represents the address of the target device on the USB,
 | |
|                        which is assigned during USB enumeration.
 | |
|     EndPointAddress  - End point address
 | |
|     DeviceSpeed      - Indicates device speed.
 | |
|     MaximumPacketLength    - Indicates the maximum packet size that the 
 | |
|                              default control transfer endpoint is capable of 
 | |
|                              sending or receiving.
 | |
|     DataBuffersNumber - Number of data buffers prepared for the transfer.
 | |
|     Data              - Array of pointers to the buffers 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.
 | |
|     Translator        - A pointr to the transaction translator data.
 | |
|     TransferResult    - A pointer to the detailed result information generated 
 | |
|                         by this control transfer.               
 | |
|                       
 | |
|   Returns:
 | |
|   
 | |
|     EFI_UNSUPPORTED 
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| EhciAsyncIsochronousTransfer (
 | |
|   IN  EFI_USB2_HC_PROTOCOL                *This,
 | |
|   IN  UINT8                               DeviceAddress,
 | |
|   IN  UINT8                               EndPointAddress,
 | |
|   IN  UINT8                               DeviceSpeed,
 | |
|   IN  UINTN                               MaximumPacketLength,
 | |
|   IN  UINT8                               DataBuffersNumber,
 | |
|   IN  OUT VOID                            *Data[EFI_USB_MAX_ISO_BUFFER_NUM],
 | |
|   IN  UINTN                               DataLength,
 | |
|   IN  EFI_USB2_HC_TRANSACTION_TRANSLATOR  *Translator,
 | |
|   IN  EFI_ASYNC_USB_TRANSFER_CALLBACK     IsochronousCallBack,
 | |
|   IN  VOID                                *Context
 | |
|   )
 | |
| /*++
 | |
|   
 | |
|   Routine Description:
 | |
|   
 | |
|     Submits Async isochronous transfer to a target USB device.
 | |
|   
 | |
|   Arguments:
 | |
|     
 | |
|     This                - A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|     DeviceAddress       - Represents the address of the target device on the USB,
 | |
|                           which is assigned during USB enumeration.
 | |
|     EndPointAddress     - End point address
 | |
|     DeviceSpeed         - Indicates device speed.
 | |
|     MaximumPacketLength - Indicates the maximum packet size that the 
 | |
|                           default control transfer endpoint is capable of 
 | |
|                           sending or receiving.
 | |
|     DataBuffersNumber   - Number of data buffers prepared for the transfer.
 | |
|     Data                - Array of pointers to the buffers of data that will be transmitted 
 | |
|                           to USB device or received from USB device.
 | |
|     Translator          - A pointr to the transaction translator data.
 | |
|     IsochronousCallBack - When the transfer complete, the call back function will be called
 | |
|     Context             - Pass to the call back function as parameter
 | |
|                     
 | |
|   Returns:
 | |
|   
 | |
|     EFI_UNSUPPORTED 
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 |