Home | History | Annotate | Download | only in IsaFloppyDxe
      1 /** @file
      2   ISA Floppy Disk UEFI Driver conforming to the UEFI driver model
      3 
      4   1. Support two types diskette drive
      5      1.44M drive and 2.88M drive (and now only support 1.44M)
      6   2. Support two diskette drives per floppy disk controller
      7   3. Use DMA channel 2 to transfer data
      8   4. Do not use interrupt
      9   5. Support diskette change line signal and write protect
     10 
     11 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
     12 This program and the accompanying materials
     13 are licensed and made available under the terms and conditions of the BSD License
     14 which accompanies this distribution.  The full text of the license may be found at
     15 http://opensource.org/licenses/bsd-license.php
     16 
     17 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     18 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     19 
     20 **/
     21 
     22 #include "IsaFloppy.h"
     23 
     24 LIST_ENTRY  mControllerHead = INITIALIZE_LIST_HEAD_VARIABLE (mControllerHead);
     25 
     26 //
     27 // ISA Floppy Driver Binding Protocol
     28 //
     29 EFI_DRIVER_BINDING_PROTOCOL gFdcControllerDriver = {
     30   FdcControllerDriverSupported,
     31   FdcControllerDriverStart,
     32   FdcControllerDriverStop,
     33   0xa,
     34   NULL,
     35   NULL
     36 };
     37 
     38 
     39 /**
     40   The main Entry Point for this driver.
     41 
     42   @param[in] ImageHandle  The firmware allocated handle for the EFI image.
     43   @param[in] SystemTable  A pointer to the EFI System Table.
     44 
     45   @retval EFI_SUCCESS     The entry point is executed successfully.
     46   @retval other           Some error occurs when executing this entry point.
     47 **/
     48 EFI_STATUS
     49 EFIAPI
     50 InitializeIsaFloppy(
     51   IN EFI_HANDLE           ImageHandle,
     52   IN EFI_SYSTEM_TABLE     *SystemTable
     53   )
     54 {
     55   EFI_STATUS  Status;
     56 
     57   //
     58   // Install driver model protocol(s).
     59   //
     60   Status = EfiLibInstallDriverBindingComponentName2 (
     61              ImageHandle,
     62              SystemTable,
     63              &gFdcControllerDriver,
     64              ImageHandle,
     65              &gIsaFloppyComponentName,
     66              &gIsaFloppyComponentName2
     67              );
     68   ASSERT_EFI_ERROR (Status);
     69 
     70   return Status;
     71 }
     72 
     73 /**
     74   Test if the controller is a floppy disk drive device
     75 
     76   @param[in] This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
     77   @param[in] Controller           The handle of the controller to test.
     78   @param[in] RemainingDevicePath  A pointer to the remaining portion of a device path.
     79 
     80   @retval EFI_SUCCESS             The device is supported by this driver.
     81   @retval EFI_ALREADY_STARTED     The device is already being managed by this driver.
     82   @retval EFI_ACCESS_DENIED       The device is already being managed by a different driver
     83                                   or an application that requires exclusive access.
     84   @retval EFI_UNSUPPORTED         The device is is not supported by this driver.
     85 **/
     86 EFI_STATUS
     87 EFIAPI
     88 FdcControllerDriverSupported (
     89   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
     90   IN EFI_HANDLE                   Controller,
     91   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
     92   )
     93 {
     94   EFI_STATUS                Status;
     95   EFI_ISA_IO_PROTOCOL       *IsaIo;
     96   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
     97 
     98   //
     99   // Ignore the parameter RemainingDevicePath because this is a device driver.
    100   //
    101 
    102   //
    103   // Open the device path protocol
    104   //
    105   Status = gBS->OpenProtocol (
    106                   Controller,
    107                   &gEfiDevicePathProtocolGuid,
    108                   (VOID **) &ParentDevicePath,
    109                   This->DriverBindingHandle,
    110                   Controller,
    111                   EFI_OPEN_PROTOCOL_BY_DRIVER
    112                   );
    113   if (EFI_ERROR (Status)) {
    114     return Status;
    115   }
    116 
    117   gBS->CloseProtocol (
    118          Controller,
    119          &gEfiDevicePathProtocolGuid,
    120          This->DriverBindingHandle,
    121          Controller
    122          );
    123 
    124   //
    125   // Open the ISA I/O Protocol
    126   //
    127   Status = gBS->OpenProtocol (
    128                   Controller,
    129                   &gEfiIsaIoProtocolGuid,
    130                   (VOID **) &IsaIo,
    131                   This->DriverBindingHandle,
    132                   Controller,
    133                   EFI_OPEN_PROTOCOL_BY_DRIVER
    134                   );
    135   if (EFI_ERROR (Status)) {
    136     return Status;
    137   }
    138   //
    139   // Use the ISA I/O Protocol to see if Controller is a floppy disk drive device
    140   //
    141   Status = EFI_SUCCESS;
    142   if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
    143     Status = EFI_UNSUPPORTED;
    144   }
    145   //
    146   // Close the ISA I/O Protocol
    147   //
    148   gBS->CloseProtocol (
    149          Controller,
    150          &gEfiIsaIoProtocolGuid,
    151          This->DriverBindingHandle,
    152          Controller
    153          );
    154 
    155   return Status;
    156 }
    157 
    158 /**
    159   Start this driver on Controller.
    160 
    161   @param[in] This                  A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    162   @param[in] ControllerHandle      The handle of the controller to start. This handle
    163                                    must support a protocol interface that supplies
    164                                    an I/O abstraction to the driver.
    165   @param[in] RemainingDevicePath   A pointer to the remaining portion of a device path.
    166                                    This parameter is ignored by device drivers, and is optional for bus drivers.
    167 
    168   @retval EFI_SUCCESS              The device was started.
    169   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.
    170                                    Currently not implemented.
    171   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    172   @retval Others                   The driver failded to start the device.
    173 **/
    174 EFI_STATUS
    175 EFIAPI
    176 FdcControllerDriverStart (
    177   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    178   IN EFI_HANDLE                   Controller,
    179   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath
    180   )
    181 {
    182   EFI_STATUS                Status;
    183   FDC_BLK_IO_DEV            *FdcDev;
    184   EFI_ISA_IO_PROTOCOL       *IsaIo;
    185   UINTN                     Index;
    186   LIST_ENTRY                *List;
    187   BOOLEAN                   Found;
    188   EFI_DEVICE_PATH_PROTOCOL  *ParentDevicePath;
    189 
    190   FdcDev  = NULL;
    191   IsaIo   = NULL;
    192 
    193   //
    194   // Open the device path protocol
    195   //
    196   Status = gBS->OpenProtocol (
    197                   Controller,
    198                   &gEfiDevicePathProtocolGuid,
    199                   (VOID **) &ParentDevicePath,
    200                   This->DriverBindingHandle,
    201                   Controller,
    202                   EFI_OPEN_PROTOCOL_BY_DRIVER
    203                   );
    204   if (EFI_ERROR (Status)) {
    205     return Status;
    206   }
    207   //
    208   // Report enable progress code
    209   //
    210   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    211     EFI_PROGRESS_CODE,
    212     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE,
    213     ParentDevicePath
    214     );
    215 
    216   //
    217   // Open the ISA I/O Protocol
    218   //
    219   Status = gBS->OpenProtocol (
    220                   Controller,
    221                   &gEfiIsaIoProtocolGuid,
    222                   (VOID **) &IsaIo,
    223                   This->DriverBindingHandle,
    224                   Controller,
    225                   EFI_OPEN_PROTOCOL_BY_DRIVER
    226                   );
    227   if (EFI_ERROR (Status)) {
    228     goto Done;
    229   }
    230   //
    231   // Allocate the floppy device's Device structure
    232   //
    233   FdcDev = AllocateZeroPool (sizeof (FDC_BLK_IO_DEV));
    234   if (FdcDev == NULL) {
    235     goto Done;
    236   }
    237   //
    238   // Initialize the floppy device's device structure
    239   //
    240   FdcDev->Signature       = FDC_BLK_IO_DEV_SIGNATURE;
    241   FdcDev->Handle          = Controller;
    242   FdcDev->IsaIo           = IsaIo;
    243   FdcDev->Disk            = (EFI_FDC_DISK) IsaIo->ResourceList->Device.UID;
    244   FdcDev->Cache           = NULL;
    245   FdcDev->Event           = NULL;
    246   FdcDev->ControllerState = NULL;
    247   FdcDev->DevicePath      = ParentDevicePath;
    248 
    249   FdcDev->ControllerNameTable = NULL;
    250   AddName (FdcDev);
    251 
    252   //
    253   // Look up the base address of the Floppy Disk Controller which controls this floppy device
    254   //
    255   for (Index = 0; FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
    256     if (FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
    257       FdcDev->BaseAddress = (UINT16) FdcDev->IsaIo->ResourceList->ResourceItem[Index].StartRange;
    258     }
    259   }
    260   //
    261   // Maintain the list of floppy disk controllers
    262   //
    263   Found = FALSE;
    264   List  = mControllerHead.ForwardLink;
    265   while (List != &mControllerHead) {
    266     FdcDev->ControllerState = FLOPPY_CONTROLLER_FROM_LIST_ENTRY (List);
    267     if (FdcDev->BaseAddress == FdcDev->ControllerState->BaseAddress) {
    268       Found = TRUE;
    269       break;
    270     }
    271 
    272     List = List->ForwardLink;
    273   }
    274 
    275   if (!Found) {
    276     //
    277     // A new floppy disk controller controlling this floppy disk drive is found
    278     //
    279     FdcDev->ControllerState = AllocatePool (sizeof (FLOPPY_CONTROLLER_CONTEXT));
    280     if (FdcDev->ControllerState == NULL) {
    281       goto Done;
    282     }
    283 
    284     FdcDev->ControllerState->Signature          = FLOPPY_CONTROLLER_CONTEXT_SIGNATURE;
    285     FdcDev->ControllerState->FddResetPerformed  = FALSE;
    286     FdcDev->ControllerState->NeedRecalibrate    = FALSE;
    287     FdcDev->ControllerState->BaseAddress        = FdcDev->BaseAddress;
    288     FdcDev->ControllerState->NumberOfDrive      = 0;
    289 
    290     InsertTailList (&mControllerHead, &FdcDev->ControllerState->Link);
    291   }
    292   //
    293   // Create a timer event for each floppy disk drive device.
    294   // This timer event is used to control the motor on and off
    295   //
    296   Status = gBS->CreateEvent (
    297                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
    298                   TPL_NOTIFY,
    299                   FddTimerProc,
    300                   FdcDev,
    301                   &FdcDev->Event
    302                   );
    303   if (EFI_ERROR (Status)) {
    304     goto Done;
    305   }
    306   //
    307   // Reset the Floppy Disk Controller
    308   //
    309   if (!FdcDev->ControllerState->FddResetPerformed) {
    310     FdcDev->ControllerState->FddResetPerformed  = TRUE;
    311     FdcDev->ControllerState->FddResetStatus     = FddReset (FdcDev);
    312   }
    313 
    314   if (EFI_ERROR (FdcDev->ControllerState->FddResetStatus)) {
    315     Status = EFI_DEVICE_ERROR;
    316     goto Done;
    317   }
    318 
    319   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    320     EFI_PROGRESS_CODE,
    321     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_PRESENCE_DETECT,
    322     ParentDevicePath
    323     );
    324 
    325   //
    326   // Discover the Floppy Drive
    327   //
    328   Status = DiscoverFddDevice (FdcDev);
    329   if (EFI_ERROR (Status)) {
    330     Status = EFI_DEVICE_ERROR;
    331     goto Done;
    332   }
    333   //
    334   // Install protocol interfaces for the serial device.
    335   //
    336   Status = gBS->InstallMultipleProtocolInterfaces (
    337                   &Controller,
    338                   &gEfiBlockIoProtocolGuid,
    339                   &FdcDev->BlkIo,
    340                   NULL
    341                   );
    342   if (!EFI_ERROR (Status)) {
    343     FdcDev->ControllerState->NumberOfDrive++;
    344   }
    345 
    346 Done:
    347   if (EFI_ERROR (Status)) {
    348 
    349     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    350       EFI_ERROR_CODE | EFI_ERROR_MINOR,
    351       EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_CONTROLLER_ERROR,
    352       ParentDevicePath
    353       );
    354 
    355     //
    356     // If a floppy drive device structure was allocated, then free it
    357     //
    358     if (FdcDev != NULL) {
    359       if (FdcDev->Event != NULL) {
    360         //
    361         // Close the event for turning the motor off
    362         //
    363         gBS->CloseEvent (FdcDev->Event);
    364       }
    365 
    366       FreeUnicodeStringTable (FdcDev->ControllerNameTable);
    367       FreePool (FdcDev);
    368     }
    369 
    370     //
    371     // Close the ISA I/O Protocol
    372     //
    373     if (IsaIo != NULL) {
    374       gBS->CloseProtocol (
    375              Controller,
    376              &gEfiIsaIoProtocolGuid,
    377              This->DriverBindingHandle,
    378              Controller
    379              );
    380     }
    381 
    382     //
    383     // Close the device path protocol
    384     //
    385     gBS->CloseProtocol (
    386            Controller,
    387            &gEfiDevicePathProtocolGuid,
    388            This->DriverBindingHandle,
    389            Controller
    390            );
    391   }
    392 
    393   return Status;
    394 }
    395 
    396 /**
    397   Stop this driver on ControllerHandle.
    398 
    399   @param[in] This               A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    400   @param[in] ControllerHandle   A handle to the device being stopped. The handle must
    401                                 support a bus specific I/O protocol for the driver
    402                                 to use to stop the device.
    403   @param[in] NumberOfChildren   The number of child device handles in ChildHandleBuffer.
    404   @param[in] ChildHandleBuffer  An array of child handles to be freed. May be NULL
    405                                 if NumberOfChildren is 0.
    406 
    407   @retval EFI_SUCCESS           The device was stopped.
    408   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    409 **/
    410 EFI_STATUS
    411 EFIAPI
    412 FdcControllerDriverStop (
    413   IN  EFI_DRIVER_BINDING_PROTOCOL  *This,
    414   IN  EFI_HANDLE                   Controller,
    415   IN  UINTN                        NumberOfChildren,
    416   IN  EFI_HANDLE                   *ChildHandleBuffer
    417   )
    418 {
    419   EFI_STATUS            Status;
    420   EFI_BLOCK_IO_PROTOCOL *BlkIo;
    421   FDC_BLK_IO_DEV        *FdcDev;
    422 
    423   //
    424   // Ignore NumberOfChildren since this is a device driver
    425   //
    426 
    427   //
    428   // Get the Block I/O Protocol on Controller
    429   //
    430   Status = gBS->OpenProtocol (
    431                   Controller,
    432                   &gEfiBlockIoProtocolGuid,
    433                   (VOID **) &BlkIo,
    434                   This->DriverBindingHandle,
    435                   Controller,
    436                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    437                   );
    438   if (EFI_ERROR (Status)) {
    439     return Status;
    440   }
    441   //
    442   // Get the floppy drive device's Device structure
    443   //
    444   FdcDev = FDD_BLK_IO_FROM_THIS (BlkIo);
    445 
    446   //
    447   // Report disable progress code
    448   //
    449   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
    450     EFI_PROGRESS_CODE,
    451     EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE,
    452     FdcDev->DevicePath
    453     );
    454 
    455   //
    456   // Uninstall the Block I/O Protocol
    457   //
    458   Status = gBS->UninstallProtocolInterface (
    459                   Controller,
    460                   &gEfiBlockIoProtocolGuid,
    461                   &FdcDev->BlkIo
    462                   );
    463   if (EFI_ERROR (Status)) {
    464     return Status;
    465   }
    466 
    467   //
    468   // Close the event for turning the motor off
    469   //
    470   gBS->CloseEvent (FdcDev->Event);
    471 
    472   //
    473   // Turn the motor off on the floppy drive device
    474   //
    475   FddTimerProc (FdcDev->Event, FdcDev);
    476 
    477   //
    478   // Close the device path protocol
    479   //
    480   gBS->CloseProtocol (
    481          Controller,
    482          &gEfiDevicePathProtocolGuid,
    483          This->DriverBindingHandle,
    484          Controller
    485          );
    486 
    487   //
    488   // Close the ISA I/O Protocol
    489   //
    490   gBS->CloseProtocol (
    491          Controller,
    492          &gEfiIsaIoProtocolGuid,
    493          This->DriverBindingHandle,
    494          Controller
    495          );
    496 
    497   //
    498   // Free the controller list if needed
    499   //
    500   FdcDev->ControllerState->NumberOfDrive--;
    501 
    502   //
    503   // Free the cache if one was allocated
    504   //
    505   FdcFreeCache (FdcDev);
    506 
    507   //
    508   // Free the floppy drive device's device structure
    509   //
    510   FreeUnicodeStringTable (FdcDev->ControllerNameTable);
    511   FreePool (FdcDev);
    512 
    513   return EFI_SUCCESS;
    514 }
    515 
    516