Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218/* * ReactOS Realtek 8139 Driver * * Copyright (C) 2013 Cameron Gutman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */
#include "nic.h"
#define NDEBUG#include <debug.h>
VOIDNTAPIMiniportISR ( OUT PBOOLEAN InterruptRecognized, OUT PBOOLEAN QueueMiniportHandleInterrupt, IN NDIS_HANDLE MiniportAdapterContext ){ PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; ULONG csConfig;
// // FIXME: We need to synchronize with this ISR for changes to InterruptPending, // LinkChange, MediaState, and LinkSpeedMbps. We can get away with IRQL // synchronization on non-SMP machines because we run a DIRQL here. //
adapter->InterruptPending |= NICInterruptRecognized(adapter, InterruptRecognized); if (!(*InterruptRecognized)) { // // This is not ours. // *QueueMiniportHandleInterrupt = FALSE; return; }
// // We have to check for a special link change interrupt before acknowledging // if (adapter->InterruptPending & R_I_RXUNDRUN) { NdisRawReadPortUlong(adapter->IoBase + R_CSCFG, &csConfig); if (csConfig & R_CSCR_LINKCHNG) { adapter->LinkChange = TRUE; NICUpdateLinkStatus(adapter); } }
// // Acknowledge the interrupt and mark the events pending service // NICAcknowledgeInterrupts(adapter); *QueueMiniportHandleInterrupt = TRUE;}
VOIDNTAPIMiniportHandleInterrupt ( IN NDIS_HANDLE MiniportAdapterContext ){ PRTL_ADAPTER adapter = (PRTL_ADAPTER)MiniportAdapterContext; ULONG txStatus; UCHAR command; PPACKET_HEADER nicHeader; PETH_HEADER ethHeader;
NdisDprAcquireSpinLock(&adapter->Lock);
NDIS_DbgPrint(MAX_TRACE, ("Interrupts pending: 0x%x\n", adapter->InterruptPending));
// // Handle a link change // if (adapter->LinkChange) { NdisDprReleaseSpinLock(&adapter->Lock); NdisMIndicateStatus(adapter->MiniportAdapterHandle, adapter->MediaState == NdisMediaStateConnected ? NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT, NULL, 0); NdisMIndicateStatusComplete(adapter->MiniportAdapterHandle); NdisDprAcquireSpinLock(&adapter->Lock); adapter->LinkChange = FALSE; }
// // Handle a TX interrupt // if (adapter->InterruptPending & (R_I_TXOK | R_I_TXERR)) { while (adapter->TxFull || adapter->DirtyTxDesc != adapter->CurrentTxDesc) { NdisRawReadPortUlong(adapter->IoBase + R_TXSTS0 + (adapter->DirtyTxDesc * sizeof(ULONG)), &txStatus);
if (!(txStatus & (R_TXS_STATOK | R_TXS_UNDERRUN | R_TXS_ABORTED))) { // // Not sent yet // break; }
NDIS_DbgPrint(MAX_TRACE, ("Transmission for desc %d complete: 0x%x\n", adapter->DirtyTxDesc, txStatus));
if (txStatus & R_TXS_STATOK) { adapter->TransmitOk++; } else { adapter->TransmitError++; }
adapter->DirtyTxDesc++; adapter->DirtyTxDesc %= TX_DESC_COUNT; adapter->InterruptPending &= ~(R_I_TXOK | R_I_TXERR); adapter->TxFull = FALSE; } }
// // Handle a good RX interrupt // if (adapter->InterruptPending & (R_I_RXOK | R_I_RXERR)) { for (;;) { NdisRawReadPortUchar(adapter->IoBase + R_CMD, &command); if (command & R_CMD_RXEMPTY) { // // The buffer is empty // adapter->InterruptPending &= ~(R_I_RXOK | R_I_RXERR); break; }
adapter->ReceiveOffset %= RECEIVE_BUFFER_SIZE;
NDIS_DbgPrint(MAX_TRACE, ("Looking for a packet at offset 0x%x\n", adapter->ReceiveOffset)); nicHeader = (PPACKET_HEADER)(adapter->ReceiveBuffer + adapter->ReceiveOffset); if (!(nicHeader->Status & RSR_ROK)) { // // Receive failed // NDIS_DbgPrint(MIN_TRACE, ("Receive failed: 0x%x\n", nicHeader->Status));
if (nicHeader->Status & RSR_FAE) { adapter->ReceiveAlignmentError++; } else if (nicHeader->Status & RSR_CRC) { adapter->ReceiveCrcError++; } adapter->ReceiveError++;
goto NextPacket; }
NDIS_DbgPrint(MAX_TRACE, ("Indicating %d byte packet to NDIS\n", nicHeader->PacketLength - RECV_CRC_LENGTH));
ethHeader = (PETH_HEADER)(nicHeader + 1); NdisMEthIndicateReceive(adapter->MiniportAdapterHandle, NULL, (PVOID)(ethHeader), sizeof(ETH_HEADER), (PVOID)(ethHeader + 1), nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH, nicHeader->PacketLength - sizeof(ETH_HEADER) - RECV_CRC_LENGTH); adapter->ReceiveOk++;
NextPacket: adapter->ReceiveOffset += nicHeader->PacketLength + sizeof(PACKET_HEADER); adapter->ReceiveOffset = (adapter->ReceiveOffset + 3) & ~3; NdisRawWritePortUshort(adapter->IoBase + R_CAPR, adapter->ReceiveOffset - 0x10);
if (adapter->InterruptPending & (R_I_RXOVRFLW | R_I_FIFOOVR)) { // // We can only clear these interrupts once CAPR has been reset // NdisRawWritePortUshort(adapter->IoBase + R_IS, R_I_RXOVRFLW | R_I_FIFOOVR); adapter->InterruptPending &= ~(R_I_RXOVRFLW | R_I_FIFOOVR); } }
NdisMEthIndicateReceiveComplete(adapter->MiniportAdapterHandle); }
NdisDprReleaseSpinLock(&adapter->Lock);}