⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 write.cpp

📁 这个是串口驱动程序开发包
💻 CPP
📖 第 1 页 / 共 2 页
字号:
        &m_KdTimer_WriteRequestTotalTimerDpc,
        StartWrite,
        GetNextWrite,
        SERIAL_REF_ISR
        );
}

BOOLEAN KdSerialDevice::ProcessEmptyTransmit()

/*++

Routine Description:

    This routine is used to determine if conditions are appropriate
    to satisfy a wait for transmit empty event, and if so to complete
    the irp that is waiting for that event.  It also call the code
    that checks to see if we should lower the RTS line if we are
    doing transmit toggling.

    NOTE: This routine is called by KeSynchronizeExecution.

    NOTE: This routine assumes that it is called with the cancel
          spinlock held.

Arguments:

    Context - Not Used.

Return Value:

    This routine always returns FALSE.

--*/

{
    if (m_IsrWaitMask && (m_IsrWaitMask & SERIAL_EV_TXEMPTY) &&
        m_EmptiedTransmit && (!m_TransmitImmediate) &&
        (!m_CurrentWriteIrp) && IsListEmpty(&m_WriteQueue)) 
    {
        m_HistoryMask |= SERIAL_EV_TXEMPTY;
        if (m_IrpMaskLocation) 
        {
            *m_IrpMaskLocation = m_HistoryMask;
            m_IrpMaskLocation = NULL;
            m_HistoryMask = 0;

            m_CurrentWaitIrp.Information() = sizeof(ULONG);
            m_KdDpc_CommWait.InsertQueue();
        }
        m_CountOfTryingToLowerRTS++;
        PerhapsLowerRTS();
    }
    return FALSE;
}

BOOLEAN KdSerialDevice::GiveWriteToIsr()

/*++

Routine Description:

    Try to start off the write by slipping it in behind
    a transmit immediate char, or if that isn't available
    and the transmit holding register is empty, "tickle"
    the UART into interrupting with a transmit buffer
    empty.

    NOTE: This routine is called by KeSynchronizeExecution.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Return Value:

    This routine always returns FALSE.

--*/

{
    // We might have a xoff counter request masquerading as a
    // write.  The length of these requests will always be one
    // and we can get a pointer to the actual character from
    // the data supplied by the user.
    if (m_CurrentWriteIrp.MajorFunction() == IRP_MJ_WRITE) 
    {
        m_WriteLength = m_CurrentWriteIrp.WriteLength();
        m_WriteCurrentChar = (PUCHAR)
            m_CurrentWriteIrp.SystemBuffer();
    } 
    else 
    {
        m_WriteLength = 1;
        m_WriteCurrentChar =
            ((PUCHAR)m_CurrentWriteIrp.SystemBuffer()) +
            FIELD_OFFSET(
                SERIAL_XOFF_COUNTER,
                XoffChar
                );
    }

    // The isr now has a reference to the irp.

    SERIAL_SET_REFERENCE(
        m_CurrentWriteIrp,
        SERIAL_REF_ISR
        );

    // Check first to see if an immediate char is transmitting.
    // If it is then we'll just slip in behind it when its
    // done.

    if (!m_TransmitImmediate) 
    {
        // If there is no immediate char transmitting then we
        // will "re-enable" the transmit holding register empty
        // interrupt.  The 8250 family of devices will always
        // signal a transmit holding register empty interrupt
        // *ANY* time this bit is set to one.  By doing things
        // this way we can simply use the normal interrupt code
        // to start off this write.
        //
        // We've been keeping track of whether the transmit holding
        // register is empty so it we only need to do this
        // if the register is empty.
        if (m_HoldingEmpty) 
        {
            DISABLE_ALL_INTERRUPTS(m_pController);
            ENABLE_ALL_INTERRUPTS(m_pController);
        }
    }
    // The rts line may already be up from previous writes,
    // however, it won't take much additional time to turn
    // on the RTS line if we are doing transmit toggling.
    if ((m_HandFlow.FlowReplace & SERIAL_RTS_MASK) == SERIAL_TRANSMIT_TOGGLE)
        SetRTS();

    return FALSE;
}

VOID KdSerialDevice::CancelCurrentWrite(KdIrp Irp)
/*++

Routine Description:

    This routine is used to cancel the current write.

Arguments:

    DeviceObject - Pointer to the device object for this device

    Irp - Pointer to the IRP to be canceled.

--*/
{
    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabWriteFromIsr,
        Irp->CancelIrql,
        STATUS_CANCELLED,
        &m_CurrentWriteIrp,
        &m_WriteQueue,
        NULL,
        &m_KdTimer_WriteRequestTotalTimerDpc,
        StartWrite,
        GetNextWrite,
        SERIAL_REF_CANCEL
        );
}

VOID KdSerialDevice::WriteTimeout(
    IN PKdDpc Dpc,
    IN PVOID SystemContext1,
    IN PVOID SystemContext2
    )

/*++

Routine Description:

    This routine will try to timeout the current write.

Arguments:

    Dpc - Not Used.

    SystemContext1 - Not Used.

    SystemContext2 - Not Used.

Return Value:

    None.

--*/

{
    KIRQL OldIrql;

    IoAcquireCancelSpinLock(&OldIrql);

    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabWriteFromIsr,
        OldIrql,
        STATUS_TIMEOUT,
        &m_CurrentWriteIrp,
        &m_WriteQueue,
        NULL,
        &m_KdTimer_WriteRequestTotalTimerDpc,
        StartWrite,
        GetNextWrite,
        SERIAL_REF_TOTAL_TIMER
        );
}

