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