// LV_read.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "read.tmh" #endif #define RETURN_READ_PHASE void FillMsgBuf(char *msg, char *buf, int amountToWrite); /////////////////////////////////////////////////////////////////////////////////////////////////// // CprReadDispatch // Handled incoming read requests // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The read IRP to handle // // Return Value: // NT status code // NTSTATUS CprReadDispatch( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension; NTSTATUS status; POWER_STATE powerState; PIO_STACK_LOCATION irpStack; //LARGE_INTEGER li; ULONG readLength; __try { //li = KeQueryPerformanceCounter(NULL); deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; //CprDebugPrint2(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p TICKS %I64X", Irp, li.QuadPart); CprDebugPrint1(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); // check the device error condition status = CprCheckForError(deviceExtension, Irp); if (!NT_SUCCESS(status)) { status = STATUS_CONNECTION_DISCONNECTED; Irp->IoStatus.Status = status; IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } Irp->IoStatus.Information = 0; irpStack = IoGetCurrentIrpStackLocation(Irp); readLength = irpStack->Parameters.Read.Length; if (readLength != 0) { if (deviceExtension->OpenHandleCount == 0) { status = STATUS_CONNECTION_DISCONNECTED; Irp->IoStatus.Status = status; IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); return status; } else { if ((deviceExtension->ListenMode == LISTEN_MODE_NONE) && (deviceExtension->NetworkStatus != CPR_NETWORK_STATUS_CONNECTED) && (deviceExtension->IsDeviceEnabled || deviceExtension->NoDiscon)) { // if ((deviceExtension->AutoReconErr) && (deviceExtension->Reconnecting == FALSE)) if ((deviceExtension->AutoReconErr) && (deviceExtension->NetworkStatus != CPR_NETWORK_STATUS_RECONNECTING)) { CprDebugPrint(deviceExtension, DBG_WRITE | DBG_IO, DBG_INFO, "Calling CprTdiStartReconnect"); CprTdiStartReconnect(deviceExtension); } if (deviceExtension->NetworkStatus != CPR_NETWORK_STATUS_CONNECTED) { status = STATUS_CONNECTION_DISCONNECTED; Irp->IoStatus.Status = status; IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); //CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"$$. IRP %p STATUS %x TICKS %I64X", Irp, status, li.QuadPart); CprDebugPrint2(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"$$. IRP %p STATUS %x", Irp, status); return status; } } CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_INFO, "Queueing Read App Irp 0x%08X Buf 0x%08X Len %d", Irp, Irp->AssociatedIrp.SystemBuffer, readLength); #ifdef RETURN_READ_PHASE deviceExtension->ReturnReadPhase = 55; #endif status = CprQueueIrp(&deviceExtension->ReadQueue, Irp, TRUE); // if (Irp->IoStatus.Status != STATUS_PENDING) // if ( !Irp->PendingReturned ) //if (status != STATUS_PENDING) //{ // IoSetCancelRoutine(Irp, NULL); // IoCompleteRequest(Irp, IO_NO_INCREMENT); //} #ifdef RETURN_READ_PHASE if ((deviceExtension->ReturnReadPhase == 99) || (deviceExtension->ReturnReadPhase == 77)) { CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_INFO, "ReturnReadPhase: %d, # bytes %d, Len %d\n", deviceExtension->ReturnReadPhase, Irp->IoStatus.Information, deviceExtension->ReadLength); status = STATUS_SUCCESS; //Irp->IoStatus.Status = status; //IoCompleteRequest(Irp, IO_NO_INCREMENT); } #endif if (LoggingEvent) { char msg[CPR_EVENT_MSG_SIZE]; if (status == STATUS_SUCCESS) { FillMsgBuf( msg, Irp->AssociatedIrp.SystemBuffer, (int)Irp->IoStatus.Information); _CprLogEvent( CPR_EVENT_TYPE_READ, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, status, msg); } else { RtlStringCchPrintfA(msg, sizeof(msg), "Request for %d bytes", readLength); _CprLogEvent( CPR_EVENT_TYPE_READ_REQUEST, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, status, msg); if (deviceExtension->ReturnReadPhase == 77) { FillMsgBuf( msg, NULL, 0); _CprLogEvent( CPR_EVENT_TYPE_PENDED_READ_RELEASED, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, STATUS_SUCCESS, msg); } } } #ifdef RETURN_READ_PHASE deviceExtension->ReturnReadPhase = 0; #endif } if (status != STATUS_PENDING) { Irp->IoStatus.Status = status; IoClearIrpPending( Irp ); IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); } } else { status = STATUS_SUCCESS; if (LoggingEvent) { char msg[CPR_EVENT_MSG_SIZE]; RtlStringCchPrintfA(msg, sizeof(msg), "Request for 0 bytes"); _CprLogEvent( CPR_EVENT_TYPE_READ_REQUEST, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, status, msg); } Irp->IoStatus.Status = status; IoClearIrpPending( Irp ); IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); } //li = KeQueryPerformanceCounter(NULL); //CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x TICKS %I64X", Irp, status, li.QuadPart); CprDebugPrint2(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p STATUS %x", Irp, status); } __except( EXCEPTION_EXECUTE_HANDLER ) { status = STATUS_INTERNAL_ERROR; // CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"-- Exception. IRP %p STATUS %x TICKS %I64X", Irp, status, li.QuadPart); CprDebugPrint2(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"-- Exception. IRP %p STATUS %x", Irp, status); } return status; } /////////////////////////////////////////////////////////////////////////////////////////////////// // ReadQueueStartIo // StartIo routine for ReadQueue IRP queue, processes serialized // requests // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The ReadQueue IRP to process // // Return Value: // None // VOID ReadQueueStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension; PIO_STACK_LOCATION irpStack; PVOID newBuffer; SERIAL_TIMEOUTS timeouts; BOOLEAN setIntervalTimer; BOOLEAN setTimer; BOOLEAN pendingDataRead; BOOLEAN os2ssreturn; BOOLEAN crunchDownToOne; LARGE_INTEGER totalTime; KIRQL oldIrql; void FillMsgBuf(char *msg, char *buf, int amountToWrite); // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); irpStack = IoGetCurrentIrpStackLocation(Irp); if (irpStack->MajorFunction != IRP_MJ_READ) { // this is IOCTL_SERIAL_SET_QUEUE_SIZE IRP CprSerialResizeBuffer(deviceExtension, Irp); CprStartNext(&deviceExtension->ReadQueue); IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { deviceExtension->ReadLength = irpStack->Parameters.Read.Length; CprDebugPrint1(deviceExtension, DBG_READ | DBG_IO, DBG_INFO, "*** READ REQUEST of %d", deviceExtension->ReadLength); timeouts = deviceExtension->Timeouts; // check if we have valid interval timeout if (timeouts.ReadIntervalTimeout && (timeouts.ReadIntervalTimeout != MAXULONG)) { setIntervalTimer = TRUE; deviceExtension->IntervalTime.QuadPart = UInt32x32To64(timeouts.ReadIntervalTimeout, 10000); if (deviceExtension->IntervalTime.QuadPart >= deviceExtension->CutOverAmount.QuadPart) { deviceExtension->IntervalTimeToUse = &deviceExtension->LongIntervalAmount; } else { deviceExtension->IntervalTimeToUse = &deviceExtension->ShortIntervalAmount; } } else { setIntervalTimer = FALSE; } // check if we need to set read timeout setTimer = FALSE; pendingDataRead = FALSE; os2ssreturn = FALSE; crunchDownToOne = FALSE; if (timeouts.ReadIntervalTimeout == MAXULONG) { if ((timeouts.ReadTotalTimeoutConstant == 0) && (timeouts.ReadTotalTimeoutMultiplier == 0)) { pendingDataRead = TRUE; } else if ((timeouts.ReadTotalTimeoutConstant != MAXULONG) && (timeouts.ReadTotalTimeoutMultiplier != MAXULONG)) { setTimer = TRUE; totalTime.QuadPart = (UInt32x32To64(deviceExtension->ReadLength, timeouts.ReadTotalTimeoutMultiplier) + timeouts.ReadTotalTimeoutConstant) * 10000; totalTime = RtlLargeIntegerNegate(totalTime); os2ssreturn = TRUE; } else if ((timeouts.ReadTotalTimeoutConstant != MAXULONG) && (timeouts.ReadTotalTimeoutMultiplier == MAXULONG)) { setTimer = TRUE; totalTime.QuadPart = timeouts.ReadTotalTimeoutConstant * 10000; totalTime = RtlLargeIntegerNegate(totalTime); os2ssreturn = TRUE; crunchDownToOne = TRUE; } } else { if (timeouts.ReadTotalTimeoutMultiplier || timeouts.ReadTotalTimeoutConstant) { setTimer = TRUE; totalTime.QuadPart = (UInt32x32To64(deviceExtension->ReadLength, timeouts.ReadTotalTimeoutMultiplier) + timeouts.ReadTotalTimeoutConstant) * 10000; totalTime = RtlLargeIntegerNegate(totalTime); } } CprAcquireSerialSpinLock(deviceExtension, &oldIrql); CprSerialGetCharsFromIntBuffer(deviceExtension); #ifdef RETURN_READ_PHASE if (Irp->IoStatus.Information && (deviceExtension->ReturnReadPhase == 55)) { // We got the data directly and still on user thread, we will complete // the read from CprReadDispatch deviceExtension->ReturnReadPhase = 99; deviceExtension->ReadQueue.CurrentIrp = NULL; // we need to just complete the read irp IoClearIrpPending( Irp ); Irp->IoStatus.Status = STATUS_SUCCESS; os2ssreturn = TRUE; } else { deviceExtension->ReturnReadPhase = 0; } #endif if (pendingDataRead || (deviceExtension->ReadLength == 0) || (os2ssreturn && Irp->IoStatus.Information)) { CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprStartNext(&deviceExtension->ReadQueue); CprDebugPrint5(deviceExtension, DBG_READ | DBG_IO, DBG_INFO, "Releasing (Int) Read App Irp 0x%08X Buf 0x%08X Info %d Pend %d Len %d", Irp, Irp->AssociatedIrp.SystemBuffer, Irp->IoStatus.Information, pendingDataRead, deviceExtension->ReadLength); #ifdef RETURN_READ_PHASE if (deviceExtension->ReturnReadPhase != 99) #endif deviceExtension->ReturnReadPhase = 77; } else { if (crunchDownToOne) { deviceExtension->ReadLength = 1; irpStack->Parameters.Read.Length = 1; } deviceExtension->ReadIrpRef = 0; IoSetCancelRoutine(Irp, CprSerialCancelCurrentRead); if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) { CprReleaseSerialSpinLock(deviceExtension, oldIrql); CprStartNext(&deviceExtension->ReadQueue); if (LoggingEvent) { char msg[CPR_EVENT_MSG_SIZE]; FillMsgBuf( msg, NULL, 0); _CprLogEvent( CPR_EVENT_TYPE_PENDED_READ_RELEASED, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, STATUS_CANCELLED, msg); } Irp->IoStatus.Status = STATUS_CANCELLED; Irp->IoStatus.Information = 0; IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { deviceExtension->ReadIrpRef |= CPR_IRPREF_CANCEL; // switch from our queue buffer to IRP_MJ_READ buffer deviceExtension->ReadBuffer = (PUCHAR)Irp->AssociatedIrp.SystemBuffer; deviceExtension->ReadCharLast = deviceExtension->ReadBuffer + Irp->IoStatus.Information; deviceExtension->ReadBufferEnd = deviceExtension->ReadBuffer + irpStack->Parameters.Read.Length - 1; deviceExtension->ReadIrpRef |= CPR_IRPREF_IO; // initialize interval read counters deviceExtension->IntervalReadCount = (LONG)Irp->IoStatus.Information; deviceExtension->LastReadCount = 0; if (setIntervalTimer) { KeQuerySystemTime(&deviceExtension->LastReadTime); KeSetTimer(&deviceExtension->ReadIntervalTimer, *deviceExtension->IntervalTimeToUse, &deviceExtension->ReadIntervalTimeoutDpc); deviceExtension->ReadIrpRef |= CPR_IRPREF_INTERVAL; } if (setTimer) { KeSetTimer(&deviceExtension->ReadTimer, totalTime, &deviceExtension->ReadTimeoutDpc); deviceExtension->ReadIrpRef |= CPR_IRPREF_TIMER; } CprReleaseSerialSpinLock(deviceExtension, oldIrql); } } } CprDebugPrint1(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p", Irp); return; } VOID ReadQueueStatusChange( IN PDEVICE_OBJECT DeviceObject, ULONG QueueIrpStatus ) { } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialGetCharsFromIntBuffer // copy characters from our read queue // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprSerialGetCharsFromIntBuffer( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { PIRP irp; PIO_STACK_LOCATION irpStack; ULONG count; ULONG countLast; irp = DeviceExtension->ReadQueue.CurrentIrp; if (irp) { irpStack = IoGetCurrentIrpStackLocation(irp); count = DeviceExtension->ReadCount; if (count > DeviceExtension->ReadLength) { count = DeviceExtension->ReadLength; } if (count != 0) { // // Read from end of circular buffer first // countLast = (ULONG)(DeviceExtension->ReadBufferEnd - DeviceExtension->ReadCharFirst) + 1; if (countLast > count) // how about the equal case????? { // // We have more data at the end than was requested. // Just read from the end and return. // RtlMoveMemory( (PUCHAR)irp->AssociatedIrp.SystemBuffer + irpStack->Parameters.Read.Length - DeviceExtension->ReadLength, DeviceExtension->ReadCharFirst, count ); //if (LoggingEvent) //{ // char msg[CPR_EVENT_MSG_SIZE]; // FillMsgBuf(msg, DeviceExtension->ReadCharFirst, count); // _CprLogEvent( // CPR_EVENT_TYPE_XFER_TO_APP_BUF, // CPR_EVENT_SUB_TYPE_NONE, // DeviceExtension, // STATUS_SUCCESS, // msg); //} DeviceExtension->ReadLength -= count; // // check if we reached the end of the read buffer and wrap if necessary // if ((DeviceExtension->ReadCharFirst + count - 1) == DeviceExtension->ReadBufferEnd) { DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer; } else { DeviceExtension->ReadCharFirst += count; } } else { // // We don't have enough data at the end of the circular // buffer to honor the whole read request. // Read what we can from the end first. // RtlMoveMemory( (PUCHAR)irp->AssociatedIrp.SystemBuffer + irpStack->Parameters.Read.Length - DeviceExtension->ReadLength, DeviceExtension->ReadCharFirst, countLast ); DeviceExtension->ReadLength -= countLast; RtlMoveMemory( (PUCHAR)irp->AssociatedIrp.SystemBuffer + irpStack->Parameters.Read.Length - DeviceExtension->ReadLength, DeviceExtension->QueueBuffer, count - countLast ); //if (LoggingEvent) //{ // char msg[CPR_EVENT_MSG_SIZE]; // FillMsgBuf( // msg, // (PUCHAR)irp->AssociatedIrp.SystemBuffer + irpStack->Parameters.Read.Length - (DeviceExtension->ReadLength + countLast), // count); // _CprLogEvent( // CPR_EVENT_TYPE_XFER_TO_APP_BUF, // CPR_EVENT_SUB_TYPE_NONE, // DeviceExtension, // STATUS_SUCCESS, // msg); //} DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer + (count - countLast); DeviceExtension->ReadLength -= (count - countLast); } } // DAG: Added to stop read overflows. 4/10/08 if ((DeviceExtension->ReadBuffer == DeviceExtension->QueueBuffer) && ((DeviceExtension->QueueSize - DeviceExtension->ReadCount) == 0)) { DeviceExtension->Uart.RxDataEvent = TRUE; CprUartCheckEvents(&DeviceExtension->Uart); } // DAG: End Add DeviceExtension->ReadCount -= count; irp->IoStatus.Information += count; } CprCheckForReceiveBufferChangedEvent(DeviceExtension); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialStopCurrentRead // Stops outstanding read io request // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // // Comment: // This method is called with SerialLock held // VOID CprSerialStopCurrentRead( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { PIRP irp; PIO_STACK_LOCATION irpStack; CprDebugPrint(DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // check if read io is still in progress if (DeviceExtension->ReadBuffer != DeviceExtension->QueueBuffer) { irp = DeviceExtension->ReadQueue.CurrentIrp; if (irp) { irpStack = IoGetCurrentIrpStackLocation(irp); irp->IoStatus.Information = irpStack->Parameters.Read.Length - (DeviceExtension->ReadBufferEnd - DeviceExtension->ReadCharLast + 1); } // Switch back to the interrupt buffer. DeviceExtension->ReadBuffer = DeviceExtension->QueueBuffer; DeviceExtension->ReadCharLast = DeviceExtension->QueueBuffer; DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer; DeviceExtension->ReadBufferEnd = DeviceExtension->QueueBuffer + (DeviceExtension->QueueSize - 1); DeviceExtension->ReadCount = 0; DeviceExtension->ReadIrpRef &= ~CPR_IRPREF_IO; } CprDebugPrint(DeviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialCancelCurrentRead // Cancel routine for outstanding read io request // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The ReadQueue IRP to cancel // // Return Value: // None // VOID CprSerialCancelCurrentRead( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; BOOLEAN atDispatch = FALSE; BOOLEAN startNext; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++"); // drop global cancel lock oldIrql = Irp->CancelIrql; IoReleaseCancelSpinLock(oldIrql); if (KeGetCurrentIrql() == DISPATCH_LEVEL) { atDispatch = TRUE; CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); } else { atDispatch = FALSE; CprAcquireSerialSpinLock(deviceExtension, &oldIrql); } // mark that cancel routine has run deviceExtension->ReadIrpRef &= ~CPR_IRPREF_CANCEL; deviceExtension->IntervalReadCount = CPR_COMPLETE_READ_CANCEL; // check if we set a timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_TIMER) { if (KeCancelTimer(&deviceExtension->ReadTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_TIMER; } } // check if we set an interval timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_INTERVAL) { if (KeCancelTimer(&deviceExtension->ReadIntervalTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_INTERVAL; } } // try to stop read io CprSerialStopCurrentRead(deviceExtension); // check we done with this read irp if (deviceExtension->ReadIrpRef == 0) { startNext = TRUE; } else { startNext = FALSE; } if (atDispatch == TRUE) { CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); } else { CprReleaseSerialSpinLock(deviceExtension, oldIrql); } if (startNext) { CprStartNext(&deviceExtension->ReadQueue); Irp->IoStatus.Status = STATUS_CANCELLED; IoSetCancelRoutine(Irp, NULL); IoCompleteRequest(Irp, IO_NO_INCREMENT); } CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialReadTimeout // Read request timeout callback // // Arguments: // IN Dpc // ReadTimeoutDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprSerialReadTimeout( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; PIRP irp; BOOLEAN startNext; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++"); //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); CprLogEvent( CPR_EVENT_TYPE_READ_TIMEOUT, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, STATUS_SUCCESS, NULL); // record the fact that timeout callback has run deviceExtension->ReadIrpRef &= ~CPR_IRPREF_TIMER; irp = deviceExtension->ReadQueue.CurrentIrp; deviceExtension->IntervalReadCount = CPR_COMPLETE_READ_TOTAL; // check if we set an interval timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_INTERVAL) { if (KeCancelTimer(&deviceExtension->ReadIntervalTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_INTERVAL; } } // try to remove cancel routine if (deviceExtension->ReadIrpRef & CPR_IRPREF_CANCEL) { if (irp && IoSetCancelRoutine(irp, NULL)) { deviceExtension->ReadIrpRef &= ~CPR_IRPREF_CANCEL; } } // try to stop read io CprSerialStopCurrentRead(deviceExtension); // check we done with this read irp if (deviceExtension->ReadIrpRef == 0) { startNext = TRUE; } else { startNext = FALSE; } // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (startNext) { CprStartNext(&deviceExtension->ReadQueue); if (irp) { irp->IoStatus.Status = STATUS_TIMEOUT; IoSetCancelRoutine(irp, NULL); IoCompleteRequest(irp, IO_NO_INCREMENT); } } CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialReadComplete // Read completion request callback // // Arguments: // IN Dpc // ReadCompleteDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprSerialReadComplete( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; PIRP irp; BOOLEAN startNext; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++"); //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); deviceExtension->ReadIrpRef &= ~CPR_IRPREF_IO; irp = deviceExtension->ReadQueue.CurrentIrp; deviceExtension->IntervalReadCount = CPR_COMPLETE_READ_COMPLETE; // check if we set a timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_TIMER) { if (KeCancelTimer(&deviceExtension->ReadTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_TIMER; } } // check if we set an interval timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_INTERVAL) { if (KeCancelTimer(&deviceExtension->ReadIntervalTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_INTERVAL; } } // try to remove cancel routine if (deviceExtension->ReadIrpRef & CPR_IRPREF_CANCEL) { if (irp && IoSetCancelRoutine(irp, NULL)) { deviceExtension->ReadIrpRef &= ~CPR_IRPREF_CANCEL; } } // check if we are done with this read irp if (deviceExtension->ReadIrpRef == 0) { startNext = TRUE; } else { startNext = FALSE; } // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (startNext) { CprStartNext(&deviceExtension->ReadQueue); if (irp) { CprDebugPrint3(deviceExtension, DBG_READ | DBG_IO, DBG_INFO, "Releasing Read App Irp 0x%08X Buf 0x%08X, Info %d", irp, irp->AssociatedIrp.SystemBuffer, irp->IoStatus.Information); if (LoggingEvent) { char msg[CPR_EVENT_MSG_SIZE]; FillMsgBuf( msg, irp->AssociatedIrp.SystemBuffer, (int)irp->IoStatus.Information); _CprLogEvent( CPR_EVENT_TYPE_PENDED_READ_RELEASED, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, STATUS_SUCCESS, msg); } irp->IoStatus.Status = STATUS_SUCCESS; IoSetCancelRoutine(irp, NULL); IoCompleteRequest(irp, IO_NO_INCREMENT); } } CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialReadIntervalTimeout // Read request timeout callback // // Arguments: // IN Dpc // ReadIntervalTimeoutDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprSerialReadIntervalTimeout( IN PKDPC Dpc, IN PVOID Context, IN PVOID Unused1, IN PVOID Unused2 ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; PIRP irp; BOOLEAN startNext; BOOLEAN cancelRead; LARGE_INTEGER currentTime; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"++"); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // record the fact that timeout callback has run deviceExtension->ReadIrpRef &= ~CPR_IRPREF_INTERVAL; irp = deviceExtension->ReadQueue.CurrentIrp; cancelRead = FALSE; if (deviceExtension->IntervalReadCount == CPR_COMPLETE_READ_TOTAL) { // total read timeout expired cancelRead = TRUE; if (irp) { irp->IoStatus.Status = STATUS_TIMEOUT; } } else if (deviceExtension->IntervalReadCount == CPR_COMPLETE_READ_COMPLETE) { // read completed successfully cancelRead = TRUE; if (irp) { irp->IoStatus.Status = STATUS_SUCCESS; } } else if (deviceExtension->IntervalReadCount == CPR_COMPLETE_READ_CANCEL) { // read is canceled cancelRead = TRUE; if (irp) { irp->IoStatus.Status = STATUS_CANCELLED; irp->IoStatus.Information = 0; } } else if (deviceExtension->IntervalReadCount || deviceExtension->LastReadCount) { if (deviceExtension->LastReadCount) { // we received new data during last interval deviceExtension->IntervalReadCount = deviceExtension->LastReadCount; deviceExtension->LastReadCount = 0; // rearm interval timer KeQuerySystemTime(&deviceExtension->LastReadTime); KeSetTimer(&deviceExtension->ReadIntervalTimer, *deviceExtension->IntervalTimeToUse, &deviceExtension->ReadIntervalTimeoutDpc); deviceExtension->ReadIrpRef |= CPR_IRPREF_INTERVAL; } else { KeQuerySystemTime(¤tTime); if ((currentTime.QuadPart - deviceExtension->LastReadTime.QuadPart) >= deviceExtension->IntervalTime.QuadPart) { // time is up cancelRead = TRUE; if (irp) { irp->IoStatus.Status = STATUS_TIMEOUT; } } else { // we still have some time left to read new data KeSetTimer(&deviceExtension->ReadIntervalTimer, *deviceExtension->IntervalTimeToUse, &deviceExtension->ReadIntervalTimeoutDpc); deviceExtension->ReadIrpRef |= CPR_IRPREF_INTERVAL; } } } else { // we have not read a single character yet, thus rearm the interval timer KeSetTimer(&deviceExtension->ReadIntervalTimer, *deviceExtension->IntervalTimeToUse, &deviceExtension->ReadIntervalTimeoutDpc); deviceExtension->ReadIrpRef |= CPR_IRPREF_INTERVAL; } if (cancelRead) { // check if we set a timer if (deviceExtension->ReadIrpRef & CPR_IRPREF_TIMER) { if (KeCancelTimer(&deviceExtension->ReadTimer)) { // timer is canceled deviceExtension->ReadIrpRef &= ~CPR_IRPREF_TIMER; } } // try to remove cancel routine if (deviceExtension->ReadIrpRef & CPR_IRPREF_CANCEL) { if (irp && IoSetCancelRoutine(irp, NULL)) { deviceExtension->ReadIrpRef &= ~CPR_IRPREF_CANCEL; } } // try to stop read io CprSerialStopCurrentRead(deviceExtension); } // check we done with this read irp if (deviceExtension->ReadIrpRef == 0) { startNext = TRUE; } else { startNext = FALSE; } // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (startNext) { CprStartNext(&deviceExtension->ReadQueue); if (irp) { if (LoggingEvent) { char msg[CPR_EVENT_MSG_SIZE]; FillMsgBuf( msg, irp->AssociatedIrp.SystemBuffer, (int)irp->IoStatus.Information); _CprLogEvent( CPR_EVENT_TYPE_PENDED_READ_RELEASED, CPR_EVENT_SUB_TYPE_NONE, deviceExtension, irp->IoStatus.Status, msg); } IoSetCancelRoutine(irp, NULL); IoCompleteRequest(irp, IO_NO_INCREMENT); } } CprDebugPrint(deviceExtension, DBG_READ | DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialResizeBuffer // Processes IOCTL_SERIAL_SET_QUEUE_SIZE IRP // // Arguments: // IN DeviceExtension // our device extension // // IN Irp // IOCTL_SERIAL_SET_QUEUE_SIZE IRP // // Return Value: // Status // NTSTATUS CprSerialResizeBuffer( IN PCPR_DEVICE_EXTENSION DeviceExtension, IN PIRP Irp ) { PIO_STACK_LOCATION irpStack; PSERIAL_QUEUE_SIZE queueSize; PUCHAR newBuffer; KIRQL oldIrql; ULONG count; ULONG countLast; irpStack = IoGetCurrentIrpStackLocation(Irp); queueSize = (PSERIAL_QUEUE_SIZE)Irp->AssociatedIrp.SystemBuffer; newBuffer = (PUCHAR)irpStack->Parameters.DeviceIoControl.Type3InputBuffer; irpStack->Parameters.DeviceIoControl.Type3InputBuffer = NULL; Irp->IoStatus.Information = 0; Irp->IoStatus.Status = STATUS_SUCCESS; if (queueSize->InSize <= DeviceExtension->QueueSize) { // queue size can only grow bigger ExFreePool(newBuffer); } else { CprAcquireSerialSpinLock(DeviceExtension, &oldIrql); // copy all the read characters to new buffer count = DeviceExtension->ReadCount; if (count) { countLast = (ULONG)(DeviceExtension->ReadBufferEnd - DeviceExtension->ReadCharFirst) + 1; if (countLast >= count) { RtlMoveMemory(newBuffer, DeviceExtension->ReadCharFirst, count); // check if we reached the end of the buffer if ((DeviceExtension->ReadCharFirst + (count - 1)) == DeviceExtension->ReadBufferEnd) { DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer; } else { DeviceExtension->ReadCharFirst += count; } } else { RtlMoveMemory(newBuffer, DeviceExtension->ReadCharFirst, countLast); RtlMoveMemory(newBuffer + countLast, DeviceExtension->QueueBuffer, count - countLast); DeviceExtension->ReadCharFirst = DeviceExtension->QueueBuffer + count - countLast; } } // free the old buffer if (DeviceExtension->QueueBuffer != NULL) { ExFreePool(DeviceExtension->QueueBuffer); } // switch to new buffer DeviceExtension->ReadBufferEnd = newBuffer + (queueSize->InSize - 1); DeviceExtension->ReadCharFirst = newBuffer; DeviceExtension->ReadBuffer = newBuffer; DeviceExtension->QueueBuffer = newBuffer; DeviceExtension->QueueSize = queueSize->InSize; DeviceExtension->ReadCharLast = DeviceExtension->QueueBuffer + DeviceExtension->ReadCount; DeviceExtension->SerialHandFlow.XoffLimit = DeviceExtension->QueueSize >> 3; DeviceExtension->SerialHandFlow.XonLimit = DeviceExtension->QueueSize >> 1; DeviceExtension->WmiCommData.XoffXmitThreshold = DeviceExtension->SerialHandFlow.XoffLimit; DeviceExtension->WmiCommData.XonXmitThreshold = DeviceExtension->SerialHandFlow.XonLimit; DeviceExtension->QueueSizePt8 = ((3*(DeviceExtension->QueueSize >> 2)) + (DeviceExtension->QueueSize >> 4)); CprCheckForReceiveBufferChangedEvent(DeviceExtension); CprReleaseSerialSpinLock(DeviceExtension, oldIrql); } return STATUS_SUCCESS; }