NTSTATUS StartIrp( PC0C_IO_PORT pIoPort, PIRP pIrp, PC0C_IRP_STATE pState, PC0C_IRP_QUEUE pQueue, PLIST_ENTRY pQueueToComplete, PC0C_FDOPORT_START_ROUTINE pStartRoutine) { NTSTATUS status; pQueue->pCurrent = pIrp; pState->flags |= C0C_IRP_FLAG_IS_CURRENT; if (pState->iQueue == C0C_QUEUE_WRITE) { ULONG length = GetWriteLength(pIrp); if (length) { pIoPort->amountInWriteQueue += length; UpdateTransmitToggle(pIoPort, pQueueToComplete); } } status = pStartRoutine(pIoPort, pQueueToComplete); if (status == STATUS_PENDING) { pIrp->IoStatus.Status = STATUS_PENDING; IoMarkIrpPending(pIrp); } else { status = NoPending(pIrp, status); if (status != STATUS_PENDING) { PIO_STACK_LOCATION pIrpStack; if (pState->iQueue == C0C_QUEUE_WRITE) { pIoPort->amountInWriteQueue -= GetWriteLength(pIrp) - (ULONG)pIrp->IoStatus.Information; } pIrpStack = IoGetCurrentIrpStackLocation(pIrp); if (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; } } if (pQueue->pCurrent == pIrp) ShiftQueue(pQueue); } return status; }
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); } }
NTSTATUS SetWriteTimeout(PC0C_IO_PORT pIoPort, PIRP pIrp) { SERIAL_TIMEOUTS timeouts; BOOLEAN setTotal; ULONG multiplier; ULONG constant; KeCancelTimer(&pIoPort->timerWriteTotal); timeouts = pIoPort->timeouts; setTotal = FALSE; multiplier = 0; constant = 0; if (timeouts.WriteTotalTimeoutMultiplier || timeouts.WriteTotalTimeoutConstant) { setTotal = TRUE; multiplier = timeouts.WriteTotalTimeoutMultiplier; constant = timeouts.WriteTotalTimeoutConstant; } if (setTotal) { LARGE_INTEGER total; ULONG length; length = GetWriteLength(pIrp); total.QuadPart = ((LONGLONG)(UInt32x32To64(length, multiplier) + constant)) * -10000; KeSetTimer( &pIoPort->timerWriteTotal, total, &pIoPort->timerWriteTotalDpc); } return STATUS_PENDING; }
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; }