Fix access rights (even if not checked in KernelMode)
[reactos.git] / reactos / drivers / storage / floppy / floppy.c
index 0428a78..dd341a9 100644 (file)
  * REVISIONS:
  *                  15-Feb-2004 vizzini - Created
  * NOTES:
+ *  - This driver is only designed to work with ISA-bus floppy controllers.  This
+ *    won't work on PCI-based controllers or on anything else with level-sensitive
+ *    interrupts without modification.  I don't think these controllers exist.
  *
  * ---- General to-do items ----
- * TODO: Clean up properly on failed init
- * TODO: Add arc-path support so we can boot from the floppy
- * TODO: Fix all these stupid STATUS_UNSUCCESSFUL return values
- * TODO: Think about IO_NO_INCREMENT
- * TODO: Figure out why CreateClose isn't called any more on XP.  Seems to correspond 
- *       with the driver not being unloadable.  Does it have to do with cleanup?
- * TODO: Consider using the built-in device object pointer in the stack location 
- *       rather than the context area
+ * TODO: Figure out why CreateClose isn't called any more.  Seems to correspond
+ *       with the driver not being unloadable.
  * TODO: Think about StopDpcQueued -- could be a race; too tired atm to tell
+ * TODO: Clean up drive start/stop responsibilities (currently a mess...)
  *
  * ---- Support for proper media detection ----
  * TODO: Handle MFM flag
  * TODO: Un-hardcode the data rate from various places
  * TODO: Proper media detection (right now we're hardcoded to 1.44)
  * TODO: Media detection based on sector 1
- *
- * ---- Support for normal floppy hardware ----
- * TODO: Support the three primary types of controller
- * TODO: Figure out thinkpad compatibility (I've heard rumors of weirdness with them)
- *
- * ---- Support for non-ISA and/or non-slave-dma controllers, if they exist ----
- * TODO: Find controllers on non-ISA buses
- * TODO: Think about making the interrupt shareable
- * TODO: Support bus-master controllers.  PCI will break ATM.
  */
 
+#define NDEBUG
+#include <debug.h>
 #include <ntddk.h>
 
 #include "floppy.h"
@@ -60,7 +51,7 @@
 #include "readwrite.h"
 
 /*
- * Global controller info structures.  Each controller gets one.  Since the system 
+ * Global controller info structures.  Each controller gets one.  Since the system
  * will probably have only one, with four being a very unlikely maximum, a static
  * global array is easiest to deal with.
  */
@@ -69,7 +60,7 @@ static ULONG gNumberOfControllers = 0;
 
 /* Queue thread management */
 static KEVENT QueueThreadTerminate;
-static PVOID ThreadObject;
+static PVOID QueueThreadObject;
 
 \f
 static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc,
@@ -97,11 +88,11 @@ static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc,
   ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
   ASSERT(ControllerInfo);
 
-  KdPrint(("floppy: MotorStopDpcFunc called\n"));
+  DPRINT("floppy: MotorStopDpcFunc called\n");
 
   HwTurnOffMotor(ControllerInfo);
   ControllerInfo->StopDpcQueued = FALSE;
-  KeSetEvent(&ControllerInfo->MotorStoppedEvent, IO_NO_INCREMENT, FALSE);
+  KeSetEvent(&ControllerInfo->MotorStoppedEvent, EVENT_INCREMENT, FALSE);
 }
 
 \f
@@ -124,18 +115,22 @@ VOID NTAPI StartMotor(PDRIVE_INFO DriveInfo)
   PAGED_CODE();
   ASSERT(DriveInfo);
 
-  KdPrint(("floppy: StartMotor called\n"));
+  DPRINT("floppy: StartMotor called\n");
 
-  if(DriveInfo->ControllerInfo->StopDpcQueued && 
-     !KeCancelTimer(&DriveInfo->ControllerInfo->MotorTimer))
+  if(DriveInfo->ControllerInfo->StopDpcQueued && !KeCancelTimer(&DriveInfo->ControllerInfo->MotorTimer))
     {
       /* Motor turner-offer is already running; wait for it to finish */
+      DPRINT("floppy: StartMotor: motor turner-offer is already running; waiting for it\n");
       KeWaitForSingleObject(&DriveInfo->ControllerInfo->MotorStoppedEvent, Executive, KernelMode, FALSE, NULL);
-      DriveInfo->ControllerInfo->StopDpcQueued = FALSE;
+      DPRINT("floppy: StartMotor: wait satisfied\n");
     }
 
+  DriveInfo->ControllerInfo->StopDpcQueued = FALSE;
+
   if(HwTurnOnMotor(DriveInfo) != STATUS_SUCCESS)
-    KdPrint(("floppy: StartMotor(): warning: HwTurnOnMotor failed\n"));
+  {
+    DPRINT("floppy: StartMotor(): warning: HwTurnOnMotor failed\n");
+  }
 }
 
 \f
@@ -154,7 +149,7 @@ VOID NTAPI StopMotor(PCONTROLLER_INFO ControllerInfo)
 
   ASSERT(ControllerInfo);
 
-  KdPrint(("floppy: StopMotor called\n"));
+  DPRINT("floppy: StopMotor called\n");
 
   /* one relative second, in 100-ns units */
   StopTime.QuadPart = 10000000;
@@ -187,7 +182,7 @@ VOID NTAPI WaitForControllerInterrupt(PCONTROLLER_INFO ControllerInfo)
 }
 
 \f
