/*-------------------------------------------------------------------------- * * 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; channelNChannels; 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;channelNChannels;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; }