git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7257 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			611 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			611 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Implementation of the USB mass storage Control/Bulk/Interrupt transport,
 | |
|   according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1.
 | |
|   Notice: it is being obsoleted by the standard body in favor of the BOT
 | |
|   (Bulk-Only Transport).
 | |
| 
 | |
| Copyright (c) 2007 - 2008, 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.
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "UsbMassBoot.h"
 | |
| #include "UsbMassCbi.h"
 | |
| 
 | |
| //
 | |
| // Definition of USB CBI0 Transport Protocol
 | |
| //
 | |
| USB_MASS_TRANSPORT mUsbCbi0Transport = {
 | |
|   USB_MASS_STORE_CBI0,
 | |
|   UsbCbiInit,
 | |
|   UsbCbiExecCommand,
 | |
|   UsbCbiResetDevice,
 | |
|   NULL,
 | |
|   UsbCbiCleanUp
 | |
| };
 | |
| 
 | |
| //
 | |
| // Definition of USB CBI1 Transport Protocol
 | |
| //
 | |
| USB_MASS_TRANSPORT mUsbCbi1Transport = {
 | |
|   USB_MASS_STORE_CBI1,
 | |
|   UsbCbiInit,
 | |
|   UsbCbiExecCommand,
 | |
|   UsbCbiResetDevice,
 | |
|   NULL,
 | |
|   UsbCbiCleanUp
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Initializes USB CBI protocol.
 | |
| 
 | |
|   This function initializes the USB mass storage class CBI protocol.
 | |
|   It will save its context which is a USB_CBI_PROTOCOL structure
 | |
|   in the Context if Context isn't NULL.
 | |
| 
 | |
|   @param  UsbIo                 The USB I/O Protocol instance
 | |
|   @param  Context               The buffer to save the context to
 | |
| 
 | |
|   @retval EFI_SUCCESS           The device is successfully initialized.
 | |
|   @retval EFI_UNSUPPORTED       The transport protocol doesn't support the device.
 | |
|   @retval Other                 The USB CBI initialization fails.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiInit (
 | |
|   IN  EFI_USB_IO_PROTOCOL   *UsbIo,
 | |
|   OUT VOID                  **Context       OPTIONAL
 | |
|   )
 | |
| {
 | |
|   USB_CBI_PROTOCOL              *UsbCbi;
 | |
|   EFI_USB_INTERFACE_DESCRIPTOR  *Interface;
 | |
|   EFI_USB_ENDPOINT_DESCRIPTOR   EndPoint;
 | |
|   EFI_STATUS                    Status;
 | |
|   UINT8                         Index;
 | |
| 
 | |
|   //
 | |
|   // Allocate the CBI context for USB_CBI_PROTOCOL and 3 endpoint descriptors.
 | |
|   //
 | |
|   UsbCbi = AllocateZeroPool (
 | |
|              sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)
 | |
|              );
 | |
|   ASSERT (UsbCbi != NULL);
 | |
| 
 | |
|   UsbCbi->UsbIo = UsbIo;
 | |
| 
 | |
|   //
 | |
|   // Get the interface descriptor and validate that it
 | |
|   // is a USB Mass Storage CBI interface.
 | |
|   //
 | |
|   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   Interface = &UsbCbi->Interface;
 | |
|   if ((Interface->InterfaceProtocol != USB_MASS_STORE_CBI0)
 | |
|       && (Interface->InterfaceProtocol != USB_MASS_STORE_CBI1)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Locate and save the bulk-in, bulk-out, and interrupt endpoint
 | |
|   //
 | |
|   for (Index = 0; Index < Interface->NumEndpoints; Index++) {
 | |
|     Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {
 | |
|       //
 | |
|       // Use the first Bulk-In and Bulk-Out endpoints
 | |
|       //
 | |
|       if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&
 | |
|          (UsbCbi->BulkInEndpoint == NULL)) {
 | |
| 
 | |
|         UsbCbi->BulkInEndpoint  = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1);
 | |
|         CopyMem(UsbCbi->BulkInEndpoint, &EndPoint, sizeof (EndPoint));;
 | |
|       }
 | |
| 
 | |
|       if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&
 | |
|          (UsbCbi->BulkOutEndpoint == NULL)) {
 | |
| 
 | |
|         UsbCbi->BulkOutEndpoint   = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1;
 | |
|         CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint));
 | |
