// waitmask.c // // // Requires DDK Only // File created on 2/2/2005 // #include "pch.h" #ifdef CPR_WMI_TRACE #include "waitmask.tmh" #endif /////////////////////////////////////////////////////////////////////////////////////////////////// // MaskQueueStartIo // StartIo routine for WriteQueue IRP queue, processes serialized // requests // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The WriteQueue IRP to process // // Return Value: // None // VOID MaskQueueStartIo( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension; NTSTATUS status; PIO_STACK_LOCATION irpStack; PIRP waitIrp; KIRQL oldIrql; // Get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++. IRP %p", Irp); irpStack = IoGetCurrentIrpStackLocation(Irp); if (irpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_SET_WAIT_MASK) { //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // if there is an outstanding IOCTL_SERIAL_WAIT_ON_MASK Irp, complete it if (deviceExtension->IrpWaitMask != NULL) { *deviceExtension->IrpWaitMask = 0; deviceExtension->IrpWaitMask = NULL; CprDebugPrint2(deviceExtension, DBG_IO, DBG_INFO, "MaskQueueStartIo: Releasing previous Wait Irp %p Events 0x%08X", deviceExtension->WaitIrp, deviceExtension->WaitEvents); deviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&deviceExtension->WaitCompleteDpc, NULL, NULL); } // save new wait mask deviceExtension->WaitMask = *(PULONG)Irp->AssociatedIrp.SystemBuffer; // mask off events we are not interested in deviceExtension->WaitEvents &= deviceExtension->WaitMask; // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { // check if wait mask is zero or we already have IOCTL_SERIAL_WAIT_ON_MASK Irp if ((deviceExtension->WaitMask == 0) || (deviceExtension->WaitIrp != NULL)) { Irp->IoStatus.Status = STATUS_INVALID_PARAMETER; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { //ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // check if some events already happened if (deviceExtension->WaitEvents != 0) { CprDebugPrint2(deviceExtension, DBG_IO, DBG_INFO, "MaskQueueStartIo: Releasing Wait Irp %p Events 0x%08X", deviceExtension->WaitIrp, deviceExtension->WaitEvents); *(PULONG)Irp->AssociatedIrp.SystemBuffer = deviceExtension->WaitEvents; deviceExtension->WaitEvents = 0; // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); Irp->IoStatus.Information = sizeof(ULONG); Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { deviceExtension->WaitIrpRef = 0; IoSetCancelRoutine(Irp, CprCancelWaitMask); if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL)) { // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } else { deviceExtension->WaitIrpRef |= CPR_IRPREF_CANCEL; deviceExtension->WaitIrp = Irp; deviceExtension->IrpWaitMask = (PULONG)Irp->AssociatedIrp.SystemBuffer; deviceExtension->WaitIrpRef |= CPR_IRPREF_IO; CprDebugPrint2(deviceExtension, DBG_IO, DBG_INFO, "MaskQueueStartIo: Queueing Wait App Irp %p Mask %08X", Irp, deviceExtension->IrpWaitMask); // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); } } } } CprStartNext(&deviceExtension->MaskQueue); CprDebugPrint1(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--. IRP %p", Irp); return; } VOID MaskQueueStatusChange( IN PDEVICE_OBJECT DeviceObject, ULONG QueueIrpStatus ) { } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialStopWaitMask // Stops outstanding wait on mask request // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // VOID CprSerialStopWaitMask( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++"); if (DeviceExtension->IrpWaitMask != NULL) { *DeviceExtension->IrpWaitMask = 0; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); DeviceExtension->WaitIrpRef &= ~CPR_IRPREF_IO; } CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCancelWaitMask // Cancel routine for outstanding wait on mask request // // Arguments: // IN DeviceObject // Device object for our device // // IN Irp // The IOCTL_SERIAL_WAIT_ON_MASK IRP to cancel // // Return Value: // None // VOID CprCancelWaitMask( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) { PCPR_DEVICE_EXTENSION deviceExtension; KIRQL oldIrql; BOOLEAN complete; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)DeviceObject->DeviceExtension; CprDebugPrint1(deviceExtension, DBG_IO, DBG_WARN, __FUNCTION__"++. IRP %p", Irp); // drop global cancel lock IoReleaseCancelSpinLock(Irp->CancelIrql); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // mark that cancel routine has run deviceExtension->WaitIrpRef &= ~CPR_IRPREF_CANCEL; // try to stop wait on mask io CprSerialStopWaitMask(deviceExtension); // check if we are done with this immediate char irp if (deviceExtension->WaitIrpRef == 0) { complete = TRUE; deviceExtension->WaitIrp = NULL; } else { complete = FALSE; } CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (complete) { Irp->IoStatus.Status = STATUS_CANCELLED; IoCompleteRequest(Irp, IO_NO_INCREMENT); } CprDebugPrint(deviceExtension, DBG_IO, DBG_WARN, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprSerialWaitComplete // wait on mask completion request callback // // Arguments: // IN Dpc // WaitCompleteDpc // // IN Context // our device extension // // IN Unused1 // unused // // IN Unused2 // unused // // Return Value: // None // VOID CprSerialWaitComplete( IN PKDPC Dpc, IN PVOID Context, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PCPR_DEVICE_EXTENSION deviceExtension; PIRP irp; BOOLEAN complete; KIRQL oldIrql; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprDebugPrint(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++"); // ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); // CprAcquireSerialSpinLockAtDpcLevel(deviceExtension); CprAcquireSerialSpinLock(deviceExtension, &oldIrql); // record the fact that io is completed deviceExtension->WaitIrpRef &= ~CPR_IRPREF_IO; irp = deviceExtension->WaitIrp; // try to remove cancel routine if (irp && deviceExtension->WaitIrpRef & CPR_IRPREF_CANCEL) { if (IoSetCancelRoutine(irp, NULL)) { deviceExtension->WaitIrpRef &= ~CPR_IRPREF_CANCEL; } } // check that we are done with this wait irp if (deviceExtension->WaitIrpRef == 0) { complete = TRUE; deviceExtension->WaitIrp = NULL; } else { complete = FALSE; } // CprReleaseSerialSpinLockFromDpcLevel(deviceExtension); CprReleaseSerialSpinLock(deviceExtension, oldIrql); if (complete) { CprDebugPrint1(deviceExtension, DBG_IO, DBG_INFO, "CprSerialWaitComplete: Releasing Wait App Irp %p", irp); if (irp) { irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(irp, IO_NO_INCREMENT); } } CprDebugPrint(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } /////////////////////////////////////////////////////////////////////////////////////////////////// // CprCheckForEmptyTransmitEvent // Checks for empty transmit event // // Arguments: // IN DeviceExtension // our device extension // // Return Value: // None // VOID CprCheckForEmptyTransmitEvent( IN PCPR_DEVICE_EXTENSION DeviceExtension ) { BOOLEAN releaseWait = FALSE; BOOLEAN releaseIrp = FALSE; CprDebugPrint3(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++ PendingWriteCount %d CurIrp %p IsListEmpty %d", DeviceExtension->PendingWriteCount, DeviceExtension->WriteQueue.CurrentIrp, IsListEmpty(&DeviceExtension->WriteQueue.IrpQueue)); if ((DeviceExtension->WriteQueue.CurrentIrp == NULL) && IsListEmpty(&DeviceExtension->WriteQueue.IrpQueue)) { if (DeviceExtension->PendingWriteCount == 0) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" Setting \n"); #endif DeviceExtension->WaitEvents |= SERIAL_EV_TXEMPTY; CprDebugPrint(DeviceExtension, DBG_IO, DBG_INFO, "CprCheckForEmptyTransmitEvent: Set WaitEvents 0x%08X", DeviceExtension->WaitEvents); if ((DeviceExtension->WaitMask & SERIAL_EV_TXEMPTY) && (DeviceExtension->IrpWaitMask != NULL)) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" Releasing Tx Empty\n"); #endif CprLogEvent( CPR_EVENT_TYPE_WAIT_TXEMPTY, CPR_EVENT_SUB_TYPE_NONE, DeviceExtension, STATUS_SUCCESS, NULL); *DeviceExtension->IrpWaitMask = DeviceExtension->WaitEvents; DeviceExtension->IrpWaitMask = NULL; DeviceExtension->WaitEvents = 0; CprDebugPrint2(DeviceExtension, DBG_IO, DBG_INFO, "CprCheckForEmptyTransmitEvent: Releasing Wait Irp %p Events 0x%08X", DeviceExtension->WaitIrp, DeviceExtension->WaitEvents); DeviceExtension->WaitIrp->IoStatus.Information = sizeof(ULONG); KeInsertQueueDpc(&DeviceExtension->WaitCompleteDpc, NULL, NULL); } } else if (DeviceExtension->UseRFC2217 && (DeviceExtension->TransmitEmpty == TX_EMPTY_SERVER) && (DeviceExtension->TxEmptyRef == CPR_TXEMPTY_CLEAR)) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" Starting Tx Empty Timer. Pending %d\n", DeviceExtension->PendingWriteCount); #endif CprDebugPrint1(DeviceExtension, DBG_IO, DBG_INFO, __FUNCTION__": Starting Tx Empty Timer. Pending %d", DeviceExtension->PendingWriteCount); DeviceExtension->TxEmptyWaitCount = 0; DeviceExtension->TxEmptyRef = CPR_TXEMPTY_DPC; DeviceExtension->TxEmptyCurrentTimeout = DeviceExtension->TxEmptyInitTimeout; KeSetTimer( &DeviceExtension->TxEmptyTimer, DeviceExtension->TxEmptyCurrentTimeout, &DeviceExtension->TxEmptyDpc); } } CprDebugPrint(DeviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); return; } VOID CprTxEmptyCheck( IN PKDPC Dpc, IN PVOID Context, IN PVOID SystemContext1, IN PVOID SystemContext2 ) { PCPR_DEVICE_EXTENSION deviceExtension; PIRP irp; BOOLEAN complete; KIRQL oldIrql; // get our device extension deviceExtension = (PCPR_DEVICE_EXTENSION)Context; CprAcquireSerialSpinLock(deviceExtension, &oldIrql); #ifdef BUFFER_STATE if (deviceExtension->BufferStatePending == FALSE) { deviceExtension->BufferStatePending = TRUE; DbgPrint("Sending TNCAS_NOTIFY_BUFFERSTATE\n"); CprRfc2217_SendCPCByteCommand(deviceExtension, TNCAS_NOTIFY_BUFFERSTATE, 0); CprRfc2217_SendToNet(deviceExtension, FALSE); } deviceExtension->TxEmptyCurrentTimeout = deviceExtension->TxEmptyInitTimeout; KeSetTimer( &deviceExtension->TxEmptyTimer, deviceExtension->TxEmptyCurrentTimeout, &deviceExtension->TxEmptyDpc); //if (deviceExtension->IsDeviceEnabled && // (deviceExtension->TxEmptyRef == CPR_TXEMPTY_DPC) && // deviceExtension->socket && // (deviceExtension->WriteLength == 0) && // IsListEmpty(&deviceExtension->WriteQueue.IrpQueue) && // (deviceExtension->WriteQueue.CurrentIrp == NULL) && // (deviceExtension->PendingWriteCount != 0)) //{ // RequestLineState(deviceExtension); //} #else #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"++ Ena %d Flg %d Soc %p WLen %d MT %d Irp %p Pend %d\n", deviceExtension->IsDeviceEnabled, deviceExtension->TxEmptyRef, deviceExtension->socket, deviceExtension->WriteLength, IsListEmpty(&deviceExtension->WriteQueue.IrpQueue), deviceExtension->WriteQueue.CurrentIrp, deviceExtension->PendingWriteCount); #endif CprDebugPrint3(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"++ Pending %d Count %d Ref %d", deviceExtension->TxEmptyVerifyPending, deviceExtension->TxEmptyWaitCount, deviceExtension->TxEmptyRef); if (deviceExtension->IsDeviceEnabled && (deviceExtension->TxEmptyRef == CPR_TXEMPTY_DPC) && deviceExtension->socket && (deviceExtension->WriteLength == 0) && IsListEmpty(&deviceExtension->WriteQueue.IrpQueue) && (deviceExtension->WriteQueue.CurrentIrp == NULL) && (deviceExtension->PendingWriteCount != 0)) { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" Setting Timer\n"); #endif RequestLineState(deviceExtension); // Note that these values are negative due to the timeout values // being relative. So a timeout value that is more negative // will last longer. // timeout value sequence should be: // 10, 20, 40, 80, 160, 320, 640, 1000, 1000... ms // if (RtlLargeIntegerLessThan(deviceExtension->TxEmptyTimeout, deviceExtension->TxEmptyCurrentTimeout)) { deviceExtension->TxEmptyCurrentTimeout = RtlLargeIntegerAdd(deviceExtension->TxEmptyCurrentTimeout, deviceExtension->TxEmptyCurrentTimeout); } if (RtlLargeIntegerGreaterThan(deviceExtension->TxEmptyTimeout, deviceExtension->TxEmptyCurrentTimeout)) { deviceExtension->TxEmptyCurrentTimeout = deviceExtension->TxEmptyTimeout; } KeSetTimer( &deviceExtension->TxEmptyTimer, deviceExtension->TxEmptyCurrentTimeout, &deviceExtension->TxEmptyDpc); } else { #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__" NOT SettingTimer\n"); #endif deviceExtension->TxEmptyRef = CPR_TXEMPTY_CLEAR; } #endif CprReleaseSerialSpinLock(deviceExtension, oldIrql); #ifdef CPR_DBG_PRINT DbgPrint(__FUNCTION__"--\n"); #endif CprDebugPrint(deviceExtension, DBG_IO, DBG_TRACE, __FUNCTION__"--"); }