You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
346 lines
9.5 KiB
346 lines
9.5 KiB
/*++
|
|
|
|
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;
|
|
}
|