2 * ReactOS Realtek 8139 Driver
4 * Copyright (C) 2013 Cameron Gutman
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
30 OUT PBOOLEAN InterruptRecognized
,
31 OUT PBOOLEAN QueueMiniportHandleInterrupt
,
32 IN NDIS_HANDLE MiniportAdapterContext
35 PRTL_ADAPTER adapter
= (PRTL_ADAPTER
)MiniportAdapterContext
;
39 // FIXME: We need to synchronize with this ISR for changes to InterruptPending,
40 // LinkChange, MediaState, and LinkSpeedMbps. We can get away with IRQL
41 // synchronization on non-SMP machines because we run a DIRQL here.
44 adapter
->InterruptPending
|= NICInterruptRecognized(adapter
, InterruptRecognized
);
45 if (!(*InterruptRecognized
))
50 *QueueMiniportHandleInterrupt
= FALSE
;
55 // We have to check for a special link change interrupt before acknowledging
57 if (adapter
->InterruptPending
& R_I_RXUNDRUN
)
59 NdisRawReadPortUlong(adapter
->IoBase
+ R_CSCFG
, &csConfig
);
60 if (csConfig
& R_CSCR_LINKCHNG
)
62 adapter
->LinkChange
= TRUE
;
63 NICUpdateLinkStatus(adapter
);
68 // Acknowledge the interrupt and mark the events pending service
70 NICAcknowledgeInterrupts(adapter
);
71 *QueueMiniportHandleInterrupt
= TRUE
;
76 MiniportHandleInterrupt (
77 IN NDIS_HANDLE MiniportAdapterContext
80 PRTL_ADAPTER adapter
= (PRTL_ADAPTER
)MiniportAdapterContext
;
83 PPACKET_HEADER nicHeader
;
84 PETH_HEADER ethHeader
;
86 NdisDprAcquireSpinLock(&adapter
->Lock
);
88 NDIS_DbgPrint(MAX_TRACE
, ("Interrupts pending: 0x%x\n", adapter
->InterruptPending
));
91 // Handle a link change
93 if (adapter
->LinkChange
)
95 NdisDprReleaseSpinLock(&adapter
->Lock
);
96 NdisMIndicateStatus(adapter
->MiniportAdapterHandle
,
97 adapter
->MediaState
== NdisMediaStateConnected
?
98 NDIS_STATUS_MEDIA_CONNECT
: NDIS_STATUS_MEDIA_DISCONNECT
,
101 NdisMIndicateStatusComplete(adapter
->MiniportAdapterHandle
);
102 NdisDprAcquireSpinLock(&adapter
->Lock
);
103 adapter
->LinkChange
= FALSE
;
107 // Handle a TX interrupt
109 if (adapter
->InterruptPending
& (R_I_TXOK
| R_I_TXERR
))
111 while (adapter
->TxFull
|| adapter
->DirtyTxDesc
!= adapter
->CurrentTxDesc
)
113 NdisRawReadPortUlong(adapter
->IoBase
+ R_TXSTS0
+
114 (adapter
->DirtyTxDesc
* sizeof(ULONG
)), &txStatus
);
116 if (!(txStatus
& (R_TXS_STATOK
| R_TXS_UNDERRUN
| R_TXS_ABORTED
)))
124 NDIS_DbgPrint(MAX_TRACE
, ("Transmission for desc %d complete: 0x%x\n",
125 adapter
->DirtyTxDesc
, txStatus
));
127 if (txStatus
& R_TXS_STATOK
)
129 adapter
->TransmitOk
++;
133 adapter
->TransmitError
++;
136 adapter
->DirtyTxDesc
++;
137 adapter
->DirtyTxDesc
%= TX_DESC_COUNT
;
138 adapter
->InterruptPending
&= ~(R_I_TXOK
| R_I_TXERR
);
139 adapter
->TxFull
= FALSE
;
144 // Handle a good RX interrupt
146 if (adapter
->InterruptPending
& (R_I_RXOK
| R_I_RXERR
))
150 NdisRawReadPortUchar(adapter
->IoBase
+ R_CMD
, &command
);
151 if (command
& R_CMD_RXEMPTY
)
154 // The buffer is empty
156 adapter
->InterruptPending
&= ~(R_I_RXOK
| R_I_RXERR
);
160 adapter
->ReceiveOffset
%= RECEIVE_BUFFER_SIZE
;
162 NDIS_DbgPrint(MAX_TRACE
, ("Looking for a packet at offset 0x%x\n",
163 adapter
->ReceiveOffset
));
164 nicHeader
= (PPACKET_HEADER
)(adapter
->ReceiveBuffer
+ adapter
->ReceiveOffset
);
165 if (!(nicHeader
->Status
& RSR_ROK
))
170 NDIS_DbgPrint(MIN_TRACE
, ("Receive failed: 0x%x\n", nicHeader
->Status
));
172 if (nicHeader
->Status
& RSR_FAE
)
174 adapter
->ReceiveAlignmentError
++;
176 else if (nicHeader
->Status
& RSR_CRC
)
178 adapter
->ReceiveCrcError
++;
180 adapter
->ReceiveError
++;
185 NDIS_DbgPrint(MAX_TRACE
, ("Indicating %d byte packet to NDIS\n",
186 nicHeader
->PacketLength
- RECV_CRC_LENGTH
));
188 ethHeader
= (PETH_HEADER
)(nicHeader
+ 1);
189 NdisMEthIndicateReceive(adapter
->MiniportAdapterHandle
,
193 (PVOID
)(ethHeader
+ 1),
194 nicHeader
->PacketLength
- sizeof(ETH_HEADER
) - RECV_CRC_LENGTH
,
195 nicHeader
->PacketLength
- sizeof(ETH_HEADER
) - RECV_CRC_LENGTH
);
196 adapter
->ReceiveOk
++;
199 adapter
->ReceiveOffset
+= nicHeader
->PacketLength
+ sizeof(PACKET_HEADER
);
200 adapter
->ReceiveOffset
= (adapter
->ReceiveOffset
+ 3) & ~3;
201 NdisRawWritePortUshort(adapter
->IoBase
+ R_CAPR
, adapter
->ReceiveOffset
- 0x10);
203 if (adapter
->InterruptPending
& (R_I_RXOVRFLW
| R_I_FIFOOVR
))
206 // We can only clear these interrupts once CAPR has been reset
208 NdisRawWritePortUshort(adapter
->IoBase
+ R_IS
, R_I_RXOVRFLW
| R_I_FIFOOVR
);
209 adapter
->InterruptPending
&= ~(R_I_RXOVRFLW
| R_I_FIFOOVR
);
213 NdisMEthIndicateReceiveComplete(adapter
->MiniportAdapterHandle
);
216 NdisDprReleaseSpinLock(&adapter
->Lock
);