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"
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 Controller The device controller
44 @param Context The variable to save context in
46 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory
47 @retval EFI_UNSUPPORTED The device isn't supported
48 @retval EFI_SUCCESS The CBI protocol is initialized.
54 IN EFI_USB_IO_PROTOCOL
*UsbIo
,
55 IN EFI_HANDLE Controller
,
56 OUT VOID
**Context OPTIONAL
59 USB_CBI_PROTOCOL
*UsbCbi
;
60 EFI_USB_INTERFACE_DESCRIPTOR
*Interface
;
61 EFI_USB_ENDPOINT_DESCRIPTOR EndPoint
;
66 // Allocate the CBI context
68 UsbCbi
= AllocateZeroPool (
69 sizeof (USB_CBI_PROTOCOL
) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR
)
73 return EFI_OUT_OF_RESOURCES
;
76 UsbCbi
->UsbIo
= UsbIo
;
79 // Get the interface descriptor and validate that it is a USB mass
80 // storage class CBI interface.
82 Status
= UsbIo
->UsbGetInterfaceDescriptor (UsbIo
, &UsbCbi
->Interface
);
83 if (EFI_ERROR (Status
)) {
87 Interface
= &UsbCbi
->Interface
;
88 if ((Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI0
)
89 && (Interface
->InterfaceProtocol
!= USB_MASS_STORE_CBI1
)) {
90 Status
= EFI_UNSUPPORTED
;
95 // Locate and save the bulk-in, bulk-out, and interrupt endpoint
97 for (Index
= 0; Index
< Interface
->NumEndpoints
; Index
++) {
98 Status
= UsbIo
->UsbGetEndpointDescriptor (UsbIo
, Index
, &EndPoint
);
99 if (EFI_ERROR (Status
)) {
103 if (USB_IS_BULK_ENDPOINT (EndPoint
.Attributes
)) {
105 // Use the first Bulk-In and Bulk-Out endpoints
107 if (USB_IS_IN_ENDPOINT (EndPoint
.EndpointAddress
) &&
108 (UsbCbi
->BulkInEndpoint
== NULL
)) {
110 UsbCbi
->BulkInEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1);
111 CopyMem(UsbCbi
->BulkInEndpoint
, &EndPoint
, sizeof (EndPoint
));;
114 if (USB_IS_OUT_ENDPOINT (EndPoint
.EndpointAddress
) &&
115 (UsbCbi
->BulkOutEndpoint
== NULL
)) {
117 UsbCbi
->BulkOutEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 1;
118 CopyMem(UsbCbi
->BulkOutEndpoint
, &EndPoint
, sizeof (EndPoint
));
121 } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint
.Attributes
)) {
123 // Use the first interrupt endpoint if it is CBI0
125 if ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
) &&
126 (UsbCbi
->InterruptEndpoint
== NULL
)) {
128 UsbCbi
->InterruptEndpoint
= (EFI_USB_ENDPOINT_DESCRIPTOR
*) (UsbCbi
+ 1) + 2;
129 CopyMem(UsbCbi
->InterruptEndpoint
, &EndPoint
, sizeof (EndPoint
));
134 if ((UsbCbi
->BulkInEndpoint
== NULL
)
135 || (UsbCbi
->BulkOutEndpoint
== NULL
)
136 || ((Interface
->InterfaceProtocol
== USB_MASS_STORE_CBI0
)
137 && (UsbCbi
->InterruptEndpoint
== NULL
))) {
138 Status
= EFI_UNSUPPORTED
;
142 if (Context
!= NULL
) {
145 gBS
->FreePool (UsbCbi
);
150 gBS
->FreePool (UsbCbi
);
157 Send the command to the device using class specific control transfer.
159 @param UsbCbi The USB CBI protocol
160 @param Cmd The high level command to transfer to device
161 @param CmdLen The length of the command
162 @param Timeout The time to wait the command to finish
164 @retval EFI_SUCCESS The command is transferred to device
165 @retval Others The command failed to transfer to device
171 IN USB_CBI_PROTOCOL
*UsbCbi
,
177 EFI_USB_DEVICE_REQUEST Request
;
184 // Fill in the device request, CBI use the "Accept Device-Specific
185 // Cmd" (ADSC) class specific request to send commands
187 Request
.RequestType
= 0x21;
190 Request
.Index
= UsbCbi
->Interface
.InterfaceNumber
;
191 Request
.Length
= CmdLen
;
193 Status
= EFI_SUCCESS
;
194 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
196 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
198 // Use the UsbIo to send the command to the device
203 Status
= UsbCbi
->UsbIo
->UsbControlTransfer (
213 // The device can fail the command by STALL the control endpoint.
214 // It can delay the command by NAK the data or status stage, this
215 // is a "class-specific exemption to the USB specification". Retry
216 // if the command is NAKed.
218 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
230 Transfer data between the device and host. The CBI contains three phase,
231 command, data, and status. This is data phase.
233 @param UsbCbi The USB CBI device
234 @param DataDir The direction of the data transfer
235 @param Data The buffer to hold the data
236 @param TransLen The expected transfer length
237 @param Timeout The time to wait the command to execute
239 @retval EFI_SUCCESS The data transfer succeeded
240 @retval Others Failed to transfer all the data
246 IN USB_CBI_PROTOCOL
*UsbCbi
,
247 IN EFI_USB_DATA_DIRECTION DataDir
,
249 IN OUT UINTN
*TransLen
,
253 EFI_USB_ENDPOINT_DESCRIPTOR
*Endpoint
;
262 // It's OK if no data to transfer
264 if ((DataDir
== EfiUsbNoData
) || (*TransLen
== 0)) {
269 // Select the endpoint then issue the transfer
271 if (DataDir
== EfiUsbDataIn
) {
272 Endpoint
= UsbCbi
->BulkInEndpoint
;
274 Endpoint
= UsbCbi
->BulkOutEndpoint
;
280 Status
= EFI_SUCCESS
;
281 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
284 // Transfer the data, if the device returns NAK, retry it.
289 if (Remain
> (UINTN
) USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
) {
290 Increment
= USB_CBI_MAX_PACKET_NUM
* Endpoint
->MaxPacketSize
;
295 Status
= UsbCbi
->UsbIo
->UsbBulkTransfer (
297 Endpoint
->EndpointAddress
,
303 if (EFI_ERROR (Status
)) {
304 if (TransStatus
== EFI_USB_ERR_NAK
) {
306 // The device can NAK the host if either the data/buffer isn't
307 // aviable or the command is in-progress. The data can be partly
308 // transferred. The transfer is aborted if several succssive data
309 // transfer commands are NAKed.
311 if (Increment
== 0) {
312 if (++Retry
> USB_CBI_MAX_RETRY
) {
326 // The device can fail the command by STALL the bulk endpoint.
327 // Clear the stall if that is the case.
329 if (TransStatus
== EFI_USB_ERR_STALL
) {
330 UsbClearEndpointStall (UsbCbi
->UsbIo
, Endpoint
->EndpointAddress
);
347 Get the result of high level command execution from interrupt
348 endpoint. This function returns the USB transfer status, and
349 put the high level command execution result in Result.
351 @param UsbCbi The USB CBI protocol
352 @param Timeout The time to wait the command to execute
353 @param Result GC_TODO: add argument description
355 @retval EFI_SUCCESS The high level command execution result is
357 @retval Others Failed to retrieve the result.
363 IN USB_CBI_PROTOCOL
*UsbCbi
,
365 OUT USB_CBI_STATUS
*Result
374 Endpoint
= UsbCbi
->InterruptEndpoint
->EndpointAddress
;
375 Status
= EFI_SUCCESS
;
376 Timeout
= Timeout
/ USB_MASS_1_MILLISECOND
;
379 // Attemp to the read the result from interrupt endpoint
381 for (Retry
= 0; Retry
< USB_CBI_MAX_RETRY
; Retry
++) {
383 Len
= sizeof (USB_CBI_STATUS
);
385 Status
= UsbCbi
->UsbIo
->UsbSyncInterruptTransfer (
394 // The CBI can NAK the interrupt endpoint if the command is in-progress.
396 if (EFI_ERROR (Status
) && (TransStatus
== EFI_USB_ERR_NAK
)) {
408 Execute USB mass storage command through the CBI0/CBI1 transport protocol
410 @param Context The USB CBI device
411 @param Cmd The command to transfer to device
412 @param CmdLen The length of the command
413 @param DataDir The direction of data transfer
414 @param Data The buffer to hold the data
415 @param DataLen The length of the buffer
416 @param Timeout The time to wait
417 @param CmdStatus The result of the command execution
419 @retval EFI_SUCCESS The command is executed OK and result in CmdStatus.
420 @retval EFI_DEVICE_ERROR Failed to execute the command
429 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
= {
610 mUsbCbi1Transport
= {