2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Novell Eagle 2000 driver
5 * PURPOSE: DP8390 NIC specific routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
8 * CSH 27/08-2000 Created
12 /* Null-terminated array of ports to probe. This is "semi-risky" (Don Becker). */
13 ULONG ProbeAddressList[] = { 0x280, 0x300, 0x320, 0x340, 0x360, 0x380, 0 };
15 BOOLEAN ProbeAddressForNIC(
18 * FUNCTION: Probes an address for a NIC
20 * address = Base address to probe
22 * TRUE if an NIC is found at the address
25 * If the adapter responds correctly to a
26 * stop command we assume it is present
31 NDIS_DbgPrint(MID_TRACE, ("Probing address 0x%x\n", address));
33 /* Disable interrupts */
34 NdisRawWritePortUchar(address + PG0_IMR, 0);
37 NdisRawWritePortUchar(address + PG0_CR, CR_STP | CR_RD2);
40 NdisStallExecution(1600);
42 /* Read NIC response */
43 NdisRawReadPortUchar(address + PG0_CR, &Tmp);
45 if ((Tmp == (CR_RD2 | CR_STP)) || (Tmp == (CR_RD2 | CR_STP | CR_STA)))
55 * FUNCTION: Tests for a NIC
57 * Adapter = Pointer to adapter information
59 * TRUE if NIC is believed to be present, FALSE if not
64 NDIS_DbgPrint(MAX_TRACE, ("Called\n"));
66 /* first try the supplied value */
67 if(ProbeAddressForNIC(Adapter->IoBaseAddress))
69 NDIS_DbgPrint(MIN_TRACE, ("Found adapter at 0x%x\n", Adapter->IoBaseAddress));
73 /* ok, no dice, time to probe */
74 for(i = 0; ProbeAddressList[i]; i++)
76 if(ProbeAddressForNIC(ProbeAddressList[i]))
78 NDIS_DbgPrint(MIN_TRACE, ("Found adapter at address 0x%x\n", ProbeAddressList[i]));
79 Adapter->IoBaseAddress = ProbeAddressList[i];
84 NDIS_DbgPrint(MIN_TRACE,("Adapter NOT found!\n"));
89 BOOLEAN NICTestAddress(
93 * FUNCTION: Tests if an address is writable
95 * Adapter = Pointer to adapter information
97 * TRUE if the address is writable, FALSE if not
104 NICReadDataAlign(Adapter, &Data, Address, 0x02);
110 NICWriteDataAlign(Adapter, Address, &Data, 0x02);
112 /* Check if it has changed on the NIC */
113 NICReadDataAlign(Adapter, &Tmp, Address, 0x02);
115 return (Data == Tmp);
120 PNIC_ADAPTER Adapter)
122 * FUNCTION: Finds out how much RAM a NIC has
124 * Adapter = Pointer to adapter information
126 * TRUE if the RAM size was found, FALSE if not
128 * Start at 1KB and test for every 1KB up to 64KB
133 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
135 /* Locate RAM base address */
136 for (Base = 0x0400; Base < 0x10000; Base += 0x0400) {
137 if (NICTestAddress(Adapter, Base))
141 if (Base == 0x10000) {
142 /* No RAM on this board */
143 NDIS_DbgPrint(MIN_TRACE, ("No RAM found on board.\n"));
147 Adapter->RamBase = (PUCHAR)Base;
150 for (; Base < 0x10000; Base += 0x0400) {
151 if (!NICTestAddress(Adapter, Base))
155 Adapter->RamSize = (UINT)(Base - (ULONG_PTR)Adapter->RamBase);
157 NDIS_DbgPrint(MID_TRACE, ("RAM is at (0x%X). Size is (0x%X).\n",
158 Adapter->RamBase, Adapter->RamSize));
164 VOID NICSetPhysicalAddress(
165 PNIC_ADAPTER Adapter)
167 * FUNCTION: Initializes the physical address on the NIC
169 * Adapter = Pointer to adapter information
171 * The physical address is taken from Adapter.
172 * The NIC is stopped by this operation
178 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
180 /* Initialize PAR - Physical Address Registers */
181 for (i = 0; i < 0x06; i++)
182 NdisRawWritePortUchar(Adapter->IOBase + PG1_PAR + i, Adapter->StationAddress[i]);
184 /* Go back to page 0 */
185 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
189 VOID NICSetMulticastAddressMask(
190 PNIC_ADAPTER Adapter)
192 * FUNCTION: Initializes the multicast address mask on the NIC
194 * Adapter = Pointer to adapter information
196 * The multicast address mask is taken from Adapter.
197 * The NIC is stopped by this operation
203 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
205 /* Initialize MAR - Multicast Address Registers */
206 for (i = 0; i < 0x08; i++)
207 NdisRawWritePortUchar(Adapter->IOBase + PG1_MAR + i, Adapter->MulticastAddressMask[i]);
209 /* Go back to page 0 */
210 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
214 BOOLEAN NICReadSAPROM(
215 PNIC_ADAPTER Adapter)
217 * FUNCTION: Reads the Station Address PROM data from the NIC
219 * Adapter = Pointer to adapter information
221 * TRUE if a the NIC is an NE2000
223 * This routine also determines if the NIC can support word mode transfers
224 * and if it does initializes the NIC for word mode.
225 * The station address in the adapter structure is initialized with
226 * the address from the SAPROM
233 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
235 /* Read Station Address PROM (SAPROM) which is 16 bytes at remote DMA address 0.
236 Some cards double the data read which we must compensate for */
238 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
239 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x20);
240 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
242 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
243 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, 0x00);
244 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, 0x00);
246 /* Select page 0, read and start the NIC */
247 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
249 /* Read one byte at a time */
250 WordLength = 2; /* Assume a word is two bytes */
251 for (i = 0; i < 32; i += 2) {
252 NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i]);
253 NdisRawReadPortUchar(Adapter->IOBase + NIC_DATA, &Buffer[i + 1]);
254 if (Buffer[i] != Buffer[i + 1])
255 WordLength = 1; /* A word is one byte long */
258 /* If WordLength is 2 the data read before was doubled. We must compensate for this */
259 if (WordLength == 2) {
260 NDIS_DbgPrint(MAX_TRACE,("NE2000 or compatible network adapter found.\n"));
262 Adapter->WordMode = TRUE;
264 /* Move the SAPROM data to the adapter object */
265 for (i = 0; i < 16; i++)
266 Adapter->SAPROM[i] = Buffer[i * 2];
268 /* Copy the station address */
270 (PVOID)&Adapter->StationAddress,
271 (PVOID)&Adapter->SAPROM,
272 DRIVER_LENGTH_OF_ADDRESS);
274 /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
275 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
279 NDIS_DbgPrint(MAX_TRACE, ("NE1000 or compatible network adapter found.\n"));
281 Adapter->WordMode = FALSE;
288 NDIS_STATUS NICInitialize(
289 PNIC_ADAPTER Adapter)
291 * FUNCTION: Initializes a NIC
293 * Adapter = Pointer to adapter information
295 * Status of NIC initialization
297 * The NIC is put into loopback mode
302 NDIS_DbgPrint(MID_TRACE, ("Called.\n"));
305 NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
308 NdisStallExecution(1600);
310 /* Write the value back */
311 NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
313 /* Select page 0 and stop NIC */
314 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
316 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
317 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
319 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
320 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
321 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
323 /* Initialize RCR - Receive Configuration Register (monitor mode) */
324 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
326 /* Enter loopback mode (internal NIC module loopback) */
327 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
329 /* Read the Station Address PROM */
330 if (!NICReadSAPROM(Adapter))
331 return NDIS_STATUS_ADAPTER_NOT_FOUND;
333 NDIS_DbgPrint(MID_TRACE, ("Station address is (%02X %02X %02X %02X %02X %02X).\n",
334 Adapter->StationAddress[0], Adapter->StationAddress[1],
335 Adapter->StationAddress[2], Adapter->StationAddress[3],
336 Adapter->StationAddress[4], Adapter->StationAddress[5]));
338 /* Select page 0 and start NIC */
339 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
341 /* Clear ISR - Interrupt Status Register */
342 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
344 /* Find NIC RAM size */
347 return NDIS_STATUS_SUCCESS;
351 NDIS_STATUS NICSetup(
352 PNIC_ADAPTER Adapter)
354 * FUNCTION: Sets up a NIC
356 * Adapter = Pointer to adapter information
358 * Status of operation
360 * The NIC is put into loopback mode
363 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
365 if (Adapter->WordMode ) {
366 /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
367 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_WTS | DCR_LS | DCR_FT10);
369 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
370 NdisRawWritePortUchar(Adapter->IOBase + PG0_DCR, DCR_LS | DCR_FT10);
373 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
374 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
375 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
377 /* Initialize RCR - Receive Configuration Register (monitor mode) */
378 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
380 /* Enter loopback mode (internal NIC module loopback) */
381 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
383 /* Set boundary page */
384 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY, Adapter->NextPacket);
387 NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTART, Adapter->PageStart);
390 NdisRawWritePortUchar(Adapter->IOBase + PG0_PSTOP, Adapter->PageStop);
392 /* Program our address on the NIC */
393 NICSetPhysicalAddress(Adapter);
395 /* Program the multicast address mask on the NIC */
396 NICSetMulticastAddressMask(Adapter);
398 /* Select page 1 and stop NIC */
399 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE1);
401 /* Initialize current page register */
402 NdisRawWritePortUchar(Adapter->IOBase + PG1_CURR, Adapter->PageStart + 1);
404 /* Select page 0 and stop NIC */
405 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
407 /* Clear ISR - Interrupt Status Register */
408 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, 0xFF);
410 /* Initialize IMR - Interrupt Mask Register */
411 NdisRawWritePortUchar(Adapter->IOBase + PG0_IMR, Adapter->InterruptMask);
413 /* Select page 0 and start NIC */
414 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
416 Adapter->CurrentPage = Adapter->PageStart + 1;
417 Adapter->NextPacket = Adapter->PageStart + 1;
418 Adapter->BufferOverflow = FALSE;
419 Adapter->ReceiveError = FALSE;
420 Adapter->TransmitError = FALSE;
422 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
424 return NDIS_STATUS_SUCCESS;
428 NDIS_STATUS NICStart(
429 PNIC_ADAPTER Adapter)
431 * FUNCTION: Starts a NIC
433 * Adapter = Pointer to adapter information
435 * Status of operation
438 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
440 /* Take NIC out of loopback mode */
441 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, 0x00);
443 /* Initialize RCR - Receive Configuration Register (accept all) */
444 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_AB | RCR_AM | RCR_PRO);
446 return NDIS_STATUS_SUCCESS;
451 PNIC_ADAPTER Adapter)
453 * FUNCTION: Stops a NIC
455 * Adapter = Pointer to adapter information
457 * Status of operation
463 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
465 /* Select page 0 and stop NIC */
466 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
468 /* Clear Remote Byte Count Register so ISR_RST will be set */
469 NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
470 NdisRawWritePortUchar( Adapter->IOBase + PG0_RBCR0, 0x00);
472 /* Wait for ISR_RST to be set, but timeout after 2ms */
473 for (i = 0; i < 4; i++) {
474 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
478 NdisStallExecution(500);
483 NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
486 /* Initialize RCR - Receive Configuration Register (monitor mode) */
487 NdisRawWritePortUchar(Adapter->IOBase + PG0_RCR, RCR_MON);
489 /* Initialize TCR - Transmit Configuration Register (loopback mode) */
490 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
493 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
495 return NDIS_STATUS_SUCCESS;
499 NDIS_STATUS NICReset(
500 PNIC_ADAPTER Adapter)
502 * FUNCTION: Resets a NIC
504 * Adapter = Pointer to adapter information
506 * Status of operation
511 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
517 NdisRawReadPortUchar(Adapter->IOBase + NIC_RESET, &Tmp);
520 NdisStallExecution(1600);
522 /* Write the value back */
523 NdisRawWritePortUchar(Adapter->IOBase + NIC_RESET, Tmp);
525 /* Restart the NIC */
528 return NDIS_STATUS_SUCCESS;
532 VOID NICStartTransmit(
533 PNIC_ADAPTER Adapter)
535 * FUNCTION: Starts transmitting a packet
537 * Adapter = Pointer to adapter information
544 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
546 //FrameStart = Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE;
547 //FrameStart = Adapter->TXStart;
548 FrameStart = (UCHAR)(Adapter->TXStart + (UCHAR)(Adapter->TXCurrent * BUFFERS_PER_TX_BUF));
550 /* Set start of frame */
551 NdisRawReadPortUchar(Adapter->IOBase + PG0_TPSR, &Tmp);
552 // NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR,
553 // Adapter->TXStart + Adapter->TXCurrent * DRIVER_BLOCK_SIZE);
555 NdisRawWritePortUchar(Adapter->IOBase + PG0_TPSR, FrameStart);
556 //NDIS_DbgPrint(MID_TRACE, ("Setting start of frame to (%d).\n", FrameStart));
558 /* Set length of frame */
559 Length = Adapter->TXSize[Adapter->TXCurrent];
560 NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR0, Length & 0xFF);
561 NdisRawWritePortUchar(Adapter->IOBase + PG0_TBCR1, Length >> 8);
563 /* Start transmitting */
564 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_TXP | CR_RD2);
566 NDIS_DbgPrint(MID_TRACE, ("Transmitting. FrameStart (%d) TXCurrent (%d) TXStart (%d) Length (%d).\n\n",
575 VOID NICSetBoundaryPage(
576 PNIC_ADAPTER Adapter)
578 * FUNCTION: Sets the boundary page on the adapter to be one less than NextPacket
580 * Adapter = Pointer to adapter information
583 if (Adapter->NextPacket == Adapter->PageStart) {
584 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
585 (UCHAR)(Adapter->PageStop - 1));
587 NdisRawWritePortUchar(Adapter->IOBase + PG0_BNRY,
588 (UCHAR)(Adapter->NextPacket - 1));
593 VOID NICGetCurrentPage(
594 PNIC_ADAPTER Adapter)
596 * FUNCTION: Retrieves the current page from the adapter
598 * Adapter = Pointer to adapter information
604 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE1);
606 /* Read current page */
607 NdisRawReadPortUchar(Adapter->IOBase + PG1_CURR, &Current);
610 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
612 Adapter->CurrentPage = Current;
616 VOID NICUpdateCounters(
617 PNIC_ADAPTER Adapter)
619 * FUNCTION: Updates counters
621 * Adapter = Pointer to adapter information
626 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
628 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR0, &Tmp);
629 Adapter->FrameAlignmentErrors += Tmp;
631 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR1, &Tmp);
632 Adapter->CrcErrors += Tmp;
634 NdisRawReadPortUchar(Adapter->IOBase + PG0_CNTR2, &Tmp);
635 Adapter->MissedPackets += Tmp;
639 VOID NICReadDataAlign(
640 PNIC_ADAPTER Adapter,
645 * FUNCTION: Copies data from a NIC's RAM into a buffer
647 * Adapter = Pointer to adapter information
648 * Target = Pointer to buffer to copy data into (in host memory)
649 * Source = Offset into NIC's RAM (must be an even number)
650 * Length = Number of bytes to copy from NIC's RAM (must be an even number)
658 /* Select page 0 and start the NIC */
659 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
661 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
662 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Source & 0xFF));
663 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Source >> 8));
665 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
666 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
667 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
669 /* Select page 0, read and start the NIC */
670 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
672 if (Adapter->WordMode)
673 NdisRawReadPortBufferUshort(Adapter->IOBase + NIC_DATA, Target, Count >> 1);
675 NdisRawReadPortBufferUchar(Adapter->IOBase + NIC_DATA, Target, Count);
677 /* Wait for remote DMA to complete, but timeout after some time */
678 for (Count = 0; Count < 0xFFFF; Count++) {
679 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
683 NdisStallExecution(4);
688 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
691 /* Clear remote DMA bit in ISR - Interrupt Status Register */
692 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
696 VOID NICWriteDataAlign(
697 PNIC_ADAPTER Adapter,
702 * FUNCTION: Copies data from a buffer into the NIC's RAM
704 * Adapter = Pointer to adapter information
705 * Target = Offset into NIC's RAM (must be an even number)
706 * Source = Pointer to buffer to copy data from (in host memory)
707 * Length = Number of bytes to copy from the buffer (must be an even number)
713 /* Select page 0 and start the NIC */
714 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2 | CR_PAGE0);
716 /* Handle read-before-write bug */
718 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
719 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
720 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
722 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
723 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x02);
724 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
726 /* Read and start the NIC */
727 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD0 | CR_PAGE0);
730 NdisRawReadPortUshort(Adapter->IOBase + NIC_DATA, &Count);
732 /* Wait for remote DMA to complete, but timeout after some time */
733 for (Count = 0; Count < 0xFFFF; Count++) {
734 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
738 NdisStallExecution(4);
743 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
746 /* Clear remote DMA bit in ISR - Interrupt Status Register */
747 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
750 /* Now output some data */
753 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
754 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR0, (UCHAR)(Target & 0xFF));
755 NdisRawWritePortUchar(Adapter->IOBase + PG0_RSAR1, (UCHAR)(Target >> 8));
757 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
758 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, (UCHAR)(Count & 0xFF));
759 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, (UCHAR)(Count >> 8));
761 /* Write and start the NIC */
762 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD1 | CR_PAGE0);
764 if (Adapter->WordMode)
765 NdisRawWritePortBufferUshort(Adapter->IOBase + NIC_DATA, Source, Count >> 1);
767 NdisRawWritePortBufferUchar(Adapter->IOBase + NIC_DATA, Source, Count);
769 /* Wait for remote DMA to complete, but timeout after some time */
770 for (Count = 0; Count < 0xFFFF; Count++) {
771 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
775 NdisStallExecution(4);
780 NDIS_DbgPrint(MIN_TRACE, ("Remote DMA did not complete.\n"));
783 /* Clear remote DMA bit in ISR - Interrupt Status Register */
784 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISR_RDC);
789 PNIC_ADAPTER Adapter,
794 * FUNCTION: Copies data from a NIC's RAM into a buffer
796 * Adapter = Pointer to adapter information
797 * Target = Pointer to buffer to copy data into (in host memory)
798 * Source = Offset into NIC's RAM
799 * Length = Number of bytes to copy from NIC's RAM
804 /* Avoid transfers to odd addresses */
806 /* Transfer one word and use the MSB */
807 NICReadDataAlign(Adapter, &Tmp, Source - 1, 0x02);
808 *Target = (UCHAR)(Tmp >> 8);
815 /* Transfer as many words as we can without exceeding the buffer length */
816 Tmp = Length & 0xFFFE;
817 NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Tmp);
819 (ULONG_PTR)Target += Tmp;
821 /* Read one word and keep the LSB */
822 NICReadDataAlign(Adapter, &Tmp, Source, 0x02);
823 *Target = (UCHAR)(Tmp & 0x00FF);
825 /* Transfer the rest of the data */
826 NICReadDataAlign(Adapter, (PUSHORT)Target, Source, Length);
831 PNIC_ADAPTER Adapter,
836 * FUNCTION: Copies data from a buffer into NIC's RAM
838 * Adapter = Pointer to adapter information
839 * Target = Offset into NIC's RAM to store data
840 * Source = Pointer to buffer to copy data from (in host memory)
841 * Length = Number of bytes to copy from buffer
846 /* Avoid transfers to odd addresses */
849 NICReadDataAlign(Adapter, &Tmp, Target - 1, 0x02);
851 /* Merge LSB with the new byte which become the new MSB */
852 Tmp = (Tmp & 0x00FF) | (*Source << 8);
854 /* Finally write the value back */
855 NICWriteDataAlign(Adapter, Target - 1, &Tmp, 0x02);
857 /* Update pointers */
858 (ULONG_PTR)Source += 1;
859 (ULONG_PTR)Target += 1;
864 /* Transfer as many words as we can without exceeding the transfer length */
865 Tmp = Length & 0xFFFE;
866 NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Tmp);
868 (ULONG_PTR)Target += Tmp;
871 NICReadDataAlign(Adapter, &Tmp, Target, 0x02);
873 /* Merge MSB with the new byte which become the new LSB */
874 Tmp = (Tmp & 0xFF00) | (*Source);
876 /* Finally write the value back */
877 NICWriteDataAlign(Adapter, Target, &Tmp, 0x02);
879 /* Transfer the rest of the data */
880 NICWriteDataAlign(Adapter, Target, (PUSHORT)Source, Length);
884 VOID NICIndicatePacket(
885 PNIC_ADAPTER Adapter)
887 * FUNCTION: Indicates a packet to the wrapper
889 * Adapter = Pointer to adapter information
894 IndicateLength = (Adapter->PacketHeader.PacketLength <
895 (Adapter->LookaheadSize + DRIVER_HEADER_SIZE))?
896 (Adapter->PacketHeader.PacketLength) :
897 (Adapter->LookaheadSize + DRIVER_HEADER_SIZE);
899 /* Fill the lookahead buffer */
901 (PUCHAR)&Adapter->Lookahead,
902 Adapter->PacketOffset + sizeof(PACKET_HEADER),
903 IndicateLength + DRIVER_HEADER_SIZE);
905 NDIS_DbgPrint(MID_TRACE, ("Indicating (%d) bytes.\n", IndicateLength));
906 DbgPrint("ne2000!NICIndicatePacket: Indicating (%d) bytes.\n", IndicateLength);
909 NDIS_DbgPrint(MAX_TRACE, ("FRAME:\n"));
910 for (i = 0; i < (IndicateLength + 7) / 8; i++) {
911 NDIS_DbgPrint(MAX_TRACE, ("%02X %02X %02X %02X %02X %02X %02X %02X\n",
912 Adapter->Lookahead[i*8+0],
913 Adapter->Lookahead[i*8+1],
914 Adapter->Lookahead[i*8+2],
915 Adapter->Lookahead[i*8+3],
916 Adapter->Lookahead[i*8+4],
917 Adapter->Lookahead[i*8+5],
918 Adapter->Lookahead[i*8+6],
919 Adapter->Lookahead[i*8+7]));
923 if (IndicateLength >= DRIVER_HEADER_SIZE) {
924 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
926 (PVOID)&Adapter->Lookahead,
928 (PVOID)&Adapter->Lookahead[DRIVER_HEADER_SIZE],
929 IndicateLength - DRIVER_HEADER_SIZE,
930 Adapter->PacketHeader.PacketLength - DRIVER_HEADER_SIZE);
932 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle,
934 (PVOID)&Adapter->Lookahead,
944 PNIC_ADAPTER Adapter)
946 * FUNCTION: Reads a full packet from the receive buffer ring
948 * Adapter = Pointer to adapter information
951 BOOLEAN SkipPacket = FALSE;
953 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
955 /* Get the header of the next packet in the receive ring */
956 Adapter->PacketOffset = Adapter->NextPacket << 8;
958 (PUCHAR)&Adapter->PacketHeader,
959 Adapter->PacketOffset,
960 sizeof(PACKET_HEADER));
962 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (Status) (0x%X)\n", Adapter->PacketHeader.Status));
963 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (NextPacket) (0x%X)\n", Adapter->PacketHeader.NextPacket));
964 NDIS_DbgPrint(MAX_TRACE, ("HEADER: (PacketLength) (0x%X)\n", Adapter->PacketHeader.PacketLength));
966 if (Adapter->PacketHeader.PacketLength < 64 ||
967 Adapter->PacketHeader.PacketLength > 1518) { /* XXX I don't think the CRC will show up... should be 1514 */
968 NDIS_DbgPrint(MAX_TRACE, ("Bogus packet size (%d).\n",
969 Adapter->PacketHeader.PacketLength));
975 Adapter->NextPacket = Adapter->CurrentPage;
977 NICIndicatePacket(Adapter);
979 /* Go to the next free buffer in receive ring */
980 Adapter->NextPacket = Adapter->PacketHeader.NextPacket;
983 /* Update boundary page */
984 NICSetBoundaryPage(Adapter);
989 PNIC_ADAPTER Adapter)
991 * FUNCTION: Writes a full packet to the transmit buffer ring
993 * Adapter = Pointer to adapter information
995 * There must be enough free buffers available in the transmit buffer ring.
996 * The packet is taken from the head of the transmit queue and the position
997 * into the transmit buffer ring is taken from TXNext
1000 PNDIS_BUFFER SrcBuffer;
1001 UINT BytesToCopy, SrcSize, DstSize;
1007 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1009 TXStart = Adapter->TXStart * DRIVER_BLOCK_SIZE;
1010 TXStop = (Adapter->TXStart + Adapter->TXCount) * DRIVER_BLOCK_SIZE;
1012 NdisQueryPacket(Adapter->TXQueueHead,
1016 &Adapter->TXSize[Adapter->TXNext]);
1018 NDIS_DbgPrint(MID_TRACE, ("Packet (%d) is now size (%d).\n",
1020 Adapter->TXSize[Adapter->TXNext]));
1022 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
1024 DstData = TXStart + Adapter->TXNext * DRIVER_BLOCK_SIZE;
1025 DstSize = TXStop - DstData;
1027 /* Start copying the data */
1029 BytesToCopy = (SrcSize < DstSize)? SrcSize : DstSize;
1031 NICWriteData(Adapter, DstData, SrcData, BytesToCopy);
1033 (ULONG_PTR)SrcData += BytesToCopy;
1034 SrcSize -= BytesToCopy;
1035 DstData += BytesToCopy;
1036 DstSize -= BytesToCopy;
1039 /* No more bytes in source buffer. Proceed to
1040 the next buffer in the source buffer chain */
1041 NdisGetNextBuffer(SrcBuffer, &SrcBuffer);
1045 NdisQueryBuffer(SrcBuffer, (PVOID)&SrcData, &SrcSize);
1049 /* Wrap around the end of the transmit buffer ring */
1051 DstSize = Adapter->TXCount * DRIVER_BLOCK_SIZE;
1057 BOOLEAN NICPrepareForTransmit(
1058 PNIC_ADAPTER Adapter)
1060 * FUNCTION: Prepares a packet for transmission
1062 * Adapter = Pointer to adapter information
1064 * There must be at least one packet in the transmit queue
1066 * TRUE if a packet was prepared, FALSE if not
1071 PNDIS_PACKET Packet;
1073 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1075 /* Calculate number of buffers needed to transmit packet */
1076 NdisQueryPacket(Adapter->TXQueueHead,
1082 BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
1084 if (BufferCount > Adapter->TXFree) {
1085 NDIS_DbgPrint(MID_TRACE, ("No transmit resources. Have (%d) buffers, need (%d).\n",
1086 Adapter->TXFree, BufferCount));
1087 /* We don't have the resources to transmit this packet right now */
1091 /* Write the packet to the card */
1092 NICWritePacket(Adapter);
1094 /* If the NIC is not transmitting, reset the current transmit pointer */
1095 if (Adapter->TXCurrent == -1)
1096 Adapter->TXCurrent = Adapter->TXNext;
1098 Adapter->TXNext = (Adapter->TXNext + BufferCount) % Adapter->TXCount;
1099 Adapter->TXFree -= BufferCount;
1101 /* Remove the packet from the queue */
1102 Packet = Adapter->TXQueueHead;
1103 Adapter->TXQueueHead = RESERVED(Packet)->Next;
1105 if (Packet == Adapter->TXQueueTail)
1106 Adapter->TXQueueTail = NULL;
1108 /* Assume the transmit went well */
1109 NdisMSendComplete(Adapter->MiniportAdapterHandle,
1111 NDIS_STATUS_SUCCESS);
1118 PNIC_ADAPTER Adapter)
1120 * FUNCTION: Starts transmitting packets in the transmit queue
1122 * Adapter = Pointer to adapter information
1124 * There must be at least one packet in the transmit queue
1127 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1129 if (Adapter->TXCurrent == -1) {
1130 /* NIC is not transmitting, so start transmitting now */
1132 /* Load next packet onto the card, and start transmitting */
1133 if (NICPrepareForTransmit(Adapter))
1134 NICStartTransmit(Adapter);
1140 PNIC_ADAPTER Adapter)
1142 * FUNCTION: Handles reception of a packet
1144 * Adapter = Pointer to adapter information
1146 * Buffer overflows are also handled here
1153 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1155 Adapter->DoneIndicating = FALSE;
1158 NICGetCurrentPage(Adapter);
1160 if (Adapter->BufferOverflow) {
1162 NDIS_DbgPrint(MID_TRACE, ("Receive ring overflow.\n"));
1164 /* Select page 0 and stop the NIC */
1165 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STP | CR_RD2 | CR_PAGE0);
1167 /* Clear RBCR0,RBCR1 - Remote Byte Count Registers */
1168 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR0, 0x00);
1169 NdisRawWritePortUchar(Adapter->IOBase + PG0_RBCR1, 0x00);
1171 /* Wait for ISR_RST to be set, but timeout after 2ms */
1172 for (i = 0; i < 4; i++) {
1173 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &Tmp);
1177 NdisStallExecution(500);
1182 NDIS_DbgPrint(MIN_TRACE, ("NIC was not reset after 2ms.\n"));
1185 if ((Adapter->InterruptStatus & (ISR_PTX | ISR_TXE)) == 0) {
1186 /* We may need to restart the transmitter */
1187 Adapter->TransmitPending = TRUE;
1190 /* Initialize TCR - Transmit Configuration Register to loopback mode 1 */
1191 NdisRawWritePortUchar(Adapter->IOBase + PG0_TCR, TCR_LOOP);
1194 NdisRawWritePortUchar(Adapter->IOBase + PG0_CR, CR_STA | CR_RD2);
1198 Adapter->BufferOverflow = FALSE;
1201 if (Adapter->ReceiveError) {
1202 NDIS_DbgPrint(MID_TRACE, ("Receive error.\n"));
1204 /* Skip this packet */
1205 Adapter->NextPacket = Adapter->CurrentPage;
1206 NICSetBoundaryPage(Adapter);
1208 Adapter->ReceiveError = FALSE;
1212 NICGetCurrentPage(Adapter);
1214 NDIS_DbgPrint(MID_TRACE, ("Current page (0x%X) NextPacket (0x%X).\n",
1215 Adapter->CurrentPage,
1216 Adapter->NextPacket));
1218 if (Adapter->CurrentPage == Adapter->NextPacket) {
1219 NDIS_DbgPrint(MID_TRACE, ("No more packets.\n"));
1222 NDIS_DbgPrint(MID_TRACE, ("Got a packet in the receive ring.\n"));
1224 /* Read packet from receive buffer ring */
1225 NICReadPacket(Adapter);
1227 Adapter->DoneIndicating = TRUE;
1230 if (PacketCount == 10) {
1231 /* Don't starve transmit interrupts */
1237 if ((Adapter->TransmitPending) && (Adapter->TXCurrent != -1)) {
1238 NDIS_DbgPrint(MID_TRACE, ("Retransmitting current packet at (%d).\n", Adapter->TXCurrent));
1239 /* Retransmit packet */
1240 NICStartTransmit(Adapter);
1241 Adapter->TransmitPending = FALSE;
1244 if (Adapter->DoneIndicating)
1245 NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
1249 VOID HandleTransmit(
1250 PNIC_ADAPTER Adapter)
1252 * FUNCTION: Handles transmission of a packet
1254 * Adapter = Pointer to adapter information
1260 // PIP_PACKET pIPPacket;
1261 // pIPPacket = (PIP_PACKET)
1262 // DisplayIPPacket(pIPPacket);
1264 if (Adapter->TransmitError) {
1265 /* FIXME: Retransmit now or let upper layer protocols handle retransmit? */
1266 Adapter->TransmitError = FALSE;
1269 /* Free transmit buffers */
1270 Length = Adapter->TXSize[Adapter->TXCurrent];
1271 BufferCount = (Length + DRIVER_BLOCK_SIZE - 1) / DRIVER_BLOCK_SIZE;
1273 NDIS_DbgPrint(MID_TRACE, ("Freeing (%d) buffers at (%d).\n",
1275 Adapter->TXCurrent));
1277 Adapter->TXFree += BufferCount;
1278 Adapter->TXSize[Adapter->TXCurrent] = 0;
1279 Adapter->TXCurrent = (Adapter->TXCurrent + BufferCount) % Adapter->TXCount;
1281 if (Adapter->TXSize[Adapter->TXCurrent] == 0) {
1282 NDIS_DbgPrint(MID_TRACE, ("No more packets in transmit buffer.\n"));
1284 Adapter->TXCurrent = -1;
1287 if (Adapter->TXQueueTail) {
1288 if (NICPrepareForTransmit(Adapter))
1289 NICStartTransmit(Adapter);
1294 VOID MiniportHandleInterrupt(
1295 IN NDIS_HANDLE MiniportAdapterContext)
1297 * FUNCTION: Handler for deferred processing of interrupts
1299 * MiniportAdapterContext = Pointer to adapter context area
1301 * Interrupt Service Register is read to determine which interrupts
1302 * are pending. All pending interrupts are handled
1308 PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
1310 ISRMask = Adapter->InterruptMask;
1311 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
1313 NDIS_DbgPrint(MID_TRACE, ("ISRValue (0x%X).\n", ISRValue));
1315 Adapter->InterruptStatus |= (ISRValue & ISRMask);
1317 if (ISRValue != 0x00)
1318 /* Acknowledge interrupts */
1319 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
1322 while (Adapter->InterruptStatus != 0x00) {
1324 NDIS_DbgPrint(MID_TRACE, ("Adapter->InterruptStatus (0x%X) Mask (0x%X).\n",
1325 Adapter->InterruptStatus, Mask));
1327 /* Find next interrupt type */
1328 while (((Adapter->InterruptStatus & Mask) == 0) && (Mask < ISRMask))
1331 switch (Adapter->InterruptStatus & Mask) {
1333 NDIS_DbgPrint(MID_TRACE, ("Overflow interrupt.\n"));
1334 /* Overflow. Handled almost the same way as a receive interrupt */
1335 Adapter->BufferOverflow = TRUE;
1337 HandleReceive(Adapter);
1339 Adapter->InterruptStatus &= ~ISR_OVW;
1343 NDIS_DbgPrint(MID_TRACE, ("Receive error interrupt.\n"));
1344 NICUpdateCounters(Adapter);
1346 Adapter->ReceiveError = TRUE;
1349 NDIS_DbgPrint(MID_TRACE, ("Receive interrupt.\n"));
1351 HandleReceive(Adapter);
1353 Adapter->InterruptStatus &= ~(ISR_PRX | ISR_RXE);
1357 NDIS_DbgPrint(MID_TRACE, ("Transmit error interrupt.\n"));
1358 NICUpdateCounters(Adapter);
1360 Adapter->TransmitError = TRUE;
1363 NDIS_DbgPrint(MID_TRACE, ("Transmit interrupt.\n"));
1365 HandleTransmit(Adapter);
1367 Adapter->InterruptStatus &= ~(ISR_PTX | ISR_TXE);
1371 NDIS_DbgPrint(MID_TRACE, ("Counter interrupt.\n"));
1372 /* Counter overflow. Read counters from the NIC */
1373 NICUpdateCounters(Adapter);
1375 Adapter->InterruptStatus &= ~ISR_CNT;
1379 NDIS_DbgPrint(MID_TRACE, ("Unknown interrupt. Adapter->InterruptStatus (0x%X).\n", Adapter->InterruptStatus));
1380 Adapter->InterruptStatus &= ~Mask;
1386 /* Check if new interrupts are generated */
1388 NdisRawReadPortUchar(Adapter->IOBase + PG0_ISR, &ISRValue);
1390 NDIS_DbgPrint(MID_TRACE, ("ISRValue (0x%X).\n", ISRValue));
1392 Adapter->InterruptStatus |= (ISRValue & ISRMask);
1394 if (ISRValue != 0x00) {
1395 /* Acknowledge interrupts */
1396 NdisRawWritePortUchar(Adapter->IOBase + PG0_ISR, ISRValue);
1401 NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);