[Description]:
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Bus / Usb / UsbMassStorageDxe / UsbMassBot.c
1 /** @file\r
2 \r
3 Copyright (c) 2007 - 2008, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14   UsbMassBot.c\r
15 \r
16 Abstract:\r
17 \r
18   Implementation of the USB mass storage Bulk-Only Transport protocol.\r
19 \r
20 Revision History\r
21 \r
22 \r
23 **/\r
24 \r
25 #include "UsbMass.h"\r
26 #include "UsbMassBot.h"\r
27 \r
28 STATIC\r
29 EFI_STATUS\r
30 UsbBotResetDevice (\r
31   IN  VOID                    *Context,\r
32   IN  BOOLEAN                  ExtendedVerification\r
33   );\r
34 \r
35 \r
36 /**\r
37   Initialize the USB mass storage class BOT transport protocol.\r
38   It will save its context which is a USB_BOT_PROTOCOL structure\r
39   in the Context if Context isn't NULL.\r
40 \r
41   @param  UsbIo                 The USB IO protocol to use\r
42   @param  Context               The variable to save the context to\r
43 \r
44   @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory\r
45   @retval EFI_UNSUPPORTED       The transport protocol doesn't support the device.\r
46   @retval EFI_SUCCESS           The device is supported and protocol initialized.\r
47 \r
48 **/\r
49 STATIC\r
50 EFI_STATUS\r
51 UsbBotInit (\r
52   IN  EFI_USB_IO_PROTOCOL       * UsbIo,\r
53   OUT VOID                      **Context OPTIONAL\r
54   )\r
55 {\r
56   USB_BOT_PROTOCOL              *UsbBot;\r
57   EFI_USB_INTERFACE_DESCRIPTOR  *Interface;\r
58   EFI_USB_ENDPOINT_DESCRIPTOR   EndPoint;\r
59   EFI_STATUS                    Status;\r
60   UINT8                         Index;\r
61 \r
62   //\r
63   // Allocate the BOT context, append two endpoint descriptors to it\r
64   //\r
65   UsbBot = AllocateZeroPool (\r
66              sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR)\r
67              );\r
68   if (UsbBot == NULL) {\r
69     return EFI_OUT_OF_RESOURCES;\r
70   }\r
71 \r
72   UsbBot->UsbIo = UsbIo;\r
73 \r
74   //\r
75   // Get the interface descriptor and validate that it\r
76   // is a USB MSC BOT interface.\r
77   //\r
78   Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface);\r
79 \r
80   if (EFI_ERROR (Status)) {\r
81     DEBUG ((EFI_D_ERROR, "UsbBotInit: Get invalid BOT interface (%r)\n", Status));\r
82     goto ON_ERROR;\r
83   }\r
84 \r
85   Interface = &UsbBot->Interface;\r
86 \r
87   if (Interface->InterfaceProtocol != USB_MASS_STORE_BOT) {\r
88     Status = EFI_UNSUPPORTED;\r
89     goto ON_ERROR;\r
90   }\r
91 \r
92   //\r
93   // Locate and save the first bulk-in and bulk-out endpoint\r
94   //\r
95   for (Index = 0; Index < Interface->NumEndpoints; Index++) {\r
96     Status = UsbIo->UsbGetEndpointDescriptor (UsbIo, Index, &EndPoint);\r
97 \r
98     if (EFI_ERROR (Status) || !USB_IS_BULK_ENDPOINT (EndPoint.Attributes)) {\r
99       continue;\r
100     }\r
101 \r
102     if (USB_IS_IN_ENDPOINT (EndPoint.EndpointAddress) &&\r
103        (UsbBot->BulkInEndpoint == NULL)) {\r
104 \r
105       UsbBot->BulkInEndpoint  = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1);\r
106       CopyMem(UsbBot->BulkInEndpoint, &EndPoint, sizeof (EndPoint));\r
107     }\r
108 \r
109     if (USB_IS_OUT_ENDPOINT (EndPoint.EndpointAddress) &&\r
110        (UsbBot->BulkOutEndpoint == NULL)) {\r
111 \r
112       UsbBot->BulkOutEndpoint   = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbBot + 1) + 1;\r
113       CopyMem(UsbBot->BulkOutEndpoint, &EndPoint, sizeof(EndPoint));\r
114     }\r
115   }\r
116 \r
117   if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) {\r
118     DEBUG ((EFI_D_ERROR, "UsbBotInit: In/Out Endpoint invalid\n"));\r
119     Status = EFI_UNSUPPORTED;\r
120     goto ON_ERROR;\r
121   }\r
122 \r
123   //\r
124   // The USB BOT protocol uses dCBWTag to match the CBW and CSW.\r
125   //\r
126   UsbBot->CbwTag = 0x01;\r
127 \r
128   if (Context != NULL) {\r
129     *Context = UsbBot;\r
130   } else {\r
131     gBS->FreePool (UsbBot);\r
132   }\r
133 \r
134   return EFI_SUCCESS;\r
135 \r
136 ON_ERROR:\r
137   gBS->FreePool (UsbBot);\r
138   return Status;\r
139 }\r
140 \r
141 \r
142 /**\r
143   Send the command to the device using Bulk-Out endpoint\r
144 \r
145   @param  UsbBot                The USB BOT device\r
146   @param  Cmd                   The command to transfer to device\r
147   @param  CmdLen                the length of the command\r
148   @param  DataDir               The direction of the data\r
149   @param  TransLen              The expected length of the data\r
150   @param  Lun                   The number of logic unit\r
151 \r
152   @retval EFI_NOT_READY         The device return NAK to the transfer\r
153   @retval EFI_SUCCESS           The command is sent to the device.\r
154   @retval Others                Failed to send the command to device\r
155 \r
156 **/\r
157 STATIC\r
158 EFI_STATUS\r
159 UsbBotSendCommand (\r
160   IN USB_BOT_PROTOCOL         *UsbBot,\r
161   IN UINT8                    *Cmd,\r
162   IN UINT8                    CmdLen,\r
163   IN EFI_USB_DATA_DIRECTION   DataDir,\r
164   IN UINT32                   TransLen,\r
165   IN UINT8                    Lun\r
166   )\r
167 {\r
168   USB_BOT_CBW               Cbw;\r
169   EFI_STATUS                Status;\r
170   UINT32                    Result;\r
171   UINTN                     DataLen;\r
172   UINTN                     Timeout;\r
173 \r
174   ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN));\r
175 \r
176   //\r
177   // Fill in the CSW. Only the first LUN is supported now.\r
178   //\r
179   Cbw.Signature = USB_BOT_CBW_SIGNATURE;\r
180   Cbw.Tag       = UsbBot->CbwTag;\r
181   Cbw.DataLen   = TransLen;\r
182   Cbw.Flag      = (UINT8) ((DataDir == EfiUsbDataIn) ? 0x80 : 0);\r
183   Cbw.Lun       = Lun;\r
184   Cbw.CmdLen    = CmdLen;\r
185 \r
186   ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN);\r
187   CopyMem (Cbw.CmdBlock, Cmd, CmdLen);\r
188 \r
189   Result        = 0;\r
190   DataLen       = sizeof (USB_BOT_CBW);\r
191   Timeout       = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND;\r
192 \r
193   //\r
194   // Use the UsbIo to send the command to the device. The default\r
195   // time out is enough.\r
196   //\r
197   Status = UsbBot->UsbIo->UsbBulkTransfer (\r
198                             UsbBot->UsbIo,\r
199                             UsbBot->BulkOutEndpoint->EndpointAddress,\r
200                             &Cbw,\r
201                             &DataLen,\r
202                             Timeout,\r
203                             &Result\r
204                             );\r
205   //\r
206   // Respond to Bulk-Out endpoint stall with a Reset Recovery,\r
207   // see the spec section 5.3.1\r
208   //\r
209   if (EFI_ERROR (Status)) {\r
210     if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) {\r
211       UsbBotResetDevice (UsbBot, FALSE);\r
212     } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {\r
213       Status = EFI_NOT_READY;\r
214     }\r
215   }\r
216 \r
217   return Status;\r
218 }\r
219 \r
220 \r
221 /**\r
222   Transfer the data between the device and host. BOT transfer\r
223   is composed of three phase, command, data, and status.\r
224 \r
225   @param  UsbBot                The USB BOT device\r
226   @param  DataDir               The direction of the data\r
227   @param  Data                  The buffer to hold data\r
228   @param  TransLen              The expected length of the data\r
229   @param  Timeout               The time to wait the command to complete\r
230 \r
231   @retval EFI_SUCCESS           The data is transferred\r
232   @retval Others                Failed to transfer data\r
233 \r
234 **/\r
235 STATIC\r
236 EFI_STATUS\r
237 UsbBotDataTransfer (\r
238   IN USB_BOT_PROTOCOL         *UsbBot,\r
239   IN EFI_USB_DATA_DIRECTION   DataDir,\r
240   IN OUT UINT8                *Data,\r
241   IN OUT UINTN                *TransLen,\r
242   IN UINT32                   Timeout\r
243   )\r
244 {\r
245   EFI_USB_ENDPOINT_DESCRIPTOR *Endpoint;\r
246   EFI_STATUS                  Status;\r
247   UINT32                      Result;\r
248 \r
249   //\r
250   // It's OK if no data to transfer\r
251   //\r
252   if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) {\r
253     return EFI_SUCCESS;\r
254   }\r
255 \r
256   //\r
257   // Select the endpoint then issue the transfer\r
258   //\r
259   if (DataDir == EfiUsbDataIn) {\r
260     Endpoint = UsbBot->BulkInEndpoint;\r
261   } else {\r
262     Endpoint = UsbBot->BulkOutEndpoint;\r
263   }\r
264 \r
265   Result  = 0;\r
266   Timeout = Timeout / USB_MASS_1_MILLISECOND;\r
267 \r
268   Status = UsbBot->UsbIo->UsbBulkTransfer (\r
269                             UsbBot->UsbIo,\r
270                             Endpoint->EndpointAddress,\r
271                             Data,\r
272                             TransLen,\r
273                             Timeout,\r
274                             &Result\r
275                             );\r
276   if (EFI_ERROR (Status)) {\r
277     DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status));\r
278     if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {\r
279       DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: DataIn Stall\n"));\r
280       UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress);\r
281     } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) {\r
282       Status = EFI_NOT_READY;\r
283     }\r
284   }\r
285 \r
286   return Status;\r
287 }\r
288 \r
289 \r
290 /**\r
291   Get the command execution status from device. BOT transfer is\r
292   composed of three phase, command, data, and status.\r
293   This function return the transfer status of the BOT's CSW status,\r
294   and return the high level command execution result in Result. So\r
295   even it returns EFI_SUCCESS, the command may still have failed.\r
296 \r
297   @param  UsbBot                The USB BOT device\r
298   @param  TransLen              The expected length of the data\r
299   @param  Timeout               The time to wait the command to complete\r
300   @param  CmdStatus             The result of the command execution.\r
301 \r
302   @retval EFI_DEVICE_ERROR      Failed to retrieve the command execute result\r
303   @retval EFI_SUCCESS           Command execute result is retrieved and in the\r
304                                 Result.\r
305 \r
306 **/\r
307 STATIC\r
308 EFI_STATUS\r
309 UsbBotGetStatus (\r
310   IN  USB_BOT_PROTOCOL      *UsbBot,\r
311   IN  UINT32                TransLen,\r
312   OUT UINT8                 *CmdStatus\r
313   )\r
314 {\r
315   USB_BOT_CSW               Csw;\r
316   UINTN                     Len;\r
317   UINT8                     Endpoint;\r
318   EFI_STATUS                Status;\r
319   UINT32                    Result;\r
320   EFI_USB_IO_PROTOCOL       *UsbIo;\r
321   UINT32                    Index;\r
322   UINTN                     Timeout;\r
323 \r
324   *CmdStatus = USB_BOT_COMMAND_ERROR;\r
325   Status     = EFI_DEVICE_ERROR;\r
326   Endpoint   = UsbBot->BulkInEndpoint->EndpointAddress;\r
327   UsbIo      = UsbBot->UsbIo;\r
328   Timeout    = USB_BOT_RECV_CSW_TIMEOUT / USB_MASS_1_MILLISECOND;\r
329 \r
330   for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) {\r
331     //\r
332     // Attemp to the read CSW from bulk in endpoint\r
333     //\r
334     ZeroMem (&Csw, sizeof (USB_BOT_CSW));\r
335     Result = 0;\r
336     Len    = sizeof (USB_BOT_CSW);\r
337     Status = UsbIo->UsbBulkTransfer (\r
338                       UsbIo,\r
339                       Endpoint,\r
340                       &Csw,\r
341                       &Len,\r
342                       Timeout,\r
343                       &Result\r
344                       );\r
345     if (EFI_ERROR(Status)) {\r
346       DEBUG ((EFI_D_ERROR, "UsbBotGetStatus (%r)\n", Status));\r
347       if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) {\r
348         DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: DataIn Stall\n"));\r
349         UsbClearEndpointStall (UsbIo, Endpoint);\r
350       }\r
351       continue;\r
352     }\r
353 \r
354     if (Csw.Signature != USB_BOT_CSW_SIGNATURE) {\r
355       //\r
356       // Invalid Csw need perform reset recovery\r
357       //\r
358       DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a invalid signature\n"));\r
359       Status = UsbBotResetDevice (UsbBot, FALSE);\r
360     } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) {\r
361       //\r
362       // Respond phase error need perform reset recovery\r
363       //\r
364       DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a phase error\n"));\r
365       Status = UsbBotResetDevice (UsbBot, FALSE);\r
366     } else {\r
367 \r
368       *CmdStatus = Csw.CmdStatus;\r
369       break;\r
370     }\r
371   }\r
372   //\r
373   //The tag is increased even there is an error.\r
374   //\r
375   UsbBot->CbwTag++;\r
376 \r
377   return Status;\r
378 }\r
379 \r
380 \r
381 /**\r
382   Call the Usb mass storage class transport protocol to issue\r
383   the command/data/status circle to execute the commands\r
384 \r
385   @param  Context               The context of the BOT protocol, that is,\r
386                                 USB_BOT_PROTOCOL\r
387   @param  Cmd                   The high level command\r
388   @param  CmdLen                The command length\r
389   @param  DataDir               The direction of the data transfer\r
390   @param  Data                  The buffer to hold data\r
391   @param  DataLen               The length of the data\r
392   @param  Lun                   The number of logic unit\r
393   @param  Timeout               The time to wait command\r
394   @param  CmdStatus             The result of high level command execution\r
395 \r
396   @retval EFI_DEVICE_ERROR      Failed to excute command\r
397   @retval EFI_SUCCESS           The command is executed OK, and result in CmdStatus\r
398 \r
399 **/\r
400 STATIC\r
401 EFI_STATUS\r
402 UsbBotExecCommand (\r
403   IN  VOID                    *Context,\r
404   IN  VOID                    *Cmd,\r
405   IN  UINT8                   CmdLen,\r
406   IN  EFI_USB_DATA_DIRECTION  DataDir,\r
407   IN  VOID                    *Data,\r
408   IN  UINT32                  DataLen,\r
409   IN  UINT8                   Lun,\r
410   IN  UINT32                  Timeout,\r
411   OUT UINT32                  *CmdStatus\r
412   )\r
413 {\r
414   USB_BOT_PROTOCOL          *UsbBot;\r
415   EFI_STATUS                Status;\r
416   UINTN                     TransLen;\r
417   UINT8                     Result;\r
418 \r
419   *CmdStatus  = USB_MASS_CMD_FAIL;\r
420   UsbBot      = (USB_BOT_PROTOCOL *) Context;\r
421 \r
422   //\r
423   // Send the command to the device. Return immediately if device\r
424   // rejects the command.\r
425   //\r
426   Status = UsbBotSendCommand (UsbBot, Cmd, CmdLen, DataDir, DataLen, Lun);\r
427   if (EFI_ERROR (Status)) {\r
428     DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotSendCommand (%r)\n", Status));\r
429     return Status;\r
430   }\r
431 \r
432   //\r
433   // Transfer the data. Don't return immediately even data transfer\r
434   // failed. The host should attempt to receive the CSW no matter\r
435   // whether it succeeds or failed.\r
436   //\r
437   TransLen = (UINTN) DataLen;\r
438   UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout);\r
439 \r
440   //\r
441   // Get the status, if that succeeds, interpret the result\r
442   //\r
443   Status = UsbBotGetStatus (UsbBot, DataLen, &Result);\r
444   if (EFI_ERROR (Status)) {\r
445     DEBUG ((EFI_D_ERROR, "UsbBotExecCommand: UsbBotGetStatus (%r)\n", Status));\r
446     return Status;\r
447   }\r
448 \r
449   if (Result == 0) {\r
450     *CmdStatus = USB_MASS_CMD_SUCCESS;\r
451   }\r
452 \r
453   return EFI_SUCCESS;\r
454 }\r
455 \r
456 \r
457 /**\r
458   Reset the mass storage device by BOT protocol\r
459 \r
460   @param  Context               The context of the BOT protocol, that is,\r
461                                 USB_BOT_PROTOCOL\r
462 \r
463   @retval EFI_SUCCESS           The device is reset\r
464   @retval Others                Failed to reset the device.\r
465 \r
466 **/\r
467 STATIC\r
468 EFI_STATUS\r
469 UsbBotResetDevice (\r
470   IN  VOID                    *Context,\r
471   IN  BOOLEAN                  ExtendedVerification\r
472   )\r
473 {\r
474   USB_BOT_PROTOCOL        *UsbBot;\r
475   EFI_USB_DEVICE_REQUEST  Request;\r
476   EFI_STATUS              Status;\r
477   UINT32                  Result;\r
478   UINT32                  Timeout;\r
479 \r
480   UsbBot = (USB_BOT_PROTOCOL *) Context;\r
481 \r
482   if (ExtendedVerification) {\r
483     //\r
484     // If we need to do strictly reset, reset its parent hub port\r
485     //\r
486     Status = UsbBot->UsbIo->UsbPortReset (UsbBot->UsbIo);\r
487     if (EFI_ERROR (Status)) {\r
488       return Status;\r
489     }\r
490   }\r
491 \r
492   //\r
493   // Issue a class specific Bulk-Only Mass Storage Reset reqest.\r
494   // See the spec section 3.1\r
495   //\r
496   Request.RequestType = 0x21; // Class, Interface, Host to Device\r
497   Request.Request     = USB_BOT_RESET_REQUEST;\r
498   Request.Value       = 0;\r
499   Request.Index       = UsbBot->Interface.InterfaceNumber;\r
500   Request.Length      = 0;\r
501   Timeout             = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;\r
502 \r
503   Status = UsbBot->UsbIo->UsbControlTransfer (\r
504                             UsbBot->UsbIo,\r
505                             &Request,\r
506                             EfiUsbNoData,\r
507                             Timeout,\r
508                             NULL,\r
509                             0,\r
510                             &Result\r
511                             );\r
512 \r
513   if (EFI_ERROR (Status)) {\r
514     DEBUG ((EFI_D_ERROR, "UsbBotResetDevice: (%r)\n", Status));\r
515     return Status;\r
516   }\r
517 \r
518   //\r
519   // The device shall NAK the host's request until the reset is\r
520   // complete. We can use this to sync the device and host. For\r
521   // now just stall 100ms to wait the device.\r
522   //\r
523   gBS->Stall (USB_BOT_RESET_DEVICE_STALL);\r
524 \r
525   //\r
526   // Clear the Bulk-In and Bulk-Out stall condition.\r
527   //\r
528   UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress);\r
529   UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress);\r
530   return Status;\r
531 }\r
532 \r
533 /*++\r
534 \r
535 Routine Description:\r
536 \r
537   Reset the mass storage device by BOT protocol\r
538 \r
539 Arguments:\r
540 \r
541   Context - The context of the BOT protocol, that is, USB_BOT_PROTOCOL\r
542   MaxLun  - Return pointer to the max number of lun. Maxlun=1 means lun0 and \r
543             lun1 in all.\r
544 \r
545 Returns:\r
546 \r
547   EFI_SUCCESS - The device is reset\r
548   Others      - Failed to reset the device.\r
549 \r
550 --*/\r
551 STATIC\r
552 EFI_STATUS\r
553 UsbBotGetMaxLun (\r
554   IN  VOID                    *Context,\r
555   IN  UINT8                   *MaxLun\r
556   )\r
557 /*++\r
558 \r
559 Routine Description:\r
560 \r
561   Reset the mass storage device by BOT protocol\r
562 \r
563 Arguments:\r
564 \r
565   Context - The context of the BOT protocol, that is, USB_BOT_PROTOCOL\r
566   MaxLun  - Return pointer to the max number of lun. Maxlun=1 means lun0 and \r
567             lun1 in all.\r
568 \r
569 Returns:\r
570 \r
571   EFI_SUCCESS - The device is reset\r
572   Others      - Failed to reset the device.\r
573 \r
574 --*/\r
575 {\r
576   USB_BOT_PROTOCOL        *UsbBot;\r
577   EFI_USB_DEVICE_REQUEST  Request;\r
578   EFI_STATUS              Status;\r
579   UINT32                  Result;\r
580   UINT32                  Timeout;\r
581 \r
582   ASSERT (Context);\r
583   \r
584   UsbBot = (USB_BOT_PROTOCOL *) Context;\r
585 \r
586   //\r
587   // Issue a class specific Bulk-Only Mass Storage get max lun reqest.\r
588   // See the spec section 3.2\r
589   //\r
590   Request.RequestType = 0xA1; // Class, Interface, Device to Host\r
591   Request.Request     = USB_BOT_GETLUN_REQUEST;\r
592   Request.Value       = 0;\r
593   Request.Index       = UsbBot->Interface.InterfaceNumber;\r
594   Request.Length      = 1;\r
595   Timeout             = USB_BOT_RESET_DEVICE_TIMEOUT / USB_MASS_1_MILLISECOND;\r
596 \r
597   Status = UsbBot->UsbIo->UsbControlTransfer (\r
598                             UsbBot->UsbIo,\r
599                             &Request,\r
600                             EfiUsbDataIn,\r
601                             Timeout,\r
602                             (VOID *)MaxLun,\r
603                             1,\r
604                             &Result\r
605                             );\r
606 \r
607   if (EFI_ERROR (Status)) {\r
608     DEBUG ((EFI_D_ERROR, "UsbBotGetMaxLun: (%r)\n", Status));\r
609   }\r
610 \r
611   return Status;\r
612 }\r
613 \r
614 /**\r
615   Clean up the resource used by this BOT protocol\r
616 \r
617   @param  Context               The context of the BOT protocol, that is,\r
618                                 USB_BOT_PROTOCOL\r
619 \r
620   @retval EFI_SUCCESS           The resource is cleaned up.\r
621 \r
622 **/\r
623 STATIC\r
624 EFI_STATUS\r
625 UsbBotFini (\r
626   IN  VOID                    *Context\r
627   )\r
628 {\r
629   gBS->FreePool (Context);\r
630   return EFI_SUCCESS;\r
631 }\r
632 \r
633 USB_MASS_TRANSPORT\r
634 mUsbBotTransport = {\r
635   USB_MASS_STORE_BOT,\r
636   UsbBotInit,\r
637   UsbBotExecCommand,\r
638   UsbBotResetDevice,\r
639   UsbBotGetMaxLun,\r
640   UsbBotFini\r
641 };\r
642 \r