]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
Fix code bug to cause deal loop when no floppy device.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / IsaFloppyDxe / IsaFloppyCtrl.c
CommitLineData
d6321d6e 1/** @file\r
2 Internal floppy disk controller programming functions for the floppy driver.\r
f8cd287b 3 \r
d6321d6e 4Copyright (c) 2006 - 2009, Intel Corporation.<BR>\r
f8cd287b 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
11f43dfd 9\r
f8cd287b 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11f43dfd 12\r
f8cd287b 13**/\r
11f43dfd 14\r
15#include "IsaFloppy.h"\r
16\r
bcd70414 17/**\r
d6321d6e 18 Detect whether a floppy drive is present or not.\r
bcd70414 19 \r
d6321d6e 20 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
bcd70414 21\r
d6321d6e 22 @retval EFI_SUCCESS The floppy disk drive is present\r
23 @retval EFI_NOT_FOUND The floppy disk drive is not present\r
bcd70414 24**/\r
11f43dfd 25EFI_STATUS\r
26DiscoverFddDevice (\r
27 IN FDC_BLK_IO_DEV *FdcDev\r
28 )\r
11f43dfd 29{\r
30 EFI_STATUS Status;\r
31\r
32 FdcDev->BlkIo.Media = &FdcDev->BlkMedia;\r
33\r
11f43dfd 34 Status = FddIdentify (FdcDev);\r
35 if (EFI_ERROR (Status)) {\r
36 return EFI_NOT_FOUND;\r
37 }\r
38\r
39 FdcDev->BlkIo.Reset = FdcReset;\r
40 FdcDev->BlkIo.FlushBlocks = FddFlushBlocks;\r
41 FdcDev->BlkIo.ReadBlocks = FddReadBlocks;\r
42 FdcDev->BlkIo.WriteBlocks = FddWriteBlocks;\r
43 FdcDev->BlkMedia.LogicalPartition = FALSE;\r
44 FdcDev->BlkMedia.WriteCaching = FALSE;\r
45\r
46 return EFI_SUCCESS;\r
47}\r
48\r
bcd70414 49/**\r
d6321d6e 50 Do recalibrate and check if the drive is present or not\r
51 and set the media parameters if the driver is present.\r
bcd70414 52 \r
d6321d6e 53 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
bcd70414 54\r
d6321d6e 55 @retval EFI_SUCCESS The floppy disk drive is present\r
56 @retval EFI_DEVICE_ERROR The floppy disk drive is not present\r
bcd70414 57**/\r
11f43dfd 58EFI_STATUS\r
59FddIdentify (\r
60 IN FDC_BLK_IO_DEV *FdcDev\r
61 )\r
11f43dfd 62{\r
63 EFI_STATUS Status;\r
64\r
65 //\r
66 // Set Floppy Disk Controller's motor on\r
67 //\r
68 Status = MotorOn (FdcDev);\r
69 if (EFI_ERROR (Status)) {\r
70 return EFI_DEVICE_ERROR;\r
71 }\r
72\r
73 Status = Recalibrate (FdcDev);\r
74\r
75 if (EFI_ERROR (Status)) {\r
76 MotorOff (FdcDev);\r
77 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
78 return EFI_DEVICE_ERROR;\r
79 }\r
80 //\r
81 // Set Media Parameter\r
82 //\r
83 FdcDev->BlkIo.Media->RemovableMedia = TRUE;\r
84 FdcDev->BlkIo.Media->MediaPresent = TRUE;\r
11f43dfd 85 FdcDev->BlkIo.Media->MediaId = 0;\r
86\r
87 //\r
88 // Check Media\r
89 //\r
90 Status = DisketChanged (FdcDev);\r
11f43dfd 91\r
ae5852b2 92 if (Status == EFI_NO_MEDIA) {\r
93 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
179a2e97 94 } else if ((Status != EFI_MEDIA_CHANGED) &&\r
95 (Status != EFI_SUCCESS)) {\r
11f43dfd 96 MotorOff (FdcDev);\r
97 return Status;\r
98 }\r
ae5852b2 99\r
11f43dfd 100 //\r
101 // Check Disk Write Protected\r
102 //\r
103 Status = SenseDrvStatus (FdcDev, 0);\r
11f43dfd 104\r
ae5852b2 105 if (Status == EFI_WRITE_PROTECTED) {\r
106 FdcDev->BlkIo.Media->ReadOnly = TRUE;\r
107 } else if (Status == EFI_SUCCESS) {\r
11f43dfd 108 FdcDev->BlkIo.Media->ReadOnly = FALSE;\r
ae5852b2 109 } else {\r
11f43dfd 110 return EFI_DEVICE_ERROR;\r
11f43dfd 111 }\r
112\r
113 MotorOff (FdcDev);\r
114\r
115 //\r
116 // Set Media Default Type\r
117 //\r
118 FdcDev->BlkIo.Media->BlockSize = DISK_1440K_BYTEPERSECTOR;\r
119 FdcDev->BlkIo.Media->LastBlock = DISK_1440K_EOT * 2 * (DISK_1440K_MAXTRACKNUM + 1) - 1;\r
120\r
121 return EFI_SUCCESS;\r
122}\r
123\r
bcd70414 124/**\r
d6321d6e 125 Reset the Floppy Logic Drive.\r
bcd70414 126 \r
d6321d6e 127 @param FdcDev FDC_BLK_IO_DEV * : A pointer to the FDC_BLK_IO_DEV\r
bcd70414 128 \r
129 @retval EFI_SUCCESS: The Floppy Logic Drive is reset\r
130 @retval EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and\r
131 can not be reset\r
132\r
133**/\r
11f43dfd 134EFI_STATUS\r
135FddReset (\r
136 IN FDC_BLK_IO_DEV *FdcDev\r
137 )\r
11f43dfd 138{\r
d6321d6e 139 UINT8 Data;\r
11f43dfd 140 UINT8 StatusRegister0;\r
141 UINT8 PresentCylinderNumber;\r
142 UINTN Index;\r
143\r
144 //\r
145 // Report reset progress code\r
146 //\r
147 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
148 EFI_PROGRESS_CODE,\r
149 EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET,\r
150 FdcDev->DevicePath\r
151 );\r
152\r
153 //\r
154 // Reset specified Floppy Logic Drive according to FdcDev -> Disk\r
155 // Set Digital Output Register(DOR) to do reset work\r
156 // bit0 & bit1 of DOR : Drive Select\r
157 // bit2 : Reset bit\r
158 // bit3 : DMA and Int bit\r
159 // Reset : a "0" written to bit2 resets the FDC, this reset will remain\r
160 // active until\r
161 // a "1" is written to this bit.\r
162 // Reset step 1:\r
163 // use bit0 & bit1 to select the logic drive\r
164 // write "0" to bit2\r
165 //\r
d6321d6e 166 Data = 0x0;\r
167 Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));\r
168 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
11f43dfd 169\r
170 //\r
171 // wait some time,at least 120us\r
172 //\r
173 MicroSecondDelay (500);\r
174\r
175 //\r
176 // Reset step 2:\r
177 // write "1" to bit2\r
178 // write "1" to bit3 : enable DMA\r
179 //\r
d6321d6e 180 Data |= 0x0C;\r
181 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
11f43dfd 182\r
183 //\r
184 // Experience value\r
185 //\r
186 MicroSecondDelay (2000);\r
187\r
188 //\r
189 // wait specified floppy logic drive is not busy\r
190 //\r
191 if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {\r
192 return EFI_DEVICE_ERROR;\r
193 }\r
194 //\r
195 // Set the Transfer Data Rate\r
196 //\r
197 FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);\r
198\r
199 //\r
200 // Experience value\r
201 //\r
202 MicroSecondDelay (100);\r
203\r
204 //\r
205 // Issue Sense interrupt command for each drive (total 4 drives)\r
206 //\r
207 for (Index = 0; Index < 4; Index++) {\r
208 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
209 return EFI_DEVICE_ERROR;\r
210 }\r
211 }\r
212 //\r
213 // issue Specify command\r
214 //\r
215 if (EFI_ERROR (Specify (FdcDev))) {\r
216 return EFI_DEVICE_ERROR;\r
217 }\r
218\r
219 return EFI_SUCCESS;\r
220}\r
221\r
bcd70414 222/**\r
d6321d6e 223 Turn the floppy disk drive's motor on.\r
224 The drive's motor must be on before any command can be executed.\r
bcd70414 225 \r
d6321d6e 226 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
bcd70414 227 \r
d6321d6e 228 @retval EFI_SUCCESS The drive's motor was turned on successfully\r
229 @retval EFI_DEVICE_ERROR The drive is busy, so can not turn motor on\r
bcd70414 230**/\r
11f43dfd 231EFI_STATUS\r
232MotorOn (\r
233 IN FDC_BLK_IO_DEV *FdcDev\r
234 )\r
11f43dfd 235{\r
236 EFI_STATUS Status;\r
d6321d6e 237 UINT8 DorData;\r
11f43dfd 238\r
239 //\r
240 // Control of the floppy drive motors is a big pain. If motor is off, you have\r
241 // to turn it on first. But you can not leave the motor on all the time, since\r
242 // that would wear out the disk. On the other hand, if you turn the motor off\r
243 // after each operation, the system performance will be awful. The compromise\r
244 // used in this driver is to leave the motor on for 2 seconds after\r
245 // each operation. If a new operation is started in that interval(2s),\r
246 // the motor need not be turned on again. If no new operation is started,\r
247 // a timer goes off and the motor is turned off\r
248 //\r
249 //\r
250 // Cancel the timer\r
251 //\r
252 Status = gBS->SetTimer (FdcDev->Event, TimerCancel, 0);\r
d6321d6e 253 ASSERT_EFI_ERROR (Status);\r
11f43dfd 254\r
11f43dfd 255 //\r
256 // Get the motor status\r
257 //\r
d6321d6e 258 DorData = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
11f43dfd 259\r
d6321d6e 260 if (((FdcDev->Disk == FdcDisk0) && ((DorData & 0x10) == 0x10)) ||\r
261 ((FdcDev->Disk == FdcDisk1) && ((DorData & 0x21) == 0x21))\r
11f43dfd 262 ) {\r
263 return EFI_SUCCESS;\r
264 }\r
265 //\r
266 // The drive's motor is off, so need turn it on\r
267 // first look at command and drive are busy or not\r
268 //\r
269 if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {\r
270 return EFI_DEVICE_ERROR;\r
271 }\r
272 //\r
273 // for drive A: 1CH, drive B: 2DH\r
274 //\r
d6321d6e 275 DorData = 0x0C;\r
276 DorData = (UINT8) (DorData | (SELECT_DRV & FdcDev->Disk));\r
277 if (FdcDev->Disk == FdcDisk0) {\r
11f43dfd 278 //\r
279 // drive A\r
280 //\r
d6321d6e 281 DorData |= DRVA_MOTOR_ON;\r
11f43dfd 282 } else {\r
283 //\r
284 // drive B\r
285 //\r
d6321d6e 286 DorData |= DRVB_MOTOR_ON;\r
11f43dfd 287 }\r
288\r
d6321d6e 289 FdcWritePort (FdcDev, FDC_REGISTER_DOR, DorData);\r
11f43dfd 290\r
291 //\r
292 // Experience value\r
293 //\r
294 MicroSecondDelay (4000);\r
295\r
296 return EFI_SUCCESS;\r
297}\r
298\r
bcd70414 299/**\r
d6321d6e 300 Set a Timer and when Timer goes off, turn the motor off.\r
bcd70414 301 \r
d6321d6e 302 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
bcd70414 303 \r
d6321d6e 304 @retval EFI_SUCCESS Set the Timer successfully\r
305 @retval EFI_INVALID_PARAMETER Fail to Set the timer\r
bcd70414 306**/\r
11f43dfd 307EFI_STATUS\r
308MotorOff (\r
309 IN FDC_BLK_IO_DEV *FdcDev\r
310 )\r
11f43dfd 311{\r
312 //\r
313 // Set the timer : 2s\r
314 //\r
315 return gBS->SetTimer (FdcDev->Event, TimerRelative, 20000000);\r
316}\r
317\r
bcd70414 318/**\r
d6321d6e 319 Detect whether the disk in the drive is changed or not.\r
bcd70414 320 \r
d6321d6e 321 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV\r
bcd70414 322 \r
d6321d6e 323 @retval EFI_SUCCESS No disk media change\r
324 @retval EFI_DEVICE_ERROR Fail to do the recalibrate or seek operation\r
325 @retval EFI_NO_MEDIA No disk in the drive\r
326 @retval EFI_MEDIA_CHANGED There is a new disk in the drive\r
bcd70414 327**/\r
11f43dfd 328EFI_STATUS\r
329DisketChanged (\r
330 IN FDC_BLK_IO_DEV *FdcDev\r
331 )\r
11f43dfd 332{\r
333 EFI_STATUS Status;\r
d6321d6e 334 UINT8 Data;\r
11f43dfd 335\r
336 //\r
337 // Check change line\r
338 //\r
d6321d6e 339 Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
11f43dfd 340\r
341 //\r
342 // Io delay\r
343 //\r
344 MicroSecondDelay (50);\r
345\r
d6321d6e 346 if ((Data & DIR_DCL) == 0x80) {\r
11f43dfd 347 //\r
348 // disk change line is active\r
349 //\r
350 if (FdcDev->PresentCylinderNumber != 0) {\r
351 Status = Recalibrate (FdcDev);\r
352 } else {\r
353 Status = Seek (FdcDev, 0x30);\r
354 }\r
355\r
356 if (EFI_ERROR (Status)) {\r
357 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
358 return EFI_DEVICE_ERROR;\r
359 //\r
360 // Fail to do the seek or recalibrate operation\r
361 //\r
362 }\r
363\r
d6321d6e 364 Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
11f43dfd 365\r
366 //\r
367 // Io delay\r
368 //\r
369 MicroSecondDelay (50);\r
370\r
d6321d6e 371 if ((Data & DIR_DCL) == 0x80) {\r
11f43dfd 372 return EFI_NO_MEDIA;\r
373 }\r
374\r
375 return EFI_MEDIA_CHANGED;\r
376 }\r
377\r
378 return EFI_SUCCESS;\r
379}\r
380\r
bcd70414 381/**\r
382 Do the Specify command, this command sets DMA operation\r
383 and the initial values for each of the three internal\r
d6321d6e 384 times: HUT, SRT and HLT.\r
bcd70414 385 \r
d6321d6e 386 @param[in] FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
bcd70414 387 \r
d6321d6e 388 @retval EFI_SUCCESS Execute the Specify command successfully\r
389 @retval EFI_DEVICE_ERROR Fail to execute the command\r
bcd70414 390**/\r
11f43dfd 391EFI_STATUS\r
392Specify (\r
393 IN FDC_BLK_IO_DEV *FdcDev\r
394 )\r
11f43dfd 395{\r
396 FDD_SPECIFY_CMD Command;\r
397 UINTN Index;\r
398 UINT8 *CommandPointer;\r
399\r
400 ZeroMem (&Command, sizeof (FDD_SPECIFY_CMD));\r
401 Command.CommandCode = SPECIFY_CMD;\r
402 //\r
403 // set SRT, HUT\r
404 //\r
405 Command.SrtHut = 0xdf;\r
406 //\r
407 // 0xdf;\r
408 //\r
409 // set HLT and DMA\r
410 //\r
411 Command.HltNd = 0x02;\r
412\r
413 CommandPointer = (UINT8 *) (&Command);\r
414 for (Index = 0; Index < sizeof (FDD_SPECIFY_CMD); Index++) {\r
415 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
416 return EFI_DEVICE_ERROR;\r
417 }\r
418 }\r
419\r
420 return EFI_SUCCESS;\r
421}\r
422\r
bcd70414 423/**\r
d6321d6e 424 Set the head of floppy drive to track 0.\r
bcd70414 425 \r
d6321d6e 426 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 427 @retval EFI_SUCCESS: Execute the Recalibrate operation successfully\r
428 @retval EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation\r
429\r
430**/\r
11f43dfd 431EFI_STATUS\r
432Recalibrate (\r
433 IN FDC_BLK_IO_DEV *FdcDev\r
434 )\r
11f43dfd 435{\r
436 FDD_COMMAND_PACKET2 Command;\r
437 UINTN Index;\r
438 UINT8 StatusRegister0;\r
439 UINT8 PresentCylinderNumber;\r
440 UINT8 *CommandPointer;\r
441 UINT8 Count;\r
442\r
443 Count = 2;\r
444\r
445 while (Count > 0) {\r
446 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));\r
447 Command.CommandCode = RECALIBRATE_CMD;\r
448 //\r
449 // drive select\r
450 //\r
d6321d6e 451 if (FdcDev->Disk == FdcDisk0) {\r
11f43dfd 452 Command.DiskHeadSel = 0;\r
453 //\r
454 // 0\r
455 //\r
456 } else {\r
457 Command.DiskHeadSel = 1;\r
458 //\r
459 // 1\r
460 //\r
461 }\r
462\r
463 CommandPointer = (UINT8 *) (&Command);\r
464 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {\r
465 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
466 return EFI_DEVICE_ERROR;\r
467 }\r
468 }\r
469 //\r
470 // Experience value\r
471 //\r
472 MicroSecondDelay (250000);\r
473 //\r
474 // need modify according to 1.44M or 2.88M\r
475 //\r
476 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
477 return EFI_DEVICE_ERROR;\r
478 }\r
479\r
480 if ((StatusRegister0 & 0xf0) == 0x20 && PresentCylinderNumber == 0) {\r
481 FdcDev->PresentCylinderNumber = 0;\r
482 FdcDev->ControllerState->NeedRecalibrate = FALSE;\r
483 return EFI_SUCCESS;\r
484 } else {\r
485 Count--;\r
486 if (Count == 0) {\r
487 return EFI_DEVICE_ERROR;\r
488 }\r
489 }\r
490 }\r
491 //\r
492 // end while\r
493 //\r
494 return EFI_SUCCESS;\r
495}\r
496\r
bcd70414 497/**\r
d6321d6e 498 Set the head of floppy drive to the new cylinder.\r
bcd70414 499 \r
d6321d6e 500 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 501 @param Lba EFI_LBA : The logic block address want to seek\r
502 \r
503 @retval EFI_SUCCESS: Execute the Seek operation successfully\r
504 @retval EFI_DEVICE_ERROR: Fail to execute the Seek operation\r
505\r
506**/\r
11f43dfd 507EFI_STATUS\r
508Seek (\r
509 IN FDC_BLK_IO_DEV *FdcDev,\r
510 IN EFI_LBA Lba\r
511 )\r
11f43dfd 512{\r
513 FDD_SEEK_CMD Command;\r
514 UINT8 EndOfTrack;\r
515 UINT8 Head;\r
516 UINT8 Cylinder;\r
517 UINT8 StatusRegister0;\r
518 UINT8 *CommandPointer;\r
519 UINT8 PresentCylinderNumber;\r
520 UINTN Index;\r
521 UINT8 DelayTime;\r
522\r
523 if (FdcDev->ControllerState->NeedRecalibrate) {\r
524 if (EFI_ERROR (Recalibrate (FdcDev))) {\r
525 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
526 return EFI_DEVICE_ERROR;\r
527 }\r
528 }\r
529\r
530 EndOfTrack = DISK_1440K_EOT;\r
531 //\r
532 // Calculate cylinder based on Lba and EOT\r
533 //\r
534 Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);\r
535\r
536 //\r
537 // if the destination cylinder is the present cylinder, unnecessary to do the\r
538 // seek operation\r
539 //\r
540 if (FdcDev->PresentCylinderNumber == Cylinder) {\r
541 return EFI_SUCCESS;\r
542 }\r
543 //\r
544 // Calculate the head : 0 or 1\r
545 //\r
546 Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
547\r
548 ZeroMem (&Command, sizeof (FDD_SEEK_CMD));\r
549 Command.CommandCode = SEEK_CMD;\r
d6321d6e 550 if (FdcDev->Disk == FdcDisk0) {\r
11f43dfd 551 Command.DiskHeadSel = 0;\r
552 //\r
553 // 0\r
554 //\r
555 } else {\r
556 Command.DiskHeadSel = 1;\r
557 //\r
558 // 1\r
559 //\r
560 }\r
561\r
562 Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));\r
563 Command.NewCylinder = Cylinder;\r
564\r
565 CommandPointer = (UINT8 *) (&Command);\r
566 for (Index = 0; Index < sizeof (FDD_SEEK_CMD); Index++) {\r
567 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
568 return EFI_DEVICE_ERROR;\r
569 }\r
570 }\r
571 //\r
572 // Io delay\r
573 //\r
574 MicroSecondDelay (100);\r
575\r
576 //\r
577 // Calculate waiting time\r
578 //\r
579 if (FdcDev->PresentCylinderNumber > Cylinder) {\r
580 DelayTime = (UINT8) (FdcDev->PresentCylinderNumber - Cylinder);\r
581 } else {\r
582 DelayTime = (UINT8) (Cylinder - FdcDev->PresentCylinderNumber);\r
583 }\r
584\r
585 MicroSecondDelay ((DelayTime + 1) * 4000);\r
586\r
587 if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {\r
588 return EFI_DEVICE_ERROR;\r
589 }\r
590\r
591 if ((StatusRegister0 & 0xf0) == 0x20) {\r
592 FdcDev->PresentCylinderNumber = Command.NewCylinder;\r
593 return EFI_SUCCESS;\r
594 } else {\r
595 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
596 return EFI_DEVICE_ERROR;\r
597 }\r
598}\r
599\r
bcd70414 600/**\r
601 Do the Sense Interrupt Status command, this command\r
d6321d6e 602 resets the interrupt signal.\r
bcd70414 603 \r
d6321d6e 604 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 605 @param StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC\r
606 @param PresentCylinderNumber UINT8 *: Be used to save present cylinder number\r
607 read from FDC\r
608 \r
609 @retval EFI_SUCCESS: Execute the Sense Interrupt Status command successfully\r
610 @retval EFI_DEVICE_ERROR: Fail to execute the command\r
611\r
612**/\r
11f43dfd 613EFI_STATUS\r
614SenseIntStatus (\r
615 IN FDC_BLK_IO_DEV *FdcDev,\r
616 IN OUT UINT8 *StatusRegister0,\r
617 IN OUT UINT8 *PresentCylinderNumber\r
618 )\r
11f43dfd 619{\r
d6321d6e 620 UINT8 Command;\r
11f43dfd 621\r
d6321d6e 622 Command = SENSE_INT_STATUS_CMD;\r
623 if (EFI_ERROR (DataOutByte (FdcDev, &Command))) {\r
11f43dfd 624 return EFI_DEVICE_ERROR;\r
625 }\r
626\r
627 if (EFI_ERROR (DataInByte (FdcDev, StatusRegister0))) {\r
628 return EFI_DEVICE_ERROR;\r
629 }\r
630\r
631 if (EFI_ERROR (DataInByte (FdcDev, PresentCylinderNumber))) {\r
632 return EFI_DEVICE_ERROR;\r
633 }\r
634\r
635 return EFI_SUCCESS;\r
636}\r
637\r
bcd70414 638/**\r
d6321d6e 639 Do the Sense Drive Status command.\r
bcd70414 640 \r
d6321d6e 641 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 642 @param Lba EFI_LBA : Logic block address\r
643 \r
644 @retval EFI_SUCCESS: Execute the Sense Drive Status command successfully\r
645 @retval EFI_DEVICE_ERROR: Fail to execute the command\r
646 @retval EFI_WRITE_PROTECTED:The disk is write protected\r
647\r
648**/\r
11f43dfd 649EFI_STATUS\r
650SenseDrvStatus (\r
651 IN FDC_BLK_IO_DEV *FdcDev,\r
652 IN EFI_LBA Lba\r
653 )\r
11f43dfd 654{\r
655 FDD_COMMAND_PACKET2 Command;\r
656 UINT8 Head;\r
657 UINT8 EndOfTrack;\r
658 UINTN Index;\r
659 UINT8 StatusRegister3;\r
660 UINT8 *CommandPointer;\r
661\r
662 //\r
663 // Sense Drive Status command obtains drive status information,\r
664 // it has not execution phase and goes directly to the result phase from the\r
665 // command phase, Status Register 3 contains the drive status information\r
666 //\r
667 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));\r
668 Command.CommandCode = SENSE_DRV_STATUS_CMD;\r
669\r
d6321d6e 670 if (FdcDev->Disk == FdcDisk0) {\r
11f43dfd 671 Command.DiskHeadSel = 0;\r
672 } else {\r
673 Command.DiskHeadSel = 1;\r
674 }\r
675\r
676 EndOfTrack = DISK_1440K_EOT;\r
677 Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
678 Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));\r
679\r
680 CommandPointer = (UINT8 *) (&Command);\r
681 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {\r
682 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
683 return EFI_DEVICE_ERROR;\r
684 }\r
685 }\r
686\r
687 if (EFI_ERROR (DataInByte (FdcDev, &StatusRegister3))) {\r
688 return EFI_DEVICE_ERROR;\r
689 }\r
690 //\r
691 // Io delay\r
692 //\r
693 MicroSecondDelay (50);\r
694\r
695 //\r
696 // Check Status Register 3 to get drive status information\r
697 //\r
698 return CheckStatus3 (StatusRegister3);\r
699}\r
700\r
bcd70414 701/**\r
d6321d6e 702 Update the disk media properties and if necessary reinstall Block I/O interface.\r
bcd70414 703 \r
d6321d6e 704 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 705 \r
706 @retval EFI_SUCCESS: Do the operation successfully\r
707 @retval EFI_DEVICE_ERROR: Fail to the operation\r
708\r
709**/\r
11f43dfd 710EFI_STATUS\r
711DetectMedia (\r
712 IN FDC_BLK_IO_DEV *FdcDev\r
713 )\r
11f43dfd 714{\r
715 EFI_STATUS Status;\r
d6321d6e 716 BOOLEAN Reset;\r
717 BOOLEAN ReadOnlyLastTime;\r
718 BOOLEAN MediaPresentLastTime;\r
11f43dfd 719\r
d6321d6e 720 Reset = FALSE;\r
721 ReadOnlyLastTime = FdcDev->BlkIo.Media->ReadOnly;\r
722 MediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent;\r
11f43dfd 723\r
724 //\r
725 // Check disk change\r
726 //\r
727 Status = DisketChanged (FdcDev);\r
ae5852b2 728\r
729 if (Status == EFI_MEDIA_CHANGED) {\r
11f43dfd 730 FdcDev->BlkIo.Media->MediaId++;\r
731 FdcDev->BlkIo.Media->MediaPresent = TRUE;\r
d6321d6e 732 Reset = TRUE;\r
ae5852b2 733 } else if (Status == EFI_NO_MEDIA) {\r
11f43dfd 734 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
ae5852b2 735 } else if (Status != EFI_SUCCESS) {\r
11f43dfd 736 MotorOff (FdcDev);\r
737 return Status;\r
738 //\r
739 // EFI_DEVICE_ERROR\r
740 //\r
741 }\r
742\r
743 if (FdcDev->BlkIo.Media->MediaPresent) {\r
744 //\r
745 // Check disk write protected\r
746 //\r
747 Status = SenseDrvStatus (FdcDev, 0);\r
748 if (Status == EFI_WRITE_PROTECTED) {\r
749 FdcDev->BlkIo.Media->ReadOnly = TRUE;\r
750 } else {\r
751 FdcDev->BlkIo.Media->ReadOnly = FALSE;\r
752 }\r
753 }\r
754\r
d6321d6e 755 if (FdcDev->BlkIo.Media->MediaPresent && (ReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) {\r
756 Reset = TRUE;\r
11f43dfd 757 }\r
758\r
d6321d6e 759 if (MediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) {\r
760 Reset = TRUE;\r
11f43dfd 761 }\r
762\r
d6321d6e 763 if (Reset) {\r
11f43dfd 764 Status = gBS->ReinstallProtocolInterface (\r
765 FdcDev->Handle,\r
766 &gEfiBlockIoProtocolGuid,\r
767 &FdcDev->BlkIo,\r
768 &FdcDev->BlkIo\r
769 );\r
770\r
771 if (EFI_ERROR (Status)) {\r
772 return Status;\r
773 }\r
774 }\r
775\r
776 return EFI_SUCCESS;\r
777}\r
778\r
bcd70414 779/**\r
d6321d6e 780 Set the data rate and so on.\r
bcd70414 781 \r
d6321d6e 782 @param FdcDev A pointer to FDC_BLK_IO_DEV\r
bcd70414 783\r
784 @retval EFI_SUCCESS success to set the data rate\r
785**/\r
11f43dfd 786EFI_STATUS\r
787Setup (\r
788 IN FDC_BLK_IO_DEV *FdcDev\r
789 )\r
11f43dfd 790{\r
791 EFI_STATUS Status;\r
792\r
793 //\r
794 // Set data rate 500kbs\r
795 //\r
796 FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);\r
797\r
798 //\r
799 // Io delay\r
800 //\r
801 MicroSecondDelay (50);\r
802\r
803 Status = Specify (FdcDev);\r
804\r
805 if (EFI_ERROR (Status)) {\r
806 return EFI_DEVICE_ERROR;\r
807 }\r
808\r
809 return EFI_SUCCESS;\r
810}\r
811\r
bcd70414 812/**\r
d6321d6e 813 Read or Write a number of blocks in the same cylinder.\r
bcd70414 814 \r
d6321d6e 815 @param FdcDev A pointer to FDC_BLK_IO_DEV\r
bcd70414 816 @param HostAddress device address \r
817 @param Lba The starting logic block address to read from on the device\r
818 @param NumberOfBlocks The number of block wanted to be read or write\r
819 @param Read Operation type: read or write\r
820 \r
821 @retval EFI_SUCCESS Success operate\r
822\r
823**/\r
11f43dfd 824EFI_STATUS\r
825ReadWriteDataSector (\r
826 IN FDC_BLK_IO_DEV *FdcDev,\r
827 IN VOID *HostAddress,\r
828 IN EFI_LBA Lba,\r
829 IN UINTN NumberOfBlocks,\r
830 IN BOOLEAN Read\r
831 )\r
11f43dfd 832{\r
833 EFI_STATUS Status;\r
834 FDD_COMMAND_PACKET1 Command;\r
835 FDD_RESULT_PACKET Result;\r
836 UINTN Index;\r
837 UINTN Times;\r
838 UINT8 *CommandPointer;\r
839\r
840 EFI_PHYSICAL_ADDRESS DeviceAddress;\r
841 EFI_ISA_IO_PROTOCOL *IsaIo;\r
842 UINTN NumberofBytes;\r
843 VOID *Mapping;\r
844 EFI_ISA_IO_PROTOCOL_OPERATION Operation;\r
845 EFI_STATUS Status1;\r
846 UINT8 Channel;\r
847 EFI_ISA_ACPI_RESOURCE *ResourceItem;\r
848 UINT32 Attribute;\r
849\r
850 Status = Seek (FdcDev, Lba);\r
851 if (EFI_ERROR (Status)) {\r
852 return EFI_DEVICE_ERROR;\r
853 }\r
854 //\r
855 // Map Dma\r
856 //\r
857 IsaIo = FdcDev->IsaIo;\r
858 NumberofBytes = NumberOfBlocks * 512;\r
859 if (Read == READ) {\r
860 Operation = EfiIsaIoOperationSlaveWrite;\r
861 } else {\r
862 Operation = EfiIsaIoOperationSlaveRead;\r
863 }\r
864\r
865 ResourceItem = IsaIo->ResourceList->ResourceItem;\r
866 Index = 0;\r
867 while (ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList) {\r
868 if (ResourceItem[Index].Type == EfiIsaAcpiResourceDma) {\r
869 break;\r
870 }\r
871\r
872 Index++;\r
873 }\r
874\r
875 if (ResourceItem[Index].Type == EfiIsaAcpiResourceEndOfList) {\r
876 return EFI_DEVICE_ERROR;\r
877 }\r
878\r
879 Channel = (UINT8) IsaIo->ResourceList->ResourceItem[Index].StartRange;\r
880 Attribute = IsaIo->ResourceList->ResourceItem[Index].Attribute;\r
881\r
882 Status1 = IsaIo->Map (\r
883 IsaIo,\r
884 Operation,\r
885 Channel,\r
886 Attribute,\r
887 HostAddress,\r
888 &NumberofBytes,\r
889 &DeviceAddress,\r
890 &Mapping\r
891 );\r
892 if (EFI_ERROR (Status1)) {\r
893 return Status1;\r
894 }\r
895\r
896 //\r
897 // Allocate Read or Write command packet\r
898 //\r
899 ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET1));\r
900 if (Read == READ) {\r
901 Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK;\r
902 } else {\r
903 Command.CommandCode = WRITE_DATA_CMD | CMD_MT | CMD_MFM;\r
904 }\r
905\r
906 FillPara (FdcDev, Lba, &Command);\r
907\r
908 //\r
909 // Write command bytes to FDC\r
910 //\r
911 CommandPointer = (UINT8 *) (&Command);\r
912 for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET1); Index++) {\r
913 if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {\r
914 return EFI_DEVICE_ERROR;\r
915 }\r
916 }\r
917 //\r
918 // wait for some time\r
919 //\r
920 Times = (STALL_1_SECOND / 50) + 1;\r
921 do {\r
922 if ((FdcReadPort (FdcDev, FDC_REGISTER_MSR) & 0xc0) == 0xc0) {\r
923 break;\r
924 }\r
925\r
926 MicroSecondDelay (50);\r
927 Times = Times - 1;\r
d6321d6e 928 } while (Times >= 0);\r
11f43dfd 929\r
930 if (Times == 0) {\r
931 return EFI_TIMEOUT;\r
932 }\r
933 //\r
934 // Read result bytes from FDC\r
935 //\r
936 CommandPointer = (UINT8 *) (&Result);\r
937 for (Index = 0; Index < sizeof (FDD_RESULT_PACKET); Index++) {\r
938 if (EFI_ERROR (DataInByte (FdcDev, CommandPointer++))) {\r
939 return EFI_DEVICE_ERROR;\r
940 }\r
941 }\r
942 //\r
943 // Flush before Unmap\r
944 //\r
945 if (Read == READ) {\r
946 Status1 = IsaIo->Flush (IsaIo);\r
947 if (EFI_ERROR (Status1)) {\r
948 return Status1;\r
949 }\r
950 }\r
951 //\r
952 // Unmap Dma\r
953 //\r
954 Status1 = IsaIo->Unmap (IsaIo, Mapping);\r
955 if (EFI_ERROR (Status1)) {\r
956 return Status1;\r
957 }\r
958\r
959 return CheckResult (&Result, FdcDev);\r
960}\r
961\r
bcd70414 962/**\r
d6321d6e 963 Fill in FDD command's parameter.\r
bcd70414 964 \r
965 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
966 @param Lba The starting logic block address to read from on the device\r
967 @param Command FDD command\r
968\r
969**/\r
11f43dfd 970VOID\r
971FillPara (\r
972 IN FDC_BLK_IO_DEV *FdcDev,\r
973 IN EFI_LBA Lba,\r
974 IN FDD_COMMAND_PACKET1 *Command\r
975 )\r
11f43dfd 976{\r
977 UINT8 EndOfTrack;\r
978\r
979 //\r
980 // Get EndOfTrack from the Para table\r
981 //\r
982 EndOfTrack = DISK_1440K_EOT;\r
983\r
984 //\r
985 // Fill the command parameter\r
986 //\r
d6321d6e 987 if (FdcDev->Disk == FdcDisk0) {\r
11f43dfd 988 Command->DiskHeadSel = 0;\r
989 } else {\r
990 Command->DiskHeadSel = 1;\r
991 }\r
992\r
993 Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);\r
994 Command->Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);\r
995 Command->Sector = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);\r
996 Command->DiskHeadSel = (UINT8) (Command->DiskHeadSel | (Command->Head << 2));\r
997 Command->Number = DISK_1440K_NUMBER;\r
998 Command->EndOfTrack = DISK_1440K_EOT;\r
999 Command->GapLength = DISK_1440K_GPL;\r
1000 Command->DataLength = DISK_1440K_DTL;\r
1001}\r
1002\r
bcd70414 1003/**\r
d6321d6e 1004 Read result byte from Data Register of FDC.\r
bcd70414 1005 \r
d6321d6e 1006 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
1007 @param Pointer Buffer to store the byte read from FDC\r
bcd70414 1008 \r
d6321d6e 1009 @retval EFI_SUCCESS Read result byte from FDC successfully\r
1010 @retval EFI_DEVICE_ERROR The FDC is not ready to be read\r
bcd70414 1011\r
1012**/\r
11f43dfd 1013EFI_STATUS\r
1014DataInByte (\r
d6321d6e 1015 IN FDC_BLK_IO_DEV *FdcDev,\r
1016 OUT UINT8 *Pointer\r
11f43dfd 1017 )\r
11f43dfd 1018{\r
d6321d6e 1019 UINT8 Data;\r
11f43dfd 1020\r
1021 //\r
1022 // wait for 1ms and detect the FDC is ready to be read\r
1023 //\r
1024 if (EFI_ERROR (FddDRQReady (FdcDev, DATA_IN, 1))) {\r
1025 return EFI_DEVICE_ERROR;\r
1026 //\r
1027 // is not ready\r
1028 //\r
1029 }\r
1030\r
d6321d6e 1031 Data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);\r
11f43dfd 1032\r
1033 //\r
1034 // Io delay\r
1035 //\r
1036 MicroSecondDelay (50);\r
1037\r
d6321d6e 1038 *Pointer = Data;\r
11f43dfd 1039 return EFI_SUCCESS;\r
1040}\r
1041\r
bcd70414 1042/**\r
d6321d6e 1043 Write command byte to Data Register of FDC.\r
bcd70414 1044 \r
1045 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
1046 @param Pointer Be used to save command byte written to FDC\r
1047 \r
1048 @retval EFI_SUCCESS: Write command byte to FDC successfully\r
1049 @retval EFI_DEVICE_ERROR: The FDC is not ready to be written\r
1050\r
1051**/\r
11f43dfd 1052EFI_STATUS\r
1053DataOutByte (\r
1054 IN FDC_BLK_IO_DEV *FdcDev,\r
1055 IN UINT8 *Pointer\r
1056 )\r
11f43dfd 1057{\r
d6321d6e 1058 UINT8 Data;\r
11f43dfd 1059\r
1060 //\r
1061 // wait for 1ms and detect the FDC is ready to be written\r
1062 //\r
1063 if (EFI_ERROR (FddDRQReady (FdcDev, DATA_OUT, 1))) {\r
11f43dfd 1064 //\r
d6321d6e 1065 // Not ready\r
11f43dfd 1066 //\r
d6321d6e 1067 return EFI_DEVICE_ERROR;\r
11f43dfd 1068 }\r
1069\r
d6321d6e 1070 Data = *Pointer;\r
11f43dfd 1071\r
d6321d6e 1072 FdcWritePort (FdcDev, FDC_REGISTER_DTR, Data);\r
11f43dfd 1073\r
1074 //\r
1075 // Io delay\r
1076 //\r
1077 MicroSecondDelay (50);\r
1078\r
1079 return EFI_SUCCESS;\r
1080}\r
1081\r
bcd70414 1082/**\r
d6321d6e 1083 Detect the specified floppy logic drive is busy or not within a period of time.\r
bcd70414 1084 \r
fdb05fa3 1085 @param FdcDev Indicate it is drive A or drive B\r
bcd70414 1086 @param TimeoutInSeconds the time period for waiting\r
1087 \r
1088 @retval EFI_SUCCESS: The drive and command are not busy\r
1089 @retval EFI_TIMEOUT: The drive or command is still busy after a period time that\r
1090 set by TimeoutInSeconds\r
1091\r
1092**/\r
11f43dfd 1093EFI_STATUS\r
1094FddWaitForBSYClear (\r
1095 IN FDC_BLK_IO_DEV *FdcDev,\r
1096 IN UINTN TimeoutInSeconds\r
1097 )\r
11f43dfd 1098{\r
1099 UINTN Delay;\r
1100 UINT8 StatusRegister;\r
1101 UINT8 Mask;\r
1102\r
1103 //\r
1104 // How to determine drive and command are busy or not: by the bits of\r
1105 // Main Status Register\r
1106 // bit0: Drive 0 busy (drive A)\r
1107 // bit1: Drive 1 busy (drive B)\r
1108 // bit4: Command busy\r
1109 //\r
1110 //\r
1111 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4\r
1112 //\r
d6321d6e 1113 Mask = (UINT8) ((FdcDev->Disk == FdcDisk0 ? MSR_DAB : MSR_DBB) | MSR_CB);\r
11f43dfd 1114\r
1115 Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;\r
1116 do {\r
1117 StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);\r
1118 if ((StatusRegister & Mask) == 0x00) {\r
1119 break;\r
1120 //\r
1121 // not busy\r
1122 //\r
1123 }\r
1124\r
1125 MicroSecondDelay (50);\r
1126 Delay = Delay - 1;\r
d6321d6e 1127 } while (Delay >= 0);\r
11f43dfd 1128\r
1129 if (Delay == 0) {\r
1130 return EFI_TIMEOUT;\r
1131 }\r
1132\r
1133 return EFI_SUCCESS;\r
1134}\r
1135\r
bcd70414 1136/**\r
1137\r
d6321d6e 1138 Routine Description: Determine whether FDC is ready to write or read.\r
bcd70414 1139 \r
1140 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
1141 @param Dio BOOLEAN: Indicate the FDC is waiting to write or read\r
1142 @param TimeoutInSeconds UINTN: The time period for waiting\r
1143 \r
1144 @retval EFI_SUCCESS: FDC is ready to write or read\r
1145 @retval EFI_NOT_READY: FDC is not ready within the specified time period\r
1146\r
1147**/\r
11f43dfd 1148EFI_STATUS\r
1149FddDRQReady (\r
1150 IN FDC_BLK_IO_DEV *FdcDev,\r
1151 IN BOOLEAN Dio,\r
1152 IN UINTN TimeoutInSeconds\r
1153 )\r
11f43dfd 1154{\r
1155 UINTN Delay;\r
1156 UINT8 StatusRegister;\r
1157 UINT8 DataInOut;\r
1158\r
1159 //\r
1160 // Before writing to FDC or reading from FDC, the Host must examine\r
1161 // the bit7(RQM) and bit6(DIO) of the Main Status Register.\r
1162 // That is to say:\r
1163 // command bytes can not be written to Data Register\r
1164 // unless RQM is 1 and DIO is 0\r
1165 // result bytes can not be read from Data Register\r
1166 // unless RQM is 1 and DIO is 1\r
1167 //\r
1168 DataInOut = (UINT8) (Dio << 6);\r
1169 //\r
1170 // in order to compare bit6\r
1171 //\r
1172 Delay = ((TimeoutInSeconds * STALL_1_MSECOND) / 50) + 1;\r
1173 do {\r
1174 StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);\r
1175 if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {\r
1176 break;\r
1177 //\r
1178 // FDC is ready\r
1179 //\r
1180 }\r
1181\r
1182 MicroSecondDelay (50);\r
1183 //\r
1184 // Stall for 50 us\r
1185 //\r
1186 Delay = Delay - 1;\r
61efb259 1187 } while (Delay > 0);\r
11f43dfd 1188\r
1189 if (Delay == 0) {\r
1190 return EFI_NOT_READY;\r
1191 //\r
1192 // FDC is not ready within the specified time period\r
1193 //\r
1194 }\r
1195\r
1196 return EFI_SUCCESS;\r
1197}\r
1198\r
bcd70414 1199/**\r
d6321d6e 1200 Set FDC control structure's attribute according to result. \r
bcd70414 1201\r
1202 @param Result Point to result structure\r
1203 @param FdcDev FDC control structure\r
1204\r
fdb05fa3 1205 @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1206 @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1207 @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
1208 @retval EFI_SUCCESS - GC_TODO: Add description for return value\r
bcd70414 1209\r
1210**/\r
11f43dfd 1211EFI_STATUS\r
1212CheckResult (\r
1213 IN FDD_RESULT_PACKET *Result,\r
1214 IN OUT FDC_BLK_IO_DEV *FdcDev\r
1215 )\r
11f43dfd 1216{\r
1217 //\r
1218 // Check Status Register0\r
1219 //\r
1220 if ((Result->Status0 & STS0_IC) != IC_NT) {\r
1221 if ((Result->Status0 & STS0_SE) == 0x20) {\r
1222 //\r
1223 // seek error\r
1224 //\r
1225 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1226 }\r
1227\r
1228 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1229 return EFI_DEVICE_ERROR;\r
1230 }\r
1231 //\r
1232 // Check Status Register1\r
1233 //\r
d6321d6e 1234 if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {\r
11f43dfd 1235 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1236 return EFI_DEVICE_ERROR;\r
1237 }\r
1238 //\r
1239 // Check Status Register2\r
1240 //\r
d6321d6e 1241 if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {\r
11f43dfd 1242 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1243 return EFI_DEVICE_ERROR;\r
1244 }\r
1245\r
1246 return EFI_SUCCESS;\r
1247}\r
1248\r
bcd70414 1249/**\r
d6321d6e 1250 Check the drive status information.\r
bcd70414 1251 \r
1252 @param StatusRegister3 the value of Status Register 3\r
1253 \r
1254 @retval EFI_SUCCESS The disk is not write protected\r
1255 @retval EFI_WRITE_PROTECTED: The disk is write protected\r
1256\r
1257**/\r
11f43dfd 1258EFI_STATUS\r
1259CheckStatus3 (\r
1260 IN UINT8 StatusRegister3\r
1261 )\r
11f43dfd 1262{\r
d6321d6e 1263 if ((StatusRegister3 & STS3_WP) != 0) {\r
11f43dfd 1264 return EFI_WRITE_PROTECTED;\r
1265 }\r
1266\r
1267 return EFI_SUCCESS;\r
1268}\r
1269\r
bcd70414 1270/**\r
d6321d6e 1271 Calculate the number of block in the same cylinder according to LBA.\r
bcd70414 1272 \r
d6321d6e 1273 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 1274 @param LBA EFI_LBA: The starting logic block address\r
1275 @param NumberOfBlocks UINTN: The number of blocks\r
1276 \r
1277 @return The number of blocks in the same cylinder which the starting\r
1278 logic block address is LBA\r
1279\r
1280**/\r
11f43dfd 1281UINTN\r
1282GetTransferBlockCount (\r
1283 IN FDC_BLK_IO_DEV *FdcDev,\r
1284 IN EFI_LBA LBA,\r
1285 IN UINTN NumberOfBlocks\r
1286 )\r
11f43dfd 1287{\r
1288 UINT8 EndOfTrack;\r
1289 UINT8 Head;\r
1290 UINT8 SectorsInTrack;\r
1291\r
1292 //\r
1293 // Calculate the number of block in the same cylinder\r
1294 //\r
1295 EndOfTrack = DISK_1440K_EOT;\r
1296 Head = (UINT8) ((UINTN) LBA / EndOfTrack % 2);\r
1297\r
1298 SectorsInTrack = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));\r
1299 if (SectorsInTrack < NumberOfBlocks) {\r
1300 return SectorsInTrack;\r
1301 } else {\r
1302 return NumberOfBlocks;\r
1303 }\r
1304}\r
1305\r
bcd70414 1306/**\r
d6321d6e 1307 When the Timer(2s) off, turn the drive's motor off.\r
bcd70414 1308 \r
1309 @param Event EFI_EVENT: Event(the timer) whose notification function is being\r
1310 invoked\r
1311 @param Context VOID *: Pointer to the notification function's context\r
1312\r
1313**/\r
11f43dfd 1314VOID\r
1315EFIAPI\r
1316FddTimerProc (\r
1317 IN EFI_EVENT Event,\r
1318 IN VOID *Context\r
1319 )\r
11f43dfd 1320{\r
1321 FDC_BLK_IO_DEV *FdcDev;\r
d6321d6e 1322 UINT8 Data;\r
11f43dfd 1323\r
1324 FdcDev = (FDC_BLK_IO_DEV *) Context;\r
1325\r
1326 //\r
1327 // Get the motor status\r
1328 //\r
d6321d6e 1329 Data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
11f43dfd 1330\r
d6321d6e 1331 if (((FdcDev->Disk == FdcDisk0) && ((Data & 0x10) != 0x10)) ||\r
1332 ((FdcDev->Disk == FdcDisk1) && ((Data & 0x21) != 0x21))\r
11f43dfd 1333 ) {\r
1334 return ;\r
1335 }\r
1336 //\r
1337 // the motor is on, so need motor off\r
1338 //\r
d6321d6e 1339 Data = 0x0C;\r
1340 Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));\r
1341 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
11f43dfd 1342 MicroSecondDelay (500);\r
1343}\r
1344\r
bcd70414 1345/**\r
d6321d6e 1346 Read an I/O port of FDC.\r
bcd70414 1347 \r
d6321d6e 1348 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV.\r
1349 @param[in] Offset The address offset of the I/O port.\r
bcd70414 1350\r
d6321d6e 1351 @retval 8-bit data read from the I/O port.\r
bcd70414 1352**/\r
11f43dfd 1353UINT8\r
1354FdcReadPort (\r
1355 IN FDC_BLK_IO_DEV *FdcDev,\r
1356 IN UINT32 Offset\r
1357 )\r
11f43dfd 1358{\r
d6321d6e 1359 EFI_STATUS Status;\r
11f43dfd 1360 UINT8 Data;\r
1361\r
d6321d6e 1362 Status = FdcDev->IsaIo->Io.Read (\r
1363 FdcDev->IsaIo,\r
1364 EfiIsaIoWidthUint8,\r
1365 FdcDev->BaseAddress + Offset,\r
1366 1,\r
1367 &Data\r
1368 );\r
1369 ASSERT_EFI_ERROR (Status);\r
11f43dfd 1370\r
1371 return Data;\r
1372}\r
1373\r
bcd70414 1374/**\r
d6321d6e 1375 Write an I/O port of FDC.\r
bcd70414 1376 \r
d6321d6e 1377 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV\r
1378 @param[in] Offset The address offset of the I/O port\r
1379 @param[in] Data 8-bit Value written to the I/O port\r
bcd70414 1380**/\r
11f43dfd 1381VOID\r
1382FdcWritePort (\r
1383 IN FDC_BLK_IO_DEV *FdcDev,\r
1384 IN UINT32 Offset,\r
1385 IN UINT8 Data\r
1386 )\r
11f43dfd 1387{\r
d6321d6e 1388 EFI_STATUS Status;\r
11f43dfd 1389\r
d6321d6e 1390 Status = FdcDev->IsaIo->Io.Write (\r
1391 FdcDev->IsaIo,\r
1392 EfiIsaIoWidthUint8,\r
1393 FdcDev->BaseAddress + Offset,\r
1394 1,\r
1395 &Data\r
1396 );\r
1397 ASSERT_EFI_ERROR (Status);\r
11f43dfd 1398}\r
bcd70414 1399\r