4 Virtual Floppy Drive for Windows NT platform
5 Kernel mode driver: miscellaneous driver functions
7 Copyright (C) 2003-2005 Ken Kato
15 // driver reinitialize routine
16 // -- create a drive letter for each device
24 IN PDRIVER_OBJECT DriverObject
,
29 // specify code segment
32 #pragma alloc_text(INIT, DriverEntry)
33 #pragma alloc_text(PAGE, VfdReinitialize)
34 #pragma alloc_text(PAGE, VfdUnloadDriver)
35 #pragma alloc_text(PAGE, VfdCreateClose)
36 #pragma alloc_text(PAGE, VfdCopyUnicode)
37 #pragma alloc_text(PAGE, VfdFreeUnicode)
38 #endif // ALLOC_PRAGMA
41 // operating system version
44 extern ULONG OsMajorVersion
= 0;
45 extern ULONG OsMinorVersion
= 0;
46 extern ULONG OsBuildNumber
= 0;
48 ULONG OsMajorVersion
= 0;
49 ULONG OsMinorVersion
= 0;
50 ULONG OsBuildNumber
= 0;
58 extern ULONG TraceFlags
= (ULONG
)-1;
60 ULONG TraceFlags
= (ULONG
)-1;
65 // Driver Entry routine
70 IN PDRIVER_OBJECT DriverObject
,
71 IN PUNICODE_STRING RegistryPath
)
74 PVFD_DRIVER_EXTENSION driver_extension
;
75 ULONG number_of_devices
= VFD_DEFAULT_DEVICES
;
79 // Get operating system version
81 PsGetVersion(&OsMajorVersion
, &OsMinorVersion
, &OsBuildNumber
, NULL
);
84 #define VFD_PNP_TAG "(Plug & Play version)"
89 VFDTRACE(0, ("[VFD] %s %s" VFD_PNP_TAG
"\n",
90 VFD_PRODUCT_NAME
, VFD_DRIVER_VERSION_STR
));
93 ("[VFD] Running on Windows NT %lu.%lu build %lu\n",
94 OsMajorVersion
, OsMinorVersion
, OsBuildNumber
));
97 ("[VFD] Build Target Environment: %d\n", VER_PRODUCTBUILD
));
101 // Create device_extension for the driver object to store driver specific
102 // information. Device specific information are stored in device extension
103 // for each device object.
105 status
= IoAllocateDriverObjectExtension(
107 VFD_DRIVER_EXTENSION_ID
,
108 sizeof(VFD_DRIVER_EXTENSION
),
111 if(!NT_SUCCESS(status
)) {
112 VFDTRACE(0, ("[VFD] IoAllocateDriverObjectExtension - %s\n",
113 GetStatusName(status
)));
119 // Windows NT doesn't have the IoAllocateDriverObjectExtension
120 // function and I think there's little point in making a non-PnP
121 // driver incompatible with Windows NT.
123 driver_extension
= (PVFD_DRIVER_EXTENSION
)ExAllocatePoolWithTag(
124 PagedPool
, sizeof(VFD_DRIVER_EXTENSION
), VFD_POOL_TAG
);
126 if (!driver_extension
) {
127 VFDTRACE(0, ("[VFD] failed to allocate the driver extension.\n"));
128 return STATUS_INSUFFICIENT_RESOURCES
;
133 RtlZeroMemory(driver_extension
, sizeof(VFD_DRIVER_EXTENSION
));
136 // Copy the registry path into the driver extension so we can use it later
138 if (VfdCopyUnicode(&(driver_extension
->RegistryPath
), RegistryPath
)) {
141 // Read config values from the registry
143 RTL_QUERY_REGISTRY_TABLE params
[3];
144 ULONG default_devs
= VFD_DEFAULT_DEVICES
;
146 ULONG default_trace
= (ULONG
)-1;
149 RtlZeroMemory(params
, sizeof(params
));
151 VFDTRACE(0, ("[VFD] Registry Path: %ws\n",
152 driver_extension
->RegistryPath
.Buffer
));
154 params
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
155 params
[0].Name
= VFD_REG_DEVICE_NUMBER
;
156 params
[0].EntryContext
= &number_of_devices
;
157 params
[0].DefaultType
= REG_DWORD
;
158 params
[0].DefaultData
= &default_devs
;
159 params
[0].DefaultLength
= sizeof(ULONG
);
162 params
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
163 params
[1].Name
= VFD_REG_TRACE_FLAGS
;
164 params
[1].EntryContext
= &TraceFlags
;
165 params
[1].DefaultType
= REG_DWORD
;
166 params
[1].DefaultData
= &default_trace
;
167 params
[1].DefaultLength
= sizeof(ULONG
);
170 status
= RtlQueryRegistryValues(
171 RTL_REGISTRY_ABSOLUTE
| RTL_REGISTRY_OPTIONAL
,
172 driver_extension
->RegistryPath
.Buffer
,
175 if (!NT_SUCCESS(status
) ||
176 number_of_devices
== 0 ||
177 number_of_devices
> VFD_MAXIMUM_DEVICES
) {
178 number_of_devices
= VFD_DEFAULT_DEVICES
;
181 VFDTRACE(0,("[VFD] NumberOfDevices = %lu\n", number_of_devices
));
182 VFDTRACE(0,("[VFD] TraceFlags = 0x%08x\n", TraceFlags
));
185 VFDTRACE(0, ("[VFD] failed to allocate the registry path buffer.\n"));
186 // this error is not fatal
190 // Create VFD device objects
194 status
= VfdCreateDevice(DriverObject
, NULL
);
196 status
= VfdCreateDevice(DriverObject
, driver_extension
);
199 if (!NT_SUCCESS(status
)) {
203 while (driver_extension
->NumberOfDevices
< number_of_devices
);
205 if (!driver_extension
->NumberOfDevices
) {
207 // Failed to create even one device
209 VfdFreeUnicode(&(driver_extension
->RegistryPath
));
214 // Setup dispatch table
216 DriverObject
->MajorFunction
[IRP_MJ_CREATE
] = VfdCreateClose
;
217 DriverObject
->MajorFunction
[IRP_MJ_CLOSE
] = VfdCreateClose
;
218 DriverObject
->MajorFunction
[IRP_MJ_READ
] = VfdReadWrite
;
219 DriverObject
->MajorFunction
[IRP_MJ_WRITE
] = VfdReadWrite
;
220 DriverObject
->MajorFunction
[IRP_MJ_DEVICE_CONTROL
] = VfdDeviceControl
;
223 DriverObject
->MajorFunction
[IRP_MJ_PNP
] = VfdPlugAndPlay
;
224 DriverObject
->MajorFunction
[IRP_MJ_POWER
] = VfdPowerControl
;
225 DriverObject
->MajorFunction
[IRP_MJ_SYSTEM_CONTROL
] = VfdSystemControl
;
226 DriverObject
->DriverExtension
->AddDevice
= VfdAddDevice
;
229 DriverObject
->DriverUnload
= VfdUnloadDriver
;
231 // Register the driver reinitialize routine to be called
232 // *after* the DriverEntry routine returns
234 IoRegisterDriverReinitialization(
235 DriverObject
, VfdReinitialize
, NULL
);
238 ("[VFD] driver initialized with %lu devices.\n",
239 driver_extension
->NumberOfDevices
));
241 return STATUS_SUCCESS
;
245 // Driver unload routine
246 // Cleans up the device objects and other resources
251 IN PDRIVER_OBJECT DriverObject
)
253 PDEVICE_OBJECT device_object
;
254 PVFD_DRIVER_EXTENSION driver_extension
;
256 VFDTRACE(VFDINFO
, ("[VFD] VfdUnloadDriver - IN\n"));
258 device_object
= DriverObject
->DeviceObject
;
261 driver_extension
= IoGetDriverObjectExtension(
262 DriverObject
, VFD_DRIVER_EXTENSION_ID
);
264 if (device_object
&& device_object
->DeviceExtension
) {
266 ((PDEVICE_EXTENSION
)(device_object
->DeviceExtension
))->DriverExtension
;
269 driver_extension
= NULL
;
274 // Delete all remaining device objects
276 while (device_object
) {
278 PDEVICE_OBJECT next_device
= device_object
->NextDevice
;
280 VfdDeleteDevice(device_object
);
282 device_object
= next_device
;
286 // Release the driver extension and the registry path buffer
288 if (driver_extension
) {
290 if (driver_extension
->RegistryPath
.Buffer
) {
291 VFDTRACE(0, ("[VFD] Releasing the registry path buffer\n"));
292 ExFreePool(driver_extension
->RegistryPath
.Buffer
);
296 // The system takes care of freeing the driver extension
297 // allocated with IoAllocateDriverObjectExtension in a PnP driver.
298 VFDTRACE(0, ("[VFD] Releasing the driver extension\n"));
299 ExFreePool(driver_extension
);
303 VFDTRACE(VFDINFO
, ("[VFD] VfdUnloadDriver - OUT\n"));
307 // IRP_MJ_CREATE and IRP_MJ_CLOSE handler
308 // Really nothing to do here...
313 IN PDEVICE_OBJECT DeviceObject
,
317 if (DeviceObject
&& DeviceObject
->DeviceExtension
&&
318 ((PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->DeviceName
.Buffer
) {
320 VFDTRACE(VFDINFO
, ("[VFD] %-40s %ws\n",
321 GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
),
322 ((PDEVICE_EXTENSION
)DeviceObject
->DeviceExtension
)->DeviceName
.Buffer
));
325 VFDTRACE(VFDINFO
, ("[VFD] %-40s %p\n",
326 GetMajorFuncName(IoGetCurrentIrpStackLocation(Irp
)->MajorFunction
),
331 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
332 Irp
->IoStatus
.Information
= FILE_OPENED
;
334 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
336 return STATUS_SUCCESS
;
340 // Called after the DriverEntry routine has returned
341 // (Re)Create a persistent drive letter for each device
346 IN PDRIVER_OBJECT DriverObject
,
350 PDEVICE_OBJECT device_object
;
351 PDEVICE_EXTENSION device_extension
;
353 UNREFERENCED_PARAMETER(Context
);
354 UNREFERENCED_PARAMETER(Count
);
356 VFDTRACE(VFDINFO
, ("[VFD] VfdReinitialize - IN\n"));
358 device_object
= DriverObject
->DeviceObject
;
360 while (device_object
) {
361 device_extension
= (PDEVICE_EXTENSION
)device_object
->DeviceExtension
;
363 #ifdef VFD_MOUNT_MANAGER
364 if (OsMajorVersion
>= 5) {
366 // Notify the mount manager of a VFD volume arrival
367 VfdMountMgrNotifyVolume(device_extension
);
369 if (device_extension
->DriveLetter
) {
370 // Create a drive letter via the mount manager.
371 // The mount manager may have created a drive letter
372 // in response to the volume arrival notification above.
373 // In that case, the following call just fails.
374 VfdMountMgrMountPoint(
375 device_extension
, device_extension
->DriveLetter
);
376 // ignoring the error for it is not fatal here
380 #endif // VFD_MOUNT_MANAGER
382 // Windows NT style drive letter assignment
383 // Simply create a symbolic link here
384 if (device_extension
->DriveLetter
) {
386 device_extension
, device_extension
->DriveLetter
);
387 // ignoring the error for it is not fatal here
391 device_object
= device_object
->NextDevice
;
394 VFDTRACE(VFDINFO
, ("[VFD] VfdReinitialize - OUT\n"));
398 // Device dedicated thread routine
399 // Dispatch read, write and device I/O request
400 // redirected from the driver dispatch routines
405 IN PVOID ThreadContext
)
407 PDEVICE_OBJECT device_object
;
408 PDEVICE_EXTENSION device_extension
;
411 PIO_STACK_LOCATION io_stack
;
413 ASSERT(ThreadContext
!= NULL
);
415 device_object
= (PDEVICE_OBJECT
)ThreadContext
;
417 device_extension
= (PDEVICE_EXTENSION
)device_object
->DeviceExtension
;
419 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY
);
422 // wait for the request event to be signalled
423 KeWaitForSingleObject(
424 &device_extension
->RequestEvent
,
430 // terminate request ?
431 if (device_extension
->TerminateThread
) {
432 VFDTRACE(0, ("[VFD] Exitting the I/O thread\n"));
433 PsTerminateSystemThread(STATUS_SUCCESS
);
436 // perform requested tasks
438 while ((request
= ExInterlockedRemoveHeadList(
439 &device_extension
->ListHead
,
440 &device_extension
->ListLock
)) != NULL
)
442 irp
= CONTAINING_RECORD(request
, IRP
, Tail
.Overlay
.ListEntry
);
444 io_stack
= IoGetCurrentIrpStackLocation(irp
);
446 irp
->IoStatus
.Information
= 0;
448 switch (io_stack
->MajorFunction
) {
450 VfdReadData(device_extension
, irp
,
451 io_stack
->Parameters
.Read
.Length
,
452 &io_stack
->Parameters
.Read
.ByteOffset
);
456 VfdWriteData(device_extension
, irp
,
457 io_stack
->Parameters
.Write
.Length
,
458 &io_stack
->Parameters
.Write
.ByteOffset
);
461 case IRP_MJ_DEVICE_CONTROL
:
462 VfdIoCtlThread(device_extension
, irp
,
463 io_stack
->Parameters
.DeviceIoControl
.IoControlCode
);
467 // This shouldn't happen...
469 ("[VFD] %s passed to the I/O thread\n",
470 GetMajorFuncName(io_stack
->MajorFunction
)));
472 irp
->IoStatus
.Status
= STATUS_DRIVER_INTERNAL_ERROR
;
475 IoCompleteRequest(irp
,
476 (CCHAR
)(NT_SUCCESS(irp
->IoStatus
.Status
) ?
477 IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
480 IoReleaseRemoveLock(&device_extension
->RemoveLock
, irp
);
487 // Copy a UNICODE_STRING adding a trailing NULL characer
489 PWSTR
VfdCopyUnicode(
493 RtlZeroMemory(dst
, sizeof(UNICODE_STRING
));
496 (USHORT
)(src
->MaximumLength
+ sizeof(UNICODE_NULL
));
498 dst
->Buffer
= (PWSTR
)ExAllocatePoolWithTag(
499 PagedPool
, dst
->MaximumLength
, VFD_POOL_TAG
);
502 dst
->Length
= src
->Length
;
503 RtlZeroMemory(dst
->Buffer
, dst
->MaximumLength
);
506 RtlCopyMemory(dst
->Buffer
, src
->Buffer
, src
->Length
);
514 // Free a UNICODE_STRING buffer
520 ExFreePool(str
->Buffer
);
522 RtlZeroMemory(str
, sizeof(UNICODE_STRING
));