|
|
/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
pnp.c
Abstract:
This file contains RAM disk driver code for processing PnP IRPs.
Author:
Chuck Lenzmeier (ChuckL) 2001
Environment:
Kernel mode only.
Notes:
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Registry value format for virtual floppy disks created by textmode setup.
// Should be in a header file, but that's not the way it was done for the
// original virtual floppy driver.
//
typedef struct _VIRTUAL_FLOPPY_DESCRIPTOR {
//
// The structure starts with a system virtual address. On 32-bit systems,
// this is padded to 64 bits.
//
union { PVOID VirtualAddress; ULONGLONG Reserved; // align to 64 bits
} ;
//
// The length of the virtual floppy comes next.
//
ULONG Length;
//
// Textmode writes the registry value with 12 bytes of data. In order
// to get the right size for our check, we use of the field offset of
// the following field. We can't use sizeof a struct that just has the
// above fields, because that comes out as 16 bytes due to alignment.
//
ULONG StructSizer;
} VIRTUAL_FLOPPY_DESCRIPTOR, *PVIRTUAL_FLOPPY_DESCRIPTOR;
#if !DBG
#define PRINT_CODE( _code )
#else
#define PRINT_CODE( _code ) \
if ( print ) { \ DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", " " #_code "\n") ); \ } \ print = FALSE;
#endif
#if DBG
PSTR StateTable[] = { "STOPPED", "WORKING", "PENDINGSTOP", "PENDINGREMOVE", "SURPRISEREMOVED", "REMOVED", "UNKNOWN" };
#endif // DBG
//
// Local functions.
//
NTSTATUS RamdiskDeleteDiskDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp OPTIONAL );
NTSTATUS RamdiskIoCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event );
NTSTATUS RamdiskQueryBusInformation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS RamdiskQueryCapabilities ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS RamdiskQueryId ( IN PDISK_EXTENSION DiskExtension, IN PIRP Irp );
NTSTATUS RamdiskQueryDeviceRelations ( IN DEVICE_RELATION_TYPE RelationsType, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
NTSTATUS RamdiskQueryDeviceText ( IN PDISK_EXTENSION DiskExtension, IN PIRP Irp );
NTSTATUS RamdiskRemoveBusDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp );
#if DBG
PSTR GetPnpIrpName ( IN UCHAR PnpMinorFunction );
PCHAR GetDeviceRelationString ( IN DEVICE_RELATION_TYPE Type );
#endif // DBG
//
// Declare pageable routines.
//
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, RamdiskPnp )
#pragma alloc_text( PAGE, RamdiskPower )
#pragma alloc_text( PAGE, RamdiskAddDevice )
#pragma alloc_text( PAGE, CreateRegistryDisks )
#pragma alloc_text( PAGE, RamdiskDeleteDiskDevice )
#pragma alloc_text( PAGE, RamdiskQueryBusInformation )
#pragma alloc_text( PAGE, RamdiskQueryCapabilities )
#pragma alloc_text( PAGE, RamdiskQueryId )
#pragma alloc_text( PAGE, RamdiskQueryDeviceRelations )
#pragma alloc_text( PAGE, RamdiskQueryDeviceText )
#pragma alloc_text( PAGE, RamdiskRemoveBusDevice )
#if DBG
#pragma alloc_text( PAGE, GetPnpIrpName )
#pragma alloc_text( PAGE, GetDeviceRelationString )
#endif // DBG
#endif // ALLOC_PRAGMA
NTSTATUS RamdiskPnp ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine is called by the I/O system to perform a PnP function.
Arguments:
DeviceObject - a pointer to the object that represents the device on which I/O is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PIO_STACK_LOCATION irpSp; PCOMMON_EXTENSION commonExtension; PBUS_EXTENSION busExtension; PDISK_EXTENSION diskExtension; KEVENT event; BOOLEAN lockHeld = FALSE;
#if DBG
BOOLEAN print = TRUE; #endif
PAGED_CODE();
//
// Get pointers the IRP stack location and the device extension.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
commonExtension = DeviceObject->DeviceExtension; busExtension = DeviceObject->DeviceExtension; diskExtension = DeviceObject->DeviceExtension;
ASSERT( commonExtension->DeviceState < RamdiskDeviceStateMaximum );
DBGPRINT( DBG_PNP, DBG_INFO, ("RamdiskPnp: DO=(%p [Type=%d]) Irp=(%p %s) Device State=%s\n", DeviceObject, commonExtension->DeviceType, Irp, GetPnpIrpName(irpSp->MinorFunction), StateTable[commonExtension->DeviceState]) );
//
// If the device has been removed, only pass IRP_REMOVE down for cleanup.
//
if ( (commonExtension->DeviceState >= RamdiskDeviceStateRemoved) && (irpSp->MinorFunction != IRP_MN_REMOVE_DEVICE) ) {
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("RamdiskPnp: rejecting IRP %d for Removed Device\n", irpSp->MinorFunction) );
status = STATUS_NO_SUCH_DEVICE; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp );
return status; }
//
// Acquire the remove lock. If this fails, fail the I/O.
//
status = IoAcquireRemoveLock( &commonExtension->RemoveLock, Irp );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("RamdiskPnp: IoAcquireRemoveLock failed: %x\n", status) );
COMPLETE_REQUEST( status, 0, Irp );
return status; }
//
// Indicate that the remove lock is held.
//
lockHeld = TRUE;
//
// Dispatch based on the minor function.
//
switch ( irpSp->MinorFunction ) { case IRP_MN_START_DEVICE: PRINT_CODE( IRP_MN_START_DEVICE );
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
//
// Starting the bus device.
//
// Send the IRP down and wait for it to come back.
//
IoCopyCurrentIrpStackLocationToNext( Irp );
KeInitializeEvent( &event, NotificationEvent, FALSE ); IoSetCompletionRoutine( Irp, RamdiskIoCompletionRoutine, &event, TRUE, TRUE, TRUE );
status = IoCallDriver( commonExtension->LowerDeviceObject, Irp );
if ( status == STATUS_PENDING ) {
KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; }
if ( NT_SUCCESS(status) ) {
//
// Lower drivers didn't fail the IRP. Start the interface.
//
status = IoSetDeviceInterfaceState( &commonExtension->InterfaceString, TRUE );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("IoSetDeviceInterfaceState FAILED Status = 0x%x\n", status) ); }
//
// Device started successfully.
//
commonExtension->DeviceState = RamdiskDeviceStateWorking; }
} else {
//
// Starting a RAM disk.
//
// Register the device interface. If it's an emulated disk, use the
// private RAM disk interface GUID. If it's an emulated volume, use
// the systemwide volume GUID.
//
if ( commonExtension->InterfaceString.Buffer != NULL ) { FREE_POOL( commonExtension->InterfaceString.Buffer, FALSE ); }
status = IoRegisterDeviceInterface( DeviceObject, diskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK ? &RamdiskDiskInterface : &VolumeClassGuid, NULL, &commonExtension->InterfaceString );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("IoRegisterDeviceInterface FAILED Status = 0x%x\n", status) ); }
//
// Start the interface.
//
if ( !diskExtension->Options.Hidden && (commonExtension->InterfaceString.Buffer != NULL) ) {
ULONG installState; ULONG resultLength;
status = IoGetDeviceProperty( DeviceObject, DevicePropertyInstallState, sizeof(installState), &installState, &resultLength );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("IoGetDeviceProperty FAILED Status = 0x%x\n", status) );
//
// If we can't get the install state, we set the interface
// state to TRUE anyway, just to be safe.
//
installState = InstallStateInstalled; }
if ( installState == InstallStateInstalled ) {
DBGPRINT( DBG_PNP, DBG_INFO, ("%s", "Calling IoSetDeviceInterfaceState(TRUE)\n") ); status = IoSetDeviceInterfaceState( &commonExtension->InterfaceString, TRUE );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("IoSetDeviceInterfaceState FAILED Status = 0x%x\n", status) ); }
} else {
DBGPRINT( DBG_PNP, DBG_INFO, ("Skipping IoSetDeviceInterfaceState; state = 0x%x\n", installState) ); } }
//
// Device started successfully.
//
commonExtension->DeviceState = RamdiskDeviceStateWorking; }
//
// Complete the I/O request.
//
COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp );
break;
case IRP_MN_QUERY_STOP_DEVICE: PRINT_CODE( IRP_MN_QUERY_STOP_DEVICE );
//
// Mark that a stop is pending.
//
commonExtension->DeviceState = RamdiskDeviceStatePendingStop;
//
// Indicate success. Send the IRP on down the stack.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
goto send_irp_down;
case IRP_MN_CANCEL_STOP_DEVICE: PRINT_CODE( IRP_MN_CANCEL_STOP_DEVICE );
//
// Before sending the IRP down make sure we have received
// a IRP_MN_QUERY_STOP_DEVICE. We may get Cancel Stop
// without receiving a Query Stop earlier, if the
// driver on top fails a Query Stop and passes down the
// Cancel Stop.
//
if ( commonExtension->DeviceState == RamdiskDeviceStatePendingStop ) {
//
// Mark that the device is back in the working state, and
// pass the IRP down.
//
commonExtension->DeviceState = RamdiskDeviceStateWorking;
Irp->IoStatus.Status = STATUS_SUCCESS;
goto send_irp_down;
} else {
//
// A spurious Cancel Stop request. Just complete it.
//
status = STATUS_SUCCESS; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
break;
case IRP_MN_STOP_DEVICE: PRINT_CODE( IRP_MN_STOP_DEVICE );
//
// Mark that the device is now stopped. Send the IRP on down the stack.
//
commonExtension->DeviceState = RamdiskDeviceStateStopped;
Irp->IoStatus.Status = STATUS_SUCCESS;
goto send_irp_down;
case IRP_MN_QUERY_REMOVE_DEVICE: PRINT_CODE( IRP_MN_QUERY_REMOVE_DEVICE );
//
// Mark that the device is pending removal. Send the IRP on down the
// stack.
//
commonExtension->DeviceState = RamdiskDeviceStatePendingRemove;
Irp->IoStatus.Status = STATUS_SUCCESS;
goto send_irp_down;
case IRP_MN_CANCEL_REMOVE_DEVICE: PRINT_CODE( IRP_MN_CANCEL_REMOVE_DEVICE );
//
// Before sending the IRP down make sure we have received
// a IRP_MN_QUERY_REMOVE_DEVICE. We may get Cancel Remove
// without receiving a Query Remove earlier, if the
// driver on top fails a Query Remove and passes down the
// Cancel Remove.
//
if ( commonExtension->DeviceState == RamdiskDeviceStatePendingRemove ) {
//
// Mark that the device is back in the working state. Send the
// IRP on down the stack.
//
commonExtension->DeviceState = RamdiskDeviceStateWorking;
Irp->IoStatus.Status = STATUS_SUCCESS; goto send_irp_down; } else {
//
// A spurious Cancel Remove request. Just complete it.
//
status = STATUS_SUCCESS; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
break;
case IRP_MN_SURPRISE_REMOVAL: PRINT_CODE( IRP_MN_SURPRISE_REMOVAL );
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
//
// Mark that the device has been removed, and
// pass the IRP down.
//
commonExtension->DeviceState = RamdiskDeviceStateSurpriseRemoved;
Irp->IoStatus.Status = STATUS_SUCCESS; goto send_irp_down; } else {
//
// Ignore surprise removal for disk PDOs.
//
ASSERT( FALSE );
status = STATUS_SUCCESS; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
break;
case IRP_MN_REMOVE_DEVICE: PRINT_CODE( IRP_MN_REMOVE_DEVICE );
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
//
// Remove the bus FDO.
//
// Note that RamdiskRemoveBusDevice() sends the IRP down the
// device stack, so we don't complete the IRP here.
//
status = RamdiskRemoveBusDevice( DeviceObject, Irp );
} else {
//
// Remove a disk PDO.
//
status = RamdiskDeleteDiskDevice( DeviceObject, Irp );
COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
//
// The remove lock was released by RamdiskRemoveBusDevice or
// RamdiskDeleteDiskDevice.
//
lockHeld = FALSE;
break;
case IRP_MN_EJECT: PRINT_CODE( IRP_MN_EJECT );
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
//
// Ignore eject for the bus FDO. Just send the IRP down.
//
Irp->IoStatus.Status = STATUS_SUCCESS; goto send_irp_down; } else {
//
// Ignore eject for a disk PDO, too. Don't send the IRP down.
//
status = STATUS_SUCCESS; COMPLETE_REQUEST( status, 0, Irp ); }
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
//
// Let RamdiskQueryDeviceRelations() do the work. Note that it
// completes the IRP.
//
status = RamdiskQueryDeviceRelations( irpSp->Parameters.QueryDeviceRelations.Type, DeviceObject, Irp );
break;
case IRP_MN_QUERY_DEVICE_TEXT:
//
// For the bus FDO, just pass the IRP down. For a disk PDO, let
// RamdiskQueryDeviceText() do the work and complete the IRP.
//
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
goto send_irp_down;
} else {
status = RamdiskQueryDeviceText( diskExtension, Irp ); }
break;
case IRP_MN_QUERY_BUS_INFORMATION: //
// Let RamdiskQueryBusInformation() do the work. Note that it
// completes the IRP.
//
status = RamdiskQueryBusInformation( DeviceObject, Irp );
break;
case IRP_MN_QUERY_CAPABILITIES: //
// For the bus FDO, just pass the IRP down. For a disk PDO, let
// RamdiskQueryCapabilities() do the work and complete the IRP.
//
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
goto send_irp_down;
} else {
status = RamdiskQueryCapabilities( DeviceObject, Irp ); }
break;
case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
//
// We don't have any resources to add to whatever might already be
// there, so just complete the IRP.
//
status = Irp->IoStatus.Status; COMPLETE_REQUEST( Irp->IoStatus.Status, Irp->IoStatus.Information, Irp );
break;
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS: //
// For the bus FDO, just pass the IRP down. For a disk PDO, just
// complete the IRP.
//
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
goto send_irp_down;
} else {
status = Irp->IoStatus.Status; COMPLETE_REQUEST( Irp->IoStatus.Status, Irp->IoStatus.Information, Irp ); }
break;
case IRP_MN_QUERY_ID: //
// For the bus FDO, just pass the IRP down. For a disk PDO, let
// RamdiskQueryId() do the work and complete the IRP.
//
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
goto send_irp_down;
} else {
status = RamdiskQueryId( diskExtension, Irp ); }
break;
case IRP_MN_QUERY_PNP_DEVICE_STATE: case IRP_MN_QUERY_LEGACY_BUS_INFORMATION: default: send_irp_down:
//
// If this is the bus FDO, and there is a lower device object,
// send the IRP down to the next device. If this is a disk PDO,
// just complete the IRP.
//
if ( (commonExtension->DeviceType == RamdiskDeviceTypeBusFdo) && (commonExtension->LowerDeviceObject != NULL) ) {
IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( commonExtension->LowerDeviceObject, Irp );
} else {
status = Irp->IoStatus.Status; COMPLETE_REQUEST( Irp->IoStatus.Status, Irp->IoStatus.Information, Irp ); }
break;
} // switch
//
// If the lock is still held, release it now.
//
if ( lockHeld ) {
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("RamdiskPnp: done; Device State=%s\n", StateTable[commonExtension->DeviceState]) );
IoReleaseRemoveLock( &commonExtension->RemoveLock, Irp ); }
return status;
} // RamdiskPnp
NTSTATUS RamdiskPower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine is called by the I/O system to perform a power function.
Arguments:
DeviceObject - a pointer to the object that represents the device on which I/O is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status = STATUS_SUCCESS; PCOMMON_EXTENSION commonExtension;
PAGED_CODE();
DBGPRINT( DBG_POWER, DBG_VERBOSE, ("RamdiskPower: DO=(%p) Irp=(%p)\n", DeviceObject, Irp) );
commonExtension = DeviceObject->DeviceExtension;
if ( commonExtension->DeviceType == RamdiskDeviceTypeBusFdo ) {
//
// This is the bus FDO. There's not much for us to do here.
//
// Start the next power IRP.
//
PoStartNextPowerIrp( Irp );
//
// If the device has been removed, the driver should not pass
// the IRP down to the next lower driver.
//
if ( commonExtension->DeviceState >= RamdiskDeviceStateRemoved ) {
status = STATUS_DELETE_PENDING; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp );
return status; }
//
// Send the IRP on down the stack.
//
IoSkipCurrentIrpStackLocation( Irp ); status = PoCallDriver( commonExtension->LowerDeviceObject, Irp );
} else {
PIO_STACK_LOCATION irpSp; POWER_STATE powerState; POWER_STATE_TYPE powerType;
//
// This is a request for a disk PDO.
//
// Get parameters from the IRP.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
powerType = irpSp->Parameters.Power.Type; powerState = irpSp->Parameters.Power.State;
//
// Dispatch based on the minor function.
//
switch ( irpSp->MinorFunction ) { case IRP_MN_SET_POWER:
//
// For SET_POWER, we don't have to do anything but return success.
//
switch ( powerType ) { case DevicePowerState: case SystemPowerState:
status = STATUS_SUCCESS;
break;
default:
status = STATUS_NOT_SUPPORTED;
break; }
break;
case IRP_MN_QUERY_POWER:
//
// For QUERY_POWER, we don't have to do anything but return
// success.
//
status = STATUS_SUCCESS;
break;
case IRP_MN_WAIT_WAKE: case IRP_MN_POWER_SEQUENCE: default:
status = STATUS_NOT_SUPPORTED;
break; }
if ( status != STATUS_NOT_SUPPORTED ) {
Irp->IoStatus.Status = status; }
PoStartNextPowerIrp( Irp );
status = Irp->IoStatus.Status; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
DBGPRINT( DBG_POWER, DBG_VERBOSE, ("RamdiskPower: status = 0x%x\n", status) );
return status; } // RamdiskPower
NTSTATUS RamdiskAddDevice ( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT Pdo )
/*++
Routine Description:
This routine is called by the PnP system to add a device.
We expect to get this call exactly once, to add our bus PDO.
Arguments:
DriverObject - a pointer to our driver object
Pdo - a pointer to the PDO for the FDO that we create
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; UNICODE_STRING deviceName; PDEVICE_OBJECT fdo; PBUS_EXTENSION busExtension; PULONG bitmap; PLOADER_PARAMETER_BLOCK loaderBlock;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskAddDevice: entered\n") );
//
// If we've already done this once, fail this call.
//
if ( RamdiskBusFdo != NULL ) {
return STATUS_DEVICE_ALREADY_ATTACHED; }
#if SUPPORT_DISK_NUMBERS
//
// Allocate space for the disk numbers bitmap.
//
bitmap = ALLOCATE_POOL( PagedPool, DiskNumbersBitmapSize, TRUE );
if ( bitmap == NULL ) {
return STATUS_INSUFFICIENT_RESOURCES; }
#endif // SUPPORT_DISK_NUMBERS
//
// Create the bus device object.
//
// ISSUE: Apply an ACL to the bus device object. (Or does the next issue obviate this?)
// ISSUE: We're supposed to use autogenerated names for FDOs. What is the
// harm in using our own name? (Benefit is that it's easier to
// find the device when creating/deleting disks.)
//
RtlInitUnicodeString( &deviceName, L"\\Device\\Ramdisk" );
status = IoCreateDevice( DriverObject, // DriverObject
sizeof(BUS_EXTENSION), // DeviceExtension
&deviceName, // DeviceName
FILE_DEVICE_BUS_EXTENDER, // DeviceType
FILE_DEVICE_SECURE_OPEN, // DeviceCharacteristics
FALSE, // Exclusive
&fdo // DeviceObject
);
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("RamdiskAddDevice: error %x creating bus FDO\n", status) );
#if SUPPORT_DISK_NUMBERS
FREE_POOL( bitmap, TRUE ); #endif // SUPPORT_DISK_NUMBERS
return status; }
busExtension = fdo->DeviceExtension; RtlZeroMemory( busExtension, sizeof(BUS_EXTENSION) );
//
// Initialize device object and extension.
//
//
// Our device does direct I/O and is power pageable.
//
fdo->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
//
// Set the device type and state in the device extension. Initialize the
// fast mutex and the remove lock. Initialize the disk PDO list.
//
busExtension->DeviceType = RamdiskDeviceTypeBusFdo; busExtension->DeviceState = RamdiskDeviceStateStopped;
ExInitializeFastMutex( &busExtension->Mutex ); IoInitializeRemoveLock( &busExtension->RemoveLock, 'dmaR', 1, 0 );
InitializeListHead( &busExtension->DiskPdoList );
//
// Save object pointers. The PDO for this extension is the PDO that
// was passed in. The FDO is the device object that we just created. The
// lower device object will be set later.
//
busExtension->Pdo = Pdo; busExtension->Fdo = fdo;
//
// Register the device interface.
//
status = IoRegisterDeviceInterface( Pdo, &RamdiskBusInterface, NULL, &busExtension->InterfaceString );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("RamdiskAddDevice: error %x registering device interface for bus FDO\n", status) );
IoDeleteDevice( fdo );
#if SUPPORT_DISK_NUMBERS
FREE_POOL( bitmap, TRUE ); #endif // SUPPORT_DISK_NUMBERS
return status; }
//
// Attach the FDO to the PDO's device stack. Remember the lower device
// object to which we are to forward PnP IRPs.
//
busExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack( fdo, Pdo );
if ( busExtension->LowerDeviceObject == NULL ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("%s", "RamdiskAddDevice: error attaching bus FDO to PDO stack\n") );
//
// Tell PnP that we're not going to be activating the interface that
// we just registered. Free the symbolic link string associated with
// the interface. Delete the device object.
//
IoSetDeviceInterfaceState( &busExtension->InterfaceString, FALSE );
RtlFreeUnicodeString( &busExtension->InterfaceString );
IoDeleteDevice( fdo );
#if SUPPORT_DISK_NUMBERS
FREE_POOL( bitmap, TRUE ); #endif // SUPPORT_DISK_NUMBERS
return STATUS_NO_SUCH_DEVICE; }
#if SUPPORT_DISK_NUMBERS
//
// Initialize the disk numbers bitmap.
//
busExtension->DiskNumbersBitmapBuffer = bitmap; RtlInitializeBitMap( &busExtension->DiskNumbersBitmap, bitmap, DiskNumbersBitmapSize ); RtlClearAllBits( &busExtension->DiskNumbersBitmap );
#endif // SUPPORT_DISK_NUMBERS
RamdiskBusFdo = fdo;
//
// If textmode setup is running, create any RAM disks specified in the
// registry.
//
loaderBlock = *(PLOADER_PARAMETER_BLOCK *)KeLoaderBlock;
if ( (loaderBlock != NULL) && (loaderBlock->SetupLoaderBlock != NULL) ) {
CreateRegistryDisks( FALSE ); }
//
// Indicate that we're done initializing the device.
//
fdo->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
} // RamdiskAddDevice
BOOLEAN CreateRegistryDisks ( IN BOOLEAN CheckPresenceOnly )
/*++
Routine Description:
This routine creates virtual floppy disks specified in the registry. It is called only during textmode setup.
Arguments:
CheckPresenceOnly - indicates whether this routine should just check for the presence of at least one disk in the registry
Return Value:
BOOLEAN - indicates whether any disks were specified in the registry
--*/
{ NTSTATUS status; OBJECT_ATTRIBUTES obja; UNICODE_STRING string; HANDLE serviceHandle; HANDLE parametersHandle; ULONG diskNumber; WCHAR valueNameBuffer[15]; UNICODE_STRING valueName; UCHAR valueBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(VIRTUAL_FLOPPY_DESCRIPTOR)]; PKEY_VALUE_PARTIAL_INFORMATION value; PVIRTUAL_FLOPPY_DESCRIPTOR descriptor; ULONG valueLength; RAMDISK_CREATE_INPUT createInput; PDISK_EXTENSION diskExtension; BOOLEAN disksPresent = FALSE; HRESULT result;
value = (PKEY_VALUE_PARTIAL_INFORMATION)valueBuffer; descriptor = (PVIRTUAL_FLOPPY_DESCRIPTOR)value->Data;
//
// Open the driver's key under Services.
//
InitializeObjectAttributes( &obja, &DriverRegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL );
status = ZwOpenKey( &serviceHandle, KEY_READ, &obja );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: ZwOpenKey(1) failed: %x\n", status) );
return FALSE; }
//
// Open the Parameters subkey.
//
RtlInitUnicodeString( &string, L"Parameters" ); InitializeObjectAttributes( &obja, &string, OBJ_CASE_INSENSITIVE, serviceHandle, NULL );
status = ZwOpenKey( ¶metersHandle, KEY_READ, &obja );
NtClose( serviceHandle );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: ZwOpenKey(2) failed: %x\n", status) );
return FALSE; }
//
// Initialize static fields in the CREATE_INPUT structure that we'll pass
// to RamdiskCreateDiskDevice.
//
RtlZeroMemory( &createInput, sizeof(createInput) ); createInput.DiskType = RAMDISK_TYPE_VIRTUAL_FLOPPY; createInput.Options.Fixed = TRUE; createInput.Options.NoDriveLetter = TRUE;
//
// Look for values named DISKn, where n starts at 0 and increases by 1
// each loop. Break out as soon as the expected DISKn is not found.
// (If values named DISK0 and DISK2 are present, only DISK0 will be
// created -- DISK2 will not be found.)
//
diskNumber = 0;
while ( TRUE ) {
// This variable is here to keep PREfast quiet (PREfast warning 209).
size_t size = sizeof(valueNameBuffer);
result = StringCbPrintfW( valueNameBuffer, size, L"DISK%u", diskNumber ); ASSERT( result == S_OK );
RtlInitUnicodeString( &valueName, valueNameBuffer );
status = ZwQueryValueKey( parametersHandle, &valueName, KeyValuePartialInformation, value, sizeof(valueBuffer), &valueLength );
if ( !NT_SUCCESS(status) ) {
if ( status != STATUS_OBJECT_NAME_NOT_FOUND ) {
DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: ZwQueryValueKey failed: %x\n", status) ); }
break; }
//
// We've found a DISKn value in the registry. For the purposes of
// the CheckPresenceOnly flag, this is enough to know that at least
// one virtual floppy disk is present. We don't care whether the
// data is valid -- we just need to know that it's there.
//
disksPresent = TRUE;
//
// If we're just checking for the presence of at least one disk, we
// can leave now.
//
if ( CheckPresenceOnly ) {
break; }
//
// We expect the value to be a REG_BINARY with the correct length.
// We don't explicitly check the value type; we assume that the
// length check is sufficient. We also expect the base address
// (which is a system virtual address -- either in KSEG0 or in
// nonpaged pool) and the length to be nonzero.
//
if ( value->DataLength != FIELD_OFFSET(VIRTUAL_FLOPPY_DESCRIPTOR, StructSizer) ) {
DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: key length wrong, wanted 0x%x, got 0x%x\n", sizeof(VIRTUAL_FLOPPY_DESCRIPTOR), valueLength) );
} else if ( (descriptor->VirtualAddress == NULL) || (descriptor->Length == 0) ) {
DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: address (%x) or length (0x%x) invalid\n", descriptor->VirtualAddress, descriptor->Length) );
} else {
//
// Create a virtual floppy RAM disk at the specified address and
// with the specified length. Pass the disk number in the GUID.
//
createInput.DiskGuid.Data1 = diskNumber; createInput.DiskLength = descriptor->Length; createInput.BaseAddress = descriptor->VirtualAddress;
DBGPRINT( DBG_INIT, DBG_INFO, ("CreateRegistryDisks: creating virtual floppy #%d at %p for %x\n", diskNumber, descriptor->VirtualAddress, descriptor->Length) );
ASSERT( RamdiskBusFdo != NULL ); ASSERT( RamdiskBusFdo->DeviceExtension != NULL );
status = RamdiskCreateDiskDevice( RamdiskBusFdo->DeviceExtension, &createInput, FALSE, &diskExtension ); if ( !NT_SUCCESS(status) ) { DBGPRINT( DBG_INIT, DBG_ERROR, ("CreateRegistryDisks: RamdiskCreateDiskDevice failed: %x\n", status) ); } }
diskNumber++; }
//
// Close the Parameters key and return.
//
NtClose( parametersHandle );
return disksPresent;
} // CreateRegistryDisks
NTSTATUS RamdiskDeleteDiskDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp OPTIONAL )
/*++
Routine Description:
This routine is called to delete a RAM disk device.
NOTE: The remove lock is held on entry to this routine. It is released on exit. If Irp == NULL, the bus mutex is held on entry and released on exit.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request. If NULL, this is a call from RamdiskRemoveBusDevice().
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PDISK_EXTENSION diskExtension; PDISK_EXTENSION tempDiskExtension; PBUS_EXTENSION busExtension; PLIST_ENTRY listEntry;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskDeleteDiskDevice\n") );
diskExtension = DeviceObject->DeviceExtension; busExtension = diskExtension->Fdo->DeviceExtension;
DBGPRINT( DBG_PNP, DBG_INFO, ("RamdiskDeleteDiskDevice: Deleting device %wZ\n", &diskExtension->DeviceName) );
//
// If no IRP was specified, then we delete the disk device unconditionally.
// (It's a call from RamdiskRemoveBusDevice().) Otherwise, we need to check
// whether we really want to delete the device now.
//
if ( Irp != NULL ) {
Irp->IoStatus.Information = 0;
//
// Check to see if the device has been marked for removal. If not,
// ignore this IRP. We do this because user-mode PnP likes to remove
// and immmediately recreate the devices that we materialize, but we
// don't want to remove the device and lose the information about the
// disk image.
//
if ( !diskExtension->MarkedForDeletion ) {
//
// This device has not really been removed, so ignore this IRP.
// But do mark that the device is no longer claimed.
//
diskExtension->Status &= ~RAMDISK_STATUS_CLAIMED;
IoReleaseRemoveLock( &diskExtension->RemoveLock, Irp );
return STATUS_SUCCESS; }
//
// The device has been marked for deletion, so it's OK for PnP to be
// trying to remove it. If this is PnP's first attempt at removing the
// device, just mark it as removed and tell PnP to reenumerate the
// bus. During reenumeration, we will skip this device, and PnP will
// come back with another remove IRP.
//
if ( diskExtension->DeviceState < RamdiskDeviceStateRemoved ) {
diskExtension->DeviceState = RamdiskDeviceStateRemoved;
busExtension = diskExtension->Fdo->DeviceExtension; IoInvalidateDeviceRelations( busExtension->Pdo, BusRelations );
IoReleaseRemoveLock( &diskExtension->RemoveLock, Irp );
return STATUS_SUCCESS; }
//
// If the device is marked as removed, but it hasn't yet been skipped
// in a bus enumeration, don't do anything now.
//
if ( diskExtension->DeviceState == RamdiskDeviceStateRemoved ) {
IoReleaseRemoveLock( &diskExtension->RemoveLock, Irp );
return STATUS_SUCCESS; }
//
// If we get here, we have already skipped this device in a bus
// enumeration, so it's time to delete it. Acquire the bus mutex
// so that we can do this.
//
KeEnterCriticalRegion(); ExAcquireFastMutex( &busExtension->Mutex ); }
//
// If we get here, we really do want to delete this device. If we've
// already deleted it, don't do it again.
//
if ( diskExtension->DeviceState >= RamdiskDeviceStateDeleted ) {
DBGPRINT( DBG_PNP, DBG_INFO, ("RamdiskDeleteDiskDevice: device %wZ has already been deleted\n", &diskExtension->DeviceName) );
//
// Release the bus mutex and the remove lock.
//
ExReleaseFastMutex( &busExtension->Mutex ); KeLeaveCriticalRegion(); IoReleaseRemoveLock( &diskExtension->RemoveLock, Irp );
return STATUS_SUCCESS; }
//
// Indicate that the device has been deleted.
//
diskExtension->DeviceState = RamdiskDeviceStateDeleted;
//
// Remove the disk PDO from the bus FDO's list.
//
for ( listEntry = busExtension->DiskPdoList.Flink; listEntry != &busExtension->DiskPdoList; listEntry = listEntry->Flink ) {
tempDiskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
if ( tempDiskExtension == diskExtension ) {
RemoveEntryList( listEntry );
#if SUPPORT_DISK_NUMBERS
RtlClearBit( &busExtension->DiskNumbersBitmap, diskExtension->DiskNumber - 1 ); #endif // SUPPORT_DISK_NUMBERS
break; } }
//
// We no longer need to hold the bus mutex and the remove lock.
//
ExReleaseFastMutex( &busExtension->Mutex ); KeLeaveCriticalRegion();
IoReleaseRemoveLockAndWait( &diskExtension->RemoveLock, Irp );
//
// If the interface has been started, stop it now.
//
if ( diskExtension->InterfaceString.Buffer != NULL ) {
if ( !diskExtension->Options.Hidden ) { status = IoSetDeviceInterfaceState( &diskExtension->InterfaceString, FALSE ); }
RtlFreeUnicodeString( &diskExtension->InterfaceString ); }
//
// Close the file backing the RAM disk, if any.
//
if ( diskExtension->SectionObject != NULL ) {
if ( diskExtension->ViewDescriptors != NULL ) {
//
// Clean up the mapped views.
//
PVIEW view;
ASSERT( diskExtension->ViewWaiterCount == 0 );
while ( !IsListEmpty( &diskExtension->ViewsByOffset ) ) {
listEntry = RemoveHeadList( &diskExtension->ViewsByOffset ); view = CONTAINING_RECORD( listEntry, VIEW, ByOffsetListEntry );
RemoveEntryList( &view->ByMruListEntry );
ASSERT( view->ReferenceCount == 0 );
if ( view->Address != NULL ) {
DBGPRINT( DBG_WINDOW, DBG_VERBOSE, ("RamdiskDeleteDiskDevice: unmapping view %p; addr %p\n", view, view->Address) );
MmUnmapViewOfSection( PsGetCurrentProcess(), view->Address ); } }
ASSERT( IsListEmpty( &diskExtension->ViewsByMru ) );
FREE_POOL( diskExtension->ViewDescriptors, TRUE ); }
ObDereferenceObject( diskExtension->SectionObject ); }
if ( !diskExtension->Options.NoDosDevice ) { //
// Delete the DosDevices symbolic link.
//
ASSERT( diskExtension->DosSymLink.Buffer != NULL );
status = IoDeleteSymbolicLink( &diskExtension->DosSymLink );
if ( !NT_SUCCESS(status) ) {
DBGPRINT( DBG_PNP, DBG_ERROR, ("RamdiskDeleteDiskDevice: IoDeleteSymbolicLink failed: %x\n", status) ); }
FREE_POOL( diskExtension->DosSymLink.Buffer, TRUE ); } //
// Delete the device name string and the GUID string.
//
if ( diskExtension->DeviceName.Buffer != NULL ) {
FREE_POOL( diskExtension->DeviceName.Buffer, TRUE ); }
if ( diskExtension->DiskGuidFormatted.Buffer != NULL ) {
FREE_POOL( diskExtension->DiskGuidFormatted.Buffer, FALSE ); }
//
// Delete the device object.
//
IoDeleteDevice( DeviceObject );
return STATUS_SUCCESS;
} // RamdiskDeleteDiskDevice
NTSTATUS RamdiskIoCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event )
/*++
Routine Description:
This internal routine is used as the I/O completion routine when we send an IRP down the device stack and want to short-circuit IRP completion so that we can do more work.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Event - a pointer to an event that is to be set to signal the calling code that the lower layers have completed the IRP
Return Value:
NTSTATUS - the status of the operation
--*/
{ UNREFERENCED_PARAMETER( DeviceObject ); UNREFERENCED_PARAMETER( Irp );
//
// Set the event to signal the IRP issuer that it's time to continue.
//
KeSetEvent( Event, 0, FALSE );
//
// Tell the I/O system to stop completing the IRP.
//
return STATUS_MORE_PROCESSING_REQUIRED;
} // RamdiskIoCompletionRoutine
NTSTATUS RamdiskQueryBusInformation ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine processes the IRP_MN_QUERY_BUS_INFORMATION IRP.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PPNP_BUS_INFORMATION busInformation;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("RamdiskQueryBusInformation: DO (0x%p) Type 0x%x\n", DeviceObject, ((PCOMMON_EXTENSION)DeviceObject->DeviceExtension)->DeviceType) );
//
// Allocate a buffer to use for returning the requested information.
//
busInformation = ALLOCATE_POOL( PagedPool, sizeof(PNP_BUS_INFORMATION), FALSE );
if ( busInformation == NULL ) {
//
// Fail the IRP.
//
status = STATUS_INSUFFICIENT_RESOURCES; COMPLETE_REQUEST( status, 0, Irp );
return status; }
//
// Fill in the requested information.
//
busInformation->BusTypeGuid = GUID_BUS_TYPE_RAMDISK; busInformation->LegacyBusType = PNPBus; busInformation->BusNumber = 0x00;
//
// Complete the IRP.
//
status = STATUS_SUCCESS; COMPLETE_REQUEST( status, (ULONG_PTR)busInformation, Irp );
return status; } // RamdiskQueryBusInformation
NTSTATUS RamdiskQueryCapabilities ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine processes the IRP_MN_QUERY_CAPABILITIES IRP.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PIO_STACK_LOCATION irpSp; PDEVICE_CAPABILITIES deviceCapabilities; PDISK_EXTENSION diskExtension;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskQueryCapabilities\n") );
//
// Get a pointer to the device extension and get parameters from the IRP.
//
diskExtension = DeviceObject->DeviceExtension;
irpSp = IoGetCurrentIrpStackLocation( Irp ); deviceCapabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
if ( (deviceCapabilities->Version != 1) || (deviceCapabilities->Size < sizeof(DEVICE_CAPABILITIES)) ) {
//
// We don't support this version. Fail the request.
//
status = STATUS_UNSUCCESSFUL;
} else {
status = STATUS_SUCCESS;
//
// If this is an emulated volume, we want to allow access to the raw
// device. (Otherwise PnP won't start the device.)
//
// Note that a RAM disk boot disk is an emulated volume.
//
deviceCapabilities->RawDeviceOK = (BOOLEAN)(diskExtension->DiskType != RAMDISK_TYPE_FILE_BACKED_DISK);
//
// Indicate that ejection is not supported.
//
deviceCapabilities->EjectSupported = FALSE; //
// This flag specifies whether the device's hardware is disabled.
// The PnP Manager only checks this bit right after the device is
// enumerated. Once the device is started, this bit is ignored.
//
deviceCapabilities->HardwareDisabled = FALSE; //
// Indicate that the emulated device cannot be physically removed.
// (Unless the right registry key was specified...)
//
deviceCapabilities->Removable = MarkRamdisksAsRemovable;
//
// Setting SurpriseRemovalOK to TRUE prevents the warning dialog from
// appearing whenever the device is surprise removed. Setting it FALSE
// allows the Hot unplug applet to stop the device.
//
// We don't want our disks to show up in the systray, so we set
// SurpriseRemovalOK to TRUE. There is never really any surprise
// removal anyway -- removal comes from the user mode control app
// calling CM_Query_And_Remove_SubTree_Ex().
//
deviceCapabilities->SurpriseRemovalOK = TRUE;
//
// We support system-wide unique IDs.
//
deviceCapabilities->UniqueID = TRUE;
//
// Indicate that the Device Manager should suppress all
// installation pop-ups except required pop-ups such as
// "no compatible drivers found."
//
deviceCapabilities->SilentInstall = TRUE;
//
// Indicate that we do not want this device displayed in
// Device Manager.
//
deviceCapabilities->NoDisplayInUI = TRUE; }
//
// Complete the request.
//
COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp );
return status; } // RamdiskQueryCapabilities
NTSTATUS RamdiskQueryId ( IN PDISK_EXTENSION DiskExtension, IN PIRP Irp )
/*++
Routine Description:
This routine processes the IRP_MN_QUERY_ID IRP for disk devices.
Arguments:
DiskExtension - a pointer to the device extension for the device object on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ #define MAX_LOCAL_STRING 50
NTSTATUS status; PIO_STACK_LOCATION irpSp; PWCHAR buffer; PWCHAR p; ULONG length; PWCHAR deviceType; HRESULT result;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskQueryId\n") );
//
// Assume success.
//
status = STATUS_SUCCESS;
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Dispatch based on the query type.
//
switch ( irpSp->Parameters.QueryId.IdType ) { case BusQueryDeviceID:
//
// DeviceID is a string to identify a device. We return the string
// "Ramdisk\RamVolume" or "Ramdisk\RamDisk".
//
// Allocate pool to hold the string.
//
length = sizeof(RAMDISK_ENUMERATOR_TEXT) - sizeof(WCHAR) + ((DiskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK) ? sizeof(RAMDISK_DISK_DEVICE_TEXT) : sizeof(RAMDISK_VOLUME_DEVICE_TEXT));
buffer = ALLOCATE_POOL( PagedPool, length, FALSE );
if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; }
//
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, length, RAMDISK_ENUMERATOR_TEXT ); ASSERT( result == S_OK ); result = StringCbCatW( buffer, length, (DiskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK) ? RAMDISK_DISK_DEVICE_TEXT : RAMDISK_VOLUME_DEVICE_TEXT ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 1) * sizeof(WCHAR)) == length );
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("BusQueryDeviceID=%S\n", buffer) );
break;
case BusQueryInstanceID:
//
// InstanceID is a string to identify the device instance. We return
// the disk GUID in string form.
//
// Allocate pool to hold the string.
//
buffer = ALLOCATE_POOL( PagedPool, DiskExtension->DiskGuidFormatted.MaximumLength, FALSE );
if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; }
//
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, DiskExtension->DiskGuidFormatted.MaximumLength, DiskExtension->DiskGuidFormatted.Buffer ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 1) * sizeof(WCHAR)) == DiskExtension->DiskGuidFormatted.MaximumLength );
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("BusQueryInstanceID=%S\n", buffer) );
break; case BusQueryHardwareIDs:
//
// HardwareIDs is a multi-sz string to identify a device's hardware
// type. We return the string "Ramdisk\RamVolume\0" or
// "Ramdisk\RamDisk\0".
//
// Allocate pool to hold the string. Note that we allocate space
// for two null terminators.
//
length = sizeof(RAMDISK_ENUMERATOR_TEXT) - sizeof(WCHAR) + ((DiskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK) ? sizeof(RAMDISK_DISK_DEVICE_TEXT) : sizeof(RAMDISK_VOLUME_DEVICE_TEXT)) + sizeof(WCHAR);
buffer = ALLOCATE_POOL( PagedPool, length, FALSE );
if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; }
//
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, length, RAMDISK_ENUMERATOR_TEXT ); ASSERT( result == S_OK ); result = StringCbCatW( buffer, length, (DiskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK) ? RAMDISK_DISK_DEVICE_TEXT : RAMDISK_VOLUME_DEVICE_TEXT ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 2) * sizeof(WCHAR)) == length );
buffer[length/sizeof(WCHAR) - 1] = 0;
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("BusQueryHardwareIDs=%S\n", buffer) );
break;
case BusQueryCompatibleIDs:
//
// HardwareIDs is a multi-sz string to identify device classes that
// are compatible with a device. For volume-emulating RAM disks, we
// return no compatible IDs, so that the device stands on its own at
// the volume level. For disk-emulating RAM disks, we return the
// string "Gendisk\0", so that the device gets hooked in below disk.sys.
//
if ( DiskExtension->DiskType == RAMDISK_TYPE_FILE_BACKED_DISK ) {
//
// Disk emulation. Allocate pool to hold the string.
//
length = sizeof(L"GenDisk") + sizeof(WCHAR);
buffer = ALLOCATE_POOL( PagedPool, length, FALSE ); if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; } //
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, length, L"GenDisk" ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 2) * sizeof(WCHAR)) == length );
buffer[length/sizeof(WCHAR) - 1] = 0;
} else {
//
// Volume emulation. Do not return any compatible IDs.
//
buffer = NULL;
status = STATUS_INVALID_DEVICE_REQUEST; }
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("BusQueryCompatibleIDs=%S\n", buffer) );
break;
default:
//
// Unknown query type. Just leave whatever's already in the IRP there.
//
status = Irp->IoStatus.Status; buffer = (PWCHAR)Irp->IoStatus.Information; }
//
// Complete the request.
//
COMPLETE_REQUEST( status, (ULONG_PTR)buffer, Irp );
return status; } // RamdiskQueryId
NTSTATUS RamdiskQueryDeviceRelations ( IN DEVICE_RELATION_TYPE RelationsType, IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine processes the IRP_MN_QUERY_DEVICE_RELATIONS IRP.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PCOMMON_EXTENSION commonExtension; PBUS_EXTENSION busExtension; PDISK_EXTENSION diskExtension; RAMDISK_DEVICE_TYPE deviceType; PLIST_ENTRY listEntry; PDEVICE_RELATIONS deviceRelations; PDEVICE_RELATIONS oldRelations; ULONG prevCount = 0; ULONG length = 0; ULONG numPdosPresent = 0;
PAGED_CODE();
//
// Assume success.
//
status = STATUS_SUCCESS;
//
// Get the device extension pointer and save the device type.
//
commonExtension = (PCOMMON_EXTENSION)DeviceObject->DeviceExtension; deviceType = commonExtension->DeviceType;
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("RamdiskQueryDeviceRelations: QueryDeviceRelation Type: %s, DeviceType 0x%x\n", GetDeviceRelationString(RelationsType), deviceType) );
//
// Dispatch based on the device type.
//
if ( deviceType == RamdiskDeviceTypeDiskPdo ) {
//
// It's a disk PDO. We only handle TargetDeviceRelation for PDOs.
//
diskExtension = (PDISK_EXTENSION)commonExtension;
if ( RelationsType == TargetDeviceRelation ) {
//
// Allocate pool to hold the return information. (DEVICE_RELATIONS
// has space for one entry built-in).
//
deviceRelations = ALLOCATE_POOL( PagedPool, sizeof(DEVICE_RELATIONS), FALSE ); if ( deviceRelations != NULL ) {
//
// Return a referenced pointer to the device object for this
// device.
//
ObReferenceObject( DeviceObject );
deviceRelations->Count = 1; deviceRelations->Objects[0] = DeviceObject;
status = STATUS_SUCCESS;
} else {
//
// Couldn't allocate pool.
//
status = STATUS_INSUFFICIENT_RESOURCES; }
//
// Complete the request.
//
COMPLETE_REQUEST( status, (ULONG_PTR)deviceRelations, Irp );
} else {
//
// PDOs just complete enumeration requests without altering
// the status.
//
status = Irp->IoStatus.Status; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp ); }
return status;
} else {
//
// It's the bus FDO. We only handle BusRelations for the FDO.
//
busExtension = (PBUS_EXTENSION)commonExtension;
if ( RelationsType == BusRelations ) {
//
// Re-enumerate the device.
//
// Lock the disk PDO list.
//
KeEnterCriticalRegion(); ExAcquireFastMutex( &busExtension->Mutex );
//
// There might also be device relations below and above this FDO,
// so propagate the relations from the upper drivers.
//
oldRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
if (oldRelations != NULL) { prevCount = oldRelations->Count; } else { prevCount = 0; }
//
// Calculate the number of PDOs actually present on the bus.
//
numPdosPresent = 0;
for ( listEntry = busExtension->DiskPdoList.Flink; listEntry != &busExtension->DiskPdoList; listEntry = listEntry->Flink ) {
diskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
if ( diskExtension->DeviceState < RamdiskDeviceStateRemoved ) { numPdosPresent++; } }
//
// Allocate a new relations structure and add our PDOs to it.
//
length = sizeof(DEVICE_RELATIONS) + ((numPdosPresent + prevCount - 1) * sizeof(PDEVICE_OBJECT));
deviceRelations = ALLOCATE_POOL( PagedPool, length, FALSE );
if ( deviceRelations == NULL ) {
//
// Fail the IRP.
//
ExReleaseFastMutex( &busExtension->Mutex ); KeLeaveCriticalRegion();
status = STATUS_INSUFFICIENT_RESOURCES; COMPLETE_REQUEST( status, Irp->IoStatus.Information, Irp );
return status; }
//
// Copy in the device objects so far.
//
if ( prevCount != 0 ) {
RtlCopyMemory( deviceRelations->Objects, oldRelations->Objects, prevCount * sizeof(PDEVICE_OBJECT) ); } deviceRelations->Count = prevCount + numPdosPresent;
//
// For each PDO present on this bus, add a pointer to the device
// relations buffer, being sure to take out a reference to that
// object. PnP will dereference the object when it is done with it
// and free the device relations buffer.
//
for ( listEntry = busExtension->DiskPdoList.Flink; listEntry != &busExtension->DiskPdoList; listEntry = listEntry->Flink ) {
diskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
if ( diskExtension->DeviceState < RamdiskDeviceStateRemoved ) {
ObReferenceObject( diskExtension->Pdo );
deviceRelations->Objects[prevCount] = diskExtension->Pdo;
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("QueryDeviceRelations(BusRelations) PDO = 0x%p\n", deviceRelations->Objects[prevCount]) );
prevCount++;
} else {
if ( diskExtension->DeviceState == RamdiskDeviceStateRemoved ) {
diskExtension->DeviceState = RamdiskDeviceStateRemovedAndNotReported; }
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("QueryDeviceRelations(BusRelations) PDO = 0x%p -- SKIPPED\n", diskExtension->Pdo) ); } }
//
// Release the lock.
//
ExReleaseFastMutex( &busExtension->Mutex ); KeLeaveCriticalRegion();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("QueryDeviceRelations(BusRelations) Total #PDOs reported = %d, " "%d were new\n", deviceRelations->Count, numPdosPresent) );
//
// Replace the relations structure in the IRP with the new
// one.
//
if ( oldRelations != NULL ) { FREE_POOL( oldRelations, FALSE ); }
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS; }
//
// Send the IRP down the device stack.
//
IoCopyCurrentIrpStackLocationToNext( Irp ); status = IoCallDriver( busExtension->LowerDeviceObject, Irp ); }
return status;
} // RamdiskQueryDeviceRelations
NTSTATUS RamdiskQueryDeviceText ( IN PDISK_EXTENSION DiskExtension, IN PIRP Irp )
/*++
Routine Description:
This routine processes the IRP_MN_QUERY_DEVICE_TEXT IRP.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PIO_STACK_LOCATION irpSp; ULONG length; PWCHAR buffer; UNICODE_STRING tempString; HRESULT result;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskQueryDeviceText\n") );
//
// Assume success.
//
status = STATUS_SUCCESS;
irpSp = IoGetCurrentIrpStackLocation( Irp );
//
// Dispatch based on the query type.
//
switch ( irpSp->Parameters.QueryDeviceText.DeviceTextType ) { case DeviceTextDescription:
//
// Description is just "RamDisk".
//
// Allocate pool to hold the string.
//
length = sizeof( RAMDISK_DISK_DEVICE_TEXT );
buffer = ALLOCATE_POOL( PagedPool, length, FALSE );
if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; }
//
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, length, RAMDISK_DISK_DEVICE_TEXT ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 1) * sizeof(WCHAR)) == length );
break;
case DeviceTextLocationInformation:
//
// LocationInformation is just "Ramdisk\\0".
//
// Allocate pool to hold the string.
//
length = sizeof( RAMDISK_ENUMERATOR_BUS_TEXT );
buffer = ALLOCATE_POOL( PagedPool, length, FALSE );
if ( buffer == NULL ) {
status = STATUS_INSUFFICIENT_RESOURCES; break; }
//
// Copy the string into the destination buffer.
//
result = StringCbCopyW( buffer, length, RAMDISK_ENUMERATOR_BUS_TEXT ); ASSERT( result == S_OK ); ASSERT( ((wcslen(buffer) + 1) * sizeof(WCHAR)) == length );
break;
default:
//
// Unknown query type. Just leave whatever's already in the IRP there.
//
status = Irp->IoStatus.Status; buffer = (PWCHAR)Irp->IoStatus.Information; }
//
// Complete the request.
//
COMPLETE_REQUEST( status, (ULONG_PTR)buffer, Irp );
return status;
} // RamdiskQueryDeviceText
NTSTATUS RamdiskRemoveBusDevice ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp )
/*++
Routine Description:
This routine removes the bus device.
The remove lock must be held on entry.
Arguments:
DeviceObject - a pointer to the object that represents the device on which the operation is to be performed
Irp - a pointer to the I/O Request Packet for this request
Return Value:
NTSTATUS - the status of the operation
--*/
{ NTSTATUS status; PBUS_EXTENSION busExtension; PLIST_ENTRY listEntry; PDISK_EXTENSION diskExtension;
PAGED_CODE();
DBGPRINT( DBG_PNP, DBG_VERBOSE, ("%s", "RamdiskRemoveBusDevice\n" ) );
//
// Get a pointer to the device extension.
//
busExtension = DeviceObject->DeviceExtension;
//
// Lock the disk PDO list. Walk the list, deleting all remaining devices.
//
KeEnterCriticalRegion(); ExAcquireFastMutex( &busExtension->Mutex );
while ( !IsListEmpty( &busExtension->DiskPdoList ) ) {
listEntry = busExtension->DiskPdoList.Flink;
//
// Delete the device and clean it up. Acquire the remove lock first.
// RamdiskDeleteDiskDevice releases it.
//
diskExtension = CONTAINING_RECORD( listEntry, DISK_EXTENSION, DiskPdoListEntry );
status = IoAcquireRemoveLock( &diskExtension->RemoveLock, NULL ); ASSERT( NT_SUCCESS(status) );
RamdiskDeleteDiskDevice( diskExtension->Pdo, NULL );
KeEnterCriticalRegion(); ExAcquireFastMutex( &busExtension->Mutex ); }
//
// Release the lock.
//
ExReleaseFastMutex( &busExtension->Mutex ); KeLeaveCriticalRegion();
//
// Pass the IRP on down to lower levels.
//
Irp->IoStatus.Status = STATUS_SUCCESS;
IoSkipCurrentIrpStackLocation( Irp ); status = IoCallDriver( busExtension->LowerDeviceObject, Irp );
//
// Set the device status to Removed and wait for other drivers
// to release the lock, then delete the device object.
//
busExtension->DeviceState = RamdiskDeviceStateRemoved; IoReleaseRemoveLockAndWait( &busExtension->RemoveLock, Irp );
//
// Stop the interface and free the interface string.
//
if ( busExtension->InterfaceString.Buffer != NULL ) {
IoSetDeviceInterfaceState( &busExtension->InterfaceString, FALSE );
RtlFreeUnicodeString( &busExtension->InterfaceString ); }
//
// If attached to a lower device, detach now.
//
if ( busExtension->LowerDeviceObject != NULL ) {
IoDetachDevice( busExtension->LowerDeviceObject ); }
#if SUPPORT_DISK_NUMBERS
//
// Free the disk numbers bitmap.
//
ASSERT( !RtlAreBitsSet( &busExtension->DiskNumbersBitmap, 0, DiskNumbersBitmapSize ) );
FREE_POOL( busExtension->DiskNumbersBitmapBuffer, TRUE );
#endif // SUPPORT_DISK_NUMBERS
//
// Indicate that we no longer have a bus FDO, and delete the device object.
//
RamdiskBusFdo = NULL;
IoDeleteDevice( DeviceObject );
DBGPRINT( DBG_PNP, DBG_NOTIFY, ("%s", "Device removed succesfully\n") );
return status; } // RamdiskRemoveBusDevice
#if DBG
PSTR GetPnpIrpName ( IN UCHAR PnpMinorFunction ) { static char functionName[25]; HRESULT result;
PAGED_CODE();
switch ( PnpMinorFunction ) {
case IRP_MN_START_DEVICE:
return "IRP_MN_START_DEVICE";
case IRP_MN_QUERY_REMOVE_DEVICE:
return "IRP_MN_QUERY_REMOVE_DEVICE";
case IRP_MN_REMOVE_DEVICE:
return "IRP_MN_REMOVE_DEVICE";
case IRP_MN_CANCEL_REMOVE_DEVICE:
return "IRP_MN_CANCEL_REMOVE_DEVICE";
case IRP_MN_STOP_DEVICE:
return "IRP_MN_STOP_DEVICE";
case IRP_MN_QUERY_STOP_DEVICE:
return "IRP_MN_QUERY_STOP_DEVICE";
case IRP_MN_CANCEL_STOP_DEVICE:
return "IRP_MN_CANCEL_STOP_DEVICE";
case IRP_MN_QUERY_DEVICE_RELATIONS:
return "IRP_MN_QUERY_DEVICE_RELATIONS";
case IRP_MN_QUERY_INTERFACE:
return "IRP_MN_QUERY_INTERFACE";
case IRP_MN_QUERY_CAPABILITIES:
return "IRP_MN_QUERY_CAPABILITIES";
case IRP_MN_QUERY_RESOURCES:
return "IRP_MN_QUERY_RESOURCES";
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
return "IRP_MN_QUERY_RESOURCE_REQUIREMENTS";
case IRP_MN_QUERY_DEVICE_TEXT:
return "IRP_MN_QUERY_DEVICE_TEXT";
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
return "IRP_MN_FILTER_RESOURCE_REQUIREMENTS";
case IRP_MN_READ_CONFIG:
return "IRP_MN_READ_CONFIG";
case IRP_MN_WRITE_CONFIG:
return "IRP_MN_WRITE_CONFIG";
case IRP_MN_EJECT:
return "IRP_MN_EJECT";
case IRP_MN_SET_LOCK:
return "IRP_MN_SET_LOCK";
case IRP_MN_QUERY_ID:
return "IRP_MN_QUERY_ID";
case IRP_MN_QUERY_PNP_DEVICE_STATE:
return "IRP_MN_QUERY_PNP_DEVICE_STATE";
case IRP_MN_QUERY_BUS_INFORMATION:
return "IRP_MN_QUERY_BUS_INFORMATION";
case IRP_MN_DEVICE_USAGE_NOTIFICATION:
return "IRP_MN_DEVICE_USAGE_NOTIFICATION";
case IRP_MN_SURPRISE_REMOVAL:
return "IRP_MN_SURPRISE_REMOVAL";
case IRP_MN_QUERY_LEGACY_BUS_INFORMATION:
return "IRP_MN_QUERY_LEGACY_BUS_INFORMATION";
default:
result = StringCbPrintfA( functionName, sizeof( functionName ), "Unknown PnP IRP 0x%02x", PnpMinorFunction ); ASSERT( result == S_OK );
return functionName; }
} // GetPnpIrpName
PCHAR GetDeviceRelationString ( IN DEVICE_RELATION_TYPE Type ) { static char relationName[30]; HRESULT result;
PAGED_CODE();
switch ( Type ) { case BusRelations:
return "BusRelations";
case EjectionRelations:
return "EjectionRelations";
case RemovalRelations:
return "RemovalRelations";
case TargetDeviceRelation:
return "TargetDeviceRelation";
default:
result = StringCbPrintfA( relationName, sizeof( relationName ), "Unknown relation 0x%02x", Type ); ASSERT( result == S_OK );
return relationName; }
} // GetDeviceRelationString
#endif // DBG
|