update for HEAD-2003091401
[reactos.git] / drivers / net / dd / pcnet / pcnet.c
1 /*
2  *  ReactOS AMD PCNet Driver
3  *  Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4  *
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.
9  *
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.
14  *
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.
18  *
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)
23  * REVISIONS:
24  *                  9-Sept-2003 vizzini - Created
25  * NOTES:
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.
32  */
33 #include <ndis.h>
34 #include "pci.h"
35 #include "pcnethw.h"
36 #include "pcnet.h"
37
38 \f
39 VOID
40 STDCALL
41 MiniportHalt(
42     IN NDIS_HANDLE MiniportAdapterContext)
43 /*
44  * FUNCTION: Stop the miniport and prepare for unload
45  * ARGUMENTS:
46  *     MiniportAdapterContext: context specified to NdisMSetAttributes
47  * NOTES:
48  *     - Called by NDIS at PASSIVE_LEVEL
49  */
50 {
51   /* XXX Implement me */
52   PCNET_DbgPrint(("Called\n"));
53 }
54
55 \f
56 VOID
57 STDCALL
58 MiniportHandleInterrupt(
59     IN NDIS_HANDLE MiniportAdapterContext)
60 /*
61  * FUNCTION: Handle an interrupt if told to by MiniportISR
62  * ARGUMENTS: 
63  *     MiniportAdapterContext: context specified to NdisMSetAttributes
64  * NOTES:
65  *     - Called by NDIS at DISPATCH_LEVEL
66  */
67 {
68   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
69   USHORT Data;
70   BOOLEAN ErrorHandled = FALSE;
71   BOOLEAN ReceiveHandled = FALSE;
72   BOOLEAN IdonHandled = FALSE;
73   USHORT Temp;
74
75   PCNET_DbgPrint(("Called\n"));
76
77   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
78   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
79
80   PCNET_DbgPrint(("CSR0 is 0x%x\n", Data));
81
82   while(Data & CSR0_INTR)
83     {
84       if(Data & CSR0_ERR)
85         {
86           if(ErrorHandled)
87             {
88               PCNET_DbgPrint(("ERROR HANDLED TWO TIMES\n"));
89               __asm__("int $3\n");
90             }
91
92           ErrorHandled = TRUE;
93
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));
98         }
99       else if(Data & CSR0_IDON)
100         {
101           if(IdonHandled)
102             {
103               PCNET_DbgPrint(("IDON HANDLED TWO TIMES\n"));
104               __asm__("int $3\n");
105             }
106
107           IdonHandled = TRUE;
108
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));
113         }
114       else if(Data & CSR0_RINT)
115         {
116           if(ReceiveHandled)
117             {
118               PCNET_DbgPrint(("RECEIVE HANDLED TWO TIMES\n"));
119               __asm__("int $3\n");
120             }
121
122           ReceiveHandled = TRUE;
123
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));
128
129           while(1)
130             {
131               PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex;
132               PCHAR Buffer;
133               ULONG ByteCount;
134
135               if(Descriptor->FLAGS & RD_OWN)
136                 {
137                   PCNET_DbgPrint(("no more receive descriptors to process\n"));
138                   break;
139                 }
140
141               if(Descriptor->FLAGS & RD_ERR)
142                 {
143                   PCNET_DbgPrint(("receive descriptor error: 0x%x\n", Descriptor->FLAGS));
144                   break;
145                 }
146
147               if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP)))
148                 {
149                   PCNET_DbgPrint(("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS));
150                   break;
151                 }
152
153               Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE;
154               ByteCount = Descriptor->MCNT & 0xfff;
155
156               PCNET_DbgPrint(("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex));
157
158               NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
159
160               memset(Descriptor, 0, sizeof(RECEIVE_DESCRIPTOR));
161               Descriptor->RBADR = 
162                   (ULONG)(Adapter->ReceiveBufferPtrPhys + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE);
163               Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000;
164               Descriptor->FLAGS &= RD_OWN;
165
166               Adapter->CurrentReceiveDescriptorIndex++;
167
168               if(Adapter->CurrentReceiveDescriptorIndex == NUMBER_OF_BUFFERS)
169                 Adapter->CurrentReceiveDescriptorIndex = 0;
170             }
171         }
172       else
173         {
174           PCNET_DbgPrint(("UNHANDLED INTERRUPT\n"));
175           __asm__("int $3\n");
176         }
177
178       NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
179     }
180
181   /* re-enable interrupts */
182   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);
183
184   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
185   PCNET_DbgPrint(("CSR0 is now 0x%x\n", Data));
186 }
187
188 \f
189 NDIS_STATUS 
190 MiQueryCard(
191     IN PADAPTER Adapter)
192 /*
193  * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
194  * ARGUMENTS:
195  *     MiniportAdapterContext: context supplied to NdisMSetAttributes
196  * RETURNS:
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
200  */
201 {
202   ULONG  buf32 = 0;
203   UCHAR  buf8  = 0;
204   NDIS_STATUS Status;
205
206   /* Detect the card in the configured slot */
207   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_PCIID, &buf32, 4);
208   if(Status != 4)
209     {
210       Status =  NDIS_STATUS_FAILURE;
211       PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
212       BREAKPOINT;
213       return Status;
214     }
215
216   if(buf32 != PCI_ID)
217     {
218       Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
219       PCNET_DbgPrint(("card in slot 0x%x isn't us: 0x%x\n", Adapter->SlotNumber, buf32));
220       BREAKPOINT;
221       return Status;
222     }
223
224   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber,
225       PCI_COMMAND, &buf32, 4);
226   if(Status != 4)
227     {
228       PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
229       BREAKPOINT;
230       return NDIS_STATUS_FAILURE;
231     }
232
233   PCNET_DbgPrint(("config/status register: 0x%x\n", buf32));
234
235   if(buf32 & 0x1)
236     {
237       PCNET_DbgPrint(("io space access is enabled.\n"));
238     }
239   else
240     {
241       PCNET_DbgPrint(("io space is NOT enabled!\n"));
242       BREAKPOINT;
243       return NDIS_STATUS_FAILURE;
244     }
245
246   /* get IO base physical address */
247   buf32 = 0;
248   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_IOBAR, &buf32, 4);
249   if(Status != 4)
250     {
251       Status = NDIS_STATUS_FAILURE;
252       PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
253       BREAKPOINT;
254       return Status;
255     }
256
257   if(!buf32)
258     {
259       PCNET_DbgPrint(("No base i/o address set\n"));
260       return NDIS_STATUS_FAILURE;
261     }
262
263   buf32 &= ~1;  /* even up address - comes out odd for some reason */
264
265   PCNET_DbgPrint(("detected io address 0x%x\n", buf32));
266   Adapter->IoBaseAddress = buf32;
267
268   /* get interrupt vector */
269   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_ILR, &buf8, 1);
270   if(Status != 1)
271     {
272       Status = NDIS_STATUS_FAILURE;
273       PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
274       BREAKPOINT;
275       return Status;
276     }
277
278   PCNET_DbgPrint(("interrupt: 0x%x\n", buf8));
279   Adapter->InterruptVector = buf8;
280
281   return NDIS_STATUS_SUCCESS;
282 }
283
284 \f
285 NDIS_STATUS
286 MiGetConfig(
287     PADAPTER Adapter, 
288     NDIS_HANDLE WrapperConfigurationContext)
289 /*
290  * FUNCTION: Get configuration parameters from the registry
291  * ARGUMENTS:
292  *     Adapter: pointer to the Adapter struct for this NIC
293  *     WrapperConfigurationContext: Context passed into MiniportInitialize
294  * RETURNS:
295  *     NDIS_STATUS_SUCCESS on success
296  *     NDIS_STATUS_{something} on failure (return val from other Ndis calls)
297  */
298 {
299   PNDIS_CONFIGURATION_PARAMETER Parameter; 
300   NDIS_HANDLE ConfigurationHandle = 0;
301   UNICODE_STRING Keyword;
302   NDIS_STATUS Status;
303
304   NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext);
305   if(Status != NDIS_STATUS_SUCCESS)
306     {
307       PCNET_DbgPrint(("Unable to open configuration: 0x%x\n", Status));
308       BREAKPOINT;
309       return Status;
310     }
311
312   RtlInitUnicodeString(&Keyword, L"SlotNumber");
313   NdisReadConfiguration(&Status, &Parameter, ConfigurationHandle, &Keyword, NdisParameterInteger);
314   if(Status != NDIS_STATUS_SUCCESS)
315     {
316       PCNET_DbgPrint(("Unable to read slot number: 0x%x\n", Status));
317       BREAKPOINT;
318     }
319   else 
320     Adapter->SlotNumber = Parameter->ParameterData.IntegerData;
321
322   NdisCloseConfiguration(ConfigurationHandle);
323
324   return NDIS_STATUS_SUCCESS;
325 }
326
327 \f
328 NDIS_STATUS
329 MiAllocateSharedMemory(
330     PADAPTER Adapter)
331 /*
332  * FUNCTION: Allocate all shared memory used by the miniport
333  * ARGUMENTS:
334  *     Adapter: Pointer to the miniport's adapter object
335  * RETURNS:
336  *     NDIS_STATUS_RESOURCES on insufficient memory
337  *     NDIS_STATUS_SUCCESS on success
338  */
339 {
340   PTRANSMIT_DESCRIPTOR TransmitDescriptor;
341   PRECEIVE_DESCRIPTOR  ReceiveDescriptor;
342   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
343   ULONG i;
344
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)
350     {
351       PCNET_DbgPrint(("insufficient resources\n"));
352       BREAKPOINT;
353       return NDIS_STATUS_RESOURCES;
354     }
355
356   if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0)
357     {
358       PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt));
359       BREAKPOINT;
360       return NDIS_STATUS_RESOURCES;
361     }
362
363   Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
364   memset(Adapter->InitializationBlockVirt, 0, sizeof(INITIALIZATION_BLOCK));
365
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)
371     {
372       PCNET_DbgPrint(("insufficient resources\n"));
373       BREAKPOINT;
374       return NDIS_STATUS_RESOURCES;
375     }
376
377   if(((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
378     {
379       PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt));
380       BREAKPOINT;
381       return NDIS_STATUS_RESOURCES;
382     }
383
384   Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
385   memset(Adapter->TransmitDescriptorRingVirt, 0, sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS);
386
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)
392     {
393       PCNET_DbgPrint(("insufficient resources\n"));
394       BREAKPOINT;
395       return NDIS_STATUS_RESOURCES;
396     }
397
398   if(((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
399     {
400       PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt));
401       BREAKPOINT;
402       return NDIS_STATUS_RESOURCES;
403     }
404
405   Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
406   memset(Adapter->ReceiveDescriptorRingVirt, 0, sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS);
407
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)
413     {
414       PCNET_DbgPrint(("insufficient resources\n"));
415       BREAKPOINT;
416       return NDIS_STATUS_RESOURCES;
417     }
418
419   if(((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
420     {
421       PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt));
422       BREAKPOINT;
423       return NDIS_STATUS_RESOURCES;
424     }
425
426   Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
427   memset(Adapter->TransmitBufferPtrVirt, 0, BUFFER_SIZE * NUMBER_OF_BUFFERS);
428
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)
434     {
435       PCNET_DbgPrint(("insufficient resources\n"));
436       BREAKPOINT;
437       return NDIS_STATUS_RESOURCES;
438     }
439
440   if(((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
441     {
442       PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt));
443       BREAKPOINT;
444       return NDIS_STATUS_RESOURCES;
445     }
446
447   Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
448   memset(Adapter->ReceiveBufferPtrVirt, 0, BUFFER_SIZE * NUMBER_OF_BUFFERS);
449
450   /* initialize tx descriptors */
451   TransmitDescriptor = Adapter->TransmitDescriptorRingVirt;
452   for(i = 0; i < NUMBER_OF_BUFFERS; i++)
453     {
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;
457     }
458
459   PCNET_DbgPrint(("transmit ring initialized\n"));
460
461   /* initialize rx */
462   ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt;
463   for(i = 0; i < NUMBER_OF_BUFFERS; i++)
464     {
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;
468     }
469
470   PCNET_DbgPrint(("receive ring initialized\n"));
471
472   return NDIS_STATUS_SUCCESS;
473 }
474
475 \f
476 VOID
477 MiPrepareInitializationBlock(
478     PADAPTER Adapter)
479 /*
480  * FUNCTION: Initialize the initialization block
481  * ARGUMENTS:
482  *     Adapter: pointer to the miniport's adapter object
483  */
484 {
485   ULONG i = 0;
486
487   /* read burned-in address from card */
488   for(i = 0; i < 6; i++)
489     NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i);
490
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;
495
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;
500 }
501
502 \f
503 VOID
504 MiFreeSharedMemory(
505     PADAPTER Adapter)
506 /*
507  * FUNCTION: Free all allocated shared memory
508  * ARGUMENTS:
509  *     Adapter: pointer to the miniport's adapter struct
510  */
511 {
512   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
513
514   PhysicalAddress.u.HighPart = 0;
515
516   if(Adapter->InitializationBlockVirt)
517     {
518       PhysicalAddress.u.LowPart = (ULONG)Adapter->InitializationBlockPhys;
519       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength, 
520           FALSE, (PVOID *)&Adapter->InitializationBlockVirt, PhysicalAddress);
521     }
522
523   if(Adapter->TransmitDescriptorRingVirt)
524     {
525       PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitDescriptorRingPhys;
526       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
527         FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
528     }
529
530   if(Adapter->ReceiveDescriptorRingVirt)
531     {
532       PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveDescriptorRingPhys;
533       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
534           FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
535     }
536
537   if(Adapter->TransmitBufferPtrVirt)
538     {
539       PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitBufferPtrPhys;
540       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength, 
541           FALSE, (PVOID *)&Adapter->TransmitBufferPtrVirt, PhysicalAddress);
542     }
543
544   if(Adapter->ReceiveBufferPtrVirt)
545     {
546       PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveBufferPtrPhys;
547       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength, 
548           FALSE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
549     }
550 }
551
552 \f
553 VOID
554 MiInitChip(
555     PADAPTER Adapter)
556 /*
557  * FUNCTION: Initialize and start the PCNET chip
558  * ARGUMENTS:
559  *     Adapter: pointer to the miniport's adapter struct
560  * NOTES:
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.
563  */
564 {
565   USHORT Data = 0;
566
567   PCNET_DbgPrint(("Called\n"));
568
569   /*
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.
573    */
574   NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data);
575   NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
576
577   /* stop the chip */
578   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
579   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
580
581   /* pause for 1ms so the chip will have time to reset */
582   NdisStallExecution(1);
583
584   PCNET_DbgPrint(("chip stopped\n"));
585
586   /* set the software style to 2 (32 bits) */
587   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58);
588   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
589
590   Data |= SW_STYLE_2;
591
592   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
593
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);
597
598   Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS;
599   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
600
601   /* set up bcr18: burst read/write enable */
602   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18);
603   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
604
605   Data |= BCR18_BREADE | BCR18_BWRITE ;
606   NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
607
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);
613
614   PCNET_DbgPrint(("programmed with init block\n"));
615
616   /* Set mode to 0 */
617   Data = 0;
618   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15);
619   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
620
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);
624
625   PCNET_DbgPrint(("card started\n"));
626
627   Adapter->Flags &= ~RESET_IN_PROGRESS;
628 }
629
630 \f
631 BOOLEAN
632 MiTestCard(
633     PADAPTER Adapter)
634 /*
635  * FUNCTION: Test the NIC
636  * ARGUMENTS:
637  *     Adapter: pointer to the miniport's adapter struct
638  * RETURNS:
639  *     TRUE if the test succeeds
640  *     FALSE otherwise
641  * NOTES:
642  *     - this is where to add diagnostics.  This is called
643  *       at the very end of initialization.
644  */
645 {
646   int i = 0;
647   UCHAR address[6];
648   USHORT Data = 0;
649
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));
654
655   /* read the BIA */
656   for(i = 0; i < 6; i++)
657       NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
658
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));
664
665   /* Read status flags from CSR3 */
666   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3);
667   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
668
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));
674
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));
679
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));
684
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));
691
692   return TRUE;
693 }
694
695 \f
696 NDIS_STATUS
697 STDCALL
698 MiniportInitialize(
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)
705 /*
706  * FUNCTION:  Initialize a new miniport
707  * ARGUMENTS:
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
715  * RETURNS:
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
721  * NOTES:
722  *     - Called by NDIS at PASSIVE_LEVEL, once per detected card
723  *     - Will int 3 on failure of MiTestCard if DBG=1
724  */
725 {
726   UINT i = 0;
727   PADAPTER Adapter = 0;
728   NDIS_STATUS Status = NDIS_STATUS_FAILURE;
729   BOOLEAN InterruptRegistered = FALSE;
730
731   /* Pick a medium */
732   for(i = 0; i < MediumArraySize; i++)
733     if(MediumArray[i] == NdisMedium802_3)
734       break;
735
736   if(i == MediumArraySize)
737     {
738       Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
739       PCNET_DbgPrint(("unsupported media\n"));
740       BREAKPOINT;
741       *OpenErrorStatus = Status;
742       return Status;
743     }
744
745   *SelectedMediumIndex = i;
746
747   /* allocate our adapter struct */
748   Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG);
749   if(Status != NDIS_STATUS_SUCCESS)
750     {
751       Status =  NDIS_STATUS_RESOURCES;
752       PCNET_DbgPrint(("Insufficient resources\n"));
753       BREAKPOINT;
754       *OpenErrorStatus = Status;
755       return Status;
756     }
757
758   memset(Adapter,0,sizeof(ADAPTER));
759
760   Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
761
762   /* register our adapter structwith ndis */
763   NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
764
765   do
766     {
767       /* get registry config */
768       Status = MiGetConfig(Adapter, WrapperConfigurationContext);
769       if(Status != NDIS_STATUS_SUCCESS)
770         {
771           PCNET_DbgPrint(("MiGetConfig failed\n"));
772           Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
773           BREAKPOINT;
774           break;
775         }
776
777       /* Card-specific detection and setup */
778       Status = MiQueryCard(Adapter);
779       if(Status != NDIS_STATUS_SUCCESS)
780         {
781           PCNET_DbgPrint(("MiQueryCard failed\n"));
782           Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
783           BREAKPOINT;
784           break;
785         }
786
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)
791         {
792           PCNET_DbgPrint(("NdisMRegisterIoPortRange failed: 0x%x\n", Status));
793           BREAKPOINT
794           break;
795         }
796
797       /* Allocate map registers */
798       Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0, 
799           NDIS_DMA_32BITS, 8, BUFFER_SIZE);
800       if(Status != NDIS_STATUS_SUCCESS)
801         {
802           PCNET_DbgPrint(("NdisMAllocateMapRegisters failed: 0x%x\n", Status));
803           BREAKPOINT
804           break;
805         }
806
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)
812         {
813           PCNET_DbgPrint(("NdisMRegisterInterrupt failed: 0x%x\n", Status));
814           BREAKPOINT
815           break;
816         }
817
818       InterruptRegistered = TRUE;
819
820       /* Allocate and initialize shared data structures */
821       Status = MiAllocateSharedMemory(Adapter);
822       if(Status != NDIS_STATUS_SUCCESS)
823         {
824           Status = NDIS_STATUS_RESOURCES;
825           PCNET_DbgPrint(("MiAllocateSharedMemory failed", Status));
826           BREAKPOINT
827           break;
828         }
829
830       /* set up the initialization block */
831       MiPrepareInitializationBlock(Adapter);
832
833       PCNET_DbgPrint(("Interrupt registered successfully\n"));
834
835       /* Initialize and start the chip */
836       MiInitChip(Adapter);
837
838       Status = NDIS_STATUS_SUCCESS;
839     }
840   while(0);
841
842   if(Status != NDIS_STATUS_SUCCESS && Adapter)
843     {
844       PCNET_DbgPrint(("Error; freeing stuff\n"));
845
846       NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); /* doesn't hurt to free if we never alloc'd? */
847
848       if(Adapter->PortOffset)
849         NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, Adapter->PortOffset);
850
851       if(InterruptRegistered)
852         NdisMDeregisterInterrupt(&Adapter->InterruptObject);
853
854       MiFreeSharedMemory(Adapter);
855
856       NdisFreeMemory(Adapter, 0, 0);
857     }
858
859 #if DBG
860   if(!MiTestCard(Adapter))
861     __asm__("int $3\n");
862 #endif
863
864   PCNET_DbgPrint(("returning 0x%x\n", Status));
865   *OpenErrorStatus = Status;
866   return Status;
867 }
868
869 \f
870 VOID
871 STDCALL
872 MiniportISR(
873     OUT PBOOLEAN InterruptRecognized,
874     OUT PBOOLEAN QueueMiniportHandleInterrupt,
875     IN NDIS_HANDLE MiniportAdapterContext)
876 /*
877  * FUNCTION: Miniport interrupt service routine
878  * ARGUMENTS:
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
882  * NOTES:
883  *     - called by NDIS at DIRQL
884  *     - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
885  *       will be called
886  */
887 {
888   USHORT Data;
889   USHORT Rap;
890   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
891
892   PCNET_DbgPrint(("Called\n"));
893
894   /* save the old RAP value */
895   NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
896
897   /* is this ours? */
898   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
899   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
900
901   if(!(Data & CSR0_INTR))
902     {
903       PCNET_DbgPrint(("not our interrupt.\n"));
904       *InterruptRecognized = FALSE;
905       *QueueMiniportHandleInterrupt = FALSE;
906     }
907   else
908     {
909       PCNET_DbgPrint(("detected our interrupt\n"));
910
911       /* disable interrupts */
912       NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
913       NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
914
915       *InterruptRecognized = TRUE;
916       *QueueMiniportHandleInterrupt = TRUE;
917     }
918
919   /* restore the rap */
920   NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
921 }
922
923 \f
924 NDIS_STATUS
925 STDCALL
926 MiniportQueryInformation(
927     IN NDIS_HANDLE MiniportAdapterContext,
928     IN NDIS_OID Oid,
929     IN PVOID InformationBuffer,
930     IN ULONG InformationBufferLength,
931     OUT PULONG BytesWritten,
932     OUT PULONG BytesNeeded)
933 /*
934  * FUNCTION: Query an OID from the driver
935  * ARGUMENTS:
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
942  * RETURNS:
943  *     NDIS_STATUS_SUCCESS on all queries
944  * NOTES:
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
948  */
949 {
950   PCNET_DbgPrint(("Called\n"));
951   return NDIS_STATUS_SUCCESS;
952 }
953
954 \f
955 NDIS_STATUS
956 STDCALL
957 MiniportReset(
958     OUT PBOOLEAN AddressingReset,
959     IN NDIS_HANDLE MiniportAdapterContext)
960 /*
961  * FUNCTION: Reset the miniport
962  * ARGUMENTS:
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
966  * RETURNS:
967  *     NDIS_STATUS_SUCCESS on all requests
968  * Notes:
969  *     - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
970  */
971 {
972   PCNET_DbgPrint(("Called\n"));
973   return NDIS_STATUS_SUCCESS;
974 }
975
976 \f
977 NDIS_STATUS
978 STDCALL
979 MiniportSetInformation(
980     IN NDIS_HANDLE MiniportAdapterContext,
981     IN NDIS_OID Oid,
982     IN PVOID InformationBuffer,
983     IN ULONG InformationBufferLength,
984     OUT PULONG BytesRead,
985     OUT PULONG BytesNeeded)
986 /*
987  * FUNCTION: Set a miniport variable (OID)
988  * ARGUMENTS:
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
995  *                  is insufficient
996  * RETURNS:
997  *     NDIS_STATUS_SUCCESS on all requests
998  * NOTES:
999  *     - Called by NDIS at PASSIVE_LEVEL
1000  */
1001 {
1002   PCNET_DbgPrint(("Called\n"));
1003   return NDIS_STATUS_SUCCESS;
1004 }
1005
1006 \f
1007 NDIS_STATUS
1008 STDCALL
1009 MiniportSend(
1010     IN NDIS_HANDLE MiniportAdapterContext,
1011     IN PNDIS_PACKET Packet,
1012     IN UINT Flags)
1013 /*
1014  * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
1015  * ARGUMENTS:
1016  *     MiniportAdapterContext: context originally input to NdisMSetAttributes
1017  *     Packet: The NDIS_PACKET to be sent
1018  *     Flags: Flags associated with Packet
1019  * RETURNS:
1020  *     NDIS_STATUS_SUCCESS on all requests
1021  * NOTES:
1022  *     - Called by NDIS at DISPATCH_LEVEL
1023  */
1024 {
1025   PCNET_DbgPrint(("Called\n"));
1026   return NDIS_STATUS_SUCCESS;
1027 }
1028
1029 \f
1030 NTSTATUS
1031 STDCALL
1032 DriverEntry(
1033     IN PDRIVER_OBJECT DriverObject,
1034     IN PUNICODE_STRING RegistryPath)
1035 /*
1036  * FUNCTION: Start this driver
1037  * ARGUMENTS:
1038  *     DriverObject: Pointer to the system-allocated driver object
1039  *     RegistryPath: Pointer to our SCM database entry
1040  * RETURNS:
1041  *     NDIS_STATUS_SUCCESS on success
1042  *     NDIS_STATUS_FAILURE on failure
1043  * NOTES:
1044  *     - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
1045  *     - TODO: convert this to NTSTATUS return values
1046  */
1047 {
1048   NDIS_HANDLE WrapperHandle;
1049   NDIS_MINIPORT_CHARACTERISTICS Characteristics;
1050   NDIS_STATUS Status;
1051
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;
1062
1063   NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
1064
1065   Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
1066   if(Status != NDIS_STATUS_SUCCESS)
1067     {
1068       NdisTerminateWrapper(WrapperHandle, 0);
1069       return NDIS_STATUS_FAILURE;
1070     }
1071
1072   return NDIS_STATUS_SUCCESS;
1073 }
1074