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