reactos/modules/rosapps/drivers/vfd/vfddrv.c

524 lines
12 KiB
C
Raw Normal View History

/*
vfddrv.c
Virtual Floppy Drive for Windows NT platform
Kernel mode driver: miscellaneous driver functions
Copyright (C) 2003-2005 Ken Kato
*/
#include "imports.h"
#include "vfddrv.h"
#include "vfddbg.h"
//
// driver reinitialize routine
// -- create a drive letter for each device
//
#ifdef __cplusplus
extern "C"
#endif // __cplusplus
static VOID
NTAPI
VfdReinitialize(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Context,
IN ULONG Count);
//
// specify code segment
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, VfdReinitialize)
#pragma alloc_text(PAGE, VfdUnloadDriver)
#pragma alloc_text(PAGE, VfdCreateClose)
#pragma alloc_text(PAGE, VfdCopyUnicode)
#pragma alloc_text(PAGE, VfdFreeUnicode)
#endif // ALLOC_PRAGMA
//
// operating system version
//
#ifndef __REACTOS__
extern ULONG OsMajorVersion = 0;
extern ULONG OsMinorVersion = 0;
extern ULONG OsBuildNumber = 0;
#else
ULONG OsMajorVersion = 0;
ULONG OsMinorVersion = 0;
ULONG OsBuildNumber = 0;
#endif
//
// Trace level flag
//
#if DBG
#ifndef __REACTOS__
extern ULONG TraceFlags = (ULONG)-1;
#else
ULONG TraceFlags = (ULONG)-1;
#endif
#endif // DBG
//
// Driver Entry routine
//
NTSTATUS
NTAPI
DriverEntry (
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
NTSTATUS status;
PVFD_DRIVER_EXTENSION driver_extension;
ULONG number_of_devices = VFD_DEFAULT_DEVICES;
ASSERT(DriverObject);
// Get operating system version
PsGetVersion(&OsMajorVersion, &OsMinorVersion, &OsBuildNumber, NULL);
#ifdef VFD_PNP
#define VFD_PNP_TAG "(Plug & Play version)"
#else
#define VFD_PNP_TAG
#endif
VFDTRACE(0, ("[VFD] %s %s" VFD_PNP_TAG "\n",
VFD_PRODUCT_NAME, VFD_DRIVER_VERSION_STR));
VFDTRACE(0,
("[VFD] Running on Windows NT %lu.%lu build %lu\n",
OsMajorVersion, OsMinorVersion, OsBuildNumber));
VFDTRACE(0,
("[VFD] Build Target Environment: %d\n", VER_PRODUCTBUILD));
#ifdef VFD_PNP
// Create device_extension for the driver object to store driver specific
// information. Device specific information are stored in device extension
// for each device object.
status = IoAllocateDriverObjectExtension(
DriverObject,
VFD_DRIVER_EXTENSION_ID,
sizeof(VFD_DRIVER_EXTENSION),
&driver_extension);
if(!NT_SUCCESS(status)) {
VFDTRACE(0, ("[VFD] IoAllocateDriverObjectExtension - %s\n",
GetStatusName(status)));
return status;
}
#else // VFD_PNP
// Windows NT doesn't have the IoAllocateDriverObjectExtension
// function and I think there's little point in making a non-PnP
// driver incompatible with Windows NT.
driver_extension = (PVFD_DRIVER_EXTENSION)ExAllocatePoolWithTag(
PagedPool, sizeof(VFD_DRIVER_EXTENSION), VFD_POOL_TAG);
if (!driver_extension) {
VFDTRACE(0, ("[VFD] failed to allocate the driver extension.\n"));
return STATUS_INSUFFICIENT_RESOURCES;
}
#endif // VFD_PNP
RtlZeroMemory(driver_extension, sizeof(VFD_DRIVER_EXTENSION));
//
// Copy the registry path into the driver extension so we can use it later
//
if (VfdCopyUnicode(&(driver_extension->RegistryPath), RegistryPath)) {
//
// Read config values from the registry
//
RTL_QUERY_REGISTRY_TABLE params[3];
ULONG default_devs = VFD_DEFAULT_DEVICES;
#if DBG
ULONG default_trace = (ULONG)-1;
#endif
RtlZeroMemory(params, sizeof(params));
VFDTRACE(0, ("[VFD] Registry Path: %ws\n",
driver_extension->RegistryPath.Buffer));
params[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
params[0].Name = VFD_REG_DEVICE_NUMBER;
params[0].EntryContext = &number_of_devices;
params[0].DefaultType = REG_DWORD;
params[0].DefaultData = &default_devs;
params[0].DefaultLength = sizeof(ULONG);
#if DBG
params[1].Flags = RTL_QUERY_REGISTRY_DIRECT;
params[1].Name = VFD_REG_TRACE_FLAGS;
params[1].EntryContext = &TraceFlags;
params[1].DefaultType = REG_DWORD;
params[1].DefaultData = &default_trace;
params[1].DefaultLength = sizeof(ULONG);
#endif // DBG
status = RtlQueryRegistryValues(
RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL,
driver_extension->RegistryPath.Buffer,
params, NULL, NULL);
if (!NT_SUCCESS(status) ||
number_of_devices == 0 ||
number_of_devices > VFD_MAXIMUM_DEVICES) {
number_of_devices = VFD_DEFAULT_DEVICES;
}
VFDTRACE(0,("[VFD] NumberOfDevices = %lu\n", number_of_devices));
VFDTRACE(0,("[VFD] TraceFlags = 0x%08x\n", TraceFlags));
}
else {
VFDTRACE(0, ("[VFD] failed to allocate the registry path buffer.\n"));
// this error is not fatal
}
//
// Create VFD device objects
//
do {
#ifdef VFD_PNP
status = VfdCreateDevice(DriverObject, NULL);
#else // VFD_PNP
status = VfdCreateDevice(DriverObject, driver_extension);
#endif // VFD_PNP
if (!NT_SUCCESS(status)) {
break;
}
}
while (driver_extension->NumberOfDevices < number_of_devices);
if (!driver_extension->NumberOfDevices) {
// Failed to create even one device
VfdFreeUnicode(&(driver_extension->RegistryPath));
return status;
}
// Setup dispatch table
DriverObject->MajorFunction[IRP_MJ_CREATE] = VfdCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = VfdCreateClose;
DriverObject->MajorFunction[IRP_MJ_READ] = VfdReadWrite;
DriverObject->MajorFunction[IRP_MJ_WRITE] = VfdReadWrite;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = VfdDeviceControl;
#ifdef VFD_PNP
DriverObject->MajorFunction[IRP_MJ_PNP] = VfdPlugAndPlay;
DriverObject->MajorFunction[IRP_MJ_POWER] = VfdPowerControl;
DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = VfdSystemControl;
DriverObject->DriverExtension->AddDevice = VfdAddDevice;
#endif // VFDPNP
DriverObject->DriverUnload = VfdUnloadDriver;
// Register the driver reinitialize routine to be called
// *after* the DriverEntry routine returns
IoRegisterDriverReinitialization(
DriverObject, VfdReinitialize, NULL);
VFDTRACE(VFDINFO,
("[VFD] driver initialized with %lu devices.\n",
driver_extension->NumberOfDevices));
return STATUS_SUCCESS;
}
//
// Driver unload routine
// Cleans up the device objects and other resources
//
VOID
NTAPI
VfdUnloadDriver (
IN PDRIVER_OBJECT DriverObject)
{
PDEVICE_OBJECT device_object;
PVFD_DRIVER_EXTENSION driver_extension;
VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - IN\n"));
device_object = DriverObject->DeviceObject;
#ifdef VFD_PNP
driver_extension = IoGetDriverObjectExtension(
DriverObject, VFD_DRIVER_EXTENSION_ID);
#else
if (device_object && device_object->DeviceExtension) {
driver_extension =
((PDEVICE_EXTENSION)(device_object->DeviceExtension))->DriverExtension;
}
else {
driver_extension = NULL;
}
#endif // VFD_PNP
//
// Delete all remaining device objects
//
while (device_object) {
PDEVICE_OBJECT next_device = device_object->NextDevice;
VfdDeleteDevice(device_object);
device_object = next_device;
}
//
// Release the driver extension and the registry path buffer
//
if (driver_extension) {
if (driver_extension->RegistryPath.Buffer) {
VFDTRACE(0, ("[VFD] Releasing the registry path buffer\n"));
ExFreePool(driver_extension->RegistryPath.Buffer);
}
#ifndef VFD_PNP
// The system takes care of freeing the driver extension
// allocated with IoAllocateDriverObjectExtension in a PnP driver.
VFDTRACE(0, ("[VFD] Releasing the driver extension\n"));
ExFreePool(driver_extension);
#endif // VFD_PNP
}
VFDTRACE(VFDINFO, ("[VFD] VfdUnloadDriver - OUT\n"));
}
//
// IRP_MJ_CREATE and IRP_MJ_CLOSE handler
// Really nothing to do here...
//
NTSTATUS
NTAPI
VfdCreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
#if DBG
if (DeviceObject && DeviceObject->DeviceExtension &&
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer) {
VFDTRACE(VFDINFO, ("[VFD] %-40s %ws\n",
GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
((PDEVICE_EXTENSION)DeviceObject->DeviceExtension)->DeviceName.Buffer));
}
else {
VFDTRACE(VFDINFO, ("[VFD] %-40s %p\n",
GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp)->MajorFunction),
DeviceObject));
}
#endif // DBG
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = FILE_OPENED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
//
// Called after the DriverEntry routine has returned
// (Re)Create a persistent drive letter for each device
//
VOID
NTAPI
VfdReinitialize(
IN PDRIVER_OBJECT DriverObject,
IN PVOID Context,
IN ULONG Count)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
UNREFERENCED_PARAMETER(Context);
UNREFERENCED_PARAMETER(Count);
VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - IN\n"));
device_object = DriverObject->DeviceObject;
while (device_object) {
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
#ifdef VFD_MOUNT_MANAGER
if (OsMajorVersion >= 5) {
// Windows 2000 / XP
// Notify the mount manager of a VFD volume arrival
VfdMountMgrNotifyVolume(device_extension);
if (device_extension->DriveLetter) {
// Create a drive letter via the mount manager.
// The mount manager may have created a drive letter
// in response to the volume arrival notification above.
// In that case, the following call just fails.
VfdMountMgrMountPoint(
device_extension, device_extension->DriveLetter);
// ignoring the error for it is not fatal here
}
}
else
#endif // VFD_MOUNT_MANAGER
{
// Windows NT style drive letter assignment
// Simply create a symbolic link here
if (device_extension->DriveLetter) {
VfdSetLink(
device_extension, device_extension->DriveLetter);
// ignoring the error for it is not fatal here
}
}
device_object = device_object->NextDevice;
}
VFDTRACE(VFDINFO, ("[VFD] VfdReinitialize - OUT\n"));
}
//
// Device dedicated thread routine
// Dispatch read, write and device I/O request
// redirected from the driver dispatch routines
//
VOID
NTAPI
VfdDeviceThread (
IN PVOID ThreadContext)
{
PDEVICE_OBJECT device_object;
PDEVICE_EXTENSION device_extension;
PLIST_ENTRY request;
PIRP irp;
PIO_STACK_LOCATION io_stack;
ASSERT(ThreadContext != NULL);
device_object = (PDEVICE_OBJECT)ThreadContext;
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
for (;;) {
// wait for the request event to be signalled
KeWaitForSingleObject(
&device_extension->RequestEvent,
Executive,
KernelMode,
FALSE,
NULL);
// terminate request ?
if (device_extension->TerminateThread) {
VFDTRACE(0, ("[VFD] Exitting the I/O thread\n"));
PsTerminateSystemThread(STATUS_SUCCESS);
}
// perform requested tasks
while ((request = ExInterlockedRemoveHeadList(
&device_extension->ListHead,
&device_extension->ListLock)) != NULL)
{
irp = CONTAINING_RECORD(request, IRP, Tail.Overlay.ListEntry);
io_stack = IoGetCurrentIrpStackLocation(irp);
irp->IoStatus.Information = 0;
switch (io_stack->MajorFunction) {
case IRP_MJ_READ:
VfdReadData(device_extension, irp,
io_stack->Parameters.Read.Length,
&io_stack->Parameters.Read.ByteOffset);
break;
case IRP_MJ_WRITE:
VfdWriteData(device_extension, irp,
io_stack->Parameters.Write.Length,
&io_stack->Parameters.Write.ByteOffset);
break;
case IRP_MJ_DEVICE_CONTROL:
VfdIoCtlThread(device_extension, irp,
io_stack->Parameters.DeviceIoControl.IoControlCode);
break;
default:
// This shouldn't happen...
VFDTRACE(0,
("[VFD] %s passed to the I/O thread\n",
GetMajorFuncName(io_stack->MajorFunction)));
irp->IoStatus.Status = STATUS_DRIVER_INTERNAL_ERROR;
}
IoCompleteRequest(irp,
(CCHAR)(NT_SUCCESS(irp->IoStatus.Status) ?
IO_DISK_INCREMENT : IO_NO_INCREMENT));
#ifdef VFD_PNP
IoReleaseRemoveLock(&device_extension->RemoveLock, irp);
#endif // VFD_PNP
} // while
} // for (;;)
}
//
// Copy a UNICODE_STRING adding a trailing NULL characer
//
PWSTR VfdCopyUnicode(
PUNICODE_STRING dst,
PUNICODE_STRING src)
{
RtlZeroMemory(dst, sizeof(UNICODE_STRING));
dst->MaximumLength =
(USHORT)(src->MaximumLength + sizeof(UNICODE_NULL));
dst->Buffer = (PWSTR)ExAllocatePoolWithTag(
PagedPool, dst->MaximumLength, VFD_POOL_TAG);
if(dst->Buffer) {
dst->Length = src->Length;
RtlZeroMemory(dst->Buffer, dst->MaximumLength);
if (src->Length) {
RtlCopyMemory(dst->Buffer, src->Buffer, src->Length);
}
}
return dst->Buffer;
}
//
// Free a UNICODE_STRING buffer
//
VOID VfdFreeUnicode(
PUNICODE_STRING str)
{
if (str->Buffer) {
ExFreePool(str->Buffer);
}
RtlZeroMemory(str, sizeof(UNICODE_STRING));
}