347 lines
9.2 KiB
C
347 lines
9.2 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 2000 Microsoft Corporation
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
mask.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module contains the code that is very specific to initialization
|
||
|
and unload operations in the irenum driver
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Brian Lieuallen, 7-13-2000
|
||
|
|
||
|
Environment:
|
||
|
|
||
|
Kernel mode
|
||
|
|
||
|
Revision History :
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#include "internal.h"
|
||
|
#include "ircomm.h"
|
||
|
|
||
|
|
||
|
VOID
|
||
|
WaitMaskCancelRoutine(
|
||
|
PDEVICE_OBJECT DeviceObject,
|
||
|
PIRP Irp
|
||
|
);
|
||
|
|
||
|
PIRP
|
||
|
GetCurrentWaitIrp(
|
||
|
PFDO_DEVICE_EXTENSION DeviceExtension
|
||
|
);
|
||
|
|
||
|
|
||
|
VOID
|
||
|
MaskStartRoutine(
|
||
|
PVOID Context,
|
||
|
PIRP Irp
|
||
|
)
|
||
|
|
||
|
{
|
||
|
|
||
|
PFDO_DEVICE_EXTENSION DeviceExtension=(PFDO_DEVICE_EXTENSION)Context;
|
||
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
|
||
|
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
PUCHAR SystemBuffer = Irp->AssociatedIrp.SystemBuffer;
|
||
|
ULONG InputLength = IrpSp->Parameters.DeviceIoControl.InputBufferLength;
|
||
|
ULONG OutputLength = IrpSp->Parameters.DeviceIoControl.OutputBufferLength;
|
||
|
|
||
|
|
||
|
switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
|
||
|
|
||
|
case IOCTL_SERIAL_GET_WAIT_MASK:
|
||
|
|
||
|
if (OutputLength >= sizeof(ULONG)) {
|
||
|
|
||
|
*(PULONG)SystemBuffer=DeviceExtension->Mask.CurrentMask;
|
||
|
Irp->IoStatus.Information=sizeof(ULONG);
|
||
|
Irp->IoStatus.Status=STATUS_SUCCESS;
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||
|
StartNextPacket(&DeviceExtension->Mask.Queue);
|
||
|
|
||
|
break;
|
||
|
|
||
|
|
||
|
case IOCTL_SERIAL_SET_WAIT_MASK: {
|
||
|
|
||
|
|
||
|
ULONG NewMask=*(PULONG)SystemBuffer;
|
||
|
|
||
|
if (InputLength >= sizeof(ULONG)) {
|
||
|
|
||
|
PIRP WaitIrp=NULL;
|
||
|
|
||
|
D_TRACE(DbgPrint("IRCOMM: mask %08lx\n",NewMask);)
|
||
|
|
||
|
KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
|
||
|
|
||
|
DeviceExtension->Mask.HistoryMask &= NewMask;
|
||
|
DeviceExtension->Mask.CurrentMask=NewMask;
|
||
|
|
||
|
Irp->IoStatus.Status=STATUS_SUCCESS;
|
||
|
|
||
|
//
|
||
|
// if there was a wait irp, clear ir out now
|
||
|
//
|
||
|
WaitIrp=GetCurrentWaitIrp(DeviceExtension);
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
if (WaitIrp != NULL) {
|
||
|
|
||
|
WaitIrp->IoStatus.Information=sizeof(ULONG);
|
||
|
WaitIrp->IoStatus.Status=STATUS_SUCCESS;
|
||
|
|
||
|
*(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=0;
|
||
|
|
||
|
IoCompleteRequest(WaitIrp,IO_NO_INCREMENT);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
|
||
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||
|
StartNextPacket(&DeviceExtension->Mask.Queue);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
|
||
|
case IOCTL_SERIAL_WAIT_ON_MASK:
|
||
|
|
||
|
if (OutputLength >= sizeof(ULONG)) {
|
||
|
|
||
|
KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
|
||
|
|
||
|
if ((DeviceExtension->Mask.CurrentWaitMaskIrp == NULL) && (DeviceExtension->Mask.CurrentMask != 0)) {
|
||
|
|
||
|
if (DeviceExtension->Mask.CurrentMask & DeviceExtension->Mask.HistoryMask) {
|
||
|
//
|
||
|
// we got an event while there a was no irp queue, complete this
|
||
|
// one with the event, and clear the history
|
||
|
//
|
||
|
D_TRACE(DbgPrint("IRCOMM: Completing wait from histroy %08lx\n", DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask);)
|
||
|
|
||
|
*(PULONG)Irp->AssociatedIrp.SystemBuffer=DeviceExtension->Mask.HistoryMask & DeviceExtension->Mask.CurrentMask;
|
||
|
DeviceExtension->Mask.HistoryMask=0;
|
||
|
|
||
|
Irp->IoStatus.Information=sizeof(ULONG);
|
||
|
Irp->IoStatus.Status=STATUS_SUCCESS;
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// the irp will remain pending here until an event happens
|
||
|
//
|
||
|
KIRQL CancelIrql;
|
||
|
|
||
|
IoAcquireCancelSpinLock(&CancelIrql);
|
||
|
|
||
|
if (Irp->Cancel) {
|
||
|
//
|
||
|
// canceled already
|
||
|
//
|
||
|
Irp->IoStatus.Status=STATUS_CANCELLED;
|
||
|
|
||
|
IoReleaseCancelSpinLock(CancelIrql);
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// not canceled, set the cancel routine and proceed
|
||
|
//
|
||
|
IoSetCancelRoutine(Irp,WaitMaskCancelRoutine);
|
||
|
|
||
|
DeviceExtension->Mask.CurrentWaitMaskIrp=Irp;
|
||
|
|
||
|
IoReleaseCancelSpinLock(CancelIrql);
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
//
|
||
|
// were done processing this so far, we can now handle more
|
||
|
// requests from the irp queue
|
||
|
//
|
||
|
Irp=NULL;
|
||
|
|
||
|
StartNextPacket(&DeviceExtension->Mask.Queue);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// already have an wait event irp or there is not currently an event mask set, fail
|
||
|
//
|
||
|
D_ERROR(DbgPrint("IRCOMM: MaskStartRoutine: WaitOnMask failing, Current=&p, Mask=%08lx\n",DeviceExtension->Mask.CurrentWaitMaskIrp,DeviceExtension->Mask.CurrentMask);)
|
||
|
|
||
|
Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// too small
|
||
|
//
|
||
|
Irp->IoStatus.Status=STATUS_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||
|
StartNextPacket(&DeviceExtension->Mask.Queue);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
ASSERT(0);
|
||
|
|
||
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||
|
StartNextPacket(&DeviceExtension->Mask.Queue);
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
VOID
|
||
|
WaitMaskCancelRoutine(
|
||
|
PDEVICE_OBJECT DeviceObject,
|
||
|
PIRP Irp
|
||
|
)
|
||
|
|
||
|
{
|
||
|
|
||
|
PFDO_DEVICE_EXTENSION DeviceExtension=DeviceObject->DeviceExtension;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
IoReleaseCancelSpinLock(Irp->CancelIrql);
|
||
|
|
||
|
KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
|
||
|
|
||
|
//
|
||
|
// since we only handle one mask irp at a time, it should not be possible for it to not
|
||
|
// be the current one
|
||
|
//
|
||
|
ASSERT(DeviceExtension->Mask.CurrentWaitMaskIrp == Irp);
|
||
|
DeviceExtension->Mask.CurrentWaitMaskIrp=NULL;
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
Irp->IoStatus.Status=STATUS_CANCELLED;
|
||
|
|
||
|
IoCompleteRequest(Irp,IO_NO_INCREMENT);
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
VOID
|
||
|
EventNotification(
|
||
|
PFDO_DEVICE_EXTENSION DeviceExtension,
|
||
|
ULONG SerialEvent
|
||
|
)
|
||
|
|
||
|
{
|
||
|
|
||
|
PIRP WaitIrp=NULL;
|
||
|
KIRQL OldIrql;
|
||
|
|
||
|
|
||
|
KeAcquireSpinLock(&DeviceExtension->Mask.Lock,&OldIrql);
|
||
|
|
||
|
if (SerialEvent & DeviceExtension->Mask.CurrentMask) {
|
||
|
//
|
||
|
// an event the the client is intereasted in occured
|
||
|
//
|
||
|
WaitIrp=GetCurrentWaitIrp(DeviceExtension);
|
||
|
|
||
|
if (WaitIrp != NULL) {
|
||
|
//
|
||
|
// There is a wait irp pending
|
||
|
//
|
||
|
D_TRACE(DbgPrint("IRCOMM: Completing wait event %08lx\n", SerialEvent & DeviceExtension->Mask.CurrentMask);)
|
||
|
|
||
|
*(PULONG)WaitIrp->AssociatedIrp.SystemBuffer=SerialEvent & DeviceExtension->Mask.CurrentMask;
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// this was an event the the client was interested in, but there was no wait irp
|
||
|
// add it to the histrory mask
|
||
|
//
|
||
|
DeviceExtension->Mask.HistoryMask |= SerialEvent & DeviceExtension->Mask.CurrentMask;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
KeReleaseSpinLock(&DeviceExtension->Mask.Lock,OldIrql);
|
||
|
|
||
|
if (WaitIrp != NULL) {
|
||
|
|
||
|
WaitIrp->IoStatus.Information=sizeof(ULONG);
|
||
|
WaitIrp->IoStatus.Status=STATUS_SUCCESS;
|
||
|
|
||
|
IoCompleteRequest(WaitIrp,IO_NO_INCREMENT);
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
|
||
|
PIRP
|
||
|
GetCurrentWaitIrp(
|
||
|
PFDO_DEVICE_EXTENSION DeviceExtension
|
||
|
)
|
||
|
|
||
|
{
|
||
|
PVOID OldCancelRoutine;
|
||
|
PIRP WaitIrp;
|
||
|
|
||
|
//
|
||
|
// if there was a wait irp, clear ir out now
|
||
|
//
|
||
|
WaitIrp=DeviceExtension->Mask.CurrentWaitMaskIrp;
|
||
|
|
||
|
if (WaitIrp != NULL) {
|
||
|
|
||
|
OldCancelRoutine=IoSetCancelRoutine(WaitIrp,NULL);
|
||
|
|
||
|
if (OldCancelRoutine == NULL) {
|
||
|
//
|
||
|
// the cancel routine has run and will complete the irp
|
||
|
//
|
||
|
WaitIrp=NULL;
|
||
|
|
||
|
} else {
|
||
|
//
|
||
|
// the cancel routine will not be running, clear the irp out
|
||
|
//
|
||
|
DeviceExtension->Mask.CurrentWaitMaskIrp=NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return WaitIrp;
|
||
|
}
|