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