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
) &&
117 (Status
!= EFI_SUCCESS
)) {
123 // Check Disk Write Protected
125 Status
= SenseDrvStatus (FdcDev
, 0);
127 if (Status
== EFI_WRITE_PROTECTED
) {
128 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
129 } else if (Status
== EFI_SUCCESS
) {
130 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
132 return EFI_DEVICE_ERROR
;
138 // Set Media Default Type
140 FdcDev
->BlkIo
.Media
->BlockSize
= DISK_1440K_BYTEPERSECTOR
;
141 FdcDev
->BlkIo
.Media
->LastBlock
= DISK_1440K_EOT
* 2 * (DISK_1440K_MAXTRACKNUM
+ 1) - 1;
148 IN FDC_BLK_IO_DEV
*FdcDev
152 Routine Description: Reset the Floppy Logic Drive
154 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
156 EFI_SUCCESS: The Floppy Logic Drive is reset
157 EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
161 // GC_TODO: function comment is missing 'Arguments:'
162 // GC_TODO: FdcDev - add argument and description to function comment
165 UINT8 StatusRegister0
;
166 UINT8 PresentCylinderNumber
;
170 // Report reset progress code
172 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
174 EFI_PERIPHERAL_REMOVABLE_MEDIA
| EFI_P_PC_RESET
,
179 // Reset specified Floppy Logic Drive according to FdcDev -> Disk
180 // Set Digital Output Register(DOR) to do reset work
181 // bit0 & bit1 of DOR : Drive Select
183 // bit3 : DMA and Int bit
184 // Reset : a "0" written to bit2 resets the FDC, this reset will remain
186 // a "1" is written to this bit.
188 // use bit0 & bit1 to select the logic drive
192 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
193 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
196 // wait some time,at least 120us
198 MicroSecondDelay (500);
203 // write "1" to bit3 : enable DMA
206 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
211 MicroSecondDelay (2000);
214 // wait specified floppy logic drive is not busy
216 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
217 return EFI_DEVICE_ERROR
;
220 // Set the Transfer Data Rate
222 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
227 MicroSecondDelay (100);
230 // Issue Sense interrupt command for each drive (total 4 drives)
232 for (Index
= 0; Index
< 4; Index
++) {
233 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
234 return EFI_DEVICE_ERROR
;
238 // issue Specify command
240 if (EFI_ERROR (Specify (FdcDev
))) {
241 return EFI_DEVICE_ERROR
;
249 IN FDC_BLK_IO_DEV
*FdcDev
253 Routine Description: Turn the drive's motor on
254 The drive's motor must be on before any command can be executed
256 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
258 EFI_SUCCESS: Turn the drive's motor on successfully
259 EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on
260 EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)
263 // GC_TODO: function comment is missing 'Arguments:'
264 // GC_TODO: FdcDev - add argument and description to function comment
270 // Control of the floppy drive motors is a big pain. If motor is off, you have
271 // to turn it on first. But you can not leave the motor on all the time, since
272 // that would wear out the disk. On the other hand, if you turn the motor off
273 // after each operation, the system performance will be awful. The compromise
274 // used in this driver is to leave the motor on for 2 seconds after
275 // each operation. If a new operation is started in that interval(2s),
276 // the motor need not be turned on again. If no new operation is started,
277 // a timer goes off and the motor is turned off
282 Status
= gBS
->SetTimer (FdcDev
->Event
, TimerCancel
, 0);
284 if (EFI_ERROR (Status
)) {
285 return EFI_INVALID_PARAMETER
;
288 // Get the motor status
290 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
292 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) == 0x10)) ||
293 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) == 0x21))
298 // The drive's motor is off, so need turn it on
299 // first look at command and drive are busy or not
301 if (EFI_ERROR (FddWaitForBSYClear (FdcDev
, 1))) {
302 return EFI_DEVICE_ERROR
;
305 // for drive A: 1CH, drive B: 2DH
308 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
309 if (FdcDev
->Disk
== FDC_DISK0
) {
313 data
|= DRVA_MOTOR_ON
;
318 data
|= DRVB_MOTOR_ON
;
321 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
326 MicroSecondDelay (4000);
333 IN FDC_BLK_IO_DEV
*FdcDev
337 Routine Description: Set a Timer and when Timer goes off, turn the motor off
339 FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
341 EFI_SUCCESS: Set the Timer successfully
342 EFI_INVALID_PARAMETER: Fail to Set the timer
345 // GC_TODO: function comment is missing 'Arguments:'
346 // GC_TODO: FdcDev - add argument and description to function comment
349 // Set the timer : 2s
351 return gBS
->SetTimer (FdcDev
->Event
, TimerRelative
, 20000000);
356 IN FDC_BLK_IO_DEV
*FdcDev
360 Routine Description: Detect the disk in the drive is changed or not
362 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
364 EFI_SUCCESS: No disk media change
365 EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation
366 EFI_NO_MEDIA: No disk in the drive
367 EFI_MEDIA_CHANGED: There is a new disk in the drive
370 // GC_TODO: function comment is missing 'Arguments:'
371 // GC_TODO: FdcDev - add argument and description to function comment
379 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
384 MicroSecondDelay (50);
386 if ((data
& DIR_DCL
) == 0x80) {
388 // disk change line is active
390 if (FdcDev
->PresentCylinderNumber
!= 0) {
391 Status
= Recalibrate (FdcDev
);
393 Status
= Seek (FdcDev
, 0x30);
396 if (EFI_ERROR (Status
)) {
397 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
398 return EFI_DEVICE_ERROR
;
400 // Fail to do the seek or recalibrate operation
404 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DIR
);
409 MicroSecondDelay (50);
411 if ((data
& DIR_DCL
) == 0x80) {
415 return EFI_MEDIA_CHANGED
;
423 IN FDC_BLK_IO_DEV
*FdcDev
427 Routine Description: Do the Specify command, this command sets DMA operation
428 and the initial values for each of the three internal
429 times: HUT, SRT and HLT
433 EFI_SUCCESS: Execute the Specify command successfully
434 EFI_DEVICE_ERROR: Fail to execute the command
437 // GC_TODO: function comment is missing 'Arguments:'
438 // GC_TODO: FdcDev - add argument and description to function comment
440 FDD_SPECIFY_CMD Command
;
442 UINT8
*CommandPointer
;
444 ZeroMem (&Command
, sizeof (FDD_SPECIFY_CMD
));
445 Command
.CommandCode
= SPECIFY_CMD
;
449 Command
.SrtHut
= 0xdf;
455 Command
.HltNd
= 0x02;
457 CommandPointer
= (UINT8
*) (&Command
);
458 for (Index
= 0; Index
< sizeof (FDD_SPECIFY_CMD
); Index
++) {
459 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
460 return EFI_DEVICE_ERROR
;
469 IN FDC_BLK_IO_DEV
*FdcDev
473 Routine Description: Set the head of floppy drive to track 0
475 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
477 EFI_SUCCESS: Execute the Recalibrate operation successfully
478 EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
481 // GC_TODO: function comment is missing 'Arguments:'
482 // GC_TODO: FdcDev - add argument and description to function comment
484 FDD_COMMAND_PACKET2 Command
;
486 UINT8 StatusRegister0
;
487 UINT8 PresentCylinderNumber
;
488 UINT8
*CommandPointer
;
494 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
495 Command
.CommandCode
= RECALIBRATE_CMD
;
499 if (FdcDev
->Disk
== FDC_DISK0
) {
500 Command
.DiskHeadSel
= 0;
505 Command
.DiskHeadSel
= 1;
511 CommandPointer
= (UINT8
*) (&Command
);
512 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
513 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
514 return EFI_DEVICE_ERROR
;
520 MicroSecondDelay (250000);
522 // need modify according to 1.44M or 2.88M
524 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
525 return EFI_DEVICE_ERROR
;
528 if ((StatusRegister0
& 0xf0) == 0x20 && PresentCylinderNumber
== 0) {
529 FdcDev
->PresentCylinderNumber
= 0;
530 FdcDev
->ControllerState
->NeedRecalibrate
= FALSE
;
535 return EFI_DEVICE_ERROR
;
547 IN FDC_BLK_IO_DEV
*FdcDev
,
552 Routine Description: Set the head of floppy drive to the new cylinder
554 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
555 Lba EFI_LBA : The logic block address want to seek
557 EFI_SUCCESS: Execute the Seek operation successfully
558 EFI_DEVICE_ERROR: Fail to execute the Seek operation
561 // GC_TODO: function comment is missing 'Arguments:'
562 // GC_TODO: FdcDev - add argument and description to function comment
563 // GC_TODO: Lba - add argument and description to function comment
565 FDD_SEEK_CMD Command
;
569 UINT8 StatusRegister0
;
570 UINT8
*CommandPointer
;
571 UINT8 PresentCylinderNumber
;
575 if (FdcDev
->ControllerState
->NeedRecalibrate
) {
576 if (EFI_ERROR (Recalibrate (FdcDev
))) {
577 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
578 return EFI_DEVICE_ERROR
;
582 EndOfTrack
= DISK_1440K_EOT
;
584 // Calculate cylinder based on Lba and EOT
586 Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
589 // if the destination cylinder is the present cylinder, unnecessary to do the
592 if (FdcDev
->PresentCylinderNumber
== Cylinder
) {
596 // Calculate the head : 0 or 1
598 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
600 ZeroMem (&Command
, sizeof (FDD_SEEK_CMD
));
601 Command
.CommandCode
= SEEK_CMD
;
602 if (FdcDev
->Disk
== FDC_DISK0
) {
603 Command
.DiskHeadSel
= 0;
608 Command
.DiskHeadSel
= 1;
614 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
615 Command
.NewCylinder
= Cylinder
;
617 CommandPointer
= (UINT8
*) (&Command
);
618 for (Index
= 0; Index
< sizeof (FDD_SEEK_CMD
); Index
++) {
619 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
620 return EFI_DEVICE_ERROR
;
626 MicroSecondDelay (100);
629 // Calculate waiting time
631 if (FdcDev
->PresentCylinderNumber
> Cylinder
) {
632 DelayTime
= (UINT8
) (FdcDev
->PresentCylinderNumber
- Cylinder
);
634 DelayTime
= (UINT8
) (Cylinder
- FdcDev
->PresentCylinderNumber
);
637 MicroSecondDelay ((DelayTime
+ 1) * 4000);
639 if (EFI_ERROR (SenseIntStatus (FdcDev
, &StatusRegister0
, &PresentCylinderNumber
))) {
640 return EFI_DEVICE_ERROR
;
643 if ((StatusRegister0
& 0xf0) == 0x20) {
644 FdcDev
->PresentCylinderNumber
= Command
.NewCylinder
;
647 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
648 return EFI_DEVICE_ERROR
;
654 IN FDC_BLK_IO_DEV
*FdcDev
,
655 IN OUT UINT8
*StatusRegister0
,
656 IN OUT UINT8
*PresentCylinderNumber
660 Routine Description: Do the Sense Interrupt Status command, this command
661 resets the interrupt signal
663 StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
664 PresentCylinderNumber UINT8 *: Be used to save present cylinder number
667 EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
668 EFI_DEVICE_ERROR: Fail to execute the command
671 // GC_TODO: function comment is missing 'Arguments:'
672 // GC_TODO: FdcDev - add argument and description to function comment
673 // GC_TODO: StatusRegister0 - add argument and description to function comment
674 // GC_TODO: PresentCylinderNumber - add argument and description to function comment
678 command
= SENSE_INT_STATUS_CMD
;
679 if (EFI_ERROR (DataOutByte (FdcDev
, &command
))) {
680 return EFI_DEVICE_ERROR
;
683 if (EFI_ERROR (DataInByte (FdcDev
, StatusRegister0
))) {
684 return EFI_DEVICE_ERROR
;
687 if (EFI_ERROR (DataInByte (FdcDev
, PresentCylinderNumber
))) {
688 return EFI_DEVICE_ERROR
;
696 IN FDC_BLK_IO_DEV
*FdcDev
,
701 Routine Description: Do the Sense Drive Status command
703 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
704 Lba EFI_LBA : Logic block address
706 EFI_SUCCESS: Execute the Sense Drive Status command successfully
707 EFI_DEVICE_ERROR: Fail to execute the command
708 EFI_WRITE_PROTECTED:The disk is write protected
711 // GC_TODO: function comment is missing 'Arguments:'
712 // GC_TODO: FdcDev - add argument and description to function comment
713 // GC_TODO: Lba - add argument and description to function comment
715 FDD_COMMAND_PACKET2 Command
;
719 UINT8 StatusRegister3
;
720 UINT8
*CommandPointer
;
723 // Sense Drive Status command obtains drive status information,
724 // it has not execution phase and goes directly to the result phase from the
725 // command phase, Status Register 3 contains the drive status information
727 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET2
));
728 Command
.CommandCode
= SENSE_DRV_STATUS_CMD
;
730 if (FdcDev
->Disk
== FDC_DISK0
) {
731 Command
.DiskHeadSel
= 0;
733 Command
.DiskHeadSel
= 1;
736 EndOfTrack
= DISK_1440K_EOT
;
737 Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
738 Command
.DiskHeadSel
= (UINT8
) (Command
.DiskHeadSel
| (Head
<< 2));
740 CommandPointer
= (UINT8
*) (&Command
);
741 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET2
); Index
++) {
742 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
743 return EFI_DEVICE_ERROR
;
747 if (EFI_ERROR (DataInByte (FdcDev
, &StatusRegister3
))) {
748 return EFI_DEVICE_ERROR
;
753 MicroSecondDelay (50);
756 // Check Status Register 3 to get drive status information
758 return CheckStatus3 (StatusRegister3
);
763 IN FDC_BLK_IO_DEV
*FdcDev
767 Routine Description: Update the disk media properties and if necessary
768 reinstall Block I/O interface
770 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
772 EFI_SUCCESS: Do the operation successfully
773 EFI_DEVICE_ERROR: Fail to the operation
776 // GC_TODO: function comment is missing 'Arguments:'
777 // GC_TODO: FdcDev - add argument and description to function comment
781 BOOLEAN bReadOnlyLastTime
;
782 BOOLEAN bMediaPresentLastTime
;
785 bReadOnlyLastTime
= FdcDev
->BlkIo
.Media
->ReadOnly
;
786 bMediaPresentLastTime
= FdcDev
->BlkIo
.Media
->MediaPresent
;
791 Status
= DisketChanged (FdcDev
);
793 if (Status
== EFI_MEDIA_CHANGED
) {
794 FdcDev
->BlkIo
.Media
->MediaId
++;
795 FdcDev
->BlkIo
.Media
->MediaPresent
= TRUE
;
797 } else if (Status
== EFI_NO_MEDIA
) {
798 FdcDev
->BlkIo
.Media
->MediaPresent
= FALSE
;
799 } else if (Status
!= EFI_SUCCESS
) {
807 if (FdcDev
->BlkIo
.Media
->MediaPresent
) {
809 // Check disk write protected
811 Status
= SenseDrvStatus (FdcDev
, 0);
812 if (Status
== EFI_WRITE_PROTECTED
) {
813 FdcDev
->BlkIo
.Media
->ReadOnly
= TRUE
;
815 FdcDev
->BlkIo
.Media
->ReadOnly
= FALSE
;
819 if (FdcDev
->BlkIo
.Media
->MediaPresent
&& (bReadOnlyLastTime
!= FdcDev
->BlkIo
.Media
->ReadOnly
)) {
823 if (bMediaPresentLastTime
!= FdcDev
->BlkIo
.Media
->MediaPresent
) {
828 Status
= gBS
->ReinstallProtocolInterface (
830 &gEfiBlockIoProtocolGuid
,
835 if (EFI_ERROR (Status
)) {
845 IN FDC_BLK_IO_DEV
*FdcDev
849 Routine Description: Set the data rate and so on
856 // GC_TODO: function comment is missing 'Arguments:'
857 // GC_TODO: FdcDev - add argument and description to function comment
858 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
863 // Set data rate 500kbs
865 FdcWritePort (FdcDev
, FDC_REGISTER_CCR
, 0x0);
870 MicroSecondDelay (50);
872 Status
= Specify (FdcDev
);
874 if (EFI_ERROR (Status
)) {
875 return EFI_DEVICE_ERROR
;
882 ReadWriteDataSector (
883 IN FDC_BLK_IO_DEV
*FdcDev
,
884 IN VOID
*HostAddress
,
886 IN UINTN NumberOfBlocks
,
891 Routine Description: Read or Write a number of blocks in the same cylinder
893 FdcDev FDC_BLK_IO_DEV * : A pointer to Data Structure FDC_BLK_IO_DEV
896 NumberOfBlocks UINTN:
902 // GC_TODO: function comment is missing 'Arguments:'
903 // GC_TODO: FdcDev - add argument and description to function comment
904 // GC_TODO: HostAddress - add argument and description to function comment
905 // GC_TODO: Lba - add argument and description to function comment
906 // GC_TODO: NumberOfBlocks - add argument and description to function comment
907 // GC_TODO: Read - add argument and description 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_DEVICE_ERROR - add return value to function comment
911 // GC_TODO: EFI_TIMEOUT - add return value to function comment
912 // GC_TODO: EFI_DEVICE_ERROR - add return value to function comment
915 FDD_COMMAND_PACKET1 Command
;
916 FDD_RESULT_PACKET Result
;
919 UINT8
*CommandPointer
;
921 EFI_PHYSICAL_ADDRESS DeviceAddress
;
922 EFI_ISA_IO_PROTOCOL
*IsaIo
;
925 EFI_ISA_IO_PROTOCOL_OPERATION Operation
;
928 EFI_ISA_ACPI_RESOURCE
*ResourceItem
;
931 Status
= Seek (FdcDev
, Lba
);
932 if (EFI_ERROR (Status
)) {
933 return EFI_DEVICE_ERROR
;
938 IsaIo
= FdcDev
->IsaIo
;
939 NumberofBytes
= NumberOfBlocks
* 512;
941 Operation
= EfiIsaIoOperationSlaveWrite
;
943 Operation
= EfiIsaIoOperationSlaveRead
;
946 ResourceItem
= IsaIo
->ResourceList
->ResourceItem
;
948 while (ResourceItem
[Index
].Type
!= EfiIsaAcpiResourceEndOfList
) {
949 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceDma
) {
956 if (ResourceItem
[Index
].Type
== EfiIsaAcpiResourceEndOfList
) {
957 return EFI_DEVICE_ERROR
;
960 Channel
= (UINT8
) IsaIo
->ResourceList
->ResourceItem
[Index
].StartRange
;
961 Attribute
= IsaIo
->ResourceList
->ResourceItem
[Index
].Attribute
;
963 Status1
= IsaIo
->Map (
973 if (EFI_ERROR (Status1
)) {
978 // Allocate Read or Write command packet
980 ZeroMem (&Command
, sizeof (FDD_COMMAND_PACKET1
));
982 Command
.CommandCode
= READ_DATA_CMD
| CMD_MT
| CMD_MFM
| CMD_SK
;
984 Command
.CommandCode
= WRITE_DATA_CMD
| CMD_MT
| CMD_MFM
;
987 FillPara (FdcDev
, Lba
, &Command
);
990 // Write command bytes to FDC
992 CommandPointer
= (UINT8
*) (&Command
);
993 for (Index
= 0; Index
< sizeof (FDD_COMMAND_PACKET1
); Index
++) {
994 if (EFI_ERROR (DataOutByte (FdcDev
, CommandPointer
++))) {
995 return EFI_DEVICE_ERROR
;
999 // wait for some time
1001 Times
= (STALL_1_SECOND
/ 50) + 1;
1003 if ((FdcReadPort (FdcDev
, FDC_REGISTER_MSR
) & 0xc0) == 0xc0) {
1007 MicroSecondDelay (50);
1015 // Read result bytes from FDC
1017 CommandPointer
= (UINT8
*) (&Result
);
1018 for (Index
= 0; Index
< sizeof (FDD_RESULT_PACKET
); Index
++) {
1019 if (EFI_ERROR (DataInByte (FdcDev
, CommandPointer
++))) {
1020 return EFI_DEVICE_ERROR
;
1024 // Flush before Unmap
1027 Status1
= IsaIo
->Flush (IsaIo
);
1028 if (EFI_ERROR (Status1
)) {
1035 Status1
= IsaIo
->Unmap (IsaIo
, Mapping
);
1036 if (EFI_ERROR (Status1
)) {
1040 return CheckResult (&Result
, FdcDev
);
1045 IN FDC_BLK_IO_DEV
*FdcDev
,
1047 IN FDD_COMMAND_PACKET1
*Command
1051 Routine Description: Fill in Parameter
1056 // GC_TODO: function comment is missing 'Arguments:'
1057 // GC_TODO: FdcDev - add argument and description to function comment
1058 // GC_TODO: Lba - add argument and description to function comment
1059 // GC_TODO: Command - add argument and description to function comment
1064 // Get EndOfTrack from the Para table
1066 EndOfTrack
= DISK_1440K_EOT
;
1069 // Fill the command parameter
1071 if (FdcDev
->Disk
== FDC_DISK0
) {
1072 Command
->DiskHeadSel
= 0;
1074 Command
->DiskHeadSel
= 1;
1077 Command
->Cylinder
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
/ 2);
1078 Command
->Head
= (UINT8
) ((UINTN
) Lba
/ EndOfTrack
% 2);
1079 Command
->Sector
= (UINT8
) ((UINT8
) ((UINTN
) Lba
% EndOfTrack
) + 1);
1080 Command
->DiskHeadSel
= (UINT8
) (Command
->DiskHeadSel
| (Command
->Head
<< 2));
1081 Command
->Number
= DISK_1440K_NUMBER
;
1082 Command
->EndOfTrack
= DISK_1440K_EOT
;
1083 Command
->GapLength
= DISK_1440K_GPL
;
1084 Command
->DataLength
= DISK_1440K_DTL
;
1089 IN FDC_BLK_IO_DEV
*FdcDev
,
1090 IN OUT UINT8
*Pointer
1094 Routine Description: Read result byte from Data Register of FDC
1096 Pointer UINT8 *: Be used to save result byte read from FDC
1098 EFI_SUCCESS: Read result byte from FDC successfully
1099 EFI_DEVICE_ERROR: The FDC is not ready to be read
1102 // GC_TODO: function comment is missing 'Arguments:'
1103 // GC_TODO: FdcDev - add argument and description to function comment
1104 // GC_TODO: Pointer - add argument and description to function comment
1109 // wait for 1ms and detect the FDC is ready to be read
1111 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_IN
, 1))) {
1112 return EFI_DEVICE_ERROR
;
1118 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DTR
);
1123 MicroSecondDelay (50);
1131 IN FDC_BLK_IO_DEV
*FdcDev
,
1136 Routine Description: Write command byte to Data Register of FDC
1138 Pointer UINT8 *: Be used to save command byte written to FDC
1140 EFI_SUCCESS: Write command byte to FDC successfully
1141 EFI_DEVICE_ERROR: The FDC is not ready to be written
1144 // GC_TODO: function comment is missing 'Arguments:'
1145 // GC_TODO: FdcDev - add argument and description to function comment
1146 // GC_TODO: Pointer - add argument and description to function comment
1151 // wait for 1ms and detect the FDC is ready to be written
1153 if (EFI_ERROR (FddDRQReady (FdcDev
, DATA_OUT
, 1))) {
1154 return EFI_DEVICE_ERROR
;
1162 FdcWritePort (FdcDev
, FDC_REGISTER_DTR
, data
);
1167 MicroSecondDelay (50);
1173 FddWaitForBSYClear (
1174 IN FDC_BLK_IO_DEV
*FdcDev
,
1175 IN UINTN TimeoutInSeconds
1179 Routine Description: Detect the specified floppy logic drive is busy or
1180 not within a period of time
1182 Disk EFI_FDC_DISK: Indicate it is drive A or drive B
1183 TimeoutInSeconds UINTN: the time period for waiting
1185 EFI_SUCCESS: The drive and command are not busy
1186 EFI_TIMEOUT: The drive or command is still busy after a period time that
1187 set by TimeoutInSeconds
1190 // GC_TODO: function comment is missing 'Arguments:'
1191 // GC_TODO: FdcDev - add argument and description to function comment
1192 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1195 UINT8 StatusRegister
;
1199 // How to determine drive and command are busy or not: by the bits of
1200 // Main Status Register
1201 // bit0: Drive 0 busy (drive A)
1202 // bit1: Drive 1 busy (drive B)
1203 // bit4: Command busy
1206 // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
1208 Mask
= (UINT8
) ((FdcDev
->Disk
== FDC_DISK0
? MSR_DAB
: MSR_DBB
) | MSR_CB
);
1210 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1212 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1213 if ((StatusRegister
& Mask
) == 0x00) {
1220 MicroSecondDelay (50);
1233 IN FDC_BLK_IO_DEV
*FdcDev
,
1235 IN UINTN TimeoutInSeconds
1239 Routine Description: Determine whether FDC is ready to write or read
1241 Dio BOOLEAN: Indicate the FDC is waiting to write or read
1242 TimeoutInSeconds UINTN: The time period for waiting
1244 EFI_SUCCESS: FDC is ready to write or read
1245 EFI_NOT_READY: FDC is not ready within the specified time period
1248 // GC_TODO: function comment is missing 'Arguments:'
1249 // GC_TODO: FdcDev - add argument and description to function comment
1250 // GC_TODO: Dio - add argument and description to function comment
1251 // GC_TODO: TimeoutInSeconds - add argument and description to function comment
1254 UINT8 StatusRegister
;
1258 // Before writing to FDC or reading from FDC, the Host must examine
1259 // the bit7(RQM) and bit6(DIO) of the Main Status Register.
1261 // command bytes can not be written to Data Register
1262 // unless RQM is 1 and DIO is 0
1263 // result bytes can not be read from Data Register
1264 // unless RQM is 1 and DIO is 1
1266 DataInOut
= (UINT8
) (Dio
<< 6);
1268 // in order to compare bit6
1270 Delay
= ((TimeoutInSeconds
* STALL_1_MSECOND
) / 50) + 1;
1272 StatusRegister
= FdcReadPort (FdcDev
, FDC_REGISTER_MSR
);
1273 if ((StatusRegister
& MSR_RQM
) == MSR_RQM
&& (StatusRegister
& MSR_DIO
) == DataInOut
) {
1280 MicroSecondDelay (50);
1288 return EFI_NOT_READY
;
1290 // FDC is not ready within the specified time period
1299 IN FDD_RESULT_PACKET
*Result
,
1300 IN OUT FDC_BLK_IO_DEV
*FdcDev
1304 Routine Description:
1306 GC_TODO: Add function description
1310 Result - GC_TODO: add argument description
1311 FdcDev - GC_TODO: add argument description
1315 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1316 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1317 EFI_DEVICE_ERROR - GC_TODO: Add description for return value
1318 EFI_SUCCESS - GC_TODO: Add description for return value
1323 // Check Status Register0
1325 if ((Result
->Status0
& STS0_IC
) != IC_NT
) {
1326 if ((Result
->Status0
& STS0_SE
) == 0x20) {
1330 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1333 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1334 return EFI_DEVICE_ERROR
;
1337 // Check Status Register1
1339 if (Result
->Status1
& (STS1_EN
| STS1_DE
| STS1_OR
| STS1_ND
| STS1_NW
| STS1_MA
)) {
1340 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1341 return EFI_DEVICE_ERROR
;
1344 // Check Status Register2
1346 if (Result
->Status2
& (STS2_CM
| STS2_DD
| STS2_WC
| STS2_BC
| STS2_MD
)) {
1347 FdcDev
->ControllerState
->NeedRecalibrate
= TRUE
;
1348 return EFI_DEVICE_ERROR
;
1356 IN UINT8 StatusRegister3
1360 Routine Description: Check the drive status information
1362 StatusRegister3 UINT8: the value of Status Register 3
1365 EFI_WRITE_PROTECTED: The disk is write protected
1368 // GC_TODO: function comment is missing 'Arguments:'
1369 // GC_TODO: StatusRegister3 - add argument and description to function comment
1371 if (StatusRegister3
& STS3_WP
) {
1372 return EFI_WRITE_PROTECTED
;
1379 GetTransferBlockCount (
1380 IN FDC_BLK_IO_DEV
*FdcDev
,
1382 IN UINTN NumberOfBlocks
1386 Routine Description: Calculate the number of block in the same cylinder
1389 FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
1390 LBA EFI_LBA: The starting logic block address
1391 NumberOfBlocks UINTN: The number of blocks
1393 UINTN : The number of blocks in the same cylinder which the starting
1394 logic block address is LBA
1397 // GC_TODO: function comment is missing 'Arguments:'
1398 // GC_TODO: FdcDev - add argument and description to function comment
1399 // GC_TODO: LBA - add argument and description to function comment
1400 // GC_TODO: NumberOfBlocks - add argument and description to function comment
1404 UINT8 SectorsInTrack
;
1407 // Calculate the number of block in the same cylinder
1409 EndOfTrack
= DISK_1440K_EOT
;
1410 Head
= (UINT8
) ((UINTN
) LBA
/ EndOfTrack
% 2);
1412 SectorsInTrack
= (UINT8
) (EndOfTrack
* (2 - Head
) - (UINT8
) ((UINTN
) LBA
% EndOfTrack
));
1413 if (SectorsInTrack
< NumberOfBlocks
) {
1414 return SectorsInTrack
;
1416 return NumberOfBlocks
;
1428 Routine Description: When the Timer(2s) off, turn the drive's motor off
1430 Event EFI_EVENT: Event(the timer) whose notification function is being
1432 Context VOID *: Pointer to the notification function's context
1437 // GC_TODO: function comment is missing 'Arguments:'
1438 // GC_TODO: Event - add argument and description to function comment
1439 // GC_TODO: Context - add argument and description to function comment
1441 FDC_BLK_IO_DEV
*FdcDev
;
1444 FdcDev
= (FDC_BLK_IO_DEV
*) Context
;
1447 // Get the motor status
1449 data
= FdcReadPort (FdcDev
, FDC_REGISTER_DOR
);
1451 if (((FdcDev
->Disk
== FDC_DISK0
) && ((data
& 0x10) != 0x10)) ||
1452 ((FdcDev
->Disk
== FDC_DISK1
) && ((data
& 0x21) != 0x21))
1457 // the motor is on, so need motor off
1460 data
= (UINT8
) (data
| (SELECT_DRV
& FdcDev
->Disk
));
1461 FdcWritePort (FdcDev
, FDC_REGISTER_DOR
, data
);
1462 MicroSecondDelay (500);
1467 IN FDC_BLK_IO_DEV
*FdcDev
,
1472 Routine Description: Read I/O port for FDC
1477 // GC_TODO: function comment is missing 'Arguments:'
1478 // GC_TODO: FdcDev - add argument and description to function comment
1479 // GC_TODO: Offset - add argument and description to function comment
1486 FdcDev
->IsaIo
->Io
.Read (
1489 FdcDev
->BaseAddress
+ Offset
,
1499 IN FDC_BLK_IO_DEV
*FdcDev
,
1505 Routine Description: Write I/O port for FDC
1510 // GC_TODO: function comment is missing 'Arguments:'
1511 // GC_TODO: FdcDev - add argument and description to function comment
1512 // GC_TODO: Offset - add argument and description to function comment
1513 // GC_TODO: Data - add argument and description to function comment
1519 FdcDev
->IsaIo
->Io
.Write (
1522 FdcDev
->BaseAddress
+ Offset
,