mirror of
https://github.com/reactos/reactos.git
synced 2024-11-05 22:26:39 +00:00
408 lines
8.9 KiB
C
408 lines
8.9 KiB
C
|
/*
|
||
|
vfddev.c
|
||
|
|
||
|
Virtual Floppy Drive for Windows NT platform
|
||
|
Kernel mode driver: device create/delete functions
|
||
|
|
||
|
Copyright (C) 2003-2005 Ken Kato
|
||
|
*/
|
||
|
|
||
|
#include "imports.h"
|
||
|
#include "vfddrv.h"
|
||
|
#include "vfddbg.h"
|
||
|
|
||
|
#ifdef ALLOC_PRAGMA
|
||
|
#pragma alloc_text(PAGE, VfdCreateDevice)
|
||
|
#pragma alloc_text(PAGE, VfdDeleteDevice)
|
||
|
#endif // ALLOC_PRAGMA
|
||
|
|
||
|
//
|
||
|
// Create a VFD device object
|
||
|
//
|
||
|
NTSTATUS
|
||
|
VfdCreateDevice(
|
||
|
IN PDRIVER_OBJECT DriverObject,
|
||
|
OUT PVOID Parameter)
|
||
|
{
|
||
|
NTSTATUS status;
|
||
|
ULONG physical_num;
|
||
|
|
||
|
UNICODE_STRING unicode_name;
|
||
|
WCHAR name_buffer[40];
|
||
|
|
||
|
PVFD_DRIVER_EXTENSION driver_extension = NULL;
|
||
|
PDEVICE_OBJECT device_object = NULL;
|
||
|
PDEVICE_EXTENSION device_extension = NULL;
|
||
|
HANDLE thread_handle = NULL;
|
||
|
|
||
|
VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - IN\n"));
|
||
|
|
||
|
#ifdef VFD_PNP
|
||
|
|
||
|
// Get the driver device_extension for the driver object
|
||
|
driver_extension = IoGetDriverObjectExtension(
|
||
|
DriverObject, VFD_DRIVER_EXTENSION_ID);
|
||
|
|
||
|
#else // VFD_PNP
|
||
|
|
||
|
// The driver device_extension is passed as the Parameter
|
||
|
driver_extension = (PVFD_DRIVER_EXTENSION)Parameter;
|
||
|
|
||
|
#endif // VFD_PNP
|
||
|
|
||
|
if (driver_extension == NULL) {
|
||
|
VFDTRACE(VFDERR, ("[VFD] Failed to get the driver extension\n"));
|
||
|
return STATUS_DRIVER_INTERNAL_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create a device object
|
||
|
// \Device\Floppy<n>
|
||
|
//
|
||
|
physical_num = 0;
|
||
|
|
||
|
do {
|
||
|
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
|
||
|
|
||
|
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
|
||
|
L"\\Device\\Floppy%lu", physical_num);
|
||
|
|
||
|
RtlInitUnicodeString(&unicode_name, name_buffer);
|
||
|
|
||
|
status = IoCreateDevice(
|
||
|
DriverObject,
|
||
|
sizeof(DEVICE_EXTENSION),
|
||
|
&unicode_name,
|
||
|
FILE_DEVICE_DISK,
|
||
|
FILE_REMOVABLE_MEDIA | FILE_FLOPPY_DISKETTE | FILE_DEVICE_SECURE_OPEN,
|
||
|
FALSE,
|
||
|
&device_object);
|
||
|
|
||
|
if (status != STATUS_OBJECT_NAME_EXISTS &&
|
||
|
status != STATUS_OBJECT_NAME_COLLISION) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
while (++physical_num < 100);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
VFDTRACE(VFDERR,
|
||
|
("[VFD] IoCreateDevice() %s\n",
|
||
|
GetStatusName(status)));
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
IoGetConfigurationInformation()->FloppyCount++;
|
||
|
|
||
|
VFDTRACE(VFDINFO | VFDDEV,
|
||
|
("[VFD] Created a device object %ws\n", name_buffer));
|
||
|
|
||
|
//
|
||
|
// Initialize the device object / device extension
|
||
|
//
|
||
|
|
||
|
device_object->Flags |= DO_DIRECT_IO;
|
||
|
|
||
|
device_extension = (PDEVICE_EXTENSION)device_object->DeviceExtension;
|
||
|
|
||
|
RtlZeroMemory(device_extension, sizeof(DEVICE_EXTENSION));
|
||
|
|
||
|
// Store the back pointer to the device object
|
||
|
|
||
|
device_extension->DeviceObject = device_object;
|
||
|
|
||
|
// Store the logical device number
|
||
|
|
||
|
device_extension->DeviceNumber = driver_extension->NumberOfDevices;
|
||
|
|
||
|
// Store the device name
|
||
|
|
||
|
if (!VfdCopyUnicode(&(device_extension->DeviceName), &unicode_name)) {
|
||
|
VFDTRACE(VFDERR,
|
||
|
("[VFD] Failed to allocate device name buffer\n"));
|
||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// set the default disk geometry (3.5" 1.44M)
|
||
|
|
||
|
device_extension->Geometry = &geom_tbl[0];
|
||
|
|
||
|
// Create the interface link (\??\VirtualFD<n>)
|
||
|
|
||
|
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
|
||
|
|
||
|
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
|
||
|
L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
|
||
|
device_extension->DeviceNumber);
|
||
|
|
||
|
RtlInitUnicodeString(&unicode_name, name_buffer);
|
||
|
|
||
|
status = IoCreateSymbolicLink(
|
||
|
&unicode_name, &device_extension->DeviceName);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
VFDTRACE(VFDERR,
|
||
|
("[VFD] IoCreateSymbolicLink(%ws) %s\n",
|
||
|
name_buffer, GetStatusName(status)));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] Created a symbolic link %ws\n", name_buffer));
|
||
|
|
||
|
// Prepare the IRP queue list for the device thread
|
||
|
|
||
|
InitializeListHead(&device_extension->ListHead);
|
||
|
|
||
|
KeInitializeSpinLock(&device_extension->ListLock);
|
||
|
|
||
|
KeInitializeEvent(
|
||
|
&device_extension->RequestEvent,
|
||
|
SynchronizationEvent,
|
||
|
FALSE);
|
||
|
|
||
|
// Create the device thread
|
||
|
|
||
|
device_extension->TerminateThread = FALSE;
|
||
|
|
||
|
status = PsCreateSystemThread(
|
||
|
&thread_handle,
|
||
|
(ACCESS_MASK) 0L,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
VfdDeviceThread,
|
||
|
device_object);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
VFDTRACE(VFDERR,
|
||
|
("[VFD] PsCreateSystemThread() %s\n",
|
||
|
GetStatusName(status)));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
// get a reference pointer to the thread
|
||
|
|
||
|
status = ObReferenceObjectByHandle(
|
||
|
thread_handle,
|
||
|
THREAD_ALL_ACCESS,
|
||
|
NULL,
|
||
|
KernelMode,
|
||
|
&device_extension->ThreadPointer,
|
||
|
NULL);
|
||
|
|
||
|
ZwClose(thread_handle);
|
||
|
|
||
|
if (!NT_SUCCESS(status)) {
|
||
|
VFDTRACE(VFDERR,
|
||
|
("[VFD] ObReferenceObjectByHandle() %s\n",
|
||
|
GetStatusName(status)));
|
||
|
goto cleanup;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load the persistent drive letter from the registry
|
||
|
//
|
||
|
if (driver_extension->RegistryPath.Buffer) {
|
||
|
VfdLoadLink(device_extension,
|
||
|
driver_extension->RegistryPath.Buffer);
|
||
|
// error is not fatal here
|
||
|
}
|
||
|
|
||
|
// increment the number of devices in the driver extension
|
||
|
|
||
|
driver_extension->NumberOfDevices++;
|
||
|
|
||
|
if (DriverObject->DriverUnload) {
|
||
|
// not called from the DriverEntry routine
|
||
|
device_object->Flags &= ~DO_DEVICE_INITIALIZING;
|
||
|
}
|
||
|
|
||
|
#ifdef VFD_PNP
|
||
|
if (Parameter) {
|
||
|
// return the device object pointer
|
||
|
*(PDEVICE_OBJECT *)Parameter = device_object;
|
||
|
}
|
||
|
#else // VFD_PNP
|
||
|
device_extension->DriverExtension = driver_extension;
|
||
|
#endif // VFD_PNP
|
||
|
|
||
|
VFDTRACE(VFDINFO | VFDDEV, ("[VFD] VfdCreateDevice - OK\n"));
|
||
|
|
||
|
return STATUS_SUCCESS;
|
||
|
|
||
|
cleanup:
|
||
|
//
|
||
|
// Something went wrong at one point
|
||
|
// Delete all resources that might be created in this function
|
||
|
//
|
||
|
if (thread_handle) {
|
||
|
|
||
|
// terminate the device thread
|
||
|
device_extension->TerminateThread = TRUE;
|
||
|
|
||
|
KeSetEvent(
|
||
|
&device_extension->RequestEvent,
|
||
|
(KPRIORITY) 0,
|
||
|
FALSE);
|
||
|
|
||
|
if (device_extension->ThreadPointer) {
|
||
|
ObDereferenceObject(device_extension->ThreadPointer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] Deleting symbolic link %ws\n", name_buffer));
|
||
|
|
||
|
IoDeleteSymbolicLink(&unicode_name);
|
||
|
|
||
|
if (device_extension->DeviceName.Buffer) {
|
||
|
VFDTRACE(VFDINFO|VFDDEV, ("[VFD] Deleting device %ws\n",
|
||
|
device_extension->DeviceName.Buffer));
|
||
|
|
||
|
ExFreePool(device_extension->DeviceName.Buffer);
|
||
|
}
|
||
|
|
||
|
IoDeleteDevice(device_object);
|
||
|
IoGetConfigurationInformation()->FloppyCount--;
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] VfdCreateDevice - %s\n",
|
||
|
GetStatusName(status)));
|
||
|
|
||
|
return status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// delete a VFD device object
|
||
|
//
|
||
|
VOID
|
||
|
VfdDeleteDevice(
|
||
|
IN PDEVICE_OBJECT DeviceObject)
|
||
|
{
|
||
|
PDEVICE_EXTENSION device_extension;
|
||
|
PVFD_DRIVER_EXTENSION driver_extension;
|
||
|
UNICODE_STRING unicode_name;
|
||
|
WCHAR name_buffer[40];
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV, ("[VFD] VfdDeleteDevice - IN\n"));
|
||
|
|
||
|
device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
||
|
|
||
|
//
|
||
|
// decrement the number of device in the driver extension
|
||
|
//
|
||
|
#ifdef VFD_PNP
|
||
|
driver_extension = IoGetDriverObjectExtension(
|
||
|
DeviceObject->DriverObject, VFD_DRIVER_EXTENSION_ID);
|
||
|
#else // VFD_PNP
|
||
|
driver_extension = device_extension->DriverExtension;
|
||
|
#endif // VFD_PNP
|
||
|
|
||
|
if (driver_extension) {
|
||
|
driver_extension->NumberOfDevices--;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// cleanup the device object
|
||
|
//
|
||
|
|
||
|
// Terminate the device thread
|
||
|
|
||
|
device_extension->TerminateThread = TRUE;
|
||
|
|
||
|
KeSetEvent(
|
||
|
&device_extension->RequestEvent,
|
||
|
(KPRIORITY) 0,
|
||
|
FALSE);
|
||
|
|
||
|
KeWaitForSingleObject(
|
||
|
device_extension->ThreadPointer,
|
||
|
Executive,
|
||
|
KernelMode,
|
||
|
FALSE,
|
||
|
NULL);
|
||
|
|
||
|
ObDereferenceObject(
|
||
|
device_extension->ThreadPointer);
|
||
|
|
||
|
// Delete security context object
|
||
|
|
||
|
if (device_extension->SecurityContext) {
|
||
|
SeDeleteClientSecurity(device_extension->SecurityContext);
|
||
|
ExFreePool(device_extension->SecurityContext);
|
||
|
}
|
||
|
|
||
|
// Close the image file or free the image buffer
|
||
|
|
||
|
if (device_extension->FileHandle) {
|
||
|
ZwClose(device_extension->FileHandle);
|
||
|
}
|
||
|
|
||
|
if (device_extension->FileBuffer) {
|
||
|
ExFreePool(device_extension->FileBuffer);
|
||
|
}
|
||
|
|
||
|
// Release the image path buffer
|
||
|
|
||
|
if (device_extension->FileName.Buffer) {
|
||
|
ExFreePool(device_extension->FileName.Buffer);
|
||
|
}
|
||
|
|
||
|
// Remove the interface symbolic link
|
||
|
|
||
|
name_buffer[sizeof(name_buffer) - 1] = UNICODE_NULL;
|
||
|
|
||
|
_snwprintf(name_buffer, sizeof(name_buffer) - 1,
|
||
|
L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
|
||
|
device_extension->DeviceNumber);
|
||
|
|
||
|
RtlInitUnicodeString(&unicode_name, name_buffer);
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] Deleting link %ws\n", name_buffer));
|
||
|
|
||
|
IoDeleteSymbolicLink(&unicode_name);
|
||
|
|
||
|
// Remove the persistent drive letter
|
||
|
|
||
|
if (device_extension->DriveLetter) {
|
||
|
#ifdef VFD_MOUNT_MANAGER
|
||
|
if (OsMajorVersion >= 5) {
|
||
|
// Request the mount manager to remove the drive letter.
|
||
|
// This will cause the mount manager to update its database
|
||
|
// and it won't arbitrarily assign the drive letter the next
|
||
|
// time the driver starts.
|
||
|
VfdMountMgrMountPoint(device_extension, 0);
|
||
|
}
|
||
|
else
|
||
|
#endif // VFD_MOUNT_MANAGER
|
||
|
{
|
||
|
// Windows NT style drive letter handling
|
||
|
// Simply remove the symbolic link
|
||
|
VfdSetLink(device_extension, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Release the device name buffer
|
||
|
|
||
|
if (device_extension->DeviceName.Buffer) {
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] Deleting device %ws\n",
|
||
|
device_extension->DeviceName.Buffer));
|
||
|
|
||
|
ExFreePool(device_extension->DeviceName.Buffer);
|
||
|
}
|
||
|
|
||
|
// Delete the device object
|
||
|
|
||
|
IoDeleteDevice(DeviceObject);
|
||
|
IoGetConfigurationInformation()->FloppyCount--;
|
||
|
|
||
|
VFDTRACE(VFDINFO|VFDDEV,
|
||
|
("[VFD] VfdDeleteDevice - OUT\n"));
|
||
|
|
||
|
return;
|
||
|
}
|