示例#1
0
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);
    }
}
示例#2
0
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
示例#3
0
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
示例#4
0
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
示例#5
0
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
示例#6
0
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