1609 lines
50 KiB
C
1609 lines
50 KiB
C
/*++
|
|
|
|
Copyright (c) 1990-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pdopnp.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the PNP IRP dispatch code for PDOs
|
|
|
|
Environment:
|
|
|
|
Kernel Mode Driver.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "busp.h"
|
|
#include "pnpisa.h"
|
|
#include <wdmguid.h>
|
|
#include "halpnpp.h"
|
|
|
|
#if ISOLATE_CARDS
|
|
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
|
|
BOOLEAN PipFailStartPdo = FALSE;
|
|
BOOLEAN PipFailStartRdp = FALSE;
|
|
|
|
NTSTATUS
|
|
PiStartPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryRemoveStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp );
|
|
|
|
NTSTATUS
|
|
PiCancelRemoveStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp );
|
|
|
|
NTSTATUS
|
|
PiStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceRelationsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryCapabilitiesPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceTextPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiFilterResourceRequirementsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryIdPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryResourcesPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryResourceRequirementsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiRemovePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryBusInformationPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryInterfacePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiDeviceUsageNotificationPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiSurpriseRemovePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PiIrpNotSupported(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
NTSTATUS
|
|
PipBuildRDPResources(
|
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources,
|
|
IN ULONG Flags
|
|
);
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceState(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,PiDispatchPnpPdo)
|
|
#pragma alloc_text(PAGE,PiStartPdo)
|
|
#pragma alloc_text(PAGE,PiQueryRemoveStopPdo)
|
|
#pragma alloc_text(PAGE,PiRemovePdo)
|
|
#pragma alloc_text(PAGE,PiCancelRemoveStopPdo)
|
|
#pragma alloc_text(PAGE,PiStopPdo)
|
|
#pragma alloc_text(PAGE,PiQueryDeviceRelationsPdo)
|
|
#pragma alloc_text(PAGE,PiQueryInterfacePdo)
|
|
#pragma alloc_text(PAGE,PiQueryCapabilitiesPdo)
|
|
#pragma alloc_text(PAGE,PiQueryResourcesPdo)
|
|
#pragma alloc_text(PAGE,PiQueryResourceRequirementsPdo)
|
|
#pragma alloc_text(PAGE,PiQueryDeviceTextPdo)
|
|
#pragma alloc_text(PAGE,PiFilterResourceRequirementsPdo)
|
|
#pragma alloc_text(PAGE,PiSurpriseRemovePdo)
|
|
#pragma alloc_text(PAGE,PiIrpNotSupported)
|
|
#pragma alloc_text(PAGE,PiQueryIdPdo)
|
|
#pragma alloc_text(PAGE,PiQueryBusInformationPdo)
|
|
#pragma alloc_text(PAGE,PiDeviceUsageNotificationPdo)
|
|
#pragma alloc_text(PAGE,PipBuildRDPResources)
|
|
#pragma alloc_text(PAGE,PiQueryDeviceState)
|
|
#endif
|
|
|
|
|
|
//
|
|
// PNP IRP Dispatch table for PDOs - This should be updated if new IRPs are added
|
|
//
|
|
|
|
PPI_DISPATCH PiPnpDispatchTablePdo[] = {
|
|
PiStartPdo, // IRP_MN_START_DEVICE
|
|
PiQueryRemoveStopPdo, // IRP_MN_QUERY_REMOVE_DEVICE
|
|
PiRemovePdo, // IRP_MN_REMOVE_DEVICE
|
|
PiCancelRemoveStopPdo, // IRP_MN_CANCEL_REMOVE_DEVICE
|
|
PiStopPdo, // IRP_MN_STOP_DEVICE
|
|
PiQueryRemoveStopPdo, // IRP_MN_QUERY_STOP_DEVICE
|
|
PiCancelRemoveStopPdo, // IRP_MN_CANCEL_STOP_DEVICE
|
|
PiQueryDeviceRelationsPdo, // IRP_MN_QUERY_DEVICE_RELATIONS
|
|
PiQueryInterfacePdo, // IRP_MN_QUERY_INTERFACE
|
|
PiQueryCapabilitiesPdo, // IRP_MN_QUERY_CAPABILITIES
|
|
PiQueryResourcesPdo, // IRP_MN_QUERY_RESOURCES
|
|
PiQueryResourceRequirementsPdo, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
PiQueryDeviceTextPdo, // IRP_MN_QUERY_DEVICE_TEXT
|
|
PiFilterResourceRequirementsPdo, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
PiIrpNotSupported, // Unused
|
|
PiIrpNotSupported, // IRP_MN_READ_CONFIG
|
|
PiIrpNotSupported, // IRP_MN_WRITE_CONFIG
|
|
PiIrpNotSupported, // IRP_MN_EJECT
|
|
PiIrpNotSupported, // IRP_MN_SET_LOCK
|
|
PiQueryIdPdo, // IRP_MN_QUERY_ID
|
|
PiQueryDeviceState, // IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
PiQueryBusInformationPdo, // IRP_MN_QUERY_BUS_INFORMATION
|
|
PiDeviceUsageNotificationPdo, // IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
PiSurpriseRemovePdo, // IRP_MN_SURPRISE_REMOVAL
|
|
PiIrpNotSupported // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
};
|
|
|
|
|
|
NTSTATUS
|
|
PiDispatchPnpPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles IRP_MJ_PNP IRPs for PDOs.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the PDO for which this IRP applies.
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
PVOID information = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get a pointer to our stack location and take appropriate action based
|
|
// on the minor function.
|
|
//
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (irpSp->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
} else {
|
|
|
|
status = PiPnpDispatchTablePdo[irpSp->MinorFunction](DeviceObject, Irp);
|
|
|
|
if ( status != STATUS_NOT_SUPPORTED ) {
|
|
|
|
//
|
|
// We understood this IRP and handled it so we need to set status before completing
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
} else {
|
|
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
}
|
|
|
|
information = (PVOID)Irp->IoStatus.Information;
|
|
|
|
ASSERT(status == Irp->IoStatus.Status);
|
|
|
|
PipCompleteRequest(Irp, status, information);
|
|
return status;
|
|
|
|
|
|
} //PipDispatchPnpPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiStartPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
PCM_RESOURCE_LIST cmResources;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
UNICODE_STRING unicodeString;
|
|
ULONG length;
|
|
POWER_STATE newPowerState;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
|
|
cmResources = irpSp->Parameters.StartDevice.AllocatedResources;
|
|
|
|
if (PipDebugMask & DEBUG_PNP) {
|
|
PipDumpCmResourceList(cmResources);
|
|
} else if (!cmResources) {
|
|
DbgPrint("StartDevice irp with empty CmResourceList\n");
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP,
|
|
"*** StartDevice irp received PDO: %x\n",DeviceObject));
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, TRUE)) {
|
|
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
ULONG curSize,newSize;
|
|
//
|
|
if (PipFailStartRdp) {
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
// Read data port is special
|
|
//
|
|
newSize=PipDetermineResourceListSize(cmResources);
|
|
curSize=PipDetermineResourceListSize(deviceInfo->AllocatedResources);
|
|
|
|
//
|
|
// Check if we've been removed, or moved (the +3 is the bit mask for the RDP , we claim 4-7, need xxxi7)
|
|
//
|
|
if ( (deviceInfo->Flags & DF_REMOVED) ||
|
|
!(deviceInfo->Flags & DF_STOPPED) ||
|
|
(curSize != newSize) ||
|
|
(newSize != RtlCompareMemory (deviceInfo->AllocatedResources,cmResources,newSize))) {
|
|
|
|
|
|
//
|
|
// This will release the unused resources
|
|
//
|
|
status = PipStartReadDataPort (deviceInfo,deviceInfo->ParentDeviceExtension,DeviceObject,cmResources);
|
|
if (NT_SUCCESS(status) || status == STATUS_NO_SUCH_DEVICE) {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Invalidate the device relations
|
|
//
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
IoInvalidateDeviceRelations (
|
|
deviceInfo->ParentDeviceExtension->PhysicalBusDevice,BusRelations);
|
|
}
|
|
deviceInfo->Flags &= ~(DF_STOPPED|DF_REMOVED|DF_SURPRISE_REMOVED);
|
|
} else {
|
|
deviceInfo->Flags &= ~DF_STOPPED;
|
|
IoInvalidateDeviceRelations (
|
|
deviceInfo->ParentDeviceExtension->PhysicalBusDevice,BusRelations);
|
|
status=STATUS_SUCCESS;
|
|
}
|
|
deviceInfo->Flags |= DF_ACTIVATED;
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
|
|
DebugPrint((DEBUG_PNP, "StartDevice(RDP) returning: %x\n",status));
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
if (PipFailStartPdo) {
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
// Do this first, so that we allow for no-resource devices in the ref count.
|
|
// (when we activate the RDP it won't have resources, yet)
|
|
//
|
|
|
|
// ASSERT (!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED)));
|
|
if (PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED)) {
|
|
//
|
|
// If the RDP isn't running, fail the start.
|
|
//
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (cmResources) {
|
|
deviceInfo->AllocatedResources = ExAllocatePool(
|
|
NonPagedPool,
|
|
PipDetermineResourceListSize(cmResources));
|
|
if (deviceInfo->AllocatedResources) {
|
|
RtlMoveMemory(deviceInfo->AllocatedResources,
|
|
cmResources,
|
|
length = PipDetermineResourceListSize(cmResources));
|
|
deviceInfo->Flags &= ~(DF_REMOVED|DF_STOPPED);
|
|
status = PipSetDeviceResources (deviceInfo, cmResources);
|
|
if (NT_SUCCESS(status)) {
|
|
|
|
PipActivateDevice();
|
|
|
|
DebugPrint((DEBUG_STATE,
|
|
"Starting CSN %d/LDN %d\n",
|
|
deviceInfo->CardInformation->CardSelectNumber,
|
|
deviceInfo->LogicalDeviceNumber));
|
|
|
|
deviceInfo->Flags |= DF_ACTIVATED;
|
|
newPowerState.DeviceState =
|
|
deviceInfo->DevicePowerState = PowerDeviceD0;
|
|
PoSetPowerState(DeviceObject,
|
|
DevicePowerState,
|
|
newPowerState);
|
|
deviceInfo->DevicePowerState = PowerDeviceD0;
|
|
|
|
if (deviceInfo->LogConfHandle) {
|
|
RtlInitUnicodeString(&unicodeString, L"AllocConfig");
|
|
ZwSetValueKey(deviceInfo->LogConfHandle,
|
|
&unicodeString,
|
|
0,
|
|
REG_RESOURCE_LIST,
|
|
cmResources,
|
|
length
|
|
);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
status = STATUS_NO_MEMORY;
|
|
}
|
|
} else if (deviceInfo->ResourceRequirements) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "StartDevice returning: %x\n",status));
|
|
return status;
|
|
|
|
} // PiStartPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryRemoveStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DebugPrint((DEBUG_PNP,
|
|
"*** Query%s irp received PDO: %x\n",
|
|
(irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? "Stop" : "Remove",
|
|
DeviceObject));
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
|
|
if (deviceInfo->Paging || deviceInfo->CrashDump) {
|
|
status = STATUS_DEVICE_BUSY;
|
|
} else if ( deviceInfo->Flags & DF_READ_DATA_PORT ) {
|
|
if (irpSp->MinorFunction != IRP_MN_QUERY_STOP_DEVICE) {
|
|
status = STATUS_SUCCESS;
|
|
} else if (deviceInfo->Flags & DF_PROCESSING_RDP) {
|
|
//
|
|
// If we're in the middle of the two part RDP start process,
|
|
// flag this as a device that needs to be requeried for
|
|
// resource requirements.
|
|
//
|
|
status = STATUS_RESOURCE_REQUIREMENTS_CHANGED;
|
|
} else {
|
|
|
|
PSINGLE_LIST_ENTRY deviceLink;
|
|
PDEVICE_INFORMATION childDeviceInfo;
|
|
PPI_BUS_EXTENSION busExtension = deviceInfo->ParentDeviceExtension;
|
|
//
|
|
// If trying to stop the RDP, then if any children fail it.
|
|
//
|
|
PipLockDeviceDatabase();
|
|
|
|
status = STATUS_SUCCESS;
|
|
deviceLink = busExtension->DeviceList.Next;
|
|
while (deviceLink) {
|
|
childDeviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|
|
|
if (!(childDeviceInfo->Flags & DF_READ_DATA_PORT) &&
|
|
((childDeviceInfo->Flags & DF_ENUMERATED) ||
|
|
!(childDeviceInfo->Flags & DF_REMOVED))) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
break;
|
|
}
|
|
deviceLink = childDeviceInfo->DeviceList.Next;
|
|
}
|
|
|
|
PipUnlockDeviceDatabase();
|
|
}
|
|
|
|
} else {
|
|
|
|
if ((irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) &&
|
|
!(deviceInfo->Flags & DF_ENUMERATED)) {
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
} else {
|
|
|
|
ASSERT(!(PipRDPNode->Flags & (DF_STOPPED|DF_REMOVED)));
|
|
if ((irpSp->MinorFunction == IRP_MN_QUERY_REMOVE_DEVICE) &&
|
|
(deviceInfo->CardInformation->CardFlags & CF_ISOLATION_BROKEN)) {
|
|
DebugPrint((DEBUG_ERROR, "Failed query remove due to broken isolatee\n"));
|
|
status = STATUS_UNSUCCESSFUL;
|
|
} else {
|
|
deviceInfo->Flags |= DF_QUERY_STOPPED;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
}
|
|
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "Query%s Device returning: %x\n",
|
|
(irpSp->MinorFunction == IRP_MN_QUERY_STOP_DEVICE) ? "Stop" : "Remove",
|
|
status));
|
|
|
|
return status;
|
|
|
|
} // PiQueryRemoveStopPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiCancelRemoveStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DebugPrint((DEBUG_PNP,
|
|
"*** Cancel%s irp received PDO: %x\n",
|
|
(irpSp->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) ? "Stop" : "Remove",
|
|
DeviceObject));
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
|
|
deviceInfo->Flags &= ~DF_QUERY_STOPPED;
|
|
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "Cancel%s Device returning: %x\n",
|
|
(irpSp->MinorFunction == IRP_MN_CANCEL_STOP_DEVICE) ? "Stop" : "Remove",
|
|
status));
|
|
|
|
return status;
|
|
|
|
} // PiCancelRemoteStopPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiStopPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
POWER_STATE newPowerState;
|
|
|
|
DebugPrint((DEBUG_PNP, "PiStopPdo %x\n",DeviceObject));
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, TRUE)) {
|
|
|
|
//
|
|
// Deselect the cards, but not the RDP node.
|
|
//
|
|
if (DeviceObject != PipRDPNode->PhysicalDeviceObject) {
|
|
|
|
PipDeactivateDevice();
|
|
DebugPrint((DEBUG_STATE,
|
|
"Stopping CSN %d/LDN %d\n",
|
|
deviceInfo->CardInformation->CardSelectNumber,
|
|
deviceInfo->LogicalDeviceNumber));
|
|
|
|
PipReleaseDeviceResources (deviceInfo);
|
|
}
|
|
|
|
if ((deviceInfo->Flags & DF_ACTIVATED)) {
|
|
deviceInfo->Flags &= ~DF_ACTIVATED;
|
|
newPowerState.DeviceState = deviceInfo->DevicePowerState = PowerDeviceD3;
|
|
PoSetPowerState(DeviceObject, DevicePowerState, newPowerState);
|
|
}
|
|
deviceInfo->Flags &= ~DF_QUERY_STOPPED;
|
|
deviceInfo->Flags |= DF_STOPPED;
|
|
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "StopDevice returning: %x\n",status));
|
|
return status;
|
|
|
|
} // PiStopPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceRelationsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_STACK_LOCATION irpSp;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// The QueryDeviceRelation Irp is for devices under enumerated PnpIsa device.
|
|
//
|
|
|
|
|
|
switch (irpSp->Parameters.QueryDeviceRelations.Type) {
|
|
case TargetDeviceRelation: {
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
|
|
deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (deviceRelations == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
deviceRelations->Count = 1;
|
|
deviceRelations->Objects[0] = DeviceObject;
|
|
ObReferenceObject(DeviceObject);
|
|
Irp->IoStatus.Information = (ULONG_PTR)deviceRelations;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RemovalRelations: {
|
|
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
|
|
if (PipRDPNode && (DeviceObject == PipRDPNode->PhysicalDeviceObject)) {
|
|
|
|
deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (deviceRelations == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
//
|
|
//Don't include ourselves in the list of Removal Relations, hence the -1
|
|
//
|
|
|
|
PipLockDeviceDatabase();
|
|
status = PipQueryDeviceRelations(
|
|
PipRDPNode->ParentDeviceExtension,
|
|
(PDEVICE_RELATIONS *)&Irp->IoStatus.Information,
|
|
TRUE
|
|
);
|
|
|
|
PipUnlockDeviceDatabase();
|
|
}
|
|
|
|
} else {
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
}
|
|
}
|
|
break;
|
|
|
|
default : {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
return status;
|
|
|
|
} // PiQueryDeviceRelationsPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryCapabilitiesPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PDEVICE_CAPABILITIES deviceCapabilities;
|
|
ULONG i;
|
|
PDEVICE_POWER_STATE state;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
deviceCapabilities = irpSp->Parameters.DeviceCapabilities.Capabilities;
|
|
deviceCapabilities->SystemWake = PowerSystemUnspecified;
|
|
deviceCapabilities->DeviceWake = PowerDeviceUnspecified;
|
|
deviceCapabilities->LockSupported = FALSE;
|
|
deviceCapabilities->EjectSupported = FALSE;
|
|
deviceCapabilities->Removable = FALSE;
|
|
deviceCapabilities->DockDevice = FALSE;
|
|
deviceCapabilities->UniqueID = TRUE;
|
|
state = deviceCapabilities->DeviceState;
|
|
//
|
|
// Init the entire DeviceState array to D3 then replace the entry
|
|
// for system state S0.
|
|
//
|
|
for (i = 0;
|
|
i < sizeof(deviceCapabilities->DeviceState);
|
|
i += sizeof(deviceCapabilities->DeviceState[0])) {
|
|
|
|
//
|
|
// Only supported state, currently, is off.
|
|
//
|
|
|
|
*state++ = PowerDeviceD3;
|
|
}
|
|
deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
|
|
|
|
//deviceCapabilities->SilentInstall = TRUE;
|
|
//deviceCapabilities->RawDeviceOK = FALSE;
|
|
if (PipRDPNode && (PipRDPNode->PhysicalDeviceObject == DeviceObject)) {
|
|
deviceCapabilities->SilentInstall = TRUE;
|
|
deviceCapabilities->RawDeviceOK = TRUE;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // PiQueryCapabilitiesPdo
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceTextPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
PWSTR functionId;
|
|
|
|
ULONG functionIdLength;
|
|
|
|
if (irpSp->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
|
|
|
|
//
|
|
// Once we know we're going to touch the IRP
|
|
//
|
|
status = STATUS_SUCCESS;
|
|
|
|
PipGetFunctionIdentifier((PUCHAR)deviceInfo->DeviceData,
|
|
&functionId,
|
|
&functionIdLength);
|
|
|
|
if (!functionId) {
|
|
if (deviceInfo->CardInformation) {
|
|
PipGetCardIdentifier((PUCHAR)deviceInfo->CardInformation->CardData + NUMBER_CARD_ID_BYTES,
|
|
&functionId,
|
|
&functionIdLength);
|
|
}else {
|
|
functionId=NULL;
|
|
}
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR)functionId;
|
|
} else {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
return status;
|
|
|
|
} // PiQueryDeviceTextPdo
|
|
|
|
NTSTATUS
|
|
PiFilterResourceRequirementsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine ensures that the RDP doesn't get its requirements filtered.
|
|
|
|
Design Note:
|
|
This code may now be extraneous now that we ensure that the
|
|
DF_PROCESSING_RDP and DF_REQ_TRIMMED flags are cleared on RDP
|
|
removal.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the PDO for which this IRP applies.
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST IoResources;
|
|
USHORT irqBootFlags;
|
|
|
|
if ((deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) == NULL) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
DebugPrint((DEBUG_PNP, "Filtering resource requirements for RDP\n"));
|
|
|
|
status = PipBuildRDPResources(&IoResources, deviceInfo->Flags);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// if someone above us filtered the RDP resource requirements,
|
|
// free them.
|
|
if (Irp->IoStatus.Information) {
|
|
ExFreePool((PVOID) Irp->IoStatus.Information);
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR) IoResources;
|
|
}
|
|
} else {
|
|
//
|
|
// If the device's resource requirements are being filtered
|
|
// and the new requirements have only one alternative vs the n
|
|
// alternatives of the original, then we're going to assume we
|
|
// are receiving a force config. Apply our earlier derived
|
|
// IRQ level/edge settings to this force config in order to
|
|
// deal with broken force configs from NT4
|
|
//
|
|
// Design Note:
|
|
// Probably should've left out the force config test
|
|
// and done it on everything, but this is what we private
|
|
// tested.
|
|
|
|
IoResources =
|
|
(PIO_RESOURCE_REQUIREMENTS_LIST) Irp->IoStatus.Information;
|
|
|
|
if (IoResources &&
|
|
(IoResources->AlternativeLists == 1) &&
|
|
(deviceInfo->ResourceRequirements->AlternativeLists > 1)) {
|
|
status = PipGetBootIrqFlags(deviceInfo, &irqBootFlags);
|
|
if (NT_SUCCESS(status)) {
|
|
status = PipTrimResourceRequirements(
|
|
&IoResources,
|
|
irqBootFlags,
|
|
NULL);
|
|
Irp->IoStatus.Information = (ULONG_PTR) IoResources;
|
|
} else {
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
} else {
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
}
|
|
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryIdPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
ULONG length;
|
|
PWCHAR requestId = NULL, ids;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if ((deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) == NULL) {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
return status;
|
|
}
|
|
|
|
switch (irpSp->Parameters.QueryId.IdType) {
|
|
case BusQueryCompatibleIDs:
|
|
|
|
ids = (PWCHAR)ExAllocatePool(PagedPool, 1024);
|
|
if (ids) {
|
|
PWCHAR p1;
|
|
ULONG i;
|
|
|
|
p1 = ids;
|
|
length = 0;
|
|
for (i = 1; TRUE; i++) {
|
|
//
|
|
// Use the -1 as a sentinel so that we get the magic RDP compat. ID and also leave the loop
|
|
//
|
|
ASSERT (i < 256);
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
i =-1;
|
|
}
|
|
|
|
status = PipGetCompatibleDeviceId(
|
|
deviceInfo->DeviceData,
|
|
i,
|
|
&requestId);
|
|
if (NT_SUCCESS(status) && requestId) {
|
|
if ((length + wcslen(requestId) * sizeof(WCHAR) + 2 * sizeof(WCHAR))
|
|
<= 1024) {
|
|
RtlMoveMemory(p1, requestId, wcslen(requestId) * sizeof(WCHAR));
|
|
p1 += wcslen(requestId);
|
|
*p1 = UNICODE_NULL;
|
|
p1++;
|
|
length += wcslen(requestId) * sizeof(WCHAR) + sizeof(WCHAR);
|
|
ExFreePool(requestId);
|
|
} else {
|
|
ExFreePool(requestId);
|
|
break;
|
|
}
|
|
if ( i == -1 ) {
|
|
break;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (length == 0) {
|
|
ExFreePool(ids);
|
|
ids = NULL;
|
|
} else {
|
|
*p1 = UNICODE_NULL;
|
|
}
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR)ids;
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case BusQueryHardwareIDs:
|
|
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
status = PipGetCompatibleDeviceId(deviceInfo->DeviceData, -1, &requestId);
|
|
}else {
|
|
status = PipGetCompatibleDeviceId(deviceInfo->DeviceData, 0, &requestId);
|
|
}
|
|
|
|
if (NT_SUCCESS(status) && requestId) {
|
|
|
|
ULONG idLength, deviceIdLength;
|
|
PWCHAR deviceId = NULL, p;
|
|
|
|
//
|
|
// create HardwareId value name. Even though it is a MULTI_SZ,
|
|
// we know there is only one HardwareId for PnpIsa.
|
|
//
|
|
// HACK - The modem inf files use the form of isapnp\xyz0001
|
|
// instead of *xyz0001 as the hardware id. To solve this
|
|
// problem we will generate two hardware Ids: *xyz0001 and
|
|
// isapnp\xyz0001 (device instance name).
|
|
//
|
|
|
|
status = PipQueryDeviceId(deviceInfo, &deviceId, 0);
|
|
|
|
if (NT_SUCCESS (status)) {
|
|
idLength = wcslen(requestId) * sizeof(WCHAR);
|
|
deviceIdLength = wcslen(deviceId) * sizeof(WCHAR);
|
|
length = idLength + // returned ID
|
|
sizeof(WCHAR) + // UNICODE_NULL
|
|
deviceIdLength + // isapnp\id
|
|
2 * sizeof(WCHAR); // two UNICODE_NULLs
|
|
ids = p = (PWCHAR)ExAllocatePool(PagedPool, length);
|
|
if (ids) {
|
|
RtlMoveMemory(ids, deviceId, deviceIdLength);
|
|
p += deviceIdLength / sizeof(WCHAR);
|
|
*p = UNICODE_NULL;
|
|
p++;
|
|
RtlMoveMemory(p, requestId, idLength);
|
|
p += idLength / sizeof(WCHAR);
|
|
*p = UNICODE_NULL;
|
|
p++;
|
|
*p = UNICODE_NULL;
|
|
ExFreePool(requestId);
|
|
Irp->IoStatus.Information = (ULONG_PTR)ids;
|
|
} else {
|
|
Irp->IoStatus.Information = (ULONG_PTR)requestId;
|
|
}
|
|
if (deviceId) {
|
|
ExFreePool(deviceId);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case BusQueryDeviceID:
|
|
|
|
status = PipQueryDeviceId(deviceInfo, &requestId, 0);
|
|
Irp->IoStatus.Information = (ULONG_PTR)requestId;
|
|
break;
|
|
|
|
case BusQueryInstanceID:
|
|
|
|
status = PipQueryDeviceUniqueId (deviceInfo, &requestId);
|
|
Irp->IoStatus.Information = (ULONG_PTR)requestId;
|
|
break;
|
|
|
|
default:
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
|
|
return status;
|
|
|
|
} // PiQueryIdPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryResourcesPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status=STATUS_SUCCESS;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PCM_RESOURCE_LIST cmResources=NULL;
|
|
ULONG length;
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
if ((deviceInfo->Flags & DF_READ_DATA_PORT) ||
|
|
((deviceInfo->Flags & (DF_ENUMERATED|DF_REMOVED)) == DF_ENUMERATED)) {
|
|
status = PipQueryDeviceResources (
|
|
deviceInfo,
|
|
0, // BusNumber
|
|
&cmResources,
|
|
&length
|
|
);
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
Irp->IoStatus.Information = (ULONG_PTR)cmResources;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "PiQueryResourcesPdo returning: %x\n",status));
|
|
return status;
|
|
|
|
} // PiQueryResourcesPdo
|
|
|
|
NTSTATUS
|
|
PiQueryResourceRequirementsPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST ioResources;
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
status = STATUS_SUCCESS;
|
|
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
status = PipBuildRDPResources (&ioResources,
|
|
deviceInfo->Flags);
|
|
} else {
|
|
if (deviceInfo->ResourceRequirements &&
|
|
!(deviceInfo->Flags & (DF_SURPRISE_REMOVED))) {
|
|
|
|
ioResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (
|
|
PagedPool, deviceInfo->ResourceRequirements->ListSize);
|
|
if (ioResources == NULL) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RtlMoveMemory(ioResources,
|
|
deviceInfo->ResourceRequirements,
|
|
deviceInfo->ResourceRequirements->ListSize
|
|
);
|
|
}
|
|
} else {
|
|
ioResources = NULL;
|
|
}
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR)ioResources;
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "PiQueryResourceRequirementsPdo returning: %x\n",status));
|
|
return status;
|
|
|
|
} // PiQueryResourceRequirementsPdo
|
|
|
|
|
|
NTSTATUS
|
|
PiRemovePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
POWER_STATE newPowerState;
|
|
|
|
//
|
|
// One of our enumerated device is being removed. Mark it and deactivate the
|
|
// device. Note, we do NOT delete its device object.
|
|
//
|
|
DebugPrint((DEBUG_PNP, "PiRemovePdo %x\n",DeviceObject));
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
if (!(deviceInfo->Flags & (DF_REMOVED|DF_SURPRISE_REMOVED))) {
|
|
deviceInfo->Flags |= DF_REMOVED;
|
|
deviceInfo->Flags &= ~DF_QUERY_STOPPED;
|
|
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
|
|
PSINGLE_LIST_ENTRY deviceLink;
|
|
PPI_BUS_EXTENSION busExtension = deviceInfo->ParentDeviceExtension;
|
|
|
|
//
|
|
// If the RDP is removed, mark everyone as missing, and then return only the
|
|
// RDP
|
|
//
|
|
PipLockDeviceDatabase();
|
|
|
|
deviceLink = busExtension->DeviceList.Next;
|
|
while (deviceLink) {
|
|
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|
if (!(deviceInfo->Flags & DF_READ_DATA_PORT)) {
|
|
deviceInfo->Flags &= ~DF_ENUMERATED;
|
|
}
|
|
deviceLink = deviceInfo->DeviceList.Next;
|
|
}
|
|
|
|
PipUnlockDeviceDatabase();
|
|
|
|
IoInvalidateDeviceRelations (
|
|
deviceInfo->ParentDeviceExtension->PhysicalBusDevice,BusRelations);
|
|
deviceInfo->Flags &= ~(DF_REQ_TRIMMED|DF_PROCESSING_RDP);
|
|
}
|
|
|
|
//
|
|
// Deactivate the device
|
|
//
|
|
if (deviceInfo->Flags & DF_ACTIVATED) {
|
|
deviceInfo->Flags &= ~DF_ACTIVATED;
|
|
|
|
if (!(deviceInfo->Flags & (DF_READ_DATA_PORT|DF_NOT_FUNCTIONING))) {
|
|
PipWakeAndSelectDevice(
|
|
(UCHAR) deviceInfo->CardInformation->CardSelectNumber,
|
|
(UCHAR)deviceInfo->LogicalDeviceNumber);
|
|
PipDeactivateDevice();
|
|
PipWaitForKey();
|
|
DebugPrint((DEBUG_STATE,
|
|
"Removing CSN %d/LDN %d\n",
|
|
deviceInfo->CardInformation->CardSelectNumber,
|
|
deviceInfo->LogicalDeviceNumber));
|
|
}
|
|
newPowerState.DeviceState = deviceInfo->DevicePowerState = PowerDeviceD3;
|
|
PoSetPowerState(DeviceObject, DevicePowerState, newPowerState);
|
|
}
|
|
|
|
PipReleaseDeviceResources (deviceInfo);
|
|
}
|
|
|
|
if (!(deviceInfo->Flags & DF_ENUMERATED)) {
|
|
PipDeleteDevice(DeviceObject);
|
|
}
|
|
|
|
PipDereferenceDeviceInformation(deviceInfo, TRUE);
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "RemoveDevice returning: %x\n",status));
|
|
|
|
return status;
|
|
|
|
} // PiRemovePdo
|
|
|
|
|
|
NTSTATUS
|
|
PiQueryBusInformationPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
PPNP_BUS_INFORMATION pnpBusInfo;
|
|
PVOID information = NULL;
|
|
PPI_BUS_EXTENSION busExtension;
|
|
NTSTATUS status;
|
|
|
|
busExtension = DeviceObject->DeviceExtension;
|
|
|
|
pnpBusInfo = (PPNP_BUS_INFORMATION) ExAllocatePool(PagedPool, sizeof(PNP_BUS_INFORMATION));
|
|
if (pnpBusInfo) {
|
|
pnpBusInfo->BusTypeGuid = GUID_BUS_TYPE_ISAPNP;
|
|
pnpBusInfo->LegacyBusType = Isa;
|
|
pnpBusInfo->BusNumber = busExtension->BusNumber;
|
|
information = pnpBusInfo;
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
information = NULL;
|
|
}
|
|
Irp->IoStatus.Information = (ULONG_PTR) information;
|
|
|
|
return status;
|
|
} // PiQueryBusInformationPdo
|
|
|
|
NTSTATUS
|
|
PiDeviceUsageNotificationPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine notes whether an ISAPNP device is on the crashdump or
|
|
paging file path. It fails attempts to put us on the hibernation path.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the PDO for which this IRP applies.
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PLONG addend;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
if ((deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) == NULL) {
|
|
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
return status;
|
|
}
|
|
|
|
DebugPrint((DEBUG_PNP, "DeviceUsage CSN %d/LSN %d: InPath %s Type %d\n",
|
|
deviceInfo->CardInformation->CardSelectNumber,
|
|
deviceInfo->LogicalDeviceNumber,
|
|
irpSp->Parameters.UsageNotification.InPath ? "TRUE" : "FALSE",
|
|
irpSp->Parameters.UsageNotification.Type));
|
|
|
|
switch (irpSp->Parameters.UsageNotification.Type) {
|
|
case DeviceUsageTypePaging:
|
|
addend = &deviceInfo->Paging;
|
|
break;
|
|
case DeviceUsageTypeHibernation:
|
|
status = STATUS_DEVICE_BUSY;
|
|
break;
|
|
case DeviceUsageTypeDumpFile:
|
|
addend = &deviceInfo->CrashDump;
|
|
break;
|
|
default:
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
if (irpSp->Parameters.UsageNotification.InPath) {
|
|
//
|
|
// Turn on broken isolation flag which causes QDR
|
|
// to use the cache instead of beating on the hardware if
|
|
// we're on the paging or crashdump paths. Some
|
|
// hardware appears unhappy during QDR and causes problems when
|
|
// we take a page fault in this routine.
|
|
//
|
|
|
|
deviceInfo->CardInformation->CardFlags |= CF_ISOLATION_BROKEN;
|
|
(*addend)++;
|
|
IoInvalidateDeviceState(DeviceObject);
|
|
}
|
|
else {
|
|
(*addend)--;
|
|
}
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
PiQueryInterfacePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(DeviceObject);
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
} // PiQueryInterfacePdo
|
|
|
|
|
|
NTSTATUS
|
|
PiSurpriseRemovePdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
PSINGLE_LIST_ENTRY deviceLink;
|
|
|
|
DebugPrint((DEBUG_PNP, "SurpriseRemove PDO %x\n", DeviceObject));
|
|
//
|
|
// One of our enumerated device is being removed. Mark it and deactivate the
|
|
// device. Note, we do NOT delete its device object.
|
|
//
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
if (deviceInfo->Flags & DF_READ_DATA_PORT) {
|
|
//
|
|
// If the RDP is removed, mark everyone as missing, and then return only the
|
|
// RDP
|
|
//
|
|
PipLockDeviceDatabase();
|
|
|
|
deviceLink = deviceInfo->ParentDeviceExtension->DeviceList.Next;
|
|
while (deviceLink) {
|
|
deviceInfo = CONTAINING_RECORD (deviceLink, DEVICE_INFORMATION, DeviceList);
|
|
if (!(deviceInfo->Flags & DF_READ_DATA_PORT)) {
|
|
deviceInfo->Flags &= ~DF_ENUMERATED;
|
|
}
|
|
deviceLink = deviceInfo->DeviceList.Next;
|
|
}
|
|
|
|
PipUnlockDeviceDatabase();
|
|
|
|
IoInvalidateDeviceRelations (
|
|
deviceInfo->ParentDeviceExtension->PhysicalBusDevice,BusRelations);
|
|
} else {
|
|
DebugPrint((DEBUG_STATE,
|
|
"Surprise removing CSN %d/LDN %d\n",
|
|
deviceInfo->CardInformation->CardSelectNumber,
|
|
deviceInfo->LogicalDeviceNumber));
|
|
if ((deviceInfo->Flags & (DF_ACTIVATED|DF_NOT_FUNCTIONING)) == DF_ACTIVATED) {
|
|
PipWakeAndSelectDevice(
|
|
(UCHAR) deviceInfo->CardInformation->CardSelectNumber,
|
|
(UCHAR)deviceInfo->LogicalDeviceNumber);
|
|
PipDeactivateDevice();
|
|
PipWaitForKey();
|
|
}
|
|
|
|
PipReleaseDeviceResources (deviceInfo);
|
|
deviceInfo->Flags |= DF_SURPRISE_REMOVED;
|
|
deviceInfo->Flags &= ~(DF_QUERY_STOPPED|DF_REMOVED|DF_ACTIVATED);
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
status = STATUS_SUCCESS;
|
|
} else {
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
return status;
|
|
} // PiSurpriseRemovePdo
|
|
|
|
|
|
|
|
NTSTATUS
|
|
PiIrpNotSupported(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
} // PiIrpNotSupported
|
|
|
|
NTSTATUS
|
|
PipBuildRDPResources(
|
|
IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *IoResources,
|
|
IN ULONG Flags
|
|
)
|
|
{
|
|
ULONG MaxCards = 0, CardsFound;
|
|
int i, j, numcases;
|
|
int resSize;
|
|
|
|
ASSERT(Flags & DF_READ_DATA_PORT);
|
|
|
|
//
|
|
// We need to assemble all possible cases for the RDP
|
|
//
|
|
numcases = 2*READ_DATA_PORT_RANGE_CHOICES;
|
|
|
|
if (Flags & DF_REQ_TRIMMED) {
|
|
numcases = 0;
|
|
for (i = 0; i < READ_DATA_PORT_RANGE_CHOICES; i++) {
|
|
CardsFound = PipReadDataPortRanges[i].CardsFound;
|
|
if (MaxCards < CardsFound) {
|
|
MaxCards = CardsFound;
|
|
numcases = 1;
|
|
} else if (MaxCards == CardsFound) {
|
|
numcases++;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// need to allow for the RDP range, the address port, the cmd port and the 0
|
|
//
|
|
resSize = sizeof (IO_RESOURCE_LIST)+((numcases+3)*sizeof (IO_RESOURCE_REQUIREMENTS_LIST));
|
|
|
|
*IoResources = (PIO_RESOURCE_REQUIREMENTS_LIST) ExAllocatePool (PagedPool,resSize);
|
|
if (*IoResources == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlZeroMemory (*IoResources,resSize);
|
|
|
|
(*IoResources)->BusNumber=0;
|
|
(*IoResources)->AlternativeLists = 1;
|
|
(*IoResources)->List->Count = numcases+4;
|
|
(*IoResources)->List->Version = ISAPNP_IO_VERSION;
|
|
(*IoResources)->List->Revision =ISAPNP_IO_REVISION;
|
|
|
|
//
|
|
// Requirements specify 16-bit decode even though the spec
|
|
// says 12. No ill effects have ever been observed from 16
|
|
// and 12-bit decode broke some machines when tried.
|
|
|
|
//
|
|
// cmd port
|
|
//
|
|
(*IoResources)->List->Descriptors[0].Type=CM_RESOURCE_PORT_IO;
|
|
(*IoResources)->List->Descriptors[0].u.Port.MinimumAddress.LowPart = COMMAND_PORT;
|
|
(*IoResources)->List->Descriptors[0].u.Port.MaximumAddress.LowPart = COMMAND_PORT;
|
|
|
|
(*IoResources)->List->Descriptors[0].u.Port.Length = 1;
|
|
(*IoResources)->List->Descriptors[0].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[0].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[0].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
|
|
//
|
|
// alternative of 0 for bioses that include COMMAND_PORT in
|
|
// a PNP0C02 node.
|
|
//
|
|
(*IoResources)->List->Descriptors[1].Type=CM_RESOURCE_PORT_IO;
|
|
(*IoResources)->List->Descriptors[1].u.Port.MinimumAddress.QuadPart = 0;
|
|
(*IoResources)->List->Descriptors[1].u.Port.MaximumAddress.QuadPart = 0;
|
|
|
|
(*IoResources)->List->Descriptors[1].u.Port.Length = 0;
|
|
(*IoResources)->List->Descriptors[1].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[1].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
(*IoResources)->List->Descriptors[1].Option = IO_RESOURCE_ALTERNATIVE;
|
|
|
|
//
|
|
// Address port
|
|
//
|
|
(*IoResources)->List->Descriptors[2].Type=CM_RESOURCE_PORT_IO;
|
|
(*IoResources)->List->Descriptors[2].u.Port.MinimumAddress.LowPart = ADDRESS_PORT;
|
|
(*IoResources)->List->Descriptors[2].u.Port.MaximumAddress.LowPart = ADDRESS_PORT;
|
|
|
|
(*IoResources)->List->Descriptors[2].u.Port.Length = 1;
|
|
(*IoResources)->List->Descriptors[2].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[2].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[2].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
//
|
|
// alternative of 0
|
|
//
|
|
(*IoResources)->List->Descriptors[3].Type=CM_RESOURCE_PORT_IO;
|
|
(*IoResources)->List->Descriptors[3].u.Port.MinimumAddress.QuadPart = 0;
|
|
(*IoResources)->List->Descriptors[3].u.Port.MaximumAddress.QuadPart = 0;
|
|
|
|
(*IoResources)->List->Descriptors[3].u.Port.Length = 0;
|
|
(*IoResources)->List->Descriptors[3].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[3].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[3].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
(*IoResources)->List->Descriptors[3].Option = IO_RESOURCE_ALTERNATIVE;
|
|
|
|
if (Flags & DF_REQ_TRIMMED) {
|
|
j = 0;
|
|
for (i = 0; i < READ_DATA_PORT_RANGE_CHOICES; i++) {
|
|
if (PipReadDataPortRanges[i].CardsFound != MaxCards) {
|
|
continue;
|
|
}
|
|
//
|
|
// An RDP alternative
|
|
//
|
|
(*IoResources)->List->Descriptors[4+j].Type=CM_RESOURCE_PORT_IO;
|
|
|
|
(*IoResources)->List->Descriptors[4+j].u.Port.MinimumAddress.LowPart =
|
|
PipReadDataPortRanges[i].MinimumAddress;
|
|
(*IoResources)->List->Descriptors[4+j].u.Port.MaximumAddress.LowPart =
|
|
PipReadDataPortRanges[i].MaximumAddress;
|
|
|
|
(*IoResources)->List->Descriptors[4+j].u.Port.Length =
|
|
PipReadDataPortRanges[i].MaximumAddress -
|
|
PipReadDataPortRanges[i].MinimumAddress+1;
|
|
(*IoResources)->List->Descriptors[4+j].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[4+j].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[4+j].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
(*IoResources)->List->Descriptors[4+j].Option = IO_RESOURCE_ALTERNATIVE;
|
|
j++;
|
|
}
|
|
(*IoResources)->List->Descriptors[4].Option = 0;
|
|
} else {
|
|
for (i = 0;i< (numcases >> 1);i++) {
|
|
//
|
|
// The RDP
|
|
//
|
|
(*IoResources)->List->Descriptors[4+i*2].Type=CM_RESOURCE_PORT_IO;
|
|
|
|
(*IoResources)->List->Descriptors[4+i*2].u.Port.MinimumAddress.LowPart =
|
|
PipReadDataPortRanges[i].MinimumAddress;
|
|
(*IoResources)->List->Descriptors[4+i*2].u.Port.MaximumAddress.LowPart =
|
|
PipReadDataPortRanges[i].MaximumAddress;
|
|
|
|
(*IoResources)->List->Descriptors[4+i*2].u.Port.Length =
|
|
PipReadDataPortRanges[i].MaximumAddress -
|
|
PipReadDataPortRanges[i].MinimumAddress+1;
|
|
|
|
(*IoResources)->List->Descriptors[4+i*2].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[4+i*2].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[4+i*2].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
|
|
//
|
|
// alternative of 0
|
|
//
|
|
(*IoResources)->List->Descriptors[4+i*2+1].Type=CM_RESOURCE_PORT_IO;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].u.Port.MinimumAddress.QuadPart = 0;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].u.Port.MaximumAddress.QuadPart = 0;
|
|
|
|
(*IoResources)->List->Descriptors[4+i*2+1].u.Port.Length = 0;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].u.Port.Alignment = 1;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].Flags = CM_RESOURCE_PORT_16_BIT_DECODE;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].ShareDisposition = CmResourceShareDeviceExclusive;
|
|
(*IoResources)->List->Descriptors[4+i*2+1].Option = IO_RESOURCE_ALTERNATIVE;
|
|
|
|
}
|
|
|
|
}
|
|
(*IoResources)->ListSize = resSize;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PiQueryDeviceState(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp
|
|
)
|
|
{
|
|
NTSTATUS status=STATUS_NOT_SUPPORTED;
|
|
PDEVICE_INFORMATION deviceInfo;
|
|
|
|
//
|
|
// One of our enumerated device is being removed. Mark it and deactivate the
|
|
// device. Note, we do NOT delete its device object.
|
|
//
|
|
|
|
if (deviceInfo = PipReferenceDeviceInformation(DeviceObject, FALSE)) {
|
|
|
|
if ((deviceInfo->Flags & DF_READ_DATA_PORT) && (deviceInfo->Flags & DF_PROCESSING_RDP)) {
|
|
Irp->IoStatus.Information |= PNP_DEVICE_RESOURCE_REQUIREMENTS_CHANGED |
|
|
PNP_DEVICE_FAILED |
|
|
PNP_DEVICE_NOT_DISABLEABLE ;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
|
|
if (deviceInfo->Paging || deviceInfo->CrashDump) {
|
|
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
PipDereferenceDeviceInformation(deviceInfo, FALSE);
|
|
}
|
|
return status;
|
|
|
|
}
|
|
#endif
|