Пример #1
0
VOID FdoPortCancelQueues(IN PC0C_IO_PORT pIoPort)
{
  LIST_ENTRY queueToComplete;
  KIRQL oldIrql;
  int i;

  InitializeListHead(&queueToComplete);
  KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql);

  for (i = 0 ; i < C0C_QUEUE_SIZE ; i++)
    CancelQueue(&pIoPort->irpQueues[i], &queueToComplete);

  KeReleaseSpinLock(pIoPort->pIoLock, oldIrql);
  FdoPortCompleteQueue(&queueToComplete);
}
Пример #2
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);
}
Пример #3
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);
}
Пример #4
0
NTSTATUS FdoPortClose(IN PC0C_FDOPORT_EXTENSION pDevExt, IN PIRP pIrp)
{
  NTSTATUS status;
  LIST_ENTRY queueToComplete;
  KIRQL oldIrql;
  PC0C_IO_PORT pIoPort;

  pIoPort = pDevExt->pIoPortLocal;

  pIoPort->isOpen = FALSE;

  if (pIoPort->pIoPortRemote->plugInMode)
    IoInvalidateDeviceRelations(pIoPort->pIoPortRemote->pPhDevObj, BusRelations);

  InitializeListHead(&queueToComplete);

  KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql);

  pIoPort->escapeChar = 0;
  pIoPort->writeHoldingRemote = 0;
  pIoPort->sendXonXoff = 0;
  SetModemControl(pIoPort, C0C_MCR_OUT2, C0C_MCR_MASK | C0C_MCR_OPEN, &queueToComplete);
  FreeBuffer(&pIoPort->readBuf);
  SetBreakHolding(pIoPort, FALSE, &queueToComplete);

  KeReleaseSpinLock(pIoPort->pIoLock, oldIrql);

  FdoPortCompleteQueue(&queueToComplete);

  status = FdoPortStartIrp(pIoPort, pIrp, C0C_QUEUE_CLOSE, StartIrpClose);

  if (status != STATUS_PENDING) {
    pIrp->IoStatus.Status = status;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  }

  return status;
}
Пример #5
0
NTSTATUS FdoPortIoCtl(
    IN PC0C_FDOPORT_EXTENSION pDevExt,
    IN PIRP pIrp)
{
    NTSTATUS status;
    PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
    ULONG code = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
    KIRQL oldIrql;
    PC0C_IO_PORT pIoPortLocal;

    pIrp->IoStatus.Information = 0;
    pIoPortLocal = pDevExt->pIoPortLocal;

    if ((pIoPortLocal->handFlow.ControlHandShake & SERIAL_ERROR_ABORT) &&
            pIoPortLocal->errors && code != IOCTL_SERIAL_GET_COMMSTATUS)
    {
        status = STATUS_CANCELLED;
    } else {
        status = STATUS_SUCCESS;

        switch (code) {
        case IOCTL_SERIAL_SET_RTS:
        case IOCTL_SERIAL_CLR_RTS:
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            switch (pIoPortLocal->handFlow.FlowReplace & SERIAL_RTS_MASK) {
            case SERIAL_RTS_HANDSHAKE:
            case SERIAL_TRANSMIT_TOGGLE:
                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                status = STATUS_INVALID_PARAMETER;
                break;
            default: {
                LIST_ENTRY queueToComplete;

                InitializeListHead(&queueToComplete);

                SetModemControl(
                    pIoPortLocal,
                    code == IOCTL_SERIAL_SET_RTS ? C0C_MCR_RTS : 0,
                    C0C_MCR_RTS,
                    &queueToComplete);

                if (pIoPortLocal->pIoPortRemote->tryWrite || pIoPortLocal->tryWrite) {
                    ReadWrite(
                        pIoPortLocal, FALSE,
                        pIoPortLocal->pIoPortRemote, FALSE,
                        &queueToComplete);
                }

                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                FdoPortCompleteQueue(&queueToComplete);
            }
            }
            break;
        case IOCTL_SERIAL_SET_DTR:
        case IOCTL_SERIAL_CLR_DTR:
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            switch (pIoPortLocal->handFlow.ControlHandShake & SERIAL_DTR_MASK) {
            case SERIAL_DTR_HANDSHAKE:
                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                status = STATUS_INVALID_PARAMETER;
                break;
            default: {
                LIST_ENTRY queueToComplete;

                InitializeListHead(&queueToComplete);

                SetModemControl(
                    pIoPortLocal,
                    code == IOCTL_SERIAL_SET_DTR ? C0C_MCR_DTR : 0,
                    C0C_MCR_DTR,
                    &queueToComplete);

                if (pIoPortLocal->pIoPortRemote->tryWrite || pIoPortLocal->tryWrite) {
                    ReadWrite(
                        pIoPortLocal, FALSE,
                        pIoPortLocal->pIoPortRemote, FALSE,
                        &queueToComplete);
                }

                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                FdoPortCompleteQueue(&queueToComplete);
            }
            }
            break;
        case IOCTL_SERIAL_SET_MODEM_CONTROL: {
            LIST_ENTRY queueToComplete;
            UCHAR mask;
            PUCHAR pSysBuf;
            ULONG InputBufferLength;

            InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

            if (InputBufferLength < sizeof(ULONG)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pSysBuf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;

            if (InputBufferLength >= (sizeof(ULONG) + sizeof(ULONG) + C0CE_SIGNATURE_SIZE) &&
                    RtlEqualMemory(pSysBuf + sizeof(ULONG) + sizeof(ULONG), C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE))
            {
                mask = C0C_MCR_MASK & (UCHAR)*((PULONG)pSysBuf + 1);
            } else {
                mask = C0C_MCR_MASK;
            }

            InitializeListHead(&queueToComplete);

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            SetModemControl(pIoPortLocal, (UCHAR)*(PULONG)pSysBuf, mask, &queueToComplete);

            if (pIoPortLocal->pIoPortRemote->tryWrite || pIoPortLocal->tryWrite) {
                ReadWrite(
                    pIoPortLocal, FALSE,
                    pIoPortLocal->pIoPortRemote, FALSE,
                    &queueToComplete);
            }

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_GET_MODEM_CONTROL:
        case IOCTL_SERIAL_GET_DTRRTS: {
            ULONG modemControl;
            PUCHAR pSysBuf;
            ULONG OutputBufferLength;

            OutputBufferLength = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;

            if (OutputBufferLength < sizeof(ULONG)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            modemControl = pIoPortLocal->modemControl;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);

            pSysBuf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;

            if (code == IOCTL_SERIAL_GET_DTRRTS) {
                modemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE;
                pIrp->IoStatus.Information = sizeof(ULONG);
            } else {
                ULONG InputBufferLength;

                InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

                if (OutputBufferLength >= (sizeof(ULONG) + C0CE_SIGNATURE_SIZE) &&
                        InputBufferLength >= C0CE_SIGNATURE_SIZE &&
                        RtlEqualMemory(pSysBuf, C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE))
                {
                    RtlCopyMemory(pSysBuf + sizeof(PULONG), C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE);

                    if (OutputBufferLength > (sizeof(ULONG) + C0CE_SIGNATURE_SIZE)) {
                        RtlZeroMemory(pSysBuf + sizeof(ULONG) + C0CE_SIGNATURE_SIZE,
                                      OutputBufferLength - (sizeof(ULONG) + C0CE_SIGNATURE_SIZE));
                    }

                    pIrp->IoStatus.Information = OutputBufferLength;
                } else {
                    pIrp->IoStatus.Information = sizeof(ULONG);
                }

                modemControl &= C0C_MCR_MASK;
            }

            *(PULONG)pSysBuf = modemControl;

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        }
        case IOCTL_SERIAL_SET_XON: {
            LIST_ENTRY queueToComplete;

            InitializeListHead(&queueToComplete);

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            SetXonXoffHolding(pIoPortLocal, C0C_XCHAR_ON);

            if (pIoPortLocal->tryWrite) {
                ReadWrite(
                    pIoPortLocal, FALSE,
                    pIoPortLocal->pIoPortRemote, FALSE,
                    &queueToComplete);
            }
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_SET_XOFF:
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            SetXonXoffHolding(pIoPortLocal, C0C_XCHAR_OFF);
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        case IOCTL_SERIAL_SET_BREAK_ON: {
            LIST_ENTRY queueToComplete;

            InitializeListHead(&queueToComplete);

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            SetBreakHolding(pIoPortLocal, TRUE, &queueToComplete);
            UpdateTransmitToggle(pIoPortLocal, &queueToComplete);

            ReadWrite(
                pIoPortLocal, FALSE,
                pIoPortLocal->pIoPortRemote, FALSE,
                &queueToComplete);

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_SET_BREAK_OFF: {
            LIST_ENTRY queueToComplete;

            InitializeListHead(&queueToComplete);

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            SetBreakHolding(pIoPortLocal, FALSE, &queueToComplete);
            UpdateTransmitToggle(pIoPortLocal, &queueToComplete);

            if (pIoPortLocal->tryWrite || pIoPortLocal->pIoPortRemote->tryWrite) {
                ReadWrite(
                    pIoPortLocal, FALSE,
                    pIoPortLocal->pIoPortRemote, FALSE,
                    &queueToComplete);
            }
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_GET_MODEMSTATUS:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PULONG)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->modemStatus;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            pIrp->IoStatus.Information = sizeof(ULONG);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_SET_WAIT_MASK:
            status = FdoPortSetWaitMask(pIoPortLocal, pIrp, pIrpStack);
            break;
        case IOCTL_SERIAL_GET_WAIT_MASK:
            status = FdoPortGetWaitMask(pIoPortLocal, pIrp, pIrpStack);
            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_WAIT_ON_MASK:
            status = FdoPortWaitOnMask(pIoPortLocal, pIrp, pIrpStack);
#if ENABLE_TRACING
            if (status == STATUS_SUCCESS)
                TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
#endif /* ENABLE_TRACING */
            break;
        case IOCTL_SERIAL_IMMEDIATE_CHAR:
            status = FdoPortImmediateChar(pIoPortLocal, pIrp, pIrpStack);
            break;
        case IOCTL_SERIAL_XOFF_COUNTER:
            status = FdoPortXoffCounter(pIoPortLocal, pIrp, pIrpStack);
            break;
        case IOCTL_SERIAL_PURGE: {
            LIST_ENTRY queueToComplete;
            PULONG pSysBuf;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(ULONG)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pSysBuf = (PULONG)pIrp->AssociatedIrp.SystemBuffer;

            if (*pSysBuf & ~(
                        SERIAL_PURGE_TXABORT |
                        SERIAL_PURGE_RXABORT |
                        SERIAL_PURGE_TXCLEAR |
                        SERIAL_PURGE_RXCLEAR
                    )) {
                status = STATUS_INVALID_PARAMETER;
                break;
            }

            InitializeListHead(&queueToComplete);
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            if (*pSysBuf & SERIAL_PURGE_RXABORT)
                CancelQueue(&pIoPortLocal->irpQueues[C0C_QUEUE_READ], &queueToComplete);

            if (*pSysBuf & SERIAL_PURGE_TXABORT)
                CancelQueue(&pIoPortLocal->irpQueues[C0C_QUEUE_WRITE], &queueToComplete);

            if (*pSysBuf & SERIAL_PURGE_RXCLEAR) {
                PurgeBuffer(&pIoPortLocal->readBuf);
                UpdateHandFlow(pIoPortLocal, TRUE, &queueToComplete);
                if (pIoPortLocal->tryWrite || pIoPortLocal->pIoPortRemote->tryWrite) {
                    ReadWrite(
                        pIoPortLocal, FALSE,
                        pIoPortLocal->pIoPortRemote, FALSE,
                        &queueToComplete);
                }
            }

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);

            break;
        }
        case IOCTL_SERIAL_GET_COMMSTATUS: {
            PSERIAL_STATUS pSysBuf;
            PIRP pIrpWrite;

            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_STATUS)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pSysBuf = (PSERIAL_STATUS)pIrp->AssociatedIrp.SystemBuffer;
            RtlZeroMemory(pSysBuf, sizeof(*pSysBuf));

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            pSysBuf->AmountInInQueue = (ULONG)C0C_BUFFER_BUSY(&pIoPortLocal->readBuf);

            pIrpWrite = pIoPortLocal->irpQueues[C0C_QUEUE_WRITE].pCurrent;

            if (pIrpWrite) {
                PIO_STACK_LOCATION pIrpStackWrite = IoGetCurrentIrpStackLocation(pIrpWrite);

                if (pIrpStackWrite->MajorFunction == IRP_MJ_DEVICE_CONTROL &&
                        pIrpStackWrite->Parameters.DeviceIoControl.IoControlCode == IOCTL_SERIAL_IMMEDIATE_CHAR)
                {
                    pSysBuf->WaitForImmediate = TRUE;
                }
            }

            pSysBuf->AmountInOutQueue = pIoPortLocal->amountInWriteQueue;
            pSysBuf->HoldReasons = pIoPortLocal->writeHolding;

            if ((pIoPortLocal->handFlow.ControlHandShake & SERIAL_DSR_SENSITIVITY) &&
                    (pIoPortLocal->modemStatus & C0C_MSB_DSR) == 0)
            {
                pSysBuf->HoldReasons |= SERIAL_RX_WAITING_FOR_DSR;
            }

            if (pIoPortLocal->writeHoldingRemote & SERIAL_TX_WAITING_FOR_XON)
                pSysBuf->HoldReasons |= SERIAL_TX_WAITING_XOFF_SENT;

            pSysBuf->Errors = pIoPortLocal->errors;
            pIoPortLocal->errors = 0;

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);

            pIrp->IoStatus.Information = sizeof(SERIAL_STATUS);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);

            break;
        }
        case IOCTL_SERIAL_SET_HANDFLOW: {
            LIST_ENTRY queueToComplete;
            PSERIAL_HANDFLOW pSysBuf;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_HANDFLOW)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pSysBuf = (PSERIAL_HANDFLOW)pIrp->AssociatedIrp.SystemBuffer;

            if (pSysBuf->ControlHandShake & SERIAL_CONTROL_INVALID ||
                    pSysBuf->FlowReplace & SERIAL_FLOW_INVALID ||
                    (pSysBuf->ControlHandShake & SERIAL_DTR_MASK) == SERIAL_DTR_MASK ||
                    pSysBuf->XonLimit < 0 ||
                    pSysBuf->XoffLimit < 0)
            {
                status = STATUS_INVALID_PARAMETER;
                break;
            }

            InitializeListHead(&queueToComplete);
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            status = SetHandFlow(pIoPortLocal, pSysBuf, &queueToComplete);

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_GET_HANDFLOW:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_HANDFLOW)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PSERIAL_HANDFLOW)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->handFlow;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            pIrp->IoStatus.Information = sizeof(SERIAL_HANDFLOW);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_SET_TIMEOUTS:
            status = FdoPortSetTimeouts(pIoPortLocal, pIrp, pIrpStack);
            break;
        case IOCTL_SERIAL_GET_TIMEOUTS:
            status = FdoPortGetTimeouts(pIoPortLocal, pIrp, pIrpStack);
            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_SET_CHARS: {
            PSERIAL_CHARS pSysBuf;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_CHARS)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pSysBuf = (PSERIAL_CHARS)pIrp->AssociatedIrp.SystemBuffer;

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            if (pIoPortLocal->escapeChar &&
                    ((pIoPortLocal->escapeChar == pSysBuf->XoffChar) ||
                     (pIoPortLocal->escapeChar == pSysBuf->XonChar)))
            {
                status = STATUS_INVALID_PARAMETER;
            }

            if (status == STATUS_SUCCESS)
                pIoPortLocal->specialChars = *pSysBuf;

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        }
        case IOCTL_SERIAL_GET_CHARS:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_CHARS)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PSERIAL_CHARS)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->specialChars;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);

            pIrp->IoStatus.Information = sizeof(SERIAL_CHARS);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_LSRMST_INSERT: {
            ULONG Information;
            ULONG optsAndBits;
            UCHAR escapeChar;
            PUCHAR pSysBuf;
            ULONG InputBufferLength;
            BOOLEAN extended;

            InputBufferLength = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;

            if (InputBufferLength < sizeof(UCHAR)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            Information = 0;
            pSysBuf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;
            escapeChar = *pSysBuf;

            if (InputBufferLength >= (sizeof(UCHAR) + C0CE_SIGNATURE_SIZE + sizeof(ULONG)) &&
                    RtlEqualMemory(pSysBuf + 1, C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE))
            {
                extended = TRUE;
                optsAndBits = *(ULONG *)(pSysBuf + 1 + C0CE_SIGNATURE_SIZE);

#define C0CE_INSERT_OPTS ( \
        C0CE_INSERT_IOCTL_GET| \
        C0CE_INSERT_IOCTL_RXCLEAR)

#define C0CE_INSERT_BITS ( \
        C0CE_INSERT_ENABLE_LSR| \
        C0CE_INSERT_ENABLE_MST| \
        C0CE_INSERT_ENABLE_RBR| \
        C0CE_INSERT_ENABLE_RLC| \
        C0CE_INSERT_ENABLE_LSR_BI)

#define C0CE_INSERT_CAPS (C0CE_INSERT_OPTS|C0CE_INSERT_BITS)

                if (optsAndBits == C0CE_INSERT_IOCTL_CAPS) {
                    optsAndBits = 0;

                    Information += C0CE_SIGNATURE_SIZE + sizeof(ULONG);

                    if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < Information) {
                        status = STATUS_BUFFER_TOO_SMALL;
                        break;
                    }

                    RtlCopyMemory(pSysBuf, C0CE_SIGNATURE, C0CE_SIGNATURE_SIZE);
                    *(ULONG *)(pSysBuf + C0CE_SIGNATURE_SIZE) = C0CE_INSERT_CAPS;
                } else {
                    if (optsAndBits & ~C0CE_INSERT_CAPS) {
                        status = STATUS_INVALID_PARAMETER;
                        break;
                    }

                    if (optsAndBits & C0CE_INSERT_IOCTL_GET) {
                        if (optsAndBits & (C0CE_INSERT_ENABLE_LSR|C0CE_INSERT_ENABLE_LSR_BI))
                            Information += sizeof(UCHAR)*2 + sizeof(UCHAR);
                        if (optsAndBits & C0CE_INSERT_ENABLE_MST)
                            Information += sizeof(UCHAR)*2 + sizeof(UCHAR);
                        if (optsAndBits & C0CE_INSERT_ENABLE_RBR)
                            Information += sizeof(UCHAR)*2 + sizeof(ULONG);
                        if (optsAndBits & C0CE_INSERT_ENABLE_RLC)
                            Information += sizeof(UCHAR)*2 + sizeof(UCHAR)*3;
                    }

                    if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < Information) {
                        status = STATUS_BUFFER_TOO_SMALL;
                        break;
                    }
                }
            } else {
                extended = FALSE;
                optsAndBits = (C0CE_INSERT_ENABLE_LSR|C0CE_INSERT_ENABLE_MST);
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            if (escapeChar && ((escapeChar == pIoPortLocal->specialChars.XoffChar) ||
                               (escapeChar == pIoPortLocal->specialChars.XonChar) ||
                               (pIoPortLocal->handFlow.FlowReplace & SERIAL_ERROR_CHAR)))
            {
                status = STATUS_INVALID_PARAMETER;
                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                break;
            }

            pIoPortLocal->insertMask = optsAndBits & C0CE_INSERT_BITS;
            pIoPortLocal->escapeChar = escapeChar;

            if (extended) {
                LIST_ENTRY queueToComplete;
                PC0C_IO_PORT pIoPortRemote;

                InitializeListHead(&queueToComplete);
                pIoPortRemote = pIoPortLocal->pIoPortRemote;

                if (optsAndBits & C0CE_INSERT_IOCTL_GET) {
                    if (optsAndBits & (C0CE_INSERT_ENABLE_LSR|C0CE_INSERT_ENABLE_LSR_BI)) {
                        UCHAR lsr = 0;

                        if (C0C_TX_BUFFER_THR_EMPTY(&pIoPortLocal->txBuf)) {
                            lsr |= 0x20;  /* transmit holding register empty */

                            if (C0C_TX_BUFFER_EMPTY(&pIoPortLocal->txBuf))
                                lsr |= 0x40;  /* transmit holding register empty and line is idle */
                        }

                        if ((optsAndBits & C0CE_INSERT_ENABLE_LSR_BI) != 0 && pIoPortLocal->rcvdBreak)
                            lsr |= 0x10;  /* break interrupt indicator */

                        *pSysBuf++ = escapeChar;
                        *pSysBuf++ = SERIAL_LSRMST_LSR_NODATA;
                        *pSysBuf++ = lsr;
                    }

                    if (optsAndBits & C0CE_INSERT_ENABLE_MST) {
                        *pSysBuf++ = escapeChar;
                        *pSysBuf++ = SERIAL_LSRMST_MST;
                        *pSysBuf++ = pIoPortLocal->modemStatus;
                    }

                    if (optsAndBits & C0CE_INSERT_ENABLE_RBR) {
                        *pSysBuf++ = escapeChar;
                        *pSysBuf++ = C0CE_INSERT_RBR;
                        *(ULONG *)pSysBuf = pIoPortRemote->baudRate.BaudRate;
                        pSysBuf += sizeof(ULONG);
                    }

                    if (optsAndBits & C0CE_INSERT_ENABLE_RLC) {
                        *pSysBuf++ = escapeChar;
                        *pSysBuf++ = C0CE_INSERT_RLC;
                        *pSysBuf++ = pIoPortRemote->lineControl.WordLength;
                        *pSysBuf++ = pIoPortRemote->lineControl.Parity;
                        *pSysBuf++ = pIoPortRemote->lineControl.StopBits;
                    }
                }

                pIrp->IoStatus.Information = Information;

                if (optsAndBits & C0CE_INSERT_IOCTL_RXCLEAR) {
                    PurgeBuffer(&pIoPortLocal->readBuf);
                    UpdateHandFlow(pIoPortLocal, TRUE, &queueToComplete);
                    if (pIoPortLocal->tryWrite || pIoPortRemote->tryWrite) {
                        ReadWrite(
                            pIoPortLocal, FALSE,
                            pIoPortRemote, FALSE,
                            &queueToComplete);
                    }
                }

                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                FdoPortCompleteQueue(&queueToComplete);

                TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
                break;
            }

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        }
        case IOCTL_SERIAL_SET_LINE_CONTROL: {
            PSERIAL_LINE_CONTROL pLineControl;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_LINE_CONTROL)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pLineControl = (PSERIAL_LINE_CONTROL)pIrp->AssociatedIrp.SystemBuffer;

            switch (pLineControl->WordLength) {
            case 5:
            case 6:
            case 7:
            case 8:
                break;
            default:
                status = STATUS_INVALID_PARAMETER;
            }

            switch (pLineControl->Parity) {
            case NO_PARITY:
            case ODD_PARITY:
            case EVEN_PARITY:
            case MARK_PARITY:
            case SPACE_PARITY:
                break;
            default:
                status = STATUS_INVALID_PARAMETER;
            }

            switch (pLineControl->StopBits) {
            case STOP_BIT_1:
            case STOP_BITS_1_5:
            case STOP_BITS_2:
                break;
            default:
                status = STATUS_INVALID_PARAMETER;
            }

            if (status == STATUS_INVALID_PARAMETER)
                break;

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            if (pIoPortLocal->lineControl.StopBits != pLineControl->StopBits ||
                    pIoPortLocal->lineControl.Parity != pLineControl->Parity ||
                    pIoPortLocal->lineControl.WordLength != pLineControl->WordLength)
            {
                PC0C_IO_PORT pIoPortRemote;

                pIoPortLocal->lineControl = *pLineControl;
                SetWriteDelay(pIoPortLocal);

                pIoPortRemote = pIoPortLocal->pIoPortRemote;

                if (pIoPortRemote->escapeChar && (pIoPortRemote->insertMask & C0CE_INSERT_ENABLE_RLC)) {
                    LIST_ENTRY queueToComplete;

                    InitializeListHead(&queueToComplete);

                    InsertRemoteLc(pIoPortRemote, &queueToComplete);

                    if (pIoPortLocal->pIoPortRemote->tryWrite || pIoPortLocal->tryWrite) {
                        ReadWrite(
                            pIoPortLocal, FALSE,
                            pIoPortLocal->pIoPortRemote, FALSE,
                            &queueToComplete);
                    }

                    KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                    FdoPortCompleteQueue(&queueToComplete);
                    break;
                }
            }
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        }
        case IOCTL_SERIAL_GET_LINE_CONTROL:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_LINE_CONTROL)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PSERIAL_LINE_CONTROL)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->lineControl;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            pIrp->IoStatus.Information = sizeof(SERIAL_LINE_CONTROL);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_SET_BAUD_RATE: {
            PSERIAL_BAUD_RATE pBaudRate;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_BAUD_RATE)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pBaudRate = (PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer;

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            if (pIoPortLocal->baudRate.BaudRate != pBaudRate->BaudRate) {
                PC0C_IO_PORT pIoPortRemote;

                pIoPortLocal->baudRate = *pBaudRate;
                SetWriteDelay(pIoPortLocal);

                pIoPortRemote = pIoPortLocal->pIoPortRemote;

                if (pIoPortRemote->escapeChar && (pIoPortRemote->insertMask & C0CE_INSERT_ENABLE_RBR)) {
                    LIST_ENTRY queueToComplete;

                    InitializeListHead(&queueToComplete);

                    InsertRemoteBr(pIoPortRemote, &queueToComplete);

                    if (pIoPortLocal->pIoPortRemote->tryWrite || pIoPortLocal->tryWrite) {
                        ReadWrite(
                            pIoPortLocal, FALSE,
                            pIoPortLocal->pIoPortRemote, FALSE,
                            &queueToComplete);
                    }

                    KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                    FdoPortCompleteQueue(&queueToComplete);
                    break;
                }
            }
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        }
        case IOCTL_SERIAL_GET_BAUD_RATE:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIAL_BAUD_RATE)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PSERIAL_BAUD_RATE)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->baudRate;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            pIrp->IoStatus.Information = sizeof(SERIAL_BAUD_RATE);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_GET_PROPERTIES: {
            ULONG size;

            status = GetCommProp(pDevExt,
                                 pIrp->AssociatedIrp.SystemBuffer,
                                 pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
                                 &size);

            if (status == STATUS_SUCCESS) {
                pIrp->IoStatus.Information = size;
                TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            }

            break;
        }
        case IOCTL_SERIAL_CONFIG_SIZE:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(ULONG)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }
            pIrp->IoStatus.Information = sizeof(ULONG);
            *(PULONG)pIrp->AssociatedIrp.SystemBuffer = 0;
            break;
        case IOCTL_SERIAL_SET_QUEUE_SIZE: {
            PSERIAL_QUEUE_SIZE pSysBuf = (PSERIAL_QUEUE_SIZE)pIrp->AssociatedIrp.SystemBuffer;
            LIST_ENTRY queueToComplete;
            PC0C_BUFFER pReadBuf;
            PUCHAR pBase;

            if (pIrpStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(SERIAL_QUEUE_SIZE)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            pReadBuf = &pIoPortLocal->readBuf;

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            if (pSysBuf->InSize <= C0C_BUFFER_SIZE(pReadBuf)) {
                KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
                break;
            }
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);

            try {
                pBase = C0C_ALLOCATE_POOL_WITH_QUOTA(NonPagedPool, pSysBuf->InSize);
            }
            except (EXCEPTION_EXECUTE_HANDLER) {
                pBase = NULL;
                status = GetExceptionCode();
            }

            if (!pBase)
                break;

            InitializeListHead(&queueToComplete);
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);

            if (SetNewBufferBase(pReadBuf, pBase, pSysBuf->InSize)) {
                pIoPortLocal->handFlow.XoffLimit = pSysBuf->InSize >> 3;
                pIoPortLocal->handFlow.XonLimit = pSysBuf->InSize >> 1;
                SetLimit(pIoPortLocal);
                UpdateHandFlow(pIoPortLocal, TRUE, &queueToComplete);
                if (pIoPortLocal->tryWrite || pIoPortLocal->pIoPortRemote->tryWrite) {
                    ReadWrite(
                        pIoPortLocal, FALSE,
                        pIoPortLocal->pIoPortRemote, FALSE,
                        &queueToComplete);
                }
            }

            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            FdoPortCompleteQueue(&queueToComplete);
            break;
        }
        case IOCTL_SERIAL_GET_STATS:
            if (pIrpStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(SERIALPERF_STATS)) {
                status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            *(PSERIALPERF_STATS)pIrp->AssociatedIrp.SystemBuffer = pIoPortLocal->perfStats;
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            pIrp->IoStatus.Information = sizeof(SERIALPERF_STATS);

            TraceIrp("FdoPortIoCtl", pIrp, &status, TRACE_FLAG_RESULTS);
            break;
        case IOCTL_SERIAL_CLEAR_STATS:
            KeAcquireSpinLock(pIoPortLocal->pIoLock, &oldIrql);
            RtlZeroMemory(&pIoPortLocal->perfStats, sizeof(pIoPortLocal->perfStats));
            KeReleaseSpinLock(pIoPortLocal->pIoLock, oldIrql);
            break;
        default:
            status = STATUS_INVALID_PARAMETER;
        }
    }
