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

floppy.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 doxygen 1.7.6.1

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