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
BotRecoveryReset(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev)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
BotCommandPhase(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev,IN VOID * Command,IN UINT8 CommandSize,IN UINT32 DataTransferLength,IN EFI_USB_DATA_DIRECTION Direction,IN UINT16 Timeout)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
BotDataPhase(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev,IN UINT32 * DataSize,IN OUT VOID * DataBuffer,IN EFI_USB_DATA_DIRECTION Direction,IN UINT16 Timeout)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
BotStatusPhase(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev,OUT UINT8 * TransferStatus,IN UINT16 Timeout)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
PeiAtapiCommand(IN EFI_PEI_SERVICES ** PeiServices,IN PEI_BOT_DEVICE * PeiBotDev,IN VOID * Command,IN UINT8 CommandSize,IN VOID * DataBuffer,IN UINT32 BufferLength,IN EFI_USB_DATA_DIRECTION Direction,IN UINT16 TimeOutInMilliSeconds)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