The restriction of UsbHc2.SyncInterruptTransfer() on interrupt transfer direction is removed. This interface could support Interrupt IN/OUT now. Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Feng Tian <feng.tian@intel.com> Reviewed-by: Star Zeng <star.zeng@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17041 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1890 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1890 lines
		
	
	
		
			53 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| 
 | |
|   The UHCI driver model and HC protocol routines.
 | |
| 
 | |
| Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
 | |
| This program and the accompanying materials
 | |
| are licensed and made available under the terms and conditions of the BSD License
 | |
| which accompanies this distribution.  The full text of the license may be found at
 | |
| http://opensource.org/licenses/bsd-license.php
 | |
| 
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Uhci.h"
 | |
| 
 | |
| 
 | |
| EFI_DRIVER_BINDING_PROTOCOL gUhciDriverBinding = {
 | |
|   UhciDriverBindingSupported,
 | |
|   UhciDriverBindingStart,
 | |
|   UhciDriverBindingStop,
 | |
|   0x20,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Provides software reset for the USB host controller according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  Attributes             A bit mask of the reset operation to perform.  See
 | |
|                                  below for a list of the supported bit mask values.
 | |
| 
 | |
|   @return EFI_SUCCESS            The reset operation succeeded.
 | |
|   @return EFI_INVALID_PARAMETER  Attributes is not valid.
 | |
|   @return EFI_UNSUPPORTED        This type of reset is not currently supported.
 | |
|   @return EFI_DEVICE_ERROR       Other errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2Reset (
 | |
|   IN EFI_USB2_HC_PROTOCOL   *This,
 | |
|   IN UINT16                 Attributes
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   EFI_TPL             OldTpl;
 | |
| 
 | |
|   if ((Attributes == EFI_USB_HC_RESET_GLOBAL_WITH_DEBUG) ||
 | |
|       (Attributes == EFI_USB_HC_RESET_HOST_WITH_DEBUG)) {
 | |
|     return EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   if (Uhc->DevicePath != NULL) {
 | |
|     //
 | |
|     // Report Status Code to indicate reset happens
 | |
|     //
 | |
|     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|       EFI_PROGRESS_CODE,
 | |
|       (EFI_IO_BUS_USB | EFI_IOB_PC_RESET),
 | |
|       Uhc->DevicePath
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   switch (Attributes) {
 | |
|   case EFI_USB_HC_RESET_GLOBAL:
 | |
|     //
 | |
|     // Stop schedule and set the Global Reset bit in the command register
 | |
|     //
 | |
|     UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
 | |
|     UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
 | |
| 
 | |
|     gBS->Stall (UHC_ROOT_PORT_RESET_STALL);
 | |
| 
 | |
|     //
 | |
|     // Clear the Global Reset bit to zero.
 | |
|     //
 | |
|     UhciClearRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_GRESET);
 | |
| 
 | |
|     gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
 | |
|     break;
 | |
| 
 | |
|   case EFI_USB_HC_RESET_HOST_CONTROLLER:
 | |
|     //
 | |
|     // Stop schedule and set Host Controller Reset bit to 1
 | |
|     //
 | |
|     UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
 | |
|     UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
 | |
| 
 | |
|     gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     goto ON_INVAILD_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Delete all old transactions on the USB bus, then
 | |
|   // reinitialize the frame list
 | |
|   //
 | |
|   UhciFreeAllAsyncReq (Uhc);
 | |
|   UhciDestoryFrameList (Uhc);
 | |
|   UhciInitFrameList (Uhc);
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ON_INVAILD_PARAMETER:
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return EFI_INVALID_PARAMETER;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Retrieves current state of the USB host controller according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  State                  Variable to receive current device state.
 | |
| 
 | |
|   @return EFI_SUCCESS            The state is returned.
 | |
|   @return EFI_INVALID_PARAMETER  State is not valid.
 | |
|   @return EFI_DEVICE_ERROR       Other errors.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2GetState (
 | |
|   IN   EFI_USB2_HC_PROTOCOL   *This,
 | |
|   OUT  EFI_USB_HC_STATE       *State
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   UINT16              UsbSts;
 | |
|   UINT16              UsbCmd;
 | |
| 
 | |
|   if (State == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   UsbCmd  = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
 | |
|   UsbSts  = UhciReadReg (Uhc->PciIo, USBSTS_OFFSET);
 | |
| 
 | |
|   if ((UsbCmd & USBCMD_EGSM) !=0 ) {
 | |
|     *State = EfiUsbHcStateSuspend;
 | |
| 
 | |
|   } else if ((UsbSts & USBSTS_HCH) != 0) {
 | |
|     *State = EfiUsbHcStateHalt;
 | |
| 
 | |
|   } else {
 | |
|     *State = EfiUsbHcStateOperational;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sets the USB host controller to a specific state according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  State                  Indicates the state of the host controller that will
 | |
|                                  be set.
 | |
| 
 | |
|   @return EFI_SUCCESS            Host controller was successfully placed in the state.
 | |
|   @return EFI_INVALID_PARAMETER  State is invalid.
 | |
|   @return EFI_DEVICE_ERROR       Failed to set the state.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2SetState (
 | |
|   IN EFI_USB2_HC_PROTOCOL    *This,
 | |
|   IN EFI_USB_HC_STATE        State
 | |
|   )
 | |
| {
 | |
|   EFI_USB_HC_STATE    CurState;
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   EFI_TPL             OldTpl;
 | |
|   EFI_STATUS          Status;
 | |
|   UINT16              UsbCmd;
 | |
| 
 | |
|   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
 | |
|   Status  = Uhci2GetState (This, &CurState);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (CurState == State) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   Status  = EFI_SUCCESS;
 | |
|   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   switch (State) {
 | |
|   case EfiUsbHcStateHalt:
 | |
|     Status = UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbHcStateOperational:
 | |
|     UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
 | |
| 
 | |
|     if (CurState == EfiUsbHcStateHalt) {
 | |
|       //
 | |
|       // Set Run/Stop bit to 1, also set the bandwidht reclamation
 | |
|       // point to 64 bytes
 | |
|       //
 | |
|       UsbCmd |= USBCMD_RS | USBCMD_MAXP;
 | |
|       UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
 | |
| 
 | |
|     } else if (CurState == EfiUsbHcStateSuspend) {
 | |
|       //
 | |
|       // If FGR(Force Global Resume) bit is 0, set it
 | |
|       //
 | |
|       if ((UsbCmd & USBCMD_FGR) == 0) {
 | |
|         UsbCmd |= USBCMD_FGR;
 | |
|         UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // wait 20ms to let resume complete (20ms is specified by UHCI spec)
 | |
|       //
 | |
|       gBS->Stall (UHC_FORCE_GLOBAL_RESUME_STALL);
 | |
| 
 | |
|       //
 | |
|       // Write FGR bit to 0 and EGSM(Enter Global Suspend Mode) bit to 0
 | |
|       //
 | |
|       UsbCmd &= ~USBCMD_FGR;
 | |
|       UsbCmd &= ~USBCMD_EGSM;
 | |
|       UsbCmd |= USBCMD_RS;
 | |
|       UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
 | |
|     }
 | |
| 
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbHcStateSuspend:
 | |
|     Status = Uhci2SetState (This, EfiUsbHcStateHalt);
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Set Enter Global Suspend Mode bit to 1.
 | |
|     //
 | |
|     UsbCmd = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
 | |
|     UsbCmd |= USBCMD_EGSM;
 | |
|     UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, UsbCmd);
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     Status = EFI_INVALID_PARAMETER;
 | |
|     break;
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Retrieves capabilities of USB host controller according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  MaxSpeed               A pointer to the max speed USB host controller
 | |
|                                  supports.
 | |
|   @param  PortNumber             A pointer to the number of root hub ports.
 | |
|   @param  Is64BitCapable         A pointer to an integer to show whether USB host
 | |
|                                  controller supports 64-bit memory addressing.
 | |
| 
 | |
|   @return EFI_SUCCESS            capabilities were retrieved successfully.
 | |
|   @return EFI_INVALID_PARAMETER  MaxSpeed or PortNumber or Is64BitCapable is NULL.
 | |
|   @return EFI_DEVICE_ERROR       An error was encountered.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2GetCapability (
 | |
|   IN  EFI_USB2_HC_PROTOCOL  *This,
 | |
|   OUT UINT8                 *MaxSpeed,
 | |
|   OUT UINT8                 *PortNumber,
 | |
|   OUT UINT8                 *Is64BitCapable
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   UINT32              Offset;
 | |
|   UINT16              PortSC;
 | |
|   UINT32              Index;
 | |
| 
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   if ((NULL == MaxSpeed) || (NULL == PortNumber) || (NULL == Is64BitCapable)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *MaxSpeed       = EFI_USB_SPEED_FULL;
 | |
|   *Is64BitCapable = (UINT8) FALSE;
 | |
| 
 | |
|   *PortNumber = 0;
 | |
| 
 | |
|   for (Index = 0; Index < USB_MAX_ROOTHUB_PORT; Index++) {
 | |
|     Offset  = USBPORTSC_OFFSET + Index * 2;
 | |
|     PortSC  = UhciReadReg (Uhc->PciIo, Offset);
 | |
| 
 | |
|     //
 | |
|     // Port status's bit 7 is reserved and always returns 1 if
 | |
|     // the port number is valid. Intel's UHCI (in EHCI controller)
 | |
|     // returns 0 in this bit if port number is invalid. Also, if
 | |
|     // PciIo IoRead returns error, 0xFFFF is returned to caller.
 | |
|     //
 | |
|     if (((PortSC & 0x80) == 0) || (PortSC == 0xFFFF)) {
 | |
|       break;
 | |
|     }
 | |
|     (*PortNumber)++;
 | |
|   }
 | |
| 
 | |
|   Uhc->RootPorts = *PortNumber;
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "Uhci2GetCapability: %d ports\n", (UINT32)Uhc->RootPorts));
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Retrieves the current status of a USB root hub port according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                    A pointer to the EFI_USB2_HC_PROTOCOL.
 | |
|   @param  PortNumber              The port to get status.
 | |
|   @param  PortStatus              A pointer to the current port status bits and  port
 | |
|                                   status change bits.
 | |
| 
 | |
|   @return EFI_SUCCESS             status of the USB root hub port was returned in PortStatus.
 | |
|   @return EFI_INVALID_PARAMETER   PortNumber is invalid.
 | |
|   @return EFI_DEVICE_ERROR        Can't read register.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2GetRootHubPortStatus (
 | |
|   IN   EFI_USB2_HC_PROTOCOL   *This,
 | |
|   IN   UINT8                  PortNumber,
 | |
|   OUT  EFI_USB_PORT_STATUS    *PortStatus
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   UINT32              Offset;
 | |
|   UINT16              PortSC;
 | |
| 
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   if (PortStatus == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (PortNumber >= Uhc->RootPorts) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Offset                        = USBPORTSC_OFFSET + PortNumber * 2;
 | |
|   PortStatus->PortStatus        = 0;
 | |
|   PortStatus->PortChangeStatus  = 0;
 | |
| 
 | |
|   PortSC                        = UhciReadReg (Uhc->PciIo, Offset);
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_CCS) != 0) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_CONNECTION;
 | |
|   }
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_PED) != 0) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_ENABLE;
 | |
|   }
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_SUSP) != 0) {
 | |
|     DEBUG ((EFI_D_INFO, "Uhci2GetRootHubPortStatus: port %d is suspended\n", PortNumber));
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_SUSPEND;
 | |
|   }
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_PR) != 0) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_RESET;
 | |
