59a699944766a3b30d3d9a49772e98f1e1481a50
[reactos.git] / reactos / drivers / net / dd / ne2000 / ne2000 / 8390.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Novell Eagle 2000 driver
4 * FILE: ne2000/8390.c
5 * PURPOSE: DP8390 NIC specific routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * REVISIONS:
8 * CSH 27/08-2000 Created
9 */
10 #include <ne2000.h>
11
12
13 BOOLEAN NICCheck(
14 PNIC_ADAPTER Adapter)
15 /*
16 * FUNCTION: Tests for a NIC
17 * ARGUMENTS:
18 * Adapter = Pointer to adapter information
19 * RETURNS:
20 * TRUE if NIC is believed to be present, FALSE if not
21 * NOTES:
22 * If the adapter responds correctly to a
23 * stop command we assume it is present
24 */
25 {
26 UCHAR Tmp;
27
28 /* Disable interrupts */
29 NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, 0);
30
31 /* Stop the NIC */
32 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2);
33
34 /* Pause for 1.6ms */
35 NdisStallExecution(1600);
36
37 /* Read NIC response */
38 NdisRawReadPortUchar(Adapter->IOBase + PG0_CR, &Tmp);
39
40 if ((Tmp == (CR_RD2 | CR_STP)) || (Tmp == (CR_RD2 | CR_STP | CR_STA)))
41 return TRUE;
42 else
43 return FALSE;
44 }
45
46
47 BOOLEAN NICTestAddress(
48 PNIC_ADAPTER Adapter,
49 ULONG Address)
50 /*
51 * FUNCTION: Tests if an address is writable
52 * ARGUMENTS:
53 * Adapter = Pointer to adapter information
54 * RETURNS:
55 * TRUE if the address is writable, FALSE if not
56 */
57 {
58 USHORT Data;
59 USHORT Tmp;
60
61 /* Read one word */
62 NICReadDataAlign(Adapter, &Data, Address, 0x02);
63
64 /* Alter it */
65 Data ^= 0xFFFF;
66
67 /* Write it back */
68 NICWriteDataAlign(Adapter, Address, &Data, 0x02);
69
70 /* Check if it has changed on the NIC */
71 NICReadDataAlign(Adapter, &Tmp, Address, 0x02);
72
73 return (Data == Tmp);
74 }
75
76
77 BOOLEAN NICTestRAM(
78 PNIC_ADAPTER Adapter)
79 /*
80 * FUNCTION: Finds out how much RAM a NIC has
81 * ARGUMENTS:
82 * Adapter = Pointer to adapter information
83 * RETURNS:
84 * TRUE if the RAM size was found, FALSE if not
85 * NOTES:
86 * Start at 1KB and test for every 1KB up to 64KB
87 */
88 {
89 ULONG Base;
90
91 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
92
93 /* Locate RAM base address */
94 for (Base = 0x0400; Base < 0x10000; Base += 0x0400) {
95 if (NICTestAddress(Adapter, Base))
96 break;
97 }
98
99 if (Base == 0x10000) {
100 /* No RAM on this board */
101 NDIS_DbgPrint(MIN_TRACE, ("No RAM found on board.\n"));
102 return FALSE;
103 }
104
105 Adapter->RamBase = (PUCHAR)Base;
106
107 /* Find RAM size */
108 for (; Base < 0x10000; Base += 0x0400) {
109 if (!NICTestAddress(Adapter, Base))
110 break;
111 }
112
113 Adapter->RamSize = (UINT)(Base - (ULONG_PTR)Adapter->RamBase);
114
115 NDIS_DbgPrint(MID_TRACE, ("RAM is at (0x%X). Size is (0x%X).\n",
116 Adapter->RamBase, Adapter->RamSize));
117
118 return TRUE;
119 }
120
121
122 VOID NICSetPhysicalAddress(
123 PNIC_ADAPTER Adapter)
124 /*
125 * FUNCTION: Initializes the physical address on the NIC
126 * ARGUMENTS:
127 * Adapter = Pointer to adapter information
128 * NOTES:
129 * The physical address is taken from Adapter.
130 * The NIC is stopped by this operation
131 */
132 {
133 UINT i;
134
135 /* Select page 1 */
136 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
137
138 /* Initialize PAR - Physical Address Registers */
139 for (i = 0; i < 0x06; i++)
140 NdisRawWritePortUchar(Adapter->IOBase + PG1_PAR + i, Adapter->StationAddress[i]);
141
142 /* Go back to page 0 */
143 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
144 }
145
146
147 VOID NICSetMulticastAddressMask(
148 PNIC_ADAPTER Adapter)
149 /*
150 * FUNCTION: Initializes the multicast address mask on the NIC
151 * ARGUMENTS:
152 * Adapter = Pointer to adapter information
153 * NOTES:
154 * The multicast address mask is taken from Adapter.
155 * The NIC is stopped by this operation
156 */
157 {
158 UINT i;
159
160 /* Select page 1 */
161 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
162
163 /* Initialize MAR - Multicast Address Registers */
164 for (i = 0; i < 0x08; i++)
165 NdisRawWritePortUchar(Adapter->IOBase + PG1_MAR + i, Adapter->MulticastAddressMask[i]);
166
167 /* Go back to page 0 */
168 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
169 }
170
171
172 BOOLEAN NICReadSAPROM(
173 PNIC_ADAPTER Adapter)
174 /*
175 * FUNCTION: Reads the Station Address PROM data from the NIC
176 * ARGUMENTS:
177 * Adapter = Pointer to adapter information
178 * RETURNS:
179 * TRUE if a the NIC is an NE2000
180 * NOTES:
181 * This routine also determines if the NIC can support word mode transfers
182 * and if it does initializes the NIC for word mode.
183 * The station address in the adapter structure is initialized with
184 * the address from the SAPROM
185 */
186 {
187 UINT i;
188 UCHAR Buffer[32];
189 UCHAR WordLength;
190
191 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
192
193 /* Read Station Address PROM (SAPROM) which is 16 bytes at remote DMA address 0.
194 Some cards double the data read which we must compensate for */
195
196 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
197 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x20);
198 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
199
200 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
201 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, 0x00);
202 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, 0x00);
203
204 /* Select page 0, read and start the NIC */
205 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
206
207 /* Read one byte at a time */
208 WordLength = 2; /* Assume a word is two bytes */
209 for (i = 0; i < 32; i += 2) {
210 NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i]);
211 NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i + 1]);
212 if (Buffer[i] != Buffer[i + 1])
213 WordLength = 1; /* A word is one byte long */
214 }
215
216 /* If WordLength is 2 the data read before was doubled. We must compensate for this */
217 if (WordLength == 2) {
218 DbgPrint("NE2000 or compatible network adapter found.\n");
219
220 Adapter->WordMode = TRUE;
221
222 /* Move the SAPROM data to the adapter object */
223 for (i = 0; i < 16; i++)
224 Adapter->SAPROM[i] = Buffer[i * 2];
225
226 /* Copy the station address */
227 NdisMoveMemory(
228 (PVOID)&Adapter->StationAddress,
229 (PVOID)&Adapter->SAPROM,
230 DRIVER_LENGTH_OF_ADDRESS);
231
232 /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
233 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
234
235 return TRUE;
236 } else {
237 DbgPrint("NE1000 or compatible network adapter found.\n");
238
239 Adapter->WordMode = FALSE;
240
241 return FALSE;
242 }
243 }
244
245
246 NDIS_STATUS NICInitialize(
247 PNIC_ADAPTER Adapter)
248 /*
249 * FUNCTION: Initializes a NIC
250 * ARGUMENTS:
251 * Adapter = Pointer to adapter information
252 * RETURNS:
253 * Status of NIC initialization
254 * NOTES:
255 * The NIC is put into loopback mode
256 */
257 {
258 UCHAR Tmp;
259
260 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
261
262 if (!NICCheck(Adapter)) {
263 NDIS_DbgPrint(MID_TRACE, ("No adapter found at (0x%X).\n", Adapter->IOBase));
264 return NDIS_STATUS_ADAPTER_NOT_FOUND;
265 } else
266 NDIS_DbgPrint(MID_TRACE, ("Adapter found at (0x%X).\n", Adapter->IOBase));
267
268 /* Reset the NIC */
269 NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
270
271 /* Wait for 1.6ms */
272 NdisStallExecution(1600);
273
274 /* Write the value back */
275 NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
276
277 /* Select page 0 and stop NIC */
278 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
279
280 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
281 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
282
283 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
284 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
285 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
286
287 /* Initialize RCR - Receive Configuration Register (monitor mode) */
288 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
289
290 /* Enter loopback mode (internal NIC module loopback) */
291 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
292
293 /* Read the Station Address PROM */
294 if (!NICReadSAPROM(Adapter))
295 return NDIS_STATUS_ADAPTER_NOT_FOUND;
296
297 NDIS_DbgPrint(MID_TRACE, ("Station address is (%02X %02X %02X %02X %02X %02X).\n",
298 Adapter->StationAddress[0], Adapter->StationAddress[1],
299 Adapter->StationAddress[2], Adapter->StationAddress[3],
300 Adapter->StationAddress[4], Adapter->StationAddress[5]));
301
302 /* Select page 0 and start NIC */
303 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
304
305 /* Clear ISR - Interrupt Status Register */
306 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
307
308 /* Find NIC RAM size */
309 NICTestRAM(Adapter);
310
311 return NDIS_STATUS_SUCCESS;
312 }
313
314
315 NDIS_STATUS NICSetup(
316 PNIC_ADAPTER Adapter)
317 /*
318 * FUNCTION: Sets up a NIC
319 * ARGUMENTS:
320 * Adapter = Pointer to adapter information
321 * RETURNS:
322 * Status of operation
323 * NOTES:
324 * The NIC is put into loopback mode
325 */
326 {
327 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
328
329 if (Adapter->WordMode ) {
330 /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
331 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
332 } else {
333 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
334 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
335 }
336
337 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
338 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
339 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
340
341 /* Initialize RCR - Receive Configuration Register (monitor mode) */
342 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
343
344 /* Enter loopback mode (internal NIC module loopback) */
345 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
346
347 /* Set boundary page */
348 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY, Adapter->NextPacket);
349
350 /* Set start page */
351 NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTART, Adapter->PageStart);
352
353 /* Set stop page */
354 NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTOP, Adapter->PageStop);
355
356 /* Program our address on the NIC */
357 NICSetPhysicalAddress(Adapter);
358
359 /* Program the multicast address mask on the NIC */
360 NICSetMulticastAddressMask(Adapter);
361
362 /* Select page 1 and stop NIC */
363 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
364
365 /* Initialize current page register */
366 NdisRawWritePortUchar(Adapter->IOBase + PG1_CURR, Adapter->PageStart + 1);
367
368 /* Select page 0 and stop NIC */
369 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
370
371 /* Clear ISR - Interrupt Status Register */
372 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
373
374 /* Initialize IMR - Interrupt Mask Register */
375 NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, Adapter->InterruptMask);
376
377 /* Select page 0 and start NIC */
378 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
379
380 Adapter->CurrentPage = Adapter->PageStart + 1;
381 Adapter->NextPacket = Adapter->PageStart + 1;
382 Adapter->BufferOverflow = FALSE;
383 Adapter->ReceiveError = FALSE;
384 Adapter->TransmitError = FALSE;
385
386 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
387
388 return NDIS_STATUS_SUCCESS;
389 }
390
391
392 NDIS_STATUS NICStart(
393 PNIC_ADAPTER Adapter)
394 /*
395 * FUNCTION: Starts a NIC
396 * ARGUMENTS:
397 * Adapter = Pointer to adapter information
398 * RETURNS:
399 * Status of operation
400 */
401 {
402 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
403
404 /* Take NIC out of loopback mode */
405 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, 0x00);
406
407 /* Initialize RCR - Receive Configuration Register (accept all) */
408 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_AB | RCR_AM | RCR_PRO);
409
410 return NDIS_STATUS_SUCCESS;
411 }
412
413
414 NDIS_STATUS NICStop(
415 PNIC_ADAPTER Adapter)
416 /*
417 * FUNCTION: Stops a NIC
418 * ARGUMENTS:
419 * Adapter = Pointer to adapter information
420 * RETURNS:
421 * Status of operation
422 */
423 {
424 UCHAR Tmp;
425 UINT i;
426
427 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
428
429 /* Select page 0 and stop NIC */
430 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
431
432 /* Clear Remote Byte Count Register so ISR_RST will be set */
433 NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
434 NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
435
436 /* Wait for ISR_RST to be set, but timeout after 2ms */
437 for (i = 0; i < 4; i++) {
438 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
439 if (Tmp & ISR_RST)
440 break;
441
442 NdisStallExecution(500);
443 }
444
445 #ifdef DBG
446 if (i == 4)
447 NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
448 #endif
449
450 /* Initialize RCR - Receive Configuration Register (monitor mode) */
451 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
452
453 /* Initialize TCR - Transmit Configuration Register (loopback mode) */
454 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
455
456 /* Start NIC */
457 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
458
459 return NDIS_STATUS_SUCCESS;
460 }
461
462
463 NDIS_STATUS NICReset(
464 PNIC_ADAPTER Adapter)
465 /*
466 * FUNCTION: Resets a NIC
467 * ARGUMENTS:
468 * Adapter = Pointer to adapter information
469 * RETURNS:
470 * Status of operation
471 */
472 {
473 UCHAR Tmp;
474
475 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
476
477 /* Stop the NIC */
478 NICStop(Adapter);
479
480 /* Reset the NIC */
481 NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
482
483 /* Wait for 1.6ms */
484 NdisStallExecution(1600);
485
486 /* Write the value back */
487 NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
488
489 /* Restart the NIC */
490 NICStart(Adapter);
491
492 return NDIS_STATUS_SUCCESS;
493 }
494
495
496 VOID NICStartTransmit(
497 PNIC_ADAPTER Adapter)
498 /*
499 * FUNCTION: Starts transmitting a packet
500 * ARGUMENTS:
501 * Adapter = Pointer to adapter information
502 */
503 {
504 UINT Length;
505
506 /* Set start of frame */
507 NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR,
508 Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE);
509
510 /* Set length of frame */
511 Length = Adapter->TXSize[Adapter->TXCurrent];
512 NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR0, Length & 0xFF);
513 NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR1, Length >> 8);
514
515 /* Start transmitting */
516 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_TXP | CR_RD2);
517
518 NDIS_DbgPrint(MAX_TRACE, ("Transmitting. Buffer (%d) Size (%d).\n",
519 Adapter->TXCurrent,
520 Length));
521
522 }
523
524
525 VOID NICSetBoundaryPage(
526 PNIC_ADAPTER Adapter)
527 /*
528 * FUNCTION: Sets the boundary page on the adapter to be one less than NextPacket
529 * ARGUMENTS:
530 * Adapter = Pointer to adapter information
531 */
532 {
533 if (Adapter->NextPacket == Adapter->PageStart) {
534 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
535 (UCHAR)(Adapter->PageStop - 1));
536 } else {
537 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
538 (UCHAR)(Adapter->NextPacket - 1));
539 }
540 }
541
542
543 VOID NICGetCurrentPage(
544 PNIC_ADAPTER Adapter)
545 /*
546 * FUNCTION: Retrieves the current page from the adapter
547 * ARGUMENTS:
548 * Adapter = Pointer to adapter information
549 */
550 {
551 UCHAR Current;
552
553 /* Select page 1 */
554 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE1);
555
556 /* Read current page */
557 NdisRawReadPortUchar(Adapter->IOBase + PG1_CURR, &Current);
558
559 /* Select page 0 */
560 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
561
562 Adapter->CurrentPage = Current;
563 }
564
565
566 VOID NICUpdateCounters(
567 PNIC_ADAPTER Adapter)
568 /*
569 * FUNCTION: Updates counters
570 * ARGUMENTS:
571 * Adapter = Pointer to adapter information
572 */
573 {
574 UCHAR Tmp;
575
576 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
577
578 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR0, &Tmp);
579 Adapter->FrameAlignmentErrors += Tmp;
580
581 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR1, &Tmp);
582 Adapter->CrcErrors += Tmp;
583
584 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR2, &Tmp);
585 Adapter->MissedPackets += Tmp;
586 }
587
588
589 VOID NICReadDataAlign(
590 PNIC_ADAPTER Adapter,
591 PUSHORT Target,
592 ULONG Source,
593 USHORT Length)
594 /*
595 * FUNCTION: Copies data from a NIC's RAM into a buffer
596 * ARGUMENTS:
597 * Adapter = Pointer to adapter information
598 * Target = Pointer to buffer to copy data into (in host memory)
599 * Source = Offset into NIC's RAM (must be an even number)
600 * Length = Number of bytes to copy from NIC's RAM (must be an even number)
601 */
602 {
603 UCHAR Tmp;
604 USHORT Count;
605
606 Count = Length;
607
608 /* Select page 0 and start the NIC */
609 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
610
611 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
612 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Source & 0xFF));
613 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Source >> 8));
614
615 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
616 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
617 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
618
619 /* Select page 0, read and start the NIC */
620 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
621
622 if (Adapter->WordMode)
623 NdisRawReadPortBufferUshort(Adapter->IOBase + NIC_DATA, Target, Count >> 1);
624 else
625 NdisRawReadPortBufferUchar(Adapter->IOBase + NIC_DATA, Target, Count);
626
627 /* Wait for remote DMA to complete, but timeout after some time */
628 for (Count = 0; Count < 0xFFFF; Count++) {
629 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
630 if (Tmp & ISR_RDC)
631 break;
632
633 NdisStallExecution(4);
634 }
635
636 #ifdef DBG
637 if (Count == 0xFFFF)
638 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
639 #endif
640
641 /* Clear remote DMA bit in ISR - Interrupt Status Register */
642 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
643 }
644
645
646 VOID NICWriteDataAlign(
647 PNIC_ADAPTER Adapter,
648 ULONG Target,
649 PUSHORT Source,
650 USHORT Length)
651 /*
652 * FUNCTION: Copies data from a buffer into the NIC's RAM
653 * ARGUMENTS:
654 * Adapter = Pointer to adapter information
655 * Target = Offset into NIC's RAM (must be an even number)
656 * Source = Pointer to buffer to copy data from (in host memory)
657 * Length = Number of bytes to copy from the buffer (must be an even number)
658 */
659 {
660 UCHAR Tmp;
661 USHORT Count;
662
663 /* Select page 0 and start the NIC */
664 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
665
666 /* Handle read-before-write bug */
667
668 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
669 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
670 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
671
672 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
673 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x02);
674 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
675
676 /* Read and start the NIC */
677 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
678
679 /* Read data */
680 NdisRawReadPortUshort(Adapter->IOBase + NIC_DATA, &Count);
681
682 /* Wait for remote DMA to complete, but timeout after some time */
683 for (Count = 0; Count < 0xFFFF; Count++) {
684 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
685 if (Tmp & ISR_RDC)
686 break;
687
688 NdisStallExecution(4);
689 }
690
691 #ifdef DBG
692 if (Count == 0xFFFF)
693 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
694 #endif
695
696 /* Clear remote DMA bit in ISR - Interrupt Status Register */
697 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
698
699
700 /* Now output some data */
701
702 Count = Length;
703
704 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
705 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
706 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
707
708 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
709 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
710 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
711
712 /* Write and start the NIC */
713 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD1 | CR_PAGE0);
714
715 if (Adapter->WordMode)
716 NdisRawWritePortBufferUshort(Adapter->IOBase + NIC_DATA, Source, Count >> 1);
717 else
718 NdisRawWritePortBufferUchar(Adapter->IOBase + NIC_DATA, Source, Count);
719
720 /* Wait for remote DMA to complete, but timeout after some time */
721 for (Count = 0; Count < 0xFFFF; Count++) {
722 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
723 if (Tmp & ISR_RDC)
724 break;
725
726 NdisStallExecution(4);
727 }
728
729 #ifdef DBG
730 if (Count == 0xFFFF)
731 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
732 #endif
733
734 /* Clear remote DMA bit in ISR - Interrupt Status Register */
735 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
736 }
737
738
739 VOID NICReadData(
740 PNIC_ADAPTER Adapter,
741 PUCHAR Target,
742 ULONG Source,
743 USHORT Length)
744 /*
745 * FUNCTION: Copies data from a NIC's RAM into a buffer
746 * ARGUMENTS:
747 * Adapter = Pointer to adapter information
748 * Target = Pointer to buffer to copy data into (in host memory)
749 * Source = Offset into NIC's RAM
750 * Length = Number of bytes to copy from NIC's RAM
751 */
752 {
753 USHORT Tmp;
754
755 /* Avoid transfers to odd addresses */
756 if (Source & 0x01) {
757 /* Transfer one word and use the MSB */
758 NICReadDataAlign(Adapter, &Tmp, Source - 1, 0x02);
759 *Target = (UCHAR)(Tmp >> 8);
760 Source++;
761 Target++;
762 Length--;
763 }
764
765 if (Length & 0x01) {
766 /* Transfer as many words as we can without exceeding the buffer length */
767 Tmp = Length & 0xFFFE;
768 NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Tmp);
769 Source += Tmp;
770 (ULONG_PTR)Target += Tmp;
771
772 /* Read one word and keep the LSB */
773 NICReadDataAlign(Adapter, &Tmp, Source, 0x02);
774 *Target = (UCHAR)(Tmp & 0x00FF);
775 } else
776 /* Transfer the rest of the data */
777 NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Length);
778 }
779
780
781 VOID NICWriteData(
782 PNIC_ADAPTER Adapter,
783 ULONG Target,
784 PUCHAR Source,
785 USHORT Length)
786 /*
787 * FUNCTION: Copies data from a buffer into NIC's RAM
788 * ARGUMENTS:
789 * Adapter = Pointer to adapter information
790 * Target = Offset into NIC's RAM to store data
791 * Source = Pointer to buffer to copy data from (in host memory)
792 * Length = Number of bytes to copy from buffer
793 */
794 {
795 USHORT Tmp;
796
797 /* Avoid transfers to odd addresses */
798 if (Target & 0x01) {
799 /* Read one word */
800 NICReadDataAlign(Adapter, &Tmp, Target - 1, 0x02);
801
802 /* Merge LSB with the new byte which become the new MSB */
803 Tmp = (Tmp & 0x00FF) | (*Source << 8);
804
805 /* Finally write the value back */
806 NICWriteDataAlign(Adapter, Target - 1, &Tmp, 0x02);
807
808 /* Update pointers */
809 (ULONG_PTR)Source += 1;
810 (ULONG_PTR)Target += 1;
811 Length--;
812 }
813
814 if (Length & 0x01) {
815 /* Transfer as many words as we can without exceeding the transfer length */
816 Tmp = Length & 0xFFFE;
817 NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Tmp);
818 Source += Tmp;
819 (ULONG_PTR)Target += Tmp;
820
821 /* Read one word */
822 NICReadDataAlign(Adapter, &Tmp, Target, 0x02);
823
824 /* Merge MSB with the new byte which become the new LSB */
825 Tmp = (Tmp & 0xFF00) | (*Source);
826
827 /* Finally write the value back */
828 NICWriteDataAlign(Adapter, Target, &Tmp, 0x02);
829 } else
830 /* Transfer the rest of the data */
831 NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Length);
832 }
833
834
835 VOID NICIndicatePacket(
836 PNIC_ADAPTER Adapter)
837 /*
838 * FUNCTION: Indicates a packet to the wrapper
839 * ARGUMENTS:
840 * Adapter = Pointer to adapter information
841 */
842 {
843 UINT IndicateLength;
844
845 IndicateLength = (Adapter->PacketHeader.PacketLength <
846 (Adapter->LookaheadSize + DRIVER_HEADER_SIZE))?
847 (Adapter->PacketHeader.PacketLength) :
848 (Adapter->LookaheadSize + DRIVER_HEADER_SIZE);
849
850 /* Fill the lookahead buffer */
851 NICReadData(Adapter,
852 (PUCHAR)&Adapter->Lookahead,
853 Adapter->PacketOffset + sizeof(PACKET_HEADER),
854 IndicateLength + DRIVER_HEADER_SIZE);
855
856 NDIS_DbgPrint(MAX_TRACE, ("Indicating (%d) bytes.\n", IndicateLength));
857
858 #if 0
859 NDIS_DbgPrint(MAX_TRACE, ("FRAME:\n"));
860 for (i = 0; i < (IndicateLength + 7) / 8; i++) {
861 NDIS_DbgPrint(MAX_TRACE, ("%02X %02X %02X %02X %02X %02X %02X %02X\n",
862 Adapter->Lookahead[i*8+0],
863 Adapter->Lookahead[i*8+1],
864 Adapter->Lookahead[i*8+2],
865 Adapter->Lookahead[i*8+3],
866 Adapter->Lookahead[i*8+4],
867 Adapter->Lookahead[i*8+5],
868 Adapter->Lookahead[i*8+6],
869 Adapter->Lookahead[i*8+7]));
870 }
871 #endif
872
873 if (IndicateLength >= DRIVER_HEADER_SIZE) {
874 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
875 NULL,
876 (PVOID)&Adapter->Lookahead,
877 DRIVER_HEADER_SIZE,
878 (PVOID)&Adapter->Lookahead[DRIVER_HEADER_SIZE],
879 IndicateLength - DRIVER_HEADER_SIZE,
880 Adapter->PacketHeader.PacketLength - DRIVER_HEADER_SIZE);
881 } else {
882 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
883 NULL,
884 (PVOID)&Adapter->Lookahead,
885 IndicateLength,
886 NULL,
887 0,
888 0);
889 }
890 }
891
892
893 VOID NICReadPacket(
894 PNIC_ADAPTER Adapter)
895 /*
896 * FUNCTION: Reads a full packet from the receive buffer ring
897 * ARGUMENTS:
898 * Adapter = Pointer to adapter information
899 */
900 {
901 BOOLEAN SkipPacket = FALSE;
902
903 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
904
905 /* Get the header of the next packet in the receive ring */
906 Adapter->PacketOffset = Adapter->NextPacket << 8;
907 NICReadData(Adapter,
908 (PUCHAR)&Adapter->PacketHeader,
909 Adapter->PacketOffset,
910 sizeof(PACKET_HEADER));
911
912 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (Status) (0x%X)\n", Adapter->PacketHeader.Status));
913 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (NextPacket) (0x%X)\n", Adapter->PacketHeader.NextPacket));
914 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (PacketLength) (0x%X)\n", Adapter->PacketHeader.PacketLength));
915
916 if (Adapter->PacketHeader.PacketLength < 64 ||
917 Adapter->PacketHeader.PacketLength > 1518) {
918 NDIS_DbgPrint(MAX_TRACE, ("Bogus packet size (%d).\n",
919 Adapter->PacketHeader.PacketLength));
920 SkipPacket = TRUE;
921 }
922
923 if (SkipPacket) {
924 /* Skip packet */
925 Adapter->NextPacket = Adapter->CurrentPage;
926 } else {
927 NICIndicatePacket(Adapter);
928
929 /* Go to the next free buffer in receive ring */
930 Adapter->NextPacket = Adapter->PacketHeader.NextPacket;
931 }
932
933 /* Update boundary page */
934 NICSetBoundaryPage(Adapter);
935 }
936
937
938 VOID NICWritePacket(
939 PNIC_ADAPTER Adapter)
940 /*
941 * FUNCTION: Writes a full packet to the transmit buffer ring
942 * ARGUMENTS:
943 * Adapter = Pointer to adapter information
944 * NOTES:
945 * There must be enough free buffers available in the transmit buffer ring.
946 * The packet is taken from the head of the transmit queue and the position
947 * into the transmit buffer ring is taken from TXNext
948 */
949 {
950 PNDIS_BUFFER SrcBuffer;
951 UINT BytesToCopy, SrcSize, DstSize;
952 PUCHAR SrcData;
953 ULONG DstData;
954 UINT TXStart;
955 UINT TXStop;
956
957 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
958
959 TXStart = Adapter->TXStart * DRIVER_BLOCK_SIZE;
960 TXStop = (Adapter->TXStart + Adapter->TXCount) * DRIVER_BLOCK_SIZE;
961
962 NdisQueryPacket(Adapter->TXQueueHead,
963 NULL,
964 NULL,
965 &SrcBuffer,
966 &Adapter->TXSize[Adapter->TXNext]);
967
968 NDIS_DbgPrint(MAX_TRACE, ("Packet Size (%d) is now (%d).\n",
969 Adapter->TXNext,
970 Adapter->TXSize[Adapter->TXNext]));
971
972 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
973
974 DstData = TXStart + Adapter->TXNext * DRIVER_BLOCK_SIZE;
975 DstSize = TXStop - DstData;
976
977 /* Start copying the data */
978 for (;;) {
979 BytesToCopy = (SrcSize < DstSize)? SrcSize : DstSize;
980
981 NICWriteData(Adapter, DstData, SrcData, BytesToCopy);
982
983 (ULONG_PTR)SrcData += BytesToCopy;
984 SrcSize -= BytesToCopy;
985 DstData += BytesToCopy;
986 DstSize -= BytesToCopy;
987
988 if (SrcSize == 0) {
989 /* No more bytes in source buffer. Proceed to
990 the next buffer in the source buffer chain */
991 NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
992 if (!SrcBuffer)
993 break;
994
995 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
996 }
997
998 if (DstSize == 0) {
999 /* Wrap around the end of the transmit buffer ring */
1000 DstData = TXStart;
1001 DstSize = Adapter->TXCount * DRIVER_BLOCK_SIZE;
1002 }
1003 }
1004 }
1005
1006
1007 BOOLEAN NICPrepareForTransmit(
1008 PNIC_ADAPTER Adapter)
1009 /*
1010 * FUNCTION: Prepares a packet for transmission
1011 * ARGUMENTS:
1012 * Adapter = Pointer to adapter information
1013 * NOTES:
1014 * There must be at least one packet in the transmit queue
1015 * RETURNS:
1016 * TRUE if a packet was prepared, FALSE if not
1017 */
1018 {
1019 UINT Length;
1020 UINT BufferCount;
1021 PNDIS_PACKET Packet;
1022
1023 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1024
1025 /* Calculate number of buffers needed to transmit packet */
1026 NdisQueryPacket(Adapter->TXQueueHead,
1027 NULL,
1028 NULL,
1029 NULL,
1030 &Length);
1031
1032 BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
1033
1034 if (BufferCount > Adapter->TXFree) {
1035 NDIS_DbgPrint(MID_TRACE, ("No transmit resources. Have (%d) buffers, need (%d).\n",
1036 Adapter->TXFree, BufferCount));
1037 /* We don't have the resources to transmit this packet right now */
1038 return FALSE;
1039 }
1040
1041 /* Write the packet to the card */
1042 NICWritePacket(Adapter);
1043
1044 /* If the NIC is not transmitting, reset the current transmit pointer */
1045 if (Adapter->TXCurrent == -1)
1046 Adapter->TXCurrent = Adapter->TXNext;
1047
1048 Adapter->TXNext = (Adapter->TXNext + BufferCount) % Adapter->TXCount;
1049 Adapter->TXFree -= BufferCount;
1050
1051 /* Remove the packet from the queue */
1052 Packet = Adapter->TXQueueHead;
1053 Adapter->TXQueueHead = RESERVED(Packet)->Next;
1054
1055 if (Packet == Adapter->TXQueueTail)
1056 Adapter->TXQueueTail = NULL;
1057
1058 /* Assume the transmit went well */
1059 NdisMSendComplete(Adapter->MiniportAdapterHandle,
1060 Packet,
1061 NDIS_STATUS_SUCCESS);
1062
1063 return TRUE;
1064 }
1065
1066
1067 VOID NICTransmit(
1068 PNIC_ADAPTER Adapter)
1069 /*
1070 * FUNCTION: Starts transmitting packets in the transmit queue
1071 * ARGUMENTS:
1072 * Adapter = Pointer to adapter information
1073 * NOTES:
1074 * There must be at least one packet in the transmit queue
1075 */
1076 {
1077 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1078
1079 if (Adapter->TXCurrent == -1) {
1080 /* NIC is not transmitting, so start transmitting now */
1081
1082 /* Load next packet onto the card, and start transmitting */
1083 if (NICPrepareForTransmit(Adapter))
1084 NICStartTransmit(Adapter);
1085 }
1086 }
1087
1088
1089 VOID HandleReceive(
1090 PNIC_ADAPTER Adapter)
1091 /*
1092 * FUNCTION: Handles reception of a packet
1093 * ARGUMENTS:
1094 * Adapter = Pointer to adapter information
1095 * NOTES:
1096 * Buffer overflows are also handled here
1097 */
1098 {
1099 UINT i;
1100 UCHAR Tmp;
1101 UINT PacketCount;
1102
1103 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1104
1105 Adapter->DoneIndicating = FALSE;
1106 PacketCount = 0;
1107
1108 NICGetCurrentPage(Adapter);
1109
1110 if (Adapter->BufferOverflow) {
1111
1112 NDIS_DbgPrint(MAX_TRACE, ("Receive ring overflow.\n"));
1113
1114 /* Select page 0 and stop the NIC */
1115 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
1116
1117 /* Clear RBCR0,RBCR1 - Remote Byte Count Registers */
1118 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
1119 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
1120
1121 /* Wait for ISR_RST to be set, but timeout after 2ms */
1122 for (i = 0; i < 4; i++) {
1123 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
1124 if (Tmp & ISR_RST)
1125 break;
1126
1127 NdisStallExecution(500);
1128 }
1129
1130 #ifdef DBG
1131 if (i == 4)
1132 NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
1133 #endif
1134
1135 if ((Adapter->InterruptStatus & (ISR_PTX | ISR_TXE)) == 0) {
1136 /* We may need to restart the transmitter */
1137 Adapter->TransmitPending = TRUE;
1138 }
1139
1140 /* Initialize TCR - Transmit Configuration Register to loopback mode 1 */
1141 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
1142
1143 /* Start NIC */
1144 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
1145
1146 NICStart(Adapter);
1147
1148 Adapter->BufferOverflow = FALSE;
1149 }
1150
1151 if (Adapter->ReceiveError) {
1152 NDIS_DbgPrint(MAX_TRACE, ("Receive error.\n"));
1153
1154 /* Skip this packet */
1155 Adapter->NextPacket = Adapter->CurrentPage;
1156 NICSetBoundaryPage(Adapter);
1157
1158 Adapter->ReceiveError = FALSE;
1159 }
1160
1161 for (;;) {
1162 NICGetCurrentPage(Adapter);
1163
1164 NDIS_DbgPrint(MAX_TRACE, ("Current page (0x%X) NextPacket (0x%X).\n",
1165 Adapter->CurrentPage,
1166 Adapter->NextPacket));
1167
1168 if (Adapter->CurrentPage == Adapter->NextPacket) {
1169 NDIS_DbgPrint(MAX_TRACE, ("No more packets.\n"));
1170 break;
1171 } else {
1172 NDIS_DbgPrint(MAX_TRACE, ("Got a packet in the receive ring.\n"));
1173
1174 /* Read packet from receive buffer ring */
1175 NICReadPacket(Adapter);
1176
1177 Adapter->DoneIndicating = TRUE;
1178
1179 PacketCount++;
1180 if (PacketCount == 10) {
1181 /* Don't starve transmit interrupts */
1182 break;
1183 }
1184 }
1185 }
1186
1187 if ((Adapter->TransmitPending) && (Adapter->TXCurrent != -1)) {
1188 NDIS_DbgPrint(MAX_TRACE, ("Retransmitting current packet at (%d).\n", Adapter->TXCurrent));
1189 /* Retransmit packet */
1190 NICStartTransmit(Adapter);
1191 Adapter->TransmitPending = FALSE;
1192 }
1193
1194 if (Adapter->DoneIndicating)
1195 NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
1196 }
1197
1198
1199 VOID HandleTransmit(
1200 PNIC_ADAPTER Adapter)
1201 /*
1202 * FUNCTION: Handles transmission of a packet
1203 * ARGUMENTS:
1204 * Adapter = Pointer to adapter information
1205 */
1206 {
1207 UINT Length;
1208 UINT BufferCount;
1209
1210 if (Adapter->TransmitError) {
1211 /* FIXME: Retransmit now or let upper layer protocols handle retransmit? */
1212 Adapter->TransmitError = FALSE;
1213 }
1214
1215 /* Free transmit buffers */
1216 Length = Adapter->TXSize[Adapter->TXCurrent];
1217 BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
1218
1219 NDIS_DbgPrint(MAX_TRACE, ("Freeing (%d) buffers at (%d).\n",
1220 BufferCount,
1221 Adapter->TXCurrent));
1222
1223 Adapter->TXFree += BufferCount;
1224 Adapter->TXSize[Adapter->TXCurrent] = 0;
1225 Adapter->TXCurrent = (Adapter->TXCurrent + BufferCount) % Adapter->TXCount;
1226
1227 if (Adapter->TXSize[Adapter->TXCurrent] == 0) {
1228 NDIS_DbgPrint(MAX_TRACE, ("No more packets in transmit buffer.\n"));
1229
1230 Adapter->TXCurrent = -1;
1231 }
1232
1233 if (Adapter->TXQueueTail) {
1234 if (NICPrepareForTransmit(Adapter))
1235 NICStartTransmit(Adapter);
1236 }
1237 }
1238
1239
1240 VOID MiniportHandleInterrupt(
1241 IN NDIS_HANDLE MiniportAdapterContext)
1242 /*
1243 * FUNCTION: Handler for deferred processing of interrupts
1244 * ARGUMENTS:
1245 * MiniportAdapterContext = Pointer to adapter context area
1246 * NOTES:
1247 * Interrupt Service Register is read to determine which interrupts
1248 * are pending. All pending interrupts are handled
1249 */
1250 {
1251 UCHAR ISRValue;
1252 UCHAR ISRMask;
1253 UCHAR Mask;
1254 PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
1255
1256 ISRMask = Adapter->InterruptMask;
1257 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
1258
1259 NDIS_DbgPrint(MAX_TRACE, ("ISRValue (0x%X).\n", ISRValue));
1260
1261 Adapter->InterruptStatus |= (ISRValue & ISRMask);
1262
1263 if (ISRValue != 0x00)
1264 /* Acknowledge interrupts */
1265 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
1266
1267 Mask = 0x01;
1268 while (Adapter->InterruptStatus != 0x00) {
1269
1270 NDIS_DbgPrint(MAX_TRACE, ("Adapter->InterruptStatus (0x%X) Mask (0x%X).\n",
1271 Adapter->InterruptStatus, Mask));
1272
1273 /* Find next interrupt type */
1274 while (((Adapter->InterruptStatus & Mask) == 0) && (Mask < ISRMask))
1275 Mask = (Mask << 1);
1276
1277 switch (Adapter->InterruptStatus & Mask) {
1278 case ISR_OVW:
1279 NDIS_DbgPrint(MAX_TRACE, ("Overflow interrupt.\n"));
1280 /* Overflow. Handled almost the same way as a receive interrupt */
1281 Adapter->BufferOverflow = TRUE;
1282
1283 HandleReceive(Adapter);
1284
1285 Adapter->InterruptStatus &= ~ISR_OVW;
1286 break;
1287
1288 case ISR_RXE:
1289 NDIS_DbgPrint(MAX_TRACE, ("Receive error interrupt.\n"));
1290 NICUpdateCounters(Adapter);
1291
1292 Adapter->ReceiveError = TRUE;
1293
1294 case ISR_PRX:
1295 NDIS_DbgPrint(MAX_TRACE, ("Receive interrupt.\n"));
1296
1297 HandleReceive(Adapter);
1298
1299 Adapter->InterruptStatus &= ~(ISR_PRX | ISR_RXE);
1300 break;
1301
1302 case ISR_TXE:
1303 NDIS_DbgPrint(MAX_TRACE, ("Transmit error interrupt.\n"));
1304 NICUpdateCounters(Adapter);
1305
1306 Adapter->TransmitError = TRUE;
1307
1308 case ISR_PTX:
1309 NDIS_DbgPrint(MAX_TRACE, ("Transmit interrupt.\n"));
1310
1311 HandleTransmit(Adapter);
1312
1313 Adapter->InterruptStatus &= ~(ISR_PTX | ISR_TXE);
1314 break;
1315
1316 case ISR_CNT:
1317 NDIS_DbgPrint(MAX_TRACE, ("Counter interrupt.\n"));
1318 /* Counter overflow. Read counters from the NIC */
1319 NICUpdateCounters(Adapter);
1320
1321 Adapter->InterruptStatus &= ~ISR_CNT;
1322 break;
1323
1324 default:
1325 NDIS_DbgPrint(MAX_TRACE, ("Unknown interrupt. Adapter->InterruptStatus (0x%X).\n", Adapter->InterruptStatus));
1326 Adapter->InterruptStatus &= ~Mask;
1327 break;
1328 }
1329
1330 Mask = (Mask << 1);
1331
1332 /* Check if new interrupts are generated */
1333
1334 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
1335
1336 NDIS_DbgPrint(MAX_TRACE, ("ISRValue (0x%X).\n", ISRValue));
1337
1338 Adapter->InterruptStatus |= (ISRValue & ISRMask);
1339
1340 if (ISRValue != 0x00) {
1341 /* Acknowledge interrupts */
1342 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
1343 Mask = 0x01;
1344 }
1345 }
1346
1347 NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
1348 }
1349
1350 /* EOF */