xref: /reactos/drivers/network/dd/pcnet/pcnet.c (revision 34593d93)
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
MiniportHandleInterrupt(IN NDIS_HANDLE MiniportAdapterContext)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
MiQueryCard(IN PADAPTER Adapter)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
MiFreeSharedMemory(PADAPTER Adapter)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
MiAllocateSharedMemory(PADAPTER Adapter)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
MiPrepareInitializationBlock(PADAPTER Adapter)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
MiSyncStop(IN PVOID SynchronizeContext)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
MiniportHalt(IN NDIS_HANDLE MiniportAdapterContext)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
MiSyncMediaDetection(IN PVOID SynchronizeContext)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
MiniportMediaDetectionTimer(IN PVOID SystemSpecific1,IN PVOID FunctionContext,IN PVOID SystemSpecific2,IN PVOID SystemSpecific3)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
MiInitChip(PADAPTER Adapter)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
MiTestCard(PADAPTER Adapter)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
MiniportShutdown(PVOID Context)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
MiniportInitialize(OUT PNDIS_STATUS OpenErrorStatus,OUT PUINT SelectedMediumIndex,IN PNDIS_MEDIUM MediumArray,IN UINT MediumArraySize,IN NDIS_HANDLE MiniportAdapterHandle,IN NDIS_HANDLE WrapperConfigurationContext)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
MiniportISR(OUT PBOOLEAN InterruptRecognized,OUT PBOOLEAN QueueMiniportHandleInterrupt,IN NDIS_HANDLE MiniportAdapterContext)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
MiniportReset(OUT PBOOLEAN AddressingReset,IN NDIS_HANDLE MiniportAdapterContext)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
MiSyncStartTransmit(IN PVOID SynchronizeContext)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
MiniportSend(IN NDIS_HANDLE MiniportAdapterContext,IN PNDIS_PACKET Packet,IN UINT Flags)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
MiEthernetCrc(UCHAR * Address)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
MiSetMulticast(PADAPTER Adapter,UCHAR * Addresses,UINT AddressCount)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
MiGetMediaDuplex(PADAPTER Adapter)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
MiGetMediaSpeed(PADAPTER Adapter)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
MiGetMediaState(PADAPTER Adapter)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
DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)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