/** 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 ) { USB_MASS_DEVICE *UsbMass; EFI_TPL OldTpl; EFI_STATUS Status; // // Raise TPL to TPL_CALLBACK to serialize all its operations // to protect shared data structures. // OldTpl = gBS->RaiseTPL (TPL_CALLBACK); UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (This); Status = UsbMass->Transport->Reset (UsbMass->Context, ExtendedVerification); gBS->RestoreTPL (OldTpl); return Status; }
/** 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 ) { USB_MASS_DEVICE *UsbMass; EFI_BLOCK_IO_MEDIA *Media; EFI_STATUS Status; EFI_TPL OldTpl; UINTN TotalBlock; // // Raise TPL to TPL_CALLBACK to serialize all its operations // to protect shared data structures. // OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 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 read/write. While some of // Usb-Flash is marked as removable media. // if (Media->RemovableMedia) { Status = UsbBootDetectMedia (UsbMass); if (EFI_ERROR (Status)) { goto ON_EXIT; } } if (!(Media->MediaPresent)) { Status = EFI_NO_MEDIA; goto ON_EXIT; } if (MediaId != Media->MediaId) { Status = EFI_MEDIA_CHANGED; goto ON_EXIT; } if (BufferSize == 0) { Status = EFI_SUCCESS; goto ON_EXIT; } if (Buffer == NULL) { Status = EFI_INVALID_PARAMETER; goto ON_EXIT; } // // BufferSize must be a multiple of the intrinsic block size of the device. // if ((BufferSize % Media->BlockSize) != 0) { Status = EFI_BAD_BUFFER_SIZE; goto ON_EXIT; } 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; } if (UsbMass->Cdb16Byte) { Status = UsbBootReadBlocks16 (UsbMass, Lba, TotalBlock, Buffer); } else { Status = UsbBootReadBlocks (UsbMass, (UINT32) Lba, TotalBlock, Buffer); } if (EFI_ERROR (Status)) { DEBUG ((EFI_D_ERROR, "UsbMassReadBlocks: UsbBootReadBlocks (%r) -> Reset\n", Status)); UsbMassReset (This, TRUE); } ON_EXIT: gBS->RestoreTPL (OldTpl); return Status; }
/** 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 EFI_DEVICE_ERROR The device could not be stopped due to a device error. @retval EFI_UNSUPPORTED Block I/O Protocol is not installed on Controller. @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 ) { EFI_STATUS Status; USB_MASS_DEVICE *UsbMass; EFI_USB_IO_PROTOCOL *UsbIo; EFI_BLOCK_IO_PROTOCOL *BlockIo; UINTN Index; BOOLEAN AllChildrenStopped; // // This is a bus driver stop function since multi-lun is supported. // There are three kinds of device handles that might be passed: // 1st is a handle with USB I/O & Block I/O installed (non-multi-lun) // 2nd is a handle with Device Path & USB I/O installed (multi-lun root) // 3rd is a handle with Device Path & USB I/O & Block I/O installed (multi-lun). // if (NumberOfChildren == 0) { // // A handle without any children, might be 1st and 2nd type. // Status = gBS->OpenProtocol ( Controller, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR(Status)) { // // This is a 2nd type handle(multi-lun root), it needs to close devicepath // and usbio protocol. // gBS->CloseProtocol ( Controller, &gEfiDevicePathProtocolGuid, This->DriverBindingHandle, Controller ); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); DEBUG ((EFI_D_INFO, "Success to stop multi-lun root handle\n")); return EFI_SUCCESS; } // // This is a 1st type handle(non-multi-lun), which only needs to uninstall // Block I/O Protocol, close USB I/O Protocol and free mass device. // UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); // // Uninstall Block I/O protocol from the device handle, // then call the transport protocol to stop itself. // Status = gBS->UninstallMultipleProtocolInterfaces ( Controller, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, &gEfiDiskInfoProtocolGuid, &UsbMass->DiskInfo, NULL ); if (EFI_ERROR (Status)) { return Status; } gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, Controller ); UsbMass->Transport->CleanUp (UsbMass->Context); FreePool (UsbMass); DEBUG ((EFI_D_INFO, "Success to stop non-multi-lun root handle\n")); return EFI_SUCCESS; } // // This is a 3rd type handle(multi-lun), which needs uninstall // Block I/O Protocol and Device Path Protocol, close USB I/O Protocol and // free mass device for all children. // AllChildrenStopped = TRUE; for (Index = 0; Index < NumberOfChildren; Index++) { Status = gBS->OpenProtocol ( ChildHandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo, This->DriverBindingHandle, Controller, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { AllChildrenStopped = FALSE; DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when opening blockio\n", (UINT32)Index)); continue; } UsbMass = USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo); gBS->CloseProtocol ( Controller, &gEfiUsbIoProtocolGuid, This->DriverBindingHandle, ChildHandleBuffer[Index] ); Status = gBS->UninstallMultipleProtocolInterfaces ( ChildHandleBuffer[Index], &gEfiDevicePathProtocolGuid, UsbMass->DevicePath, &gEfiBlockIoProtocolGuid, &UsbMass->BlockIo, &gEfiDiskInfoProtocolGuid, &UsbMass->DiskInfo, NULL ); if (EFI_ERROR (Status)) { // // Fail to uninstall Block I/O Protocol and Device Path Protocol, so re-open USB I/O Protocol by child. // AllChildrenStopped = FALSE; DEBUG ((EFI_D_ERROR, "Fail to stop No.%d multi-lun child handle when uninstalling blockio and devicepath\n", (UINT32)Index)); gBS->OpenProtocol ( Controller, &gEfiUsbIoProtocolGuid, (VOID **) &UsbIo, This->DriverBindingHandle, ChildHandleBuffer[Index], EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER ); } else { // // Succeed to stop this multi-lun handle, so go on with next child. // if (((Index + 1) == NumberOfChildren) && AllChildrenStopped) { UsbMass->Transport->CleanUp (UsbMass->Context); } FreePool (UsbMass); } } if (!AllChildrenStopped) { return EFI_DEVICE_ERROR; } DEBUG ((EFI_D_INFO, "Success to stop all %d multi-lun children handles\n", (UINT32) NumberOfChildren)); return EFI_SUCCESS; }
/*** Get all USB devices in system. @param[out] DeviceList - Linked list of USB devices. @param[out] MaxDevices - Number of USB devices in linked list. @retval EFI_SUCCESS The function exited normally. @retval Other An error occurred. ***/ EFI_STATUS UsbGetAllUsbDevices ( OUT LIST_ENTRY *DeviceList, OUT UINTN *MaxDevices ) { EFI_STATUS Status; DISK_ENTRY *DiskEntry = NULL; EFI_BLOCK_IO_PROTOCOL *BlockIo = NULL; EFI_DEVICE_PATH *DevPath = NULL; EFI_DEVICE_PATH *TmpPath = NULL; EFI_HANDLE *HandleBuffer; UINTN NumberHandles, Index; UINTN NumDevices = 0; Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &NumberHandles, &HandleBuffer); if (EFI_ERROR (Status)) { ERROR (L"Error on locating handles of gEfiDevicePathProtocolGuid\n"); return Status; } for (Index = 0; Index < NumberHandles; Index++) { Status = gBS->HandleProtocol ( HandleBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID**)&DevPath ); if (!EFI_ERROR (Status)) { TmpPath = DevPath; while (!IsDevicePathEnd (TmpPath)) { if (DevicePathType (TmpPath) == MESSAGING_DEVICE_PATH && (DevicePathSubType (TmpPath) == MSG_USB_DP || DevicePathSubType (TmpPath) == MSG_USB_CLASS_DP || DevicePathSubType (TmpPath) == MSG_USB_WWID_DP || DevicePathSubType (TmpPath) == MSG_DEVICE_LOGICAL_UNIT_DP)) { //Open BlockIo protocol Status = gBS->OpenProtocol ( HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID**)&BlockIo, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (!EFI_ERROR (Status) && BlockIo != NULL) { //A USB partition will be also detected like a USB device. we only get USB devices. if ((USB_MASS_DEVICE_FROM_BLOCK_IO (BlockIo))->Signature == USB_MASS_SIGNATURE) { DBG ("An USB device.\n"); NumDevices++; DiskEntry = (DISK_ENTRY*)AllocatePool (sizeof (DISK_ENTRY)); DiskEntry->DiskInfo.DiskHandle = HandleBuffer[Index]; DiskEntry->DiskInfo.DiskIndex = NumDevices; DiskEntry->DiskInfo.BlockIo = BlockIo; DiskEntry->DiskInfo.MaxPartitions = 0; InsertTailList (DeviceList, &DiskEntry->Link); } } } //end if() TmpPath = NextDevicePathNode (TmpPath); } //end while() } } //end for() *MaxDevices = NumDevices; return EFI_SUCCESS; }