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