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