* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* PROJECT: ReactOS Floppy Driver
* FILE: floppy.c
* 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.
*/
#include <ntddk.h>
+#include <debug.h>
#include "floppy.h"
#include "hardware.h"
#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.
*/
/* Queue thread management */
static KEVENT QueueThreadTerminate;
-static PVOID ThreadObject;
+static PVOID QueueThreadObject;
\f
static VOID NTAPI MotorStopDpcFunc(PKDPC UnusedDpc,
ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
ASSERT(ControllerInfo);
- KdPrint(("floppy: MotorStopDpcFunc called\n"));
+ TRACE_(FLOPPY, "MotorStopDpcFunc called\n");
HwTurnOffMotor(ControllerInfo);
ControllerInfo->StopDpcQueued = FALSE;
- KeSetEvent(&ControllerInfo->MotorStoppedEvent, IO_NO_INCREMENT, FALSE);
+ KeSetEvent(&ControllerInfo->MotorStoppedEvent, EVENT_INCREMENT, FALSE);
}
\f
PAGED_CODE();
ASSERT(DriveInfo);
- KdPrint(("floppy: StartMotor called\n"));
+ TRACE_(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 */
+ INFO_(FLOPPY, "StartMotor: motor turner-offer is already running; waiting for it\n");
KeWaitForSingleObject(&DriveInfo->ControllerInfo->MotorStoppedEvent, Executive, KernelMode, FALSE, NULL);
- DriveInfo->ControllerInfo->StopDpcQueued = FALSE;
+ INFO_(FLOPPY, "StartMotor: wait satisfied\n");
}
+ DriveInfo->ControllerInfo->StopDpcQueued = FALSE;
+
if(HwTurnOnMotor(DriveInfo) != STATUS_SUCCESS)
- KdPrint(("floppy: StartMotor(): warning: HwTurnOnMotor failed\n"));
+ {
+ WARN_(FLOPPY, "StartMotor(): warning: HwTurnOnMotor failed\n");
+ }
}
\f
ASSERT(ControllerInfo);
- KdPrint(("floppy: StopMotor called\n"));
+ TRACE_(FLOPPY, "StopMotor called\n");
/* one relative second, in 100-ns units */
StopTime.QuadPart = 10000000;
KeClearEvent(&ControllerInfo->SynchEvent);
}
-\f
-static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject,
+static DRIVER_DISPATCH CreateClose;
+static NTSTATUS NTAPI CreateClose(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
/*
* FUNCTION: Dispatch function called for Create and Close IRPs
* - 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"));
+ TRACE_(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;
}
* 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
StartMotor(DriveInfo);
/* set the data rate */
- KdPrint(("floppy: FIXME: UN-HARDCODE DATA RATE\n"));
+ WARN_(FLOPPY, "FIXME: UN-HARDCODE DATA RATE\n");
if(HwSetDataRate(DriveInfo->ControllerInfo, 0) != STATUS_SUCCESS)
{
- KdPrint(("floppy: Recalibrate: HwSetDataRate failed\n"));
- return STATUS_UNSUCCESSFUL;
+ WARN_(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"));
+ WARN_(FLOPPY, "Recalibrate: HwRecalibrate returned error\n");
continue;
}
Status = HwRecalibrateResult(DriveInfo->ControllerInfo);
if(Status != STATUS_SUCCESS)
{
- KdPrint(("floppy: Recalibrate: HwRecalibrateResult returned error\n"));
+ WARN_(FLOPPY, "Recalibrate: HwRecalibrateResult returned error\n");
break;
}
}
PAGED_CODE();
ASSERT(DriveInfo);
- KdPrint(("floppy: ResetChangeFlag called\n"));
+ TRACE_(FLOPPY, "ResetChangeFlag called\n");
/* Try to recalibrate. We don't care if it works. */
Recalibrate(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"));
+ WARN_(FLOPPY, "ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n");
+ StopMotor(DriveInfo->ControllerInfo);
return STATUS_IO_DEVICE_ERROR;
}
if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS)
{
- KdPrint(("floppy: ResetChangeFlag(): HwSenseInterruptStatus failed; bailing out\n"));
+ WARN_(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"));
+ WARN_(FLOPPY, "ResetChangeFlag(): HwSeek failed; returning STATUS_IO_DEVICE_ERROR\n");
+ StopMotor(DriveInfo->ControllerInfo);
return STATUS_IO_DEVICE_ERROR;
}
if(HwSenseInterruptStatus(DriveInfo->ControllerInfo) != STATUS_SUCCESS)
{
- KdPrint(("floppy: ResetChangeFlag(): HwSenseInterruptStatus #2 failed; bailing\n"));
+ WARN_(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"));
+ WARN_(FLOPPY, "ResetChangeFlag(): HwDiskChanged 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;
* FUNCTION: Unload the driver from memory
* ARGUMENTS:
* DriverObject - The driver that is being unloaded
- *
- * TODO: Delete ARC links
*/
{
ULONG i,j;
PAGED_CODE();
UNREFERENCED_PARAMETER(DriverObject);
- KdPrint(("floppy: unloading\n"));
+ TRACE_(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);
}
}
/* Power down the controller */
if(HwPowerOff(&gControllerInfo[i]) != STATUS_SUCCESS)
- KdPrint(("floppy: unload: warning: HwPowerOff failed\n"));
+ {
+ WARN_(FLOPPY, "unload: warning: HwPowerOff failed\n");
+ }
}
}
*/
{
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;
UNREFERENCED_PARAMETER(PathName);
- KdPrint(("floppy: ConfigCallback called with ControllerNumber %d\n", ControllerNumber));
+ TRACE_(FLOPPY, "ConfigCallback called with ControllerNumber %d\n", ControllerNumber);
gControllerInfo[gNumberOfControllers].ControllerNumber = ControllerNumber;
gControllerInfo[gNumberOfControllers].InterfaceType = BusType;
if(!HalTranslateBusAddress(BusType, BusNumber, PartialDescriptor->u.Port.Start, &AddressSpace, &TranslatedAddress))
{
- KdPrint(("floppy: HalTranslateBusAddress failed; returning\n"));
+ WARN_(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)
* 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
ASSERT(ControllerInfo);
- KdPrint(("floppy: ISR called\n"));
+ TRACE_(FLOPPY, "ISR called\n");
/*
* Due to the stupidity of the drive/controller relationship on the floppy drive, only one device object
* 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.
ASSERT(ControllerInfo);
- KdPrint(("floppy: DpcForIsr called\n"));
+ TRACE_(FLOPPY, "DpcForIsr called\n");
- KeSetEvent(&ControllerInfo->SynchEvent, IO_NO_INCREMENT, FALSE);
+ KeSetEvent(&ControllerInfo->SynchEvent, EVENT_INCREMENT, FALSE);
}
\f
* 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;
PAGED_CODE();
ASSERT(ControllerInfo);
- KdPrint(("floppy: InitController called with Controller 0x%x\n", ControllerInfo));
+ TRACE_(FLOPPY, "InitController called with Controller 0x%p\n", ControllerInfo);
KeClearEvent(&ControllerInfo->SynchEvent);
- //HwDumpRegisters(ControllerInfo);
-
- KdPrint(("floppy: InitController: resetting the controller\n"));
+ INFO_(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;
+ WARN_(FLOPPY, "InitController: unable to reset controller\n");
+ return STATUS_IO_DEVICE_ERROR;
}
- //HwDumpRegisters(ControllerInfo);
+ /* All controllers should support this so
+ * if we get something strange back then we
+ * know that this isn't a floppy controller
+ */
+ if (HwGetVersion(ControllerInfo) <= 0)
+ {
+ WARN_(FLOPPY, "InitController: unable to contact controller\n");
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ /* Reset the controller to avoid interrupt garbage on certain controllers */
+ if(HwReset(ControllerInfo) != STATUS_SUCCESS)
+ {
+ WARN_(FLOPPY, "InitController: unable to reset controller #2\n");
+ return STATUS_IO_DEVICE_ERROR;
+ }
- KdPrint(("floppy: InitController: setting data rate\n"));
+ INFO_(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;
+ WARN_(FLOPPY, "InitController: unable to set data rate\n");
+ return STATUS_IO_DEVICE_ERROR;
}
- KdPrint(("floppy: InitController: waiting for initial interrupt\n"));
+ INFO_(FLOPPY, "InitController: waiting for initial interrupt\n");
/* Wait for an interrupt */
WaitForControllerInterrupt(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);
+ INFO_(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;
+ WARN_(FLOPPY, "InitController: Unable to clear interrupt 0x%x\n", i);
+ return STATUS_IO_DEVICE_ERROR;
}
}
- KdPrint(("floppy: InitController: done sensing interrupts\n"));
-
- //HwDumpRegisters(ControllerInfo);
+ INFO_(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"));
+ WARN_(FLOPPY, "InitController: unable to set up implied seek\n");
ControllerInfo->ImpliedSeeks = FALSE;
}
- else
+ else
{
- KdPrint(("floppy: InitController: implied seeks set!\n"));
+ INFO_(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
+ {
+ INFO_(FLOPPY, "InitController: enhanced version not supported; disabling implied seeks\n");
+ ControllerInfo->ImpliedSeeks = FALSE;
+ ControllerInfo->Model30 = FALSE;
+ }
+
/* Specify */
- KdPrint(("FLOPPY: FIXME: Figure out speed\n"));
+ WARN_(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"));
-
+ INFO_(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;
+ WARN_(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;
- }
+ INFO_(FLOPPY, "InitController: recalibrating drive 0x%x on controller 0x%p\n", i, ControllerInfo);
+ Recalibrate(&ControllerInfo->DriveInfo[i]);
}
- //HwDumpRegisters(ControllerInfo);
-
- KdPrint(("floppy: InitController: done initializing; returning STATUS_SUCCESS\n"));
+ INFO_(FLOPPY, "InitController: done initializing; returning STATUS_SUCCESS\n");
return STATUS_SUCCESS;
}
* 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;
/* 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"));
+ WARN_(FLOPPY, "AddControllers: failed to get controller info from registry\n");
return FALSE;
}
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,
/* 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]));
+ INFO_(FLOPPY, "Connecting interrupt %d to controller%d (object 0x%p)\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;
+ WARN_(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"));
+ WARN_(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 */
+ WARN_(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));
+ INFO_(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
* 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 */
+ RtlZeroMemory(&DeviceNameBuf, MAX_DEVICE_NAME * sizeof(WCHAR));
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"));
+ WARN_(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));
+ INFO_(FLOPPY, "AddControllers: New device: %S (0x%p)\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;
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));
+ WARN_(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 */
- IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, DpcForIsr);
+ IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, (PIO_DPC_ROUTINE)DpcForIsr);
/* 3f: Point the device extension at our DriveInfo struct */
gControllerInfo[i].DriveInfo[j].DeviceObject->DeviceExtension = &gControllerInfo[i].DriveInfo[j];
/* 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;
+
+ /* 3j: Clear the DO_DEVICE_INITIALIZING flag */
+ gControllerInfo[i].DriveInfo[j].DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
}
- KdPrint(("floppy: AddControllers: --------------------------------------------> finished adding controllers\n"));
+ INFO_(FLOPPY, "AddControllers: --------------------------------------------> finished adding controllers\n");
return TRUE;
}
{
PDRIVE_INFO DriveInfo = DeviceObject->DeviceExtension;
- KdPrint(("floppy: SignalMediaChanged called\n"));
+ TRACE_(FLOPPY, "SignalMediaChanged called\n");
DriveInfo->DiskChangeCount++;
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
if(KeReadStateEvent(&QueueThreadTerminate))
{
- KdPrint(("floppy: QueueThread terminating\n"));
+ INFO_(FLOPPY, "QueueThread terminating\n");
return;
}
- KdPrint(("floppy: QueueThread: servicing an IRP\n"));
+ INFO_(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"));
+ INFO_(FLOPPY, "QueueThread: IRP queue empty\n");
continue;
}
break;
default:
- KdPrint(("floppy: QueueThread(): Unrecognized irp: mj: 0x%x\n", Stack->MajorFunction));
+ WARN_(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);
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));
/*
* 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);
/*
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;
+ WARN_(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"));
+ WARN_(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;