windows-nt/Source/XPSP1/NT/net/irda/comm/ircomm/mask.c

347 lines
9.2 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}