Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhardware.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
1.7.6.1
|