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

408 lines
8.9 KiB
C
Raw Normal View History

/*
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;
}