// event.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "event.tmh" #endif void FillMsgBuf(char *msg, char *buf, int amountToWrite); /////////////////////////////////////////////////////////////////////////////////////////////////// // CprUartEventDpcCallback // Uart event notification dpc callback // // Arguments: // IN Dpc // XoffTimeoutDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprUartEventDpcCallback( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; UCHAR iir; UCHAR lsr; deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint1(deviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. DEVEXT %p", deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); deviceExtension->DpcThreadId = PsGetCurrentThreadId(); iir = CprUartReadIIR(&deviceExtension->Uart); // check if virtual uart has any pending events if (iir & CPR_UART_IIR_NO_INTERRUPT_PENDING) { NOTHING; } else if (!(deviceExtension->IsDeviceEnabled || deviceExtension->IsDeviceOpening) || (deviceExtension->DevicePowerState != PowerDeviceD0)) { // nobody cares what is going on with this UART, so just make sure that it quiets down do { iir &= ~CPR_UART_IIR_FIFOS_ENABLED; switch (iir) { case CPR_UART_IIR_RLS: CprUartReadLSR(&deviceExtension->Uart); break; case CPR_UART_IIR_RDA: case CPR_UART_IIR_CTI: CprUartRead(&deviceExtension->Uart); break; case CPR_UART_IIR_THR: deviceExtension->TxIdle = TRUE; break; case CPR_UART_IIR_MS: CprUartReadMSR(&deviceExtension->Uart); break; default: break; } } while (!((iir = CprUartReadIIR(&deviceExtension->Uart)) & CPR_UART_IIR_NO_INTERRUPT_PENDING)); } else { // we have a new event do { // apply valid event bit mask iir &= CPR_UART_IIR_RLS | CPR_UART_IIR_RDA | CPR_UART_IIR_CTI | CPR_UART_IIR_THR | CPR_UART_IIR_MS; switch (iir) { case CPR_UART_IIR_RLS: // line status changed CprSerialProcessLSR(deviceExtension); break; case CPR_UART_IIR_RDA: case CPR_UART_IIR_CTI: // we have new read data if (deviceExtension->QueueBuffer != NULL) { // DAG: Added to stop read overflows. 4/10/08 if ((deviceExtension->ReadBuffer == deviceExtension->QueueBuffer) && ((deviceExtension->QueueSize - deviceExtension->ReadCount) == 0)) { deviceExtension->Uart.RxDataEvent = 0; // DAG: End Add } else { CprSerialProcessDataReady(deviceExtension); } } else { deviceExtension->Uart.RxDataEvent = 0; } break; case CPR_UART_IIR_THR: // check if transmit is done CprSerialProcessTransmitDone(deviceExtension); break; case CPR_UART_IIR_MS: // modem status changed CprSerialHandleModemUpdate(deviceExtension, FALSE); break; } } while (!((iir = CprUartReadIIR(&deviceExtension->Uart)) & CPR_UART_IIR_NO_INTERRUPT_PENDING)); } deviceExtension->DpcThreadId = NULL; CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprDebugPrint1(deviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. DEVEXT %p", deviceExtension); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialPutChar // add character to read buffer // // Arguments: // IN DeviceExtension // our device extension // // IN Data // new character // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprSerialPutChar( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN UCHAR Data ) { PIRP irp; PIO_STACK_LOCATION irpStack; // CprDebugPrint1(DeviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. <<<<< Data 0x%0X >>>>>", Data); CprDebugPrint(DeviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++."); // check if we should ignore all the characters if DSR is down if (DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) { CprSerialHandleModemUpdate(DeviceExtension, FALSE); if (DeviceExtension->RxStopReason & CPR_SERIAL_RX_DSR) { return; } } // update xoff down counter if (DeviceExtension->XoffCount) { --DeviceExtension->XoffCount; if (DeviceExtension->XoffCount == 0) { DeviceExtension->XoffIrp->IoStatus.Status = STATUS_SUCCESS; DeviceExtension->XoffIrp->IoStatus.Information = 0; KeInsertQueueDpc(&DeviceExtension->XoffCompleteDpc, NULL, NULL); } } irp = DeviceExtension->ReadQueue.CurrentIrp; // check we are copying directly into irp buffer or our queue buffer // first check to see if the irp is valid (non-zero) if (irp && (DeviceExtension->ReadBuffer != DeviceExtension->QueueBuffer)) { // // There is a read IRP waiting. Copy directly to IRP's buffer. // // update last read count for interval timer ++DeviceExtension->LastReadCount; // add new character to the buffer *DeviceExtension->ReadCharLast = Data; // check if we reached the end of the IRP buffer if (DeviceExtension->ReadCharLast == DeviceExtension->ReadBufferEnd) { CprDebugPrint1(DeviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_INFO, __FUNCTION__" Switching back to queue buffer. info %d", irp->IoStatus.Information); // switch back to our queue buffer DeviceExtension->ReadBuffer = DeviceExtension->QueueBuffer; DeviceExtension->ReadCharLast = DeviceExtension->QueueBuffer; DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer; DeviceExtension->ReadBufferEnd = DeviceExtension->QueueBuffer + (DeviceExtension->QueueSize - 1); DeviceExtension->ReadCount = 0; irpStack = IoGetCurrentIrpStackLocation(irp); if (irpStack) irp->IoStatus.Information = irpStack->Parameters.Read.Length; else irp->IoStatus.Information = 1; // complete the read irp KeInsertQueueDpc(&DeviceExtension->ReadCompleteDpc, NULL, NULL); } else { // we still have room in our read irp buffer ++DeviceExtension->ReadCharLast; } } else { // // There is no read IRP, so we are going to copy new character to our read queue // we might need to do some flow control depending on how full our read queue gets // check if we are doing DTR flow control if ((DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { if (!(DeviceExtension->RxStopReason & CPR_SERIAL_RX_DTR)) { // check if we are over xoff limit if ((DeviceExtension->QueueSize - DeviceExtension->SerialHandFlow.XoffLimit) <= (DeviceExtension->ReadCount + 1)) { // lower DTR to stop receiving new data DeviceExtension->RxStopReason |= CPR_SERIAL_RX_DTR; CprSerialClrDTR(DeviceExtension); } } } // check if we are doing RTS flow control if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) { if (!(DeviceExtension->RxStopReason & CPR_SERIAL_RX_RTS)) { // check if we are over xoff limit if ((DeviceExtension->QueueSize - DeviceExtension->SerialHandFlow.XoffLimit) <= (DeviceExtension->ReadCount + 1)) { DeviceExtension->RxStopReason |= CPR_SERIAL_RX_RTS; CprSerialClrRTS(DeviceExtension); } } } // check if we are doing xon/xoff flow control if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_AUTO_RECEIVE) { if (!(DeviceExtension->RxStopReason & CPR_SERIAL_RX_XOFF)) { // check if we are over xoff limit if ((DeviceExtension->QueueSize - DeviceExtension->SerialHandFlow.XoffLimit) <= (DeviceExtension->ReadCount + 1)) { DeviceExtension->RxStopReason |= CPR_SERIAL_RX_XOFF; CprSerialProdXonXoff(DeviceExtension, FALSE); } } } // check if we have room in our read queue if (DeviceExtension->ReadCount < DeviceExtension->QueueSize) { *DeviceExtension->ReadCharLast = Data; ++DeviceExtension->ReadCount; // check if we reached 80% capacity of our queue if (DeviceExtension->ReadCount == DeviceExtension->QueueSizePt8) { CprLogEvent( CPR_EVENT_TYPE_WAIT_RX80FULL, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); // see if our client wants to know about it if (DeviceExtension->WaitMask & SERIAL_EV_RX80FULL) { DeviceExtension->WaitEvents |= SERIAL_EV_RX80FULL; if (DeviceExtension->IrpWaitMask) { *DeviceExtension->IrpWaitMask = DeviceExtension->WaitEvents; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitEvents = 0; CprDebugPrint1(DeviceExtension, DBG_IO, DBG_INFO, "CprSerialPutChar: WaitDpc App Irp %p", DeviceExtension->WaitIrp); DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&DeviceExtension->WaitCompleteDpc, NULL, NULL); } } } // check if we reached the end of the buffer if (DeviceExtension->ReadCharLast == DeviceExtension->ReadBufferEnd) { // we have a circular buffer, so we need to wrap DeviceExtension->ReadCharLast = DeviceExtension->QueueBuffer; } else { ++DeviceExtension->ReadCharLast; } } else { CprDebugPrint(DeviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_INFO, __FUNCTION__" We have a READ OVERFLOW!!"); // DAG: Added to report read overflows. 4/10/08 if (DeviceExtension->RxOverrun == FALSE) { DeviceExtension->RxOverrun = TRUE; CprLogEvent( CPR_EVENT_TYPE_READ_OVERFLOW, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } // DAG: End Add. // we do not have room for a new character, so record // a buffer overrun error ++DeviceExtension->SerialStats.BufferOverrunErrorCount; ++DeviceExtension->WmiPerfData.BufferOverrunErrorCount; DeviceExtension->ErrorWord |= SERIAL_ERROR_QUEUEOVERRUN; // see if we need to insert an error character if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_ERROR_CHAR) { if (DeviceExtension->ReadCharLast == DeviceExtension->QueueBuffer) { *(DeviceExtension->QueueBuffer + (DeviceExtension->QueueSize - 1)) = DeviceExtension->SerialChars.ErrorChar; } else { *(DeviceExtension->ReadCharLast - 1) = DeviceExtension->SerialChars.ErrorChar; } } // check if we should abort all io on error if (DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { KeInsertQueueDpc(&DeviceExtension->ErrorDpc, NULL, NULL); } } } CprDebugPrint(DeviceExtension, DBG_WRITE | DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--."); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialProcessLSR // line status change event handler // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // Old line status // // Comment: // This method is called with SerialLock held // UCHAR CprSerialProcessLSR( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { UCHAR lineStatus; lineStatus = CprUartReadLSR(&DeviceExtension->Uart); // check the state of the transmitter if (lineStatus & CPR_UART_LSR_THRE) { DeviceExtension->TxIdle = TRUE; } else { DeviceExtension->TxIdle = FALSE; } if (lineStatus & ~(CPR_UART_LSR_THRE | CPR_UART_LSR_TEMT | CPR_UART_LSR_DR)) { // we have an error condition, see if our client wants to know about it and how // we should tell it about the error // if we are using escape character, insert line status in receive data stream if (DeviceExtension->EscapeChar) { CprSerialPutChar(DeviceExtension, DeviceExtension->EscapeChar); CprSerialPutChar(DeviceExtension, (UCHAR)(lineStatus & CPR_UART_LSR_DR ? SERIAL_LSRMST_LSR_DATA : SERIAL_LSRMST_LSR_NODATA)); CprSerialPutChar(DeviceExtension, lineStatus); // check if this is a data ready event if (lineStatus & CPR_UART_LSR_DR) { ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; CprSerialPutChar(DeviceExtension, CprUartRead(&DeviceExtension->Uart)); } } // check if this is an overrun error if (lineStatus & CPR_UART_LSR_OE) { ++DeviceExtension->SerialStats.SerialOverrunErrorCount; ++DeviceExtension->WmiPerfData.SerialOverrunErrorCount; DeviceExtension->ErrorWord |= SERIAL_ERROR_OVERRUN; // check if we need to insert error char in receive character stream if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_ERROR_CHAR) { CprSerialPutChar(DeviceExtension, DeviceExtension->SerialChars.ErrorChar); if (lineStatus & CPR_UART_LSR_DR) { ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; CprUartRead(&DeviceExtension->Uart); } } else { if (lineStatus & CPR_UART_LSR_DR) { ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; CprSerialPutChar(DeviceExtension, CprUartRead(&DeviceExtension->Uart)); } } } // check if we received break interrupt if (lineStatus & CPR_UART_LSR_BI) { DeviceExtension->ErrorWord |= SERIAL_ERROR_BREAK; // check if we need to insert error char in receive character stream if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_BREAK_CHAR) { CprSerialPutChar(DeviceExtension, DeviceExtension->SerialChars.BreakChar); } } else { // check for parity error if (lineStatus & CPR_UART_LSR_PE) { ++DeviceExtension->SerialStats.ParityErrorCount; ++DeviceExtension->WmiPerfData.ParityErrorCount; DeviceExtension->ErrorWord |= SERIAL_ERROR_PARITY; // check if we need to insert error char in receive character stream if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_ERROR_CHAR) { CprSerialPutChar(DeviceExtension, DeviceExtension->SerialChars.ErrorChar); // if we also received some data, flush it if (lineStatus & CPR_UART_LSR_DR) { ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; CprUartRead(&DeviceExtension->Uart); } } } // check for framing error if (lineStatus & CPR_UART_LSR_FE) { ++DeviceExtension->SerialStats.FrameErrorCount; ++DeviceExtension->WmiPerfData.FrameErrorCount; DeviceExtension->ErrorWord |= SERIAL_ERROR_FRAMING; // check if we need to insert error char in receive character stream if (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_ERROR_CHAR) { CprSerialPutChar(DeviceExtension, DeviceExtension->SerialChars.ErrorChar); // if we also received some data, flush it if (lineStatus & CPR_UART_LSR_DR) { ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; CprUartRead(&DeviceExtension->Uart); } } } } // check if we need to abort io on error if (DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_ERROR_ABORT) { KeInsertQueueDpc(&DeviceExtension->ErrorDpc, NULL, NULL); } // check if there is an wait on mask ioctl if (DeviceExtension->WaitMask) { // check for error condition if ((DeviceExtension->WaitMask & SERIAL_EV_ERR) && (lineStatus & (CPR_UART_LSR_OE | CPR_UART_LSR_PE | CPR_UART_LSR_FE))) { DeviceExtension->WaitEvents |= SERIAL_EV_ERR; CprLogEvent( CPR_EVENT_TYPE_WAIT_ERR, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } // check for break interrupt if ((DeviceExtension->WaitMask & SERIAL_EV_BREAK) && (lineStatus & CPR_UART_LSR_BI)) { DeviceExtension->WaitEvents |= SERIAL_EV_BREAK; CprLogEvent( CPR_EVENT_TYPE_WAIT_BREAK, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } // complete the wait on mask ioctl if (DeviceExtension->IrpWaitMask && DeviceExtension->WaitEvents) { CprDebugPrint2(DeviceExtension, DBG_IO, DBG_INFO, "CprSerialProcessLSR: Releasing Wait Irp %p Events 0x%08X", DeviceExtension->WaitIrp, DeviceExtension->WaitEvents); *DeviceExtension->IrpWaitMask = DeviceExtension->WaitEvents; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitEvents = 0; DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&DeviceExtension->WaitCompleteDpc, NULL, NULL); } } // check if we need to restart transmitter if (lineStatus & CPR_UART_LSR_THRE) { if (DeviceExtension->WriteLength | DeviceExtension->TxImmediate) { CprUartStartWrite(&DeviceExtension->Uart); } } } return lineStatus; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialProcessDataReady // data ready event handler // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprSerialProcessDataReady( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { UCHAR data; UCHAR rawData; UCHAR lsr; UCHAR *buf = DeviceExtension->TempReadBuf; ULONG bufSize; ULONG roomLeft; ULONG dataSize; ULONG i; char Msg[CPR_EVENT_MSG_SIZE]; char *sendMsg = NULL; Msg[0] = '\0'; CprDebugPrint1(DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. DEVEXT %p", DeviceExtension); do { bufSize = PAGE_SIZE; // DAG: Added to stop read overflows. 4/10/08 if (DeviceExtension->ReadBuffer == DeviceExtension->QueueBuffer) { roomLeft = DeviceExtension->QueueSize - DeviceExtension->ReadCount; if (roomLeft == 0) break; if (bufSize > roomLeft) bufSize = roomLeft; } // End Add. // Dynamically allocate buf so the stack usage is not so large!! dataSize = CprUartReadBlock(&DeviceExtension->Uart, buf, bufSize); if (LoggingEvent && dataSize) { char msg[CPR_EVENT_MSG_SIZE]; FillMsgBuf(msg, (char*)buf, dataSize); _CprLogEvent( CPR_EVENT_TYPE_DATA_RECEIVE, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, msg); } for (i = 0; i < dataSize; i++) { rawData = data = buf[i]; ++DeviceExtension->SerialStats.ReceivedCount; ++DeviceExtension->WmiPerfData.ReceivedCount; // make sure that we are using only the valid data bits data &= DeviceExtension->DataMask; if (DeviceExtension->UseRFC2217) { if ((DeviceExtension->IACEscape == IACNormal) && (data == 0) && (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_NULL_STRIPPING)) { //DbgPrint("RFC2217 NUll STRIPPING: data %X Flow %X\n", // data, DeviceExtension->SerialHandFlow.FlowReplace); // if we are not allowing null characters // ignore null character continue; } // check for xon/xoff handshake if ((DeviceExtension->IACEscape == IACNormal) && (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) && ((data == DeviceExtension->SerialChars.XonChar) || (data == DeviceExtension->SerialChars.XoffChar))) { // see if it is xoff if (data == DeviceExtension->SerialChars.XoffChar) { if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Received"); CprLogEvent( CPR_EVENT_TYPE_XOFF, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, Msg); } // disable the transmitter DeviceExtension->TxStopReason |= CPR_SERIAL_TX_XOFF; #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } #endif } else { if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Received"); CprLogEvent( CPR_EVENT_TYPE_XON, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, Msg); } // we received xon character, so we need to reenable the transmitter if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_XOFF) { DeviceExtension->TxStopReason &= ~CPR_SERIAL_TX_XOFF; CprUartStartWrite(&DeviceExtension->Uart); } } } else { // see if there is a wait on mask pending ioctl if (DeviceExtension->WaitMask) { if (((rawData != TNIAC) && (DeviceExtension->IACEscape == IACNormal)) || ((rawData == TNIAC) && (DeviceExtension->LastFromNet == TNIAC))) { // record receive character event if (DeviceExtension->WaitMask & SERIAL_EV_RXCHAR) { if (LoggingEvent && ((DeviceExtension->WaitEvents & SERIAL_EV_RXCHAR) == 0)) { CprLogEvent( CPR_EVENT_TYPE_WAIT_RXCHAR, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } DeviceExtension->WaitEvents |= SERIAL_EV_RXCHAR; } // check for special event character if ((DeviceExtension->WaitMask & SERIAL_EV_RXFLAG) && (DeviceExtension->SerialChars.EventChar == data)) { DeviceExtension->WaitEvents |= SERIAL_EV_RXFLAG; CprLogEvent( CPR_EVENT_TYPE_WAIT_RXFLAG, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } // complete the wait on event ioctl if (DeviceExtension->IrpWaitMask && DeviceExtension->WaitEvents) { CprDebugPrint2(DeviceExtension, DBG_IO, DBG_INFO, "CprSerialProcessDataReady 1: Releasing Wait Irp %p Events 0x%08X", DeviceExtension->WaitIrp, DeviceExtension->WaitEvents); *DeviceExtension->IrpWaitMask = DeviceExtension->WaitEvents; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitEvents = 0; DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&DeviceExtension->WaitCompleteDpc, NULL, NULL); } } } // Are we are performing RFC 2217 communication? // Places data in receive buffer, does signalling, etc. // places response commands in deviceExtension->ToNetBuf // CprRfc2217_EscRedirectChar(DeviceExtension, rawData); // check for escape character if (DeviceExtension->EscapeChar && (DeviceExtension->EscapeChar == data)) { CprSerialPutChar(DeviceExtension, SERIAL_LSRMST_ESCAPE); } } } else if ((data == 0) && (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_NULL_STRIPPING)) { // if we are not allowing null characters // ignore null character //DbgPrint("NORMAL NUll STRIPPING: data %X Flow %X\n", // data, DeviceExtension->SerialHandFlow.FlowReplace); NOTHING; } else { // check for xon/xoff handshake if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_AUTO_TRANSMIT) && ((data == DeviceExtension->SerialChars.XonChar) || (data == DeviceExtension->SerialChars.XoffChar))) { // see if it is xoff if (data == DeviceExtension->SerialChars.XoffChar) { if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Received"); CprLogEvent( CPR_EVENT_TYPE_XOFF, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, Msg); } // disable the transmitter DeviceExtension->TxStopReason |= CPR_SERIAL_TX_XOFF; #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } #endif } else { if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Received"); CprLogEvent( CPR_EVENT_TYPE_XON, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, Msg); } // we received xon character, so we need to reenable the transmitter if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_XOFF) { DeviceExtension->TxStopReason &= ~CPR_SERIAL_TX_XOFF; CprUartStartWrite(&DeviceExtension->Uart); } } } else { // see if there is a wait on mask pending ioctl if (DeviceExtension->WaitMask) { // record receive character event if (DeviceExtension->WaitMask & SERIAL_EV_RXCHAR) { if (LoggingEvent && ((DeviceExtension->WaitEvents & SERIAL_EV_RXCHAR) == 0)) { CprLogEvent( CPR_EVENT_TYPE_WAIT_RXCHAR, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } DeviceExtension->WaitEvents |= SERIAL_EV_RXCHAR; } // check for special event character if ((DeviceExtension->WaitMask & SERIAL_EV_RXFLAG) && (DeviceExtension->SerialChars.EventChar == data)) { DeviceExtension->WaitEvents |= SERIAL_EV_RXFLAG; CprLogEvent( CPR_EVENT_TYPE_WAIT_RXFLAG, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); } // complete the wait on event ioctl if (DeviceExtension->IrpWaitMask && DeviceExtension->WaitEvents) { CprDebugPrint2(DeviceExtension, DBG_IO, DBG_INFO, "CprSerialProcessDataReady 2: Releasing Wait Irp %p Events 0x%08X", DeviceExtension->WaitIrp, DeviceExtension->WaitEvents); *DeviceExtension->IrpWaitMask = DeviceExtension->WaitEvents; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitEvents = 0; DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&DeviceExtension->WaitCompleteDpc, NULL, NULL); } } // insert the new character in the receive character stream CprSerialPutChar(DeviceExtension, data); // check for escape character if (DeviceExtension->EscapeChar && (DeviceExtension->EscapeChar == data)) { CprSerialPutChar(DeviceExtension, SERIAL_LSRMST_ESCAPE); } } } } // check for RFC2217 data to send to device server // if ( DeviceExtension->UseRFC2217 && !IsBufferEmpty(&DeviceExtension->ToNetBuf) ) { CprRfc2217_SendToNet(DeviceExtension, FALSE); } // check for more data lsr = CprSerialProcessLSR(DeviceExtension); if (!(lsr & CPR_UART_LSR_DR)) { // no more data break; } // check for an error if ((lsr & ~(CPR_UART_LSR_THRE | CPR_UART_LSR_TEMT | CPR_UART_LSR_DR)) && DeviceExtension->EscapeChar) { break; } } while (TRUE); CprDebugPrint1(DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. DEVEXT %p", DeviceExtension); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialProcessTransmitDone // tx done event handler // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprSerialProcessTransmitDone( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { NTSTATUS status = 0xFAB01; char msg[CPR_EVENT_MSG_SIZE]; // return if we are currently processing this Irp // One case is where an Xoff is received between // a CprTdiSend and the CprTdiWriteComplete. When // the Xon is received it kicks off the queue processing // before CprTdiWriteComplete is called. // if (DeviceExtension->WriteQueue.CurrentIrp && TDI_IRP_REFERENCE(DeviceExtension->WriteQueue.CurrentIrp)) { CprDebugPrint1(DeviceExtension, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"--(Already Processing IRP). %p", DeviceExtension->WriteQueue.CurrentIrp); return; } // Need to send for the TxBuffer first, if there is data. // Then send from IRPs. Once IRPs are complete, reset // TxOverflow, if set. CprDebugPrint1(DeviceExtension, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"++. DEVEXT %p", DeviceExtension); // transmitter is now idle DeviceExtension->TxIdle = TRUE; CprDebugPrint6(DeviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, __FUNCTION__ " NetStat %d len %d immed %d xoff %d xon %d sysWrt %d", DeviceExtension->NetworkStatus, DeviceExtension->WriteLength, DeviceExtension->TxImmediate, DeviceExtension->SendXoffChar, DeviceExtension->SendXonChar, DeviceExtension->SystemWriteInProgress); CprDebugPrint6(DeviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, __FUNCTION__ " ok %d, stop %d bufwrites %d curirp %p hand 0x%X flow 0x%X", TxOkToSend(&DeviceExtension->Uart), DeviceExtension->TxStopReason, DeviceExtension->BufferWrites, DeviceExtension->WriteQueue.CurrentIrp, DeviceExtension->SerialHandFlow.ControlHandShake, DeviceExtension->SerialHandFlow.FlowReplace); // Now process any IRPs // check if we have more data to send if (DeviceExtension->NetworkStatus == CPR_NETWORK_STATUS_CONNECTED && (DeviceExtension->WriteLength || DeviceExtension->TxImmediate || DeviceExtension->SendXoffChar || DeviceExtension->SendXonChar || TxOkToSend(&DeviceExtension->Uart)) && (DeviceExtension->SystemWriteInProgress == FALSE) //TxDataAvailable(&DeviceExtension->Uart)) ) { // make sure that we are in sync with flow control if (DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_OUT_HANDSHAKEMASK) { CprSerialHandleModemUpdate(DeviceExtension, TRUE); } // check if we need to send xon if (DeviceExtension->SendXonChar && !(DeviceExtension->TxStopReason & ~CPR_SERIAL_TX_XOFF)) { status = 0xFAB03; #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } else #endif { ++DeviceExtension->SerialStats.TransmittedCount; ++DeviceExtension->WmiPerfData.TransmittedCount; status = CprUartWrite(&DeviceExtension->Uart, &DeviceExtension->SerialChars.XonChar, 1); if (DeviceExtension->UseRFC2217) { SendCPCFlowCommand(DeviceExtension, TNCAS_FLOWCONTROL_RESUME); CprRfc2217_SendToNet(DeviceExtension, TRUE); } } DeviceExtension->SendXonChar = FALSE; DeviceExtension->TxIdle = FALSE; // remove xoff stop reason DeviceExtension->TxStopReason &= ~CPR_SERIAL_TX_XOFF; DeviceExtension->RxStopReason &= ~CPR_SERIAL_RX_XOFF; } else if (DeviceExtension->SendXoffChar && (DeviceExtension->TxStopReason == 0)) { status = 0xFAB04; // we need to send xoff character #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } else #endif { ++DeviceExtension->SerialStats.TransmittedCount; ++DeviceExtension->WmiPerfData.TransmittedCount; status = CprUartWrite(&DeviceExtension->Uart, &DeviceExtension->SerialChars.XoffChar, 1); if (DeviceExtension->UseRFC2217) { SendCPCFlowCommand(DeviceExtension, TNCAS_FLOWCONTROL_SUSPEND); CprRfc2217_SendToNet(DeviceExtension, TRUE); } } // check we have xoff continue mode if (!(DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_XOFF_CONTINUE)) { status = 0xFAB05; // we need to block transmitter DeviceExtension->TxStopReason |= CPR_SERIAL_TX_XOFF; #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } #endif } DeviceExtension->SendXoffChar = FALSE; DeviceExtension->TxIdle = FALSE; } else if (DeviceExtension->TxImmediate && (!DeviceExtension->TxStopReason || (DeviceExtension->TxStopReason == CPR_SERIAL_TX_XOFF))) { // Even if transmission is being held up, we should still transmit an immediate // character if all that is holding us up is xon/xoff (OS/2 rules). DeviceExtension->TxImmediate = FALSE; status = 0xFAB06; #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } else #endif { ++DeviceExtension->SerialStats.TransmittedCount; ++DeviceExtension->WmiPerfData.TransmittedCount; status = CprUartWriteImmediate(&DeviceExtension->Uart, &DeviceExtension->ImmediateChar); } } else if (DeviceExtension->TxStopReason == 0) { // // Normal Data Path // ULONG amountToWrite; status = 0xFAB07; if ((DeviceExtension->BufferWrites) && (DeviceExtension->WriteQueue.CurrentIrp == NULL)) { //CprDumpBufPtrs(DeviceExtension, __FUNCTION__" Before"); amountToWrite = TxAmountToWrite(&DeviceExtension->Uart); DeviceExtension->Uart.TxSendBegPtr = DeviceExtension->Uart.TxReadPtr; DeviceExtension->Uart.TxSendEndPtr = DeviceExtension->Uart.TxWritePtr; if (DeviceExtension->Uart.TxWritePtr < DeviceExtension->Uart.TxReadPtr) { status = 0xFAB08; // Due to wrap around, do one portion at a time. DeviceExtension->Uart.TxSendEndPtr = DeviceExtension->Uart.TxEndBuffer; } DeviceExtension->Uart.TxTdiWriteLength = (ULONG)(DeviceExtension->Uart.TxSendEndPtr - DeviceExtension->Uart.TxSendBegPtr); DeviceExtension->Uart.TxSerialWriteLength += DeviceExtension->Uart.TxTdiWriteLength; //CprDumpBufPtrs(DeviceExtension, __FUNCTION__" After"); } else { amountToWrite = DeviceExtension->WriteLength; } if (amountToWrite > 0) { #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE) { // not implemented ASSERT(FALSE); } else #endif { DeviceExtension->WriteQueue.StatusChangeRoutine( DeviceExtension->WriteQueue.DeviceObject, CURRENT_IRP_STATUS_TRANSMITTING); if ((DeviceExtension->BufferWrites) && (DeviceExtension->WriteQueue.CurrentIrp == NULL)) { if (LoggingEvent) { FillMsgBuf(msg, (char*)DeviceExtension->Uart.TxReadPtr, amountToWrite); } status = CprUartWrite( &DeviceExtension->Uart, DeviceExtension->Uart.TxReadPtr, amountToWrite); } else { if (LoggingEvent) { FillMsgBuf(msg, (char*)DeviceExtension->WriteBuffer, amountToWrite); } DeviceExtension->SystemWriteInProgress = TRUE; status = CprUartWrite( &DeviceExtension->Uart, DeviceExtension->WriteBuffer, amountToWrite); if ((status != STATUS_PENDING) && (status != STATUS_SUCCESS)) DeviceExtension->SystemWriteInProgress = FALSE; } DeviceExtension->WriteQueue.StatusChangeRoutine( DeviceExtension->WriteQueue.DeviceObject, CURRENT_IRP_STATUS_TRANSMITTED); if (LoggingEvent) { _CprLogEvent( CPR_EVENT_TYPE_DATA_TRANSMIT, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, status, msg); } } } else { status = 0xFAB09; DbgPrint(__FUNCTION__" ************* amountToWrite was zero\n"); } } } else { status = 0xFAB02; } CprDebugPrint5(DeviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, __FUNCTION__ " TxBuffer %p, TxReadPtr %p, TxWritePtr %p, TxSendBegPtr %p, TxSendEndPtr %p", DeviceExtension->Uart.TxBuffer, DeviceExtension->Uart.TxReadPtr, DeviceExtension->Uart.TxWritePtr, DeviceExtension->Uart.TxSendBegPtr, DeviceExtension->Uart.TxSendEndPtr); CprDebugPrint2(DeviceExtension, DBG_WRITE | DBG_IO, DBG_TRACE, __FUNCTION__"--. DEVEXT %p status %x", DeviceExtension, status); return; } void FillMsgBuf(char *msg, char *buf, int amountToWrite) { USHORT len; USHORT *actual = (USHORT*)msg; USHORT *avail = (USHORT*)&msg[2]; if (buf == NULL) amountToWrite = 0; len = (USHORT)amountToWrite; if (len > CPR_EVENT_MSG_SIZE-4) len = CPR_EVENT_MSG_SIZE-4; *actual = len; *avail = (USHORT)amountToWrite; if (buf) { RtlMoveMemory(&msg[4], buf, len); } }