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