wxString RaceAnalyzerComm::readScript(){ wxMutexLocker lock(_commMutex); wxString script = ""; int scriptPage = 0; int to = 0; CComm *serialPort = GetSerialPort(); if (NULL==serialPort) throw CommException(CommException::OPEN_PORT_FAILED); FlushReceiveBuffer(serialPort); while(!to){ //wxString cmd = wxString::Format("println(getScriptPage(%d))",scriptPage++); wxString cmd = wxString::Format("readScriptPage %d",scriptPage++); wxString buffer = SendCommand(serialPort, cmd); wxString scriptFrag = GetParam(buffer,"script", true); VERBOSE(FMT("escaped: %s", scriptFrag.ToAscii())); Unescape(scriptFrag); VERBOSE(FMT("unescaped: %s", scriptFrag.ToAscii())); size_t scriptFragmentLen = scriptFrag.Length(); if (scriptFragmentLen > 0 ) script+=scriptFrag; //the last page is a 'partial page' if (scriptFragmentLen < SCRIPT_PAGE_LENGTH ) break; } CloseSerialPort(); if (to){ throw CommException(CommException::COMM_TIMEOUT); } return script; }
NTSTATUS SerialCreate( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: Arguments: Return Value: --*/ { PDIGI_DEVICE_EXTENSION DeviceExt = DeviceObject->DeviceExtension; PDIGI_CONTROLLER_EXTENSION ControllerExt = DeviceExt->ParentControllerExt; NTSTATUS Status=STATUS_SUCCESS; PFEP_CHANNEL_STRUCTURE ChInfo; DIGI_XFLAG IFlag; USHORT Rmax, Tmax, Rhigh; KIRQL OldIrql; UCHAR MStatSet, MStatClear, HFlowSet, HFlowClear; #if DBG LARGE_INTEGER CurrentSystemTime; #endif if (DeviceObject==ControllerExt->ControllerDeviceObject) { /* ** All controller opens succeed. */ DigiDump( (DIGIIRP|DIGIFLOW|DIGICREATE), ("ControllerCreate\n")); Irp->IoStatus.Status = STATUS_SUCCESS; Irp->IoStatus.Information = 0; DigiIoCompleteRequest( Irp, IO_NO_INCREMENT ); return STATUS_SUCCESS; } #if DBG KeQuerySystemTime( &CurrentSystemTime ); #endif DigiDump( (DIGIIRP|DIGIFLOW|DIGICREATE), ("Entering SerialCreate: port = %s\tIRP = 0x%x\t%u:%u\n", DeviceExt->DeviceDbgString, Irp, CurrentSystemTime.HighPart, CurrentSystemTime.LowPart) ); ASSERT( IoGetCurrentIrpStackLocation(Irp)->MajorFunction == IRP_MJ_CREATE ); InterlockedIncrement(&ControllerExt->PerfData.OpenRequests); KeAcquireSpinLock( &DeviceExt->ControlAccess, &OldIrql ); DeviceExt->DeviceState = DIGI_DEVICE_STATE_OPEN; DeviceExt->WaitMask = 0L; DeviceExt->HistoryWait = 0L; DeviceExt->TotalCharsQueued = 0L; DeviceExt->EscapeChar = 0; DeviceExt->SpecialFlags = 0; DeviceExt->UnscannedRXFLAGPosition = MAXULONG; KeReleaseSpinLock( &DeviceExt->ControlAccess, OldIrql ); // // Okay, lets make sure the port on the controller is in a known // state. // ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress + DeviceExt->ChannelInfo.Offset); FlushTransmitBuffer( ControllerExt, DeviceExt ); FlushReceiveBuffer( ControllerExt, DeviceExt ); // Set default flow control limits. EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Rmax = READ_REGISTER_USHORT( &ChInfo->rmax ); Tmax = READ_REGISTER_USHORT( &ChInfo->tmax ); DisableWindow( ControllerExt ); DeviceExt->XonLimit = (((LONG)Rmax + 1) / 4); Rhigh = Rmax - (USHORT)DeviceExt->XonLimit; DeviceExt->XoffLimit = DeviceExt->XonLimit; // We preserve XoffLimit in Win32 semantics WriteCommandWord( DeviceExt, SET_RCV_LOW, (USHORT)DeviceExt->XonLimit ); WriteCommandWord( DeviceExt, SET_RCV_HIGH, Rhigh ); WriteCommandWord( DeviceExt, SET_TX_LOW, (USHORT)((Tmax + 1) / 4) ); // // Based on 10ms polling frequency and 115.2Kbps bit rate, // we acquire up to 115.2 bytes per polling iteration. // Thus, to avoid flow control, we need notification up to // two polling iterations prior to reaching XoffLimit. // However, we need at least 50 bytes to make the interaction worthwhile. // DH Calculate limit dynamically based on communication characteristics. // if( Rhigh > 2*115 + 50 ) DeviceExt->ReceiveNotificationLimit = Rhigh - 2*115; else if( Rmax >= 100 ) DeviceExt->ReceiveNotificationLimit = 50; else // shouldn't happen DeviceExt->ReceiveNotificationLimit = Rmax / 2; // // Initialize requested queue sizes. // DeviceExt->RequestedQSize.InSize = (ULONG)(Rmax + 1); DeviceExt->RequestedQSize.OutSize = (ULONG)(Tmax + 1); // // Set where RxChar and RxFlag were last seen in the buffer to a // bogus value so we catch the condition where the 1st character in // is RxFlag, and so we give notification for the 1st character // received. // DeviceExt->PreviousRxChar = MAXULONG; DeviceExt->UnscannedRXFLAGPosition = MAXULONG; // // Set the Xon & Xoff characters for this device to default values. // WriteCommandBytes( DeviceExt, SET_XON_XOFF_CHARACTERS, DEFAULT_XON_CHAR, DEFAULT_XOFF_CHAR ); MStatClear = MStatSet = 0; HFlowClear = HFlowSet = 0; // // We have some RTS flow control to worry about. // // Don't forget that flow control is sticky across // open requests. // if( (DeviceExt->FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE ) { // // This is normal RTS input flow control // HFlowSet |= ControllerExt->ModemSignalTable[RTS_SIGNAL]; } else if( (DeviceExt->FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_CONTROL ) { // // We need to make sure RTS is asserted when certain 'things' // occur, or when we are in a certain state. // MStatSet |= ControllerExt->ModemSignalTable[RTS_SIGNAL]; } else if( (DeviceExt->FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE ) { } else { // // RTS Control Mode is in a Disabled state. // MStatClear |= ControllerExt->ModemSignalTable[RTS_SIGNAL]; } // // We have some DTR flow control to worry about. // // Don't forget that flow control is sticky across // open requests. // if( (DeviceExt->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE ) { // // This is normal DTR input flow control // HFlowSet |= ControllerExt->ModemSignalTable[DTR_SIGNAL]; } else if( (DeviceExt->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_CONTROL ) { // // We need to make sure DTR is asserted when certain 'things' // occur, or when we are in a certain state. // MStatSet |= ControllerExt->ModemSignalTable[DTR_SIGNAL]; } else { // // DTR Control Mode is in a Disabled state. // MStatClear |= ControllerExt->ModemSignalTable[DTR_SIGNAL]; } // // CTS, DSR, and DCD output handshaking is sticky across OPEN requests. // if( (DeviceExt->ControlHandShake & SERIAL_CTS_HANDSHAKE) ) { HFlowSet |= ControllerExt->ModemSignalTable[CTS_SIGNAL]; } else { HFlowClear |= ControllerExt->ModemSignalTable[CTS_SIGNAL]; } if( (DeviceExt->ControlHandShake & SERIAL_DSR_HANDSHAKE) ) { HFlowSet |= ControllerExt->ModemSignalTable[DSR_SIGNAL]; } else { HFlowClear |= ControllerExt->ModemSignalTable[DSR_SIGNAL]; } if( (DeviceExt->ControlHandShake & SERIAL_DCD_HANDSHAKE) ) { HFlowSet |= ControllerExt->ModemSignalTable[DCD_SIGNAL]; } else { HFlowClear |= ControllerExt->ModemSignalTable[DCD_SIGNAL]; } // // Make sure we enable/disable flow controls before trying to // explicitly set/clear modem control lines. // if( HFlowSet || HFlowClear ) { DeviceExt->WriteOnlyModemSignalMask = (~HFlowSet) & (ControllerExt->ModemSignalTable[DTR_SIGNAL]|ControllerExt->ModemSignalTable[RTS_SIGNAL]); WriteCommandBytes( DeviceExt, SET_HDW_FLOW_CONTROL, HFlowSet, HFlowClear ); } if( MStatSet || MStatClear ) { DeviceExt->CurrentModemSignals |= MStatSet; DeviceExt->CurrentModemSignals &= ~MStatClear; DeviceExt->WriteOnlyModemSignalValue |= MStatSet; DeviceExt->WriteOnlyModemSignalValue &= ~MStatClear; WriteCommandBytes( DeviceExt, SET_MODEM_LINES, MStatSet, MStatClear ); } // // Make sure we get break notification through the event queue to // begin with. // IFlag.Mask = (USHORT)(~( IFLAG_PARMRK | IFLAG_INPCK | IFLAG_DOSMODE )); IFlag.Src = IFLAG_BRKINT; IFlag.Command = SET_IFLAGS; SetXFlag( DeviceExt, &IFlag ); // // Okay, were done, lets get the heck out of dodge. // Irp->IoStatus.Status = Status; Irp->IoStatus.Information = 0L; // // We do this check here to make sure the controller has had // a chance to catch up. Running on fast machines doesn't always // give the controller a chance. // EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); if( READ_REGISTER_USHORT( &ChInfo->rlow ) == 0 ) DigiDump( DIGIINIT, ("ChInfo->rlow == 0\n")); if( READ_REGISTER_USHORT( &ChInfo->rhigh ) == 0 ) DigiDump( DIGIINIT, ("ChInfo->rhigh == 0\n")); if( READ_REGISTER_USHORT( &ChInfo->tlow ) == 0 ) DigiDump( DIGIINIT, ("ChInfo->tlow == 0\n")); // // Enable IDATA so we get notified when new data has arrived. // WRITE_REGISTER_UCHAR( &ChInfo->idata, TRUE ); DisableWindow( ControllerExt ); DigiIoCompleteRequest( Irp, IO_NO_INCREMENT ); InterlockedIncrement(&ControllerExt->PerfData.OpenPorts); DigiDump( (DIGIFLOW|DIGICREATE), ("Exiting SerialCreate: port = %s\n", DeviceExt->DeviceDbgString) ); return( STATUS_SUCCESS ); } // end SerialCreate
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