|       }
 | |
|     } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) {
 | |
|       //
 | |
|       // Use the first interrupt endpoint if it is CBI0
 | |
|       //
 | |
|       if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) &&
 | |
|           (UsbCbi->InterruptEndpoint == NULL)) {
 | |
| 
 | |
|         UsbCbi->InterruptEndpoint   = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 2;
 | |
|         CopyMem(UsbCbi->InterruptEndpoint, &EndPoint, sizeof (EndPoint));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
|   if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) {
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     goto ON_ERROR;
 | |
|   }
 | |
| 
 | |
|   if (Context != NULL) {
 | |
|     *Context = UsbCbi;
 | |
|   } else {
 | |
|     FreePool (UsbCbi);
 | |
|   }
 | |
|  
 | |
|   return EFI_SUCCESS;
 | |
| 
 | |
| ON_ERROR:
 | |
|   FreePool (UsbCbi);
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Send the command to the device using class specific control transfer.
 | |
| 
 | |
|   This function sends command to the device using class specific control transfer.
 | |
|   The CBI contains three phases: Command, Data, and Status. This is Command phase.
 | |
| 
 | |
|   @param  UsbCbi                The USB CBI protocol
 | |
|   @param  Cmd                   The high level command to transfer to device
 | |
|   @param  CmdLen                The length of the command
 | |
|   @param  Timeout               The time to wait the command to finish
 | |
| 
 | |
|   @retval EFI_SUCCESS           The command is sent to the device.
 | |
