📄 pnp.c
字号:
// without first receiving a query-remove. This could happen if
// someone above us fails a query-remove and passes down the
// subsequent cancel-remove.
//
if(RemovePending == DeviceData->DevicePnPState)
{
//
// We did receive a query-remove, so restore.
//
RESTORE_PREVIOUS_PNP_STATE(DeviceData);
}
Irp->IoStatus.Status = STATUS_SUCCESS;// You must not fail the IRP.
break;
case IRP_MN_SURPRISE_REMOVAL:
//
// The device has been unexpectedly removed from the machine
// and is no longer available for I/O. Bus_RemoveFdo clears
// all the resources, frees the interface and de-registers
// with WMI, but it doesn't delete the FDO. That's done
// later in Remove device query.
//
SET_NEW_PNP_STATE(DeviceData, SurpriseRemovePending);
Bus_RemoveFdo(DeviceData);
ExAcquireFastMutex (&DeviceData->Mutex);
listHead = &DeviceData->ListOfPDOs;
for(entry = listHead->Flink,nextEntry = entry->Flink;
entry != listHead;
entry = nextEntry,nextEntry = entry->Flink) {
pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
RemoveEntryList (&pdoData->Link);
InitializeListHead (&pdoData->Link);
pdoData->ParentFdo = NULL;
pdoData->ReportedMissing = TRUE;
}
ExReleaseFastMutex (&DeviceData->Mutex);
Irp->IoStatus.Status = STATUS_SUCCESS; // You must not fail the IRP.
break;
case IRP_MN_REMOVE_DEVICE:
//
// The Plug & Play system has dictated the removal of this device.
// We have no choice but to detach and delete the device object.
//
//
// Check the state flag to see whether you are surprise removed
//
if(DeviceData->DevicePnPState != SurpriseRemovePending)
{
Bus_RemoveFdo(DeviceData);
}
SET_NEW_PNP_STATE(DeviceData, Deleted);
//
// Wait for all outstanding requests to complete.
// We need two decrements here, one for the increment in
// the beginning of this function, the other for the 1-biased value of
// OutstandingIO.
//
Bus_DecIoCount (DeviceData);
//
// The requestCount is at least one here (is 1-biased)
//
Bus_DecIoCount (DeviceData);
KeWaitForSingleObject (
&DeviceData->RemoveEvent,
Executive,
KernelMode,
FALSE,
NULL);
//
// Typically the system removes all the children before
// removing the parent FDO. If for any reason child Pdos are
// still present we will destroy them explicitly, with one exception -
// we will not delete the PDOs that are in SurpriseRemovePending state.
//
ExAcquireFastMutex (&DeviceData->Mutex);
listHead = &DeviceData->ListOfPDOs;
for(entry = listHead->Flink,nextEntry = entry->Flink;
entry != listHead;
entry = nextEntry,nextEntry = entry->Flink) {
pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
RemoveEntryList (&pdoData->Link);
if(SurpriseRemovePending == pdoData->DevicePnPState)
{
//
// We will reinitialize the list head so that we
// wouldn't barf when we try to delink this PDO from
// the parent's PDOs list, when the system finally
// removes the PDO. Let's also not forget to set the
// ReportedMissing flag to cause the deletion of the PDO.
//
Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO,
("\tFound a surprise removed device: 0x%x\n", pdoData->Self));
InitializeListHead (&pdoData->Link);
pdoData->ParentFdo = NULL;
pdoData->ReportedMissing = TRUE;
continue;
}
DeviceData->NumPDOs--;
Bus_DestroyPdo (pdoData->Self, pdoData);
}
ExReleaseFastMutex (&DeviceData->Mutex);
//
// 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;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (DeviceData->NextLowerDriver, Irp);
//
// Detach from the underlying devices.
//
IoDetachDevice (DeviceData->NextLowerDriver);
Bus_KdPrint_Cont(DeviceData, BUS_DBG_PNP_INFO,
("\tDeleting FDO: 0x%x\n", DeviceObject));
IoDeleteDevice (DeviceObject);
return status;
case IRP_MN_QUERY_DEVICE_RELATIONS:
Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE,
("\tQueryDeviceRelation Type: %s\n",
DbgDeviceRelationString(\
IrpStack->Parameters.QueryDeviceRelations.Type)));
if (BusRelations != IrpStack->Parameters.QueryDeviceRelations.Type) {
//
// We don't support any other Device Relations
//
break;
}
//
// Tell the plug and play system about all the PDOs.
//
// There might also be device relations below and above this FDO,
// so, be sure to propagate the relations from the upper drivers.
//
// No Completion routine is needed so long as the status is preset
// to success. (PDOs complete plug and play irps with the current
// IoStatus.Status and IoStatus.Information as the default.)
//
ExAcquireFastMutex (&DeviceData->Mutex);
oldRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
if (oldRelations) {
prevcount = oldRelations->Count;
if (!DeviceData->NumPDOs) {
//
// There is a device relations struct already present and we have
// nothing to add to it, so just call IoSkip and IoCall
//
ExReleaseFastMutex (&DeviceData->Mutex);
break;
}
}
else {
prevcount = 0;
}
//
// Calculate the number of PDOs actually present on the bus
//
numPdosPresent = 0;
for (entry = DeviceData->ListOfPDOs.Flink;
entry != &DeviceData->ListOfPDOs;
entry = entry->Flink) {
pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
if(pdoData->Present)
numPdosPresent++;
}
//
// Need to allocate a new relations structure and add our
// PDOs to it.
//
length = sizeof(DEVICE_RELATIONS) +
((numPdosPresent + prevcount) * sizeof (PDEVICE_OBJECT)) -1;
relations = (PDEVICE_RELATIONS) ExAllocatePoolWithTag (PagedPool,
length, BUSENUM_POOL_TAG);
if (NULL == relations) {
//
// Fail the IRP
//
ExReleaseFastMutex (&DeviceData->Mutex);
Irp->IoStatus.Status = status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
Bus_DecIoCount (DeviceData);
return status;
}
//
// Copy in the device objects so far
//
if (prevcount) {
RtlCopyMemory (relations->Objects, oldRelations->Objects,
prevcount * sizeof (PDEVICE_OBJECT));
}
relations->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.
// The Plug & Play system will dereference the object when it is done
// with it and free the device relations buffer.
//
for (entry = DeviceData->ListOfPDOs.Flink;
entry != &DeviceData->ListOfPDOs;
entry = entry->Flink) {
pdoData = CONTAINING_RECORD (entry, PDO_DEVICE_DATA, Link);
if(pdoData->Present) {
relations->Objects[prevcount] = pdoData->Self;
ObReferenceObject (pdoData->Self);
prevcount++;
} else {
pdoData->ReportedMissing = TRUE;
}
}
Bus_KdPrint_Cont (DeviceData, BUS_DBG_PNP_TRACE,
("\t#PDOS present = %d\n\t#PDOs reported = %d\n",
DeviceData->NumPDOs, relations->Count));
//
// Replace the relations structure in the IRP with the new
// one.
//
if (oldRelations) {
ExFreePool (oldRelations);
}
Irp->IoStatus.Information = (ULONG_PTR) relations;
ExReleaseFastMutex (&DeviceData->Mutex);
//
// Set up and pass the IRP further down the stack
//
Irp->IoStatus.Status = STATUS_SUCCESS;
break;
default:
//
// In the default case we merely call the next driver.
// We must not modify Irp->IoStatus.Status or complete the IRP.
//
break;
}
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (DeviceData->NextLowerDriver, Irp);
Bus_DecIoCount (DeviceData);
return status;
}
NTSTATUS
Bus_StartFdo (
IN PFDO_DEVICE_DATA FdoData,
IN PIRP Irp )
/*++
Routine Description:
Initialize and start the bus controller. Get the resources
by parsing the list and map them if required.
Arguments:
DeviceData - Pointer to the FDO's device extension.
Irp - Pointer to the irp.
Return Value:
NT Status is returned.
--*/
{
NTSTATUS status;
PAGED_CODE ();
//
// Check the function driver source to learn
// about parsing resource list.
//
//
// Enable device interface. If the return status is
// STATUS_OBJECT_NAME_EXISTS means we are enabling the interface
// that was already enabled, which could happen if the device
// is stopped and restarted for resource rebalancing.
//
status = IoSetDeviceInterfaceState(&FdoData->InterfaceName, TRUE);
if (!NT_SUCCESS (status)) {
Bus_KdPrint (FdoData, BUS_DBG_PNP_TRACE,
("IoSetDeviceInterfaceState failed: 0x%x\n", status));
}
//
// Set the device power state to fully on. Also if this Start
// is due to resource rebalance, you should restore the device
// to the state it was before you stopped the device and relinquished
// resources.
//
FdoData->DevicePowerState = PowerDeviceD0;
SET_NEW_PNP_STATE(FdoData, Started);
return status;
}
void
Bus_RemoveFdo (
IN PFDO_DEVICE_DATA FdoData
)
/*++
Routine Description:
Frees any memory allocated by the FDO and unmap any IO mapped as well.
This function does not the delete the deviceobject.
Arguments:
DeviceData - Pointer to the FDO's device extension.
Return Value:
NT Status is returned.
--*/
{
PAGED_CODE ();
//
// Stop all access to the device, fail any outstanding I/O to the device,
// and free all the resources associated with the device.
//
//
// Disable the device interface and free the buffer
//
if (FdoData->InterfaceName.Buffer != NULL) {
IoSetDeviceInterfaceState (&FdoData->InterfaceName, FALSE);
ExFreePool (FdoData->InterfaceName.Buffer);
RtlZeroMemory (&FdoData->InterfaceName,
sizeof (UNICODE_STRING));
}
//
// Inform WMI to remove this DeviceObject from its
// list of providers.
//
Bus_WmiDeRegistration(FdoData);
}
NTSTATUS
Bus_SendIrpSynchronously (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
Sends the Irp down to lower driver and waits for it to
come back by setting a completion routine.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Return Value:
NT Status is returned.
--*/
{
KEVENT event;
NTSTATUS status;
PAGED_CODE();
KeInitializeEvent(&event, NotificationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
IoSetCompletionRoutine(Irp,
Bus_CompletionRoutine,
&event,
TRUE,
TRUE,
TRUE
);
status = IoCallDriver(DeviceObject, Irp);
//
// Wait for lower drivers to be done with the Irp.
// Important thing to note here is when you allocate
// the memory for an event in the stack you must do a
// KernelMode wait instead of UserMode to prevent
// the stack from getting paged out.
//
if (status == STATUS_PENDING) {
KeWaitForSingleObject(&event,
Executive,
KernelMode,
FALSE,
NULL
);
status = Irp->IoStatus.Status;
}
return status;
}
NTSTATUS
Bus_CompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
A completion routine for use when calling the lower device objects to
which our bus (FDO) is attached.
Arguments:
DeviceObject - Pointer to deviceobject
Irp - Pointer to a PnP Irp.
Context - Pointer to an event object
Return Value:
NT Status is returned.
--*/
{
UNREFERENCED_PARAMETER (DeviceObject);
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED; // Keep this IRP
}
NTSTATUS
Bus_DestroyPdo (
PDEVICE_OBJECT Device,
PPDO_DEVICE_DATA PdoData
)
/*++
Routine Description:
The Plug & Play subsystem has instructed that this PDO should be removed.
We should therefore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -