748 lines
26 KiB
C
748 lines
26 KiB
C
/*++
|
||
|
||
*****************************************************************************
|
||
* *
|
||
* This software contains proprietary and confidential information of *
|
||
* *
|
||
* Digi International Inc. *
|
||
* *
|
||
* By accepting transfer of this copy, Recipient agrees to retain this *
|
||
* software in confidence, to prevent disclosure to others, and to make *
|
||
* no use of this software other than that for which it was delivered. *
|
||
* This is an unpublished copyrighted work of Digi International Inc. *
|
||
* Except as permitted by federal law, 17 USC 117, copying is strictly *
|
||
* prohibited. *
|
||
* *
|
||
*****************************************************************************
|
||
|
||
Module Name:
|
||
|
||
fepevent.c
|
||
|
||
Abstract:
|
||
|
||
This module is responsible for processing events from the FEP event queue.
|
||
|
||
Revision History:
|
||
|
||
* $Log: /Components/Windows/NT/Async/FEP5/fepevent.c $
|
||
*
|
||
* 1 3/04/96 12:12p Stana
|
||
* Procedures to process FEP events.
|
||
*
|
||
* Revision 1.1 1995/07/31 17:12:20 dirkh
|
||
* Initial revision
|
||
*
|
||
--*/
|
||
|
||
#include "header.h"
|
||
|
||
#ifndef _FEPEVENT_DOT_C
|
||
# define _FEPEVENT_DOT_C
|
||
static char RCSInfo_FepeventDotC[] = "$Header: /Components/Windows/NT/Async/FEP5/fepevent.c 1 3/04/96 12:12p Stana $";
|
||
#endif
|
||
|
||
|
||
VOID
|
||
DigiServiceEvent( IN PDIGI_CONTROLLER_EXTENSION ControllerExt,
|
||
IN USHORT Ein,
|
||
IN USHORT Eout )
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
const USHORT Emax = 0x03FC;
|
||
|
||
DigiDump( (DIGIFLOW|DIGIEVENT), ("Entering DigiServiceEvent\n") );
|
||
|
||
// Event registers should be in range and DWORD-aligned.
|
||
ASSERT( Ein <= Emax && (Ein & 3) == 0 );
|
||
ASSERT( Eout <= Emax && (Eout & 3) == 0 );
|
||
|
||
DigiDump( DIGIEVENT, ("--------- Ein(0x%.4x) != Eout(0x%.4x)\n",
|
||
Ein, Eout ) );
|
||
|
||
for( ; Eout != Ein ; Eout += 4, Eout &= Emax )
|
||
{
|
||
PDIGI_DEVICE_EXTENSION DeviceExt;
|
||
PFEP_EVENT pEvent;
|
||
FEP_EVENT Event;
|
||
ULONG EventReason;
|
||
|
||
pEvent = (PFEP_EVENT)(ControllerExt->VirtualAddress +
|
||
ControllerExt->EventQueue.Offset + Eout );
|
||
|
||
EnableWindow( ControllerExt, ControllerExt->EventQueue.Window );
|
||
|
||
READ_REGISTER_BUFFER_UCHAR( (PUCHAR)pEvent, (PUCHAR)&Event, sizeof(Event) );
|
||
|
||
DisableWindow( ControllerExt );
|
||
|
||
if( (Event.Channel <= 0xDF) &&
|
||
(Event.Channel < ControllerExt->NumberOfPorts) )
|
||
{
|
||
DeviceExt = ControllerExt->DeviceObjectArray[Event.Channel]->DeviceExtension;
|
||
}
|
||
else // bad command?
|
||
{
|
||
DeviceExt = NULL;
|
||
DigiDump( DIGIEVENT, ("Event on unknown channel %d (flags = 0x%.2x), ignored\n", Event.Channel, Event.Flags) );
|
||
continue;
|
||
}
|
||
|
||
DigiDump( DIGIEVENT, ("--------- Channel = %d\tFlags = 0x%.2x\n"
|
||
"--------- Current = 0x%.2x\tPrev. = 0x%.2x\n",
|
||
Event.Channel, Event.Flags, Event.CurrentModem,
|
||
Event.PreviousModem) );
|
||
|
||
//
|
||
// OK, let's process the event
|
||
//
|
||
|
||
if( Event.Flags & ~(FEP_ALL_EVENT_FLAGS) )
|
||
{
|
||
DigiDump( DIGIERRORS, ("Unknown event queue flag 0x%.2x\n",
|
||
Event.Flags & ~(FEP_ALL_EVENT_FLAGS) ) );
|
||
// Process the event bits that we *do* understand.
|
||
}
|
||
|
||
// Modem signals are always processed, regardless of whether the port is open.
|
||
if( Event.Flags & FEP_MODEM_CHANGE_SIGNAL )
|
||
{
|
||
DigiDump( (DIGIMODEM|DIGIEVENT|DIGIWAIT),
|
||
("--------- Modem Change Event (%s:%d)\n",
|
||
__FILE__, __LINE__ ) );
|
||
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
|
||
DigiDump( (DIGIMODEM|DIGIWAIT),
|
||
(" CurrentModem = 0x%x\tPreviousModem = 0x%x\n",
|
||
Event.CurrentModem, Event.PreviousModem ));
|
||
|
||
DeviceExt->CurrentModemSignals = Event.CurrentModem;
|
||
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
|
||
// If the port isn't open, don't bother with the rest.
|
||
if( DeviceExt->DeviceState != DIGI_DEVICE_STATE_OPEN )
|
||
{
|
||
// If we might return to OPEN, don't touch anything!
|
||
if( DeviceExt->DeviceState != DIGI_DEVICE_STATE_CLEANUP)
|
||
{
|
||
if( Event.Flags & (FEP_RX_PRESENT | FEP_RECEIVE_BUFFER_OVERRUN | FEP_UART_RECEIVE_OVERRUN) )
|
||
{
|
||
PFEP_CHANNEL_STRUCTURE ChInfo;
|
||
|
||
FlushReceiveBuffer( ControllerExt, DeviceExt );
|
||
|
||
ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress +
|
||
DeviceExt->ChannelInfo.Offset);
|
||
|
||
// Notify us when more data comes in.
|
||
EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window );
|
||
WRITE_REGISTER_UCHAR( &ChInfo->idata, TRUE );
|
||
DisableWindow( ControllerExt );
|
||
}
|
||
// Don't flush transmit (might kill end of data).
|
||
}
|
||
continue;
|
||
}
|
||
|
||
// Reset event notifications.
|
||
EventReason = 0;
|
||
|
||
if( Event.Flags & FEP_EV_BREAK )
|
||
{
|
||
EventReason |= SERIAL_EV_BREAK;
|
||
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
DeviceExt->ErrorWord |= SERIAL_ERROR_BREAK;
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
|
||
if( (Event.Flags & (FEP_TX_LOW | FEP_TX_EMPTY) ) )
|
||
{
|
||
PLIST_ENTRY WriteQueue;
|
||
|
||
#if DBG
|
||
switch( Event.Flags & (FEP_TX_LOW | FEP_TX_EMPTY) )
|
||
{
|
||
case FEP_TX_LOW:
|
||
DigiDump( (DIGIEVENT|DIGIWRITE), ("%s:\tTXLOW event\n", DeviceExt->DeviceDbgString) );
|
||
break;
|
||
case FEP_TX_EMPTY:
|
||
DigiDump( (DIGIEVENT|DIGIWRITE), ("%s:\tTXEMPTY event\n", DeviceExt->DeviceDbgString) );
|
||
break;
|
||
default:
|
||
DigiDump( (DIGIEVENT|DIGIWRITE), ("%s:\tTXLOW and TXEMPTY events\n", DeviceExt->DeviceDbgString) );
|
||
break;
|
||
}
|
||
#endif
|
||
|
||
WriteQueue = &DeviceExt->WriteQueue;
|
||
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
|
||
if( !IsListEmpty( WriteQueue ) )
|
||
{
|
||
PIRP Irp;
|
||
|
||
Irp = CONTAINING_RECORD( WriteQueue->Flink,
|
||
IRP,
|
||
Tail.Overlay.ListEntry );
|
||
|
||
if( Irp->IoStatus.Information != MAXULONG )
|
||
{
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
if( IrpSp->MajorFunction == IRP_MJ_WRITE
|
||
|| ( IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL
|
||
&& Irp->IoStatus.Information == 0
|
||
)
|
||
)
|
||
{
|
||
DigiDump( DIGIEVENT, ("--------- WriteQueue list NOT empty\n") );
|
||
|
||
if( IrpSp->MajorFunction == IRP_MJ_WRITE )
|
||
{
|
||
ASSERT( Irp->IoStatus.Information < IrpSp->Parameters.Write.Length );
|
||
}
|
||
else
|
||
{
|
||
ASSERT( IrpSp->Parameters.DeviceIoControl.IoControlCode ==
|
||
IOCTL_SERIAL_IMMEDIATE_CHAR
|
||
|| IrpSp->Parameters.DeviceIoControl.IoControlCode ==
|
||
IOCTL_SERIAL_XOFF_COUNTER );
|
||
}
|
||
|
||
if( WriteTxBuffer( DeviceExt ) == STATUS_SUCCESS )
|
||
{
|
||
KIRQL OldIrql = DISPATCH_LEVEL;
|
||
|
||
DigiDump( DIGIEVENT, ("--------- Write complete. Successfully completing Irp.\n"
|
||
"--------- #bytes completing = %d\n",
|
||
Irp->IoStatus.Information ) );
|
||
|
||
DIGI_INC_REFERENCE( Irp );
|
||
DigiTryToCompleteIrp( DeviceExt, &OldIrql,
|
||
STATUS_SUCCESS, WriteQueue,
|
||
NULL,
|
||
&DeviceExt->WriteRequestTotalTimer,
|
||
StartWriteRequest );
|
||
|
||
goto WriteDone; // skip unlock
|
||
} // WriteTxBuffer returned SUCCESS
|
||
} // IRP is eligible for WriteTxBuffer
|
||
} // IRP started
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
WriteDone:;
|
||
}
|
||
else // empty(WQ)
|
||
{
|
||
DigiDump( DIGIEVENT, ("--------- WriteQueue was empty\n") );
|
||
|
||
if( Event.Flags & FEP_TX_EMPTY )
|
||
EventReason |= SERIAL_EV_TXEMPTY;
|
||
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
} // FEP_TX_LOW | FEP_TX_EMPTY
|
||
|
||
if( Event.Flags & FEP_RX_PRESENT )
|
||
{
|
||
PLIST_ENTRY ReadQueue;
|
||
PFEP_CHANNEL_STRUCTURE ChInfo;
|
||
USHORT Rin, Rout, Rmax, RxSize;
|
||
|
||
DigiDump( DIGIEVENT, ("--------- Rcv Data Present Event: (%s:%d)\n",
|
||
__FILE__, __LINE__ ) );
|
||
|
||
GetReceivedData:;
|
||
|
||
ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress +
|
||
DeviceExt->ChannelInfo.Offset);
|
||
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
|
||
EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window );
|
||
Rout = READ_REGISTER_USHORT( &ChInfo->rout );
|
||
Rin = READ_REGISTER_USHORT( &ChInfo->rin );
|
||
Rmax = READ_REGISTER_USHORT( &ChInfo->rmax );
|
||
DisableWindow( ControllerExt );
|
||
|
||
if( (DeviceExt->WaitMask & SERIAL_EV_RXCHAR) &&
|
||
(DeviceExt->PreviousRxChar != (ULONG)Rin) )
|
||
{
|
||
EventReason |= SERIAL_EV_RXCHAR;
|
||
}
|
||
|
||
if( (DeviceExt->WaitMask & SERIAL_EV_RXFLAG) &&
|
||
(DeviceExt->UnscannedRXFLAGPosition != (ULONG)Rin) )
|
||
{
|
||
if( ScanReadBufferForSpecialCharacter( DeviceExt,
|
||
DeviceExt->SpecialChars.EventChar ) )
|
||
{
|
||
EventReason |= SERIAL_EV_RXFLAG;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Determine if we are waiting to notify a 80% receive buffer
|
||
// full.
|
||
//
|
||
// NOTE: I assume the controller will continue to notify
|
||
// us that data is still in the buffer, even if
|
||
// we don't take the data out of the controller's
|
||
// buffer.
|
||
//
|
||
if( (DeviceExt->WaitMask & SERIAL_EV_RX80FULL)
|
||
&& !(DeviceExt->HistoryWait & SERIAL_EV_RX80FULL) ) // notification is already pending
|
||
{
|
||
//
|
||
// Okay, is the receive buffer 80% or more full??
|
||
//
|
||
RxSize = (Rin - Rout) & Rmax;
|
||
|
||
if( RxSize )
|
||
{
|
||
if( DeviceExt->SpecialFlags & DIGI_SPECIAL_FLAG_FAST_RAS )
|
||
{
|
||
if( RxSize >= DeviceExt->ReceiveNotificationLimit )
|
||
{
|
||
EventReason |= SERIAL_EV_RX80FULL;
|
||
}
|
||
}
|
||
else // not RAS
|
||
{
|
||
// Perform 32-bit math to avoid roundoff errors.
|
||
if( RxSize >= (USHORT) ( ((ULONG)Rmax + 1UL) * 8UL / 10UL) )
|
||
{
|
||
EventReason |= SERIAL_EV_RX80FULL;
|
||
}
|
||
else
|
||
{
|
||
USHORT RxHighWater;
|
||
|
||
EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window );
|
||
RxHighWater = READ_REGISTER_USHORT( &ChInfo->rhigh );
|
||
DisableWindow( ControllerExt );
|
||
|
||
// If flow control is engaged, trigger the event (we won't get any more data).
|
||
if( RxSize >= RxHighWater - 1 )
|
||
{
|
||
EventReason |= SERIAL_EV_RX80FULL;
|
||
}
|
||
}
|
||
} // not RAS
|
||
} // if data
|
||
} // RX80FULL
|
||
|
||
ReadQueue = &DeviceExt->ReadQueue;
|
||
if( !IsListEmpty( ReadQueue ) )
|
||
{
|
||
PIRP Irp;
|
||
|
||
Irp = CONTAINING_RECORD( ReadQueue->Flink,
|
||
IRP,
|
||
Tail.Overlay.ListEntry );
|
||
|
||
if( DeviceExt->ReadStatus == STATUS_PENDING
|
||
&& Irp->IoStatus.Information != MAXULONG ) // not started yet
|
||
{
|
||
KIRQL OldIrql = DISPATCH_LEVEL;
|
||
|
||
// Hold IRP across lock drop in ReadRxBuffer:ProcessSlowRead:DigiSatisfyWait.
|
||
DIGI_INC_REFERENCE( Irp );
|
||
|
||
if( STATUS_SUCCESS == ReadRxBuffer( DeviceExt, &OldIrql ) )
|
||
{
|
||
#if DBG
|
||
if( DigiDebugLevel & DIGIRXTRACE )
|
||
{
|
||
PUCHAR Temp;
|
||
ULONG i;
|
||
|
||
Temp = Irp->AssociatedIrp.SystemBuffer;
|
||
|
||
DigiDump( DIGIRXTRACE, ("Read buffer contains: %s",
|
||
DeviceExt->DeviceDbgString) );
|
||
for( i = 0;
|
||
i < Irp->IoStatus.Information;
|
||
i++ )
|
||
{
|
||
if( (i & 15) == 0 )
|
||
DigiDump( DIGIRXTRACE, ( "\n\t") );
|
||
|
||
DigiDump( DIGIRXTRACE, ( "-%02x", Temp[i]) );
|
||
}
|
||
DigiDump( DIGIRXTRACE, ("\n") );
|
||
}
|
||
#endif
|
||
//
|
||
// We have satisfied this current request, so lets
|
||
// complete it.
|
||
//
|
||
DigiDump( DIGIEVENT, ("--------- Read complete. Successfully completing Irp.\n") );
|
||
|
||
DigiDump( DIGIEVENT, ("--------- #bytes completing = %d\n",
|
||
Irp->IoStatus.Information ) );
|
||
|
||
DeviceExt->ReadStatus = SERIAL_COMPLETE_READ_COMPLETE;
|
||
|
||
DigiTryToCompleteIrp( DeviceExt, &OldIrql,
|
||
STATUS_SUCCESS, ReadQueue,
|
||
&DeviceExt->ReadRequestIntervalTimer,
|
||
&DeviceExt->ReadRequestTotalTimer,
|
||
StartReadRequest );
|
||
|
||
goto ReadDone; // skip DEC and unlock
|
||
} // else ReadRxBuffer != SUCCESS
|
||
DIGI_DEC_REFERENCE( Irp );
|
||
} // else ReadStatus != STATUS_PENDING || IRP not started
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
ReadDone:;
|
||
}
|
||
else // empty(RQ)
|
||
{
|
||
PSERIAL_XOFF_COUNTER Xc;
|
||
|
||
//
|
||
// We don't have an outstanding read request, so make sure
|
||
// we reset the IDATA flag on the controller.
|
||
//
|
||
ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress +
|
||
DeviceExt->ChannelInfo.Offset);
|
||
|
||
EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window );
|
||
WRITE_REGISTER_UCHAR( &ChInfo->idata, TRUE );
|
||
DisableWindow( ControllerExt );
|
||
|
||
DigiDump( DIGIEVENT, ("--------- No outstanding read IRP's to place received data.\n") );
|
||
|
||
DeviceExt->PreviousRxChar = (ULONG)Rin;
|
||
|
||
// The perception of receive data might complete an XOFF_COUNTER on the WriteQueue.
|
||
// Keep track of what we've eaten via XcPreview to avoid counting bytes twice (in ReadRxBuffer).
|
||
Xc = DeviceExt->pXoffCounter;
|
||
if( Xc )
|
||
{
|
||
RxSize = (Rin - Rout) & Rmax;
|
||
|
||
if( RxSize < Xc->Counter )
|
||
{
|
||
DigiDump( (DIGIWRITE|DIGIDIAG1), ("IDATA reduced XOFF_COUNTER\n") );
|
||
Xc->Counter -= RxSize;
|
||
DeviceExt->XcPreview += RxSize;
|
||
}
|
||
else
|
||
{
|
||
// XOFF_COUNTER is complete.
|
||
|
||
KIRQL OldIrql = DISPATCH_LEVEL;
|
||
#if DBG
|
||
Xc->Counter = 0; // Looks a little nicer...
|
||
#endif
|
||
DigiDump( (DIGIWRITE|DIGIDIAG1), ("IDATA on empty(RQ) is completing XOFF_COUNTER\n") );
|
||
DigiTryToCompleteIrp( DeviceExt, &OldIrql, STATUS_SUCCESS,
|
||
&DeviceExt->WriteQueue, NULL, &DeviceExt->WriteRequestTotalTimer, StartWriteRequest );
|
||
goto XcDone; // skip unlock
|
||
}
|
||
}
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
XcDone:;
|
||
}
|
||
} // FEP_RX_PRESENT
|
||
|
||
if( Event.Flags & FEP_MODEM_CHANGE_SIGNAL )
|
||
{
|
||
ULONG WaitMask;
|
||
UCHAR ChangedModemState;
|
||
|
||
ChangedModemState = Event.CurrentModem ^ Event.PreviousModem;
|
||
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
|
||
WaitMask = DeviceExt->WaitMask;
|
||
|
||
DigiDump( (DIGIMODEM|DIGIEVENT|DIGIWAIT),
|
||
("--------- Modem Change Event (%s:%d)\t",
|
||
" ChangedModemState = 0x%x\n",
|
||
ChangedModemState,
|
||
__FILE__, __LINE__ ) );
|
||
|
||
if( (WaitMask & SERIAL_EV_CTS) &&
|
||
(ControllerExt->ModemSignalTable[CTS_SIGNAL] & ChangedModemState) )
|
||
{
|
||
EventReason |= SERIAL_EV_CTS;
|
||
}
|
||
if( (WaitMask & SERIAL_EV_DSR) &&
|
||
(ControllerExt->ModemSignalTable[DSR_SIGNAL] & ChangedModemState) )
|
||
{
|
||
EventReason |= SERIAL_EV_DSR;
|
||
}
|
||
if( (WaitMask & SERIAL_EV_RLSD) &&
|
||
(ControllerExt->ModemSignalTable[DCD_SIGNAL] & ChangedModemState) )
|
||
{
|
||
EventReason |= SERIAL_EV_RLSD;
|
||
}
|
||
if( (WaitMask & SERIAL_EV_RING) &&
|
||
(ControllerExt->ModemSignalTable[RI_SIGNAL] & ChangedModemState) )
|
||
{
|
||
EventReason |= SERIAL_EV_RING;
|
||
}
|
||
|
||
if( DeviceExt->EscapeChar )
|
||
{
|
||
UCHAR MSRByte, CurrentModemSignals;
|
||
|
||
if( DeviceExt->PreviousMSRByte )
|
||
DigiDump( DIGIERRORS, (" PreviousMSRByte != 0\n") );
|
||
|
||
MSRByte = 0;
|
||
|
||
if( ControllerExt->ModemSignalTable[CTS_SIGNAL] & ChangedModemState )
|
||
{
|
||
MSRByte |= SERIAL_MSR_DCTS;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[DSR_SIGNAL] & ChangedModemState )
|
||
{
|
||
MSRByte |= SERIAL_MSR_DDSR;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[RI_SIGNAL] & ChangedModemState )
|
||
{
|
||
MSRByte |= SERIAL_MSR_TERI;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[DCD_SIGNAL] & ChangedModemState )
|
||
{
|
||
MSRByte |= SERIAL_MSR_DDCD;
|
||
}
|
||
|
||
CurrentModemSignals = DeviceExt->CurrentModemSignals;
|
||
if( ControllerExt->ModemSignalTable[CTS_SIGNAL] & CurrentModemSignals )
|
||
{
|
||
MSRByte |= SERIAL_MSR_CTS;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[DSR_SIGNAL] & CurrentModemSignals )
|
||
{
|
||
MSRByte |= SERIAL_MSR_DSR;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[RI_SIGNAL] & CurrentModemSignals )
|
||
{
|
||
MSRByte |= SERIAL_MSR_RI;
|
||
}
|
||
if( ControllerExt->ModemSignalTable[DCD_SIGNAL] & CurrentModemSignals )
|
||
{
|
||
MSRByte |= SERIAL_MSR_DCD;
|
||
}
|
||
|
||
if( !IsListEmpty( &DeviceExt->ReadQueue ) )
|
||
{
|
||
PIRP Irp;
|
||
PIO_STACK_LOCATION IrpSp;
|
||
|
||
Irp = CONTAINING_RECORD( DeviceExt->ReadQueue.Flink,
|
||
IRP,
|
||
Tail.Overlay.ListEntry );
|
||
|
||
IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
||
|
||
if( (IrpSp->Parameters.Read.Length - Irp->IoStatus.Information) > 3 )
|
||
{
|
||
PUCHAR ReadBuffer;
|
||
|
||
ReadBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer +
|
||
Irp->IoStatus.Information;
|
||
|
||
ReadBuffer[0] = DeviceExt->EscapeChar;
|
||
ReadBuffer[1] = SERIAL_LSRMST_MST;
|
||
ReadBuffer[2] = MSRByte;
|
||
Irp->IoStatus.Information += 3;
|
||
|
||
DeviceExt->PreviousMSRByte = 0;
|
||
|
||
DigiDump( DIGIMODEM, (" CurrentModemSignals = 0x%x\n"
|
||
" ChangedModemState = 0x%x\n"
|
||
" MSRByte = 0x%x\n",
|
||
DeviceExt->CurrentModemSignals,
|
||
ChangedModemState,
|
||
MSRByte) );
|
||
}
|
||
else
|
||
{
|
||
DigiDump( (DIGIMODEM|DIGIERRORS),
|
||
("Insufficient read IRP space available to record modem status change!\n") );
|
||
DeviceExt->PreviousMSRByte = MSRByte;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
DigiDump( (DIGIMODEM|DIGIERRORS),
|
||
("No read IRP in which to record modem status change!\n") );
|
||
DeviceExt->PreviousMSRByte = MSRByte;
|
||
}
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
|
||
//
|
||
// We need to read any data which may be available.
|
||
//
|
||
Event.Flags &= ~FEP_MODEM_CHANGE_SIGNAL;
|
||
goto GetReceivedData;
|
||
}
|
||
else
|
||
{
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
} // FEP_MODEM_CHANGE_SIGNAL
|
||
|
||
if( Event.Flags & FEP_RECEIVE_BUFFER_OVERRUN )
|
||
{
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
DeviceExt->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
|
||
InterlockedIncrement(&DeviceExt->PerfData.BufferOverrunErrorCount);
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
|
||
if( Event.Flags & FEP_UART_RECEIVE_OVERRUN )
|
||
{
|
||
KeAcquireSpinLockAtDpcLevel( &DeviceExt->ControlAccess );
|
||
DeviceExt->ErrorWord |= SERIAL_ERROR_OVERRUN;
|
||
InterlockedIncrement(&DeviceExt->PerfData.SerialOverrunErrorCount);
|
||
KeReleaseSpinLockFromDpcLevel( &DeviceExt->ControlAccess );
|
||
}
|
||
|
||
if( EventReason )
|
||
DigiSatisfyEvent( ControllerExt, DeviceExt, EventReason );
|
||
|
||
}
|
||
|
||
//
|
||
// Regardless of whether we processed the event, make sure we forward
|
||
// the event out pointer.
|
||
//
|
||
EnableWindow( ControllerExt, ControllerExt->Global.Window );
|
||
|
||
WRITE_REGISTER_USHORT( (PUSHORT)((PUCHAR)ControllerExt->VirtualAddress+FEP_EOUT),
|
||
Eout );
|
||
|
||
DisableWindow( ControllerExt );
|
||
|
||
DigiDump( (DIGIFLOW|DIGIEVENT), ("Exiting DigiServiceEvent\n") );
|
||
|
||
} // DigiServiceEvent
|
||
|
||
|
||
|
||
VOID
|
||
DigiDPCService( IN PKDPC Dpc,
|
||
IN PVOID DeferredContext,
|
||
IN PVOID SystemContext1,
|
||
IN PVOID SystemContext2 )
|
||
{
|
||
extern BOOLEAN DigiDriverInitialized; // from init.c
|
||
PDIGI_CONTROLLER_EXTENSION ControllerExt = DeferredContext;
|
||
|
||
DigiDump( DIGIDPCFLOW, ("DigiBoard: Entering DigiDPCService\n") );
|
||
|
||
// Ensure the controller is intialized.
|
||
if( DigiDriverInitialized // We can't get here if we're not initialized. --SWA
|
||
&& ControllerExt->ControllerState == DIGI_DEVICE_STATE_INITIALIZED )
|
||
{
|
||
USHORT DownloadRequest, FepStat;
|
||
USHORT Ein, Eout;
|
||
|
||
EnableWindow( ControllerExt, ControllerExt->Global.Window );
|
||
|
||
FepStat =
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)ControllerExt->VirtualAddress+
|
||
FEP_FEPSTAT) );
|
||
DownloadRequest =
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)ControllerExt->VirtualAddress+
|
||
FEP_DLREQ) );
|
||
Ein =
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)ControllerExt->VirtualAddress+
|
||
FEP_EIN) );
|
||
Eout =
|
||
READ_REGISTER_USHORT( (PUSHORT)((PUCHAR)ControllerExt->VirtualAddress+
|
||
FEP_EOUT) );
|
||
|
||
DisableWindow( ControllerExt );
|
||
|
||
if (FepStat!=FEP_FEPSTAT_OK)
|
||
{
|
||
LARGE_INTEGER CurrentSystemTime;
|
||
|
||
KeQuerySystemTime( &CurrentSystemTime );
|
||
InterlockedIncrement(&ControllerExt->WindowFailureCount);
|
||
|
||
DigiDump( DIGIERRORS, ("DigiBoard: Memory Window Failure (%d)\n", ControllerExt->WindowFailureCount));
|
||
|
||
if (CurrentSystemTime.HighPart!=ControllerExt->LastErrorLogTime.HighPart)
|
||
{
|
||
PHYSICAL_ADDRESS Signature;
|
||
|
||
Signature.LowPart = 0x5a5a5a5a;
|
||
ControllerExt->LastErrorLogTime = CurrentSystemTime;
|
||
DigiLogError( ControllerExt->DriverObject,
|
||
NULL,
|
||
Diagnose(ControllerExt),
|
||
Signature,
|
||
0,
|
||
0,
|
||
(UCHAR)ControllerExt->WindowFailureCount,
|
||
__LINE__,
|
||
STATUS_SUCCESS,
|
||
SERIAL_MEMORY_WINDOW_FAILURE,
|
||
ControllerExt->ControllerName.Length+1,
|
||
ControllerExt->ControllerName.Buffer,
|
||
0,
|
||
NULL );
|
||
}
|
||
}
|
||
else if( DownloadRequest ) // Look and see if there is a download request
|
||
{
|
||
// The Controller is requesting a concentrator download.
|
||
|
||
XXDownload( ControllerExt );
|
||
|
||
//
|
||
// We don't service any ports until all concentrator
|
||
// requests have been satisfied.
|
||
//
|
||
}
|
||
else if( Ein != Eout )
|
||
{
|
||
//
|
||
// Architecture ensures we have exclusive access to events on the controller.
|
||
// (We reschedule ourselves to run, so two instances cannot coexist.)
|
||
//
|
||
DigiServiceEvent( ControllerExt, Ein, Eout );
|
||
}
|
||
|
||
}
|
||
|
||
// Reset our timer.
|
||
KeSetTimer( &ControllerExt->PollTimer,
|
||
ControllerExt->PollTimerLength,
|
||
&ControllerExt->PollDpc );
|
||
|
||
DigiDump( DIGIDPCFLOW, ("DigiBoard: Exiting DigiDPCService\n") );
|
||
|
||
} // DigiDPCService
|
||
|
||
|
||
|