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
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.
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
);
123 if (Status
== EFI_NO_MEDIA
) {
124 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
125 } else if (Status
!= EFI_MEDIA_CHANGED
) {
131 // Check Disk Write Protected
133 Status
= SenseDrvStatus (FdcDev
, 0);
135 if (Status
== EFI_WRITE_PROTECTED
) {
136 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
137 } else if (Status
== EFI_SUCCESS
) {
138 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
140 return EFI_DEVICE_ERROR
;
146 // Set Media Default Type
148 FdcDev
->BlkIo
.Media
->BlockSize
= DISK_1440K_BYTEPERSECTOR
;
149 FdcDev
->BlkIo
.Media
->LastBlock
= DISK_1440K_EOT
* 2 * (DISK_1440K_MAXTRACKNUM
+ 1) - 1;
156 IN FDC_BLK_IO_DEV
*FdcDev
160 Routine Description: Reset the Floppy Logic Drive
162 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
164 EFI_SUCCESS: The Floppy Logic Drive is reset
165 EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
169 // GC_TODO: function comment is missing 'Arguments:'
170 // GC_TODO: FdcDev - add argument and description to function comment
173 UINT8 StatusRegister0
;
174 UINT8 PresentCylinderNumber
;
178 // Report reset progress code
180 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
182 EFI_PERIPHERAL_REMOVABLE_MEDIA
| EFI_P_PC_RESET
,
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
191 // bit3 : DMA and Int bit
192 // Reset : a "0" written to bit2 resets the FDC, this reset will remain
194 // a "1" is written to this bit.
196 // use bit0 & bit1 to select the logic drive
200 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
201 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
204 // wait some time,at least 120us
206 MicroSecondDelay (500);
211 // write "1" to bit3 : enable DMA
214 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
219 MicroSecondDelay (2000);
222 // wait specified floppy logic drive is not busy
224 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
225 return EFI_DEVICE_ERROR
;
228 // Set the Transfer Data Rate
230 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
235 MicroSecondDelay (100);
238 // Issue Sense interrupt command for each drive (total 4 drives)
240 for (Index
= 0; Index
< 4; Index
++) {
241 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
242 return EFI_DEVICE_ERROR
;
246 // issue Specify command
248 if (EFI_ERROR (Specify (FdcDev
))) {
249 return EFI_DEVICE_ERROR
;
257 IN FDC_BLK_IO_DEV
*FdcDev
261 Routine Description: Turn the drive's motor on
262 The drive's motor must be on before any command can be executed
264 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
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)
271 // GC_TODO: function comment is missing 'Arguments:'
272 // GC_TODO: FdcDev - add argument and description to function comment
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
290 Status
= gBS
->SetTimer (FdcDev
->Event
, TimerCancel
, 0);
292 if (EFI_ERROR (Status
)) {
293 return EFI_INVALID_PARAMETER
;
296 // Get the motor status
298 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
300 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) == 0x10)) ||
301 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) == 0x21))
306 // The drive's motor is off, so need turn it on
307 // first look at command and drive are busy or not
309 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
310 return EFI_DEVICE_ERROR
;
313 // for drive A: 1CH, drive B: 2DH
316 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
317 if (FdcDev
->Disk
== FDC_DISK0
) {
321 data
|= DRVA_MOTOR_ON
;
326 data
|= DRVB_MOTOR_ON
;
329 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
334 MicroSecondDelay (4000);
341 IN FDC_BLK_IO_DEV
*FdcDev
345 Routine Description: Set a Timer and when Timer goes off, turn the motor off
347 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
349 EFI_SUCCESS: Set the Timer successfully
350 EFI_INVALID_PARAMETER: Fail to Set the timer
353 // GC_TODO: function comment is missing 'Arguments:'
354 // GC_TODO: FdcDev - add argument and description to function comment
357 // Set the timer : 2s
359 return gBS
->SetTimer (FdcDev
->Event
, TimerRelative
, 20000000);
364 IN FDC_BLK_IO_DEV
*FdcDev
368 Routine Description: Detect the disk in the drive is changed or not
370 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
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
378 // GC_TODO: function comment is missing 'Arguments:'
379 // GC_TODO: FdcDev - add argument and description to function comment
387 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
392 MicroSecondDelay (50);
394 if ((data
& DIR_DCL
) == 0x80) {
396 // disk change line is active
398 if (FdcDev
->PresentCylinderNumber
!= 0) {
399 Status
= Recalibrate (FdcDev
);
401 Status
= Seek (FdcDev
, 0x30);
404 if (EFI_ERROR (Status
)) {
405 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
406 return EFI_DEVICE_ERROR
;
408 // Fail to do the seek or recalibrate operation
412 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
417 MicroSecondDelay (50);
419 if ((data
& DIR_DCL
) == 0x80) {
423 return EFI_MEDIA_CHANGED
;
431 IN FDC_BLK_IO_DEV
*FdcDev
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
441 EFI_SUCCESS: Execute the Specify command successfully
442 EFI_DEVICE_ERROR: Fail to execute the command
445 // GC_TODO: function comment is missing 'Arguments:'
446 // GC_TODO: FdcDev - add argument and description to function comment
448 FDD_SPECIFY_CMD Command
;
450 UINT8
*CommandPointer
;
452 ZeroMem (&Command
, sizeof (FDD_SPECIFY_CMD
));
453 Command
.CommandCode
= SPECIFY_CMD
;
457 Command
.SrtHut
= 0xdf;
463 Command
.HltNd
= 0x02;
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
;
477 IN FDC_BLK_IO_DEV
*FdcDev
481 Routine Description: Set the head of floppy drive to track 0
483 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
485 EFI_SUCCESS: Execute the Recalibrate operation successfully
486 EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
489 // GC_TODO: function comment is missing 'Arguments:'
490 // GC_TODO: FdcDev - add argument and description to function comment
492 FDD_COMMAND_PACKET2 Command
;
494 UINT8 StatusRegister0
;
495 UINT8 PresentCylinderNumber
;
496 UINT8
*CommandPointer
;
502 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
503 Command
.CommandCode
= RECALIBRATE_CMD
;
507 if (FdcDev
->Disk
== FDC_DISK0
) {
508 Command
.DiskHeadSel
= 0;
513 Command
.DiskHeadSel
= 1;
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
;
528 MicroSecondDelay (250000);
530 // need modify according to 1.44M or 2.88M
532 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
533 return EFI_DEVICE_ERROR
;
536 if ((StatusRegister0
& 0xf0) == 0x20 && PresentCylinderNumber
== 0) {
537 FdcDev
->PresentCylinderNumber
= 0;
538 FdcDev
->ControllerState
->NeedRecalibrate
= FALSE
;
543 return EFI_DEVICE_ERROR
;
555 IN FDC_BLK_IO_DEV
*FdcDev
,
560 Routine Description: Set the head of floppy drive to the new cylinder
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
565 EFI_SUCCESS: Execute the Seek operation successfully
566 EFI_DEVICE_ERROR: Fail to execute the Seek operation
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
573 FDD_SEEK_CMD Command
;
577 UINT8 StatusRegister0
;
578 UINT8
*CommandPointer
;
579 UINT8 PresentCylinderNumber
;
583 if (FdcDev
->ControllerState
->NeedRecalibrate
) {
584 if (EFI_ERROR (Recalibrate (FdcDev
))) {
585 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
586 return EFI_DEVICE_ERROR
;
590 EndOfTrack
= DISK_1440K_EOT
;
592 // Calculate cylinder based on Lba and EOT
594 Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
597 // if the destination cylinder is the present cylinder, unnecessary to do the
600 if (FdcDev
->PresentCylinderNumber
== Cylinder
) {
604 // Calculate the head : 0 or 1
606 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
608 ZeroMem (&Command
, sizeof (FDD_SEEK_CMD
));
609 Command
.CommandCode
= SEEK_CMD
;
610 if (FdcDev
->Disk
== FDC_DISK0
) {
611 Command
.DiskHeadSel
= 0;
616 Command
.DiskHeadSel
= 1;
622 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
623 Command
.NewCylinder
= Cylinder
;
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
;
634 MicroSecondDelay (100);
637 // Calculate waiting time
639 if (FdcDev
->PresentCylinderNumber
> Cylinder
) {
640 DelayTime
= (UINT8
) (FdcDev
->PresentCylinderNumber
- Cylinder
);
642 DelayTime
= (UINT8
) (Cylinder
- FdcDev
->PresentCylinderNumber
);
645 MicroSecondDelay ((DelayTime
+ 1) * 4000);
647 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
648 return EFI_DEVICE_ERROR
;
651 if ((StatusRegister0
& 0xf0) == 0x20) {
652 FdcDev
->PresentCylinderNumber
= Command
.NewCylinder
;
655 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
656 return EFI_DEVICE_ERROR
;
662 IN FDC_BLK_IO_DEV
*FdcDev
,
663 IN OUT UINT8
*StatusRegister0
,
664 IN OUT UINT8
*PresentCylinderNumber
668 Routine Description: Do the Sense Interrupt Status command, this command
669 resets the interrupt signal
671 StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
672 PresentCylinderNumber UINT8 *: Be used to save present cylinder number
675 EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
676 EFI_DEVICE_ERROR: Fail to execute the command
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
686 command
= SENSE_INT_STATUS_CMD
;
687 if (EFI_ERROR (DataOutByte (FdcDev
, &command
))) {
688 return EFI_DEVICE_ERROR
;
691 if (EFI_ERROR (DataInByte (FdcDev
, StatusRegister0
))) {
692 return EFI_DEVICE_ERROR
;
695 if (EFI_ERROR (DataInByte (FdcDev
, PresentCylinderNumber
))) {
696 return EFI_DEVICE_ERROR
;
704 IN FDC_BLK_IO_DEV
*FdcDev
,
709 Routine Description: Do the Sense Drive Status command
711 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
712 Lba EFI_LBA : Logic block address
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
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
723 FDD_COMMAND_PACKET2 Command
;
727 UINT8 StatusRegister3
;
728 UINT8
*CommandPointer
;
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
735 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
736 Command
.CommandCode
= SENSE_DRV_STATUS_CMD
;
738 if (FdcDev
->Disk
== FDC_DISK0
) {
739 Command
.DiskHeadSel
= 0;
741 Command
.DiskHeadSel
= 1;
744 EndOfTrack
= DISK_1440K_EOT
;
745 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
746 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
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
;
755 if (EFI_ERROR (DataInByte (FdcDev
, &StatusRegister3
))) {
756 return EFI_DEVICE_ERROR
;
761 MicroSecondDelay (50);
764 // Check Status Register 3 to get drive status information
766 return CheckStatus3 (StatusRegister3
);
771 IN FDC_BLK_IO_DEV
*FdcDev
775 Routine Description: Update the disk media properties and if necessary
776 reinstall Block I/O interface
778 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
780 EFI_SUCCESS: Do the operation successfully
781 EFI_DEVICE_ERROR: Fail to the operation
784 // GC_TODO: function comment is missing 'Arguments:'
785 // GC_TODO: FdcDev - add argument and description to function comment
789 BOOLEAN bReadOnlyLastTime
;
790 BOOLEAN bMediaPresentLastTime
;
793 bReadOnlyLastTime
= FdcDev
->BlkIo
.Media
->ReadOnly
;
794 bMediaPresentLastTime
= FdcDev
->BlkIo
.Media
->MediaPresent
;
799 Status
= DisketChanged (FdcDev
);
801 if (Status
== EFI_MEDIA_CHANGED
) {
802 FdcDev
->BlkIo
.Media
->MediaId
++;
803 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
805 } else if (Status
== EFI_NO_MEDIA
) {
806 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
807 } else if (Status
!= EFI_SUCCESS
) {
815 if (FdcDev
->BlkIo
.Media
->MediaPresent
) {
817 // Check disk write protected
819 Status
= SenseDrvStatus (FdcDev
, 0);
820 if (Status
== EFI_WRITE_PROTECTED
) {
821 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
823 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
827 if (FdcDev
->BlkIo
.Media
->MediaPresent
&& (bReadOnlyLastTime
!= FdcDev
->BlkIo
.Media
->ReadOnly
)) {
831 if (bMediaPresentLastTime
!= FdcDev
->BlkIo
.Media
->MediaPresent
) {
836 Status
= gBS
->ReinstallProtocolInterface (
838 &gEfiBlockIoProtocolGuid
,
843 if (EFI_ERROR (Status
)) {
853 IN FDC_BLK_IO_DEV
*FdcDev
857 Routine Description: Set the data rate and so on
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
871 // Set data rate 500kbs
873 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
878 MicroSecondDelay (50);
880 Status
= Specify (FdcDev
);
882 if (EFI_ERROR (Status
)) {
883 return EFI_DEVICE_ERROR
;
890 ReadWriteDataSector (
891 IN FDC_BLK_IO_DEV
*FdcDev
,
892 IN VOID
*HostAddress
,
894 IN UINTN NumberOfBlocks
,
899 Routine Description: Read or Write a number of blocks in the same cylinder
901 FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV
904 NumberOfBlocks UINTN:
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
923 FDD_COMMAND_PACKET1 Command
;
924 FDD_RESULT_PACKET Result
;
927 UINT8
*CommandPointer
;
929 EFI_PHYSICAL_ADDRESS DeviceAddress
;
930 EFI_ISA_IO_PROTOCOL
*IsaIo
;
933 EFI_ISA_IO_PROTOCOL_OPERATION Operation
;
936 EFI_ISA_ACPI_RESOURCE
*ResourceItem
;
939 Status
= Seek (FdcDev
, Lba
);
940 if (EFI_ERROR (Status
)) {
941 return EFI_DEVICE_ERROR
;
946 IsaIo
= FdcDev
->IsaIo
;
947 NumberofBytes
= NumberOfBlocks
* 512;
949 Operation
= EfiIsaIoOperationSlaveWrite
;
951 Operation
= EfiIsaIoOperationSlaveRead
;
954 ResourceItem
= IsaIo
->ResourceList
->ResourceItem
;
956 while (ResourceItem
[Index
].Type
!= EfiIsaAcpiResourceEndOfList
) {
957 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceDma
) {
964 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceEndOfList
) {
965 return EFI_DEVICE_ERROR
;
968 Channel
= (UINT8
) IsaIo
->ResourceList
->ResourceItem
[Index
].StartRange
;
969 Attribute
= IsaIo
->ResourceList
->ResourceItem
[Index
].Attribute
;
971 Status1
= IsaIo
->Map (
981 if (EFI_ERROR (Status1
)) {
986 // Allocate Read or Write command packet
988 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET1
));
990 Command
.CommandCode
= READ_DATA_CMD
| CMD_MT
| CMD_MFM
| CMD_SK
;
992 Command
.CommandCode
= WRITE_DATA_CMD
| CMD_MT
| CMD_MFM
;
995 FillPara (FdcDev
, Lba
, &Command
);
998 // Write command bytes to FDC
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
;
1007 // wait for some time
1009 Times
= (STALL_1_SECOND
/ 50) + 1;
1011 if ((FdcReadPort (FdcDev
, FDC_REGISTER_MSR
) & 0xc0) == 0xc0) {
1015 MicroSecondDelay (50);
1023 // Read result bytes from FDC
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
;
1032 // Flush before Unmap
1035 Status1
= IsaIo
->Flush (IsaIo
);
1036 if (EFI_ERROR (Status1
)) {
1043 Status1
= IsaIo
->Unmap (IsaIo
, Mapping
);
1044 if (EFI_ERROR (Status1
)) {
1048 return CheckResult (&Result
, FdcDev
);
1053 IN FDC_BLK_IO_DEV
*FdcDev
,
1055 IN FDD_COMMAND_PACKET1
*Command
1059 Routine Description: Fill in Parameter
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
1072 // Get EndOfTrack from the Para table
1074 EndOfTrack
= DISK_1440K_EOT
;
1077 // Fill the command parameter
1079 if (FdcDev
->Disk
== FDC_DISK0
) {
1080 Command
->DiskHeadSel
= 0;
1082 Command
->DiskHeadSel
= 1;
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
;
1097 IN FDC_BLK_IO_DEV
*FdcDev
,
1098 IN OUT UINT8
*Pointer
1102 Routine Description: Read result byte from Data Register of FDC
1104 Pointer UINT8 *: Be used to save result byte read from FDC
1106 EFI_SUCCESS: Read result byte from FDC successfully
1107 EFI_DEVICE_ERROR: The FDC is not ready to be read
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
1117 // wait for 1ms and detect the FDC is ready to be read
1119 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_IN
, 1))) {
1120 return EFI_DEVICE_ERROR
;
1126 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DTR
);
1131 MicroSecondDelay (50);
1139 IN FDC_BLK_IO_DEV
*FdcDev
,
1144 Routine Description: Write command byte to Data Register of FDC
1146 Pointer UINT8 *: Be used to save command byte written to FDC
1148 EFI_SUCCESS: Write command byte to FDC successfully
1149 EFI_DEVICE_ERROR: The FDC is not ready to be written
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
1159 // wait for 1ms and detect the FDC is ready to be written
1161 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_OUT
, 1))) {
1162 return EFI_DEVICE_ERROR
;
1170 FdcWritePort (FdcDev
, FDC_REGISTER_DTR
, data
);
1175 MicroSecondDelay (50);
1181 FddWaitForBSYClear (
1182 IN FDC_BLK_IO_DEV
*FdcDev
,
1183 IN UINTN TimeoutInSeconds
1187 Routine Description: Detect the specified floppy logic drive is busy or
1188 not within a period of time
1190 Disk EFI_FDC_DISK: Indicate it is drive A or drive B
1191 TimeoutInSeconds UINTN: the time period for waiting
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
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
1203 UINT8 StatusRegister
;
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
1214 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
1216 Mask
= (UINT8
) ((FdcDev
->Disk
== FDC_DISK0
? MSR_DAB
: MSR_DBB
) | MSR_CB
);
1218 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1220 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1221 if ((StatusRegister
& Mask
) == 0x00) {
1228 MicroSecondDelay (50);
1241 IN FDC_BLK_IO_DEV
*FdcDev
,
1243 IN UINTN TimeoutInSeconds
1247 Routine Description: Determine whether FDC is ready to write or read
1249 Dio BOOLEAN: Indicate the FDC is waiting to write or read
1250 TimeoutInSeconds UINTN: The time period for waiting
1252 EFI_SUCCESS: FDC is ready to write or read
1253 EFI_NOT_READY: FDC is not ready within the specified time period
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
1262 UINT8 StatusRegister
;
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.
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
1274 DataInOut
= (UINT8
) (Dio
<< 6);
1276 // in order to compare bit6
1278 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1280 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1281 if ((StatusRegister
& MSR_RQM
) == MSR_RQM
&& (StatusRegister
& MSR_DIO
) == DataInOut
) {
1288 MicroSecondDelay (50);
1296 return EFI_NOT_READY
;
1298 // FDC is not ready within the specified time period
1307 IN FDD_RESULT_PACKET
*Result
,
1308 IN OUT FDC_BLK_IO_DEV
*FdcDev
1312 Routine Description:
1314 GC_TODO: Add function description
1318 Result - GC_TODO: add argument description
1319 FdcDev - GC_TODO: add argument description
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
1331 // Check Status Register0
1333 if ((Result
->Status0
& STS0_IC
) != IC_NT
) {
1334 if ((Result
->Status0
& STS0_SE
) == 0x20) {
1338 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1341 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1342 return EFI_DEVICE_ERROR
;
1345 // Check Status Register1
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
;
1352 // Check Status Register2
1354 if (Result
->Status2
& (STS2_CM
| STS2_DD
| STS2_WC
| STS2_BC
| STS2_MD
)) {
1355 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1356 return EFI_DEVICE_ERROR
;
1364 IN UINT8 StatusRegister3
1368 Routine Description: Check the drive status information
1370 StatusRegister3 UINT8: the value of Status Register 3
1373 EFI_WRITE_PROTECTED: The disk is write protected
1376 // GC_TODO: function comment is missing 'Arguments:'
1377 // GC_TODO: StatusRegister3 - add argument and description to function comment
1379 if (StatusRegister3
& STS3_WP
) {
1380 return EFI_WRITE_PROTECTED
;
1387 GetTransferBlockCount (
1388 IN FDC_BLK_IO_DEV
*FdcDev
,
1390 IN UINTN NumberOfBlocks
1394 Routine Description: Calculate the number of block in the same cylinder
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
1401 UINTN : The number of blocks in the same cylinder which the starting
1402 logic block address is LBA
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
1412 UINT8 SectorsInTrack
;
1415 // Calculate the number of block in the same cylinder
1417 EndOfTrack
= DISK_1440K_EOT
;
1418 Head
= (UINT8
) ((UINTN
) LBA
/ EndOfTrack
% 2);
1420 SectorsInTrack
= (UINT8
) (EndOfTrack
* (2 - Head
) - (UINT8
) ((UINTN
) LBA
% EndOfTrack
));
1421 if (SectorsInTrack
< NumberOfBlocks
) {
1422 return SectorsInTrack
;
1424 return NumberOfBlocks
;
1436 Routine Description: When the Timer(2s) off, turn the drive's motor off
1438 Event EFI_EVENT: Event(the timer) whose notification function is being
1440 Context VOID *: Pointer to the notification function's context
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
1449 FDC_BLK_IO_DEV
*FdcDev
;
1452 FdcDev
= (FDC_BLK_IO_DEV
*) Context
;
1455 // Get the motor status
1457 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
1459 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) != 0x10)) ||
1460 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) != 0x21))
1465 // the motor is on, so need motor off
1468 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
1469 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
1470 MicroSecondDelay (500);
1475 IN FDC_BLK_IO_DEV
*FdcDev
,
1480 Routine Description: Read I/O port for FDC
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
1494 FdcDev
->IsaIo
->Io
.Read (
1497 FdcDev
->BaseAddress
+ Offset
,
1507 IN FDC_BLK_IO_DEV
*FdcDev
,
1513 Routine Description: Write I/O port for FDC
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
1527 FdcDev
->IsaIo
->Io
.Write (
1530 FdcDev
->BaseAddress
+ Offset
,