]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
IntelFrameworkModulePkg: Clean up source files
[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
0a6f4824
LG
3\r
4Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
180a5a35 5This program and the accompanying materials\r
f8cd287b 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
0a6f4824 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
0a6f4824 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
0a6f4824 126\r
d6321d6e 127 @param FdcDev FDC_BLK_IO_DEV * : A pointer to the FDC_BLK_IO_DEV\r
0a6f4824 128\r
bcd70414 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
0a6f4824 225\r
d6321d6e 226 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
0a6f4824 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
0a6f4824 301\r
d6321d6e 302 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
0a6f4824 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
0a6f4824 320\r
d6321d6e 321 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV\r
0a6f4824 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
0a6f4824 385\r
d6321d6e 386 @param[in] FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
0a6f4824 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
0a6f4824 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
0a6f4824 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
0a6f4824 502\r
bcd70414 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
0a6f4824 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
0a6f4824 608\r
bcd70414 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
0a6f4824 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
0a6f4824 643\r
bcd70414 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
0a6f4824 703\r
d6321d6e 704 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
0a6f4824 705\r
bcd70414 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
0a6f4824 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
0a6f4824 814\r
d6321d6e 815 @param FdcDev A pointer to FDC_BLK_IO_DEV\r
0a6f4824 816 @param HostAddress device address\r
bcd70414 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
0a6f4824 820\r
bcd70414 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
2101c62a 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
0a6f4824 964\r
bcd70414 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
0a6f4824 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
0a6f4824 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
0a6f4824 1044\r
bcd70414 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
0a6f4824 1047\r
bcd70414 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
0a6f4824 1084\r
fdb05fa3 1085 @param FdcDev Indicate it is drive A or drive B\r
e9bf5b1d 1086 @param Timeout The time period for waiting\r
0a6f4824 1087\r
bcd70414 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
e9bf5b1d 1090 set by Timeout\r
bcd70414 1091\r
1092**/\r
11f43dfd 1093EFI_STATUS\r
1094FddWaitForBSYClear (\r
1095 IN FDC_BLK_IO_DEV *FdcDev,\r
e9bf5b1d 1096 IN UINTN Timeout\r
11f43dfd 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
e9bf5b1d 1115 Delay = ((Timeout * STALL_1_MSECOND) / 50) + 1;\r
11f43dfd 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
2101c62a 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
e9bf5b1d 1137 Determine whether FDC is ready to write or read.\r
0a6f4824 1138\r
bcd70414 1139 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
1140 @param Dio BOOLEAN: Indicate the FDC is waiting to write or read\r
e9bf5b1d 1141 @param Timeout The time period for waiting\r
0a6f4824 1142\r
bcd70414 1143 @retval EFI_SUCCESS: FDC is ready to write or read\r
1144 @retval EFI_NOT_READY: FDC is not ready within the specified time period\r
1145\r
1146**/\r
11f43dfd 1147EFI_STATUS\r
1148FddDRQReady (\r
1149 IN FDC_BLK_IO_DEV *FdcDev,\r
1150 IN BOOLEAN Dio,\r
e9bf5b1d 1151 IN UINTN Timeout\r
11f43dfd 1152 )\r
11f43dfd 1153{\r
1154 UINTN Delay;\r
1155 UINT8 StatusRegister;\r
1156 UINT8 DataInOut;\r
1157\r
1158 //\r
1159 // Before writing to FDC or reading from FDC, the Host must examine\r
1160 // the bit7(RQM) and bit6(DIO) of the Main Status Register.\r
1161 // That is to say:\r
1162 // command bytes can not be written to Data Register\r
1163 // unless RQM is 1 and DIO is 0\r
1164 // result bytes can not be read from Data Register\r
1165 // unless RQM is 1 and DIO is 1\r
1166 //\r
1167 DataInOut = (UINT8) (Dio << 6);\r
1168 //\r
1169 // in order to compare bit6\r
1170 //\r
e9bf5b1d 1171 Delay = ((Timeout * STALL_1_MSECOND) / 50) + 1;\r
11f43dfd 1172 do {\r
1173 StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);\r
1174 if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {\r
1175 break;\r
1176 //\r
1177 // FDC is ready\r
1178 //\r
1179 }\r
1180\r
1181 MicroSecondDelay (50);\r
1182 //\r
1183 // Stall for 50 us\r
1184 //\r
1185 Delay = Delay - 1;\r
61efb259 1186 } while (Delay > 0);\r
11f43dfd 1187\r
1188 if (Delay == 0) {\r
1189 return EFI_NOT_READY;\r
1190 //\r
1191 // FDC is not ready within the specified time period\r
1192 //\r
1193 }\r
1194\r
1195 return EFI_SUCCESS;\r
1196}\r
1197\r
bcd70414 1198/**\r
0a6f4824 1199 Set FDC control structure's attribute according to result.\r
bcd70414 1200\r
1201 @param Result Point to result structure\r
1202 @param FdcDev FDC control structure\r
1203\r
fdb05fa3 1204 @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value\r
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_SUCCESS - GC_TODO: Add description for return value\r
bcd70414 1208\r
1209**/\r
11f43dfd 1210EFI_STATUS\r
1211CheckResult (\r
1212 IN FDD_RESULT_PACKET *Result,\r
1213 IN OUT FDC_BLK_IO_DEV *FdcDev\r
1214 )\r
11f43dfd 1215{\r
1216 //\r
1217 // Check Status Register0\r
1218 //\r
1219 if ((Result->Status0 & STS0_IC) != IC_NT) {\r
1220 if ((Result->Status0 & STS0_SE) == 0x20) {\r
1221 //\r
1222 // seek error\r
1223 //\r
1224 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1225 }\r
1226\r
1227 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1228 return EFI_DEVICE_ERROR;\r
1229 }\r
1230 //\r
1231 // Check Status Register1\r
1232 //\r
d6321d6e 1233 if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {\r
11f43dfd 1234 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1235 return EFI_DEVICE_ERROR;\r
1236 }\r
1237 //\r
1238 // Check Status Register2\r
1239 //\r
d6321d6e 1240 if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {\r
11f43dfd 1241 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1242 return EFI_DEVICE_ERROR;\r
1243 }\r
1244\r
1245 return EFI_SUCCESS;\r
1246}\r
1247\r
bcd70414 1248/**\r
d6321d6e 1249 Check the drive status information.\r
0a6f4824 1250\r
bcd70414 1251 @param StatusRegister3 the value of Status Register 3\r
0a6f4824 1252\r
bcd70414 1253 @retval EFI_SUCCESS The disk is not write protected\r
1254 @retval EFI_WRITE_PROTECTED: The disk is write protected\r
1255\r
1256**/\r
11f43dfd 1257EFI_STATUS\r
1258CheckStatus3 (\r
1259 IN UINT8 StatusRegister3\r
1260 )\r
11f43dfd 1261{\r
d6321d6e 1262 if ((StatusRegister3 & STS3_WP) != 0) {\r
11f43dfd 1263 return EFI_WRITE_PROTECTED;\r
1264 }\r
1265\r
1266 return EFI_SUCCESS;\r
1267}\r
1268\r
bcd70414 1269/**\r
d6321d6e 1270 Calculate the number of block in the same cylinder according to LBA.\r
0a6f4824 1271\r
d6321d6e 1272 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
bcd70414 1273 @param LBA EFI_LBA: The starting logic block address\r
1274 @param NumberOfBlocks UINTN: The number of blocks\r
0a6f4824 1275\r
bcd70414 1276 @return The number of blocks in the same cylinder which the starting\r
1277 logic block address is LBA\r
1278\r
1279**/\r
11f43dfd 1280UINTN\r
1281GetTransferBlockCount (\r
1282 IN FDC_BLK_IO_DEV *FdcDev,\r
1283 IN EFI_LBA LBA,\r
1284 IN UINTN NumberOfBlocks\r
1285 )\r
11f43dfd 1286{\r
1287 UINT8 EndOfTrack;\r
1288 UINT8 Head;\r
1289 UINT8 SectorsInTrack;\r
1290\r
1291 //\r
1292 // Calculate the number of block in the same cylinder\r
1293 //\r
1294 EndOfTrack = DISK_1440K_EOT;\r
1295 Head = (UINT8) ((UINTN) LBA / EndOfTrack % 2);\r
1296\r
1297 SectorsInTrack = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));\r
1298 if (SectorsInTrack < NumberOfBlocks) {\r
1299 return SectorsInTrack;\r
1300 } else {\r
1301 return NumberOfBlocks;\r
1302 }\r
1303}\r
1304\r
bcd70414 1305/**\r
d6321d6e 1306 When the Timer(2s) off, turn the drive's motor off.\r
0a6f4824 1307\r
bcd70414 1308 @param Event EFI_EVENT: Event(the timer) whose notification function is being\r
1309 invoked\r
1310 @param Context VOID *: Pointer to the notification function's context\r
1311\r
1312**/\r
11f43dfd 1313VOID\r
1314EFIAPI\r
1315FddTimerProc (\r
1316 IN EFI_EVENT Event,\r
1317 IN VOID *Context\r
1318 )\r
11f43dfd 1319{\r
1320 FDC_BLK_IO_DEV *FdcDev;\r
d6321d6e 1321 UINT8 Data;\r
11f43dfd 1322\r
1323 FdcDev = (FDC_BLK_IO_DEV *) Context;\r
1324\r
1325 //\r
1326 // Get the motor status\r
1327 //\r
d6321d6e 1328 Data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
11f43dfd 1329\r
d6321d6e 1330 if (((FdcDev->Disk == FdcDisk0) && ((Data & 0x10) != 0x10)) ||\r
1331 ((FdcDev->Disk == FdcDisk1) && ((Data & 0x21) != 0x21))\r
11f43dfd 1332 ) {\r
1333 return ;\r
1334 }\r
1335 //\r
1336 // the motor is on, so need motor off\r
1337 //\r
d6321d6e 1338 Data = 0x0C;\r
1339 Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));\r
1340 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
11f43dfd 1341 MicroSecondDelay (500);\r
1342}\r
1343\r
bcd70414 1344/**\r
d6321d6e 1345 Read an I/O port of FDC.\r
0a6f4824 1346\r
d6321d6e 1347 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV.\r
1348 @param[in] Offset The address offset of the I/O port.\r
bcd70414 1349\r
d6321d6e 1350 @retval 8-bit data read from the I/O port.\r
bcd70414 1351**/\r
11f43dfd 1352UINT8\r
1353FdcReadPort (\r
1354 IN FDC_BLK_IO_DEV *FdcDev,\r
1355 IN UINT32 Offset\r
1356 )\r
11f43dfd 1357{\r
d6321d6e 1358 EFI_STATUS Status;\r
11f43dfd 1359 UINT8 Data;\r
1360\r
d6321d6e 1361 Status = FdcDev->IsaIo->Io.Read (\r
1362 FdcDev->IsaIo,\r
1363 EfiIsaIoWidthUint8,\r
1364 FdcDev->BaseAddress + Offset,\r
1365 1,\r
1366 &Data\r
1367 );\r
1368 ASSERT_EFI_ERROR (Status);\r
11f43dfd 1369\r
1370 return Data;\r
1371}\r
1372\r
bcd70414 1373/**\r
d6321d6e 1374 Write an I/O port of FDC.\r
0a6f4824 1375\r
d6321d6e 1376 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV\r
1377 @param[in] Offset The address offset of the I/O port\r
1378 @param[in] Data 8-bit Value written to the I/O port\r
bcd70414 1379**/\r
11f43dfd 1380VOID\r
1381FdcWritePort (\r
1382 IN FDC_BLK_IO_DEV *FdcDev,\r
1383 IN UINT32 Offset,\r
1384 IN UINT8 Data\r
1385 )\r
11f43dfd 1386{\r
d6321d6e 1387 EFI_STATUS Status;\r
11f43dfd 1388\r
d6321d6e 1389 Status = FdcDev->IsaIo->Io.Write (\r
1390 FdcDev->IsaIo,\r
1391 EfiIsaIoWidthUint8,\r
1392 FdcDev->BaseAddress + Offset,\r
1393 1,\r
1394 &Data\r
1395 );\r
1396 ASSERT_EFI_ERROR (Status);\r
11f43dfd 1397}\r
bcd70414 1398\r