|
|
/*++
Copyright (c) 1997-1998 Microsoft Corporation, All Rights Reserved
Module Name:
detect.c
Abstract:
Detection of surprise removal of the mouse. Environment:
Kernel mode only.
Notes:
Revision History:
--*/
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
#include "ntddk.h"
#include "mouser.h"
#include "sermlog.h"
#include "debug.h"
VOID SerialMouseSerialMaskEventWorker( PDEVICE_OBJECT DeviceObject, PIO_WORKITEM Item );
NTSTATUS SerialMouseSerialMaskEventComplete ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context );
NTSTATUS SerialMouseSendWaitMaskIrp( IN PDEVICE_EXTENSION DeviceExtension );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, SerialMouseSerialMaskEventWorker)
#pragma alloc_text(PAGE, SerialMouseStartDetection)
#pragma alloc_text(PAGE, SerialMouseStopDetection)
#pragma alloc_text(PAGE, SerialMouseSendWaitMaskIrp)
#endif
NTSTATUS SerialMouseSendWaitMaskIrp( IN PDEVICE_EXTENSION DeviceExtension ) { PIRP irp; PIO_STACK_LOCATION next; NTSTATUS status;
PAGED_CODE();
irp = DeviceExtension->DetectionIrp;
DeviceExtension->SerialEventBits = 0x0;
//
// Will be released in the completion routine
//
status = IoAcquireRemoveLock (&DeviceExtension->RemoveLock, irp); if (!NT_SUCCESS(status)) { return status; } IoReuseIrp(irp, STATUS_SUCCESS);
next = IoGetNextIrpStackLocation(irp); next->MajorFunction = IRP_MJ_DEVICE_CONTROL; next->Parameters.DeviceIoControl.IoControlCode = IOCTL_SERIAL_WAIT_ON_MASK; next->Parameters.DeviceIoControl.OutputBufferLength = sizeof(ULONG); irp->AssociatedIrp.SystemBuffer = &DeviceExtension->SerialEventBits; //
// Hook a completion routine for when the device completes.
//
IoSetCompletionRoutine(irp, SerialMouseSerialMaskEventComplete, DeviceExtension, TRUE, TRUE, TRUE);
return IoCallDriver(DeviceExtension->TopOfStack, irp); }
VOID SerialMouseStartDetection( PDEVICE_EXTENSION DeviceExtension ) /*++
Routine Description
This will cancel any previous set on the timer and queue the timer for DetectionTimeout # of seconds and repeatedly trigger the timer every DetectionTimeout # of seconds.
Arguments:
DeviceExtension - pointer to the device extension
Return Value:
None --*/ { IO_STATUS_BLOCK iosb; KEVENT event; ULONG waitMask, bits = 0x0; NTSTATUS status; PDEVICE_OBJECT self; ULONG statusBits[] = { SERIAL_DSR_STATE, SERIAL_CTS_STATE, 0x0 }; ULONG eventBits[] = { SERIAL_EV_DSR, SERIAL_EV_CTS, }; int i;
PAGED_CODE();
//
// Check to see if removal detection was turned off in the registry
//
if (DeviceExtension->WaitEventMask == 0xffffffff) { DeviceExtension->DetectionSupported = FALSE; return; }
KeInitializeEvent(&event, NotificationEvent, FALSE);
if (!DeviceExtension->WaitEventMask) { status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS, DeviceExtension->TopOfStack, &event, &iosb, NULL, 0, &bits, sizeof(ULONG) ); Print(DeviceExtension, DBG_SS_NOISE, ("get modem status, NTSTATUS = 0x%x, bits = 0x%x\n", status, bits));
if (!NT_SUCCESS(status) || !bits) { Print(DeviceExtension, DBG_SS_ERROR, ("modem status failed, status = 0x%x, bits are 0x%x\n", status, bits));
DeviceExtension->ModemStatusBits = 0x0; DeviceExtension->DetectionSupported = FALSE;
return; }
DeviceExtension->ModemStatusBits = bits;
for (i = 0, waitMask = 0x0; statusBits[i] != 0x0; i++) { if (bits & statusBits[i]) { waitMask |= eventBits[i]; } }
Print(DeviceExtension, DBG_SS_NOISE, ("event wait bits are 0x%x\n", waitMask));
} else { waitMask = DeviceExtension->WaitEventMask; }
status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_SET_WAIT_MASK, DeviceExtension->TopOfStack, &event, &iosb, &waitMask, sizeof(ULONG), NULL, 0);
if (!NT_SUCCESS(status)) { Print(DeviceExtension, DBG_SS_ERROR, ("set mask failed, status = 0x%x\n", status));
DeviceExtension->DetectionSupported = FALSE; return; }
self = DeviceExtension->Self;
if (!DeviceExtension->DetectionIrp) { if (!(DeviceExtension->DetectionIrp = IoAllocateIrp(self->StackSize, FALSE))) { DeviceExtension->DetectionSupported = FALSE; return; } }
status = SerialMouseSendWaitMaskIrp(DeviceExtension);
Print(DeviceExtension, DBG_SS_NOISE, ("set wait event status = 0x%x\n", status));
if (NT_SUCCESS(status)) { DeviceExtension->DetectionSupported = TRUE; } else { IoCancelIrp(DeviceExtension->DetectionIrp); DeviceExtension->DetectionSupported = FALSE; } }
VOID SerialMouseStopDetection( PDEVICE_EXTENSION DeviceExtension ) { PAGED_CODE();
if (!DeviceExtension->DetectionSupported) { return; }
if (!DeviceExtension->RemovalDetected) { IoCancelIrp(DeviceExtension->DetectionIrp); } }
NTSTATUS SerialMouseSerialMaskEventComplete ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PDEVICE_EXTENSION deviceExtension = (PDEVICE_EXTENSION) Context; PIO_WORKITEM item; NTSTATUS status; BOOLEAN killMouse = FALSE;
//
// DeviceObject is NULL b/c this driver was the one that allocated and sent
// the irp, we must use deviceExtension->Self instead.
//
UNREFERENCED_PARAMETER(DeviceObject);
if (!deviceExtension->Removed && !deviceExtension->SurpriseRemoved) { item = IoAllocateWorkItem(deviceExtension->Self); if (!item) { //
// Well, we can't allocate the work item, so lets invalidate our device
// state and hope everything gets torn down.
//
killMouse = TRUE; } else { status = IoAcquireRemoveLock(&deviceExtension->RemoveLock, item);
if (NT_SUCCESS(status)) { IoQueueWorkItem (item, SerialMouseSerialMaskEventWorker, DelayedWorkQueue, item); } else { killMouse = TRUE; } } }
if (killMouse) { deviceExtension->RemovalDetected = TRUE; IoInvalidateDeviceState(deviceExtension->PDO); }
IoReleaseRemoveLock (&deviceExtension->RemoveLock, deviceExtension->DetectionIrp);
return STATUS_MORE_PROCESSING_REQUIRED; }
VOID SerialMouseSerialMaskEventWorker( PDEVICE_OBJECT DeviceObject, PIO_WORKITEM Item ) { IO_STATUS_BLOCK iosb; PIRP irp; KEVENT event; NTSTATUS status; ULONG bits; BOOLEAN removeSelf = FALSE; PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
PAGED_CODE();
irp = deviceExtension->DetectionIrp;
KeInitializeEvent(&event, NotificationEvent, FALSE);
switch (irp->IoStatus.Status) { case STATUS_SUCCESS:
Print(deviceExtension, DBG_SS_NOISE, ("SerialEventBits are 0x%x\n", deviceExtension->SerialEventBits));
bits = 0x0;
status = SerialMouseIoSyncIoctlEx(IOCTL_SERIAL_GET_MODEMSTATUS, deviceExtension->TopOfStack, &event, &iosb, NULL, 0, &bits, sizeof(ULONG) ); Print(deviceExtension, DBG_SS_NOISE, ("get modem status, NTSTATUS = 0x%x, bits = 0x%x, MSB = 0x%x\n", status, bits, deviceExtension->ModemStatusBits));
//
// Make sure that the lines truly changed
//
if (deviceExtension->ModemStatusBits == bits) { //
// Resend the detection irp
//
SerialMouseSendWaitMaskIrp(deviceExtension); } else { //
// The lines have changed, it is a hot removal
//
Print(deviceExtension, DBG_SS_NOISE, ("device hot removed!\n")); SerialMouseIoSyncInternalIoctl(IOCTL_INTERNAL_SERENUM_REMOVE_SELF, deviceExtension->TopOfStack, &event, &iosb); deviceExtension->RemovalDetected = TRUE; }
break;
case STATUS_CANCELLED: //
// We get here if the user manually removes the device (ie through the
// device manager) and we send the clean up irp down the stack
//
Print(deviceExtension, DBG_SS_NOISE, ("wait cancelled!\n")); if (deviceExtension->PowerState != PowerDeviceD0 && !deviceExtension->PoweringDown) { deviceExtension->RemovalDetected = TRUE; }
break;
default: Print(deviceExtension, DBG_SS_ERROR, ("unknown status in mask event (0x%x)\n", irp->IoStatus.Status)); TRAP(); }
IoReleaseRemoveLock(&deviceExtension->RemoveLock, Item); IoFreeWorkItem(Item); }
|