361 lines
9.6 KiB
C
361 lines
9.6 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
All rights reserved
|
||
|
||
Module Name:
|
||
|
||
pnpdd.c
|
||
|
||
Abstract:
|
||
|
||
This module implements new Plug-And-Play driver entries and IRPs.
|
||
|
||
Author:
|
||
|
||
Shie-Lin Tzong (shielint) June-16-1995
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
*/
|
||
|
||
#include "iop.h"
|
||
|
||
#if _PNP_POWER_
|
||
|
||
typedef struct _DEVICE_CHANGE_COMPLETION_CONTEXT {
|
||
KEVENT Event;
|
||
IO_STATUS_BLOCK IoStatus;
|
||
} DEVICE_CHANGE_COMPLETION_CONTEXT, *PDEVICE_CHANGE_COMPLETION_CONTEXT;
|
||
|
||
NTSTATUS
|
||
IopReconfigureResources(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN DRIVER_RECONFIGURE_OPERATION Operation,
|
||
IN PCM_RESOURCE_LIST CmResources
|
||
);
|
||
|
||
NTSTATUS
|
||
IoAddDevice (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING ServiceKeyName,
|
||
IN OUT PULONG InstanceNumber
|
||
);
|
||
|
||
NTSTATUS
|
||
IoRemoveDevice (
|
||
IN PDEVICE_OBJECT TargetDevice,
|
||
IN ULONG IrpMinorCode
|
||
);
|
||
|
||
NTSTATUS
|
||
IopDeviceRemovalComplete (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE, IopReconfigureResources)
|
||
#pragma alloc_text(PAGE, IoAddDevice)
|
||
#pragma alloc_text(PAGE, IoRemoveDevice)
|
||
#endif
|
||
|
||
NTSTATUS
|
||
IopReconfigureResources(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PDEVICE_OBJECT DeviceObject OPTIONAL,
|
||
IN DRIVER_RECONFIGURE_OPERATION Operation,
|
||
IN PCM_RESOURCE_LIST CmResources
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sends Reconfiguration related requests to device drivers.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Supplies the driver object of the device driver being queried
|
||
or reconfigured.
|
||
|
||
DeviceObject - Supplies the device object of the device being queried or
|
||
reconfigured. If the resources being reconfigured are driver specific,
|
||
this parameter will be NULL.
|
||
|
||
Operation - Specifies the operation requested.
|
||
|
||
ResourceList - Supplies the new resource list for the device/driver.
|
||
This parameter is specified only if Operation is either
|
||
QueryReconfigureResources or ReconfigureResources.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS code.
|
||
|
||
--*/
|
||
{
|
||
PDRIVER_RECONFIGURE_DEVICE reconfigRoutine;
|
||
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
||
|
||
PAGED_CODE();
|
||
|
||
reconfigRoutine = DriverObject->DriverExtension->ReconfigureDevice;
|
||
if (reconfigRoutine != NULL) {
|
||
status = (reconfigRoutine) ( DriverObject,
|
||
DeviceObject,
|
||
Operation,
|
||
CmResources
|
||
);
|
||
}
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IoAddDevice (
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING ServiceKeyName,
|
||
IN OUT PULONG InstanceNumber
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This functions is used by Pnp manager to inform device driver to add a device to
|
||
its device list or is used by Pnp enumerator to give device driver a chance to
|
||
report/detect devices at run time.
|
||
|
||
If run time device detection is desired, the AddDevice entry will be invoked with
|
||
InstanceNumber = PLUG_PLAY_NO_INSTANCE. (For example, bus extender drivers will
|
||
use this interface to report new bus detected at run time.) If the driver
|
||
responses the call with a new device instance, it will be called repeatedly until
|
||
a STATUS_NO_MORE_ENTRIES is returned. For a driver which does not support run time
|
||
detection, it can simply return STATUS_NO_MORE_ENTRIES when its AddDevice entry is
|
||
invoked with InstanceNumber = PLUG_PLAY_NO_INSTANCE.
|
||
|
||
Parameters:
|
||
|
||
DriverObject - Supplies a driver object to receive the add device request.
|
||
|
||
ServiceKeyName - Supplies the name of the subkey in the system service list
|
||
(HKEY_LOCAL_MACHINE\CurrentControlSet\Services) that caused the driver to load.
|
||
|
||
InstanceNumber - Supplies an ordinal value indicating the device instance to be
|
||
added or PLUG_PLAY_NO_INSTANCE to initiate device/bus run time detection.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS code.
|
||
|
||
--*/
|
||
{
|
||
PDRIVER_ADD_DEVICE addDeviceRoutine;
|
||
NTSTATUS status = STATUS_NOT_IMPLEMENTED;
|
||
|
||
PAGED_CODE();
|
||
|
||
addDeviceRoutine = DriverObject->DriverExtension->AddDevice;
|
||
if (addDeviceRoutine != NULL) {
|
||
status = (addDeviceRoutine) ( ServiceKeyName, InstanceNumber );
|
||
}
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IoRemoveDevice (
|
||
IN PDEVICE_OBJECT TargetDevice,
|
||
IN ULONG IrpMinorCode
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sends a requested DeviceRemoval irp to the top level device
|
||
object which roots on TargetDevice. If there is a VPB associated with the
|
||
TargetDevice, the corresponding filesystem's VDO will be used. Otherwise
|
||
the irp will be sent directly to the target device/ or its assocated device
|
||
object.
|
||
|
||
Parameters:
|
||
|
||
TargetDevice - Supplies the device object of the device being removed.
|
||
|
||
Operation - Specifies the operation requested.
|
||
The following IRP codes are used with IRP_MJ_DEVICE_CHANGE for removing
|
||
devices:
|
||
IRP_MN_QUERY_REMOVE_DEVICE
|
||
IRP_MN_CANCEL_REMOVE_DEVICE
|
||
IRP_MN_REMOVE_DEVICE
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS code.
|
||
|
||
--*/
|
||
{
|
||
PDEVICE_OBJECT deviceObject;
|
||
PDEVOBJ_EXTENSION deviceExtension;
|
||
PIRP irp;
|
||
PIO_STACK_LOCATION irpSp;
|
||
DEVICE_CHANGE_COMPLETION_CONTEXT completionContext;
|
||
NTSTATUS status;
|
||
|
||
PAGED_CODE();
|
||
|
||
ASSERT(IrpMinorCode == IRP_MN_QUERY_REMOVE_DEVICE ||
|
||
IrpMinorCode == IRP_MN_CANCEL_REMOVE_DEVICE ||
|
||
IrpMinorCode == IRP_MN_REMOVE_DEVICE);
|
||
|
||
//
|
||
// If the target device object has a VPB associated with it.
|
||
// make the filesystem's volume device object the irp target.
|
||
//
|
||
|
||
if (TargetDevice->Vpb) {
|
||
deviceObject = TargetDevice->Vpb->DeviceObject;
|
||
} else {
|
||
deviceObject = TargetDevice;
|
||
}
|
||
|
||
//
|
||
// Get a pointer to the topmost device object in the stack of devices,
|
||
// beginning with the deviceObject.
|
||
//
|
||
|
||
deviceObject = IoGetAttachedDevice(deviceObject);
|
||
deviceExtension = deviceObject->DeviceObjectExtension;
|
||
|
||
//
|
||
// Allocate an I/O Request Packet (IRP) for this device removal operation.
|
||
//
|
||
|
||
irp = IoAllocateIrp( (CCHAR) (deviceObject->StackSize + 1), FALSE );
|
||
if (!irp) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
//
|
||
// Copy some state into the first stack location
|
||
//
|
||
|
||
irpSp = IoGetNextIrpStackLocation (irp);
|
||
irpSp->Parameters.Others.Argument1 = (PVOID) TargetDevice;
|
||
irpSp->Parameters.Others.Argument2 = (PVOID) IrpMinorCode;
|
||
|
||
//
|
||
// Get a pointer to the next stack location in the packet. This location
|
||
// will be used to pass the function codes and parameters to the first
|
||
// driver.
|
||
//
|
||
|
||
IoSetNextIrpStackLocation (irp);
|
||
irpSp = IoGetNextIrpStackLocation (irp);
|
||
|
||
//
|
||
// Fill in the IRP according to this request.
|
||
//
|
||
|
||
irp->Tail.Overlay.Thread = PsGetCurrentThread();
|
||
irp->RequestorMode = KernelMode;
|
||
irp->UserIosb = NULL;
|
||
irp->UserEvent = NULL;
|
||
irpSp->MajorFunction = IRP_MJ_DEVICE_CHANGE;
|
||
irpSp->MinorFunction = (UCHAR)IrpMinorCode;
|
||
irpSp->Parameters.RemoveDevice.DeviceToRemove = TargetDevice;
|
||
|
||
KeInitializeEvent( &completionContext.Event, SynchronizationEvent, FALSE );
|
||
IoSetCompletionRoutine(irp,
|
||
IopDeviceRemovalComplete,
|
||
&completionContext, /* Completion context */
|
||
TRUE, /* Invoke on success */
|
||
TRUE, /* Invoke on error */
|
||
TRUE /* Invoke on cancel */
|
||
);
|
||
|
||
//
|
||
// Hold the device object's Device Queue and Send the request packet to the
|
||
// appropriate driver...
|
||
//
|
||
|
||
IoHoldDeviceQueue(deviceObject, irp);
|
||
status = IoCallDriver( deviceObject, irp );
|
||
if (status == STATUS_PENDING) {
|
||
(VOID) KeWaitForSingleObject( &completionContext.Event,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
(PLARGE_INTEGER) NULL );
|
||
}
|
||
return completionContext.IoStatus.Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
IopDeviceRemovalComplete (
|
||
IN PDEVICE_OBJECT DeviceObject,
|
||
IN PIRP Irp,
|
||
IN PVOID Context
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Completion function for a DeviceRemoval IRP. The device objects'
|
||
StartIoHoldingQueue will be released if no other queue holding irp
|
||
pending.
|
||
|
||
Arguments:
|
||
|
||
DeviceObject - NULL.
|
||
Irp - SetPower irp which has completed
|
||
Context - a pointer to the DEVICE_CHANGE_COMPLETION_CONTEXT.
|
||
|
||
Return Value:
|
||
|
||
STATUS_MORE_PROCESSING_REQUIRED is returned to IoCompleteRequest
|
||
to signify that IoCompleteRequest should not continue processing
|
||
the IRP.
|
||
|
||
--*/
|
||
{
|
||
PIO_STACK_LOCATION irpSp;
|
||
PDEVOBJ_EXTENSION deviceObjectExt;
|
||
PDEVICE_OBJECT deviceObject;
|
||
ULONG irpCode;
|
||
|
||
//
|
||
// Read state from Irp.
|
||
//
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation (Irp);
|
||
deviceObject = irpSp->DeviceObject;
|
||
irpCode = (ULONG)irpSp->Parameters.Others.Argument2;
|
||
|
||
if ((irpCode == IRP_MN_QUERY_REMOVE_DEVICE && !NT_SUCCESS (Irp->IoStatus.Status)) ||
|
||
irpCode != IRP_MN_REMOVE_DEVICE) {
|
||
|
||
//
|
||
// Release any irps which were postponded from IoStartPacket if
|
||
// it is NOT a device removal irp and if a driver returned failure to query.
|
||
//
|
||
|
||
IoReleaseStartIoHoldingQueue(deviceObject);
|
||
}
|
||
|
||
//
|
||
// Irp processing is complete, free the irp and then return
|
||
// more_processing_requered which causes IoCompleteRequest to
|
||
// stop "completing" this irp any future.
|
||
//
|
||
|
||
IoFreeIrp (Irp);
|
||
return STATUS_MORE_PROCESSING_REQUIRED;
|
||
}
|
||
#endif // _PNP_POWER_
|