// ioctl.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "ioctl.tmh" #endif void SetFlowMsg( PCPR_DEVICE_EXTENSION DeviceExtension, char *Msg, DWORD sizeofMsg) { DWORD handShake = DeviceExtension->SerialHandFlow.ControlHandShake; DWORD flowReplace = DeviceExtension->SerialHandFlow.FlowReplace; //typedef struct _SERIAL_HANDFLOW { // ULONG ControlHandShake; // ULONG FlowReplace; // LONG XonLimit; // LONG XoffLimit; // } SERIAL_HANDFLOW,*PSERIAL_HANDFLOW; RtlStringCchPrintfA(Msg, sizeofMsg, "CtrlHS 0x%X, FlwRep 0x%X, XonL 0x%X, XofL 0x%X", handShake, flowReplace, DeviceExtension->SerialHandFlow.XonLimit, DeviceExtension->SerialHandFlow.XoffLimit); if (handShake & SERIAL_DTR_CONTROL) RtlStringCchCatA(Msg, sizeofMsg, " DtrCt"); if (handShake & SERIAL_DTR_HANDSHAKE) RtlStringCchCatA(Msg, sizeofMsg, " DtrHS"); if (handShake & SERIAL_CTS_HANDSHAKE) RtlStringCchCatA(Msg, sizeofMsg, " CtsHS"); if (handShake & SERIAL_DSR_HANDSHAKE) RtlStringCchCatA(Msg, sizeofMsg, " DsrHS"); if (handShake & SERIAL_DCD_HANDSHAKE) RtlStringCchCatA(Msg, sizeofMsg, " DcdHS"); if (handShake & SERIAL_DSR_SENSITIVITY) RtlStringCchCatA(Msg, sizeofMsg, " DsrSn"); if (handShake & SERIAL_ERROR_ABORT) RtlStringCchCatA(Msg, sizeofMsg, " ErrAb"); if (flowReplace & SERIAL_AUTO_TRANSMIT) RtlStringCchCatA(Msg, sizeofMsg, " AtoTx"); if (flowReplace & SERIAL_AUTO_RECEIVE) RtlStringCchCatA(Msg, sizeofMsg, " AtoRx"); if (flowReplace & SERIAL_ERROR_CHAR) RtlStringCchCatA(Msg, sizeofMsg, " ErrCh"); if (flowReplace & SERIAL_NULL_STRIPPING) RtlStringCchCatA(Msg, sizeofMsg, " NulSt"); if (flowReplace & SERIAL_BREAK_CHAR) RtlStringCchCatA(Msg, sizeofMsg, " BrkCh"); if (flowReplace & SERIAL_RTS_CONTROL) RtlStringCchCatA(Msg, sizeofMsg, " RtsCt"); if (flowReplace & SERIAL_RTS_HANDSHAKE) RtlStringCchCatA(Msg, sizeofMsg, " RtsHS"); if (flowReplace & SERIAL_XOFF_CONTINUE) RtlStringCchCatA(Msg, sizeofMsg, " XofCu"); } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprDeviceIoControlDispatch // Handled incoming IOCTL requests // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The IOCTL IRP to handle // // Return Value: // NT status code // NTSTATUS CprDeviceIoControlDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { NTSTATUS status; POWER_STATE powerState; PCPR_DEVICE_EXTENSION deviceExtension; __try { deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_IOCTL, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); if (DeviceObject->DeviceType == FILE_DEVICE_CPR) { status = CprBackdoorIoctl(DeviceObject, Irp); } else { status = CprSerialIoControl(deviceExtension, Irp); } CprDebugPrint2(deviceExtension, DBG_IOCTL, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); } __except( EXCEPTION_EXECUTE_HANDLER ) { status = STATUS_INTERNAL_ERROR; } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialIoControl // IOCTL_SERIAL_XXX handler // // Arguments: // IN DeviceExtension // our device extension // // IN Irp // IOCTL_SERIAL_XXX IRP // // Return Value: // Status // NTSTATUS CprSerialIoControl( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp ) { NTSTATUS status; PIO_STACK_LOCATION irpStack; KIRQL oldIrql; char Msg[CPR_EVENT_MSG_SIZE]; BOOLEAN CompleteThisRequest = TRUE; ULONG IoLogType = CPR_EVENT_TYPE_NONE; char *sendMsg = NULL; Msg[0] = '\0'; // Get our IRP stack location irpStack = IoGetCurrentIrpStackLocation(Irp); Irp->IoStatus.Information = 0; // check the device error condition status = CprCheckForError(DeviceExtension, Irp); if (!NT_SUCCESS(status)) { return status; } switch (irpStack->Parameters.DeviceIoControl.IoControlCode) { // The IOCTL_SERIAL_SET_BAUD_RATE request sets the baud rate on a COM port. case IOCTL_SERIAL_SET_BAUD_RATE: { unsigned long int SaveBaudRate; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_BAUD_RATE"); IoLogType = CPR_ET_IOCTL_SET_BAUDRATE; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) { status = STATUS_BUFFER_TOO_SMALL; break; } SaveBaudRate = DeviceExtension->BaudRate; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { //DbgPrint(__FUNCTION__"--. IRP %p STATUS 0x%X\n", Irp, status); CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } DeviceExtension->BaudRate = ((PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer)->BaudRate; DeviceExtension->WmiCommData.BaudRate = DeviceExtension->BaudRate; //DeviceExtension->PendingWriteCount = 0; //DeviceExtension->TxStopReason = 0; //DeviceExtension->RxStopReason = 0; if (DeviceExtension->UseRFC2217) { if ((SaveBaudRate != DeviceExtension->BaudRate) || (DeviceExtension->BaudSent == FALSE)) //if (SaveBaudRate != DeviceExtension->BaudRate) { CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); DeviceExtension->BaudSent = TRUE; CprRfc2217_SendBaudRate(DeviceExtension, DeviceExtension->BaudRate); CprRfc2217_SendToNet(DeviceExtension, TRUE); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } } if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "BaudRate = %d", DeviceExtension->BaudRate); } CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_BAUD_RATE request returns the baud rate that is currently set for a COM port. case IOCTL_SERIAL_GET_BAUD_RATE: { PSERIAL_BAUD_RATE br; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_BAUD_RATE"); IoLogType = CPR_ET_IOCTL_GET_BAUDRATE; br = (PSERIAL_BAUD_RATE)Irp->AssociatedIrp.SystemBuffer; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } br->BaudRate = DeviceExtension->BaudRate; Irp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE); if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "BaudRate = %d", DeviceExtension->BaudRate); } CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_MODEM_CONTROL request returns the value of the modem control register. case IOCTL_SERIAL_GET_MODEM_CONTROL: { ULONG mcr; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_MODEM_CONTROL"); IoLogType = CPR_ET_IOCTL_GET_MODEM_CONTROL; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); mcr = CprUartReadMCR(&DeviceExtension->Uart); *(PULONG)Irp->AssociatedIrp.SystemBuffer = mcr; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "DTR %d, RTS %d, OUT1 %d, OUT2 %d, LOOP %d", (mcr & CPR_UART_MCR_DTR) ? 1 : 0, (mcr & CPR_UART_MCR_RTS) ? 1 : 0, (mcr & CPR_UART_MCR_OUT1) ? 1 : 0, (mcr & CPR_UART_MCR_OUT2) ? 1 : 0, (mcr & CPR_UART_MCR_LOOP) ? 1 : 0); } Irp->IoStatus.Information = sizeof(ULONG); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_MODEM_CONTROL request sets the modem control register. Parameter checking is not done. case IOCTL_SERIAL_SET_MODEM_CONTROL: { UCHAR mcr; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_MODEM_CONTROL"); IoLogType = CPR_ET_IOCTL_SET_MODEM_CONTROL; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); mcr = *(PUCHAR)Irp->AssociatedIrp.SystemBuffer; CprUartWriteMCR(&DeviceExtension->Uart, mcr); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "DTR %d, RTS %d, OUT1 %d, OUT2 %d, LOOP %d", (mcr & CPR_UART_MCR_DTR) ? 1 : 0, (mcr & CPR_UART_MCR_RTS) ? 1 : 0, (mcr & CPR_UART_MCR_OUT1) ? 1 : 0, (mcr & CPR_UART_MCR_OUT2) ? 1 : 0, (mcr & CPR_UART_MCR_LOOP) ? 1 : 0); } CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_FIFO_CONTROL request sets the FIFO control register (FCR). // Serial does not verify the specified FIFO control information. case IOCTL_SERIAL_SET_FIFO_CONTROL: CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_FIFO_CONTROL"); break; // The IOCTL_SERIAL_SET_LINE_CONTROL request sets the line control register (LCR). // The line control register controls the data size, the number of stop bits, and the parity. case IOCTL_SERIAL_SET_LINE_CONTROL: { PSERIAL_LINE_CONTROL lineControl; UCHAR data; UCHAR stop; UCHAR parity; UCHAR mask; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_TRACE, "IOCTL_SERIAL_SET_LINE_CONTROL"); IoLogType = CPR_ET_IOCTL_SET_LINE_CONTROL; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } lineControl = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; mask = 0xff; switch (lineControl->WordLength) { case 5: data = CPR_UART_LCR_5_DATA; mask = 0x1f; break; case 6: data = CPR_UART_LCR_6_DATA; mask = 0x3f; break; case 7: data = CPR_UART_LCR_7_DATA; mask = 0x7f; break; case 8: data = CPR_UART_LCR_8_DATA; break; default: status = STATUS_INVALID_PARAMETER; break; } DeviceExtension->WmiCommData.BitsPerByte = lineControl->WordLength; switch (lineControl->Parity) { case NO_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_NONE; parity = CPR_UART_LCR_NONE_PARITY; break; case EVEN_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_EVEN; parity = CPR_UART_LCR_EVEN_PARITY; break; case ODD_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_ODD; parity = CPR_UART_LCR_ODD_PARITY; break; case SPACE_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_SPACE; parity = CPR_UART_LCR_SPACE_PARITY; break; case MARK_PARITY: DeviceExtension->WmiCommData.Parity = SERIAL_WMI_PARITY_MARK; parity = CPR_UART_LCR_MARK_PARITY; break; default: status = STATUS_INVALID_PARAMETER; break; } switch (lineControl->StopBits) { case STOP_BIT_1: DeviceExtension->WmiCommData.StopBits = SERIAL_WMI_STOP_1; stop = CPR_UART_LCR_1_STOP; break; case STOP_BITS_1_5: DeviceExtension->WmiCommData.StopBits = SERIAL_WMI_STOP_1_5; stop = CPR_UART_LCR_1_5_STOP; break; case STOP_BITS_2: DeviceExtension->WmiCommData.StopBits = SERIAL_WMI_STOP_2; stop = CPR_UART_LCR_2_STOP; break; default: status = STATUS_INVALID_PARAMETER; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); DeviceExtension->LineControl = (UCHAR)((DeviceExtension->LineControl & CPR_UART_LCR_BREAK) | (data | parity | stop)); DeviceExtension->DataMask = mask; CprUartWriteLCR(&DeviceExtension->Uart, DeviceExtension->LineControl); if (LoggingEvent) { UCHAR linec = DeviceExtension->LineControl; UCHAR pMask = linec & CPR_UART_LCR_PARITY_MASK; UCHAR sMask = linec & CPR_UART_LCR_STOP_MASK; RtlStringCchPrintfA(Msg, sizeof(Msg), "Break %s, (%d, %c, %d)", (linec & CPR_UART_LCR_BREAK) ? "On" : "Off", 5 + (linec & CPR_UART_LCR_DATA_MASK), (pMask == CPR_UART_LCR_ODD_PARITY) ? 'O' : (pMask == CPR_UART_LCR_EVEN_PARITY) ? 'E' : (pMask == CPR_UART_LCR_MARK_PARITY) ? 'M' : (pMask == CPR_UART_LCR_SPACE_PARITY) ? 'S' : 'N', (sMask == CPR_UART_LCR_2_STOP) ? 2 : 1 ); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_LINE_CONTROL request returns information about the line control set for a COM port. // The line control parameters include the number of stop bits, the number of data bits, and the parity. case IOCTL_SERIAL_GET_LINE_CONTROL: { PSERIAL_LINE_CONTROL lineControl; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_LINE_CONTROL"); IoLogType = CPR_ET_IOCTL_GET_LINE_CONTROL; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) { status = STATUS_BUFFER_TOO_SMALL; break; } lineControl = (PSERIAL_LINE_CONTROL)Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(Irp->AssociatedIrp.SystemBuffer, irpStack->Parameters.DeviceIoControl.OutputBufferLength); CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if ((DeviceExtension->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_5_DATA) { lineControl->WordLength = 5; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_6_DATA) { lineControl->WordLength = 6; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_7_DATA) { lineControl->WordLength = 7; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_DATA_MASK) == CPR_UART_LCR_8_DATA) { lineControl->WordLength = 8; } if ((DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_NONE_PARITY) { lineControl->Parity = NO_PARITY; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_ODD_PARITY) { lineControl->Parity = ODD_PARITY; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_EVEN_PARITY) { lineControl->Parity = EVEN_PARITY; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_MARK_PARITY) { lineControl->Parity = MARK_PARITY; } else if ((DeviceExtension->LineControl & CPR_UART_LCR_PARITY_MASK) == CPR_UART_LCR_SPACE_PARITY) { lineControl->Parity = SPACE_PARITY; } if (DeviceExtension->LineControl & CPR_UART_LCR_2_STOP) { if (lineControl->WordLength == 5) { lineControl->StopBits = STOP_BITS_1_5; } else { lineControl->StopBits = STOP_BITS_2; } } else { lineControl->StopBits = STOP_BIT_1; } if (LoggingEvent) { UCHAR linec = DeviceExtension->LineControl; UCHAR pMask = linec & CPR_UART_LCR_PARITY_MASK; UCHAR sMask = linec & CPR_UART_LCR_STOP_MASK; RtlStringCchPrintfA(Msg, sizeof(Msg), "Break %s, (%d, %c, %d)", (linec & CPR_UART_LCR_BREAK) ? "On" : "Off", 5 + (linec & CPR_UART_LCR_DATA_MASK), (pMask == CPR_UART_LCR_ODD_PARITY) ? 'O' : (pMask == CPR_UART_LCR_EVEN_PARITY) ? 'E' : (pMask == CPR_UART_LCR_MARK_PARITY) ? 'M' : (pMask == CPR_UART_LCR_SPACE_PARITY) ? 'S' : 'N', (sMask == CPR_UART_LCR_2_STOP) ? 2 : 1 ); } Irp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } break; // The IOCTL_SERIAL_SET_TIMEOUTS request sets the timeout values that the driver uses with read and write requests. case IOCTL_SERIAL_SET_TIMEOUTS: { PSERIAL_TIMEOUTS timeouts; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_TIMEOUTS"); IoLogType = CPR_ET_IOCTL_SET_TIMEOUTS; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_TIMEOUTS)) { status = STATUS_BUFFER_TOO_SMALL; break; } timeouts = (PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer; if ((timeouts->ReadIntervalTimeout == MAXULONG) && (timeouts->ReadTotalTimeoutMultiplier == MAXULONG) && (timeouts->ReadTotalTimeoutConstant == MAXULONG)) { status = STATUS_INVALID_PARAMETER; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); DeviceExtension->Timeouts.ReadIntervalTimeout = timeouts->ReadIntervalTimeout; DeviceExtension->Timeouts.ReadTotalTimeoutMultiplier = timeouts->ReadTotalTimeoutMultiplier; DeviceExtension->Timeouts.ReadTotalTimeoutConstant = timeouts->ReadTotalTimeoutConstant; DeviceExtension->Timeouts.WriteTotalTimeoutMultiplier = 0; DeviceExtension->Timeouts.WriteTotalTimeoutConstant = 0; //DeviceExtension->Timeouts.WriteTotalTimeoutMultiplier = timeouts->WriteTotalTimeoutMultiplier; // DeviceExtension->Timeouts.WriteTotalTimeoutConstant = timeouts->WriteTotalTimeoutConstant; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { // Minimum length = 49 // Maximum length = 49 + (5 * 9) = 49 + 45 = 94 RtlStringCchPrintfA(Msg, sizeof(Msg), "RdInt %d, RdMult %d, RdConst %d, WrMult %d, WrConst %d", timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant); } } break; // The IOCTL_SERIAL_GET_TIMEOUTS request returns the timeout values that Serial uses with read and write requests. case IOCTL_SERIAL_GET_TIMEOUTS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_TIMEOUTS"); IoLogType = CPR_ET_IOCTL_GET_TIMEOUTS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_TIMEOUTS)) { status = STATUS_BUFFER_TOO_SMALL; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); *((PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->Timeouts; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); Irp->IoStatus.Information = sizeof(SERIAL_TIMEOUTS); if (LoggingEvent) { PSERIAL_TIMEOUTS timeouts = (PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer;; // Minimum length = 49 // Maximum length = 49 + (5 * 9) = 49 + 45 = 94 RtlStringCchPrintfA(Msg, sizeof(Msg), "RdInt %d, RdMult %d, RdConst %d, WrMult %d, WrConst %d", timeouts->ReadIntervalTimeout, timeouts->ReadTotalTimeoutMultiplier, timeouts->ReadTotalTimeoutConstant, timeouts->WriteTotalTimeoutMultiplier, timeouts->WriteTotalTimeoutConstant); } } break; // The IOCTL_SERIAL_SET_CHARS request sets the special characters that Serial uses for handshake flow control. // Serial verifies the specified special characters. case IOCTL_SERIAL_SET_CHARS: { PSERIAL_CHARS newChars; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_CHARS"); IoLogType = CPR_ET_IOCTL_SET_CHARS; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) { status = STATUS_BUFFER_TOO_SMALL; break; } newChars = (PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer; CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if (DeviceExtension->EscapeChar) { if ((DeviceExtension->EscapeChar == newChars->XonChar) || (DeviceExtension->EscapeChar == newChars->XoffChar)) { status = STATUS_INVALID_PARAMETER; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); break; } } DeviceExtension->SerialChars = *newChars; DeviceExtension->WmiCommData.XonCharacter = newChars->XonChar; DeviceExtension->WmiCommData.XoffCharacter = newChars->XoffChar; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { PSERIAL_TIMEOUTS timeouts = (PSERIAL_TIMEOUTS)Irp->AssociatedIrp.SystemBuffer;; // typedef struct _SERIAL_CHARS { // UCHAR EofChar; // UCHAR ErrorChar; // UCHAR BreakChar; // UCHAR EventChar; // UCHAR XonChar; // UCHAR XoffChar; // } SERIAL_CHARS,*PSERIAL_CHARS; // Minimum length = 71 // Maximum length = 71 + (6 * 2) = 71 + 12 = 83 RtlStringCchPrintfA(Msg, sizeof(Msg), "EofChar %d, ErrorChar %d, BreakChar %d, EventChar %d, XonChar %d, XoffChar %d", newChars->EofChar, newChars->ErrorChar, newChars->BreakChar, newChars->EventChar, newChars->XonChar, newChars->XoffChar); } } break; // The IOCTL_SERIAL_GET_CHARS request returns the special characters that Serial uses with handshake flow control. case IOCTL_SERIAL_GET_CHARS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_CHARS"); IoLogType = CPR_ET_IOCTL_GET_CHARS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) { status = STATUS_BUFFER_TOO_SMALL; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); *(PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer = DeviceExtension->SerialChars; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); Irp->IoStatus.Information = sizeof(SERIAL_CHARS); if (LoggingEvent) { PSERIAL_CHARS newChars = (PSERIAL_CHARS)Irp->AssociatedIrp.SystemBuffer; // typedef struct _SERIAL_CHARS { // UCHAR EofChar; // UCHAR ErrorChar; // UCHAR BreakChar; // UCHAR EventChar; // UCHAR XonChar; // UCHAR XoffChar; // } SERIAL_CHARS,*PSERIAL_CHARS; // Minimum length = 71 // Maximum length = 71 + (6 * 2) = 71 + 12 = 83 RtlStringCchPrintfA(Msg, sizeof(Msg), "EofChar %d, ErrorChar %d, BreakChar %d, EventChar %d, XonChar %d, XoffChar %d", newChars->EofChar, newChars->ErrorChar, newChars->BreakChar, newChars->EventChar, newChars->XonChar, newChars->XoffChar); } } break; // The IOCTL_SERIAL_SET_DTR request sets DTR (data terminal ready). case IOCTL_SERIAL_SET_DTR: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_DTR"); IoLogType = CPR_ET_IOCTL_SET_DTR; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if ((DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { status = STATUS_INVALID_PARAMETER; } else { CprSerialSetDTR(DeviceExtension); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_CLR_DTR request clears the data terminal ready control signal (DTR). case IOCTL_SERIAL_CLR_DTR: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_CLR_DTR"); IoLogType = CPR_ET_IOCTL_CLEAR_DTR; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if ((DeviceExtension->SerialHandFlow.ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_HANDSHAKE) { status = STATUS_INVALID_PARAMETER; } else { CprSerialClrDTR(DeviceExtension); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_RESET_DEVICE request resets a COM port. case IOCTL_SERIAL_RESET_DEVICE: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_RESET_DEVICE"); status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } //***************************************************************** //***************************************************************** // TODO: Reset the device //***************************************************************** //***************************************************************** CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_RTS request sets RTS (request to send). case IOCTL_SERIAL_SET_RTS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_TRACE, "IOCTL_SERIAL_SET_RTS"); IoLogType = CPR_ET_IOCTL_SET_RTS; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if (((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { status = STATUS_INVALID_PARAMETER; } else #endif { CprSerialSetRTS(DeviceExtension); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_CLR_RTS request clears the request to send control signal (RTS). case IOCTL_SERIAL_CLR_RTS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_TRACE, "IOCTL_SERIAL_CLR_RTS"); IoLogType = CPR_ET_IOCTL_CLEAR_RTS; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); #ifdef REMOVE_FOR_TESTING_WITH_GRID_CONNECT // GridConnect had FlowReplace = 0xC0 if (((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_RTS_HANDSHAKE) || ((DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)) { status = STATUS_INVALID_PARAMETER; } else #endif { CprSerialClrRTS(DeviceExtension); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_XOFF request emulates the reception of an XOFF character. // The request stops reception of data. If automatic XON/XOFF flow control is not set, then a client // must use a subsequent IOCTL_SERIAL_SET_XON request to restart reception of data. case IOCTL_SERIAL_SET_XOFF: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_XOFF"); IoLogType = CPR_ET_IOCTL_SET_XOFF; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); CprSerialPretendXoff(DeviceExtension); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_XON request emulates the reception of a XON character, which restarts reception of data. case IOCTL_SERIAL_SET_XON: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_XON"); IoLogType = CPR_ET_IOCTL_SET_XON; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); CprSerialPretendXon(DeviceExtension); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_BREAK_ON request sets the line control break signal active. case IOCTL_SERIAL_SET_BREAK_ON: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_BREAK_ON"); IoLogType = CPR_ET_IOCTL_SET_BREAK_ON; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); CprSerialTurnOnBreak(DeviceExtension); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_BREAK_OFF request sets the line control break signal inactive. case IOCTL_SERIAL_SET_BREAK_OFF: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_BREAK_OFF"); IoLogType = CPR_ET_IOCTL_SET_BREAK_OFF; status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); CprSerialTurnOffBreak(DeviceExtension); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_SET_QUEUE_SIZE request sets the size of the internal receive buffer. // If the requested size is greater than the current receive buffer size, a new receive buffer is created. // Otherwise, the receive buffer is not changed. case IOCTL_SERIAL_SET_QUEUE_SIZE: { PSERIAL_QUEUE_SIZE queueSize; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_QUEUE_SIZE"); IoLogType = CPR_ET_IOCTL_SET_QUEUE_SIZE; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE)) { status = STATUS_BUFFER_TOO_SMALL; break; } queueSize = (PSERIAL_QUEUE_SIZE)Irp->AssociatedIrp.SystemBuffer; CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_INFO, "Request %d Current %d", queueSize->InSize, DeviceExtension->QueueSize); if (LoggingEvent) { //typedef struct _SERIAL_QUEUE_SIZE { // ULONG InSize; // ULONG OutSize; // } SERIAL_QUEUE_SIZE,*PSERIAL_QUEUE_SIZE; RtlStringCchPrintfA(Msg, sizeof(Msg), "Request %d Current %d", queueSize->InSize, DeviceExtension->QueueSize); } if (queueSize->InSize <= DeviceExtension->QueueSize) { status = STATUS_SUCCESS; break; } __try { irpStack->Parameters.DeviceIoControl.Type3InputBuffer = ExAllocatePoolWithQuota(NonPagedPool, queueSize->InSize); } __except(EXCEPTION_EXECUTE_HANDLER) { irpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; status = GetExceptionCode(); } if (irpStack->Parameters.DeviceIoControl.Type3InputBuffer == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; break; } CompleteThisRequest = FALSE; status = CprQueueIrp(&DeviceExtension->ReadQueue, Irp, TRUE); break; } break; // The IOCTL_SERIAL_GET_WAIT_MASK request returns the event wait mask that is currently set on a COM port. case IOCTL_SERIAL_GET_WAIT_MASK: { //#define SERIAL_EV_RXCHAR 0x0001 // Any Character received //#define SERIAL_EV_RXFLAG 0x0002 // Received certain character //#define SERIAL_EV_TXEMPTY 0x0004 // Transmitt Queue Empty //#define SERIAL_EV_CTS 0x0008 // CTS changed state //#define SERIAL_EV_DSR 0x0010 // DSR changed state //#define SERIAL_EV_RLSD 0x0020 // RLSD changed state //#define SERIAL_EV_BREAK 0x0040 // BREAK received //#define SERIAL_EV_ERR 0x0080 // Line status error occurred //#define SERIAL_EV_RING 0x0100 // Ring signal detected //#define SERIAL_EV_PERR 0x0200 // Printer error occured //#define SERIAL_EV_RX80FULL 0x0400 // Receive buffer is 80 percent full //#define SERIAL_EV_EVENT1 0x0800 // Provider specific event 1 //#define SERIAL_EV_EVENT2 0x1000 // Provider specific event 2 CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_WAIT_MASK"); IoLogType = CPR_ET_IOCTL_GET_WAIT_MASK; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); *(PULONG)Irp->AssociatedIrp.SystemBuffer = DeviceExtension->WaitMask; if (LoggingEvent) { RtlStringCchPrintfA( Msg, sizeof(Msg), "Wait Mask 0x%08X", DeviceExtension->WaitMask); } } break; // The IOCTL_SERIAL_SET_WAIT_MASK request configures Serial to notify a client after // the occurrence of any one of a specified set of wait events. case IOCTL_SERIAL_SET_WAIT_MASK: { ULONG mask; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_WAIT_MASK"); IoLogType = CPR_ET_IOCTL_SET_WAIT_MASK; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } mask = *(PULONG)Irp->AssociatedIrp.SystemBuffer; if (mask & ~(SERIAL_EV_RXCHAR | SERIAL_EV_RXFLAG | SERIAL_EV_TXEMPTY | SERIAL_EV_CTS | SERIAL_EV_DSR | SERIAL_EV_RLSD | SERIAL_EV_BREAK | SERIAL_EV_ERR | SERIAL_EV_RING | SERIAL_EV_PERR | SERIAL_EV_RX80FULL | SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2)) { status = STATUS_INVALID_PARAMETER; break; } //RequestLineState(DeviceExtension); CompleteThisRequest = FALSE; status = CprQueueIrp(&DeviceExtension->MaskQueue, Irp, TRUE); if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Mask 0x%08X", mask); } break; } break; // The IOCTL_SERIAL_WAIT_ON_MASK request is used to wait for the occurrence of any wait event specified // by using an IOCTL_SERIAL_SET_WAIT_MASK request. A wait-on-mask request is completed after one of // the following events occurs: // 1) A wait event occurs that was specified by the most recent set-wait-mask request. // 2) An IOCTL_SERIAL_SET_WAIT_MASK request is received while a wait-on-mask request is pending. // The driver completes the pending wait-on-mask request with a status of STATUS_SUCCESS and the output wait mask is set to zero. case IOCTL_SERIAL_WAIT_ON_MASK: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_WAIT_ON_MASK"); IoLogType = CPR_ET_IOCTL_WAIT_ON_MASK; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } CompleteThisRequest = FALSE; status = CprQueueIrp(&DeviceExtension->MaskQueue, Irp, TRUE); break; } break; // The IOCTL_SERIAL_IMMEDIATE_CHAR request causes a specified character to be transmitted as soon as possible. // The immediate character request completes immediately after any other write that might be in progress. // Only one immediate character request can be pending at a time case IOCTL_SERIAL_IMMEDIATE_CHAR: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_IMMEDIATE_CHAR"); IoLogType = CPR_ET_IOCTL_IMMEDIATE_CHAR; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if (DeviceExtension->ImmediateCharIrp != NULL) { status = STATUS_INVALID_PARAMETER; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } else { DeviceExtension->ImmediateCharIrp = Irp; ++DeviceExtension->PendingWriteCount; // DAG-TX-EMPTY //++DeviceExtension->PendingWriteCountTxEmpty; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CompleteThisRequest = FALSE; status = CprSerialStartImmediate(DeviceExtension); break; // return CprSerialStartImmediate(DeviceExtension); } } break; // The IOCTL_SERIAL_PURGE request cancels the specified requests and deletes data from the specified buffers. // The purge request can be used to cancel all read requests and write requests and to delete all data from the read buffer and the write buffer. // The completion of the purge request does not indicate that the requests canceled by the purge request are completed. // A client must verify that the purged requests are completed before the client frees or reuses the corresponding IRPs. case IOCTL_SERIAL_PURGE: { ULONG mask; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_PURGE"); IoLogType = CPR_ET_IOCTL_PURGE; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } mask = *(PULONG)Irp->AssociatedIrp.SystemBuffer; if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "Mask 0x%08X: TxAbort %s, RxAbort %s, TxClear %s, RxClear %s", mask, (mask & SERIAL_PURGE_TXABORT) ? "Yes" : "No", (mask & SERIAL_PURGE_RXABORT) ? "Yes" : "No", (mask & SERIAL_PURGE_TXCLEAR) ? "Yes" : "No", (mask & SERIAL_PURGE_RXCLEAR) ? "Yes" : "No" ); } if ((mask == 0) || (mask & ~(SERIAL_PURGE_TXABORT | SERIAL_PURGE_RXABORT | SERIAL_PURGE_TXCLEAR | SERIAL_PURGE_RXCLEAR))) { status = STATUS_INVALID_PARAMETER; break; } CompleteThisRequest = FALSE; status = CprQueueIrp(&DeviceExtension->PurgeQueue, Irp, TRUE); if (status == STATUS_CONNECTION_INVALID) status = STATUS_SUCCESS; break; } break; // The IOCTL_SERIAL_GET_HANDFLOW request returns information about the configuration of the handshake flow control set for a COM port. case IOCTL_SERIAL_GET_HANDFLOW: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_HANDFLOW"); IoLogType = CPR_ET_IOCTL_GET_HANDFLOW; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(SERIAL_HANDFLOW); CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); *((PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer) = DeviceExtension->SerialHandFlow; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { SetFlowMsg(DeviceExtension, Msg, sizeof(Msg)); } } break; // The IOCTL_SERIAL_SET_HANDFLOW request sets the configuration of handshake flow control. // Serial verifies the specified handshake flow control information. case IOCTL_SERIAL_SET_HANDFLOW: { PSERIAL_HANDFLOW handFlow; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_SET_HANDFLOW"); IoLogType = CPR_ET_IOCTL_SET_HANDFLOW; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) { status = STATUS_BUFFER_TOO_SMALL; break; } handFlow = (PSERIAL_HANDFLOW)Irp->AssociatedIrp.SystemBuffer; if (handFlow->ControlHandShake & SERIAL_CONTROL_INVALID) { status = STATUS_INVALID_PARAMETER; break; } if (handFlow->FlowReplace & SERIAL_FLOW_INVALID) { status = STATUS_INVALID_PARAMETER; break; } if ((handFlow->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK) { status = STATUS_INVALID_PARAMETER; break; } if ((handFlow->XonLimit < 0) || ((ULONG)handFlow->XonLimit > DeviceExtension->QueueSize)) { status = STATUS_INVALID_PARAMETER; break; } if ((handFlow->XoffLimit < 0) || ((ULONG)handFlow->XoffLimit > DeviceExtension->QueueSize)) { status = STATUS_INVALID_PARAMETER; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if (DeviceExtension->EscapeChar) { if (handFlow->FlowReplace & SERIAL_ERROR_CHAR) { status = STATUS_INVALID_PARAMETER; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); CprDecrementIoCount(&DeviceExtension->IoLock); break; } } CprSerialSetHandFlow(DeviceExtension, handFlow); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { SetFlowMsg(DeviceExtension, Msg, sizeof(Msg)); } CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_MODEMSTATUS request updates the modem status, and returns // the value of the modem status register before the update. case IOCTL_SERIAL_GET_MODEMSTATUS: { ULONG modemStatus; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_MODEMSTATUS"); IoLogType = CPR_ET_IOCTL_GET_MODEM_STATUS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } Irp->IoStatus.Information = sizeof(ULONG); CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); modemStatus = CprSerialHandleModemUpdate(DeviceExtension, FALSE); *(PULONG)Irp->AssociatedIrp.SystemBuffer = modemStatus; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "DCTS %d, DDSR %d, TERI %d, DDCD %d, CTS %d, DSR %d, RI %d, DCD %d", (modemStatus & CPR_UART_MSR_DCTS) ? 1 : 0, (modemStatus & CPR_UART_MSR_DDSR) ? 1 : 0, (modemStatus & CPR_UART_MSR_TERI) ? 1 : 0, (modemStatus & CPR_UART_MSR_DDCD) ? 1 : 0, (modemStatus & CPR_UART_MSR_CTS) ? 1 : 0, (modemStatus & CPR_UART_MSR_DSR) ? 1 : 0, (modemStatus & CPR_UART_MSR_RI) ? 1 : 0, (modemStatus & CPR_UART_MSR_DCD) ? 1 : 0); } CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_DTRRTS request returns information about the data terminal // ready control signal (DTR) and the request to send control signal (RTS). case IOCTL_SERIAL_GET_DTRRTS: { ULONG ModemControl; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_DTRRTS"); IoLogType = CPR_ET_IOCTL_GET_DTRRTS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } status = CprCheckIoLock(&DeviceExtension->IoLock, Irp); if (!NT_SUCCESS(status) || (status == STATUS_PENDING)) { CprDebugPrint2(DeviceExtension, DBG_IOCTL, DBG_WARN, __FUNCTION__"--. IRP %p STATUS 0x%X", Irp, status); CompleteThisRequest = FALSE; break; //return status; } Irp->IoStatus.Information = sizeof(ULONG); ModemControl = CprUartReadMCR(&DeviceExtension->Uart); ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE; *(PULONG)Irp->AssociatedIrp.SystemBuffer = ModemControl; CprDecrementIoCount(&DeviceExtension->IoLock); } break; // The IOCTL_SERIAL_GET_COMMSTATUS request returns information about the communication status of a COM port. case IOCTL_SERIAL_GET_COMMSTATUS: { PSERIAL_STATUS serialStatus; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_COMMSTATUS"); //RequestLineState(DeviceExtension); IoLogType = CPR_ET_IOCTL_GET_COMM_STATUS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) { status = STATUS_BUFFER_TOO_SMALL; break; } serialStatus = (PSERIAL_STATUS)Irp->AssociatedIrp.SystemBuffer; CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); //#ifdef BUFFER_STATE // if (DeviceExtension->PendingWriteCount && DeviceExtension->BufferStatePending == FALSE) // { // DeviceExtension->BufferStatePending = TRUE; // DbgPrint("Sending TNCAS_NOTIFY_BUFFERSTATE\n"); // CprRfc2217_SendCPCByteCommand(DeviceExtension, TNCAS_NOTIFY_BUFFERSTATE, 0); // CprRfc2217_SendToNet(DeviceExtension, TRUE); // } //#endif serialStatus->Errors = DeviceExtension->ErrorWord; DeviceExtension->ErrorWord = 0; serialStatus->EofReceived = FALSE; serialStatus->AmountInInQueue = DeviceExtension->ReadCount; serialStatus->AmountInOutQueue = DeviceExtension->PendingWriteCount; //serialStatus->AmountInOutQueue = DeviceExtension->PendingWriteCountTxEmpty; #ifdef __WRITE_LENGTH__ if (DeviceExtension->WriteLength) { ASSERT(DeviceExtension->WriteQueue.CurrentIrp != NULL); if (DeviceExtension->WriteQueue.CurrentIrp != NULL) { //ASSERT(IoGetCurrentIrpStackLocation(DeviceExtension->WriteQueue.CurrentIrp) != NULL); serialStatus->AmountInOutQueue -= IoGetCurrentIrpStackLocation(DeviceExtension->WriteQueue.CurrentIrp)->Parameters.Write.Length - (DeviceExtension->WriteLength); } } #endif serialStatus->WaitForImmediate = DeviceExtension->TxImmediate; serialStatus->HoldReasons = 0; if (DeviceExtension->TxStopReason) { if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_CTS) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_CTS; } if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_DSR) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_DSR; } if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_DCD) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_DCD; } if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_XOFF) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_FOR_XON; } if (DeviceExtension->TxStopReason & CPR_SERIAL_TX_BREAK) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_ON_BREAK; } } if (DeviceExtension->RxStopReason & CPR_SERIAL_RX_DSR) { serialStatus->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR; } if (DeviceExtension->RxStopReason & CPR_SERIAL_RX_XOFF) { serialStatus->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT; } #ifdef CPR_DBG_PRINT DbgPrint("Errors %d WaitForImmediate %d AmountInInQueue %d\n", serialStatus->Errors, serialStatus->WaitForImmediate, serialStatus->AmountInInQueue); DbgPrint("AmountInOutQueue %d EofReceived %d HoldReasons 0x%08X\n", serialStatus->AmountInOutQueue, serialStatus->EofReceived, serialStatus->HoldReasons); #endif CprDebugPrint3(DeviceExtension, DBG_IOCTL, DBG_INFO, "Errors %d WaitForImmediate %d AmountInInQueue %d", serialStatus->Errors, serialStatus->WaitForImmediate, serialStatus->AmountInInQueue); CprDebugPrint3(DeviceExtension, DBG_IOCTL, DBG_INFO, "AmountInOutQueue %d EofReceived %d HoldReasons 0x%08X", serialStatus->AmountInOutQueue, serialStatus->EofReceived, serialStatus->HoldReasons); if (LoggingEvent) { RtlStringCchPrintfA( Msg, sizeof(Msg), "Err %d WaitImm %d InQue %d OutQue %d EOF %d Hold 0x%X", serialStatus->Errors, serialStatus->WaitForImmediate, serialStatus->AmountInInQueue, serialStatus->AmountInOutQueue, DeviceExtension->PendingWriteCount, serialStatus->EofReceived, serialStatus->HoldReasons); } CprReleaseSerialSpinLock(DeviceExtension, oldIrql); Irp->IoStatus.Information = sizeof(SERIAL_STATUS); } break; // The IOCTL_SERIAL_GET_PROPERTIES request returns information about the capabilities of a COM port. case IOCTL_SERIAL_GET_PROPERTIES: { PSERIAL_COMMPROP serialProp; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_PROPERTIES"); IoLogType = CPR_ET_IOCTL_GET_PROPERTIES; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_COMMPROP)) { status = STATUS_BUFFER_TOO_SMALL; break; } serialProp = (PSERIAL_COMMPROP)Irp->AssociatedIrp.SystemBuffer; RtlZeroMemory(serialProp, sizeof(SERIAL_COMMPROP)); //***************************************************************** //***************************************************************** // TODO: modify to match device properties //***************************************************************** //***************************************************************** serialProp->PacketLength = sizeof(SERIAL_COMMPROP); serialProp->PacketVersion = 2; serialProp->ServiceMask = SERIAL_SP_SERIALCOMM; serialProp->MaxTxQueue = 0; serialProp->MaxRxQueue = 0; serialProp->MaxBaud = SERIAL_BAUD_USER; serialProp->SettableBaud = SERIAL_BAUD_USER | SERIAL_BAUD_075 | SERIAL_BAUD_110 | SERIAL_BAUD_134_5 | SERIAL_BAUD_150 | SERIAL_BAUD_300 | SERIAL_BAUD_600 | SERIAL_BAUD_1200 | SERIAL_BAUD_1800 | SERIAL_BAUD_2400 | SERIAL_BAUD_4800 | SERIAL_BAUD_7200 | SERIAL_BAUD_9600 | SERIAL_BAUD_14400 | SERIAL_BAUD_19200 | SERIAL_BAUD_38400 | SERIAL_BAUD_56K | SERIAL_BAUD_57600 | SERIAL_BAUD_115200 | SERIAL_BAUD_128K; serialProp->ProvSubType = SERIAL_SP_RS232; serialProp->ProvCapabilities = SERIAL_PCF_DTRDSR | SERIAL_PCF_RTSCTS | SERIAL_PCF_CD | SERIAL_PCF_PARITY_CHECK | SERIAL_PCF_XONXOFF | SERIAL_PCF_SETXCHAR | SERIAL_PCF_TOTALTIMEOUTS | SERIAL_PCF_INTTIMEOUTS; serialProp->SettableParams = SERIAL_SP_PARITY | SERIAL_SP_BAUD | SERIAL_SP_DATABITS | SERIAL_SP_STOPBITS | SERIAL_SP_HANDSHAKING | SERIAL_SP_PARITY_CHECK | SERIAL_SP_CARRIER_DETECT; serialProp->SettableData = SERIAL_DATABITS_5 | SERIAL_DATABITS_6 | SERIAL_DATABITS_7 | SERIAL_DATABITS_8; serialProp->SettableStopParity = SERIAL_STOPBITS_10 | SERIAL_STOPBITS_15 | SERIAL_STOPBITS_20 | SERIAL_PARITY_NONE | SERIAL_PARITY_ODD | SERIAL_PARITY_EVEN | SERIAL_PARITY_MARK | SERIAL_PARITY_SPACE; serialProp->CurrentTxQueue = 0; serialProp->CurrentRxQueue = DeviceExtension->QueueSize; if (LoggingEvent) { RtlStringCchPrintfA(Msg, sizeof(Msg), "0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X", serialProp->PacketLength, serialProp->PacketVersion, serialProp->ServiceMask, serialProp->MaxTxQueue, serialProp->MaxRxQueue, serialProp->MaxBaud, serialProp->SettableBaud, serialProp->ProvSubType, serialProp->ProvCapabilities, serialProp->SettableParams, serialProp->SettableData, serialProp->SettableStopParity, serialProp->CurrentTxQueue, serialProp->CurrentRxQueue); } Irp->IoStatus.Information = sizeof(SERIAL_COMMPROP); } break; // The IOCTL_SERIAL_XOFF_COUNTER request sets an XOFF counter. An XOFF counter request // supports clients that use software to emulate hardware handshake flow control. // An XOFF counter request is synchronized with write requests. The driver sends a specified XOFF character, // and completes the request after one of the following events occurs: // 1) A write request is received. // 2) A timer expires (a timeout value is specified by the XOFF counter request). // 3) Serial receives a number of characters that is greater than or equal to a count specified by the XOFF counter request. case IOCTL_SERIAL_XOFF_COUNTER: { PSERIAL_XOFF_COUNTER xoffCounter; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_XOFF_COUNTER"); IoLogType = CPR_ET_IOCTL_XOFF_COUNTER; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_XOFF_COUNTER)) { status = STATUS_BUFFER_TOO_SMALL; break; } xoffCounter = (PSERIAL_XOFF_COUNTER)Irp->AssociatedIrp.SystemBuffer; if (xoffCounter->Counter <= 0) { status = STATUS_INVALID_PARAMETER; break; } Irp->IoStatus.Information = 0; CompleteThisRequest = FALSE; status = CprQueueIrp(&DeviceExtension->WriteQueue, Irp, TRUE); break; } break; // The IOCTL_SERIAL_LSRMST_INSERT request enables or disables the insertion of information about line status // and modem status in the receive data stream. If LSRMST insertion is enabled, the driver inserts event // information for the supported event types. The event information includes an event header followed by // event-specific data. The event header contains a client-specified escape character and a flag that identifies // the event. The driver supports the following event types: // SERIAL_LSRMST_LSR_DATA // A change occurred in the line status. Serial inserts an event header followed by the event-specific data, // which is the value of the line status register followed by the character present in the receive hardware // when the line-status change was processed. // SERIAL_LSRMST_LSR_NODATA // A line status change occurred, but no data was available in the receive buffer. Serial inserts an // event header followed by the event-specific data, which is the value of the line status register // when the line status change was processed. // SERIAL_LSRMST_MST // A change occurred in the modem status. Serial inserts an event header followed by the event-specific // data, which is the value of the modem status register when the modem-status change was processed. // SERIAL_LSRMST_ESCAPE // Indicates that the next character in the receive data stream, which was received from the device, // is identical to the client-specified escape character. Serial inserts an event header. There is // no event-specific data. case IOCTL_SERIAL_LSRMST_INSERT: { PUCHAR escapeChar; CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_LSRMST_INSERT"); // IoLogType = CPR_ET_IOCTL_LSRMST_INSERT; if (irpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(UCHAR)) { status = STATUS_BUFFER_TOO_SMALL; break; } escapeChar = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); if (*escapeChar) { if ((*escapeChar == DeviceExtension->SerialChars.XoffChar) || (*escapeChar == DeviceExtension->SerialChars.XonChar) || (DeviceExtension->SerialHandFlow.FlowReplace & SERIAL_ERROR_CHAR)) { status = STATUS_INVALID_PARAMETER; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); break; } } DeviceExtension->EscapeChar = *escapeChar; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } break; // The IOCTL_SERIAL_CONFIG_SIZE request returns information about configuration size. case IOCTL_SERIAL_CONFIG_SIZE: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_CONFIG_SIZE"); if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) { status = STATUS_BUFFER_TOO_SMALL; break; } Irp->IoStatus.Information = sizeof(ULONG); *(PULONG)Irp->AssociatedIrp.SystemBuffer = 0; } break; // The IOCTL_SERIAL_GET_STATS request returns information about the performance of a COM port. // The statistics include the number of characters transmitted, the number of characters received, // and useful error statistics. The driver continuously increments performance values. case IOCTL_SERIAL_GET_STATS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_GET_STATS"); IoLogType = CPR_ET_IOCTL_GET_STATS; if (irpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) { status = STATUS_BUFFER_TOO_SMALL; break; } CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); *(PSERIALPERF_STATS)Irp->AssociatedIrp.SystemBuffer = DeviceExtension->SerialStats; CprReleaseSerialSpinLock(DeviceExtension, oldIrql); Irp->IoStatus.Information = sizeof(SERIALPERF_STATS); } break; // The IOCTL_SERIAL_CLEAR_STATS request clears the performance statistics for a COM port. case IOCTL_SERIAL_CLEAR_STATS: { CprDebugPrint(DeviceExtension, DBG_IOCTL, DBG_INFO, "IOCTL_SERIAL_CLEAR_STATS"); CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); RtlZeroMemory(&DeviceExtension->SerialStats, sizeof(SERIALPERF_STATS)); RtlZeroMemory(&DeviceExtension->WmiPerfData, sizeof(SERIAL_WMI_PERF_DATA)); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } break; default: status = STATUS_INVALID_PARAMETER; break; } if (Msg[0] != '\0') sendMsg = Msg; CprLogEvent( CPR_EVENT_TYPE_NONE, IoLogType, DeviceExtension, status, sendMsg); if (CompleteThisRequest == TRUE) { Irp->IoStatus.Status = status; IoCompleteRequest (Irp, IO_NO_INCREMENT); } return status; }