-static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject, 
+static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject,
                                   PIRP Irp)
 /*
  * FUNCTION: Dispatch function called for Create and Close IRPs
@@ -202,17 +197,17 @@ static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject,
  *     - No state to track, so this routine is easy
  *     - Can be called <= DISPATCH_LEVEL
  *
- * TODO: Figure out why this isn't getting called any more, and remove the ASSERT once that happens
+ * TODO: Figure out why this isn't getting called
  */
 {
   UNREFERENCED_PARAMETER(DeviceObject);
 
-  KdPrint(("floppy: CreateClose called\n"));
+  DPRINT("floppy: CreateClose called\n");
 
   Irp->IoStatus.Status = STATUS_SUCCESS;
   Irp->IoStatus.Information = FILE_OPENED;
 
-  IoCompleteRequest(Irp, IO_NO_INCREMENT);
+  IoCompleteRequest(Irp, IO_DISK_INCREMENT);
 
   return STATUS_SUCCESS;
 }
@@ -225,7 +220,7 @@ static NTSTATUS NTAPI Recalibrate(PDRIVE_INFO DriveInfo)
  *     DriveInfo: Pointer to the driveinfo struct associated with the targeted drive
  * RETURNS:
  *     STATUS_SUCCESS on successful starting of the process
- *     STATUS_UNSUCCESSFUL if it fails
+ *     STATUS_IO_DEVICE_ERROR if it fails
  * NOTES:
  *     - Sometimes you have to do two recalibrations, particularly if the disk has <80 tracks.
  *     - PAGED_CODE because we wait
@@ -242,24 +237,28 @@ static NTSTATUS NTAPI Recalibrate(PDRIVE_INFO DriveInfo)
   StartMotor(DriveInfo);
 
   /* set the data rate */
-  KdPrint(("floppy: FIXME: UN-HARDCODE DATA RATE\n"));
+  DPRINT("floppy: FIXME: UN-HARDCODE DATA RATE\n");
   if(HwSetDataRate(DriveInfo->ControllerInfo, 0) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: Recalibrate: HwSetDataRate failed\n"));
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("floppy: Recalibrate: HwSetDataRate failed\n");
+      StopMotor(DriveInfo->ControllerInfo);
+      return STATUS_IO_DEVICE_ERROR;
     }
 
   /* clear the event just in case the last call forgot */
   KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
 
-  /* sometimes you have to do this twice */
+  /* sometimes you have to do this twice; we'll just do it twice all the time since
+   * we don't know if the people calling this Recalibrate routine expect a disk to
+   * even be in the drive, and if so, if that disk is formatted.
+   */
   for(i = 0; i < 2; i++)
     {
       /* Send the command */
       Status = HwRecalibrate(DriveInfo);
       if(Status != STATUS_SUCCESS)
        {
-         KdPrint(("floppy: Recalibrate: HwRecalibrate returned error\n"));
+         DPRINT("floppy: Recalibrate: HwRecalibrate returned error\n");
           continue;
        }
 
@@ -269,7 +268,7 @@ static NTSTATUS NTAPI Recalibrate(PDRIVE_INFO DriveInfo)
       Status = HwRecalibrateResult(DriveInfo->ControllerInfo);
       if(Status != STATUS_SUCCESS)
        {
-         KdPrint(("floppy: Recalibrate: HwRecalibrateResult returned error\n"));
+         DPRINT("floppy: Recalibrate: HwRecalibrateResult returned error\n");
           break;
         }
     }
@@ -304,7 +303,7 @@ NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
   PAGED_CODE();
   ASSERT(DriveInfo);
 
-  KdPrint(("floppy: ResetChangeFlag called\n"));
+  DPRINT("floppy: ResetChangeFlag called\n");
 
   /* Try to recalibrate.  We don't care if it works. */
   Recalibrate(DriveInfo);
@@ -312,10 +311,14 @@ NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
   /* clear spurious interrupts in prep for seeks */
   KeClearEvent(&DriveInfo->ControllerInfo->SynchEvent);
 
+  /* must re-start the drive because Recalibrate() stops it */
+  StartMotor(DriveInfo);
+
   /* Seek to 1 */
   if(HwSeek(DriveInfo, 1) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n"));
+      DPRINT("floppy: ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n");
+      StopMotor(DriveInfo->ControllerInfo);
       return STATUS_IO_DEVICE_ERROR;
     }
 
@@ -323,14 +326,16 @@ NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
 
   if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: ResetChangeFlag(): HwSenseInterruptStatus failed; bailing out\n"));
+      DPRINT("floppy: ResetChangeFlag(): HwSenseInterruptStatus failed; bailing out\n");
+      StopMotor(DriveInfo->ControllerInfo);
       return STATUS_IO_DEVICE_ERROR;
     }
 
   /* Seek back to 0 */
-  if(HwSeek(DriveInfo, 1) != STATUS_SUCCESS)
+  if(HwSeek(DriveInfo, 0) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n"));
+      DPRINT("floppy: ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n");
+      StopMotor(DriveInfo->ControllerInfo);
       return STATUS_IO_DEVICE_ERROR;
     }
 
@@ -338,17 +343,21 @@ NTSTATUS NTAPI ResetChangeFlag(PDRIVE_INFO DriveInfo)
 
   if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: ResetChangeFlag(): HwSenseInterruptStatus #2 failed; bailing\n"));
