📄 sspnp.c
字号:
//
// need 2 decrements
//
SSDbgPrint(3, ("HandleRemoveDevice::"));
requestCount = SSIoDecrement(deviceExtension);
ASSERT(requestCount > 0);
SSDbgPrint(3, ("HandleRemoveDevice::"));
requestCount = SSIoDecrement(deviceExtension);
KeWaitForSingleObject(&deviceExtension->RemoveEvent,
Executive,
KernelMode,
FALSE,
NULL);
ReleaseMemory(DeviceObject);
//
// We need to send the remove down the stack before we detach,
// but we don't need to wait for the completion of this operation
// (and to register a completion routine).
//
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoSkipCurrentIrpStackLocation(Irp);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
//
// Detach the FDO from the device stack
//
IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
IoDeleteDevice(DeviceObject);
SSDbgPrint(3, ("HandleRemoveDevice - ends\n"));
return ntStatus;
}
NTSTATUS
HandleQueryCapabilities(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine services Irp of minor type IRP_MN_QUERY_CAPABILITIES
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet sent by the pnp manager.
Return Value:
NT status value
--*/
{
ULONG i;
KEVENT event;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PDEVICE_CAPABILITIES pdc;
PIO_STACK_LOCATION irpStack;
SSDbgPrint(3, ("HandleQueryCapabilities - begins\n"));
//
// initialize variables
//
irpStack = IoGetCurrentIrpStackLocation(Irp);
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
pdc = irpStack->Parameters.DeviceCapabilities.Capabilities;
//
// We will provide here an example of an IRP that is processed
// both on its way down and on its way up: there might be no need for
// a function driver process this Irp (the bus driver will do that).
// The driver will wait for the lower drivers (the bus driver among
// them) to process this IRP, then it processes it again.
//
if(pdc->Version < 1 || pdc->Size < sizeof(DEVICE_CAPABILITIES)) {
SSDbgPrint(1, ("HandleQueryCapabilities::request failed\n"));
ntStatus = STATUS_UNSUCCESSFUL;
return ntStatus;
}
//
// Set some values in deviceCapabilities here...
//
//.............................................
//
//
// Prepare to pass the IRP down
//
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
(PIO_COMPLETION_ROUTINE)IrpCompletionRoutine,
(PVOID)&event,
TRUE,
TRUE,
TRUE);
ntStatus = IoCallDriver(deviceExtension->TopOfStackDeviceObject, Irp);
if(ntStatus == STATUS_PENDING) {
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL);
ntStatus = Irp->IoStatus.Status;
}
//
// initialize PowerDownLevel to disabled
//
deviceExtension->PowerDownLevel = PowerDeviceUnspecified;
//
// Lower drivers have finished their operation, so now
// we can finish ours.
//
if(NT_SUCCESS(ntStatus)) {
deviceExtension->DeviceCapabilities = *pdc;
for(i = PowerSystemSleeping1; i <= PowerSystemSleeping3; i++) {
if(deviceExtension->DeviceCapabilities.DeviceState[i] <
PowerDeviceD3) {
deviceExtension->PowerDownLevel =
deviceExtension->DeviceCapabilities.DeviceState[i];
}
}
//
// since its safe to surprise-remove this device, we shall
// set the SurpriseRemoveOK flag to supress any dialog to
// user.
//
pdc->SurpriseRemovalOK = 1;
}
if(deviceExtension->PowerDownLevel == PowerDeviceUnspecified ||
deviceExtension->PowerDownLevel <= PowerDeviceD0) {
deviceExtension->PowerDownLevel = PowerDeviceD2;
}
SSDbgPrint(3, ("HandleQueryCapabilities - ends\n"));
return ntStatus;
}
VOID
DpcRoutine(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2
)
/*++
Routine Description:
DPC routine triggered by the timer to check the idle state
of the device and submit an idle request for the device.
Arguments:
DeferredContext - context for the dpc routine.
DeviceObject in our case.
Return Value:
None
--*/
{
NTSTATUS ntStatus;
PDEVICE_OBJECT deviceObject;
PDEVICE_EXTENSION deviceExtension;
PIO_WORKITEM item;
deviceObject = (PDEVICE_OBJECT)DeferredContext;
deviceExtension = (PDEVICE_EXTENSION)deviceObject->DeviceExtension;
SSDbgPrint(3, ("DpcRoutine - begins\n"));
//
// Clear this event since a DPC has been fired!
//
KeClearEvent(&deviceExtension->NoDpcWorkItemPendingEvent);
if(CanDeviceSuspend(deviceExtension)) {
SSDbgPrint(3, ("Device is Idle\n"));
item = IoAllocateWorkItem(deviceObject);
if(item) {
IoQueueWorkItem(item,
IdleRequestWorkerRoutine,
DelayedWorkQueue,
item);
ntStatus = STATUS_PENDING;
}
else {
SSDbgPrint(3, ("Cannot alloc memory for work item\n"));
ntStatus = STATUS_INSUFFICIENT_RESOURCES;
//
// signal the NoDpcWorkItemPendingEvent.
//
KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
IO_NO_INCREMENT,
FALSE);
}
}
else {
SSDbgPrint(3, ("Idle event not signaled\n"));
//
// signal the NoDpcWorkItemPendingEvent.
//
KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
IO_NO_INCREMENT,
FALSE);
}
SSDbgPrint(3, ("DpcRoutine - ends\n"));
}
VOID
IdleRequestWorkerRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Context
)
/*++
Routine Description:
This is the work item fired from the DPC.
This workitem checks the idle state of the device
and submits an idle request.
Arguments:
DeviceObject - pointer to device object
Context - context for the work item.
Return Value:
None
--*/
{
PIRP irp;
NTSTATUS ntStatus;
PDEVICE_EXTENSION deviceExtension;
PIO_WORKITEM workItem;
SSDbgPrint(3, ("IdleRequestWorkerRoutine - begins\n"));
//
// initialize variables
//
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
workItem = (PIO_WORKITEM) Context;
if(CanDeviceSuspend(deviceExtension)) {
SSDbgPrint(3, ("Device is idle\n"));
ntStatus = SubmitIdleRequestIrp(deviceExtension);
if(!NT_SUCCESS(ntStatus)) {
SSDbgPrint(1, ("SubmitIdleRequestIrp failed\n"));
}
}
else {
SSDbgPrint(3, ("Device is not idle\n"));
}
IoFreeWorkItem(workItem);
//
// signal the NoDpcWorkItemPendingEvent.
//
KeSetEvent(&deviceExtension->NoDpcWorkItemPendingEvent,
IO_NO_INCREMENT,
FALSE);
SSDbgPrint(3, ("IdleRequestsWorkerRoutine - ends\n"));
}
VOID
ProcessQueuedRequests(
IN OUT PDEVICE_EXTENSION DeviceExtension
)
/*++
Routine Description:
Remove and process the entries in the queue. If this routine is called
when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
are complete with STATUS_DELETE_PENDING
Arguments:
DeviceExtension - pointer to device extension
Return Value:
None
--*/
{
KIRQL oldIrql;
PIRP nextIrp,
cancelledIrp;
PVOID cancelRoutine;
LIST_ENTRY cancelledIrpList;
PLIST_ENTRY listEntry;
SSDbgPrint(3, ("ProcessQueuedRequests - begins\n"));
//
// initialize variables
//
cancelRoutine = NULL;
InitializeListHead(&cancelledIrpList);
//
// 1. dequeue the entries in the queue
// 2. reset the cancel routine
// 3. process them
// 3a. if the device is active, send them down
// 3b. else complete with STATUS_DELETE_PENDING
//
while(1) {
KeAcquireSpinLock(&DeviceExtension->QueueLock, &oldIrql);
if(IsListEmpty(&DeviceExtension->NewRequestsQueue)) {
KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
break;
}
//
// Remove a request from the queue
//
listEntry = RemoveHeadList(&DeviceExtension->NewRequestsQueue);
nextIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
//
// set the cancel routine to NULL
//
cancelRoutine = IoSetCancelRoutine(nextIrp, NULL);
//
// check if its already cancelled
//
if(nextIrp->Cancel) {
if(cancelRoutine) {
//
// the cancel routine for this IRP hasnt been called yet
// so queue the IRP in the cancelledIrp list and complete
// after releasing the lock
//
InsertTailList(&cancelledIrpList, listEntry);
}
else {
//
// the cancel routine has run
// it must be waiting to hold the queue lock
// so initialize the IRPs listEntry
//
InitializeListHead(listEntry);
}
KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
}
else {
KeReleaseSpinLock(&DeviceExtension->QueueLock, oldIrql);
if(FailRequests == DeviceExtension->QueueState) {
nextIrp->IoStatus.Information = 0;
nextIrp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest(nextIrp, IO_NO_INCREMENT);
}
else {
PIO_STACK_LOCATION irpStack;
SSDbgPrint(3, ("ProcessQueuedRequests::"));
SSIoIncrement(DeviceExtension);
IoSkipCurrentIrpStackLocation(nextIrp);
IoCallDriver(DeviceExtension->TopOfStackDeviceObject, nextIrp);
SSDbgPrint(3, ("ProcessQueuedRequests::"));
SSIoDecrement(DeviceExtension);
}
}
} // while loop
//
// walk through the cancelledIrp list and cancel them
//
while(!IsListEmpty(&cancelledIrpList)) {
PLIST_ENTRY listEntry = RemoveHeadList(&cancelledIrpList);
cancelledIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
cancelledIrp->IoStatus.Status = STATUS_CANCELLED;
cancelledIrp->IoStatus.Information = 0;
IoCompleteRequest(cancelledIrp, IO_NO_INCREMENT);
}
SSDbgPrint(3, ("ProcessQueuedRequests - ends\n"));
return;
}
NTSTATUS
SS_DispatchClean(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Dispatch routine for IRP_MJ_CLEANUP
Arguments:
DeviceObject - pointer to device object
Irp - I/O request packet sent by the pnp manager
Return Value:
NT status value
--*/
{
PDEVICE_EXTENSION deviceExtension;
KIRQL oldIrql;
LIST_ENTRY cleanupList;
PLIST_ENTRY thisEntry,
nextEntry,
listHead;
PIRP pendingIrp;
PIO_STACK_LOCATION pendingIrpStack,
irpStack;
NTSTATUS ntStatus;
//
// initialize variables
//
deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
irpStack = IoGetCurrentIrpStackLocation(Irp);
InitializeListHead(&cleanupList);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -