/** @file Fat File System driver routines that support EFI driver model. Copyright (c) 2005 - 2014, Intel Corporation. All rights reserved.
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; }