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
16 * FUNCTION: Tests for a NIC
18 * Adapter = Pointer to adapter information
20 * TRUE if NIC is believed to be present, FALSE if not
22 * If the adapter responds correctly to a
23 * stop command we assume it is present
28 /* Disable interrupts */
29 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_IMR
, 0);
32 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
);
35 NdisStallExecution(1600);
37 /* Read NIC response */
38 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_CR
, &Tmp
);
40 if ((Tmp
== (CR_RD2
| CR_STP
)) || (Tmp
== (CR_RD2
| CR_STP
| CR_STA
)))
47 BOOLEAN
NICTestAddress(
51 * FUNCTION: Tests if an address is writable
53 * Adapter = Pointer to adapter information
55 * TRUE if the RAM size was found, FALSE if not
57 * Starts at 1KB and tests every 1KB up to 64KB
64 NICReadDataAlign(Adapter
, &Data
, Address
, 0x02);
70 NICWriteDataAlign(Adapter
, Address
, &Data
, 0x02);
72 /* Check if it has changed on the NIC */
73 NICReadDataAlign(Adapter
, &Tmp
, Address
, 0x02);
82 * FUNCTION: Finds out how much RAM a NIC has
84 * Adapter = Pointer to adapter information
86 * TRUE if the RAM size was found, FALSE if not
88 * Start at 1KB and test for every 1KB up to 64KB
93 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
95 /* Locate RAM base address */
96 for (Base
= 0x0400; Base
< 0x10000; Base
+= 0x0400) {
97 if (NICTestAddress(Adapter
, Base
))
101 if (Base
== 0x10000) {
102 /* No RAM on this board */
103 NDIS_DbgPrint(MIN_TRACE
, ("No RAM found on board.\n"));
107 Adapter
->RamBase
= (PUCHAR
)Base
;
110 for (; Base
< 0x10000; Base
+= 0x0400) {
111 if (!NICTestAddress(Adapter
, Base
))
115 Adapter
->RamSize
= (UINT
)(Base
- (ULONG_PTR
)Adapter
->RamBase
);
117 NDIS_DbgPrint(MID_TRACE
, ("RAM is at (0x%X). Size is (0x%X).\n",
118 Adapter
->RamBase
, Adapter
->RamSize
));
124 VOID
NICSetPhysicalAddress(
125 PNIC_ADAPTER Adapter
)
127 * FUNCTION: Initializes the physical address on the NIC
129 * Adapter = Pointer to adapter information
131 * The physical address is taken from Adapter.
132 * The NIC is stopped by this operation
138 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE1
);
140 /* Initialize PAR - Physical Address Registers */
141 for (i
= 0; i
< 0x06; i
++)
142 NdisRawWritePortUchar(Adapter
->IOBase
+ PG1_PAR
+ i
, Adapter
->StationAddress
[i
]);
144 /* Go back to page 0 */
145 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
149 VOID
NICSetMulticastAddressMask(
150 PNIC_ADAPTER Adapter
)
152 * FUNCTION: Initializes the multicast address mask on the NIC
154 * Adapter = Pointer to adapter information
156 * The multicast address mask is taken from Adapter.
157 * The NIC is stopped by this operation
163 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE1
);
165 /* Initialize MAR - Multicast Address Registers */
166 for (i
= 0; i
< 0x08; i
++)
167 NdisRawWritePortUchar(Adapter
->IOBase
+ PG1_MAR
+ i
, Adapter
->MulticastAddressMask
[i
]);
169 /* Go back to page 0 */
170 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
174 BOOLEAN
NICReadSAPROM(
175 PNIC_ADAPTER Adapter
)
177 * FUNCTION: Reads the Station Address PROM data from the NIC
179 * Adapter = Pointer to adapter information
181 * TRUE if a the NIC is an NE2000
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
193 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
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 */
198 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
199 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR0
, 0x20);
200 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR1
, 0x00);
202 /* Initialize RSAR0 and RSAR1 - Remote Start Address Registers */
203 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RSAR0
, 0x00);
204 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RSAR1
, 0x00);
206 /* Select page 0, read and start the NIC */
207 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD0
| CR_PAGE0
);
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 */
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"));
222 Adapter
->WordMode
= TRUE
;
224 /* Move the SAPROM data to the adapter object */
225 for (i
= 0; i
< 16; i
++)
226 Adapter
->SAPROM
[i
] = Buffer
[i
* 2];
228 /* Copy the station address */
230 (PVOID
)&Adapter
->StationAddress
,
231 (PVOID
)&Adapter
->SAPROM
,
232 DRIVER_LENGTH_OF_ADDRESS
);
234 /* Initialize DCR - Data Configuration Register (word mode/4 words FIFO) */
235 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_DCR
, DCR_WTS
| DCR_LS
| DCR_FT10
);
239 NDIS_DbgPrint(MIN_TRACE
, ("NE1000 found.\n"));
241 Adapter
->WordMode
= FALSE
;
248 NDIS_STATUS
NICInitialize(
249 PNIC_ADAPTER Adapter
)
251 * FUNCTION: Initializes a NIC
253 * Adapter = Pointer to adapter information
255 * Status of NIC initialization
257 * The NIC is put into loopback mode
262 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
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
;
268 NDIS_DbgPrint(MID_TRACE
, ("Adapter found at (0x%X).\n", Adapter
->IOBase
));
271 NdisRawReadPortUchar(Adapter
->IOBase
+ NIC_RESET
, &Tmp
);
274 NdisStallExecution(1600);
276 /* Write the value back */
277 NdisRawWritePortUchar(Adapter
->IOBase
+ NIC_RESET
, Tmp
);
279 /* Select page 0 and stop NIC */
280 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
282 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
283 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_DCR
, DCR_LS
| DCR_FT10
);
285 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
286 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR0
, 0x00);
287 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR1
, 0x00);
289 /* Initialize RCR - Receive Configuration Register (monitor mode) */
290 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RCR
, RCR_MON
);
292 /* Enter loopback mode (internal NIC module loopback) */
293 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TCR
, TCR_LOOP
);
295 /* Read the Station Address PROM */
296 if (!NICReadSAPROM(Adapter
))
297 return NDIS_STATUS_ADAPTER_NOT_FOUND
;
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]));
304 /* Select page 0 and start NIC */
305 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
| CR_PAGE0
);
307 /* Clear ISR - Interrupt Status Register */
308 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, 0xFF);
310 /* Find NIC RAM size */
313 return NDIS_STATUS_SUCCESS
;
317 NDIS_STATUS
NICSetup(
318 PNIC_ADAPTER Adapter
)
320 * FUNCTION: Sets up a NIC
322 * Adapter = Pointer to adapter information
324 * Status of operation
326 * The NIC is put into loopback mode
329 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
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
);
335 /* Initialize DCR - Data Configuration Register (byte mode/8 bytes FIFO) */
336 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_DCR
, DCR_LS
| DCR_FT10
);
339 /* Clear RBCR0 and RBCR1 - Remote Byte Count Registers */
340 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR0
, 0x00);
341 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR1
, 0x00);
343 /* Initialize RCR - Receive Configuration Register (monitor mode) */
344 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RCR
, RCR_MON
);
346 /* Enter loopback mode (internal NIC module loopback) */
347 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TCR
, TCR_LOOP
);
349 /* Set boundary page */
350 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_BNRY
, Adapter
->NextPacket
);
353 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_PSTART
, Adapter
->PageStart
);
356 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_PSTOP
, Adapter
->PageStop
);
358 /* Program our address on the NIC */
359 NICSetPhysicalAddress(Adapter
);
361 /* Program the multicast address mask on the NIC */
362 NICSetMulticastAddressMask(Adapter
);
364 /* Select page 1 and stop NIC */
365 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE1
);
367 /* Initialize current page register */
368 NdisRawWritePortUchar(Adapter
->IOBase
+ PG1_CURR
, Adapter
->PageStart
+ 1);
370 /* Select page 0 and stop NIC */
371 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
373 /* Clear ISR - Interrupt Status Register */
374 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, 0xFF);
376 /* Initialize IMR - Interrupt Mask Register */
377 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_IMR
, Adapter
->InterruptMask
);
379 /* Select page 0 and start NIC */
380 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
| CR_PAGE0
);
382 Adapter
->CurrentPage
= Adapter
->PageStart
+ 1;
383 Adapter
->NextPacket
= Adapter
->PageStart
+ 1;
384 Adapter
->BufferOverflow
= FALSE
;
385 Adapter
->ReceiveError
= FALSE
;
386 Adapter
->TransmitError
= FALSE
;
388 NDIS_DbgPrint(MAX_TRACE
, ("Leaving.\n"));
390 return NDIS_STATUS_SUCCESS
;
394 NDIS_STATUS
NICStart(
395 PNIC_ADAPTER Adapter
)
397 * FUNCTION: Starts a NIC
399 * Adapter = Pointer to adapter information
401 * Status of operation
404 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
406 /* Take NIC out of loopback mode */
407 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TCR
, 0x00);
409 /* Initialize RCR - Receive Configuration Register (accept all) */
410 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RCR
, RCR_AB
| RCR_AM
| RCR_PRO
);
412 return NDIS_STATUS_SUCCESS
;
417 PNIC_ADAPTER Adapter
)
419 * FUNCTION: Stops a NIC
421 * Adapter = Pointer to adapter information
423 * Status of operation
429 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
431 /* Select page 0 and stop NIC */
432 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
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);
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
);
444 NdisStallExecution(500);
449 NDIS_DbgPrint(MIN_TRACE
, ("NIC was not reset after 2ms.\n"));
452 /* Initialize RCR - Receive Configuration Register (monitor mode) */
453 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RCR
, RCR_MON
);
455 /* Initialize TCR - Transmit Configuration Register (loopback mode) */
456 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TCR
, TCR_LOOP
);
459 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
);
461 return NDIS_STATUS_SUCCESS
;
465 NDIS_STATUS
NICReset(
466 PNIC_ADAPTER Adapter
)
468 * FUNCTION: Resets a NIC
470 * Adapter = Pointer to adapter information
472 * Status of operation
477 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
483 NdisRawReadPortUchar(Adapter
->IOBase
+ NIC_RESET
, &Tmp
);
486 NdisStallExecution(1600);
488 /* Write the value back */
489 NdisRawWritePortUchar(Adapter
->IOBase
+ NIC_RESET
, Tmp
);
491 /* Restart the NIC */
494 return NDIS_STATUS_SUCCESS
;
498 VOID
NICStartTransmit(
499 PNIC_ADAPTER Adapter
)
501 * FUNCTION: Starts transmitting a packet
503 * Adapter = Pointer to adapter information
508 /* Set start of frame */
509 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TPSR
,
510 Adapter
->TXStart
+ Adapter
->TXCurrent
* DRIVER_BLOCK_SIZE
);
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);
517 /* Start transmitting */
518 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_TXP
| CR_RD2
);
520 NDIS_DbgPrint(MAX_TRACE
, ("Transmitting. Buffer (%d) Size (%d).\n",
527 VOID
NICSetBoundaryPage(
528 PNIC_ADAPTER Adapter
)
530 * FUNCTION: Sets the boundary page on the adapter to be one less than NextPacket
532 * Adapter = Pointer to adapter information
535 if (Adapter
->NextPacket
== Adapter
->PageStart
) {
536 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_BNRY
,
537 (UCHAR
)(Adapter
->PageStop
- 1));
539 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_BNRY
,
540 (UCHAR
)(Adapter
->NextPacket
- 1));
545 VOID
NICGetCurrentPage(
546 PNIC_ADAPTER Adapter
)
548 * FUNCTION: Retrieves the current page from the adapter
550 * Adapter = Pointer to adapter information
556 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE1
);
558 /* Read current page */
559 NdisRawReadPortUchar(Adapter
->IOBase
+ PG1_CURR
, &Current
);
562 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
564 Adapter
->CurrentPage
= Current
;
568 VOID
NICUpdateCounters(
569 PNIC_ADAPTER Adapter
)
571 * FUNCTION: Updates counters
573 * Adapter = Pointer to adapter information
578 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
580 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_CNTR0
, &Tmp
);
581 Adapter
->FrameAlignmentErrors
+= Tmp
;
583 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_CNTR1
, &Tmp
);
584 Adapter
->CrcErrors
+= Tmp
;
586 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_CNTR2
, &Tmp
);
587 Adapter
->MissedPackets
+= Tmp
;
591 VOID
NICReadDataAlign(
592 PNIC_ADAPTER Adapter
,
597 * FUNCTION: Copies data from a NIC's RAM into a buffer
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)
610 /* Select page 0 and start the NIC */
611 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
| CR_PAGE0
);
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));
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));
621 /* Select page 0, read and start the NIC */
622 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD0
| CR_PAGE0
);
624 if (Adapter
->WordMode
)
625 NdisRawReadPortBufferUshort(Adapter
->IOBase
+ NIC_DATA
, Target
, Count
>> 1);
627 NdisRawReadPortBufferUchar(Adapter
->IOBase
+ NIC_DATA
, Target
, Count
);
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
);
635 NdisStallExecution(4);
640 NDIS_DbgPrint(MIN_TRACE
, ("Remote DMA did not complete.\n"));
643 /* Clear remote DMA bit in ISR - Interrupt Status Register */
644 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, ISR_RDC
);
648 VOID
NICWriteDataAlign(
649 PNIC_ADAPTER Adapter
,
654 * FUNCTION: Copies data from a buffer into the NIC's RAM
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)
665 /* Select page 0 and start the NIC */
666 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
| CR_PAGE0
);
668 /* Handle read-before-write bug */
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));
674 /* Initialize RBCR0 and RBCR1 - Remote Byte Count Registers */
675 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR0
, 0x02);
676 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR1
, 0x00);
678 /* Read and start the NIC */
679 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD0
| CR_PAGE0
);
682 NdisRawReadPortUshort(Adapter
->IOBase
+ NIC_DATA
, &Count
);
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
);
690 NdisStallExecution(4);
695 NDIS_DbgPrint(MIN_TRACE
, ("Remote DMA did not complete.\n"));
698 /* Clear remote DMA bit in ISR - Interrupt Status Register */
699 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, ISR_RDC
);
702 /* Now output some data */
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));
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));
714 /* Write and start the NIC */
715 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD1
| CR_PAGE0
);
717 if (Adapter
->WordMode
)
718 NdisRawWritePortBufferUshort(Adapter
->IOBase
+ NIC_DATA
, Source
, Count
>> 1);
720 NdisRawWritePortBufferUchar(Adapter
->IOBase
+ NIC_DATA
, Source
, Count
);
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
);
728 NdisStallExecution(4);
733 NDIS_DbgPrint(MIN_TRACE
, ("Remote DMA did not complete.\n"));
736 /* Clear remote DMA bit in ISR - Interrupt Status Register */
737 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, ISR_RDC
);
742 PNIC_ADAPTER Adapter
,
747 * FUNCTION: Copies data from a NIC's RAM into a buffer
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
757 /* Avoid transfers to odd addresses */
759 /* Transfer one word and use the MSB */
760 NICReadDataAlign(Adapter
, &Tmp
, Source
- 1, 0x02);
761 *Target
= (UCHAR
)(Tmp
>> 8);
768 /* Transfer as many words as we can without exceeding the buffer length */
769 Tmp
= Length
& 0xFFFE;
770 NICReadDataAlign(Adapter
, (PUSHORT
)Target
, Source
, Tmp
);
772 (ULONG_PTR
)Target
+= Tmp
;
774 /* Read one word and keep the LSB */
775 NICReadDataAlign(Adapter
, &Tmp
, Source
, 0x02);
776 *Target
= (UCHAR
)(Tmp
& 0x00FF);
778 /* Transfer the rest of the data */
779 NICReadDataAlign(Adapter
, (PUSHORT
)Target
, Source
, Length
);
784 PNIC_ADAPTER Adapter
,
789 * FUNCTION: Copies data from a buffer into NIC's RAM
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
799 /* Avoid transfers to odd addresses */
802 NICReadDataAlign(Adapter
, &Tmp
, Target
- 1, 0x02);
804 /* Merge LSB with the new byte which become the new MSB */
805 Tmp
= (Tmp
& 0x00FF) | (*Source
<< 8);
807 /* Finally write the value back */
808 NICWriteDataAlign(Adapter
, Target
- 1, &Tmp
, 0x02);
810 /* Update pointers */
811 (ULONG_PTR
)Source
+= 1;
812 (ULONG_PTR
)Target
+= 1;
817 /* Transfer as many words as we can without exceeding the transfer length */
818 Tmp
= Length
& 0xFFFE;
819 NICWriteDataAlign(Adapter
, Target
, (PUSHORT
)Source
, Tmp
);
821 (ULONG_PTR
)Target
+= Tmp
;
824 NICReadDataAlign(Adapter
, &Tmp
, Target
, 0x02);
826 /* Merge MSB with the new byte which become the new LSB */
827 Tmp
= (Tmp
& 0xFF00) | (*Source
);
829 /* Finally write the value back */
830 NICWriteDataAlign(Adapter
, Target
, &Tmp
, 0x02);
832 /* Transfer the rest of the data */
833 NICWriteDataAlign(Adapter
, Target
, (PUSHORT
)Source
, Length
);
837 VOID
NICIndicatePacket(
838 PNIC_ADAPTER Adapter
)
840 * FUNCTION: Indicates a packet to the wrapper
842 * Adapter = Pointer to adapter information
847 IndicateLength
= (Adapter
->PacketHeader
.PacketLength
<
848 (Adapter
->LookaheadSize
+ DRIVER_HEADER_SIZE
))?
849 (Adapter
->PacketHeader
.PacketLength
) :
850 (Adapter
->LookaheadSize
+ DRIVER_HEADER_SIZE
);
852 /* Fill the lookahead buffer */
854 (PUCHAR
)&Adapter
->Lookahead
,
855 Adapter
->PacketOffset
+ sizeof(PACKET_HEADER
),
856 IndicateLength
+ DRIVER_HEADER_SIZE
);
858 NDIS_DbgPrint(MAX_TRACE
, ("Indicating (%d) bytes.\n", IndicateLength
));
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]));
875 if (IndicateLength
>= DRIVER_HEADER_SIZE
) {
876 NdisMEthIndicateReceive(Adapter
->MiniportAdapterHandle
,
878 (PVOID
)&Adapter
->Lookahead
,
880 (PVOID
)&Adapter
->Lookahead
[DRIVER_HEADER_SIZE
],
881 IndicateLength
- DRIVER_HEADER_SIZE
,
882 Adapter
->PacketHeader
.PacketLength
- DRIVER_HEADER_SIZE
);
884 NdisMEthIndicateReceive(Adapter
->MiniportAdapterHandle
,
886 (PVOID
)&Adapter
->Lookahead
,
896 PNIC_ADAPTER Adapter
)
898 * FUNCTION: Reads a full packet from the receive buffer ring
900 * Adapter = Pointer to adapter information
904 BOOLEAN SkipPacket
= FALSE
;
906 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
908 /* Check if receive buffer ring is empty */
910 /* Read boundary page */
911 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_BNRY
, &Tmp
);
913 /* Get the header of the next packet in the receive ring */
914 Adapter
->PacketOffset
= Adapter
->NextPacket
<< 8;
916 (PUCHAR
)&Adapter
->PacketHeader
,
917 Adapter
->PacketOffset
,
918 sizeof(PACKET_HEADER
));
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
));
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
));
933 Adapter
->NextPacket
= Adapter
->CurrentPage
;
935 NICIndicatePacket(Adapter
);
937 /* Go to the next free buffer in receive ring */
938 Adapter
->NextPacket
= Adapter
->PacketHeader
.NextPacket
;
941 /* Update boundary page */
942 NICSetBoundaryPage(Adapter
);
947 PNIC_ADAPTER Adapter
)
949 * FUNCTION: Writes a full packet to the transmit buffer ring
951 * Adapter = Pointer to adapter information
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
958 PNDIS_BUFFER SrcBuffer
;
959 UINT BytesToCopy
, SrcSize
, DstSize
;
965 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
967 TXStart
= Adapter
->TXStart
* DRIVER_BLOCK_SIZE
;
968 TXStop
= (Adapter
->TXStart
+ Adapter
->TXCount
) * DRIVER_BLOCK_SIZE
;
970 NdisQueryPacket(Adapter
->TXQueueHead
,
974 &Adapter
->TXSize
[Adapter
->TXNext
]);
976 NDIS_DbgPrint(MAX_TRACE
, ("Packet Size (%d) is now (%d).\n",
978 Adapter
->TXSize
[Adapter
->TXNext
]));
980 NdisQueryBuffer(SrcBuffer
, (PVOID
)&SrcData
, &SrcSize
);
982 DstData
= TXStart
+ Adapter
->TXNext
* DRIVER_BLOCK_SIZE
;
983 DstSize
= TXStop
- DstData
;
985 /* Start copying the data */
987 BytesToCopy
= (SrcSize
< DstSize
)? SrcSize
: DstSize
;
989 NICWriteData(Adapter
, DstData
, SrcData
, BytesToCopy
);
991 (ULONG_PTR
)SrcData
+= BytesToCopy
;
992 SrcSize
-= BytesToCopy
;
993 DstData
+= BytesToCopy
;
994 DstSize
-= BytesToCopy
;
997 /* No more bytes in source buffer. Proceed to
998 the next buffer in the source buffer chain */
999 NdisGetNextBuffer(SrcBuffer
, &SrcBuffer
);
1003 NdisQueryBuffer(SrcBuffer
, (PVOID
)&SrcData
, &SrcSize
);
1007 /* Wrap around the end of the transmit buffer ring */
1009 DstSize
= Adapter
->TXCount
* DRIVER_BLOCK_SIZE
;
1015 BOOLEAN
NICPrepareForTransmit(
1016 PNIC_ADAPTER Adapter
)
1018 * FUNCTION: Prepares a packet for transmission
1020 * Adapter = Pointer to adapter information
1022 * There must be at least one packet in the transmit queue
1024 * TRUE if a packet was prepared, FALSE if not
1029 PNDIS_PACKET Packet
;
1031 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
1033 /* Calculate number of buffers needed to transmit packet */
1034 NdisQueryPacket(Adapter
->TXQueueHead
,
1040 BufferCount
= (Length
+ DRIVER_BLOCK_SIZE
- 1) / DRIVER_BLOCK_SIZE
;
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 */
1049 /* Write the packet to the card */
1050 NICWritePacket(Adapter
);
1052 /* If the NIC is not transmitting, reset the current transmit pointer */
1053 if (Adapter
->TXCurrent
== -1)
1054 Adapter
->TXCurrent
= Adapter
->TXNext
;
1056 Adapter
->TXNext
= (Adapter
->TXNext
+ BufferCount
) % Adapter
->TXCount
;
1057 Adapter
->TXFree
-= BufferCount
;
1059 /* Remove the packet from the queue */
1060 Packet
= Adapter
->TXQueueHead
;
1061 Adapter
->TXQueueHead
= RESERVED(Packet
)->Next
;
1063 if (Packet
== Adapter
->TXQueueTail
)
1064 Adapter
->TXQueueTail
= NULL
;
1066 /* Assume the transmit went well */
1067 NdisMSendComplete(Adapter
->MiniportAdapterHandle
,
1069 NDIS_STATUS_SUCCESS
);
1076 PNIC_ADAPTER Adapter
)
1078 * FUNCTION: Starts transmitting packets in the transmit queue
1080 * Adapter = Pointer to adapter information
1082 * There must be at least one packet in the transmit queue
1085 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
1087 if (Adapter
->TXCurrent
== -1) {
1088 /* NIC is not transmitting, so start transmitting now */
1090 /* Load next packet onto the card, and start transmitting */
1091 if (NICPrepareForTransmit(Adapter
))
1092 NICStartTransmit(Adapter
);
1098 PNIC_ADAPTER Adapter
)
1100 * FUNCTION: Handles reception of a packet
1102 * Adapter = Pointer to adapter information
1104 * Buffer overflows are also handled here
1111 NDIS_DbgPrint(MAX_TRACE
, ("Called.\n"));
1113 Adapter
->DoneIndicating
= FALSE
;
1116 NICGetCurrentPage(Adapter
);
1118 if (Adapter
->BufferOverflow
) {
1120 NDIS_DbgPrint(MAX_TRACE
, ("Receive ring overflow.\n"));
1122 /* Select page 0 and stop the NIC */
1123 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STP
| CR_RD2
| CR_PAGE0
);
1125 /* Clear RBCR0,RBCR1 - Remote Byte Count Registers */
1126 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR0
, 0x00);
1127 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_RBCR1
, 0x00);
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
);
1135 NdisStallExecution(500);
1138 if ((Adapter
->InterruptStatus
& (ISR_PTX
| ISR_TXE
)) == 0) {
1139 /* We may need to restart the transmitter */
1140 Adapter
->TransmitPending
= TRUE
;
1143 /* Initialize TCR - Transmit Configuration Register to loopback mode 1 */
1144 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_TCR
, TCR_LOOP
);
1147 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_CR
, CR_STA
| CR_RD2
);
1151 Adapter
->BufferOverflow
= FALSE
;
1154 if (Adapter
->ReceiveError
) {
1155 NDIS_DbgPrint(MAX_TRACE
, ("Receive error.\n"));
1157 /* Skip this packet */
1158 Adapter
->NextPacket
= Adapter
->CurrentPage
;
1159 NICSetBoundaryPage(Adapter
);
1161 Adapter
->ReceiveError
= FALSE
;
1165 NICGetCurrentPage(Adapter
);
1167 if (Adapter
->CurrentPage
== Adapter
->NextPacket
) {
1168 NDIS_DbgPrint(MAX_TRACE
, ("No more packets.\n"));
1171 NDIS_DbgPrint(MAX_TRACE
, ("Got a packet in the receive ring.\n"));
1173 /* Read packet from receive buffer ring */
1174 NICReadPacket(Adapter
);
1176 Adapter
->DoneIndicating
= TRUE
;
1179 if (PacketCount
== 10) {
1180 /* Don't starve transmit interrupts */
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
;
1193 if (Adapter
->DoneIndicating
)
1194 NdisMEthIndicateReceiveComplete(Adapter
->MiniportAdapterHandle
);
1198 VOID
HandleTransmit(
1199 PNIC_ADAPTER Adapter
)
1201 * FUNCTION: Handles transmission of a packet
1203 * Adapter = Pointer to adapter information
1209 if (Adapter
->TransmitError
) {
1210 /* FIXME: Retransmit now or let upper layer protocols handle retransmit? */
1211 Adapter
->TransmitError
= FALSE
;
1214 /* Free transmit buffers */
1215 Length
= Adapter
->TXSize
[Adapter
->TXCurrent
];
1216 BufferCount
= (Length
+ DRIVER_BLOCK_SIZE
- 1) / DRIVER_BLOCK_SIZE
;
1218 NDIS_DbgPrint(MAX_TRACE
, ("Freeing (%d) buffers at (%d).\n",
1220 Adapter
->TXCurrent
));
1222 Adapter
->TXFree
+= BufferCount
;
1223 Adapter
->TXSize
[Adapter
->TXCurrent
] = 0;
1224 Adapter
->TXCurrent
= (Adapter
->TXCurrent
+ BufferCount
) % Adapter
->TXCount
;
1226 if (Adapter
->TXSize
[Adapter
->TXCurrent
] == 0) {
1227 NDIS_DbgPrint(MAX_TRACE
, ("No more packets in transmit buffer.\n"));
1229 Adapter
->TXCurrent
= -1;
1232 if (Adapter
->TXQueueTail
) {
1233 if (NICPrepareForTransmit(Adapter
))
1234 NICStartTransmit(Adapter
);
1239 VOID
MiniportHandleInterrupt(
1240 IN NDIS_HANDLE MiniportAdapterContext
)
1242 * FUNCTION: Handler for deferred processing of interrupts
1244 * MiniportAdapterContext = Pointer to adapter context area
1246 * Interrupt Service Register is read to determine which interrupts
1247 * are pending. All pending interrupts are handled
1253 PNIC_ADAPTER Adapter
= (PNIC_ADAPTER
)MiniportAdapterContext
;
1255 ISRMask
= Adapter
->InterruptMask
;
1256 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_ISR
, &ISRValue
);
1258 NDIS_DbgPrint(MAX_TRACE
, ("ISRValue (0x%X).\n", ISRValue
));
1260 Adapter
->InterruptStatus
= (ISRValue
& ISRMask
);
1262 if (ISRValue
!= 0x00)
1263 /* Acknowledge interrupts */
1264 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, ISRValue
);
1267 while (Adapter
->InterruptStatus
!= 0x00) {
1269 NDIS_DbgPrint(MAX_TRACE
, ("Adapter->InterruptStatus (0x%X).\n", Adapter
->InterruptStatus
));
1271 while (((Adapter
->InterruptStatus
& Mask
) == 0) && (Mask
< ISRMask
))
1274 switch (Adapter
->InterruptStatus
& Mask
) {
1276 NDIS_DbgPrint(MAX_TRACE
, ("Overflow interrupt.\n"));
1277 /* Overflow. Handled almost the same way as a receive interrupt */
1278 Adapter
->BufferOverflow
= TRUE
;
1280 HandleReceive(Adapter
);
1282 Adapter
->InterruptStatus
&= ~ISR_OVW
;
1286 NDIS_DbgPrint(MAX_TRACE
, ("Receive error interrupt.\n"));
1287 NICUpdateCounters(Adapter
);
1289 Adapter
->ReceiveError
= TRUE
;
1292 NDIS_DbgPrint(MAX_TRACE
, ("Receive interrupt.\n"));
1294 HandleReceive(Adapter
);
1296 Adapter
->InterruptStatus
&= ~(ISR_PRX
| ISR_RXE
);
1300 NDIS_DbgPrint(MAX_TRACE
, ("Transmit error interrupt.\n"));
1301 NICUpdateCounters(Adapter
);
1303 Adapter
->TransmitError
= TRUE
;
1306 NDIS_DbgPrint(MAX_TRACE
, ("Transmit interrupt.\n"));
1308 HandleTransmit(Adapter
);
1310 Adapter
->InterruptStatus
&= ~(ISR_PTX
| ISR_TXE
);
1314 NDIS_DbgPrint(MAX_TRACE
, ("Counter interrupt.\n"));
1315 /* Counter overflow. Read counters from the NIC */
1316 NICUpdateCounters(Adapter
);
1318 Adapter
->InterruptStatus
&= ~ISR_CNT
;
1322 NDIS_DbgPrint(MAX_TRACE
, ("Unknown interrupt. Adapter->InterruptStatus (0x%X).\n", Adapter
->InterruptStatus
));
1323 Adapter
->InterruptStatus
&= ~Mask
;
1329 /* Check if new interrupts are generated */
1330 NdisRawReadPortUchar(Adapter
->IOBase
+ PG0_ISR
, &ISRValue
);
1331 Adapter
->InterruptStatus
|= (ISRValue
& ISRMask
);
1333 if (ISRValue
!= 0x00) {
1334 /* Acknowledge interrupts */
1335 NdisRawWritePortUchar(Adapter
->IOBase
+ PG0_ISR
, ISRValue
);
1340 NICEnableInterrupts((PNIC_ADAPTER
)MiniportAdapterContext
);