2 * ReactOS AMD PCNet Driver
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * PROJECT: ReactOS AMD PCNet Driver
20 * FILE: drivers/net/dd/pcnet/pcnet.c
21 * PURPOSE: PCNet Device Driver
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
24 * 9-Sept-2003 vizzini - Created
26 * - this is hard-coded to NDIS4
27 * - this assumes a little-endian machine
28 * - this assumes a 32-bit machine
29 * - this doesn't handle multiple PCNET NICs yet
30 * - this driver includes both NdisRaw and NdisImmediate calls
31 * for NDIS testing purposes. Pick your poison below.
42 IN NDIS_HANDLE MiniportAdapterContext
)
44 * FUNCTION: Stop the miniport and prepare for unload
46 * MiniportAdapterContext: context specified to NdisMSetAttributes
48 * - Called by NDIS at PASSIVE_LEVEL
51 /* XXX Implement me */
52 PCNET_DbgPrint(("Called\n"));
58 MiniportHandleInterrupt(
59 IN NDIS_HANDLE MiniportAdapterContext
)
61 * FUNCTION: Handle an interrupt if told to by MiniportISR
63 * MiniportAdapterContext: context specified to NdisMSetAttributes
65 * - Called by NDIS at DISPATCH_LEVEL
68 PADAPTER Adapter
= (PADAPTER
)MiniportAdapterContext
;
70 BOOLEAN ErrorHandled
= FALSE
;
71 BOOLEAN ReceiveHandled
= FALSE
;
72 BOOLEAN IdonHandled
= FALSE
;
75 PCNET_DbgPrint(("Called\n"));
77 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
78 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
80 PCNET_DbgPrint(("CSR0 is 0x%x\n", Data
));
82 while(Data
& CSR0_INTR
)
88 PCNET_DbgPrint(("ERROR HANDLED TWO TIMES\n"));
94 PCNET_DbgPrint(("clearing an error\n"));
95 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_MERR
|CSR0_BABL
|CSR0_CERR
|CSR0_MISS
);
96 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Temp
);
97 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp
));
99 else if(Data
& CSR0_IDON
)
103 PCNET_DbgPrint(("IDON HANDLED TWO TIMES\n"));
109 PCNET_DbgPrint(("clearing IDON\n"));
110 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_IDON
);
111 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Temp
);
112 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp
));
114 else if(Data
& CSR0_RINT
)
118 PCNET_DbgPrint(("RECEIVE HANDLED TWO TIMES\n"));
122 ReceiveHandled
= TRUE
;
124 PCNET_DbgPrint(("receive interrupt - clearing\n"));
125 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_RINT
);
126 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Temp
);
127 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp
));
131 PRECEIVE_DESCRIPTOR Descriptor
= Adapter
->ReceiveDescriptorRingVirt
+ Adapter
->CurrentReceiveDescriptorIndex
;
135 if(Descriptor
->FLAGS
& RD_OWN
)
137 PCNET_DbgPrint(("no more receive descriptors to process\n"));
141 if(Descriptor
->FLAGS
& RD_ERR
)
143 PCNET_DbgPrint(("receive descriptor error: 0x%x\n", Descriptor
->FLAGS
));
147 if(!((Descriptor
->FLAGS
& RD_STP
) && (Descriptor
->FLAGS
& RD_ENP
)))
149 PCNET_DbgPrint(("receive descriptor not start&end: 0x%x\n", Descriptor
->FLAGS
));
153 Buffer
= Adapter
->ReceiveBufferPtrVirt
+ Adapter
->CurrentReceiveDescriptorIndex
* BUFFER_SIZE
;
154 ByteCount
= Descriptor
->MCNT
& 0xfff;
156 PCNET_DbgPrint(("Indicating a %d-byte packet (index %d)\n", ByteCount
, Adapter
->CurrentReceiveDescriptorIndex
));
158 NdisMEthIndicateReceive(Adapter
->MiniportAdapterHandle
, 0, Buffer
, 14, Buffer
+14, ByteCount
-14, ByteCount
-14);
160 memset(Descriptor
, 0, sizeof(RECEIVE_DESCRIPTOR
));
162 (ULONG
)(Adapter
->ReceiveBufferPtrPhys
+ Adapter
->CurrentReceiveDescriptorIndex
* BUFFER_SIZE
);
163 Descriptor
->BCNT
= (-BUFFER_SIZE
) | 0xf000;
164 Descriptor
->FLAGS
&= RD_OWN
;
166 Adapter
->CurrentReceiveDescriptorIndex
++;
168 if(Adapter
->CurrentReceiveDescriptorIndex
== NUMBER_OF_BUFFERS
)
169 Adapter
->CurrentReceiveDescriptorIndex
= 0;
174 PCNET_DbgPrint(("UNHANDLED INTERRUPT\n"));
178 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
181 /* re-enable interrupts */
182 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_IENA
);
184 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
185 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Data
));
193 * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
195 * MiniportAdapterContext: context supplied to NdisMSetAttributes
197 * NDIS_STATUS_FAILURE on a general error
198 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
199 * NDIS_STATUS_SUCCESS on succes
206 /* Detect the card in the configured slot */
207 Status
= NdisReadPciSlotInformation(Adapter
->MiniportAdapterHandle
, Adapter
->SlotNumber
, PCI_PCIID
, &buf32
, 4);
210 Status
= NDIS_STATUS_FAILURE
;
211 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
218 Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
219 PCNET_DbgPrint(("card in slot 0x%x isn't us: 0x%x\n", Adapter
->SlotNumber
, buf32
));
224 Status
= NdisReadPciSlotInformation(Adapter
->MiniportAdapterHandle
, Adapter
->SlotNumber
,
225 PCI_COMMAND
, &buf32
, 4);
228 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
230 return NDIS_STATUS_FAILURE
;
233 PCNET_DbgPrint(("config/status register: 0x%x\n", buf32
));
237 PCNET_DbgPrint(("io space access is enabled.\n"));
241 PCNET_DbgPrint(("io space is NOT enabled!\n"));
243 return NDIS_STATUS_FAILURE
;
246 /* get IO base physical address */
248 Status
= NdisReadPciSlotInformation(Adapter
->MiniportAdapterHandle
, Adapter
->SlotNumber
, PCI_IOBAR
, &buf32
, 4);
251 Status
= NDIS_STATUS_FAILURE
;
252 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
259 PCNET_DbgPrint(("No base i/o address set\n"));
260 return NDIS_STATUS_FAILURE
;
263 buf32
&= ~1; /* even up address - comes out odd for some reason */
265 PCNET_DbgPrint(("detected io address 0x%x\n", buf32
));
266 Adapter
->IoBaseAddress
= buf32
;
268 /* get interrupt vector */
269 Status
= NdisReadPciSlotInformation(Adapter
->MiniportAdapterHandle
, Adapter
->SlotNumber
, PCI_ILR
, &buf8
, 1);
272 Status
= NDIS_STATUS_FAILURE
;
273 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
278 PCNET_DbgPrint(("interrupt: 0x%x\n", buf8
));
279 Adapter
->InterruptVector
= buf8
;
281 return NDIS_STATUS_SUCCESS
;
288 NDIS_HANDLE WrapperConfigurationContext
)
290 * FUNCTION: Get configuration parameters from the registry
292 * Adapter: pointer to the Adapter struct for this NIC
293 * WrapperConfigurationContext: Context passed into MiniportInitialize
295 * NDIS_STATUS_SUCCESS on success
296 * NDIS_STATUS_{something} on failure (return val from other Ndis calls)
299 PNDIS_CONFIGURATION_PARAMETER Parameter
;
300 NDIS_HANDLE ConfigurationHandle
= 0;
301 UNICODE_STRING Keyword
;
304 NdisOpenConfiguration(&Status
, &ConfigurationHandle
, WrapperConfigurationContext
);
305 if(Status
!= NDIS_STATUS_SUCCESS
)
307 PCNET_DbgPrint(("Unable to open configuration: 0x%x\n", Status
));
312 RtlInitUnicodeString(&Keyword
, L
"SlotNumber");
313 NdisReadConfiguration(&Status
, &Parameter
, ConfigurationHandle
, &Keyword
, NdisParameterInteger
);
314 if(Status
!= NDIS_STATUS_SUCCESS
)
316 PCNET_DbgPrint(("Unable to read slot number: 0x%x\n", Status
));
320 Adapter
->SlotNumber
= Parameter
->ParameterData
.IntegerData
;
322 NdisCloseConfiguration(ConfigurationHandle
);
324 return NDIS_STATUS_SUCCESS
;
329 MiAllocateSharedMemory(
332 * FUNCTION: Allocate all shared memory used by the miniport
334 * Adapter: Pointer to the miniport's adapter object
336 * NDIS_STATUS_RESOURCES on insufficient memory
337 * NDIS_STATUS_SUCCESS on success
340 PTRANSMIT_DESCRIPTOR TransmitDescriptor
;
341 PRECEIVE_DESCRIPTOR ReceiveDescriptor
;
342 NDIS_PHYSICAL_ADDRESS PhysicalAddress
;
345 /* allocate the initialization block */
346 Adapter
->InitializationBlockLength
= sizeof(INITIALIZATION_BLOCK
);
347 NdisMAllocateSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->InitializationBlockLength
,
348 FALSE
, (PVOID
*)&Adapter
->InitializationBlockVirt
, &PhysicalAddress
);
349 if(!Adapter
->InitializationBlockVirt
)
351 PCNET_DbgPrint(("insufficient resources\n"));
353 return NDIS_STATUS_RESOURCES
;
356 if(((ULONG
)Adapter
->InitializationBlockVirt
& 0x00000003) != 0)
358 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter
->InitializationBlockVirt
));
360 return NDIS_STATUS_RESOURCES
;
363 Adapter
->InitializationBlockPhys
= (PINITIALIZATION_BLOCK
)NdisGetPhysicalAddressLow(PhysicalAddress
);
364 memset(Adapter
->InitializationBlockVirt
, 0, sizeof(INITIALIZATION_BLOCK
));
366 /* allocate the transport descriptor ring */
367 Adapter
->TransmitDescriptorRingLength
= sizeof(TRANSMIT_DESCRIPTOR
) * NUMBER_OF_BUFFERS
;
368 NdisMAllocateSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->TransmitDescriptorRingLength
,
369 FALSE
, (PVOID
*)&Adapter
->TransmitDescriptorRingVirt
, &PhysicalAddress
);
370 if(!Adapter
->TransmitDescriptorRingVirt
)
372 PCNET_DbgPrint(("insufficient resources\n"));
374 return NDIS_STATUS_RESOURCES
;
377 if(((ULONG
)Adapter
->TransmitDescriptorRingVirt
& 0x00000003) != 0)
379 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter
->TransmitDescriptorRingVirt
));
381 return NDIS_STATUS_RESOURCES
;
384 Adapter
->TransmitDescriptorRingPhys
= (PTRANSMIT_DESCRIPTOR
)NdisGetPhysicalAddressLow(PhysicalAddress
);
385 memset(Adapter
->TransmitDescriptorRingVirt
, 0, sizeof(TRANSMIT_DESCRIPTOR
) * NUMBER_OF_BUFFERS
);
387 /* allocate the receive descriptor ring */
388 Adapter
->ReceiveDescriptorRingLength
= sizeof(RECEIVE_DESCRIPTOR
) * NUMBER_OF_BUFFERS
;
389 NdisMAllocateSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->ReceiveDescriptorRingLength
,
390 FALSE
, (PVOID
*)&Adapter
->ReceiveDescriptorRingVirt
, &PhysicalAddress
);
391 if(!Adapter
->ReceiveDescriptorRingVirt
)
393 PCNET_DbgPrint(("insufficient resources\n"));
395 return NDIS_STATUS_RESOURCES
;
398 if(((ULONG
)Adapter
->ReceiveDescriptorRingVirt
& 0x00000003) != 0)
400 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter
->ReceiveDescriptorRingVirt
));
402 return NDIS_STATUS_RESOURCES
;
405 Adapter
->ReceiveDescriptorRingPhys
= (PRECEIVE_DESCRIPTOR
)NdisGetPhysicalAddressLow(PhysicalAddress
);
406 memset(Adapter
->ReceiveDescriptorRingVirt
, 0, sizeof(RECEIVE_DESCRIPTOR
) * NUMBER_OF_BUFFERS
);
408 /* allocate transmit buffers */
409 Adapter
->TransmitBufferLength
= BUFFER_SIZE
* NUMBER_OF_BUFFERS
;
410 NdisMAllocateSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->TransmitBufferLength
,
411 FALSE
, (PVOID
*)&Adapter
->TransmitBufferPtrVirt
, &PhysicalAddress
);
412 if(!Adapter
->TransmitBufferPtrVirt
)
414 PCNET_DbgPrint(("insufficient resources\n"));
416 return NDIS_STATUS_RESOURCES
;
419 if(((ULONG
)Adapter
->TransmitBufferPtrVirt
& 0x00000003) != 0)
421 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter
->TransmitBufferPtrVirt
));
423 return NDIS_STATUS_RESOURCES
;
426 Adapter
->TransmitBufferPtrPhys
= (PCHAR
)NdisGetPhysicalAddressLow(PhysicalAddress
);
427 memset(Adapter
->TransmitBufferPtrVirt
, 0, BUFFER_SIZE
* NUMBER_OF_BUFFERS
);
429 /* allocate receive buffers */
430 Adapter
->ReceiveBufferLength
= BUFFER_SIZE
* NUMBER_OF_BUFFERS
;
431 NdisMAllocateSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->ReceiveBufferLength
,
432 FALSE
, (PVOID
*)&Adapter
->ReceiveBufferPtrVirt
, &PhysicalAddress
);
433 if(!Adapter
->ReceiveBufferPtrVirt
)
435 PCNET_DbgPrint(("insufficient resources\n"));
437 return NDIS_STATUS_RESOURCES
;
440 if(((ULONG
)Adapter
->ReceiveBufferPtrVirt
& 0x00000003) != 0)
442 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter
->ReceiveBufferPtrVirt
));
444 return NDIS_STATUS_RESOURCES
;
447 Adapter
->ReceiveBufferPtrPhys
= (PCHAR
)NdisGetPhysicalAddressLow(PhysicalAddress
);
448 memset(Adapter
->ReceiveBufferPtrVirt
, 0, BUFFER_SIZE
* NUMBER_OF_BUFFERS
);
450 /* initialize tx descriptors */
451 TransmitDescriptor
= Adapter
->TransmitDescriptorRingVirt
;
452 for(i
= 0; i
< NUMBER_OF_BUFFERS
; i
++)
454 (TransmitDescriptor
+i
)->TBADR
= (ULONG
)Adapter
->TransmitBufferPtrPhys
+ i
* BUFFER_SIZE
;
455 (TransmitDescriptor
+i
)->BCNT
= 0xf000 | -BUFFER_SIZE
; /* 2's compliment + set top 4 bits */
456 (TransmitDescriptor
+i
)->FLAGS
= TD1_STP
| TD1_ENP
;
459 PCNET_DbgPrint(("transmit ring initialized\n"));
462 ReceiveDescriptor
= Adapter
->ReceiveDescriptorRingVirt
;
463 for(i
= 0; i
< NUMBER_OF_BUFFERS
; i
++)
465 (ReceiveDescriptor
+i
)->RBADR
= (ULONG
)Adapter
->ReceiveBufferPtrPhys
+ i
* BUFFER_SIZE
;
466 (ReceiveDescriptor
+i
)->BCNT
= 0xf0000 | -BUFFER_SIZE
; /* 2's compliment + set top 4 bits */
467 (ReceiveDescriptor
+i
)->FLAGS
|= RD_OWN
;
470 PCNET_DbgPrint(("receive ring initialized\n"));
472 return NDIS_STATUS_SUCCESS
;
477 MiPrepareInitializationBlock(
480 * FUNCTION: Initialize the initialization block
482 * Adapter: pointer to the miniport's adapter object
487 /* read burned-in address from card */
488 for(i
= 0; i
< 6; i
++)
489 NdisRawReadPortUchar(Adapter
->PortOffset
+ i
, Adapter
->InitializationBlockVirt
->PADR
+ i
);
491 /* set up receive ring */
492 PCNET_DbgPrint(("Receive ring physical address: 0x%x\n", Adapter
->ReceiveDescriptorRingPhys
));
493 Adapter
->InitializationBlockVirt
->RDRA
= (ULONG
)Adapter
->ReceiveDescriptorRingPhys
;
494 Adapter
->InitializationBlockVirt
->RLEN
= (LOG_NUMBER_OF_BUFFERS
<< 4) & 0xf0;
496 /* set up transmit ring */
497 PCNET_DbgPrint(("Transmit ring physical address: 0x%x\n", Adapter
->TransmitDescriptorRingPhys
));
498 Adapter
->InitializationBlockVirt
->TDRA
= (ULONG
)Adapter
->TransmitDescriptorRingPhys
;
499 Adapter
->InitializationBlockVirt
->TLEN
= (LOG_NUMBER_OF_BUFFERS
<< 4) & 0xf0;
507 * FUNCTION: Free all allocated shared memory
509 * Adapter: pointer to the miniport's adapter struct
512 NDIS_PHYSICAL_ADDRESS PhysicalAddress
;
514 PhysicalAddress
.u
.HighPart
= 0;
516 if(Adapter
->InitializationBlockVirt
)
518 PhysicalAddress
.u
.LowPart
= (ULONG
)Adapter
->InitializationBlockPhys
;
519 NdisMFreeSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->InitializationBlockLength
,
520 FALSE
, (PVOID
*)&Adapter
->InitializationBlockVirt
, PhysicalAddress
);
523 if(Adapter
->TransmitDescriptorRingVirt
)
525 PhysicalAddress
.u
.LowPart
= (ULONG
)Adapter
->TransmitDescriptorRingPhys
;
526 NdisMFreeSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->TransmitDescriptorRingLength
,
527 FALSE
, (PVOID
*)&Adapter
->TransmitDescriptorRingVirt
, PhysicalAddress
);
530 if(Adapter
->ReceiveDescriptorRingVirt
)
532 PhysicalAddress
.u
.LowPart
= (ULONG
)Adapter
->ReceiveDescriptorRingPhys
;
533 NdisMFreeSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->ReceiveDescriptorRingLength
,
534 FALSE
, (PVOID
*)&Adapter
->ReceiveDescriptorRingVirt
, PhysicalAddress
);
537 if(Adapter
->TransmitBufferPtrVirt
)
539 PhysicalAddress
.u
.LowPart
= (ULONG
)Adapter
->TransmitBufferPtrPhys
;
540 NdisMFreeSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->TransmitBufferLength
,
541 FALSE
, (PVOID
*)&Adapter
->TransmitBufferPtrVirt
, PhysicalAddress
);
544 if(Adapter
->ReceiveBufferPtrVirt
)
546 PhysicalAddress
.u
.LowPart
= (ULONG
)Adapter
->ReceiveBufferPtrPhys
;
547 NdisMFreeSharedMemory(Adapter
->MiniportAdapterHandle
, Adapter
->ReceiveBufferLength
,
548 FALSE
, (PVOID
*)&Adapter
->ReceiveBufferPtrVirt
, PhysicalAddress
);
557 * FUNCTION: Initialize and start the PCNET chip
559 * Adapter: pointer to the miniport's adapter struct
561 * - should be coded to detect failure and return an error
562 * - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that.
567 PCNET_DbgPrint(("Called\n"));
570 * first reset the chip - 32-bit reset followed by 16-bit reset. if it's in 32-bit mode, it'll reset
571 * twice. if it's in 16-bit mode, the first read will be nonsense and the second will be a reset. the
572 * card is reset by reading from the reset register. on reset it's in 16-bit i/o mode.
574 NdisRawReadPortUshort(Adapter
->PortOffset
+ RESET32
, &Data
);
575 NdisRawReadPortUshort(Adapter
->PortOffset
+ RESET16
, &Data
);
578 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
579 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_STOP
);
581 /* pause for 1ms so the chip will have time to reset */
582 NdisStallExecution(1);
584 PCNET_DbgPrint(("chip stopped\n"));
586 /* set the software style to 2 (32 bits) */
587 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR58
);
588 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
592 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, Data
);
594 /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */
595 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR4
);
596 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
598 Data
|= CSR4_APAD_XMT
| /* CSR4_DPOLL |*/ CSR4_TXSTRTM
| CSR4_DMAPLUS
;
599 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, Data
);
601 /* set up bcr18: burst read/write enable */
602 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, BCR18
);
603 NdisRawReadPortUshort(Adapter
->PortOffset
+ BDP
, &Data
);
605 Data
|= BCR18_BREADE
| BCR18_BWRITE
;
606 NdisRawWritePortUshort(Adapter
->PortOffset
+ BDP
, Data
);
608 /* set up csr1 and csr2 with init block */
609 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR1
);
610 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, (USHORT
)((ULONG
)Adapter
->InitializationBlockPhys
& 0xffff));
611 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR2
);
612 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, (USHORT
)((ULONG
)Adapter
->InitializationBlockPhys
>> 16) & 0xffff);
614 PCNET_DbgPrint(("programmed with init block\n"));
618 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR15
);
619 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, Data
);
621 /* load init block and start the card */
622 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
623 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, CSR0_STRT
|CSR0_INIT
|CSR0_IENA
);
625 PCNET_DbgPrint(("card started\n"));
627 Adapter
->Flags
&= ~RESET_IN_PROGRESS
;
635 * FUNCTION: Test the NIC
637 * Adapter: pointer to the miniport's adapter struct
639 * TRUE if the test succeeds
642 * - this is where to add diagnostics. This is called
643 * at the very end of initialization.
650 /* see if we can read/write now */
651 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
652 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
653 PCNET_DbgPrint(("Port 0x%x RAP 0x%x CSR0 0x%x RDP 0x%x, Interupt status register is 0x%x\n", Adapter
->PortOffset
, RAP
, CSR0
, RDP
, Data
));
656 for(i
= 0; i
< 6; i
++)
657 NdisRawReadPortUchar(Adapter
->PortOffset
+ i
, &address
[i
]);
659 PCNET_DbgPrint(("burned-in address: %x:%x:%x:%x:%x:%x\n", address
[0], address
[1], address
[2], address
[3], address
[4], address
[5]));
660 /* Read status flags from CSR0 */
661 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
662 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
663 PCNET_DbgPrint(("CSR0: 0x%x\n", Data
));
665 /* Read status flags from CSR3 */
666 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR3
);
667 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
669 PCNET_DbgPrint(("CSR3: 0x%x\n", Data
));
670 /* Read status flags from CSR4 */
671 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR4
);
672 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
673 PCNET_DbgPrint(("CSR4: 0x%x\n", Data
));
675 /* Read status flags from CSR5 */
676 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR5
);
677 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
678 PCNET_DbgPrint(("CSR5: 0x%x\n", Data
));
680 /* Read status flags from CSR6 */
681 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR6
);
682 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
683 PCNET_DbgPrint(("CSR6: 0x%x\n", Data
));
685 /* finally, fire a test interrupt to test the ISR */
686 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR4
);
687 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
688 Data
|= CSR4_UINTCMD
;
689 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, Data
);
690 PCNET_DbgPrint(("just wrote 0x%x to CSR4 for test interrupt\n", Data
));
699 OUT PNDIS_STATUS OpenErrorStatus
,
700 OUT PUINT SelectedMediumIndex
,
701 IN PNDIS_MEDIUM MediumArray
,
702 IN UINT MediumArraySize
,
703 IN NDIS_HANDLE MiniportAdapterHandle
,
704 IN NDIS_HANDLE WrapperConfigurationContext
)
706 * FUNCTION: Initialize a new miniport
708 * OpenErrorStatus: pointer to a var to return status info in
709 * SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3)
710 * MediumArray: array of media that we can pick from
711 * MediumArraySize: size of MediumArray
712 * MiniportAdapterHandle: NDIS-assigned handle for this miniport instance
713 * WrapperConfigurationContext: temporary NDIS-assigned handle for passing
714 * to configuration APIs
716 * NDIS_STATUS_SUCCESS on success
717 * NDIS_STATUS_FAILURE on general failure
718 * NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray
719 * NDIS_STATUS_RESOURCES on insufficient system resources
720 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
722 * - Called by NDIS at PASSIVE_LEVEL, once per detected card
723 * - Will int 3 on failure of MiTestCard if DBG=1
727 PADAPTER Adapter
= 0;
728 NDIS_STATUS Status
= NDIS_STATUS_FAILURE
;
729 BOOLEAN InterruptRegistered
= FALSE
;
732 for(i
= 0; i
< MediumArraySize
; i
++)
733 if(MediumArray
[i
] == NdisMedium802_3
)
736 if(i
== MediumArraySize
)
738 Status
= NDIS_STATUS_UNSUPPORTED_MEDIA
;
739 PCNET_DbgPrint(("unsupported media\n"));
741 *OpenErrorStatus
= Status
;
745 *SelectedMediumIndex
= i
;
747 /* allocate our adapter struct */
748 Status
= NdisAllocateMemoryWithTag((PVOID
*)&Adapter
, sizeof(ADAPTER
), PCNET_TAG
);
749 if(Status
!= NDIS_STATUS_SUCCESS
)
751 Status
= NDIS_STATUS_RESOURCES
;
752 PCNET_DbgPrint(("Insufficient resources\n"));
754 *OpenErrorStatus
= Status
;
758 memset(Adapter
,0,sizeof(ADAPTER
));
760 Adapter
->MiniportAdapterHandle
= MiniportAdapterHandle
;
762 /* register our adapter structwith ndis */
763 NdisMSetAttributesEx(Adapter
->MiniportAdapterHandle
, Adapter
, 0, NDIS_ATTRIBUTE_BUS_MASTER
, NdisInterfacePci
);
767 /* get registry config */
768 Status
= MiGetConfig(Adapter
, WrapperConfigurationContext
);
769 if(Status
!= NDIS_STATUS_SUCCESS
)
771 PCNET_DbgPrint(("MiGetConfig failed\n"));
772 Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
777 /* Card-specific detection and setup */
778 Status
= MiQueryCard(Adapter
);
779 if(Status
!= NDIS_STATUS_SUCCESS
)
781 PCNET_DbgPrint(("MiQueryCard failed\n"));
782 Status
= NDIS_STATUS_ADAPTER_NOT_FOUND
;
787 /* register an IO port range */
788 Status
= NdisMRegisterIoPortRange(&Adapter
->PortOffset
, Adapter
->MiniportAdapterHandle
,
789 Adapter
->IoBaseAddress
, NUMBER_OF_PORTS
);
790 if(Status
!= NDIS_STATUS_SUCCESS
)
792 PCNET_DbgPrint(("NdisMRegisterIoPortRange failed: 0x%x\n", Status
));
797 /* Allocate map registers */
798 Status
= NdisMAllocateMapRegisters(Adapter
->MiniportAdapterHandle
, 0,
799 NDIS_DMA_32BITS
, 8, BUFFER_SIZE
);
800 if(Status
!= NDIS_STATUS_SUCCESS
)
802 PCNET_DbgPrint(("NdisMAllocateMapRegisters failed: 0x%x\n", Status
));
807 /* set up the interrupt */
808 memset(&Adapter
->InterruptObject
, 0, sizeof(NDIS_MINIPORT_INTERRUPT
));
809 Status
= NdisMRegisterInterrupt(&Adapter
->InterruptObject
, Adapter
->MiniportAdapterHandle
, Adapter
->InterruptVector
,
810 Adapter
->InterruptVector
, FALSE
, TRUE
, NdisInterruptLevelSensitive
);
811 if(Status
!= NDIS_STATUS_SUCCESS
)
813 PCNET_DbgPrint(("NdisMRegisterInterrupt failed: 0x%x\n", Status
));
818 InterruptRegistered
= TRUE
;
820 /* Allocate and initialize shared data structures */
821 Status
= MiAllocateSharedMemory(Adapter
);
822 if(Status
!= NDIS_STATUS_SUCCESS
)
824 Status
= NDIS_STATUS_RESOURCES
;
825 PCNET_DbgPrint(("MiAllocateSharedMemory failed", Status
));
830 /* set up the initialization block */
831 MiPrepareInitializationBlock(Adapter
);
833 PCNET_DbgPrint(("Interrupt registered successfully\n"));
835 /* Initialize and start the chip */
838 Status
= NDIS_STATUS_SUCCESS
;
842 if(Status
!= NDIS_STATUS_SUCCESS
&& Adapter
)
844 PCNET_DbgPrint(("Error; freeing stuff\n"));
846 NdisMFreeMapRegisters(Adapter
->MiniportAdapterHandle
); /* doesn't hurt to free if we never alloc'd? */
848 if(Adapter
->PortOffset
)
849 NdisMDeregisterIoPortRange(Adapter
->MiniportAdapterHandle
, Adapter
->IoBaseAddress
, NUMBER_OF_PORTS
, Adapter
->PortOffset
);
851 if(InterruptRegistered
)
852 NdisMDeregisterInterrupt(&Adapter
->InterruptObject
);
854 MiFreeSharedMemory(Adapter
);
856 NdisFreeMemory(Adapter
, 0, 0);
860 if(!MiTestCard(Adapter
))
864 PCNET_DbgPrint(("returning 0x%x\n", Status
));
865 *OpenErrorStatus
= Status
;
873 OUT PBOOLEAN InterruptRecognized
,
874 OUT PBOOLEAN QueueMiniportHandleInterrupt
,
875 IN NDIS_HANDLE MiniportAdapterContext
)
877 * FUNCTION: Miniport interrupt service routine
879 * InterruptRecognized: the interrupt was ours
880 * QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
881 * MiniportAdapterContext: the context originally passed to NdisMSetAttributes
883 * - called by NDIS at DIRQL
884 * - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
890 PADAPTER Adapter
= (PADAPTER
)MiniportAdapterContext
;
892 PCNET_DbgPrint(("Called\n"));
894 /* save the old RAP value */
895 NdisRawReadPortUshort(Adapter
->PortOffset
+ RAP
, &Rap
);
898 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
899 NdisRawReadPortUshort(Adapter
->PortOffset
+ RDP
, &Data
);
901 if(!(Data
& CSR0_INTR
))
903 PCNET_DbgPrint(("not our interrupt.\n"));
904 *InterruptRecognized
= FALSE
;
905 *QueueMiniportHandleInterrupt
= FALSE
;
909 PCNET_DbgPrint(("detected our interrupt\n"));
911 /* disable interrupts */
912 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, CSR0
);
913 NdisRawWritePortUshort(Adapter
->PortOffset
+ RDP
, 0);
915 *InterruptRecognized
= TRUE
;
916 *QueueMiniportHandleInterrupt
= TRUE
;
919 /* restore the rap */
920 NdisRawWritePortUshort(Adapter
->PortOffset
+ RAP
, Rap
);
926 MiniportQueryInformation(
927 IN NDIS_HANDLE MiniportAdapterContext
,
929 IN PVOID InformationBuffer
,
930 IN ULONG InformationBufferLength
,
931 OUT PULONG BytesWritten
,
932 OUT PULONG BytesNeeded
)
934 * FUNCTION: Query an OID from the driver
936 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
937 * Oid: OID NDIS is querying
938 * InformationBuffer: pointer to buffer into which to write the results of the query
939 * InformationBufferLength: size in bytes of InformationBuffer
940 * BytesWritten: number of bytes written into InformationBuffer in response to the query
941 * BytesNeeded: number of bytes needed to answer the query
943 * NDIS_STATUS_SUCCESS on all queries
945 * - Called by NDIS at PASSIVE_LEVEL
946 * - If InformationBufferLength is insufficient to store the results, return the amount
947 * needed in BytesNeeded and return NDIS_STATUS_INVALID_LENGTH
950 PCNET_DbgPrint(("Called\n"));
951 return NDIS_STATUS_SUCCESS
;
958 OUT PBOOLEAN AddressingReset
,
959 IN NDIS_HANDLE MiniportAdapterContext
)
961 * FUNCTION: Reset the miniport
963 * AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
964 * to reset our addresses and filters
965 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
967 * NDIS_STATUS_SUCCESS on all requests
969 * - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
972 PCNET_DbgPrint(("Called\n"));
973 return NDIS_STATUS_SUCCESS
;
979 MiniportSetInformation(
980 IN NDIS_HANDLE MiniportAdapterContext
,
982 IN PVOID InformationBuffer
,
983 IN ULONG InformationBufferLength
,
984 OUT PULONG BytesRead
,
985 OUT PULONG BytesNeeded
)
987 * FUNCTION: Set a miniport variable (OID)
989 * MiniportAdapterContext: context originally passed into NdisMSetAttributes
990 * Oid: the variable being set
991 * InformationBuffer: the data to set the variable to
992 * InformationBufferLength: number of bytes in InformationBuffer
993 * BytesRead: number of bytes read by us out of the buffer
994 * BytesNeeded: number of bytes required to satisfy the request if InformationBufferLength
997 * NDIS_STATUS_SUCCESS on all requests
999 * - Called by NDIS at PASSIVE_LEVEL
1002 PCNET_DbgPrint(("Called\n"));
1003 return NDIS_STATUS_SUCCESS
;
1010 IN NDIS_HANDLE MiniportAdapterContext
,
1011 IN PNDIS_PACKET Packet
,
1014 * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
1016 * MiniportAdapterContext: context originally input to NdisMSetAttributes
1017 * Packet: The NDIS_PACKET to be sent
1018 * Flags: Flags associated with Packet
1020 * NDIS_STATUS_SUCCESS on all requests
1022 * - Called by NDIS at DISPATCH_LEVEL
1025 PCNET_DbgPrint(("Called\n"));
1026 return NDIS_STATUS_SUCCESS
;
1033 IN PDRIVER_OBJECT DriverObject
,
1034 IN PUNICODE_STRING RegistryPath
)
1036 * FUNCTION: Start this driver
1038 * DriverObject: Pointer to the system-allocated driver object
1039 * RegistryPath: Pointer to our SCM database entry
1041 * NDIS_STATUS_SUCCESS on success
1042 * NDIS_STATUS_FAILURE on failure
1044 * - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
1045 * - TODO: convert this to NTSTATUS return values
1048 NDIS_HANDLE WrapperHandle
;
1049 NDIS_MINIPORT_CHARACTERISTICS Characteristics
;
1052 memset(&Characteristics
, 0, sizeof(Characteristics
));
1053 Characteristics
.MajorNdisVersion
= 4;
1054 Characteristics
.HaltHandler
= MiniportHalt
;
1055 Characteristics
.HandleInterruptHandler
= MiniportHandleInterrupt
;
1056 Characteristics
.InitializeHandler
= MiniportInitialize
;
1057 Characteristics
.ISRHandler
= MiniportISR
;
1058 Characteristics
.QueryInformationHandler
= MiniportQueryInformation
;
1059 Characteristics
.ResetHandler
= MiniportReset
;
1060 Characteristics
.SetInformationHandler
= MiniportSetInformation
;
1061 Characteristics
.u1
.SendHandler
= MiniportSend
;
1063 NdisMInitializeWrapper(&WrapperHandle
, DriverObject
, RegistryPath
, 0);
1065 Status
= NdisMRegisterMiniport(WrapperHandle
, &Characteristics
, sizeof(Characteristics
));
1066 if(Status
!= NDIS_STATUS_SUCCESS
)
1068 NdisTerminateWrapper(WrapperHandle
, 0);
1069 return NDIS_STATUS_FAILURE
;
1072 return NDIS_STATUS_SUCCESS
;