/*++ Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved Module Name: pnp.c Abstract: This module contains plug & play code for the serial Mouse Filter Driver, including code for the creation and removal of serial mouse device contexts. Environment: Kernel & user mode. Revision History: --*/ #include "mouser.h" #include "sermlog.h" #include "debug.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGE, SerialMouseAddDevice) #pragma alloc_text(PAGE, SerialMousePnP) #pragma alloc_text(PAGE, SerialMousePower) #pragma alloc_text(PAGE, SerialMouseRemoveDevice) #pragma alloc_text(PAGE, SerialMouseSendIrpSynchronously) #endif NTSTATUS SerialMouseAddDevice ( IN PDRIVER_OBJECT Driver, IN PDEVICE_OBJECT PDO ) /*++ Routine Description: Arguments: Return Value: NTSTATUS result code. --*/ { NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION deviceExtension; PDEVICE_OBJECT device; KIRQL oldIrql; PAGED_CODE(); status = IoCreateDevice(Driver, sizeof(DEVICE_EXTENSION), NULL, // no name for this Filter DO FILE_DEVICE_SERIAL_MOUSE_PORT, 0, FALSE, &device); if (!NT_SUCCESS(status)) { return status; } deviceExtension = (PDEVICE_EXTENSION) device->DeviceExtension; Print(deviceExtension, DBG_PNP_TRACE, ("enter Add Device\n")); // // Initialize the fields. // RtlZeroMemory(deviceExtension, sizeof(DEVICE_EXTENSION)); deviceExtension->TopOfStack = IoAttachDeviceToDeviceStack(device, PDO); if (deviceExtension->TopOfStack == NULL) { PIO_ERROR_LOG_PACKET errorLogEntry; // // Not good; in only extreme cases will this fail // errorLogEntry = (PIO_ERROR_LOG_PACKET) IoAllocateErrorLogEntry(Driver, (UCHAR) sizeof(IO_ERROR_LOG_PACKET)); if (errorLogEntry) { errorLogEntry->ErrorCode = SERMOUSE_ATTACH_DEVICE_FAILED; errorLogEntry->DumpDataSize = 0; errorLogEntry->SequenceNumber = 0; errorLogEntry->MajorFunctionCode = 0; errorLogEntry->IoControlCode = 0; errorLogEntry->RetryCount = 0; errorLogEntry->UniqueErrorValue = 0; errorLogEntry->FinalStatus = STATUS_DEVICE_NOT_CONNECTED; IoWriteErrorLogEntry(errorLogEntry); } IoDeleteDevice(device); return STATUS_DEVICE_NOT_CONNECTED; } ASSERT(deviceExtension->TopOfStack); deviceExtension->PDO = PDO; deviceExtension->Self = device; deviceExtension->Removed = FALSE; deviceExtension->Started = FALSE; deviceExtension->Stopped = FALSE; deviceExtension->PowerState = PowerDeviceD0; deviceExtension->WaitWakePending = FALSE; KeInitializeSpinLock(&deviceExtension->PnpStateLock); KeInitializeEvent(&deviceExtension->StopEvent, SynchronizationEvent, FALSE); IoInitializeRemoveLock(&deviceExtension->RemoveLock, SERMOU_POOL_TAG, 0, 10); deviceExtension->ReadIrp = IoAllocateIrp( device->StackSize, FALSE ); if (!deviceExtension->ReadIrp) { // // The ReadIrp is critical to this driver, if we can't get one, no use // in going any further // IoDetachDevice(deviceExtension->TopOfStack); IoDeleteDevice(device); return STATUS_INSUFFICIENT_RESOURCES; } deviceExtension->WmiLibInfo.GuidCount = sizeof(WmiGuidList) / sizeof(WMIGUIDREGINFO); deviceExtension->WmiLibInfo.GuidList = WmiGuidList; deviceExtension->WmiLibInfo.QueryWmiRegInfo = SerialMouseQueryWmiRegInfo; deviceExtension->WmiLibInfo.QueryWmiDataBlock = SerialMouseQueryWmiDataBlock; deviceExtension->WmiLibInfo.SetWmiDataBlock = SerialMouseSetWmiDataBlock; deviceExtension->WmiLibInfo.SetWmiDataItem = SerialMouseSetWmiDataItem; deviceExtension->WmiLibInfo.ExecuteWmiMethod = NULL; deviceExtension->WmiLibInfo.WmiFunctionControl = NULL; IoWMIRegistrationControl(deviceExtension->Self, WMIREG_ACTION_REGISTER); KeInitializeTimer(&deviceExtension->DelayTimer); // // Set all the appropriate device object flags // device->Flags &= ~DO_DEVICE_INITIALIZING; device->Flags |= DO_BUFFERED_IO; device->Flags |= DO_POWER_PAGABLE; return status; } VOID SerialMouseRemoveDevice( PDEVICE_EXTENSION DeviceExtension, PIRP Irp ) { BOOLEAN closePort = FALSE; PAGED_CODE(); // // Run the (surprise remove code). If we are surprise removed, then this // will be called twice. We only run the removal code once. // if (!DeviceExtension->SurpriseRemoved) { DeviceExtension->SurpriseRemoved = TRUE; // // Here if we had any outstanding requests in a personal queue we should // complete them all now. // // Note, the device could be GONE so we cannot send it any non- // PNP IRPS. // IoWMIRegistrationControl(DeviceExtension->Self, WMIREG_ACTION_DEREGISTER); if (DeviceExtension->Started && DeviceExtension->EnableCount > 0) { Print(DeviceExtension, DBG_PNP_INFO, ("Cancelling and stopping detection for remove\n")); IoCancelIrp(DeviceExtension->ReadIrp); // // Cancel the detection timer, SerialMouseRemoveLockAndWait will // guarantee that we don't yank the device from under the polling // routine // SerialMouseStopDetection(DeviceExtension); } } // // The stack is about to be torn down, make sure that the underlying serial // port is closed. No other piece of code will be looking at EnableCount if // Remove is true, so there is no need for InterlockedXxx. // if (DeviceExtension->Removed && DeviceExtension->EnableCount > 0) { Print(DeviceExtension, DBG_PNP_INFO | DBG_PNP_ERROR, ("sending final close, enable count %d\n", DeviceExtension->EnableCount)); DeviceExtension->EnableCount = 0; SerialMouseClosePort(DeviceExtension, Irp); } } NTSTATUS SerialMouseCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PKEVENT Event ) /*++ Routine Description: The pnp IRP is in the process of completing. signal Arguments: Context set to the device object in question. --*/ { UNREFERENCED_PARAMETER(DeviceObject); UNREFERENCED_PARAMETER(Irp); KeSetEvent(Event, 0, FALSE); return STATUS_MORE_PROCESSING_REQUIRED; } NTSTATUS SerialMouseSendIrpSynchronously ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN BOOLEAN CopyToNext ) { KEVENT event; NTSTATUS status; PAGED_CODE(); KeInitializeEvent(&event, SynchronizationEvent, FALSE); if (CopyToNext) { IoCopyCurrentIrpStackLocationToNext(Irp); } IoSetCompletionRoutine(Irp, SerialMouseCompletionRoutine, &event, TRUE, // on success TRUE, // on error TRUE // on cancel ); status = IoCallDriver(DeviceObject, Irp); // // Wait for lower drivers to be done with the Irp // if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; } return status; } void SerialMouseHandleStartStopStart( IN PDEVICE_EXTENSION DeviceExtension ) { KIRQL irql; KeAcquireSpinLock(&DeviceExtension->PnpStateLock, &irql); if (DeviceExtension->Stopped) { DeviceExtension->Stopped = FALSE; IoReuseIrp(DeviceExtension->ReadIrp, STATUS_SUCCESS); } KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql); } void SerialMouseStopDevice ( IN PDEVICE_EXTENSION DeviceExtension ) { KIRQL irql; KeAcquireSpinLock(&DeviceExtension->PnpStateLock, &irql); DeviceExtension->Stopped = TRUE; KeReleaseSpinLock(&DeviceExtension->PnpStateLock, irql); if (DeviceExtension->Started) { Print(DeviceExtension, DBG_PNP_INFO, ("Cancelling and stopping detection for stop\n")); DeviceExtension->Started = FALSE; // // Stop detection and cancel the read // SerialMouseStopDetection(DeviceExtension); // // BUGBUG: should I only wait if IoCancelIrp fails? // if (!IoCancelIrp(DeviceExtension->ReadIrp)) { // // Wait for the read irp to complete // Print(DeviceExtension, DBG_PNP_INFO, ("Waiting for stop event\n")); KeWaitForSingleObject(&DeviceExtension->StopEvent, Executive, KernelMode, FALSE, NULL ); Print(DeviceExtension, DBG_PNP_INFO, ("Done waiting for stop event\n")); } } } NTSTATUS SerialMousePnP ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: The plug and play dispatch routines. Most of these this filter driver will completely ignore. In all cases it must pass on the IRP to the lower driver. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PDEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION stack; HANDLE keyHandle; NTSTATUS status; KIRQL oldIrql; BOOLEAN skipIt = FALSE; PAGED_CODE(); deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; stack = IoGetCurrentIrpStackLocation(Irp); status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp); if (!NT_SUCCESS(status)) { // // Someone gave us a pnp irp after a remove. Unthinkable! // ASSERT(FALSE); Irp->IoStatus.Information = 0; Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } Print(deviceExtension, DBG_PNP_TRACE, ("PnP Enter (min func=0x%x)\n", stack->MinorFunction)); switch (stack->MinorFunction) { case IRP_MN_START_DEVICE: // // Send the actual start down the stack // status = SerialMouseSendIrpSynchronously(deviceExtension->TopOfStack, Irp, TRUE); if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { PIO_STACK_LOCATION nextStack; // // If a create has not been sent down the stack yet, then send one // now. The serial port driver reequires a create before // any reads or IOCTLS are to be sent. // if (InterlockedIncrement(&deviceExtension->EnableCount) == 1) { NTSTATUS prevStatus; ULONG_PTR prevInformation; // // No previous create has been sent, send one now // prevStatus = Irp->IoStatus.Status; prevInformation = Irp->IoStatus.Information; nextStack = IoGetNextIrpStackLocation (Irp); RtlZeroMemory(nextStack, sizeof(IO_STACK_LOCATION)); nextStack->MajorFunction = IRP_MJ_CREATE; status = SerialMouseSendIrpSynchronously(deviceExtension->TopOfStack, Irp, FALSE); Print(deviceExtension, DBG_PNP_NOISE, ("Create for start 0x%x\n", status)); if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { Irp->IoStatus.Status = prevStatus; Irp->IoStatus.Information = prevInformation; } else { Print(deviceExtension, DBG_CC_ERROR | DBG_PNP_ERROR, ("Create for start failed, 0x%x!\n", status)); goto SerialMouseStartFinished; } } // // Open the device registry key and read the devnode stored values // status = IoOpenDeviceRegistryKey(deviceExtension->PDO, PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_READ, &keyHandle); if (NT_SUCCESS(status)) { SerialMouseServiceParameters(deviceExtension, keyHandle); ZwClose(keyHandle); } // // Handle the transition from start to stop to start correctly // SerialMouseHandleStartStopStart(deviceExtension); // // Initialize the device to make sure we can start it and report // data from it // status = SerialMouseInitializeDevice(deviceExtension); Print(deviceExtension, DBG_PNP_INFO, ("Start InitializeDevice 0x%x\n", status)); if (InterlockedDecrement(&deviceExtension->EnableCount) == 0) { // // We will start the read loop when we receive a "real" create // from the raw input thread. We do not keep our own create // around after the start device because it will mess up the // logic for handling QUERY_REMOVE (our "fake" create will still // be in effect and the QUERY_REMOVE will fail). // Print(deviceExtension, DBG_PNP_NOISE, ("sending close for start\n")); SerialMouseClosePort(deviceExtension, Irp); } else { // // We already have an outstanding create, just spin up the read // loop again // ASSERT(deviceExtension->EnableCount >= 1); Print(deviceExtension, DBG_PNP_INFO, ("spinning up read in start\n")); status = SerialMouseSpinUpRead(deviceExtension); } } SerialMouseStartFinished: Irp->IoStatus.Status = status; Irp->IoStatus.Information = 0; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IRP_MN_STOP_DEVICE: // // After the start IRP has been sent to the lower driver object, the // bus may NOT send any more IRPS down ``touch'' until another START // has occured. // What ever access is required must be done before the Irp is passed // on. // SerialMouseStopDevice(deviceExtension); // // We don't need a completion routine so fire and forget. // skipIt = TRUE; Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_SURPRISE_REMOVAL: SerialMouseRemoveDevice(deviceExtension, Irp); skipIt = TRUE; Irp->IoStatus.Status = STATUS_SUCCESS; break; case IRP_MN_REMOVE_DEVICE: // // The PlugPlay system has dictacted the removal of this device. We // have no choise but to detach and delete the device objecct. // (If we wanted to express and interest in preventing this removal, // we should have filtered the query remove and query stop routines.) // // Note! we might receive a remove WITHOUT first receiving a stop. // Print(deviceExtension, DBG_PNP_TRACE, ("enter RemoveDevice \n")); deviceExtension->Removed = TRUE; SerialMouseRemoveDevice(deviceExtension, Irp); // // Send on the remove IRP // Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(deviceExtension->TopOfStack, Irp); // // Wait for the remove lock to free. // IoReleaseRemoveLockAndWait(&deviceExtension->RemoveLock, Irp); // // Free the associated memory. // IoFreeIrp(deviceExtension->ReadIrp); deviceExtension->ReadIrp = NULL; if (deviceExtension->DetectionIrp) { IoFreeIrp(deviceExtension->DetectionIrp); deviceExtension->DetectionIrp = NULL; } Print(deviceExtension, DBG_PNP_NOISE, ("remove and wait done\n")); IoDetachDevice(deviceExtension->TopOfStack); IoDeleteDevice(deviceExtension->Self); return status; case IRP_MN_QUERY_CAPABILITIES: status = SerialMouseSendIrpSynchronously(deviceExtension->TopOfStack, Irp, TRUE); if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { PDEVICE_CAPABILITIES devCaps; devCaps = stack->Parameters.DeviceCapabilities.Capabilities; if (devCaps) { SYSTEM_POWER_STATE i; // // We do not want to show up in the hot plug removal applet // devCaps->SurpriseRemovalOK = TRUE; // // While the underlying serial bus might be able to wake the // machine from low power (via wake on ring), the mouse cannot. // devCaps->SystemWake = PowerSystemUnspecified; devCaps->DeviceWake = PowerDeviceUnspecified; devCaps->WakeFromD0 = devCaps->WakeFromD1 = devCaps->WakeFromD2 = devCaps->WakeFromD3 = FALSE; devCaps->DeviceState[PowerSystemWorking] = PowerDeviceD0; for (i = PowerSystemSleeping1; i < PowerSystemMaximum; i++) { devCaps->DeviceState[i] = PowerDeviceD3; } } } // // status, Irp->IoStatus.Status set above // IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IRP_MN_QUERY_PNP_DEVICE_STATE: status = SerialMouseSendIrpSynchronously(deviceExtension->TopOfStack, Irp, TRUE); // // If the lower filter does not support this Irp, this is // OK, we can ignore this error // if (status == STATUS_NOT_SUPPORTED || status == STATUS_INVALID_DEVICE_REQUEST) { status = STATUS_SUCCESS; } if (NT_SUCCESS(status) && deviceExtension->RemovalDetected) { (PNP_DEVICE_STATE) Irp->IoStatus.Information |= PNP_DEVICE_REMOVED; } if (!NT_SUCCESS(status)) { Print(deviceExtension, DBG_PNP_ERROR, ("error pending query pnp device state event (0x%x)\n", status )); } // // Irp->IoStatus.Information will contain the new i/o resource // requirements list so leave it alone // Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); break; case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_CANCEL_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: case IRP_MN_CANCEL_STOP_DEVICE: case IRP_MN_QUERY_DEVICE_RELATIONS: case IRP_MN_QUERY_INTERFACE: case IRP_MN_QUERY_RESOURCES: case IRP_MN_QUERY_RESOURCE_REQUIREMENTS: case IRP_MN_READ_CONFIG: case IRP_MN_WRITE_CONFIG: case IRP_MN_EJECT: case IRP_MN_SET_LOCK: case IRP_MN_QUERY_ID: default: skipIt = TRUE; break; } if (skipIt) { // // Don't touch the irp... // IoSkipCurrentIrpStackLocation(Irp); status = IoCallDriver(deviceExtension->TopOfStack, Irp); } IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); Print(deviceExtension, DBG_PNP_TRACE, ("PnP exit (%x)\n", status)); return status; } typedef struct _MOUSER_START_WORKITEM { PDEVICE_EXTENSION DeviceExtension; PIO_WORKITEM WorkItem; } MOUSER_START_WORKITEM, *PMOUSER_START_WORKITEM; VOID StartDeviceWorker ( IN PDEVICE_OBJECT DeviceObject, IN PMOUSER_START_WORKITEM WorkItemContext ) { PDEVICE_EXTENSION deviceExtension = WorkItemContext->DeviceExtension; NTSTATUS status; PIRP irp; if (deviceExtension->Started && !deviceExtension->Removed && deviceExtension->EnableCount > 0) { irp = IoAllocateIrp( deviceExtension->Self->StackSize, FALSE ); if (irp) { status = SerialMouseStartDevice(deviceExtension, irp, FALSE); if (!NT_SUCCESS(status)) { KEVENT event; IO_STATUS_BLOCK iosb; Print(deviceExtension, DBG_POWER_INFO, ("mouse not found on power up, 0x%x\n", status)); // // The device has been removed or is not detectable // after powering back up ... have serenum do the // removal work // KeInitializeEvent(&event, SynchronizationEvent, FALSE); SerialMouseIoSyncInternalIoctl( IOCTL_INTERNAL_SERENUM_REMOVE_SELF, deviceExtension->TopOfStack, &event, &iosb ); } IoFreeIrp(irp); } } IoFreeWorkItem(WorkItemContext->WorkItem); ExFreePool(WorkItemContext); IoReleaseRemoveLock(&deviceExtension->RemoveLock, deviceExtension); } NTSTATUS SerialMousePower ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: The power dispatch routine. All we care about is the transition from a low D state to D0. Arguments: DeviceObject - pointer to a device object. Irp - pointer to an I/O Request Packet. Return Value: NT status code --*/ { PIO_STACK_LOCATION stack; NTSTATUS status = STATUS_SUCCESS; PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension; POWER_STATE powerState; POWER_STATE_TYPE powerType; KEVENT event; IO_STATUS_BLOCK iosb; LARGE_INTEGER li; PAGED_CODE(); Print(deviceExtension, DBG_POWER_TRACE, ("Power Enter.\n")); deviceExtension = (PDEVICE_EXTENSION) DeviceObject->DeviceExtension; stack = IoGetCurrentIrpStackLocation(Irp); powerType = stack->Parameters.Power.Type; powerState = stack->Parameters.Power.State; status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, Irp); if (!NT_SUCCESS(status)) { PoStartNextPowerIrp(Irp); Irp->IoStatus.Status = status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } switch (stack->MinorFunction) { case IRP_MN_WAIT_WAKE: break; case IRP_MN_SET_POWER: // // Let system power irps fall through // if (powerType == DevicePowerState && powerState.DeviceState != deviceExtension->PowerState) { switch (powerState.DeviceState) { case PowerDeviceD0: // // Transitioning from a low D state to D0 // Print(deviceExtension, DBG_POWER_INFO, ("Powering up to PowerDeviceD0\n")); KeInitializeEvent(&event, SynchronizationEvent, FALSE); deviceExtension->PoweringDown = FALSE; deviceExtension->PowerState = stack->Parameters.Power.State.DeviceState; IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine(Irp, SerialMouseCompletionRoutine, &event, TRUE, // on success TRUE, // on error TRUE // on cancel ); status = PoCallDriver(deviceExtension->TopOfStack, Irp); // // Wait for lower drivers to be done with the Irp // if (status == STATUS_PENDING) { KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL ); status = Irp->IoStatus.Status; } if (NT_SUCCESS(status) && NT_SUCCESS(Irp->IoStatus.Status)) { PoSetPowerState(DeviceObject, powerType, powerState); if (NT_SUCCESS(IoAcquireRemoveLock(&deviceExtension->RemoveLock, deviceExtension))) { PIO_WORKITEM workItem; PMOUSER_START_WORKITEM workItemContext; workItem = IoAllocateWorkItem(DeviceObject); if (workItem) { workItemContext = ExAllocatePool(NonPagedPool, sizeof(MOUSER_START_WORKITEM)); if (workItemContext) { workItemContext->WorkItem = workItem; workItemContext->DeviceExtension = deviceExtension; IoQueueWorkItem( workItem, StartDeviceWorker, DelayedWorkQueue, workItemContext); } else { IoFreeWorkItem(workItem); IoReleaseRemoveLock(&deviceExtension->RemoveLock, deviceExtension); } } else { IoReleaseRemoveLock(&deviceExtension->RemoveLock, deviceExtension); } } } Irp->IoStatus.Status = status; IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); PoStartNextPowerIrp(Irp); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; case PowerDeviceD1: case PowerDeviceD2: case PowerDeviceD3: deviceExtension->PoweringDown = TRUE; // If a wait wake is pending against the mouse, keep it powered // if (deviceExtension->WaitWakePending) { Print(deviceExtension, DBG_POWER_INFO, ("Ignoring power down for wait wake (-> D%d)\n", powerState.DeviceState-1 )); break; } Print(deviceExtension, DBG_POWER_INFO, ("Powering down to PowerDeviceD%d\n", powerState.DeviceState-1 )); // // Acquire another reference to the lock so that the decrement // in the cancel section of the completion routine will not fall // to zero (and have the remlock think we are removed) // // status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, // deviceExtension->ReadIrp); ASSERT(NT_SUCCESS(status)); deviceExtension->PowerState = stack->Parameters.Power.State.DeviceState; // // Cancel the read irp so that it won't conflict with power up // initialization (which involves some reads against the port) // IoCancelIrp(deviceExtension->ReadIrp); // // We don't want the powering down of the port to be confused // with removal // SerialMouseStopDetection(deviceExtension); // // Power down the device by clearing RTS and waiting 150 ms // Print(deviceExtension, DBG_POWER_INFO, ("Clearing RTS...\n")); KeInitializeEvent(&event, NotificationEvent, FALSE); status = SerialMouseIoSyncIoctl(IOCTL_SERIAL_CLR_RTS, deviceExtension->TopOfStack, &event, &iosb ); if (NT_SUCCESS(status)) { Print(deviceExtension, DBG_POWER_INFO, ("150ms wait\n")); li.QuadPart = (LONGLONG) -PAUSE_150_MS; KeDelayExecutionThread(KernelMode, FALSE, &li); } PoSetPowerState(DeviceObject, stack->Parameters.Power.Type, stack->Parameters.Power.State); IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); // // Fire and forget // Irp->IoStatus.Status = STATUS_SUCCESS; IoCopyCurrentIrpStackLocationToNext(Irp); PoStartNextPowerIrp(Irp); return PoCallDriver(deviceExtension->TopOfStack, Irp); } } break; case IRP_MN_QUERY_POWER: break; default: Print(deviceExtension, DBG_POWER_ERROR, ("Power minor (0x%x) is not handled\n", stack->MinorFunction)); } // // Must call the Po versions of these functions or bad things (tm) will happen! // PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); status = PoCallDriver(deviceExtension->TopOfStack, Irp); IoReleaseRemoveLock(&deviceExtension->RemoveLock, Irp); return status; }