|   }
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_LSDA) != 0) {
 | |
|     PortStatus->PortStatus |= USB_PORT_STAT_LOW_SPEED;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // CHC will always return one in port owner bit
 | |
|   //
 | |
|   PortStatus->PortStatus |= USB_PORT_STAT_OWNER;
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_CSC) != 0) {
 | |
|     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_CONNECTION;
 | |
|   }
 | |
| 
 | |
|   if ((PortSC & USBPORTSC_PEDC) != 0) {
 | |
|     PortStatus->PortChangeStatus |= USB_PORT_STAT_C_ENABLE;
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Sets a feature for the specified root hub port according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL.
 | |
|   @param  PortNumber             Specifies the root hub port whose feature  is
 | |
|                                  requested to be set.
 | |
|   @param  PortFeature            Indicates the feature selector associated  with the
 | |
|                                  feature set request.
 | |
| 
 | |
|   @return EFI_SUCCESS            PortFeature was set for the root port.
 | |
|   @return EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
 | |
|   @return EFI_DEVICE_ERROR       Can't read register.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2SetRootHubPortFeature (
 | |
|   IN EFI_USB2_HC_PROTOCOL    *This,
 | |
|   IN UINT8                   PortNumber,
 | |
|   IN EFI_USB_PORT_FEATURE    PortFeature
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   EFI_TPL             OldTpl;
 | |
|   UINT32              Offset;
 | |
|   UINT16              PortSC;
 | |
|   UINT16              Command;
 | |
| 
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   if (PortNumber >= Uhc->RootPorts) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Offset  = USBPORTSC_OFFSET + PortNumber * 2;
 | |
| 
 | |
|   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
 | |
|   PortSC  = UhciReadReg (Uhc->PciIo, Offset);
 | |
| 
 | |
|   switch (PortFeature) {
 | |
|   case EfiUsbPortSuspend:
 | |
|     Command = UhciReadReg (Uhc->PciIo, USBCMD_OFFSET);
 | |
|     if ((Command & USBCMD_EGSM) == 0) {
 | |
|       //
 | |
|       // if global suspend is not active, can set port suspend
 | |
|       //
 | |
|       PortSC &= 0xfff5;
 | |
|       PortSC |= USBPORTSC_SUSP;
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortReset:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC |= USBPORTSC_PR;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortPower:
 | |
|     //
 | |
|     // No action
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortEnable:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC |= USBPORTSC_PED;
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   UhciWriteReg (Uhc->PciIo, Offset, PortSC);
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Clears a feature for the specified root hub port according to Uefi 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  PortNumber             Specifies the root hub port whose feature  is
 | |
|                                  requested to be cleared.
 | |
|   @param  PortFeature            Indicates the feature selector associated with the
 | |
|                                  feature clear request.
 | |
| 
 | |
|   @return EFI_SUCCESS            PortFeature was cleared for the USB root hub port.
 | |
|   @return EFI_INVALID_PARAMETER  PortNumber is invalid or PortFeature is invalid.
 | |
|   @return EFI_DEVICE_ERROR       Can't read register.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2ClearRootHubPortFeature (
 | |
|   IN EFI_USB2_HC_PROTOCOL    *This,
 | |
|   IN UINT8                   PortNumber,
 | |
|   IN EFI_USB_PORT_FEATURE    PortFeature
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   EFI_TPL             OldTpl;
 | |
|   UINT32              Offset;
 | |
|   UINT16              PortSC;
 | |
| 
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
|   if (PortNumber >= Uhc->RootPorts) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   Offset  = USBPORTSC_OFFSET + PortNumber * 2;
 | |
| 
 | |
|   OldTpl  = gBS->RaiseTPL (UHCI_TPL);
 | |
|   PortSC  = UhciReadReg (Uhc->PciIo, Offset);
 | |
| 
 | |
|   switch (PortFeature) {
 | |
|   case EfiUsbPortEnable:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC &= ~USBPORTSC_PED;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortSuspend:
 | |
|     //
 | |
|     // Cause a resume on the specified port if in suspend mode.
 | |
|     //
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC &= ~USBPORTSC_SUSP;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortPower:
 | |
|     //
 | |
|     // No action
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortReset:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC &= ~USBPORTSC_PR;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortConnectChange:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC |= USBPORTSC_CSC;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortEnableChange:
 | |
|     PortSC &= 0xfff5;
 | |
|     PortSC |= USBPORTSC_PEDC;
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortSuspendChange:
 | |
|     //
 | |
|     // Root hub does not support this
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortOverCurrentChange:
 | |
|     //
 | |
|     // Root hub does not support this
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   case EfiUsbPortResetChange:
 | |
|     //
 | |
|     // Root hub does not support this
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   UhciWriteReg (Uhc->PciIo, Offset, PortSC);
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submits control transfer to a target USB device accroding to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress          Target device address.
 | |
|   @param  DeviceSpeed            Device speed.
 | |
|   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
 | |
|   @param  Request                USB device request to send.
 | |
|   @param  TransferDirection      Data direction of the Data stage in control transfer.
 | |
|   @param  Data                   Data to transmit/receive in data stage.
 | |
|   @param  DataLength             Length of the data.
 | |
|   @param  TimeOut                Maximum time, in microseconds, for transfer to complete.
 | |
|   @param  Translator             Transaction translator to be used by this device.
 | |
|   @param  TransferResult         Variable to receive the transfer result.
 | |
| 
 | |
|   @return EFI_SUCCESS            The control transfer was completed successfully.
 | |
|   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
 | |
|   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
 | |
|   @return EFI_TIMEOUT            Failed due to timeout.
 | |
|   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2ControlTransfer (
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV              *Uhc;
 | |
|   UHCI_TD_SW              *TDs;
 | |
|   EFI_TPL                 OldTpl;
 | |
|   EFI_STATUS              Status;
 | |
|   UHCI_QH_RESULT          QhResult;
 | |
|   UINT8                   PktId;
 | |
|   UINT8                   *RequestPhy;
 | |
|   VOID                    *RequestMap;
 | |
|   UINT8                   *DataPhy;
 | |
|   VOID                    *DataMap;
 | |
|   BOOLEAN                 IsSlowDevice;
 | |
|   UINTN                   TransferDataLength;
 | |
| 
 | |
|   Uhc         = UHC_FROM_USB2_HC_PROTO (This);
 | |
|   TDs         = NULL;
 | |
|   DataPhy     = NULL;
 | |
|   DataMap     = NULL;
 | |
|   RequestPhy  = NULL;
 | |
|   RequestMap  = NULL;
 | |
| 
 | |
|   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
 | |
| 
 | |
|   //
 | |
|   // Parameters Checking
 | |
|   //
 | |
|   if (Request == NULL || TransferResult == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (IsSlowDevice && (MaximumPacketLength != 8)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((MaximumPacketLength != 8) &&  (MaximumPacketLength != 16) &&
 | |
|       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
 | |
| 
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((TransferDirection != EfiUsbNoData) && (Data == NULL || DataLength == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (TransferDirection == EfiUsbNoData) {
 | |
|     TransferDataLength = 0;
 | |
|   } else {
 | |
|     TransferDataLength = *DataLength;
 | |
|   }
 | |
| 
 | |
|   *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|   Status          = EFI_DEVICE_ERROR;
 | |
| 
 | |
|   //
 | |
|   // If errors exist that cause host controller halt,
 | |
|   // clear status then return EFI_DEVICE_ERROR.
 | |
|   //
 | |
|   UhciAckAllInterrupt (Uhc);
 | |
| 
 | |
|   if (!UhciIsHcWorking (Uhc->PciIo)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   //
 | |
|   // Map the Request and data for bus master access,
 | |
|   // then create a list of TD for this transfer
 | |
|   //
 | |
|   Status = UhciMapUserRequest (Uhc, Request, &RequestPhy, &RequestMap);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = UhciMapUserData (Uhc, TransferDirection, Data, DataLength, &PktId, &DataPhy, &DataMap);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   TDs = UhciCreateCtrlTds (
 | |
|           Uhc,
 | |
|           DeviceAddress,
 | |
|           PktId,
 | |
|           (UINT8*)Request,
 | |
|           RequestPhy,
 | |
|           (UINT8*)Data,
 | |
|           DataPhy,
 | |
|           TransferDataLength,
 | |
|           (UINT8) MaximumPacketLength,
 | |
|           IsSlowDevice
 | |
|           );
 | |
| 
 | |
|   if (TDs == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto UNMAP_DATA;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // According to the speed of the end point, link
 | |
|   // the TD to corrosponding queue head, then check
 | |
|   // the execution result
 | |
|   //
 | |
|   UhciLinkTdToQh (Uhc, Uhc->CtrlQh, TDs);
 | |
|   Status = UhciExecuteTransfer (Uhc, Uhc->CtrlQh, TDs, TimeOut, IsSlowDevice, &QhResult);
 | |
|   UhciUnlinkTdFromQh (Uhc->CtrlQh, TDs);
 | |
| 
 | |
|   Uhc->PciIo->Flush (Uhc->PciIo);
 | |
| 
 | |
|   *TransferResult = QhResult.Result;
 | |
| 
 | |
|   if (DataLength != NULL) {
 | |
|     *DataLength = QhResult.Complete;
 | |
|   }
 | |
| 
 | |
|   UhciDestoryTds (Uhc, TDs);
 | |
| 
 | |
| UNMAP_DATA:
 | |
|   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
 | |
|   Uhc->PciIo->Unmap (Uhc->PciIo, RequestMap);
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submits bulk transfer to a bulk endpoint of a USB device.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress          Target device address.
 | |
|   @param  EndPointAddress        Endpoint number and direction.
 | |
|   @param  DeviceSpeed            Device speed.
 | |
|   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
 | |
|   @param  DataBuffersNumber      Number of data buffers prepared for the transfer.
 | |
|   @param  Data                   Array of pointers to the buffers of data.
 | |
|   @param  DataLength             On input, size of the data buffer, On output,
 | |
|                                  actually transferred data size.
 | |
|   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
 | |
|   @param  TimeOut                Maximum time out, in microseconds.
 | |
|   @param  Translator             A pointr to the transaction translator data.
 | |
|   @param  TransferResult         Variable to receive transfer result.
 | |
| 
 | |
|   @return EFI_SUCCESS            The bulk transfer was completed successfully.
 | |
|   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
 | |
|   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
 | |
|   @return EFI_TIMEOUT            Failed due to timeout.
 | |
|   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2BulkTransfer (
 | |
|   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_USB_DATA_DIRECTION  Direction;
 | |
|   EFI_TPL                 OldTpl;
 | |
|   USB_HC_DEV              *Uhc;
 | |
|   UHCI_TD_SW              *TDs;
 | |
|   UHCI_QH_SW              *BulkQh;
 | |
|   UHCI_QH_RESULT          QhResult;
 | |
|   EFI_STATUS              Status;
 | |
|   UINT8                   PktId;
 | |
|   UINT8                   *DataPhy;
 | |
|   VOID                    *DataMap;
 | |
| 
 | |
|   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
 | |
|   DataPhy = NULL;
 | |
|   DataMap = NULL;
 | |
| 
 | |
|   if (DeviceSpeed == EFI_USB_SPEED_LOW) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((DataLength == NULL) || (*DataLength == 0) || (Data == NULL) || (TransferResult == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((*DataToggle != 1) && (*DataToggle != 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((MaximumPacketLength != 8) && (MaximumPacketLength != 16) &&
 | |
|       (MaximumPacketLength != 32) && (MaximumPacketLength != 64)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|   Status          = EFI_OUT_OF_RESOURCES;
 | |
| 
 | |
|   //
 | |
|   // If has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   UhciAckAllInterrupt (Uhc);
 | |
| 
 | |
|   if (!UhciIsHcWorking (Uhc->PciIo)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   //
 | |
|   // Map the source data buffer for bus master access,
 | |
|   // then create a list of TDs
 | |
|   //
 | |
|   if ((EndPointAddress & 0x80) != 0) {
 | |
|     Direction = EfiUsbDataIn;
 | |
|   } else {
 | |
|     Direction = EfiUsbDataOut;
 | |
|   }
 | |
| 
 | |
|   Status = UhciMapUserData (Uhc, Direction, *Data, DataLength, &PktId, &DataPhy, &DataMap);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   Status = EFI_OUT_OF_RESOURCES;
 | |
|   TDs    = UhciCreateBulkOrIntTds (
 | |
|              Uhc,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              PktId,
 | |
|              (UINT8 *)*Data,
 | |
|              DataPhy,
 | |
|              *DataLength,
 | |
|              DataToggle,
 | |
|              (UINT8) MaximumPacketLength,
 | |
|              FALSE
 | |
|              );
 | |
| 
 | |
|   if (TDs == NULL) {
 | |
|     Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Link the TDs to bulk queue head. According to the platfore
 | |
|   // defintion of UHCI_NO_BW_RECLAMATION, BulkQh is either configured
 | |
|   // to do full speed bandwidth reclamation or not.
 | |
|   //
 | |
|   BulkQh = Uhc->BulkQh;
 | |
| 
 | |
|   UhciLinkTdToQh (Uhc, BulkQh, TDs);
 | |
|   Status = UhciExecuteTransfer (Uhc, BulkQh, TDs, TimeOut, FALSE, &QhResult);
 | |
|   UhciUnlinkTdFromQh (BulkQh, TDs);
 | |
| 
 | |
|   Uhc->PciIo->Flush (Uhc->PciIo);
 | |
| 
 | |
|   *TransferResult = QhResult.Result;
 | |
|   *DataToggle     = QhResult.NextToggle;
 | |
|   *DataLength     = QhResult.Complete;
 | |
| 
 | |
|   UhciDestoryTds (Uhc, TDs);
 | |
|   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submits an asynchronous interrupt transfer to an
 | |
|   interrupt endpoint of a USB device according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress          Target device address.
 | |
|   @param  EndPointAddress        Endpoint number and direction.
 | |
|   @param  DeviceSpeed            Device speed.
 | |
|   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
 | |
|   @param  IsNewTransfer          If TRUE, submit a new transfer, if FALSE cancel old transfer.
 | |
|   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
 | |
|   @param  PollingInterval        Interrupt poll rate in milliseconds.
 | |
|   @param  DataLength             On input, size of the data buffer, On output,
 | |
|                                  actually transferred data size.
 | |
|   @param  Translator             A pointr to the transaction translator data.
 | |
|   @param  CallBackFunction       Function to call periodically.
 | |
|   @param  Context                User context.
 | |
| 
 | |
|   @return EFI_SUCCESS            Transfer was submitted.
 | |
|   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
 | |
|   @return EFI_OUT_OF_RESOURCES   Failed due to a lack of resources.
 | |
|   @return EFI_DEVICE_ERROR       Can't read register.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2AsyncInterruptTransfer (
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   BOOLEAN             IsSlowDevice;
 | |
|   UHCI_QH_SW          *Qh;
 | |
|   UHCI_TD_SW          *IntTds;
 | |
|   EFI_TPL             OldTpl;
 | |
|   EFI_STATUS          Status;
 | |
|   UINT8               *DataPtr;
 | |
|   UINT8               *DataPhy;
 | |
|   UINT8               PktId;
 | |
| 
 | |
|   Uhc       = UHC_FROM_USB2_HC_PROTO (This);
 | |
|   Qh        = NULL;
 | |
|   IntTds    = NULL;
 | |
|   DataPtr   = NULL;
 | |
|   DataPhy   = NULL;
 | |
| 
 | |
|   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
 | |
| 
 | |
|   if ((EndPointAddress & 0x80) == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Delete Async interrupt transfer request
 | |
|   //
 | |
|   if (!IsNewTransfer) {
 | |
|     OldTpl = gBS->RaiseTPL (UHCI_TPL);
 | |
|     Status = UhciRemoveAsyncReq (Uhc, DeviceAddress, EndPointAddress, DataToggle);
 | |
| 
 | |
|     gBS->RestoreTPL (OldTpl);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (PollingInterval < 1 || PollingInterval > 255) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (DataLength == 0) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((*DataToggle != 1) && (*DataToggle != 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If has errors that cause host controller halt,
 | |
|   // then return EFI_DEVICE_ERROR directly.
 | |
|   //
 | |
|   UhciAckAllInterrupt (Uhc);
 | |
| 
 | |
|   if (!UhciIsHcWorking (Uhc->PciIo)) {
 | |
|     return EFI_DEVICE_ERROR;
 | |
|   }
 | |
| 
 | |
|   if ((EndPointAddress & 0x80) == 0) {
 | |
|     PktId = OUTPUT_PACKET_ID;
 | |
|   } else {
 | |
|     PktId = INPUT_PACKET_ID;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate and map source data buffer for bus master access.
 | |
|   //
 | |
|   DataPtr = UsbHcAllocateMem (Uhc->MemPool, DataLength);
 | |
| 
 | |
|   if (DataPtr == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   DataPhy = (UINT8 *) (UINTN) UsbHcGetPciAddressForHostMem (Uhc->MemPool, DataPtr, DataLength);
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   Qh = UhciCreateQh (Uhc, PollingInterval);
 | |
| 
 | |
|   if (Qh == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto FREE_DATA;
 | |
|   }
 | |
| 
 | |
|   IntTds = UhciCreateBulkOrIntTds (
 | |
|              Uhc,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              PktId,
 | |
|              DataPtr,
 | |
|              DataPhy,
 | |
|              DataLength,
 | |
|              DataToggle,
 | |
|              (UINT8) MaximumPacketLength,
 | |
|              IsSlowDevice
 | |
|              );
 | |
| 
 | |
|   if (IntTds == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto DESTORY_QH;
 | |
|   }
 | |
| 
 | |
|   UhciLinkTdToQh (Uhc, Qh, IntTds);
 | |
| 
 | |
|   //
 | |
|   // Save QH-TD structures to async Interrupt transfer list,
 | |
|   // for monitor interrupt transfer execution routine use.
 | |
|   //
 | |
|   Status = UhciCreateAsyncReq (
 | |
|              Uhc,
 | |
|              Qh,
 | |
|              IntTds,
 | |
|              DeviceAddress,
 | |
|              EndPointAddress,
 | |
|              DataLength,
 | |
|              PollingInterval,
 | |
|              DataPtr,
 | |
|              CallBackFunction,
 | |
|              Context,
 | |
|              IsSlowDevice
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto DESTORY_QH;
 | |
|   }
 | |
| 
 | |
|   UhciLinkQhToFrameList (Uhc, Qh);
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| DESTORY_QH:
 | |
|   UsbHcFreeMem (Uhc->MemPool, Qh, sizeof (UHCI_QH_SW));
 | |
| 
 | |
| FREE_DATA:
 | |
|   UsbHcFreeMem (Uhc->MemPool, DataPtr, DataLength);
 | |
|   Uhc->PciIo->Flush (Uhc->PciIo);
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Submits synchronous interrupt transfer to an interrupt endpoint
 | |
|   of a USB device according to UEFI 2.0 spec.
 | |
| 
 | |
| 
 | |
|   @param  This                   A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress          Target device address.
 | |
|   @param  EndPointAddress        Endpoint number and direction.
 | |
|   @param  DeviceSpeed            Device speed.
 | |
|   @param  MaximumPacketLength    Maximum packet size of the target endpoint.
 | |
|   @param  Data                   Array of pointers to the buffers of data.
 | |
|   @param  DataLength             On input, size of the data buffer, On output,
 | |
|                                  actually transferred data size.
 | |
|   @param  DataToggle             On input, data toggle to use; On output, next data toggle.
 | |
|   @param  TimeOut                Maximum time out, in microseconds.
 | |
|   @param  Translator             A pointr to the transaction translator data.
 | |
|   @param  TransferResult         Variable to receive transfer result.
 | |
| 
 | |
|   @return EFI_SUCCESS            The transfer was completed successfully.
 | |
|   @return EFI_OUT_OF_RESOURCES   Failed due to lack of resource.
 | |
|   @return EFI_INVALID_PARAMETER  Some parameters are invalid.
 | |
|   @return EFI_TIMEOUT            Failed due to timeout.
 | |
|   @return EFI_DEVICE_ERROR       Failed due to host controller or device error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2SyncInterruptTransfer (
 | |
|   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          Status;
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   UHCI_TD_SW          *TDs;
 | |
|   UHCI_QH_RESULT      QhResult;
 | |
|   EFI_TPL             OldTpl;
 | |
|   UINT8               *DataPhy;
 | |
|   VOID                *DataMap;
 | |
|   UINT8               PktId;
 | |
|   BOOLEAN             IsSlowDevice;
 | |
| 
 | |
|   Uhc     = UHC_FROM_USB2_HC_PROTO (This);
 | |
|   DataPhy = NULL;
 | |
|   DataMap = NULL;
 | |
|   TDs     = NULL;
 | |
| 
 | |
|   if (DeviceSpeed == EFI_USB_SPEED_HIGH) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   IsSlowDevice  = (BOOLEAN) ((EFI_USB_SPEED_LOW == DeviceSpeed) ? TRUE : FALSE);
 | |
| 
 | |
|   if ((DataLength == NULL) || (Data == NULL) || (TransferResult == NULL)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((*DataToggle != 1) && (*DataToggle != 0)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if ((*DataLength == 0) || (MaximumPacketLength > 64)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (IsSlowDevice && (MaximumPacketLength > 8)) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   *TransferResult = EFI_USB_ERR_SYSTEM;
 | |
|   Status          = EFI_DEVICE_ERROR;
 | |
| 
 | |
| 
 | |
|   UhciAckAllInterrupt (Uhc);
 | |
| 
 | |
|   if (!UhciIsHcWorking (Uhc->PciIo)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (UHCI_TPL);
 | |
| 
 | |
|   //
 | |
|   // Map the source data buffer for bus master access.
 | |
|   // Create Tds list, then link it to the UHC's interrupt list
 | |
|   //
 | |
|   Status = UhciMapUserData (
 | |
|              Uhc,
 | |
|              EfiUsbDataIn,
 | |
|              Data,
 | |
|              DataLength,
 | |
|              &PktId,
 | |
|              &DataPhy,
 | |
|              &DataMap
 | |
|              );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   TDs = UhciCreateBulkOrIntTds (
 | |
|           Uhc,
 | |
|           DeviceAddress,
 | |
|           EndPointAddress,
 | |
|           PktId,
 | |
|           (UINT8 *)Data,
 | |
|           DataPhy,
 | |
|           *DataLength,
 | |
|           DataToggle,
 | |
|           (UINT8) MaximumPacketLength,
 | |
|           IsSlowDevice
 | |
|           );
 | |
| 
 | |
|   if (TDs == NULL) {
 | |
|     Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
 | |
| 
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
| 
 | |
|   UhciLinkTdToQh (Uhc, Uhc->SyncIntQh, TDs);
 | |
| 
 | |
|   Status = UhciExecuteTransfer (Uhc, Uhc->SyncIntQh, TDs, TimeOut, IsSlowDevice, &QhResult);
 | |
| 
 | |
|   UhciUnlinkTdFromQh (Uhc->SyncIntQh, TDs);
 | |
|   Uhc->PciIo->Flush (Uhc->PciIo);
 | |
| 
 | |
|   *TransferResult = QhResult.Result;
 | |
|   *DataToggle     = QhResult.NextToggle;
 | |
|   *DataLength     = QhResult.Complete;
 | |
| 
 | |
|   UhciDestoryTds (Uhc, TDs);
 | |
|   Uhc->PciIo->Unmap (Uhc->PciIo, DataMap);
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submits isochronous transfer to a target USB device according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress         Target device address.
 | |
|   @param  EndPointAddress       Endpoint number and direction.
 | |
|   @param  DeviceSpeed           Device speed.
 | |
|   @param  MaximumPacketLength   Maximum packet size of the target endpoint.
 | |
|   @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
 | |
|   @param  Data                  Array of pointers to the buffers of data.
 | |
|   @param  DataLength            On input, size of the data buffer, On output,
 | |
|                                 actually transferred data size.
 | |
|   @param  Translator            A pointr to the transaction translator data.
 | |
|   @param  TransferResult        Variable to receive transfer result.
 | |
| 
 | |
|   @return EFI_UNSUPPORTED
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2IsochronousTransfer (
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Submits Async isochronous transfer to a target USB device according to UEFI 2.0 spec.
 | |
| 
 | |
|   @param  This                  A pointer to the EFI_USB2_HC_PROTOCOL instance.
 | |
|   @param  DeviceAddress         Target device address.
 | |
|   @param  EndPointAddress       Endpoint number and direction.
 | |
|   @param  DeviceSpeed           Device speed.
 | |
|   @param  MaximumPacketLength   Maximum packet size of the target endpoint.
 | |
|   @param  DataBuffersNumber     Number of data buffers prepared for the transfer.
 | |
|   @param  Data                  Array of pointers to the buffers of data.
 | |
|   @param  DataLength            On input, size of the data buffer, On output,
 | |
|                                 actually transferred data size.
 | |
|   @param  Translator            A pointr to the transaction translator data.
 | |
|   @param  IsochronousCallBack   Function to call when the transfer complete.
 | |
|   @param  Context               Pass to the call back function as parameter.
 | |
| 
 | |
|   @return EFI_UNSUPPORTED
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| Uhci2AsyncIsochronousTransfer (
 | |
|   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
 | |
|   )
 | |
| {
 | |
|   return EFI_UNSUPPORTED;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Entry point for EFI drivers.
 | |
| 
 | |
|   @param  ImageHandle      EFI_HANDLE.
 | |
|   @param  SystemTable      EFI_SYSTEM_TABLE.
 | |
| 
 | |
|   @retval EFI_SUCCESS      Driver is successfully loaded.
 | |
|   @return Others           Failed.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UhciDriverEntryPoint (
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   return EfiLibInstallDriverBindingComponentName2 (
 | |
|            ImageHandle,
 | |
|            SystemTable,
 | |
|            &gUhciDriverBinding,
 | |
|            ImageHandle,
 | |
|            &gUhciComponentName,
 | |
|            &gUhciComponentName2
 | |
|            );
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Test to see if this driver supports ControllerHandle. Any
 | |
|   ControllerHandle that has UsbHcProtocol installed will be supported.
 | |
| 
 | |
|   @param  This                 Protocol instance pointer.
 | |
|   @param  Controller           Handle of device to test.
 | |
|   @param  RemainingDevicePath  Not used.
 | |
| 
 | |
|   @return EFI_SUCCESS          This driver supports this device.
 | |
|   @return EFI_UNSUPPORTED      This driver does not support this device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UhciDriverBindingSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN EFI_HANDLE                      Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            OpenStatus;
 | |
|   EFI_STATUS            Status;
 | |
|   EFI_PCI_IO_PROTOCOL   *PciIo;
 | |
|   USB_CLASSC            UsbClassCReg;
 | |
| 
 | |
|   //
 | |
|   // Test whether there is PCI IO Protocol attached on the controller handle.
 | |
|   //
 | |
|   OpenStatus = gBS->OpenProtocol (
 | |
|                       Controller,
 | |
|                       &gEfiPciIoProtocolGuid,
 | |
|                       (VOID **) &PciIo,
 | |
|                       This->DriverBindingHandle,
 | |
|                       Controller,
 | |
|                       EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                       );
 | |
| 
 | |
|   if (EFI_ERROR (OpenStatus)) {
 | |
|     return OpenStatus;
 | |
|   }
 | |
| 
 | |
|   Status = PciIo->Pci.Read (
 | |
|                         PciIo,
 | |
|                         EfiPciIoWidthUint8,
 | |
|                         PCI_CLASSCODE_OFFSET,
 | |
|                         sizeof (USB_CLASSC) / sizeof (UINT8),
 | |
|                         &UsbClassCReg
 | |
|                         );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto ON_EXIT;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Test whether the controller belongs to UHCI type
 | |
|   //
 | |
|   if ((UsbClassCReg.BaseCode != PCI_CLASS_SERIAL) ||
 | |
|       (UsbClassCReg.SubClassCode != PCI_CLASS_SERIAL_USB) ||
 | |
|       (UsbClassCReg.ProgInterface != PCI_IF_UHCI)
 | |
|       ) {
 | |
| 
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiPciIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return Status;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Allocate and initialize the empty UHCI device.
 | |
| 
 | |
|   @param  PciIo                  The PCIIO to use.
 | |
|   @param  DevicePath             The device path of host controller.
 | |
|   @param  OriginalPciAttributes  The original PCI attributes.
 | |
| 
 | |
|   @return Allocated UHCI device. If err, return NULL.
 | |
| 
 | |
| **/
 | |
| USB_HC_DEV *
 | |
| UhciAllocateDev (
 | |
|   IN EFI_PCI_IO_PROTOCOL       *PciIo,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL  *DevicePath,
 | |
|   IN UINT64                    OriginalPciAttributes
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV  *Uhc;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   Uhc = AllocateZeroPool (sizeof (USB_HC_DEV));
 | |
| 
 | |
|   if (Uhc == NULL) {
 | |
|     return NULL;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // This driver supports both USB_HC_PROTOCOL and USB2_HC_PROTOCOL.
 | |
|   // USB_HC_PROTOCOL is for EFI 1.1 backward compability.
 | |
|   //
 | |
|   Uhc->Signature                        = USB_HC_DEV_SIGNATURE;
 | |
|   Uhc->Usb2Hc.GetCapability             = Uhci2GetCapability;
 | |
|   Uhc->Usb2Hc.Reset                     = Uhci2Reset;
 | |
|   Uhc->Usb2Hc.GetState                  = Uhci2GetState;
 | |
|   Uhc->Usb2Hc.SetState                  = Uhci2SetState;
 | |
|   Uhc->Usb2Hc.ControlTransfer           = Uhci2ControlTransfer;
 | |
|   Uhc->Usb2Hc.BulkTransfer              = Uhci2BulkTransfer;
 | |
|   Uhc->Usb2Hc.AsyncInterruptTransfer    = Uhci2AsyncInterruptTransfer;
 | |
|   Uhc->Usb2Hc.SyncInterruptTransfer     = Uhci2SyncInterruptTransfer;
 | |
|   Uhc->Usb2Hc.IsochronousTransfer       = Uhci2IsochronousTransfer;
 | |
|   Uhc->Usb2Hc.AsyncIsochronousTransfer  = Uhci2AsyncIsochronousTransfer;
 | |
|   Uhc->Usb2Hc.GetRootHubPortStatus      = Uhci2GetRootHubPortStatus;
 | |
|   Uhc->Usb2Hc.SetRootHubPortFeature     = Uhci2SetRootHubPortFeature;
 | |
|   Uhc->Usb2Hc.ClearRootHubPortFeature   = Uhci2ClearRootHubPortFeature;
 | |
|   Uhc->Usb2Hc.MajorRevision             = 0x1;
 | |
|   Uhc->Usb2Hc.MinorRevision             = 0x1;
 | |
| 
 | |
|   Uhc->PciIo                 = PciIo;
 | |
|   Uhc->DevicePath            = DevicePath;
 | |
|   Uhc->OriginalPciAttributes = OriginalPciAttributes;
 | |
|   Uhc->MemPool               = UsbHcInitMemPool (PciIo, TRUE, 0);
 | |
| 
 | |
|   if (Uhc->MemPool == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   InitializeListHead (&Uhc->AsyncIntList);
 | |
| 
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_CALLBACK,
 | |
|                   UhciMonitorAsyncReqList,
 | |
|                   Uhc,
 | |
|                   &Uhc->AsyncIntMonitor
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     UsbHcFreeMemPool (Uhc->MemPool);
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   return Uhc;
 | |
| 
 | |
| ON_ERROR:
 | |
|   FreePool (Uhc);
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Free the UHCI device and release its associated resources.
 | |
| 
 | |
|   @param  Uhc     The UHCI device to release.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| UhciFreeDev (
 | |
|   IN USB_HC_DEV           *Uhc
 | |
|   )
 | |
| {
 | |
|   if (Uhc->AsyncIntMonitor != NULL) {
 | |
|     gBS->CloseEvent (Uhc->AsyncIntMonitor);
 | |
|   }
 | |
| 
 | |
|   if (Uhc->ExitBootServiceEvent != NULL) {
 | |
|     gBS->CloseEvent (Uhc->ExitBootServiceEvent);
 | |
|   }
 | |
|   
 | |
|   if (Uhc->MemPool != NULL) {
 | |
|     UsbHcFreeMemPool (Uhc->MemPool);
 | |
|   }
 | |
| 
 | |
|   if (Uhc->CtrlNameTable != NULL) {
 | |
|     FreeUnicodeStringTable (Uhc->CtrlNameTable);
 | |
|   }
 | |
| 
 | |
|   FreePool (Uhc);
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Uninstall all Uhci Interface.
 | |
| 
 | |
|   @param  Controller           Controller handle.
 | |
|   @param  This                 Protocol instance pointer.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| UhciCleanDevUp (
 | |
|   IN  EFI_HANDLE           Controller,
 | |
|   IN  EFI_USB2_HC_PROTOCOL *This
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   EFI_STATUS          Status;
 | |
| 
 | |
|   //
 | |
|   // Uninstall the USB_HC and USB_HC2 protocol, then disable the controller
 | |
|   //
 | |
|   Uhc = UHC_FROM_USB2_HC_PROTO (This);
 | |
| 
 | |
| 
 | |
|   Status = gBS->UninstallProtocolInterface (
 | |
|                   Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   &Uhc->Usb2Hc
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
 | |
|   UhciFreeAllAsyncReq (Uhc);
 | |
|   UhciDestoryFrameList (Uhc);
 | |
| 
 | |
|   //
 | |
|   // Restore original PCI attributes
 | |
|   //
 | |
|   Uhc->PciIo->Attributes (
 | |
|                   Uhc->PciIo,
 | |
|                   EfiPciIoAttributeOperationSet,
 | |
|                   Uhc->OriginalPciAttributes,
 | |
|                   NULL
 | |
|                   );
 | |
| 
 | |
|   UhciFreeDev (Uhc);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   One notified function to stop the Host Controller when gBS->ExitBootServices() called.
 | |
| 
 | |
|   @param  Event                   Pointer to this event
 | |
|   @param  Context                 Event handler private data
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| UhcExitBootService (
 | |
|   EFI_EVENT                      Event,
 | |
|   VOID                           *Context
 | |
|   )
 | |
| {
 | |
|   USB_HC_DEV   *Uhc;
 | |
| 
 | |
|   Uhc = (USB_HC_DEV *) Context;
 | |
| 
 | |
|   //
 | |
|   // Stop the Host Controller
 | |
|   //
 | |
|   UhciStopHc (Uhc, UHC_GENERIC_TIMEOUT);
 | |
| 
 | |
|   //
 | |
|   // Reset the Host Controller
 | |
|   //
 | |
|   UhciSetRegBit (Uhc->PciIo, USBCMD_OFFSET, USBCMD_HCRESET);
 | |
|   gBS->Stall (UHC_ROOT_PORT_RECOVERY_STALL);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Starting the Usb UHCI Driver.
 | |
| 
 | |
|   @param  This                 Protocol instance pointer.
 | |
|   @param  Controller           Handle of device to test.
 | |
|   @param  RemainingDevicePath  Not used.
 | |
| 
 | |
|   @retval EFI_SUCCESS          This driver supports this device.
 | |
|   @retval EFI_UNSUPPORTED      This driver does not support this device.
 | |
|   @retval EFI_DEVICE_ERROR     This driver cannot be started due to device Error.
 | |
|                                EFI_OUT_OF_RESOURCES- Failed due to resource shortage.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UhciDriverBindingStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN EFI_HANDLE                      Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL        *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS          Status;
 | |
|   EFI_PCI_IO_PROTOCOL *PciIo;
 | |
|   USB_HC_DEV          *Uhc;
 | |
|   UINT64              Supports;
 | |
|   UINT64              OriginalPciAttributes;
 | |
|   BOOLEAN             PciAttributesSaved;
 | |
|   EFI_DEVICE_PATH_PROTOCOL  *HcDevicePath;
 | |
| 
 | |
|   //
 | |
|   // Open PCIIO, then enable the EHC device and turn off emulation
 | |
|   //
 | |
|   Uhc = NULL;
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiPciIoProtocolGuid,
 | |
|                   (VOID **) &PciIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Open Device Path Protocol for on USB host controller
 | |
|   //
 | |
|   HcDevicePath = NULL;
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &HcDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
| 
 | |
|   PciAttributesSaved = FALSE;
 | |
|   //
 | |
|   // Save original PCI attributes
 | |
|   //
 | |
|   Status = PciIo->Attributes (
 | |
|                     PciIo,
 | |
|                     EfiPciIoAttributeOperationGet,
 | |
|                     0,
 | |
|                     &OriginalPciAttributes
 | |
|                     );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto CLOSE_PCIIO;
 | |
|   }
 | |
|   PciAttributesSaved = TRUE;
 | |
| 
 | |
|   //
 | |
|   // Robustnesss improvement such as for UoL
 | |
|   // Default is not required.
 | |
|   //
 | |
|   if (FeaturePcdGet (PcdTurnOffUsbLegacySupport)) {
 | |
|     UhciTurnOffUsbEmulation (PciIo);
 | |
|   }
 | |
| 
 | |
|   Status = PciIo->Attributes (
 | |
|                     PciIo,
 | |
|                     EfiPciIoAttributeOperationSupported,
 | |
|                     0,
 | |
|                     &Supports
 | |
|                     );
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
 | |
|     Status = PciIo->Attributes (
 | |
|                       PciIo,
 | |
|                       EfiPciIoAttributeOperationEnable,
 | |
|                       Supports,
 | |
|                       NULL
 | |
|                       );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto CLOSE_PCIIO;
 | |
|   }
 | |
| 
 | |
|   Uhc = UhciAllocateDev (PciIo, HcDevicePath, OriginalPciAttributes);
 | |
| 
 | |
|   if (Uhc == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto CLOSE_PCIIO;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Allocate and Init Host Controller's Frame List Entry
 | |
|   //
 | |
|   Status = UhciInitFrameList (Uhc);
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto FREE_UHC;
 | |
|   }
 | |
| 
 | |
|   Status = gBS->SetTimer (
 | |
|                   Uhc->AsyncIntMonitor,
 | |
|                   TimerPeriodic,
 | |
|                   UHC_ASYNC_POLL_INTERVAL
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto FREE_UHC;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Install USB2_HC_PROTOCOL
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   &Uhc->Usb2Hc,
 | |
|                   NULL
 | |
|                   );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto FREE_UHC;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Create event to stop the HC when exit boot service.
 | |
|   //
 | |
|   Status = gBS->CreateEventEx (
 | |
|                   EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   UhcExitBootService,
 | |
|                   Uhc,
 | |
|                   &gEfiEventExitBootServicesGuid,
 | |
|                   &Uhc->ExitBootServiceEvent
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto UNINSTALL_USBHC;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Install the component name protocol
 | |
|   //
 | |
|   Uhc->CtrlNameTable = NULL;
 | |
| 
 | |
|   AddUnicodeString2 (
 | |
|     "eng",
 | |
|     gUhciComponentName.SupportedLanguages,
 | |
|     &Uhc->CtrlNameTable,
 | |
|     L"Usb Universal Host Controller",
 | |
|     TRUE
 | |
|     );
 | |
|   AddUnicodeString2 (
 | |
|     "en",
 | |
|     gUhciComponentName2.SupportedLanguages,
 | |
|     &Uhc->CtrlNameTable,
 | |
|     L"Usb Universal Host Controller",
 | |
|     FALSE
 | |
|     );
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Start the UHCI hardware, also set its reclamation point to 64 bytes
 | |
|   //
 | |
|   UhciWriteReg (Uhc->PciIo, USBCMD_OFFSET, USBCMD_RS | USBCMD_MAXP);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
|   
 | |
| UNINSTALL_USBHC:
 | |
|   gBS->UninstallMultipleProtocolInterfaces (
 | |
|          Controller,
 | |
|          &gEfiUsb2HcProtocolGuid,
 | |
|          &Uhc->Usb2Hc,
 | |
|          NULL
 | |
|          );
 | |
| 
 | |
| FREE_UHC:
 | |
|   UhciFreeDev (Uhc);
 | |
| 
 | |
| CLOSE_PCIIO:
 | |
|   if (PciAttributesSaved) {
 | |
|     //
 | |
|     // Restore original PCI attributes
 | |
|     //
 | |
|     PciIo->Attributes (
 | |
|                     PciIo,
 | |
|                     EfiPciIoAttributeOperationSet,
 | |
|                     OriginalPciAttributes,
 | |
|                     NULL
 | |
|                     );
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         Controller,
 | |
|         &gEfiPciIoProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Controller
 | |
|         );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|   created by this driver.
 | |
| 
 | |
|   @param  This                 Protocol instance pointer.
 | |
|   @param  Controller           Handle of device to stop driver on.
 | |
|   @param  NumberOfChildren     Number of Children in the ChildHandleBuffer.
 | |
|   @param  ChildHandleBuffer    List of handles for the children we need to stop.
 | |
| 
 | |
|   @return EFI_SUCCESS
 | |
|   @return others
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| UhciDriverBindingStop (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL     *This,
 | |
|   IN EFI_HANDLE                      Controller,
 | |
|   IN UINTN                           NumberOfChildren,
 | |
|   IN EFI_HANDLE                      *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_USB2_HC_PROTOCOL  *Usb2Hc;
 | |
|   EFI_STATUS            Status;
 | |
| 
 | |
|    Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiUsb2HcProtocolGuid,
 | |
|                   (VOID **) &Usb2Hc,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
| 
 | |
|   //
 | |
|   // Test whether the Controller handler passed in is a valid
 | |
|   // Usb controller handle that should be supported, if not,
 | |
|   // return the error status directly
 | |
|   //
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   UhciCleanDevUp (Controller, Usb2Hc);
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|         Controller,
 | |
|         &gEfiPciIoProtocolGuid,
 | |
|         This->DriverBindingHandle,
 | |
|         Controller
 | |
|         );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 |