2 * ReactOS Floppy Driver
3 * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 * PROJECT: ReactOS Floppy Driver
21 * PURPOSE: FDC Hardware control routines
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
24 * 15-Feb-2004 vizzini - Created
26 * - Many of these functions are based directly on information from the
27 * Intel datasheet for their enhanced floppy controller. Send_Byte and
28 * Get_Byte are direct C implementations of their flowcharts, and the
29 * read/write routine and others are loose adaptations of their charts.
30 * - These routines are generally designed to be small, atomic operations. They
31 * do not wait for interrupts, deal with DMA, or do any other Windows-
32 * specific things, unless they have to.
33 * - If you compare this to Microsoft samples or to the old ReactOS driver,
34 * or even to the linux driver, you will notice a big difference: we use
35 * a system thread to drain the queue. This is because it's illegal to block
36 * in a dispatch routine, unless you're a top-level driver (which we absolutely
37 * are not). One big reason is that we may be called at raised IRQL, at which
38 * it's illegal to block. The floppy controller is a *dumb* piece of hardware,
39 * too - it is slow and difficult to deal with. The solution is to do all
40 * of the blocking and servicing of the controller in a dedicated worker
42 * - Some information taken from Intel 82077AA data sheet (order #290166-007)
44 * TODO: ATM the constants defined in hardware.h *might* be shifted to line up
45 * with the bit position in the register, or they *might not*. This should
46 * all be converted to standardize on absolute values or shifts.
47 * I prefer bit fields, but they break endianness.
48 * TODO: Figure out the right delays in Send_Byte and Get_Byte
58 * Global variable that tracks the amount of time we've
59 * been waiting on the controller
61 static ULONG TimeIncrement
= 0;
65 * Hardware Support Routines
69 static BOOLEAN NTAPI
ReadyForWrite(PCONTROLLER_INFO ControllerInfo
)
71 * FUNCTION: Determine of the controller is ready to accept a byte on the FIFO
73 * ControllerInfo: Info structure for the FDC we're testing
75 * TRUE if the controller can accept a byte right now
78 * - it is necessary to check both that the FIFO is set to "outbound"
79 * and that the "ready for i/o" bit is set.
82 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
84 if(Status
& MSR_IO_DIRECTION
) /* 0 for out */
87 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
94 static BOOLEAN NTAPI
ReadyForRead(PCONTROLLER_INFO ControllerInfo
)
96 * FUNCTION: Determine of the controller is ready to read a byte on the FIFO
98 * ControllerInfo: Info structure for the FDC we're testing
100 * TRUE if the controller can read a byte right now
103 * - it is necessary to check both that the FIFO is set to "inbound"
104 * and that the "ready for i/o" bit is set.
107 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
109 if(!(Status
& MSR_IO_DIRECTION
)) /* Read = 1 */
112 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
119 static NTSTATUS NTAPI
Send_Byte(PCONTROLLER_INFO ControllerInfo
,
122 * FUNCTION: Send a byte from the host to the controller's FIFO
124 * ControllerInfo: Info structure for the controller we're writing to
125 * Offset: Offset over the controller's base address that we're writing to
126 * Byte: Byte to write to the bus
128 * STATUS_SUCCESS if the byte was written successfully
129 * STATUS_UNSUCCESSFUL if not
131 * - Function designed after flowchart in intel datasheet
132 * - 250us max delay. Note that this is exactly 5 times longer
133 * than Microsoft recommends stalling the processor
134 * - Remember that we can be interrupted here, so this might
135 * take much more wall clock time than 250us
136 * - PAGED_CODE, because we spin for more than the Microsoft-recommended
138 * - This function is necessary because sometimes the FIFO reacts slowly
139 * and isn't yet ready to read or write the next byte
140 * FIXME: time interval here and in Get_Byte
143 LARGE_INTEGER StartingTickCount
;
144 LARGE_INTEGER CurrentTickCount
;
149 Address
= ControllerInfo
->BaseAddress
+ FIFO
;
152 TimeIncrement
= KeQueryTimeIncrement();
154 StartingTickCount
.QuadPart
= 0;
158 if(!ReadyForWrite(ControllerInfo
))
160 ULONG64 ElapsedTicks
;
163 /* If this is the first time through... */
164 if(!StartingTickCount
.QuadPart
)
166 KeQueryTickCount(&StartingTickCount
);
170 /* Otherwise, only do this for 250 us == 2500 100ns units */
171 KeQueryTickCount(&CurrentTickCount
);
172 ElapsedTicks
= CurrentTickCount
.QuadPart
- StartingTickCount
.QuadPart
;
173 TimeUnits
= ElapsedTicks
* TimeIncrement
;
175 if(TimeUnits
> 25000000)
181 WRITE_PORT_UCHAR(Address
, Byte
);
182 return STATUS_SUCCESS
;
185 INFO_(FLOPPY
, "Send_Byte: timed out trying to write\n");
186 HwDumpRegisters(ControllerInfo
);
187 return STATUS_UNSUCCESSFUL
;
191 static NTSTATUS NTAPI
Get_Byte(PCONTROLLER_INFO ControllerInfo
,
194 * FUNCTION: Read a byte from the controller to the host
196 * ControllerInfo: Info structure for the controller we're reading from
197 * Offset: Offset over the controller's base address that we're reading from
198 * Byte: Byte to read from the bus
200 * STATUS_SUCCESS if the byte was read successfully
201 * STATUS_UNSUCCESSFUL if not
203 * - Function designed after flowchart in intel datasheet
204 * - 250us max delay. Note that this is exactly 5 times longer
205 * than Microsoft recommends stalling the processor
206 * - Remember that we can be interrupted here, so this might
207 * take much more wall clock time than 250us
208 * - PAGED_CODE because we spin for longer than Microsoft recommends
211 LARGE_INTEGER StartingTickCount
;
212 LARGE_INTEGER CurrentTickCount
;
217 Address
= ControllerInfo
->BaseAddress
+ FIFO
;
220 TimeIncrement
= KeQueryTimeIncrement();
222 StartingTickCount
.QuadPart
= 0;
226 if(!ReadyForRead(ControllerInfo
))
228 ULONG64 ElapsedTicks
;
231 /* if this is the first time through, start the timer */
232 if(!StartingTickCount
.QuadPart
)
234 KeQueryTickCount(&StartingTickCount
);
238 /* Otherwise, only do this for 250 us == 2500 100ns units */
239 KeQueryTickCount(&CurrentTickCount
);
240 ElapsedTicks
= CurrentTickCount
.QuadPart
- StartingTickCount
.QuadPart
;
241 TimeUnits
= ElapsedTicks
* TimeIncrement
;
243 if(TimeUnits
> 25000000)
249 *Byte
= READ_PORT_UCHAR(Address
);
251 return STATUS_SUCCESS
;
254 WARN_(FLOPPY
, "Get_Byte: timed out trying to read\n");
255 HwDumpRegisters(ControllerInfo
);
256 return STATUS_UNSUCCESSFUL
;
260 NTSTATUS NTAPI
HwSetDataRate(PCONTROLLER_INFO ControllerInfo
,
263 * FUNCTION: Set the data rte on a controller
265 * ControllerInfo: Controller whose rate is being set
266 * DataRate: Data rate code to set the controller to
271 TRACE_(FLOPPY
, "HwSetDataRate called; writing rate code 0x%x to offset 0x%x\n", DataRate
, DATA_RATE_SELECT_REGISTER
);
273 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DataRate
);
275 return STATUS_SUCCESS
;
279 NTSTATUS NTAPI
HwTurnOffMotor(PCONTROLLER_INFO ControllerInfo
)
281 * FUNCTION: Turn off all motors
283 * DriveInfo: drive to turn off
285 * STATUS_SUCCESS if the motor is successfully turned off
287 * - Don't call this routine directly unless you've thought about it
288 * and read the source to StartMotor() and StopMotor().
289 * - Called at DISPATCH_LEVEL
292 TRACE_(FLOPPY
, "HwTurnOffMotor: writing byte 0x%x to offset 0x%x\n", DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
, DIGITAL_OUTPUT_REGISTER
);
294 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
);
296 return STATUS_SUCCESS
;
300 NTSTATUS NTAPI
HwTurnOnMotor(PDRIVE_INFO DriveInfo
)
302 * FUNCTION: Turn on the motor on the selected drive
304 * DriveInfo: drive to turn on
306 * STATUS_SUCCESS if the motor is successfully turned on
307 * STATUS_UNSUCCESSFUL otherwise
309 * - Doesn't interrupt
310 * - Currently cannot fail
313 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
314 UCHAR Unit
= DriveInfo
->UnitNumber
;
322 Buffer
|= DOR_FDC_ENABLE
;
323 Buffer
|= DOR_DMA_IO_INTERFACE_ENABLE
;
326 Buffer
|= DOR_FLOPPY_MOTOR_ON_A
;
328 Buffer
|= DOR_FLOPPY_MOTOR_ON_B
;
330 Buffer
|= DOR_FLOPPY_MOTOR_ON_C
;
332 Buffer
|= DOR_FLOPPY_MOTOR_ON_D
;
334 TRACE_(FLOPPY
, "HwTurnOnMotor: writing byte 0x%x to offset 0x%x\n", Buffer
, DIGITAL_OUTPUT_REGISTER
);
335 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, Buffer
);
337 return STATUS_SUCCESS
;
341 NTSTATUS NTAPI
HwSenseDriveStatus(PDRIVE_INFO DriveInfo
)
343 * FUNCTION: Start a sense status command
345 * DriveInfo: Drive to inquire about
347 * STATUS_SUCCESS if the command is successfully queued to the controller
348 * STATUS_UNSUCCESSFUL if not
350 * - Generates an interrupt
351 * - hard-wired to head 0
359 TRACE_(FLOPPY
, "HwSenseDriveStatus called\n");
361 Buffer
[0] = COMMAND_SENSE_DRIVE_STATUS
;
362 Buffer
[1] = DriveInfo
->UnitNumber
; /* hard-wired to head 0 for now */
364 for(i
= 0; i
< 2; i
++)
365 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
367 WARN_(FLOPPY
, "HwSenseDriveStatus: failed to write FIFO\n");
368 return STATUS_UNSUCCESSFUL
;
371 return STATUS_SUCCESS
;
375 NTSTATUS NTAPI
HwReadWriteData(PCONTROLLER_INFO ControllerInfo
,
381 UCHAR BytesPerSector
,
386 * FUNCTION: Read or write data to the drive
388 * ControllerInfo: controller to target the read/write request to
389 * Read: TRUE if the device should be read; FALSE if written
390 * Unit: Drive number to target
391 * Cylinder: cylinder to start the read on
392 * Head: head to start the read on
393 * Sector: sector to start the read on (1-based!)
394 * BytesPerSector: sector size constant (hardware.h)
395 * EndOfTrack: Marks the last sector number to read/write on the track
396 * Gap3Length: Gap length for the operation
397 * DataLength: Bytes to read, *unless* BytesPerSector is specified
399 * STATUS_SUCCESS if the operation was successfully queued to the controller
400 * STATUS_UNSUCCESSFUL otherwise
402 * - Generates an interrupt
410 /* Shouldn't be using DataLength in this driver */
411 ASSERT(DataLength
== 0xff);
413 /* Build the command to send */
415 Buffer
[0] = COMMAND_READ_DATA
;
417 Buffer
[0] = COMMAND_WRITE_DATA
;
419 Buffer
[0] |= READ_DATA_MFM
| READ_DATA_MT
;
421 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
422 Buffer
[2] = Cylinder
;
425 Buffer
[5] = BytesPerSector
;
426 Buffer
[6] = EndOfTrack
;
427 Buffer
[7] = Gap3Length
;
428 Buffer
[8] = DataLength
;
430 /* Send the command */
431 for(i
= 0; i
< 9; i
++)
433 INFO_(FLOPPY
, "HwReadWriteData: Sending a command byte to the FIFO: 0x%x\n", Buffer
[i
]);
435 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
437 WARN_(FLOPPY
, "HwReadWriteData: Unable to write to the FIFO\n");
438 return STATUS_UNSUCCESSFUL
;
442 return STATUS_SUCCESS
;
446 NTSTATUS NTAPI
HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo
)
448 * FUNCTION: Get the result of a recalibrate command
450 * ControllerInfo: controller to query
452 * STATUS_SUCCESS if the recalibratewas a success
453 * STATUS_UNSUCCESSFUL otherwise
455 * - This function tests the error conditions itself, and boils the
456 * whole thing down to a single SUCCESS or FAILURE result
457 * - Called post-interrupt; does not interrupt
459 * - perhaps handle more status
467 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
469 WARN_(FLOPPY
, "HwRecalibrateResult: Unable to write the controller\n");
470 return STATUS_UNSUCCESSFUL
;
473 for(i
= 0; i
< 2; i
++)
474 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
476 WARN_(FLOPPY
, "HwRecalibrateResult: unable to read FIFO\n");
477 return STATUS_UNSUCCESSFUL
;
480 /* Validate that it did what we told it to */
481 INFO_(FLOPPY
, "HwRecalibrateResult results: ST0: 0x%x PCN: 0x%x\n", Buffer
[0], Buffer
[1]);
491 WARN_(FLOPPY
, "HwRecalibrateResult: PCN not 0\n");
492 return STATUS_UNSUCCESSFUL
;
495 /* test seek complete */
496 if((Buffer
[0] & SR0_SEEK_COMPLETE
) != SR0_SEEK_COMPLETE
)
498 WARN_(FLOPPY
, "HwRecalibrateResult: Failed to complete the seek\n");
499 return STATUS_UNSUCCESSFUL
;
502 /* Is the equipment check flag set? Could be no disk in drive... */
503 if((Buffer
[0] & SR0_EQUIPMENT_CHECK
) == SR0_EQUIPMENT_CHECK
)
504 INFO_(FLOPPY
, "HwRecalibrateResult: Seeked to track 0 successfully, but EC is set; returning STATUS_SUCCESS anyway\n");
506 return STATUS_SUCCESS
;
510 NTSTATUS NTAPI
HwReadWriteResult(PCONTROLLER_INFO ControllerInfo
)
512 * FUNCTION: Get the result of a read or write from the controller
514 * ControllerInfo: controller to query
516 * STATUS_SUCCESS if the read/write was a success
517 * STATUS_UNSUCCESSFUL otherwise
519 * - This function tests the error conditions itself, and boils the
520 * whole thing down to a single SUCCESS or FAILURE result
521 * - Called post-interrupt; does not interrupt
523 * - perhaps handle more status
531 for(i
= 0; i
< 7; i
++)
532 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
534 WARN_(FLOPPY
, "HwReadWriteResult: unable to read fifo\n");
535 return STATUS_UNSUCCESSFUL
;
538 /* Validate that it did what we told it to */
539 INFO_(FLOPPY
, "HwReadWriteResult results: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", Buffer
[0], Buffer
[1], Buffer
[2], Buffer
[3],
540 Buffer
[4], Buffer
[5], Buffer
[6]);
542 /* Last command successful? */
543 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
544 return STATUS_UNSUCCESSFUL
;
546 return STATUS_SUCCESS
;
550 NTSTATUS NTAPI
HwRecalibrate(PDRIVE_INFO DriveInfo
)
552 * FUNCTION: Start a recalibration of a drive
554 * DriveInfo: Drive to recalibrate
556 * STATUS_SUCCESS if the command was successfully queued to the controller
557 * STATUS_UNSUCCESSFUL otherwise
559 * - Generates an interrupt
562 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
563 UCHAR Unit
= DriveInfo
->UnitNumber
;
567 TRACE_(FLOPPY
, "HwRecalibrate called\n");
571 Buffer
[0] = COMMAND_RECALIBRATE
;
574 for(i
= 0; i
< 2; i
++)
575 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
577 WARN_(FLOPPY
, "HwRecalibrate: unable to write FIFO\n");
578 return STATUS_UNSUCCESSFUL
;
581 return STATUS_SUCCESS
;
585 NTSTATUS NTAPI
HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo
)
587 * FUNCTION: Send a sense interrupt status command to a controller
589 * ControllerInfo: controller to queue the command to
591 * STATUS_SUCCESS if the command is queued successfully
592 * STATUS_UNSUCCESSFUL if not
600 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
602 WARN_(FLOPPY
, "HwSenseInterruptStatus: failed to write controller\n");
603 return STATUS_UNSUCCESSFUL
;
606 for(i
= 0; i
< 2; i
++)
608 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
610 WARN_(FLOPPY
, "HwSenseInterruptStatus: failed to read controller\n");
611 return STATUS_UNSUCCESSFUL
;
615 INFO_(FLOPPY
, "HwSenseInterruptStatus returned 0x%x 0x%x\n", Buffer
[0], Buffer
[1]);
617 return STATUS_SUCCESS
;
621 NTSTATUS NTAPI
HwReadId(PDRIVE_INFO DriveInfo
, UCHAR Head
)
623 * FUNCTION: Issue a read id command to the drive
625 * DriveInfo: Drive to read id from
626 * Head: Head to read the ID from
628 * STATUS_SUCCESS if the command is queued
629 * STATUS_UNSUCCESSFUL otherwise
631 * - Generates an interrupt
637 TRACE_(FLOPPY
, "HwReadId called\n");
641 Buffer
[0] = COMMAND_READ_ID
| READ_ID_MFM
;
642 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | DriveInfo
->UnitNumber
;
644 for(i
= 0; i
< 2; i
++)
645 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
647 WARN_(FLOPPY
, "HwReadId: unable to send bytes to fifo\n");
648 return STATUS_UNSUCCESSFUL
;
651 return STATUS_SUCCESS
;
655 NTSTATUS NTAPI
HwFormatTrack(PCONTROLLER_INFO ControllerInfo
,
658 UCHAR BytesPerSector
,
659 UCHAR SectorsPerTrack
,
663 * FUNCTION: Format a track
665 * ControllerInfo: controller to target with the request
666 * Unit: drive to format on
667 * Head: head to format on
668 * BytesPerSector: constant from hardware.h to select density
669 * SectorsPerTrack: sectors per track
670 * Gap3Length: gap length to use during format
671 * FillerPattern: pattern to write into the data portion of sectors
673 * STATUS_SUCCESS if the command is successfully queued
674 * STATUS_UNSUCCESSFUL otherwise
680 TRACE_(FLOPPY
, "HwFormatTrack called\n");
684 Buffer
[0] = COMMAND_FORMAT_TRACK
;
685 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
686 Buffer
[2] = BytesPerSector
;
687 Buffer
[3] = SectorsPerTrack
;
688 Buffer
[4] = Gap3Length
;
689 Buffer
[5] = FillerPattern
;
691 for(i
= 0; i
< 6; i
++)
692 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
694 WARN_(FLOPPY
, "HwFormatTrack: unable to send bytes to floppy\n");
695 return STATUS_UNSUCCESSFUL
;
698 return STATUS_SUCCESS
;
702 NTSTATUS NTAPI
HwSeek(PDRIVE_INFO DriveInfo
,
705 * FUNCTION: Seek the heads to a particular cylinder
707 * DriveInfo: Drive to seek
708 * Cylinder: cylinder to move to
710 * STATUS_SUCCESS if the command is successfully sent
711 * STATUS_UNSUCCESSFUL otherwise
713 * - Generates an interrupt
720 TRACE_(FLOPPY
, "HwSeek called for cyl 0x%x\n", Cylinder
);
724 Buffer
[0] = COMMAND_SEEK
;
725 Buffer
[1] = DriveInfo
->UnitNumber
;
726 Buffer
[2] = Cylinder
;
728 for(i
= 0; i
< 3; i
++)
729 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
731 WARN_(FLOPPY
, "HwSeek: failed to write fifo\n");
732 return STATUS_UNSUCCESSFUL
;
735 /* Wait for the head to settle */
736 Delay
.QuadPart
= 10 * 1000;
737 Delay
.QuadPart
*= -1;
738 Delay
.QuadPart
*= DriveInfo
->FloppyDeviceData
.HeadSettleTime
;
740 KeDelayExecutionThread(KernelMode
, FALSE
, &Delay
);
742 return STATUS_SUCCESS
;
746 NTSTATUS NTAPI
HwConfigure(PCONTROLLER_INFO ControllerInfo
,
753 * FUNCTION: Sends configuration to the drive
755 * ControllerInfo: controller to target with the request
756 * EIS: Enable implied seek
757 * EFIFO: Enable advanced fifo
758 * POLL: Enable polling
759 * FIFOTHR: fifo threshold
760 * PRETRK: precomp (see intel datasheet)
762 * STATUS_SUCCESS if the command is successfully sent
763 * STATUS_UNSUCCESSFUL otherwise
771 TRACE_(FLOPPY
, "HwConfigure called\n");
775 Buffer
[0] = COMMAND_CONFIGURE
;
777 Buffer
[2] = (EIS
* CONFIGURE_EIS
) + (EFIFO
* CONFIGURE_EFIFO
) + (POLL
* CONFIGURE_POLL
) + (FIFOTHR
);
780 for(i
= 0; i
< 4; i
++)
781 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
783 WARN_(FLOPPY
, "HwConfigure: failed to write the fifo\n");
784 return STATUS_UNSUCCESSFUL
;
787 return STATUS_SUCCESS
;
791 NTSTATUS NTAPI
HwGetVersion(PCONTROLLER_INFO ControllerInfo
)
793 * FUNCTION: Gets the version of the controller
795 * ControllerInfo: controller to target with the request
796 * ConfigValue: Configuration value to send to the drive (see header)
798 * Version number returned by the command, or
801 * - This command doesn't interrupt, so we go right to reading after
802 * we issue the command
809 if(Send_Byte(ControllerInfo
, COMMAND_VERSION
) != STATUS_SUCCESS
)
811 WARN_(FLOPPY
, "HwGetVersion: unable to write fifo\n");
812 return STATUS_UNSUCCESSFUL
;
815 if(Get_Byte(ControllerInfo
, &Buffer
) != STATUS_SUCCESS
)
817 WARN_(FLOPPY
, "HwGetVersion: unable to write fifo\n");
818 return STATUS_UNSUCCESSFUL
;
821 INFO_(FLOPPY
, "HwGetVersion returning version 0x%x\n", Buffer
);
826 NTSTATUS NTAPI
HwDiskChanged(PDRIVE_INFO DriveInfo
,
827 PBOOLEAN DiskChanged
)
829 * FUNCTION: Detect whether the hardware has sensed a disk change
831 * DriveInfo: pointer to the drive that we are to check
832 * DiskChanged: boolean that is set with whether or not the controller thinks there has been a disk change
834 * STATUS_SUCCESS if the drive is successfully queried
836 * - Does not interrupt.
837 * - Guessing a bit at the Model30 stuff
841 PCONTROLLER_INFO ControllerInfo
= (PCONTROLLER_INFO
) DriveInfo
->ControllerInfo
;
843 Buffer
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
);
845 TRACE_(FLOPPY
, "HwDiskChanged: read 0x%x from DIR\n", Buffer
);
847 if(ControllerInfo
->Model30
)
849 if(!(Buffer
& DIR_DISKETTE_CHANGE
))
851 INFO_(FLOPPY
, "HdDiskChanged - Model30 - returning TRUE\n");
856 INFO_(FLOPPY
, "HdDiskChanged - Model30 - returning FALSE\n");
857 *DiskChanged
= FALSE
;
862 if(Buffer
& DIR_DISKETTE_CHANGE
)
864 INFO_(FLOPPY
, "HdDiskChanged - PS2 - returning TRUE\n");
869 INFO_(FLOPPY
, "HdDiskChanged - PS2 - returning FALSE\n");
870 *DiskChanged
= FALSE
;
874 return STATUS_SUCCESS
;
877 NTSTATUS NTAPI
HwSenseDriveStatusResult(PCONTROLLER_INFO ControllerInfo
,
880 * FUNCTION: Get the result of a sense drive status command
882 * ControllerInfo: controller to query
883 * Status: Status from the drive sense command
885 * STATUS_SUCCESS if we can successfully read the status
886 * STATUS_UNSUCCESSFUL otherwise
888 * - Called post-interrupt; does not interrupt
893 if(Get_Byte(ControllerInfo
, Status
) != STATUS_SUCCESS
)
895 WARN_(FLOPPY
, "HwSenseDriveStatus: unable to read fifo\n");
896 return STATUS_UNSUCCESSFUL
;
899 TRACE_(FLOPPY
, "HwSenseDriveStatusResult: ST3: 0x%x\n", *Status
);
901 return STATUS_SUCCESS
;
905 NTSTATUS NTAPI
HwReadIdResult(PCONTROLLER_INFO ControllerInfo
,
909 * FUNCTION: Get the result of a read id command
911 * ControllerInfo: controller to query
912 * CurCylinder: Returns the cylinder that we're at
913 * CurHead: Returns the head that we're at
915 * STATUS_SUCCESS if the read id was a success
916 * STATUS_UNSUCCESSFUL otherwise
918 * - This function tests the error conditions itself, and boils the
919 * whole thing down to a single SUCCESS or FAILURE result
920 * - Called post-interrupt; does not interrupt
922 * - perhaps handle more status
925 UCHAR Buffer
[7] = {0,0,0,0,0,0,0};
930 for(i
= 0; i
< 7; i
++)
931 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
933 WARN_(FLOPPY
, "ReadIdResult(): can't read from the controller\n");
934 return STATUS_UNSUCCESSFUL
;
937 /* Validate that it did what we told it to */
938 INFO_(FLOPPY
, "ReadId results: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", Buffer
[0], Buffer
[1], Buffer
[2], Buffer
[3],
939 Buffer
[4], Buffer
[5], Buffer
[6]);
941 /* Last command successful? */
942 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
944 WARN_(FLOPPY
, "ReadId didn't return last command success\n");
945 return STATUS_UNSUCCESSFUL
;
949 if(Buffer
[1] & SR1_CANNOT_FIND_ID_ADDRESS
)
951 WARN_(FLOPPY
, "ReadId didn't find an address mark\n");
952 return STATUS_UNSUCCESSFUL
;
956 *CurCylinder
= Buffer
[3];
959 *CurHead
= Buffer
[4];
961 return STATUS_SUCCESS
;
965 NTSTATUS NTAPI
HwSpecify(PCONTROLLER_INFO ControllerInfo
,
967 UCHAR HeadUnloadTime
,
971 * FUNCTION: Set up timing and DMA mode for the controller
973 * ControllerInfo: Controller to set up
974 * HeadLoadTime: Head load time (see data sheet for details)
975 * HeadUnloadTime: Head unload time
976 * StepRateTime: Step rate time
977 * NonDma: TRUE to disable DMA mode
979 * STATUS_SUCCESS if the contrller is successfully programmed
980 * STATUS_UNSUCCESSFUL if not
982 * - Does not interrupt
984 * TODO: Figure out timings
990 Buffer
[0] = COMMAND_SPECIFY
;
992 Buffer[1] = (StepRateTime << 4) + HeadUnloadTime;
993 Buffer[2] = (HeadLoadTime << 1) + (NonDma ? 1 : 0);
998 //INFO_(FLOPPY, "HwSpecify: sending 0x%x 0x%x 0x%x to FIFO\n", Buffer[0], Buffer[1], Buffer[2]);
999 WARN_(FLOPPY
, "HWSPECIFY: FIXME - sending 0x3 0xd1 0x2 to FIFO\n");
1001 for(i
= 0; i
< 3; i
++)
1002 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
1004 WARN_(FLOPPY
, "HwSpecify: unable to write to controller\n");
1005 return STATUS_UNSUCCESSFUL
;
1008 return STATUS_SUCCESS
;
1012 NTSTATUS NTAPI
HwReset(PCONTROLLER_INFO ControllerInfo
)
1014 * FUNCTION: Reset the controller
1016 * ControllerInfo: controller to reset
1018 * STATUS_SUCCESS in all cases
1020 * - Generates an interrupt that must be serviced four times (one per drive)
1023 TRACE_(FLOPPY
, "HwReset called\n");
1025 /* Write the reset bit in the DRSR */
1026 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_SW_RESET
);
1028 /* Check for the reset bit in the DOR and set it if necessary (see Intel doc) */
1029 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
1031 HwDumpRegisters(ControllerInfo
);
1032 INFO_(FLOPPY
, "HwReset: Setting Enable bit\n");
1033 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_DMA_IO_INTERFACE_ENABLE
|DOR_RESET
);
1034 HwDumpRegisters(ControllerInfo
);
1036 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
1038 WARN_(FLOPPY
, "HwReset: failed to set the DOR enable bit!\n");
1039 HwDumpRegisters(ControllerInfo
);
1040 return STATUS_UNSUCCESSFUL
;
1044 return STATUS_SUCCESS
;
1048 NTSTATUS NTAPI
HwPowerOff(PCONTROLLER_INFO ControllerInfo
)
1050 * FUNCTION: Power down a controller
1052 * ControllerInfo: Controller to power down
1056 * - Wake up with a hardware reset
1059 TRACE_(FLOPPY
, "HwPowerOff called on controller 0x%p\n", ControllerInfo
);
1061 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_POWER_DOWN
);
1063 return STATUS_SUCCESS
;
1066 VOID NTAPI
HwDumpRegisters(PCONTROLLER_INFO ControllerInfo
)
1068 * FUNCTION: Dump all readable registers from the floppy controller
1070 * ControllerInfo: Controller to dump registers from
1073 UNREFERENCED_PARAMETER(ControllerInfo
);
1075 INFO_(FLOPPY
, "STATUS:\n");
1076 INFO_(FLOPPY
, "STATUS_REGISTER_A = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_A
));
1077 INFO_(FLOPPY
, "STATUS_REGISTER_B = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_B
));
1078 INFO_(FLOPPY
, "DIGITAL_OUTPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
));
1079 INFO_(FLOPPY
, "MAIN_STATUS_REGISTER =0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
));
1080 INFO_(FLOPPY
, "DIGITAL_INPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
));