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