3 Copyright (c) 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Implementation of the USB mass storage Control/Bulk/Interrupt transpor.
19 Notice: it is being obseleted by the standard body in favor of the BOT
20 (Bulk-Only Transport).
28 #include "UsbMassCbi.h"
30 UINTN mUsbCbiInfo
= DEBUG_INFO
;
31 UINTN mUsbCbiError
= DEBUG_ERROR
;
37 IN BOOLEAN ExtendedVerification
42 Initialize the USB mass storage class CBI transport protocol.
43 If Context isn't NULL, it will save its context in it.
45 @param UsbIo The USB IO to use
46 @param Controller The device controller
47 @param Context The variable to save context in
49 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
50 @retval EFI_UNSUPPORTED The device isn't supported
51 @retval EFI_SUCCESS The CBI protocol is initialized.
57 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
58 IN EFI_HANDLE Controller
,
59 OUT VOID
**Context OPTIONAL
62 USB_CBI_PROTOCOL
*UsbCbi
;
63 EFI_USB_INTERFACE_DESCRIPTOR
*Interface
;
64 EFI_USB_ENDPOINT_DESCRIPTOR EndPoint
;
69 // Allocate the CBI context
71 UsbCbi
= AllocateZeroPool (
72 sizeof (USB_CBI_PROTOCOL
) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR
)
76 return EFI_OUT_OF_RESOURCES
;
79 UsbCbi
->UsbIo
= UsbIo
;
82 // Get the interface descriptor and validate that it is a USB mass
83 // storage class CBI interface.
85 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &UsbCbi
->Interface
);
86 if (EFI_ERROR (Status
)) {
90 Interface
= &UsbCbi
->Interface
;
91 if ((Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI0
)
92 && (Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI1
)) {
93 Status
= EFI_UNSUPPORTED
;
98 // Locate and save the bulk-in, bulk-out, and interrupt endpoint
100 for (Index
= 0; Index
< Interface
->NumEndpoints
; Index
++) {
101 Status
= UsbIo
->UsbGetEndpointDescriptor (UsbIo
, Index
, &EndPoint
);
102 if (EFI_ERROR (Status
)) {
106 if (USB_IS_BULK_ENDPOINT (EndPoint
.Attributes
)) {
108 // Use the first Bulk-In and Bulk-Out endpoints
110 if (USB_IS_IN_ENDPOINT (EndPoint
.EndpointAddress
) &&
111 (UsbCbi
->BulkInEndpoint
== NULL
)) {
113 UsbCbi
->BulkInEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1);
114 CopyMem(UsbCbi
->BulkInEndpoint
, &EndPoint
, sizeof (EndPoint
));;
117 if (USB_IS_OUT_ENDPOINT (EndPoint
.EndpointAddress
) &&
118 (UsbCbi
->BulkOutEndpoint
== NULL
)) {
120 UsbCbi
->BulkOutEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 1;
121 CopyMem(UsbCbi
->BulkOutEndpoint
, &EndPoint
, sizeof (EndPoint
));
124 } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint
.Attributes
)) {
126 // Use the first interrupt endpoint if it is CBI0
128 if ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
) &&
129 (UsbCbi
->InterruptEndpoint
== NULL
)) {
131 UsbCbi
->InterruptEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 2;
132 CopyMem(UsbCbi
->InterruptEndpoint
, &EndPoint
, sizeof (EndPoint
));
137 if ((UsbCbi
->BulkInEndpoint
== NULL
)
138 || (UsbCbi
->BulkOutEndpoint
== NULL
)
139 || ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
)
140 && (UsbCbi
->InterruptEndpoint
== NULL
))) {
141 Status
= EFI_UNSUPPORTED
;
145 if (Context
!= NULL
) {
148 gBS
->FreePool (UsbCbi
);
153 gBS
->FreePool (UsbCbi
);
160 Send the command to the device using class specific control transfer.
162 @param UsbCbi The USB CBI protocol
163 @param Cmd The high level command to transfer to device
164 @param CmdLen The length of the command
165 @param Timeout The time to wait the command to finish
167 @retval EFI_SUCCESS The command is transferred to device
168 @retval Others The command failed to transfer to device
174 IN USB_CBI_PROTOCOL
*UsbCbi
,
180 EFI_USB_DEVICE_REQUEST Request
;
187 // Fill in the device request, CBI use the "Accept Device-Specific
188 // Cmd" (ADSC) class specific request to send commands
190 Request
.RequestType
= 0x21;
193 Request
.Index
= UsbCbi
->Interface
.InterfaceNumber
;
194 Request
.Length
= CmdLen
;
196 Status
= EFI_SUCCESS
;
197 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
199 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
201 // Use the UsbIo to send the command to the device
206 Status
= UsbCbi
->UsbIo
->UsbControlTransfer (
216 // The device can fail the command by STALL the control endpoint.
217 // It can delay the command by NAK the data or status stage, this
218 // is a "class-specific exemption to the USB specification". Retry
219 // if the command is NAKed.
221 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
233 Transfer data between the device and host. The CBI contains three phase,
234 command, data, and status. This is data phase.
236 @param UsbCbi The USB CBI device
237 @param DataDir The direction of the data transfer
238 @param Data The buffer to hold the data
239 @param TransLen The expected transfer length
240 @param Timeout The time to wait the command to execute
242 @retval EFI_SUCCESS The data transfer succeeded
243 @retval Others Failed to transfer all the data
249 IN USB_CBI_PROTOCOL
*UsbCbi
,
250 IN EFI_USB_DATA_DIRECTION DataDir
,
252 IN OUT UINTN
*TransLen
,
256 EFI_USB_ENDPOINT_DESCRIPTOR
*Endpoint
;
265 // It's OK if no data to transfer
267 if ((DataDir
== EfiUsbNoData
) || (*TransLen
== 0)) {
272 // Select the endpoint then issue the transfer
274 if (DataDir
== EfiUsbDataIn
) {
275 Endpoint
= UsbCbi
->BulkInEndpoint
;
277 Endpoint
= UsbCbi
->BulkOutEndpoint
;
283 Status
= EFI_SUCCESS
;
284 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
287 // Transfer the data, if the device returns NAK, retry it.
292 if (Remain
> (UINTN
) USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
) {
293 Increment
= USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
;
298 Status
= UsbCbi
->UsbIo
->UsbBulkTransfer (
300 Endpoint
->EndpointAddress
,
306 if (EFI_ERROR (Status
)) {
307 if (TransStatus
== EFI_USB_ERR_NAK
) {
309 // The device can NAK the host if either the data/buffer isn't
310 // aviable or the command is in-progress. The data can be partly
311 // transferred. The transfer is aborted if several succssive data
312 // transfer commands are NAKed.
314 if (Increment
== 0) {
315 if (++Retry
> USB_CBI_MAX_RETRY
) {
329 // The device can fail the command by STALL the bulk endpoint.
330 // Clear the stall if that is the case.
332 if (TransStatus
== EFI_USB_ERR_STALL
) {
333 UsbClearEndpointStall (UsbCbi
->UsbIo
, Endpoint
->EndpointAddress
);
350 Get the result of high level command execution from interrupt
351 endpoint. This function returns the USB transfer status, and
352 put the high level command execution result in Result.
354 @param UsbCbi The USB CBI protocol
355 @param Timeout The time to wait the command to execute
356 @param Result GC_TODO: add argument description
358 @retval EFI_SUCCESS The high level command execution result is
360 @retval Others Failed to retrieve the result.
366 IN USB_CBI_PROTOCOL
*UsbCbi
,
368 OUT USB_CBI_STATUS
*Result
377 Endpoint
= UsbCbi
->InterruptEndpoint
->EndpointAddress
;
378 Status
= EFI_SUCCESS
;
379 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
382 // Attemp to the read the result from interrupt endpoint
384 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
386 Len
= sizeof (USB_CBI_STATUS
);
388 Status
= UsbCbi
->UsbIo
->UsbSyncInterruptTransfer (
397 // The CBI can NAK the interrupt endpoint if the command is in-progress.
399 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
411 Execute USB mass storage command through the CBI0/CBI1 transport protocol
413 @param Context The USB CBI device
414 @param Cmd The command to transfer to device
415 @param CmdLen The length of the command
416 @param DataDir The direction of data transfer
417 @param Data The buffer to hold the data
418 @param DataLen The length of the buffer
419 @param Timeout The time to wait
420 @param CmdStatus The result of the command execution
422 @retval EFI_SUCCESS The command is executed OK and result in CmdStatus.
423 @retval EFI_DEVICE_ERROR Failed to execute the command
432 IN EFI_USB_DATA_DIRECTION DataDir
,
436 OUT UINT32
*CmdStatus
439 USB_CBI_PROTOCOL
*UsbCbi
;
440 USB_CBI_STATUS Result
;
444 *CmdStatus
= USB_MASS_CMD_SUCCESS
;
445 UsbCbi
= (USB_CBI_PROTOCOL
*) Context
;
448 // Send the command to the device. Return immediately if device
449 // rejects the command.
451 Status
= UsbCbiSendCommand (UsbCbi
, Cmd
, CmdLen
, Timeout
);
452 if (EFI_ERROR (Status
)) {
453 DEBUG ((mUsbCbiError
, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status
));
458 // Transfer the data, return this status if no interrupt endpoint
459 // is used to report the transfer status.
461 TransLen
= (UINTN
) DataLen
;
463 Status
= UsbCbiDataTransfer (UsbCbi
, DataDir
, Data
, &TransLen
, Timeout
);
464 if (UsbCbi
->InterruptEndpoint
== NULL
) {
465 DEBUG ((mUsbCbiError
, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status
));
470 // Get the status, if that succeeds, interpret the result
472 Status
= UsbCbiGetStatus (UsbCbi
, Timeout
, &Result
);
473 if (EFI_ERROR (Status
)) {
474 DEBUG ((mUsbCbiError
, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status
));
475 return EFI_DEVICE_ERROR
;
478 if (UsbCbi
->Interface
.InterfaceSubClass
== USB_MASS_STORE_UFI
) {
480 // For UFI device, ASC and ASCQ are returned.
482 if (Result
.Type
!= 0) {
483 *CmdStatus
= USB_MASS_CMD_FAIL
;
488 // Check page 27, CBI spec 1.1 for vaious reture status.
490 switch (Result
.Value
& 0x03) {
495 *CmdStatus
= USB_MASS_CMD_SUCCESS
;
500 // Phase Error, response with reset. Fall through to Fail.
502 UsbCbiResetDevice (UsbCbi
, FALSE
);
508 *CmdStatus
= USB_MASS_CMD_FAIL
;
513 // Persistent Fail, need to send REQUEST SENSE.
515 *CmdStatus
= USB_MASS_CMD_PERSISTENT
;
525 Call the Usb mass storage class transport protocol to
526 reset the device. The reset is defined as a Non-Data
527 command. Don't use UsbCbiExecCommand to send the command
528 to device because that may introduce recursive loop.
530 @param Context The USB CBI device protocol
532 @retval EFI_SUCCESS the device is reset
533 @retval Others Failed to reset the device
540 IN BOOLEAN ExtendedVerification
543 UINT8 ResetCmd
[USB_CBI_RESET_CMD_LEN
];
544 USB_CBI_PROTOCOL
*UsbCbi
;
545 USB_CBI_STATUS Result
;
549 UsbCbi
= (USB_CBI_PROTOCOL
*) Context
;
552 // Fill in the reset command.
554 SetMem (ResetCmd
, USB_CBI_RESET_CMD_LEN
, 0xFF);
558 Timeout
= USB_CBI_RESET_DEVICE_TIMEOUT
/ USB_MASS_1_MILLISECOND
;
561 // Send the command to the device. Don't use UsbCbiExecCommand here.
563 Status
= UsbCbiSendCommand (UsbCbi
, ResetCmd
, USB_CBI_RESET_CMD_LEN
, Timeout
);
564 if (EFI_ERROR (Status
)) {
569 // Just retrieve the status and ignore that. Then stall
570 // 50ms to wait it complete
572 UsbCbiGetStatus (UsbCbi
, Timeout
, &Result
);
573 gBS
->Stall (USB_CBI_RESET_DEVICE_STALL
);
576 // Clear the Bulk-In and Bulk-Out stall condition and
579 UsbClearEndpointStall (UsbCbi
->UsbIo
, UsbCbi
->BulkInEndpoint
->EndpointAddress
);
580 UsbClearEndpointStall (UsbCbi
->UsbIo
, UsbCbi
->BulkOutEndpoint
->EndpointAddress
);
586 Clean up the CBI protocol's resource
588 @param Context The CBI protocol
590 @retval EFI_SUCCESS The resource is cleaned up.
599 gBS
->FreePool (Context
);
604 mUsbCbi0Transport
= {
613 mUsbCbi1Transport
= {