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