Home | History | Annotate | Download | only in UsbBotPei
      1 /** @file
      2 BOT Transportation implementation.
      3 
      4 Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
      5 
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions
      8 of the BSD License which accompanies this distribution.  The
      9 full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "UsbBotPeim.h"
     18 #include "BotPeim.h"
     19 #include "PeiUsbLib.h"
     20 
     21 /**
     22   Reset the given usb device.
     23 
     24   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
     25   @param  PeiBotDev              The instance to PEI_BOT_DEVICE.
     26 
     27   @retval EFI_INVALID_PARAMETER  Can not get usb io ppi.
     28   @retval EFI_SUCCESS            Failed to reset the given usb device.
     29 
     30 **/
     31 EFI_STATUS
     32 BotRecoveryReset (
     33   IN  EFI_PEI_SERVICES          **PeiServices,
     34   IN  PEI_BOT_DEVICE            *PeiBotDev
     35   )
     36 {
     37   EFI_USB_DEVICE_REQUEST  DevReq;
     38   UINT32                  Timeout;
     39   PEI_USB_IO_PPI          *UsbIoPpi;
     40   UINT8                   EndpointAddr;
     41   EFI_STATUS              Status;
     42 
     43   UsbIoPpi = PeiBotDev->UsbIoPpi;
     44 
     45   if (UsbIoPpi == NULL) {
     46     return EFI_INVALID_PARAMETER;
     47   }
     48 
     49   ZeroMem (&DevReq, sizeof (EFI_USB_DEVICE_REQUEST));
     50 
     51   DevReq.RequestType  = 0x21;
     52   DevReq.Request      = 0xFF;
     53   DevReq.Value        = 0;
     54   DevReq.Index        = 0;
     55   DevReq.Length       = 0;
     56 
     57   Timeout             = 3000;
     58 
     59   Status = UsbIoPpi->UsbControlTransfer (
     60                       PeiServices,
     61                       UsbIoPpi,
     62                       &DevReq,
     63                       EfiUsbNoData,
     64                       Timeout,
     65                       NULL,
     66                       0
     67                       );
     68 
     69   //
     70   // clear bulk in endpoint stall feature
     71   //
     72   EndpointAddr = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
     73   PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
     74 
     75   //
     76   // clear bulk out endpoint stall feature
     77   //
     78   EndpointAddr = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
     79   PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
     80 
     81   return Status;
     82 }
     83 
     84 /**
     85   Send the command to the device using Bulk-Out endpoint.
     86 
     87   This function sends the command to the device using Bulk-Out endpoint.
     88   BOT transfer is composed of three phases: Command, Data, and Status.
     89   This is the Command phase.
     90 
     91   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
     92   @param  PeiBotDev              The instance to PEI_BOT_DEVICE.
     93   @param  Command                The command to transfer to device.
     94   @param  CommandSize            The length of the command.
     95   @param  DataTransferLength     The expected length of the data.
     96   @param  Direction              The direction of the data.
     97   @param  Timeout                Indicates the maximum time, in millisecond, which the
     98                                  transfer is allowed to complete.
     99 
    100   @retval EFI_DEVICE_ERROR       Successful to send the command to device.
    101   @retval EFI_SUCCESS            Failed to send the command to device.
    102 
    103 **/
    104 EFI_STATUS
    105 BotCommandPhase (
    106   IN  EFI_PEI_SERVICES          **PeiServices,
    107   IN  PEI_BOT_DEVICE            *PeiBotDev,
    108   IN  VOID                      *Command,
    109   IN  UINT8                     CommandSize,
    110   IN  UINT32                    DataTransferLength,
    111   IN  EFI_USB_DATA_DIRECTION    Direction,
    112   IN  UINT16                    Timeout
    113   )
    114 {
    115   CBW             Cbw;
    116   EFI_STATUS      Status;
    117   PEI_USB_IO_PPI  *UsbIoPpi;
    118   UINTN           DataSize;
    119 
    120   UsbIoPpi = PeiBotDev->UsbIoPpi;
    121 
    122   ZeroMem (&Cbw, sizeof (CBW));
    123 
    124   //
    125   // Fill the command block, detailed see BOT spec
    126   //
    127   Cbw.Signature           = CBWSIG;
    128   Cbw.Tag                 = 0x01;
    129   Cbw.DataTransferLength  = DataTransferLength;
    130   Cbw.Flags               = (UINT8) ((Direction == EfiUsbDataIn) ? 0x80 : 0);
    131   Cbw.Lun                 = 0;
    132   Cbw.CmdLen              = CommandSize;
    133 
    134   CopyMem (Cbw.CmdBlock, Command, CommandSize);
    135 
    136   DataSize = sizeof (CBW);
    137 
    138   Status = UsbIoPpi->UsbBulkTransfer (
    139                       PeiServices,
    140                       UsbIoPpi,
    141                       (PeiBotDev->BulkOutEndpoint)->EndpointAddress,
    142                       (UINT8 *) &Cbw,
    143                       &DataSize,
    144                       Timeout
    145                       );
    146   if (EFI_ERROR (Status)) {
    147     //
    148     // Command phase fail, we need to recovery reset this device
    149     //
    150     BotRecoveryReset (PeiServices, PeiBotDev);
    151     return EFI_DEVICE_ERROR;
    152   }
    153 
    154   return EFI_SUCCESS;
    155 }
    156 
    157 /**
    158   Transfer the data between the device and host.
    159 
    160   This function transfers the data between the device and host.
    161   BOT transfer is composed of three phases: Command, Data, and Status.
    162   This is the Data phase.
    163 
    164   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
    165   @param  PeiBotDev              The instance to PEI_BOT_DEVICE.
    166   @param  DataSize               The length of the data.
    167   @param  DataBuffer             The pointer to the data.
    168   @param  Direction              The direction of the data.
    169   @param  Timeout                Indicates the maximum time, in millisecond, which the
    170                                  transfer is allowed to complete.
    171 
    172   @retval EFI_DEVICE_ERROR       Successful to send the data to device.
    173   @retval EFI_SUCCESS            Failed to send the data to device.
    174 
    175 **/
    176 EFI_STATUS
    177 BotDataPhase (
    178   IN  EFI_PEI_SERVICES          **PeiServices,
    179   IN  PEI_BOT_DEVICE            *PeiBotDev,
    180   IN  UINT32                    *DataSize,
    181   IN  OUT VOID                  *DataBuffer,
    182   IN  EFI_USB_DATA_DIRECTION    Direction,
    183   IN  UINT16                    Timeout
    184   )
    185 {
    186   EFI_STATUS      Status;
    187   PEI_USB_IO_PPI  *UsbIoPpi;
    188   UINT8           EndpointAddr;
    189   UINTN           Remain;
    190   UINTN           Increment;
    191   UINT32          MaxPacketLen;
    192   UINT8           *BufferPtr;
    193   UINTN           TransferredSize;
    194 
    195   UsbIoPpi        = PeiBotDev->UsbIoPpi;
    196 
    197   Remain          = *DataSize;
    198   BufferPtr       = (UINT8 *) DataBuffer;
    199   TransferredSize = 0;
    200 
    201   //
    202   // retrieve the the max packet length of the given endpoint
    203   //
    204   if (Direction == EfiUsbDataIn) {
    205     MaxPacketLen  = (PeiBotDev->BulkInEndpoint)->MaxPacketSize;
    206     EndpointAddr  = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
    207   } else {
    208     MaxPacketLen  = (PeiBotDev->BulkOutEndpoint)->MaxPacketSize;
    209     EndpointAddr  = (PeiBotDev->BulkOutEndpoint)->EndpointAddress;
    210   }
    211 
    212   while (Remain > 0) {
    213     //
    214     // Using 15 packets to avoid Bitstuff error
    215     //
    216     if (Remain > 16 * MaxPacketLen) {
    217       Increment = 16 * MaxPacketLen;
    218     } else {
    219       Increment = Remain;
    220     }
    221 
    222     Status = UsbIoPpi->UsbBulkTransfer (
    223                         PeiServices,
    224                         UsbIoPpi,
    225                         EndpointAddr,
    226                         BufferPtr,
    227                         &Increment,
    228                         Timeout
    229                         );
    230 
    231     TransferredSize += Increment;
    232 
    233     if (EFI_ERROR (Status)) {
    234       PeiUsbClearEndpointHalt (PeiServices, UsbIoPpi, EndpointAddr);
    235       return Status;
    236     }
    237 
    238     BufferPtr += Increment;
    239     Remain -= Increment;
    240   }
    241 
    242   *DataSize = (UINT32) TransferredSize;
    243 
    244   return EFI_SUCCESS;
    245 }
    246 
    247 /**
    248   Get the command execution status from device.
    249 
    250   This function gets the command execution status from device.
    251   BOT transfer is composed of three phases: Command, Data, and Status.
    252   This is the Status phase.
    253 
    254   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
    255   @param  PeiBotDev              The instance to PEI_BOT_DEVICE.
    256   @param  TransferStatus         The status of the transaction.
    257   @param  Timeout                Indicates the maximum time, in millisecond, which the
    258                                  transfer is allowed to complete.
    259 
    260   @retval EFI_DEVICE_ERROR       Successful to get the status of device.
    261   @retval EFI_SUCCESS            Failed to get the status of device.
    262 
    263 **/
    264 EFI_STATUS
    265 BotStatusPhase (
    266   IN  EFI_PEI_SERVICES          **PeiServices,
    267   IN  PEI_BOT_DEVICE            *PeiBotDev,
    268   OUT UINT8                     *TransferStatus,
    269   IN  UINT16                    Timeout
    270   )
    271 {
    272   CSW             Csw;
    273   EFI_STATUS      Status;
    274   PEI_USB_IO_PPI  *UsbIoPpi;
    275   UINT8           EndpointAddr;
    276   UINTN           DataSize;
    277 
    278   UsbIoPpi = PeiBotDev->UsbIoPpi;
    279 
    280   ZeroMem (&Csw, sizeof (CSW));
    281 
    282   EndpointAddr  = (PeiBotDev->BulkInEndpoint)->EndpointAddress;
    283 
    284   DataSize      = sizeof (CSW);
    285 
    286   //
    287   // Get the status field from bulk transfer
    288   //
    289   Status = UsbIoPpi->UsbBulkTransfer (
    290                       PeiServices,
    291                       UsbIoPpi,
    292                       EndpointAddr,
    293                       &Csw,
    294                       &DataSize,
    295                       Timeout
    296                       );
    297   if (EFI_ERROR (Status)) {
    298     return Status;
    299   }
    300 
    301   if (Csw.Signature == CSWSIG) {
    302     *TransferStatus = Csw.Status;
    303   } else {
    304     return EFI_DEVICE_ERROR;
    305   }
    306 
    307   return EFI_SUCCESS;
    308 }
    309 
    310 /**
    311   Send ATAPI command using BOT protocol.
    312 
    313   @param  PeiServices            The pointer of EFI_PEI_SERVICES.
    314   @param  PeiBotDev              The instance to PEI_BOT_DEVICE.
    315   @param  Command                The command to be sent to ATAPI device.
    316   @param  CommandSize            The length of the data to be sent.
    317   @param  DataBuffer             The pointer to the data.
    318   @param  BufferLength           The length of the data.
    319   @param  Direction              The direction of the data.
    320   @param  TimeOutInMilliSeconds  Indicates the maximum time, in millisecond, which the
    321                                  transfer is allowed to complete.
    322 
    323   @retval EFI_DEVICE_ERROR       Successful to get the status of device.
    324   @retval EFI_SUCCESS            Failed to get the status of device.
    325 
    326 **/
    327 EFI_STATUS
    328 PeiAtapiCommand (
    329   IN  EFI_PEI_SERVICES            **PeiServices,
    330   IN  PEI_BOT_DEVICE              *PeiBotDev,
    331   IN  VOID                        *Command,
    332   IN  UINT8                       CommandSize,
    333   IN  VOID                        *DataBuffer,
    334   IN  UINT32                      BufferLength,
    335   IN  EFI_USB_DATA_DIRECTION      Direction,
    336   IN  UINT16                      TimeOutInMilliSeconds
    337   )
    338 {
    339   EFI_STATUS  Status;
    340   EFI_STATUS  BotDataStatus;
    341   UINT8       TransferStatus;
    342   UINT32      BufferSize;
    343 
    344   BotDataStatus = EFI_SUCCESS;
    345   //
    346   // First send ATAPI command through Bot
    347   //
    348   Status = BotCommandPhase (
    349             PeiServices,
    350             PeiBotDev,
    351             Command,
    352             CommandSize,
    353             BufferLength,
    354             Direction,
    355             TimeOutInMilliSeconds
    356             );
    357 
    358   if (EFI_ERROR (Status)) {
    359     return EFI_DEVICE_ERROR;
    360   }
    361   //
    362   // Send/Get Data if there is a Data Stage
    363   //
    364   switch (Direction) {
    365   case EfiUsbDataIn:
    366   case EfiUsbDataOut:
    367     BufferSize = BufferLength;
    368 
    369     BotDataStatus = BotDataPhase (
    370                       PeiServices,
    371                       PeiBotDev,
    372                       &BufferSize,
    373                       DataBuffer,
    374                       Direction,
    375                       TimeOutInMilliSeconds
    376                       );
    377     break;
    378 
    379   case EfiUsbNoData:
    380     break;
    381   }
    382   //
    383   // Status Phase
    384   //
    385   Status = BotStatusPhase (
    386             PeiServices,
    387             PeiBotDev,
    388             &TransferStatus,
    389             TimeOutInMilliSeconds
    390             );
    391   if (EFI_ERROR (Status)) {
    392     BotRecoveryReset (PeiServices, PeiBotDev);
    393     return EFI_DEVICE_ERROR;
    394   }
    395 
    396   if (TransferStatus == 0x01) {
    397     return EFI_DEVICE_ERROR;
    398   }
    399 
    400   return BotDataStatus;
    401 }
    402