BOOLEAN KdSerialDevice::GrabWriteFromIsr()

/*++

Routine Description:


    This routine is used to grab the current irp, which could be timing
    out or canceling, from the ISR

    NOTE: This routine is being called from KeSynchronizeExecution.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Return Value:

    Always false.

--*/

{
    // Check if the write length is non-zero.  If it is non-zero
    // then the ISR still owns the irp. We calculate the the number
    // of characters written and update the information field of the
    // irp with the characters written.  We then clear the write length
    // the isr sees.

    if (m_WriteLength)
    {
        // We could have an xoff counter masquerading as a
        // write irp.  If so, don't update the write length.
        if (m_CurrentWriteIrp.MajorFunction() == IRP_MJ_WRITE) 
        {
            m_CurrentWriteIrp.Information() = m_CurrentWriteIrp.WriteLength() -
                m_WriteLength;

        }
        else
            m_CurrentWriteIrp.Information() = 0;

        // Since the isr no longer references this irp, we can
        // decrement it's reference count.

        SERIAL_CLEAR_REFERENCE(
            m_CurrentWriteIrp,
            SERIAL_REF_ISR
            );
        m_WriteLength = 0;
    }
    return FALSE;
}

BOOLEAN KdSerialDevice::GrabXoffFromIsr()

/*++

Routine Description:

    This routine is used to grab an xoff counter irp from the
    isr when it is no longer masquerading as a write irp.  This
    routine is called by the cancel and timeout code for the
    xoff counter ioctl.


    NOTE: This routine is being called from KeSynchronizeExecution.

    NOTE: This routine assumes that the cancel spin lock is held
          when this routine is called.

Return Value:

    Always false.

--*/

{
    if (m_CountSinceXoff) 
    {
        // This is only non-zero when there actually is a Xoff ioctl
        // counting down.
        m_CountSinceXoff = 0;

        // We decrement the count since the isr no longer owns
        // the irp.
        SERIAL_CLEAR_REFERENCE(
            m_CurrentXoffIrp,
            SERIAL_REF_ISR
            );
    }
    return FALSE;
}

VOID KdSerialDevice::CompleteXoff(
    IN PKdDpc Dpc,
    IN PVOID SystemContext1,
    IN PVOID SystemContext2
    )

/*++

Routine Description:

    This routine is merely used to truly complete an xoff counter irp.  It
    assumes that the status and the information fields of the irp are
    already correctly filled in.

Arguments:

    Dpc - Not Used.

    SystemContext1 - Not Used.

    SystemContext2 - Not Used.

--*/

{
    KIRQL OldIrql;

    IoAcquireCancelSpinLock(&OldIrql);

    TryToCompleteCurrent(
        NULL,
        OldIrql,
        STATUS_SUCCESS,
        &m_CurrentXoffIrp,
        NULL,
        NULL,
        &m_KdTimer_XoffCountTimerDpc,
        NULL,
        NULL,
        SERIAL_REF_ISR
        );
}

VOID KdSerialDevice::TimeoutXoff(
    IN PKdDpc Dpc,
    IN PVOID SystemContext1,
    IN PVOID SystemContext2
    )

/*++

Routine Description:

    This routine is merely used to truly complete an xoff counter irp,
    if its timer has run out.

Arguments:

    Dpc - Not Used.

    SystemContext1 - Not Used.

    SystemContext2 - Not Used.

--*/

{
    KIRQL OldIrql;

    IoAcquireCancelSpinLock(&OldIrql);

    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabXoffFromIsr,
        OldIrql,
        STATUS_SERIAL_COUNTER_TIMEOUT,
        &m_CurrentXoffIrp,
        NULL,
        NULL,
        NULL,
        NULL,
        NULL,
        SERIAL_REF_TOTAL_TIMER
        );
}

VOID KdSerialDevice::CancelCurrentXoff(KdIrp Irp)
/*++

Routine Description:

    This routine is used to cancel the current write.

Arguments:

    Irp - Pointer to the IRP to be canceled.
--*/
{
    TryToCompleteCurrent(
        (KDIRQ_SYNC_CALLBACK) GrabXoffFromIsr,
        Irp->CancelIrql,
        STATUS_CANCELLED,
        &m_CurrentXoffIrp,
        NULL,
        NULL,
        &m_KdTimer_XoffCountTimerDpc,
        NULL,
        NULL,
        SERIAL_REF_CANCEL
        );
}

BOOLEAN KdSerialDevice::GiveXoffToIsr()

/*++

Routine Description:


    This routine starts off the xoff counter.  It merely
    has to set the xoff count and increment the reference
    count to denote that the isr has a reference to the irp.

    NOTE: This routine is called by KeSynchronizeExecution.

    NOTE: This routine assumes that it is called with the
          cancel spin lock held.

Return Value:

    This routine always returns FALSE.

--*/

{
    // The current stack location.  This contains all of the
    // information we need to process this particular request.

    PSERIAL_XOFF_COUNTER Xc = (PSERIAL_XOFF_COUNTER)
        m_CurrentXoffIrp.SystemBuffer();

    ASSERT(m_CurrentXoffIrp);
    m_CountSinceXoff = Xc->Counter;

    // The isr now has a reference to the irp.

    SERIAL_SET_REFERENCE(
        m_CurrentXoffIrp,
        SERIAL_REF_ISR
        );

    return FALSE;
}

⌨️ 快捷键说明

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