xref: /reactos/drivers/network/dd/pcnet/pcnet.c (revision 64daf542)
1 /*
2  * ReactOS AMD PCNet Driver
3  *
4  * Copyright (C) 2003 Vizzini <vizzini@plasmic.com>
5  * Copyright (C) 2004 Filip Navara <navaraf@reactos.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with this program; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * REVISIONS:
22  *     09-Sep-2003 vizzini - Created
23  *     10-Oct-2004 navaraf - Fix receive to work on VMware adapters (
24  *                           need to set busmaster bit on PCI).
25  *                         - Indicate receive completion.
26  *                         - Implement packet transmitting.
27  *                         - Don't read slot number from registry and
28  *                           report itself as NDIS 5.0 miniport.
29  *     11-Oct-2004 navaraf - Fix nasty bugs in halt code path.
30  *     17-Oct-2004 navaraf - Add multicast support.
31  *                         - Add media state detection support.
32  *                         - Protect the adapter context with spinlock
33  *                           and move code talking to card to inside
34  *                           NdisMSynchronizeWithInterrupt calls where
35  *                           necessary.
36  *
37  * NOTES:
38  *     - this assumes a 32-bit machine
39  */
40 
41 #include "pcnet.h"
42 
43 #define NDEBUG
44 #include <debug.h>
45 
46 NTSTATUS
47 NTAPI
48 DriverEntry(
49     IN PDRIVER_OBJECT DriverObject,
50     IN PUNICODE_STRING RegistryPath);
51 
52 static VOID
53 NTAPI
54 MiniportHandleInterrupt(
55     IN NDIS_HANDLE MiniportAdapterContext)
56 /*
57  * FUNCTION: Handle an interrupt if told to by MiniportISR
58  * ARGUMENTS:
59  *     MiniportAdapterContext: context specified to NdisMSetAttributes
60  * NOTES:
61  *     - Called by NDIS at DISPATCH_LEVEL
62  */
63 {
64   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
65   USHORT Data;
66   UINT i = 0;
67 
68   DPRINT("Called\n");
69 
70   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
71 
72   NdisDprAcquireSpinLock(&Adapter->Lock);
73 
74   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
75   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
76 
77   DPRINT("CSR0 is 0x%x\n", Data);
78 
79   while((Data & CSR0_INTR) && i++ < INTERRUPT_LIMIT)
80     {
81       /* Clear interrupt flags early to avoid race conditions. */
82       NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
83 
84       if(Data & CSR0_ERR)
85         {
86           DPRINT("error: %x\n", Data & (CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS));
87           if (Data & CSR0_CERR)
88             Adapter->Statistics.XmtCollisions++;
89         }
90       if(Data & CSR0_IDON)
91         {
92           DPRINT("IDON\n");
93         }
94       if(Data & CSR0_RINT)
95         {
96           BOOLEAN IndicatedData = FALSE;
97 
98           DPRINT("receive interrupt\n");
99 
100           while(1)
101             {
102               PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex;
103               PCHAR Buffer;
104               ULONG ByteCount;
105 
106               if(Descriptor->FLAGS & RD_OWN)
107                 {
108                   DPRINT("no more receive descriptors to process\n");
109                   break;
110                 }
111 
112               if(Descriptor->FLAGS & RD_ERR)
113                 {
114                   DPRINT("receive descriptor error: 0x%x\n", Descriptor->FLAGS);
115                   if (Descriptor->FLAGS & RD_BUFF)
116                     Adapter->Statistics.RcvBufferErrors++;
117                   if (Descriptor->FLAGS & RD_CRC)
118                     Adapter->Statistics.RcvCrcErrors++;
119                   if (Descriptor->FLAGS & RD_OFLO)
120                     Adapter->Statistics.RcvOverflowErrors++;
121                   if (Descriptor->FLAGS & RD_FRAM)
122                     Adapter->Statistics.RcvFramingErrors++;
123                   break;
124                 }
125 
126               if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP)))
127                 {
128                   DPRINT("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS);
129                   break;
130                 }
131 
132               Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE;
133               ByteCount = Descriptor->MCNT & 0xfff;
134 
135               DPRINT("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex);
136 
137               NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
138 
139               IndicatedData = TRUE;
140 
141               RtlZeroMemory(Descriptor, sizeof(RECEIVE_DESCRIPTOR));
142               Descriptor->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart +
143                                   (Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE);
144               Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000;
145               Descriptor->FLAGS |= RD_OWN;
146 
147               Adapter->CurrentReceiveDescriptorIndex++;
148               Adapter->CurrentReceiveDescriptorIndex %= Adapter->BufferCount;
149 
150               Adapter->Statistics.RcvGoodFrames++;
151             }
152 
153             if (IndicatedData)
154                 NdisMEthIndicateReceiveComplete(Adapter->MiniportAdapterHandle);
155         }
156       if(Data & CSR0_TINT)
157         {
158           PTRANSMIT_DESCRIPTOR Descriptor;
159 
160           DPRINT("transmit interrupt\n");
161 
162           while (Adapter->CurrentTransmitStartIndex !=
163                  Adapter->CurrentTransmitEndIndex)
164             {
165               Descriptor = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitStartIndex;
166 
167               DPRINT("buffer %d flags %x flags2 %x\n",
168                      Adapter->CurrentTransmitStartIndex,
169                      Descriptor->FLAGS, Descriptor->FLAGS2);
170 
171               if (Descriptor->FLAGS & TD1_OWN)
172                 {
173                   DPRINT("non-TXed buffer\n");
174                   break;
175                 }
176 
177               if (Descriptor->FLAGS & TD1_STP)
178                 {
179                   if (Descriptor->FLAGS & TD1_ONE)
180                     Adapter->Statistics.XmtOneRetry++;
181                   else if (Descriptor->FLAGS & TD1_MORE)
182                     Adapter->Statistics.XmtMoreThanOneRetry++;
183                 }
184 
185               if (Descriptor->FLAGS & TD1_ERR)
186                 {
187                   DPRINT("major error: %x\n", Descriptor->FLAGS2);
188                   if (Descriptor->FLAGS2 & TD2_RTRY)
189                     Adapter->Statistics.XmtRetryErrors++;
190                   if (Descriptor->FLAGS2 & TD2_LCAR)
191                     Adapter->Statistics.XmtLossesOfCarrier++;
192                   if (Descriptor->FLAGS2 & TD2_LCOL)
193                     Adapter->Statistics.XmtLateCollisions++;
194                   if (Descriptor->FLAGS2 & TD2_EXDEF)
195                     Adapter->Statistics.XmtExcessiveDeferrals++;
196                   if (Descriptor->FLAGS2 & TD2_UFLO)
197                     Adapter->Statistics.XmtBufferUnderflows++;
198                   if (Descriptor->FLAGS2 & TD2_BUFF)
199                     Adapter->Statistics.XmtBufferErrors++;
200                   break;
201                 }
202 
203               Adapter->CurrentTransmitStartIndex++;
204               Adapter->CurrentTransmitStartIndex %= Adapter->BufferCount;
205 
206               Adapter->Statistics.XmtGoodFrames++;
207             }
208           NdisMSendResourcesAvailable(Adapter->MiniportAdapterHandle);
209         }
210       if(Data & ~(CSR0_ERR | CSR0_IDON | CSR0_RINT | CSR0_TINT))
211         {
212           DPRINT("UNHANDLED INTERRUPT CSR0 0x%x\n", Data);
213         }
214 
215       NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
216     }
217 
218   /* re-enable interrupts */
219   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);
220 
221   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
222   DPRINT("CSR0 is now 0x%x\n", Data);
223 
224   NdisDprReleaseSpinLock(&Adapter->Lock);
225 }
226 
227 static NDIS_STATUS
228 MiQueryCard(
229     IN PADAPTER Adapter)
230 /*
231  * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
232  * ARGUMENTS:
233  *     MiniportAdapterContext: context supplied to NdisMSetAttributes
234  * RETURNS:
235  *     NDIS_STATUS_FAILURE on a general error
236  *     NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
237  *     NDIS_STATUS_SUCCESS on succes
238  */
239 {
240   ULONG  buf32 = 0;
241   UCHAR  buf8  = 0;
242   NDIS_STATUS Status;
243 
244   /* Detect the card in the configured slot */
245   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_PCIID, &buf32, 4);
246   if(Status != 4)
247     {
248       Status =  NDIS_STATUS_FAILURE;
249       DPRINT1("NdisReadPciSlotInformation failed\n");
250       return Status;
251     }
252 
253   if(buf32 != PCI_ID)
254     {
255       Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
256       DPRINT1("card in slot isn't our: 0x%x\n", 0, buf32);
257       return Status;
258     }
259 
260   /* set busmaster and io space enable bits */
261   buf32 = PCI_BMEN | PCI_IOEN;
262   NdisWritePciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_COMMAND, &buf32, 4);
263 
264   /* get IO base physical address */
265   buf32 = 0;
266   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_IOBAR, &buf32, 4);
267   if(Status != 4)
268     {
269       Status = NDIS_STATUS_FAILURE;
270       DPRINT1("NdisReadPciSlotInformation failed\n");
271       return Status;
272     }
273 
274   if(!buf32)
275     {
276       DPRINT1("No base i/o address set\n");
277       return NDIS_STATUS_FAILURE;
278     }
279 
280   buf32 &= ~1;  /* even up address - comes out odd for some reason */
281 
282   DPRINT("detected io address 0x%x\n", buf32);
283   Adapter->IoBaseAddress = buf32;
284 
285   /* get interrupt vector */
286   Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, 0, PCI_ILR, &buf8, 1);
287   if(Status != 1)
288     {
289       Status = NDIS_STATUS_FAILURE;
290       DPRINT1("NdisReadPciSlotInformation failed\n");
291       return Status;
292     }
293 
294   DPRINT("interrupt: 0x%x\n", buf8);
295   Adapter->InterruptVector = buf8;
296 
297   return NDIS_STATUS_SUCCESS;
298 }
299 
300 static VOID
301 MiFreeSharedMemory(
302     PADAPTER Adapter)
303 /*
304  * FUNCTION: Free all allocated shared memory
305  * ARGUMENTS:
306  *     Adapter: pointer to the miniport's adapter struct
307  */
308 {
309   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
310 
311   if(Adapter->InitializationBlockVirt)
312     {
313       PhysicalAddress = Adapter->InitializationBlockPhys;
314       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
315           FALSE, Adapter->InitializationBlockVirt, PhysicalAddress);
316       Adapter->InitializationBlockVirt = NULL;
317     }
318 
319   if(Adapter->TransmitDescriptorRingVirt)
320     {
321       PhysicalAddress = Adapter->TransmitDescriptorRingPhys;
322       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
323         FALSE, Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
324       Adapter->TransmitDescriptorRingVirt = NULL;
325     }
326 
327   if(Adapter->ReceiveDescriptorRingVirt)
328     {
329       PhysicalAddress = Adapter->ReceiveDescriptorRingPhys;
330       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
331           FALSE, Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
332       Adapter->ReceiveDescriptorRingVirt = NULL;
333     }
334 
335   if(Adapter->TransmitBufferPtrVirt)
336     {
337       PhysicalAddress = Adapter->TransmitBufferPtrPhys;
338       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
339           TRUE, Adapter->TransmitBufferPtrVirt, PhysicalAddress);
340       Adapter->TransmitBufferPtrVirt = NULL;
341     }
342 
343   if(Adapter->ReceiveBufferPtrVirt)
344     {
345       PhysicalAddress = Adapter->ReceiveBufferPtrPhys;
346       NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
347           TRUE, Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
348       Adapter->ReceiveBufferPtrVirt = NULL;
349     }
350 }
351 
352 static NDIS_STATUS
353 MiAllocateSharedMemory(
354     PADAPTER Adapter)
355 /*
356  * FUNCTION: Allocate all shared memory used by the miniport
357  * ARGUMENTS:
358  *     Adapter: Pointer to the miniport's adapter object
359  * RETURNS:
360  *     NDIS_STATUS_RESOURCES on insufficient memory
361  *     NDIS_STATUS_SUCCESS on success
362  */
363 {
364   PTRANSMIT_DESCRIPTOR TransmitDescriptor;
365   PRECEIVE_DESCRIPTOR  ReceiveDescriptor;
366   NDIS_PHYSICAL_ADDRESS PhysicalAddress;
367   ULONG i;
368   ULONG BufferCount = NUMBER_OF_BUFFERS;
369   ULONG LogBufferCount = LOG_NUMBER_OF_BUFFERS;
370 
371   while (BufferCount != 0)
372   {
373       /* allocate the initialization block (we have this in the loop so we can use MiFreeSharedMemory) */
374       Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
375       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
376           FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
377       if(!Adapter->InitializationBlockVirt)
378       {
379          /* Buffer backoff won't help us here */
380          DPRINT1("insufficient resources\n");
381          return NDIS_STATUS_RESOURCES;
382       }
383 
384       if (((ULONG_PTR)Adapter->InitializationBlockVirt & 0x00000003) != 0)
385       {
386          DPRINT1("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt);
387          return NDIS_STATUS_RESOURCES;
388       }
389 
390       Adapter->InitializationBlockPhys = PhysicalAddress;
391 
392       /* allocate the transport descriptor ring */
393       Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * BufferCount;
394       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
395           FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
396       if (!Adapter->TransmitDescriptorRingVirt)
397       {
398           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
399           BufferCount = BufferCount >> 1;
400           LogBufferCount--;
401           MiFreeSharedMemory(Adapter);
402           continue;
403       }
404 
405       if (((ULONG_PTR)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
406       {
407          DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt);
408          return NDIS_STATUS_RESOURCES;
409       }
410 
411       Adapter->TransmitDescriptorRingPhys = PhysicalAddress;
412       RtlZeroMemory(Adapter->TransmitDescriptorRingVirt, sizeof(TRANSMIT_DESCRIPTOR) * BufferCount);
413 
414       /* allocate the receive descriptor ring */
415       Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * BufferCount;
416       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
417           FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
418       if (!Adapter->ReceiveDescriptorRingVirt)
419       {
420           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
421           BufferCount = BufferCount >> 1;
422           LogBufferCount--;
423           MiFreeSharedMemory(Adapter);
424           continue;
425       }
426 
427       if (((ULONG_PTR)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
428       {
429           DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt);
430           return NDIS_STATUS_RESOURCES;
431       }
432 
433       Adapter->ReceiveDescriptorRingPhys = PhysicalAddress;
434       RtlZeroMemory(Adapter->ReceiveDescriptorRingVirt, sizeof(RECEIVE_DESCRIPTOR) * BufferCount);
435 
436       /* allocate transmit buffers */
437       Adapter->TransmitBufferLength = BUFFER_SIZE * BufferCount;
438       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
439          TRUE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
440       if(!Adapter->TransmitBufferPtrVirt)
441       {
442           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
443           BufferCount = BufferCount >> 1;
444           LogBufferCount--;
445           MiFreeSharedMemory(Adapter);
446           continue;
447       }
448 
449       if(((ULONG_PTR)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
450       {
451           DPRINT1("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt);
452           return NDIS_STATUS_RESOURCES;
453       }
454 
455       Adapter->TransmitBufferPtrPhys = PhysicalAddress;
456       RtlZeroMemory(Adapter->TransmitBufferPtrVirt, BUFFER_SIZE * BufferCount);
457 
458       /* allocate receive buffers */
459       Adapter->ReceiveBufferLength = BUFFER_SIZE * BufferCount;
460       NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
461          TRUE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
462       if(!Adapter->ReceiveBufferPtrVirt)
463       {
464           DPRINT1("Backing off buffer count by %d buffers due to allocation failure\n", (BufferCount >> 1));
465           BufferCount = BufferCount >> 1;
466           LogBufferCount--;
467           MiFreeSharedMemory(Adapter);
468           continue;
469       }
470 
471       if (((ULONG_PTR)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
472       {
473           DPRINT1("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt);
474           return NDIS_STATUS_RESOURCES;
475       }
476 
477       Adapter->ReceiveBufferPtrPhys = PhysicalAddress;
478       RtlZeroMemory(Adapter->ReceiveBufferPtrVirt, BUFFER_SIZE * BufferCount);
479 
480       break;
481   }
482 
483   if (!BufferCount)
484   {
485       DPRINT1("Failed to allocate adapter buffers\n");
486       return NDIS_STATUS_RESOURCES;
487   }
488 
489   Adapter->BufferCount = BufferCount;
490   Adapter->LogBufferCount = LogBufferCount;
491 
492   /* initialize tx descriptors */
493   TransmitDescriptor = Adapter->TransmitDescriptorRingVirt;
494   for(i = 0; i < BufferCount; i++)
495     {
496       (TransmitDescriptor+i)->TBADR = Adapter->TransmitBufferPtrPhys.QuadPart + i * BUFFER_SIZE;
497       (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment  + set top 4 bits */
498       (TransmitDescriptor+i)->FLAGS = TD1_STP | TD1_ENP;
499     }
500 
501   DPRINT("transmit ring initialized\n");
502 
503   /* initialize rx */
504   ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt;
505   for(i = 0; i < BufferCount; i++)
506     {
507       (ReceiveDescriptor+i)->RBADR = Adapter->ReceiveBufferPtrPhys.QuadPart + i * BUFFER_SIZE;
508       (ReceiveDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment  + set top 4 bits */
509       (ReceiveDescriptor+i)->FLAGS = RD_OWN;
510     }
511 
512   DPRINT("receive ring initialized\n");
513 
514   return NDIS_STATUS_SUCCESS;
515 }
516 
517 static VOID
518 MiPrepareInitializationBlock(
519     PADAPTER Adapter)
520 /*
521  * FUNCTION: Initialize the initialization block
522  * ARGUMENTS:
523  *     Adapter: pointer to the miniport's adapter object
524  */
525 {
526   ULONG i = 0;
527 
528   RtlZeroMemory(Adapter->InitializationBlockVirt, sizeof(INITIALIZATION_BLOCK));
529 
530   /* read burned-in address from card */
531   for(i = 0; i < 6; i++)
532     NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i);
533   DPRINT("MAC address: %02x-%02x-%02x-%02x-%02x-%02x\n",
534          Adapter->InitializationBlockVirt->PADR[0],
535          Adapter->InitializationBlockVirt->PADR[1],
536          Adapter->InitializationBlockVirt->PADR[2],
537          Adapter->InitializationBlockVirt->PADR[3],
538          Adapter->InitializationBlockVirt->PADR[4],
539          Adapter->InitializationBlockVirt->PADR[5]);
540 
541   /* set up receive ring */
542   DPRINT("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys);
543   Adapter->InitializationBlockVirt->RDRA = Adapter->ReceiveDescriptorRingPhys.QuadPart;
544   Adapter->InitializationBlockVirt->RLEN = (Adapter->LogBufferCount << 4) & 0xf0;
545 
546   /* set up transmit ring */
547   DPRINT("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys);
548   Adapter->InitializationBlockVirt->TDRA = Adapter->TransmitDescriptorRingPhys.QuadPart;
549   Adapter->InitializationBlockVirt->TLEN = (Adapter->LogBufferCount << 4) & 0xf0;
550 }
551 
552 static BOOLEAN
553 NTAPI
554 MiSyncStop(
555     IN PVOID SynchronizeContext)
556 /*
557  * FUNCTION: Stop the adapter
558  * ARGUMENTS:
559  *     SynchronizeContext: Adapter context
560  */
561 {
562   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
563   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
564   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
565   return TRUE;
566 }
567 
568 static VOID
569 NTAPI
570 MiniportHalt(
571     IN NDIS_HANDLE MiniportAdapterContext)
572 /*
573  * FUNCTION: Stop the adapter and release any per-adapter resources
574  * ARGUMENTS:
575  *     MiniportAdapterContext: context specified to NdisMSetAttributes
576  * NOTES:
577  *     - Called by NDIS at PASSIVE_LEVEL
578  */
579 {
580   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
581   BOOLEAN TimerCancelled;
582 
583   DPRINT("Called\n");
584   ASSERT(Adapter);
585 
586   /* stop the media detection timer */
587   NdisMCancelTimer(&Adapter->MediaDetectionTimer, &TimerCancelled);
588 
589   /* stop the chip */
590   NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStop, Adapter);
591 
592   /* deregister the interrupt */
593   NdisMDeregisterInterrupt(&Adapter->InterruptObject);
594 
595   /* deregister i/o port range */
596   NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
597 
598   /* deregister the shutdown routine */
599   NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle);
600 
601   /* free shared memory */
602   MiFreeSharedMemory(Adapter);
603 
604   /* free map registers */
605   NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
606 
607   /* free the lock */
608   NdisFreeSpinLock(&Adapter->Lock);
609 
610   /* free the adapter */
611   NdisFreeMemory(Adapter, 0, 0);
612 }
613 
614 static BOOLEAN
615 NTAPI
616 MiSyncMediaDetection(
617     IN PVOID SynchronizeContext)
618 /*
619  * FUNCTION: Stop the adapter
620  * ARGUMENTS:
621  *     SynchronizeContext: Adapter context
622  */
623 {
624   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
625   NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter);
626   UINT MediaSpeed = MiGetMediaSpeed(Adapter);
627   BOOLEAN FullDuplex = MiGetMediaDuplex(Adapter);
628 
629   DPRINT("Called\n");
630   DPRINT("MediaState: %d\n", MediaState);
631   if (MediaState != Adapter->MediaState ||
632       MediaSpeed != Adapter->MediaSpeed ||
633       FullDuplex != Adapter->FullDuplex)
634     {
635       Adapter->MediaState = MediaState;
636       Adapter->MediaSpeed = MediaSpeed;
637       Adapter->FullDuplex = FullDuplex;
638       return TRUE;
639     }
640   return FALSE;
641 }
642 
643 static VOID
644 NTAPI
645 MiniportMediaDetectionTimer(
646     IN PVOID SystemSpecific1,
647     IN PVOID FunctionContext,
648     IN PVOID SystemSpecific2,
649     IN PVOID SystemSpecific3)
650 /*
651  * FUNCTION: Periodically query media state
652  * ARGUMENTS:
653  *     FunctionContext: Adapter context
654  * NOTES:
655  *     - Called by NDIS at DISPATCH_LEVEL
656  */
657 {
658   PADAPTER Adapter = (PADAPTER)FunctionContext;
659 
660   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
661 
662   if (NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject,
663                                     MiSyncMediaDetection,
664                                     FunctionContext))
665     {
666       NdisMIndicateStatus(Adapter->MiniportAdapterHandle,
667         Adapter->MediaState == NdisMediaStateConnected ?
668         NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
669         (PVOID)0, 0);
670       NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
671     }
672 }
673 
674 static VOID
675 MiInitChip(
676     PADAPTER Adapter)
677 /*
678  * FUNCTION: Initialize and start the PCNET chip
679  * ARGUMENTS:
680  *     Adapter: pointer to the miniport's adapter struct
681  * NOTES:
682  *     - should be coded to detect failure and return an error
683  *     - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that.
684  */
685 {
686   USHORT Data = 0;
687 
688   DPRINT("Called\n");
689 
690   /*
691    * first reset the chip - 32-bit reset followed by 16-bit reset.  if it's in 32-bit mode, it'll reset
692    * twice.  if it's in 16-bit mode, the first read will be nonsense and the second will be a reset.  the
693    * card is reset by reading from the reset register.  on reset it's in 16-bit i/o mode.
694    */
695   NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data);
696   NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
697 
698   /* stop the chip */
699   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
700   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
701 
702   /* pause for 1ms so the chip will have time to reset */
703   NdisStallExecution(1);
704 
705   DPRINT("chip stopped\n");
706 
707   /* set the software style to 2 (32 bits) */
708   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58);
709   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
710 
711   Data |= SW_STYLE_2;
712 
713   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
714 
715   /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */
716   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
717   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
718 
719   Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS;
720   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
721 
722   /* set up bcr18: burst read/write enable */
723   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18);
724   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
725 
726   Data |= BCR18_BREADE | BCR18_BWRITE ;
727   NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
728 
729   /* set up csr1 and csr2 with init block */
730   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1);
731   NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart & 0xffff));
732   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2);
733   NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)(Adapter->InitializationBlockPhys.LowPart >> 16) & 0xffff);
734 
735   DPRINT("programmed with init block\n");
736 
737   /* Set mode to 0 */
738   Data = 0;
739   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15);
740   NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
741 
742   /* load init block and start the card */
743   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
744   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
745 
746   /* Allow LED programming */
747   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR2);
748   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR2_LEDPE);
749 
750   /* LED0 is configured for link status (on = up, off = down) */
751   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
752   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE | BCR4_PSE);
753 
754   /* LED1 is configured for link duplex (on = full, off = half) */
755   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5);
756   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR5_FDLSE | BCR5_PSE);
757 
758   /* LED2 is configured for link speed (on = 100M, off = 10M) */
759   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6);
760   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR6_E100 | BCR6_PSE);
761 
762   /* LED3 is configured for trasmit/receive activity */
763   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR7);
764   NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR7_XMTE | BCR7_RCVE | BCR7_PSE);
765 
766   Adapter->MediaState = MiGetMediaState(Adapter);
767   Adapter->FullDuplex = MiGetMediaDuplex(Adapter);
768   Adapter->MediaSpeed = MiGetMediaSpeed(Adapter);
769 
770   DPRINT("card started\n");
771 
772   Adapter->Flags &= ~RESET_IN_PROGRESS;
773 }
774 
775 #if DBG
776 static BOOLEAN
777 MiTestCard(
778     PADAPTER Adapter)
779 /*
780  * FUNCTION: Test the NIC
781  * ARGUMENTS:
782  *     Adapter: pointer to the miniport's adapter struct
783  * RETURNS:
784  *     TRUE if the test succeeds
785  *     FALSE otherwise
786  * NOTES:
787  *     - this is where to add diagnostics.  This is called
788  *       at the very end of initialization.
789  */
790 {
791   int i = 0;
792   UCHAR address[6];
793   USHORT Data = 0;
794 
795   /* see if we can read/write now */
796   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
797   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
798   DPRINT("Port 0x%x RAP 0x%x CSR0 0x%x RDP 0x%x, Interrupt status register is 0x%x\n", Adapter->PortOffset, RAP, CSR0, RDP, Data);
799 
800   /* read the BIA */
801   for(i = 0; i < 6; i++)
802       NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
803 
804   DPRINT("burned-in address: %02x:%02x:%02x:%02x:%02x:%02x\n", address[0], address[1], address[2], address[3], address[4], address[5]);
805   /* Read status flags from CSR0 */
806   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
807   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
808   DPRINT("CSR0: 0x%x\n", Data);
809 
810   /* Read status flags from CSR3 */
811   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3);
812   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
813   DPRINT("CSR3: 0x%x\n", Data);
814 
815   /* Read status flags from CSR4 */
816   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
817   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
818   DPRINT("CSR4: 0x%x\n", Data);
819 
820   /* Read status flags from CSR5 */
821   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5);
822   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
823   DPRINT("CSR5: 0x%x\n", Data);
824 
825   /* Read status flags from CSR6 */
826   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6);
827   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
828   DPRINT("CSR6: 0x%x\n", Data);
829 
830   /* Read status flags from BCR4 */
831   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
832   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
833   DPRINT("BCR4: 0x%x\n", Data);
834 
835   return TRUE;
836 }
837 #endif
838 
839 VOID
840 NTAPI
841 MiniportShutdown( PVOID Context )
842 {
843   PADAPTER Adapter = Context;
844 
845   DPRINT("Stopping the chip\n");
846 
847   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
848   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
849 }
850 
851 static NDIS_STATUS
852 NTAPI
853 MiniportInitialize(
854     OUT PNDIS_STATUS OpenErrorStatus,
855     OUT PUINT SelectedMediumIndex,
856     IN PNDIS_MEDIUM MediumArray,
857     IN UINT MediumArraySize,
858     IN NDIS_HANDLE MiniportAdapterHandle,
859     IN NDIS_HANDLE WrapperConfigurationContext)
860 /*
861  * FUNCTION:  Initialize a new miniport
862  * ARGUMENTS:
863  *     OpenErrorStatus:  pointer to a var to return status info in
864  *     SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3)
865  *     MediumArray: array of media that we can pick from
866  *     MediumArraySize: size of MediumArray
867  *     MiniportAdapterHandle: NDIS-assigned handle for this miniport instance
868  *     WrapperConfigurationContext: temporary NDIS-assigned handle for passing
869  *                                  to configuration APIs
870  * RETURNS:
871  *     NDIS_STATUS_SUCCESS on success
872  *     NDIS_STATUS_FAILURE on general failure
873  *     NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray
874  *     NDIS_STATUS_RESOURCES on insufficient system resources
875  *     NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
876  * NOTES:
877  *     - Called by NDIS at PASSIVE_LEVEL, once per detected card
878  *     - Will int 3 on failure of MiTestCard if DBG=1
879  */
880 {
881   UINT i = 0;
882   PADAPTER Adapter = 0;
883   NDIS_STATUS Status = NDIS_STATUS_FAILURE;
884   BOOLEAN InterruptRegistered = FALSE, MapRegistersAllocated = FALSE;
885   NDIS_HANDLE ConfigurationHandle;
886   UINT *RegNetworkAddress = 0;
887   UINT RegNetworkAddressLength = 0;
888 
889   ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
890 
891   /* Pick a medium */
892   for(i = 0; i < MediumArraySize; i++)
893     if(MediumArray[i] == NdisMedium802_3)
894       break;
895 
896   if(i == MediumArraySize)
897     {
898       Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
899       DPRINT1("unsupported media\n");
900       *OpenErrorStatus = Status;
901       return Status;
902     }
903 
904   *SelectedMediumIndex = i;
905 
906   /* allocate our adapter struct */
907   Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG);
908   if(Status != NDIS_STATUS_SUCCESS)
909     {
910       Status =  NDIS_STATUS_RESOURCES;
911       DPRINT1("Insufficient resources\n");
912       *OpenErrorStatus = Status;
913       return Status;
914     }
915 
916   RtlZeroMemory(Adapter, sizeof(ADAPTER));
917 
918   Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
919 
920   /* register our adapter structwith ndis */
921   NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
922 
923   do
924     {
925       /* Card-specific detection and setup */
926       Status = MiQueryCard(Adapter);
927       if(Status != NDIS_STATUS_SUCCESS)
928         {
929           DPRINT1("MiQueryCard failed\n");
930           Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
931           break;
932         }
933 
934       /* register an IO port range */
935       Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->PortOffset, Adapter->MiniportAdapterHandle,
936           (UINT)Adapter->IoBaseAddress, NUMBER_OF_PORTS);
937       if(Status != NDIS_STATUS_SUCCESS)
938         {
939           DPRINT1("NdisMRegisterIoPortRange failed: 0x%x\n", Status);
940           break;
941         }
942 
943       /* Allocate map registers */
944       Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0,
945           NDIS_DMA_32BITS, 8, BUFFER_SIZE);
946       if(Status != NDIS_STATUS_SUCCESS)
947         {
948           DPRINT1("NdisMAllocateMapRegisters failed: 0x%x\n", Status);
949           break;
950         }
951 
952       MapRegistersAllocated = TRUE;
953 
954       /* set up the interrupt */
955       Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector,
956           Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive);
957       if(Status != NDIS_STATUS_SUCCESS)
958         {
959           DPRINT1("NdisMRegisterInterrupt failed: 0x%x\n", Status);
960           break;
961         }
962 
963       InterruptRegistered = TRUE;
964 
965       /* Allocate and initialize shared data structures */
966       Status = MiAllocateSharedMemory(Adapter);
967       if(Status != NDIS_STATUS_SUCCESS)
968         {
969           Status = NDIS_STATUS_RESOURCES;
970           DPRINT1("MiAllocateSharedMemory failed\n", Status);
971           break;
972         }
973 
974       /* set up the initialization block */
975       MiPrepareInitializationBlock(Adapter);
976 
977       /* see if someone set a network address manually */
978       NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext);
979       if (Status == NDIS_STATUS_SUCCESS)
980       {
981          NdisReadNetworkAddress(&Status, (PVOID *)&RegNetworkAddress, &RegNetworkAddressLength, ConfigurationHandle);
982          if(Status == NDIS_STATUS_SUCCESS && RegNetworkAddressLength == 6)
983          {
984              int i;
985              DPRINT("NdisReadNetworkAddress returned successfully, address %x:%x:%x:%x:%x:%x\n",
986                      RegNetworkAddress[0], RegNetworkAddress[1], RegNetworkAddress[2], RegNetworkAddress[3],
987                      RegNetworkAddress[4], RegNetworkAddress[5]);
988 
989              for(i = 0; i < 6; i++)
990                  Adapter->InitializationBlockVirt->PADR[i] = RegNetworkAddress[i];
991          }
992 
993          NdisCloseConfiguration(ConfigurationHandle);
994       }
995 
996       DPRINT("Interrupt registered successfully\n");
997 
998       /* Initialize and start the chip */
999       MiInitChip(Adapter);
1000 
1001       NdisAllocateSpinLock(&Adapter->Lock);
1002 
1003       Status = NDIS_STATUS_SUCCESS;
1004     }
1005   while(0);
1006 
1007   if(Status != NDIS_STATUS_SUCCESS && Adapter)
1008     {
1009       DPRINT("Error; freeing stuff\n");
1010 
1011       MiFreeSharedMemory(Adapter);
1012 
1013       if(MapRegistersAllocated)
1014         NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
1015 
1016       if(Adapter->PortOffset)
1017         NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
1018 
1019       if(InterruptRegistered)
1020         NdisMDeregisterInterrupt(&Adapter->InterruptObject);
1021 
1022       NdisFreeMemory(Adapter, 0, 0);
1023     }
1024 
1025   if(Status == NDIS_STATUS_SUCCESS)
1026     {
1027       NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
1028                            Adapter->MiniportAdapterHandle,
1029                            MiniportMediaDetectionTimer,
1030                            Adapter);
1031       NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
1032                             MEDIA_DETECTION_INTERVAL);
1033       NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle,
1034                                           Adapter,
1035                                           MiniportShutdown);
1036     }
1037 
1038 #if DBG
1039   if(!MiTestCard(Adapter))
1040     ASSERT(0);
1041 #endif
1042 
1043   DPRINT("returning 0x%x\n", Status);
1044   *OpenErrorStatus = Status;
1045   return Status;
1046 }
1047 
1048 static VOID
1049 NTAPI
1050 MiniportISR(
1051     OUT PBOOLEAN InterruptRecognized,
1052     OUT PBOOLEAN QueueMiniportHandleInterrupt,
1053     IN NDIS_HANDLE MiniportAdapterContext)
1054 /*
1055  * FUNCTION: Miniport interrupt service routine
1056  * ARGUMENTS:
1057  *     InterruptRecognized: the interrupt was ours
1058  *     QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
1059  *     MiniportAdapterContext: the context originally passed to NdisMSetAttributes
1060  * NOTES:
1061  *     - called by NDIS at DIRQL
1062  *     - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
1063  *       will be called
1064  */
1065 {
1066   USHORT Data;
1067   USHORT Rap;
1068   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
1069 
1070   DPRINT("Called\n");
1071 
1072   /* save the old RAP value */
1073   NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
1074 
1075   /* is this ours? */
1076   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1077   NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
1078 
1079   if(!(Data & CSR0_INTR))
1080     {
1081       DPRINT("not our interrupt.\n");
1082       *InterruptRecognized = FALSE;
1083       *QueueMiniportHandleInterrupt = FALSE;
1084     }
1085   else
1086     {
1087       DPRINT("detected our interrupt\n");
1088 
1089       /* disable interrupts */
1090       NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1091       NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
1092 
1093       *InterruptRecognized = TRUE;
1094       *QueueMiniportHandleInterrupt = TRUE;
1095     }
1096 
1097   /* restore the rap */
1098   NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
1099 }
1100 
1101 static NDIS_STATUS
1102 NTAPI
1103 MiniportReset(
1104     OUT PBOOLEAN AddressingReset,
1105     IN NDIS_HANDLE MiniportAdapterContext)
1106 /*
1107  * FUNCTION: Reset the miniport
1108  * ARGUMENTS:
1109  *     AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
1110  *                      to reset our addresses and filters
1111  *     MiniportAdapterContext: context originally passed to NdisMSetAttributes
1112  * RETURNS:
1113  *     NDIS_STATUS_SUCCESS on all requests
1114  * Notes:
1115  *     - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
1116  */
1117 {
1118   DPRINT("Called\n");
1119 
1120   /* MiniportReset doesn't do anything at the moment... perhaps this should be fixed. */
1121 
1122   *AddressingReset = FALSE;
1123   return NDIS_STATUS_SUCCESS;
1124 }
1125 
1126 static BOOLEAN
1127 NTAPI
1128 MiSyncStartTransmit(
1129     IN PVOID SynchronizeContext)
1130 /*
1131  * FUNCTION: Stop the adapter
1132  * ARGUMENTS:
1133  *     SynchronizeContext: Adapter context
1134  */
1135 {
1136   PADAPTER Adapter = (PADAPTER)SynchronizeContext;
1137   NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1138   NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD);
1139   return TRUE;
1140 }
1141 
1142 static NDIS_STATUS
1143 NTAPI
1144 MiniportSend(
1145     IN NDIS_HANDLE MiniportAdapterContext,
1146     IN PNDIS_PACKET Packet,
1147     IN UINT Flags)
1148 /*
1149  * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
1150  * ARGUMENTS:
1151  *     MiniportAdapterContext: context originally input to NdisMSetAttributes
1152  *     Packet: The NDIS_PACKET to be sent
1153  *     Flags: Flags associated with Packet
1154  * RETURNS:
1155  *     NDIS_STATUS_SUCCESS on processed requests
1156  *     NDIS_STATUS_RESOURCES if there's no place in buffer ring
1157  * NOTES:
1158  *     - Called by NDIS at DISPATCH_LEVEL
1159  */
1160 {
1161   PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
1162   PTRANSMIT_DESCRIPTOR Desc;
1163   PNDIS_BUFFER NdisBuffer;
1164   PVOID SourceBuffer;
1165   UINT TotalPacketLength, SourceLength, Position = 0;
1166 
1167   DPRINT("Called\n");
1168 
1169   ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
1170 
1171   NdisDprAcquireSpinLock(&Adapter->Lock);
1172 
1173   /* Check if we have free entry in our circular buffer. */
1174   if ((Adapter->CurrentTransmitEndIndex + 1 ==
1175        Adapter->CurrentTransmitStartIndex) ||
1176       (Adapter->CurrentTransmitEndIndex == Adapter->BufferCount - 1 &&
1177        Adapter->CurrentTransmitStartIndex == 0))
1178     {
1179       DPRINT1("No free space in circular buffer\n");
1180       NdisDprReleaseSpinLock(&Adapter->Lock);
1181       return NDIS_STATUS_RESOURCES;
1182     }
1183 
1184   Desc = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitEndIndex;
1185 
1186   NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &TotalPacketLength);
1187   ASSERT(TotalPacketLength <= BUFFER_SIZE);
1188 
1189   DPRINT("TotalPacketLength: %x\n", TotalPacketLength);
1190 
1191   while (NdisBuffer)
1192     {
1193       NdisQueryBuffer(NdisBuffer, &SourceBuffer, &SourceLength);
1194 
1195       DPRINT("Buffer: %x Length: %x\n", SourceBuffer, SourceLength);
1196 
1197       RtlCopyMemory(Adapter->TransmitBufferPtrVirt +
1198                     Adapter->CurrentTransmitEndIndex * BUFFER_SIZE + Position,
1199                     SourceBuffer, SourceLength);
1200 
1201       Position += SourceLength;
1202 
1203       NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
1204     }
1205 
1206 #if DBG && 0
1207   {
1208     PUCHAR Ptr = Adapter->TransmitBufferPtrVirt +
1209                  Adapter->CurrentTransmitEndIndex * BUFFER_SIZE;
1210     for (Position = 0; Position < TotalPacketLength; Position++)
1211       {
1212         if (Position % 16 == 0)
1213           DbgPrint("\n");
1214         DbgPrint("%x ", *Ptr++);
1215       }
1216   }
1217   DbgPrint("\n");
1218 #endif
1219 
1220   Adapter->CurrentTransmitEndIndex++;
1221   Adapter->CurrentTransmitEndIndex %= Adapter->BufferCount;
1222 
1223   Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
1224   Desc->BCNT = 0xf000 | -(INT)TotalPacketLength;
1225 
1226   NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
1227 
1228   NdisDprReleaseSpinLock(&Adapter->Lock);
1229 
1230   return NDIS_STATUS_SUCCESS;
1231 }
1232 
1233 static ULONG
1234 NTAPI
1235 MiEthernetCrc(UCHAR *Address)
1236 /*
1237  * FUNCTION: Calculate Ethernet CRC32
1238  * ARGUMENTS:
1239  *     Address: 6-byte ethernet address
1240  * RETURNS:
1241  *     The calculated CRC32 value.
1242  */
1243 {
1244   UINT Counter, Length;
1245   ULONG Value = ~0;
1246 
1247   for (Length = 0; Length < 6; Length++)
1248     {
1249       Value ^= *Address++;
1250       for (Counter = 0; Counter < 8; Counter++)
1251         {
1252           Value >>= 1;
1253           Value ^= (Value & 1) * 0xedb88320;
1254         }
1255     }
1256 
1257   return Value;
1258 }
1259 
1260 NDIS_STATUS
1261 NTAPI
1262 MiSetMulticast(
1263     PADAPTER Adapter,
1264     UCHAR *Addresses,
1265     UINT AddressCount)
1266 {
1267   UINT Index;
1268   ULONG CrcIndex;
1269 
1270   NdisZeroMemory(Adapter->InitializationBlockVirt->LADR, 8);
1271   for (Index = 0; Index < AddressCount; Index++)
1272     {
1273       CrcIndex = MiEthernetCrc(Addresses) >> 26;
1274       Adapter->InitializationBlockVirt->LADR[CrcIndex >> 3] |= 1 << (CrcIndex & 15);
1275       Addresses += 6;
1276     }
1277 
1278   /* FIXME: The specification mentions we need to reload the init block here. */
1279 
1280   return NDIS_STATUS_SUCCESS;
1281 }
1282 
1283 BOOLEAN
1284 NTAPI
1285 MiGetMediaDuplex(PADAPTER Adapter)
1286 {
1287   ULONG Data;
1288 
1289   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR5);
1290   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
1291 
1292   return (Data & BCR5_LEDOUT) != 0;
1293 }
1294 
1295 UINT
1296 NTAPI
1297 MiGetMediaSpeed(PADAPTER Adapter)
1298 {
1299   ULONG Data;
1300 
1301   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR6);
1302   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
1303 
1304   return Data & BCR6_LEDOUT ? 100 : 10;
1305 }
1306 
1307 NDIS_MEDIA_STATE
1308 NTAPI
1309 MiGetMediaState(PADAPTER Adapter)
1310 /*
1311  * FUNCTION: Determine the link state
1312  * ARGUMENTS:
1313  *     Adapter: Adapter context
1314  * RETURNS:
1315  *     NdisMediaStateConnected if the cable is connected
1316  *     NdisMediaStateDisconnected if the cable is disconnected
1317  */
1318 {
1319   ULONG Data;
1320   NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
1321   NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
1322   return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected;
1323 }
1324 
1325 NTSTATUS
1326 NTAPI
1327 DriverEntry(
1328     IN PDRIVER_OBJECT DriverObject,
1329     IN PUNICODE_STRING RegistryPath)
1330 /*
1331  * FUNCTION: Start this driver
1332  * ARGUMENTS:
1333  *     DriverObject: Pointer to the system-allocated driver object
1334  *     RegistryPath: Pointer to our SCM database entry
1335  * RETURNS:
1336  *     NDIS_STATUS_SUCCESS on success
1337  *     NDIS_STATUS_FAILURE on failure
1338  * NOTES:
1339  *     - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
1340  *     - TODO: convert this to NTSTATUS return values
1341  */
1342 {
1343   NDIS_HANDLE WrapperHandle;
1344   NDIS_MINIPORT_CHARACTERISTICS Characteristics;
1345   NDIS_STATUS Status;
1346 
1347   RtlZeroMemory(&Characteristics, sizeof(Characteristics));
1348   Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
1349   Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
1350   Characteristics.HaltHandler = MiniportHalt;
1351   Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
1352   Characteristics.InitializeHandler = MiniportInitialize;
1353   Characteristics.ISRHandler = MiniportISR;
1354   Characteristics.QueryInformationHandler = MiniportQueryInformation;
1355   Characteristics.ResetHandler = MiniportReset;
1356   Characteristics.SetInformationHandler = MiniportSetInformation;
1357   Characteristics.SendHandler = MiniportSend;
1358 
1359   NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
1360   if (!WrapperHandle) return NDIS_STATUS_FAILURE;
1361 
1362   Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
1363   if(Status != NDIS_STATUS_SUCCESS)
1364     {
1365       NdisTerminateWrapper(WrapperHandle, 0);
1366       return NDIS_STATUS_FAILURE;
1367     }
1368 
1369   return NDIS_STATUS_SUCCESS;
1370 }
1371