+      DPRINT("floppy: ResetChangeFlag(): HwSenseInterruptStatus #2 failed; bailing\n");
+      StopMotor(DriveInfo->ControllerInfo);
       return STATUS_IO_DEVICE_ERROR;
     }
 
   /* Check the change bit */
   if(HwDiskChanged(DriveInfo, &DiskChanged) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: ResetChangeFlag(): HwDiskChagned failed; returning STATUS_IO_DEVICE_ERROR\n"));
+      DPRINT("floppy: ResetChangeFlag(): HwDiskChagned failed; returning STATUS_IO_DEVICE_ERROR\n");
+      StopMotor(DriveInfo->ControllerInfo);
       return STATUS_IO_DEVICE_ERROR;
     }
 
+  StopMotor(DriveInfo->ControllerInfo);
+
   /* if the change flag is still set, there's probably no media in the drive. */
   if(DiskChanged)
     return STATUS_NO_MEDIA_IN_DEVICE;
@@ -363,8 +372,6 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
  * FUNCTION: Unload the driver from memory
  * ARGUMENTS:
  *     DriverObject - The driver that is being unloaded
- *
- * TODO: Delete ARC links
  */
 {
   ULONG i,j;
@@ -372,24 +379,32 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
   PAGED_CODE();
   UNREFERENCED_PARAMETER(DriverObject);
 
-  KdPrint(("floppy: unloading\n"));
+  DPRINT("floppy: unloading\n");
 
   KeSetEvent(&QueueThreadTerminate, 0, FALSE);
-  KeWaitForSingleObject(ThreadObject, Executive, KernelMode, FALSE, 0);
-  ObDereferenceObject(ThreadObject);
+  KeWaitForSingleObject(QueueThreadObject, Executive, KernelMode, FALSE, 0);
+  ObDereferenceObject(QueueThreadObject);
 
   for(i = 0; i < gNumberOfControllers; i++)
     {
-      if(!gControllerInfo[i].Populated)
+      if(!gControllerInfo[i].Initialized)
        continue;
 
       for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++)
        {
+         if(!gControllerInfo[i].DriveInfo[j].Initialized)
+           continue;
+
           if(gControllerInfo[i].DriveInfo[j].DeviceObject)
             {
              UNICODE_STRING Link;
+
              RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].SymLinkBuffer);
              IoDeleteSymbolicLink(&Link);
+
+             RtlInitUnicodeString(&Link, gControllerInfo[i].DriveInfo[j].ArcPathBuffer);
+             IoDeassignArcName(&Link);
+
               IoDeleteDevice(gControllerInfo[i].DriveInfo[j].DeviceObject);
             }
        }
@@ -398,7 +413,9 @@ static VOID NTAPI Unload(PDRIVER_OBJECT DriverObject)
 
       /* Power down the controller */
       if(HwPowerOff(&gControllerInfo[i]) != STATUS_SUCCESS)
-       KdPrint(("floppy: unload: warning: HwPowerOff failed\n"));
+      {
+       DPRINT("floppy: unload: warning: HwPowerOff failed\n");
+      }
     }
 }
 
@@ -446,11 +463,11 @@ static NTSTATUS NTAPI ConfigCallback(PVOID Context,
  */
 {
   PKEY_VALUE_FULL_INFORMATION ControllerFullDescriptor = ControllerInformation[IoQueryDeviceConfigurationData];
-  PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor + 
+  PCM_FULL_RESOURCE_DESCRIPTOR ControllerResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)ControllerFullDescriptor +
                                                                ControllerFullDescriptor->DataOffset);
 
   PKEY_VALUE_FULL_INFORMATION PeripheralFullDescriptor = PeripheralInformation[IoQueryDeviceConfigurationData];
-  PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor + 
+  PCM_FULL_RESOURCE_DESCRIPTOR PeripheralResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PCHAR)PeripheralFullDescriptor +
                                                                PeripheralFullDescriptor->DataOffset);
 
   PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor;
