ReactOS  0.4.13-dev-249-gcba1a2f
hardware.c
Go to the documentation of this file.
1 /*
2  * ReactOS Floppy Driver
3  * Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
4  *
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.
9  *
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.
14  *
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.
18  *
19  * PROJECT: ReactOS Floppy Driver
20  * FILE: hardware.c
21  * PURPOSE: FDC Hardware control routines
22  * PROGRAMMER: Vizzini (vizzini@plasmic.com)
23  * REVISIONS:
24  * 15-Feb-2004 vizzini - Created
25  * NOTES:
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
41  * thread.
42  * - Some information taken from Intel 82077AA data sheet (order #290166-007)
43  *
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  */
49 
50 #include "precomp.h"
51 
52 #include <debug.h>
53 
54 /*
55  * Hardware Support Routines
56  */
57 
58 static BOOLEAN NTAPI
60 /*
61  * FUNCTION: Determine of the controller is ready to accept a byte on the FIFO
62  * ARGUMENTS:
63  * ControllerInfo: Info structure for the FDC we're testing
64  * RETURNS:
65  * TRUE if the controller can accept a byte right now
66  * FALSE otherwise
67  * NOTES:
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.
70  */
71 {
73 
74  if(Status & MSR_IO_DIRECTION) /* 0 for out */
75  return FALSE;
76 
78  return FALSE;
79 
80  return TRUE;
81 }
82 
83 
84 static BOOLEAN NTAPI
86 /*
87  * FUNCTION: Determine of the controller is ready to read a byte on the FIFO
88  * ARGUMENTS:
89  * ControllerInfo: Info structure for the FDC we're testing
90  * RETURNS:
91  * TRUE if the controller can read a byte right now
92  * FALSE otherwise
93  * NOTES:
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.
96  */
97 {
99 
100  if(!(Status & MSR_IO_DIRECTION)) /* Read = 1 */
101  return FALSE;
102 
104  return FALSE;
105 
106  return TRUE;
107 }
108 
109 
110 static NTSTATUS NTAPI
112 /*
113  * FUNCTION: Send a byte from the host to the controller's FIFO
114  * ARGUMENTS:
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
118  * RETURNS:
119  * STATUS_SUCCESS if the byte was written successfully
120  * STATUS_UNSUCCESSFUL if not
121  * NOTES:
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
126  * maximum.
127  * - This function is necessary because sometimes the FIFO reacts slowly
128  * and isn't yet ready to read or write the next byte
129  */
130 {
131  int i;
132 
133  PAGED_CODE();
134 
135  for(i = 0; i < 5; i++)
136  {
137  if(ReadyForWrite(ControllerInfo))
138  break;
139 
141  }
142 
143  if (i < 5)
144  {
145  WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + FIFO, Byte);
146  return STATUS_SUCCESS;
147  }
148  else
149  {
150  INFO_(FLOPPY, "Send_Byte: timed out trying to write\n");
151  HwDumpRegisters(ControllerInfo);
152  return STATUS_UNSUCCESSFUL;
153  }
154 }
155 
156 
157 static NTSTATUS NTAPI
159 /*
160  * FUNCTION: Read a byte from the controller to the host
161  * ARGUMENTS:
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
165  * RETURNS:
166  * STATUS_SUCCESS if the byte was read successfully
167  * STATUS_UNSUCCESSFUL if not
168  * NOTES:
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
175  */
176 {
177  int i;
178 
179  PAGED_CODE();
180 
181  for(i = 0; i < 5; i++)
182  {
183  if(ReadyForRead(ControllerInfo))
184  break;
185 
187  }
188 
189  if (i < 5)
190  {
191  *Byte = READ_PORT_UCHAR(ControllerInfo->BaseAddress + FIFO);
192  return STATUS_SUCCESS;
193  }
194  else
195  {
196  INFO_(FLOPPY, "Get_Byte: timed out trying to write\n");
197  HwDumpRegisters(ControllerInfo);
198  return STATUS_UNSUCCESSFUL;
199  }
200 }
201 
202 
204 HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
205 /*
206  * FUNCTION: Set the data rte on a controller
207  * ARGUMENTS:
208  * ControllerInfo: Controller whose rate is being set
209  * DataRate: Data rate code to set the controller to
210  * RETURNS:
211  * STATUS_SUCCESS
212  */
213 {
214  TRACE_(FLOPPY, "HwSetDataRate called; writing rate code 0x%x to offset 0x%x\n", DataRate, DATA_RATE_SELECT_REGISTER);
215 
216  WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DATA_RATE_SELECT_REGISTER, DataRate);
217 
218  return STATUS_SUCCESS;
219 }
220 
221 
224 /*
225  * FUNCTION: Turn off all motors
226  * ARGUMENTS:
227  * DriveInfo: drive to turn off
228  * RETURNS:
229  * STATUS_SUCCESS if the motor is successfully turned off
230  * NOTES:
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
234  */
235 {
236  TRACE_(FLOPPY, "HwTurnOffMotor: writing byte 0x%x to offset 0x%x\n", DOR_FDC_ENABLE|DOR_DMA_IO_INTERFACE_ENABLE, DIGITAL_OUTPUT_REGISTER);
237 
239 
240  return STATUS_SUCCESS;
241 }
242 
243 
246 /*
247  * FUNCTION: Turn on the motor on the selected drive
248  * ARGUMENTS:
249  * DriveInfo: drive to turn on
250  * RETURNS:
251  * STATUS_SUCCESS if the motor is successfully turned on
252  * STATUS_UNSUCCESSFUL otherwise
253  * NOTES:
254  * - Doesn't interrupt
255  * - Currently cannot fail
256  */
257 {
258  PCONTROLLER_INFO ControllerInfo = DriveInfo->ControllerInfo;
259  UCHAR Unit = DriveInfo->UnitNumber;
260  UCHAR Buffer;
261 
262  PAGED_CODE();
263 
264  /* turn on motor */
265  Buffer = Unit;
266 
269 
270  if(Unit == 0)
272  else if (Unit == 1)
274  else if (Unit == 2)
276  else if (Unit == 3)
278 
279  TRACE_(FLOPPY, "HwTurnOnMotor: writing byte 0x%x to offset 0x%x\n", Buffer, DIGITAL_OUTPUT_REGISTER);
281 
282  return STATUS_SUCCESS;
283 }
284 
285 
288 /*
289  * FUNCTION: Start a sense status command
290  * ARGUMENTS:
291  * DriveInfo: Drive to inquire about
292  * RETURNS:
293  * STATUS_SUCCESS if the command is successfully queued to the controller
294  * STATUS_UNSUCCESSFUL if not
295  * NOTES:
296  * - Generates an interrupt
297  * - hard-wired to head 0
298  */
299 {
300  UCHAR Buffer[2];
301  int i;
302 
303  PAGED_CODE();
304 
305  TRACE_(FLOPPY, "HwSenseDriveStatus called\n");
306 
308  Buffer[1] = DriveInfo->UnitNumber; /* hard-wired to head 0 for now */
309 
310  for(i = 0; i < 2; i++)
311  if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
312  {
313  WARN_(FLOPPY, "HwSenseDriveStatus: failed to write FIFO\n");
314  return STATUS_UNSUCCESSFUL;
315  }
316 
317  return STATUS_SUCCESS;
318 }
319 
320 
323  BOOLEAN Read,
324  UCHAR Unit,
325  UCHAR Cylinder,
326  UCHAR Head,
327  UCHAR Sector,
328  UCHAR BytesPerSector,
329  UCHAR EndOfTrack,
330  UCHAR Gap3Length,
332 /*
333  * FUNCTION: Read or write data to the drive
334  * ARGUMENTS:
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
345  * RETURNS:
346  * STATUS_SUCCESS if the operation was successfully queued to the controller
347  * STATUS_UNSUCCESSFUL otherwise
348  * NOTES:
349  * - Generates an interrupt
350  */
351 {
352  UCHAR Buffer[9];
353  int i;
354 
355  PAGED_CODE();
356 
357  /* Shouldn't be using DataLength in this driver */
358  ASSERT(DataLength == 0xff);
359 
360  /* Build the command to send */
361  if(Read)
363  else
365 
367 
368  Buffer[1] = (Head << COMMAND_HEAD_NUMBER_SHIFT) | Unit;
369  Buffer[2] = Cylinder;
370  Buffer[3] = Head;
371  Buffer[4] = Sector;
372  Buffer[5] = BytesPerSector;
373  Buffer[6] = EndOfTrack;
374  Buffer[7] = Gap3Length;
375  Buffer[8] = DataLength;
376 
377  /* Send the command */
378  for(i = 0; i < 9; i++)
379  {
380  INFO_(FLOPPY, "HwReadWriteData: Sending a command byte to the FIFO: 0x%x\n", Buffer[i]);
381 
382  if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
383  {
384  WARN_(FLOPPY, "HwReadWriteData: Unable to write to the FIFO\n");
385  return STATUS_UNSUCCESSFUL;
386  }
387  }
388 
389  return STATUS_SUCCESS;
390 }
391 
392 
395 /*
396  * FUNCTION: Get the result of a recalibrate command
397  * ARGUMENTS:
398  * ControllerInfo: controller to query
399  * RETURNS:
400  * STATUS_SUCCESS if the recalibratewas a success
401  * STATUS_UNSUCCESSFUL otherwise
402  * NOTES:
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
406  * TODO
407  * - perhaps handle more status
408  */
409 {
410  UCHAR Buffer[2];
411  int i;
412 
413  PAGED_CODE();
414 
416  {
417  WARN_(FLOPPY, "HwRecalibrateResult: Unable to write the controller\n");
418  return STATUS_UNSUCCESSFUL;
419  }
420 
421  for(i = 0; i < 2; i++)
422  if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
423  {
424  WARN_(FLOPPY, "HwRecalibrateResult: unable to read FIFO\n");
425  return STATUS_UNSUCCESSFUL;
426  }
427 
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]);
430 
431  /*
432  * Buffer[0] = ST0
433  * Buffer[1] = PCN
434  */
435 
436  /* Is the PCN 0? */
437  if(Buffer[1] != 0)
438  {
439  WARN_(FLOPPY, "HwRecalibrateResult: PCN not 0\n");
440  return STATUS_UNSUCCESSFUL;
441  }
442 
443  /* test seek complete */
445  {
446  WARN_(FLOPPY, "HwRecalibrateResult: Failed to complete the seek\n");
447  return STATUS_UNSUCCESSFUL;
448  }
449 
450  /* Is the equipment check flag set? Could be no disk in drive... */
452  {
453  WARN_(FLOPPY, "HwRecalibrateResult: Seeked to track 0 successfully, but EC is set; returning failure\n");
454  return STATUS_UNSUCCESSFUL;
455  }
456 
457  return STATUS_SUCCESS;
458 }
459 
460 
463 /*
464  * FUNCTION: Get the result of a read or write from the controller
465  * ARGUMENTS:
466  * ControllerInfo: controller to query
467  * RETURNS:
468  * STATUS_SUCCESS if the read/write was a success
469  * STATUS_UNSUCCESSFUL otherwise
470  * NOTES:
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
474  * TODO:
475  * - perhaps handle more status
476  */
477 {
478  UCHAR Buffer[7];
479  int i;
480 
481  PAGED_CODE();
482 
483  for(i = 0; i < 7; i++)
484  if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
485  {
486  WARN_(FLOPPY, "HwReadWriteResult: unable to read fifo\n");
487  return STATUS_UNSUCCESSFUL;
488  }
489 
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]);
493 
494  /* Last command successful? */
496  return STATUS_UNSUCCESSFUL;
497 
498  return STATUS_SUCCESS;
499 }
500 
501 
504 /*
505  * FUNCTION: Start a recalibration of a drive
506  * ARGUMENTS:
507  * DriveInfo: Drive to recalibrate
508  * RETURNS:
509  * STATUS_SUCCESS if the command was successfully queued to the controller
510  * STATUS_UNSUCCESSFUL otherwise
511  * NOTES:
512  * - Generates an interrupt
513  */
514 {
515  PCONTROLLER_INFO ControllerInfo = DriveInfo->ControllerInfo;
516  UCHAR Unit = DriveInfo->UnitNumber;
517  UCHAR Buffer[2];
518  int i;
519 
520  TRACE_(FLOPPY, "HwRecalibrate called\n");
521 
522  PAGED_CODE();
523 
525  Buffer[1] = Unit;
526 
527  for(i = 0; i < 2; i++)
528  if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
529  {
530  WARN_(FLOPPY, "HwRecalibrate: unable to write FIFO\n");
531  return STATUS_UNSUCCESSFUL;
532  }
533 
534  return STATUS_SUCCESS;
535 }
536 
537 
540 /*
541  * FUNCTION: Send a sense interrupt status command to a controller
542  * ARGUMENTS:
543  * ControllerInfo: controller to queue the command to
544  * RETURNS:
545  * STATUS_SUCCESS if the command is queued successfully
546  * STATUS_UNSUCCESSFUL if not
547  */
548 {
549  UCHAR Buffer[2];
550  int i;
551 
552  PAGED_CODE();
553 
555  {
556  WARN_(FLOPPY, "HwSenseInterruptStatus: failed to write controller\n");
557  return STATUS_UNSUCCESSFUL;
558  }
559 
560  for(i = 0; i < 2; i++)
561  {
562  if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
563  {
564  WARN_(FLOPPY, "HwSenseInterruptStatus: failed to read controller\n");
565  return STATUS_UNSUCCESSFUL;
566  }
567  }
568 
569  INFO_(FLOPPY, "HwSenseInterruptStatus returned 0x%x 0x%x\n", Buffer[0], Buffer[1]);
570 
571  return STATUS_SUCCESS;
572 }
573 
574 
576 HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
577 /*
578  * FUNCTION: Issue a read id command to the drive
579  * ARGUMENTS:
580  * DriveInfo: Drive to read id from
581  * Head: Head to read the ID from
582  * RETURNS:
583  * STATUS_SUCCESS if the command is queued
584  * STATUS_UNSUCCESSFUL otherwise
585  * NOTES:
586  * - Generates an interrupt
587  */
588 {
589  UCHAR Buffer[2];
590  int i;
591 
592  TRACE_(FLOPPY, "HwReadId called\n");
593 
594  PAGED_CODE();
595 
597  Buffer[1] = (Head << COMMAND_HEAD_NUMBER_SHIFT) | DriveInfo->UnitNumber;
598 
599  for(i = 0; i < 2; i++)
600  if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
601  {
602  WARN_(FLOPPY, "HwReadId: unable to send bytes to fifo\n");
603  return STATUS_UNSUCCESSFUL;
604  }
605 
606  return STATUS_SUCCESS;
607 }
608 
609 
612  UCHAR Unit,
613  UCHAR Head,
614  UCHAR BytesPerSector,
616  UCHAR Gap3Length,
617  UCHAR FillerPattern)
618 /*
619  * FUNCTION: Format a track
620  * ARGUMENTS:
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
628  * RETURNS:
629  * STATUS_SUCCESS if the command is successfully queued
630  * STATUS_UNSUCCESSFUL otherwise
631  */
632 {
633  UCHAR Buffer[6];
634  int i;
635 
636  TRACE_(FLOPPY, "HwFormatTrack called\n");
637 
638  PAGED_CODE();
639 
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;
646 
647  for(i = 0; i < 6; i++)
648  if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
649  {
650  WARN_(FLOPPY, "HwFormatTrack: unable to send bytes to floppy\n");
651  return STATUS_UNSUCCESSFUL;
652  }
653 
654  return STATUS_SUCCESS;
655 }
656 
657 
659 HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
660 /*
661  * FUNCTION: Seek the heads to a particular cylinder
662  * ARGUMENTS:
663  * DriveInfo: Drive to seek
664  * Cylinder: cylinder to move to
665  * RETURNS:
666  * STATUS_SUCCESS if the command is successfully sent
667  * STATUS_UNSUCCESSFUL otherwise
668  * NOTES:
669  * - Generates an interrupt
670  */
671 {
672  LARGE_INTEGER Delay;
673  UCHAR Buffer[3];
674  int i;
675 
676  TRACE_(FLOPPY, "HwSeek called for cyl 0x%x\n", Cylinder);
677 
678  PAGED_CODE();
679 
680  Buffer[0] = COMMAND_SEEK;
681  Buffer[1] = DriveInfo->UnitNumber;
682  Buffer[2] = Cylinder;
683 
684  for(i = 0; i < 3; i++)
685  if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
686  {
687  WARN_(FLOPPY, "HwSeek: failed to write fifo\n");
688  return STATUS_UNSUCCESSFUL;
689  }
690 
691  /* Wait for the head to settle */
692  Delay.QuadPart = 10 * 1000;
693  Delay.QuadPart *= -1;
694  Delay.QuadPart *= DriveInfo->FloppyDeviceData.HeadSettleTime;
695 
697 
698  return STATUS_SUCCESS;
699 }
700 
701 
704  BOOLEAN EIS,
705  BOOLEAN EFIFO,
706  BOOLEAN POLL,
707  UCHAR FIFOTHR,
708  UCHAR PRETRK)
709 /*
710  * FUNCTION: Sends configuration to the drive
711  * ARGUMENTS:
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)
718  * RETURNS:
719  * STATUS_SUCCESS if the command is successfully sent
720  * STATUS_UNSUCCESSFUL otherwise
721  * NOTES:
722  * - No interrupt
723  */
724 {
725  UCHAR Buffer[4];
726  int i;
727 
728  TRACE_(FLOPPY, "HwConfigure called\n");
729 
730  PAGED_CODE();
731 
733  Buffer[1] = 0;
734  Buffer[2] = (EIS * CONFIGURE_EIS) + (EFIFO * CONFIGURE_EFIFO) + (POLL * CONFIGURE_POLL) + (FIFOTHR);
735  Buffer[3] = PRETRK;
736 
737  for(i = 0; i < 4; i++)
738  if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
739  {
740  WARN_(FLOPPY, "HwConfigure: failed to write the fifo\n");
741  return STATUS_UNSUCCESSFUL;
742  }
743 
744  return STATUS_SUCCESS;
745 }
746 
747 
750 /*
751  * FUNCTION: Gets the version of the controller
752  * ARGUMENTS:
753  * ControllerInfo: controller to target with the request
754  * ConfigValue: Configuration value to send to the drive (see header)
755  * RETURNS:
756  * Version number returned by the command, or
757  * 0 on failure
758  * NOTE:
759  * - This command doesn't interrupt, so we go right to reading after
760  * we issue the command
761  */
762 {
763  UCHAR Buffer;
764 
765  PAGED_CODE();
766 
767  if(Send_Byte(ControllerInfo, COMMAND_VERSION) != STATUS_SUCCESS)
768  {
769  WARN_(FLOPPY, "HwGetVersion: unable to write fifo\n");
770  return STATUS_UNSUCCESSFUL;
771  }
772 
773  if(Get_Byte(ControllerInfo, &Buffer) != STATUS_SUCCESS)
774  {
775  WARN_(FLOPPY, "HwGetVersion: unable to write fifo\n");
776  return STATUS_UNSUCCESSFUL;
777  }
778 
779  INFO_(FLOPPY, "HwGetVersion returning version 0x%x\n", Buffer);
780 
781  return Buffer;
782 }
783 
785 HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
786 /*
787  * FUNCTION: Detect whether the hardware has sensed a disk change
788  * ARGUMENTS:
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
791  * RETURNS:
792  * STATUS_SUCCESS if the drive is successfully queried
793  * NOTES:
794  * - Does not interrupt.
795  * - Guessing a bit at the Model30 stuff
796  */
797 {
798  UCHAR Buffer;
799  PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO) DriveInfo->ControllerInfo;
800 
802 
803  TRACE_(FLOPPY, "HwDiskChanged: read 0x%x from DIR\n", Buffer);
804 
805  if(ControllerInfo->Model30)
806  {
807  if(!(Buffer & DIR_DISKETTE_CHANGE))
808  {
809  INFO_(FLOPPY, "HdDiskChanged - Model30 - returning TRUE\n");
810  *DiskChanged = TRUE;
811  }
812  else
813  {
814  INFO_(FLOPPY, "HdDiskChanged - Model30 - returning FALSE\n");
815  *DiskChanged = FALSE;
816  }
817  }
818  else
819  {
821  {
822  INFO_(FLOPPY, "HdDiskChanged - PS2 - returning TRUE\n");
823  *DiskChanged = TRUE;
824  }
825  else
826  {
827  INFO_(FLOPPY, "HdDiskChanged - PS2 - returning FALSE\n");
828  *DiskChanged = FALSE;
829  }
830  }
831 
832  return STATUS_SUCCESS;
833 }
834 
837 /*
838  * FUNCTION: Get the result of a sense drive status command
839  * ARGUMENTS:
840  * ControllerInfo: controller to query
841  * Status: Status from the drive sense command
842  * RETURNS:
843  * STATUS_SUCCESS if we can successfully read the status
844  * STATUS_UNSUCCESSFUL otherwise
845  * NOTES:
846  * - Called post-interrupt; does not interrupt
847  */
848 {
849  PAGED_CODE();
850 
851  if(Get_Byte(ControllerInfo, Status) != STATUS_SUCCESS)
852  {
853  WARN_(FLOPPY, "HwSenseDriveStatus: unable to read fifo\n");
854  return STATUS_UNSUCCESSFUL;
855  }
856 
857  TRACE_(FLOPPY, "HwSenseDriveStatusResult: ST3: 0x%x\n", *Status);
858 
859  return STATUS_SUCCESS;
860 }
861 
862 
865  PUCHAR CurCylinder,
866  PUCHAR CurHead)
867 /*
868  * FUNCTION: Get the result of a read id command
869  * ARGUMENTS:
870  * ControllerInfo: controller to query
871  * CurCylinder: Returns the cylinder that we're at
872  * CurHead: Returns the head that we're at
873  * RETURNS:
874  * STATUS_SUCCESS if the read id was a success
875  * STATUS_UNSUCCESSFUL otherwise
876  * NOTES:
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
880  * TODO
881  * - perhaps handle more status
882  */
883 {
884  UCHAR Buffer[7] = {0,0,0,0,0,0,0};
885  int i;
886 
887  PAGED_CODE();
888 
889  for(i = 0; i < 7; i++)
890  if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
891  {
892  WARN_(FLOPPY, "ReadIdResult(): can't read from the controller\n");
893  return STATUS_UNSUCCESSFUL;
894  }
895 
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]);
899 
900  /* Last command successful? */
902  {
903  WARN_(FLOPPY, "ReadId didn't return last command success\n");
904  return STATUS_UNSUCCESSFUL;
905  }
906 
907  /* ID mark found? */
909  {
910  WARN_(FLOPPY, "ReadId didn't find an address mark\n");
911  return STATUS_UNSUCCESSFUL;
912  }
913 
914  if(CurCylinder)
915  *CurCylinder = Buffer[3];
916 
917  if(CurHead)
918  *CurHead = Buffer[4];
919 
920  return STATUS_SUCCESS;
921 }
922 
923 
926  UCHAR HeadLoadTime,
927  UCHAR HeadUnloadTime,
928  UCHAR StepRateTime,
929  BOOLEAN NonDma)
930 /*
931  * FUNCTION: Set up timing and DMA mode for the controller
932  * ARGUMENTS:
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
938  * RETURNS:
939  * STATUS_SUCCESS if the controller is successfully programmed
940  * STATUS_UNSUCCESSFUL if not
941  * NOTES:
942  * - Does not interrupt
943  *
944  * TODO: Figure out timings
945  */
946 {
947  UCHAR Buffer[3];
948  int i;
949 
950  Buffer[0] = COMMAND_SPECIFY;
951  /*
952  Buffer[1] = (StepRateTime << 4) + HeadUnloadTime;
953  Buffer[2] = (HeadLoadTime << 1) + (NonDma ? 1 : 0);
954  */
955  Buffer[1] = 0xdf;
956  Buffer[2] = 0x2;
957 
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");
960 
961  for(i = 0; i < 3; i++)
962  if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
963  {
964  WARN_(FLOPPY, "HwSpecify: unable to write to controller\n");
965  return STATUS_UNSUCCESSFUL;
966  }
967 
968  return STATUS_SUCCESS;
969 }
970 
971 
973 HwReset(PCONTROLLER_INFO ControllerInfo)
974 /*
975  * FUNCTION: Reset the controller
976  * ARGUMENTS:
977  * ControllerInfo: controller to reset
978  * RETURNS:
979  * STATUS_SUCCESS in all cases
980  * NOTES:
981  * - Generates an interrupt that must be serviced four times (one per drive)
982  */
983 {
984  TRACE_(FLOPPY, "HwReset called\n");
985 
986  /* Write the reset bit in the DRSR */
988 
989  /* Check for the reset bit in the DOR and set it if necessary (see Intel doc) */
991  {
992  HwDumpRegisters(ControllerInfo);
993  INFO_(FLOPPY, "HwReset: Setting Enable bit\n");
995  HwDumpRegisters(ControllerInfo);
996 
998  {
999  WARN_(FLOPPY, "HwReset: failed to set the DOR enable bit!\n");
1000  HwDumpRegisters(ControllerInfo);
1001  return STATUS_UNSUCCESSFUL;
1002  }
1003  }
1004 
1005  return STATUS_SUCCESS;
1006 }
1007 
1008 
1011 /*
1012  * FUNCTION: Power down a controller
1013  * ARGUMENTS:
1014  * ControllerInfo: Controller to power down
1015  * RETURNS:
1016  * STATUS_SUCCESS
1017  * NOTES:
1018  * - Wake up with a hardware reset
1019  */
1020 {
1021  TRACE_(FLOPPY, "HwPowerOff called on controller 0x%p\n", ControllerInfo);
1022 
1024 
1025  return STATUS_SUCCESS;
1026 }
1027 
1028 VOID NTAPI
1030 /*
1031  * FUNCTION: Dump all readable registers from the floppy controller
1032  * ARGUMENTS:
1033  * ControllerInfo: Controller to dump registers from
1034  */
1035 {
1036  UNREFERENCED_PARAMETER(ControllerInfo);
1037 
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));
1044 }
#define COMMAND_VERSION
Definition: hardware.h:200
#define COMMAND_FORMAT_TRACK
Definition: hardware.h:198
struct _CONTROLLER_INFO * PCONTROLLER_INFO
_In_ BOOLEAN Read
Definition: strmini.h:479
static BOOLEAN NTAPI ReadyForWrite(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:59
#define TRUE
Definition: types.h:120
#define INFO_(ch,...)
Definition: debug.h:159
#define COMMAND_SPECIFY
Definition: hardware.h:189
Unit
Definition: gdiplusenums.h:25
#define COMMAND_HEAD_NUMBER_SHIFT
Definition: hardware.h:236
unsigned char Byte
Definition: zconf.h:391
#define READ_ID_MFM
Definition: hardware.h:215
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
unsigned char * PUCHAR
Definition: retypes.h:3
#define FIFO
Definition: hardware.h:49
UCHAR NTAPI READ_PORT_UCHAR(PUCHAR Address)
Definition: mach.c:535
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS NTAPI HwReadIdResult(PCONTROLLER_INFO ControllerInfo, PUCHAR CurCylinder, PUCHAR CurHead)
Definition: hardware.c:864
NTSTATUS NTAPI HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
Definition: hardware.c:785
#define DIGITAL_INPUT_REGISTER
Definition: hardware.h:51
NTSTATUS NTAPI HwFormatTrack(PCONTROLLER_INFO ControllerInfo, UCHAR Unit, UCHAR Head, UCHAR BytesPerSector, UCHAR SectorsPerTrack, UCHAR Gap3Length, UCHAR FillerPattern)
Definition: hardware.c:611
#define DOR_DMA_IO_INTERFACE_ENABLE
Definition: hardware.h:76
VOID NTAPI HwDumpRegisters(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:1029
#define MAIN_STATUS_REGISTER
Definition: hardware.h:47
#define CONFIGURE_POLL
Definition: hardware.h:247
struct _CONTROLLER_INFO * ControllerInfo
Definition: fdc.h:23
#define PAGED_CODE()
Definition: video.h:57
#define DOR_FLOPPY_MOTOR_ON_A
Definition: hardware.h:77
#define DIR_DISKETTE_CHANGE
Definition: hardware.h:176
#define MSR_DATA_REG_READY_FOR_IO
Definition: hardware.h:96
NTSTATUS NTAPI HwTurnOffMotor(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:223
NTSTATUS NTAPI HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
Definition: hardware.c:204
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_In_ ULONG _In_ ULONG SectorsPerTrack
Definition: iofuncs.h:2066
#define DATA_RATE_SELECT_REGISTER
Definition: hardware.h:48
#define SR0_EQUIPMENT_CHECK
Definition: hardware.h:116
NTSTATUS NTAPI KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
Definition: wait.c:283
NTSTATUS NTAPI HwReset(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:973
unsigned char BOOLEAN
NTSTATUS NTAPI HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
Definition: hardware.c:576
NTSTATUS NTAPI HwSenseDriveStatusResult(PCONTROLLER_INFO ControllerInfo, PUCHAR Status)
Definition: hardware.c:836
#define STATUS_REGISTER_A
Definition: hardware.h:43
Definition: bufpool.h:45
NTSTATUS NTAPI HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:394
static NTSTATUS NTAPI Get_Byte(PCONTROLLER_INFO ControllerInfo, PUCHAR Byte)
Definition: hardware.c:158
static BOOLEAN NTAPI ReadyForRead(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:85
NTSTATUS NTAPI HwTurnOnMotor(PDRIVE_INFO DriveInfo)
Definition: hardware.c:245
NTSTATUS NTAPI HwConfigure(PCONTROLLER_INFO ControllerInfo, BOOLEAN EIS, BOOLEAN EFIFO, BOOLEAN POLL, UCHAR FIFOTHR, UCHAR PRETRK)
Definition: hardware.c:703
NTSTATUS NTAPI HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:539
#define DOR_FLOPPY_MOTOR_ON_B
Definition: hardware.h:78
#define TRACE_(x)
Definition: compat.h:66
NTSTATUS NTAPI HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
Definition: hardware.c:659
NTSTATUS NTAPI HwGetVersion(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:749
#define READ_DATA_MT
Definition: hardware.h:212
#define SR0_SEEK_COMPLETE
Definition: hardware.h:117
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define DIGITAL_OUTPUT_REGISTER
Definition: hardware.h:45
#define MSR_IO_DIRECTION
Definition: hardware.h:95
#define COMMAND_WRITE_DATA
Definition: hardware.h:191
unsigned char UCHAR
Definition: xmlstorage.h:181
BOOLEAN Model30
Definition: floppy.h:82
char * PBOOLEAN
Definition: retypes.h:11
CM_FLOPPY_DEVICE_DATA FloppyDeviceData
Definition: fdc.h:27
#define COMMAND_SEEK
Definition: hardware.h:199
#define COMMAND_READ_DATA
Definition: hardware.h:192
#define SR0_LAST_COMMAND_STATUS
Definition: hardware.h:118
UCHAR UnitNumber
Definition: fdc.h:24
NTSTATUS NTAPI HwReadWriteData(PCONTROLLER_INFO ControllerInfo, BOOLEAN Read, UCHAR Unit, UCHAR Cylinder, UCHAR Head, UCHAR Sector, UCHAR BytesPerSector, UCHAR EndOfTrack, UCHAR Gap3Length, UCHAR DataLength)
Definition: hardware.c:322
#define COMMAND_READ_ID
Definition: hardware.h:196
Status
Definition: gdiplustypes.h:24
#define DRSR_POWER_DOWN
Definition: hardware.h:102
#define COMMAND_SENSE_DRIVE_STATUS
Definition: hardware.h:190
#define DOR_RESET
Definition: hardware.h:75
NTSTATUS NTAPI HwPowerOff(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:1010
NTSTATUS NTAPI HwRecalibrate(PDRIVE_INFO DriveInfo)
Definition: hardware.c:503
#define CONFIGURE_EFIFO
Definition: hardware.h:248
#define CONFIGURE_EIS
Definition: hardware.h:249
#define DOR_FDC_ENABLE
Definition: hardware.h:74
#define DOR_FLOPPY_MOTOR_ON_D
Definition: hardware.h:80
static NTSTATUS NTAPI Send_Byte(PCONTROLLER_INFO ControllerInfo, UCHAR Byte)
Definition: hardware.c:111
#define DRSR_SW_RESET
Definition: hardware.h:103
#define DOR_FLOPPY_MOTOR_ON_C
Definition: hardware.h:79
#define COMMAND_SENSE_INTERRUPT_STATUS
Definition: hardware.h:194
PUCHAR BaseAddress
Definition: fdc.h:49
#define STATUS_REGISTER_B
Definition: hardware.h:44
NTSTATUS NTAPI HwSpecify(PCONTROLLER_INFO ControllerInfo, UCHAR HeadLoadTime, UCHAR HeadUnloadTime, UCHAR StepRateTime, BOOLEAN NonDma)
Definition: hardware.c:925
NTSTATUS NTAPI HwReadWriteResult(PCONTROLLER_INFO ControllerInfo)
Definition: hardware.c:462
void WRITE_PORT_UCHAR(PUCHAR Address, UCHAR Value)
Definition: mach.c:539
NTSTATUS NTAPI HwSenseDriveStatus(PDRIVE_INFO DriveInfo)
Definition: hardware.c:287
#define COMMAND_RECALIBRATE
Definition: hardware.h:193
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
return STATUS_SUCCESS
Definition: btrfs.c:2745
#define SR0_LCS_SUCCESS
Definition: hardware.h:133
#define WARN_(ch,...)
Definition: debug.h:157
#define READ_DATA_MFM
Definition: hardware.h:211
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:99
#define COMMAND_CONFIGURE
Definition: hardware.h:202
#define SR1_CANNOT_FIND_ID_ADDRESS
Definition: hardware.h:139
LONGLONG QuadPart
Definition: typedefs.h:112