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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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
59 * Global variable that tracks the amount of time we've
60 * been waiting on the controller
62 static ULONG TimeIncrement
= 0;
66 * Hardware Support Routines
70 static BOOLEAN NTAPI
ReadyForWrite(PCONTROLLER_INFO ControllerInfo
)
72 * FUNCTION: Determine of the controller is ready to accept a byte on the FIFO
74 * ControllerInfo: Info structure for the FDC we're testing
76 * TRUE if the controller can accept a byte right now
79 * - it is necessary to check both that the FIFO is set to "outbound"
80 * and that the "ready for i/o" bit is set.
83 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
85 if(Status
& MSR_IO_DIRECTION
) /* 0 for out */
88 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
95 static BOOLEAN NTAPI
ReadyForRead(PCONTROLLER_INFO ControllerInfo
)
97 * FUNCTION: Determine of the controller is ready to read a byte on the FIFO
99 * ControllerInfo: Info structure for the FDC we're testing
101 * TRUE if the controller can read a byte right now
104 * - it is necessary to check both that the FIFO is set to "inbound"
105 * and that the "ready for i/o" bit is set.
108 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
110 if(!(Status
& MSR_IO_DIRECTION
)) /* Read = 1 */
113 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
120 static NTSTATUS NTAPI
Send_Byte(PCONTROLLER_INFO ControllerInfo
,
123 * FUNCTION: Send a byte from the host to the controller's FIFO
125 * ControllerInfo: Info structure for the controller we're writing to
126 * Offset: Offset over the controller's base address that we're writing to
127 * Byte: Byte to write to the bus
129 * STATUS_SUCCESS if the byte was written successfully
130 * STATUS_UNSUCCESSFUL if not
132 * - Function designed after flowchart in intel datasheet
133 * - 250us max delay. Note that this is exactly 5 times longer
134 * than Microsoft recommends stalling the processor
135 * - Remember that we can be interrupted here, so this might
136 * take much more wall clock time than 250us
137 * - PAGED_CODE, because we spin for more than the Microsoft-recommended
139 * - This function is necessary because sometimes the FIFO reacts slowly
140 * and isn't yet ready to read or write the next byte
141 * FIXME: time interval here and in Get_Byte
144 LARGE_INTEGER StartingTickCount
;
145 LARGE_INTEGER CurrentTickCount
;
150 Address
= ControllerInfo
->BaseAddress
+ FIFO
;
153 TimeIncrement
= KeQueryTimeIncrement();
155 StartingTickCount
.QuadPart
= 0;
159 if(!ReadyForWrite(ControllerInfo
))
161 ULONG64 ElapsedTicks
;
164 /* If this is the first time through... */
165 if(!StartingTickCount
.QuadPart
)
167 KeQueryTickCount(&StartingTickCount
);
171 /* Otherwise, only do this for 250 us == 2500 100ns units */
172 KeQueryTickCount(&CurrentTickCount
);
173 ElapsedTicks
= CurrentTickCount
.QuadPart
- StartingTickCount
.QuadPart
;
174 TimeUnits
= ElapsedTicks
* TimeIncrement
;
176 if(TimeUnits
> 25000000)
182 WRITE_PORT_UCHAR(Address
, Byte
);
183 return STATUS_SUCCESS
;
186 DPRINT("floppy: Send_Byte: timed out trying to write\n");
187 HwDumpRegisters(ControllerInfo
);
188 return STATUS_UNSUCCESSFUL
;
192 static NTSTATUS NTAPI
Get_Byte(PCONTROLLER_INFO ControllerInfo
,
195 * FUNCTION: Read a byte from the controller to the host
197 * ControllerInfo: Info structure for the controller we're reading from
198 * Offset: Offset over the controller's base address that we're reading from
199 * Byte: Byte to read from the bus
201 * STATUS_SUCCESS if the byte was read successfully
202 * STATUS_UNSUCCESSFUL if not
204 * - Function designed after flowchart in intel datasheet
205 * - 250us max delay. Note that this is exactly 5 times longer
206 * than Microsoft recommends stalling the processor
207 * - Remember that we can be interrupted here, so this might
208 * take much more wall clock time than 250us
209 * - PAGED_CODE because we spin for longer than Microsoft recommends
212 LARGE_INTEGER StartingTickCount
;
213 LARGE_INTEGER CurrentTickCount
;
218 Address
= ControllerInfo
->BaseAddress
+ FIFO
;
221 TimeIncrement
= KeQueryTimeIncrement();
223 StartingTickCount
.QuadPart
= 0;
227 if(!ReadyForRead(ControllerInfo
))
229 ULONG64 ElapsedTicks
;
232 /* if this is the first time through, start the timer */
233 if(!StartingTickCount
.QuadPart
)
235 KeQueryTickCount(&StartingTickCount
);
239 /* Otherwise, only do this for 250 us == 2500 100ns units */
240 KeQueryTickCount(&CurrentTickCount
);
241 ElapsedTicks
= CurrentTickCount
.QuadPart
- StartingTickCount
.QuadPart
;
242 TimeUnits
= ElapsedTicks
* TimeIncrement
;
244 if(TimeUnits
> 25000000)
250 *Byte
= READ_PORT_UCHAR(Address
);
252 return STATUS_SUCCESS
;
255 DPRINT("floppy: Get_Byte: timed out trying to read\n");
256 HwDumpRegisters(ControllerInfo
);
257 return STATUS_UNSUCCESSFUL
;
261 NTSTATUS NTAPI
HwSetDataRate(PCONTROLLER_INFO ControllerInfo
,
264 * FUNCTION: Set the data rte on a controller
266 * ControllerInfo: Controller whose rate is being set
267 * DataRate: Data rate code to set the controller to
272 DPRINT("floppy: HwSetDataRate called; writing rate code 0x%x to offset 0x%x\n", DataRate
, DATA_RATE_SELECT_REGISTER
);
274 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DataRate
);
276 return STATUS_SUCCESS
;
280 NTSTATUS NTAPI
HwTurnOffMotor(PCONTROLLER_INFO ControllerInfo
)
282 * FUNCTION: Turn off all motors
284 * DriveInfo: drive to turn off
286 * STATUS_SUCCESS if the motor is successfully turned off
288 * - Don't call this routine directly unless you've thought about it
289 * and read the source to StartMotor() and StopMotor().
290 * - Called at DISPATCH_LEVEL
293 DPRINT("floppy: HwTurnOffMotor: writing byte 0x%x to offset 0x%x\n", DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
, DIGITAL_OUTPUT_REGISTER
);
295 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
);
297 return STATUS_SUCCESS
;
301 NTSTATUS NTAPI
HwTurnOnMotor(PDRIVE_INFO DriveInfo
)
303 * FUNCTION: Turn on the motor on the selected drive
305 * DriveInfo: drive to turn on
307 * STATUS_SUCCESS if the motor is successfully turned on
308 * STATUS_UNSUCCESSFUL otherwise
310 * - Doesn't interrupt
311 * - Currently cannot fail
314 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
315 UCHAR Unit
= DriveInfo
->UnitNumber
;
323 Buffer
|= DOR_FDC_ENABLE
;
324 Buffer
|= DOR_DMA_IO_INTERFACE_ENABLE
;
327 Buffer
|= DOR_FLOPPY_MOTOR_ON_A
;
329 Buffer
|= DOR_FLOPPY_MOTOR_ON_B
;
331 Buffer
|= DOR_FLOPPY_MOTOR_ON_C
;
333 Buffer
|= DOR_FLOPPY_MOTOR_ON_D
;
335 DPRINT("floppy: HwTurnOnMotor: writing byte 0x%x to offset 0x%x\n", Buffer
, DIGITAL_OUTPUT_REGISTER
);
336 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, Buffer
);
338 return STATUS_SUCCESS
;
342 NTSTATUS NTAPI
HwSenseDriveStatus(PDRIVE_INFO DriveInfo
)
344 * FUNCTION: Start a sense status command
346 * DriveInfo: Drive to inquire about
348 * STATUS_SUCCESS if the command is successfully queued to the controller
349 * STATUS_UNSUCCESSFUL if not
351 * - Generates an interrupt
352 * - hard-wired to head 0
360 DPRINT("floppy: HwSenseDriveStatus called\n");
362 Buffer
[0] = COMMAND_SENSE_DRIVE_STATUS
;
363 Buffer
[1] = DriveInfo
->UnitNumber
; /* hard-wired to head 0 for now */
365 for(i
= 0; i
< 2; i
++)
366 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
368 DPRINT("floppy: HwSenseDriveStatus: failed to write FIFO\n");
369 return STATUS_UNSUCCESSFUL
;
372 return STATUS_SUCCESS
;
376 NTSTATUS NTAPI
HwReadWriteData(PCONTROLLER_INFO ControllerInfo
,
382 UCHAR BytesPerSector
,
387 * FUNCTION: Read or write data to the drive
389 * ControllerInfo: controller to target the read/write request to
390 * Read: TRUE if the device should be read; FALSE if written
391 * Unit: Drive number to target
392 * Cylinder: cylinder to start the read on
393 * Head: head to start the read on
394 * Sector: sector to start the read on (1-based!)
395 * BytesPerSector: sector size constant (hardware.h)
396 * EndOfTrack: Marks the last sector number to read/write on the track
397 * Gap3Length: Gap length for the operation
398 * DataLength: Bytes to read, *unless* BytesPerSector is specified
400 * STATUS_SUCCESS if the operation was successfully queued to the controller
401 * STATUS_UNSUCCESSFUL otherwise
403 * - Generates an interrupt
411 /* Shouldn't be using DataLength in this driver */
412 ASSERT(DataLength
== 0xff);
414 /* Build the command to send */
416 Buffer
[0] = COMMAND_READ_DATA
;
418 Buffer
[0] = COMMAND_WRITE_DATA
;
420 Buffer
[0] |= READ_DATA_MFM
| READ_DATA_MT
;
422 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
423 Buffer
[2] = Cylinder
;
426 Buffer
[5] = BytesPerSector
;
427 Buffer
[6] = EndOfTrack
;
428 Buffer
[7] = Gap3Length
;
429 Buffer
[8] = DataLength
;
431 /* Send the command */
432 for(i
= 0; i
< 9; i
++)
434 DPRINT("floppy: HwReadWriteData: Sending a command byte to the FIFO: 0x%x\n", Buffer
[i
]);
436 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
438 DPRINT("HwReadWriteData: Unable to write to the FIFO\n");
439 return STATUS_UNSUCCESSFUL
;
443 return STATUS_SUCCESS
;
447 NTSTATUS NTAPI
HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo
)
449 * FUNCTION: Get the result of a recalibrate command
451 * ControllerInfo: controller to query
453 * STATUS_SUCCESS if the recalibratewas a success
454 * STATUS_UNSUCCESSFUL otherwise
456 * - This function tests the error conditions itself, and boils the
457 * whole thing down to a single SUCCESS or FAILURE result
458 * - Called post-interrupt; does not interrupt
460 * - perhaps handle more status
468 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
470 DPRINT("floppy: HwRecalibrateResult: Unable to write the controller\n");
471 return STATUS_UNSUCCESSFUL
;
474 for(i
= 0; i
< 2; i
++)
475 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
477 DPRINT("floppy: HwRecalibrateResult: unable to read FIFO\n");
478 return STATUS_UNSUCCESSFUL
;
481 /* Validate that it did what we told it to */
482 DPRINT("floppy: HwRecalibrateResult results: ST0: 0x%x PCN: 0x%x\n", Buffer
[0], Buffer
[1]);
492 DPRINT("floppy: HwRecalibrateResult: PCN not 0\n");
493 return STATUS_UNSUCCESSFUL
;
496 /* test seek complete */
497 if((Buffer
[0] & SR0_SEEK_COMPLETE
) != SR0_SEEK_COMPLETE
)
499 DPRINT("floppy: HwRecalibrateResult: Failed to complete the seek\n");
500 return STATUS_UNSUCCESSFUL
;
503 /* Is the equipment check flag set? Could be no disk in drive... */
504 if((Buffer
[0] & SR0_EQUIPMENT_CHECK
) == SR0_EQUIPMENT_CHECK
)
505 DPRINT("floppy: HwRecalibrateResult: Seeked to track 0 successfully, but EC is set; returning STATUS_SUCCESS anyway\n");
507 return STATUS_SUCCESS
;
511 NTSTATUS NTAPI
HwReadWriteResult(PCONTROLLER_INFO ControllerInfo
)
513 * FUNCTION: Get the result of a read or write from the controller
515 * ControllerInfo: controller to query
517 * STATUS_SUCCESS if the read/write was a success
518 * STATUS_UNSUCCESSFUL otherwise
520 * - This function tests the error conditions itself, and boils the
521 * whole thing down to a single SUCCESS or FAILURE result
522 * - Called post-interrupt; does not interrupt
524 * - perhaps handle more status
532 for(i
= 0; i
< 7; i
++)
533 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
535 DPRINT("floppy: HwReadWriteResult: unable to read fifo\n");
536 return STATUS_UNSUCCESSFUL
;
539 /* Validate that it did what we told it to */
540 DPRINT("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],
541 Buffer
[4], Buffer
[5], Buffer
[6]);
543 /* Last command successful? */
544 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
545 return STATUS_UNSUCCESSFUL
;
547 return STATUS_SUCCESS
;
551 NTSTATUS NTAPI
HwRecalibrate(PDRIVE_INFO DriveInfo
)
553 * FUNCTION: Start a recalibration of a drive
555 * DriveInfo: Drive to recalibrate
557 * STATUS_SUCCESS if the command was successfully queued to the controller
558 * STATUS_UNSUCCESSFUL otherwise
560 * - Generates an interrupt
563 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
564 UCHAR Unit
= DriveInfo
->UnitNumber
;
568 DPRINT("floppy: HwRecalibrate called\n");
572 Buffer
[0] = COMMAND_RECALIBRATE
;
575 for(i
= 0; i
< 2; i
++)
576 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
578 DPRINT("floppy: HwRecalibrate: unable to write FIFO\n");
579 return STATUS_UNSUCCESSFUL
;
582 return STATUS_SUCCESS
;
586 NTSTATUS NTAPI
HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo
)
588 * FUNCTION: Send a sense interrupt status command to a controller
590 * ControllerInfo: controller to queue the command to
592 * STATUS_SUCCESS if the command is queued successfully
593 * STATUS_UNSUCCESSFUL if not
601 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
603 DPRINT("floppy: HwSenseInterruptStatus: failed to write controller\n");
604 return STATUS_UNSUCCESSFUL
;
607 for(i
= 0; i
< 2; i
++)
609 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
611 DPRINT("floppy: HwSenseInterruptStatus: failed to read controller\n");
612 return STATUS_UNSUCCESSFUL
;
616 DPRINT("floppy: HwSenseInterruptStatus returned 0x%x 0x%x\n", Buffer
[0], Buffer
[1]);
618 return STATUS_SUCCESS
;
622 NTSTATUS NTAPI
HwReadId(PDRIVE_INFO DriveInfo
, UCHAR Head
)
624 * FUNCTION: Issue a read id command to the drive
626 * DriveInfo: Drive to read id from
627 * Head: Head to read the ID from
629 * STATUS_SUCCESS if the command is queued
630 * STATUS_UNSUCCESSFUL otherwise
632 * - Generates an interrupt
638 DPRINT("floppy: HwReadId called\n");
642 Buffer
[0] = COMMAND_READ_ID
| READ_ID_MFM
;
643 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | DriveInfo
->UnitNumber
;
645 for(i
= 0; i
< 2; i
++)
646 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
648 DPRINT("floppy: HwReadId: unable to send bytes to fifo\n");
649 return STATUS_UNSUCCESSFUL
;
652 return STATUS_SUCCESS
;
656 NTSTATUS NTAPI
HwFormatTrack(PCONTROLLER_INFO ControllerInfo
,
659 UCHAR BytesPerSector
,
660 UCHAR SectorsPerTrack
,
664 * FUNCTION: Format a track
666 * ControllerInfo: controller to target with the request
667 * Unit: drive to format on
668 * Head: head to format on
669 * BytesPerSector: constant from hardware.h to select density
670 * SectorsPerTrack: sectors per track
671 * Gap3Length: gap length to use during format
672 * FillerPattern: pattern to write into the data portion of sectors
674 * STATUS_SUCCESS if the command is successfully queued
675 * STATUS_UNSUCCESSFUL otherwise
681 DPRINT("floppy: HwFormatTrack called\n");
685 Buffer
[0] = COMMAND_FORMAT_TRACK
;
686 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
687 Buffer
[2] = BytesPerSector
;
688 Buffer
[3] = SectorsPerTrack
;
689 Buffer
[4] = Gap3Length
;
690 Buffer
[5] = FillerPattern
;
692 for(i
= 0; i
< 6; i
++)
693 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
695 DPRINT("floppy: HwFormatTrack: unable to send bytes to floppy\n");
696 return STATUS_UNSUCCESSFUL
;
699 return STATUS_SUCCESS
;
703 NTSTATUS NTAPI
HwSeek(PDRIVE_INFO DriveInfo
,
706 * FUNCTION: Seek the heads to a particular cylinder
708 * DriveInfo: Drive to seek
709 * Cylinder: cylinder to move to
711 * STATUS_SUCCESS if the command is successfully sent
712 * STATUS_UNSUCCESSFUL otherwise
714 * - Generates an interrupt
721 DPRINT("floppy: HwSeek called for cyl 0x%x\n", Cylinder
);
725 Buffer
[0] = COMMAND_SEEK
;
726 Buffer
[1] = DriveInfo
->UnitNumber
;
727 Buffer
[2] = Cylinder
;
729 for(i
= 0; i
< 3; i
++)
730 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
732 DPRINT("floppy: HwSeek: failed to write fifo\n");
733 return STATUS_UNSUCCESSFUL
;
736 /* Wait for the head to settle */
737 Delay
.QuadPart
= 10 * 1000;
738 Delay
.QuadPart
*= -1;
739 Delay
.QuadPart
*= DriveInfo
->FloppyDeviceData
.HeadSettleTime
;
741 KeDelayExecutionThread(KernelMode
, FALSE
, &Delay
);
743 return STATUS_SUCCESS
;
747 NTSTATUS NTAPI
HwConfigure(PCONTROLLER_INFO ControllerInfo
,
754 * FUNCTION: Sends configuration to the drive
756 * ControllerInfo: controller to target with the request
757 * EIS: Enable implied seek
758 * EFIFO: Enable advanced fifo
759 * POLL: Enable polling
760 * FIFOTHR: fifo threshold
761 * PRETRK: precomp (see intel datasheet)
763 * STATUS_SUCCESS if the command is successfully sent
764 * STATUS_UNSUCCESSFUL otherwise
772 DPRINT("floppy: HwConfigure called\n");
776 Buffer
[0] = COMMAND_CONFIGURE
;
778 Buffer
[2] = (EIS
* CONFIGURE_EIS
) + (EFIFO
* CONFIGURE_EFIFO
) + (POLL
* CONFIGURE_POLL
) + (FIFOTHR
);
781 for(i
= 0; i
< 4; i
++)
782 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
784 DPRINT("floppy: HwConfigure: failed to write the fifo\n");
785 return STATUS_UNSUCCESSFUL
;
788 return STATUS_SUCCESS
;
792 NTSTATUS NTAPI
HwGetVersion(PCONTROLLER_INFO ControllerInfo
)
794 * FUNCTION: Gets the version of the controller
796 * ControllerInfo: controller to target with the request
797 * ConfigValue: Configuration value to send to the drive (see header)
799 * Version number returned by the command, or
802 * - This command doesn't interrupt, so we go right to reading after
803 * we issue the command
810 if(Send_Byte(ControllerInfo
, COMMAND_VERSION
) != STATUS_SUCCESS
)
812 DPRINT("floppy: HwGetVersion: unable to write fifo\n");
813 return STATUS_UNSUCCESSFUL
;
816 if(Get_Byte(ControllerInfo
, &Buffer
) != STATUS_SUCCESS
)
818 DPRINT("floppy: HwGetVersion: unable to write fifo\n");
819 return STATUS_UNSUCCESSFUL
;
822 DPRINT("floppy: HwGetVersion returning version 0x%x\n", Buffer
);
827 NTSTATUS NTAPI
HwDiskChanged(PDRIVE_INFO DriveInfo
,
828 PBOOLEAN DiskChanged
)
830 * FUNCTION: Detect whether the hardware has sensed a disk change
832 * DriveInfo: pointer to the drive that we are to check
833 * DiskChanged: boolean that is set with whether or not the controller thinks there has been a disk change
835 * STATUS_SUCCESS if the drive is successfully queried
837 * - Does not interrupt.
838 * - Guessing a bit at the Model30 stuff
842 PCONTROLLER_INFO ControllerInfo
= (PCONTROLLER_INFO
) DriveInfo
->ControllerInfo
;
844 Buffer
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
);
846 DPRINT("floppy: HwDiskChanged: read 0x%x from DIR\n", Buffer
);
848 if(ControllerInfo
->Model30
)
850 if(!(Buffer
& DIR_DISKETTE_CHANGE
))
852 DPRINT("floppy: HdDiskChanged - Model30 - returning TRUE\n");
857 DPRINT("floppy: HdDiskChanged - Model30 - returning FALSE\n");
858 *DiskChanged
= FALSE
;
863 if(Buffer
& DIR_DISKETTE_CHANGE
)
865 DPRINT("floppy: HdDiskChanged - PS2 - returning TRUE\n");
870 DPRINT("floppy: HdDiskChanged - PS2 - returning FALSE\n");
871 *DiskChanged
= FALSE
;
875 return STATUS_SUCCESS
;
878 NTSTATUS NTAPI
HwSenseDriveStatusResult(PCONTROLLER_INFO ControllerInfo
,
881 * FUNCTION: Get the result of a sense drive status command
883 * ControllerInfo: controller to query
884 * Status: Status from the drive sense command
886 * STATUS_SUCCESS if we can successfully read the status
887 * STATUS_UNSUCCESSFUL otherwise
889 * - Called post-interrupt; does not interrupt
894 if(Get_Byte(ControllerInfo
, Status
) != STATUS_SUCCESS
)
896 DPRINT("floppy: HwSenseDriveStatus: unable to read fifo\n");
897 return STATUS_UNSUCCESSFUL
;
900 DPRINT("floppy: HwSenseDriveStatusResult: ST3: 0x%x\n", *Status
);
902 return STATUS_SUCCESS
;
906 NTSTATUS NTAPI
HwReadIdResult(PCONTROLLER_INFO ControllerInfo
,
910 * FUNCTION: Get the result of a read id command
912 * ControllerInfo: controller to query
913 * CurCylinder: Returns the cylinder that we're at
914 * CurHead: Returns the head that we're at
916 * STATUS_SUCCESS if the read id was a success
917 * STATUS_UNSUCCESSFUL otherwise
919 * - This function tests the error conditions itself, and boils the
920 * whole thing down to a single SUCCESS or FAILURE result
921 * - Called post-interrupt; does not interrupt
923 * - perhaps handle more status
926 UCHAR Buffer
[7] = {0,0,0,0,0,0,0};
931 for(i
= 0; i
< 7; i
++)
932 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
934 DPRINT("floppy: ReadIdResult(): can't read from the controller\n");
935 return STATUS_UNSUCCESSFUL
;
938 /* Validate that it did what we told it to */
939 DPRINT("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],
940 Buffer
[4], Buffer
[5], Buffer
[6]);
942 /* Last command successful? */
943 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
945 DPRINT("floppy: ReadId didn't return last command success\n");
946 return STATUS_UNSUCCESSFUL
;
950 if(Buffer
[1] & SR1_CANNOT_FIND_ID_ADDRESS
)
952 DPRINT("floppy: ReadId didn't find an address mark\n");
953 return STATUS_UNSUCCESSFUL
;
957 *CurCylinder
= Buffer
[3];
960 *CurHead
= Buffer
[4];
962 return STATUS_SUCCESS
;
966 NTSTATUS NTAPI
HwSpecify(PCONTROLLER_INFO ControllerInfo
,
968 UCHAR HeadUnloadTime
,
972 * FUNCTION: Set up timing and DMA mode for the controller
974 * ControllerInfo: Controller to set up
975 * HeadLoadTime: Head load time (see data sheet for details)
976 * HeadUnloadTime: Head unload time
977 * StepRateTime: Step rate time
978 * NonDma: TRUE to disable DMA mode
980 * STATUS_SUCCESS if the contrller is successfully programmed
981 * STATUS_UNSUCCESSFUL if not
983 * - Does not interrupt
985 * TODO: Figure out timings
991 Buffer
[0] = COMMAND_SPECIFY
;
993 Buffer[1] = (StepRateTime << 4) + HeadUnloadTime;
994 Buffer[2] = (HeadLoadTime << 1) + (NonDma ? 1 : 0);
999 //DPRINT("HwSpecify: sending 0x%x 0x%x 0x%x to FIFO\n", Buffer[0], Buffer[1], Buffer[2]);
1000 DPRINT("FLOPPY: HWSPECIFY: FIXME - sending 0x3 0xd1 0x2 to FIFO\n");
1002 for(i
= 0; i
< 3; i
++)
1003 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
1005 DPRINT("floppy: HwSpecify: unable to write to controller\n");
1006 return STATUS_UNSUCCESSFUL
;
1009 return STATUS_SUCCESS
;
1013 NTSTATUS NTAPI
HwReset(PCONTROLLER_INFO ControllerInfo
)
1015 * FUNCTION: Reset the controller
1017 * ControllerInfo: controller to reset
1019 * STATUS_SUCCESS in all cases
1021 * - Generates an interrupt that must be serviced four times (one per drive)
1024 DPRINT("floppy: HwReset called\n");
1026 /* Write the reset bit in the DRSR */
1027 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_SW_RESET
);
1029 /* Check for the reset bit in the DOR and set it if necessary (see Intel doc) */
1030 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
1032 HwDumpRegisters(ControllerInfo
);
1033 DPRINT("floppy: HwReset: Setting Enable bit\n");
1034 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_DMA_IO_INTERFACE_ENABLE
|DOR_RESET
);
1035 HwDumpRegisters(ControllerInfo
);
1037 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
1039 DPRINT("floppy: HwReset: failed to set the DOR enable bit!\n");
1040 HwDumpRegisters(ControllerInfo
);
1041 return STATUS_UNSUCCESSFUL
;
1045 return STATUS_SUCCESS
;
1049 NTSTATUS NTAPI
HwPowerOff(PCONTROLLER_INFO ControllerInfo
)
1051 * FUNCTION: Power down a controller
1053 * ControllerInfo: Controller to power down
1057 * - Wake up with a hardware reset
1060 DPRINT("floppy: HwPowerOff called on controller 0x%x\n", ControllerInfo
);
1062 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_POWER_DOWN
);
1064 return STATUS_SUCCESS
;
1067 VOID NTAPI
HwDumpRegisters(PCONTROLLER_INFO ControllerInfo
)
1069 * FUNCTION: Dump all readable registers from the floppy controller
1071 * ControllerInfo: Controller to dump registers from
1074 UNREFERENCED_PARAMETER(ControllerInfo
);
1076 DPRINT("floppy: STATUS: ");
1077 DPRINT("STATUS_REGISTER_A = 0x%x ", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_A
));
1078 DPRINT("STATUS_REGISTER_B = 0x%x ", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_B
));
1079 DPRINT("DIGITAL_OUTPUT_REGISTER = 0x%x ", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
));
1080 DPRINT("MAIN_STATUS_REGISTER =0x%x ", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
));
1081 DPRINT("DIGITAL_INPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
));