@@ -466,7 +483,7 @@ static NTSTATUS NTAPI ConfigCallback(PVOID Context,
   UNREFERENCED_PARAMETER(PathName);
 
 
-  KdPrint(("floppy: ConfigCallback called with ControllerNumber %d\n", ControllerNumber));
+  DPRINT("floppy: ConfigCallback called with ControllerNumber %d\n", ControllerNumber);
 
   gControllerInfo[gNumberOfControllers].ControllerNumber = ControllerNumber;
   gControllerInfo[gNumberOfControllers].InterfaceType = BusType;
@@ -497,18 +514,14 @@ static NTSTATUS NTAPI ConfigCallback(PVOID Context,
 
           if(!HalTranslateBusAddress(BusType, BusNumber, PartialDescriptor->u.Port.Start, &AddressSpace, &TranslatedAddress))
            {
-             KdPrint(("floppy: HalTranslateBusAddress failed; returning\n"));
+             DPRINT("floppy: HalTranslateBusAddress failed; returning\n");
              return STATUS_IO_DEVICE_ERROR;
            }
 
           if(AddressSpace == 0)
-           {
-              gControllerInfo[gNumberOfControllers].BaseAddress = MmMapIoSpace(TranslatedAddress, 8, MmNonCached); // symbolic constant?
-           }
+              gControllerInfo[gNumberOfControllers].BaseAddress = MmMapIoSpace(TranslatedAddress, FDC_PORT_BYTES, MmNonCached);
           else
-           {
               gControllerInfo[gNumberOfControllers].BaseAddress = (PUCHAR)TranslatedAddress.u.LowPart;
-           }
         }
 
       else if(PartialDescriptor->Type == CmResourceTypeDma)
@@ -579,10 +592,9 @@ static BOOLEAN NTAPI Isr(PKINTERRUPT Interrupt,
  *       triggered, this is safe to not do here, as we can just wait for the DPC.
  *     - Either way, we don't want to do this here.  The controller shouldn't interrupt again, so we'll
  *       schedule a DPC to take care of it.
- * TODO:
- *     - This driver really cannot shrare interrupts, as I don't know how to conclusively say 
+ *     - This driver really cannot shrare interrupts, as I don't know how to conclusively say
  *       whether it was our controller that interrupted or not.  I just have to assume that any time
- *       my ISR gets called, it was my board that called it.  Dumb design, yes, but it goes back to 
+ *       my ISR gets called, it was my board that called it.  Dumb design, yes, but it goes back to
  *       the semantics of ISA buses.  That, and I don't know much about ISA drivers. :-)
  *       UPDATE: The high bit of Status Register A seems to work on non-AT controllers.
  *     - Called at DIRQL
@@ -594,7 +606,7 @@ static BOOLEAN NTAPI Isr(PKINTERRUPT Interrupt,
 
   ASSERT(ControllerInfo);
 
-  KdPrint(("floppy: ISR called\n"));
+  DPRINT("floppy: ISR called\n");
 
   /*
    * Due to the stupidity of the drive/controller relationship on the floppy drive, only one device object
@@ -619,7 +631,7 @@ VOID NTAPI DpcForIsr(PKDPC UnusedDpc,
  *     UnusedDpc: Pointer to the DPC object that represents our function
  *     DeviceObject: Device that this DPC is running for
  *     Irp: Unused
- *     Context: Pointer to our ControllerInfo struct 
+ *     Context: Pointer to our ControllerInfo struct
  * NOTES:
  *     - This function just kicks off whatever the SynchEvent is and returns.  We depend on
  *       the thing that caused the drive to interrupt to handle the work of clearing the interrupt.
@@ -638,9 +650,9 @@ VOID NTAPI DpcForIsr(PKDPC UnusedDpc,
 
   ASSERT(ControllerInfo);
 
-  KdPrint(("floppy: DpcForIsr called\n"));
+  DPRINT("floppy: DpcForIsr called\n");
 
-  KeSetEvent(&ControllerInfo->SynchEvent, IO_NO_INCREMENT, FALSE);
+  KeSetEvent(&ControllerInfo->SynchEvent, EVENT_INCREMENT, FALSE);
 }
 
 \f
@@ -651,7 +663,7 @@ static NTSTATUS NTAPI InitController(PCONTROLLER_INFO ControllerInfo)
  *     ControllerInfo: pointer to the controller to be initialized
  * RETURNS:
  *     STATUS_SUCCESS if the controller is successfully initialized
- *     STATUS_UNSUCCESSFUL otherwise
+ *     STATUS_IO_DEVICE_ERROR otherwise
  */
 {
   int i;
@@ -662,33 +674,29 @@ static NTSTATUS NTAPI InitController(PCONTROLLER_INFO ControllerInfo)
   PAGED_CODE();
   ASSERT(ControllerInfo);
 
-  KdPrint(("floppy: InitController called with Controller 0x%x\n", ControllerInfo));
+  DPRINT("floppy: InitController called with Controller 0x%x\n", ControllerInfo);
 
   KeClearEvent(&ControllerInfo->SynchEvent);
 
-  //HwDumpRegisters(ControllerInfo);
-
-  KdPrint(("floppy: InitController: resetting the controller\n"));
+  DPRINT("floppy: InitController: resetting the controller\n");
 
   /* Reset the controller */
   if(HwReset(ControllerInfo) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: InitController: unable to reset controller\n"));
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("floppy: InitController: unable to reset controller\n");
+      return STATUS_IO_DEVICE_ERROR;
     }
 
-  //HwDumpRegisters(ControllerInfo);
-
-  KdPrint(("floppy: InitController: setting data rate\n"));
+  DPRINT("floppy: InitController: setting data rate\n");
 
   /* Set data rate */
   if(HwSetDataRate(ControllerInfo, DRSR_DSEL_500KBPS) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: InitController: unable to set data rate\n"));
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("floppy: InitController: unable to set data rate\n");
+      return STATUS_IO_DEVICE_ERROR;
     }
 
-  KdPrint(("floppy: InitController: waiting for initial interrupt\n"));
+  DPRINT("floppy: InitController: waiting for initial interrupt\n");
 
   /* Wait for an interrupt */
   WaitForControllerInterrupt(ControllerInfo);
@@ -696,83 +704,92 @@ static NTSTATUS NTAPI InitController(PCONTROLLER_INFO ControllerInfo)
   /* Reset means you have to clear each of the four interrupts (one per drive) */
   for(i = 0; i < MAX_DRIVES_PER_CONTROLLER; i++)
     {
-      KdPrint(("floppy: InitController: Sensing interrupt %d\n", i));
-      //HwDumpRegisters(ControllerInfo);
+      DPRINT("floppy: InitController: Sensing interrupt %d\n", i);
 
       if(HwSenseInterruptStatus(ControllerInfo) != STATUS_SUCCESS)
        {
-         KdPrint(("floppy: InitController: Unable to clear interrupt 0x%x\n", i));
-         return STATUS_UNSUCCESSFUL;
+         DPRINT("floppy: InitController: Unable to clear interrupt 0x%x\n", i);
+         return STATUS_IO_DEVICE_ERROR;
        }
     }
 
-  KdPrint(("floppy: InitController: done sensing interrupts\n"));
-
-  //HwDumpRegisters(ControllerInfo);
+  DPRINT("floppy: InitController: done sensing interrupts\n");
 
   /* Next, see if we have the right version to do implied seek */
-  if(HwGetVersion(ControllerInfo) != VERSION_ENHANCED)
-    {
-      KdPrint(("floppy: InitController: enhanced version not supported; disabling implied seeks\n"));
-      ControllerInfo->ImpliedSeeks = FALSE;
-      ControllerInfo->Model30 = FALSE;
-    }
-  else
+  if(HwGetVersion(ControllerInfo) == VERSION_ENHANCED)
     {
       /* If so, set that up -- all defaults below except first TRUE for EIS */
       if(HwConfigure(ControllerInfo, TRUE, TRUE, FALSE, 0, 0) != STATUS_SUCCESS)
        {
-         KdPrint(("floppy: InitController: unable to set up implied seek\n"));
+         DPRINT("floppy: InitController: unable to set up implied seek\n");
           ControllerInfo->ImpliedSeeks = FALSE;
        }
-      else 
+      else
        {
-         KdPrint(("floppy: InitController: implied seeks set!\n"));
+         DPRINT("floppy: InitController: implied seeks set!\n");
           ControllerInfo->ImpliedSeeks = TRUE;
        }
 
-      ControllerInfo->Model30 = TRUE;
+      /*
+       * FIXME: Figure out the answer to the below
+       *
+       * I must admit that I'm really confused about the Model 30 issue.  At least one
+       * important bit (the disk change bit in the DIR) is flipped if this is a Model 30
+       * controller.  However, at least one other floppy driver believes that there are only
+       * two computers that are guaranteed to have a Model 30 controller:
+       *  - IBM Thinkpad 750
+       *  - IBM PS2e
+       *
+       * ...and another driver only lists a config option for "thinkpad", that flips
+       * the change line.  A third driver doesn't mention the Model 30 issue at all.
+       *
+       * What I can't tell is whether or not the average, run-of-the-mill computer now has
+       * a Model 30 controller.  For the time being, I'm going to wire this to FALSE,
+       * and just not support the computers mentioned above, while I try to figure out
+       * how ubiquitous these newfangled 30 thingies are.
+       */
+      //ControllerInfo->Model30 = TRUE;
+      ControllerInfo->Model30 = FALSE;
     }
-  
+  else
+    {
+      DPRINT("floppy: InitController: enhanced version not supported; disabling implied seeks\n");
+      ControllerInfo->ImpliedSeeks = FALSE;
+      ControllerInfo->Model30 = FALSE;
+    }
+
   /* Specify */
-  KdPrint(("FLOPPY: FIXME: Figure out speed\n"));
+  DPRINT("FLOPPY: FIXME: Figure out speed\n");
   HeadLoadTime = SPECIFY_HLT_500K;
   HeadUnloadTime = SPECIFY_HUT_500K;
   StepRateTime = SPECIFY_SRT_500K;
 
-  KdPrint(("floppy: InitController: issuing specify command to controller\n"));
-      
+  DPRINT("floppy: InitController: issuing specify command to controller\n");
+
   /* Don't disable DMA --> enable dma (dumb & confusing) */
   if(HwSpecify(ControllerInfo, HeadLoadTime, HeadUnloadTime, StepRateTime, FALSE) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: InitController: unable to specify options\n"));
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("floppy: InitController: unable to specify options\n");
+      return STATUS_IO_DEVICE_ERROR;
     }
 
-  //HwDumpRegisters(ControllerInfo);
-
   /* Init the stop stuff */
   KeInitializeDpc(&ControllerInfo->MotorStopDpc, MotorStopDpcFunc, ControllerInfo);
   KeInitializeTimer(&ControllerInfo->MotorTimer);
-  KeInitializeEvent(&ControllerInfo->MotorStoppedEvent, SynchronizationEvent, FALSE);
+  KeInitializeEvent(&ControllerInfo->MotorStoppedEvent, NotificationEvent, FALSE);
   ControllerInfo->StopDpcQueued = FALSE;
 
-  /* Recalibrate each drive on the controller (depends on StartMotor, which depends on the timer stuff above) */
-  /* TODO: Handle failure of one or more drives */
+  /*
+   * Recalibrate each drive on the controller (depends on StartMotor, which depends on the timer stuff above)
+   * We don't even know if there is a disk in the drive, so this may not work, but that's OK.
+   */
   for(i = 0; i < ControllerInfo->NumberOfDrives; i++)
     {
-      KdPrint(("floppy: InitController: recalibrating drive 0x%x on controller 0x%x\n", i, ControllerInfo));
-
-      if(Recalibrate(&ControllerInfo->DriveInfo[i]) != STATUS_SUCCESS)
-       {
-         KdPrint(("floppy: InitController: unable to recalibrate drive\n"));
-         return STATUS_UNSUCCESSFUL;
-       }
+      DPRINT("floppy: InitController: recalibrating drive 0x%x on controller 0x%x\n", i, ControllerInfo);
+      Recalibrate(&ControllerInfo->DriveInfo[i]);
     }
 
-  //HwDumpRegisters(ControllerInfo);
-
-  KdPrint(("floppy: InitController: done initializing; returning STATUS_SUCCESS\n"));
+  DPRINT("floppy: InitController: done initializing; returning STATUS_SUCCESS\n");
 
   return STATUS_SUCCESS;
 }
@@ -787,16 +804,12 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
  *     FALSE if we can't allocate a device, adapter, or interrupt object, or if we fail to find any controllers
  *     TRUE otherwise (i.e. we have at least one fully-configured controller)
  * NOTES:
- *     - Currently we only support ISA buses.  
+ *     - Currently we only support ISA buses.
  *     - BUG: Windows 2000 seems to clobber the response from the IoQueryDeviceDescription callback, so now we
  *       just test a boolean value in the first object to see if it was completely populated.  The same value
  *       is tested for each controller before we build device objects for it.
  * TODO:
- *     - Figure out a workable interrupt-sharing scheme and un-hardcode FALSE in IoConnectInterrupt
- *     - Add support for non-ISA buses, by looping through all of the bus types looking for floppy controllers
  *     - Report resource usage to the HAL
- *     - Add ARC path support
- *     - Think more about error handling; atm most errors abort the start of the driver
  */
 {
   INTERFACE_TYPE InterfaceType = Isa;
@@ -812,13 +825,13 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
   /* Find our controllers on all ISA buses */
   IoQueryDeviceDescription(&InterfaceType, 0, &ControllerType, 0, &PeripheralType, 0, ConfigCallback, 0);
 
-  /* 
+  /*
    * w2k breaks the return val from ConfigCallback, so we have to hack around it, rather than just
-   * looking for a return value from ConfigCallback
-   */ 
+   * looking for a return value from ConfigCallback.  We expect at least one controller.
+   */
   if(!gControllerInfo[0].Populated)
     {
-      KdPrint(("floppy: AddControllers: failed to get controller info from registry\n"));
+      DPRINT("floppy: AddControllers: failed to get controller info from registry\n");
       return FALSE;
     }
 
@@ -826,7 +839,7 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
   for(i = 0; i < gNumberOfControllers; i++)
     {
       /* 0: Report resource usage to the kernel, to make sure they aren't assigned to anyone else */
-      /* XXX do me baby */
+      /* FIXME: Implement me. */
 
       /* 1: Set up interrupt */
       gControllerInfo[i].MappedVector = HalGetInterruptVector(gControllerInfo[i].InterfaceType, gControllerInfo[i].BusNumber,
@@ -836,64 +849,61 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
       /* Must set up the DPC before we connect the interrupt */
       KeInitializeDpc(&gControllerInfo[i].Dpc, DpcForIsr, &gControllerInfo[i]);
 
-      KdPrint(("floppy: Connecting interrupt %d to controller%d (object 0x%x)\n", gControllerInfo[i].MappedVector,
-              i, &gControllerInfo[i]));
+      DPRINT("floppy: Connecting interrupt %d to controller%d (object 0x%x)\n", gControllerInfo[i].MappedVector,
+              i, &gControllerInfo[i]);
 
       /* NOTE: We cannot share our interrupt, even on level-triggered buses.  See Isr() for details. */
       if(IoConnectInterrupt(&gControllerInfo[i].InterruptObject, Isr, &gControllerInfo[i], 0, gControllerInfo[i].MappedVector,
          gControllerInfo[i].MappedLevel, gControllerInfo[i].MappedLevel, gControllerInfo[i].InterruptMode,
          FALSE, Affinity, 0) != STATUS_SUCCESS)
         {
-          KdPrint(("floppy: AddControllers: unable to connect interrupt\n"));
-          return FALSE;
+          DPRINT("floppy: AddControllers: unable to connect interrupt\n");
+          continue;
         }
 
       /* 2: Set up DMA */
-
       memset(&DeviceDescription, 0, sizeof(DeviceDescription));
       DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
-      DeviceDescription.Master = (gControllerInfo[i].InterfaceType == PCIBus ? TRUE : FALSE); /* guessing if not pci not master */
       DeviceDescription.DmaChannel = gControllerInfo[i].Dma;
       DeviceDescription.InterfaceType = gControllerInfo[i].InterfaceType;
       DeviceDescription.BusNumber = gControllerInfo[i].BusNumber;
+      DeviceDescription.MaximumLength = 2*18*512; /* based on a 1.44MB floppy */
 
-      if(gControllerInfo[i].InterfaceType == PCIBus)
-        {
-          DeviceDescription.Dma32BitAddresses = TRUE;
-          DeviceDescription.DmaWidth = Width32Bits;
-        }
-      else
-       /* DMA 0,1,2,3 are 8-bit; 4,5,6,7 are 16-bit (4 is chain i think) */
-        DeviceDescription.DmaWidth = gControllerInfo[i].Dma > 3 ? Width16Bits: Width8Bits;
+      /* DMA 0,1,2,3 are 8-bit; 4,5,6,7 are 16-bit (4 is chain i think) */
+      DeviceDescription.DmaWidth = gControllerInfo[i].Dma > 3 ? Width16Bits: Width8Bits;
 
       gControllerInfo[i].AdapterObject = HalGetAdapter(&DeviceDescription, &gControllerInfo[i].MapRegisters);
 
       if(!gControllerInfo[i].AdapterObject)
         {
-          KdPrint(("floppy: AddControllers: unable to allocate an adapter object\n"));
+          DPRINT("floppy: AddControllers: unable to allocate an adapter object\n");
           IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
-          return FALSE;
+          continue;
         }
 
       /* 2b: Initialize the new controller */
       if(InitController(&gControllerInfo[i]) != STATUS_SUCCESS)
        {
-         KdPrint(("floppy: AddControllers():Unable to set up controller %d - initialization failed\n", i));
-         ASSERT(0); /* FIXME: clean up properly */
+         DPRINT("floppy: AddControllers():Unable to set up controller %d - initialization failed\n", i);
+          IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
          continue;
        }
 
+      /* 2c: Set the controller's initlized flag so we know to release stuff in Unload */
+      gControllerInfo[i].Initialized = TRUE;
+
       /* 3: per-drive setup */
       for(j = 0; j < gControllerInfo[i].NumberOfDrives; j++)
         {
           WCHAR DeviceNameBuf[MAX_DEVICE_NAME];
           UNICODE_STRING DeviceName;
           UNICODE_STRING LinkName;
+         UNICODE_STRING ArcPath;
          UCHAR DriveNumber;
 
-         KdPrint(("floppy: AddControllers(): Configuring drive %d on controller %d\n", i, j));
+         DPRINT("floppy: AddControllers(): Configuring drive %d on controller %d\n", i, j);
 
-         /* 
+         /*
           * 3a: create a device object for the drive
           * Controllers and drives are 0-based, so the combos are:
           * 0: 0,0
@@ -904,23 +914,30 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
           * 5: 1,1
           * ...
           * 14: 3,2
-          * 15: 3,3 
-          */ 
+          * 15: 3,3
+          */
          DriveNumber = (UCHAR)(i*4 + j); /* loss of precision is OK; there are only 16 of 'em */
 
           swprintf(DeviceNameBuf, L"\\Device\\Floppy%d", DriveNumber);
           RtlInitUnicodeString(&DeviceName, DeviceNameBuf);
 
-          if(IoCreateDevice(DriverObject, sizeof(PVOID), &DeviceName, 
+          if(IoCreateDevice(DriverObject, sizeof(PVOID), &DeviceName,
                            FILE_DEVICE_DISK, FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, FALSE,
                             &gControllerInfo[i].DriveInfo[j].DeviceObject) != STATUS_SUCCESS)
             {
-              KdPrint(("floppy: AddControllers: unable to register a Device object\n"));
+              DPRINT("floppy: AddControllers: unable to register a Device object\n");
               IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
-              return FALSE;
+              continue; /* continue on to next drive */
             }
 
-         KdPrint(("floppy: AddControllers: New device: %S (0x%x)\n", DeviceNameBuf, gControllerInfo[i].DriveInfo[j].DeviceObject));
+         DPRINT("floppy: AddControllers: New device: %S (0x%x)\n", DeviceNameBuf, gControllerInfo[i].DriveInfo[j].DeviceObject);
+
+         /* 3b.5: Create an ARC path in case we're booting from this drive */
+         swprintf(gControllerInfo[i].DriveInfo[j].ArcPathBuffer,
+                  L"\\ArcName\\multi(%d)disk(%d)fdisk(%d)", gControllerInfo[i].BusNumber, i, DriveNumber);
+
+         RtlInitUnicodeString(&ArcPath, gControllerInfo[i].DriveInfo[j].ArcPathBuffer);
+         IoAssignArcName(&ArcPath, &DeviceName);
 
          /* 3c: Set flags up */
          gControllerInfo[i].DriveInfo[j].DeviceObject->Flags |= DO_DIRECT_IO;
@@ -930,10 +947,10 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
          RtlInitUnicodeString(&LinkName, gControllerInfo[i].DriveInfo[j].SymLinkBuffer);
          if(IoCreateSymbolicLink(&LinkName, &DeviceName) != STATUS_SUCCESS)
            {
-             KdPrint(("floppy: AddControllers: Unable to create a symlink for drive %d\n", DriveNumber));
+             DPRINT("floppy: AddControllers: Unable to create a symlink for drive %d\n", DriveNumber);
              IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
-             // delete devices too?
-             return FALSE;
+             IoDeassignArcName(&ArcPath);
+             continue; /* continue to next drive */
            }
 
          /* 3e: Set up the DPC */
@@ -947,10 +964,13 @@ static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
          /* 3h: set the initial media type to unknown */
          memset(&gControllerInfo[i].DriveInfo[j].DiskGeometry, 0, sizeof(DISK_GEOMETRY));
          gControllerInfo[i].DriveInfo[j].DiskGeometry.MediaType = Unknown;
+
+         /* 3i: Now that we're done, set the Initialized flag so we know to free this in Unload */
+         gControllerInfo[i].DriveInfo[j].Initialized = TRUE;
         }
     }
 
-  KdPrint(("floppy: AddControllers: --------------------------------------------> finished adding controllers\n"));
+  DPRINT("floppy: AddControllers: --------------------------------------------> finished adding controllers\n");
 
   return TRUE;
 }
@@ -971,7 +991,7 @@ VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject,
 {
   PDRIVE_INFO DriveInfo = DeviceObject->DeviceExtension;
 
-  KdPrint(("floppy: SignalMediaChanged called\n"));
+  DPRINT("floppy: SignalMediaChanged called\n");
 
   DriveInfo->DiskChangeCount++;
 
@@ -988,7 +1008,7 @@ VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject,
   Irp->IoStatus.Status = STATUS_VERIFY_REQUIRED;
   Irp->IoStatus.Information = 0;
 
-  /* 
+  /*
    * If this is a user-based, threaded request, let the IO manager know to pop up a box asking
    * the user to supply the correct media, but only if the error (which we just picked out above)
    * is deemed by the IO manager to be "user induced".  The reason we don't just unconditionally
@@ -1024,18 +1044,18 @@ static VOID NTAPI QueueThread(PVOID Context)
 
       if(KeReadStateEvent(&QueueThreadTerminate))
        {
-         KdPrint(("floppy: QueueThread terminating\n"));
+         DPRINT("floppy: QueueThread terminating\n");
           return;
        }
 
-      KdPrint(("floppy: QueueThread: servicing an IRP\n"));
+      DPRINT("floppy: QueueThread: servicing an IRP\n");
 
       Irp = IoCsqRemoveNextIrp(&Csq, 0);
 
       /* we won't get an irp if it was canceled */
       if(!Irp)
        {
-         KdPrint(("floppy: QueueThread: IRP queue empty\n"));
+         DPRINT("floppy: QueueThread: IRP queue empty\n");
           continue;
        }
 
@@ -1058,7 +1078,7 @@ static VOID NTAPI QueueThread(PVOID Context)
          break;
 
        default:
-         KdPrint(("floppy: QueueThread(): Unrecognized irp: mj: 0x%x\n", Stack->MajorFunction));
+         DPRINT("floppy: QueueThread(): Unrecognized irp: mj: 0x%x\n", Stack->MajorFunction);
          Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
          Irp->IoStatus.Information = 0;
          IoCompleteRequest(Irp, IO_NO_INCREMENT);
@@ -1096,7 +1116,7 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
   DriverObject->DriverUnload = Unload;
 
   /*
-   * We depend on some zeroes in these structures.  I know this is supposed to be 
+   * We depend on some zeroes in these structures.  I know this is supposed to be
    * initialized to 0 by the complier but this makes me feel beter.
    */
   memset(&gControllerInfo, 0, sizeof(gControllerInfo));
@@ -1104,7 +1124,7 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
   /*
    * Set up queue.  This routine cannot fail (trust me, I wrote it).
    */
-  IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp, 
+  IoCsqInitialize(&Csq, CsqInsertIrp, CsqRemoveIrp, CsqPeekNextIrp,
                   CsqAcquireLock, CsqReleaseLock, CsqCompleteCanceledIrp);
 
   /*
@@ -1118,39 +1138,43 @@ NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
   InitializeListHead(&IrpQueue);
 
   /*
-   * The queue is counted by a semaphore.  The queue management thread 
+   * The queue is counted by a semaphore.  The queue management thread
    * blocks on this semaphore, so if requests come in faster than the queue
-   * thread can handle them, the semaphore count goes up. 
+   * thread can handle them, the semaphore count goes up.
    */
   KeInitializeSemaphore(&QueueSemaphore, 0, 0x7fffffff);
 
+  /*
+   * Event to terminate that thread
+   */
+  KeInitializeEvent(&QueueThreadTerminate, NotificationEvent, FALSE);
+
   /*
    * Create the queue processing thread.  Save its handle in the global variable
    * ThreadHandle so we can wait on its termination during Unload.
    */
-  if(PsCreateSystemThread(&ThreadHandle, 0, 0, 0, 0, QueueThread, 0) != STATUS_SUCCESS)
+  if(PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, 0, 0, 0, QueueThread, 0) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: Unable to create system thread; failing init\n"));
-      return STATUS_UNSUCCESSFUL;
+      DPRINT("floppy: Unable to create system thread; failing init\n");
+      return STATUS_INSUFFICIENT_RESOURCES;
     }
 
-  if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &ThreadObject, NULL) != STATUS_SUCCESS)
+  if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS)
     {
-      KdPrint(("floppy: Unable to reference returned thread handle; failing init\n"));
+      DPRINT("floppy: Unable to reference returned thread handle; failing init\n");
       return STATUS_UNSUCCESSFUL;
     }
 
-  ZwClose(ThreadHandle);
-
   /*
-   * Event to terminate that thread
+   * Close the handle, now that we have the object pointer and a reference of our own.
+   * The handle will certainly not be valid in the context of the caller next time we
+   * need it, as handles are process-specific.
    */
-  KeInitializeEvent(&QueueThreadTerminate, NotificationEvent, FALSE);
+  ZwClose(ThreadHandle);
 
   /*
-   * Start the device discovery proces.  In theory, this should return STATUS_SUCCESS if
-   * it finds even one drive attached to one controller.  In practice, the AddControllers
-   * routine doesn't handle all of the errors right just yet.  FIXME.
+   * Start the device discovery proces.  Returns STATUS_SUCCESS if
+   * it finds even one drive attached to one controller.
    */
   if(!AddControllers(DriverObject))
     return STATUS_NO_SUCH_DEVICE;