|   @retval Others                The command failed to transfer to device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiSendCommand (
 | |
|   IN USB_CBI_PROTOCOL       *UsbCbi,
 | |
|   IN UINT8                  *Cmd,
 | |
|   IN UINT8                  CmdLen,
 | |
|   IN UINT32                 Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_USB_DEVICE_REQUEST  Request;
 | |
|   EFI_STATUS              Status;
 | |
|   UINT32                  TransStatus;
 | |
|   UINTN                   DataLen;
 | |
|   INTN                    Retry;
 | |
| 
 | |
|   //
 | |
|   // Fill in the device request, CBI use the "Accept Device-Specific
 | |
|   // Cmd" (ADSC) class specific request to send commands.
 | |
|   //
 | |
|   Request.RequestType = 0x21;
 | |
|   Request.Request     = 0;
 | |
|   Request.Value       = 0;
 | |
|   Request.Index       = UsbCbi->Interface.InterfaceNumber;
 | |
|   Request.Length      = CmdLen;
 | |
| 
 | |
|   Status              = EFI_SUCCESS;
 | |
|   Timeout             = Timeout / USB_MASS_1_MILLISECOND;
 | |
| 
 | |
|   for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
 | |
|     //
 | |
|     // Use USB I/O Protocol to send the command to the device
 | |
|     //
 | |
|     TransStatus = 0;
 | |
|     DataLen     = CmdLen;
 | |
| 
 | |
|     Status = UsbCbi->UsbIo->UsbControlTransfer (
 | |
|                               UsbCbi->UsbIo,
 | |
|                               &Request,
 | |
|                               EfiUsbDataOut,
 | |
|                               Timeout,
 | |
|                               Cmd,
 | |
|                               DataLen,
 | |
|                               &TransStatus
 | |
|                               );
 | |
|     //
 | |
|     // The device can fail the command by STALL the control endpoint.
 | |
|     // It can delay the command by NAK the data or status stage, this
 | |
|     // is a "class-specific exemption to the USB specification". Retry
 | |
|     // if the command is NAKed.
 | |
|     //
 | |
|     if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Transfer data between the device and host.
 | |
| 
 | |
|   This function transfers data between the device and host.
 | |
|   The CBI contains three phases: Command, Data, and Status. This is Data phase.
 | |
| 
 | |
|   @param  UsbCbi                The USB CBI device
 | |
|   @param  DataDir               The direction of the data transfer
 | |
|   @param  Data                  The buffer to hold the data for input or output.
 | |
|   @param  TransLen              On input, the expected transfer length.
 | |
|                                 On output, the length of data actually transferred.
 | |
|   @param  Timeout               The time to wait for the command to execute
 | |
| 
 | |
|   @retval EFI_SUCCESS           The data transferred successfully.
 | |
|   @retval EFI_SUCCESS           No data to transfer
 | |
|   @retval Others                Failed to transfer all the data
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiDataTransfer (
 | |
|   IN USB_CBI_PROTOCOL         *UsbCbi,
 | |
|   IN EFI_USB_DATA_DIRECTION   DataDir,
 | |
|   IN OUT UINT8                *Data,
 | |
|   IN OUT UINTN                *TransLen,
 | |
|   IN UINT32                   Timeout
 | |
|   )
 | |
| {
 | |
|   EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;
 | |
|   EFI_STATUS                  Status;
 | |
|   UINT32                      TransStatus;
 | |
|   UINTN                       Remain;
 | |
|   UINTN                       Increment;
 | |
|   UINT8                       *Next;
 | |
|   UINTN                       Retry;
 | |
| 
 | |
|   //
 | |
|   // If no data to transfer, just return EFI_SUCCESS.
 | |
|   //
 | |
|   if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Select the endpoint then issue the transfer
 | |
|   //
 | |
|   if (DataDir == EfiUsbDataIn) {
 | |
|     Endpoint = UsbCbi->BulkInEndpoint;
 | |
|   } else {
 | |
|     Endpoint = UsbCbi->BulkOutEndpoint;
 | |
|   }
 | |
| 
 | |
|   Next    = Data;
 | |
|   Remain  = *TransLen;
 | |
|   Retry   = 0;
 | |
|   Status  = EFI_SUCCESS;
 | |
|   Timeout = Timeout / USB_MASS_1_MILLISECOND;
 | |
| 
 | |
|   //
 | |
|   // Transfer the data with a loop. The length of data transferred once is restricted.
 | |
|   //
 | |
|   while (Remain > 0) {
 | |
|     TransStatus = 0;
 | |
| 
 | |
|     if (Remain > (UINTN) USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize) {
 | |
|       Increment = USB_CBI_MAX_PACKET_NUM * Endpoint->MaxPacketSize;
 | |
|     } else {
 | |
|       Increment = Remain;
 | |
|     }
 | |
| 
 | |
|     Status = UsbCbi->UsbIo->UsbBulkTransfer (
 | |
|                               UsbCbi->UsbIo,
 | |
|                               Endpoint->EndpointAddress,
 | |
|                               Next,
 | |
|                               &Increment,
 | |
|                               Timeout,
 | |
|                               &TransStatus
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       if (TransStatus == EFI_USB_ERR_NAK) {
 | |
|         //
 | |
|         // The device can NAK the host if either the data/buffer isn't
 | |
|         // aviable or the command is in-progress.
 | |
|         // If data are partially transferred, we just ignore NAK and continue.
 | |
|         // If all data have been transferred and status is NAK, then we retry for several times.
 | |
|         // If retry exceeds the USB_CBI_MAX_RETRY, then return error status.
 | |
|         //
 | |
|         if (Increment == 0) {
 | |
|           if (++Retry > USB_CBI_MAX_RETRY) {
 | |
|             goto ON_EXIT;
 | |
|           }
 | |
|         } else {
 | |
|           Next   += Increment;
 | |
|           Remain -= Increment;
 | |
|           Retry   = 0;
 | |
|         }
 | |
| 
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // The device can fail the command by STALL the bulk endpoint.
 | |
|       // Clear the stall if that is the case.
 | |
|       //
 | |
|       if (TransStatus == EFI_USB_ERR_STALL) {
 | |
|         UsbClearEndpointStall (UsbCbi->UsbIo, Endpoint->EndpointAddress);
 | |
|       }
 | |
| 
 | |
|       goto ON_EXIT;
 | |
|     }
 | |
| 
 | |
|     Next += Increment;
 | |
|     Remain -= Increment;
 | |
|   }
 | |
| 
 | |
| ON_EXIT:
 | |
|   *TransLen -= Remain;
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Gets the result of high level command execution from interrupt endpoint.
 | |
| 
 | |
|   This function returns the USB transfer status, and put the high level
 | |
|   command execution result in Result.
 | |
|   The CBI contains three phases: Command, Data, and Status. This is Status phase.
 | |
| 
 | |
|   @param  UsbCbi                The USB CBI protocol
 | |
|   @param  Timeout               The time to wait for the command to execute
 | |
|   @param  Result                The result of the command execution.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The high level command execution result is
 | |
|                                 retrieved in Result.
 | |
|   @retval Others                Failed to retrieve the result.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiGetStatus (
 | |
|   IN  USB_CBI_PROTOCOL        *UsbCbi,
 | |
|   IN  UINT32                  Timeout,
 | |
|   OUT USB_CBI_STATUS          *Result
 | |
|   )
 | |
| {
 | |
|   UINTN                     Len;
 | |
|   UINT8                     Endpoint;
 | |
|   EFI_STATUS                Status;
 | |
|   UINT32                    TransStatus;
 | |
|   INTN                      Retry;
 | |
| 
 | |
|   Endpoint  = UsbCbi->InterruptEndpoint->EndpointAddress;
 | |
|   Status    = EFI_SUCCESS;
 | |
|   Timeout   = Timeout / USB_MASS_1_MILLISECOND;
 | |
| 
 | |
|   //
 | |
|   // Attemp to the read the result from interrupt endpoint
 | |
|   //
 | |
|   for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) {
 | |
|     TransStatus = 0;
 | |
|     Len         = sizeof (USB_CBI_STATUS);
 | |
| 
 | |
|     Status = UsbCbi->UsbIo->UsbSyncInterruptTransfer (
 | |
|                               UsbCbi->UsbIo,
 | |
|                               Endpoint,
 | |
|                               Result,
 | |
|                               &Len,
 | |
|                               Timeout,
 | |
|                               &TransStatus
 | |
|                               );
 | |
|     //
 | |
|     // The CBI can NAK the interrupt endpoint if the command is in-progress.
 | |
|     //
 | |
|     if (EFI_ERROR (Status) && (TransStatus == EFI_USB_ERR_NAK)) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Execute USB mass storage command through the CBI0/CBI1 transport protocol.
 | |
| 
 | |
|   @param  Context               The USB CBI Protocol.
 | |
|   @param  Cmd                   The command to transfer to device
 | |
|   @param  CmdLen                The length of the command
 | |
|   @param  DataDir               The direction of data transfer
 | |
|   @param  Data                  The buffer to hold the data
 | |
|   @param  DataLen               The length of the buffer
 | |
|   @param  Lun                   Should be 0, this field for bot only
 | |
|   @param  Timeout               The time to wait
 | |
|   @param  CmdStatus             The result of the command execution
 | |
| 
 | |
|   @retval EFI_SUCCESS           The command is executed successfully.
 | |
|   @retval Other                 Failed to execute the command
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiExecCommand (
 | |
|   IN  VOID                    *Context,
 | |
|   IN  VOID                    *Cmd,
 | |
|   IN  UINT8                   CmdLen,
 | |
|   IN  EFI_USB_DATA_DIRECTION  DataDir,
 | |
|   IN  VOID                    *Data,
 | |
|   IN  UINT32                  DataLen,
 | |
|   IN  UINT8                   Lun,
 | |
|   IN  UINT32                  Timeout,
 | |
|   OUT UINT32                  *CmdStatus
 | |
|   )
 | |
| {
 | |
|   USB_CBI_PROTOCOL          *UsbCbi;
 | |
|   USB_CBI_STATUS            Result;
 | |
|   EFI_STATUS                Status;
 | |
|   UINTN                     TransLen;
 | |
| 
 | |
|   *CmdStatus  = USB_MASS_CMD_SUCCESS;
 | |
|   UsbCbi      = (USB_CBI_PROTOCOL *) Context;
 | |
| 
 | |
|   //
 | |
|   // Send the command to the device. Return immediately if device
 | |
|   // rejects the command.
 | |
|   //
 | |
|   Status = UsbCbiSendCommand (UsbCbi, Cmd, CmdLen, Timeout);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Transfer the data. Return this status if no interrupt endpoint
 | |
|   // is used to report the transfer status.
 | |
|   //
 | |
|   TransLen = (UINTN) DataLen;
 | |
| 
 | |
|   Status   = UsbCbiDataTransfer (UsbCbi, DataDir, Data, &TransLen, Timeout);
 | |
|   if (UsbCbi->InterruptEndpoint == NULL) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Get the status. If it succeeds, interpret the result.
 | |
|   //
 | |
|   Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status));
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) {
 | |
|     //
 | |
|     // For UFI device, ASC and ASCQ are returned.
 | |
|     //
 | |
|     if (Result.Type != 0) {
 | |
|       *CmdStatus = USB_MASS_CMD_FAIL;
 | |
|     }
 | |
| 
 | |
|   } else {
 | |
|     //
 | |
|     // Check page 27, CBI spec 1.1 for vaious reture status.
 | |
|     //
 | |
|     switch (Result.Value & 0x03) {
 | |
|     case 0x00:
 | |
|       //
 | |
|       // Pass
 | |
|       //
 | |
|       *CmdStatus = USB_MASS_CMD_SUCCESS;
 | |
|       break;
 | |
| 
 | |
|     case 0x02:
 | |
|       //
 | |
|       // Phase Error, response with reset.
 | |
|       // No break here to fall through to "Fail".
 | |
|       //
 | |
|       UsbCbiResetDevice (UsbCbi, FALSE);
 | |
| 
 | |
|     case 0x01:
 | |
|       //
 | |
|       // Fail
 | |
|       //
 | |
|       *CmdStatus = USB_MASS_CMD_FAIL;
 | |
|       break;
 | |
| 
 | |
|     case 0x03:
 | |
|       //
 | |
|       // Persistent Fail. Need to send REQUEST SENSE.
 | |
|       //
 | |
|       *CmdStatus = USB_MASS_CMD_PERSISTENT;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Reset the USB mass storage device by CBI protocol.
 | |
| 
 | |
|   This function resets the USB mass storage device by CBI protocol.
 | |
|   The reset is defined as a non-data command. Don't use UsbCbiExecCommand
 | |
|   to send the command to device because that may introduce recursive loop.
 | |
| 
 | |
|   @param  Context               The USB CBI protocol
 | |
|   @param  ExtendedVerification  The flag controlling the rule of reset.
 | |
|                                 Not used here.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The device is reset.
 | |
|   @retval Others                Failed to reset the device.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiResetDevice (
 | |
|   IN  VOID                    *Context,
 | |
|   IN  BOOLEAN                  ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   UINT8                     ResetCmd[USB_CBI_RESET_CMD_LEN];
 | |
|   USB_CBI_PROTOCOL          *UsbCbi;
 | |
|   USB_CBI_STATUS            Result;
 | |
|   EFI_STATUS                Status;
 | |
|   UINT32                    Timeout;
 | |
| 
 | |
|   UsbCbi = (USB_CBI_PROTOCOL *) Context;
 | |
| 
 | |
|   //
 | |
|   // Fill in the reset command.
 | |
|   //
 | |
|   SetMem (ResetCmd, USB_CBI_RESET_CMD_LEN, 0xFF);
 | |
| 
 | |
|   ResetCmd[0] = 0x1D;
 | |
|   ResetCmd[1] = 0x04;
 | |
|   Timeout     = USB_CBI_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;
 | |
| 
 | |
|   //
 | |
|   // Send the command to the device. Don't use UsbCbiExecCommand here.
 | |
|   //
 | |
|   Status = UsbCbiSendCommand (UsbCbi, ResetCmd, USB_CBI_RESET_CMD_LEN, Timeout);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Just retrieve the status and ignore that. Then stall
 | |
|   // 50ms to wait for it to complete.
 | |
|   //
 | |
|   UsbCbiGetStatus (UsbCbi, Timeout, &Result);
 | |
|   gBS->Stall (USB_CBI_RESET_DEVICE_STALL);
 | |
| 
 | |
|   //
 | |
|   // Clear the Bulk-In and Bulk-Out stall condition and init data toggle.
 | |
|   //
 | |
|   UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress);
 | |
|   UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| 
 | |
| /**
 | |
|   Clean up the CBI protocol's resource.
 | |
| 
 | |
|   @param  Context               The instance of CBI protocol.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The resource is cleaned up.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| UsbCbiCleanUp (
 | |
|   IN  VOID                   *Context
 | |
|   )
 | |
| {
 | |
|   FreePool (Context);
 | |
|   return EFI_SUCCESS;
 | |
| }
 |