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