3 Copyright (c) 2007 - 2008, 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"
34 IN BOOLEAN ExtendedVerification
39 Initialize the USB mass storage class CBI transport protocol.
40 If Context isn't NULL, it will save its context in it.
42 @param UsbIo The USB IO to use
43 @param Context The variable to save context in
45 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
46 @retval EFI_UNSUPPORTED The device isn't supported
47 @retval EFI_SUCCESS The CBI protocol is initialized.
53 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
54 OUT VOID
**Context OPTIONAL
57 USB_CBI_PROTOCOL
*UsbCbi
;
58 EFI_USB_INTERFACE_DESCRIPTOR
*Interface
;
59 EFI_USB_ENDPOINT_DESCRIPTOR EndPoint
;
64 // Allocate the CBI context
66 UsbCbi
= AllocateZeroPool (
67 sizeof (USB_CBI_PROTOCOL
) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR
)
71 return EFI_OUT_OF_RESOURCES
;
74 UsbCbi
->UsbIo
= UsbIo
;
77 // Get the interface descriptor and validate that it is a USB mass
78 // storage class CBI interface.
80 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &UsbCbi
->Interface
);
81 if (EFI_ERROR (Status
)) {
85 Interface
= &UsbCbi
->Interface
;
86 if ((Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI0
)
87 && (Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI1
)) {
88 Status
= EFI_UNSUPPORTED
;
93 // Locate and save the bulk-in, bulk-out, and interrupt endpoint
95 for (Index
= 0; Index
< Interface
->NumEndpoints
; Index
++) {
96 Status
= UsbIo
->UsbGetEndpointDescriptor (UsbIo
, Index
, &EndPoint
);
97 if (EFI_ERROR (Status
)) {
101 if (USB_IS_BULK_ENDPOINT (EndPoint
.Attributes
)) {
103 // Use the first Bulk-In and Bulk-Out endpoints
105 if (USB_IS_IN_ENDPOINT (EndPoint
.EndpointAddress
) &&
106 (UsbCbi
->BulkInEndpoint
== NULL
)) {
108 UsbCbi
->BulkInEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1);
109 CopyMem(UsbCbi
->BulkInEndpoint
, &EndPoint
, sizeof (EndPoint
));;
112 if (USB_IS_OUT_ENDPOINT (EndPoint
.EndpointAddress
) &&
113 (UsbCbi
->BulkOutEndpoint
== NULL
)) {
115 UsbCbi
->BulkOutEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 1;
116 CopyMem(UsbCbi
->BulkOutEndpoint
, &EndPoint
, sizeof (EndPoint
));
119 } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint
.Attributes
)) {
121 // Use the first interrupt endpoint if it is CBI0
123 if ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
) &&
124 (UsbCbi
->InterruptEndpoint
== NULL
)) {
126 UsbCbi
->InterruptEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 2;
127 CopyMem(UsbCbi
->InterruptEndpoint
, &EndPoint
, sizeof (EndPoint
));
132 if ((UsbCbi
->BulkInEndpoint
== NULL
)
133 || (UsbCbi
->BulkOutEndpoint
== NULL
)
134 || ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
)
135 && (UsbCbi
->InterruptEndpoint
== NULL
))) {
136 Status
= EFI_UNSUPPORTED
;
140 if (Context
!= NULL
) {
143 gBS
->FreePool (UsbCbi
);
148 gBS
->FreePool (UsbCbi
);
155 Send the command to the device using class specific control transfer.
157 @param UsbCbi The USB CBI protocol
158 @param Cmd The high level command to transfer to device
159 @param CmdLen The length of the command
160 @param Timeout The time to wait the command to finish
162 @retval EFI_SUCCESS The command is transferred to device
163 @retval Others The command failed to transfer to device
169 IN USB_CBI_PROTOCOL
*UsbCbi
,
175 EFI_USB_DEVICE_REQUEST Request
;
182 // Fill in the device request, CBI use the "Accept Device-Specific
183 // Cmd" (ADSC) class specific request to send commands
185 Request
.RequestType
= 0x21;
188 Request
.Index
= UsbCbi
->Interface
.InterfaceNumber
;
189 Request
.Length
= CmdLen
;
191 Status
= EFI_SUCCESS
;
192 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
194 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
196 // Use the UsbIo to send the command to the device
201 Status
= UsbCbi
->UsbIo
->UsbControlTransfer (
211 // The device can fail the command by STALL the control endpoint.
212 // It can delay the command by NAK the data or status stage, this
213 // is a "class-specific exemption to the USB specification". Retry
214 // if the command is NAKed.
216 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
228 Transfer data between the device and host. The CBI contains three phase,
229 command, data, and status. This is data phase.
231 @param UsbCbi The USB CBI device
232 @param DataDir The direction of the data transfer
233 @param Data The buffer to hold the data
234 @param TransLen The expected transfer length
235 @param Timeout The time to wait the command to execute
237 @retval EFI_SUCCESS The data transfer succeeded
238 @retval Others Failed to transfer all the data
244 IN USB_CBI_PROTOCOL
*UsbCbi
,
245 IN EFI_USB_DATA_DIRECTION DataDir
,
247 IN OUT UINTN
*TransLen
,
251 EFI_USB_ENDPOINT_DESCRIPTOR
*Endpoint
;
260 // It's OK if no data to transfer
262 if ((DataDir
== EfiUsbNoData
) || (*TransLen
== 0)) {
267 // Select the endpoint then issue the transfer
269 if (DataDir
== EfiUsbDataIn
) {
270 Endpoint
= UsbCbi
->BulkInEndpoint
;
272 Endpoint
= UsbCbi
->BulkOutEndpoint
;
278 Status
= EFI_SUCCESS
;
279 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
282 // Transfer the data, if the device returns NAK, retry it.
287 if (Remain
> (UINTN
) USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
) {
288 Increment
= USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
;
293 Status
= UsbCbi
->UsbIo
->UsbBulkTransfer (
295 Endpoint
->EndpointAddress
,
301 if (EFI_ERROR (Status
)) {
302 if (TransStatus
== EFI_USB_ERR_NAK
) {
304 // The device can NAK the host if either the data/buffer isn't
305 // aviable or the command is in-progress. The data can be partly
306 // transferred. The transfer is aborted if several succssive data
307 // transfer commands are NAKed.
309 if (Increment
== 0) {
310 if (++Retry
> USB_CBI_MAX_RETRY
) {
324 // The device can fail the command by STALL the bulk endpoint.
325 // Clear the stall if that is the case.
327 if (TransStatus
== EFI_USB_ERR_STALL
) {
328 UsbClearEndpointStall (UsbCbi
->UsbIo
, Endpoint
->EndpointAddress
);
345 Get the result of high level command execution from interrupt
346 endpoint. This function returns the USB transfer status, and
347 put the high level command execution result in Result.
349 @param UsbCbi The USB CBI protocol
350 @param Timeout The time to wait the command to execute
351 @param Result GC_TODO: add argument description
353 @retval EFI_SUCCESS The high level command execution result is
355 @retval Others Failed to retrieve the result.
361 IN USB_CBI_PROTOCOL
*UsbCbi
,
363 OUT USB_CBI_STATUS
*Result
372 Endpoint
= UsbCbi
->InterruptEndpoint
->EndpointAddress
;
373 Status
= EFI_SUCCESS
;
374 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
377 // Attemp to the read the result from interrupt endpoint
379 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
381 Len
= sizeof (USB_CBI_STATUS
);
383 Status
= UsbCbi
->UsbIo
->UsbSyncInterruptTransfer (
392 // The CBI can NAK the interrupt endpoint if the command is in-progress.
394 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
406 Execute USB mass storage command through the CBI0/CBI1 transport protocol
408 @param Context The USB CBI device
409 @param Cmd The command to transfer to device
410 @param CmdLen The length of the command
411 @param DataDir The direction of data transfer
412 @param Data The buffer to hold the data
413 @param DataLen The length of the buffer
414 @param Lun Should be 0, this field for bot only
415 @param Timeout The time to wait
416 @param CmdStatus The result of the command execution
418 @retval EFI_SUCCESS The command is executed OK and result in CmdStatus.
419 @retval EFI_DEVICE_ERROR Failed to execute the command
428 IN EFI_USB_DATA_DIRECTION DataDir
,
433 OUT UINT32
*CmdStatus
436 USB_CBI_PROTOCOL
*UsbCbi
;
437 USB_CBI_STATUS Result
;
441 *CmdStatus
= USB_MASS_CMD_SUCCESS
;
442 UsbCbi
= (USB_CBI_PROTOCOL
*) Context
;
445 // Send the command to the device. Return immediately if device
446 // rejects the command.
448 Status
= UsbCbiSendCommand (UsbCbi
, Cmd
, CmdLen
, Timeout
);
449 if (EFI_ERROR (Status
)) {
450 DEBUG ((EFI_D_ERROR
, "UsbCbiExecCommand: UsbCbiSendCommand (%r)\n",Status
));
455 // Transfer the data, return this status if no interrupt endpoint
456 // is used to report the transfer status.
458 TransLen
= (UINTN
) DataLen
;
460 Status
= UsbCbiDataTransfer (UsbCbi
, DataDir
, Data
, &TransLen
, Timeout
);
461 if (UsbCbi
->InterruptEndpoint
== NULL
) {
462 DEBUG ((EFI_D_ERROR
, "UsbCbiExecCommand: UsbCbiDataTransfer (%r)\n",Status
));
467 // Get the status, if that succeeds, interpret the result
469 Status
= UsbCbiGetStatus (UsbCbi
, Timeout
, &Result
);
470 if (EFI_ERROR (Status
)) {
471 DEBUG ((EFI_D_ERROR
, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status
));
472 return EFI_DEVICE_ERROR
;
475 if (UsbCbi
->Interface
.InterfaceSubClass
== USB_MASS_STORE_UFI
) {
477 // For UFI device, ASC and ASCQ are returned.
479 if (Result
.Type
!= 0) {
480 *CmdStatus
= USB_MASS_CMD_FAIL
;
485 // Check page 27, CBI spec 1.1 for vaious reture status.
487 switch (Result
.Value
& 0x03) {
492 *CmdStatus
= USB_MASS_CMD_SUCCESS
;
497 // Phase Error, response with reset. Fall through to Fail.
499 UsbCbiResetDevice (UsbCbi
, FALSE
);
505 *CmdStatus
= USB_MASS_CMD_FAIL
;
510 // Persistent Fail, need to send REQUEST SENSE.
512 *CmdStatus
= USB_MASS_CMD_PERSISTENT
;
522 Call the Usb mass storage class transport protocol to
523 reset the device. The reset is defined as a Non-Data
524 command. Don't use UsbCbiExecCommand to send the command
525 to device because that may introduce recursive loop.
527 @param Context The USB CBI device protocol
529 @retval EFI_SUCCESS the device is reset
530 @retval Others Failed to reset the device
537 IN BOOLEAN ExtendedVerification
540 UINT8 ResetCmd
[USB_CBI_RESET_CMD_LEN
];
541 USB_CBI_PROTOCOL
*UsbCbi
;
542 USB_CBI_STATUS Result
;
546 UsbCbi
= (USB_CBI_PROTOCOL
*) Context
;
549 // Fill in the reset command.
551 SetMem (ResetCmd
, USB_CBI_RESET_CMD_LEN
, 0xFF);
555 Timeout
= USB_CBI_RESET_DEVICE_TIMEOUT
/ USB_MASS_1_MILLISECOND
;
558 // Send the command to the device. Don't use UsbCbiExecCommand here.
560 Status
= UsbCbiSendCommand (UsbCbi
, ResetCmd
, USB_CBI_RESET_CMD_LEN
, Timeout
);
561 if (EFI_ERROR (Status
)) {
566 // Just retrieve the status and ignore that. Then stall
567 // 50ms to wait it complete
569 UsbCbiGetStatus (UsbCbi
, Timeout
, &Result
);
570 gBS
->Stall (USB_CBI_RESET_DEVICE_STALL
);
573 // Clear the Bulk-In and Bulk-Out stall condition and
576 UsbClearEndpointStall (UsbCbi
->UsbIo
, UsbCbi
->BulkInEndpoint
->EndpointAddress
);
577 UsbClearEndpointStall (UsbCbi
->UsbIo
, UsbCbi
->BulkOutEndpoint
->EndpointAddress
);
583 Clean up the CBI protocol's resource
585 @param Context The CBI protocol
587 @retval EFI_SUCCESS The resource is cleaned up.
596 gBS
->FreePool (Context
);
601 mUsbCbi0Transport
= {
611 mUsbCbi1Transport
= {