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