|
|
/*++
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); }
|