예제 #1
0
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;
  }
}
예제 #2
0
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);
  }
}
예제 #3
0
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);
}
예제 #4
0
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);
}
예제 #5
0
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;
}
예제 #6
0
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;
}