VOID ShiftQueue(PC0C_IRP_QUEUE pQueue) { if (pQueue->pCurrent) { PC0C_IRP_STATE pState; pState = GetIrpState(pQueue->pCurrent); HALT_UNLESS(pState); pQueue->pCurrent = NULL; pState->flags &= ~C0C_IRP_FLAG_IS_CURRENT; } if (!IsListEmpty(&pQueue->queue)) { PC0C_IRP_STATE pState; PIRP pIrp; PLIST_ENTRY pListEntry; pListEntry = RemoveHeadList(&pQueue->queue); pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry); pState = GetIrpState(pIrp); HALT_UNLESS(pState); pQueue->pCurrent = pIrp; pState->flags &= ~C0C_IRP_FLAG_IN_QUEUE; pState->flags |= C0C_IRP_FLAG_IS_CURRENT; } }
VOID FdoPortCompleteQueue(IN PLIST_ENTRY pQueueToComplete) { while (!IsListEmpty(pQueueToComplete)) { PIRP pIrp; PC0C_IRP_STATE pState; PLIST_ENTRY pListEntry; PIO_STACK_LOCATION pIrpStack; pListEntry = RemoveHeadList(pQueueToComplete); pIrp = CONTAINING_RECORD(pListEntry, IRP, Tail.Overlay.ListEntry); pIrpStack = IoGetCurrentIrpStackLocation(pIrp); if (pIrp->IoStatus.Status == STATUS_TIMEOUT && pIrp->IoStatus.Information && pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER) { pIrp->IoStatus.Status = STATUS_SERIAL_COUNTER_TIMEOUT; } TraceIrp("complete", pIrp, &pIrp->IoStatus.Status, TRACE_FLAG_RESULTS); pState = GetIrpState(pIrp); HALT_UNLESS(pState); if (pState->iQueue == C0C_QUEUE_WRITE) { KIRQL oldIrql; PC0C_IO_PORT pIoPort; pIoPort = FDO_PORT_TO_IO_PORT(IoGetCurrentIrpStackLocation(pIrp)->DeviceObject); KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql); pIoPort->amountInWriteQueue -= GetWriteLength(pIrp) - (ULONG)pIrp->IoStatus.Information; KeReleaseSpinLock(pIoPort->pIoLock, oldIrql); } if (pIrp->IoStatus.Status == STATUS_CANCELLED || (pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && (pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR || pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER))) { pIrp->IoStatus.Information = 0; } IoCompleteRequest(pIrp, IO_SERIAL_INCREMENT); } }
VOID TimeoutRoutine( PC0C_IO_PORT pIoPort, IN PC0C_IRP_QUEUE pQueue) { LIST_ENTRY queueToComplete; KIRQL oldIrql; InitializeListHead(&queueToComplete); KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql); if (pQueue->pCurrent) { PC0C_IRP_STATE pState; pState = GetIrpState(pQueue->pCurrent); HALT_UNLESS(pState); pState->flags |= C0C_IRP_FLAG_EXPIRED; switch (pState->iQueue) { case C0C_QUEUE_WRITE: ReadWrite(pIoPort->pIoPortRemote, FALSE, pIoPort, FALSE, &queueToComplete); break; case C0C_QUEUE_READ: ReadWrite(pIoPort, FALSE, pIoPort->pIoPortRemote, FALSE, &queueToComplete); break; case C0C_QUEUE_CLOSE: FdoPortIo(C0C_IO_TYPE_CLOSE_COMPLETE, NULL, pIoPort, &pIoPort->irpQueues[C0C_QUEUE_CLOSE], &queueToComplete); break; } } KeReleaseSpinLock(pIoPort->pIoLock, oldIrql); FdoPortCompleteQueue(&queueToComplete); }
VOID CancelRoutine(IN PDEVICE_OBJECT pDevObj, IN PIRP pIrp) { LIST_ENTRY queueToComplete; PC0C_IO_PORT pIoPort; PC0C_IRP_STATE pState; KIRQL oldIrql; PC0C_IRP_QUEUE pQueue; IoReleaseCancelSpinLock(pIrp->CancelIrql); pIoPort = FDO_PORT_TO_IO_PORT(pDevObj); pState = GetIrpState(pIrp); HALT_UNLESS(pState); pQueue = &pIoPort->irpQueues[pState->iQueue]; InitializeListHead(&queueToComplete); KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql); if (pState->flags & C0C_IRP_FLAG_IN_QUEUE) { RemoveEntryList(&pIrp->Tail.Overlay.ListEntry); pState->flags &= ~C0C_IRP_FLAG_IN_QUEUE; } pIrp->IoStatus.Status = STATUS_CANCELLED; InsertTailList(&queueToComplete, &pIrp->Tail.Overlay.ListEntry); if (pState->flags & C0C_IRP_FLAG_IS_CURRENT) { ShiftQueue(pQueue); if (pState->iQueue == C0C_QUEUE_WRITE) ReadWrite(pIoPort->pIoPortRemote, FALSE, pIoPort, FALSE, &queueToComplete); } KeReleaseSpinLock(pIoPort->pIoLock, oldIrql); FdoPortCompleteQueue(&queueToComplete); }
NTSTATUS FdoPortStartIrp( IN PC0C_IO_PORT pIoPort, IN PIRP pIrp, IN UCHAR iQueue, IN PC0C_FDOPORT_START_ROUTINE pStartRoutine) { NTSTATUS status; LIST_ENTRY queueToComplete; KIRQL oldIrql; PC0C_IRP_QUEUE pQueue; PC0C_IRP_STATE pState; InitializeListHead(&queueToComplete); pState = GetIrpState(pIrp); HALT_UNLESS(pState); pState->flags = 0; pState->iQueue = iQueue; pQueue = &pIoPort->irpQueues[iQueue]; KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql); #pragma warning(push, 3) IoSetCancelRoutine(pIrp, CancelRoutine); #pragma warning(pop) if (pIrp->Cancel) { status = NoPending(pIrp, STATUS_CANCELLED); } else { if (!pQueue->pCurrent) { status = StartIrp(pIoPort, pIrp, pState, pQueue, &queueToComplete, pStartRoutine); } else { PIO_STACK_LOCATION pIrpStack; PIO_STACK_LOCATION pCurrentStack; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); pCurrentStack = IoGetCurrentIrpStackLocation(pQueue->pCurrent); if (pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) { status = NoPending(pIrp, STATUS_INVALID_PARAMETER); } else if (pIrpStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && pIrpStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) { if (pCurrentStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && pCurrentStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR) { status = NoPending(pIrp, STATUS_INVALID_PARAMETER); } else { PC0C_IRP_STATE pCurrentState; pCurrentState = GetIrpState(pQueue->pCurrent); HALT_UNLESS(pCurrentState); pCurrentState->flags &= ~C0C_IRP_FLAG_IS_CURRENT; InsertHeadList(&pQueue->queue, &pQueue->pCurrent->Tail.Overlay.ListEntry); pCurrentState->flags |= C0C_IRP_FLAG_IN_QUEUE; status = StartIrp(pIoPort, pIrp, pState, pQueue, &queueToComplete, pStartRoutine); } } else { InsertTailList(&pQueue->queue, &pIrp->Tail.Overlay.ListEntry); pState->flags |= C0C_IRP_FLAG_IN_QUEUE; if (pState->iQueue == C0C_QUEUE_WRITE) { pIoPort->amountInWriteQueue += GetWriteLength(pIrp); } if (pCurrentStack->MajorFunction == IRP_MJ_DEVICE_CONTROL && pCurrentStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_XOFF_COUNTER && pQueue->pCurrent->IoStatus.Information) { if (pIrpStack->MajorFunction == IRP_MJ_FLUSH_BUFFERS) { RemoveEntryList(&pIrp->Tail.Overlay.ListEntry); pState->flags &= ~C0C_IRP_FLAG_IN_QUEUE; status = NoPending(pIrp, STATUS_SUCCESS); } else { PIRP pIrpXoffCounter = pQueue->pCurrent; ShiftQueue(pQueue); CompleteIrp(pIrpXoffCounter, STATUS_SERIAL_MORE_WRITES, &queueToComplete); status = StartIrp(pIoPort, pIrp, pState, pQueue, &queueToComplete, pStartRoutine); } } else { pIrp->IoStatus.Status = STATUS_PENDING; IoMarkIrpPending(pIrp); status = STATUS_PENDING; } } } } KeReleaseSpinLock(pIoPort->pIoLock, oldIrql); FdoPortCompleteQueue(&queueToComplete); return status; }
NTSTATUS SetReadTimeout(PC0C_IO_PORT pIoPort, PIRP pIrp) { SERIAL_TIMEOUTS timeouts; BOOLEAN setTotal; ULONG multiplier; ULONG constant; PC0C_IRP_STATE pState; KeCancelTimer(&pIoPort->timerReadTotal); KeCancelTimer(&pIoPort->timerReadInterval); pState = GetIrpState(pIrp); HALT_UNLESS(pState); timeouts = pIoPort->timeouts; if (timeouts.ReadIntervalTimeout == MAXULONG && !timeouts.ReadTotalTimeoutMultiplier && !timeouts.ReadTotalTimeoutConstant) { return STATUS_SUCCESS; } setTotal = FALSE; multiplier = 0; constant = 0; if (timeouts.ReadIntervalTimeout == MAXULONG && timeouts.ReadTotalTimeoutMultiplier == MAXULONG && timeouts.ReadTotalTimeoutConstant < MAXULONG && timeouts.ReadTotalTimeoutConstant > 0) { if (pIrp->IoStatus.Information) { return STATUS_SUCCESS; } pState->flags |= C0C_IRP_FLAG_WAIT_ONE; setTotal = TRUE; multiplier = 0; constant = timeouts.ReadTotalTimeoutConstant; } else { if (timeouts.ReadTotalTimeoutMultiplier || timeouts.ReadTotalTimeoutConstant) { setTotal = TRUE; multiplier = timeouts.ReadTotalTimeoutMultiplier; constant = timeouts.ReadTotalTimeoutConstant; } if (timeouts.ReadIntervalTimeout) { pState->flags |= C0C_IRP_FLAG_INTERVAL_TIMEOUT; pIoPort->timeoutInterval.QuadPart = ((LONGLONG)timeouts.ReadIntervalTimeout + pIoPort->addRITO) * -10000; if (pIrp->IoStatus.Information) SetIntervalTimeout(pIoPort); } } if (setTotal) { LARGE_INTEGER total; ULONG length; length = IoGetCurrentIrpStackLocation(pIrp)->Parameters.Read.Length; total.QuadPart = ((LONGLONG)( UInt32x32To64(length, multiplier) + constant + pIoPort->addRTTO)) * -10000; KeSetTimer( &pIoPort->timerReadTotal, total, &pIoPort->timerReadTotalDpc); } return STATUS_PENDING; }