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 + -
显示快捷键?