ioctl.cpp

来自「这个是串口驱动程序开发包」· C++ 代码 · 共 1,202 行 · 第 1/3 页

CPP
1,202
字号
                IoReleaseCancelSpinLock(OldIrql);

            } 
            else 
            {
                // We can queue the char.  We need to set
                // a cancel routine because flow control could
                // keep the char from transmitting.  Make sure
                // that the irp hasn't already been canceled.
                if (Irp->Cancel) 
                {
                    IoReleaseCancelSpinLock(OldIrql);
                    Status = STATUS_CANCELLED;
                } 
                else 
                {
                    m_CurrentImmediateIrp = Irp;
                    m_TotalCharsQueued++;
                    IoReleaseCancelSpinLock(OldIrql);
                    StartImmediate();

                    return STATUS_PENDING;
                }
            }
            break;

        case IOCTL_SERIAL_PURGE:

            ULONG Mask;

            if (Irp.IoctlInputBufferLength() < sizeof(ULONG)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }
            // Check to make sure that the mask only has
            // 0 or the other appropriate values.

            Mask = *((PULONG)(Irp.SystemBuffer()));

            if ((!Mask) || (Mask & (~(SERIAL_PURGE_TXABORT |
                                      SERIAL_PURGE_RXABORT |
                                      SERIAL_PURGE_TXCLEAR |
                                      SERIAL_PURGE_RXCLEAR
                                     )
                                   )
                           )) 
            {
                Status = STATUS_INVALID_PARAMETER;
                break;
            }
            
            // Either start this irp or put it on the
            // queue.
            return StartOrQueue(
                       Irp,
                       &m_PurgeQueue,
                       &m_CurrentPurgeIrp,
                       StartPurge
                       );

        case IOCTL_SERIAL_GET_HANDFLOW:

            if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_HANDFLOW)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            Irp.Information() = sizeof(SERIAL_HANDFLOW);

            m_ControlLock.Lock();
            *((PSERIAL_HANDFLOW)Irp.SystemBuffer()) = m_HandFlow;
            m_ControlLock.Release();

            break;

        case IOCTL_SERIAL_SET_HANDFLOW:
            {
                PSERIAL_HANDFLOW HandFlow = (PSERIAL_HANDFLOW) Irp.SystemBuffer();

                // Make sure that the hand shake and control is the
                // right size.

                if (Irp.IoctlInputBufferLength() < sizeof(SERIAL_HANDFLOW)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                // Make sure that there are no invalid bits set in
                // the control and handshake.

                if (HandFlow->ControlHandShake & SERIAL_CONTROL_INVALID) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                if (HandFlow->FlowReplace & SERIAL_FLOW_INVALID) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                // Make sure that the app hasn't set an invlid DTR mode.
                if ((HandFlow->ControlHandShake & SERIAL_DTR_MASK) ==
                    SERIAL_DTR_MASK) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                // Make sure that haven't set totally invalid xon/xoff
                // limits.

                if ((HandFlow->XonLimit < 0) ||
                    ((ULONG)HandFlow->XonLimit > m_BufferSize)) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                if ((HandFlow->XoffLimit < 0) ||
                    ((ULONG)HandFlow->XoffLimit > m_BufferSize)) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                m_ControlLock.Lock();

                // Under the protection of the lock, make sure that
                // we aren't turning on error replacement when we
                // are doing line status/modem status insertion.

                if (m_EscapeChar) 
                {
                    if (HandFlow->FlowReplace & SERIAL_ERROR_CHAR) 
                    {
                        Status = STATUS_INVALID_PARAMETER;
                        m_ControlLock.Release();
                        break;
                    }
                }
                m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) SetHandFlow, HandFlow);
                m_ControlLock.Release();
                break;
            }
        case IOCTL_SERIAL_GET_MODEMSTATUS:
            if (Irp.IoctlOutputBufferLength() < sizeof(ULONG)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            Irp.Information() = sizeof(ULONG);

            m_ControlLock.Lock();
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) GetModemUpdate, 
                Irp.SystemBuffer());
            m_ControlLock.Release();

            break;

        case IOCTL_SERIAL_GET_DTRRTS:
            {
                ULONG ModemControl;
                if (Irp.IoctlOutputBufferLength() < sizeof(ULONG)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                Irp.Information() = sizeof(ULONG);
                Irp.Status() = STATUS_SUCCESS;

                // Reading this hardware has no effect on the device.

                ModemControl = m_pController->ReadByte(MODEM_CONTROL_REGISTER);

                ModemControl &= SERIAL_DTR_STATE | SERIAL_RTS_STATE;

                *(PULONG)Irp.SystemBuffer() = ModemControl;

                break;
            }
        case IOCTL_SERIAL_GET_COMMSTATUS: 
            {
            KIRQL OldIrql;               

                if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_STATUS)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                Irp.Information() = sizeof(SERIAL_STATUS);

                // Acquire the cancel spin lock so nothing much
                // changes while were getting the state.

                IoAcquireCancelSpinLock(&OldIrql);

                m_KdInterrupt.SynchronizeExecution(
                    (KDIRQ_SYNC_CALLBACK_PARM) GetCommStatus,
                    Irp.SystemBuffer()
                    );

                IoReleaseCancelSpinLock(OldIrql);

                break;
            }
        case IOCTL_SERIAL_GET_PROPERTIES:

            if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_COMMPROP)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            // No synchronization is required since this information
            // is "static".
            GetProperties(
                (PSERIAL_COMMPROP)Irp.SystemBuffer()
                );

            Irp.Information() = sizeof(SERIAL_COMMPROP);
            Irp.Status() = STATUS_SUCCESS;
            break;

        case IOCTL_SERIAL_XOFF_COUNTER:
            {
                PSERIAL_XOFF_COUNTER Xc = (PSERIAL_XOFF_COUNTER) Irp.SystemBuffer();

                if (Irp.IoctlInputBufferLength() < sizeof(SERIAL_XOFF_COUNTER)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                if (Xc->Counter <= 0) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                // So far so good.  Put the irp onto the write queue.
                return StartOrQueue(
                           Irp,
                           &m_WriteQueue,
                           &m_CurrentWriteIrp,
                           StartWrite
                           );
            }
        case IOCTL_SERIAL_LSRMST_INSERT:
            {
                PUCHAR escapeChar = (PUCHAR) Irp.SystemBuffer();

                // Make sure we get a byte.

                if (Irp.IoctlInputBufferLength() < sizeof(UCHAR)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                m_ControlLock.Lock();

                if (*escapeChar) 
                {
                    // We've got some escape work to do.  We will make sure that
                    // the character is not the same as the Xon or Xoff character,
                    // or that we are already doing error replacement.
                    if ((*escapeChar == m_SpecialChars.XoffChar) ||
                        (*escapeChar == m_SpecialChars.XonChar) ||
                        (m_HandFlow.FlowReplace & SERIAL_ERROR_CHAR)) 
                    {
                        Status = STATUS_INVALID_PARAMETER;
                        m_ControlLock.Release();
                        break;
                    }
                }
                m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) SetEscapeChar, Irp);
                m_ControlLock.Release();

                break;
            }
        case IOCTL_SERIAL_CONFIG_SIZE:

            if (Irp.IoctlOutputBufferLength() < sizeof(ULONG)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            Irp.Information() = sizeof(ULONG);
            Irp.Status() = STATUS_SUCCESS;

            *(PULONG)Irp.SystemBuffer() = 0;

            break;

        case IOCTL_SERIAL_GET_STATS:

            if (Irp.IoctlOutputBufferLength() < sizeof(SERIALPERF_STATS)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }
            Irp.Information() = sizeof(SERIALPERF_STATS);
            Irp.Status() = STATUS_SUCCESS;

            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) GetStats, Irp);

            break;

        case IOCTL_SERIAL_CLEAR_STATS:
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) ClearStats);
            break;
        
        default:
            Status = STATUS_INVALID_PARAMETER;
            break;
    }

