reactos/sdk/lib/drivers/wdf/shared/irphandlers/pnp/km/fxpkgpdokm.cpp
Victor Perevertkin 1f377076d7
[WDF] Fix KMDF so it can compile with ReactOS SDK
Not all files are included, but these are necessary to compile cdrom driver.
So far it can only be statically linked with drivers, a proper
implementation requires wdfldr helper driver
2020-11-03 00:06:27 +03:00

387 lines
11 KiB
C++

/*++
Copyright (c) Microsoft Corporation
Module Name:
FxPkgPdoKM.cpp
Abstract:
This module implements the Pnp package for Pdo devices.
Author:
Environment:
Kernel mode only
Revision History:
--*/
#include "../pnppriv.hpp"
#include <wdmguid.h>
// Tracing support
#if defined(EVENT_TRACING)
extern "C" {
#include "FxPkgPdoKM.tmh"
}
#endif
_Must_inspect_result_
NTSTATUS
FxPkgPdo::_PnpQueryResources(
__inout FxPkgPnp* This,
__inout FxIrp *Irp
)
{
return ((FxPkgPdo*) This)->PnpQueryResources(Irp);
}
_Must_inspect_result_
NTSTATUS
FxPkgPdo::PnpQueryResources(
__inout FxIrp *Irp
)
/*++
Routine Description:
This method is invoked in response to a Pnp QueryResources IRP. We return
the resources that the device is currently consuming.
Arguments:
Irp - a pointer to the FxIrp
Returns:
NTSTATUS
--*/
{
FxCmResList *pResList = NULL;
PCM_RESOURCE_LIST pWdmResourceList;
WDFCMRESLIST list;
NTSTATUS status;
//
// It is only necessary to create a collection if the caller is interested
// in this callback.
//
if (m_DeviceResourcesQuery.m_Method == NULL) {
return CompletePnpRequest(Irp, Irp->GetStatus());
}
pWdmResourceList = NULL;
status = FxCmResList::_CreateAndInit(&pResList,
GetDriverGlobals(),
m_Device,
WDF_NO_OBJECT_ATTRIBUTES,
FxResourceAllAccessAllowed);
if (!NT_SUCCESS(status)) {
goto exit;
}
status = pResList->Commit(NULL, (PWDFOBJECT) &list);
if (NT_SUCCESS(status)) {
status = m_DeviceResourcesQuery.Invoke(
m_Device->GetHandle(), list);
if (NT_SUCCESS(status)) {
//
// Walk the resource collection and create the appropriate
// CM_RESOURCE_LIST.
//
if (pResList->Count()) {
pWdmResourceList = pResList->CreateWdmList();
}
else {
//
// The driver didn't add any resources, so we'll just
// ignore this Irp.
//
// Return that status that was passed in.
//
status = Irp->GetStatus();
pWdmResourceList = (PCM_RESOURCE_LIST) Irp->GetInformation();
}
}
}
pResList->DeleteObject();
exit:
Irp->SetInformation((ULONG_PTR) pWdmResourceList);
return CompletePnpRequest(Irp, status);
}
_Must_inspect_result_
NTSTATUS
FxPkgPdo::_PnpQueryResourceRequirements(
__inout FxPkgPnp* This,
__inout FxIrp *Irp
)
{
return ((FxPkgPdo*) This)->PnpQueryResourceRequirements(Irp);
}
_Must_inspect_result_
NTSTATUS
FxPkgPdo::PnpQueryResourceRequirements(
__inout FxIrp *Irp
)
/*++
Routine Description:
This method is invoked in response to a Pnp QueryResourceRequirements IRP.
We return the set (of sets) of possible resources that we could accept
which would allow our device to work.
Arguments:
Irp - a pointer to the FxIrp
Returns:
NTSTATUS
--*/
{
PIO_RESOURCE_REQUIREMENTS_LIST pWdmRequirementsList;
FxIoResReqList *pIoResReqList = NULL;
PSINGLE_LIST_ENTRY ple;
NTSTATUS status;
status = STATUS_SUCCESS;
m_DeviceInterfaceLock.AcquireLock(GetDriverGlobals());
// We know for sure that the PDO is known to pnp now because it has received
// this query resource requirements request.
m_Device->m_PdoKnown = TRUE;
//
// Now that it is a known PDO, we can register interfaces on it whose
// registration was delayed because the PDO was unknown at the time of the
// call to WdfDeviceCreateDeviceInterface. If it is not the first time
// then we re-register (see comments below for reason).
//
for (ple = m_DeviceInterfaceHead.Next; ple != NULL; ple = ple->Next) {
FxDeviceInterface *pDeviceInterface;
pDeviceInterface = FxDeviceInterface::_FromEntry(ple);
//
// At this time the interface may be in registered or unregistered state.
// The reason being that pnp may unregister the interface from underneath
// during the life of PDO (note that drivers never unregister explicitly
// as there is no unregistration API, and the scenarios in which it can
// happen are given below). Therefore WDF needs to re-register the interface,
// otherwise driver may end up with an unregistered interface and fail to
// enable interface.
//
// Pnp can unregister the interface in following cases:
// 1. The driver is uninstalled, and re-installed
// In this case, the stack is torn down but the PDO is not
// deleted. Pnp deletes the interface registration, however WDF
// doesn't delete the interface structure because it is deleted as
// part of PDO deletion in destructor. When the driver is re-installed
// Pnp sends another query resource requirements irp and WDF needs to
// re-register at this time.
//
// 2. Pnp couldn't find a driver and loaded a NULL driver while
// waiting for reinstall to happen from WU. This is similar to case above
// except that the pnp activities are transparent to user.
// In this case, PDO was never started. However it did get
// the query resource requirements irp and therefore its interface
// was registered by WDF. Pnp deleted the interface registration
// when installing NULL driver. When pnp finally finds a driver from
// WU, it sends another query resource requirement irp. At this time,
// WDF needs to re-register.
//
// In both the above cases, WDF has to re-register (and free previous
// sym link) when query resource requirements irp arrives again. Note
// that Pnp doesn't delete the interface registration during disable,
// s/w surprise-removal, or resource rebalance. In case of resource
// rebalance, query resource requirement irp is sent after stop, and
// WDF will end up registering again even though pnp did not unregister
// the interface. This is fine because kernel API for registration
// allows multiple calls to register, and in case registration already
// exists it returns informational status (not error status)
// STATUS_OBJECT_NAME_EXISTS and also returns the same symbolic link.
//
//
// Free the symbolic link if already present
//
if (pDeviceInterface->m_SymbolicLinkName.Buffer != NULL) {
RtlFreeUnicodeString(&pDeviceInterface->m_SymbolicLinkName);
RtlZeroMemory(&pDeviceInterface->m_SymbolicLinkName,
sizeof(pDeviceInterface->m_SymbolicLinkName));
}
//
// Register. Note that if the interface was already registered, the
// call to IoRegisterDeviceInterface will return informational status
// (not error status) STATUS_OBJECT_NAME_EXISTS and also return the
// symbolic link.
//
status = pDeviceInterface->Register(
m_Device->GetPhysicalDevice()
);
if (!NT_SUCCESS(status)) {
DoTraceLevelMessage(
GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGPNP,
"could not register device interface on PDO WDFDEVICE %p, "
"!devobj %p, failing IRP_MN_QUERY_RESOURCE_REQUIREMENTS %!STATUS!",
m_Device->GetHandle(),
m_Device->GetDeviceObject(), status);
break;
}
}
m_DeviceInterfaceLock.ReleaseLock(GetDriverGlobals());
if (!NT_SUCCESS(status)) {
return CompletePnpRequest(Irp, status);
}
//
// Driver writer is not interested in this callback, forgoe the allocation
// of the FxCollection and complete the request here.
//
if (m_DeviceResourceRequirementsQuery.m_Method == NULL) {
return CompletePnpRequest(Irp, status);
}
pWdmRequirementsList = NULL;
//
// Create a collection which will be populated by the
// bus driver.
//
status = FxIoResReqList::_CreateAndInit(&pIoResReqList,
GetDriverGlobals(),
WDF_NO_OBJECT_ATTRIBUTES,
FxResourceAllAccessAllowed);
if (!NT_SUCCESS(status)) {
goto exit;
}
WDFIORESREQLIST reqlist;
//
// Get a handle to the collection that can be passed to the driver.
//
status = pIoResReqList->Commit(NULL, (PWDFOBJECT) &reqlist);
//
// We control the object's state, this should never fail
//
ASSERT(NT_SUCCESS(status));
UNREFERENCED_PARAMETER(status);
//
// Call the driver. The driver will populate the resource collection
// with a set of child collections which will contain each of the
// possible resource assignments.
//
status = m_DeviceResourceRequirementsQuery.Invoke(
m_Device->GetHandle(), reqlist);
if (NT_SUCCESS(status)) {
if (pIoResReqList->Count()) {
//
// Create a IO_RESOURCE_REQUIREMENTS_LIST based on the
// contents of our collection.
//
pWdmRequirementsList = pIoResReqList->CreateWdmList();
if (pWdmRequirementsList != NULL) {
Irp->SetInformation((ULONG_PTR) pWdmRequirementsList);
}
else {
status = STATUS_INSUFFICIENT_RESOURCES;
}
}
else {
//
// The driver didn't add any resources, so we'll just
// ignore this request.
//
// Return the status that was passed in.
//
status = Irp->GetStatus();
}
}
pIoResReqList->DeleteObject();
exit:
return CompletePnpRequest(Irp, status);
}
_Must_inspect_result_
NTSTATUS
FxPkgPdo::_PnpFilterResourceRequirements(
__inout FxPkgPnp* This,
__inout FxIrp *Irp
)
/*++
Routine Description:
Filter resource requirements for the PDO. A chance to further muck with
the resources assigned to the device.
Arguments:
This - the package
Irp - the request
Return Value:
NTSTATUS
--*/
{
NTSTATUS status;
//
// Give the Framework objects a pass at the list.
//
status = ((FxPkgPdo*) This)->FilterResourceRequirements(
(PIO_RESOURCE_REQUIREMENTS_LIST*)(&Irp->GetIrp()->IoStatus.Information)
);
if (NT_SUCCESS(status)) {
//
// Upon successful internal filtering, return the embedded status.
//
status = Irp->GetStatus();
}
else {
//
// Only on failure do we change the status of the irp
//
Irp->SetStatus(status);
}
return ((FxPkgPdo*) This)->CompletePnpRequest(Irp, status);
}