3 1. Support two types diskette drive
4 1.44M drive and 2.88M drive (and now only support 1.44M)
5 2. Support two diskette drives
6 3. Use DMA channel 2 to transfer data
7 4. Do not use interrupt
8 5. Support diskette change line signal and write protect
10 The internal function for the floppy driver
12 Copyright (c) 2006 - 2007, Intel Corporation.<BR>
13 All rights reserved. This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
23 #include "IsaFloppy.h"
27 IN FDC_BLK_IO_DEV
*FdcDev
31 Routine Description: Detect the floppy drive is presented or not
33 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
35 EFI_SUCCESS Drive is presented
36 EFI_NOT_FOUND Drive is not presented
39 // GC_TODO: function comment is missing 'Arguments:'
40 // GC_TODO: FdcDev - add argument and description to function comment
44 FdcDev
->BlkIo
.Media
= &FdcDev
->BlkMedia
;
47 // Call FddIndentify subroutine
49 Status
= FddIdentify (FdcDev
);
50 if (EFI_ERROR (Status
)) {
54 FdcDev
->BlkIo
.Reset
= FdcReset
;
55 FdcDev
->BlkIo
.FlushBlocks
= FddFlushBlocks
;
56 FdcDev
->BlkIo
.ReadBlocks
= FddReadBlocks
;
57 FdcDev
->BlkIo
.WriteBlocks
= FddWriteBlocks
;
58 FdcDev
->BlkMedia
.LogicalPartition
= FALSE
;
59 FdcDev
->BlkMedia
.WriteCaching
= FALSE
;
66 IN FDC_BLK_IO_DEV
*FdcDev
70 Routine Description: Do recalibrate and see the drive is presented or not
71 Set the media parameters
73 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
79 // GC_TODO: function comment is missing 'Arguments:'
80 // GC_TODO: FdcDev - add argument and description to function comment
85 // Set Floppy Disk Controller's motor on
87 Status
= MotorOn (FdcDev
);
88 if (EFI_ERROR (Status
)) {
89 return EFI_DEVICE_ERROR
;
92 Status
= Recalibrate (FdcDev
);
94 if (EFI_ERROR (Status
)) {
96 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
97 return EFI_DEVICE_ERROR
;
100 // Set Media Parameter
102 FdcDev
->BlkIo
.Media
->RemovableMedia
= TRUE
;
103 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
107 FdcDev
->BlkIo
.Media
->MediaId
= 0;
112 Status
= DisketChanged (FdcDev
);
114 if (Status
== EFI_NO_MEDIA
) {
115 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
116 } else if (Status
!= EFI_MEDIA_CHANGED
) {
122 // Check Disk Write Protected
124 Status
= SenseDrvStatus (FdcDev
, 0);
126 if (Status
== EFI_WRITE_PROTECTED
) {
127 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
128 } else if (Status
== EFI_SUCCESS
) {
129 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
131 return EFI_DEVICE_ERROR
;
137 // Set Media Default Type
139 FdcDev
->BlkIo
.Media
->BlockSize
= DISK_1440K_BYTEPERSECTOR
;
140 FdcDev
->BlkIo
.Media
->LastBlock
= DISK_1440K_EOT
* 2 * (DISK_1440K_MAXTRACKNUM
+ 1) - 1;
147 IN FDC_BLK_IO_DEV
*FdcDev
151 Routine Description: Reset the Floppy Logic Drive
153 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
155 EFI_SUCCESS: The Floppy Logic Drive is reset
156 EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
160 // GC_TODO: function comment is missing 'Arguments:'
161 // GC_TODO: FdcDev - add argument and description to function comment
164 UINT8 StatusRegister0
;
165 UINT8 PresentCylinderNumber
;
169 // Report reset progress code
171 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
173 EFI_PERIPHERAL_REMOVABLE_MEDIA
| EFI_P_PC_RESET
,
178 // Reset specified Floppy Logic Drive according to FdcDev -> Disk
179 // Set Digital Output Register(DOR) to do reset work
180 // bit0 & bit1 of DOR : Drive Select
182 // bit3 : DMA and Int bit
183 // Reset : a "0" written to bit2 resets the FDC, this reset will remain
185 // a "1" is written to this bit.
187 // use bit0 & bit1 to select the logic drive
191 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
192 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
195 // wait some time,at least 120us
197 MicroSecondDelay (500);
202 // write "1" to bit3 : enable DMA
205 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
210 MicroSecondDelay (2000);
213 // wait specified floppy logic drive is not busy
215 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
216 return EFI_DEVICE_ERROR
;
219 // Set the Transfer Data Rate
221 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
226 MicroSecondDelay (100);
229 // Issue Sense interrupt command for each drive (total 4 drives)
231 for (Index
= 0; Index
< 4; Index
++) {
232 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
233 return EFI_DEVICE_ERROR
;
237 // issue Specify command
239 if (EFI_ERROR (Specify (FdcDev
))) {
240 return EFI_DEVICE_ERROR
;
248 IN FDC_BLK_IO_DEV
*FdcDev
252 Routine Description: Turn the drive's motor on
253 The drive's motor must be on before any command can be executed
255 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
257 EFI_SUCCESS: Turn the drive's motor on successfully
258 EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on
259 EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)
262 // GC_TODO: function comment is missing 'Arguments:'
263 // GC_TODO: FdcDev - add argument and description to function comment
269 // Control of the floppy drive motors is a big pain. If motor is off, you have
270 // to turn it on first. But you can not leave the motor on all the time, since
271 // that would wear out the disk. On the other hand, if you turn the motor off
272 // after each operation, the system performance will be awful. The compromise
273 // used in this driver is to leave the motor on for 2 seconds after
274 // each operation. If a new operation is started in that interval(2s),
275 // the motor need not be turned on again. If no new operation is started,
276 // a timer goes off and the motor is turned off
281 Status
= gBS
->SetTimer (FdcDev
->Event
, TimerCancel
, 0);
283 if (EFI_ERROR (Status
)) {
284 return EFI_INVALID_PARAMETER
;
287 // Get the motor status
289 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
291 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) == 0x10)) ||
292 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) == 0x21))
297 // The drive's motor is off, so need turn it on
298 // first look at command and drive are busy or not
300 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
301 return EFI_DEVICE_ERROR
;
304 // for drive A: 1CH, drive B: 2DH
307 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
308 if (FdcDev
->Disk
== FDC_DISK0
) {
312 data
|= DRVA_MOTOR_ON
;
317 data
|= DRVB_MOTOR_ON
;
320 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
325 MicroSecondDelay (4000);
332 IN FDC_BLK_IO_DEV
*FdcDev
336 Routine Description: Set a Timer and when Timer goes off, turn the motor off
338 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
340 EFI_SUCCESS: Set the Timer successfully
341 EFI_INVALID_PARAMETER: Fail to Set the timer
344 // GC_TODO: function comment is missing 'Arguments:'
345 // GC_TODO: FdcDev - add argument and description to function comment
348 // Set the timer : 2s
350 return gBS
->SetTimer (FdcDev
->Event
, TimerRelative
, 20000000);
355 IN FDC_BLK_IO_DEV
*FdcDev
359 Routine Description: Detect the disk in the drive is changed or not
361 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
363 EFI_SUCCESS: No disk media change
364 EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation
365 EFI_NO_MEDIA: No disk in the drive
366 EFI_MEDIA_CHANGED: There is a new disk in the drive
369 // GC_TODO: function comment is missing 'Arguments:'
370 // GC_TODO: FdcDev - add argument and description to function comment
378 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
383 MicroSecondDelay (50);
385 if ((data
& DIR_DCL
) == 0x80) {
387 // disk change line is active
389 if (FdcDev
->PresentCylinderNumber
!= 0) {
390 Status
= Recalibrate (FdcDev
);
392 Status
= Seek (FdcDev
, 0x30);
395 if (EFI_ERROR (Status
)) {
396 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
397 return EFI_DEVICE_ERROR
;
399 // Fail to do the seek or recalibrate operation
403 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
408 MicroSecondDelay (50);
410 if ((data
& DIR_DCL
) == 0x80) {
414 return EFI_MEDIA_CHANGED
;
422 IN FDC_BLK_IO_DEV
*FdcDev
426 Routine Description: Do the Specify command, this command sets DMA operation
427 and the initial values for each of the three internal
428 times: HUT, SRT and HLT
432 EFI_SUCCESS: Execute the Specify command successfully
433 EFI_DEVICE_ERROR: Fail to execute the command
436 // GC_TODO: function comment is missing 'Arguments:'
437 // GC_TODO: FdcDev - add argument and description to function comment
439 FDD_SPECIFY_CMD Command
;
441 UINT8
*CommandPointer
;
443 ZeroMem (&Command
, sizeof (FDD_SPECIFY_CMD
));
444 Command
.CommandCode
= SPECIFY_CMD
;
448 Command
.SrtHut
= 0xdf;
454 Command
.HltNd
= 0x02;
456 CommandPointer
= (UINT8
*) (&Command
);
457 for (Index
= 0; Index
< sizeof (FDD_SPECIFY_CMD
); Index
++) {
458 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
459 return EFI_DEVICE_ERROR
;
468 IN FDC_BLK_IO_DEV
*FdcDev
472 Routine Description: Set the head of floppy drive to track 0
474 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
476 EFI_SUCCESS: Execute the Recalibrate operation successfully
477 EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
480 // GC_TODO: function comment is missing 'Arguments:'
481 // GC_TODO: FdcDev - add argument and description to function comment
483 FDD_COMMAND_PACKET2 Command
;
485 UINT8 StatusRegister0
;
486 UINT8 PresentCylinderNumber
;
487 UINT8
*CommandPointer
;
493 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
494 Command
.CommandCode
= RECALIBRATE_CMD
;
498 if (FdcDev
->Disk
== FDC_DISK0
) {
499 Command
.DiskHeadSel
= 0;
504 Command
.DiskHeadSel
= 1;
510 CommandPointer
= (UINT8
*) (&Command
);
511 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
512 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
513 return EFI_DEVICE_ERROR
;
519 MicroSecondDelay (250000);
521 // need modify according to 1.44M or 2.88M
523 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
524 return EFI_DEVICE_ERROR
;
527 if ((StatusRegister0
& 0xf0) == 0x20 && PresentCylinderNumber
== 0) {
528 FdcDev
->PresentCylinderNumber
= 0;
529 FdcDev
->ControllerState
->NeedRecalibrate
= FALSE
;
534 return EFI_DEVICE_ERROR
;
546 IN FDC_BLK_IO_DEV
*FdcDev
,
551 Routine Description: Set the head of floppy drive to the new cylinder
553 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
554 Lba EFI_LBA : The logic block address want to seek
556 EFI_SUCCESS: Execute the Seek operation successfully
557 EFI_DEVICE_ERROR: Fail to execute the Seek operation
560 // GC_TODO: function comment is missing 'Arguments:'
561 // GC_TODO: FdcDev - add argument and description to function comment
562 // GC_TODO: Lba - add argument and description to function comment
564 FDD_SEEK_CMD Command
;
568 UINT8 StatusRegister0
;
569 UINT8
*CommandPointer
;
570 UINT8 PresentCylinderNumber
;
574 if (FdcDev
->ControllerState
->NeedRecalibrate
) {
575 if (EFI_ERROR (Recalibrate (FdcDev
))) {
576 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
577 return EFI_DEVICE_ERROR
;
581 EndOfTrack
= DISK_1440K_EOT
;
583 // Calculate cylinder based on Lba and EOT
585 Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
588 // if the destination cylinder is the present cylinder, unnecessary to do the
591 if (FdcDev
->PresentCylinderNumber
== Cylinder
) {
595 // Calculate the head : 0 or 1
597 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
599 ZeroMem (&Command
, sizeof (FDD_SEEK_CMD
));
600 Command
.CommandCode
= SEEK_CMD
;
601 if (FdcDev
->Disk
== FDC_DISK0
) {
602 Command
.DiskHeadSel
= 0;
607 Command
.DiskHeadSel
= 1;
613 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
614 Command
.NewCylinder
= Cylinder
;
616 CommandPointer
= (UINT8
*) (&Command
);
617 for (Index
= 0; Index
< sizeof (FDD_SEEK_CMD
); Index
++) {
618 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
619 return EFI_DEVICE_ERROR
;
625 MicroSecondDelay (100);
628 // Calculate waiting time
630 if (FdcDev
->PresentCylinderNumber
> Cylinder
) {
631 DelayTime
= (UINT8
) (FdcDev
->PresentCylinderNumber
- Cylinder
);
633 DelayTime
= (UINT8
) (Cylinder
- FdcDev
->PresentCylinderNumber
);
636 MicroSecondDelay ((DelayTime
+ 1) * 4000);
638 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
639 return EFI_DEVICE_ERROR
;
642 if ((StatusRegister0
& 0xf0) == 0x20) {
643 FdcDev
->PresentCylinderNumber
= Command
.NewCylinder
;
646 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
647 return EFI_DEVICE_ERROR
;
653 IN FDC_BLK_IO_DEV
*FdcDev
,
654 IN OUT UINT8
*StatusRegister0
,
655 IN OUT UINT8
*PresentCylinderNumber
659 Routine Description: Do the Sense Interrupt Status command, this command
660 resets the interrupt signal
662 StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
663 PresentCylinderNumber UINT8 *: Be used to save present cylinder number
666 EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
667 EFI_DEVICE_ERROR: Fail to execute the command
670 // GC_TODO: function comment is missing 'Arguments:'
671 // GC_TODO: FdcDev - add argument and description to function comment
672 // GC_TODO: StatusRegister0 - add argument and description to function comment
673 // GC_TODO: PresentCylinderNumber - add argument and description to function comment
677 command
= SENSE_INT_STATUS_CMD
;
678 if (EFI_ERROR (DataOutByte (FdcDev
, &command
))) {
679 return EFI_DEVICE_ERROR
;
682 if (EFI_ERROR (DataInByte (FdcDev
, StatusRegister0
))) {
683 return EFI_DEVICE_ERROR
;
686 if (EFI_ERROR (DataInByte (FdcDev
, PresentCylinderNumber
))) {
687 return EFI_DEVICE_ERROR
;
695 IN FDC_BLK_IO_DEV
*FdcDev
,
700 Routine Description: Do the Sense Drive Status command
702 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
703 Lba EFI_LBA : Logic block address
705 EFI_SUCCESS: Execute the Sense Drive Status command successfully
706 EFI_DEVICE_ERROR: Fail to execute the command
707 EFI_WRITE_PROTECTED:The disk is write protected
710 // GC_TODO: function comment is missing 'Arguments:'
711 // GC_TODO: FdcDev - add argument and description to function comment
712 // GC_TODO: Lba - add argument and description to function comment
714 FDD_COMMAND_PACKET2 Command
;
718 UINT8 StatusRegister3
;
719 UINT8
*CommandPointer
;
722 // Sense Drive Status command obtains drive status information,
723 // it has not execution phase and goes directly to the result phase from the
724 // command phase, Status Register 3 contains the drive status information
726 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
727 Command
.CommandCode
= SENSE_DRV_STATUS_CMD
;
729 if (FdcDev
->Disk
== FDC_DISK0
) {
730 Command
.DiskHeadSel
= 0;
732 Command
.DiskHeadSel
= 1;
735 EndOfTrack
= DISK_1440K_EOT
;
736 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
737 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
739 CommandPointer
= (UINT8
*) (&Command
);
740 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
741 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
742 return EFI_DEVICE_ERROR
;
746 if (EFI_ERROR (DataInByte (FdcDev
, &StatusRegister3
))) {
747 return EFI_DEVICE_ERROR
;
752 MicroSecondDelay (50);
755 // Check Status Register 3 to get drive status information
757 return CheckStatus3 (StatusRegister3
);
762 IN FDC_BLK_IO_DEV
*FdcDev
766 Routine Description: Update the disk media properties and if necessary
767 reinstall Block I/O interface
769 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
771 EFI_SUCCESS: Do the operation successfully
772 EFI_DEVICE_ERROR: Fail to the operation
775 // GC_TODO: function comment is missing 'Arguments:'
776 // GC_TODO: FdcDev - add argument and description to function comment
780 BOOLEAN bReadOnlyLastTime
;
781 BOOLEAN bMediaPresentLastTime
;
784 bReadOnlyLastTime
= FdcDev
->BlkIo
.Media
->ReadOnly
;
785 bMediaPresentLastTime
= FdcDev
->BlkIo
.Media
->MediaPresent
;
790 Status
= DisketChanged (FdcDev
);
792 if (Status
== EFI_MEDIA_CHANGED
) {
793 FdcDev
->BlkIo
.Media
->MediaId
++;
794 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
796 } else if (Status
== EFI_NO_MEDIA
) {
797 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
798 } else if (Status
!= EFI_SUCCESS
) {
806 if (FdcDev
->BlkIo
.Media
->MediaPresent
) {
808 // Check disk write protected
810 Status
= SenseDrvStatus (FdcDev
, 0);
811 if (Status
== EFI_WRITE_PROTECTED
) {
812 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
814 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
818 if (FdcDev
->BlkIo
.Media
->MediaPresent
&& (bReadOnlyLastTime
!= FdcDev
->BlkIo
.Media
->ReadOnly
)) {
822 if (bMediaPresentLastTime
!= FdcDev
->BlkIo
.Media
->MediaPresent
) {
827 Status
= gBS
->ReinstallProtocolInterface (
829 &gEfiBlockIoProtocolGuid
,
834 if (EFI_ERROR (Status
)) {
844 IN FDC_BLK_IO_DEV
*FdcDev
848 Routine Description: Set the data rate and so on
855 // GC_TODO: function comment is missing 'Arguments:'
856 // GC_TODO: FdcDev - add argument and description to function comment
857 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
862 // Set data rate 500kbs
864 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
869 MicroSecondDelay (50);
871 Status
= Specify (FdcDev
);
873 if (EFI_ERROR (Status
)) {
874 return EFI_DEVICE_ERROR
;
881 ReadWriteDataSector (
882 IN FDC_BLK_IO_DEV
*FdcDev
,
883 IN VOID
*HostAddress
,
885 IN UINTN NumberOfBlocks
,
890 Routine Description: Read or Write a number of blocks in the same cylinder
892 FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV
895 NumberOfBlocks UINTN:
901 // GC_TODO: function comment is missing 'Arguments:'
902 // GC_TODO: FdcDev - add argument and description to function comment
903 // GC_TODO: HostAddress - add argument and description to function comment
904 // GC_TODO: Lba - add argument and description to function comment
905 // GC_TODO: NumberOfBlocks - add argument and description to function comment
906 // GC_TODO: Read - add argument and description to function comment
907 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
908 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
909 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
910 // GC_TODO: EFI_TIMEOUT - add return value to function comment
911 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
914 FDD_COMMAND_PACKET1 Command
;
915 FDD_RESULT_PACKET Result
;
918 UINT8
*CommandPointer
;
920 EFI_PHYSICAL_ADDRESS DeviceAddress
;
921 EFI_ISA_IO_PROTOCOL
*IsaIo
;
924 EFI_ISA_IO_PROTOCOL_OPERATION Operation
;
927 EFI_ISA_ACPI_RESOURCE
*ResourceItem
;
930 Status
= Seek (FdcDev
, Lba
);
931 if (EFI_ERROR (Status
)) {
932 return EFI_DEVICE_ERROR
;
937 IsaIo
= FdcDev
->IsaIo
;
938 NumberofBytes
= NumberOfBlocks
* 512;
940 Operation
= EfiIsaIoOperationSlaveWrite
;
942 Operation
= EfiIsaIoOperationSlaveRead
;
945 ResourceItem
= IsaIo
->ResourceList
->ResourceItem
;
947 while (ResourceItem
[Index
].Type
!= EfiIsaAcpiResourceEndOfList
) {
948 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceDma
) {
955 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceEndOfList
) {
956 return EFI_DEVICE_ERROR
;
959 Channel
= (UINT8
) IsaIo
->ResourceList
->ResourceItem
[Index
].StartRange
;
960 Attribute
= IsaIo
->ResourceList
->ResourceItem
[Index
].Attribute
;
962 Status1
= IsaIo
->Map (
972 if (EFI_ERROR (Status1
)) {
977 // Allocate Read or Write command packet
979 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET1
));
981 Command
.CommandCode
= READ_DATA_CMD
| CMD_MT
| CMD_MFM
| CMD_SK
;
983 Command
.CommandCode
= WRITE_DATA_CMD
| CMD_MT
| CMD_MFM
;
986 FillPara (FdcDev
, Lba
, &Command
);
989 // Write command bytes to FDC
991 CommandPointer
= (UINT8
*) (&Command
);
992 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET1
); Index
++) {
993 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
994 return EFI_DEVICE_ERROR
;
998 // wait for some time
1000 Times
= (STALL_1_SECOND
/ 50) + 1;
1002 if ((FdcReadPort (FdcDev
, FDC_REGISTER_MSR
) & 0xc0) == 0xc0) {
1006 MicroSecondDelay (50);
1014 // Read result bytes from FDC
1016 CommandPointer
= (UINT8
*) (&Result
);
1017 for (Index
= 0; Index
< sizeof (FDD_RESULT_PACKET
); Index
++) {
1018 if (EFI_ERROR (DataInByte (FdcDev
, CommandPointer
++))) {
1019 return EFI_DEVICE_ERROR
;
1023 // Flush before Unmap
1026 Status1
= IsaIo
->Flush (IsaIo
);
1027 if (EFI_ERROR (Status1
)) {
1034 Status1
= IsaIo
->Unmap (IsaIo
, Mapping
);
1035 if (EFI_ERROR (Status1
)) {
1039 return CheckResult (&Result
, FdcDev
);
1044 IN FDC_BLK_IO_DEV
*FdcDev
,
1046 IN FDD_COMMAND_PACKET1
*Command
1050 Routine Description: Fill in Parameter
1055 // GC_TODO: function comment is missing 'Arguments:'
1056 // GC_TODO: FdcDev - add argument and description to function comment
1057 // GC_TODO: Lba - add argument and description to function comment
1058 // GC_TODO: Command - add argument and description to function comment
1063 // Get EndOfTrack from the Para table
1065 EndOfTrack
= DISK_1440K_EOT
;
1068 // Fill the command parameter
1070 if (FdcDev
->Disk
== FDC_DISK0
) {
1071 Command
->DiskHeadSel
= 0;
1073 Command
->DiskHeadSel
= 1;
1076 Command
->Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
1077 Command
->Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
1078 Command
->Sector
= (UINT8
) ((UINT8
) ((UINTN
) Lba
% EndOfTrack
) + 1);
1079 Command
->DiskHeadSel
= (UINT8
) (Command
->DiskHeadSel
| (Command
->Head
<< 2));
1080 Command
->Number
= DISK_1440K_NUMBER
;
1081 Command
->EndOfTrack
= DISK_1440K_EOT
;
1082 Command
->GapLength
= DISK_1440K_GPL
;
1083 Command
->DataLength
= DISK_1440K_DTL
;
1088 IN FDC_BLK_IO_DEV
*FdcDev
,
1089 IN OUT UINT8
*Pointer
1093 Routine Description: Read result byte from Data Register of FDC
1095 Pointer UINT8 *: Be used to save result byte read from FDC
1097 EFI_SUCCESS: Read result byte from FDC successfully
1098 EFI_DEVICE_ERROR: The FDC is not ready to be read
1101 // GC_TODO: function comment is missing 'Arguments:'
1102 // GC_TODO: FdcDev - add argument and description to function comment
1103 // GC_TODO: Pointer - add argument and description to function comment
1108 // wait for 1ms and detect the FDC is ready to be read
1110 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_IN
, 1))) {
1111 return EFI_DEVICE_ERROR
;
1117 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DTR
);
1122 MicroSecondDelay (50);
1130 IN FDC_BLK_IO_DEV
*FdcDev
,
1135 Routine Description: Write command byte to Data Register of FDC
1137 Pointer UINT8 *: Be used to save command byte written to FDC
1139 EFI_SUCCESS: Write command byte to FDC successfully
1140 EFI_DEVICE_ERROR: The FDC is not ready to be written
1143 // GC_TODO: function comment is missing 'Arguments:'
1144 // GC_TODO: FdcDev - add argument and description to function comment
1145 // GC_TODO: Pointer - add argument and description to function comment
1150 // wait for 1ms and detect the FDC is ready to be written
1152 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_OUT
, 1))) {
1153 return EFI_DEVICE_ERROR
;
1161 FdcWritePort (FdcDev
, FDC_REGISTER_DTR
, data
);
1166 MicroSecondDelay (50);
1172 FddWaitForBSYClear (
1173 IN FDC_BLK_IO_DEV
*FdcDev
,
1174 IN UINTN TimeoutInSeconds
1178 Routine Description: Detect the specified floppy logic drive is busy or
1179 not within a period of time
1181 Disk EFI_FDC_DISK: Indicate it is drive A or drive B
1182 TimeoutInSeconds UINTN: the time period for waiting
1184 EFI_SUCCESS: The drive and command are not busy
1185 EFI_TIMEOUT: The drive or command is still busy after a period time that
1186 set by TimeoutInSeconds
1189 // GC_TODO: function comment is missing 'Arguments:'
1190 // GC_TODO: FdcDev - add argument and description to function comment
1191 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1194 UINT8 StatusRegister
;
1198 // How to determine drive and command are busy or not: by the bits of
1199 // Main Status Register
1200 // bit0: Drive 0 busy (drive A)
1201 // bit1: Drive 1 busy (drive B)
1202 // bit4: Command busy
1205 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
1207 Mask
= (UINT8
) ((FdcDev
->Disk
== FDC_DISK0
? MSR_DAB
: MSR_DBB
) | MSR_CB
);
1209 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1211 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1212 if ((StatusRegister
& Mask
) == 0x00) {
1219 MicroSecondDelay (50);
1232 IN FDC_BLK_IO_DEV
*FdcDev
,
1234 IN UINTN TimeoutInSeconds
1238 Routine Description: Determine whether FDC is ready to write or read
1240 Dio BOOLEAN: Indicate the FDC is waiting to write or read
1241 TimeoutInSeconds UINTN: The time period for waiting
1243 EFI_SUCCESS: FDC is ready to write or read
1244 EFI_NOT_READY: FDC is not ready within the specified time period
1247 // GC_TODO: function comment is missing 'Arguments:'
1248 // GC_TODO: FdcDev - add argument and description to function comment
1249 // GC_TODO: Dio - add argument and description to function comment
1250 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1253 UINT8 StatusRegister
;
1257 // Before writing to FDC or reading from FDC, the Host must examine
1258 // the bit7(RQM) and bit6(DIO) of the Main Status Register.
1260 // command bytes can not be written to Data Register
1261 // unless RQM is 1 and DIO is 0
1262 // result bytes can not be read from Data Register
1263 // unless RQM is 1 and DIO is 1
1265 DataInOut
= (UINT8
) (Dio
<< 6);
1267 // in order to compare bit6
1269 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1271 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1272 if ((StatusRegister
& MSR_RQM
) == MSR_RQM
&& (StatusRegister
& MSR_DIO
) == DataInOut
) {
1279 MicroSecondDelay (50);
1287 return EFI_NOT_READY
;
1289 // FDC is not ready within the specified time period
1298 IN FDD_RESULT_PACKET
*Result
,
1299 IN OUT FDC_BLK_IO_DEV
*FdcDev
1303 Routine Description:
1305 GC_TODO: Add function description
1309 Result - GC_TODO: add argument description
1310 FdcDev - GC_TODO: add argument description
1314 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1315 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1316 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1317 EFI_SUCCESS - GC_TODO: Add description for return value
1322 // Check Status Register0
1324 if ((Result
->Status0
& STS0_IC
) != IC_NT
) {
1325 if ((Result
->Status0
& STS0_SE
) == 0x20) {
1329 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1332 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1333 return EFI_DEVICE_ERROR
;
1336 // Check Status Register1
1338 if (Result
->Status1
& (STS1_EN
| STS1_DE
| STS1_OR
| STS1_ND
| STS1_NW
| STS1_MA
)) {
1339 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1340 return EFI_DEVICE_ERROR
;
1343 // Check Status Register2
1345 if (Result
->Status2
& (STS2_CM
| STS2_DD
| STS2_WC
| STS2_BC
| STS2_MD
)) {
1346 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1347 return EFI_DEVICE_ERROR
;
1355 IN UINT8 StatusRegister3
1359 Routine Description: Check the drive status information
1361 StatusRegister3 UINT8: the value of Status Register 3
1364 EFI_WRITE_PROTECTED: The disk is write protected
1367 // GC_TODO: function comment is missing 'Arguments:'
1368 // GC_TODO: StatusRegister3 - add argument and description to function comment
1370 if (StatusRegister3
& STS3_WP
) {
1371 return EFI_WRITE_PROTECTED
;
1378 GetTransferBlockCount (
1379 IN FDC_BLK_IO_DEV
*FdcDev
,
1381 IN UINTN NumberOfBlocks
1385 Routine Description: Calculate the number of block in the same cylinder
1388 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
1389 LBA EFI_LBA: The starting logic block address
1390 NumberOfBlocks UINTN: The number of blocks
1392 UINTN : The number of blocks in the same cylinder which the starting
1393 logic block address is LBA
1396 // GC_TODO: function comment is missing 'Arguments:'
1397 // GC_TODO: FdcDev - add argument and description to function comment
1398 // GC_TODO: LBA - add argument and description to function comment
1399 // GC_TODO: NumberOfBlocks - add argument and description to function comment
1403 UINT8 SectorsInTrack
;
1406 // Calculate the number of block in the same cylinder
1408 EndOfTrack
= DISK_1440K_EOT
;
1409 Head
= (UINT8
) ((UINTN
) LBA
/ EndOfTrack
% 2);
1411 SectorsInTrack
= (UINT8
) (EndOfTrack
* (2 - Head
) - (UINT8
) ((UINTN
) LBA
% EndOfTrack
));
1412 if (SectorsInTrack
< NumberOfBlocks
) {
1413 return SectorsInTrack
;
1415 return NumberOfBlocks
;
1427 Routine Description: When the Timer(2s) off, turn the drive's motor off
1429 Event EFI_EVENT: Event(the timer) whose notification function is being
1431 Context VOID *: Pointer to the notification function's context
1436 // GC_TODO: function comment is missing 'Arguments:'
1437 // GC_TODO: Event - add argument and description to function comment
1438 // GC_TODO: Context - add argument and description to function comment
1440 FDC_BLK_IO_DEV
*FdcDev
;
1443 FdcDev
= (FDC_BLK_IO_DEV
*) Context
;
1446 // Get the motor status
1448 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
1450 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) != 0x10)) ||
1451 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) != 0x21))
1456 // the motor is on, so need motor off
1459 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
1460 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
1461 MicroSecondDelay (500);
1466 IN FDC_BLK_IO_DEV
*FdcDev
,
1471 Routine Description: Read I/O port for FDC
1476 // GC_TODO: function comment is missing 'Arguments:'
1477 // GC_TODO: FdcDev - add argument and description to function comment
1478 // GC_TODO: Offset - add argument and description to function comment
1485 FdcDev
->IsaIo
->Io
.Read (
1488 FdcDev
->BaseAddress
+ Offset
,
1498 IN FDC_BLK_IO_DEV
*FdcDev
,
1504 Routine Description: Write I/O port for FDC
1509 // GC_TODO: function comment is missing 'Arguments:'
1510 // GC_TODO: FdcDev - add argument and description to function comment
1511 // GC_TODO: Offset - add argument and description to function comment
1512 // GC_TODO: Data - add argument and description to function comment
1518 FdcDev
->IsaIo
->Io
.Write (
1521 FdcDev
->BaseAddress
+ Offset
,