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