/* * 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; }