floppy.c
来自「一个类似windows」· C语言 代码 · 共 1,185 行 · 第 1/3 页
C
1,185 行
DPRINT("floppy: InitController: done initializing; returning STATUS_SUCCESS\n");
return STATUS_SUCCESS;
}
static BOOLEAN NTAPI AddControllers(PDRIVER_OBJECT DriverObject)
/*
* FUNCTION: Called on initialization to find our controllers and build device and controller objects for them
* ARGUMENTS:
* DriverObject: Our driver's DriverObject (so we can create devices against it)
* RETURNS:
* 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.
* - 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:
* - Report resource usage to the HAL
*/
{
INTERFACE_TYPE InterfaceType = Isa;
CONFIGURATION_TYPE ControllerType = DiskController;
CONFIGURATION_TYPE PeripheralType = FloppyDiskPeripheral;
KAFFINITY Affinity;
DEVICE_DESCRIPTION DeviceDescription;
UCHAR i;
UCHAR j;
PAGED_CODE();
/* 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. We expect at least one controller.
*/
if(!gControllerInfo[0].Populated)
{
DPRINT("floppy: AddControllers: failed to get controller info from registry\n");
return FALSE;
}
/* Now that we have a controller, set it up with the system */
for(i = 0; i < gNumberOfControllers; i++)
{
/* 0: Report resource usage to the kernel, to make sure they aren't assigned to anyone else */
/* FIXME: Implement me. */
/* 1: Set up interrupt */
gControllerInfo[i].MappedVector = HalGetInterruptVector(gControllerInfo[i].InterfaceType, gControllerInfo[i].BusNumber,
gControllerInfo[i].Level, gControllerInfo[i].Vector,
&gControllerInfo[i].MappedLevel, &Affinity);
/* Must set up the DPC before we connect the interrupt */
KeInitializeDpc(&gControllerInfo[i].Dpc, DpcForIsr, &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)
{
DPRINT("floppy: AddControllers: unable to connect interrupt\n");
continue;
}
/* 2: Set up DMA */
memset(&DeviceDescription, 0, sizeof(DeviceDescription));
DeviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
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 */
/* 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)
{
DPRINT("floppy: AddControllers: unable to allocate an adapter object\n");
IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
continue;
}
/* 2b: Initialize the new controller */
if(InitController(&gControllerInfo[i]) != STATUS_SUCCESS)
{
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;
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
* 1: 0,1
* 2: 0,2
* 3: 0,3
* 4: 1,0
* 5: 1,1
* ...
* 14: 3,2
* 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,
FILE_DEVICE_DISK, FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE, FALSE,
&gControllerInfo[i].DriveInfo[j].DeviceObject) != STATUS_SUCCESS)
{
DPRINT("floppy: AddControllers: unable to register a Device object\n");
IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
continue; /* continue on to next drive */
}
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;
/* 3d: Create a symlink */
swprintf(gControllerInfo[i].DriveInfo[j].SymLinkBuffer, L"\\DosDevices\\%c:", DriveNumber + 'A');
RtlInitUnicodeString(&LinkName, gControllerInfo[i].DriveInfo[j].SymLinkBuffer);
if(IoCreateSymbolicLink(&LinkName, &DeviceName) != STATUS_SUCCESS)
{
DPRINT("floppy: AddControllers: Unable to create a symlink for drive %d\n", DriveNumber);
IoDisconnectInterrupt(gControllerInfo[i].InterruptObject);
IoDeassignArcName(&ArcPath);
continue; /* continue to next drive */
}
/* 3e: Set up the DPC */
IoInitializeDpcRequest(gControllerInfo[i].DriveInfo[j].DeviceObject, DpcForIsr);
/* 3f: Point the device extension at our DriveInfo struct */
gControllerInfo[i].DriveInfo[j].DeviceObject->DeviceExtension = &gControllerInfo[i].DriveInfo[j];
/* 3g: neat comic strip */
/* 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;
}
}
DPRINT("floppy: AddControllers: --------------------------------------------> finished adding controllers\n");
return TRUE;
}
VOID NTAPI SignalMediaChanged(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
/*
* FUNCTION: Process an IRP when the media has changed, and possibly notify the user
* ARGUMENTS:
* DeviceObject: DeviceObject associated with the IRP
* Irp: IRP that we're failing due to change
* NOTES:
* - This procedure is documented in the DDK by "Notifying the File System of Possible Media Changes",
* "IoSetHardErrorOrVerifyDevice", and by "Responding to Check-Verify Requests from the File System".
* - Callable at <= DISPATCH_LEVEL
*/
{
PDRIVE_INFO DriveInfo = DeviceObject->DeviceExtension;
DPRINT("floppy: SignalMediaChanged called\n");
DriveInfo->DiskChangeCount++;
/* If volume is not mounted, do NOT set verify and return STATUS_IO_DEVICE_ERROR */
if(!(DeviceObject->Vpb->Flags & VPB_MOUNTED))
{
Irp->IoStatus.Status = STATUS_IO_DEVICE_ERROR;
Irp->IoStatus.Information = 0;
return;
}
/* Notify the filesystem that it will need to verify the volume */
DeviceObject->Flags |= DO_VERIFY_VOLUME;
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
* call IoSetHardError... is because MS might change the definition of "user induced" some day,
* and we don't want to have to remember to re-code this.
*/
if(Irp->Tail.Overlay.Thread && IoIsErrorUserInduced(Irp->IoStatus.Status))
IoSetHardErrorOrVerifyDevice(Irp, DeviceObject);
}
static VOID NTAPI QueueThread(PVOID Context)
/*
* FUNCTION: Thread that manages the queue and dispatches any queued requests
* ARGUMENTS:
* Context: unused
*/
{
PIRP Irp;
PIO_STACK_LOCATION Stack;
PDEVICE_OBJECT DeviceObject;
PVOID Objects[2];
PAGED_CODE();
UNREFERENCED_PARAMETER(Context);
Objects[0] = &QueueSemaphore;
Objects[1] = &QueueThreadTerminate;
for(;;)
{
KeWaitForMultipleObjects(2, Objects, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
if(KeReadStateEvent(&QueueThreadTerminate))
{
DPRINT("floppy: QueueThread terminating\n");
return;
}
DPRINT("floppy: QueueThread: servicing an IRP\n");
Irp = IoCsqRemoveNextIrp(&Csq, 0);
/* we won't get an irp if it was canceled */
if(!Irp)
{
DPRINT("floppy: QueueThread: IRP queue empty\n");
continue;
}
DeviceObject = (PDEVICE_OBJECT)Irp->Tail.Overlay.DriverContext[0];
ASSERT(DeviceObject);
Stack = IoGetCurrentIrpStackLocation(Irp);
/* Decide what to do with the IRP */
switch(Stack->MajorFunction)
{
case IRP_MJ_READ:
case IRP_MJ_WRITE:
ReadWritePassive(DeviceObject->DeviceExtension, Irp);
break;
case IRP_MJ_DEVICE_CONTROL:
DeviceIoctlPassive(DeviceObject->DeviceExtension, Irp);
break;
default:
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);
}
}
}
NTSTATUS NTAPI DriverEntry(PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
/*
* FUNCTION: Entry-point for the driver
* ARGUMENTS:
* DriverObject: Our driver object
* RegistryPath: Unused
* RETURNS:
* STATUS_SUCCESS on successful initialization of at least one drive
* STATUS_NO_SUCH_DEVICE if we didn't find even one drive
* STATUS_UNSUCCESSFUL otherwise
*/
{
HANDLE ThreadHandle;
UNREFERENCED_PARAMETER(RegistryPath);
/*
* Set up dispatch routines
*/
DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)CreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)ReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)ReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)DeviceIoctl;
DriverObject->DriverUnload = Unload;
/*
* 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,
CsqAcquireLock, CsqReleaseLock, CsqCompleteCanceledIrp);
/*
* ...and its lock
*/
KeInitializeSpinLock(&IrpQueueLock);
/*
* ...and the queue list itself
*/
InitializeListHead(&IrpQueue);
/*
* 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.
*/
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, THREAD_ALL_ACCESS, 0, 0, 0, QueueThread, 0) != STATUS_SUCCESS)
{
DPRINT("floppy: Unable to create system thread; failing init\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
if(ObReferenceObjectByHandle(ThreadHandle, STANDARD_RIGHTS_ALL, NULL, KernelMode, &QueueThreadObject, NULL) != STATUS_SUCCESS)
{
DPRINT("floppy: Unable to reference returned thread handle; failing init\n");
return STATUS_UNSUCCESSFUL;
}
/*
* 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.
*/
ZwClose(ThreadHandle);
/*
* 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;
return STATUS_SUCCESS;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?