intcom.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,163 行 · 第 1/3 页

C
1,163
字号
/* Copyright (c) 1998 Motorola Inc. All rights reserved. */

/*++

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:

    interrup.c

Abstract:

    This file contains the interrupt-handling routines that are
    called to handle Ethernet transmission, receive, and error
    events. This driver conforms to the NDIS 4.0 interface.

Functions:

    eth8xxEnableInterrupt()
    eth8xxDisableInterrupt()
    eth8xxIsr()
    eth8xxHandleInterrupt()
    eth8xxRcvDpc()
    eth8xxXmitDpc()
    eth8xxPacketOK()
    eth8xxIndicatePacket()
    eth8xxTransferData()
    eth8xxDoNextSend()

Notes:

    These functions process all of the events associated with
    incoming and outgoing Ethernet traffic. The NDIS wrapper 
    calls eth8xxSend() on behalf of the TCP/IP protocol stack
    to transmit new frames while eth8xxIndicatePacket() calls
    NDIS to notify it of newly arrived frames. Error conditions,
    when indicated by the Ethernet event register or the flags
    in the buffer descriptor, are currently handled by simply
    discarding the defective frame. It is up to higher level
    protocols (e.g., TCP/IP) to decide what to do when a frame
    is discarded. There is no real need for this device driver
    to attempt any fancy error recovery.

--*/


#include <ndis.h>

#include "eth8xx.h"

STATIC VOID    eth8xxIndicatePacket(IN PETH8XX_ADAPTER Adapter);
STATIC BOOLEAN eth8xxRcvDpc(IN PETH8XX_ADAPTER Adapter);
STATIC BOOLEAN eth8xxXmitDpc(IN PETH8XX_ADAPTER Adapter);
STATIC BOOLEAN eth8xxPacketOK(IN PETH8XX_ADAPTER Adapter, BD *cur_bd);
STATIC VOID    eth8xxIndicatePacket(IN PETH8XX_ADAPTER Adapter);


/*----------------------------------------------------------------------*/
VOID eth8xxEnableInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
/*++

Description:

    This routine enables interrupts from the Ethernet interface.

Arguments:

    MiniportAdapterContext - pointer to the NDIS miniport adapter block

Return Value:

    None

--*/
{
    PETH8XX_ADAPTER Adapter =
        PETH8XX_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR,
    (TEXT("+ETH8XX: eth8xxEnableInterrupt\r\n")));

    IF_LOG( eth8xxLog('P'); )
    IF_LOG( eth8xxLog('P'); )

    HW_Unblock_Interrupts(Adapter);

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR,
    (TEXT("-ETH8XX: eth8xxEnableInterrupt\r\n")));
}


/*----------------------------------------------------------------------*/
VOID eth8xxDisableInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
/*++

Description:

    This routine disables interrupts from the Ethernet interface.

Arguments:

    MiniportAdapterContext - pointer to the NDIS miniport adapter block

Return Value:

    None

--*/
{
    PETH8XX_ADAPTER Adapter =
        PETH8XX_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR,
    (TEXT("+ETH8XX: eth8xxDisableInterrupt\r\n")));

    IF_LOG( eth8xxLog('p'); )
    IF_LOG( eth8xxLog('p'); )

    HW_Block_Interrupts(Adapter);

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR,
    (TEXT("-ETH8XX: eth8xxDisableInterrupt\r\n")));
}


/*----------------------------------------------------------------------*/
VOID eth8xxIsr(OUT PBOOLEAN InterruptRecognized,
               OUT PBOOLEAN QueueDpc,
               IN PVOID Context)
/*++

Description:

    This is the interrupt handler which is registered with the NDIS
    wrapper. This routine is called with all interrupts to the Windows
    CE kernel disabled. Hence, it must be very short and simple. Its
    only function is to indicate whether it recognizes the interrupt
    and whether a "Deferred Procedure Call" (DPC) should be queued to
    complete the interrupt handling process.

Arguments:

    InterruptRecognized - Boolean value which returns TRUE if the
                          ISR recognizes the interrupt as coming
              from this adapter.
    QueueDpc            - TRUE if a DPC should be queued.
    Context             - pointer to the NDIS miniport adapter block

Return Value:

    None

--*/
{
    PETH8XX_ADAPTER Adapter = ((PETH8XX_ADAPTER)Context);

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR, (TEXT("+ETH8XX: eth8xxIsr\r\n")));

    IF_LOG( eth8xxLog('i'); )
    IF_LOG( eth8xxLog('i'); )

    /* Block all further Ethernet events while servicing this interrupt. */
    HW_Block_Interrupts(Adapter);

    *InterruptRecognized = TRUE; /* Yes, we do recognize this interrupt. */
    *QueueDpc            = TRUE; /* Yes, queue the NDIS-registered DPC.  */

    IF_LOG( eth8xxLog('I'); )
    IF_LOG( eth8xxLog('I'); )

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR, (TEXT("-ETH8XX: eth8xxIsr\r\n")));
}


