Home | History | Annotate | Download | only in IsaFloppyDxe
      1 /** @file
      2   Implementation of the EFI Block IO Protocol for ISA Floppy driver
      3 
      4 Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "IsaFloppy.h"
     16 
     17 /**
     18   Reset the Block Device.
     19 
     20   @param  This                 Indicates a pointer to the calling context.
     21   @param  ExtendedVerification Driver may perform diagnostics on reset.
     22 
     23   @retval EFI_SUCCESS          The device was reset.
     24   @retval EFI_DEVICE_ERROR     The device is not functioning properly and could
     25                                not be reset.
     26 **/
     27 EFI_STATUS
     28 EFIAPI
     29 FdcReset (
     30   IN  EFI_BLOCK_IO_PROTOCOL  *This,
     31   IN  BOOLEAN                ExtendedVerification
     32   )
     33 {
     34   FDC_BLK_IO_DEV  *FdcDev;
     35 
     36   //
     37   // Reset the Floppy Disk Controller
     38   //
     39   FdcDev = FDD_BLK_IO_FROM_THIS (This);
     40 
     41   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
     42     EFI_PROGRESS_CODE,
     43     EFI_P_PC_RESET | EFI_PERIPHERAL_REMOVABLE_MEDIA,
     44     FdcDev->DevicePath
     45     );
     46 
     47   return FddReset (FdcDev);
     48 }
     49 
     50 /**
     51   Flush the Block Device.
     52 
     53   @param  This              Indicates a pointer to the calling context.
     54 
     55   @retval EFI_SUCCESS       All outstanding data was written to the device
     56   @retval EFI_DEVICE_ERROR  The device reported an error while writting back the data
     57   @retval EFI_NO_MEDIA      There is no media in the device.
     58 
     59 **/
     60 EFI_STATUS
     61 EFIAPI
     62 FddFlushBlocks (
     63   IN  EFI_BLOCK_IO_PROTOCOL  *This
     64   )
     65 {
     66   //
     67   // Not supported yet
     68   //
     69   return EFI_SUCCESS;
     70 }
     71 
     72 /**
     73   Common report status code interface.
     74 
     75   @param This  Pointer of FDC_BLK_IO_DEV instance
     76   @param Read  Read or write operation when error occurrs
     77 **/
     78 VOID
     79 FddReportStatus (
     80   IN  EFI_BLOCK_IO_PROTOCOL  *This,
     81   IN  BOOLEAN                Read
     82   )
     83 {
     84   FDC_BLK_IO_DEV  *FdcDev;
     85 
     86   FdcDev = FDD_BLK_IO_FROM_THIS (This);
     87 
     88   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
     89     EFI_ERROR_CODE,
     90     ((Read) ? EFI_P_EC_INPUT_ERROR : EFI_P_EC_OUTPUT_ERROR) | EFI_PERIPHERAL_REMOVABLE_MEDIA,
     91     FdcDev->DevicePath
     92     );
     93 }
     94 
     95 /**
     96   Read BufferSize bytes from Lba into Buffer.
     97 
     98   @param  This       Indicates a pointer to the calling context.
     99   @param  MediaId    Id of the media, changes every time the media is replaced.
    100   @param  Lba        The starting Logical Block Address to read from
    101   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    102   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    103                      responsible for either having implicit or explicit ownership of the buffer.
    104 
    105   @retval EFI_SUCCESS           The data was read correctly from the device.
    106   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    107   @retval EFI_NO_MEDIA          There is no media in the device.
    108   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    109   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    110   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    111                                 or the buffer is not on proper alignment.
    112 
    113 **/
    114 EFI_STATUS
    115 EFIAPI
    116 FddReadBlocks (
    117   IN  EFI_BLOCK_IO_PROTOCOL  *This,
    118   IN  UINT32                 MediaId,
    119   IN  EFI_LBA                Lba,
    120   IN  UINTN                  BufferSize,
    121   OUT VOID                   *Buffer
    122   )
    123 {
    124   EFI_STATUS  Status;
    125 
    126   Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, READ, Buffer);
    127 
    128   if (EFI_ERROR (Status)) {
    129     FddReportStatus (This, TRUE);
    130   }
    131 
    132   return Status;
    133 }
    134 
    135 /**
    136   Write BufferSize bytes from Lba into Buffer.
    137 
    138   @param  This       Indicates a pointer to the calling context.
    139   @param  MediaId    The media ID that the write request is for.
    140   @param  Lba        The starting logical block address to be written. The caller is
    141                      responsible for writing to only legitimate locations.
    142   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    143   @param  Buffer     A pointer to the source buffer for the data.
    144 
    145   @retval EFI_SUCCESS           The data was written correctly to the device.
    146   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    147   @retval EFI_DEVICE_ERROR      The device reported an error while performing the write.
    148   @retval EFI_NO_MEDIA          There is no media in the device.
    149   @retval EFI_MEDIA_CHNAGED     The MediaId does not matched the current device.
    150   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    151   @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
    152                                 or the buffer is not on proper alignment.
    153 
    154 **/
    155 EFI_STATUS
    156 EFIAPI
    157 FddWriteBlocks (
    158   IN EFI_BLOCK_IO_PROTOCOL  *This,
    159   IN UINT32                 MediaId,
    160   IN EFI_LBA                Lba,
    161   IN UINTN                  BufferSize,
    162   IN VOID                   *Buffer
    163   )
    164 {
    165   EFI_STATUS  Status;
    166 
    167   Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, WRITE, Buffer);
    168 
    169   if (EFI_ERROR (Status)) {
    170     FddReportStatus (This, FALSE);
    171   }
    172 
    173   return Status;
    174 }
    175 
    176 /**
    177   Read or Write a number of blocks to floppy disk
    178 
    179   @param  This       Indicates a pointer to the calling context.
    180   @param  MediaId    Id of the media, changes every time the media is replaced.
    181   @param  Lba        The starting Logical Block Address to read from
    182   @param  BufferSize Size of Buffer, must be a multiple of device block size.
    183   @param  Operation  Specifies the read or write operation.
    184   @param  Buffer     A pointer to the destination buffer for the data. The caller is
    185                      responsible for either having implicit or explicit ownership of the buffer.
    186 
    187   @retval EFI_SUCCESS           The data was read correctly from the device.
    188   @retval EFI_DEVICE_ERROR      The device reported an error while performing the read.
    189   @retval EFI_NO_MEDIA          There is no media in the device.
    190   @retval EFI_MEDIA_CHANGED     The MediaId does not matched the current device.
    191   @retval EFI_BAD_BUFFER_SIZE   The Buffer was not a multiple of the block size of the device.
    192   @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
    193                                 or the buffer is not on proper alignment.
    194   @retval EFI_WRITE_PROTECTED   The device can not be written to.
    195 
    196 **/
    197 EFI_STATUS
    198 FddReadWriteBlocks (
    199   IN  EFI_BLOCK_IO_PROTOCOL  *This,
    200   IN  UINT32                 MediaId,
    201   IN  EFI_LBA                Lba,
    202   IN  UINTN                  BufferSize,
    203   IN  BOOLEAN                Operation,
    204   OUT VOID                   *Buffer
    205   )
    206 {
    207   EFI_BLOCK_IO_MEDIA  *Media;
    208   FDC_BLK_IO_DEV      *FdcDev;
    209   UINTN               BlockSize;
    210   UINTN               NumberOfBlocks;
    211   UINTN               BlockCount;
    212   EFI_STATUS          Status;
    213   EFI_LBA             Lba0;
    214   UINT8               *Pointer;
    215 
    216   //
    217   // Get the intrinsic block size
    218   //
    219   Media     = This->Media;
    220   BlockSize = Media->BlockSize;
    221   FdcDev    = FDD_BLK_IO_FROM_THIS (This);
    222 
    223   if (Operation == WRITE) {
    224     if (Lba == 0) {
    225       FdcFreeCache (FdcDev);
    226     }
    227   }
    228 
    229   //
    230   // Set the drive motor on
    231   //
    232   Status = MotorOn (FdcDev);
    233   if (EFI_ERROR (Status)) {
    234     return EFI_DEVICE_ERROR;
    235   }
    236   //
    237   // Check to see if media can be detected
    238   //
    239   Status = DetectMedia (FdcDev);
    240   if (EFI_ERROR (Status)) {
    241     MotorOff (FdcDev);
    242     FdcFreeCache (FdcDev);
    243     return EFI_DEVICE_ERROR;
    244   }
    245   //
    246   // Check to see if media is present
    247   //
    248   if (!(Media->MediaPresent)) {
    249     MotorOff (FdcDev);
    250     FdcFreeCache (FdcDev);
    251     return EFI_NO_MEDIA;
    252   }
    253   //
    254   // Check to see if media has been changed
    255   //
    256   if (MediaId != Media->MediaId) {
    257     MotorOff (FdcDev);
    258     FdcFreeCache (FdcDev);
    259     return EFI_MEDIA_CHANGED;
    260   }
    261 
    262   if (BufferSize == 0) {
    263     MotorOff (FdcDev);
    264     return EFI_SUCCESS;
    265   }
    266 
    267   if (Operation == WRITE) {
    268     if (Media->ReadOnly) {
    269       MotorOff (FdcDev);
    270       return EFI_WRITE_PROTECTED;
    271     }
    272   }
    273   //
    274   // Check the parameters for this read/write operation
    275   //
    276   if (Buffer == NULL) {
    277     MotorOff (FdcDev);
    278     return EFI_INVALID_PARAMETER;
    279   }
    280 
    281   if (BufferSize % BlockSize != 0) {
    282     MotorOff (FdcDev);
    283     return EFI_BAD_BUFFER_SIZE;
    284   }
    285 
    286   if (Lba > Media->LastBlock) {
    287     MotorOff (FdcDev);
    288     return EFI_INVALID_PARAMETER;
    289   }
    290 
    291   if (((BufferSize / BlockSize) + Lba - 1) > Media->LastBlock) {
    292     MotorOff (FdcDev);
    293     return EFI_INVALID_PARAMETER;
    294   }
    295 
    296   if (Operation == READ) {
    297     //
    298     // See if the data that is being read is already in the cache
    299     //
    300     if (FdcDev->Cache != NULL) {
    301       if (Lba == 0 && BufferSize == BlockSize) {
    302         MotorOff (FdcDev);
    303         CopyMem ((UINT8 *) Buffer, (UINT8 *) FdcDev->Cache, BlockSize);
    304         return EFI_SUCCESS;
    305       }
    306     }
    307   }
    308   //
    309   // Set up Floppy Disk Controller
    310   //
    311   Status = Setup (FdcDev);
    312   if (EFI_ERROR (Status)) {
    313     MotorOff (FdcDev);
    314     return EFI_DEVICE_ERROR;
    315   }
    316 
    317   NumberOfBlocks  = BufferSize / BlockSize;
    318   Lba0            = Lba;
    319   Pointer         = Buffer;
    320 
    321   //
    322   // read blocks in the same cylinder.
    323   // in a cylinder , there are 18 * 2 = 36 blocks
    324   //
    325   BlockCount = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
    326   while ((BlockCount != 0) && !EFI_ERROR (Status)) {
    327     Status = ReadWriteDataSector (FdcDev, Buffer, Lba, BlockCount, Operation);
    328     if (EFI_ERROR (Status)) {
    329       MotorOff (FdcDev);
    330       FddReset (FdcDev);
    331       return EFI_DEVICE_ERROR;
    332     }
    333 
    334     Lba += BlockCount;
    335     NumberOfBlocks -= BlockCount;
    336     Buffer      = (VOID *) ((UINTN) Buffer + BlockCount * BlockSize);
    337     BlockCount  = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
    338   }
    339 
    340   Buffer = Pointer;
    341 
    342   //
    343   // Turn the motor off
    344   //
    345   MotorOff (FdcDev);
    346 
    347   if (Operation == READ) {
    348     //
    349     // Cache the data read
    350     //
    351     if (Lba0 == 0 && FdcDev->Cache == NULL) {
    352       FdcDev->Cache = AllocateCopyPool (BlockSize, Buffer);
    353     }
    354   }
    355 
    356   return EFI_SUCCESS;
    357 
    358 }
    359 
    360 /**
    361   Free cache for a floppy disk.
    362 
    363   @param FdcDev  A Pointer to FDC_BLK_IO_DEV instance
    364 
    365 **/
    366 VOID
    367 FdcFreeCache (
    368   IN FDC_BLK_IO_DEV  *FdcDev
    369   )
    370 {
    371   if (FdcDev->Cache != NULL) {
    372     FreePool (FdcDev->Cache);
    373     FdcDev->Cache = NULL;
    374   }
    375 }
    376