Windows-Server-2003/net/unimodem/sample/sys/pnp.c

436 lines
12 KiB
C

/*
* UNIMODEM "Fakemodem" controllerless driver illustrative example
*
* (C) 2000 Microsoft Corporation
* All Rights Reserved
*
*/
#include "fakemodem.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,FakeModemPnP)
#pragma alloc_text(PAGE,FakeModemDealWithResources)
#endif
NTSTATUS
ForwardIrp(
PDEVICE_OBJECT NextDevice,
PIRP Irp
)
{
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(NextDevice, Irp);
}
NTSTATUS
FakeModemAdapterIoCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PKEVENT pdoIoCompletedEvent
)
{
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
WaitForLowerDriverToCompleteIrp(
PDEVICE_OBJECT TargetDeviceObject,
PIRP Irp,
PKEVENT Event
)
{
NTSTATUS Status;
KeResetEvent(Event);
IoSetCompletionRoutine(Irp, FakeModemAdapterIoCompletion, Event, TRUE,
TRUE, TRUE);
Status = IoCallDriver(TargetDeviceObject, Irp);
if (Status == STATUS_PENDING)
{
D_ERROR(DbgPrint("MODEM: Waiting for PDO\n");)
KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
}
return Irp->IoStatus.Status;
}
NTSTATUS
FakeModemPnP(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
KEVENT pdoStartedEvent;
NTSTATUS status;
PDEVICE_RELATIONS deviceRelations = NULL;
PDEVICE_RELATIONS *DeviceRelations;
ULONG newRelationsSize, oldRelationsSize = 0;
switch (irpSp->MinorFunction) {
case IRP_MN_START_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_START_DEVICE\n");)
// Send this down to the PDO first so the bus driver can setup
// our resources so we can talk to the hardware
KeInitializeEvent(&deviceExtension->PdoStartEvent,
SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
status=WaitForLowerDriverToCompleteIrp(
deviceExtension->LowerDevice, Irp,
&deviceExtension->PdoStartEvent);
if (status == STATUS_SUCCESS)
{
deviceExtension->Started=TRUE;
//
// do something useful with resources
//
FakeModemDealWithResources(DeviceObject, Irp);
}
Irp->IoStatus.Status = status;
Irp->IoStatus.Information=0L;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return status;
case IRP_MN_QUERY_DEVICE_RELATIONS: {
PDEVICE_RELATIONS CurrentRelations=
(PDEVICE_RELATIONS)Irp->IoStatus.Information;
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_DEVICE_RELATIONS type=%d\n",irpSp->Parameters.QueryDeviceRelations.Type);)
D_PNP(DbgPrint(" Information=%08lx\n",Irp->IoStatus.Information);)
switch (irpSp->Parameters.QueryDeviceRelations.Type )
{
case TargetDeviceRelation:
default: {
IoCopyCurrentIrpStackLocationToNext(Irp);
return IoCallDriver(deviceExtension->LowerDevice, Irp);
}
}
}
case IRP_MN_QUERY_REMOVE_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_REMOVE_DEVICE\n");)
deviceExtension->Removing=TRUE;
return ForwardIrp(deviceExtension->LowerDevice,Irp);
case IRP_MN_CANCEL_REMOVE_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_CANCEL_REMOVE_DEVICE\n");)
deviceExtension->Removing=FALSE;
return ForwardIrp(deviceExtension->LowerDevice,Irp);
case IRP_MN_SURPRISE_REMOVAL:
// Fall through
case IRP_MN_REMOVE_DEVICE: {
ULONG NewReferenceCount;
NTSTATUS StatusToReturn;
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE\n");)
// the device is going away, block new requests
deviceExtension->Removing=TRUE;
// Complete all pending requests
FakeModemKillPendingIrps(DeviceObject);
// send it down to the PDO
IoCopyCurrentIrpStackLocationToNext(Irp);
StatusToReturn=IoCallDriver(deviceExtension->LowerDevice, Irp);
// remove the ref for the AddDevice
NewReferenceCount=InterlockedDecrement
(&deviceExtension->ReferenceCount);
if (NewReferenceCount != 0) {
// Still have outstanding request, wait
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE- waiting for refcount to drop, %d\n",NewReferenceCount);)
KeWaitForSingleObject(&deviceExtension->RemoveEvent,
Executive, KernelMode, FALSE, NULL);
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE- Done waiting\n");)
}
ASSERT(deviceExtension->ReferenceCount == 0);
IoDetachDevice(deviceExtension->LowerDevice);
IoDeleteDevice(DeviceObject);
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_REMOVE_DEVICE %08lx\n",StatusToReturn);)
return StatusToReturn;
}
case IRP_MN_QUERY_STOP_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_STOP_DEVICE\n");)
if (deviceExtension->OpenCount != 0) {
// no can do
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_QUERY_STOP_DEVICE -- failing\n");)
Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
IoCompleteRequest( Irp, IO_NO_INCREMENT);
return STATUS_UNSUCCESSFUL;
}
deviceExtension->Started=FALSE;
return ForwardIrp(deviceExtension->LowerDevice,Irp);
case IRP_MN_CANCEL_STOP_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_CANCEL_STOP_DEVICE\n");)
deviceExtension->Started=TRUE;
return ForwardIrp(deviceExtension->LowerDevice,Irp);
case IRP_MN_STOP_DEVICE:
D_PNP(DbgPrint("FAKEMODEM: IRP_MN_STOP_DEVICE\n");)
deviceExtension->Started=FALSE;
return ForwardIrp(deviceExtension->LowerDevice,Irp);
case IRP_MN_QUERY_CAPABILITIES: {
ULONG i;
KEVENT WaitEvent;
// Send this down to the PDO first
KeInitializeEvent(&WaitEvent, SynchronizationEvent, FALSE);
IoCopyCurrentIrpStackLocationToNext(Irp);
status=WaitForLowerDriverToCompleteIrp
(deviceExtension->LowerDevice, Irp, &WaitEvent);
irpSp = IoGetCurrentIrpStackLocation(Irp);
for (i = PowerSystemUnspecified; i < PowerSystemMaximum; i++)
{
deviceExtension->SystemPowerStateMap[i]=PowerDeviceD3;
}
for (i = PowerSystemWorking; i < PowerSystemHibernate; i++) {
D_POWER(DbgPrint("FAKEMODEM: DevicePower for System %d is %d\n",i,irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i]);)
deviceExtension->SystemPowerStateMap[i]=irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceState[i];
}
deviceExtension->SystemPowerStateMap[PowerSystemWorking]=PowerDeviceD0;
deviceExtension->SystemWake=irpSp->Parameters.DeviceCapabilities.Capabilities->SystemWake;
deviceExtension->DeviceWake=irpSp->Parameters.DeviceCapabilities.Capabilities->DeviceWake;
D_POWER(DbgPrint("FAKEMODEM: DeviceWake=%d, SystemWake=%d\n",
deviceExtension->DeviceWake,
deviceExtension->SystemWake);)
IoCompleteRequest( Irp, IO_NO_INCREMENT);
return status;
}
default:
D_PNP(DbgPrint("FAKEMODEM: PnP IRP, MN func=%d\n",irpSp->MinorFunction);)
return ForwardIrp(deviceExtension->LowerDevice,Irp);
}
// If device has started again then we can continue processing
if (deviceExtension->Started)
{
WriteIrpWorker(DeviceObject);
}
return STATUS_SUCCESS;
}
NTSTATUS
FakeModemDealWithResources(
IN PDEVICE_OBJECT Fdo,
IN PIRP Irp
)
{
NTSTATUS status = STATUS_SUCCESS;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
ULONG count;
ULONG i;
PCM_RESOURCE_LIST pResourceList;
PCM_PARTIAL_RESOURCE_LIST pPartialResourceList;
PCM_PARTIAL_RESOURCE_DESCRIPTOR pPartialResourceDesc;
PCM_FULL_RESOURCE_DESCRIPTOR pFullResourceDesc = NULL;
// Get resource list
pResourceList = irpSp->Parameters.StartDevice.AllocatedResources;
if (pResourceList != NULL) {
pFullResourceDesc = &pResourceList->List[0];
} else {
pFullResourceDesc=NULL;
}
// Ok, if we have a full resource descriptor. Let's take it apart.
if (pFullResourceDesc) {
pPartialResourceList = &pFullResourceDesc->PartialResourceList;
pPartialResourceDesc = pPartialResourceList->PartialDescriptors;
count = pPartialResourceList->Count;
// Pull out the stuff that is in the full descriptor.
// Now run through the partial resource descriptors looking for the
// port interrupt, and clock rate.
for (i = 0; i < count; i++, pPartialResourceDesc++) {
switch (pPartialResourceDesc->Type) {
case CmResourceTypeMemory: {
D_PNP(DbgPrint("FAKEMODEM: Memory resource at %x, length %d, addressSpace=%d\n",
pPartialResourceDesc->u.Memory.Start.LowPart,
pPartialResourceDesc->u.Memory.Length,
pPartialResourceDesc->Flags
);)
break;
}
case CmResourceTypePort: {
D_PNP(DbgPrint("FAKEMODEM: Port resource at %x, length %d, addressSpace=%d\n",
pPartialResourceDesc->u.Port.Start.LowPart,
pPartialResourceDesc->u.Port.Length,
pPartialResourceDesc->Flags
);)
break;
}
case CmResourceTypeDma: {
D_PNP(DbgPrint("FAKEMODEM: DMA channel %d, port %d, addressSpace=%d\n",
pPartialResourceDesc->u.Dma.Channel,
pPartialResourceDesc->u.Dma.Port
);)
break;
break;
}
case CmResourceTypeInterrupt: {
D_PNP(DbgPrint("FAKEMODEM: Interrupt resource, level=%d, vector=%d, %s\n",
pPartialResourceDesc->u.Interrupt.Level,
pPartialResourceDesc->u.Interrupt.Vector,
(pPartialResourceDesc->Flags & CM_RESOURCE_INTERRUPT_LATCHED) ? "Latched" : "Level"
);)
break;
}
default: {
D_PNP(DbgPrint("FAKEMODEM: Other resources\n");)
break;
}
}
}
}
return status;
}