392 lines
11 KiB
C
392 lines
11 KiB
C
/*++
|
|
|
|
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);
|
|
}
|