You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1618 lines
42 KiB
1618 lines
42 KiB
/*++
|
|
|
|
Copyright (c) 1997-2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
pdo.c
|
|
|
|
Abstract:
|
|
|
|
This module provides the functions that pertain to MF.SYS PDOs
|
|
|
|
Author:
|
|
|
|
Andy Thornton (andrewth) 20-Oct-97
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mfp.h"
|
|
|
|
/*++
|
|
|
|
The majority of functions in this file are called based on their presence
|
|
in Pnp and Po dispatch tables. In the interests of brevity the arguments
|
|
to all those functions will be described below:
|
|
|
|
NTSTATUS
|
|
MfXxxPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
|
|
Routine Description:
|
|
|
|
This function handles the Xxx requests for multifunction PDO's
|
|
|
|
Arguments:
|
|
|
|
Irp - Points to the IRP associated with this request.
|
|
|
|
Child - Points to the child PDO's device extension.
|
|
|
|
IrpStack - Points to the current stack location for this request.
|
|
|
|
Return Value:
|
|
|
|
Status code that indicates whether or not the function was successful.
|
|
|
|
STATUS_NOT_SUPPORTED indicates that the IRP should be completed without
|
|
changing the Irp->IoStatus.Status field otherwise it is updated with this
|
|
status.
|
|
|
|
--*/
|
|
|
|
NTSTATUS
|
|
MfCreatePdo(
|
|
IN PMF_PARENT_EXTENSION Parent,
|
|
OUT PDEVICE_OBJECT *PhysicalDeviceObject
|
|
);
|
|
|
|
NTSTATUS
|
|
MfStartPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfSurpriseRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfCancelRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfCancelStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
NTSTATUS
|
|
MfQueryDeviceRelationsPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryInterfacePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
NTSTATUS
|
|
MfQueryCapabilitiesPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryResourcesPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryResourceRequirementsPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryDeviceTextPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryIdPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
MfQueryPnpDeviceStatePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfPagingNotificationPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfSetPowerPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
NTSTATUS
|
|
MfQueryPowerPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
);
|
|
|
|
VOID
|
|
MfTranslatorReference(
|
|
IN PVOID Context
|
|
);
|
|
|
|
VOID
|
|
MfTranslatorDereference(
|
|
IN PVOID Context
|
|
);
|
|
|
|
BOOLEAN
|
|
MfIsSubResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Super,
|
|
IN ULONGLONG SubStart,
|
|
IN ULONG SubLength,
|
|
OUT PULONGLONG Offset
|
|
);
|
|
|
|
NTSTATUS
|
|
MfPerformTranslation(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated,
|
|
IN ULONGLONG Offset,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
|
|
);
|
|
|
|
NTSTATUS
|
|
MfTransFromRawRequirements(
|
|
IN PVOID Context,
|
|
IN PIO_RESOURCE_DESCRIPTOR Source,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PULONG TargetCount,
|
|
OUT PIO_RESOURCE_DESCRIPTOR *Target
|
|
);
|
|
|
|
NTSTATUS
|
|
MfTransFromRawResources(
|
|
IN PVOID Context,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
|
IN RESOURCE_TRANSLATION_DIRECTION Direction,
|
|
IN ULONG AlternativesCount, OPTIONAL
|
|
IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MfCancelRemovePdo)
|
|
#pragma alloc_text(PAGE, MfCancelStopPdo)
|
|
#pragma alloc_text(PAGE, MfCreatePdo)
|
|
#pragma alloc_text(PAGE, MfDispatchPnpPdo)
|
|
#pragma alloc_text(PAGE, MfIsSubResource)
|
|
#pragma alloc_text(PAGE, MfPerformTranslation)
|
|
#pragma alloc_text(PAGE, MfQueryCapabilitiesPdo)
|
|
#pragma alloc_text(PAGE, MfQueryDeviceRelationsPdo)
|
|
#pragma alloc_text(PAGE, MfQueryDeviceTextPdo)
|
|
#pragma alloc_text(PAGE, MfQueryIdPdo)
|
|
#pragma alloc_text(PAGE, MfQueryInterfacePdo)
|
|
#pragma alloc_text(PAGE, MfQueryRemovePdo)
|
|
#pragma alloc_text(PAGE, MfQueryResourceRequirementsPdo)
|
|
#pragma alloc_text(PAGE, MfQueryResourcesPdo)
|
|
#pragma alloc_text(PAGE, MfQueryStopPdo)
|
|
#pragma alloc_text(PAGE, MfRemovePdo)
|
|
#pragma alloc_text(PAGE, MfStartPdo)
|
|
#pragma alloc_text(PAGE, MfStopPdo)
|
|
#pragma alloc_text(PAGE, MfTransFromRawRequirements)
|
|
#pragma alloc_text(PAGE, MfTransFromRawResources)
|
|
#endif
|
|
|
|
PMF_DISPATCH MfPnpDispatchTablePdo[] = {
|
|
|
|
MfStartPdo, // IRP_MN_START_DEVICE
|
|
MfQueryRemovePdo, // IRP_MN_QUERY_REMOVE_DEVICE
|
|
MfRemovePdo, // IRP_MN_REMOVE_DEVICE
|
|
MfCancelRemovePdo, // IRP_MN_CANCEL_REMOVE_DEVICE
|
|
MfIrpNotSupported, // IRP_MN_STOP_DEVICE
|
|
MfQueryStopPdo, // IRP_MN_QUERY_STOP_DEVICE
|
|
MfCancelStopPdo, // IRP_MN_CANCEL_STOP_DEVICE
|
|
MfQueryDeviceRelationsPdo, // IRP_MN_QUERY_DEVICE_RELATIONS
|
|
MfQueryInterfacePdo, // IRP_MN_QUERY_INTERFACE
|
|
MfQueryCapabilitiesPdo, // IRP_MN_QUERY_CAPABILITIES
|
|
MfQueryResourcesPdo, // IRP_MN_QUERY_RESOURCES
|
|
MfQueryResourceRequirementsPdo, // IRP_MN_QUERY_RESOURCE_REQUIREMENTS
|
|
MfQueryDeviceTextPdo, // IRP_MN_QUERY_DEVICE_TEXT
|
|
MfIrpNotSupported, // IRP_MN_FILTER_RESOURCE_REQUIREMENTS
|
|
MfIrpNotSupported, // Unused
|
|
MfForwardIrpToParent, // IRP_MN_READ_CONFIG
|
|
MfForwardIrpToParent, // IRP_MN_WRITE_CONFIG
|
|
MfForwardIrpToParent, // IRP_MN_EJECT
|
|
MfForwardIrpToParent, // IRP_MN_SET_LOCK
|
|
MfQueryIdPdo, // IRP_MN_QUERY_ID
|
|
MfQueryPnpDeviceStatePdo, // IRP_MN_QUERY_PNP_DEVICE_STATE
|
|
MfForwardIrpToParent, // IRP_MN_QUERY_BUS_INFORMATION
|
|
MfDeviceUsageNotificationCommon,// IRP_MN_DEVICE_USAGE_NOTIFICATION
|
|
MfSurpriseRemovePdo, // IRP_MN_SURPRISE_REMOVAL
|
|
MfIrpNotSupported // IRP_MN_QUERY_LEGACY_BUS_INFORMATION
|
|
};
|
|
|
|
PMF_DISPATCH MfPoDispatchTablePdo[] = {
|
|
NULL, // IRP_MN_WAIT_WAKE
|
|
NULL, // IRP_MN_POWER_SEQUENCE
|
|
MfSetPowerPdo, // IRP_MN_SET_POWER
|
|
MfQueryPowerPdo // IRP_MN_QUERY_POWER
|
|
};
|
|
|
|
NTSTATUS
|
|
MfCreatePdo(
|
|
IN PMF_PARENT_EXTENSION Parent,
|
|
OUT PDEVICE_OBJECT *PhysicalDeviceObject
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates and initializes a new pdo inserting it into the list of PDOs owned
|
|
by Parent
|
|
|
|
Arguments:
|
|
|
|
Parent - The parent device that owns this pdo.
|
|
|
|
PhysicalDeviceObject - On success pointer to the physical device object created
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PDEVICE_OBJECT pdo;
|
|
PMF_CHILD_EXTENSION extension;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT((sizeof(MfPnpDispatchTablePdo) / sizeof(PMF_DISPATCH)) - 1
|
|
== IRP_MN_PNP_MAXIMUM_FUNCTION);
|
|
|
|
ASSERT((sizeof(MfPoDispatchTablePdo) / sizeof(PMF_DISPATCH)) - 1
|
|
== IRP_MN_PO_MAXIMUM_FUNCTION);
|
|
|
|
status = IoCreateDevice(Parent->Self->DriverObject,
|
|
sizeof(MF_CHILD_EXTENSION),
|
|
NULL, // Name
|
|
FILE_DEVICE_UNKNOWN,
|
|
FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN,
|
|
FALSE, // Exclusive
|
|
&pdo
|
|
);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Fill in our extension
|
|
//
|
|
|
|
extension = pdo->DeviceExtension;
|
|
|
|
MfInitCommonExtension(&extension->Common, MfPhysicalDeviceObject);
|
|
|
|
extension->Self = pdo;
|
|
extension->Parent = Parent;
|
|
|
|
extension->Common.PowerState = PowerDeviceUnspecified;
|
|
|
|
//
|
|
// Insert the child into the parents child list. Access already
|
|
// protected by the children lock taken in the QDR code.
|
|
//
|
|
|
|
InsertHeadList(&Parent->Children, &extension->ListEntry);
|
|
|
|
//
|
|
// Our FDO stack is pagable, so we need to
|
|
// assume pagable as well.
|
|
//
|
|
|
|
pdo->Flags |= DO_POWER_PAGABLE;
|
|
|
|
//
|
|
// We have finished initializing
|
|
//
|
|
|
|
pdo->Flags &= ~DO_DEVICE_INITIALIZING;
|
|
|
|
*PhysicalDeviceObject = pdo;
|
|
|
|
//
|
|
// Dump the info about the PDO just created
|
|
//
|
|
|
|
DEBUG_MSG(1, ("Created PDO @ 0x%08x\n", pdo));
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
VOID
|
|
MfDeletePdo(
|
|
IN PMF_CHILD_EXTENSION Child
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cleans a PDO extension and any associated allocations. Then
|
|
deletes the PDO itself.
|
|
|
|
Arguments:
|
|
|
|
Child - PDO extension
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
if (Child->Common.DeviceState & MF_DEVICE_DELETED) {
|
|
//
|
|
// Trying to delete twice
|
|
//
|
|
ASSERT(!(Child->Common.DeviceState & MF_DEVICE_DELETED));
|
|
return;
|
|
}
|
|
|
|
MfFreeDeviceInfo(&Child->Info);
|
|
|
|
Child->Common.DeviceState |= MF_DEVICE_DELETED;
|
|
DEBUG_MSG(1, ("Deleted PDO @ 0x%08x\n", Child->Self));
|
|
IoDeleteDevice(Child->Self);
|
|
}
|
|
|
|
NTSTATUS
|
|
MfDispatchPnpPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
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.
|
|
|
|
Child - PDO extension
|
|
|
|
IrpStack - Current stack location
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
BOOLEAN isRemove;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Child->Common.DeviceState & MF_DEVICE_DELETED) {
|
|
status = Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
|
|
} else if (IrpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
|
|
status = Irp->IoStatus.Status;
|
|
} else {
|
|
//
|
|
// If IRP_MN_REMOVE_DEVICE is received by a pdo that was not
|
|
// enumerated in the last BusRelations query, then it needs to
|
|
// delete the pdo *AFTER* completing the remove irp. As this
|
|
// is in conflict with the standard dispatch functionality
|
|
// provided by this function, explicitly delegate completion
|
|
// of this irp to the dispatched routine.
|
|
|
|
isRemove = IrpStack->MinorFunction == IRP_MN_REMOVE_DEVICE;
|
|
status =
|
|
MfPnpDispatchTablePdo[IrpStack->MinorFunction](Irp,
|
|
Child,
|
|
IrpStack
|
|
);
|
|
if (isRemove) {
|
|
return status;
|
|
}
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
Irp->IoStatus.Status = status;
|
|
} else {
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
}
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return status;
|
|
}
|
|
|
|
POWER_STATE
|
|
MfUpdatePowerPdo(
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN DEVICE_POWER_STATE NewDevicePowerState
|
|
)
|
|
{
|
|
POWER_STATE previousState, newState;
|
|
DEVICE_POWER_STATE newParentState;
|
|
|
|
newState.DeviceState = NewDevicePowerState;
|
|
previousState = PoSetPowerState(Child->Self,
|
|
DevicePowerState,
|
|
newState);
|
|
|
|
ASSERT(previousState.DeviceState == Child->Common.PowerState);
|
|
DEBUG_MSG(1,
|
|
("Updating child power state from %s (believed %s) to %s\n",
|
|
DEVICE_POWER_STRING(previousState.DeviceState),
|
|
DEVICE_POWER_STRING(Child->Common.PowerState),
|
|
DEVICE_POWER_STRING(NewDevicePowerState)
|
|
));
|
|
|
|
Child->Common.PowerState = NewDevicePowerState;
|
|
|
|
//
|
|
// We may be receiving an operation after our parent has been
|
|
// surprise removed/removed in which case we should keep our
|
|
// hands out of the cookie jar.
|
|
//
|
|
if (Child->Parent) {
|
|
//
|
|
// * We've already claimed that we can go to this power
|
|
// state via the capabilities
|
|
// * Said yes to QUERY_POWER
|
|
// * Children's power state is defined to be as resource consuming
|
|
// or less than the parent
|
|
|
|
//
|
|
// Update the children power state references stored in the
|
|
// parent extension. Compute a new target power state for the
|
|
// parent
|
|
|
|
newParentState =
|
|
MfUpdateChildrenPowerReferences(Child->Parent,
|
|
previousState.DeviceState,
|
|
NewDevicePowerState
|
|
);
|
|
|
|
//
|
|
// Modify the parent's power state to reflect that of it's
|
|
// children.
|
|
//
|
|
|
|
MfUpdateParentPowerState(Child->Parent, newParentState);
|
|
}
|
|
|
|
return previousState;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfStartPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PDEVICE_OBJECT pDO;
|
|
POWER_STATE previousState, newState;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
//
|
|
// Trivially succeed the start
|
|
//
|
|
|
|
MfUpdatePowerPdo(Child, PowerDeviceD0);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
NTSTATUS
|
|
MfQueryRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (Child->Common.PagingCount > 0
|
|
|| Child->Common.HibernationCount > 0
|
|
|| Child->Common.DumpCount > 0) {
|
|
|
|
return STATUS_DEVICE_BUSY;
|
|
|
|
} else {
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
MfCancelRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) == 0) {
|
|
|
|
MfUpdatePowerPdo(Child, PowerDeviceD3);
|
|
}
|
|
|
|
Child->Common.DeviceState &= ~MF_DEVICE_SURPRISE_REMOVED;
|
|
|
|
//
|
|
// If child appeared in the last BusRelations then just mark it
|
|
// removed, otherwise completely delete it.
|
|
//
|
|
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
if (Child->Common.DeviceState & MF_DEVICE_ENUMERATED) {
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
} else {
|
|
if (Child->Parent) {
|
|
MfAcquireChildrenLock(Child->Parent);
|
|
RemoveEntryList(&Child->ListEntry);
|
|
MfReleaseChildrenLock(Child->Parent);
|
|
}
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
MfDeletePdo(Child);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfSurpriseRemovePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Mark device as surprise removed.
|
|
//
|
|
Child->Common.DeviceState |= MF_DEVICE_SURPRISE_REMOVED;
|
|
|
|
//
|
|
// Update my pdo's power state *AND* my parent's power state *IFF*
|
|
// the parent is still connected.
|
|
//
|
|
MfUpdatePowerPdo(Child, PowerDeviceD3);
|
|
|
|
//
|
|
// The surprise remove could have one of many causes. One
|
|
// possibility that can be excluded is MF reporting its children
|
|
// missing directly since MF children can't disappear.
|
|
//
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// Stopping is disabled at the moment because MF is dependent on
|
|
// changes in the arbiters to support resource rebalance.
|
|
//
|
|
|
|
NTSTATUS
|
|
MfStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (Child->Common.PagingCount > 0
|
|
|| Child->Common.HibernationCount > 0
|
|
|| Child->Common.DumpCount > 0) {
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
} else {
|
|
|
|
// REBALANCE
|
|
// If rebalance was supported by parent, then this would have
|
|
// to succeed.
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MfCancelStopPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryDeviceRelationsPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PDEVICE_RELATIONS deviceRelations;
|
|
PMF_CHILD_EXTENSION nextChild;
|
|
NTSTATUS status;
|
|
ULONG index;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) ||
|
|
(Child->Parent == NULL)) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
switch (IrpStack->Parameters.QueryDeviceRelations.Type) {
|
|
|
|
case TargetDeviceRelation:
|
|
|
|
deviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (!deviceRelations) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
status = ObReferenceObjectByPointer(Child->Self,
|
|
0,
|
|
NULL,
|
|
KernelMode);
|
|
if (!NT_SUCCESS(status)) {
|
|
ExFreePool(deviceRelations);
|
|
return status;
|
|
}
|
|
deviceRelations->Count = 1;
|
|
deviceRelations->Objects[0] = Child->Self;
|
|
Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
|
|
break;
|
|
|
|
default:
|
|
//
|
|
// Don't touch the status
|
|
//
|
|
break;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
//
|
|
// Seeing as the MF translator don't allocate any memory for their context the
|
|
// reference and dereference are nops.
|
|
//
|
|
|
|
VOID
|
|
MfTranslatorReference(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
}
|
|
|
|
VOID
|
|
MfTranslatorDereference(
|
|
IN PVOID Context
|
|
)
|
|
{
|
|
}
|
|
|
|
BOOLEAN
|
|
MfIsSubResource(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Super,
|
|
IN ULONGLONG SubStart,
|
|
IN ULONG SubLength,
|
|
OUT PULONGLONG Offset
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reports whether one resource descriptor is encapsulated
|
|
in another
|
|
|
|
Arguments:
|
|
|
|
Super - the resource descriptor that we want to encapsulate
|
|
SubStart - The start of the subrange
|
|
SubLength - The length of the subrange
|
|
Offset - On success the offset from the beginning of Super and
|
|
SubStart.
|
|
|
|
Return Value:
|
|
|
|
TRUE on succeess FALSE otherwise
|
|
--*/
|
|
|
|
NTSTATUS status;
|
|
ULONGLONG superStart;
|
|
ULONG superLength;
|
|
PMF_RESOURCE_TYPE restype;
|
|
|
|
PAGED_CODE();
|
|
|
|
ASSERT(Offset);
|
|
|
|
restype = MfFindResourceType(Super->Type);
|
|
|
|
if (restype == NULL) {
|
|
ASSERT(restype != NULL);
|
|
return FALSE;
|
|
}
|
|
|
|
status = restype->UnpackResource(Super,&superStart,&superLength);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
ASSERT(NT_SUCCESS(status));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// special case 0 length resources
|
|
//
|
|
|
|
if (superLength == 0) {
|
|
|
|
if (SubLength == 0 &&
|
|
SubStart == superStart) {
|
|
|
|
*Offset = 0;
|
|
return TRUE;
|
|
}
|
|
else return FALSE;
|
|
}
|
|
|
|
if (SubLength == 0) {
|
|
|
|
if (SubStart >= superStart &&
|
|
SubStart <= superStart + superLength - 1) {
|
|
|
|
*Offset = SubStart-superStart;
|
|
return TRUE;
|
|
}
|
|
|
|
else return FALSE;
|
|
}
|
|
|
|
//
|
|
// if SubStart falls in between the ends of Super, we have
|
|
// potential encapsulation
|
|
//
|
|
if ((SubStart >= superStart) && (SubStart <= superStart+superLength-1)) {
|
|
|
|
//
|
|
// It is an error if the two ranges overlap. Either
|
|
// Sub should be encapsulated in Super or they should
|
|
// not intersect.
|
|
//
|
|
ASSERT(SubStart+SubLength-1 <= superStart+superLength-1);
|
|
if (SubStart+SubLength-1 > superStart+superLength-1) {
|
|
return FALSE;
|
|
}
|
|
*Offset = SubStart-superStart;
|
|
return TRUE;
|
|
|
|
} else {
|
|
//
|
|
// Checking again to make sure ranges don't overlap
|
|
//
|
|
ASSERT((SubStart > superStart+superLength-1) ||
|
|
(SubStart+SubLength-1 < superStart));
|
|
return FALSE;
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MfPerformTranslation(
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated,
|
|
IN ULONGLONG Offset,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
|
|
)
|
|
{
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
stores the translated version of the Source resource in Target.
|
|
|
|
Arguments:
|
|
|
|
Source - the raw resource
|
|
Translated - the translated resource that matches the raw resource
|
|
that encapsulates Source.
|
|
offset - the offset of the beginning of Source from the raw parent
|
|
resource.
|
|
Target - the resource descriptor in which the translated version of
|
|
source is stored.
|
|
|
|
Return Value:
|
|
|
|
status of operation
|
|
|
|
--*/
|
|
|
|
NTSTATUS status;
|
|
PMF_RESOURCE_TYPE restype;
|
|
ULONGLONG translatedStart, dummy;
|
|
ULONG sourceLength, dummy2;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlCopyMemory(Target, Translated, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
|
|
//
|
|
// Get the length from the source
|
|
//
|
|
|
|
restype = MfFindResourceType(Source->Type);
|
|
if (restype == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = restype->UnpackResource(Source, &dummy, &sourceLength);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Get the start of the translated
|
|
//
|
|
|
|
restype = MfFindResourceType(Translated->Type);
|
|
if (restype == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = restype->UnpackResource(Translated, &translatedStart, &dummy2);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// Apply the offset and any length changes and update the descriptor
|
|
//
|
|
|
|
status = restype->UpdateResource(Target, translatedStart + Offset, sourceLength);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MfTransFromRawResources(
|
|
IN PVOID Context,
|
|
IN PCM_PARTIAL_RESOURCE_DESCRIPTOR Source,
|
|
IN RESOURCE_TRANSLATION_DIRECTION Direction,
|
|
IN ULONG AlternativesCount, OPTIONAL
|
|
IN IO_RESOURCE_DESCRIPTOR Alternatives[], OPTIONAL
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PCM_PARTIAL_RESOURCE_DESCRIPTOR Target
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Translates a raw resource into a global translated resource.
|
|
|
|
MF has translators to deal with child devices who request interrupts. The system
|
|
interrupt translator can translate for PDOs that have routing information in the BIOS.
|
|
This includes the MF parent device. MF child devices, however, are just logical
|
|
subdivisions of the MF parent device, so they don't have the appropriate BIOS goop,
|
|
and the system interrupt translator will fail translation on MF child PDOs.
|
|
|
|
To handle this, MF exposes a translator. It only translates resources, not requirements,
|
|
since raw requirements are the same as translated requirements. The translator recognizes
|
|
that child resources are simply sub-resources of parent resources. Therefore, for a given
|
|
raw child resource, the translator finds the raw parent resource that is a superset of the
|
|
child resource, and copies the corresponding translated parent resource into the translated
|
|
child resource, applying appropriate offsets. It then returns STATUS_TRANSLATION_COMPLETE
|
|
to indicate that this is the final translation, and no other translators should be sought
|
|
out for this device.
|
|
|
|
Thus, the system interrupt translator will do the appropriate translation for the parent,
|
|
and then MF applies this translation to the child inside its own translator. Returning
|
|
STATUS_TRANSLATION_COMPLETE prevents the system interrupt translator from being called
|
|
for the child device, and so prevents it from failing the translation.
|
|
|
|
Arguments:
|
|
|
|
Context - the parent extension that stores the raw and translated resources
|
|
Source - the raw child resource
|
|
Direction - ChildToParent or ParentToChild
|
|
PhysicalDeviceObject - the PDO associated with this
|
|
Target - the translated child resource
|
|
|
|
Return Value:
|
|
|
|
NT Status code. If the translation actually occurs, this will be STATUS_TRANSLATION_COMPLETE
|
|
to indicate that pnp does not need to traverse the tree any more to find other translators.
|
|
|
|
--*/
|
|
{
|
|
PMF_PARENT_EXTENSION parent = (PMF_PARENT_EXTENSION) Context;
|
|
PCM_PARTIAL_RESOURCE_DESCRIPTOR raw, translated;
|
|
NTSTATUS status;
|
|
ULONGLONG offset;
|
|
ULONGLONG sourceStart;
|
|
ULONG sourceLength;
|
|
PMF_RESOURCE_TYPE restype;
|
|
ULONG index;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (Direction == TranslateParentToChild) {
|
|
//
|
|
// Perform an identity translation
|
|
//
|
|
RtlCopyMemory(Target, Source, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
//
|
|
// Do some real translation
|
|
//
|
|
|
|
ASSERT(Direction == TranslateChildToParent);
|
|
|
|
restype = MfFindResourceType(Source->Type);
|
|
if (restype == NULL) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
status = restype->UnpackResource(Source,&sourceStart,&sourceLength);
|
|
if (!NT_SUCCESS(status)) {
|
|
return status;
|
|
}
|
|
|
|
//
|
|
// runs through raw and translated resource lists, looking for the
|
|
// element of the raw list that corresponds to the source we are
|
|
// given as a parameter, then does the translation using the parallel
|
|
// element of the translated list
|
|
//
|
|
index = 0;
|
|
status = STATUS_INVALID_PARAMETER;
|
|
FOR_ALL_CM_DESCRIPTORS(parent->ResourceList, raw) {
|
|
|
|
if (raw->Type == Source->Type
|
|
&& MfIsSubResource(raw, sourceStart, sourceLength, &offset)) {
|
|
|
|
//
|
|
// This is a match, look up the translated entry in the parallel array
|
|
//
|
|
translated = &parent->TranslatedResourceList->List[0].PartialResourceList.PartialDescriptors[index];
|
|
|
|
status = MfPerformTranslation(Source, translated, offset, Target);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// We did our translation from the translated resources our parent got
|
|
// and these are already
|
|
//
|
|
status = STATUS_TRANSLATION_COMPLETE;
|
|
}
|
|
break;
|
|
|
|
} else {
|
|
index++;
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfTransFromRawRequirements(
|
|
IN PVOID Context,
|
|
IN PIO_RESOURCE_DESCRIPTOR Source,
|
|
IN PDEVICE_OBJECT PhysicalDeviceObject,
|
|
OUT PULONG TargetCount,
|
|
OUT PIO_RESOURCE_DESCRIPTOR *Target
|
|
)
|
|
{
|
|
|
|
PAGED_CODE();
|
|
|
|
*Target = ExAllocatePool(PagedPool, sizeof(IO_RESOURCE_DESCRIPTOR));
|
|
if (!*Target) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(*Target, Source, sizeof(IO_RESOURCE_DESCRIPTOR));
|
|
*TargetCount = 1;
|
|
|
|
return STATUS_TRANSLATION_COMPLETE;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryInterfacePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PTRANSLATOR_INTERFACE transInterface;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) ||
|
|
(Child->Parent == NULL)) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
if (MfCompareGuid(&GUID_TRANSLATOR_INTERFACE_STANDARD,
|
|
IrpStack->Parameters.QueryInterface.InterfaceType)) {
|
|
|
|
transInterface = (PTRANSLATOR_INTERFACE)IrpStack->Parameters.QueryInterface.Interface;
|
|
|
|
transInterface->Size = sizeof(TRANSLATOR_INTERFACE);
|
|
transInterface->Version = MF_TRANSLATOR_INTERFACE_VERSION;
|
|
transInterface->Context = Child->Parent;
|
|
transInterface->InterfaceReference = MfTranslatorReference;
|
|
transInterface->InterfaceDereference = MfTranslatorDereference;
|
|
transInterface->TranslateResources = MfTransFromRawResources;
|
|
transInterface->TranslateResourceRequirements = MfTransFromRawRequirements;
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
// NTRAID#54667
|
|
// Aren't we supposed to reference this before returning it?
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} else if (MfCompareGuid(&GUID_ARBITER_INTERFACE_STANDARD,
|
|
IrpStack->Parameters.QueryInterface.InterfaceType)) {
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
} else if (MfCompareGuid(&GUID_MF_ENUMERATION_INTERFACE,
|
|
IrpStack->Parameters.QueryInterface.InterfaceType)) {
|
|
//
|
|
// Otherwise you wouldn't be able to instantiate MF on top of a
|
|
// MF child.
|
|
//
|
|
return Irp->IoStatus.Status;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Fire these off to the parent
|
|
//
|
|
|
|
// NOTE: There is the potential that some future interface(s)
|
|
// shouldn't be forwarded to the parent.
|
|
|
|
return MfForwardIrpToParent(Irp, Child, IrpStack);
|
|
}
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryCapabilitiesPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PDEVICE_CAPABILITIES capabilities;
|
|
IO_STACK_LOCATION location;
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) ||
|
|
(Child->Parent == NULL)) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
ASSERT (Child->Parent);
|
|
|
|
if (IrpStack->Parameters.DeviceCapabilities.Capabilities->Version != 1) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
capabilities = ExAllocatePool(PagedPool, sizeof(DEVICE_CAPABILITIES));
|
|
if (capabilities == NULL) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(capabilities, sizeof(DEVICE_CAPABILITIES));
|
|
capabilities->Size = sizeof(DEVICE_CAPABILITIES);
|
|
capabilities->Version = 1;
|
|
capabilities->Address = capabilities->UINumber = -1;
|
|
|
|
RtlZeroMemory(&location, sizeof(IO_STACK_LOCATION));
|
|
location.MajorFunction = IRP_MJ_PNP;
|
|
location.MinorFunction = IRP_MN_QUERY_CAPABILITIES;
|
|
location.Parameters.DeviceCapabilities.Capabilities = capabilities;
|
|
|
|
status = MfSendPnpIrp(Child->Parent->Self,
|
|
&location,
|
|
NULL);
|
|
if (NT_SUCCESS(status)) {
|
|
RtlCopyMemory(IrpStack->Parameters.DeviceCapabilities.Capabilities,
|
|
location.Parameters.DeviceCapabilities.Capabilities,
|
|
sizeof(DEVICE_CAPABILITIES)
|
|
);
|
|
|
|
//
|
|
// The child has now inherited the capabilities of the MF
|
|
// parent. Some of these capabilities must now be filtered
|
|
// out in order to avoid implying functionality that is really
|
|
// limited to the parent's bus driver.
|
|
//
|
|
|
|
//
|
|
// Child is not removable, lockable, ejectable or
|
|
// SurpriseRemovalOK. Ensure this
|
|
//
|
|
IrpStack->Parameters.DeviceCapabilities.Capabilities->LockSupported =
|
|
IrpStack->Parameters.DeviceCapabilities.Capabilities->EjectSupported =
|
|
IrpStack->Parameters.DeviceCapabilities.Capabilities->Removable =
|
|
IrpStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = FALSE;
|
|
}
|
|
|
|
ExFreePool(capabilities);
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryResourcesPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
//
|
|
// If the parent device had a boot config then it will have
|
|
// reported it (and they will have been preallocated). Don't
|
|
// bother to report boot configs for the children as they don't
|
|
// gain us anything other than extra arbitration.
|
|
//
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MfQueryResourceRequirementsPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
PIO_RESOURCE_REQUIREMENTS_LIST requirements;
|
|
|
|
PAGED_CODE();
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) ||
|
|
(Child->Parent == NULL)) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
status = MfBuildChildRequirements(Child, &requirements);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
#if DBG
|
|
DEBUG_MSG(1, ("Reporting resource requirements for child 0x%08x\n", Child));
|
|
MfDbgPrintIoResReqList(1, requirements);
|
|
#endif
|
|
Irp->IoStatus.Information = (ULONG_PTR) requirements;
|
|
}
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
MfQueryDeviceTextPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (IrpStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription) {
|
|
#define MF_DEFAULT_DEVICE_TEXT L"Multifunction Device"
|
|
ULONG len = sizeof(MF_DEFAULT_DEVICE_TEXT);
|
|
PWSTR pStr;
|
|
|
|
pStr = ExAllocatePool(PagedPool, len);
|
|
|
|
if (!pStr) {
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
} else {
|
|
RtlCopyMemory(pStr, MF_DEFAULT_DEVICE_TEXT, len);
|
|
Irp->IoStatus.Information = (ULONG_PTR) pStr;
|
|
status = STATUS_SUCCESS;
|
|
}
|
|
} else {
|
|
status = Irp->IoStatus.Status;
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryIdPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
PUNICODE_STRING copy;
|
|
PVOID buffer = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
Irp->IoStatus.Information = 0;
|
|
|
|
if ((Child->Common.DeviceState & MF_DEVICE_SURPRISE_REMOVED) ||
|
|
(Child->Parent == NULL)) {
|
|
return STATUS_NO_SUCH_DEVICE;
|
|
}
|
|
|
|
switch (IrpStack->Parameters.QueryId.IdType) {
|
|
case BusQueryDeviceID: // <Enumerator>\<Enumerator-specific device id>
|
|
|
|
return MfBuildDeviceID(Child->Parent,
|
|
(PWSTR*)&Irp->IoStatus.Information
|
|
);
|
|
break;
|
|
|
|
|
|
case BusQueryInstanceID: // persistent id for this instance of the device
|
|
|
|
return MfBuildInstanceID(Child,
|
|
(PWSTR*)&Irp->IoStatus.Information
|
|
);
|
|
|
|
break;
|
|
|
|
case BusQueryHardwareIDs: // Hardware ids
|
|
|
|
copy = &Child->Info.HardwareID;
|
|
|
|
break;
|
|
|
|
case BusQueryCompatibleIDs: // compatible device ids
|
|
|
|
copy = &Child->Info.CompatibleID;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
ASSERT(copy);
|
|
|
|
if (copy->Length == 0) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Allocate the buffer for the ID and copy it
|
|
//
|
|
|
|
buffer = ExAllocatePoolWithTag(PagedPool,
|
|
copy->Length,
|
|
MF_HARDWARE_COMPATIBLE_ID_TAG
|
|
);
|
|
|
|
if (!buffer) {
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
RtlCopyMemory(buffer, copy->Buffer, copy->Length);
|
|
|
|
Irp->IoStatus.Information = (ULONG_PTR) buffer;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
MfQueryPnpDeviceStatePdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
if (Child->Common.PagingCount > 0
|
|
|| Child->Common.HibernationCount > 0
|
|
|| Child->Common.DumpCount > 0) {
|
|
Irp->IoStatus.Information |= PNP_DEVICE_NOT_DISABLEABLE;
|
|
}
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// --- Power operations ---
|
|
//
|
|
|
|
NTSTATUS
|
|
MfDispatchPowerPdo(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine handles all IRP_MJ_POWER IRPs for PDO. It dispatches
|
|
to the routines described in the PoDispatchTable entry in the
|
|
device object extension.
|
|
|
|
This routine is NOT pageable as it can be called at DISPATCH_LEVEL
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Pointer to the device object for which this IRP applies.
|
|
|
|
Child - PDO extension
|
|
|
|
Irp - Pointer to the IRP_MJ_PNP IRP to dispatch.
|
|
|
|
IrpStack
|
|
|
|
Return Value:
|
|
|
|
NT status.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
PMF_COMMON_EXTENSION common = (PMF_COMMON_EXTENSION) Child;
|
|
|
|
|
|
if ((Child->Common.DeviceState & (MF_DEVICE_SURPRISE_REMOVED|MF_DEVICE_DELETED)) ||
|
|
(Child->Parent == NULL)) {
|
|
PoStartNextPowerIrp(Irp);
|
|
status = STATUS_NO_SUCH_DEVICE;
|
|
} else if ((IrpStack->MinorFunction <= IRP_MN_PO_MAXIMUM_FUNCTION) &&
|
|
(MfPoDispatchTablePdo[IrpStack->MinorFunction])) {
|
|
|
|
//
|
|
// We are interested in this irp...
|
|
//
|
|
|
|
DEBUG_MSG(1,
|
|
("--> Dispatching %s IRP for PDO 0x%08x\n",
|
|
PO_IRP_STRING(IrpStack->MinorFunction),
|
|
DeviceObject
|
|
));
|
|
|
|
status =
|
|
MfPoDispatchTablePdo[IrpStack->MinorFunction](Irp,
|
|
(PVOID) common,
|
|
IrpStack
|
|
);
|
|
} else {
|
|
|
|
//
|
|
// We don't know about this irp
|
|
//
|
|
|
|
DEBUG_MSG(0,
|
|
("Unknown POWER IRP 0x%x for PDO 0x%08x\n",
|
|
IrpStack->MinorFunction,
|
|
DeviceObject
|
|
));
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
if (status != STATUS_NOT_SUPPORTED) {
|
|
|
|
//
|
|
// We understood the irp so we can set status - otherwise leave
|
|
// the status alone as we don't know what we are doing and a filter
|
|
// might have done the job for us!
|
|
//
|
|
|
|
Irp->IoStatus.Status = status;
|
|
|
|
DEBUG_MSG(1,
|
|
("<-- Completing irp with status %s (0x%08x)\n",
|
|
STATUS_STRING(status),
|
|
status
|
|
));
|
|
|
|
} else {
|
|
|
|
DEBUG_MSG(1,
|
|
("<-- Completing unhandled irp, status is %s (0x%08x)\n",
|
|
STATUS_STRING(Irp->IoStatus.Status),
|
|
Irp->IoStatus.Status
|
|
));
|
|
|
|
status = Irp->IoStatus.Status;
|
|
|
|
}
|
|
|
|
ASSERT(status == Irp->IoStatus.Status);
|
|
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfSetPowerPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
|
|
NTSTATUS status;
|
|
POWER_STATE previousState;
|
|
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
|
|
//
|
|
// If this is a system power state then someone else in the stack will have
|
|
// set the policy and we just leave well alone as we don't know anything
|
|
// about the hardware.
|
|
//
|
|
|
|
if (IrpStack->Parameters.Power.Type == DevicePowerState) {
|
|
MfUpdatePowerPdo(Child,
|
|
IrpStack->Parameters.Power.State.DeviceState);
|
|
}
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
MfQueryPowerPdo(
|
|
IN PIRP Irp,
|
|
IN PMF_CHILD_EXTENSION Child,
|
|
IN PIO_STACK_LOCATION IrpStack
|
|
)
|
|
{
|
|
|
|
UNREFERENCED_PARAMETER(Irp);
|
|
UNREFERENCED_PARAMETER(Child);
|
|
UNREFERENCED_PARAMETER(IrpStack);
|
|
|
|
//
|
|
// We can go to any power state...
|
|
//
|
|
|
|
PoStartNextPowerIrp(Irp);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|