Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1599 lines
55 KiB

/*--------------------------------------------------------------------------
*
* Copyright (C) Cyclades Corporation, 1997-2001.
* All rights reserved.
*
* Cyclades-Z Port Driver
*
* This file: cyzpoll.c
*
* Description: This module contains the code related to the polling
* of the hardware. It replaces the ISR.
*
* 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"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGESER,CyzPutChar)
#pragma alloc_text(PAGESER,CyzProcessLSR)
#pragma alloc_text(PAGESER,CyzTxStart)
#pragma alloc_text(PAGESER,CyzQueueCompleteWrite)
#endif
static const PHYSICAL_ADDRESS CyzPhysicalZero = {0};
VOID
CyzPollingDpc(
IN PKDPC Dpc,
IN PVOID DeferredContext,
IN PVOID SystemContext1,
IN PVOID SystemContext2
)
/*--------------------------------------------------------------------------
Routine Description:
This is the polling routine for the Cyclades-Z driver. It replaces
the ISR, as we are not enabling interrupts.
Arguments:
Dpc - Not Used.
DeferredContext - Really points to the device extention.
SystemContext1 - Not used.
SystemContext2 - Not used.
Return Value:
None.
--------------------------------------------------------------------------*/
{
PCYZ_DISPATCH Dispatch = DeferredContext;
PCYZ_DEVICE_EXTENSION Extension, dbExtension; //Note: db=doorbell
struct INT_QUEUE *pt_zf_int_queue;
struct BUF_CTRL *buf_ctrl;
ULONG qu_get, qu_put;
ULONG channel, dbChannel; //Note: db=doorbell
ULONG fwcmd_param;
ULONG rx_bufsize, rx_get, rx_put;
UCHAR loc_doorbell;
UCHAR rxchar;
UNREFERENCED_PARAMETER(Dpc);
UNREFERENCED_PARAMETER(SystemContext1);
UNREFERENCED_PARAMETER(SystemContext2);
KeAcquireSpinLockAtDpcLevel(&Dispatch->PollingLock);
if (!Dispatch->PollingStarted) {
Dispatch->PollingDrained = TRUE;
KeSetEvent(&Dispatch->PendingDpcEvent, IO_NO_INCREMENT, FALSE);
goto EndDpc;
}
for (channel=0; channel<Dispatch->NChannels; channel++) {
Extension = Dispatch->Extensions[channel];
if (Extension == NULL) {
continue;
}
pt_zf_int_queue = Extension->PtZfIntQueue;
if (pt_zf_int_queue == NULL) {
continue;
}
qu_get = CYZ_READ_ULONG(&pt_zf_int_queue->get);
qu_put = CYZ_READ_ULONG(&pt_zf_int_queue->put);
while (qu_get != qu_put) {
if (qu_get >= QUEUE_SIZE) {
// bad value, reset qu_get
qu_get = 0;
break;
}
if (qu_put >= QUEUE_SIZE) {
// bad value
break;
}
loc_doorbell = CYZ_READ_UCHAR(&pt_zf_int_queue->intr_code[qu_get]);
dbChannel = CYZ_READ_ULONG(&pt_zf_int_queue->channel[qu_get]);
if (dbChannel >= Dispatch->NChannels) {
break;
}
// so far, only DCD status is sent on the fwcmd_param.
fwcmd_param = CYZ_READ_ULONG(&pt_zf_int_queue->param[qu_get]);
dbExtension = Dispatch->Extensions[dbChannel];
if (!dbExtension) {
goto NextQueueGet;
}
KeAcquireSpinLockAtDpcLevel(&dbExtension->PollLock);
//-- Error Injection
//loc_doorbell = C_CM_FATAL;
//loc_doorbell = C_CM_CMDERROR;
//----
switch (loc_doorbell) {
case C_CM_IOCTLW:
//CyzDump (CYZDIAG5,("CyzPollingDpc C_CM_IOCTLW\n"));
dbExtension->IoctlwProcessed = TRUE;
break;
case C_CM_CMD_DONE:
//CyzDump (CYZDIAG5,("CyzPollingDpc C_CM_CMD_DONE\n"));
break;
case C_CM_RXHIWM: // Reception above high watermark
case C_CM_RXNNDT: // Timeout without receiving more chars.
case C_CM_INTBACK2: // Not used in polling mode.
//CyzDump (CYZERRORS,
// ("CyzPollingDpc C_CM_RXHIWM,C_CM_RXNNDT,C_CM_INTBACK2\n"));
break;
case C_CM_TXBEMPTY: // Firmware buffer empty
//dbExtension->HoldingEmpty = TRUE;
//CyzDump (CYZDIAG5,("CyzPollingDpc C_CM_TXBEMPTY\n"));
break;
case C_CM_TXFEMPTY: // Hardware FIFO empty
dbExtension->HoldingEmpty = TRUE;
//CyzDump (CYZDIAG5,("CyzPollingDpc C_CM_TXFEMPTY\n"));
break;
case C_CM_INTBACK: // New transmission
//CyzDump(CYZBUGCHECK,
// ("C_CM_INTBACK! We should not receive this...\n"));
break;
case C_CM_TXLOWWM:
//CyzDump (CYZBUGCHECK,("CyzPollingDpc C_CM_TXLOWN\n"));
break;
case C_CM_MDCD: // Modem
dbExtension->DCDstatus = fwcmd_param;
case C_CM_MDSR:
case C_CM_MRI:
case C_CM_MCTS:
//CyzDump(CYZDIAG5,
// ("doorbell %x port%d\n",loc_doorbell,dbExtension->PortIndex+1));
if (dbExtension->DeviceIsOpened) {
CyzHandleModemUpdate(dbExtension,FALSE,loc_doorbell);
}
break;
case C_CM_RXBRK:
//CyzDump (CYZERRORS,("CyzPollingDpc C_CM_RXBRK\n"));
if (dbExtension->DeviceIsOpened) {
CyzProcessLSR(dbExtension,SERIAL_LSR_BI);
}
break;
case C_CM_PR_ERROR:
//dbExtension->PerfStats.ParityErrorCount++;
//dbExtension->ErrorWord |= SERIAL_ERROR_PARITY;
if (dbExtension->DeviceIsOpened) {
CyzProcessLSR(dbExtension,SERIAL_LSR_PE);
}
break;
case C_CM_FR_ERROR:
//dbExtension->PerfStats.FrameErrorCount++;
//dbExtension->ErrorWord |= SERIAL_ERROR_FRAMING;
if (dbExtension->DeviceIsOpened) {
CyzProcessLSR(dbExtension,SERIAL_LSR_FE);
}
break;
case C_CM_OVR_ERROR:
//dbExtension->PerfStats.SerialOverrunErrorCount++;
//dbExtension->ErrorWord |= SERIAL_ERROR_OVERRUN;
if (dbExtension->DeviceIsOpened) {
CyzProcessLSR(dbExtension,SERIAL_LSR_OE);
}
break;
case C_CM_RXOFL:
//dbExtension->PerfStats.SerialOverrunErrorCount++;
//dbExtension->ErrorWord |= SERIAL_ERROR_OVERRUN;
if (dbExtension->DeviceIsOpened) {
CyzProcessLSR(dbExtension,SERIAL_LSR_OE);
}
break;
case C_CM_CMDERROR:
//CyzDump (CYZBUGCHECK,("CyzPollingDpc C_CM_CMDERROR\n"));
CyzLogError( dbExtension->DriverObject,dbExtension->DeviceObject,
dbExtension->OriginalBoardMemory,CyzPhysicalZero,
0,0,0,dbExtension->PortIndex+1,STATUS_SUCCESS,
CYZ_FIRMWARE_CMDERROR,0,NULL,0,NULL);
break;
case C_CM_FATAL:
//CyzDump (CYZBUGCHECK,("CyzPollingDpc C_CM_FATAL\n"));
CyzLogError( dbExtension->DriverObject,dbExtension->DeviceObject,
dbExtension->OriginalBoardMemory,CyzPhysicalZero,
0,0,0,dbExtension->PortIndex+1,STATUS_SUCCESS,
CYZ_FIRMWARE_FATAL,0,NULL,0,NULL);
break;
} // end switch
KeReleaseSpinLockFromDpcLevel(&dbExtension->PollLock);
NextQueueGet:
if (qu_get == QUEUE_SIZE-1) {
qu_get = 0;
} else {
qu_get++;
}
} // end while (qu_get != qu_put)
CYZ_WRITE_ULONG(&pt_zf_int_queue->get,qu_get);
KeAcquireSpinLockAtDpcLevel(&Extension->PollLock);
// Reception
buf_ctrl = Extension->BufCtrl;
rx_put = CYZ_READ_ULONG(&buf_ctrl->rx_put);
rx_get = CYZ_READ_ULONG(&buf_ctrl->rx_get);
rx_bufsize = Extension->RxBufsize;
if ((rx_put >= rx_bufsize) || (rx_get >= rx_bufsize)) {
CYZ_WRITE_ULONG(&buf_ctrl->rx_get,rx_get);
KeReleaseSpinLockFromDpcLevel(&Extension->PollLock);
continue;
}
if (rx_put != rx_get) {
if (Extension->DeviceIsOpened) {
ULONG pppflag = 0;
while ((rx_get != rx_put) &&
(Extension->CharsInInterruptBuffer <
Extension->BufferSize) ){
rxchar = CYZ_READ_UCHAR(&Extension->RxBufaddr[rx_get]);
Extension->PerfStats.ReceivedCount++;
Extension->WmiPerfData.ReceivedCount++;
rxchar &= Extension->ValidDataMask;
if (!rxchar && // NULL stripping
(Extension->HandFlow.FlowReplace &
SERIAL_NULL_STRIPPING)) {
goto nextchar1;
}
if((Extension->HandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT)
&& ((rxchar == Extension->SpecialChars.XonChar) ||
(rxchar == Extension->SpecialChars.XoffChar))) {
if (rxchar == Extension->SpecialChars.XoffChar) {
Extension->TXHolding |= CYZ_TX_XOFF;
if ((Extension->HandFlow.FlowReplace &
SERIAL_RTS_MASK) ==
SERIAL_TRANSMIT_TOGGLE) {
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,
NULL,
NULL,
Extension
)?Extension->CountOfTryingToLowerRTS++:0;
}
} else {
if (Extension->TXHolding & CYZ_TX_XOFF) {
Extension->TXHolding &= ~CYZ_TX_XOFF;
}
}
goto nextchar1;
}
// 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 (rxchar == 0x7e){ //Optimized for RAS PPP
if (Extension->PPPaware) {
if (pppflag == 0){
pppflag = 1;
} else {
pppflag = 2;
}
}
}
}
if (Extension->IrpMaskLocation &&
Extension->HistoryMask) {
*Extension->IrpMaskLocation =
Extension->HistoryMask;
Extension->IrpMaskLocation = NULL;
Extension->HistoryMask = 0;
Extension->CurrentWaitIrp->IoStatus.Information =
sizeof(ULONG);
CyzInsertQueueDpc(&Extension->CommWaitDpc,NULL,NULL,Extension);
}
}
CyzPutChar(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)) {
CyzPutChar(Extension,SERIAL_LSRMST_ESCAPE);
}
nextchar1:;
if (rx_get == rx_bufsize-1)
rx_get = 0;
else
rx_get++;
if (pppflag == 2) //Optimized for NT RAS PPP
break;
} // end while
} else { // device is being closed, discard rx chars
rx_get = rx_put;
}
CYZ_WRITE_ULONG(&buf_ctrl->rx_get,rx_get);
} // end if (rx_put != rx_get)
// Transmission
if (Extension->DeviceIsOpened) {
if (Extension->ReturnStatusAfterFwEmpty) {
if (Extension->ReturnWriteStatus && Extension->WriteLength) {
if (!CyzAmountInTxBuffer(Extension)) {
//txfempty Extension->HoldingEmpty = TRUE;
Extension->WriteLength = 0;
Extension->ReturnWriteStatus = FALSE;
CyzQueueCompleteWrite(Extension);
}
} else {
CyzTxStart(Extension);
}
} else { // We don't wait for the firmware buff empty to tx
CyzTxStart(Extension);
}
}
KeReleaseSpinLockFromDpcLevel(&Extension->PollLock);
} // end for (channel=0;channel<Dispatch->NChannels;channel++);
//KeSetTimer(&Dispatch->PollingTimer,Dispatch->PollingTime,&Dispatch->PollingDpc);
EndDpc:
KeReleaseSpinLockFromDpcLevel(&Dispatch->PollingLock);
}
VOID
CyzPutChar(
IN PCYZ_DEVICE_EXTENSION Extension,
IN UCHAR CharToPut
)
/*--------------------------------------------------------------------------
CyzPutChar()
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.
--------------------------------------------------------------------------*/
{
CYZ_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) {
CyzHandleModemUpdate(Extension,FALSE,0);
if (Extension->RXHolding & CYZ_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;
CyzInsertQueueDpc(&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;
CyzInsertQueueDpc(&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 &
CYZ_RX_DTR)) {
if ((Extension->BufferSize -
Extension->HandFlow.XoffLimit)
<= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYZ_RX_DTR;
#ifndef FIRMWARE_HANDSHAKE
CyzClrDTR(Extension);
#endif
}
}
}
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 & CYZ_RX_RTS)) {
if ((Extension->BufferSize -
Extension->HandFlow.XoffLimit)
<= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYZ_RX_RTS;
#ifndef FIRMWARE_HANDSHAKE
CyzClrRTS(Extension);
#endif
}
}
}
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 & CYZ_RX_XOFF)) {
if ((Extension->BufferSize -
Extension->HandFlow.XoffLimit)
<= (Extension->CharsInInterruptBuffer+1)) {
Extension->RXHolding |= CYZ_RX_XOFF;
// If necessary cause an
// off to be sent.
CyzProdXonXoff(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);
CyzInsertQueueDpc(&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) {
CyzInsertQueueDpc(&Extension->CommErrorDpc,NULL,NULL,Extension);
}
}
}
}
UCHAR
CyzProcessLSR(
IN PCYZ_DEVICE_EXTENSION Extension,
IN UCHAR LineStatus
)
{
// UCHAR LineStatus = 0; // READ_LINE_STATUS(Extension->Controller);
CYZ_LOCKED_PAGED_CODE();
if (Extension->EscapeChar) {
CyzPutChar(
Extension,
Extension->EscapeChar
);
CyzPutChar(
Extension,
(UCHAR)(SERIAL_LSRMST_LSR_NODATA)
);
CyzPutChar(
Extension,
LineStatus
);
}
if (LineStatus & SERIAL_LSR_OE) {
Extension->PerfStats.SerialOverrunErrorCount++;
Extension->WmiPerfData.SerialOverrunErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_OVERRUN;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
CyzPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
}
}
if (LineStatus & SERIAL_LSR_BI) {
Extension->ErrorWord |= SERIAL_ERROR_BREAK;
if (Extension->HandFlow.FlowReplace &
SERIAL_BREAK_CHAR) {
CyzPutChar(
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) {
CyzPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
}
}
if (LineStatus & SERIAL_LSR_FE) {
Extension->PerfStats.FrameErrorCount++;
Extension->WmiPerfData.FrameErrorCount++;
Extension->ErrorWord |= SERIAL_ERROR_FRAMING;
if (Extension->HandFlow.FlowReplace &
SERIAL_ERROR_CHAR) {
CyzPutChar(
Extension,
Extension->SpecialChars.ErrorChar
);
}
}
}
//
// If the application has requested it,
// abort all the reads and writes
// on an error.
//
if (Extension->HandFlow.ControlHandShake &
SERIAL_ERROR_ABORT) {
CyzInsertQueueDpc(
&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);
CyzInsertQueueDpc(
&Extension->CommWaitDpc,
NULL,
NULL,
Extension
);
}
}
return LineStatus;
}
BOOLEAN
CyzTxStart(
IN PVOID Context
)
/*--------------------------------------------------------------------------
CyzTxStart()
Description: Enable Tx interrupt.
Parameters:
Extension: Pointer to device extension.
Return Value: None
--------------------------------------------------------------------------*/
{
struct BUF_CTRL *buf_ctrl;
ULONG tx_bufsize, tx_get, tx_put;
ULONG numOfLongs, numOfBytes;
PCYZ_DEVICE_EXTENSION Extension = Context;
if (Extension->PowerState != PowerDeviceD0) {
return FALSE;
}
//doTransmitStuff:;
if( //(Extension->DeviceIsOpened) && moved to before CyzTxStart
(Extension->WriteLength || Extension->TransmitImmediate ||
Extension->SendXoffChar || Extension->SendXonChar)) {
buf_ctrl = Extension->BufCtrl;
tx_put = CYZ_READ_ULONG(&buf_ctrl->tx_put);
tx_get = CYZ_READ_ULONG(&buf_ctrl->tx_get);
tx_bufsize = Extension->TxBufsize;
if ((tx_put >= tx_bufsize) || (tx_get >= tx_bufsize)) {
return FALSE;
}
if ((tx_put+1 == tx_get) || ((tx_put==tx_bufsize-1)&&(tx_get==0))) {
return FALSE;
}
Extension->EmptiedTransmit = TRUE;
if (Extension->HandFlow.ControlHandShake &
SERIAL_OUT_HANDSHAKEMASK) {
CyzHandleModemUpdate(Extension,TRUE,0);
}
// LOGENTRY(LOG_MISC, ZSIG_TX_START,
// Extension->PortIndex+1,
// Extension->WriteLength,
// Extension->TXHolding);
//
// We can only send the xon character if
// the only reason we are holding is because
// of the xoff. (Hardware flow control or
// sending break preclude putting a new character
// on the wire.)
//
if (Extension->SendXonChar &&
!(Extension->TXHolding & ~CYZ_TX_XOFF)) {
if ((Extension->HandFlow.FlowReplace &
SERIAL_RTS_MASK) ==
SERIAL_TRANSMIT_TOGGLE) {
//
// We have to raise if we're sending
// this character.
//
CyzSetRTS(Extension);
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CyzIssueCmd(Extension,C_CM_SENDXON,0L,FALSE);
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,
NULL,
NULL,
Extension
)?Extension->CountOfTryingToLowerRTS++:0;
} else {
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CyzIssueCmd(Extension,C_CM_SENDXON,0L,FALSE);
}
Extension->SendXonChar = FALSE;
Extension->HoldingEmpty = FALSE;
//
// If we send an xon, by definition we
// can't be holding by Xoff.
//
Extension->TXHolding &= ~CYZ_TX_XOFF;
//
// If we are sending an xon char then
// by definition we can't be "holding"
// up reception by Xoff.
//
Extension->RXHolding &= ~CYZ_RX_XOFF;
} else if (Extension->SendXoffChar &&
!Extension->TXHolding) {
if ((Extension->HandFlow.FlowReplace &
SERIAL_RTS_MASK) ==
SERIAL_TRANSMIT_TOGGLE) {
//
// We have to raise if we're sending
// this character.
//
CyzSetRTS(Extension);
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CyzIssueCmd(Extension,C_CM_SENDXOFF,0L,FALSE);
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,
NULL,
NULL,
Extension
)?Extension->CountOfTryingToLowerRTS++:0;
} else {
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CyzIssueCmd(Extension,C_CM_SENDXOFF,0L,FALSE);
}
//
// We can't be sending an Xoff character
// if the transmission is already held
// up because of Xoff. Therefore, if we
// are holding then we can't send the char.
//
//
// If the application has set xoff continue
// mode then we don't actually stop sending
// characters if we send an xoff to the other
// side.
//
if (!(Extension->HandFlow.FlowReplace &
SERIAL_XOFF_CONTINUE)) {
Extension->TXHolding |= CYZ_TX_XOFF;
if ((Extension->HandFlow.FlowReplace &
SERIAL_RTS_MASK) ==
SERIAL_TRANSMIT_TOGGLE) {
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,
NULL,
NULL,
Extension
)?Extension->CountOfTryingToLowerRTS++:0;
}
}
Extension->SendXoffChar = FALSE;
Extension->HoldingEmpty = FALSE;
} else if(Extension->TransmitImmediate&&(!Extension->TXHolding ||
(Extension->TXHolding == CYZ_TX_XOFF) )) {
Extension->TransmitImmediate = FALSE;
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_TRANSMIT_TOGGLE) {
CyzSetRTS(Extension);
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CYZ_WRITE_UCHAR( &Extension->TxBufaddr[tx_put],
Extension->ImmediateChar);
if (tx_put + 1 == tx_bufsize) {
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,0);
} else {
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,tx_put + 1);
}
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,NULL,NULL,
Extension)? Extension->CountOfTryingToLowerRTS++:0;
} else {
Extension->PerfStats.TransmittedCount++;
Extension->WmiPerfData.TransmittedCount++;
CYZ_WRITE_UCHAR(&Extension->TxBufaddr[tx_put],
Extension->ImmediateChar);
if (tx_put + 1 == tx_bufsize) {
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,0);
} else {
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,tx_put + 1);
}
}
Extension->HoldingEmpty = FALSE;
CyzInsertQueueDpc(
&Extension->CompleteImmediateDpc,
NULL,
NULL,
Extension
);
} else if (!Extension->TXHolding) {
ULONG amountToWrite1, amountToWrite2;
ULONG newput;
ULONG amount1;
if (tx_put >= tx_get) {
if (tx_get == 0) {
amountToWrite1 = tx_bufsize - tx_put -1;
amountToWrite2 = 0;
if (amountToWrite1 > Extension->WriteLength){
amountToWrite1 = Extension->WriteLength;
}
newput = amountToWrite1 + 1;
} else if (tx_get == 1) {
amountToWrite1 = tx_bufsize - tx_put;
amountToWrite2 = 0;
if (amountToWrite1 > Extension->WriteLength){
amountToWrite1 = Extension->WriteLength;
newput = amountToWrite1 + 1;
} else {
newput = 0;
}
} else {
amountToWrite1 = tx_bufsize - tx_put;
amountToWrite2 = tx_get - 1;
if (amountToWrite1 > Extension->WriteLength) {
amountToWrite1 = Extension->WriteLength;
amountToWrite2 = 0;
newput = amountToWrite1 + 1;
} else if (amountToWrite1 == Extension->WriteLength) {
amountToWrite2 = 0;
newput = 0;
} else {
if (amountToWrite2 > Extension->WriteLength - amountToWrite1) {
amountToWrite2 = Extension->WriteLength - amountToWrite1;
newput = amountToWrite2 + 1;
}
}
}
} else {
//
// put < get
//
amountToWrite1 = tx_get - tx_put - 1;
amountToWrite2 = 0;
if (amountToWrite1 > Extension->WriteLength) {
amountToWrite1 = Extension->WriteLength;
newput = amountToWrite1 + 1;
}
}
if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK)
== SERIAL_TRANSMIT_TOGGLE) {
// We have to raise if we're sending
// this character.
CyzSetRTS(Extension);
if (amountToWrite1) {
Extension->PerfStats.TransmittedCount += amountToWrite1;
Extension->WmiPerfData.TransmittedCount += amountToWrite1;
amount1 = amountToWrite1;
while (amount1 && (tx_put & 0x07)) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
amount1--;
}
#if _WIN64
numOfLongs = amount1/8;
numOfBytes = amount1%8;
RtlCopyMemory((PULONG64)&Extension->TxBufaddr[tx_put],
(PULONG64)Extension->WriteCurrentChar,
numOfLongs*8);
tx_put += 8*numOfLongs;
(PULONG64)Extension->WriteCurrentChar += numOfLongs;
#else
numOfLongs = amount1/sizeof(ULONG);
numOfBytes = amount1%sizeof(ULONG);
// RtlCopyMemory((PULONG)&Extension->TxBufaddr[tx_put],
// (PULONG)Extension->WriteCurrentChar,
// numOfLongs*sizeof(ULONG));
// tx_put += sizeof(ULONG)*numOfLongs;
// (PULONG)Extension->WriteCurrentChar += numOfLongs;
while (numOfLongs--) {
CYZ_WRITE_ULONG(
(PULONG)(&Extension->TxBufaddr[tx_put]),
*((PULONG)Extension->WriteCurrentChar));
tx_put += sizeof(ULONG);
((PULONG)Extension->WriteCurrentChar)++;
}
#endif
while (numOfBytes--) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
}
if (tx_put == tx_bufsize) {
tx_put = 0;
}
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,tx_put);
}
if (amountToWrite2) {
Extension->PerfStats.TransmittedCount += amountToWrite2;
Extension->WmiPerfData.TransmittedCount += amountToWrite2;
#if _WIN64
numOfLongs = amountToWrite2/8;
numOfBytes = amountToWrite2%8;
RtlCopyMemory((PULONG64)&Extension->TxBufaddr[tx_put],
(PULONG64)Extension->WriteCurrentChar,
numOfLongs*8);
tx_put += 8*numOfLongs;
(PULONG64)Extension->WriteCurrentChar += numOfLongs;
#else
numOfLongs = amountToWrite2/sizeof(ULONG);
numOfBytes = amountToWrite2%sizeof(ULONG);
// RtlCopyMemory((PULONG)&Extension->TxBufaddr[tx_put],
// (PULONG)Extension->WriteCurrentChar,
// numOfLongs*sizeof(ULONG));
// tx_put += sizeof(ULONG)*numOfLongs;
// (PULONG)Extension->WriteCurrentChar += numOfLongs;
while (numOfLongs--) {
CYZ_WRITE_ULONG(
(PULONG)(&Extension->TxBufaddr[tx_put]),
*((PULONG)Extension->WriteCurrentChar));
tx_put += sizeof(ULONG);
((PULONG)Extension->WriteCurrentChar)++;
}
#endif
while (numOfBytes--) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
}
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,amountToWrite2);
}
CyzInsertQueueDpc(
&Extension->StartTimerLowerRTSDpc,
NULL,
NULL,
Extension
)?Extension->CountOfTryingToLowerRTS++:0;
} else {
if (amountToWrite1) {
Extension->PerfStats.TransmittedCount += amountToWrite1;
Extension->WmiPerfData.TransmittedCount += amountToWrite1;
amount1 = amountToWrite1;
while (amount1 && (tx_put & 0x07)) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
amount1--;
}
#if _WIN64
numOfLongs = amount1/8;
numOfBytes = amount1%8;
RtlCopyMemory((PULONG64)&Extension->TxBufaddr[tx_put],
(PULONG64)Extension->WriteCurrentChar,
numOfLongs*8);
tx_put += 8*numOfLongs;
(PULONG64)Extension->WriteCurrentChar += numOfLongs;
#else
numOfLongs = amount1/sizeof(ULONG);
numOfBytes = amount1%sizeof(ULONG);
// RtlCopyMemory((PULONG)&Extension->TxBufaddr[tx_put],
// (PULONG)Extension->WriteCurrentChar,
// numOfLongs*sizeof(ULONG));
// tx_put += sizeof(ULONG)*numOfLongs;
// (PULONG)Extension->WriteCurrentChar += numOfLongs;
while (numOfLongs--) {
CYZ_WRITE_ULONG(
(PULONG)(&Extension->TxBufaddr[tx_put]),
*((PULONG)Extension->WriteCurrentChar));
tx_put += sizeof(ULONG);
((PULONG)Extension->WriteCurrentChar)++;
}
#endif
while (numOfBytes--) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
}
if (tx_put == tx_bufsize) {
tx_put = 0;
}
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,tx_put);
}
if (amountToWrite2) {
Extension->PerfStats.TransmittedCount += amountToWrite2;
Extension->WmiPerfData.TransmittedCount += amountToWrite2;
#if _WIN64
numOfLongs = amountToWrite2/8;
numOfBytes = amountToWrite2%8;
RtlCopyMemory((PULONG64)&Extension->TxBufaddr[tx_put],
(PULONG64)Extension->WriteCurrentChar,
numOfLongs*8);
tx_put += 8*numOfLongs;
(PULONG64)Extension->WriteCurrentChar += numOfLongs;
#else
numOfLongs = amountToWrite2/sizeof(ULONG);
numOfBytes = amountToWrite2%sizeof(ULONG);
// RtlCopyMemory((PULONG)&Extension->TxBufaddr[tx_put],
// (PULONG)Extension->WriteCurrentChar,
// numOfLongs*sizeof(ULONG));
// tx_put += sizeof(ULONG)*numOfLongs;
// (PULONG)Extension->WriteCurrentChar += numOfLongs;
while (numOfLongs--) {
CYZ_WRITE_ULONG(
(PULONG)(&Extension->TxBufaddr[tx_put]),
*((PULONG)Extension->WriteCurrentChar));
tx_put += sizeof(ULONG);
((PULONG)Extension->WriteCurrentChar)++;
}
#endif
while (numOfBytes--) {
CYZ_WRITE_UCHAR(
(PUCHAR)&Extension->TxBufaddr[tx_put],
*((PUCHAR)Extension->WriteCurrentChar));
tx_put++;
((PUCHAR)Extension->WriteCurrentChar)++;
}
CYZ_WRITE_ULONG(&buf_ctrl->tx_put,amountToWrite2);
}
}
//LOGENTRY(LOG_MISC, ZSIG_WRITE_TO_FW,
// Extension->PortIndex+1,
// amountToWrite1+amountToWrite2,
// 0);
Extension->HoldingEmpty = FALSE;
Extension->WriteLength -= (amountToWrite1+amountToWrite2);
if (!Extension->WriteLength) {
if (Extension->ReturnStatusAfterFwEmpty) {
// We will CompleteWrite only when fw buff empties...
Extension->WriteLength += (amountToWrite1+amountToWrite2);
Extension->ReturnWriteStatus = TRUE;
} else {
CyzQueueCompleteWrite(Extension);
} // if-ReturnStatusAfterFwEmpty-else.
} // There is WriteLength
} // !Extension->TXHolding
} //There is data to be sent
// In the normal code, HoldingEmpty will be set to True here. But
// if we want to make sure that CyzWrite had finished the transmission,
// HoldingEmpty will be TRUE only when the firmware empties the firmware
// tx buffer.
//txfempty if (!Extension->ReturnStatusAfterFwEmpty) {
//txfempty Extension->HoldingEmpty = TRUE;
//txfempty}
return(FALSE);
}
//
//BOOLEAN
//CyzSendXon(
// IN PVOID Context
// )
///*--------------------------------------------------------------------------
// CyzSendXon()
//
// Description: Send a Xon.
//
// Parameters:
//
// Exetension: Pointer to device extension.
//
// Return Value: Always FALSE.
//--------------------------------------------------------------------------*/
//{
// PCYZ_DEVICE_EXTENSION Extension = Context;
//
// if(!(Extension->TXHolding & ~CYZ_TX_XOFF)) {
// if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
// SERIAL_TRANSMIT_TOGGLE) {
//
// CyzSetRTS(Extension);
//
// Extension->PerfStats.TransmittedCount++;
// Extension->WmiPerfData.TransmittedCount++;
// CyzIssueCmd(Extension,C_CM_SENDXON,0L);
//
// CyzInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
// NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
// } else {
//
// Extension->PerfStats.TransmittedCount++;
// Extension->WmiPerfData.TransmittedCount++;
// CyzIssueCmd(Extension,C_CM_SENDXON,0L);
// }
//
// // If we send an xon, by definition we can't be holding by Xoff.
//
// Extension->TXHolding &= ~CYZ_TX_XOFF;
// Extension->RXHolding &= ~CYZ_RX_XOFF;
// }
// return(FALSE);
//}
//
//
//
//
//BOOLEAN
//CyzSendXoff(
// IN PVOID Context
// )
///*--------------------------------------------------------------------------
// CyzSendXoff()
//
// Description: Send a Xoff.
//
// Parameters:
//
// Extension: Pointer to device extension.
//
// Return Value: Always FALSE.
//--------------------------------------------------------------------------*/
//{
// PCYZ_DEVICE_EXTENSION Extension = Context;
//
// if(!Extension->TXHolding) {
// if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
// SERIAL_TRANSMIT_TOGGLE) {
//
// CyzSetRTS(Extension);
//
// Extension->PerfStats.TransmittedCount++;
// Extension->WmiPerfData.TransmittedCount++;
// CyzIssueCmd(Extension,C_CM_SENDXOFF,0L);
//
// CyzInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
// NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
// } else {
//
// Extension->PerfStats.TransmittedCount++;
// Extension->WmiPerfData.TransmittedCount++;
// CyzIssueCmd(Extension,C_CM_SENDXOFF,0L);
// }
//
// // 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 |= CYZ_TX_XOFF;
//
// if ((Extension->HandFlow.FlowReplace & SERIAL_RTS_MASK) ==
// SERIAL_TRANSMIT_TOGGLE) {
//
// CyzInsertQueueDpc(&Extension->StartTimerLowerRTSDpc,NULL,
// NULL,Extension)?Extension->CountOfTryingToLowerRTS++:0;
// }
// }
// }
//
// return(FALSE);
//}
ULONG
CyzAmountInTxBuffer(
IN PCYZ_DEVICE_EXTENSION extension
)
/*--------------------------------------------------------------------------
CyzAmountInTxBuffer()
Description: Gets the amount in the Tx Buffer in the board.
Parameters:
Extension: Pointer to device extension.
Return Value: Return the number of bytes in the HW Tx buffer.
--------------------------------------------------------------------------*/
{
struct BUF_CTRL *buf_ctrl;
ULONG tx_put, tx_get, tx_bufsize;
ULONG txAmount1, txAmount2;
buf_ctrl = extension->BufCtrl;
tx_put = CYZ_READ_ULONG(&buf_ctrl->tx_put);
tx_get = CYZ_READ_ULONG(&buf_ctrl->tx_get);
tx_bufsize = extension->TxBufsize;
if (tx_put >= tx_get) {
txAmount1 = tx_put - tx_get;
txAmount2 = 0;
} else {
txAmount1 = tx_bufsize - tx_get;
txAmount2 = tx_put;
}
return(txAmount1+txAmount2);
}
VOID
CyzQueueCompleteWrite(
IN PCYZ_DEVICE_EXTENSION Extension
)
/*--------------------------------------------------------------------------
CyzQueueCompleteWrite()
Description: Queue CompleteWrite dpc
Parameters:
Extension: Pointer to device extension.
Return Value: None
--------------------------------------------------------------------------*/
{
PIO_STACK_LOCATION IrpSp;
//LOGENTRY(LOG_MISC, ZSIG_WRITE_COMPLETE_QUEUE,
// Extension->PortIndex+1,
// 0,
// 0);
//
// 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);
CyzInsertQueueDpc(
&Extension->CompleteWriteDpc,
NULL,
NULL,
Extension
);
}
BOOLEAN
CyzCheckIfTxEmpty(
IN PVOID Context
)
/*--------------------------------------------------------------------------
CyzCheckIfTxEmpty()
Routine Description: This routine is used to set the FIFO settings
during the InternalIoControl.
Arguments:
Context - Pointer to a structure that contains a pointer to the device
extension and a pointer to the Basic structure.
Return Value: This routine always returns FALSE.
--------------------------------------------------------------------------*/
{
PCYZ_CLOSE_SYNC S = Context;
PCYZ_DEVICE_EXTENSION Extension = S->Extension;
PULONG pHoldingEmpty = S->Data;
*pHoldingEmpty = Extension->HoldingEmpty;
return FALSE;
}