]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
IntelFrameworkModulePkg: Clean up source files
[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
5This 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
9\r
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
12\r
13**/\r
14\r
15#include "IsaFloppy.h"\r
16\r
17/**\r
18 Detect whether a floppy drive is present or not.\r
19\r
20 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
21\r
22 @retval EFI_SUCCESS The floppy disk drive is present\r
23 @retval EFI_NOT_FOUND The floppy disk drive is not present\r
24**/\r
25EFI_STATUS\r
26DiscoverFddDevice (\r
27 IN FDC_BLK_IO_DEV *FdcDev\r
28 )\r
29{\r
30 EFI_STATUS Status;\r
31\r
32 FdcDev->BlkIo.Media = &FdcDev->BlkMedia;\r
33\r
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
49/**\r
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
52\r
53 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
54\r
55 @retval EFI_SUCCESS The floppy disk drive is present\r
56 @retval EFI_DEVICE_ERROR The floppy disk drive is not present\r
57**/\r
58EFI_STATUS\r
59FddIdentify (\r
60 IN FDC_BLK_IO_DEV *FdcDev\r
61 )\r
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
85 FdcDev->BlkIo.Media->MediaId = 0;\r
86\r
87 //\r
88 // Check Media\r
89 //\r
90 Status = DisketChanged (FdcDev);\r
91\r
92 if (Status == EFI_NO_MEDIA) {\r
93 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
94 } else if ((Status != EFI_MEDIA_CHANGED) &&\r
95 (Status != EFI_SUCCESS)) {\r
96 MotorOff (FdcDev);\r
97 return Status;\r
98 }\r
99\r
100 //\r
101 // Check Disk Write Protected\r
102 //\r
103 Status = SenseDrvStatus (FdcDev, 0);\r
104\r
105 if (Status == EFI_WRITE_PROTECTED) {\r
106 FdcDev->BlkIo.Media->ReadOnly = TRUE;\r
107 } else if (Status == EFI_SUCCESS) {\r
108 FdcDev->BlkIo.Media->ReadOnly = FALSE;\r
109 } else {\r
110 return EFI_DEVICE_ERROR;\r
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
124/**\r
125 Reset the Floppy Logic Drive.\r
126\r
127 @param FdcDev FDC_BLK_IO_DEV * : A pointer to the FDC_BLK_IO_DEV\r
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
134EFI_STATUS\r
135FddReset (\r
136 IN FDC_BLK_IO_DEV *FdcDev\r
137 )\r
138{\r
139 UINT8 Data;\r
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
166 Data = 0x0;\r
167 Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));\r
168 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
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
180 Data |= 0x0C;\r
181 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
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
222/**\r
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
225\r
226 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
227\r
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
230**/\r
231EFI_STATUS\r
232MotorOn (\r
233 IN FDC_BLK_IO_DEV *FdcDev\r
234 )\r
235{\r
236 EFI_STATUS Status;\r
237 UINT8 DorData;\r
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
253 ASSERT_EFI_ERROR (Status);\r
254\r
255 //\r
256 // Get the motor status\r
257 //\r
258 DorData = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
259\r
260 if (((FdcDev->Disk == FdcDisk0) && ((DorData & 0x10) == 0x10)) ||\r
261 ((FdcDev->Disk == FdcDisk1) && ((DorData & 0x21) == 0x21))\r
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
275 DorData = 0x0C;\r
276 DorData = (UINT8) (DorData | (SELECT_DRV & FdcDev->Disk));\r
277 if (FdcDev->Disk == FdcDisk0) {\r
278 //\r
279 // drive A\r
280 //\r
281 DorData |= DRVA_MOTOR_ON;\r
282 } else {\r
283 //\r
284 // drive B\r
285 //\r
286 DorData |= DRVB_MOTOR_ON;\r
287 }\r
288\r
289 FdcWritePort (FdcDev, FDC_REGISTER_DOR, DorData);\r
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
299/**\r
300 Set a Timer and when Timer goes off, turn the motor off.\r
301\r
302 @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV\r
303\r
304 @retval EFI_SUCCESS Set the Timer successfully\r
305 @retval EFI_INVALID_PARAMETER Fail to Set the timer\r
306**/\r
307EFI_STATUS\r
308MotorOff (\r
309 IN FDC_BLK_IO_DEV *FdcDev\r
310 )\r
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
318/**\r
319 Detect whether the disk in the drive is changed or not.\r
320\r
321 @param[in] FdcDev A pointer to FDC_BLK_IO_DEV\r
322\r
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
327**/\r
328EFI_STATUS\r
329DisketChanged (\r
330 IN FDC_BLK_IO_DEV *FdcDev\r
331 )\r
332{\r
333 EFI_STATUS Status;\r
334 UINT8 Data;\r
335\r
336 //\r
337 // Check change line\r
338 //\r
339 Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
340\r
341 //\r
342 // Io delay\r
343 //\r
344 MicroSecondDelay (50);\r
345\r
346 if ((Data & DIR_DCL) == 0x80) {\r
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
364 Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);\r
365\r
366 //\r
367 // Io delay\r
368 //\r
369 MicroSecondDelay (50);\r
370\r
371 if ((Data & DIR_DCL) == 0x80) {\r
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
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
384 times: HUT, SRT and HLT.\r
385\r
386 @param[in] FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
387\r
388 @retval EFI_SUCCESS Execute the Specify command successfully\r
389 @retval EFI_DEVICE_ERROR Fail to execute the command\r
390**/\r
391EFI_STATUS\r
392Specify (\r
393 IN FDC_BLK_IO_DEV *FdcDev\r
394 )\r
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
423/**\r
424 Set the head of floppy drive to track 0.\r
425\r
426 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
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
431EFI_STATUS\r
432Recalibrate (\r
433 IN FDC_BLK_IO_DEV *FdcDev\r
434 )\r
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
451 if (FdcDev->Disk == FdcDisk0) {\r
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
497/**\r
498 Set the head of floppy drive to the new cylinder.\r
499\r
500 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
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
507EFI_STATUS\r
508Seek (\r
509 IN FDC_BLK_IO_DEV *FdcDev,\r
510 IN EFI_LBA Lba\r
511 )\r
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
550 if (FdcDev->Disk == FdcDisk0) {\r
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
600/**\r
601 Do the Sense Interrupt Status command, this command\r
602 resets the interrupt signal.\r
603\r
604 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
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
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
619{\r
620 UINT8 Command;\r
621\r
622 Command = SENSE_INT_STATUS_CMD;\r
623 if (EFI_ERROR (DataOutByte (FdcDev, &Command))) {\r
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
638/**\r
639 Do the Sense Drive Status command.\r
640\r
641 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
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
649EFI_STATUS\r
650SenseDrvStatus (\r
651 IN FDC_BLK_IO_DEV *FdcDev,\r
652 IN EFI_LBA Lba\r
653 )\r
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
670 if (FdcDev->Disk == FdcDisk0) {\r
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
701/**\r
702 Update the disk media properties and if necessary reinstall Block I/O interface.\r
703\r
704 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
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
710EFI_STATUS\r
711DetectMedia (\r
712 IN FDC_BLK_IO_DEV *FdcDev\r
713 )\r
714{\r
715 EFI_STATUS Status;\r
716 BOOLEAN Reset;\r
717 BOOLEAN ReadOnlyLastTime;\r
718 BOOLEAN MediaPresentLastTime;\r
719\r
720 Reset = FALSE;\r
721 ReadOnlyLastTime = FdcDev->BlkIo.Media->ReadOnly;\r
722 MediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent;\r
723\r
724 //\r
725 // Check disk change\r
726 //\r
727 Status = DisketChanged (FdcDev);\r
728\r
729 if (Status == EFI_MEDIA_CHANGED) {\r
730 FdcDev->BlkIo.Media->MediaId++;\r
731 FdcDev->BlkIo.Media->MediaPresent = TRUE;\r
732 Reset = TRUE;\r
733 } else if (Status == EFI_NO_MEDIA) {\r
734 FdcDev->BlkIo.Media->MediaPresent = FALSE;\r
735 } else if (Status != EFI_SUCCESS) {\r
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
755 if (FdcDev->BlkIo.Media->MediaPresent && (ReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) {\r
756 Reset = TRUE;\r
757 }\r
758\r
759 if (MediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) {\r
760 Reset = TRUE;\r
761 }\r
762\r
763 if (Reset) {\r
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
779/**\r
780 Set the data rate and so on.\r
781\r
782 @param FdcDev A pointer to FDC_BLK_IO_DEV\r
783\r
784 @retval EFI_SUCCESS success to set the data rate\r
785**/\r
786EFI_STATUS\r
787Setup (\r
788 IN FDC_BLK_IO_DEV *FdcDev\r
789 )\r
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
812/**\r
813 Read or Write a number of blocks in the same cylinder.\r
814\r
815 @param FdcDev A pointer to FDC_BLK_IO_DEV\r
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
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
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
928 } while (Times > 0);\r
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
962/**\r
963 Fill in FDD command's parameter.\r
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
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
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
987 if (FdcDev->Disk == FdcDisk0) {\r
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
1003/**\r
1004 Read result byte from Data Register of FDC.\r
1005\r
1006 @param FdcDev Pointer to instance of FDC_BLK_IO_DEV\r
1007 @param Pointer Buffer to store the byte read from FDC\r
1008\r
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
1011\r
1012**/\r
1013EFI_STATUS\r
1014DataInByte (\r
1015 IN FDC_BLK_IO_DEV *FdcDev,\r
1016 OUT UINT8 *Pointer\r
1017 )\r
1018{\r
1019 UINT8 Data;\r
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
1031 Data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);\r
1032\r
1033 //\r
1034 // Io delay\r
1035 //\r
1036 MicroSecondDelay (50);\r
1037\r
1038 *Pointer = Data;\r
1039 return EFI_SUCCESS;\r
1040}\r
1041\r
1042/**\r
1043 Write command byte to Data Register of FDC.\r
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
1052EFI_STATUS\r
1053DataOutByte (\r
1054 IN FDC_BLK_IO_DEV *FdcDev,\r
1055 IN UINT8 *Pointer\r
1056 )\r
1057{\r
1058 UINT8 Data;\r
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
1064 //\r
1065 // Not ready\r
1066 //\r
1067 return EFI_DEVICE_ERROR;\r
1068 }\r
1069\r
1070 Data = *Pointer;\r
1071\r
1072 FdcWritePort (FdcDev, FDC_REGISTER_DTR, Data);\r
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
1082/**\r
1083 Detect the specified floppy logic drive is busy or not within a period of time.\r
1084\r
1085 @param FdcDev Indicate it is drive A or drive B\r
1086 @param Timeout 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 Timeout\r
1091\r
1092**/\r
1093EFI_STATUS\r
1094FddWaitForBSYClear (\r
1095 IN FDC_BLK_IO_DEV *FdcDev,\r
1096 IN UINTN Timeout\r
1097 )\r
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
1113 Mask = (UINT8) ((FdcDev->Disk == FdcDisk0 ? MSR_DAB : MSR_DBB) | MSR_CB);\r
1114\r
1115 Delay = ((Timeout * 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
1127 } while (Delay > 0);\r
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
1136/**\r
1137 Determine whether FDC is ready to write or read.\r
1138\r
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
1141 @param Timeout The time period for waiting\r
1142\r
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
1147EFI_STATUS\r
1148FddDRQReady (\r
1149 IN FDC_BLK_IO_DEV *FdcDev,\r
1150 IN BOOLEAN Dio,\r
1151 IN UINTN Timeout\r
1152 )\r
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
1171 Delay = ((Timeout * STALL_1_MSECOND) / 50) + 1;\r
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
1186 } while (Delay > 0);\r
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
1198/**\r
1199 Set FDC control structure's attribute according to result.\r
1200\r
1201 @param Result Point to result structure\r
1202 @param FdcDev FDC control structure\r
1203\r
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
1208\r
1209**/\r
1210EFI_STATUS\r
1211CheckResult (\r
1212 IN FDD_RESULT_PACKET *Result,\r
1213 IN OUT FDC_BLK_IO_DEV *FdcDev\r
1214 )\r
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
1233 if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {\r
1234 FdcDev->ControllerState->NeedRecalibrate = TRUE;\r
1235 return EFI_DEVICE_ERROR;\r
1236 }\r
1237 //\r
1238 // Check Status Register2\r
1239 //\r
1240 if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {\r
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
1248/**\r
1249 Check the drive status information.\r
1250\r
1251 @param StatusRegister3 the value of Status Register 3\r
1252\r
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
1257EFI_STATUS\r
1258CheckStatus3 (\r
1259 IN UINT8 StatusRegister3\r
1260 )\r
1261{\r
1262 if ((StatusRegister3 & STS3_WP) != 0) {\r
1263 return EFI_WRITE_PROTECTED;\r
1264 }\r
1265\r
1266 return EFI_SUCCESS;\r
1267}\r
1268\r
1269/**\r
1270 Calculate the number of block in the same cylinder according to LBA.\r
1271\r
1272 @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV\r
1273 @param LBA EFI_LBA: The starting logic block address\r
1274 @param NumberOfBlocks UINTN: The number of blocks\r
1275\r
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
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
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
1305/**\r
1306 When the Timer(2s) off, turn the drive's motor off.\r
1307\r
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
1313VOID\r
1314EFIAPI\r
1315FddTimerProc (\r
1316 IN EFI_EVENT Event,\r
1317 IN VOID *Context\r
1318 )\r
1319{\r
1320 FDC_BLK_IO_DEV *FdcDev;\r
1321 UINT8 Data;\r
1322\r
1323 FdcDev = (FDC_BLK_IO_DEV *) Context;\r
1324\r
1325 //\r
1326 // Get the motor status\r
1327 //\r
1328 Data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);\r
1329\r
1330 if (((FdcDev->Disk == FdcDisk0) && ((Data & 0x10) != 0x10)) ||\r
1331 ((FdcDev->Disk == FdcDisk1) && ((Data & 0x21) != 0x21))\r
1332 ) {\r
1333 return ;\r
1334 }\r
1335 //\r
1336 // the motor is on, so need motor off\r
1337 //\r
1338 Data = 0x0C;\r
1339 Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));\r
1340 FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);\r
1341 MicroSecondDelay (500);\r
1342}\r
1343\r
1344/**\r
1345 Read an I/O port of FDC.\r
1346\r
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
1349\r
1350 @retval 8-bit data read from the I/O port.\r
1351**/\r
1352UINT8\r
1353FdcReadPort (\r
1354 IN FDC_BLK_IO_DEV *FdcDev,\r
1355 IN UINT32 Offset\r
1356 )\r
1357{\r
1358 EFI_STATUS Status;\r
1359 UINT8 Data;\r
1360\r
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
1369\r
1370 return Data;\r
1371}\r
1372\r
1373/**\r
1374 Write an I/O port of FDC.\r
1375\r
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
1379**/\r
1380VOID\r
1381FdcWritePort (\r
1382 IN FDC_BLK_IO_DEV *FdcDev,\r
1383 IN UINT32 Offset,\r
1384 IN UINT8 Data\r
1385 )\r
1386{\r
1387 EFI_STATUS Status;\r
1388\r
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
1397}\r
1398\r