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