DoneWithIoctl:;

    Irp.Status() = Status;

    DebugDump(DBG_DIAG6, ("Complete Irp: %x\n",Irp) );
    Irp.Complete();

    return Status;
}

VOID KdSerialDevice::GetProperties(IN PSERIAL_COMMPROP Properties)

/*++

Routine Description:

    This function returns the capabilities of this particular
    serial device.

Arguments:

    Properties - The structure used to return the properties

--*/

{
    RtlZeroMemory(
        Properties,
        sizeof(SERIAL_COMMPROP)
        );

    Properties->PacketLength = sizeof(SERIAL_COMMPROP);
    Properties->PacketVersion = 2;
    Properties->ServiceMask = SERIAL_SP_SERIALCOMM;
    Properties->MaxTxQueue = 0;
    Properties->MaxRxQueue = 0;

    Properties->MaxBaud = SERIAL_BAUD_USER;
    Properties->SettableBaud = m_SupportedBauds;

    Properties->ProvSubType = SERIAL_SP_RS232;
    Properties->ProvCapabilities = SERIAL_PCF_DTRDSR |
                                   SERIAL_PCF_RTSCTS |
                                   SERIAL_PCF_CD     |
                                   SERIAL_PCF_PARITY_CHECK |
                                   SERIAL_PCF_XONXOFF |
                                   SERIAL_PCF_SETXCHAR |
                                   SERIAL_PCF_TOTALTIMEOUTS |
                                   SERIAL_PCF_INTTIMEOUTS;
    Properties->SettableParams = SERIAL_SP_PARITY |
                                 SERIAL_SP_BAUD |
                                 SERIAL_SP_DATABITS |
                                 SERIAL_SP_STOPBITS |
                                 SERIAL_SP_HANDSHAKING |
                                 SERIAL_SP_PARITY_CHECK |
                                 SERIAL_SP_CARRIER_DETECT;


    Properties->SettableData = SERIAL_DATABITS_5 |
                               SERIAL_DATABITS_6 |
                               SERIAL_DATABITS_7 |
                               SERIAL_DATABITS_8;
    Properties->SettableStopParity = SERIAL_STOPBITS_10 |
                                     SERIAL_STOPBITS_15 |
                                     SERIAL_STOPBITS_20 |
                                     SERIAL_PARITY_NONE |
                                     SERIAL_PARITY_ODD  |
                                     SERIAL_PARITY_EVEN |
                                     SERIAL_PARITY_MARK |
                                     SERIAL_PARITY_SPACE;
    Properties->CurrentTxQueue = 0;
    Properties->CurrentRxQueue = m_BufferSize;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?