Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Star Zeng <star.zeng@intel.com> Reviewed-by: Feng Tian <feng.tian@intel.com> git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@15611 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			373 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| The module is used to implement Usb Io PPI interfaces.
 | |
| 
 | |
| Copyright (c) 2006 - 2014, 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 "UsbPeim.h"
 | |
| #include "PeiUsbLib.h"
 | |
| 
 | |
| /**
 | |
|   Submits control transfer to a target USB device.
 | |
|   
 | |
|   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
 | |
|   @param  This                   The pointer of PEI_USB_IO_PPI.
 | |
|   @param  Request                USB device request to send.
 | |
|   @param  Direction              Specifies the data direction for the data stage.
 | |
|   @param  Timeout                Indicates the maximum timeout, in millisecond. If Timeout
 | |
|                                  is 0, then the caller must wait for the function to be
 | |
|                                  completed until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
 | |
|   @param  Data                   Data buffer to be transmitted or received from USB device.
 | |
|   @param  DataLength             The size (in bytes) of the data buffer.
 | |
| 
 | |
|   @retval EFI_SUCCESS            Transfer was completed successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES   The transfer failed due to lack of resources.
 | |
|   @retval EFI_INVALID_PARAMETER  Some parameters are invalid.
 | |
|   @retval EFI_TIMEOUT            Transfer failed due to timeout.
 | |
|   @retval EFI_DEVICE_ERROR       Transfer failed due to host controller or device error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeiUsbControlTransfer (
 | |
|   IN     EFI_PEI_SERVICES          **PeiServices,
 | |
|   IN     PEI_USB_IO_PPI            *This,
 | |
|   IN     EFI_USB_DEVICE_REQUEST    *Request,
 | |
|   IN     EFI_USB_DATA_DIRECTION    Direction,
 | |
|   IN     UINT32                    Timeout,
 | |
|   IN OUT VOID                      *Data,      OPTIONAL
 | |
|   IN     UINTN                     DataLength  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   PEI_USB_DEVICE              *PeiUsbDev;
 | |
|   UINT32                      TransferResult;
 | |
|   EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
 | |
|   UINT8                       EndpointIndex;
 | |
| 
 | |
|   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
 | |
| 
 | |
|   EndpointDescriptor = NULL;
 | |
|   EndpointIndex = 0;
 | |
| 
 | |
|   if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&
 | |
|       (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
 | |
|       (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {
 | |
|     //
 | |
|     // Request->Index is the Endpoint Address, use it to get the Endpoint Index.
 | |
|     //
 | |
|     while (EndpointIndex < MAX_ENDPOINT) {
 | |
|       Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         return EFI_INVALID_PARAMETER;
 | |
|       }
 | |
| 
 | |
|       if (EndpointDescriptor->EndpointAddress == Request->Index) {
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|       EndpointIndex++;
 | |
|     }
 | |
| 
 | |
|     if (EndpointIndex == MAX_ENDPOINT) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (PeiUsbDev->Usb2HcPpi != NULL) {
 | |
|     Status = PeiUsbDev->Usb2HcPpi->ControlTransfer (
 | |
|                         PeiServices,
 | |
|                         PeiUsbDev->Usb2HcPpi,
 | |
|                         PeiUsbDev->DeviceAddress,
 | |
|                         PeiUsbDev->DeviceSpeed,
 | |
|                         PeiUsbDev->MaxPacketSize0,
 | |
|                         Request,
 | |
|                         Direction,
 | |
|                         Data,
 | |
|                         &DataLength,
 | |
|                         Timeout,
 | |
|                         &(PeiUsbDev->Translator),
 | |
|                         &TransferResult
 | |
|                         );
 | |
|   } else {
 | |
|     Status = PeiUsbDev->UsbHcPpi->ControlTransfer (
 | |
|                         PeiServices,
 | |
|                         PeiUsbDev->UsbHcPpi,
 | |
|                         PeiUsbDev->DeviceAddress,
 | |
|                         PeiUsbDev->DeviceSpeed,
 | |
|                         (UINT8) PeiUsbDev->MaxPacketSize0,
 | |
|                         Request,
 | |
|                         Direction,
 | |
|                         Data,
 | |
|                         &DataLength,
 | |
|                         Timeout,
 | |
|                         &TransferResult
 | |
|                         );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Reset the endpoint toggle when endpoint stall is cleared
 | |
|   //
 | |
|   if ((Request->Request     == USB_REQ_CLEAR_FEATURE) &&
 | |
|       (Request->RequestType == USB_DEV_CLEAR_FEATURE_REQ_TYPE_E) &&
 | |
|       (Request->Value       == USB_FEATURE_ENDPOINT_HALT)) {
 | |
|     if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
 | |
|       PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "PeiUsbControlTransfer: %r\n", Status));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Submits bulk transfer to a bulk endpoint of a USB device.
 | |
|   
 | |
|   @param  PeiServices           The pointer of EFI_PEI_SERVICES.
 | |
|   @param  This                  The pointer of PEI_USB_IO_PPI.
 | |
|   @param  DeviceEndpoint        Endpoint number and its direction in bit 7.
 | |
|   @param  Data                  A pointer to the buffer of data to transmit 
 | |
|                                 from or receive into.
 | |
|   @param  DataLength            The lenght of the data buffer.
 | |
|   @param  Timeout               Indicates the maximum time, in millisecond, which the
 | |
|                                 transfer is allowed to complete. If Timeout is 0, then
 | |
|                                 the caller must wait for the function to be completed
 | |
|                                 until EFI_SUCCESS or EFI_DEVICE_ERROR is returned.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The transfer was completed successfully.
 | |
|   @retval EFI_OUT_OF_RESOURCES  The transfer failed due to lack of resource.
 | |
|   @retval EFI_INVALID_PARAMETER Parameters are invalid.
 | |
|   @retval EFI_TIMEOUT           The transfer failed due to timeout.
 | |
|   @retval EFI_DEVICE_ERROR      The transfer failed due to host controller error.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeiUsbBulkTransfer (
 | |
|   IN     EFI_PEI_SERVICES    **PeiServices,
 | |
|   IN     PEI_USB_IO_PPI      *This,
 | |
|   IN     UINT8               DeviceEndpoint,
 | |
|   IN OUT VOID                *Data,
 | |
|   IN OUT UINTN               *DataLength,
 | |
|   IN     UINTN               Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   PEI_USB_DEVICE              *PeiUsbDev;
 | |
|   UINT32                      TransferResult;
 | |
|   UINTN                       MaxPacketLength;
 | |
|   UINT8                       DataToggle;
 | |
|   UINT8                       OldToggle;
 | |
|   EFI_USB_ENDPOINT_DESCRIPTOR *EndpointDescriptor;
 | |
|   UINT8                       EndpointIndex;
 | |
|   VOID                        *Data2[EFI_USB_MAX_BULK_BUFFER_NUM];
 | |
| 
 | |
|   PeiUsbDev     = PEI_USB_DEVICE_FROM_THIS (This);
 | |
| 
 | |
|   EndpointDescriptor = NULL;
 | |
|   EndpointIndex = 0;
 | |
|   Data2[0] = Data;
 | |
|   Data2[1] = NULL;
 | |
| 
 | |
|   while (EndpointIndex < MAX_ENDPOINT) {
 | |
|     Status = PeiUsbGetEndpointDescriptor (PeiServices, This, EndpointIndex, &EndpointDescriptor);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return EFI_INVALID_PARAMETER;
 | |
|     }
 | |
| 
 | |
|     if (EndpointDescriptor->EndpointAddress == DeviceEndpoint) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     EndpointIndex++;
 | |
|   }
 | |
| 
 | |
|   if (EndpointIndex == MAX_ENDPOINT) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   MaxPacketLength = PeiUsbDev->EndpointDesc[EndpointIndex]->MaxPacketSize;
 | |
|   if ((PeiUsbDev->DataToggle & (1 << EndpointIndex)) != 0) {
 | |
|     DataToggle = 1;
 | |
|   } else {
 | |
|     DataToggle = 0;
 | |
|   }
 | |
| 
 | |
|   OldToggle = DataToggle;
 | |
| 
 | |
|   if (PeiUsbDev->Usb2HcPpi != NULL) {
 | |
|     Status = PeiUsbDev->Usb2HcPpi->BulkTransfer (
 | |
|                         PeiServices,
 | |
|                         PeiUsbDev->Usb2HcPpi,
 | |
|                         PeiUsbDev->DeviceAddress,
 | |
|                         DeviceEndpoint,
 | |
|                         PeiUsbDev->DeviceSpeed,
 | |
|                         MaxPacketLength,
 | |
|                         Data2,
 | |
|                         DataLength,
 | |
|                         &DataToggle,
 | |
|                         Timeout,
 | |
|                         &(PeiUsbDev->Translator),
 | |
|                         &TransferResult
 | |
|                         );
 | |
|   } else {
 | |
|     Status = PeiUsbDev->UsbHcPpi->BulkTransfer (
 | |
|                         PeiServices,
 | |
|                         PeiUsbDev->UsbHcPpi,
 | |
|                         PeiUsbDev->DeviceAddress,
 | |
|                         DeviceEndpoint,
 | |
|                         (UINT8) MaxPacketLength,
 | |
|                         Data,
 | |
|                         DataLength,
 | |
|                         &DataToggle,
 | |
|                         Timeout,
 | |
|                         &TransferResult
 | |
|                         );
 | |
|   }
 | |
| 
 | |
|   if (OldToggle != DataToggle) {
 | |
|     PeiUsbDev->DataToggle = (UINT16) (PeiUsbDev->DataToggle ^ (1 << EndpointIndex));
 | |
|   }
 | |
| 
 | |
|   DEBUG ((EFI_D_INFO, "PeiUsbBulkTransfer: %r\n", Status));
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the usb interface descriptor.
 | |
| 
 | |
|   @param  PeiServices          General-purpose services that are available to every PEIM.
 | |
|   @param  This                 Indicates the PEI_USB_IO_PPI instance.
 | |
|   @param  InterfaceDescriptor  Request interface descriptor.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS          Usb interface descriptor is obtained successfully.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeiUsbGetInterfaceDescriptor (
 | |
|   IN  EFI_PEI_SERVICES               **PeiServices,
 | |
|   IN  PEI_USB_IO_PPI                 *This,
 | |
|   OUT EFI_USB_INTERFACE_DESCRIPTOR   **InterfaceDescriptor
 | |
|   )
 | |
| {
 | |
|   PEI_USB_DEVICE  *PeiUsbDev;
 | |
|   PeiUsbDev             = PEI_USB_DEVICE_FROM_THIS (This);
 | |
|   *InterfaceDescriptor  = PeiUsbDev->InterfaceDesc;
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get the usb endpoint descriptor.
 | |
| 
 | |
|   @param  PeiServices          General-purpose services that are available to every PEIM.
 | |
|   @param  This                 Indicates the PEI_USB_IO_PPI instance.
 | |
|   @param  EndpointIndex        The valid index of the specified endpoint.
 | |
|   @param  EndpointDescriptor   Request endpoint descriptor.
 | |
| 
 | |
|   @retval EFI_SUCCESS       Usb endpoint descriptor is obtained successfully.
 | |
|   @retval EFI_NOT_FOUND     Usb endpoint descriptor is NOT found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeiUsbGetEndpointDescriptor (
 | |
|   IN  EFI_PEI_SERVICES               **PeiServices,
 | |
|   IN  PEI_USB_IO_PPI                 *This,
 | |
|   IN  UINT8                          EndpointIndex,
 | |
|   OUT EFI_USB_ENDPOINT_DESCRIPTOR    **EndpointDescriptor
 | |
|   )
 | |
| {
 | |
|   PEI_USB_DEVICE  *PeiUsbDev;
 | |
| 
 | |
|   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
 | |
| 
 | |
|   ASSERT (EndpointDescriptor != NULL);
 | |
| 
 | |
|   //
 | |
|   // The valid range of EndpointIndex is 0..15
 | |
|   // If EndpointIndex is lesser than 15 but larger than the number of interfaces,
 | |
|   // a EFI_NOT_FOUND should be returned
 | |
|   //
 | |
|   ASSERT (EndpointIndex <= 15);
 | |
| 
 | |
|   if (EndpointIndex >= PeiUsbDev->InterfaceDesc->NumEndpoints) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   *EndpointDescriptor = PeiUsbDev->EndpointDesc[EndpointIndex];
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset the port and re-configure the usb device.
 | |
| 
 | |
|   @param  PeiServices    General-purpose services that are available to every PEIM.
 | |
|   @param  This           Indicates the PEI_USB_IO_PPI instance.
 | |
| 
 | |
|   @retval EFI_SUCCESS    Usb device is reset and configured successfully.
 | |
|   @retval Others         Other failure occurs.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PeiUsbPortReset (
 | |
|   IN EFI_PEI_SERVICES               **PeiServices,
 | |
|   IN PEI_USB_IO_PPI                 *This
 | |
|   )
 | |
| {
 | |
|   PEI_USB_DEVICE  *PeiUsbDev;
 | |
|   EFI_STATUS      Status;
 | |
|   UINT8           Address;
 | |
| 
 | |
|   PeiUsbDev = PEI_USB_DEVICE_FROM_THIS (This);
 | |
| 
 | |
|   ResetRootPort (
 | |
|     PeiServices,
 | |
|     PeiUsbDev->UsbHcPpi,
 | |
|     PeiUsbDev->Usb2HcPpi,
 | |
|     PeiUsbDev->DeviceAddress,
 | |
|     0
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Set address
 | |
|   //
 | |
|   Address                   = PeiUsbDev->DeviceAddress;
 | |
|   PeiUsbDev->DeviceAddress  = 0;
 | |
| 
 | |
|   Status = PeiUsbSetDeviceAddress (
 | |
|             PeiServices,
 | |
|             This,
 | |
|             Address
 | |
|             );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   PeiUsbDev->DeviceAddress = Address;
 | |
| 
 | |
|   //
 | |
|   // Set default configuration
 | |
|   //
 | |
|   Status = PeiUsbSetConfiguration (
 | |
|             PeiServices,
 | |
|             This
 | |
|             );
 | |
| 
 | |
|   return Status;
 | |
| }
 |