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