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
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;
|
|
}
|