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