/** @file | |
Fat File System driver routines that support EFI driver model. | |
Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "Fat.h" | |
/** | |
Register Driver Binding protocol for this driver. | |
@param ImageHandle - Handle for the image of this driver. | |
@param SystemTable - Pointer to the EFI System Table. | |
@retval EFI_SUCCESS - Driver loaded. | |
@return other - Driver not loaded. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
); | |
/** | |
Unload function for this image. Uninstall DriverBinding protocol. | |
@param ImageHandle - Handle for the image of this driver. | |
@retval EFI_SUCCESS - Driver unloaded successfully. | |
@return other - Driver can not unloaded. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatUnload ( | |
IN EFI_HANDLE ImageHandle | |
); | |
/** | |
Test to see if this driver can add a file system to ControllerHandle. | |
ControllerHandle must support both Disk IO and Block IO protocols. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to test. | |
@param RemainingDevicePath - Not used. | |
@retval EFI_SUCCESS - This driver supports this device. | |
@retval EFI_ALREADY_STARTED - This driver is already running on this device. | |
@return other - This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
); | |
/** | |
Start this driver on ControllerHandle by opening a Block IO and Disk IO | |
protocol, reading Device Path. Add a Simple File System protocol to | |
ControllerHandle if the media contains a valid file system. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to bind driver to. | |
@param RemainingDevicePath - Not used. | |
@retval EFI_SUCCESS - This driver is added to DeviceHandle. | |
@retval EFI_ALREADY_STARTED - This driver is already running on DeviceHandle. | |
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory. | |
@return other - This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
); | |
/** | |
Stop this driver on ControllerHandle. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to stop driver on. | |
@param NumberOfChildren - Not used. | |
@param ChildHandleBuffer - Not used. | |
@retval EFI_SUCCESS - This driver is removed DeviceHandle. | |
@return other - This driver was not removed from this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE Controller, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
); | |
// | |
// DriverBinding protocol instance | |
// | |
EFI_DRIVER_BINDING_PROTOCOL gFatDriverBinding = { | |
FatDriverBindingSupported, | |
FatDriverBindingStart, | |
FatDriverBindingStop, | |
0xa, | |
NULL, | |
NULL | |
}; | |
/** | |
Register Driver Binding protocol for this driver. | |
@param ImageHandle - Handle for the image of this driver. | |
@param SystemTable - Pointer to the EFI System Table. | |
@retval EFI_SUCCESS - Driver loaded. | |
@return other - Driver not loaded. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
// | |
// Initialize the EFI Driver Library | |
// | |
Status = EfiLibInstallDriverBindingComponentName2 ( | |
ImageHandle, | |
SystemTable, | |
&gFatDriverBinding, | |
ImageHandle, | |
&gFatComponentName, | |
&gFatComponentName2 | |
); | |
ASSERT_EFI_ERROR (Status); | |
return Status; | |
} | |
/** | |
Unload function for this image. Uninstall DriverBinding protocol. | |
@param ImageHandle - Handle for the image of this driver. | |
@retval EFI_SUCCESS - Driver unloaded successfully. | |
@return other - Driver can not unloaded. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatUnload ( | |
IN EFI_HANDLE ImageHandle | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HANDLE *DeviceHandleBuffer; | |
UINTN DeviceHandleCount; | |
UINTN Index; | |
VOID *ComponentName; | |
VOID *ComponentName2; | |
Status = gBS->LocateHandleBuffer ( | |
AllHandles, | |
NULL, | |
NULL, | |
&DeviceHandleCount, | |
&DeviceHandleBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < DeviceHandleCount; Index++) { | |
Status = EfiTestManagedDevice (DeviceHandleBuffer[Index], ImageHandle, &gEfiDiskIoProtocolGuid); | |
if (!EFI_ERROR (Status)) { | |
Status = gBS->DisconnectController ( | |
DeviceHandleBuffer[Index], | |
ImageHandle, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
break; | |
} | |
} | |
} | |
if (Index == DeviceHandleCount) { | |
// | |
// Driver is stopped successfully. | |
// | |
Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentNameProtocolGuid, &ComponentName); | |
if (EFI_ERROR (Status)) { | |
ComponentName = NULL; | |
} | |
Status = gBS->HandleProtocol (ImageHandle, &gEfiComponentName2ProtocolGuid, &ComponentName2); | |
if (EFI_ERROR (Status)) { | |
ComponentName2 = NULL; | |
} | |
if (ComponentName == NULL) { | |
if (ComponentName2 == NULL) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gFatDriverBinding, | |
NULL | |
); | |
} else { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gFatDriverBinding, | |
&gEfiComponentName2ProtocolGuid, | |
ComponentName2, | |
NULL | |
); | |
} | |
} else { | |
if (ComponentName2 == NULL) { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gFatDriverBinding, | |
&gEfiComponentNameProtocolGuid, | |
ComponentName, | |
NULL | |
); | |
} else { | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ImageHandle, | |
&gEfiDriverBindingProtocolGuid, | |
&gFatDriverBinding, | |
&gEfiComponentNameProtocolGuid, | |
ComponentName, | |
&gEfiComponentName2ProtocolGuid, | |
ComponentName2, | |
NULL | |
); | |
} | |
} | |
} | |
if (DeviceHandleBuffer != NULL) { | |
FreePool (DeviceHandleBuffer); | |
} | |
return Status; | |
} | |
/** | |
Test to see if this driver can add a file system to ControllerHandle. | |
ControllerHandle must support both Disk IO and Block IO protocols. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to test. | |
@param RemainingDevicePath - Not used. | |
@retval EFI_SUCCESS - This driver supports this device. | |
@retval EFI_ALREADY_STARTED - This driver is already running on this device. | |
@return other - This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingSupported ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_DISK_IO_PROTOCOL *DiskIo; | |
// | |
// Open the IO Abstraction(s) needed to perform the supported test | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiDiskIoProtocolGuid, | |
(VOID **)&DiskIo, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Close the I/O Abstraction(s) used to perform the supported test | |
// | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDiskIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
// | |
// Open the IO Abstraction(s) needed to perform the supported test | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiBlockIoProtocolGuid, | |
NULL, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
return Status; | |
} | |
/** | |
Start this driver on ControllerHandle by opening a Block IO and Disk IO | |
protocol, reading Device Path. Add a Simple File System protocol to | |
ControllerHandle if the media contains a valid file system. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to bind driver to. | |
@param RemainingDevicePath - Not used. | |
@retval EFI_SUCCESS - This driver is added to DeviceHandle. | |
@retval EFI_ALREADY_STARTED - This driver is already running on DeviceHandle. | |
@retval EFI_OUT_OF_RESOURCES - Can not allocate the memory. | |
@return other - This driver does not support this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingStart ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_BLOCK_IO_PROTOCOL *BlockIo; | |
EFI_DISK_IO_PROTOCOL *DiskIo; | |
EFI_DISK_IO2_PROTOCOL *DiskIo2; | |
BOOLEAN LockedByMe; | |
LockedByMe = FALSE; | |
// | |
// Acquire the lock. | |
// If caller has already acquired the lock, cannot lock it again. | |
// | |
Status = FatAcquireLockOrFail (); | |
if (!EFI_ERROR (Status)) { | |
LockedByMe = TRUE; | |
} | |
Status = InitializeUnicodeCollationSupport (This->DriverBindingHandle); | |
if (EFI_ERROR (Status)) { | |
goto Exit; | |
} | |
// | |
// Open our required BlockIo and DiskIo | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiBlockIoProtocolGuid, | |
(VOID **)&BlockIo, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
goto Exit; | |
} | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiDiskIoProtocolGuid, | |
(VOID **)&DiskIo, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
goto Exit; | |
} | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiDiskIo2ProtocolGuid, | |
(VOID **)&DiskIo2, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_BY_DRIVER | |
); | |
if (EFI_ERROR (Status)) { | |
DiskIo2 = NULL; | |
} | |
// | |
// Allocate Volume structure. In FatAllocateVolume(), Resources | |
// are allocated with protocol installed and cached initialized | |
// | |
Status = FatAllocateVolume (ControllerHandle, DiskIo, DiskIo2, BlockIo); | |
// | |
// When the media changes on a device it will Reinstall the BlockIo interface. | |
// This will cause a call to our Stop(), and a subsequent reentrant call to our | |
// Start() successfully. We should leave the device open when this happen. | |
// | |
if (EFI_ERROR (Status)) { | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
NULL, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_TEST_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDiskIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDiskIo2ProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
} | |
} | |
Exit: | |
// | |
// Unlock if locked by myself. | |
// | |
if (LockedByMe) { | |
FatReleaseLock (); | |
} | |
return Status; | |
} | |
/** | |
Stop this driver on ControllerHandle. | |
@param This - Protocol instance pointer. | |
@param ControllerHandle - Handle of device to stop driver on. | |
@param NumberOfChildren - Not used. | |
@param ChildHandleBuffer - Not used. | |
@retval EFI_SUCCESS - This driver is removed DeviceHandle. | |
@return other - This driver was not removed from this device. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
FatDriverBindingStop ( | |
IN EFI_DRIVER_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ControllerHandle, | |
IN UINTN NumberOfChildren, | |
IN EFI_HANDLE *ChildHandleBuffer | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; | |
FAT_VOLUME *Volume; | |
EFI_DISK_IO2_PROTOCOL *DiskIo2; | |
DiskIo2 = NULL; | |
// | |
// Get our context back | |
// | |
Status = gBS->OpenProtocol ( | |
ControllerHandle, | |
&gEfiSimpleFileSystemProtocolGuid, | |
(VOID **)&FileSystem, | |
This->DriverBindingHandle, | |
ControllerHandle, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
if (!EFI_ERROR (Status)) { | |
Volume = VOLUME_FROM_VOL_INTERFACE (FileSystem); | |
DiskIo2 = Volume->DiskIo2; | |
Status = FatAbandonVolume (Volume); | |
} | |
if (!EFI_ERROR (Status)) { | |
if (DiskIo2 != NULL) { | |
Status = gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDiskIo2ProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
ASSERT_EFI_ERROR (Status); | |
} | |
Status = gBS->CloseProtocol ( | |
ControllerHandle, | |
&gEfiDiskIoProtocolGuid, | |
This->DriverBindingHandle, | |
ControllerHandle | |
); | |
ASSERT_EFI_ERROR (Status); | |
} | |
return Status; | |
} |