Leaked source code of windows server 2003
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.
 
 
 
 
 
 

373 lines
6.6 KiB

/*++
Module Name:
waitmask.c
Environment:
Kernel mode
Revision History :
--*/
#include "precomp.h"
NTSTATUS
MoxaStartMask(
IN PMOXA_DEVICE_EXTENSION Extension
)
{
PIO_STACK_LOCATION irpSp;
PIRP newIrp;
BOOLEAN setFirstStatus = FALSE;
NTSTATUS firstStatus;
do {
irpSp = IoGetCurrentIrpStackLocation(Extension->CurrentMaskIrp);
if (irpSp->Parameters.DeviceIoControl.IoControlCode ==
IOCTL_SERIAL_SET_WAIT_MASK) {
KeSynchronizeExecution(
Extension->Interrupt,
MoxaFinishOldWait,
Extension
);
Extension->CurrentMaskIrp->IoStatus.Status = STATUS_SUCCESS;
if (!setFirstStatus) {
firstStatus = STATUS_SUCCESS;
setFirstStatus = TRUE;
}
MoxaGetNextIrp(
&Extension->CurrentMaskIrp,
&Extension->MaskQueue,
&newIrp,
TRUE,
Extension
);
}
else {
//
// IOCTL_SERIAL_WAIT_ON_MASK
//
// First make sure that we have a non-zero mask.
// If the app queues a wait on a zero mask it can't
// be statisfied so it makes no sense to start it.
//
if ((!Extension->IsrWaitMask) || (Extension->CurrentWaitIrp)) {
Extension->CurrentMaskIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
if (!setFirstStatus) {
firstStatus = STATUS_INVALID_PARAMETER;
setFirstStatus = TRUE;
}
MoxaGetNextIrp(
&Extension->CurrentMaskIrp,
&Extension->MaskQueue,
&newIrp,
TRUE,
Extension
);
}
else {
KIRQL oldIrql;
IoAcquireCancelSpinLock(&oldIrql);
if (Extension->CurrentMaskIrp->Cancel) {
Extension->CurrentMaskIrp->IoStatus.Status = STATUS_CANCELLED;
IoReleaseCancelSpinLock(oldIrql);
if (!setFirstStatus) {
firstStatus = STATUS_CANCELLED;
setFirstStatus = TRUE;
}
MoxaGetNextIrp(
&Extension->CurrentMaskIrp,
&Extension->MaskQueue,
&newIrp,
TRUE,
Extension
);
}
else {
if (!setFirstStatus) {
firstStatus = STATUS_PENDING;
setFirstStatus = TRUE;
IoMarkIrpPending(Extension->CurrentMaskIrp);
}
Extension->CurrentWaitIrp = Extension->CurrentMaskIrp;
MOXA_INIT_REFERENCE(Extension->CurrentWaitIrp);
IoSetCancelRoutine(
Extension->CurrentWaitIrp,
MoxaCancelWait
);
//
// Since the cancel routine has a reference to
// the irp we need to update the reference
// count.
//
MOXA_INC_REFERENCE(Extension->CurrentWaitIrp);
KeSynchronizeExecution(
Extension->Interrupt,
MoxaGiveWaitToIsr,
Extension
);
IoReleaseCancelSpinLock(oldIrql);
MoxaGetNextIrp(
&Extension->CurrentMaskIrp,
&Extension->MaskQueue,
&newIrp,
FALSE,
Extension
);
}
}
}
} while (newIrp);
return firstStatus;
}
BOOLEAN
MoxaFinishOldWait(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
PUCHAR ofs;
if (extension->IrpMaskLocation) {
//
// The isr still "owns" the irp.
//
*extension->IrpMaskLocation = 0;
extension->IrpMaskLocation = NULL;
extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
//
// We don't decrement the reference since the completion routine
// will do that.
//
MoxaInsertQueueDpc(
&extension->CommWaitDpc,
NULL,
NULL,
extension
);
}
//
// Don't wipe out any historical data we are still interested in.
//
extension->HistoryMask &= *((ULONG *)extension->CurrentMaskIrp->
AssociatedIrp.SystemBuffer);
extension->IsrWaitMask = *((ULONG *)extension->CurrentMaskIrp->
AssociatedIrp.SystemBuffer);
ofs = extension->PortOfs;
if (extension->IsrWaitMask & SERIAL_EV_RXCHAR)
*(PUSHORT)(ofs + HostStat) |= WakeupRx;
else
*(PUSHORT)(ofs + HostStat) &= ~WakeupRx;
if (extension->IsrWaitMask & SERIAL_EV_RXFLAG)
*(PUSHORT)(ofs + HostStat) |= WakeupEvent;
else
*(PUSHORT)(ofs + HostStat) &= ~WakeupEvent;
if (extension->IsrWaitMask & SERIAL_EV_RX80FULL)
*(PUSHORT)(ofs + HostStat) |= WakeupRx80Full;
else
*(PUSHORT)(ofs + HostStat) &= ~WakeupRx80Full;
if (extension->IsrWaitMask & SERIAL_EV_ERR) {
*(PUSHORT)(ofs + HostStat) |= WakeupError;
}
else {
*(PUSHORT)(ofs + HostStat) &= ~WakeupError;
}
if (extension->IsrWaitMask & SERIAL_EV_BREAK) {
*(PUSHORT)(ofs + HostStat) |= WakeupBreak;
}
else {
*(PUSHORT)(ofs + HostStat) &= ~WakeupBreak;
}
return FALSE;
}
VOID
MoxaCancelWait(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PMOXA_DEVICE_EXTENSION extension = DeviceObject->DeviceExtension;
MoxaTryToCompleteCurrent(
extension,
MoxaGrabWaitFromIsr,
Irp->CancelIrql,
STATUS_CANCELLED,
&extension->CurrentWaitIrp,
NULL,
NULL,
NULL,
NULL,
NULL
);
}
BOOLEAN
MoxaGrabWaitFromIsr(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
if (extension->IrpMaskLocation) {
//
// The isr still "owns" the irp.
//
*extension->IrpMaskLocation = 0;
extension->IrpMaskLocation = NULL;
extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
//
// Since the isr no longer references the irp we need to
// decrement the reference count.
//
MOXA_DEC_REFERENCE(extension->CurrentWaitIrp);
}
return FALSE;
}
BOOLEAN
MoxaGiveWaitToIsr(
IN PVOID Context
)
{
PMOXA_DEVICE_EXTENSION extension = Context;
MOXA_INC_REFERENCE(extension->CurrentWaitIrp);
if (!extension->HistoryMask)
extension->IrpMaskLocation =
extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer;
else {
*((ULONG *)extension->CurrentWaitIrp->AssociatedIrp.SystemBuffer) =
extension->HistoryMask;
extension->HistoryMask = 0;
extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG);
extension->CurrentWaitIrp->IoStatus.Status = STATUS_SUCCESS;
MoxaInsertQueueDpc(
&extension->CommWaitDpc,
NULL,
NULL,
extension
);
}
return FALSE;
}
VOID
MoxaCompleteWait(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
{
PMOXA_DEVICE_EXTENSION extension = DeferredContext;
KIRQL oldIrql;
IoAcquireCancelSpinLock(&oldIrql);
MoxaTryToCompleteCurrent(
extension,
NULL,
oldIrql,
STATUS_SUCCESS,
&extension->CurrentWaitIrp,
NULL,
NULL,
NULL,
NULL,
NULL
);
MoxaDpcEpilogue(extension, Dpc);
}