reactos/drivers/wdm/audio/backpln/portcls/irp.cpp

553 lines
16 KiB
C++

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS
* FILE: drivers/wdm/audio/backpln/portcls/irp.cpp
* PURPOSE: Port Class driver / IRP Handling
* PROGRAMMER: Andrew Greenwood
* Johannes Anderwald
* HISTORY:
* 27 Jan 07 Created
*/
#include "private.hpp"
#ifndef YDEBUG
#define NDEBUG
#endif
#include <debug.h>
typedef struct
{
PIRP Irp;
PDEVICE_OBJECT DeviceObject;
}QUERY_POWER_CONTEXT, *PQUERY_POWER_CONTEXT;
NTSTATUS
NTAPI
PortClsCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("PortClsCreate called\n");
return KsDispatchIrp(DeviceObject, Irp);
}
NTSTATUS
NTAPI
PortClsPnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
NTSTATUS Status;
PPCLASS_DEVICE_EXTENSION DeviceExt;
PIO_STACK_LOCATION IoStack;
POWER_STATE PowerState;
IResourceList* resource_list = NULL;
//ULONG Index;
//PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor, UnPartialDescriptor;
DeviceExt = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
IoStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("PortClsPnp called %u\n", IoStack->MinorFunction);
//PC_ASSERT(DeviceExt);
switch (IoStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
DPRINT("IRP_MN_START_DEVICE\n");
// Create the resource list
Status = PcNewResourceList(
&resource_list,
NULL,
PagedPool,
IoStack->Parameters.StartDevice.AllocatedResourcesTranslated,
IoStack->Parameters.StartDevice.AllocatedResources);
if (!NT_SUCCESS(Status))
{
DPRINT("PcNewResourceList failed [0x%8x]\n", Status);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
// forward irp to lower device object
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
if (!NT_SUCCESS(Status))
{
// lower device object failed to start
resource_list->Release();
// complete the request
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// return result
return Status;
}
// sanity check
//PC_ASSERT(DeviceExt->StartDevice);
// Call the StartDevice routine
DPRINT("Calling StartDevice at 0x%8p\n", DeviceExt->StartDevice);
Status = DeviceExt->StartDevice(DeviceObject, Irp, resource_list);
if (!NT_SUCCESS(Status))
{
DPRINT("StartDevice returned a failure code [0x%8x]\n", Status);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
// Assign the resource list to our extension
DeviceExt->resources = resource_list;
// store device power state
DeviceExt->DevicePowerState = PowerDeviceD0;
DeviceExt->SystemPowerState = PowerSystemWorking;
// notify power manager of current state
PowerState.DeviceState = DeviceExt->DevicePowerState;
PoSetPowerState(DeviceObject, DevicePowerState, PowerState);
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
case IRP_MN_REMOVE_DEVICE:
// Clean up
DPRINT("IRP_MN_REMOVE_DEVICE\n");
// sanity check
PC_ASSERT(DeviceExt);
// FIXME more cleanup */
if (DeviceExt->resources)
{
// free resource list */
DeviceExt->resources->Release();
// set to null
DeviceExt->resources = NULL;
}
// Forward request
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
case IRP_MN_QUERY_INTERFACE:
DPRINT("IRP_MN_QUERY_INTERFACE\n");
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
case IRP_MN_QUERY_DEVICE_RELATIONS:
DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS\n");
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS\n");
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
DPRINT("IRP_MN_QUERY_RESOURCE_REQUIREMENTS\n");
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
case IRP_MN_READ_CONFIG:
DPRINT("IRP_MN_READ_CONFIG\n");
Status = PcForwardIrpSynchronous(DeviceObject, Irp);
return PcCompleteIrp(DeviceObject, Irp, Status);
}
DPRINT("unhandled function %u\n", IoStack->MinorFunction);
Status = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
VOID
CALLBACK
PwrCompletionFunction(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR MinorFunction,
IN POWER_STATE PowerState,
IN PVOID Context,
IN PIO_STATUS_BLOCK IoStatus)
{
NTSTATUS Status;
PQUERY_POWER_CONTEXT PwrContext = (PQUERY_POWER_CONTEXT)Context;
if (NT_SUCCESS(IoStatus->Status))
{
// forward request to lower device object
Status = PcForwardIrpSynchronous(PwrContext->DeviceObject, PwrContext->Irp);
}
else
{
// failed
Status = IoStatus->Status;
}
// start next power irp
PoStartNextPowerIrp(PwrContext->Irp);
// complete request
PwrContext->Irp->IoStatus.Status = Status;
IoCompleteRequest(PwrContext->Irp, IO_NO_INCREMENT);
// free context
FreeItem(PwrContext, TAG_PORTCLASS);
}
NTSTATUS
NTAPI
PortClsPower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PPCLASS_DEVICE_EXTENSION DeviceExtension;
PQUERY_POWER_CONTEXT PwrContext;
POWER_STATE PowerState;
NTSTATUS Status = STATUS_SUCCESS;
DPRINT("PortClsPower called\n");
// get currrent stack location
IoStack = IoGetCurrentIrpStackLocation(Irp);
// get device extension
DeviceExtension = (PPCLASS_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
if (IoStack->MinorFunction != IRP_MN_SET_POWER && IoStack->MinorFunction != IRP_MN_QUERY_POWER)
{
// forward unknown requests down the stack and forget
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(DeviceExtension->PrevDeviceObject, Irp);
}
// get current request type
if (IoStack->Parameters.Power.Type == DevicePowerState)
{
// request for device power state
if (DeviceExtension->DevicePowerState == IoStack->Parameters.Power.State.DeviceState)
{
// nothing has changed
if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
{
// only forward query requests; we can forget about them
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(DeviceExtension->PrevDeviceObject, Irp);
}
// start next power irp
PoStartNextPowerIrp(Irp);
// complete request
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// done
return Status;
}
if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
{
// check if there is a registered adapter power management
if (DeviceExtension->AdapterPowerManagement)
{
// it is query if the change can be changed
PowerState = IoStack->Parameters.Power.State;
Status = DeviceExtension->AdapterPowerManagement->QueryPowerChangeState(PowerState);
if (!NT_SUCCESS(Status))
{
// fail the IRP if the adapter power manager failed
PoStartNextPowerIrp(Irp);
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
}
// only forward query requests
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(DeviceExtension->PrevDeviceObject, Irp);
}
else
{
// set power state
PowerState = IoStack->Parameters.Power.State;
PoSetPowerState(DeviceObject, DevicePowerState, PowerState);
// check if there is a registered adapter power management
if (DeviceExtension->AdapterPowerManagement)
{
// notify of a power change state
DeviceExtension->AdapterPowerManagement->PowerChangeState(PowerState);
}
// FIXME call all registered IPowerNotify interfaces via ISubdevice interface
// store new power state
DeviceExtension->DevicePowerState = IoStack->Parameters.Power.State.DeviceState;
// complete request
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// done
return Status;
}
}
else
{
// sanity check
PC_ASSERT(IoStack->Parameters.Power.Type == SystemPowerState);
if (IoStack->MinorFunction == IRP_MN_QUERY_POWER)
{
// mark irp as pending
IoMarkIrpPending(Irp);
// allocate power completion context
PwrContext = (PQUERY_POWER_CONTEXT)AllocateItem(NonPagedPool, sizeof(QUERY_POWER_CONTEXT), TAG_PORTCLASS);
if (!PwrContext)
{
// no memory
PoStartNextPowerIrp(Irp);
// complete and forget
Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// done
return STATUS_PENDING;
}
// setup power context
PwrContext->Irp = Irp;
PwrContext->DeviceObject = DeviceObject;
// pass the irp down
PowerState = IoStack->Parameters.Power.State;
Status = PoRequestPowerIrp(DeviceExtension->PhysicalDeviceObject, IoStack->MinorFunction, PowerState, PwrCompletionFunction, (PVOID)PwrContext, NULL);
// check for success
if (!NT_SUCCESS(Status))
{
// failed
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
// done
return STATUS_PENDING;
}
// done
return STATUS_PENDING;
}
else
{
// set power request
DeviceExtension->SystemPowerState = IoStack->Parameters.Power.State.SystemState;
// only forward query requests
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(DeviceExtension->PrevDeviceObject, Irp);
}
}
}
NTSTATUS
NTAPI
PortClsSysControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
DPRINT("PortClsSysControl called\n");
// TODO
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PortClsShutdown(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPCLASS_DEVICE_EXTENSION DeviceExtension;
DPRINT("PortClsShutdown called\n");
// get device extension
DeviceExtension = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
if (DeviceExtension->AdapterPowerManagement)
{
// release adapter power management
DPRINT("Power %u\n", DeviceExtension->AdapterPowerManagement->Release());
}
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PcDispatchIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
IoStack = IoGetCurrentIrpStackLocation(Irp);
DPRINT("PcDispatchIrp called - handling IRP in PortCls MajorFunction %x MinorFunction %x\n", IoStack->MajorFunction, IoStack->MinorFunction);
switch ( IoStack->MajorFunction )
{
// PortCls
case IRP_MJ_CREATE :
return PortClsCreate(DeviceObject, Irp);
case IRP_MJ_PNP :
return PortClsPnp(DeviceObject, Irp);
case IRP_MJ_POWER :
return PortClsPower(DeviceObject, Irp);
case IRP_MJ_DEVICE_CONTROL:
return KsDispatchIrp(DeviceObject, Irp);
case IRP_MJ_CLOSE:
return KsDispatchIrp(DeviceObject, Irp);
case IRP_MJ_SYSTEM_CONTROL :
return PortClsSysControl(DeviceObject, Irp);
case IRP_MJ_SHUTDOWN:
return PortClsShutdown(DeviceObject, Irp);
default:
DPRINT("Unhandled function %x\n", IoStack->MajorFunction);
break;
};
// If we reach here, we just complete the IRP
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
NTAPI
PcCompleteIrp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN NTSTATUS Status)
{
#if 0
PC_ASSERT(DeviceObject);
PC_ASSERT(Irp);
PC_ASSERT(Status != STATUS_PENDING);
#endif
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
NTAPI
CompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context)
{
if (Irp->PendingReturned != FALSE)
{
KeSetEvent ((PKEVENT) Context, IO_NO_INCREMENT, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
#undef IoSetCompletionRoutine
#define IoSetCompletionRoutine(_Irp, \
_CompletionRoutine, \
_Context, \
_InvokeOnSuccess, \
_InvokeOnError, \
_InvokeOnCancel) \
{ \
PIO_STACK_LOCATION _IrpSp; \
_IrpSp = IoGetNextIrpStackLocation(_Irp); \
_IrpSp->CompletionRoutine = (PIO_COMPLETION_ROUTINE)(_CompletionRoutine); \
_IrpSp->Context = (_Context); \
_IrpSp->Control = 0; \
if (_InvokeOnSuccess) _IrpSp->Control = SL_INVOKE_ON_SUCCESS; \
if (_InvokeOnError) _IrpSp->Control |= SL_INVOKE_ON_ERROR; \
if (_InvokeOnCancel) _IrpSp->Control |= SL_INVOKE_ON_CANCEL; \
}
NTSTATUS
NTAPI
PcForwardIrpSynchronous(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
KEVENT Event;
PPCLASS_DEVICE_EXTENSION DeviceExt;
NTSTATUS Status;
PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
DeviceExt = (PPCLASS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
// initialize the notification event
KeInitializeEvent(&Event, NotificationEvent, FALSE);
// are there enough irp stack locations
if (Irp->CurrentLocation < Irp->StackCount + 1)
{
IoCopyCurrentIrpStackLocationToNext(Irp);
}
IoSetCompletionRoutine(Irp, CompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
// now call the driver
Status = IoCallDriver(DeviceExt->PrevDeviceObject, Irp);
// did the request complete yet
if (Status == STATUS_PENDING)
{
// not yet, lets wait a bit
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = Irp->IoStatus.Status;
}
return Status;
}