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