|
|
/*--------------------------------------------------------------------------
* * Copyright (C) Cyclades Corporation, 1996-2001. * All rights reserved. * * Cyclom-Y Port Driver * * This file: cyyintr.c * * Description: This module contains the code related to interrupt * handling in the Cyclom-Y Port driver. * * Notes: This code supports Windows 2000 and Windows XP, * x86 and IA64 processors. * * Complies with Cyclades SW Coding Standard rev 1.3. * *-------------------------------------------------------------------------- */
/*-------------------------------------------------------------------------
* * Change History * *-------------------------------------------------------------------------- * * *-------------------------------------------------------------------------- */ #include "precomp.h"
// FANNY: THIS WAS IN CYINIT.C. IT WILL PROBABLY DESAPPEAR FROM HERE TOO.
//extern const unsigned long CyyCDOffset[];
const unsigned long CyyCDOffset[] = { // CD1400 offsets within the board
0x00000000,0x00000400,0x00000800,0x00000C00, 0x00000200,0x00000600,0x00000A00,0x00000E00 };
//ADDED TO DEBUG_RTPR
extern PDRIVER_OBJECT CyyDO; //END DEBUG_RTPR
#ifdef ALLOC_PRAGMA
//#pragma alloc_text(PAGESER,CyyIsr)
//#pragma alloc_text(PAGESER,CyyPutChar)
//#pragma alloc_text(PAGESER,CyyProcessLSR)
//#pragma alloc_text(PAGESER,CyyTxStart)
//#pragma alloc_text(PAGESER,CyySendXon)
//#pragma alloc_text(PAGESER,CyySendXoff)
#endif
BOOLEAN CyyIsr( IN PKINTERRUPT InterruptObject, IN PVOID Context ) /*--------------------------------------------------------------------------
CyyIsr() Routine Description: This is the interrupt service routine for the Cyclom-Y Port driver.
Arguments:
InterruptObject - Pointer to interrupt object (not used).
Context - Pointer to the device extension for this device.
Return Value: This function will return TRUE if the serial port is the source of this interrupt, FALSE otherwise. --------------------------------------------------------------------------*/ { PCYY_DISPATCH Dispatch = Context; PCYY_DEVICE_EXTENSION Extension;
BOOLEAN ServicedAnInterrupt = FALSE;
PUCHAR chip; PUCHAR mappedboard = NULL; ULONG bus = Dispatch->IsPci; unsigned char status, save_xir, save_car, x, rxchar=0; ULONG i,channel,chipindex,portindex; UCHAR misr;
BOOLEAN thisChipInterrupted; PCYY_DEVICE_EXTENSION interlockedExtension[CYY_CHANNELS_PER_CHIP];
UNREFERENCED_PARAMETER(InterruptObject);
//DbgPrint("Isr>\n");
// Loop polling all chips in the board
for(portindex = 0 ; portindex < CYY_MAX_PORTS ;) {
if (!(Extension=Dispatch->Extensions[portindex]) || !(chip=Dispatch->Cd1400[portindex])) { portindex++; continue; } chipindex = portindex/4; mappedboard = Extension->BoardMemory; thisChipInterrupted = FALSE; interlockedExtension[0] = interlockedExtension[1] = interlockedExtension[2] = interlockedExtension[3] = 0;
while ((status = CD1400_READ(chip,bus,SVRR)) != 0x00) { ServicedAnInterrupt = TRUE; thisChipInterrupted = TRUE;
if (status & 0x01) { //Reception
save_xir = CD1400_READ(chip,bus,RIR); channel = (ULONG) (save_xir & 0x03); save_car = CD1400_READ(chip,bus,CAR); CD1400_WRITE(chip,bus,CAR,save_xir); Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex]; x = CD1400_READ(chip,bus,RIVR) & 0x07; if (Extension) { //
// Apply lock so if close happens concurrently we don't miss the DPC
// queueing
//
if (interlockedExtension[channel] == NULL) { interlockedExtension[channel] = Extension; InterlockedIncrement(&Extension->DpcCount); LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in bld 2128
} if (x == 0x07) { // exception
x = CD1400_READ(chip,bus,RDSR); // status
CyyDbgPrintEx(DPFLTR_WARNING_LEVEL, "exception %x\n",x);
if (Extension->DeviceIsOpened && (Extension->PowerState == PowerDeviceD0)) { if (x & CYY_LSR_ERROR){ BOOLEAN ProcessRxChar; if (!(x & CYY_LSR_OE)) { rxchar = CD1400_READ(chip,bus,RDSR); // error data
}
// TODO: SERIAL SAMPLE FOR W2000 HAS ADDED
// CHECKING FOR EscapeChar TO BREAK TO RX LOOP
// IN CASE OF ERROR.
ProcessRxChar = CyyProcessLSR(Extension,x,rxchar);
if (ProcessRxChar) { x = 1; // 1 character
i = 0; // prepare for for(;;)
goto Handle_rxchar; } } // end error handling
} // end if DeviceIsOpened..
} else { // good reception
x = CD1400_READ(chip,bus,RDCR); if (Extension->DeviceIsOpened && (Extension->PowerState == PowerDeviceD0)) { for(i = 0 ; i < x ; i++) { // read from FIFO
rxchar = CD1400_READ(chip,bus,RDSR); Handle_rxchar: Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; rxchar &= Extension->ValidDataMask; if (!rxchar && // NULL stripping
(Extension->HandFlow.FlowReplace & SERIAL_NULL_STRIPPING)) { continue; } if((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) && ((rxchar == Extension->SpecialChars.XonChar) || (rxchar == Extension->SpecialChars.XoffChar))) { if (rxchar == Extension->SpecialChars.XoffChar) { Extension->TXHolding |= CYY_TX_XOFF; if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { CyyInsertQueueDpc( &Extension->StartTimerLowerRTSDpc, NULL, NULL, Extension )?Extension->CountOfTryingToLowerRTS++:0; } } else { if (Extension->TXHolding & CYY_TX_XOFF) { Extension->TXHolding &= ~CYY_TX_XOFF; } } continue; } // Check to see if we should note the receive
// character or special character event.
if (Extension->IsrWaitMask) { if (Extension->IsrWaitMask & SERIAL_EV_RXCHAR) { Extension->HistoryMask |= SERIAL_EV_RXCHAR; } if ((Extension->IsrWaitMask & SERIAL_EV_RXFLAG) && (Extension->SpecialChars.EventChar == rxchar)) { Extension->HistoryMask |= SERIAL_EV_RXFLAG; } if (Extension->IrpMaskLocation && Extension->HistoryMask) { *Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0; Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); CyyInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension); } } CyyPutChar(Extension,rxchar); // If we're doing line status and modem
// status insertion then we need to insert
// a zero following the character we just
// placed into the buffer to mark that this
// was reception of what we are using to
// escape.
if (Extension->EscapeChar && (Extension->EscapeChar == rxchar)) { CyyPutChar(Extension,SERIAL_LSRMST_ESCAPE); } } // end for
} else { // device is being closed, discard rx chars
for(i = 0 ; i < x ; i++) rxchar = CD1400_READ(chip,bus,RDSR); } // end if device is opened else closed
} } else { // No Extension
if (x == 0x07) { // exception
x = CD1400_READ(chip,bus,RDSR); // status
} else { // good char
x = CD1400_READ(chip,bus,RDCR); // number of chars
for(i = 0 ; i < x ; i++) rxchar = CD1400_READ(chip,bus,RDSR); } } CD1400_WRITE(chip,bus,RIR,(save_xir & 0x3f)); // end service
CD1400_WRITE(chip,bus,CAR,save_car);
} // end reception
if (status & 0x02) { //Transmission
save_xir = CD1400_READ(chip,bus,TIR); channel = (ULONG) (save_xir & 0x03); save_car = CD1400_READ(chip,bus,CAR); CD1400_WRITE(chip,bus,CAR,save_xir); Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex]; if (Extension) { //
// Apply lock so if close happens concurrently we don't miss the DPC
// queueing
//
if (interlockedExtension[channel] == NULL) { interlockedExtension[channel] = Extension; InterlockedIncrement(&Extension->DpcCount); LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in build 2128
} Extension->HoldingEmpty = TRUE; if( Extension->DeviceIsOpened && (Extension->PowerState == PowerDeviceD0)) {
if (Extension->BreakCmd != NO_BREAK) {
if (Extension->BreakCmd == SEND_BREAK) { if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { CyySetRTS(Extension); } CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x00); // escape sequence
CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x81); // Send Break
Extension->TXHolding |= CYY_TX_BREAK; Extension->HoldingEmpty = FALSE; Extension->BreakCmd = DISABLE_ETC; } else if (Extension->BreakCmd == STOP_BREAK){ if (Extension->TXHolding & CYY_TX_BREAK) { CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x00); // escape sequence
CD1400_WRITE(chip,bus,TDR,(unsigned char) 0x83); // Stop Break
Extension->HoldingEmpty = FALSE; Extension->TXHolding &= ~CYY_TX_BREAK; } Extension->BreakCmd = DISABLE_ETC; } else if (Extension->BreakCmd == DISABLE_ETC) { UCHAR cor2; cor2 = CD1400_READ(chip,bus,COR2); CD1400_WRITE(chip,bus, COR2,cor2 & ~EMBED_TX_ENABLE); // disable ETC bit
CyyCDCmd(Extension,CCR_CORCHG_COR2); // COR2 changed
Extension->BreakCmd = NO_BREAK;
if (!Extension->TXHolding && (Extension->TransmitImmediate || Extension->WriteLength) && Extension->HoldingEmpty) {
//CyyTxStart(Extension); no need for CyyTxStart from here.
} else { UCHAR srer = CD1400_READ(chip,bus,SRER); CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY));
//
// The following routine will lower the rts if we
// are doing transmit toggleing and there is no
// reason to keep it up.
//
Extension->CountOfTryingToLowerRTS++; CyyPerhapsLowerRTS(Extension); }
}
} else {
// This is not a Send Break.
// Check if there are bytes to be transmitted
if (Extension->WriteLength || Extension->TransmitImmediate) { Extension->EmptiedTransmit = TRUE; if (Extension->HandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) { CyyHandleModemUpdate(Extension,TRUE); } if (Extension->TransmitImmediate&&(!Extension->TXHolding || (Extension->TXHolding == CYY_TX_XOFF) )) {
Extension->TransmitImmediate = FALSE;
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
CyySetRTS(Extension); Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,TDR,(unsigned char)(Extension->ImmediateChar)); CyyInsertQueueDpc( &Extension->StartTimerLowerRTSDpc,NULL,NULL, Extension)? Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,TDR,(unsigned char)(Extension->ImmediateChar)); } Extension->HoldingEmpty = FALSE;
CyyInsertQueueDpc( &Extension->CompleteImmediateDpc, NULL, NULL, Extension ); } else if (!Extension->TXHolding) {
ULONG amountToWrite;
amountToWrite = (Extension->TxFifoAmount < Extension->WriteLength)? Extension->TxFifoAmount:Extension->WriteLength;
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
// We have to raise if we're sending
// this character.
CyySetRTS(Extension);
for(i = 0 ; i < amountToWrite ; i++) { // write to FIFO
CD1400_WRITE(chip,bus,TDR,((unsigned char *) (Extension->WriteCurrentChar))[i]); } Extension->PerfStats.TransmittedCount += amountToWrite; Extension->WmiPerfData.TransmittedCount += amountToWrite;
CyyInsertQueueDpc( &Extension->StartTimerLowerRTSDpc, NULL, NULL, Extension )?Extension->CountOfTryingToLowerRTS++:0;
} else {
for(i = 0 ; i < amountToWrite ; i++) { // write to FIFO
CD1400_WRITE(chip,bus,TDR,((unsigned char *) (Extension->WriteCurrentChar))[i]); } Extension->PerfStats.TransmittedCount += amountToWrite; Extension->WmiPerfData.TransmittedCount += amountToWrite; }
Extension->HoldingEmpty = FALSE; Extension->WriteCurrentChar += amountToWrite; Extension->WriteLength -= amountToWrite;
if (!Extension->WriteLength) {
PIO_STACK_LOCATION IrpSp; //
// No More characters left. This
// write is complete. Take care
// when updating the information field,
// we could have an xoff counter masquerading
// as a write irp.
//
IrpSp = IoGetCurrentIrpStackLocation( Extension->CurrentWriteIrp );
Extension->CurrentWriteIrp->IoStatus.Information = (IrpSp->MajorFunction == IRP_MJ_WRITE)? (IrpSp->Parameters.Write.Length): (1);
CyyInsertQueueDpc( &Extension->CompleteWriteDpc, NULL, NULL, Extension ); } // end write complete
} // end of if(!TXHolding)
} else { // nothing to be transmitted - disable interrupts.
UCHAR srer; Extension->EmptiedTransmit = TRUE; srer = CD1400_READ(chip,bus,SRER); CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY)); } } // end of if(break)
} else { // Device is closed. Disable interrupts
UCHAR srer = CD1400_READ(chip,bus,SRER); CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY)); Extension->EmptiedTransmit = TRUE; } } else { // Device was not created, no extension attached.
UCHAR srer = CD1400_READ(chip,bus,SRER); CD1400_WRITE(chip,bus,SRER,srer & (~SRER_TXRDY)); } // end if Extension
CD1400_WRITE(chip,bus,TIR,(save_xir & 0x3f)); // end service
CD1400_WRITE(chip,bus,CAR,save_car);
} // end transmission
if (status & 0x04) { //Modem
save_xir = CD1400_READ(chip,bus,MIR); channel = (ULONG) (save_xir & 0x03); save_car = CD1400_READ(chip,bus,CAR); CD1400_WRITE(chip,bus,CAR,save_xir); //CyyDump(CYYDIAG5,("modem\n"));
Extension = Dispatch->Extensions[channel + CYY_CHANNELS_PER_CHIP*chipindex]; if (Extension) { //
// Apply lock so if close happens concurrently we don't miss the DPC
// queueing
//
if (interlockedExtension[channel] == NULL) { interlockedExtension[channel] = Extension; InterlockedIncrement(&Extension->DpcCount); LOGENTRY(LOG_CNT, 'DpI3', 0, Extension->DpcCount, 0); // Added in build 2128
} if (Extension->DeviceIsOpened && (Extension->PowerState == PowerDeviceD0)) { misr = CD1400_READ(chip,bus,MISR); CyyHandleModemUpdateForModem(Extension,FALSE,misr); } } CD1400_WRITE(chip,bus,MIR,(save_xir & 0x3f)); // end service
CD1400_WRITE(chip,bus,CAR,save_car);
} // end modem
} // end READ SVRR
if (thisChipInterrupted) { for (channel=0; channel<CYY_CHANNELS_PER_CHIP; channel++) { if (Extension = interlockedExtension[channel]) { LONG pendingCnt;
//
// Increment once more. This is just a quick test to see if we
// have a chance of causing the event to fire... we don't want
// to run a DPC on every ISR if we don't have to....
//
retryDPCFiring:;
InterlockedIncrement(&Extension->DpcCount); LOGENTRY(LOG_CNT, 'DpI4', 0, Extension->DpcCount, 0); // Added in build 2128
//
// Decrement and see if the lock above looks like the only one left.
//
pendingCnt = InterlockedDecrement(&Extension->DpcCount); // LOGENTRY(LOG_CNT, 'DpD5', 0, Extension->DpcCount, 0); // Added in build 2128
if (pendingCnt == 1) { KeInsertQueueDpc(&Extension->IsrUnlockPagesDpc, NULL, NULL); } else { if (InterlockedDecrement(&Extension->DpcCount) == 0) {
// LOGENTRY(LOG_CNT, 'DpD6', &Extension->IsrUnlockPagesDpc, // Added in bld 2128
// Extension->DpcCount, 0);
//
// We missed it. Retry...
//
InterlockedIncrement(&Extension->DpcCount); goto retryDPCFiring; } }
} // if (Extension = interlockedExtension[])
} // for (;channel<CYY_CHANNELS_PER_CHIP;)
portindex = (chipindex+1)*4; continue;
} // if (thisChipInterrupted)
portindex++;
} // for(;portindex<CYY_MAX_PORTS;);
if (mappedboard) { CYY_CLEAR_INTERRUPT(mappedboard,Dispatch->IsPci); }
//DbgPrint("<Isr\n");
return ServicedAnInterrupt; }
VOID CyyPutChar( IN PCYY_DEVICE_EXTENSION Extension, IN UCHAR CharToPut ) /*--------------------------------------------------------------------------
CyyPutChar() Routine Description: This routine, which only runs at device level, takes care of placing a character into the typeahead (receive) buffer.
Arguments:
Extension - The serial device extension.
Return Value: None. --------------------------------------------------------------------------*/ {
CYY_LOCKED_PAGED_CODE();
// If we have dsr sensitivity enabled then
// we need to check the modem status register
// to see if it has changed.
if (Extension->HandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) { CyyHandleModemUpdate(Extension,FALSE);
if (Extension->RXHolding & CYY_RX_DSR) { // We simply act as if we haven't seen the character if
// dsr line is low.
return; } }
// If the xoff counter is non-zero then decrement it.
// If the counter then goes to zero, complete that irp.
if (Extension->CountSinceXoff) { Extension->CountSinceXoff--; if (!Extension->CountSinceXoff) { Extension->CurrentXoffIrp->IoStatus.Status = STATUS_SUCCESS; Extension->CurrentXoffIrp->IoStatus.Information = 0; CyyInsertQueueDpc(&Extension->XoffCountCompleteDpc,NULL,NULL,Extension); } } // Check to see if we are copying into the
// users buffer or into the interrupt buffer.
//
// If we are copying into the user buffer
// then we know there is always room for one more.
// (We know this because if there wasn't room
// then that read would have completed and we
// would be using the interrupt buffer.)
//
// If we are copying into the interrupt buffer
// then we will need to check if we have enough
// room.
if (Extension->ReadBufferBase != Extension->InterruptReadBuffer) {
// Increment the following value so
// that the interval timer (if one exists
// for this read) can know that a character
// has been read.
Extension->ReadByIsr++;
// We are in the user buffer. Place the character into the buffer.
// See if the read is complete.
*Extension->CurrentCharSlot = CharToPut;
if (Extension->CurrentCharSlot == Extension->LastCharSlot) { // We've filled up the users buffer.
// Switch back to the interrupt buffer
// and send off a DPC to Complete the read.
//
// It is inherent that when we were using
// a user buffer that the interrupt buffer
// was empty.
Extension->ReadBufferBase = Extension->InterruptReadBuffer; Extension->CurrentCharSlot = Extension->InterruptReadBuffer; Extension->FirstReadableChar = Extension->InterruptReadBuffer; Extension->LastCharSlot = Extension->InterruptReadBuffer + (Extension->BufferSize - 1); Extension->CharsInInterruptBuffer = 0;
Extension->CurrentReadIrp->IoStatus.Information = IoGetCurrentIrpStackLocation( Extension->CurrentReadIrp )->Parameters.Read.Length;
CyyInsertQueueDpc(&Extension->CompleteReadDpc,NULL,NULL,Extension); } else { // Not done with the users read.
Extension->CurrentCharSlot++; } } else { // We need to see if we reached our flow
// control threshold. If we have then
// we turn on whatever flow control the
// owner has specified. If no flow
// control was specified, well..., we keep
// trying to receive characters and hope that
// we have enough room. Note that no matter
// what flow control protocol we are using, it
// will not prevent us from reading whatever
// characters are available.
if ((Extension->HandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) {
// If we are already doing a
// dtr hold then we don't have
// to do anything else.
if (!(Extension->RXHolding & CYY_RX_DTR)) {
if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYY_RX_DTR;
CyyClrDTR(Extension); } } }
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) {
// If we are already doing a
// rts hold then we don't have
// to do anything else.
if (!(Extension->RXHolding & CYY_RX_RTS)) {
if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYY_RX_RTS;
CyyClrRTS(Extension); } } }
if (Extension->HandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) { // If we are already doing a
// xoff hold then we don't have
// to do anything else.
if (!(Extension->RXHolding & CYY_RX_XOFF)) {
if ((Extension->BufferSize - Extension->HandFlow.XoffLimit) <= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYY_RX_XOFF;
// If necessary cause an
// off to be sent.
CyyProdXonXoff(Extension,FALSE); } } }
if (Extension->CharsInInterruptBuffer < Extension->BufferSize) {
*Extension->CurrentCharSlot = CharToPut; Extension->CharsInInterruptBuffer++;
// If we've become 80% full on this character
// and this is an interesting event, note it.
if (Extension->CharsInInterruptBuffer == Extension->BufferSizePt8) {
if (Extension->IsrWaitMask & SERIAL_EV_RX80FULL) {
Extension->HistoryMask |= SERIAL_EV_RX80FULL;
if (Extension->IrpMaskLocation) {
*Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); CyyInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension); } } }
// Point to the next available space
// for a received character. Make sure
// that we wrap around to the beginning
// of the buffer if this last character
// received was placed at the last slot
// in the buffer.
if (Extension->CurrentCharSlot == Extension->LastCharSlot) { Extension->CurrentCharSlot = Extension->InterruptReadBuffer; } else { Extension->CurrentCharSlot++; } } else { // We have a new character but no room for it.
Extension->PerfStats.BufferOverrunErrorCount++; Extension->WmiPerfData.BufferOverrunErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN;
if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
// Place the error character into the last
// valid place for a character. Be careful!,
// that place might not be the previous location!
if (Extension->CurrentCharSlot == Extension->InterruptReadBuffer) { *(Extension->InterruptReadBuffer+ (Extension->BufferSize-1)) = Extension->SpecialChars.ErrorChar; } else { *(Extension->CurrentCharSlot-1) = Extension->SpecialChars.ErrorChar; } } // If the application has requested it, abort all reads
// and writes on an error.
if (Extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { CyyInsertQueueDpc(&Extension->CommErrorDpc,NULL,NULL,Extension); } } } }
BOOLEAN CyyProcessLSR( IN PCYY_DEVICE_EXTENSION Extension, IN UCHAR Rdsr, IN UCHAR RxChar )
/*++
Routine Description:
This routine, which only runs at device level, reads the ISR and totally processes everything that might have changed.
Arguments:
Extension - The serial device extension.
Return Value:
TRUE if RxChar still needs to be processed.
--*/
{
BOOLEAN StillProcessRxChar=TRUE; UCHAR LineStatus=0;
CYY_LOCKED_PAGED_CODE();
if (Rdsr & CYY_LSR_OE) LineStatus |= SERIAL_LSR_OE; if (Rdsr & CYY_LSR_FE) LineStatus |= SERIAL_LSR_FE; if (Rdsr & CYY_LSR_PE) LineStatus |= SERIAL_LSR_PE; if (Rdsr & CYY_LSR_BI) LineStatus |= SERIAL_LSR_BI; if (Extension->EscapeChar) {
CyyPutChar( Extension, Extension->EscapeChar );
CyyPutChar( Extension, (UCHAR)((LineStatus & SERIAL_LSR_OE)? (SERIAL_LSRMST_LSR_NODATA):(SERIAL_LSRMST_LSR_DATA)) );
CyyPutChar( Extension, LineStatus );
if (!(LineStatus & SERIAL_LSR_OE)) { Extension->PerfStats.ReceivedCount++; Extension->WmiPerfData.ReceivedCount++; CyyPutChar( Extension, RxChar ); StillProcessRxChar = FALSE; }
}
if (LineStatus & SERIAL_LSR_OE) {
Extension->PerfStats.SerialOverrunErrorCount++; Extension->WmiPerfData.SerialOverrunErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
CyyPutChar( Extension, Extension->SpecialChars.ErrorChar ); } StillProcessRxChar = FALSE; }
if (LineStatus & SERIAL_LSR_BI) {
Extension->ErrorWord |= SERIAL_ERROR_BREAK;
if (Extension->HandFlow.FlowReplace & SERIAL_BREAK_CHAR) {
CyyPutChar( Extension, Extension->SpecialChars.BreakChar );
}
} else {
//
// Framing errors only count if they
// occur exclusive of a break being
// received.
//
if (LineStatus & SERIAL_LSR_PE) { Extension->PerfStats.ParityErrorCount++; Extension->WmiPerfData.ParityErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_PARITY; if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
CyyPutChar( Extension, Extension->SpecialChars.ErrorChar ); StillProcessRxChar = FALSE; }
}
if (LineStatus & SERIAL_LSR_FE) {
Extension->PerfStats.FrameErrorCount++; Extension->WmiPerfData.FrameErrorCount++; Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
if (Extension->HandFlow.FlowReplace & SERIAL_ERROR_CHAR) {
CyyPutChar( Extension, Extension->SpecialChars.ErrorChar ); StillProcessRxChar = FALSE; }
}
}
//
// If the application has requested it,
// abort all the reads and writes
// on an error.
//
if (Extension->HandFlow.ControlHandShake & SERIAL_ERROR_ABORT) {
CyyInsertQueueDpc( &Extension->CommErrorDpc, NULL, NULL, Extension );
}
//
// Check to see if we have a wait
// pending on the comm error events. If we
// do then we schedule a dpc to satisfy
// that wait.
//
if (Extension->IsrWaitMask) {
if ((Extension->IsrWaitMask & SERIAL_EV_ERR) && (LineStatus & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE))) { Extension->HistoryMask |= SERIAL_EV_ERR;
}
if ((Extension->IsrWaitMask & SERIAL_EV_BREAK) && (LineStatus & SERIAL_LSR_BI)) {
Extension->HistoryMask |= SERIAL_EV_BREAK;
}
if (Extension->IrpMaskLocation && Extension->HistoryMask) {
*Extension->IrpMaskLocation = Extension->HistoryMask; Extension->IrpMaskLocation = NULL; Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->IoStatus.Information = sizeof(ULONG); CyyInsertQueueDpc( &Extension->CommWaitDpc, NULL, NULL, Extension );
}
} return StillProcessRxChar;
}
BOOLEAN CyyTxStart( IN PVOID Context ) /*--------------------------------------------------------------------------
CyyTxStart() Description: Enable Tx interrupt. Parameters: Exetnsion: Pointer to device extension. Return Value: None --------------------------------------------------------------------------*/ { PCYY_DEVICE_EXTENSION Extension = Context; PUCHAR chip = Extension->Cd1400; ULONG bus = Extension->IsPci; UCHAR srer;
if (Extension->PowerState == PowerDeviceD0) { CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03); srer = CD1400_READ (chip,bus,SRER); CD1400_WRITE(chip,bus,SRER,srer | SRER_TXRDY); } return(FALSE); }
BOOLEAN CyySendXon( IN PVOID Context ) /*--------------------------------------------------------------------------
CyySendXon() Description: Send a Xon. Parameters: Exetension: Pointer to device extension. Return Value: Always FALSE. --------------------------------------------------------------------------*/ { PCYY_DEVICE_EXTENSION Extension = Context; PUCHAR chip = Extension->Cd1400; ULONG bus = Extension->IsPci; if(!(Extension->TXHolding & ~CYY_TX_XOFF)) { if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
CyySetRTS(Extension);
Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03); CyyCDCmd(Extension,CCR_SENDSC_SCHR1); CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL, NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03); CyyCDCmd(Extension,CCR_SENDSC_SCHR1); }
// If we send an xon, by definition we can't be holding by Xoff.
Extension->TXHolding &= ~CYY_TX_XOFF; Extension->RXHolding &= ~CYY_RX_XOFF; } return(FALSE); }
BOOLEAN CyySendXoff( IN PVOID Context ) /*--------------------------------------------------------------------------
CyySendXoff() Description: Send a Xoff. Parameters: Extension: Pointer to device extension. Return Value: Always FALSE. --------------------------------------------------------------------------*/ { PCYY_DEVICE_EXTENSION Extension = Context; PUCHAR chip = Extension->Cd1400; ULONG bus = Extension->IsPci; if(!Extension->TXHolding) { if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
CyySetRTS(Extension); Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03); CyyCDCmd(Extension,CCR_SENDSC_SCHR2); CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL, NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0; } else { Extension->PerfStats.TransmittedCount++; Extension->WmiPerfData.TransmittedCount++; CD1400_WRITE(chip,bus,CAR,Extension->CdChannel & 0x03); CyyCDCmd(Extension,CCR_SENDSC_SCHR2); }
// no xoff is sent if the transmission is already held up.
// If xoff continue mode is set, we don't actually stop sending
if (!(Extension->HandFlow.FlowReplace & SERIAL_XOFF_CONTINUE)) { Extension->TXHolding |= CYY_TX_XOFF;
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) {
CyyInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL, NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0; } } } return(FALSE); }
|