void CAccountLayer::button_press(int tag) { CGameScene *pGameScene = (CGameScene *)parent(); if (tag == 10200) { pGameScene->window_closed(0); Root::instance()->queue_end_rendering(); } else if (tag == 10201) { CMD_C_Account Account; Account.wChairID = pGameScene->GetMeChairID(); pGameScene->GetClientKernel()->SendSocketData(MDM_GF_GAME, SUB_C_ACCOUNT, &Account, sizeof(CMD_C_Account)); DisableWindow(true); } else if (tag == 10202) { ShowWidnow(false); } }
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
USHORT NBytesInRecvBuffer( PDIGI_CONTROLLER_EXTENSION ControllerExt, PDIGI_DEVICE_EXTENSION DeviceExt ) /*++ Routine Description: Determine the number of actual bytes in the receive buffer. This routine takes into account DOSMODE on the controller. Arguments: ControllerExt - pointer to the controller extension information assosicated with DeviceExt. DeviceExt - pointer to the device specific information. Return Value: Number of bytes in the receive buffer. --*/ { PUCHAR ControllerBuffer; PFEP_CHANNEL_STRUCTURE ChInfo; USHORT AmountInQueue; USHORT Rin, Rout, Rmax; USHORT DosMode; UCHAR ReceivedByte, SecondReceivedByte; ControllerBuffer = ControllerExt->VirtualAddress + DeviceExt->RxSeg.Offset; ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress + DeviceExt->ChannelInfo.Offset); EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Rout = READ_REGISTER_USHORT( &ChInfo->rout ); Rin = READ_REGISTER_USHORT( &ChInfo->rin ); Rmax = READ_REGISTER_USHORT( &ChInfo->rmax ); DosMode = READ_REGISTER_USHORT( &ChInfo->iflag ); DisableWindow( ControllerExt ); DosMode &= IFLAG_DOSMODE; if( !DosMode ) { AmountInQueue = Rin - Rout; if( (SHORT)AmountInQueue < 0) AmountInQueue += (Rmax + 1); return( AmountInQueue ); } AmountInQueue = 0; EnableWindow( ControllerExt, DeviceExt->RxSeg.Window ); DigiDump( DIGIIOCTL, (" NRecvRoutine: Rin = 0x%x, Rout = 0x%x\n", Rin, Rout) ); while( Rout != Rin ) { ReceivedByte = READ_REGISTER_UCHAR( (ControllerBuffer + Rout) ); Rout++; Rout &= Rmax; AmountInQueue++; DigiDump( DIGIIOCTL, (" NRecvByte = 0x%x, Rout = 0x%x\n", ReceivedByte, Rout) ); // // We need to process out DigiBoard specific 0xFF. // if( ReceivedByte == 0xFF ) { // // We have some special processing to do! // // // Is there a second character available?? // if( Rout == Rin ) { // // The second character isn't available! // AmountInQueue--; DigiDump( DIGIIOCTL, (" NRecvRoutine, 2nd byte not available!\n" ) ); break; } else { // // Get the 2nd characters // SecondReceivedByte = READ_REGISTER_UCHAR( (ControllerBuffer + Rout) ); Rout++; Rout &= Rmax; if( SecondReceivedByte == 0xFF ) { // // We actually received a 0xFF in the data stream. // DigiDump( DIGIIOCTL, (" NRecvRoutine, Actually recv'ed 0xFF\n" ) ); continue; } else { // // This is Line Status information. Is the last // character available?? // if( Rin == Rout ) { // // The 3rd byte isn't available // AmountInQueue--; DigiDump( DIGIIOCTL, (" NRecvRoutine, 3rd byte not available!\n" ) ); break; } Rout++; Rout &= Rmax; } } } } DisableWindow( ControllerExt ); DigiDump( DIGIIOCTL, (" NRecvRoutine, return RecvBytes = %d!\n", AmountInQueue ) ); return( AmountInQueue ); } // end NBytesInRecvBuffer
VOID DrainTransmit( PDIGI_CONTROLLER_EXTENSION ControllerExt, PDIGI_DEVICE_EXTENSION DeviceExt, PIRP Irp ) /*++ Routine Description: We do the necessary checks to determine if the controller has transmitted all the data it has been given. The check basically is: if( CIN == COUT TIN == TOUT TBusy == 0 ) transmit buffer is empty. NOTE: Care should be taken when using this function, and at what dispatch level it is being called from. I don't do any synch'ing with the WriteQueue in the DeviceObject. So it is potentially possible that data could keep getting put on the controller while the function is waiting for it to drain. Arguments: ControllerExt - a pointer to this devices controllers extension. DeviceObject - a pointer to this devices object. Irp - Pointer to the current Irp request whose context this function is being called. This allows us to determine if the Irp has been cancelled. Return Value: --*/ { PFEP_CHANNEL_STRUCTURE ChInfo; PCOMMAND_STRUCT CommandQ; COMMAND_STRUCT CmdStruct; UCHAR TBusy; ULONG count; USHORT OrgTout, Tin, Tout; TIME DelayInterval; ChInfo = (PFEP_CHANNEL_STRUCTURE)(ControllerExt->VirtualAddress + DeviceExt->ChannelInfo.Offset); EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Tin = READ_REGISTER_USHORT( &ChInfo->tin ); Tout = READ_REGISTER_USHORT( &ChInfo->tout ); TBusy = READ_REGISTER_UCHAR( &ChInfo->tbusy ); DisableWindow( ControllerExt ); OrgTout = Tout; // // Get the command queue info // CommandQ = ((PCOMMAND_STRUCT)(ControllerExt->VirtualAddress + FEP_CIN)); EnableWindow( ControllerExt, ControllerExt->Global.Window ); READ_REGISTER_BUFFER_UCHAR( (PUCHAR)CommandQ, (PUCHAR)&CmdStruct, sizeof(CmdStruct) ); DisableWindow( ControllerExt ); // // Delay for 10 milliseconds // #if rmm < 807 DelayInterval = RtlConvertLongToLargeInteger( -10 * 10000 ); #else DelayInterval.QuadPart = -10 * 10000; #endif count = 0; while( ((Tin != Tout) || (TBusy) || (CmdStruct.cmHead != CmdStruct.cmTail)) && !Irp->Cancel ) { ASSERT( KeGetCurrentIrql() < DISPATCH_LEVEL ); // not DPC, or KeDelay won't ever return KeDelayExecutionThread( KernelMode, FALSE, &DelayInterval ); EnableWindow( ControllerExt, DeviceExt->ChannelInfo.Window ); Tin = READ_REGISTER_USHORT( &ChInfo->tin ); Tout = READ_REGISTER_USHORT( &ChInfo->tout ); TBusy = READ_REGISTER_UCHAR( &ChInfo->tbusy ); DisableWindow( ControllerExt ); EnableWindow( ControllerExt, ControllerExt->Global.Window ); READ_REGISTER_BUFFER_UCHAR( (PUCHAR)CommandQ, (PUCHAR)&CmdStruct, sizeof(CmdStruct) ); DisableWindow( ControllerExt ); if( Tout != OrgTout ) { count = 0; OrgTout = Tout; } if( count++ > 2500 ) { // // We have waited for 25 seconds and haven't seen the transmit // buffer change. Assume we are in a deadlock flow control state // and exit! // // // We go ahead and flush the transmit queue because a close // may be following soon, and we don't want it to have to // wait again. Basically, it had its chance to drain. // FlushTransmitBuffer( ControllerExt, DeviceExt ); break; } } } // end DrainTransmit
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
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