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