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.
55 * Hardware Support Routines
59 ReadyForWrite(PCONTROLLER_INFO ControllerInfo
)
61 * FUNCTION: Determine of the controller is ready to accept a byte on the FIFO
63 * ControllerInfo: Info structure for the FDC we're testing
65 * TRUE if the controller can accept a byte right now
68 * - it is necessary to check both that the FIFO is set to "outbound"
69 * and that the "ready for i/o" bit is set.
72 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
74 if(Status
& MSR_IO_DIRECTION
) /* 0 for out */
77 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
85 ReadyForRead(PCONTROLLER_INFO ControllerInfo
)
87 * FUNCTION: Determine of the controller is ready to read a byte on the FIFO
89 * ControllerInfo: Info structure for the FDC we're testing
91 * TRUE if the controller can read a byte right now
94 * - it is necessary to check both that the FIFO is set to "inbound"
95 * and that the "ready for i/o" bit is set.
98 UCHAR Status
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
);
100 if(!(Status
& MSR_IO_DIRECTION
)) /* Read = 1 */
103 if(!(Status
& MSR_DATA_REG_READY_FOR_IO
))
110 static NTSTATUS NTAPI
111 Send_Byte(PCONTROLLER_INFO ControllerInfo
, UCHAR Byte
)
113 * FUNCTION: Send a byte from the host to the controller's FIFO
115 * ControllerInfo: Info structure for the controller we're writing to
116 * Offset: Offset over the controller's base address that we're writing to
117 * Byte: Byte to write to the bus
119 * STATUS_SUCCESS if the byte was written successfully
120 * STATUS_UNSUCCESSFUL if not
122 * - Function designed after flowchart in intel datasheet
123 * - 250us max delay. Note that this is exactly 5 times longer
124 * than Microsoft recommends stalling the processor
125 * - PAGED_CODE, because we spin for more than the Microsoft-recommended
127 * - This function is necessary because sometimes the FIFO reacts slowly
128 * and isn't yet ready to read or write the next byte
135 for(i
= 0; i
< 5; i
++)
137 if(ReadyForWrite(ControllerInfo
))
140 KeStallExecutionProcessor(50);
145 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ FIFO
, Byte
);
146 return STATUS_SUCCESS
;
150 INFO_(FLOPPY
, "Send_Byte: timed out trying to write\n");
151 HwDumpRegisters(ControllerInfo
);
152 return STATUS_UNSUCCESSFUL
;
157 static NTSTATUS NTAPI
158 Get_Byte(PCONTROLLER_INFO ControllerInfo
, PUCHAR Byte
)
160 * FUNCTION: Read a byte from the controller to the host
162 * ControllerInfo: Info structure for the controller we're reading from
163 * Offset: Offset over the controller's base address that we're reading from
164 * Byte: Byte to read from the bus
166 * STATUS_SUCCESS if the byte was read successfully
167 * STATUS_UNSUCCESSFUL if not
169 * - Function designed after flowchart in intel datasheet
170 * - 250us max delay. Note that this is exactly 5 times longer
171 * than Microsoft recommends stalling the processor
172 * - Remember that we can be interrupted here, so this might
173 * take much more wall clock time than 250us
174 * - PAGED_CODE because we spin for longer than Microsoft recommends
181 for(i
= 0; i
< 5; i
++)
183 if(ReadyForRead(ControllerInfo
))
186 KeStallExecutionProcessor(50);
191 *Byte
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ FIFO
);
192 return STATUS_SUCCESS
;
196 INFO_(FLOPPY
, "Get_Byte: timed out trying to write\n");
197 HwDumpRegisters(ControllerInfo
);
198 return STATUS_UNSUCCESSFUL
;
204 HwSetDataRate(PCONTROLLER_INFO ControllerInfo
, UCHAR DataRate
)
206 * FUNCTION: Set the data rte on a controller
208 * ControllerInfo: Controller whose rate is being set
209 * DataRate: Data rate code to set the controller to
214 TRACE_(FLOPPY
, "HwSetDataRate called; writing rate code 0x%x to offset 0x%x\n", DataRate
, DATA_RATE_SELECT_REGISTER
);
216 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DataRate
);
218 return STATUS_SUCCESS
;
223 HwTurnOffMotor(PCONTROLLER_INFO ControllerInfo
)
225 * FUNCTION: Turn off all motors
227 * DriveInfo: drive to turn off
229 * STATUS_SUCCESS if the motor is successfully turned off
231 * - Don't call this routine directly unless you've thought about it
232 * and read the source to StartMotor() and StopMotor().
233 * - Called at DISPATCH_LEVEL
236 TRACE_(FLOPPY
, "HwTurnOffMotor: writing byte 0x%x to offset 0x%x\n", DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
, DIGITAL_OUTPUT_REGISTER
);
238 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_FDC_ENABLE
|DOR_DMA_IO_INTERFACE_ENABLE
);
240 return STATUS_SUCCESS
;
245 HwTurnOnMotor(PDRIVE_INFO DriveInfo
)
247 * FUNCTION: Turn on the motor on the selected drive
249 * DriveInfo: drive to turn on
251 * STATUS_SUCCESS if the motor is successfully turned on
252 * STATUS_UNSUCCESSFUL otherwise
254 * - Doesn't interrupt
255 * - Currently cannot fail
258 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
259 UCHAR Unit
= DriveInfo
->UnitNumber
;
267 Buffer
|= DOR_FDC_ENABLE
;
268 Buffer
|= DOR_DMA_IO_INTERFACE_ENABLE
;
271 Buffer
|= DOR_FLOPPY_MOTOR_ON_A
;
273 Buffer
|= DOR_FLOPPY_MOTOR_ON_B
;
275 Buffer
|= DOR_FLOPPY_MOTOR_ON_C
;
277 Buffer
|= DOR_FLOPPY_MOTOR_ON_D
;
279 TRACE_(FLOPPY
, "HwTurnOnMotor: writing byte 0x%x to offset 0x%x\n", Buffer
, DIGITAL_OUTPUT_REGISTER
);
280 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, Buffer
);
282 return STATUS_SUCCESS
;
287 HwSenseDriveStatus(PDRIVE_INFO DriveInfo
)
289 * FUNCTION: Start a sense status command
291 * DriveInfo: Drive to inquire about
293 * STATUS_SUCCESS if the command is successfully queued to the controller
294 * STATUS_UNSUCCESSFUL if not
296 * - Generates an interrupt
297 * - hard-wired to head 0
305 TRACE_(FLOPPY
, "HwSenseDriveStatus called\n");
307 Buffer
[0] = COMMAND_SENSE_DRIVE_STATUS
;
308 Buffer
[1] = DriveInfo
->UnitNumber
; /* hard-wired to head 0 for now */
310 for(i
= 0; i
< 2; i
++)
311 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
313 WARN_(FLOPPY
, "HwSenseDriveStatus: failed to write FIFO\n");
314 return STATUS_UNSUCCESSFUL
;
317 return STATUS_SUCCESS
;
322 HwReadWriteData(PCONTROLLER_INFO ControllerInfo
,
328 UCHAR BytesPerSector
,
333 * FUNCTION: Read or write data to the drive
335 * ControllerInfo: controller to target the read/write request to
336 * Read: TRUE if the device should be read; FALSE if written
337 * Unit: Drive number to target
338 * Cylinder: cylinder to start the read on
339 * Head: head to start the read on
340 * Sector: sector to start the read on (1-based!)
341 * BytesPerSector: sector size constant (hardware.h)
342 * EndOfTrack: Marks the last sector number to read/write on the track
343 * Gap3Length: Gap length for the operation
344 * DataLength: Bytes to read, *unless* BytesPerSector is specified
346 * STATUS_SUCCESS if the operation was successfully queued to the controller
347 * STATUS_UNSUCCESSFUL otherwise
349 * - Generates an interrupt
357 /* Shouldn't be using DataLength in this driver */
358 ASSERT(DataLength
== 0xff);
360 /* Build the command to send */
362 Buffer
[0] = COMMAND_READ_DATA
;
364 Buffer
[0] = COMMAND_WRITE_DATA
;
366 Buffer
[0] |= READ_DATA_MFM
| READ_DATA_MT
;
368 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
369 Buffer
[2] = Cylinder
;
372 Buffer
[5] = BytesPerSector
;
373 Buffer
[6] = EndOfTrack
;
374 Buffer
[7] = Gap3Length
;
375 Buffer
[8] = DataLength
;
377 /* Send the command */
378 for(i
= 0; i
< 9; i
++)
380 INFO_(FLOPPY
, "HwReadWriteData: Sending a command byte to the FIFO: 0x%x\n", Buffer
[i
]);
382 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
384 WARN_(FLOPPY
, "HwReadWriteData: Unable to write to the FIFO\n");
385 return STATUS_UNSUCCESSFUL
;
389 return STATUS_SUCCESS
;
394 HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo
)
396 * FUNCTION: Get the result of a recalibrate command
398 * ControllerInfo: controller to query
400 * STATUS_SUCCESS if the recalibratewas a success
401 * STATUS_UNSUCCESSFUL otherwise
403 * - This function tests the error conditions itself, and boils the
404 * whole thing down to a single SUCCESS or FAILURE result
405 * - Called post-interrupt; does not interrupt
407 * - perhaps handle more status
415 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
417 WARN_(FLOPPY
, "HwRecalibrateResult: Unable to write the controller\n");
418 return STATUS_UNSUCCESSFUL
;
421 for(i
= 0; i
< 2; i
++)
422 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
424 WARN_(FLOPPY
, "HwRecalibrateResult: unable to read FIFO\n");
425 return STATUS_UNSUCCESSFUL
;
428 /* Validate that it did what we told it to */
429 INFO_(FLOPPY
, "HwRecalibrateResult results: ST0: 0x%x PCN: 0x%x\n", Buffer
[0], Buffer
[1]);
439 WARN_(FLOPPY
, "HwRecalibrateResult: PCN not 0\n");
440 return STATUS_UNSUCCESSFUL
;
443 /* test seek complete */
444 if((Buffer
[0] & SR0_SEEK_COMPLETE
) != SR0_SEEK_COMPLETE
)
446 WARN_(FLOPPY
, "HwRecalibrateResult: Failed to complete the seek\n");
447 return STATUS_UNSUCCESSFUL
;
450 /* Is the equipment check flag set? Could be no disk in drive... */
451 if((Buffer
[0] & SR0_EQUIPMENT_CHECK
) == SR0_EQUIPMENT_CHECK
)
453 WARN_(FLOPPY
, "HwRecalibrateResult: Seeked to track 0 successfully, but EC is set; returning failure\n");
454 return STATUS_UNSUCCESSFUL
;
457 return STATUS_SUCCESS
;
462 HwReadWriteResult(PCONTROLLER_INFO ControllerInfo
)
464 * FUNCTION: Get the result of a read or write from the controller
466 * ControllerInfo: controller to query
468 * STATUS_SUCCESS if the read/write was a success
469 * STATUS_UNSUCCESSFUL otherwise
471 * - This function tests the error conditions itself, and boils the
472 * whole thing down to a single SUCCESS or FAILURE result
473 * - Called post-interrupt; does not interrupt
475 * - perhaps handle more status
483 for(i
= 0; i
< 7; i
++)
484 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
486 WARN_(FLOPPY
, "HwReadWriteResult: unable to read fifo\n");
487 return STATUS_UNSUCCESSFUL
;
490 /* Validate that it did what we told it to */
491 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],
492 Buffer
[4], Buffer
[5], Buffer
[6]);
494 /* Last command successful? */
495 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
496 return STATUS_UNSUCCESSFUL
;
498 return STATUS_SUCCESS
;
503 HwRecalibrate(PDRIVE_INFO DriveInfo
)
505 * FUNCTION: Start a recalibration of a drive
507 * DriveInfo: Drive to recalibrate
509 * STATUS_SUCCESS if the command was successfully queued to the controller
510 * STATUS_UNSUCCESSFUL otherwise
512 * - Generates an interrupt
515 PCONTROLLER_INFO ControllerInfo
= DriveInfo
->ControllerInfo
;
516 UCHAR Unit
= DriveInfo
->UnitNumber
;
520 TRACE_(FLOPPY
, "HwRecalibrate called\n");
524 Buffer
[0] = COMMAND_RECALIBRATE
;
527 for(i
= 0; i
< 2; i
++)
528 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
530 WARN_(FLOPPY
, "HwRecalibrate: unable to write FIFO\n");
531 return STATUS_UNSUCCESSFUL
;
534 return STATUS_SUCCESS
;
539 HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo
)
541 * FUNCTION: Send a sense interrupt status command to a controller
543 * ControllerInfo: controller to queue the command to
545 * STATUS_SUCCESS if the command is queued successfully
546 * STATUS_UNSUCCESSFUL if not
554 if(Send_Byte(ControllerInfo
, COMMAND_SENSE_INTERRUPT_STATUS
) != STATUS_SUCCESS
)
556 WARN_(FLOPPY
, "HwSenseInterruptStatus: failed to write controller\n");
557 return STATUS_UNSUCCESSFUL
;
560 for(i
= 0; i
< 2; i
++)
562 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
564 WARN_(FLOPPY
, "HwSenseInterruptStatus: failed to read controller\n");
565 return STATUS_UNSUCCESSFUL
;
569 INFO_(FLOPPY
, "HwSenseInterruptStatus returned 0x%x 0x%x\n", Buffer
[0], Buffer
[1]);
571 return STATUS_SUCCESS
;
576 HwReadId(PDRIVE_INFO DriveInfo
, UCHAR Head
)
578 * FUNCTION: Issue a read id command to the drive
580 * DriveInfo: Drive to read id from
581 * Head: Head to read the ID from
583 * STATUS_SUCCESS if the command is queued
584 * STATUS_UNSUCCESSFUL otherwise
586 * - Generates an interrupt
592 TRACE_(FLOPPY
, "HwReadId called\n");
596 Buffer
[0] = COMMAND_READ_ID
| READ_ID_MFM
;
597 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | DriveInfo
->UnitNumber
;
599 for(i
= 0; i
< 2; i
++)
600 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
602 WARN_(FLOPPY
, "HwReadId: unable to send bytes to fifo\n");
603 return STATUS_UNSUCCESSFUL
;
606 return STATUS_SUCCESS
;
611 HwFormatTrack(PCONTROLLER_INFO ControllerInfo
,
614 UCHAR BytesPerSector
,
615 UCHAR SectorsPerTrack
,
619 * FUNCTION: Format a track
621 * ControllerInfo: controller to target with the request
622 * Unit: drive to format on
623 * Head: head to format on
624 * BytesPerSector: constant from hardware.h to select density
625 * SectorsPerTrack: sectors per track
626 * Gap3Length: gap length to use during format
627 * FillerPattern: pattern to write into the data portion of sectors
629 * STATUS_SUCCESS if the command is successfully queued
630 * STATUS_UNSUCCESSFUL otherwise
636 TRACE_(FLOPPY
, "HwFormatTrack called\n");
640 Buffer
[0] = COMMAND_FORMAT_TRACK
;
641 Buffer
[1] = (Head
<< COMMAND_HEAD_NUMBER_SHIFT
) | Unit
;
642 Buffer
[2] = BytesPerSector
;
643 Buffer
[3] = SectorsPerTrack
;
644 Buffer
[4] = Gap3Length
;
645 Buffer
[5] = FillerPattern
;
647 for(i
= 0; i
< 6; i
++)
648 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
650 WARN_(FLOPPY
, "HwFormatTrack: unable to send bytes to floppy\n");
651 return STATUS_UNSUCCESSFUL
;
654 return STATUS_SUCCESS
;
659 HwSeek(PDRIVE_INFO DriveInfo
, UCHAR Cylinder
)
661 * FUNCTION: Seek the heads to a particular cylinder
663 * DriveInfo: Drive to seek
664 * Cylinder: cylinder to move to
666 * STATUS_SUCCESS if the command is successfully sent
667 * STATUS_UNSUCCESSFUL otherwise
669 * - Generates an interrupt
676 TRACE_(FLOPPY
, "HwSeek called for cyl 0x%x\n", Cylinder
);
680 Buffer
[0] = COMMAND_SEEK
;
681 Buffer
[1] = DriveInfo
->UnitNumber
;
682 Buffer
[2] = Cylinder
;
684 for(i
= 0; i
< 3; i
++)
685 if(Send_Byte(DriveInfo
->ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
687 WARN_(FLOPPY
, "HwSeek: failed to write fifo\n");
688 return STATUS_UNSUCCESSFUL
;
691 /* Wait for the head to settle */
692 Delay
.QuadPart
= 10 * 1000;
693 Delay
.QuadPart
*= -1;
694 Delay
.QuadPart
*= DriveInfo
->FloppyDeviceData
.HeadSettleTime
;
696 KeDelayExecutionThread(KernelMode
, FALSE
, &Delay
);
698 return STATUS_SUCCESS
;
703 HwConfigure(PCONTROLLER_INFO ControllerInfo
,
710 * FUNCTION: Sends configuration to the drive
712 * ControllerInfo: controller to target with the request
713 * EIS: Enable implied seek
714 * EFIFO: Enable advanced fifo
715 * POLL: Enable polling
716 * FIFOTHR: fifo threshold
717 * PRETRK: precomp (see intel datasheet)
719 * STATUS_SUCCESS if the command is successfully sent
720 * STATUS_UNSUCCESSFUL otherwise
728 TRACE_(FLOPPY
, "HwConfigure called\n");
732 Buffer
[0] = COMMAND_CONFIGURE
;
734 Buffer
[2] = (EIS
* CONFIGURE_EIS
) + (EFIFO
* CONFIGURE_EFIFO
) + (POLL
* CONFIGURE_POLL
) + (FIFOTHR
);
737 for(i
= 0; i
< 4; i
++)
738 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
740 WARN_(FLOPPY
, "HwConfigure: failed to write the fifo\n");
741 return STATUS_UNSUCCESSFUL
;
744 return STATUS_SUCCESS
;
749 HwGetVersion(PCONTROLLER_INFO ControllerInfo
)
751 * FUNCTION: Gets the version of the controller
753 * ControllerInfo: controller to target with the request
754 * ConfigValue: Configuration value to send to the drive (see header)
756 * Version number returned by the command, or
759 * - This command doesn't interrupt, so we go right to reading after
760 * we issue the command
767 if(Send_Byte(ControllerInfo
, COMMAND_VERSION
) != STATUS_SUCCESS
)
769 WARN_(FLOPPY
, "HwGetVersion: unable to write fifo\n");
770 return STATUS_UNSUCCESSFUL
;
773 if(Get_Byte(ControllerInfo
, &Buffer
) != STATUS_SUCCESS
)
775 WARN_(FLOPPY
, "HwGetVersion: unable to write fifo\n");
776 return STATUS_UNSUCCESSFUL
;
779 INFO_(FLOPPY
, "HwGetVersion returning version 0x%x\n", Buffer
);
785 HwDiskChanged(PDRIVE_INFO DriveInfo
, PBOOLEAN DiskChanged
)
787 * FUNCTION: Detect whether the hardware has sensed a disk change
789 * DriveInfo: pointer to the drive that we are to check
790 * DiskChanged: boolean that is set with whether or not the controller thinks there has been a disk change
792 * STATUS_SUCCESS if the drive is successfully queried
794 * - Does not interrupt.
795 * - Guessing a bit at the Model30 stuff
799 PCONTROLLER_INFO ControllerInfo
= (PCONTROLLER_INFO
) DriveInfo
->ControllerInfo
;
801 Buffer
= READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
);
803 TRACE_(FLOPPY
, "HwDiskChanged: read 0x%x from DIR\n", Buffer
);
805 if(ControllerInfo
->Model30
)
807 if(!(Buffer
& DIR_DISKETTE_CHANGE
))
809 INFO_(FLOPPY
, "HdDiskChanged - Model30 - returning TRUE\n");
814 INFO_(FLOPPY
, "HdDiskChanged - Model30 - returning FALSE\n");
815 *DiskChanged
= FALSE
;
820 if(Buffer
& DIR_DISKETTE_CHANGE
)
822 INFO_(FLOPPY
, "HdDiskChanged - PS2 - returning TRUE\n");
827 INFO_(FLOPPY
, "HdDiskChanged - PS2 - returning FALSE\n");
828 *DiskChanged
= FALSE
;
832 return STATUS_SUCCESS
;
836 HwSenseDriveStatusResult(PCONTROLLER_INFO ControllerInfo
, PUCHAR Status
)
838 * FUNCTION: Get the result of a sense drive status command
840 * ControllerInfo: controller to query
841 * Status: Status from the drive sense command
843 * STATUS_SUCCESS if we can successfully read the status
844 * STATUS_UNSUCCESSFUL otherwise
846 * - Called post-interrupt; does not interrupt
851 if(Get_Byte(ControllerInfo
, Status
) != STATUS_SUCCESS
)
853 WARN_(FLOPPY
, "HwSenseDriveStatus: unable to read fifo\n");
854 return STATUS_UNSUCCESSFUL
;
857 TRACE_(FLOPPY
, "HwSenseDriveStatusResult: ST3: 0x%x\n", *Status
);
859 return STATUS_SUCCESS
;
864 HwReadIdResult(PCONTROLLER_INFO ControllerInfo
,
868 * FUNCTION: Get the result of a read id command
870 * ControllerInfo: controller to query
871 * CurCylinder: Returns the cylinder that we're at
872 * CurHead: Returns the head that we're at
874 * STATUS_SUCCESS if the read id was a success
875 * STATUS_UNSUCCESSFUL otherwise
877 * - This function tests the error conditions itself, and boils the
878 * whole thing down to a single SUCCESS or FAILURE result
879 * - Called post-interrupt; does not interrupt
881 * - perhaps handle more status
884 UCHAR Buffer
[7] = {0,0,0,0,0,0,0};
889 for(i
= 0; i
< 7; i
++)
890 if(Get_Byte(ControllerInfo
, &Buffer
[i
]) != STATUS_SUCCESS
)
892 WARN_(FLOPPY
, "ReadIdResult(): can't read from the controller\n");
893 return STATUS_UNSUCCESSFUL
;
896 /* Validate that it did what we told it to */
897 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],
898 Buffer
[4], Buffer
[5], Buffer
[6]);
900 /* Last command successful? */
901 if((Buffer
[0] & SR0_LAST_COMMAND_STATUS
) != SR0_LCS_SUCCESS
)
903 WARN_(FLOPPY
, "ReadId didn't return last command success\n");
904 return STATUS_UNSUCCESSFUL
;
908 if(Buffer
[1] & SR1_CANNOT_FIND_ID_ADDRESS
)
910 WARN_(FLOPPY
, "ReadId didn't find an address mark\n");
911 return STATUS_UNSUCCESSFUL
;
915 *CurCylinder
= Buffer
[3];
918 *CurHead
= Buffer
[4];
920 return STATUS_SUCCESS
;
925 HwSpecify(PCONTROLLER_INFO ControllerInfo
,
927 UCHAR HeadUnloadTime
,
931 * FUNCTION: Set up timing and DMA mode for the controller
933 * ControllerInfo: Controller to set up
934 * HeadLoadTime: Head load time (see data sheet for details)
935 * HeadUnloadTime: Head unload time
936 * StepRateTime: Step rate time
937 * NonDma: TRUE to disable DMA mode
939 * STATUS_SUCCESS if the controller is successfully programmed
940 * STATUS_UNSUCCESSFUL if not
942 * - Does not interrupt
944 * TODO: Figure out timings
950 Buffer
[0] = COMMAND_SPECIFY
;
952 Buffer[1] = (StepRateTime << 4) + HeadUnloadTime;
953 Buffer[2] = (HeadLoadTime << 1) + (NonDma ? 1 : 0);
958 //INFO_(FLOPPY, "HwSpecify: sending 0x%x 0x%x 0x%x to FIFO\n", Buffer[0], Buffer[1], Buffer[2]);
959 WARN_(FLOPPY
, "HWSPECIFY: FIXME - sending 0x3 0xd1 0x2 to FIFO\n");
961 for(i
= 0; i
< 3; i
++)
962 if(Send_Byte(ControllerInfo
, Buffer
[i
]) != STATUS_SUCCESS
)
964 WARN_(FLOPPY
, "HwSpecify: unable to write to controller\n");
965 return STATUS_UNSUCCESSFUL
;
968 return STATUS_SUCCESS
;
973 HwReset(PCONTROLLER_INFO ControllerInfo
)
975 * FUNCTION: Reset the controller
977 * ControllerInfo: controller to reset
979 * STATUS_SUCCESS in all cases
981 * - Generates an interrupt that must be serviced four times (one per drive)
984 TRACE_(FLOPPY
, "HwReset called\n");
986 /* Write the reset bit in the DRSR */
987 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_SW_RESET
);
989 /* Check for the reset bit in the DOR and set it if necessary (see Intel doc) */
990 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
992 HwDumpRegisters(ControllerInfo
);
993 INFO_(FLOPPY
, "HwReset: Setting Enable bit\n");
994 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
, DOR_DMA_IO_INTERFACE_ENABLE
|DOR_RESET
);
995 HwDumpRegisters(ControllerInfo
);
997 if(!(READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
) & DOR_RESET
))
999 WARN_(FLOPPY
, "HwReset: failed to set the DOR enable bit!\n");
1000 HwDumpRegisters(ControllerInfo
);
1001 return STATUS_UNSUCCESSFUL
;
1005 return STATUS_SUCCESS
;
1010 HwPowerOff(PCONTROLLER_INFO ControllerInfo
)
1012 * FUNCTION: Power down a controller
1014 * ControllerInfo: Controller to power down
1018 * - Wake up with a hardware reset
1021 TRACE_(FLOPPY
, "HwPowerOff called on controller 0x%p\n", ControllerInfo
);
1023 WRITE_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DATA_RATE_SELECT_REGISTER
, DRSR_POWER_DOWN
);
1025 return STATUS_SUCCESS
;
1029 HwDumpRegisters(PCONTROLLER_INFO ControllerInfo
)
1031 * FUNCTION: Dump all readable registers from the floppy controller
1033 * ControllerInfo: Controller to dump registers from
1036 UNREFERENCED_PARAMETER(ControllerInfo
);
1038 INFO_(FLOPPY
, "STATUS:\n");
1039 INFO_(FLOPPY
, "STATUS_REGISTER_A = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_A
));
1040 INFO_(FLOPPY
, "STATUS_REGISTER_B = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ STATUS_REGISTER_B
));
1041 INFO_(FLOPPY
, "DIGITAL_OUTPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_OUTPUT_REGISTER
));
1042 INFO_(FLOPPY
, "MAIN_STATUS_REGISTER =0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ MAIN_STATUS_REGISTER
));
1043 INFO_(FLOPPY
, "DIGITAL_INPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo
->BaseAddress
+ DIGITAL_INPUT_REGISTER
));