ioctl.cpp

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

CPP
1,202
字号
                            (LData | LParity | LStop));
                m_ValidDataMask = Mask;
                m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)SetLineControl);
                m_ControlLock.Release();
                break;
            }
        case IOCTL_SERIAL_GET_LINE_CONTROL:
            {
                PSERIAL_LINE_CONTROL Lc = (PSERIAL_LINE_CONTROL)Irp.SystemBuffer();
                if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_LINE_CONTROL)) 
                {
                    Status = STATUS_BUFFER_TOO_SMALL;
                    break;
                }

                m_ControlLock.Lock();

                switch (m_LineControl & SERIAL_DATA_MASK)
                {
                    case SERIAL_5_DATA:
                        Lc->WordLength = 5;
                        break;
                    case SERIAL_6_DATA:
                        Lc->WordLength = 6;
                        break;
                    case SERIAL_7_DATA:
                        Lc->WordLength = 7;
                        break;
                    case SERIAL_8_DATA:
                        Lc->WordLength = 8;
                        break;
                }

                switch (m_LineControl & SERIAL_PARITY_MASK)
                {
                    case SERIAL_NONE_PARITY:
                        Lc->Parity = NO_PARITY;
                        break;
                    case SERIAL_ODD_PARITY:
                        Lc->Parity = ODD_PARITY;
                        break;
                    case SERIAL_EVEN_PARITY:
                        Lc->Parity = EVEN_PARITY;
                        break;
                    case SERIAL_SPACE_PARITY:
                        Lc->Parity = SPACE_PARITY;
                        break;
                }

                if (m_LineControl & SERIAL_2_STOP) 
                {
                    if (Lc->WordLength == 5)
                        Lc->StopBits = STOP_BITS_1_5;
                    else
                        Lc->StopBits = STOP_BITS_2;
                } 
                else 
                    Lc->StopBits = STOP_BIT_1;

                Irp.Information() = sizeof(SERIAL_LINE_CONTROL);

                m_ControlLock.Release();
                break;
            }
        case IOCTL_SERIAL_SET_TIMEOUTS:
            {
                PSERIAL_TIMEOUTS NewTimeouts =
                    ((PSERIAL_TIMEOUTS) Irp.SystemBuffer());

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

                if ((NewTimeouts->ReadIntervalTimeout == MAXULONG) &&
                    (NewTimeouts->ReadTotalTimeoutMultiplier == MAXULONG) &&
                    (NewTimeouts->ReadTotalTimeoutConstant == MAXULONG)) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }

                m_ControlLock.Lock();

                m_Timeouts.ReadIntervalTimeout =
                    NewTimeouts->ReadIntervalTimeout;

                m_Timeouts.ReadTotalTimeoutMultiplier =
                    NewTimeouts->ReadTotalTimeoutMultiplier;

                m_Timeouts.ReadTotalTimeoutConstant =
                    NewTimeouts->ReadTotalTimeoutConstant;

                m_Timeouts.WriteTotalTimeoutMultiplier =
                    NewTimeouts->WriteTotalTimeoutMultiplier;

                m_Timeouts.WriteTotalTimeoutConstant =
                    NewTimeouts->WriteTotalTimeoutConstant;

                m_ControlLock.Release();
                break;
            }
        case IOCTL_SERIAL_GET_TIMEOUTS:

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

            m_ControlLock.Lock();
            *((PSERIAL_TIMEOUTS)Irp.SystemBuffer()) = m_Timeouts;
            Irp.Information() = sizeof(SERIAL_TIMEOUTS);
            m_ControlLock.Release();

            break;

        case IOCTL_SERIAL_SET_CHARS:
            {
                PSERIAL_CHARS NewChars = (PSERIAL_CHARS)Irp.SystemBuffer();

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

                // The only thing that can be wrong with the chars
                // is that the xon and xoff characters are the same.
#if 0
                if (NewChars->XonChar == NewChars->XoffChar) 
                {
                    Status = STATUS_INVALID_PARAMETER;
                    break;
                }
#endif
                // We acquire the control lock so that only
                // one request can GET or SET the characters
                // at a time.  The sets could be synchronized
                // by the interrupt spinlock, but that wouldn't
                // prevent multiple gets at the same time.

                m_ControlLock.Lock();

                // Under the protection of the lock, make sure that
                // the xon and xoff characters aren't the same as
                // the escape character.

                if (m_EscapeChar) 
                {
                    if ((m_EscapeChar == NewChars->XonChar) ||
                        (m_EscapeChar == NewChars->XoffChar)) 
                    {
                        Status = STATUS_INVALID_PARAMETER;
                        m_ControlLock.Release();
                        break;
                    }
                }
                m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK_PARM) SetChars, (PVOID) NewChars);
                m_ControlLock.Release();
                break;
            }
        case IOCTL_SERIAL_GET_CHARS:
            if (Irp.IoctlOutputBufferLength() < sizeof(SERIAL_CHARS)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            m_ControlLock.Lock();
            *((PSERIAL_CHARS)Irp.SystemBuffer()) = m_SpecialChars;
            Irp.Information() = sizeof(SERIAL_CHARS);
            m_ControlLock.Release();

            break;

        case IOCTL_SERIAL_SET_DTR:
        case IOCTL_SERIAL_CLR_DTR:

            // We acquire the lock so that we can check whether
            // automatic dtr flow control is enabled.  If it is
            // then we return an error since the app is not allowed
            // to touch this if it is automatic.
            m_ControlLock.Lock();
            if ((m_HandFlow.ControlHandShake & SERIAL_DTR_MASK)
                == SERIAL_DTR_HANDSHAKE) 
            {
                Irp.Status() = STATUS_INVALID_PARAMETER;
            } 
            else 
            {
                m_KdInterrupt.SynchronizeExecution( (KDIRQ_SYNC_CALLBACK)
                    (Irp.IoctlCode() == IOCTL_SERIAL_SET_DTR ? SetDTR : ClrDTR ));
            }
            m_ControlLock.Release();
            break;

        case IOCTL_SERIAL_RESET_DEVICE:
            break;

        case IOCTL_SERIAL_SET_RTS:
        case IOCTL_SERIAL_CLR_RTS:

            // We acquire the lock so that we can check whether
            // automatic rts flow control or transmit toggleing
            // is enabled.  If it is then we return an error since
            // the app is not allowed to touch this if it is automatic
            // or toggling.
            m_ControlLock.Lock();
            if (((m_HandFlow.FlowReplace & SERIAL_RTS_MASK)
                 == SERIAL_RTS_HANDSHAKE) ||
                ((m_HandFlow.FlowReplace & SERIAL_RTS_MASK)
                 == SERIAL_TRANSMIT_TOGGLE)) 
            {
                Irp.Status() = STATUS_INVALID_PARAMETER;
            } 
            else 
            {
                m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK)
                    (Irp.IoctlCode() == IOCTL_SERIAL_SET_RTS ? SetRTS : ClrRTS ));
            }
            m_ControlLock.Release();
            break;

        case IOCTL_SERIAL_SET_XOFF:
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) PretendXoff);
            break;
        
        case IOCTL_SERIAL_SET_XON: 
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) PretendXon);
            break;

        case IOCTL_SERIAL_SET_BREAK_ON:
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) TurnOnBreak);
            break;

        case IOCTL_SERIAL_SET_BREAK_OFF:
            m_KdInterrupt.SynchronizeExecution((KDIRQ_SYNC_CALLBACK) TurnOffBreak);
            break;

        case IOCTL_SERIAL_SET_QUEUE_SIZE:
            {
                // Type ahead buffer is fixed, so we just validate
                // the the users request is not bigger that our
                // own internal buffer size.
                PSERIAL_QUEUE_SIZE Rs = (PSERIAL_QUEUE_SIZE) Irp.SystemBuffer();

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

                // We have to allocate the memory for the new
                // buffer while we're still in the context of the
                // caller.  We don't even try to protect this
                // with a lock because the value could be stale
                // as soon as we release the lock - The only time
                // we will know for sure is when we actually try
                // to do the resize.

                if (Rs->InSize <= m_BufferSize) 
                {
                    Status = STATUS_SUCCESS;
                    break;
                }

                __try 
                {
                    Irp.IoctlType3InputBuffer() = ExAllocatePoolWithQuota(
                            NonPagedPool,
                            Rs->InSize
                            );

                } 
                __except (EXCEPTION_EXECUTE_HANDLER) 
                {

                    Irp.IoctlType3InputBuffer() = NULL;
                    Status = GetExceptionCode();

                }

                if (!Irp.IoctlType3InputBuffer())
                    break;

                // Well the data passed was big enough.  Do the request.
                //
                // There are two reason we place it in the read queue:
                //
                // 1) We want to serialize these resize requests so that
                //    they don't contend with each other.
                //
                // 2) We want to serialize these requests with reads since
                //    we don't want reads and resizes contending over the
                //    read buffer.
                return StartOrQueue(
                           Irp,
                           &m_ReadQueue,
                           &m_CurrentReadIrp,
                           StartRead
                           );
                break;
            }
        case IOCTL_SERIAL_GET_WAIT_MASK:
            if (Irp.IoctlOutputBufferLength() < sizeof(ULONG)) 
            {
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            // Simple scalar read.  No reason to acquire a lock.

            Irp.Information() = sizeof(ULONG);
            *((PULONG) Irp.SystemBuffer()) = m_IsrWaitMask;
            break;

        case IOCTL_SERIAL_SET_WAIT_MASK:

            ULONG NewMask;

            DebugDump(DBG_DIAG3 | DBG_DIAG6, ("In Ioctl processing for set mask\n") );

            if (Irp.IoctlInputBufferLength() < sizeof(ULONG)) 
            {
                DebugDump(DBG_DIAG3, ("Invalid size fo the buffer %d\n", Irp.IoctlInputBufferLength()) );
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            } 
            else 
                NewMask = *((PULONG) Irp.SystemBuffer());

            // Make sure that the mask only contains valid
            // waitable events.

            if (NewMask & ~(SERIAL_EV_RXCHAR   |
                            SERIAL_EV_RXFLAG   |
                            SERIAL_EV_TXEMPTY  |
                            SERIAL_EV_CTS      |
                            SERIAL_EV_DSR      |
                            SERIAL_EV_RLSD     |
                            SERIAL_EV_BREAK    |
                            SERIAL_EV_ERR      |
                            SERIAL_EV_RING     |
                            SERIAL_EV_PERR     |
                            SERIAL_EV_RX80FULL |
                            SERIAL_EV_EVENT1   |
                            SERIAL_EV_EVENT2)) {

                DebugDump(DBG_DIAG3, ("Unknown mask %x\n",NewMask) );
                Status = STATUS_INVALID_PARAMETER;
                break;
            }

            // Either start this irp or put it on the
            // queue.

            DebugDump(DBG_DIAG3 | DBG_DIAG6, ("Starting or queuing set mask irp %x\n",Irp) );
            return StartOrQueue(
                       Irp,
                       &m_MaskQueue,
                       &m_CurrentMaskIrp,
                       StartMask
                       );

        case IOCTL_SERIAL_WAIT_ON_MASK:

            DebugDump(DBG_DIAG3 | DBG_DIAG6, ("In Ioctl processing for wait mask\n") );
            if (Irp.IoctlOutputBufferLength() < sizeof(ULONG)) 
            {
                DebugDump(DBG_DIAG3, ("Invalid size fo the buffer %d\n", Irp.IoctlInputBufferLength()) );
                Status = STATUS_BUFFER_TOO_SMALL;
                break;
            }

            // Either start this irp or put it on the
            // queue.

            DebugDump(DBG_DIAG3 | DBG_DIAG6, ("Starting or queuing wait mask irp %x\n",Irp) );
            return StartOrQueue(
                       Irp,
                       &m_MaskQueue,
                       &m_CurrentMaskIrp,
                       StartMask
                       );

        case IOCTL_SERIAL_IMMEDIATE_CHAR:

            KIRQL OldIrql;

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

            IoAcquireCancelSpinLock(&OldIrql);
            if (m_CurrentImmediateIrp) 
            {
                Status = STATUS_INVALID_PARAMETER;

⌨️ 快捷键说明

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