Пример #6
0
NTSTATUS FdoPortOpen(IN PC0C_FDOPORT_EXTENSION pDevExt)
{
  LIST_ENTRY queueToComplete;
  PUCHAR pBase;
  ULONG size;
  KIRQL oldIrql;
  PC0C_IO_PORT pIoPort;

  if (InterlockedIncrement(&pDevExt->openCount) != 1) {
    InterlockedDecrement(&pDevExt->openCount);
    return STATUS_ACCESS_DENIED;
  }

  pIoPort = pDevExt->pIoPortLocal;

  if (pIoPort->plugInMode && !pIoPort->pIoPortRemote->isOpen) {
    InterlockedDecrement(&pDevExt->openCount);
    return STATUS_ACCESS_DENIED;
  }

  if (pIoPort->exclusiveMode)
    IoInvalidateDeviceRelations(pIoPort->pPhDevObj, BusRelations);

  switch (MmQuerySystemSize()) {
  case MmLargeSystem:
    size = 4096;
    pBase = (PUCHAR)C0C_ALLOCATE_POOL(NonPagedPool, size);
    if (pBase)
      break;
  case MmMediumSystem:
    size = 1024;
    pBase = (PUCHAR)C0C_ALLOCATE_POOL(NonPagedPool, size);
    if (pBase)
      break;
  case MmSmallSystem:
    size = 128;
    pBase = (PUCHAR)C0C_ALLOCATE_POOL(NonPagedPool, size);
    if (pBase)
      break;
  default:
    size = 0;
    pBase = NULL;
  }

  InitializeListHead(&queueToComplete);

#if ENABLE_TRACING
  if (pIoPort->amountInWriteQueue) {
    NTSTATUS status;
    UNICODE_STRING msg;

    status = STATUS_SUCCESS;
    RtlInitUnicodeString(&msg, NULL);
    StrAppendStr0(&status, &msg, L"!!!WARNING!!! amountInWriteQueue = ");
    StrAppendNum(&status, &msg, pIoPort->amountInWriteQueue, 10);

    Trace0((PC0C_COMMON_EXTENSION)pDevExt, msg.Buffer);

    StrFree(&msg);
  }
#endif /* ENABLE_TRACING */

  KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql);

  InitBuffer(&pIoPort->readBuf, pBase, size);

  pIoPort->amountInWriteQueue = 0;
  pIoPort->tryWrite = FALSE;
  pIoPort->errors = 0;
  pIoPort->waitMask = 0;
  pIoPort->eventMask = 0;
  RtlZeroMemory(&pIoPort->perfStats, sizeof(pIoPort->perfStats));
  pIoPort->handFlow.XoffLimit = size >> 3;
  pIoPort->handFlow.XonLimit = size >> 1;
  pIoPort->pIoPortRemote->brokeIdleChars = 0;

  SetHandFlow(pIoPort, NULL, &queueToComplete);
  SetModemControl(pIoPort, C0C_MCR_OPEN, C0C_MCR_OPEN, &queueToComplete);

  if (pIoPort->pIoPortRemote->pWriteDelay && pIoPort->pIoPortRemote->brokeCharsProbability > 0)
    StartWriteDelayTimer(pIoPort->pIoPortRemote->pWriteDelay);

  KeReleaseSpinLock(pIoPort->pIoLock, oldIrql);

  pIoPort->isOpen = TRUE;

  if (pIoPort->pIoPortRemote->plugInMode)
    IoInvalidateDeviceRelations(pIoPort->pIoPortRemote->pPhDevObj, BusRelations);

  FdoPortCompleteQueue(&queueToComplete);

  return STATUS_SUCCESS;
}
Пример #7
0
NTSTATUS FdoPortPnp(
    IN PC0C_FDOPORT_EXTENSION pDevExt,
    IN PIRP                   pIrp)
{
  NTSTATUS status;
  PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  ULONG minorFunction = pIrpStack->MinorFunction;
  PDEVICE_OBJECT pLowDevObj = pDevExt->pLowDevObj; // IRP_MN_REMOVE_DEVICE deletes *pDevExt!

  status = STATUS_SUCCESS;

  switch (minorFunction) {
  case IRP_MN_QUERY_DEVICE_RELATIONS: {
    LIST_ENTRY queueToComplete;
    KIRQL oldIrql;
    PC0C_IO_PORT pIoPort = pDevExt->pIoPortLocal;

    if ((pIoPort->exclusiveMode && pIoPort->isOpen) ||
        (pIoPort->plugInMode && !pIoPort->pIoPortRemote->isOpen))
    {
      HidePort(pDevExt);
    } else {
      ShowPort(pDevExt);
    }

    /* complete pending CLOSE IRPs */

    InitializeListHead(&queueToComplete);

    KeAcquireSpinLock(pIoPort->pIoLock, &oldIrql);
    FdoPortIo(C0C_IO_TYPE_CLOSE_COMPLETE,
              NULL,
              pIoPort,
              &pIoPort->irpQueues[C0C_QUEUE_CLOSE],
              &queueToComplete);
    KeReleaseSpinLock(pIoPort->pIoLock, oldIrql);

    FdoPortCompleteQueue(&queueToComplete);
    break;
  }
  case IRP_MN_QUERY_REMOVE_DEVICE:
    if (pDevExt->openCount)
      status = STATUS_DEVICE_BUSY;
    else
      pIrp->IoStatus.Status = STATUS_SUCCESS;
    break;
  case IRP_MN_REMOVE_DEVICE:
    RemoveFdoPort(pDevExt);
    pDevExt = NULL;
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    break;
  case IRP_MN_START_DEVICE:
  case IRP_MN_STOP_DEVICE:
  case IRP_MN_QUERY_STOP_DEVICE:
  case IRP_MN_CANCEL_STOP_DEVICE:
  case IRP_MN_SURPRISE_REMOVAL:
    pIrp->IoStatus.Status = STATUS_SUCCESS;
    break;
  }

  if (status == STATUS_SUCCESS) {
    IoSkipCurrentIrpStackLocation(pIrp);
    status = IoCallDriver(pLowDevObj, pIrp);

    TraceCode((PC0C_COMMON_EXTENSION)pDevExt, "PNP ", codeNameTablePnp, minorFunction, &status);
  } else {
    TraceIrp("PNP", pIrp, &status, TRACE_FLAG_RESULTS);

    pIrp->IoStatus.Status = status;
    IoCompleteRequest(pIrp, IO_NO_INCREMENT);
  }

  return status;
}
Пример #8
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;
}