/*----------------------------------------------------------------------*/
VOID eth8xxHandleInterrupt(IN NDIS_HANDLE MiniportAdapterContext)
/*++

Description:

    This is the deferred processing routine for Ethernet interrupts.
    It reads the SCC Interrupt Event Register to obtain all active
    events and subsequently handles them. If multiple events are
    simultaneously pending, they are serviced in the following fixed
    sequence:

    1. GRACEFUL STOP TX (completion of GRACEFUL STOP TX command)
    2. RX BUSY (frame discarded due to lack of receive buffers)
    3. RXB (buffer contains partial a frame)
    4. TXE (transmit error)
    5. RXF (buffer descriptor closed)
    6. TXB (buffer transmitted)

    The following aspects of the Ethernet interface must all be handled
    properly:

    1. The Ethernet receiver remains enabled while servicing
       interrupts. Hence, new incoming traffic may still arrive
       at any time if more than one receive buffer has been
       allocated.
    2. The Ethernet transmitter also remains enabled and the
       hardware may continue transmitting frames if more than
       one transmit buffer has been queued.
    3. Transmission and receive errors may still occur while
       servicing an interrupt.
    4. A single interrupt may be associated with multiple events,
       either due to a single action (e.g., a transmit error) or
           multiple actions (e.g., multiple frames have been received).
    5. This Deferred Procedure Call function is not re-entrant
       and Ethernet interrupts must be disabled by the interrupt
       handler eth8xxIsr().
        6. A consistently high Ethernet traffic load may exist for
       extended periods of time. Therefore, trying to handle all
       Ethernet events in a single call to this DPC may result
       in starving the rest of the system of CPU cycles (leading
       to a potential system crash).

    To handle the fact that the Ethernet hardware may still be processing
    incoming and outgoing frames in the background, this DPC will handle
    multiple buffers per call. This, however, may result in "spurious"
    interrupts (i.e., an interrupt is signalled but the buffer has already
    been processed in a previous call). Don't try to fix this by just
    clearing the Ethernet event register prior to exiting this DPC. This
    results in a very subtle race condition that can cause necessary
    interrupts to be lost.

    Loop termination counters are used to ensure that a consistently high
    Ethernet traffic load will not result in a loop that will starve the
    rest of the system of CPU cycles.

Arguments:

    MiniportAdapterContext - a handle to the adapter block.

Return Value:

    None

--*/
{
    PETH8XX_ADAPTER Adapter =         /* The adapter to process.   */
        PETH8XX_ADAPTER_FROM_CONTEXT_HANDLE(MiniportAdapterContext);
    UCHAR           InterruptStatus;  /* CPM event/intr. bits.     */
    UINT            count   = 0;      /* Loop termination counter. */

    DEBUGMSG(ZONE_FUNCTION | ZONE_INTR,
    (TEXT("+ETH8XX: eth8xxHandleInterrupt\r\n")));

    IF_LOG( eth8xxLog('d'); )
    IF_LOG( eth8xxLog('d'); )

    do
    {
    /* Get the event/interrupt bits and save them. */
    HW_Get_Interrupt_Status(Adapter, &InterruptStatus);
    Adapter->InterruptStatus |= InterruptStatus;

    DEBUGMSG(ZONE_INTR,
        (TEXT(" ETH8XX: new INTR: 0x%X, all INTR: 0x%X\r\n"),
        InterruptStatus, Adapter->InterruptStatus));

    if (Adapter->Status != ENABLED)
    {
        /* Don't do anything, adapter is shutting down or disabled. */
        DEBUGMSG(ZONE_INTR,
                (TEXT(" ETH8XX: interrupt ignored, interface not enabled.\r\n")));
            break;

    } else if (Adapter->InterruptStatus & ETH_GRA_EVENT) {

        IF_LOG( eth8xxLog('G'); )
        IF_LOG( eth8xxLog('G'); )

        /* Handle the GRACEFUL STOP TX event. */
        Adapter->Status = DISABLED;

        Adapter->InterruptStatus &= ~(ETH_GRA_EVENT);
        HW_Ack_Interrupt_Status(Adapter, ETH_GRA_EVENT);

        /* No need to do anything else; whoever issued the
         * GRACEFUL STOP TX command is also responsible for
         * cleaning up, and if desired, reinitializing, and
         * restarting the Ethernet interface.
         */
        break;
    }
        
    /* Check for Rx Busy Error condition. */
    if (Adapter->InterruptStatus & ETH_BSY_EVENT)
    {
        DEBUGMSG(ZONE_INTR | ZONE_RCV | ZONE_WARN,
            (TEXT(" ETH8XX: receiver BSY error\r\n")));

        IF_LOG( eth8xxLog('B'); )
        IF_LOG( eth8xxLog('B'); )

        Adapter->MissedPackets++;

        /* Clear the Busy interrupt bit. */
        Adapter->InterruptStatus &= ~(ETH_BSY_EVENT);
        HW_Ack_Interrupt_Status(Adapter, ETH_BSY_EVENT);

        /* Make sure to call eth8xxRcvDpc() later to try and free
         * up some receive buffer descriptors and data buffers.
         */
        Adapter->InterruptStatus |= ETH_RXF_EVENT;
    }

        /* Check for an incoming buffer that's not a complete frame.
     * This should never happen since all buffers are big enough
     * to hold the largest possible Ethernet frame (14 byte header
     * + 1500 bytes data + 4 bytes CRC = 1518 bytes).
     */
    if (Adapter->InterruptStatus & ETH_RXB_EVENT)
    {
        DEBUGMSG(ZONE_INTR | ZONE_RCV | ZONE_WARN,
            (TEXT(" ETH8XX: receiver RXB error\r\n")));

        IF_LOG( eth8xxLog('E'); )
        IF_LOG( eth8xxLog('E'); )

        /* Skip this buffer. Leave it up to higher-level protocols
         * to decide what, if any, recovery actions are required.
         */
        HW_Advance_Element(&(Adapter->ActiveRx),
                   ETH_RX_BD_MODE_MASK,
                   ETH_RX_EMPT,
                   Adapter->FirstRxBD,
                   Adapter->RxStart,
                   Adapter->LastRxBD,
                   Adapter->MaxRxBufferSize,
                   TRUE);

        /* Clear the RXB interrupt bit. */
        Adapter->InterruptStatus &= ~(ETH_RXB_EVENT);
        HW_Ack_Interrupt_Status(Adapter, ETH_RXB_EVENT);
    }

    /* Handle transmit errors. */
    if (Adapter->InterruptStatus & ETH_TXE_EVENT)
    {
        DEBUGMSG(ZONE_INTR | ZONE_XMIT | ZONE_WARN,
        (TEXT(" ETH8XX: transmitter TXE error\r\n")));

        IF_LOG( eth8xxLog('X'); )
        IF_LOG( eth8xxLog('X'); )

        /* Check for TX errors other than Carrier Sense Lost (CSL).
         * In the case of CSL, transmission continues normally so no
         * action is necessary. Any other error will halt the
         * transmitter and require an explicit RESTART TX command to
         * be issued.
         */
        if ((Adapter->ActiveTx.pBufferDescriptor != NULL)
        && (!(Adapter->ActiveTx.pBufferDescriptor->bd_status & ETH_TX_CSL)))
        {
        /* In that case, TRANSMIT RESTART command must be issued
         * to re-enable Ethernet transmission
         */
        if (!KernelIoControl(OEM_IOCTL_ISSUE_CPM_CMD, (LPVOID)SCC_ETH_CH_NUM,
            RESTART_TX, NOTUSED, NOTUSED, NOTUSED))
        {
            /* OOPS, cannot restart transmitter */
            DEBUGMSG(ZONE_INTR | ZONE_XMIT | ZONE_ERROR,
            (TEXT("*ETH8XX: RESTART TRANSMIT failed\r\n")));
            Adapter->Status = DISABLED;

        } else {

            DEBUGMSG(ZONE_INTR | ZONE_XMIT | ZONE_WARN,
            (TEXT(" ETH8XX: transmitter reenabled\r\n")));

            /* Transmitter successfully restarted. */
            Adapter->Status = ENABLED;

            /* Ensure that eth8xxXmitDpc() is called later. */
            Adapter->InterruptStatus |= ETH_TXB_EVENT;
        }

        } else {

        /* Ensure that eth8xxXmitDpc() is called later. */
        Adapter->InterruptStatus |= ETH_TXB_EVENT;
        }

⌨️ 快捷键说明

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