3 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR>
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
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
26 The internal function for the floppy driver
32 #include "IsaFloppy.h"
36 IN FDC_BLK_IO_DEV
*FdcDev
40 Routine Description: Detect the floppy drive is presented or not
42 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
44 EFI_SUCCESS Drive is presented
45 EFI_NOT_FOUND Drive is not presented
48 // GC_TODO: function comment is missing 'Arguments:'
49 // GC_TODO: FdcDev - add argument and description to function comment
53 FdcDev
->BlkIo
.Media
= &FdcDev
->BlkMedia
;
56 // Call FddIndentify subroutine
58 Status
= FddIdentify (FdcDev
);
59 if (EFI_ERROR (Status
)) {
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
;
75 IN FDC_BLK_IO_DEV
*FdcDev
79 Routine Description: Do recalibrate and see the drive is presented or not
80 Set the media parameters
82 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
88 // GC_TODO: function comment is missing 'Arguments:'
89 // GC_TODO: FdcDev - add argument and description to function comment
94 // Set Floppy Disk Controller's motor on
96 Status
= MotorOn (FdcDev
);
97 if (EFI_ERROR (Status
)) {
98 return EFI_DEVICE_ERROR
;
101 Status
= Recalibrate (FdcDev
);
103 if (EFI_ERROR (Status
)) {
105 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
106 return EFI_DEVICE_ERROR
;
109 // Set Media Parameter
111 FdcDev
->BlkIo
.Media
->RemovableMedia
= TRUE
;
112 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
116 FdcDev
->BlkIo
.Media
->MediaId
= 0;
121 Status
= DisketChanged (FdcDev
);
124 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
127 case EFI_MEDIA_CHANGED
:
136 // Check Disk Write Protected
138 Status
= SenseDrvStatus (FdcDev
, 0);
140 case EFI_WRITE_PROTECTED
:
141 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
145 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
149 return EFI_DEVICE_ERROR
;
156 // Set Media Default Type
158 FdcDev
->BlkIo
.Media
->BlockSize
= DISK_1440K_BYTEPERSECTOR
;
159 FdcDev
->BlkIo
.Media
->LastBlock
= DISK_1440K_EOT
* 2 * (DISK_1440K_MAXTRACKNUM
+ 1) - 1;
166 IN FDC_BLK_IO_DEV
*FdcDev
170 Routine Description: Reset the Floppy Logic Drive
172 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
174 EFI_SUCCESS: The Floppy Logic Drive is reset
175 EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
179 // GC_TODO: function comment is missing 'Arguments:'
180 // GC_TODO: FdcDev - add argument and description to function comment
183 UINT8 StatusRegister0
;
184 UINT8 PresentCylinderNumber
;
188 // Report reset progress code
190 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
192 EFI_PERIPHERAL_REMOVABLE_MEDIA
| EFI_P_PC_RESET
,
197 // Reset specified Floppy Logic Drive according to FdcDev -> Disk
198 // Set Digital Output Register(DOR) to do reset work
199 // bit0 & bit1 of DOR : Drive Select
201 // bit3 : DMA and Int bit
202 // Reset : a "0" written to bit2 resets the FDC, this reset will remain
204 // a "1" is written to this bit.
206 // use bit0 & bit1 to select the logic drive
210 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
211 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
214 // wait some time,at least 120us
216 MicroSecondDelay (500);
221 // write "1" to bit3 : enable DMA
224 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
229 MicroSecondDelay (2000);
232 // wait specified floppy logic drive is not busy
234 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
235 return EFI_DEVICE_ERROR
;
238 // Set the Transfer Data Rate
240 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
245 MicroSecondDelay (100);
248 // Issue Sense interrupt command for each drive (total 4 drives)
250 for (Index
= 0; Index
< 4; Index
++) {
251 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
252 return EFI_DEVICE_ERROR
;
256 // issue Specify command
258 if (EFI_ERROR (Specify (FdcDev
))) {
259 return EFI_DEVICE_ERROR
;
267 IN FDC_BLK_IO_DEV
*FdcDev
271 Routine Description: Turn the drive's motor on
272 The drive's motor must be on before any command can be executed
274 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
276 EFI_SUCCESS: Turn the drive's motor on successfully
277 EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on
278 EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)
281 // GC_TODO: function comment is missing 'Arguments:'
282 // GC_TODO: FdcDev - add argument and description to function comment
288 // Control of the floppy drive motors is a big pain. If motor is off, you have
289 // to turn it on first. But you can not leave the motor on all the time, since
290 // that would wear out the disk. On the other hand, if you turn the motor off
291 // after each operation, the system performance will be awful. The compromise
292 // used in this driver is to leave the motor on for 2 seconds after
293 // each operation. If a new operation is started in that interval(2s),
294 // the motor need not be turned on again. If no new operation is started,
295 // a timer goes off and the motor is turned off
300 Status
= gBS
->SetTimer (FdcDev
->Event
, TimerCancel
, 0);
302 if (EFI_ERROR (Status
)) {
303 return EFI_INVALID_PARAMETER
;
306 // Get the motor status
308 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
310 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) == 0x10)) ||
311 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) == 0x21))
316 // The drive's motor is off, so need turn it on
317 // first look at command and drive are busy or not
319 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
320 return EFI_DEVICE_ERROR
;
323 // for drive A: 1CH, drive B: 2DH
326 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
327 if (FdcDev
->Disk
== FDC_DISK0
) {
331 data
|= DRVA_MOTOR_ON
;
336 data
|= DRVB_MOTOR_ON
;
339 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
344 MicroSecondDelay (4000);
351 IN FDC_BLK_IO_DEV
*FdcDev
355 Routine Description: Set a Timer and when Timer goes off, turn the motor off
357 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
359 EFI_SUCCESS: Set the Timer successfully
360 EFI_INVALID_PARAMETER: Fail to Set the timer
363 // GC_TODO: function comment is missing 'Arguments:'
364 // GC_TODO: FdcDev - add argument and description to function comment
367 // Set the timer : 2s
369 return gBS
->SetTimer (FdcDev
->Event
, TimerRelative
, 20000000);
374 IN FDC_BLK_IO_DEV
*FdcDev
378 Routine Description: Detect the disk in the drive is changed or not
380 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
382 EFI_SUCCESS: No disk media change
383 EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation
384 EFI_NO_MEDIA: No disk in the drive
385 EFI_MEDIA_CHANGED: There is a new disk in the drive
388 // GC_TODO: function comment is missing 'Arguments:'
389 // GC_TODO: FdcDev - add argument and description to function comment
397 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
402 MicroSecondDelay (50);
404 if ((data
& DIR_DCL
) == 0x80) {
406 // disk change line is active
408 if (FdcDev
->PresentCylinderNumber
!= 0) {
409 Status
= Recalibrate (FdcDev
);
411 Status
= Seek (FdcDev
, 0x30);
414 if (EFI_ERROR (Status
)) {
415 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
416 return EFI_DEVICE_ERROR
;
418 // Fail to do the seek or recalibrate operation
422 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
427 MicroSecondDelay (50);
429 if ((data
& DIR_DCL
) == 0x80) {
433 return EFI_MEDIA_CHANGED
;
441 IN FDC_BLK_IO_DEV
*FdcDev
445 Routine Description: Do the Specify command, this command sets DMA operation
446 and the initial values for each of the three internal
447 times: HUT, SRT and HLT
451 EFI_SUCCESS: Execute the Specify command successfully
452 EFI_DEVICE_ERROR: Fail to execute the command
455 // GC_TODO: function comment is missing 'Arguments:'
456 // GC_TODO: FdcDev - add argument and description to function comment
458 FDD_SPECIFY_CMD Command
;
460 UINT8
*CommandPointer
;
462 ZeroMem (&Command
, sizeof (FDD_SPECIFY_CMD
));
463 Command
.CommandCode
= SPECIFY_CMD
;
467 Command
.SrtHut
= 0xdf;
473 Command
.HltNd
= 0x02;
475 CommandPointer
= (UINT8
*) (&Command
);
476 for (Index
= 0; Index
< sizeof (FDD_SPECIFY_CMD
); Index
++) {
477 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
478 return EFI_DEVICE_ERROR
;
487 IN FDC_BLK_IO_DEV
*FdcDev
491 Routine Description: Set the head of floppy drive to track 0
493 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
495 EFI_SUCCESS: Execute the Recalibrate operation successfully
496 EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
499 // GC_TODO: function comment is missing 'Arguments:'
500 // GC_TODO: FdcDev - add argument and description to function comment
502 FDD_COMMAND_PACKET2 Command
;
504 UINT8 StatusRegister0
;
505 UINT8 PresentCylinderNumber
;
506 UINT8
*CommandPointer
;
512 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
513 Command
.CommandCode
= RECALIBRATE_CMD
;
517 if (FdcDev
->Disk
== FDC_DISK0
) {
518 Command
.DiskHeadSel
= 0;
523 Command
.DiskHeadSel
= 1;
529 CommandPointer
= (UINT8
*) (&Command
);
530 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
531 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
532 return EFI_DEVICE_ERROR
;
538 MicroSecondDelay (250000);
540 // need modify according to 1.44M or 2.88M
542 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
543 return EFI_DEVICE_ERROR
;
546 if ((StatusRegister0
& 0xf0) == 0x20 && PresentCylinderNumber
== 0) {
547 FdcDev
->PresentCylinderNumber
= 0;
548 FdcDev
->ControllerState
->NeedRecalibrate
= FALSE
;
553 return EFI_DEVICE_ERROR
;
565 IN FDC_BLK_IO_DEV
*FdcDev
,
570 Routine Description: Set the head of floppy drive to the new cylinder
572 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
573 Lba EFI_LBA : The logic block address want to seek
575 EFI_SUCCESS: Execute the Seek operation successfully
576 EFI_DEVICE_ERROR: Fail to execute the Seek operation
579 // GC_TODO: function comment is missing 'Arguments:'
580 // GC_TODO: FdcDev - add argument and description to function comment
581 // GC_TODO: Lba - add argument and description to function comment
583 FDD_SEEK_CMD Command
;
587 UINT8 StatusRegister0
;
588 UINT8
*CommandPointer
;
589 UINT8 PresentCylinderNumber
;
593 if (FdcDev
->ControllerState
->NeedRecalibrate
) {
594 if (EFI_ERROR (Recalibrate (FdcDev
))) {
595 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
596 return EFI_DEVICE_ERROR
;
600 EndOfTrack
= DISK_1440K_EOT
;
602 // Calculate cylinder based on Lba and EOT
604 Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
607 // if the destination cylinder is the present cylinder, unnecessary to do the
610 if (FdcDev
->PresentCylinderNumber
== Cylinder
) {
614 // Calculate the head : 0 or 1
616 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
618 ZeroMem (&Command
, sizeof (FDD_SEEK_CMD
));
619 Command
.CommandCode
= SEEK_CMD
;
620 if (FdcDev
->Disk
== FDC_DISK0
) {
621 Command
.DiskHeadSel
= 0;
626 Command
.DiskHeadSel
= 1;
632 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
633 Command
.NewCylinder
= Cylinder
;
635 CommandPointer
= (UINT8
*) (&Command
);
636 for (Index
= 0; Index
< sizeof (FDD_SEEK_CMD
); Index
++) {
637 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
638 return EFI_DEVICE_ERROR
;
644 MicroSecondDelay (100);
647 // Calculate waiting time
649 if (FdcDev
->PresentCylinderNumber
> Cylinder
) {
650 DelayTime
= (UINT8
) (FdcDev
->PresentCylinderNumber
- Cylinder
);
652 DelayTime
= (UINT8
) (Cylinder
- FdcDev
->PresentCylinderNumber
);
655 MicroSecondDelay ((DelayTime
+ 1) * 4000);
657 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
658 return EFI_DEVICE_ERROR
;
661 if ((StatusRegister0
& 0xf0) == 0x20) {
662 FdcDev
->PresentCylinderNumber
= Command
.NewCylinder
;
665 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
666 return EFI_DEVICE_ERROR
;
672 IN FDC_BLK_IO_DEV
*FdcDev
,
673 IN OUT UINT8
*StatusRegister0
,
674 IN OUT UINT8
*PresentCylinderNumber
678 Routine Description: Do the Sense Interrupt Status command, this command
679 resets the interrupt signal
681 StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
682 PresentCylinderNumber UINT8 *: Be used to save present cylinder number
685 EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
686 EFI_DEVICE_ERROR: Fail to execute the command
689 // GC_TODO: function comment is missing 'Arguments:'
690 // GC_TODO: FdcDev - add argument and description to function comment
691 // GC_TODO: StatusRegister0 - add argument and description to function comment
692 // GC_TODO: PresentCylinderNumber - add argument and description to function comment
696 command
= SENSE_INT_STATUS_CMD
;
697 if (EFI_ERROR (DataOutByte (FdcDev
, &command
))) {
698 return EFI_DEVICE_ERROR
;
701 if (EFI_ERROR (DataInByte (FdcDev
, StatusRegister0
))) {
702 return EFI_DEVICE_ERROR
;
705 if (EFI_ERROR (DataInByte (FdcDev
, PresentCylinderNumber
))) {
706 return EFI_DEVICE_ERROR
;
714 IN FDC_BLK_IO_DEV
*FdcDev
,
719 Routine Description: Do the Sense Drive Status command
721 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
722 Lba EFI_LBA : Logic block address
724 EFI_SUCCESS: Execute the Sense Drive Status command successfully
725 EFI_DEVICE_ERROR: Fail to execute the command
726 EFI_WRITE_PROTECTED:The disk is write protected
729 // GC_TODO: function comment is missing 'Arguments:'
730 // GC_TODO: FdcDev - add argument and description to function comment
731 // GC_TODO: Lba - add argument and description to function comment
733 FDD_COMMAND_PACKET2 Command
;
737 UINT8 StatusRegister3
;
738 UINT8
*CommandPointer
;
741 // Sense Drive Status command obtains drive status information,
742 // it has not execution phase and goes directly to the result phase from the
743 // command phase, Status Register 3 contains the drive status information
745 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
746 Command
.CommandCode
= SENSE_DRV_STATUS_CMD
;
748 if (FdcDev
->Disk
== FDC_DISK0
) {
749 Command
.DiskHeadSel
= 0;
751 Command
.DiskHeadSel
= 1;
754 EndOfTrack
= DISK_1440K_EOT
;
755 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
756 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
758 CommandPointer
= (UINT8
*) (&Command
);
759 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
760 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
761 return EFI_DEVICE_ERROR
;
765 if (EFI_ERROR (DataInByte (FdcDev
, &StatusRegister3
))) {
766 return EFI_DEVICE_ERROR
;
771 MicroSecondDelay (50);
774 // Check Status Register 3 to get drive status information
776 return CheckStatus3 (StatusRegister3
);
781 IN FDC_BLK_IO_DEV
*FdcDev
785 Routine Description: Update the disk media properties and if necessary
786 reinstall Block I/O interface
788 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
790 EFI_SUCCESS: Do the operation successfully
791 EFI_DEVICE_ERROR: Fail to the operation
794 // GC_TODO: function comment is missing 'Arguments:'
795 // GC_TODO: FdcDev - add argument and description to function comment
799 BOOLEAN bReadOnlyLastTime
;
800 BOOLEAN bMediaPresentLastTime
;
803 bReadOnlyLastTime
= FdcDev
->BlkIo
.Media
->ReadOnly
;
804 bMediaPresentLastTime
= FdcDev
->BlkIo
.Media
->MediaPresent
;
809 Status
= DisketChanged (FdcDev
);
811 case EFI_MEDIA_CHANGED
:
812 FdcDev
->BlkIo
.Media
->MediaId
++;
813 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
818 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
832 if (FdcDev
->BlkIo
.Media
->MediaPresent
) {
834 // Check disk write protected
836 Status
= SenseDrvStatus (FdcDev
, 0);
837 if (Status
== EFI_WRITE_PROTECTED
) {
838 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
840 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
844 if (FdcDev
->BlkIo
.Media
->MediaPresent
&& (bReadOnlyLastTime
!= FdcDev
->BlkIo
.Media
->ReadOnly
)) {
848 if (bMediaPresentLastTime
!= FdcDev
->BlkIo
.Media
->MediaPresent
) {
853 Status
= gBS
->ReinstallProtocolInterface (
855 &gEfiBlockIoProtocolGuid
,
860 if (EFI_ERROR (Status
)) {
870 IN FDC_BLK_IO_DEV
*FdcDev
874 Routine Description: Set the data rate and so on
881 // GC_TODO: function comment is missing 'Arguments:'
882 // GC_TODO: FdcDev - add argument and description to function comment
883 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
888 // Set data rate 500kbs
890 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
895 MicroSecondDelay (50);
897 Status
= Specify (FdcDev
);
899 if (EFI_ERROR (Status
)) {
900 return EFI_DEVICE_ERROR
;
907 ReadWriteDataSector (
908 IN FDC_BLK_IO_DEV
*FdcDev
,
909 IN VOID
*HostAddress
,
911 IN UINTN NumberOfBlocks
,
916 Routine Description: Read or Write a number of blocks in the same cylinder
918 FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV
921 NumberOfBlocks UINTN:
927 // GC_TODO: function comment is missing 'Arguments:'
928 // GC_TODO: FdcDev - add argument and description to function comment
929 // GC_TODO: HostAddress - add argument and description to function comment
930 // GC_TODO: Lba - add argument and description to function comment
931 // GC_TODO: NumberOfBlocks - add argument and description to function comment
932 // GC_TODO: Read - add argument and description to function comment
933 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
934 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
935 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
936 // GC_TODO: EFI_TIMEOUT - add return value to function comment
937 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
940 FDD_COMMAND_PACKET1 Command
;
941 FDD_RESULT_PACKET Result
;
944 UINT8
*CommandPointer
;
946 EFI_PHYSICAL_ADDRESS DeviceAddress
;
947 EFI_ISA_IO_PROTOCOL
*IsaIo
;
950 EFI_ISA_IO_PROTOCOL_OPERATION Operation
;
953 EFI_ISA_ACPI_RESOURCE
*ResourceItem
;
956 Status
= Seek (FdcDev
, Lba
);
957 if (EFI_ERROR (Status
)) {
958 return EFI_DEVICE_ERROR
;
963 IsaIo
= FdcDev
->IsaIo
;
964 NumberofBytes
= NumberOfBlocks
* 512;
966 Operation
= EfiIsaIoOperationSlaveWrite
;
968 Operation
= EfiIsaIoOperationSlaveRead
;
971 ResourceItem
= IsaIo
->ResourceList
->ResourceItem
;
973 while (ResourceItem
[Index
].Type
!= EfiIsaAcpiResourceEndOfList
) {
974 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceDma
) {
981 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceEndOfList
) {
982 return EFI_DEVICE_ERROR
;
985 Channel
= (UINT8
) IsaIo
->ResourceList
->ResourceItem
[Index
].StartRange
;
986 Attribute
= IsaIo
->ResourceList
->ResourceItem
[Index
].Attribute
;
988 Status1
= IsaIo
->Map (
998 if (EFI_ERROR (Status1
)) {
1003 // Allocate Read or Write command packet
1005 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET1
));
1007 Command
.CommandCode
= READ_DATA_CMD
| CMD_MT
| CMD_MFM
| CMD_SK
;
1009 Command
.CommandCode
= WRITE_DATA_CMD
| CMD_MT
| CMD_MFM
;
1012 FillPara (FdcDev
, Lba
, &Command
);
1015 // Write command bytes to FDC
1017 CommandPointer
= (UINT8
*) (&Command
);
1018 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET1
); Index
++) {
1019 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
1020 return EFI_DEVICE_ERROR
;
1024 // wait for some time
1026 Times
= (STALL_1_SECOND
/ 50) + 1;
1028 if ((FdcReadPort (FdcDev
, FDC_REGISTER_MSR
) & 0xc0) == 0xc0) {
1032 MicroSecondDelay (50);
1040 // Read result bytes from FDC
1042 CommandPointer
= (UINT8
*) (&Result
);
1043 for (Index
= 0; Index
< sizeof (FDD_RESULT_PACKET
); Index
++) {
1044 if (EFI_ERROR (DataInByte (FdcDev
, CommandPointer
++))) {
1045 return EFI_DEVICE_ERROR
;
1049 // Flush before Unmap
1052 Status1
= IsaIo
->Flush (IsaIo
);
1053 if (EFI_ERROR (Status1
)) {
1060 Status1
= IsaIo
->Unmap (IsaIo
, Mapping
);
1061 if (EFI_ERROR (Status1
)) {
1065 return CheckResult (&Result
, FdcDev
);
1070 IN FDC_BLK_IO_DEV
*FdcDev
,
1072 IN FDD_COMMAND_PACKET1
*Command
1076 Routine Description: Fill in Parameter
1081 // GC_TODO: function comment is missing 'Arguments:'
1082 // GC_TODO: FdcDev - add argument and description to function comment
1083 // GC_TODO: Lba - add argument and description to function comment
1084 // GC_TODO: Command - add argument and description to function comment
1089 // Get EndOfTrack from the Para table
1091 EndOfTrack
= DISK_1440K_EOT
;
1094 // Fill the command parameter
1096 if (FdcDev
->Disk
== FDC_DISK0
) {
1097 Command
->DiskHeadSel
= 0;
1099 Command
->DiskHeadSel
= 1;
1102 Command
->Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
1103 Command
->Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
1104 Command
->Sector
= (UINT8
) ((UINT8
) ((UINTN
) Lba
% EndOfTrack
) + 1);
1105 Command
->DiskHeadSel
= (UINT8
) (Command
->DiskHeadSel
| (Command
->Head
<< 2));
1106 Command
->Number
= DISK_1440K_NUMBER
;
1107 Command
->EndOfTrack
= DISK_1440K_EOT
;
1108 Command
->GapLength
= DISK_1440K_GPL
;
1109 Command
->DataLength
= DISK_1440K_DTL
;
1114 IN FDC_BLK_IO_DEV
*FdcDev
,
1115 IN OUT UINT8
*Pointer
1119 Routine Description: Read result byte from Data Register of FDC
1121 Pointer UINT8 *: Be used to save result byte read from FDC
1123 EFI_SUCCESS: Read result byte from FDC successfully
1124 EFI_DEVICE_ERROR: The FDC is not ready to be read
1127 // GC_TODO: function comment is missing 'Arguments:'
1128 // GC_TODO: FdcDev - add argument and description to function comment
1129 // GC_TODO: Pointer - add argument and description to function comment
1134 // wait for 1ms and detect the FDC is ready to be read
1136 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_IN
, 1))) {
1137 return EFI_DEVICE_ERROR
;
1143 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DTR
);
1148 MicroSecondDelay (50);
1156 IN FDC_BLK_IO_DEV
*FdcDev
,
1161 Routine Description: Write command byte to Data Register of FDC
1163 Pointer UINT8 *: Be used to save command byte written to FDC
1165 EFI_SUCCESS: Write command byte to FDC successfully
1166 EFI_DEVICE_ERROR: The FDC is not ready to be written
1169 // GC_TODO: function comment is missing 'Arguments:'
1170 // GC_TODO: FdcDev - add argument and description to function comment
1171 // GC_TODO: Pointer - add argument and description to function comment
1176 // wait for 1ms and detect the FDC is ready to be written
1178 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_OUT
, 1))) {
1179 return EFI_DEVICE_ERROR
;
1187 FdcWritePort (FdcDev
, FDC_REGISTER_DTR
, data
);
1192 MicroSecondDelay (50);
1198 FddWaitForBSYClear (
1199 IN FDC_BLK_IO_DEV
*FdcDev
,
1200 IN UINTN TimeoutInSeconds
1204 Routine Description: Detect the specified floppy logic drive is busy or
1205 not within a period of time
1207 Disk EFI_FDC_DISK: Indicate it is drive A or drive B
1208 TimeoutInSeconds UINTN: the time period for waiting
1210 EFI_SUCCESS: The drive and command are not busy
1211 EFI_TIMEOUT: The drive or command is still busy after a period time that
1212 set by TimeoutInSeconds
1215 // GC_TODO: function comment is missing 'Arguments:'
1216 // GC_TODO: FdcDev - add argument and description to function comment
1217 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1220 UINT8 StatusRegister
;
1224 // How to determine drive and command are busy or not: by the bits of
1225 // Main Status Register
1226 // bit0: Drive 0 busy (drive A)
1227 // bit1: Drive 1 busy (drive B)
1228 // bit4: Command busy
1231 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
1233 Mask
= (UINT8
) ((FdcDev
->Disk
== FDC_DISK0
? MSR_DAB
: MSR_DBB
) | MSR_CB
);
1235 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1237 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1238 if ((StatusRegister
& Mask
) == 0x00) {
1245 MicroSecondDelay (50);
1258 IN FDC_BLK_IO_DEV
*FdcDev
,
1260 IN UINTN TimeoutInSeconds
1264 Routine Description: Determine whether FDC is ready to write or read
1266 Dio BOOLEAN: Indicate the FDC is waiting to write or read
1267 TimeoutInSeconds UINTN: The time period for waiting
1269 EFI_SUCCESS: FDC is ready to write or read
1270 EFI_NOT_READY: FDC is not ready within the specified time period
1273 // GC_TODO: function comment is missing 'Arguments:'
1274 // GC_TODO: FdcDev - add argument and description to function comment
1275 // GC_TODO: Dio - add argument and description to function comment
1276 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1279 UINT8 StatusRegister
;
1283 // Before writing to FDC or reading from FDC, the Host must examine
1284 // the bit7(RQM) and bit6(DIO) of the Main Status Register.
1286 // command bytes can not be written to Data Register
1287 // unless RQM is 1 and DIO is 0
1288 // result bytes can not be read from Data Register
1289 // unless RQM is 1 and DIO is 1
1291 DataInOut
= (UINT8
) (Dio
<< 6);
1293 // in order to compare bit6
1295 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1297 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1298 if ((StatusRegister
& MSR_RQM
) == MSR_RQM
&& (StatusRegister
& MSR_DIO
) == DataInOut
) {
1305 MicroSecondDelay (50);
1313 return EFI_NOT_READY
;
1315 // FDC is not ready within the specified time period
1324 IN FDD_RESULT_PACKET
*Result
,
1325 IN OUT FDC_BLK_IO_DEV
*FdcDev
1329 Routine Description:
1331 GC_TODO: Add function description
1335 Result - GC_TODO: add argument description
1336 FdcDev - GC_TODO: add argument description
1340 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1341 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1342 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1343 EFI_SUCCESS - GC_TODO: Add description for return value
1348 // Check Status Register0
1350 if ((Result
->Status0
& STS0_IC
) != IC_NT
) {
1351 if ((Result
->Status0
& STS0_SE
) == 0x20) {
1355 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1358 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1359 return EFI_DEVICE_ERROR
;
1362 // Check Status Register1
1364 if (Result
->Status1
& (STS1_EN
| STS1_DE
| STS1_OR
| STS1_ND
| STS1_NW
| STS1_MA
)) {
1365 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1366 return EFI_DEVICE_ERROR
;
1369 // Check Status Register2
1371 if (Result
->Status2
& (STS2_CM
| STS2_DD
| STS2_WC
| STS2_BC
| STS2_MD
)) {
1372 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1373 return EFI_DEVICE_ERROR
;
1381 IN UINT8 StatusRegister3
1385 Routine Description: Check the drive status information
1387 StatusRegister3 UINT8: the value of Status Register 3
1390 EFI_WRITE_PROTECTED: The disk is write protected
1393 // GC_TODO: function comment is missing 'Arguments:'
1394 // GC_TODO: StatusRegister3 - add argument and description to function comment
1396 if (StatusRegister3
& STS3_WP
) {
1397 return EFI_WRITE_PROTECTED
;
1404 GetTransferBlockCount (
1405 IN FDC_BLK_IO_DEV
*FdcDev
,
1407 IN UINTN NumberOfBlocks
1411 Routine Description: Calculate the number of block in the same cylinder
1414 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
1415 LBA EFI_LBA: The starting logic block address
1416 NumberOfBlocks UINTN: The number of blocks
1418 UINTN : The number of blocks in the same cylinder which the starting
1419 logic block address is LBA
1422 // GC_TODO: function comment is missing 'Arguments:'
1423 // GC_TODO: FdcDev - add argument and description to function comment
1424 // GC_TODO: LBA - add argument and description to function comment
1425 // GC_TODO: NumberOfBlocks - add argument and description to function comment
1429 UINT8 SectorsInTrack
;
1432 // Calculate the number of block in the same cylinder
1434 EndOfTrack
= DISK_1440K_EOT
;
1435 Head
= (UINT8
) ((UINTN
) LBA
/ EndOfTrack
% 2);
1437 SectorsInTrack
= (UINT8
) (EndOfTrack
* (2 - Head
) - (UINT8
) ((UINTN
) LBA
% EndOfTrack
));
1438 if (SectorsInTrack
< NumberOfBlocks
) {
1439 return SectorsInTrack
;
1441 return NumberOfBlocks
;
1453 Routine Description: When the Timer(2s) off, turn the drive's motor off
1455 Event EFI_EVENT: Event(the timer) whose notification function is being
1457 Context VOID *: Pointer to the notification function's context
1462 // GC_TODO: function comment is missing 'Arguments:'
1463 // GC_TODO: Event - add argument and description to function comment
1464 // GC_TODO: Context - add argument and description to function comment
1466 FDC_BLK_IO_DEV
*FdcDev
;
1469 FdcDev
= (FDC_BLK_IO_DEV
*) Context
;
1472 // Get the motor status
1474 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
1476 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) != 0x10)) ||
1477 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) != 0x21))
1482 // the motor is on, so need motor off
1485 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
1486 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
1487 MicroSecondDelay (500);
1492 IN FDC_BLK_IO_DEV
*FdcDev
,
1497 Routine Description: Read I/O port for FDC
1502 // GC_TODO: function comment is missing 'Arguments:'
1503 // GC_TODO: FdcDev - add argument and description to function comment
1504 // GC_TODO: Offset - add argument and description to function comment
1511 FdcDev
->IsaIo
->Io
.Read (
1514 FdcDev
->BaseAddress
+ Offset
,
1524 IN FDC_BLK_IO_DEV
*FdcDev
,
1530 Routine Description: Write I/O port for FDC
1535 // GC_TODO: function comment is missing 'Arguments:'
1536 // GC_TODO: FdcDev - add argument and description to function comment
1537 // GC_TODO: Offset - add argument and description to function comment
1538 // GC_TODO: Data - add argument and description to function comment
1544 FdcDev
->IsaIo
->Io
.Write (
1547 FdcDev
->BaseAddress
+ Offset
,