From d80ed2a76eec1786412fb76cc080cfb38ae77011 Mon Sep 17 00:00:00 2001 From: xli24 Date: Mon, 12 Jan 2009 03:11:00 +0000 Subject: [PATCH] Code scrub for USB Mass Storage Driver. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@7243 6f19259b-4bc3-4df7-8a09-765794883524 --- .../Bus/Usb/UsbMassStorageDxe/UsbMass.h | 54 +-- .../Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c | 326 +++++++----------- .../Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h | 101 ++---- .../Bus/Usb/UsbMassStorageDxe/UsbMassBot.c | 205 +++++------ .../Bus/Usb/UsbMassStorageDxe/UsbMassBot.h | 160 +++++++-- .../Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c | 195 +++++------ .../Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h | 109 +++++- .../Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c | 294 +++++++++------- .../Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h | 196 ++++++++++- 9 files changed, 949 insertions(+), 691 deletions(-) diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h index b65fc18b14..546dbed882 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMass.h @@ -37,10 +37,10 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include -#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0x80) -#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & 0x80) == 0) -#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x02) -#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & 0x03) == 0x03) +#define USB_IS_IN_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == BIT7) +#define USB_IS_OUT_ENDPOINT(EndPointAddr) (((EndPointAddr) & BIT7) == 0) +#define USB_IS_BULK_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_BULK) +#define USB_IS_INTERRUPT_ENDPOINT(Attribute) (((Attribute) & (BIT0 | BIT1)) == USB_ENDPOINT_INTERRUPT) #define USB_IS_ERROR(Result, Error) (((Result) & (Error)) != 0) typedef enum { @@ -52,19 +52,19 @@ typedef enum { // // Usb mass storage subclass code, specify the command set used. // - USB_MASS_STORE_RBC = 0x01, // Reduced Block Commands - USB_MASS_STORE_8020I = 0x02, // SFF-8020i, typically a CD/DVD device - USB_MASS_STORE_QIC = 0x03, // Typically a tape device - USB_MASS_STORE_UFI = 0x04, // Typically a floppy disk driver device - USB_MASS_STORE_8070I = 0x05, // SFF-8070i, typically a floppy disk driver device. - USB_MASS_STORE_SCSI = 0x06, // SCSI transparent command set + USB_MASS_STORE_RBC = 0x01, ///< Reduced Block Commands + USB_MASS_STORE_8020I = 0x02, ///< SFF-8020i, typically a CD/DVD device + USB_MASS_STORE_QIC = 0x03, ///< Typically a tape device + USB_MASS_STORE_UFI = 0x04, ///< Typically a floppy disk driver device + USB_MASS_STORE_8070I = 0x05, ///< SFF-8070i, typically a floppy disk driver device. + USB_MASS_STORE_SCSI = 0x06, ///< SCSI transparent command set // // Usb mass storage protocol code, specify the transport protocol // - USB_MASS_STORE_CBI0 = 0x00, // CBI protocol with command completion interrupt - USB_MASS_STORE_CBI1 = 0x01, // CBI protocol without command completion interrupt - USB_MASS_STORE_BOT = 0x50, // Bulk-Only Transport + USB_MASS_STORE_CBI0 = 0x00, ///< CBI protocol with command completion interrupt + USB_MASS_STORE_CBI1 = 0x01, ///< CBI protocol without command completion interrupt + USB_MASS_STORE_BOT = 0x50, ///< Bulk-Only Transport USB_MASS_1_MILLISECOND = 1000, USB_MASS_1_SECOND = 1000 * USB_MASS_1_MILLISECOND, @@ -111,25 +111,25 @@ EFI_STATUS typedef EFI_STATUS -(*USB_MASS_FINI) ( +(*USB_MASS_CLEAN_UP) ( IN VOID *Context ); -// -// This structure contains information necessary to select the -// proper transport protocol. The mass storage class defines -// two transport protocols. One is the CBI, and the other is BOT. -// CBI is being obseleted. The design is made modular by this -// structure so that the CBI protocol can be easily removed when -// it is no longer necessary. -// +/// +/// This structure contains information necessary to select the +/// proper transport protocol. The mass storage class defines +/// two transport protocols. One is the CBI, and the other is BOT. +/// CBI is being obseleted. The design is made modular by this +/// structure so that the CBI protocol can be easily removed when +/// it is no longer necessary. +/// typedef struct { UINT8 Protocol; - USB_MASS_INIT_TRANSPORT Init; // Initialize the mass storage transport protocol - USB_MASS_EXEC_COMMAND ExecCommand; // Transport command to the device then get result - USB_MASS_RESET Reset; // Reset the device - USB_MASS_GET_MAX_LUN GetMaxLun; // Get max lun, only for bot - USB_MASS_FINI Fini; // Clean up the resources. + USB_MASS_INIT_TRANSPORT Init; ///< Initialize the mass storage transport protocol + USB_MASS_EXEC_COMMAND ExecCommand; ///< Transport command to the device then get result + USB_MASS_RESET Reset; ///< Reset the device + USB_MASS_GET_MAX_LUN GetMaxLun; ///< Get max lun, only for bot + USB_MASS_CLEAN_UP CleanUp; ///< Clean up the resources. } USB_MASS_TRANSPORT; diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c index 589087accd..44f0b03833 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.c @@ -1,7 +1,6 @@ /** @file - - This file implement the command set of "USB Mass Storage Specification - for Bootability". + Implementation of the command set of USB Mass Storage Specification + for Bootability, Revision 1.0. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -16,96 +15,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UsbMassImpl.h" - /** - Return the current TPL. + Execute REQUEST SENSE Command to retrieve sense data from device. - @return Current TPL. + @param UsbMass The device whose sense data is requested. -**/ -EFI_TPL -UsbGetCurrentTpl ( - VOID - ) -{ - EFI_TPL Tpl; - - Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL); - gBS->RestoreTPL (Tpl); - - return Tpl; -} - -/** - Read an UINT32 from the buffer to avoid byte alignment problems, then - convert that to the little endia. The USB mass storage bootability spec - use big endia. - - @param Buf The buffer contains the first byte of the UINT32 - in big endia. - - @return The UINT32 value read from the buffer in little endia. - -**/ -UINT32 -UsbBootGetUint32 ( - IN UINT8 *Buf - ) -{ - UINT32 Value; - - CopyMem (&Value, Buf, sizeof (UINT32)); - return USB_BOOT_SWAP32 (Value); -} - - -/** - Put an UINT32 in little endia to the buffer. The data is converted to - big endia before writing. - - @param Buf The buffer to write data to. - @param Data32 The data to write. - - @return None. - -**/ -VOID -UsbBootPutUint32 ( - IN UINT8 *Buf, - IN UINT32 Data32 - ) -{ - Data32 = USB_BOOT_SWAP32 (Data32); - CopyMem (Buf, &Data32, sizeof (UINT32)); -} - -/** - Put an UINT16 in little endia to the buffer. The data is converted to - big endia before writing. - - @param Buf The buffer to write data to. - @param Data16 The data to write. - - @return None. - -**/ -VOID -UsbBootPutUint16 ( - IN UINT8 *Buf, - IN UINT16 Data16 - ) -{ - Data16 = (UINT16) (USB_BOOT_SWAP16 (Data16)); - CopyMem (Buf, &Data16, sizeof (UINT16)); -} - -/** - Request sense information via sending Request Sense - Packet Command. - - @param UsbMass The device to be requested sense data. - - @retval EFI_SUCCESS The command is excuted OK. + @retval EFI_SUCCESS The command is excuted successfully. @retval EFI_DEVICE_ERROR Failed to request sense. @retval EFI_NO_RESPONSE The device media doesn't response this request. @retval EFI_INVALID_PARAMETER The command has some invalid parameters. @@ -128,7 +43,7 @@ UsbBootRequestSense ( Transport = UsbMass->Transport; // - // Request the sense data from the device if command failed + // Request the sense data from the device // ZeroMem (&SenseCmd, sizeof (USB_BOOT_REQUEST_SENSE_CMD)); ZeroMem (&SenseData, sizeof (USB_BOOT_REQUEST_SENSE_DATA)); @@ -154,7 +69,8 @@ UsbBootRequestSense ( } // - // Interpret the sense data and update the media status if necessary. + // If sense data is retrieved successfully, interpret the sense data + // and update the media status if necessary. // Media = &UsbMass->BlockIoMedia; @@ -174,10 +90,10 @@ UsbBootRequestSense ( case USB_BOOT_SENSE_NOT_READY: Status = EFI_DEVICE_ERROR; if (SenseData.ASC == USB_BOOT_ASC_NO_MEDIA) { - Media->MediaPresent = FALSE; - Status = EFI_NO_MEDIA; + Media->MediaPresent = FALSE; + Status = EFI_NO_MEDIA; } else if (SenseData.ASC == USB_BOOT_ASC_NOT_READY) { - Status = EFI_NOT_READY; + Status = EFI_NOT_READY; } break; @@ -189,16 +105,16 @@ UsbBootRequestSense ( Status = EFI_DEVICE_ERROR; if (SenseData.ASC == USB_BOOT_ASC_MEDIA_CHANGE) { // - // If MediaChange, reset ReadOnly and new MediId + // If MediaChange, reset ReadOnly and new MediaId // - Status = EFI_MEDIA_CHANGED; + Status = EFI_MEDIA_CHANGED; Media->ReadOnly = FALSE; Media->MediaId++; } break; - case USB_BOOT_SNESE_DATA_PROTECT: - Status = EFI_WRITE_PROTECTED; + case USB_BOOT_SENSE_DATA_PROTECT: + Status = EFI_WRITE_PROTECTED; Media->ReadOnly = TRUE; break; @@ -219,9 +135,11 @@ UsbBootRequestSense ( /** - Execute the USB mass storage bootability commands. If execution - failed, retrieve the error by REQUEST_SENSE then update the device's - status, such as ReadyOnly. + Execute the USB mass storage bootability commands. + + This function executes the USB mass storage bootability commands. + If execution failed, retrieve the error by REQUEST_SENSE, then + update the device's status, such as ReadyOnly. @param UsbMass The device to issue commands to @param Cmd The command to execute @@ -231,11 +149,8 @@ UsbBootRequestSense ( @param DataLen The length of expected data @param Timeout The timeout used to transfer - @retval EFI_SUCCESS The command is excuted OK - @retval EFI_DEVICE_ERROR Failed to request sense - @retval EFI_INVALID_PARAMETER The command has some invalid parameters - @retval EFI_WRITE_PROTECTED The device is write protected - @retval EFI_MEDIA_CHANGED The device media has been changed + @retval EFI_SUCCESS Command is excuted successfully + @retval Others Command execution failed. **/ EFI_STATUS @@ -266,25 +181,31 @@ UsbBootExecCmd ( &CmdResult ); // - // ExecCommand return success and get the right CmdResult means - // the commnad transfer is OK. + // If ExecCommand() returns no error and CmdResult is success, + // then the commnad transfer is successful. // - if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR(Status)) { + if ((CmdResult == USB_MASS_CMD_SUCCESS) && !EFI_ERROR (Status)) { return EFI_SUCCESS; } DEBUG ((EFI_D_INFO, "UsbBootExecCmd: Fail to Exec 0x%x Cmd /w %r\n", *(UINT8 *)Cmd ,Status)); + // + // If command execution failed, then retrieve error info via sense request. + // return UsbBootRequestSense (UsbMass); } /** - Execute the USB mass storage bootability commands. If execution - failed, retrieve the error by REQUEST_SENSE then update the device's - status, such as ReadyOnly. + Execute the USB mass storage bootability commands with retrial. + This function executes USB mass storage bootability commands. + If the device isn't ready, wait for it. If the device is ready + and error occurs, retry the command again until it exceeds the + limit of retrial times. + @param UsbMass The device to issue commands to @param Cmd The command to execute @param CmdLen The length of the command @@ -293,11 +214,9 @@ UsbBootExecCmd ( @param DataLen The length of expected data @param Timeout The timeout used to transfer - @retval EFI_SUCCESS The command is excuted OK - @retval EFI_DEVICE_ERROR Failed to request sense - @retval EFI_INVALID_PARAMETER The command has some invalid parameters - @retval EFI_WRITE_PROTECTED The device is write protected - @retval EFI_MEDIA_CHANGED The device media has been changed + @retval EFI_SUCCESS The command is executed successfully. + @retval EFI_MEDIA_CHANGED The device media has been changed. + @retval Others Command execution failed after retrial. **/ EFI_STATUS @@ -312,18 +231,12 @@ UsbBootExecCmdWithRetry ( ) { EFI_STATUS Status; - INT16 Index; + UINTN Retry; - // - // If the device isn't ready, wait some time. If the device is ready, - // retry the command again. - // Status = EFI_SUCCESS; - for (Index = 0; Index < USB_BOOT_COMMAND_RETRY; Index++) { - // - // Execute the command with an increasingly larger timeout value. - // + for (Retry = 0; Retry < USB_BOOT_COMMAND_RETRY; Retry++) { + Status = UsbBootExecCmd ( UsbMass, Cmd, @@ -333,15 +246,14 @@ UsbBootExecCmdWithRetry ( DataLen, Timeout ); - if (Status == EFI_SUCCESS || - Status == EFI_MEDIA_CHANGED) { + if (Status == EFI_SUCCESS || Status == EFI_MEDIA_CHANGED) { break; } // - // Need retry once more, so reset index + // If the device isn't ready, just wait for it without limit on retrial times. // if (Status == EFI_NOT_READY) { - Index = 0; + Retry = 0; } } @@ -350,12 +262,11 @@ UsbBootExecCmdWithRetry ( /** - Use the TEST UNIT READY command to check whether it is ready. - If it is ready, update the parameters. + Execute TEST UNIT READY command to check if the device is ready. @param UsbMass The device to test - @retval EFI_SUCCESS The device is ready and parameters are updated. + @retval EFI_SUCCESS The device is ready. @retval Others Device not ready. **/ @@ -384,13 +295,13 @@ UsbBootIsUnitReady ( /** - Inquiry Command requests that information regrarding parameters of - the Device be sent to the Host. + Execute INQUIRY Command to request information regarding parameters of + the device be sent to the host computer. - @param UsbMass The device to inquiry. + @param UsbMass The device to inquire. - @retval EFI_SUCCESS The device is ready and parameters are updated. - @retval Others Device not ready. + @retval EFI_SUCCESS INQUIRY Command is executed successfully. + @retval Others INQUIRY Command is not executed successfully. **/ EFI_STATUS @@ -405,9 +316,6 @@ UsbBootInquiry ( Media = &(UsbMass->BlockIoMedia); - // - // Use the Inquiry command to get the RemovableMedia setting. - // ZeroMem (&InquiryCmd, sizeof (USB_BOOT_INQUIRY_CMD)); ZeroMem (&InquiryData, sizeof (USB_BOOT_INQUIRY_DATA)); @@ -428,10 +336,14 @@ UsbBootInquiry ( return Status; } + // + // Get information from PDT (Peripheral Device Type) field and Removable Medium Bit + // from the inquiry data. + // UsbMass->Pdt = (UINT8) (USB_BOOT_PDT (InquiryData.Pdt)); Media->RemovableMedia = (BOOLEAN) (USB_BOOT_REMOVABLE (InquiryData.Removable)); // - // Default value 512 Bytes, in case no media present at first time + // Set block size to the default value of 512 Bytes, in case no media is present at first time. // Media->BlockSize = 0x0200; @@ -440,17 +352,18 @@ UsbBootInquiry ( /** - Get the capacity of the USB mass storage media, including - the presentation, block size, and last block number. This - function is used to get the disk parameters at the start if - it is a non-removable media or to detect the media if it is - removable. + Execute READ CAPACITY command to request information regarding + the capacity of the installed medium of the device. + + This function executes READ CAPACITY command to get the capacity + of the USB mass storage media, including the presence, block size, + and last block number. @param UsbMass The device to retireve disk gemotric. - @retval EFI_SUCCESS The disk gemotric is successfully retrieved. - @retval EFI_DEVICE_ERROR Something is inconsistent with the disk gemotric. - @retval Other Read capacity request fails. + @retval EFI_SUCCESS The disk geometry is successfully retrieved. + @retval EFI_NOT_READY The returned block size is zero. + @retval Other READ CAPACITY command execution failed. **/ EFI_STATUS @@ -465,9 +378,6 @@ UsbBootReadCapacity ( Media = &UsbMass->BlockIoMedia; - // - // Use the READ CAPACITY command to get the block length and last blockno - // ZeroMem (&CapacityCmd, sizeof (USB_BOOT_READ_CAPACITY_CMD)); ZeroMem (&CapacityData, sizeof (USB_BOOT_READ_CAPACITY_DATA)); @@ -487,9 +397,13 @@ UsbBootReadCapacity ( return Status; } + // + // Get the information on media presence, block size, and last block number + // from READ CAPACITY data. + // Media->MediaPresent = TRUE; - Media->LastBlock = UsbBootGetUint32 (CapacityData.LastLba); - Media->BlockSize = UsbBootGetUint32 (CapacityData.BlockLen); + Media->LastBlock = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.LastLba)); + Media->BlockSize = SwapBytes32 (ReadUnaligned32 ((CONST UINT32 *) CapacityData.BlockLen)); if (Media->BlockSize == 0) { return EFI_NOT_READY; @@ -502,13 +416,12 @@ UsbBootReadCapacity ( } /** - Retrieves mode sense information via sending Mode Sense - Packet Command. + Retrieves SCSI mode sense information via MODE SENSE(6) command. - @param UsbMass The USB_FLOPPY_DEV instance. + @param UsbMass The device whose sense data is requested. - @retval EFI_SUCCESS Success - @retval Other Execute Request command fails. + @retval EFI_SUCCESS SCSI mode sense information retrieved successfully. + @retval Other Command execution failed. **/ EFI_STATUS @@ -527,7 +440,7 @@ UsbScsiModeSense ( ZeroMem (&ModeParaHeader, sizeof (USB_SCSI_MODE_SENSE6_PARA_HEADER)); // - // ModeSense6 command is defined in [SCSI2Spec-Page151] + // MODE SENSE(6) command is defined in Section 8.2.10 of SCSI-2 Spec // ModeSenseCmd.OpCode = USB_SCSI_MODE_SENSE6_OPCODE; ModeSenseCmd.Lun = (UINT8) USB_BOOT_LUN (UsbMass->Lun); @@ -545,11 +458,12 @@ UsbScsiModeSense ( ); // - // ModeSense(6) is used to get the information of WriteProtected. While only some of - // devices support this command, so have a try here. + // Format of device-specific parameter byte of the mode parameter header is defined in + // Section 8.2.10 of SCSI-2 Spec. + // BIT7 of this byte is indicates whether the medium is write protected. // if (!EFI_ERROR (Status)) { - Media->ReadOnly = (BOOLEAN) (((ModeParaHeader.DevicePara & 0x80) != 0) ? TRUE : FALSE); + Media->ReadOnly = (BOOLEAN) ((ModeParaHeader.DevicePara & BIT7) != 0); } return Status; @@ -557,17 +471,18 @@ UsbScsiModeSense ( /** - Get the parameters for the USB mass storage media, including - the RemovableMedia, block size, and last block number. This - function is used both to initialize the media during the - DriverBindingStart and to re-initialize it when the media is - changed. Althought the RemoveableMedia is unlikely to change, - I include it here. + Get the parameters for the USB mass storage media. - @param UsbMass The device to retireve disk gemotric. + This function get the parameters for the USB mass storage media, + It is used both to initialize the media during the Start() phase + of Driver Binding Protocol and to re-initialize it when the media is + changed. Althought the RemoveableMedia is unlikely to change, + it is also included here. + + @param UsbMass The device to retrieve disk gemotric. @retval EFI_SUCCESS The disk gemotric is successfully retrieved. - @retval Other Get the parameters failed. + @retval Other Failed to get the parameters. **/ EFI_STATUS @@ -589,7 +504,7 @@ UsbBootGetParams ( } // - // Don't use the Removable bit in inquirydata to test whether the media + // Don't use the Removable bit in inquiry data to test whether the media // is removable because many flash disks wrongly set this bit. // if ((UsbMass->Pdt == USB_PDT_CDROM) || (UsbMass->Pdt == USB_PDT_OPTICAL)) { @@ -620,12 +535,11 @@ UsbBootGetParams ( /** Detect whether the removable media is present and whether it has changed. - The Non-removable media doesn't need it. - @param UsbMass The device to retireve disk gemotric. + @param UsbMass The device to check. - @retval EFI_SUCCESS The disk gemotric is successfully retrieved. - @retval Other Decect media fails. + @retval EFI_SUCCESS The media status is successfully checked. + @retval Other Failed to detect media. **/ EFI_STATUS @@ -641,27 +555,22 @@ UsbBootDetectMedia ( Media = &UsbMass->BlockIoMedia; - CopyMem ( - &OldMedia, - &(UsbMass->BlockIoMedia), - sizeof (EFI_BLOCK_IO_MEDIA) - ); + CopyMem (&OldMedia, &(UsbMass->BlockIoMedia), sizeof (EFI_BLOCK_IO_MEDIA)); CmdSet = ((EFI_USB_INTERFACE_DESCRIPTOR *) (UsbMass->Context))->InterfaceSubClass; Status = UsbBootIsUnitReady (UsbMass); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: UsbBootIsUnitReady (%r)\n", Status)); goto ON_ERROR; } if ((UsbMass->Pdt != USB_PDT_CDROM) && (CmdSet == USB_MASS_STORE_SCSI)) { // - // ModeSense is required for the device with PDT of 0x00/0x07/0x0E, - // which is from [MassStorageBootabilitySpec-Page7]. - // ModeSense(10) is useless here, while ModeSense(6) defined in SCSI - // could get the information of WriteProtected. - // Since not all device support this command, so skip if fail. + // MODE SENSE is required for the device with PDT of 0x00/0x07/0x0E, + // according to Section 4 of USB Mass Storage Specification for Bootability. + // MODE SENSE(10) is useless here, while MODE SENSE(6) defined in SCSI + // could get the information of Write Protected. + // Since not all device support this command, skip if fail. // UsbScsiModeSense (UsbMass); } @@ -676,7 +585,7 @@ UsbBootDetectMedia ( ON_ERROR: // - // Detect whether it is necessary to reinstall the BlockIO + // Detect whether it is necessary to reinstall the Block I/O Protocol. // // MediaId may change in RequestSense for MediaChanged // MediaPresent may change in RequestSense for NoMedia @@ -689,9 +598,11 @@ ON_ERROR: (Media->BlockSize != OldMedia.BlockSize) || (Media->LastBlock != OldMedia.LastBlock)) { - OldTpl = UsbGetCurrentTpl (); - DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL before reinstall BlockIoProtocol is %d\n", (UINT32)OldTpl)); - + // + // This function is called by Block I/O Protocol APIs, which run at TPL_NOTIFY. + // Here we temporarily restore TPL to TPL_CALLBACK to invoke ReinstallProtocolInterface(). + // + OldTpl = EfiGetCurrentTpl (); gBS->RestoreTPL (TPL_CALLBACK); gBS->ReinstallProtocolInterface ( @@ -701,16 +612,14 @@ ON_ERROR: &UsbMass->BlockIo ); - DEBUG ((EFI_D_ERROR, "UsbBootDetectMedia: TPL after reinstall is %d\n", (UINT32)UsbGetCurrentTpl())); - ASSERT (UsbGetCurrentTpl () == TPL_CALLBACK); - + ASSERT (EfiGetCurrentTpl () == TPL_CALLBACK); gBS->RaiseTPL (OldTpl); // - // Update MediaId after reinstall BLOCK_IO_PROTOCOL + // Update MediaId after reinstalling Block I/O Protocol. // if (Media->MediaPresent != OldMedia.MediaPresent) { - if (Media->MediaPresent == TRUE) { + if (Media->MediaPresent) { Media->MediaId = 1; } else { Media->MediaId = 0; @@ -779,8 +688,8 @@ UsbBootReadBlocks ( ReadCmd.OpCode = USB_BOOT_READ10_OPCODE; ReadCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - UsbBootPutUint32 (ReadCmd.Lba, Lba); - UsbBootPutUint16 (ReadCmd.TransferLen, Count); + WriteUnaligned32 ((UINT32 *) ReadCmd.Lba, SwapBytes32 (Lba)); + WriteUnaligned16 ((UINT16 *) ReadCmd.TransferLen, SwapBytes16 (Count)); Status = UsbBootExecCmdWithRetry ( UsbMass, @@ -810,7 +719,7 @@ UsbBootReadBlocks ( @param UsbMass The USB mass storage device to write to @param Lba The start block number @param TotalBlock Total block number to write - @param Buffer The buffer to write to + @param Buffer Pointer to the source buffer for the data. @retval EFI_SUCCESS Data are written into the buffer @retval Others Failed to write all the data @@ -821,7 +730,7 @@ UsbBootWriteBlocks ( IN USB_MASS_DEVICE *UsbMass, IN UINT32 Lba, IN UINTN TotalBlock, - OUT UINT8 *Buffer + IN UINT8 *Buffer ) { USB_BOOT_WRITE10_CMD WriteCmd; @@ -855,8 +764,8 @@ UsbBootWriteBlocks ( WriteCmd.OpCode = USB_BOOT_WRITE10_OPCODE; WriteCmd.Lun = (UINT8) (USB_BOOT_LUN (UsbMass->Lun)); - UsbBootPutUint32 (WriteCmd.Lba, Lba); - UsbBootPutUint16 (WriteCmd.TransferLen, Count); + WriteUnaligned32 ((UINT32 *) WriteCmd.Lba, SwapBytes32 (Lba)); + WriteUnaligned16 ((UINT16 *) WriteCmd.TransferLen, SwapBytes16 (Count)); Status = UsbBootExecCmdWithRetry ( UsbMass, @@ -881,14 +790,13 @@ UsbBootWriteBlocks ( /** - Use the USB clear feature control transfer to clear the endpoint - stall condition. + Use the USB clear feature control transfer to clear the endpoint stall condition. - @param UsbIo The USB IO protocol to use + @param UsbIo The USB I/O Protocol instance @param EndpointAddr The endpoint to clear stall for - @retval EFI_SUCCESS The endpoint stall condtion is clear - @retval Others Failed to clear the endpoint stall condtion + @retval EFI_SUCCESS The endpoint stall condition is cleared. + @retval Others Failed to clear the endpoint stall condition. **/ EFI_STATUS diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h index daad70131c..ab3fb68e4a 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBoot.h @@ -1,6 +1,8 @@ /** @file + Definition of the command set of USB Mass Storage Specification + for Bootability, Revision 1.0. -Copyright (c) 2007, Intel Corporation +Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License which accompanies this distribution. The full text of the license may be found at @@ -9,18 +11,6 @@ http://opensource.org/licenses/bsd-license.php THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - - UsbMassBoot.h - -Abstract: - - The definition of command and data of the USB mass storage for - bootability command set. - -Revision History - - **/ #ifndef _EFI_USB_MASS_BOOT_H_ @@ -28,13 +18,11 @@ Revision History typedef enum { // - // The opcodes of various usb boot commands: + // The opcodes of various USB boot commands: // INQUIRY/REQUEST_SENSE are "No Timeout Commands" as specified - // by MMC command set. Others are "Group 1 Timeout Commands". That - // is they should be retried if driver is ready. - // We can't use the Peripheral Device Type in Inquiry data to - // determine the timeout used. For example, both floppy and flash - // are likely set their PDT to 0, or Direct Access Device. + // by Multi-Media Commands (MMC) set. + // Others are "Group 1 Timeout Commands". That is, + // they should be retried if driver is ready. // USB_BOOT_INQUIRY_OPCODE = 0x12, USB_BOOT_REQUEST_SENSE_OPCODE = 0x03, @@ -50,19 +38,19 @@ typedef enum { // The Sense Key part of the sense data. Sense data has three levels: // Sense key, Additional Sense Code and Additional Sense Code Qualifier // - USB_BOOT_SENSE_NO_SENSE = 0x00, // No sense key - USB_BOOT_SENSE_RECOVERED = 0x01, // Last command succeed with recovery actions - USB_BOOT_SENSE_NOT_READY = 0x02, // Device not ready - USB_BOOT_SNESE_MEDIUM_ERROR = 0X03, // Failed probably because flaw in the media - USB_BOOT_SENSE_HARDWARE_ERROR = 0X04, // Non-recoverable hardware failure - USB_BOOT_SENSE_ILLEGAL_REQUEST = 0X05, // Illegal parameters in the request - USB_BOOT_SENSE_UNIT_ATTENTION = 0X06, // Removable medium may have been changed - USB_BOOT_SNESE_DATA_PROTECT = 0X07, // Write protected - USB_BOOT_SENSE_BLANK_CHECK = 0X08, // Blank/non-blank medium while reading/writing - USB_BOOT_SENSE_VENDOR = 0X09, // Vendor specific sense key - USB_BOOT_SENSE_ABORTED = 0X0B, // Command aborted by the device - USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, // Partition overflow - USB_BOOT_SENSE_MISCOMPARE = 0x0E, // Source data mis-match while verfying. + USB_BOOT_SENSE_NO_SENSE = 0x00, ///< No sense key + USB_BOOT_SENSE_RECOVERED = 0x01, ///< Last command succeed with recovery actions + USB_BOOT_SENSE_NOT_READY = 0x02, ///< Device not ready + USB_BOOT_SNESE_MEDIUM_ERROR = 0X03, ///< Failed probably because flaw in the media + USB_BOOT_SENSE_HARDWARE_ERROR = 0X04, ///< Non-recoverable hardware failure + USB_BOOT_SENSE_ILLEGAL_REQUEST = 0X05, ///< Illegal parameters in the request + USB_BOOT_SENSE_UNIT_ATTENTION = 0X06, ///< Removable medium may have been changed + USB_BOOT_SENSE_DATA_PROTECT = 0X07, ///< Write protected + USB_BOOT_SENSE_BLANK_CHECK = 0X08, ///< Blank/non-blank medium while reading/writing + USB_BOOT_SENSE_VENDOR = 0X09, ///< Vendor specific sense key + USB_BOOT_SENSE_ABORTED = 0X0B, ///< Command aborted by the device + USB_BOOT_SENSE_VOLUME_OVERFLOW = 0x0D, ///< Partition overflow + USB_BOOT_SENSE_MISCOMPARE = 0x0E, ///< Source data mis-match while verfying. USB_BOOT_ASC_NOT_READY = 0x04, USB_BOOT_ASC_NO_MEDIA = 0x3A, @@ -71,10 +59,10 @@ typedef enum { // // Supported PDT codes, or Peripheral Device Type // - USB_PDT_DIRECT_ACCESS = 0x00, // Direct access device - USB_PDT_CDROM = 0x05, // CDROM - USB_PDT_OPTICAL = 0x07, // Non-CD optical disks - USB_PDT_SIMPLE_DIRECT = 0x0E, // Simplified direct access device + USB_PDT_DIRECT_ACCESS = 0x00, ///< Direct access device + USB_PDT_CDROM = 0x05, ///< CDROM + USB_PDT_OPTICAL = 0x07, ///< Non-CD optical disks + USB_PDT_SIMPLE_DIRECT = 0x0E, ///< Simplified direct access device // // Other parameters, Max carried size is 512B * 128 = 64KB @@ -99,7 +87,6 @@ typedef enum { // USB CD-Rom and iPod devices are much slower than USB key when reponse // most of commands, So we set 5s as timeout here. // - // USB_BOOT_GENERAL_CMD_TIMEOUT = 5 * USB_MASS_1_SECOND }USB_BOOT_OPTCODE; @@ -112,7 +99,7 @@ typedef enum { #pragma pack(1) typedef struct { UINT8 OpCode; - UINT8 Lun; // Lun (high 3 bits) + UINT8 Lun; ///< Lun (high 3 bits) UINT8 Reserved0[2]; UINT8 AllocLen; UINT8 Reserved1; @@ -120,10 +107,10 @@ typedef struct { } USB_BOOT_INQUIRY_CMD; typedef struct { - UINT8 Pdt; // Peripheral Device Type (low 5 bits) - UINT8 Removable; // Removable Media (highest bit) + UINT8 Pdt; ///< Peripheral Device Type (low 5 bits) + UINT8 Removable; ///< Removable Media (highest bit) UINT8 Reserved0[2]; - UINT8 AddLen; // Additional length + UINT8 AddLen; ///< Additional length UINT8 Reserved1[3]; UINT8 VendorID[8]; UINT8 ProductID[16]; @@ -170,10 +157,10 @@ typedef struct { typedef struct { UINT8 OpCode; - UINT8 Lun; // Lun (High 3 bits) - UINT8 Lba[4]; // Logical block address + UINT8 Lun; ///< Lun (High 3 bits) + UINT8 Lba[4]; ///< Logical block address UINT8 Reserved0; - UINT8 TransferLen[2]; // Transfer length + UINT8 TransferLen[2]; ///< Transfer length UINT8 Reserverd1; UINT8 Pad[2]; } USB_BOOT_READ10_CMD; @@ -190,9 +177,9 @@ typedef struct { typedef struct { UINT8 OpCode; - UINT8 Lun; // Lun (High 3 bits) + UINT8 Lun; ///< Lun (High 3 bits) UINT8 Reserved0[2]; - UINT8 AllocLen; // Allocation length + UINT8 AllocLen; ///< Allocation length UINT8 Reserved1; UINT8 Pad[6]; } USB_BOOT_REQUEST_SENSE_CMD; @@ -200,12 +187,12 @@ typedef struct { typedef struct { UINT8 ErrorCode; UINT8 Reserved0; - UINT8 SenseKey; // Sense key (low 4 bits) + UINT8 SenseKey; ///< Sense key (low 4 bits) UINT8 Infor[4]; - UINT8 AddLen; // Additional Sense length, 10 + UINT8 AddLen; ///< Additional Sense length, 10 UINT8 Reserved1[4]; - UINT8 ASC; // Additional Sense Code - UINT8 ASCQ; // Additional Sense Code Qualifier + UINT8 ASC; ///< Additional Sense Code + UINT8 ASCQ; ///< Additional Sense Code Qualifier UINT8 Reserverd2[4]; } USB_BOOT_REQUEST_SENSE_DATA; @@ -234,22 +221,10 @@ typedef struct { // // Get the removable, PDT, and sense key bits from the command data // -#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & 0x80) != 0) +#define USB_BOOT_REMOVABLE(RmbByte) (((RmbByte) & BIT7) != 0) #define USB_BOOT_PDT(Pdt) ((Pdt) & 0x1f) #define USB_BOOT_SENSE_KEY(Key) ((Key) & 0x0f) -// -// Swap the byte sequence of a UINT32. Intel CPU uses little endian -// in UEFI environment, but USB boot uses big endian. -// -#define USB_BOOT_SWAP32(Data32) \ - ((((Data32) & 0x000000ff) << 24) | (((Data32) & 0xff000000) >> 24) | \ - (((Data32) & 0x0000ff00) << 8) | (((Data32) & 0x00ff0000) >> 8)) - -#define USB_BOOT_SWAP16(Data16) \ - ((((Data16) & 0x00ff) << 8) | (((Data16) & 0xff00) >> 8)) - - /** Get the parameters for the USB mass storage media, including the RemovableMedia, block size, and last block number. This diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c index ba5f9d025b..178aa80d3e 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.c @@ -1,6 +1,6 @@ /** @file - - Implementation of the USB mass storage Bulk-Only Transport protocol. + Implementation of the USB mass storage Bulk-Only Transport protocol, + according to USB Mass Storage Class Bulk-Only Transport, Revision 1.0. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -16,41 +16,36 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UsbMass.h" #include "UsbMassBot.h" -/** - Reset the mass storage device by BOT protocol. - - @param Context The context of the BOT protocol, that is, - USB_BOT_PROTOCOL. - @param ExtendedVerification The flag controlling the rule of reset dev. - - @retval EFI_SUCCESS The device is reset. - @retval Others Failed to reset the device.. - -**/ -EFI_STATUS -UsbBotResetDevice ( - IN VOID *Context, - IN BOOLEAN ExtendedVerification - ); - +// +// Definition of USB BOT Transport Protocol +// +USB_MASS_TRANSPORT mUsbBotTransport = { + USB_MASS_STORE_BOT, + UsbBotInit, + UsbBotExecCommand, + UsbBotResetDevice, + UsbBotGetMaxLun, + UsbBotCleanUp +}; /** - Initialize the USB mass storage class BOT transport protocol. + Initializes USB BOT protocol. + + This function initializes the USB mass storage class BOT protocol. It will save its context which is a USB_BOT_PROTOCOL structure in the Context if Context isn't NULL. - @param UsbIo The USB IO protocol to use - @param Context The variable to save the context to + @param UsbIo The USB I/O Protocol instance + @param Context The buffer to save the context to - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory + @retval EFI_SUCCESS The device is successfully initialized. @retval EFI_UNSUPPORTED The transport protocol doesn't support the device. - @retval EFI_SUCCESS The device is supported and protocol initialized. - @retval Other The UBS BOT initialization fails. + @retval Other The USB BOT initialization fails. **/ EFI_STATUS UsbBotInit ( - IN EFI_USB_IO_PROTOCOL * UsbIo, + IN EFI_USB_IO_PROTOCOL *UsbIo, OUT VOID **Context OPTIONAL ) { @@ -61,25 +56,22 @@ UsbBotInit ( UINT8 Index; // - // Allocate the BOT context, append two endpoint descriptors to it + // Allocate the BOT context for USB_BOT_PROTOCOL and two endpoint descriptors. // UsbBot = AllocateZeroPool ( sizeof (USB_BOT_PROTOCOL) + 2 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) ); - if (UsbBot == NULL) { - return EFI_OUT_OF_RESOURCES; - } + ASSERT (UsbBot != NULL); UsbBot->UsbIo = UsbIo; // // Get the interface descriptor and validate that it - // is a USB MSC BOT interface. + // is a USB Mass Storage BOT interface. // Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbBot->Interface); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBotInit: Get invalid BOT interface (%r)\n", Status)); goto ON_ERROR; } @@ -115,14 +107,16 @@ UsbBotInit ( } } + // + // If bulk-in or bulk-out endpoint is not found, report error. + // if ((UsbBot->BulkInEndpoint == NULL) || (UsbBot->BulkOutEndpoint == NULL)) { - DEBUG ((EFI_D_ERROR, "UsbBotInit: In/Out Endpoint invalid\n")); Status = EFI_UNSUPPORTED; goto ON_ERROR; } // - // The USB BOT protocol uses dCBWTag to match the CBW and CSW. + // The USB BOT protocol uses CBWTag to match the CBW and CSW. // UsbBot->CbwTag = 0x01; @@ -139,19 +133,22 @@ ON_ERROR: return Status; } - /** Send the command to the device using Bulk-Out endpoint. + This function sends the command to the device using Bulk-Out endpoint. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Command phase. + @param UsbBot The USB BOT device @param Cmd The command to transfer to device - @param CmdLen the length of the command + @param CmdLen The length of the command @param DataDir The direction of the data @param TransLen The expected length of the data @param Lun The number of logic unit - @retval EFI_NOT_READY The device return NAK to the transfer @retval EFI_SUCCESS The command is sent to the device. + @retval EFI_NOT_READY The device return NAK to the transfer @retval Others Failed to send the command to device **/ @@ -174,25 +171,24 @@ UsbBotSendCommand ( ASSERT ((CmdLen > 0) && (CmdLen <= USB_BOT_MAX_CMDLEN)); // - // Fill in the CSW. Only the first LUN is supported now. + // Fill in the Command Block Wrapper. // Cbw.Signature = USB_BOT_CBW_SIGNATURE; Cbw.Tag = UsbBot->CbwTag; Cbw.DataLen = TransLen; - Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? 0x80 : 0); + Cbw.Flag = (UINT8) ((DataDir == EfiUsbDataIn) ? BIT7 : 0); Cbw.Lun = Lun; Cbw.CmdLen = CmdLen; ZeroMem (Cbw.CmdBlock, USB_BOT_MAX_CMDLEN); CopyMem (Cbw.CmdBlock, Cmd, CmdLen); - Result = 0; - DataLen = sizeof (USB_BOT_CBW); - Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND; + Result = 0; + DataLen = sizeof (USB_BOT_CBW); + Timeout = USB_BOT_SEND_CBW_TIMEOUT / USB_MASS_1_MILLISECOND; // - // Use the UsbIo to send the command to the device. The default - // time out is enough. + // Use USB I/O Protocol to send the Command Block Wrapper to the device. // Status = UsbBot->UsbIo->UsbBulkTransfer ( UsbBot->UsbIo, @@ -202,12 +198,12 @@ UsbBotSendCommand ( Timeout, &Result ); - // - // Respond to Bulk-Out endpoint stall with a Reset Recovery, - // see the spec section 5.3.1 - // if (EFI_ERROR (Status)) { if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL) && DataDir == EfiUsbDataOut) { + // + // Respond to Bulk-Out endpoint stall with a Reset Recovery, + // according to section 5.3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0. + // UsbBotResetDevice (UsbBot, FALSE); } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) { Status = EFI_NOT_READY; @@ -219,8 +215,11 @@ UsbBotSendCommand ( /** - Transfer the data between the device and host. BOT transfer - is composed of three phase, command, data, and status. + Transfer the data between the device and host. + + This function transfers the data between the device and host. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Data phase. @param UsbBot The USB BOT device @param DataDir The direction of the data @@ -229,6 +228,8 @@ UsbBotSendCommand ( @param Timeout The time to wait the command to complete @retval EFI_SUCCESS The data is transferred + @retval EFI_SUCCESS No data to transfer + @retval EFI_NOT_READY The device return NAK to the transfer @retval Others Failed to transfer data **/ @@ -246,7 +247,7 @@ UsbBotDataTransfer ( UINT32 Result; // - // It's OK if no data to transfer + // If no data to transfer, just return EFI_SUCCESS. // if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) { return EFI_SUCCESS; @@ -273,9 +274,7 @@ UsbBotDataTransfer ( &Result ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: (%r)\n", Status)); if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) { - DEBUG ((EFI_D_ERROR, "UsbBotDataTransfer: DataIn Stall\n")); UsbClearEndpointStall (UsbBot->UsbIo, Endpoint->EndpointAddress); } else if (USB_IS_ERROR (Result, EFI_USB_ERR_NAK)) { Status = EFI_NOT_READY; @@ -287,19 +286,22 @@ UsbBotDataTransfer ( /** - Get the command execution status from device. BOT transfer is - composed of three phase, command, data, and status. - This function return the transfer status of the BOT's CSW status, - and return the high level command execution result in Result. So - even it returns EFI_SUCCESS, the command may still have failed. + Get the command execution status from device. - @param UsbBot The USB BOT device. - @param TransLen The expected length of the data. - @param CmdStatus The result of the command execution. + This function gets the command execution status from device. + BOT transfer is composed of three phases: Command, Data, and Status. + This is the Status phase. - @retval EFI_SUCCESS Command execute result is retrieved and in the - Result. - @retval Other Failed to get status. + This function returns the transfer status of the BOT's CSW status, + and returns the high level command execution result in Result. So + even if EFI_SUCCESS is returned, the command may still have failed. + + @param UsbBot The USB BOT device. + @param TransLen The expected length of the data. + @param CmdStatus The result of the command execution. + + @retval EFI_SUCCESS Command execute result is retrieved and in the Result. + @retval Other Error occurred when trying to get status. **/ EFI_STATUS @@ -326,7 +328,7 @@ UsbBotGetStatus ( for (Index = 0; Index < USB_BOT_RECV_CSW_RETRY; Index++) { // - // Attemp to the read CSW from bulk in endpoint + // Attemp to the read Command Status Wrapper from bulk in endpoint // ZeroMem (&Csw, sizeof (USB_BOT_CSW)); Result = 0; @@ -340,9 +342,7 @@ UsbBotGetStatus ( &Result ); if (EFI_ERROR(Status)) { - DEBUG ((EFI_D_ERROR, "UsbBotGetStatus (%r)\n", Status)); if (USB_IS_ERROR (Result, EFI_USB_ERR_STALL)) { - DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: DataIn Stall\n")); UsbClearEndpointStall (UsbIo, Endpoint); } continue; @@ -350,24 +350,21 @@ UsbBotGetStatus ( if (Csw.Signature != USB_BOT_CSW_SIGNATURE) { // - // Invalid Csw need perform reset recovery + // CSW is invalid, so perform reset recovery // - DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a invalid signature\n")); Status = UsbBotResetDevice (UsbBot, FALSE); } else if (Csw.CmdStatus == USB_BOT_COMMAND_ERROR) { // - // Respond phase error need perform reset recovery + // Respond phase error also needs reset recovery // - DEBUG ((EFI_D_ERROR, "UsbBotGetStatus: Device return a phase error\n")); Status = UsbBotResetDevice (UsbBot, FALSE); } else { - *CmdStatus = Csw.CmdStatus; break; } } // - //The tag is increased even there is an error. + //The tag is increased even if there is an error. // UsbBot->CbwTag++; @@ -376,7 +373,7 @@ UsbBotGetStatus ( /** - Call the Usb mass storage class transport protocol to issue + Call the USB Mass Storage Class BOT protocol to issue the command/data/status circle to execute the commands. @param Context The context of the BOT protocol, that is, @@ -390,7 +387,7 @@ UsbBotGetStatus ( @param Timeout The time to wait command @param CmdStatus The result of high level command execution - @retval EFI_SUCCESS The command is executed OK, and result in CmdStatus + @retval EFI_SUCCESS The command is executed successfully. @retval Other Failed to excute command **/ @@ -428,7 +425,7 @@ UsbBotExecCommand ( // // Transfer the data. Don't return immediately even data transfer // failed. The host should attempt to receive the CSW no matter - // whether it succeeds or failed. + // whether it succeeds or fails. // TransLen = (UINTN) DataLen; UsbBotDataTransfer (UsbBot, DataDir, Data, &TransLen, Timeout); @@ -451,11 +448,12 @@ UsbBotExecCommand ( /** - Reset the mass storage device by BOT protocol. + Reset the USB mass storage device by BOT protocol. @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL. - @param ExtendedVerification The flag controlling the rule of reset dev. + @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request. + If TRUE, additionally reset parent hub port. @retval EFI_SUCCESS The device is reset. @retval Others Failed to reset the device.. @@ -464,7 +462,7 @@ UsbBotExecCommand ( EFI_STATUS UsbBotResetDevice ( IN VOID *Context, - IN BOOLEAN ExtendedVerification + IN BOOLEAN ExtendedVerification ) { USB_BOT_PROTOCOL *UsbBot; @@ -486,10 +484,10 @@ UsbBotResetDevice ( } // - // Issue a class specific Bulk-Only Mass Storage Reset reqest. - // See the spec section 3.1 + // Issue a class specific Bulk-Only Mass Storage Reset request, + // according to section 3.1 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0. // - Request.RequestType = 0x21; // Class, Interface, Host to Device + Request.RequestType = 0x21; Request.Request = USB_BOT_RESET_REQUEST; Request.Value = 0; Request.Index = UsbBot->Interface.InterfaceNumber; @@ -507,14 +505,13 @@ UsbBotResetDevice ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBotResetDevice: (%r)\n", Status)); return Status; } // // The device shall NAK the host's request until the reset is // complete. We can use this to sync the device and host. For - // now just stall 100ms to wait the device. + // now just stall 100ms to wait for the device. // gBS->Stall (USB_BOT_RESET_DEVICE_STALL); @@ -523,25 +520,26 @@ UsbBotResetDevice ( // UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkInEndpoint->EndpointAddress); UsbClearEndpointStall (UsbBot->UsbIo, UsbBot->BulkOutEndpoint->EndpointAddress); + return Status; } /** - Get the max lun of mass storage device. + Get the max LUN (Logical Unit Number) of USB mass storage device. @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL - @param MaxLun Return pointer to the max number of lun. Maxlun=1 means lun0 and - lun1 in all. + @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and + LUN1 in all.) - @retval EFI_SUCCESS Get max lun success. - @retval Others Failed to execute this request. + @retval EFI_SUCCESS Max LUN is got successfully. + @retval Others Fail to execute this request. **/ EFI_STATUS UsbBotGetMaxLun ( IN VOID *Context, - IN UINT8 *MaxLun + OUT UINT8 *MaxLun ) { USB_BOT_PROTOCOL *UsbBot; @@ -556,9 +554,9 @@ UsbBotGetMaxLun ( // // Issue a class specific Bulk-Only Mass Storage get max lun reqest. - // See the spec section 3.2 + // according to section 3.2 of USB Mass Storage Class Bulk-Only Transport Spec, v1.0. // - Request.RequestType = 0xA1; // Class, Interface, Device to Host + Request.RequestType = 0xA1; Request.Request = USB_BOT_GETLUN_REQUEST; Request.Value = 0; Request.Index = UsbBot->Interface.InterfaceNumber; @@ -570,29 +568,24 @@ UsbBotGetMaxLun ( &Request, EfiUsbDataIn, Timeout, - (VOID *)MaxLun, + (VOID *) MaxLun, 1, &Result ); - if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbBotGetMaxLun: (%r)\n", Status)); - } - return Status; } /** Clean up the resource used by this BOT protocol. - @param Context The context of the BOT protocol, that is, - USB_BOT_PROTOCOL. + @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL. - @retval EFI_SUCCESS The resource is cleaned up. + @retval EFI_SUCCESS The resource is cleaned up. **/ EFI_STATUS -UsbBotFini ( +UsbBotCleanUp ( IN VOID *Context ) { @@ -600,13 +593,3 @@ UsbBotFini ( return EFI_SUCCESS; } -USB_MASS_TRANSPORT -mUsbBotTransport = { - USB_MASS_STORE_BOT, - UsbBotInit, - UsbBotExecCommand, - UsbBotResetDevice, - UsbBotGetMaxLun, - UsbBotFini -}; - diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h index 6b1705c11a..7f6f5fff8e 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassBot.h @@ -1,8 +1,7 @@ /** @file - - Defination for the USB mass storage Bulk-Only Transport protocol. - This implementation is based on the "Universal Serial Bus Mass - Storage Class Bulk-Only Transport" Revision 1.0, September 31, 1999. + Definition for the USB mass storage Bulk-Only Transport protocol, + based on the "Universal Serial Bus Mass Storage Class Bulk-Only + Transport" Revision 1.0, September 31, 1999. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -18,33 +17,35 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef _EFI_USBMASS_BOT_H_ #define _EFI_USBMASS_BOT_H_ +extern USB_MASS_TRANSPORT mUsbBotTransport; + typedef enum { // // Usb Bulk-Only class specfic request // - USB_BOT_RESET_REQUEST = 0xFF, // Bulk-Only Mass Storage Reset - USB_BOT_GETLUN_REQUEST = 0xFE, // Get Max Lun - USB_BOT_CBW_SIGNATURE = 0x43425355, // dCBWSignature, tag the packet as CBW - USB_BOT_CSW_SIGNATURE = 0x53425355, // dCSWSignature, tag the packet as CSW - USB_BOT_MAX_LUN = 0x0F, // Lun number is from 0 to 15 - USB_BOT_MAX_CMDLEN = 16, // Maxium number of command from command set + USB_BOT_RESET_REQUEST = 0xFF, ///< Bulk-Only Mass Storage Reset + USB_BOT_GETLUN_REQUEST = 0xFE, ///< Get Max Lun + USB_BOT_CBW_SIGNATURE = 0x43425355, ///< dCBWSignature, tag the packet as CBW + USB_BOT_CSW_SIGNATURE = 0x53425355, ///< dCSWSignature, tag the packet as CSW + USB_BOT_MAX_LUN = 0x0F, ///< Lun number is from 0 to 15 + USB_BOT_MAX_CMDLEN = 16, ///< Maxium number of command from command set // // Usb BOT command block status values // - USB_BOT_COMMAND_OK = 0x00, // Command passed, good status - USB_BOT_COMMAND_FAILED = 0x01, // Command failed - USB_BOT_COMMAND_ERROR = 0x02, // Phase error, need to reset the device + USB_BOT_COMMAND_OK = 0x00, ///< Command passed, good status + USB_BOT_COMMAND_FAILED = 0x01, ///< Command failed + USB_BOT_COMMAND_ERROR = 0x02, ///< Phase error, need to reset the device // // Usb Bot retry to get CSW, refers to specification[BOT10-5.3, it says 2 times] // - USB_BOT_RECV_CSW_RETRY = 3, + USB_BOT_RECV_CSW_RETRY = 3, // // Usb Bot wait device reset complete, set by experience // - USB_BOT_RESET_DEVICE_STALL = 100 * USB_MASS_1_MILLISECOND, + USB_BOT_RESET_DEVICE_STALL = 100 * USB_MASS_1_MILLISECOND, // // Usb Bot transport timeout, set by experience @@ -52,23 +53,25 @@ typedef enum { USB_BOT_SEND_CBW_TIMEOUT = 3 * USB_MASS_1_SECOND, USB_BOT_RECV_CSW_TIMEOUT = 3 * USB_MASS_1_SECOND, USB_BOT_RESET_DEVICE_TIMEOUT = 3 * USB_MASS_1_SECOND -}USB_BOT_SUBCLASS; +} USB_BOT_SUBCLASS; -// -// The CBW (Command Block Wrapper) and CSW (Command Status Wrapper) -// structures used by the Usb BOT protocol. -// #pragma pack(1) +/// +/// The CBW (Command Block Wrapper) structures used by the USB BOT protocol. +/// typedef struct { UINT32 Signature; UINT32 Tag; - UINT32 DataLen; // Length of data between CBW and CSW - UINT8 Flag; // Bit 7, 0 ~ Data-Out, 1 ~ Data-In - UINT8 Lun; // Lun number. Bits 0~3 are used - UINT8 CmdLen; // Length of the command. Bits 0~4 are used + UINT32 DataLen; ///< Length of data between CBW and CSW + UINT8 Flag; ///< Bit 7, 0 ~ Data-Out, 1 ~ Data-In + UINT8 Lun; ///< Lun number. Bits 0~3 are used + UINT8 CmdLen; ///< Length of the command. Bits 0~4 are used UINT8 CmdBlock[USB_BOT_MAX_CMDLEN]; } USB_BOT_CBW; +/// +/// The and CSW (Command Status Wrapper) structures used by the USB BOT protocol. +/// typedef struct { UINT32 Signature; UINT32 Tag; @@ -77,11 +80,10 @@ typedef struct { } USB_BOT_CSW; #pragma pack() -// -// Put Interface at the first field is to make it easy to get by Context, which -// could be BOT/CBI Protocol instance -// typedef struct { + // + // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance + // EFI_USB_INTERFACE_DESCRIPTOR Interface; EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint; @@ -89,5 +91,105 @@ typedef struct { EFI_USB_IO_PROTOCOL *UsbIo; } USB_BOT_PROTOCOL; -extern USB_MASS_TRANSPORT mUsbBotTransport; +/** + Initializes USB BOT protocol. + + This function initializes the USB mass storage class BOT protocol. + It will save its context which is a USB_BOT_PROTOCOL structure + in the Context if Context isn't NULL. + + @param UsbIo The USB I/O Protocol instance + @param Context The buffer to save the context to + + @retval EFI_SUCCESS The device is successfully initialized. + @retval EFI_UNSUPPORTED The transport protocol doesn't support the device. + @retval Other The USB BOT initialization fails. + +**/ +EFI_STATUS +UsbBotInit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT VOID **Context OPTIONAL + ); + +/** + Call the USB Mass Storage Class BOT protocol to issue + the command/data/status circle to execute the commands. + + @param Context The context of the BOT protocol, that is, + USB_BOT_PROTOCOL + @param Cmd The high level command + @param CmdLen The command length + @param DataDir The direction of the data transfer + @param Data The buffer to hold data + @param DataLen The length of the data + @param Lun The number of logic unit + @param Timeout The time to wait command + @param CmdStatus The result of high level command execution + + @retval EFI_SUCCESS The command is executed successfully. + @retval Other Failed to excute command + +**/ +EFI_STATUS +UsbBotExecCommand ( + IN VOID *Context, + IN VOID *Cmd, + IN UINT8 CmdLen, + IN EFI_USB_DATA_DIRECTION DataDir, + IN VOID *Data, + IN UINT32 DataLen, + IN UINT8 Lun, + IN UINT32 Timeout, + OUT UINT32 *CmdStatus + ); + +/** + Reset the USB mass storage device by BOT protocol. + + @param Context The context of the BOT protocol, that is, + USB_BOT_PROTOCOL. + @param ExtendedVerification If FALSE, just issue Bulk-Only Mass Storage Reset request. + If TRUE, additionally reset parent hub port. + + @retval EFI_SUCCESS The device is reset. + @retval Others Failed to reset the device.. + +**/ +EFI_STATUS +UsbBotResetDevice ( + IN VOID *Context, + IN BOOLEAN ExtendedVerification + ); + +/** + Get the max LUN (Logical Unit Number) of USB mass storage device. + + @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL + @param MaxLun Return pointer to the max number of LUN. (e.g. MaxLun=1 means LUN0 and + LUN1 in all.) + + @retval EFI_SUCCESS Max LUN is got successfully. + @retval Others Fail to execute this request. + +**/ +EFI_STATUS +UsbBotGetMaxLun ( + IN VOID *Context, + OUT UINT8 *MaxLun + ); + +/** + Clean up the resource used by this BOT protocol. + + @param Context The context of the BOT protocol, that is, USB_BOT_PROTOCOL. + + @retval EFI_SUCCESS The resource is cleaned up. + +**/ +EFI_STATUS +UsbBotCleanUp ( + IN VOID *Context + ); + #endif diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c index f4dd109696..d56254b77c 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.c @@ -1,6 +1,6 @@ /** @file - - Implementation of the USB mass storage Control/Bulk/Interrupt transport. + Implementation of the USB mass storage Control/Bulk/Interrupt transport, + according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1. Notice: it is being obsoleted by the standard body in favor of the BOT (Bulk-Only Transport). @@ -18,37 +18,43 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UsbMass.h" #include "UsbMassCbi.h" -/** - Call the Usb mass storage class transport protocol to - reset the device. The reset is defined as a Non-Data - command. Don't use UsbCbiExecCommand to send the command - to device because that may introduce recursive loop. - - @param Context The USB CBI device protocol - @param ExtendedVerification The flag controlling the rule of reset - - @retval EFI_SUCCESS the device is reset - @retval Others Failed to reset the device - -**/ -EFI_STATUS -UsbCbiResetDevice ( - IN VOID *Context, - IN BOOLEAN ExtendedVerification - ); +// +// Definition of USB CBI0 Transport Protocol +// +USB_MASS_TRANSPORT mUsbCbi0Transport = { + USB_MASS_STORE_CBI0, + UsbCbiInit, + UsbCbiExecCommand, + UsbCbiResetDevice, + NULL, + UsbCbiCleanUp +}; +// +// Definition of USB CBI1 Transport Protocol +// +USB_MASS_TRANSPORT mUsbCbi1Transport = { + USB_MASS_STORE_CBI1, + UsbCbiInit, + UsbCbiExecCommand, + UsbCbiResetDevice, + NULL, + UsbCbiCleanUp +}; /** - Initialize the USB mass storage class CBI transport protocol. - If Context isn't NULL, it will save its context in it. + Initializes USB CBI protocol. - @param UsbIo The USB IO to use - @param Context The variable to save context in + This function initializes the USB mass storage class CBI protocol. + It will save its context which is a USB_CBI_PROTOCOL structure + in the Context if Context isn't NULL. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory - @retval EFI_UNSUPPORTED The device isn't supported - @retval EFI_SUCCESS The CBI protocol is initialized. - @retval Other The Usb cbi init failed. + @param UsbIo The USB I/O Protocol instance + @param Context The buffer to save the context to + + @retval EFI_SUCCESS The device is successfully initialized. + @retval EFI_UNSUPPORTED The transport protocol doesn't support the device. + @retval Other The USB CBI initialization fails. **/ EFI_STATUS @@ -64,21 +70,18 @@ UsbCbiInit ( UINT8 Index; // - // Allocate the CBI context + // Allocate the CBI context for USB_CBI_PROTOCOL and 3 endpoint descriptors. // UsbCbi = AllocateZeroPool ( sizeof (USB_CBI_PROTOCOL) + 3 * sizeof (EFI_USB_ENDPOINT_DESCRIPTOR) ); - - if (UsbCbi == NULL) { - return EFI_OUT_OF_RESOURCES; - } + ASSERT (UsbCbi != NULL); UsbCbi->UsbIo = UsbIo; // - // Get the interface descriptor and validate that it is a USB mass - // storage class CBI interface. + // Get the interface descriptor and validate that it + // is a USB Mass Storage CBI interface. // Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &UsbCbi->Interface); if (EFI_ERROR (Status)) { @@ -118,7 +121,6 @@ UsbCbiInit ( UsbCbi->BulkOutEndpoint = (EFI_USB_ENDPOINT_DESCRIPTOR *) (UsbCbi + 1) + 1; CopyMem(UsbCbi->BulkOutEndpoint, &EndPoint, sizeof (EndPoint)); } - } else if (USB_IS_INTERRUPT_ENDPOINT (EndPoint.Attributes)) { // // Use the first interrupt endpoint if it is CBI0 @@ -132,10 +134,11 @@ UsbCbiInit ( } } - if ((UsbCbi->BulkInEndpoint == NULL) - || (UsbCbi->BulkOutEndpoint == NULL) - || ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) - && (UsbCbi->InterruptEndpoint == NULL))) { + if ((UsbCbi->BulkInEndpoint == NULL) || (UsbCbi->BulkOutEndpoint == NULL)) { + Status = EFI_UNSUPPORTED; + goto ON_ERROR; + } + if ((Interface->InterfaceProtocol == USB_MASS_STORE_CBI0) && (UsbCbi->InterruptEndpoint == NULL)) { Status = EFI_UNSUPPORTED; goto ON_ERROR; } @@ -145,6 +148,7 @@ UsbCbiInit ( } else { gBS->FreePool (UsbCbi); } + return EFI_SUCCESS; ON_ERROR: @@ -152,16 +156,18 @@ ON_ERROR: return Status; } - /** Send the command to the device using class specific control transfer. + This function sends command to the device using class specific control transfer. + The CBI contains three phases: Command, Data, and Status. This is Command phase. + @param UsbCbi The USB CBI protocol @param Cmd The high level command to transfer to device @param CmdLen The length of the command @param Timeout The time to wait the command to finish - @retval EFI_SUCCESS The command is transferred to device + @retval EFI_SUCCESS The command is sent to the device. @retval Others The command failed to transfer to device **/ @@ -181,7 +187,7 @@ UsbCbiSendCommand ( // // Fill in the device request, CBI use the "Accept Device-Specific - // Cmd" (ADSC) class specific request to send commands + // Cmd" (ADSC) class specific request to send commands. // Request.RequestType = 0x21; Request.Request = 0; @@ -194,7 +200,7 @@ UsbCbiSendCommand ( for (Retry = 0; Retry < USB_CBI_MAX_RETRY; Retry++) { // - // Use the UsbIo to send the command to the device + // Use USB I/O Protocol to send the command to the device // TransStatus = 0; DataLen = CmdLen; @@ -226,16 +232,20 @@ UsbCbiSendCommand ( /** - Transfer data between the device and host. The CBI contains three phase, - command, data, and status. This is data phase. + Transfer data between the device and host. + + This function transfers data between the device and host. + The CBI contains three phases: Command, Data, and Status. This is Data phase. @param UsbCbi The USB CBI device @param DataDir The direction of the data transfer - @param Data The buffer to hold the data - @param TransLen The expected transfer length - @param Timeout The time to wait the command to execute + @param Data The buffer to hold the data for input or output. + @param TransLen On input, the expected transfer length. + On output, the length of data actually transferred. + @param Timeout The time to wait for the command to execute - @retval EFI_SUCCESS The data transfer succeeded + @retval EFI_SUCCESS The data transferred successfully. + @retval EFI_SUCCESS No data to transfer @retval Others Failed to transfer all the data **/ @@ -257,7 +267,7 @@ UsbCbiDataTransfer ( UINTN Retry; // - // It's OK if no data to transfer + // If no data to transfer, just return EFI_SUCCESS. // if ((DataDir == EfiUsbNoData) || (*TransLen == 0)) { return EFI_SUCCESS; @@ -279,7 +289,7 @@ UsbCbiDataTransfer ( Timeout = Timeout / USB_MASS_1_MILLISECOND; // - // Transfer the data, if the device returns NAK, retry it. + // Transfer the data with a loop. The length of data transferred once is restricted. // while (Remain > 0) { TransStatus = 0; @@ -302,15 +312,15 @@ UsbCbiDataTransfer ( if (TransStatus == EFI_USB_ERR_NAK) { // // The device can NAK the host if either the data/buffer isn't - // aviable or the command is in-progress. The data can be partly - // transferred. The transfer is aborted if several succssive data - // transfer commands are NAKed. + // aviable or the command is in-progress. + // If data are partially transferred, we just ignore NAK and continue. + // If all data have been transferred and status is NAK, then we retry for several times. + // If retry exceeds the USB_CBI_MAX_RETRY, then return error status. // if (Increment == 0) { if (++Retry > USB_CBI_MAX_RETRY) { goto ON_EXIT; } - } else { Next += Increment; Remain -= Increment; @@ -342,13 +352,15 @@ ON_EXIT: /** - Get the result of high level command execution from interrupt - endpoint. This function returns the USB transfer status, and - put the high level command execution result in Result. + Gets the result of high level command execution from interrupt endpoint. + + This function returns the USB transfer status, and put the high level + command execution result in Result. + The CBI contains three phases: Command, Data, and Status. This is Status phase. @param UsbCbi The USB CBI protocol - @param Timeout The time to wait the command to execute - @param Result GC_TODO: add argument description + @param Timeout The time to wait for the command to execute + @param Result The result of the command execution. @retval EFI_SUCCESS The high level command execution result is retrieved in Result. @@ -404,7 +416,7 @@ UsbCbiGetStatus ( /** Execute USB mass storage command through the CBI0/CBI1 transport protocol. - @param Context The USB CBI device + @param Context The USB CBI Protocol. @param Cmd The command to transfer to device @param CmdLen The length of the command @param DataDir The direction of data transfer @@ -414,7 +426,7 @@ UsbCbiGetStatus ( @param Timeout The time to wait @param CmdStatus The result of the command execution - @retval EFI_SUCCESS The command is executed OK and result in CmdStatus. + @retval EFI_SUCCESS The command is executed successfully. @retval Other Failed to execute the command **/ @@ -450,7 +462,7 @@ UsbCbiExecCommand ( } // - // Transfer the data, return this status if no interrupt endpoint + // Transfer the data. Return this status if no interrupt endpoint // is used to report the transfer status. // TransLen = (UINTN) DataLen; @@ -462,12 +474,12 @@ UsbCbiExecCommand ( } // - // Get the status, if that succeeds, interpret the result + // Get the status. If it succeeds, interpret the result. // Status = UsbCbiGetStatus (UsbCbi, Timeout, &Result); if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbCbiExecCommand: UsbCbiGetStatus (%r)\n",Status)); - return EFI_DEVICE_ERROR; + return Status; } if (UsbCbi->Interface.InterfaceSubClass == USB_MASS_STORE_UFI) { @@ -492,7 +504,8 @@ UsbCbiExecCommand ( case 0x02: // - // Phase Error, response with reset. Fall through to Fail. + // Phase Error, response with reset. + // No break here to fall through to "Fail". // UsbCbiResetDevice (UsbCbi, FALSE); @@ -505,7 +518,7 @@ UsbCbiExecCommand ( case 0x03: // - // Persistent Fail, need to send REQUEST SENSE. + // Persistent Fail. Need to send REQUEST SENSE. // *CmdStatus = USB_MASS_CMD_PERSISTENT; break; @@ -517,16 +530,18 @@ UsbCbiExecCommand ( /** - Call the Usb mass storage class transport protocol to - reset the device. The reset is defined as a Non-Data - command. Don't use UsbCbiExecCommand to send the command - to device because that may introduce recursive loop. + Reset the USB mass storage device by CBI protocol. - @param Context The USB CBI device protocol - @param ExtendedVerification The flag controlling the rule of reset + This function resets the USB mass storage device by CBI protocol. + The reset is defined as a non-data command. Don't use UsbCbiExecCommand + to send the command to device because that may introduce recursive loop. - @retval EFI_SUCCESS the device is reset - @retval Others Failed to reset the device + @param Context The USB CBI protocol + @param ExtendedVerification The flag controlling the rule of reset. + Not used here. + + @retval EFI_SUCCESS The device is reset. + @retval Others Failed to reset the device. **/ EFI_STATUS @@ -562,17 +577,17 @@ UsbCbiResetDevice ( // // Just retrieve the status and ignore that. Then stall - // 50ms to wait it complete + // 50ms to wait for it to complete. // UsbCbiGetStatus (UsbCbi, Timeout, &Result); gBS->Stall (USB_CBI_RESET_DEVICE_STALL); // - // Clear the Bulk-In and Bulk-Out stall condition and - // init data toggle. + // Clear the Bulk-In and Bulk-Out stall condition and init data toggle. // UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkInEndpoint->EndpointAddress); UsbClearEndpointStall (UsbCbi->UsbIo, UsbCbi->BulkOutEndpoint->EndpointAddress); + return Status; } @@ -586,30 +601,10 @@ UsbCbiResetDevice ( **/ EFI_STATUS -UsbCbiFini ( +UsbCbiCleanUp ( IN VOID *Context ) { gBS->FreePool (Context); return EFI_SUCCESS; } - -USB_MASS_TRANSPORT -mUsbCbi0Transport = { - USB_MASS_STORE_CBI0, - UsbCbiInit, - UsbCbiExecCommand, - UsbCbiResetDevice, - NULL, - UsbCbiFini -}; - -USB_MASS_TRANSPORT -mUsbCbi1Transport = { - USB_MASS_STORE_CBI1, - UsbCbiInit, - UsbCbiExecCommand, - UsbCbiResetDevice, - NULL, - UsbCbiFini -}; diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h index 555a789ffd..ec4c3e14da 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassCbi.h @@ -1,6 +1,6 @@ /** @file - - Defination for the USB mass storage Control/Bulk/Interrupt transport. + Defination for the USB mass storage Control/Bulk/Interrupt (CBI) transport, + according to USB Mass Storage Class Control/Bulk/Interrupt (CBI) Transport, Revision 1.1. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -16,31 +16,33 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #ifndef _EFI_USBMASS_CBI_H_ #define _EFI_USBMASS_CBI_H_ +extern USB_MASS_TRANSPORT mUsbCbi0Transport; +extern USB_MASS_TRANSPORT mUsbCbi1Transport; + typedef enum { USB_CBI_MAX_PACKET_NUM = 16, USB_CBI_RESET_CMD_LEN = 12, // - // Usb Cbi retry C/B/I transport times, set by experience + // USB CBI retry C/B/I transport times, set by experience // USB_CBI_MAX_RETRY = 3, // - // Usb Cbi wait device reset complete, set by experience + // Time to wait for USB CBI reset to complete, set by experience // USB_CBI_RESET_DEVICE_STALL = 50 * USB_MASS_1_MILLISECOND, // - // Usb Cbi transport timeout, set by experience + // USB CBI transport timeout, set by experience // USB_CBI_RESET_DEVICE_TIMEOUT = 1 * USB_MASS_1_SECOND -}USB_CBI_DATA; +} USB_CBI_DATA; -// -// Put Interface at the first field is to make it easy to get by Context, which -// could be BOT/CBI Protocol instance -// typedef struct { + // + // Put Interface at the first field to make it easy to distinguish BOT/CBI Protocol instance + // EFI_USB_INTERFACE_DESCRIPTOR Interface; EFI_USB_ENDPOINT_DESCRIPTOR *BulkInEndpoint; EFI_USB_ENDPOINT_DESCRIPTOR *BulkOutEndpoint; @@ -55,6 +57,89 @@ typedef struct { } USB_CBI_STATUS; #pragma pack() -extern USB_MASS_TRANSPORT mUsbCbi0Transport; -extern USB_MASS_TRANSPORT mUsbCbi1Transport; +/** + Initializes USB CBI protocol. + + This function initializes the USB mass storage class CBI protocol. + It will save its context which is a USB_CBI_PROTOCOL structure + in the Context if Context isn't NULL. + + @param UsbIo The USB I/O Protocol instance + @param Context The buffer to save the context to + + @retval EFI_SUCCESS The device is successfully initialized. + @retval EFI_UNSUPPORTED The transport protocol doesn't support the device. + @retval Other The USB CBI initialization fails. + +**/ +EFI_STATUS +UsbCbiInit ( + IN EFI_USB_IO_PROTOCOL *UsbIo, + OUT VOID **Context OPTIONAL + ); + +/** + Execute USB mass storage command through the CBI0/CBI1 transport protocol. + + @param Context The USB CBI Protocol. + @param Cmd The command to transfer to device + @param CmdLen The length of the command + @param DataDir The direction of data transfer + @param Data The buffer to hold the data + @param DataLen The length of the buffer + @param Lun Should be 0, this field for bot only + @param Timeout The time to wait + @param CmdStatus The result of the command execution + + @retval EFI_SUCCESS The command is executed successfully. + @retval Other Failed to execute the command + +**/ +EFI_STATUS +UsbCbiExecCommand ( + IN VOID *Context, + IN VOID *Cmd, + IN UINT8 CmdLen, + IN EFI_USB_DATA_DIRECTION DataDir, + IN VOID *Data, + IN UINT32 DataLen, + IN UINT8 Lun, + IN UINT32 Timeout, + OUT UINT32 *CmdStatus + ); + +/** + Reset the USB mass storage device by CBI protocol. + + This function resets the USB mass storage device by CBI protocol. + The reset is defined as a non-data command. Don't use UsbCbiExecCommand + to send the command to device because that may introduce recursive loop. + + @param Context The USB CBI protocol + @param ExtendedVerification The flag controlling the rule of reset. + Not used here. + + @retval EFI_SUCCESS The device is reset. + @retval Others Failed to reset the device. + +**/ +EFI_STATUS +UsbCbiResetDevice ( + IN VOID *Context, + IN BOOLEAN ExtendedVerification + ); + +/** + Clean up the CBI protocol's resource. + + @param Context The instance of CBI protocol. + + @retval EFI_SUCCESS The resource is cleaned up. + +**/ +EFI_STATUS +UsbCbiCleanUp ( + IN VOID *Context + ); + #endif diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c index 724246d9f1..6efdf10af1 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.c @@ -1,8 +1,5 @@ /** @file - - The implementation of USB mass storage class device driver. - The command set supported is "USB Mass Storage Specification - for Bootability". + USB Mass Storage Driver that manages USB Mass Storage Device and produces Block I/O Protocol. Copyright (c) 2007 - 2008, Intel Corporation All rights reserved. This program and the accompanying materials @@ -17,6 +14,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "UsbMassImpl.h" +// +// Array of USB transport interfaces. +// USB_MASS_TRANSPORT *mUsbMassTransport[] = { &mUsbCbi0Transport, &mUsbCbi1Transport, @@ -24,14 +24,28 @@ USB_MASS_TRANSPORT *mUsbMassTransport[] = { NULL }; +EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = { + USBMassDriverBindingSupported, + USBMassDriverBindingStart, + USBMassDriverBindingStop, + 0x11, + NULL, + NULL +}; + /** - Reset the block device. ExtendedVerification is ignored for this. + Reset the block device. - @param This The BLOCK IO protocol - @param ExtendedVerification Whether to execute extended verification. + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. - @retval EFI_SUCCESS The device is successfully reseted. - @retval Others Failed to reset the device. + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. **/ EFI_STATUS @@ -45,9 +59,13 @@ UsbMassReset ( EFI_TPL OldTpl; EFI_STATUS Status; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); + // + // Raise TPL to TPL_NOTIFY to serialize all its operations + // to protect shared data structures. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification); gBS->RestoreTPL (OldTpl); @@ -56,22 +74,27 @@ UsbMassReset ( } /** - Read some blocks of data from the block device. + Reads the requested number of blocks from the device. - @param This The Block IO protocol - @param MediaId The media's ID of the device for current request - @param Lba The start block number - @param BufferSize The size of buffer to read data in - @param Buffer The buffer to read data to + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. - @retval EFI_SUCCESS The data is successfully read - @retval EFI_NO_MEDIA Media isn't present - @retval EFI_MEDIA_CHANGED The device media has been changed, that is, - MediaId changed - @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is - NULL. - @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block - size, or overflow the last block number. + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. **/ EFI_STATUS @@ -90,34 +113,35 @@ UsbMassReadBlocks ( EFI_TPL OldTpl; UINTN TotalBlock; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); - Media = &UsbMass->BlockIoMedia; - // // First, validate the parameters // if ((Buffer == NULL) || (BufferSize == 0)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; + return EFI_INVALID_PARAMETER; } + // + // Raise TPL to TPL_NOTIFY to serialize all its operations + // to protect shared data structures. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); + Media = &UsbMass->BlockIoMedia; + // // If it is a removable media, such as CD-Rom or Usb-Floppy, - // need to detect the media before each rw. While some of + // need to detect the media before each read/write. While some of // Usb-Flash is marked as removable media. // - // - if (Media->RemovableMedia == TRUE) { + if (Media->RemovableMedia) { Status = UsbBootDetectMedia (UsbMass); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootDetectMedia (%r)\n", Status)); goto ON_EXIT; } } // - // Make sure BlockSize and LBA is consistent with BufferSize + // BufferSize must be a multiple of the intrinsic block size of the device. // if ((BufferSize % Media->BlockSize) != 0) { Status = EFI_BAD_BUFFER_SIZE; @@ -126,6 +150,9 @@ UsbMassReadBlocks ( TotalBlock = BufferSize / Media->BlockSize; + // + // Make sure the range to read is valid. + // if (Lba + TotalBlock - 1 > Media->LastBlock) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; @@ -154,22 +181,28 @@ ON_EXIT: /** - Write some blocks of data to the block device. + Writes a specified number of blocks to the device. - @param This The Block IO protocol - @param MediaId The media's ID of the device for current request - @param Lba The start block number - @param BufferSize The size of buffer to write data to - @param Buffer The buffer to write data to + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. - @retval EFI_SUCCESS The data is successfully written - @retval EFI_NO_MEDIA Media isn't present - @retval EFI_MEDIA_CHANGED The device media has been changed, that is, - MediaId changed - @retval EFI_INVALID_PARAMETER Some parameters are invalid, such as Buffer is - NULL. - @retval EFI_BAD_BUFFER_SIZE The buffer size isn't a multiple of media's block - size, + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. **/ EFI_STATUS @@ -188,34 +221,35 @@ UsbMassWriteBlocks ( EFI_TPL OldTpl; UINTN TotalBlock; - OldTpl = gBS->RaiseTPL (USB_MASS_TPL); - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (This); - Media = &UsbMass->BlockIoMedia; - // // First, validate the parameters // if ((Buffer == NULL) || (BufferSize == 0)) { - Status = EFI_INVALID_PARAMETER; - goto ON_EXIT; + return EFI_INVALID_PARAMETER; } + // + // Raise TPL to TPL_NOTIFY to serialize all its operations + // to protect shared data structures. + // + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); + Media = &UsbMass->BlockIoMedia; + // // If it is a removable media, such as CD-Rom or Usb-Floppy, - // need to detect the media before each rw. While some of - // Usb-Flash is marked as removable media. + // need to detect the media before each read/write. Some of + // USB Flash is marked as removable media. // - // - if (Media->RemovableMedia == TRUE) { + if (Media->RemovableMedia) { Status = UsbBootDetectMedia (UsbMass); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassWriteBlocks: UsbBootDetectMedia (%r)\n", Status)); goto ON_EXIT; } } // - // Make sure BlockSize and LBA is consistent with BufferSize + // BufferSize must be a multiple of the intrinsic block size of the device. // if ((BufferSize % Media->BlockSize) != 0) { Status = EFI_BAD_BUFFER_SIZE; @@ -224,6 +258,9 @@ UsbMassWriteBlocks ( TotalBlock = BufferSize / Media->BlockSize; + // + // Make sure the range to write is valid. + // if (Lba + TotalBlock - 1 > Media->LastBlock) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; @@ -255,12 +292,17 @@ ON_EXIT: } /** - Flush the cached writes to disks. USB mass storage device doesn't - support write cache, so return EFI_SUCCESS directly. + Flushes all modified data to a physical block device. - @param This The BLOCK IO protocol + This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks(). + USB mass storage device doesn't support write cache, + so return EFI_SUCCESS directly. - @retval EFI_SUCCESS Always returns success + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. **/ EFI_STATUS @@ -273,12 +315,11 @@ UsbMassFlushBlocks ( } /** - Retrieve the media parameters such as disk geometric for the - device's BLOCK IO protocol. + Initialize the media parameter data for EFI_BLOCK_IO_MEDIA of Block I/O Protocol. @param UsbMass The USB mass storage device - @retval EFI_SUCCESS The media parameters is updated successfully. + @retval EFI_SUCCESS The media parameters are updated successfully. @retval Others Failed to get the media parameters. **/ @@ -294,18 +335,8 @@ UsbMassInitMedia ( Media = &UsbMass->BlockIoMedia; // - // Initialize the MediaPrsent/ReadOnly and others to the default. - // We are not forced to get it right at this time, check UEFI2.0 - // spec for more information: - // - // MediaPresent: This field shows the media present status as - // of the most recent ReadBlocks or WriteBlocks call. - // - // ReadOnly : This field shows the read-only status as of the - // recent WriteBlocks call. - // - // but remember to update MediaId/MediaPresent/ReadOnly status - // after ReadBlocks and WriteBlocks + // Fields of EFI_BLOCK_IO_MEDIA are defined in UEFI 2.0 spec, + // section for Block I/O Protocol. // Media->MediaPresent = FALSE; Media->LogicalPartition = FALSE; @@ -323,9 +354,7 @@ UsbMassInitMedia ( for (Index = 0; Index < USB_BOOT_INIT_MEDIA_RETRY; Index++) { Status = UsbBootGetParams (UsbMass); - if ((Status != EFI_MEDIA_CHANGED) - && (Status != EFI_NOT_READY) - && (Status != EFI_TIMEOUT)) { + if ((Status != EFI_MEDIA_CHANGED) && (Status != EFI_NOT_READY) && (Status != EFI_TIMEOUT)) { break; } @@ -333,14 +362,16 @@ UsbMassInitMedia ( if (EFI_ERROR (Status)) { gBS->Stall (USB_BOOT_RETRY_UNIT_READY_STALL * (Index + 1)); } - } return Status; } /** - Initilize the transport. + Initilize the USB Mass Storage transport. + + This function tries to find the matching USB Mass Storage transport + protocol for USB device. If found, initializes the matching transport. @param This The USB mass driver's driver binding. @param Controller The device to test. @@ -349,6 +380,7 @@ UsbMassInitMedia ( @param MaxLun Get the MaxLun if is BOT dev. @retval EFI_SUCCESS The initialization is successful. + @retval EFI_UNSUPPORTED No matching transport protocol is found. @retval Others Failed to initialize dev. **/ @@ -376,18 +408,22 @@ UsbMassInitTransport ( ); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: OpenUsbIoProtocol By Driver (%r)\n", Status)); return Status; } Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: UsbIo->UsbGetInterfaceDescriptor (%r)\n", Status)); goto ON_EXIT; } Status = EFI_UNSUPPORTED; + // + // Traverse the USB_MASS_TRANSPORT arrary and try to find the + // matching transport protocol. + // If not found, return EFI_UNSUPPORTED. + // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. + // for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { *Transport = mUsbMassTransport[Index]; @@ -398,17 +434,16 @@ UsbMassInitTransport ( } if (EFI_ERROR (Status)) { - DEBUG ((EFI_D_ERROR, "UsbMassInitTransport: Transport->Init (%r)\n", Status)); goto ON_EXIT; } // - // For bot device, try to get max lun. - // If maxlun=0, then non-lun device, else multi-lun device. + // For BOT device, try to get its max LUN. + // If max LUN is 0, then it is a non-lun device. + // Otherwise, it is a multi-lun device. // if ((*Transport)->Protocol == USB_MASS_STORE_BOT) { (*Transport)->GetMaxLun (*Context, MaxLun); - DEBUG ((EFI_D_INFO, "UsbMassInitTransport: GetMaxLun = %d\n", *MaxLun)); } ON_EXIT: @@ -687,13 +722,12 @@ ON_ERROR: /** Check whether the controller is a supported USB mass storage. - @param This The USB mass driver's driver binding. - @param Controller The device to test against. - @param RemainingDevicePath The remaining device path + @param This The USB mass storage driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. - @retval EFI_SUCCESS This device is a supported USB mass storage. - @retval EFI_UNSUPPORTED The device isn't supported - @retval Others Some error happened. + @retval EFI_SUCCESS The driver supports this controller. + @retval other This device isn't supported. **/ EFI_STATUS @@ -708,11 +742,8 @@ USBMassDriverBindingSupported ( EFI_USB_INTERFACE_DESCRIPTOR Interface; USB_MASS_TRANSPORT *Transport; EFI_STATUS Status; - INTN Index; + UINTN Index; - // - // Check whether the controller support USB_IO - // Status = gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, @@ -726,7 +757,7 @@ USBMassDriverBindingSupported ( } // - // Get the interface to check the USB class and find a transport + // Get the interface descriptor to check the USB class and find a transport // protocol handler. // Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &Interface); @@ -740,6 +771,12 @@ USBMassDriverBindingSupported ( goto ON_EXIT; } + // + // Traverse the USB_MASS_TRANSPORT arrary and try to find the + // matching transport method. + // If not found, return EFI_UNSUPPORTED. + // If found, execute USB_MASS_TRANSPORT.Init() to initialize the transport context. + // for (Index = 0; mUsbMassTransport[Index] != NULL; Index++) { Transport = mUsbMassTransport[Index]; if (Interface.InterfaceProtocol == Transport->Protocol) { @@ -748,31 +785,34 @@ USBMassDriverBindingSupported ( } } - DEBUG ((EFI_D_INFO, "Found a USB mass store device %r\n", Status)); - ON_EXIT: gBS->CloseProtocol ( - Controller, - &gEfiUsbIoProtocolGuid, - This->DriverBindingHandle, - Controller - ); + Controller, + &gEfiUsbIoProtocolGuid, + This->DriverBindingHandle, + Controller + ); return Status; } /** - Start the USB mass storage device on the controller. It will - install a BLOCK_IO protocol on the device if everything is OK. + Starts the USB mass storage device with this driver. - @param This The USB mass storage driver binding. + This function consumes USB I/O Portocol, intializes USB mass storage device, + installs Block I/O Protocol, and submits Asynchronous Interrupt + Transfer to manage the USB mass storage device. + + @param This The USB mass storage driver binding protocol. @param Controller The USB mass storage device to start on @param RemainingDevicePath The remaining device path. - @retval EFI_SUCCESS The driver has started on the device. - @retval EFI_OUT_OF_RESOURCES Failed to allocate memory - @retval Others Failed to start the driver on the device. + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @retval EFI_ALREADY_STARTED This driver has been started. **/ EFI_STATUS @@ -831,7 +871,7 @@ USBMassDriverBindingStart ( // // Try best to initialize all LUNs, and return success only if one of LUNs successed to initialized. // - Status = UsbMassInitMultiLun(This, Controller, Transport, Context, DevicePath, MaxLun); + Status = UsbMassInitMultiLun (This, Controller, Transport, Context, DevicePath, MaxLun); if (EFI_ERROR (Status)) { gBS->CloseProtocol ( Controller, @@ -913,7 +953,7 @@ USBMassDriverBindingStop ( // This is a 1st type handle(non-multi-lun), which only needs uninstall // blockio protocol, close usbio protocol and free mass device. // - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); // // Uninstall Block I/O protocol from the device handle, @@ -935,7 +975,7 @@ USBMassDriverBindingStop ( Controller ); - UsbMass->Transport->Fini (UsbMass->Context); + UsbMass->Transport->CleanUp (UsbMass->Context); gBS->FreePool (UsbMass); DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n")); @@ -965,7 +1005,7 @@ USBMassDriverBindingStop ( continue; } - UsbMass = USB_MASS_DEVICE_FROM_BLOCKIO (BlockIo); + UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); gBS->CloseProtocol ( Controller, @@ -1003,7 +1043,7 @@ USBMassDriverBindingStop ( // Success to stop this multi-lun handle, so go on next child. // if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) { - UsbMass->Transport->Fini (UsbMass->Context); + UsbMass->Transport->CleanUp (UsbMass->Context); } gBS->FreePool (UsbMass); } @@ -1017,15 +1057,6 @@ USBMassDriverBindingStop ( return EFI_SUCCESS; } -EFI_DRIVER_BINDING_PROTOCOL gUSBMassDriverBinding = { - USBMassDriverBindingSupported, - USBMassDriverBindingStart, - USBMassDriverBindingStop, - 0x11, - NULL, - NULL -}; - /** The entry point for the driver, which will install the driver binding and component name protocol. @@ -1057,6 +1088,7 @@ USBMassStorageEntryPoint ( &gUsbMassStorageComponentName, &gUsbMassStorageComponentName2 ); + ASSERT_EFI_ERROR (Status); - return Status; + return EFI_SUCCESS; } diff --git a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h index 95395f7e1c..c4c987f2f6 100644 --- a/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h +++ b/MdeModulePkg/Bus/Usb/UsbMassStorageDxe/UsbMassImpl.h @@ -23,16 +23,8 @@ typedef struct _USB_MASS_DEVICE USB_MASS_DEVICE; #include "UsbMassCbi.h" #include "UsbMassBoot.h" - -// -// MassStorage raises TPL to TPL_NOTIFY to serialize all its operations -// to protect shared data structures. -// -#define USB_MASS_TPL TPL_NOTIFY - #define USB_MASS_SIGNATURE SIGNATURE_32 ('U', 's', 'b', 'M') - struct _USB_MASS_DEVICE { UINT32 Signature; EFI_HANDLE Controller; @@ -47,10 +39,196 @@ struct _USB_MASS_DEVICE { VOID *Context; // Opaque storage for mass transport }; -#define USB_MASS_DEVICE_FROM_BLOCKIO(a) \ +#define USB_MASS_DEVICE_FROM_BLOCK_IO(a) \ CR (a, USB_MASS_DEVICE, BlockIo, USB_MASS_SIGNATURE) extern EFI_COMPONENT_NAME_PROTOCOL gUsbMassStorageComponentName; extern EFI_COMPONENT_NAME2_PROTOCOL gUsbMassStorageComponentName2; +// +// Functions for Driver Binding Protocol +// + +/** + Check whether the controller is a supported USB mass storage. + + @param This The USB mass storage driver binding protocol. + @param Controller The controller handle to check. + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS The driver supports this controller. + @retval other This device isn't supported. + +**/ +EFI_STATUS +EFIAPI +USBMassDriverBindingSupported ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Starts the USB mass storage device with this driver. + + This function consumes USB I/O Portocol, intializes USB mass storage device, + installs Block I/O Protocol, and submits Asynchronous Interrupt + Transfer to manage the USB mass storage device. + + @param This The USB mass storage driver binding protocol. + @param Controller The USB mass storage device to start on + @param RemainingDevicePath The remaining device path. + + @retval EFI_SUCCESS This driver supports this device. + @retval EFI_UNSUPPORTED This driver does not support this device. + @retval EFI_DEVICE_ERROR This driver cannot be started due to device Error. + @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources. + @retval EFI_ALREADY_STARTED This driver has been started. + +**/ +EFI_STATUS +EFIAPI +USBMassDriverBindingStart ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath + ); + +/** + Stop controlling the device. + + @param This The USB mass storage driver binding + @param Controller The device controller controlled by the driver. + @param NumberOfChildren The number of children of this device + @param ChildHandleBuffer The buffer of children handle. + + @retval EFI_SUCCESS The driver stopped from controlling the device. + @retval Others Failed to stop the driver + +**/ +EFI_STATUS +EFIAPI +USBMassDriverBindingStop ( + IN EFI_DRIVER_BINDING_PROTOCOL *This, + IN EFI_HANDLE Controller, + IN UINTN NumberOfChildren, + IN EFI_HANDLE *ChildHandleBuffer + ); + +// +// Functions for Block I/O Protocol +// + +/** + Reset the block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.Reset(). + It resets the block device hardware. + ExtendedVerification is ignored in this implementation. + + @param This Indicates a pointer to the calling context. + @param ExtendedVerification Indicates that the driver may perform a more exhaustive + verification operation of the device during reset. + + @retval EFI_SUCCESS The block device was reset. + @retval EFI_DEVICE_ERROR The block device is not functioning correctly and could not be reset. + +**/ +EFI_STATUS +EFIAPI +UsbMassReset ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN BOOLEAN ExtendedVerification + ); + +/** + Reads the requested number of blocks from the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.ReadBlocks(). + It reads the requested number of blocks from the device. + All the blocks are read, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the read request is for. + @param Lba The starting logical block address to read from on the device. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer A pointer to the destination buffer for the data. The caller is + responsible for either having implicit or explicit ownership of the buffer. + + @retval EFI_SUCCESS The data was read correctly from the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the read operation. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic block size of the device. + @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +UsbMassReadBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + OUT VOID *Buffer + ); + +/** + Writes a specified number of blocks to the device. + + This function implements EFI_BLOCK_IO_PROTOCOL.WriteBlocks(). + It writes a specified number of blocks to the device. + All blocks are written, or an error is returned. + + @param This Indicates a pointer to the calling context. + @param MediaId The media ID that the write request is for. + @param Lba The starting logical block address to be written. + @param BufferSize The size of the Buffer in bytes. + This must be a multiple of the intrinsic block size of the device. + @param Buffer Pointer to the source buffer for the data. + + @retval EFI_SUCCESS The data were written correctly to the device. + @retval EFI_WRITE_PROTECTED The device cannot be written to. + @retval EFI_NO_MEDIA There is no media in the device. + @retval EFI_MEDIA_CHANGED The MediaId is not for the current media. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to perform the write operation. + @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the intrinsic + block size of the device. + @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid, + or the buffer is not on proper alignment. + +**/ +EFI_STATUS +EFIAPI +UsbMassWriteBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This, + IN UINT32 MediaId, + IN EFI_LBA Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + +/** + Flushes all modified data to a physical block device. + + This function implements EFI_BLOCK_IO_PROTOCOL.FlushBlocks(). + USB mass storage device doesn't support write cache, + so return EFI_SUCCESS directly. + + @param This Indicates a pointer to the calling context. + + @retval EFI_SUCCESS All outstanding data were written correctly to the device. + @retval EFI_DEVICE_ERROR The device reported an error while attempting to write data. + @retval EFI_NO_MEDIA There is no media in the device. + +**/ +EFI_STATUS +EFIAPI +UsbMassFlushBlocks ( + IN EFI_BLOCK_IO_PROTOCOL *This + ); + + #endif