ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

hardware.c
Go to the documentation of this file.
00001 /*
00002  *  ReactOS Floppy Driver
00003  *  Copyright (C) 2004, Vizzini (vizzini@plasmic.com)
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License along
00016  *  with this program; if not, write to the Free Software Foundation, Inc.,
00017  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018  *
00019  * PROJECT:         ReactOS Floppy Driver
00020  * FILE:            hardware.c
00021  * PURPOSE:         FDC Hardware control routines
00022  * PROGRAMMER:      Vizzini (vizzini@plasmic.com)
00023  * REVISIONS:
00024  *                  15-Feb-2004 vizzini - Created
00025  * NOTES:
00026  *     - Many of these functions are based directly on information from the
00027  *       Intel datasheet for their enhanced floppy controller.  Send_Byte and
00028  *       Get_Byte are direct C implementations of their flowcharts, and the
00029  *       read/write routine and others are loose adaptations of their charts.
00030  *     - These routines are generally designed to be small, atomic operations.  They
00031  *       do not wait for interrupts, deal with DMA, or do any other Windows-
00032  *       specific things, unless they have to.
00033  *     - If you compare this to Microsoft samples or to the old ReactOS driver,
00034  *       or even to the linux driver, you will notice a big difference:  we use
00035  *       a system thread to drain the queue.  This is because it's illegal to block
00036  *       in a dispatch routine, unless you're a top-level driver (which we absolutely
00037  *       are not).  One big reason is that we may be called at raised IRQL, at which
00038  *       it's illegal to block.  The floppy controller is a *dumb* piece of hardware,
00039  *       too - it is slow and difficult to deal with.  The solution is to do all
00040  *       of the blocking and servicing of the controller in a dedicated worker
00041  *       thread.
00042  *     - Some information taken from Intel 82077AA data sheet (order #290166-007)
00043  *
00044  * TODO: ATM the constants defined in hardware.h *might* be shifted to line up
00045  *       with the bit position in the register, or they *might not*.  This should
00046  *       all be converted to standardize on absolute values or shifts.
00047  *       I prefer bit fields, but they break endianness.
00048  */
00049 
00050 #include "precomp.h"
00051 
00052 /*
00053  * Hardware Support Routines
00054  */
00055 
00056 
00057 static BOOLEAN NTAPI
00058 ReadyForWrite(PCONTROLLER_INFO ControllerInfo)
00059 /*
00060  * FUNCTION: Determine of the controller is ready to accept a byte on the FIFO
00061  * ARGUMENTS:
00062  *     ControllerInfo: Info structure for the FDC we're testing
00063  * RETURNS:
00064  *     TRUE if the controller can accept a byte right now
00065  *     FALSE otherwise
00066  * NOTES:
00067  *     - it is necessary to check both that the FIFO is set to "outbound"
00068  *       and that the "ready for i/o" bit is set.
00069  */
00070 {
00071     UCHAR Status = READ_PORT_UCHAR(ControllerInfo->BaseAddress + MAIN_STATUS_REGISTER);
00072 
00073     if(Status & MSR_IO_DIRECTION) /* 0 for out */
00074         return FALSE;
00075 
00076     if(!(Status & MSR_DATA_REG_READY_FOR_IO))
00077         return FALSE;
00078 
00079     return TRUE;
00080 }
00081 
00082 
00083 static BOOLEAN NTAPI
00084 ReadyForRead(PCONTROLLER_INFO ControllerInfo)
00085 /*
00086  * FUNCTION: Determine of the controller is ready to read a byte on the FIFO
00087  * ARGUMENTS:
00088  *     ControllerInfo: Info structure for the FDC we're testing
00089  * RETURNS:
00090  *     TRUE if the controller can read a byte right now
00091  *     FALSE otherwise
00092  * NOTES:
00093  *     - it is necessary to check both that the FIFO is set to "inbound"
00094  *       and that the "ready for i/o" bit is set.
00095  */
00096 {
00097     UCHAR Status = READ_PORT_UCHAR(ControllerInfo->BaseAddress + MAIN_STATUS_REGISTER);
00098 
00099     if(!(Status & MSR_IO_DIRECTION)) /* Read = 1 */
00100         return FALSE;
00101 
00102     if(!(Status & MSR_DATA_REG_READY_FOR_IO))
00103         return FALSE;
00104 
00105     return TRUE;
00106 }
00107 
00108 
00109 static NTSTATUS NTAPI
00110 Send_Byte(PCONTROLLER_INFO ControllerInfo, UCHAR Byte)
00111 /*
00112  * FUNCTION: Send a byte from the host to the controller's FIFO
00113  * ARGUMENTS:
00114  *     ControllerInfo: Info structure for the controller we're writing to
00115  *     Offset: Offset over the controller's base address that we're writing to
00116  *     Byte: Byte to write to the bus
00117  * RETURNS:
00118  *     STATUS_SUCCESS if the byte was written successfully
00119  *     STATUS_UNSUCCESSFUL if not
00120  * NOTES:
00121  *     - Function designed after flowchart in intel datasheet
00122  *     - 250us max delay.  Note that this is exactly 5 times longer
00123  *       than Microsoft recommends stalling the processor
00124  *     - PAGED_CODE, because we spin for more than the Microsoft-recommended
00125  *       maximum.
00126  *     - This function is necessary because sometimes the FIFO reacts slowly
00127  *       and isn't yet ready to read or write the next byte
00128  */
00129 {
00130     int i;
00131 
00132     PAGED_CODE();
00133 
00134     for(i = 0; i < 5; i++)
00135     {
00136         if(ReadyForWrite(ControllerInfo))
00137             break;
00138 
00139         KeStallExecutionProcessor(50);
00140     }
00141 
00142     if (i < 5)
00143     {
00144         WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + FIFO, Byte);
00145         return STATUS_SUCCESS;
00146     }
00147     else
00148     {
00149         INFO_(FLOPPY, "Send_Byte: timed out trying to write\n");
00150         HwDumpRegisters(ControllerInfo);
00151         return STATUS_UNSUCCESSFUL;
00152     }
00153 }
00154 
00155 
00156 static NTSTATUS NTAPI
00157 Get_Byte(PCONTROLLER_INFO ControllerInfo, PUCHAR Byte)
00158 /*
00159  * FUNCTION: Read a byte from the controller to the host
00160  * ARGUMENTS:
00161  *     ControllerInfo: Info structure for the controller we're reading from
00162  *     Offset: Offset over the controller's base address  that we're reading from
00163  *     Byte: Byte to read from the bus
00164  * RETURNS:
00165  *     STATUS_SUCCESS if the byte was read successfully
00166  *     STATUS_UNSUCCESSFUL if not
00167  * NOTES:
00168  *     - Function designed after flowchart in intel datasheet
00169  *     - 250us max delay.  Note that this is exactly 5 times longer
00170  *       than Microsoft recommends stalling the processor
00171  *     - Remember that we can be interrupted here, so this might
00172  *       take much more wall clock time than 250us
00173  *     - PAGED_CODE because we spin for longer than Microsoft recommends
00174  */
00175 {
00176     int i;
00177 
00178     PAGED_CODE();
00179 
00180     for(i = 0; i < 5; i++)
00181     {
00182         if(ReadyForRead(ControllerInfo))
00183             break;
00184 
00185         KeStallExecutionProcessor(50);
00186     }
00187 
00188     if (i < 5)
00189     {
00190         *Byte = READ_PORT_UCHAR(ControllerInfo->BaseAddress + FIFO);
00191         return STATUS_SUCCESS;
00192     }
00193     else
00194     {
00195         INFO_(FLOPPY, "Get_Byte: timed out trying to write\n");
00196         HwDumpRegisters(ControllerInfo);
00197         return STATUS_UNSUCCESSFUL;
00198     }
00199 }
00200 
00201 
00202 NTSTATUS NTAPI
00203 HwSetDataRate(PCONTROLLER_INFO ControllerInfo, UCHAR DataRate)
00204 /*
00205  * FUNCTION: Set the data rte on a controller
00206  * ARGUMENTS:
00207  *     ControllerInfo: Controller whose rate is being set
00208  *     DataRate: Data rate code to set the controller to
00209  * RETURNS:
00210  *     STATUS_SUCCESS
00211  */
00212 {
00213     TRACE_(FLOPPY, "HwSetDataRate called; writing rate code 0x%x to offset 0x%x\n", DataRate, DATA_RATE_SELECT_REGISTER);
00214 
00215     WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DATA_RATE_SELECT_REGISTER, DataRate);
00216 
00217     return STATUS_SUCCESS;
00218 }
00219 
00220 
00221 NTSTATUS NTAPI
00222 HwTurnOffMotor(PCONTROLLER_INFO ControllerInfo)
00223 /*
00224  * FUNCTION: Turn off all motors
00225  * ARGUMENTS:
00226  *     DriveInfo: drive to turn off
00227  * RETURNS:
00228  *     STATUS_SUCCESS if the motor is successfully turned off
00229  * NOTES:
00230  *     - Don't call this routine directly unless you've thought about it
00231  *       and read the source to StartMotor() and StopMotor().
00232  *     - Called at DISPATCH_LEVEL
00233  */
00234 {
00235     TRACE_(FLOPPY, "HwTurnOffMotor: writing byte 0x%x to offset 0x%x\n", DOR_FDC_ENABLE|DOR_DMA_IO_INTERFACE_ENABLE, DIGITAL_OUTPUT_REGISTER);
00236 
00237     WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER, DOR_FDC_ENABLE|DOR_DMA_IO_INTERFACE_ENABLE);
00238 
00239     return STATUS_SUCCESS;
00240 }
00241 
00242 
00243 NTSTATUS NTAPI
00244 HwTurnOnMotor(PDRIVE_INFO DriveInfo)
00245 /*
00246  * FUNCTION: Turn on the motor on the selected drive
00247  * ARGUMENTS:
00248  *     DriveInfo: drive to turn on
00249  * RETURNS:
00250  *     STATUS_SUCCESS if the motor is successfully turned on
00251  *     STATUS_UNSUCCESSFUL otherwise
00252  * NOTES:
00253  *     - Doesn't interrupt
00254  *     - Currently cannot fail
00255  */
00256 {
00257     PCONTROLLER_INFO ControllerInfo = DriveInfo->ControllerInfo;
00258     UCHAR Unit = DriveInfo->UnitNumber;
00259     UCHAR Buffer;
00260 
00261     PAGED_CODE();
00262 
00263     /* turn on motor */
00264     Buffer = Unit;
00265 
00266     Buffer |= DOR_FDC_ENABLE;
00267     Buffer |= DOR_DMA_IO_INTERFACE_ENABLE;
00268 
00269     if(Unit == 0)
00270         Buffer |= DOR_FLOPPY_MOTOR_ON_A;
00271     else if (Unit == 1)
00272         Buffer |= DOR_FLOPPY_MOTOR_ON_B;
00273     else if (Unit == 2)
00274         Buffer |= DOR_FLOPPY_MOTOR_ON_C;
00275     else if (Unit == 3)
00276         Buffer |= DOR_FLOPPY_MOTOR_ON_D;
00277 
00278     TRACE_(FLOPPY, "HwTurnOnMotor: writing byte 0x%x to offset 0x%x\n", Buffer, DIGITAL_OUTPUT_REGISTER);
00279     WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER, Buffer);
00280 
00281     return STATUS_SUCCESS;
00282 }
00283 
00284 
00285 NTSTATUS NTAPI
00286 HwSenseDriveStatus(PDRIVE_INFO DriveInfo)
00287 /*
00288  * FUNCTION: Start a sense status command
00289  * ARGUMENTS:
00290  *     DriveInfo: Drive to inquire about
00291  * RETURNS:
00292  *     STATUS_SUCCESS if the command is successfully queued to the controller
00293  *     STATUS_UNSUCCESSFUL if not
00294  * NOTES:
00295  *     - Generates an interrupt
00296  *     - hard-wired to head 0
00297  */
00298 {
00299     UCHAR Buffer[2];
00300     int i;
00301 
00302     PAGED_CODE();
00303 
00304     TRACE_(FLOPPY, "HwSenseDriveStatus called\n");
00305 
00306     Buffer[0] = COMMAND_SENSE_DRIVE_STATUS;
00307     Buffer[1] = DriveInfo->UnitNumber; /* hard-wired to head 0 for now */
00308 
00309     for(i = 0; i < 2; i++)
00310         if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00311         {
00312             WARN_(FLOPPY, "HwSenseDriveStatus: failed to write FIFO\n");
00313             return STATUS_UNSUCCESSFUL;
00314         }
00315 
00316     return STATUS_SUCCESS;
00317 }
00318 
00319 
00320 NTSTATUS NTAPI
00321 HwReadWriteData(PCONTROLLER_INFO ControllerInfo,
00322                 BOOLEAN Read,
00323                 UCHAR Unit,
00324                 UCHAR Cylinder,
00325                 UCHAR Head,
00326                 UCHAR Sector,
00327                 UCHAR BytesPerSector,
00328                 UCHAR EndOfTrack,
00329                 UCHAR Gap3Length,
00330                 UCHAR DataLength)
00331 /*
00332  * FUNCTION: Read or write data to the drive
00333  * ARGUMENTS:
00334  *     ControllerInfo: controller to target the read/write request to
00335  *     Read: TRUE if the device should be read; FALSE if written
00336  *     Unit: Drive number to target
00337  *     Cylinder: cylinder to start the read on
00338  *     Head: head to start the read on
00339  *     Sector: sector to start the read on (1-based!)
00340  *     BytesPerSector: sector size constant (hardware.h)
00341  *     EndOfTrack: Marks the last sector number to read/write on the track
00342  *     Gap3Length: Gap length for the operation
00343  *     DataLength: Bytes to read, *unless* BytesPerSector is specified
00344  * RETURNS:
00345  *     STATUS_SUCCESS if the operation was successfully queued to the controller
00346  *     STATUS_UNSUCCESSFUL otherwise
00347  * NOTES:
00348  *     - Generates an interrupt
00349  */
00350 {
00351     UCHAR Buffer[9];
00352     int i;
00353 
00354     PAGED_CODE();
00355 
00356     /* Shouldn't be using DataLength in this driver */
00357     ASSERT(DataLength == 0xff);
00358 
00359     /* Build the command to send */
00360     if(Read)
00361         Buffer[0] = COMMAND_READ_DATA;
00362     else
00363         Buffer[0] = COMMAND_WRITE_DATA;
00364 
00365     Buffer[0] |= READ_DATA_MFM | READ_DATA_MT;
00366 
00367     Buffer[1] = (Head << COMMAND_HEAD_NUMBER_SHIFT) | Unit;
00368     Buffer[2] = Cylinder;
00369     Buffer[3] = Head;
00370     Buffer[4] = Sector;
00371     Buffer[5] = BytesPerSector;
00372     Buffer[6] = EndOfTrack;
00373     Buffer[7] = Gap3Length;
00374     Buffer[8] = DataLength;
00375 
00376     /* Send the command */
00377     for(i = 0; i < 9; i++)
00378     {
00379         INFO_(FLOPPY, "HwReadWriteData: Sending a command byte to the FIFO: 0x%x\n", Buffer[i]);
00380 
00381         if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00382         {
00383             WARN_(FLOPPY, "HwReadWriteData: Unable to write to the FIFO\n");
00384             return STATUS_UNSUCCESSFUL;
00385         }
00386     }
00387 
00388     return STATUS_SUCCESS;
00389 }
00390 
00391 
00392 NTSTATUS NTAPI
00393 HwRecalibrateResult(PCONTROLLER_INFO ControllerInfo)
00394 /*
00395  * FUNCTION: Get the result of a recalibrate command
00396  * ARGUMENTS:
00397  *     ControllerInfo: controller to query
00398  * RETURNS:
00399  *     STATUS_SUCCESS if the recalibratewas a success
00400  *     STATUS_UNSUCCESSFUL otherwise
00401  * NOTES:
00402  *     - This function tests the error conditions itself, and boils the
00403  *       whole thing down to a single SUCCESS or FAILURE result
00404  *     - Called post-interrupt; does not interrupt
00405  * TODO
00406  *     - perhaps handle more status
00407  */
00408 {
00409     UCHAR Buffer[2];
00410     int i;
00411 
00412     PAGED_CODE();
00413 
00414     if(Send_Byte(ControllerInfo, COMMAND_SENSE_INTERRUPT_STATUS) != STATUS_SUCCESS)
00415     {
00416         WARN_(FLOPPY, "HwRecalibrateResult: Unable to write the controller\n");
00417         return STATUS_UNSUCCESSFUL;
00418     }
00419 
00420     for(i = 0; i < 2; i++)
00421         if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
00422         {
00423             WARN_(FLOPPY, "HwRecalibrateResult: unable to read FIFO\n");
00424             return STATUS_UNSUCCESSFUL;
00425         }
00426 
00427     /* Validate  that it did what we told it to */
00428     INFO_(FLOPPY, "HwRecalibrateResult results: ST0: 0x%x PCN: 0x%x\n", Buffer[0], Buffer[1]);
00429 
00430     /*
00431      * Buffer[0] = ST0
00432      * Buffer[1] = PCN
00433      */
00434 
00435     /* Is the PCN 0? */
00436     if(Buffer[1] != 0)
00437     {
00438         WARN_(FLOPPY, "HwRecalibrateResult: PCN not 0\n");
00439         return STATUS_UNSUCCESSFUL;
00440     }
00441 
00442     /* test seek complete */
00443     if((Buffer[0] & SR0_SEEK_COMPLETE) != SR0_SEEK_COMPLETE)
00444     {
00445         WARN_(FLOPPY, "HwRecalibrateResult: Failed to complete the seek\n");
00446         return STATUS_UNSUCCESSFUL;
00447     }
00448 
00449     /* Is the equipment check flag set?  Could be no disk in drive... */
00450     if((Buffer[0] & SR0_EQUIPMENT_CHECK) == SR0_EQUIPMENT_CHECK)
00451     {
00452         WARN_(FLOPPY, "HwRecalibrateResult: Seeked to track 0 successfully, but EC is set; returning failure\n");
00453         return STATUS_UNSUCCESSFUL;
00454     }
00455 
00456     return STATUS_SUCCESS;
00457 }
00458 
00459 
00460 NTSTATUS NTAPI
00461 HwReadWriteResult(PCONTROLLER_INFO ControllerInfo)
00462 /*
00463  * FUNCTION: Get the result of a read or write from the controller
00464  * ARGUMENTS:
00465  *     ControllerInfo: controller to query
00466  * RETURNS:
00467  *     STATUS_SUCCESS if the read/write was a success
00468  *     STATUS_UNSUCCESSFUL otherwise
00469  * NOTES:
00470  *     - This function tests the error conditions itself, and boils the
00471  *       whole thing down to a single SUCCESS or FAILURE result
00472  *     - Called post-interrupt; does not interrupt
00473  * TODO:
00474  *     - perhaps handle more status
00475  */
00476 {
00477     UCHAR Buffer[7];
00478     int i;
00479 
00480     PAGED_CODE();
00481 
00482     for(i = 0; i < 7; i++)
00483         if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
00484         {
00485             WARN_(FLOPPY, "HwReadWriteResult: unable to read fifo\n");
00486             return STATUS_UNSUCCESSFUL;
00487         }
00488 
00489     /* Validate  that it did what we told it to */
00490     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],
00491           Buffer[4], Buffer[5], Buffer[6]);
00492 
00493     /* Last command successful? */
00494     if((Buffer[0] & SR0_LAST_COMMAND_STATUS) != SR0_LCS_SUCCESS)
00495         return STATUS_UNSUCCESSFUL;
00496 
00497     return STATUS_SUCCESS;
00498 }
00499 
00500 
00501 NTSTATUS NTAPI
00502 HwRecalibrate(PDRIVE_INFO DriveInfo)
00503 /*
00504  * FUNCTION: Start a recalibration of a drive
00505  * ARGUMENTS:
00506  *     DriveInfo: Drive to recalibrate
00507  * RETURNS:
00508  *     STATUS_SUCCESS if the command was successfully queued to the controller
00509  *     STATUS_UNSUCCESSFUL otherwise
00510  * NOTES:
00511  *     - Generates an interrupt
00512  */
00513 {
00514     PCONTROLLER_INFO ControllerInfo = DriveInfo->ControllerInfo;
00515     UCHAR Unit = DriveInfo->UnitNumber;
00516     UCHAR Buffer[2];
00517     int i;
00518 
00519     TRACE_(FLOPPY, "HwRecalibrate called\n");
00520 
00521     PAGED_CODE();
00522 
00523     Buffer[0] = COMMAND_RECALIBRATE;
00524     Buffer[1] = Unit;
00525 
00526     for(i = 0; i < 2; i++)
00527         if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00528         {
00529             WARN_(FLOPPY, "HwRecalibrate: unable to write FIFO\n");
00530             return STATUS_UNSUCCESSFUL;
00531         }
00532 
00533     return STATUS_SUCCESS;
00534 }
00535 
00536 
00537 NTSTATUS NTAPI
00538 HwSenseInterruptStatus(PCONTROLLER_INFO ControllerInfo)
00539 /*
00540  * FUNCTION: Send a sense interrupt status command to a controller
00541  * ARGUMENTS:
00542  *     ControllerInfo: controller to queue the command to
00543  * RETURNS:
00544  *     STATUS_SUCCESS if the command is queued successfully
00545  *     STATUS_UNSUCCESSFUL if not
00546  */
00547 {
00548     UCHAR Buffer[2];
00549     int i;
00550 
00551     PAGED_CODE();
00552 
00553     if(Send_Byte(ControllerInfo, COMMAND_SENSE_INTERRUPT_STATUS) != STATUS_SUCCESS)
00554     {
00555         WARN_(FLOPPY, "HwSenseInterruptStatus: failed to write controller\n");
00556         return STATUS_UNSUCCESSFUL;
00557     }
00558 
00559     for(i = 0; i  < 2; i++)
00560     {
00561         if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
00562         {
00563             WARN_(FLOPPY, "HwSenseInterruptStatus: failed to read controller\n");
00564             return STATUS_UNSUCCESSFUL;
00565         }
00566     }
00567 
00568     INFO_(FLOPPY, "HwSenseInterruptStatus returned 0x%x 0x%x\n", Buffer[0], Buffer[1]);
00569 
00570     return STATUS_SUCCESS;
00571 }
00572 
00573 
00574 NTSTATUS NTAPI
00575 HwReadId(PDRIVE_INFO DriveInfo, UCHAR Head)
00576 /*
00577  * FUNCTION: Issue a read id command to the drive
00578  * ARGUMENTS:
00579  *     DriveInfo: Drive to read id from
00580  *     Head: Head to read the ID from
00581  * RETURNS:
00582  *     STATUS_SUCCESS if the command is queued
00583  *     STATUS_UNSUCCESSFUL otherwise
00584  * NOTES:
00585  *     - Generates an interrupt
00586  */
00587 {
00588     UCHAR Buffer[2];
00589     int i;
00590 
00591     TRACE_(FLOPPY, "HwReadId called\n");
00592 
00593     PAGED_CODE();
00594 
00595     Buffer[0] = COMMAND_READ_ID | READ_ID_MFM;
00596     Buffer[1] = (Head << COMMAND_HEAD_NUMBER_SHIFT) | DriveInfo->UnitNumber;
00597 
00598     for(i = 0; i < 2; i++)
00599         if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00600         {
00601             WARN_(FLOPPY, "HwReadId: unable to send bytes to fifo\n");
00602             return STATUS_UNSUCCESSFUL;
00603         }
00604 
00605     return STATUS_SUCCESS;
00606 }
00607 
00608 
00609 NTSTATUS NTAPI
00610 HwFormatTrack(PCONTROLLER_INFO ControllerInfo,
00611               UCHAR Unit,
00612               UCHAR Head,
00613               UCHAR BytesPerSector,
00614               UCHAR SectorsPerTrack,
00615               UCHAR Gap3Length,
00616               UCHAR FillerPattern)
00617 /*
00618  * FUNCTION: Format a track
00619  * ARGUMENTS:
00620  *     ControllerInfo: controller to target with the request
00621  *     Unit: drive to format on
00622  *     Head: head to format on
00623  *     BytesPerSector: constant from hardware.h to select density
00624  *     SectorsPerTrack: sectors per track
00625  *     Gap3Length: gap length to use during format
00626  *     FillerPattern: pattern to write into the data portion of sectors
00627  * RETURNS:
00628  *     STATUS_SUCCESS if the command is successfully queued
00629  *     STATUS_UNSUCCESSFUL otherwise
00630  */
00631 {
00632     UCHAR Buffer[6];
00633     int i;
00634 
00635     TRACE_(FLOPPY, "HwFormatTrack called\n");
00636 
00637     PAGED_CODE();
00638 
00639     Buffer[0] = COMMAND_FORMAT_TRACK;
00640     Buffer[1] = (Head << COMMAND_HEAD_NUMBER_SHIFT) | Unit;
00641     Buffer[2] = BytesPerSector;
00642     Buffer[3] = SectorsPerTrack;
00643     Buffer[4] = Gap3Length;
00644     Buffer[5] = FillerPattern;
00645 
00646     for(i = 0; i < 6; i++)
00647         if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00648         {
00649             WARN_(FLOPPY, "HwFormatTrack: unable to send bytes to floppy\n");
00650             return STATUS_UNSUCCESSFUL;
00651         }
00652 
00653     return STATUS_SUCCESS;
00654 }
00655 
00656 
00657 NTSTATUS NTAPI
00658 HwSeek(PDRIVE_INFO DriveInfo, UCHAR Cylinder)
00659 /*
00660  * FUNCTION: Seek the heads to a particular cylinder
00661  * ARGUMENTS:
00662  *     DriveInfo: Drive to seek
00663  *     Cylinder: cylinder to move to
00664  * RETURNS:
00665  *     STATUS_SUCCESS if the command is successfully sent
00666  *     STATUS_UNSUCCESSFUL otherwise
00667  * NOTES:
00668  *     - Generates an interrupt
00669  */
00670 {
00671     LARGE_INTEGER Delay;
00672     UCHAR Buffer[3];
00673     int i;
00674 
00675     TRACE_(FLOPPY, "HwSeek called for cyl 0x%x\n", Cylinder);
00676 
00677     PAGED_CODE();
00678 
00679     Buffer[0] = COMMAND_SEEK;
00680     Buffer[1] = DriveInfo->UnitNumber;
00681     Buffer[2] = Cylinder;
00682 
00683     for(i = 0; i < 3; i++)
00684         if(Send_Byte(DriveInfo->ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00685         {
00686             WARN_(FLOPPY, "HwSeek: failed to write fifo\n");
00687             return STATUS_UNSUCCESSFUL;
00688         }
00689 
00690     /* Wait for the head to settle */
00691     Delay.QuadPart = 10 * 1000;
00692     Delay.QuadPart *= -1;
00693     Delay.QuadPart *= DriveInfo->FloppyDeviceData.HeadSettleTime;
00694 
00695     KeDelayExecutionThread(KernelMode, FALSE, &Delay);
00696 
00697     return STATUS_SUCCESS;
00698 }
00699 
00700 
00701 NTSTATUS NTAPI
00702 HwConfigure(PCONTROLLER_INFO ControllerInfo,
00703             BOOLEAN EIS,
00704             BOOLEAN EFIFO,
00705             BOOLEAN POLL,
00706             UCHAR FIFOTHR,
00707             UCHAR PRETRK)
00708 /*
00709  * FUNCTION: Sends configuration to the drive
00710  * ARGUMENTS:
00711  *     ControllerInfo: controller to target with the request
00712  *     EIS: Enable implied seek
00713  *     EFIFO: Enable advanced fifo
00714  *     POLL: Enable polling
00715  *     FIFOTHR: fifo threshold
00716  *     PRETRK: precomp (see intel datasheet)
00717  * RETURNS:
00718  *     STATUS_SUCCESS if the command is successfully sent
00719  *     STATUS_UNSUCCESSFUL otherwise
00720  * NOTES:
00721  *     - No interrupt
00722  */
00723 {
00724     UCHAR Buffer[4];
00725     int i;
00726 
00727     TRACE_(FLOPPY, "HwConfigure called\n");
00728 
00729     PAGED_CODE();
00730 
00731     Buffer[0] = COMMAND_CONFIGURE;
00732     Buffer[1] = 0;
00733     Buffer[2] = (EIS * CONFIGURE_EIS) + (EFIFO * CONFIGURE_EFIFO) + (POLL * CONFIGURE_POLL) + (FIFOTHR);
00734     Buffer[3] = PRETRK;
00735 
00736     for(i = 0; i < 4; i++)
00737         if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00738         {
00739             WARN_(FLOPPY, "HwConfigure: failed to write the fifo\n");
00740             return STATUS_UNSUCCESSFUL;
00741         }
00742 
00743     return STATUS_SUCCESS;
00744 }
00745 
00746 
00747 NTSTATUS NTAPI
00748 HwGetVersion(PCONTROLLER_INFO ControllerInfo)
00749 /*
00750  * FUNCTION: Gets the version of the controller
00751  * ARGUMENTS:
00752  *     ControllerInfo: controller to target with the request
00753  *     ConfigValue: Configuration value to send to the drive (see header)
00754  * RETURNS:
00755  *     Version number returned by the command, or
00756  *     0 on failure
00757  * NOTE:
00758  *     - This command doesn't interrupt, so we go right to reading after
00759  *       we issue the command
00760  */
00761 {
00762     UCHAR Buffer;
00763 
00764     PAGED_CODE();
00765 
00766     if(Send_Byte(ControllerInfo, COMMAND_VERSION) != STATUS_SUCCESS)
00767     {
00768         WARN_(FLOPPY, "HwGetVersion: unable to write fifo\n");
00769         return STATUS_UNSUCCESSFUL;
00770     }
00771 
00772     if(Get_Byte(ControllerInfo, &Buffer) != STATUS_SUCCESS)
00773     {
00774         WARN_(FLOPPY, "HwGetVersion: unable to write fifo\n");
00775         return STATUS_UNSUCCESSFUL;
00776     }
00777 
00778     INFO_(FLOPPY, "HwGetVersion returning version 0x%x\n", Buffer);
00779 
00780     return Buffer;
00781 }
00782 
00783 NTSTATUS NTAPI
00784 HwDiskChanged(PDRIVE_INFO DriveInfo, PBOOLEAN DiskChanged)
00785 /*
00786  * FUNCTION: Detect whether the hardware has sensed a disk change
00787  * ARGUMENTS:
00788  *     DriveInfo: pointer to the drive that we are to check
00789  *     DiskChanged: boolean that is set with whether or not the controller thinks there has been a disk change
00790  * RETURNS:
00791  *     STATUS_SUCCESS if the drive is successfully queried
00792  * NOTES:
00793  *     - Does not interrupt.
00794  *     - Guessing a bit at the Model30 stuff
00795  */
00796 {
00797     UCHAR Buffer;
00798     PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO) DriveInfo->ControllerInfo;
00799 
00800     Buffer = READ_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_INPUT_REGISTER);
00801 
00802     TRACE_(FLOPPY, "HwDiskChanged: read 0x%x from DIR\n", Buffer);
00803 
00804     if(ControllerInfo->Model30)
00805     {
00806         if(!(Buffer & DIR_DISKETTE_CHANGE))
00807         {
00808             INFO_(FLOPPY, "HdDiskChanged - Model30 - returning TRUE\n");
00809             *DiskChanged = TRUE;
00810         }
00811         else
00812         {
00813             INFO_(FLOPPY, "HdDiskChanged - Model30 - returning FALSE\n");
00814             *DiskChanged = FALSE;
00815         }
00816     }
00817     else
00818     {
00819         if(Buffer & DIR_DISKETTE_CHANGE)
00820         {
00821             INFO_(FLOPPY, "HdDiskChanged - PS2 - returning TRUE\n");
00822             *DiskChanged = TRUE;
00823         }
00824         else
00825         {
00826             INFO_(FLOPPY, "HdDiskChanged - PS2 - returning FALSE\n");
00827             *DiskChanged = FALSE;
00828         }
00829     }
00830 
00831     return STATUS_SUCCESS;
00832 }
00833 
00834 NTSTATUS NTAPI
00835 HwSenseDriveStatusResult(PCONTROLLER_INFO ControllerInfo, PUCHAR Status)
00836 /*
00837  * FUNCTION: Get the result of a sense drive status command
00838  * ARGUMENTS:
00839  *     ControllerInfo: controller to query
00840  *     Status: Status from the drive sense command
00841  * RETURNS:
00842  *     STATUS_SUCCESS if we can successfully read the status
00843  *     STATUS_UNSUCCESSFUL otherwise
00844  * NOTES:
00845  *     - Called post-interrupt; does not interrupt
00846  */
00847 {
00848     PAGED_CODE();
00849 
00850     if(Get_Byte(ControllerInfo, Status) != STATUS_SUCCESS)
00851     {
00852         WARN_(FLOPPY, "HwSenseDriveStatus: unable to read fifo\n");
00853         return STATUS_UNSUCCESSFUL;
00854     }
00855 
00856     TRACE_(FLOPPY, "HwSenseDriveStatusResult: ST3: 0x%x\n", *Status);
00857 
00858     return STATUS_SUCCESS;
00859 }
00860 
00861 
00862 NTSTATUS NTAPI
00863 HwReadIdResult(PCONTROLLER_INFO ControllerInfo,
00864                PUCHAR CurCylinder,
00865                PUCHAR CurHead)
00866 /*
00867  * FUNCTION: Get the result of a read id command
00868  * ARGUMENTS:
00869  *     ControllerInfo: controller to query
00870  *     CurCylinder: Returns the cylinder that we're at
00871  *     CurHead: Returns the head that we're at
00872  * RETURNS:
00873  *     STATUS_SUCCESS if the read id was a success
00874  *     STATUS_UNSUCCESSFUL otherwise
00875  * NOTES:
00876  *     - This function tests the error conditions itself, and boils the
00877  *       whole thing down to a single SUCCESS or FAILURE result
00878  *     - Called post-interrupt; does not interrupt
00879  * TODO
00880  *     - perhaps handle more status
00881  */
00882 {
00883     UCHAR Buffer[7] = {0,0,0,0,0,0,0};
00884     int i;
00885 
00886     PAGED_CODE();
00887 
00888     for(i = 0; i < 7; i++)
00889         if(Get_Byte(ControllerInfo, &Buffer[i]) != STATUS_SUCCESS)
00890         {
00891             WARN_(FLOPPY, "ReadIdResult(): can't read from the controller\n");
00892             return STATUS_UNSUCCESSFUL;
00893         }
00894 
00895     /* Validate  that it did what we told it to */
00896     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],
00897           Buffer[4], Buffer[5], Buffer[6]);
00898 
00899     /* Last command successful? */
00900     if((Buffer[0] & SR0_LAST_COMMAND_STATUS) != SR0_LCS_SUCCESS)
00901     {
00902         WARN_(FLOPPY, "ReadId didn't return last command success\n");
00903         return STATUS_UNSUCCESSFUL;
00904     }
00905 
00906     /* ID mark found? */
00907     if(Buffer[1] & SR1_CANNOT_FIND_ID_ADDRESS)
00908     {
00909         WARN_(FLOPPY, "ReadId didn't find an address mark\n");
00910         return STATUS_UNSUCCESSFUL;
00911     }
00912 
00913     if(CurCylinder)
00914         *CurCylinder = Buffer[3];
00915 
00916     if(CurHead)
00917         *CurHead = Buffer[4];
00918 
00919     return STATUS_SUCCESS;
00920 }
00921 
00922 
00923 NTSTATUS NTAPI
00924 HwSpecify(PCONTROLLER_INFO ControllerInfo,
00925           UCHAR HeadLoadTime,
00926           UCHAR HeadUnloadTime,
00927           UCHAR StepRateTime,
00928           BOOLEAN NonDma)
00929 /*
00930  * FUNCTION: Set up timing and DMA mode for the controller
00931  * ARGUMENTS:
00932  *     ControllerInfo: Controller to set up
00933  *     HeadLoadTime: Head load time (see data sheet for details)
00934  *     HeadUnloadTime: Head unload time
00935  *     StepRateTime: Step rate time
00936  *     NonDma: TRUE to disable DMA mode
00937  * RETURNS:
00938  *     STATUS_SUCCESS if the contrller is successfully programmed
00939  *     STATUS_UNSUCCESSFUL if not
00940  * NOTES:
00941  *     - Does not interrupt
00942  *
00943  * TODO: Figure out timings
00944  */
00945 {
00946     UCHAR Buffer[3];
00947     int i;
00948 
00949     Buffer[0] = COMMAND_SPECIFY;
00950     /*
00951     Buffer[1] = (StepRateTime << 4) + HeadUnloadTime;
00952     Buffer[2] = (HeadLoadTime << 1) + (NonDma ? 1 : 0);
00953     */
00954     Buffer[1] = 0xdf;
00955     Buffer[2] = 0x2;
00956 
00957     //INFO_(FLOPPY, "HwSpecify: sending 0x%x 0x%x 0x%x to FIFO\n", Buffer[0], Buffer[1], Buffer[2]);
00958     WARN_(FLOPPY, "HWSPECIFY: FIXME - sending 0x3 0xd1 0x2 to FIFO\n");
00959 
00960     for(i = 0; i < 3; i++)
00961         if(Send_Byte(ControllerInfo, Buffer[i]) != STATUS_SUCCESS)
00962         {
00963             WARN_(FLOPPY, "HwSpecify: unable to write to controller\n");
00964             return STATUS_UNSUCCESSFUL;
00965         }
00966 
00967     return STATUS_SUCCESS;
00968 }
00969 
00970 
00971 NTSTATUS NTAPI
00972 HwReset(PCONTROLLER_INFO ControllerInfo)
00973 /*
00974  * FUNCTION: Reset the controller
00975  * ARGUMENTS:
00976  *     ControllerInfo: controller to reset
00977  * RETURNS:
00978  *     STATUS_SUCCESS in all cases
00979  * NOTES:
00980  *     - Generates an interrupt that must be serviced four times (one per drive)
00981  */
00982 {
00983     TRACE_(FLOPPY, "HwReset called\n");
00984 
00985     /* Write the reset bit in the DRSR */
00986     WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DATA_RATE_SELECT_REGISTER, DRSR_SW_RESET);
00987 
00988     /* Check for the reset bit in the DOR and set it if necessary (see Intel doc) */
00989     if(!(READ_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER) & DOR_RESET))
00990     {
00991         HwDumpRegisters(ControllerInfo);
00992         INFO_(FLOPPY, "HwReset: Setting Enable bit\n");
00993         WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER, DOR_DMA_IO_INTERFACE_ENABLE|DOR_RESET);
00994         HwDumpRegisters(ControllerInfo);
00995 
00996         if(!(READ_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER) & DOR_RESET))
00997         {
00998             WARN_(FLOPPY, "HwReset: failed to set the DOR enable bit!\n");
00999             HwDumpRegisters(ControllerInfo);
01000             return STATUS_UNSUCCESSFUL;
01001         }
01002     }
01003 
01004     return STATUS_SUCCESS;
01005 }
01006 
01007 
01008 NTSTATUS NTAPI
01009 HwPowerOff(PCONTROLLER_INFO ControllerInfo)
01010 /*
01011  * FUNCTION: Power down a controller
01012  * ARGUMENTS:
01013  *     ControllerInfo: Controller to power down
01014  * RETURNS:
01015  *     STATUS_SUCCESS
01016  * NOTES:
01017  *     - Wake up with a hardware reset
01018  */
01019 {
01020     TRACE_(FLOPPY, "HwPowerOff called on controller 0x%p\n", ControllerInfo);
01021 
01022     WRITE_PORT_UCHAR(ControllerInfo->BaseAddress + DATA_RATE_SELECT_REGISTER, DRSR_POWER_DOWN);
01023 
01024     return STATUS_SUCCESS;
01025 }
01026 
01027 VOID NTAPI
01028 HwDumpRegisters(PCONTROLLER_INFO ControllerInfo)
01029 /*
01030  * FUNCTION: Dump all readable registers from the floppy controller
01031  * ARGUMENTS:
01032  *     ControllerInfo: Controller to dump registers from
01033  */
01034 {
01035     UNREFERENCED_PARAMETER(ControllerInfo);
01036 
01037     INFO_(FLOPPY, "STATUS:\n");
01038     INFO_(FLOPPY, "STATUS_REGISTER_A = 0x%x\n", READ_PORT_UCHAR(ControllerInfo->BaseAddress + STATUS_REGISTER_A));
01039     INFO_(FLOPPY, "STATUS_REGISTER_B = 0x%x\n", READ_PORT_UCHAR(ControllerInfo->BaseAddress + STATUS_REGISTER_B));
01040     INFO_(FLOPPY, "DIGITAL_OUTPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_OUTPUT_REGISTER));
01041     INFO_(FLOPPY, "MAIN_STATUS_REGISTER =0x%x\n", READ_PORT_UCHAR(ControllerInfo->BaseAddress + MAIN_STATUS_REGISTER));
01042     INFO_(FLOPPY, "DIGITAL_INPUT_REGISTER = 0x%x\n", READ_PORT_UCHAR(ControllerInfo->BaseAddress + DIGITAL_INPUT_REGISTER));
01043 }
01044 

Generated on Sun May 27 2012 04:19:08 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.