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