Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenfloppy.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: floppy.c 00021 * PURPOSE: Main floppy driver routines 00022 * PROGRAMMER: Vizzini (vizzini@plasmic.com) 00023 * REVISIONS: 00024 * 15-Feb-2004 vizzini - Created 00025 * NOTES: 00026 * - This driver is only designed to work with ISA-bus floppy controllers. This 00027 * won't work on PCI-based controllers or on anything else with level-sensitive 00028 * interrupts without modification. I don't think these controllers exist. 00029 * 00030 * ---- General to-do items ---- 00031 * TODO: Figure out why CreateClose isn't called any more. Seems to correspond 00032 * with the driver not being unloadable. 00033 * TODO: Think about StopDpcQueued -- could be a race; too tired atm to tell 00034 * TODO: Clean up drive start/stop responsibilities (currently a mess...) 00035 * 00036 * ---- Support for proper media detection ---- 00037 * TODO: Handle MFM flag 00038 * TODO: Un-hardcode the data rate from various places 00039 * TODO: Proper media detection (right now we're hardcoded to 1.44) 00040 * TODO: Media detection based on sector 1 00041 */ 00042 00043 #include "precomp.h" 00044 00045 /* 00046 * Global controller info structures. Each controller gets one. Since the system 00047 * will probably have only one, with four being a very unlikely maximum, a static 00048 * global array is easiest to deal with. 00049 */ 00050 static CONTROLLER_INFO gControllerInfo[MAX_CONTROLLERS]; 00051 static ULONG gNumberOfControllers = 0; 00052 00053 /* Queue thread management */ 00054 static KEVENT QueueThreadTerminate; 00055 static PVOID QueueThreadObject; 00056 00057 00058 static VOID NTAPI 00059 MotorStopDpcFunc(PKDPC UnusedDpc, PVOID DeferredContext, PVOID SystemArgument1, PVOID SystemArgument2) 00060 /* 00061 * FUNCTION: Stop the floppy motor 00062 * ARGUMENTS: 00063 * UnusedDpc: DPC object that's going off 00064 * DeferredContext: called with DRIVE_INFO for drive to turn off 00065 * SystemArgument1: unused 00066 * SystemArgument2: unused 00067 * NOTES: 00068 * - Must set an event to let other threads know we're done turning off the motor 00069 * - Called back at DISPATCH_LEVEL 00070 */ 00071 { 00072 PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)DeferredContext; 00073 00074 UNREFERENCED_PARAMETER(SystemArgument1); 00075 UNREFERENCED_PARAMETER(SystemArgument2); 00076 UNREFERENCED_PARAMETER(UnusedDpc); 00077 00078 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); 00079 ASSERT(ControllerInfo); 00080 00081 TRACE_(FLOPPY, "MotorStopDpcFunc called\n"); 00082 00083 HwTurnOffMotor(ControllerInfo); 00084 ControllerInfo->StopDpcQueued = FALSE; 00085 KeSetEvent(&ControllerInfo->MotorStoppedEvent, EVENT_INCREMENT, FALSE); 00086 } 00087 00088 00089 VOID NTAPI 00090 StartMotor(PDRIVE_INFO DriveInfo) 00091 /* 00092 * FUNCTION: Start the motor, taking into account proper handling of the timer race 00093 * ARGUMENTS: 00094 * DriveInfo: drive to start 00095 * NOTES: 00096 * - Never call HwTurnOnMotor() directly 00097 * - This protocol manages a race between the cancel timer and the requesting thread. 00098 * You wouldn't want to turn on the motor and then cancel the timer, because the 00099 * cancel dpc might fire in the meantime, and that'd un-do what you just did. If you 00100 * cancel the timer first, but KeCancelTimer returns false, the dpc is already running, 00101 * so you have to wait until the dpc is completly done running, or else you'll race 00102 * with the turner-offer 00103 * - PAGED_CODE because we wait 00104 */ 00105 { 00106 PAGED_CODE(); 00107 ASSERT(DriveInfo); 00108 00109 TRACE_(FLOPPY, "StartMotor called\n"); 00110 00111 if(DriveInfo->ControllerInfo->StopDpcQueued && !KeCancelTimer(&DriveInfo->ControllerInfo->MotorTimer)) 00112 { 00113 /* Motor turner-offer is already running; wait for it to finish */ 00114 INFO_(FLOPPY, "StartMotor: motor turner-offer is already running; waiting for it\n"); 00115 KeWaitForSingleObject(&DriveInfo->ControllerInfo->MotorStoppedEvent, Executive, KernelMode, FALSE, NULL); 00116 INFO_(FLOPPY, "StartMotor: wait satisfied\n"); 00117 } 00118 00119 DriveInfo->ControllerInfo->StopDpcQueued = FALSE; 00120 00121 if(HwTurnOnMotor(DriveInfo) != STATUS_SUCCESS) 00122 { 00123 WARN_(FLOPPY, "StartMotor(): warning: HwTurnOnMotor failed\n"); 00124 } 00125 } 00126 00127 00128 VOID NTAPI 00129 StopMotor(PCONTROLLER_INFO ControllerInfo) 00130 /* 00131 * FUNCTION: Stop all motors on the controller 00132 * ARGUMENTS: 00133 * DriveInfo: Drive to stop 00134 * NOTES: 00135 * - Never call HwTurnOffMotor() directly 00136 * - This manages the timer cancelation race (see StartMotor for details). 00137 * All we have to do is set up a timer. 00138 */ 00139 { 00140 LARGE_INTEGER StopTime; 00141 00142 ASSERT(ControllerInfo); 00143 00144 TRACE_(FLOPPY, "StopMotor called\n"); 00145 00146 /* one relative second, in 100-ns units */ 00147 StopTime.QuadPart = 10000000; 00148 StopTime.QuadPart *= -1; 00149 00150 KeClearEvent(&ControllerInfo->MotorStoppedEvent); 00151 KeSetTimer(&ControllerInfo->MotorTimer, StopTime, &ControllerInfo->MotorStopDpc); 00152 ControllerInfo->StopDpcQueued = TRUE; 00153 } 00154 00155 00156 VOID NTAPI 00157 WaitForControllerInterrupt(PCONTROLLER_INFO ControllerInfo) 00158 /* 00159 * FUNCTION: Wait for the controller to interrupt, and then clear the event 00160 * ARGUMENTS: 00161 * ControllerInfo: Controller to wait for 00162 * NOTES: 00163 * - There is a small chance that an unexpected or spurious interrupt could 00164 * be lost with this clear/wait/clear scheme used in this driver. This is 00165 * deemed to be an acceptable risk due to the unlikeliness of the scenario, 00166 * and the fact that it'll probably work fine next time. 00167 * - PAGED_CODE because it waits 00168 */ 00169 { 00170 PAGED_CODE(); 00171 ASSERT(ControllerInfo); 00172 00173 KeWaitForSingleObject(&ControllerInfo->SynchEvent, Executive, KernelMode, FALSE, NULL); 00174 KeClearEvent(&ControllerInfo->SynchEvent); 00175 } 00176 00177 static DRIVER_DISPATCH CreateClose; 00178 static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject, 00179 PIRP Irp) 00180 /* 00181 * FUNCTION: Dispatch function called for Create and Close IRPs 00182 * ARGUMENTS: 00183 * DeviceObject: DeviceObject that is the target of the IRP 00184 * Irp: IRP to process 00185 * RETURNS: 00186 * STATUS_SUCCESS in all cases 00187 * NOTES: 00188 * - The Microsoft sample drivers tend to return FILE_OPENED in Information, so I do too. 00189 * - No reason to fail the device open 00190 * - No state to track, so this routine is easy 00191 * - Can be called <= DISPATCH_LEVEL 00192 * 00193 * TODO: Figure out why this isn't getting called 00194 */ 00195 { 00196 UNREFERENCED_PARAMETER(DeviceObject); 00197 00198 TRACE_(FLOPPY, "CreateClose called\n"); 00199 00200 Irp->IoStatus.Status = STATUS_SUCCESS; 00201 Irp->IoStatus.Information = FILE_OPENED; 00202 00203 IoCompleteRequest(Irp, IO_DISK_INCREMENT); 00204 00205 return STATUS_SUCCESS; 00206 } 00207 00208 00209 static NTSTATUS NTAPI 00210 Recalibrate(PDRIVE_INFO DriveInfo) 00211 /* 00212 * FUNCTION: Start the recalibration process 00213 * ARGUMENTS: 00214 * DriveInfo: Pointer to the driveinfo struct associated with the targeted drive 00215 * RETURNS: 00216 * STATUS_SUCCESS on successful starting of the process 00217 * STATUS_IO_DEVICE_ERROR if it fails 00218 * NOTES: 00219 * - Sometimes you have to do two recalibrations, particularly if the disk has <80 tracks. 00220 * - PAGED_CODE because we wait 00221 */ 00222 { 00223 NTSTATUS Status; 00224 ULONG i; 00225 00226 PAGED_CODE(); 00227 ASSERT(DriveInfo); 00228 00229 /* first turn on the motor */ 00230 /* Must stop after every start, prior to return */ 00231 StartMotor(DriveInfo); 00232 00233 /* set the data rate */ 00234 WARN_(FLOPPY, "FIXME: UN-HARDCODE DATA RATE\n"); 00235 if(HwSetDataRate(DriveInfo->ControllerInfo, 0) != STATUS_SUCCESS) 00236 { 00237 WARN_(FLOPPY, "Recalibrate: HwSetDataRate failed\n"); 00238 StopMotor(DriveInfo->ControllerInfo); 00239 return STATUS_IO_DEVICE_ERROR; 00240 } 00241 00242 /* clear the event just in case the last call forgot */ 00243 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent); 00244 00245 /* sometimes you have to do this twice; we'll just do it twice all the time since 00246 * we don't know if the people calling this Recalibrate routine expect a disk to 00247 * even be in the drive, and if so, if that disk is formatted. 00248 */ 00249 for(i = 0; i < 2; i++) 00250 { 00251 /* Send the command */ 00252 Status = HwRecalibrate(DriveInfo); 00253 if(Status != STATUS_SUCCESS) 00254 { 00255 WARN_(FLOPPY, "Recalibrate: HwRecalibrate returned error\n"); 00256 continue; 00257 } 00258 00259 WaitForControllerInterrupt(DriveInfo->ControllerInfo); 00260 00261 /* Get the results */ 00262 Status = HwRecalibrateResult(DriveInfo->ControllerInfo); 00263 if(Status != STATUS_SUCCESS) 00264 { 00265 WARN_(FLOPPY, "Recalibrate: HwRecalibrateResult returned error\n"); 00266 break; 00267 } 00268 } 00269 00270 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent); 00271 00272 /* Must stop after every start, prior to return */ 00273 StopMotor(DriveInfo->ControllerInfo); 00274 00275 return Status; 00276 } 00277 00278 00279 NTSTATUS NTAPI 00280 ResetChangeFlag(PDRIVE_INFO DriveInfo) 00281 /* 00282 * FUNCTION: Reset the drive's change flag (as reflected in the DIR) 00283 * ARGUMENTS: 00284 * DriveInfo: the drive to reset 00285 * RETURNS: 00286 * STATUS_SUCCESS if the changeline is cleared 00287 * STATUS_NO_MEDIA_IN_DEVICE if the changeline cannot be cleared 00288 * STATUS_IO_DEVICE_ERROR if the controller cannot be communicated with 00289 * NOTES: 00290 * - Change reset procedure: recalibrate, seek 1, seek 0 00291 * - If the line is still set after that, there's clearly no disk in the 00292 * drive, so we return STATUS_NO_MEDIA_IN_DEVICE 00293 * - PAGED_CODE because we wait 00294 */ 00295 { 00296 BOOLEAN DiskChanged; 00297 00298 PAGED_CODE(); 00299 ASSERT(DriveInfo); 00300 00301 TRACE_(FLOPPY, "ResetChangeFlag called\n"); 00302 00303 /* Try to recalibrate. We don't care if it works. */ 00304 Recalibrate(DriveInfo); 00305 00306 /* clear spurious interrupts in prep for seeks */ 00307 KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent); 00308 00309 /* must re-start the drive because Recalibrate() stops it */ 00310 StartMotor(DriveInfo); 00311 00312 /* Seek to 1 */ 00313 if(HwSeek(DriveInfo, 1) != STATUS_SUCCESS) 00314 { 00315 WARN_(FLOPPY, "ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n"); 00316 StopMotor(DriveInfo->ControllerInfo); 00317 return STATUS_IO_DEVICE_ERROR; 00318 } 00319 00320 WaitForControllerInterrupt(DriveInfo->ControllerInfo); 00321 00322 if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS) 00323 { 00324 WARN_(FLOPPY, "ResetChangeFlag(): HwSenseInterruptStatus failed; bailing out\n"); 00325 StopMotor(DriveInfo->ControllerInfo); 00326 return STATUS_IO_DEVICE_ERROR; 00327 } 00328 00329 /* Seek back to 0 */ 00330 if(HwSeek(DriveInfo, 0) != STATUS_SUCCESS) 00331 { 00332 WARN_(FLOPPY, "ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n"); 00333 StopMotor(DriveInfo->ControllerInfo); 00334 return STATUS_IO_DEVICE_ERROR; 00335 } 00336 00337 WaitForControllerInterrupt(DriveInfo->ControllerInfo); 00338 00339 if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS) 00340 { 00341 WARN_(FLOPPY, "ResetChangeFlag(): HwSenseInterruptStatus #2 failed; bailing\n"); 00342 StopMotor(DriveInfo->ControllerInfo); 00343 return STATUS_IO_DEVICE_ERROR; 00344 } 00345 00346 /* Check the change bit */ 00347 if(HwDiskChanged(DriveInfo, &DiskChanged) != STATUS_SUCCESS) 00348 { 00349 WARN_(FLOPPY, "ResetChangeFlag(): HwDiskChanged failed; returning STATUS_IO_DEVICE_ERROR\n"); 00350 StopMotor(DriveInfo->ControllerInfo); 00351 return STATUS_IO_DEVICE_ERROR; 00352 } 00353 00354 StopMotor(DriveInfo->ControllerInfo); 00355 00356 /* if the change flag is still set, there's probably no media in the drive. */ 00357 if(DiskChanged) 00358 return STATUS_NO_MEDIA_IN_DEVICE; 00359 00360 /* else we're done! */ 00361 return STATUS_SUCCESS; 00362 } 00363 00364 00365 static VOID NTAPI 00366 Unload(PDRIVER_OBJECT DriverObject) 00367 /* 00368 * FUNCTION: Unload the driver from memory 00369 * ARGUMENTS: 00370 * DriverObject - The driver that is being unloaded 00371 */ 00372 { 00373 ULONG i,j; 00374 00375 PAGED_CODE(); 00376 UNREFERENCED_PARAMETER(DriverObject); 00377 00378 TRACE_(FLOPPY, "unloading\n"); 00379 00380 KeSetEvent(&QueueThreadTerminate, 0, FALSE); 00381 KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0); 00382 ObDereferenceObject(QueueThreadObject); 00383 00384 for(i = 0; i < gNumberOfControllers; i++) 00385 { 00386 if(!gControllerInfo[i].Initialized) 00387 continue; 00388 00389 for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++) 00390 { 00391 if(!gControllerInfo[i].DriveInfo[j].Initialized) 00392 continue; 00393 00394 if(gControllerInfo[i].DriveInfo[j].DeviceObject) 00395 { 00396 UNICODE_STRING Link; 00397 00398 RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].SymLinkBuffer); 00399 IoDeleteSymbolicLink(&Link); 00400 00401 RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].ArcPathBuffer); 00402 IoDeassignArcName(&Link); 00403 00404 IoDeleteDevice(gControllerInfo[i].DriveInfo[j].DeviceObject); 00405 } 00406 } 00407 00408 IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); 00409 00410 /* Power down the controller */ 00411 if(HwPowerOff(&gControllerInfo[i]) != STATUS_SUCCESS) 00412 { 00413 WARN_(FLOPPY, "unload: warning: HwPowerOff failed\n"); 00414 } 00415 } 00416 } 00417 00418 00419 static NTSTATUS NTAPI 00420 ConfigCallback(PVOID Context, 00421 PUNICODE_STRING PathName, 00422 INTERFACE_TYPE BusType, 00423 ULONG BusNumber, 00424 PKEY_VALUE_FULL_INFORMATION *BusInformation, 00425 CONFIGURATION_TYPE ControllerType, 00426 ULONG ControllerNumber, 00427 PKEY_VALUE_FULL_INFORMATION *ControllerInformation, 00428 CONFIGURATION_TYPE PeripheralType, 00429 ULONG PeripheralNumber, 00430 PKEY_VALUE_FULL_INFORMATION *PeripheralInformation) 00431 /* 00432 * FUNCTION: Callback to IoQueryDeviceDescription, which tells us about our controllers 00433 * ARGUMENTS: 00434 * Context: Unused 00435 * PathName: Unused 00436 * BusType: Type of the bus that our controller is on 00437 * BusNumber: Number of the bus that our controller is on 00438 * BusInformation: Unused 00439 * ControllerType: Unused 00440 * ControllerNumber: Number of the controller that we're adding 00441 * ControllerInformation: Full configuration information for our controller 00442 * PeripheralType: Unused 00443 * PeripheralNumber: Unused 00444 * PeripheralInformation: Full configuration information for each drive on our controller 00445 * RETURNS: 00446 * STATUS_SUCCESS in all cases 00447 * NOTES: 00448 * - The only documentation I've found about the contents of these structures is 00449 * from the various Microsoft floppy samples and from the DDK headers. They're 00450 * very vague, though, so I'm only mostly sure that this stuff is correct, as 00451 * the MS samples do things completely differently than I have done them. Seems 00452 * to work in my VMWare, though. 00453 * - Basically, the function gets all of the information (port, dma, irq) about the 00454 * controller, and then loops through all of the drives presented in PeripheralInformation. 00455 * - Each controller has a CONTROLLER_INFO created for it, and each drive has a DRIVE_INFO. 00456 * - Device objects are created for each drive (not controller), as that's the targeted 00457 * device in the eyes of the rest of the OS. Each DRIVE_INFO points to a single CONTROLLER_INFO. 00458 * - We only support up to four controllers in the whole system, each of which supports up to four 00459 * drives. 00460 */ 00461 { 00462 PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData]; 00463 PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor + 00464 ControllerFullDescriptor->DataOffset); 00465 00466 PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData]; 00467 PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor + 00468 PeripheralFullDescriptor->DataOffset); 00469 00470 PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; 00471 PCM_FLOPPY_DEVICE_DATA FloppyDeviceData; 00472 UCHAR i; 00473 00474 PAGED_CODE(); 00475 UNREFERENCED_PARAMETER(PeripheralType); 00476 UNREFERENCED_PARAMETER(PeripheralNumber); 00477 UNREFERENCED_PARAMETER(BusInformation); 00478 UNREFERENCED_PARAMETER(Context); 00479 UNREFERENCED_PARAMETER(ControllerType); 00480 UNREFERENCED_PARAMETER(PathName); 00481 00482 00483 TRACE_(FLOPPY, "ConfigCallback called with ControllerNumber %d\n", ControllerNumber); 00484 00485 gControllerInfo[gNumberOfControllers].ControllerNumber = ControllerNumber; 00486 gControllerInfo[gNumberOfControllers].InterfaceType = BusType; 00487 gControllerInfo[gNumberOfControllers].BusNumber = BusNumber; 00488 00489 /* Get controller interrupt level/vector, dma channel, and port base */ 00490 for(i = 0; i < ControllerResourceDescriptor->PartialResourceList.Count; i++) 00491 { 00492 KeInitializeEvent(&gControllerInfo[gNumberOfControllers].SynchEvent, NotificationEvent, FALSE); 00493 00494 PartialDescriptor = &ControllerResourceDescriptor->PartialResourceList.PartialDescriptors[i]; 00495 00496 if(PartialDescriptor->Type == CmResourceTypeInterrupt) 00497 { 00498 gControllerInfo[gNumberOfControllers].Level = PartialDescriptor->u.Interrupt.Level; 00499 gControllerInfo[gNumberOfControllers].Vector = PartialDescriptor->u.Interrupt.Vector; 00500 00501 if(PartialDescriptor->Flags & CM_RESOURCE_INTERRUPT_LATCHED) 00502 gControllerInfo[gNumberOfControllers].InterruptMode = Latched; 00503 else 00504 gControllerInfo[gNumberOfControllers].InterruptMode = LevelSensitive; 00505 } 00506 00507 else if(PartialDescriptor->Type == CmResourceTypePort) 00508 { 00509 PHYSICAL_ADDRESS TranslatedAddress; 00510 ULONG AddressSpace = 0x1; /* I/O Port Range */ 00511 00512 if(!HalTranslateBusAddress(BusType, BusNumber, PartialDescriptor->u.Port.Start, &AddressSpace, &TranslatedAddress)) 00513 { 00514 WARN_(FLOPPY, "HalTranslateBusAddress failed; returning\n"); 00515 return STATUS_IO_DEVICE_ERROR; 00516 } 00517 00518 if(AddressSpace == 0) 00519 gControllerInfo[gNumberOfControllers].BaseAddress = MmMapIoSpace(TranslatedAddress, FDC_PORT_BYTES, MmNonCached); 00520 else 00521 gControllerInfo[gNumberOfControllers].BaseAddress = (PUCHAR)(ULONG_PTR)TranslatedAddress.QuadPart; 00522 } 00523 00524 else if(PartialDescriptor->Type == CmResourceTypeDma) 00525 gControllerInfo[gNumberOfControllers].Dma = PartialDescriptor->u.Dma.Channel; 00526 } 00527 00528 /* Start with 0 drives, then go looking */ 00529 gControllerInfo[gNumberOfControllers].NumberOfDrives = 0; 00530 00531 /* learn about drives attached to controller */ 00532 for(i = 0; i < PeripheralResourceDescriptor->PartialResourceList.Count; i++) 00533 { 00534 PDRIVE_INFO DriveInfo = &gControllerInfo[gNumberOfControllers].DriveInfo[i]; 00535 00536 PartialDescriptor = &PeripheralResourceDescriptor->PartialResourceList.PartialDescriptors[i]; 00537 00538 if(PartialDescriptor->Type != CmResourceTypeDeviceSpecific) 00539 continue; 00540 00541 FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)(PartialDescriptor + 1); 00542 00543 DriveInfo->ControllerInfo = &gControllerInfo[gNumberOfControllers]; 00544 DriveInfo->UnitNumber = i; 00545 00546 DriveInfo->FloppyDeviceData.MaxDensity = FloppyDeviceData->MaxDensity; 00547 DriveInfo->FloppyDeviceData.MountDensity = FloppyDeviceData->MountDensity; 00548 DriveInfo->FloppyDeviceData.StepRateHeadUnloadTime = FloppyDeviceData->StepRateHeadUnloadTime; 00549 DriveInfo->FloppyDeviceData.HeadLoadTime = FloppyDeviceData->HeadLoadTime; 00550 DriveInfo->FloppyDeviceData.MotorOffTime = FloppyDeviceData->MotorOffTime; 00551 DriveInfo->FloppyDeviceData.SectorLengthCode = FloppyDeviceData->SectorLengthCode; 00552 DriveInfo->FloppyDeviceData.SectorPerTrack = FloppyDeviceData->SectorPerTrack; 00553 DriveInfo->FloppyDeviceData.ReadWriteGapLength = FloppyDeviceData->ReadWriteGapLength; 00554 DriveInfo->FloppyDeviceData.FormatGapLength = FloppyDeviceData->FormatGapLength; 00555 DriveInfo->FloppyDeviceData.FormatFillCharacter = FloppyDeviceData->FormatFillCharacter; 00556 DriveInfo->FloppyDeviceData.HeadSettleTime = FloppyDeviceData->HeadSettleTime; 00557 DriveInfo->FloppyDeviceData.MotorSettleTime = FloppyDeviceData->MotorSettleTime; 00558 DriveInfo->FloppyDeviceData.MaximumTrackValue = FloppyDeviceData->MaximumTrackValue; 00559 DriveInfo->FloppyDeviceData.DataTransferLength = FloppyDeviceData->DataTransferLength; 00560 00561 /* Once it's all set up, acknowledge its existance in the controller info object */ 00562 gControllerInfo[gNumberOfControllers].NumberOfDrives++; 00563 } 00564 00565 gControllerInfo[gNumberOfControllers].Populated = TRUE; 00566 gNumberOfControllers++; 00567 00568 return STATUS_SUCCESS; 00569 } 00570 00571 00572 static BOOLEAN NTAPI 00573 Isr(PKINTERRUPT Interrupt, PVOID ServiceContext) 00574 /* 00575 * FUNCTION: Interrupt service routine for the controllers 00576 * ARGUMENTS: 00577 * Interrupt: Interrupt object representing the interrupt that occured 00578 * ServiceContext: Pointer to the ControllerInfo object that caused the interrupt 00579 * RETURNS: 00580 * TRUE in all cases (see notes) 00581 * NOTES: 00582 * - We should always be the target of the interrupt, being an edge-triggered ISA interrupt, but 00583 * this won't be the case with a level-sensitive system like PCI 00584 * - Note that it probably doesn't matter if the interrupt isn't dismissed, as it's edge-triggered. 00585 * It probably won't keep re-interrupting. 00586 * - There are two different ways to dismiss a floppy interrupt. If the command has a result phase 00587 * (see intel datasheet), you dismiss the interrupt by reading the first data byte. If it does 00588 * not, you dismiss the interrupt by doing a Sense Interrupt command. Again, because it's edge- 00589 * triggered, this is safe to not do here, as we can just wait for the DPC. 00590 * - Either way, we don't want to do this here. The controller shouldn't interrupt again, so we'll 00591 * schedule a DPC to take care of it. 00592 * - This driver really cannot shrare interrupts, as I don't know how to conclusively say 00593 * whether it was our controller that interrupted or not. I just have to assume that any time 00594 * my ISR gets called, it was my board that called it. Dumb design, yes, but it goes back to 00595 * the semantics of ISA buses. That, and I don't know much about ISA drivers. :-) 00596 * UPDATE: The high bit of Status Register A seems to work on non-AT controllers. 00597 * - Called at DIRQL 00598 */ 00599 { 00600 PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)ServiceContext; 00601 00602 UNREFERENCED_PARAMETER(Interrupt); 00603 00604 ASSERT(ControllerInfo); 00605 00606 TRACE_(FLOPPY, "ISR called\n"); 00607 00608 /* 00609 * Due to the stupidity of the drive/controller relationship on the floppy drive, only one device object 00610 * can have an active interrupt pending. Due to the nature of these IRPs, though, there will only ever 00611 * be one thread expecting an interrupt at a time, and furthermore, Interrupts (outside of spurious ones) 00612 * won't ever happen unless a thread is expecting them. Therefore, all we have to do is signal an event 00613 * and we're done. Queue a DPC and leave. 00614 */ 00615 KeInsertQueueDpc(&ControllerInfo->Dpc, NULL, NULL); 00616 00617 return TRUE; 00618 } 00619 00620 00621 VOID NTAPI 00622 DpcForIsr(PKDPC UnusedDpc, PVOID Context, PVOID SystemArgument1, PVOID SystemArgument2) 00623 /* 00624 * FUNCTION: This DPC gets queued by every ISR. Does the real per-interrupt work. 00625 * ARGUMENTS: 00626 * UnusedDpc: Pointer to the DPC object that represents our function 00627 * DeviceObject: Device that this DPC is running for 00628 * Irp: Unused 00629 * Context: Pointer to our ControllerInfo struct 00630 * NOTES: 00631 * - This function just kicks off whatever the SynchEvent is and returns. We depend on 00632 * the thing that caused the drive to interrupt to handle the work of clearing the interrupt. 00633 * This enables us to get back to PASSIVE_LEVEL and not hog system time on a really stupid, 00634 * slow, screwed-up piece of hardare. 00635 * - If nothing is waiting for us to set the event, the interrupt is effectively lost and will 00636 * never be dismissed. I wonder if this will become a problem. 00637 * - Called at DISPATCH_LEVEL 00638 */ 00639 { 00640 PCONTROLLER_INFO ControllerInfo = (PCONTROLLER_INFO)Context; 00641 00642 UNREFERENCED_PARAMETER(UnusedDpc); 00643 UNREFERENCED_PARAMETER(SystemArgument1); 00644 UNREFERENCED_PARAMETER(SystemArgument2); 00645 00646 ASSERT(ControllerInfo); 00647 00648 TRACE_(FLOPPY, "DpcForIsr called\n"); 00649 00650 KeSetEvent(&ControllerInfo->SynchEvent, EVENT_INCREMENT, FALSE); 00651 } 00652 00653 00654 static NTSTATUS NTAPI 00655 InitController(PCONTROLLER_INFO ControllerInfo) 00656 /* 00657 * FUNCTION: Initialize a newly-found controller 00658 * ARGUMENTS: 00659 * ControllerInfo: pointer to the controller to be initialized 00660 * RETURNS: 00661 * STATUS_SUCCESS if the controller is successfully initialized 00662 * STATUS_IO_DEVICE_ERROR otherwise 00663 */ 00664 { 00665 int i; 00666 UCHAR HeadLoadTime; 00667 UCHAR HeadUnloadTime; 00668 UCHAR StepRateTime; 00669 UCHAR ControllerVersion; 00670 00671 PAGED_CODE(); 00672 ASSERT(ControllerInfo); 00673 00674 TRACE_(FLOPPY, "InitController called with Controller 0x%p\n", ControllerInfo); 00675 00676 /* Get controller in a known state */ 00677 HwConfigure(ControllerInfo, FALSE, TRUE, TRUE, 0, 0); 00678 00679 /* Get the controller version */ 00680 ControllerVersion = HwGetVersion(ControllerInfo); 00681 00682 KeClearEvent(&ControllerInfo->SynchEvent); 00683 00684 /* Reset the controller */ 00685 if(HwReset(ControllerInfo) != STATUS_SUCCESS) 00686 { 00687 WARN_(FLOPPY, "InitController: unable to reset controller\n"); 00688 return STATUS_IO_DEVICE_ERROR; 00689 } 00690 00691 INFO_(FLOPPY, "InitController: waiting for initial interrupt\n"); 00692 00693 /* Wait for an interrupt */ 00694 WaitForControllerInterrupt(ControllerInfo); 00695 00696 /* Reset means you have to clear each of the four interrupts (one per drive) */ 00697 for(i = 0; i < MAX_DRIVES_PER_CONTROLLER; i++) 00698 { 00699 INFO_(FLOPPY, "InitController: Sensing interrupt %d\n", i); 00700 00701 if(HwSenseInterruptStatus(ControllerInfo) != STATUS_SUCCESS) 00702 { 00703 WARN_(FLOPPY, "InitController: Unable to clear interrupt 0x%x\n", i); 00704 return STATUS_IO_DEVICE_ERROR; 00705 } 00706 } 00707 00708 INFO_(FLOPPY, "InitController: done sensing interrupts\n"); 00709 00710 /* Next, see if we have the right version to do implied seek */ 00711 if(ControllerVersion == VERSION_ENHANCED) 00712 { 00713 /* If so, set that up -- all defaults below except first TRUE for EIS */ 00714 if(HwConfigure(ControllerInfo, TRUE, TRUE, TRUE, 0, 0) != STATUS_SUCCESS) 00715 { 00716 WARN_(FLOPPY, "InitController: unable to set up implied seek\n"); 00717 ControllerInfo->ImpliedSeeks = FALSE; 00718 } 00719 else 00720 { 00721 INFO_(FLOPPY, "InitController: implied seeks set!\n"); 00722 ControllerInfo->ImpliedSeeks = TRUE; 00723 } 00724 00725 /* 00726 * FIXME: Figure out the answer to the below 00727 * 00728 * I must admit that I'm really confused about the Model 30 issue. At least one 00729 * important bit (the disk change bit in the DIR) is flipped if this is a Model 30 00730 * controller. However, at least one other floppy driver believes that there are only 00731 * two computers that are guaranteed to have a Model 30 controller: 00732 * - IBM Thinkpad 750 00733 * - IBM PS2e 00734 * 00735 * ...and another driver only lists a config option for "thinkpad", that flips 00736 * the change line. A third driver doesn't mention the Model 30 issue at all. 00737 * 00738 * What I can't tell is whether or not the average, run-of-the-mill computer now has 00739 * a Model 30 controller. For the time being, I'm going to wire this to FALSE, 00740 * and just not support the computers mentioned above, while I try to figure out 00741 * how ubiquitous these newfangled 30 thingies are. 00742 */ 00743 //ControllerInfo->Model30 = TRUE; 00744 ControllerInfo->Model30 = FALSE; 00745 } 00746 else 00747 { 00748 INFO_(FLOPPY, "InitController: enhanced version not supported; disabling implied seeks\n"); 00749 ControllerInfo->ImpliedSeeks = FALSE; 00750 ControllerInfo->Model30 = FALSE; 00751 } 00752 00753 /* Specify */ 00754 WARN_(FLOPPY, "FIXME: Figure out speed\n"); 00755 HeadLoadTime = SPECIFY_HLT_500K; 00756 HeadUnloadTime = SPECIFY_HUT_500K; 00757 StepRateTime = SPECIFY_SRT_500K; 00758 00759 INFO_(FLOPPY, "InitController: setting data rate\n"); 00760 00761 /* Set data rate */ 00762 if(HwSetDataRate(ControllerInfo, DRSR_DSEL_500KBPS) != STATUS_SUCCESS) 00763 { 00764 WARN_(FLOPPY, "InitController: unable to set data rate\n"); 00765 return STATUS_IO_DEVICE_ERROR; 00766 } 00767 00768 INFO_(FLOPPY, "InitController: issuing specify command to controller\n"); 00769 00770 /* Don't disable DMA --> enable dma (dumb & confusing) */ 00771 if(HwSpecify(ControllerInfo, HeadLoadTime, HeadUnloadTime, StepRateTime, FALSE) != STATUS_SUCCESS) 00772 { 00773 WARN_(FLOPPY, "InitController: unable to specify options\n"); 00774 return STATUS_IO_DEVICE_ERROR; 00775 } 00776 00777 /* Init the stop stuff */ 00778 KeInitializeDpc(&ControllerInfo->MotorStopDpc, MotorStopDpcFunc, ControllerInfo); 00779 KeInitializeTimer(&ControllerInfo->MotorTimer); 00780 KeInitializeEvent(&ControllerInfo->MotorStoppedEvent, NotificationEvent, FALSE); 00781 ControllerInfo->StopDpcQueued = FALSE; 00782 00783 /* 00784 * Recalibrate each drive on the controller (depends on StartMotor, which depends on the timer stuff above) 00785 * We don't even know if there is a disk in the drive, so this may not work, but that's OK. 00786 */ 00787 for(i = 0; i < ControllerInfo->NumberOfDrives; i++) 00788 { 00789 INFO_(FLOPPY, "InitController: recalibrating drive 0x%x on controller 0x%p\n", i, ControllerInfo); 00790 Recalibrate(&ControllerInfo->DriveInfo[i]); 00791 } 00792 00793 INFO_(FLOPPY, "InitController: done initializing; returning STATUS_SUCCESS\n"); 00794 00795 return STATUS_SUCCESS; 00796 } 00797 00798 00799 static BOOLEAN NTAPI 00800 AddControllers(PDRIVER_OBJECT DriverObject) 00801 /* 00802 * FUNCTION: Called on initialization to find our controllers and build device and controller objects for them 00803 * ARGUMENTS: 00804 * DriverObject: Our driver's DriverObject (so we can create devices against it) 00805 * RETURNS: 00806 * FALSE if we can't allocate a device, adapter, or interrupt object, or if we fail to find any controllers 00807 * TRUE otherwise (i.e. we have at least one fully-configured controller) 00808 * NOTES: 00809 * - Currently we only support ISA buses. 00810 * - BUG: Windows 2000 seems to clobber the response from the IoQueryDeviceDescription callback, so now we 00811 * just test a boolean value in the first object to see if it was completely populated. The same value 00812 * is tested for each controller before we build device objects for it. 00813 * TODO: 00814 * - Report resource usage to the HAL 00815 */ 00816 { 00817 INTERFACE_TYPE InterfaceType = Isa; 00818 CONFIGURATION_TYPE ControllerType = DiskController; 00819 CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral; 00820 KAFFINITY Affinity; 00821 DEVICE_DESCRIPTION DeviceDescription; 00822 UCHAR i; 00823 UCHAR j; 00824 00825 PAGED_CODE(); 00826 00827 /* Find our controllers on all ISA buses */ 00828 IoQueryDeviceDescription(&InterfaceType, 0, &ControllerType, 0, &PeripheralType, 0, ConfigCallback, 0); 00829 00830 /* 00831 * w2k breaks the return val from ConfigCallback, so we have to hack around it, rather than just 00832 * looking for a return value from ConfigCallback. We expect at least one controller. 00833 */ 00834 if(!gControllerInfo[0].Populated) 00835 { 00836 WARN_(FLOPPY, "AddControllers: failed to get controller info from registry\n"); 00837 return FALSE; 00838 } 00839 00840 /* Now that we have a controller, set it up with the system */ 00841 for(i = 0; i < gNumberOfControllers && gControllerInfo[i].NumberOfDrives > 0; i++) 00842 { 00843 /* 0: Report resource usage to the kernel, to make sure they aren't assigned to anyone else */ 00844 /* FIXME: Implement me. */ 00845 00846 /* 1: Set up interrupt */ 00847 gControllerInfo[i].MappedVector = HalGetInterruptVector(gControllerInfo[i].InterfaceType, gControllerInfo[i].BusNumber, 00848 gControllerInfo[i].Level, gControllerInfo[i].Vector, 00849 &gControllerInfo[i].MappedLevel, &Affinity); 00850 00851 /* Must set up the DPC before we connect the interrupt */ 00852 KeInitializeDpc(&gControllerInfo[i].Dpc, DpcForIsr, &gControllerInfo[i]); 00853 00854 INFO_(FLOPPY, "Connecting interrupt %d to controller%d (object 0x%p)\n", gControllerInfo[i].MappedVector, 00855 i, &gControllerInfo[i]); 00856 00857 /* NOTE: We cannot share our interrupt, even on level-triggered buses. See Isr() for details. */ 00858 if(IoConnectInterrupt(&gControllerInfo[i].InterruptObject, Isr, &gControllerInfo[i], 0, gControllerInfo[i].MappedVector, 00859 gControllerInfo[i].MappedLevel, gControllerInfo[i].MappedLevel, gControllerInfo[i].InterruptMode, 00860 FALSE, Affinity, 0) != STATUS_SUCCESS) 00861 { 00862 WARN_(FLOPPY, "AddControllers: unable to connect interrupt\n"); 00863 continue; 00864 } 00865 00866 /* 2: Set up DMA */ 00867 memset(&DeviceDescription, 0, sizeof(DeviceDescription)); 00868 DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION; 00869 DeviceDescription.DmaChannel = gControllerInfo[i].Dma; 00870 DeviceDescription.InterfaceType = gControllerInfo[i].InterfaceType; 00871 DeviceDescription.BusNumber = gControllerInfo[i].BusNumber; 00872 DeviceDescription.MaximumLength = 2*18*512; /* based on a 1.44MB floppy */ 00873 00874 /* DMA 0,1,2,3 are 8-bit; 4,5,6,7 are 16-bit (4 is chain i think) */ 00875 DeviceDescription.DmaWidth = gControllerInfo[i].Dma > 3 ? Width16Bits: Width8Bits; 00876 00877 gControllerInfo[i].AdapterObject = HalGetAdapter(&DeviceDescription, &gControllerInfo[i].MapRegisters); 00878 00879 if(!gControllerInfo[i].AdapterObject) 00880 { 00881 WARN_(FLOPPY, "AddControllers: unable to allocate an adapter object\n"); 00882 IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); 00883 continue; 00884 } 00885 00886 /* 2b: Initialize the new controller */ 00887 if(InitController(&gControllerInfo[i]) != STATUS_SUCCESS) 00888 { 00889 WARN_(FLOPPY, "AddControllers(): Unable to set up controller %d - initialization failed\n", i); 00890 IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); 00891 continue; 00892 } 00893 00894 /* 2c: Set the controller's initlized flag so we know to release stuff in Unload */ 00895 gControllerInfo[i].Initialized = TRUE; 00896 00897 /* 3: per-drive setup */ 00898 for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++) 00899 { 00900 WCHAR DeviceNameBuf[MAX_DEVICE_NAME]; 00901 UNICODE_STRING DeviceName; 00902 UNICODE_STRING LinkName; 00903 UNICODE_STRING ArcPath; 00904 UCHAR DriveNumber; 00905 00906 INFO_(FLOPPY, "AddControllers(): Configuring drive %d on controller %d\n", i, j); 00907 00908 /* 00909 * 3a: create a device object for the drive 00910 * Controllers and drives are 0-based, so the combos are: 00911 * 0: 0,0 00912 * 1: 0,1 00913 * 2: 0,2 00914 * 3: 0,3 00915 * 4: 1,0 00916 * 5: 1,1 00917 * ... 00918 * 14: 3,2 00919 * 15: 3,3 00920 */ 00921 00922 DriveNumber = (UCHAR)(i*4 + j); /* loss of precision is OK; there are only 16 of 'em */ 00923 00924 RtlZeroMemory(&DeviceNameBuf, MAX_DEVICE_NAME * sizeof(WCHAR)); 00925 swprintf(DeviceNameBuf, L"\\Device\\Floppy%d", DriveNumber); 00926 RtlInitUnicodeString(&DeviceName, DeviceNameBuf); 00927 00928 if(IoCreateDevice(DriverObject, sizeof(PVOID), &DeviceName, 00929 FILE_DEVICE_DISK, FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, FALSE, 00930 &gControllerInfo[i].DriveInfo[j].DeviceObject) != STATUS_SUCCESS) 00931 { 00932 WARN_(FLOPPY, "AddControllers: unable to register a Device object\n"); 00933 IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); 00934 continue; /* continue on to next drive */ 00935 } 00936 00937 INFO_(FLOPPY, "AddControllers: New device: %S (0x%p)\n", DeviceNameBuf, gControllerInfo[i].DriveInfo[j].DeviceObject); 00938 00939 /* 3b.5: Create an ARC path in case we're booting from this drive */ 00940 swprintf(gControllerInfo[i].DriveInfo[j].ArcPathBuffer, 00941 L"\\ArcName\\multi(%d)disk(%d)fdisk(%d)", gControllerInfo[i].BusNumber, i, DriveNumber); 00942 00943 RtlInitUnicodeString(&ArcPath, gControllerInfo[i].DriveInfo[j].ArcPathBuffer); 00944 IoAssignArcName(&ArcPath, &DeviceName); 00945 00946 /* 3c: Set flags up */ 00947 gControllerInfo[i].DriveInfo[j].DeviceObject->Flags |= DO_DIRECT_IO; 00948 00949 /* 3d: Create a symlink */ 00950 swprintf(gControllerInfo[i].DriveInfo[j].SymLinkBuffer, L"\\DosDevices\\%c:", DriveNumber + 'A'); 00951 RtlInitUnicodeString(&LinkName, gControllerInfo[i].DriveInfo[j].SymLinkBuffer); 00952 if(IoCreateSymbolicLink(&LinkName, &DeviceName) != STATUS_SUCCESS) 00953 { 00954 WARN_(FLOPPY, "AddControllers: Unable to create a symlink for drive %d\n", DriveNumber); 00955 IoDisconnectInterrupt(gControllerInfo[i].InterruptObject); 00956 IoDeassignArcName(&ArcPath); 00957 continue; /* continue to next drive */ 00958 } 00959 00960 /* 3e: Increase global floppy drives count */ 00961 IoGetConfigurationInformation()->FloppyCount++; 00962 00963 /* 3f: Set up the DPC */ 00964 IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, (PIO_DPC_ROUTINE)DpcForIsr); 00965 00966 /* 3g: Point the device extension at our DriveInfo struct */ 00967 gControllerInfo[i].DriveInfo[j].DeviceObject->DeviceExtension = &gControllerInfo[i].DriveInfo[j]; 00968 00969 /* 3h: neat comic strip */ 00970 00971 /* 3i: set the initial media type to unknown */ 00972 memset(&gControllerInfo[i].DriveInfo[j].DiskGeometry, 0, sizeof(DISK_GEOMETRY)); 00973 gControllerInfo[i].DriveInfo[j].DiskGeometry.MediaType = Unknown; 00974 00975 /* 3j: Now that we're done, set the Initialized flag so we know to free this in Unload */ 00976 gControllerInfo[i].DriveInfo[j].Initialized = TRUE; 00977 00978 /* 3k: Clear the DO_DEVICE_INITIALIZING flag */ 00979 gControllerInfo[i].DriveInfo[j].DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; 00980 } 00981 } 00982 00983 INFO_(FLOPPY, "AddControllers: --------------------------------------------> finished adding controllers\n"); 00984 00985 return (IoGetConfigurationInformation()->FloppyCount != 0); 00986 } 00987 00988 00989 VOID NTAPI 00990 SignalMediaChanged(PDEVICE_OBJECT DeviceObject, PIRP Irp) 00991 /* 00992 * FUNCTION: Process an IRP when the media has changed, and possibly notify the user 00993 * ARGUMENTS: 00994 * DeviceObject: DeviceObject associated with the IRP 00995 * Irp: IRP that we're failing due to change 00996 * NOTES: 00997 * - This procedure is documented in the DDK by "Notifying the File System of Possible Media Changes", 00998 * "IoSetHardErrorOrVerifyDevice", and by "Responding to Check-Verify Requests from the File System". 00999 * - Callable at <= DISPATCH_LEVEL 01000 */ 01001 { 01002 PDRIVE_INFO DriveInfo = DeviceObject->DeviceExtension; 01003 01004 TRACE_(FLOPPY, "SignalMediaChanged called\n"); 01005 01006 DriveInfo->DiskChangeCount++; 01007 01008 /* If volume is not mounted, do NOT set verify and return STATUS_IO_DEVICE_ERROR */ 01009 if(!(DeviceObject->Vpb->Flags & VPB_MOUNTED)) 01010 { 01011 Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR; 01012 Irp->IoStatus.Information = 0; 01013 return; 01014 } 01015 01016 /* Notify the filesystem that it will need to verify the volume */ 01017 DeviceObject->Flags |= DO_VERIFY_VOLUME; 01018 Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED; 01019 Irp->IoStatus.Information = 0; 01020 01021 /* 01022 * If this is a user-based, threaded request, let the IO manager know to pop up a box asking 01023 * the user to supply the correct media, but only if the error (which we just picked out above) 01024 * is deemed by the IO manager to be "user induced". The reason we don't just unconditionally 01025 * call IoSetHardError... is because MS might change the definition of "user induced" some day, 01026 * and we don't want to have to remember to re-code this. 01027 */ 01028 if(Irp->Tail.Overlay.Thread && IoIsErrorUserInduced(Irp->IoStatus.Status)) 01029 IoSetHardErrorOrVerifyDevice(Irp, DeviceObject); 01030 } 01031 01032 01033 static VOID NTAPI 01034 QueueThread(PVOID Context) 01035 /* 01036 * FUNCTION: Thread that manages the queue and dispatches any queued requests 01037 * ARGUMENTS: 01038 * Context: unused 01039 */ 01040 { 01041 PIRP Irp; 01042 PIO_STACK_LOCATION Stack; 01043 PDEVICE_OBJECT DeviceObject; 01044 PVOID Objects[2]; 01045 01046 PAGED_CODE(); 01047 UNREFERENCED_PARAMETER(Context); 01048 01049 Objects[0] = &QueueSemaphore; 01050 Objects[1] = &QueueThreadTerminate; 01051 01052 for(;;) 01053 { 01054 KeWaitForMultipleObjects(2, Objects, WaitAny, Executive, KernelMode, FALSE, NULL, NULL); 01055 01056 if(KeReadStateEvent(&QueueThreadTerminate)) 01057 { 01058 INFO_(FLOPPY, "QueueThread terminating\n"); 01059 return; 01060 } 01061 01062 INFO_(FLOPPY, "QueueThread: servicing an IRP\n"); 01063 01064 Irp = IoCsqRemoveNextIrp(&Csq, 0); 01065 01066 /* we won't get an irp if it was canceled */ 01067 if(!Irp) 01068 { 01069 INFO_(FLOPPY, "QueueThread: IRP queue empty\n"); 01070 continue; 01071 } 01072 01073 DeviceObject = (PDEVICE_OBJECT)Irp->Tail.Overlay.DriverContext[0]; 01074 01075 ASSERT(DeviceObject); 01076 01077 Stack = IoGetCurrentIrpStackLocation(Irp); 01078 01079 /* Decide what to do with the IRP */ 01080 switch(Stack->MajorFunction) 01081 { 01082 case IRP_MJ_READ: 01083 case IRP_MJ_WRITE: 01084 ReadWritePassive(DeviceObject->DeviceExtension, Irp); 01085 break; 01086 01087 case IRP_MJ_DEVICE_CONTROL: 01088 DeviceIoctlPassive(DeviceObject->DeviceExtension, Irp); 01089 break; 01090 01091 default: 01092 WARN_(FLOPPY, "QueueThread(): Unrecognized irp: mj: 0x%x\n", Stack->MajorFunction); 01093 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED; 01094 Irp->IoStatus.Information = 0; 01095 IoCompleteRequest(Irp, IO_NO_INCREMENT); 01096 } 01097 } 01098 } 01099 01100 01101 NTSTATUS NTAPI 01102 DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath) 01103 /* 01104 * FUNCTION: Entry-point for the driver 01105 * ARGUMENTS: 01106 * DriverObject: Our driver object 01107 * RegistryPath: Unused 01108 * RETURNS: 01109 * STATUS_SUCCESS on successful initialization of at least one drive 01110 * STATUS_NO_SUCH_DEVICE if we didn't find even one drive 01111 * STATUS_UNSUCCESSFUL otherwise 01112 */ 01113 { 01114 HANDLE ThreadHandle; 01115 01116 UNREFERENCED_PARAMETER(RegistryPath); 01117 01118 /* 01119 * Set up dispatch routines 01120 */ 01121 DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)CreateClose; 01122 DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)CreateClose; 01123 DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)ReadWrite; 01124 DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)ReadWrite; 01125 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)DeviceIoctl; 01126 01127 DriverObject->DriverUnload = Unload; 01128 01129 /* 01130 * We depend on some zeroes in these structures. I know this is supposed to be 01131 * initialized to 0 by the complier but this makes me feel beter. 01132 */ 01133 memset(&gControllerInfo, 0, sizeof(gControllerInfo)); 01134 01135 /* 01136 * Set up queue. This routine cannot fail (trust me, I wrote it). 01137 */ 01138 IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp, 01139 CsqAcquireLock, CsqReleaseLock, CsqCompleteCanceledIrp); 01140 01141 /* 01142 * ...and its lock 01143 */ 01144 KeInitializeSpinLock(&IrpQueueLock); 01145 01146 /* 01147 * ...and the queue list itself 01148 */ 01149 InitializeListHead(&IrpQueue); 01150 01151 /* 01152 * The queue is counted by a semaphore. The queue management thread 01153 * blocks on this semaphore, so if requests come in faster than the queue 01154 * thread can handle them, the semaphore count goes up. 01155 */ 01156 KeInitializeSemaphore(&QueueSemaphore, 0, 0x7fffffff); 01157 01158 /* 01159 * Event to terminate that thread 01160 */ 01161 KeInitializeEvent(&QueueThreadTerminate, NotificationEvent, FALSE); 01162 01163 /* 01164 * Create the queue processing thread. Save its handle in the global variable 01165 * ThreadHandle so we can wait on its termination during Unload. 01166 */ 01167 if(PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, QueueThread, 0) != STATUS_SUCCESS) 01168 { 01169 WARN_(FLOPPY, "Unable to create system thread; failing init\n"); 01170 return STATUS_INSUFFICIENT_RESOURCES; 01171 } 01172 01173 if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, PsThreadType, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS) 01174 { 01175 WARN_(FLOPPY, "Unable to reference returned thread handle; failing init\n"); 01176 return STATUS_UNSUCCESSFUL; 01177 } 01178 01179 /* 01180 * Close the handle, now that we have the object pointer and a reference of our own. 01181 * The handle will certainly not be valid in the context of the caller next time we 01182 * need it, as handles are process-specific. 01183 */ 01184 ZwClose(ThreadHandle); 01185 01186 /* 01187 * Start the device discovery proces. Returns STATUS_SUCCESS if 01188 * it finds even one drive attached to one controller. 01189 */ 01190 if(!AddControllers(DriverObject)) 01191 return STATUS_NO_SUCH_DEVICE; 01192 01193 return STATUS_SUCCESS; 01194 } 01195 Generated on Mon May 28 2012 04:28:01 for ReactOS by
1.7.6.1
|