- Merge aicom-network-fixes up to r36740
[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)(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)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)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)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)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)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)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)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)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)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)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)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)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)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)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)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)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)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)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)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 /* deregister the shutdown routine */
577 NdisMDeregisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle);
578
579 /* free shared memory */
580 MiFreeSharedMemory(Adapter);
581
582 /* free map registers */
583 NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle);
584
585 /* free the lock */
586 NdisFreeSpinLock(&Adapter->Lock);
587
588 /* free the adapter */
589 NdisFreeMemory(Adapter, 0, 0);
590 }
591
592 static BOOLEAN
593 STDCALL
594 MiSyncMediaDetection(
595 IN PVOID SynchronizeContext)
596 /*
597 * FUNCTION: Stop the adapter
598 * ARGUMENTS:
599 * SynchronizeContext: Adapter context
600 */
601 {
602 PADAPTER Adapter = (PADAPTER)SynchronizeContext;
603 NDIS_MEDIA_STATE MediaState = MiGetMediaState(Adapter);
604
605 DPRINT("Called\n");
606 DPRINT("MediaState: %d\n", MediaState);
607 if (MediaState != Adapter->MediaState)
608 {
609 Adapter->MediaState = MediaState;
610 return TRUE;
611 }
612 return FALSE;
613 }
614
615 static VOID
616 STDCALL
617 MiniportMediaDetectionTimer(
618 IN PVOID SystemSpecific1,
619 IN PVOID FunctionContext,
620 IN PVOID SystemSpecific2,
621 IN PVOID SystemSpecific3)
622 /*
623 * FUNCTION: Periodially query media state
624 * ARGUMENTS:
625 * FunctionContext: Adapter context
626 * NOTES:
627 * - Called by NDIS at DISPATCH_LEVEL
628 */
629 {
630 PADAPTER Adapter = (PADAPTER)FunctionContext;
631
632 ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
633
634 if (NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject,
635 MiSyncMediaDetection,
636 FunctionContext))
637 {
638 NdisMIndicateStatus(Adapter->MiniportAdapterHandle,
639 Adapter->MediaState == NdisMediaStateConnected ?
640 NDIS_STATUS_MEDIA_CONNECT : NDIS_STATUS_MEDIA_DISCONNECT,
641 (PVOID)0, 0);
642 NdisMIndicateStatusComplete(Adapter->MiniportAdapterHandle);
643 }
644 }
645
646 static VOID
647 MiInitChip(
648 PADAPTER Adapter)
649 /*
650 * FUNCTION: Initialize and start the PCNET chip
651 * ARGUMENTS:
652 * Adapter: pointer to the miniport's adapter struct
653 * NOTES:
654 * - should be coded to detect failure and return an error
655 * - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that.
656 */
657 {
658 USHORT Data = 0;
659
660 DPRINT("Called\n");
661
662 /*
663 * first reset the chip - 32-bit reset followed by 16-bit reset. if it's in 32-bit mode, it'll reset
664 * twice. if it's in 16-bit mode, the first read will be nonsense and the second will be a reset. the
665 * card is reset by reading from the reset register. on reset it's in 16-bit i/o mode.
666 */
667 NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data);
668 NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
669
670 /* stop the chip */
671 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
672 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
673
674 /* pause for 1ms so the chip will have time to reset */
675 NdisStallExecution(1);
676
677 DPRINT("chip stopped\n");
678
679 /* set the software style to 2 (32 bits) */
680 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58);
681 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
682
683 Data |= SW_STYLE_2;
684
685 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
686
687 /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */
688 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
689 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
690
691 Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS;
692 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
693
694 /* set up bcr18: burst read/write enable */
695 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18);
696 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
697
698 Data |= BCR18_BREADE | BCR18_BWRITE ;
699 NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
700
701 /* set up csr1 and csr2 with init block */
702 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1);
703 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys & 0xffff));
704 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2);
705 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys >> 16) & 0xffff);
706
707 DPRINT("programmed with init block\n");
708
709 /* Set mode to 0 */
710 Data = 0;
711 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15);
712 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
713
714 /* load init block and start the card */
715 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
716 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
717
718 /* detect the media state */
719 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
720 NdisRawWritePortUshort(Adapter->PortOffset + BDP, BCR4_LNKSTE|BCR4_FDLSE);
721 Adapter->MediaState = MiGetMediaState(Adapter);
722
723 DPRINT("card started\n");
724
725 Adapter->Flags &= ~RESET_IN_PROGRESS;
726 }
727
728 #if DBG
729 static BOOLEAN
730 MiTestCard(
731 PADAPTER Adapter)
732 /*
733 * FUNCTION: Test the NIC
734 * ARGUMENTS:
735 * Adapter: pointer to the miniport's adapter struct
736 * RETURNS:
737 * TRUE if the test succeeds
738 * FALSE otherwise
739 * NOTES:
740 * - this is where to add diagnostics. This is called
741 * at the very end of initialization.
742 */
743 {
744 int i = 0;
745 UCHAR address[6];
746 USHORT Data = 0;
747
748 /* see if we can read/write now */
749 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
750 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
751 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);
752
753 /* read the BIA */
754 for(i = 0; i < 6; i++)
755 NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
756
757 DPRINT("burned-in address: %x:%x:%x:%x:%x:%x\n", address[0], address[1], address[2], address[3], address[4], address[5]);
758 /* Read status flags from CSR0 */
759 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
760 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
761 DPRINT("CSR0: 0x%x\n", Data);
762
763 /* Read status flags from CSR3 */
764 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3);
765 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
766
767 DPRINT("CSR3: 0x%x\n", Data);
768 /* Read status flags from CSR4 */
769 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
770 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
771 DPRINT("CSR4: 0x%x\n", Data);
772
773 /* Read status flags from CSR5 */
774 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5);
775 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
776 DPRINT("CSR5: 0x%x\n", Data);
777
778 /* Read status flags from CSR6 */
779 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6);
780 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
781 DPRINT("CSR6: 0x%x\n", Data);
782
783 return TRUE;
784 }
785 #endif
786
787 VOID
788 STDCALL
789 MiniportShutdown( PVOID Context )
790 {
791 PADAPTER Adapter = Context;
792
793 DPRINT("Stopping the chip\n");
794
795 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
796 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
797 }
798
799 static NDIS_STATUS
800 STDCALL
801 MiniportInitialize(
802 OUT PNDIS_STATUS OpenErrorStatus,
803 OUT PUINT SelectedMediumIndex,
804 IN PNDIS_MEDIUM MediumArray,
805 IN UINT MediumArraySize,
806 IN NDIS_HANDLE MiniportAdapterHandle,
807 IN NDIS_HANDLE WrapperConfigurationContext)
808 /*
809 * FUNCTION: Initialize a new miniport
810 * ARGUMENTS:
811 * OpenErrorStatus: pointer to a var to return status info in
812 * SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3)
813 * MediumArray: array of media that we can pick from
814 * MediumArraySize: size of MediumArray
815 * MiniportAdapterHandle: NDIS-assigned handle for this miniport instance
816 * WrapperConfigurationContext: temporary NDIS-assigned handle for passing
817 * to configuration APIs
818 * RETURNS:
819 * NDIS_STATUS_SUCCESS on success
820 * NDIS_STATUS_FAILURE on general failure
821 * NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray
822 * NDIS_STATUS_RESOURCES on insufficient system resources
823 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
824 * NOTES:
825 * - Called by NDIS at PASSIVE_LEVEL, once per detected card
826 * - Will int 3 on failure of MiTestCard if DBG=1
827 */
828 {
829 UINT i = 0;
830 PADAPTER Adapter = 0;
831 NDIS_STATUS Status = NDIS_STATUS_FAILURE;
832 BOOLEAN InterruptRegistered = FALSE;
833
834 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
835
836 /* Pick a medium */
837 for(i = 0; i < MediumArraySize; i++)
838 if(MediumArray[i] == NdisMedium802_3)
839 break;
840
841 if(i == MediumArraySize)
842 {
843 Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
844 DPRINT1("unsupported media\n");
845 BREAKPOINT;
846 *OpenErrorStatus = Status;
847 return Status;
848 }
849
850 *SelectedMediumIndex = i;
851
852 /* allocate our adapter struct */
853 Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG);
854 if(Status != NDIS_STATUS_SUCCESS)
855 {
856 Status = NDIS_STATUS_RESOURCES;
857 DPRINT1("Insufficient resources\n");
858 BREAKPOINT;
859 *OpenErrorStatus = Status;
860 return Status;
861 }
862
863 RtlZeroMemory(Adapter, sizeof(ADAPTER));
864
865 Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
866
867 /* register our adapter structwith ndis */
868 NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
869
870 do
871 {
872 /* Card-specific detection and setup */
873 Status = MiQueryCard(Adapter);
874 if(Status != NDIS_STATUS_SUCCESS)
875 {
876 DPRINT1("MiQueryCard failed\n");
877 Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
878 BREAKPOINT;
879 break;
880 }
881
882 /* register an IO port range */
883 Status = NdisMRegisterIoPortRange((PVOID*)&Adapter->PortOffset, Adapter->MiniportAdapterHandle,
884 (UINT)Adapter->IoBaseAddress, NUMBER_OF_PORTS);
885 if(Status != NDIS_STATUS_SUCCESS)
886 {
887 DPRINT1("NdisMRegisterIoPortRange failed: 0x%x\n", Status);
888 BREAKPOINT
889 break;
890 }
891
892 /* Allocate map registers */
893 Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0,
894 NDIS_DMA_32BITS, 8, BUFFER_SIZE);
895 if(Status != NDIS_STATUS_SUCCESS)
896 {
897 DPRINT1("NdisMAllocateMapRegisters failed: 0x%x\n", Status);
898 BREAKPOINT
899 break;
900 }
901
902 /* set up the interrupt */
903 Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector,
904 Adapter->InterruptVector, TRUE, TRUE, NdisInterruptLevelSensitive);
905 if(Status != NDIS_STATUS_SUCCESS)
906 {
907 DPRINT("NdisMRegisterInterrupt failed: 0x%x\n", Status);
908 BREAKPOINT
909 break;
910 }
911
912 InterruptRegistered = TRUE;
913
914 /* Allocate and initialize shared data structures */
915 Status = MiAllocateSharedMemory(Adapter);
916 if(Status != NDIS_STATUS_SUCCESS)
917 {
918 Status = NDIS_STATUS_RESOURCES;
919 DPRINT("MiAllocateSharedMemory failed", Status);
920 BREAKPOINT
921 break;
922 }
923
924 /* set up the initialization block */
925 MiPrepareInitializationBlock(Adapter);
926
927 DPRINT("Interrupt registered successfully\n");
928
929 /* Initialize and start the chip */
930 MiInitChip(Adapter);
931
932 NdisAllocateSpinLock(&Adapter->Lock);
933
934 Status = NDIS_STATUS_SUCCESS;
935 }
936 while(0);
937
938 if(Status != NDIS_STATUS_SUCCESS && Adapter)
939 {
940 DPRINT("Error; freeing stuff\n");
941
942 NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); /* doesn't hurt to free if we never alloc'd? */
943
944 if(Adapter->PortOffset)
945 NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, (PVOID)Adapter->PortOffset);
946
947 if(InterruptRegistered)
948 NdisMDeregisterInterrupt(&Adapter->InterruptObject);
949
950 MiFreeSharedMemory(Adapter);
951
952 NdisFreeMemory(Adapter, 0, 0);
953 }
954
955 if(Status == NDIS_STATUS_SUCCESS)
956 {
957 NdisMInitializeTimer(&Adapter->MediaDetectionTimer,
958 Adapter->MiniportAdapterHandle,
959 MiniportMediaDetectionTimer,
960 Adapter);
961 NdisMSetPeriodicTimer(&Adapter->MediaDetectionTimer,
962 MEDIA_DETECTION_INTERVAL);
963 }
964
965 #if DBG
966 if(!MiTestCard(Adapter))
967 ASSERT(0);
968 #endif
969
970 NdisMRegisterAdapterShutdownHandler(Adapter->MiniportAdapterHandle, Adapter, MiniportShutdown);
971
972 DPRINT("returning 0x%x\n", Status);
973 *OpenErrorStatus = Status;
974 return Status;
975 }
976
977 static VOID
978 STDCALL
979 MiniportISR(
980 OUT PBOOLEAN InterruptRecognized,
981 OUT PBOOLEAN QueueMiniportHandleInterrupt,
982 IN NDIS_HANDLE MiniportAdapterContext)
983 /*
984 * FUNCTION: Miniport interrupt service routine
985 * ARGUMENTS:
986 * InterruptRecognized: the interrupt was ours
987 * QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
988 * MiniportAdapterContext: the context originally passed to NdisMSetAttributes
989 * NOTES:
990 * - called by NDIS at DIRQL
991 * - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
992 * will be called
993 */
994 {
995 USHORT Data;
996 USHORT Rap;
997 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
998
999 DPRINT("Called\n");
1000
1001 /* save the old RAP value */
1002 NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
1003
1004 /* is this ours? */
1005 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1006 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
1007
1008 if(!(Data & CSR0_INTR))
1009 {
1010 DPRINT("not our interrupt.\n");
1011 *InterruptRecognized = FALSE;
1012 *QueueMiniportHandleInterrupt = FALSE;
1013 }
1014 else
1015 {
1016 DPRINT("detected our interrupt\n");
1017
1018 /* disable interrupts */
1019 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1020 NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
1021
1022 *InterruptRecognized = TRUE;
1023 *QueueMiniportHandleInterrupt = TRUE;
1024 }
1025
1026 /* restore the rap */
1027 NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
1028 }
1029
1030 static NDIS_STATUS
1031 STDCALL
1032 MiniportReset(
1033 OUT PBOOLEAN AddressingReset,
1034 IN NDIS_HANDLE MiniportAdapterContext)
1035 /*
1036 * FUNCTION: Reset the miniport
1037 * ARGUMENTS:
1038 * AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
1039 * to reset our addresses and filters
1040 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
1041 * RETURNS:
1042 * NDIS_STATUS_SUCCESS on all requests
1043 * Notes:
1044 * - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
1045 */
1046 {
1047 DPRINT("Called\n");
1048
1049 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
1050
1051 /* MiniportReset doesn't do anything at the moment... perhaps this should be fixed. */
1052
1053 *AddressingReset = FALSE;
1054 return NDIS_STATUS_SUCCESS;
1055 }
1056
1057 static BOOLEAN
1058 STDCALL
1059 MiSyncStartTransmit(
1060 IN PVOID SynchronizeContext)
1061 /*
1062 * FUNCTION: Stop the adapter
1063 * ARGUMENTS:
1064 * SynchronizeContext: Adapter context
1065 */
1066 {
1067 PADAPTER Adapter = (PADAPTER)SynchronizeContext;
1068 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
1069 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA | CSR0_TDMD);
1070 return TRUE;
1071 }
1072
1073 static NDIS_STATUS
1074 STDCALL
1075 MiniportSend(
1076 IN NDIS_HANDLE MiniportAdapterContext,
1077 IN PNDIS_PACKET Packet,
1078 IN UINT Flags)
1079 /*
1080 * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
1081 * ARGUMENTS:
1082 * MiniportAdapterContext: context originally input to NdisMSetAttributes
1083 * Packet: The NDIS_PACKET to be sent
1084 * Flags: Flags associated with Packet
1085 * RETURNS:
1086 * NDIS_STATUS_SUCCESS on processed requests
1087 * NDIS_STATUS_RESOURCES if there's no place in buffer ring
1088 * NOTES:
1089 * - Called by NDIS at DISPATCH_LEVEL
1090 */
1091 {
1092 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
1093 PTRANSMIT_DESCRIPTOR Desc;
1094 PNDIS_BUFFER NdisBuffer;
1095 PVOID SourceBuffer;
1096 UINT TotalPacketLength, SourceLength, Position = 0;
1097
1098 DPRINT("Called\n");
1099
1100 ASSERT_IRQL_EQUAL(DISPATCH_LEVEL);
1101
1102 NdisDprAcquireSpinLock(&Adapter->Lock);
1103
1104 /* Check if we have free entry in our circular buffer. */
1105 if ((Adapter->CurrentTransmitEndIndex + 1 ==
1106 Adapter->CurrentTransmitStartIndex) ||
1107 (Adapter->CurrentTransmitEndIndex == NUMBER_OF_BUFFERS - 1 &&
1108 Adapter->CurrentTransmitStartIndex == 0))
1109 {
1110 DPRINT1("No free space in circular buffer\n");
1111 NdisDprReleaseSpinLock(&Adapter->Lock);
1112 return NDIS_STATUS_RESOURCES;
1113 }
1114
1115 Desc = Adapter->TransmitDescriptorRingVirt + Adapter->CurrentTransmitEndIndex;
1116
1117 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, &TotalPacketLength);
1118 ASSERT(TotalPacketLength <= BUFFER_SIZE);
1119
1120 DPRINT("TotalPacketLength: %x\n", TotalPacketLength);
1121
1122 while (NdisBuffer)
1123 {
1124 NdisQueryBuffer(NdisBuffer, &SourceBuffer, &SourceLength);
1125
1126 DPRINT("Buffer: %x Length: %x\n", SourceBuffer, SourceLength);
1127
1128 RtlCopyMemory(Adapter->TransmitBufferPtrVirt +
1129 Adapter->CurrentTransmitEndIndex * BUFFER_SIZE + Position,
1130 SourceBuffer, SourceLength);
1131
1132 Position += SourceLength;
1133
1134 NdisGetNextBuffer(NdisBuffer, &NdisBuffer);
1135 }
1136
1137 #if DBG && 0
1138 {
1139 PUCHAR Ptr = Adapter->TransmitBufferPtrVirt +
1140 Adapter->CurrentTransmitEndIndex * BUFFER_SIZE;
1141 for (Position = 0; Position < TotalPacketLength; Position++)
1142 {
1143 if (Position % 16 == 0)
1144 DbgPrint("\n");
1145 DbgPrint("%x ", *Ptr++);
1146 }
1147 }
1148 DbgPrint("\n");
1149 #endif
1150
1151 Adapter->CurrentTransmitEndIndex++;
1152 Adapter->CurrentTransmitEndIndex %= NUMBER_OF_BUFFERS;
1153
1154 Desc->FLAGS = TD1_OWN | TD1_STP | TD1_ENP;
1155 Desc->BCNT = 0xf000 | -TotalPacketLength;
1156
1157 NdisMSynchronizeWithInterrupt(&Adapter->InterruptObject, MiSyncStartTransmit, Adapter);
1158
1159 NdisDprReleaseSpinLock(&Adapter->Lock);
1160
1161 return NDIS_STATUS_SUCCESS;
1162 }
1163
1164 static ULONG
1165 STDCALL
1166 MiEthernetCrc(UCHAR *Address)
1167 /*
1168 * FUNCTION: Calculate Ethernet CRC32
1169 * ARGUMENTS:
1170 * Address: 6-byte ethernet address
1171 * RETURNS:
1172 * The calculated CRC32 value.
1173 */
1174 {
1175 UINT Counter, Length;
1176 ULONG Value = ~0;
1177
1178 for (Length = 0; Length < 6; Length++)
1179 {
1180 Value ^= *Address++;
1181 for (Counter = 0; Counter < 8; Counter++)
1182 {
1183 Value >>= 1;
1184 Value ^= (Value & 1) * 0xedb88320;
1185 }
1186 }
1187
1188 return Value;
1189 }
1190
1191 NDIS_STATUS
1192 STDCALL
1193 MiSetMulticast(
1194 PADAPTER Adapter,
1195 UCHAR *Addresses,
1196 UINT AddressCount)
1197 {
1198 UINT Index;
1199 ULONG CrcIndex;
1200
1201 NdisZeroMemory(Adapter->InitializationBlockVirt->LADR, 8);
1202 for (Index = 0; Index < AddressCount; Index++)
1203 {
1204 CrcIndex = MiEthernetCrc(Addresses) >> 26;
1205 Adapter->InitializationBlockVirt->LADR[CrcIndex >> 3] |= 1 << (CrcIndex & 15);
1206 Addresses += 6;
1207 }
1208
1209 /* FIXME: The specification mentions we need to reload the init block here. */
1210
1211 return NDIS_STATUS_SUCCESS;
1212 }
1213
1214 NDIS_MEDIA_STATE
1215 STDCALL
1216 MiGetMediaState(PADAPTER Adapter)
1217 /*
1218 * FUNCTION: Determine the link state
1219 * ARGUMENTS:
1220 * Adapter: Adapter context
1221 * RETURNS:
1222 * NdisMediaStateConnected if the cable is connected
1223 * NdisMediaStateDisconnected if the cable is disconnected
1224 */
1225 {
1226 ULONG Data;
1227 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR4);
1228 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
1229 return Data & BCR4_LEDOUT ? NdisMediaStateConnected : NdisMediaStateDisconnected;
1230 }
1231
1232 NTSTATUS
1233 STDCALL
1234 DriverEntry(
1235 IN PDRIVER_OBJECT DriverObject,
1236 IN PUNICODE_STRING RegistryPath)
1237 /*
1238 * FUNCTION: Start this driver
1239 * ARGUMENTS:
1240 * DriverObject: Pointer to the system-allocated driver object
1241 * RegistryPath: Pointer to our SCM database entry
1242 * RETURNS:
1243 * NDIS_STATUS_SUCCESS on success
1244 * NDIS_STATUS_FAILURE on failure
1245 * NOTES:
1246 * - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
1247 * - TODO: convert this to NTSTATUS return values
1248 */
1249 {
1250 NDIS_HANDLE WrapperHandle;
1251 NDIS_MINIPORT_CHARACTERISTICS Characteristics;
1252 NDIS_STATUS Status;
1253
1254 RtlZeroMemory(&Characteristics, sizeof(Characteristics));
1255 Characteristics.MajorNdisVersion = NDIS_MINIPORT_MAJOR_VERSION;
1256 Characteristics.MinorNdisVersion = NDIS_MINIPORT_MINOR_VERSION;
1257 Characteristics.HaltHandler = MiniportHalt;
1258 Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
1259 Characteristics.InitializeHandler = MiniportInitialize;
1260 Characteristics.ISRHandler = MiniportISR;
1261 Characteristics.QueryInformationHandler = MiniportQueryInformation;
1262 Characteristics.ResetHandler = MiniportReset;
1263 Characteristics.SetInformationHandler = MiniportSetInformation;
1264 Characteristics.SendHandler = MiniportSend;
1265
1266 NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
1267
1268 Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
1269 if(Status != NDIS_STATUS_SUCCESS)
1270 {
1271 NdisTerminateWrapper(WrapperHandle, 0);
1272 return NDIS_STATUS_FAILURE;
1273 }
1274
1275 return NDIS_STATUS_SUCCESS;
1276 }
1277