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