a45d4143fead3d6484972d542d92b221978ec6c7
[reactos.git] / reactos / drivers / net / dd / pcnet / pcnet.c
1 /*
2 * ReactOS AMD PCNet Driver
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 * PROJECT: ReactOS AMD PCNet Driver
20 * FILE: drivers/net/dd/pcnet/pcnet.c
21 * PURPOSE: PCNet Device Driver
22 * PROGRAMMER: Vizzini (vizzini@plasmic.com)
23 * REVISIONS:
24 * 9-Sept-2003 vizzini - Created
25 * NOTES:
26 * - this is hard-coded to NDIS4
27 * - this assumes a little-endian machine
28 * - this assumes a 32-bit machine
29 * - this doesn't handle multiple PCNET NICs yet
30 * - this driver includes both NdisRaw and NdisImmediate calls
31 * for NDIS testing purposes. Pick your poison below.
32 */
33 #include <ndis.h>
34 #include "pci.h"
35 #include "pcnethw.h"
36 #include "pcnet.h"
37
38 \f
39 VOID
40 STDCALL
41 MiniportHalt(
42 IN NDIS_HANDLE MiniportAdapterContext)
43 /*
44 * FUNCTION: Stop the miniport and prepare for unload
45 * ARGUMENTS:
46 * MiniportAdapterContext: context specified to NdisMSetAttributes
47 * NOTES:
48 * - Called by NDIS at PASSIVE_LEVEL
49 */
50 {
51 /* XXX Implement me */
52 PCNET_DbgPrint(("Called\n"));
53 }
54
55 \f
56 VOID
57 STDCALL
58 MiniportHandleInterrupt(
59 IN NDIS_HANDLE MiniportAdapterContext)
60 /*
61 * FUNCTION: Handle an interrupt if told to by MiniportISR
62 * ARGUMENTS:
63 * MiniportAdapterContext: context specified to NdisMSetAttributes
64 * NOTES:
65 * - Called by NDIS at DISPATCH_LEVEL
66 */
67 {
68 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
69 USHORT Data;
70 BOOLEAN ErrorHandled = FALSE;
71 BOOLEAN ReceiveHandled = FALSE;
72 BOOLEAN IdonHandled = FALSE;
73 USHORT Temp;
74
75 PCNET_DbgPrint(("Called\n"));
76
77 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
78 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
79
80 PCNET_DbgPrint(("CSR0 is 0x%x\n", Data));
81
82 while(Data & CSR0_INTR)
83 {
84 if(Data & CSR0_ERR)
85 {
86 if(ErrorHandled)
87 {
88 PCNET_DbgPrint(("ERROR HANDLED TWO TIMES\n"));
89 __asm__("int $3\n");
90 }
91
92 ErrorHandled = TRUE;
93
94 PCNET_DbgPrint(("clearing an error\n"));
95 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_MERR|CSR0_BABL|CSR0_CERR|CSR0_MISS);
96 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Temp);
97 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp));
98 }
99 else if(Data & CSR0_IDON)
100 {
101 if(IdonHandled)
102 {
103 PCNET_DbgPrint(("IDON HANDLED TWO TIMES\n"));
104 __asm__("int $3\n");
105 }
106
107 IdonHandled = TRUE;
108
109 PCNET_DbgPrint(("clearing IDON\n"));
110 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IDON);
111 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Temp);
112 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp));
113 }
114 else if(Data & CSR0_RINT)
115 {
116 if(ReceiveHandled)
117 {
118 PCNET_DbgPrint(("RECEIVE HANDLED TWO TIMES\n"));
119 __asm__("int $3\n");
120 }
121
122 ReceiveHandled = TRUE;
123
124 PCNET_DbgPrint(("receive interrupt - clearing\n"));
125 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_RINT);
126 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Temp);
127 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Temp));
128
129 while(1)
130 {
131 PRECEIVE_DESCRIPTOR Descriptor = Adapter->ReceiveDescriptorRingVirt + Adapter->CurrentReceiveDescriptorIndex;
132 PCHAR Buffer;
133 ULONG ByteCount;
134
135 if(Descriptor->FLAGS & RD_OWN)
136 {
137 PCNET_DbgPrint(("no more receive descriptors to process\n"));
138 break;
139 }
140
141 if(Descriptor->FLAGS & RD_ERR)
142 {
143 PCNET_DbgPrint(("receive descriptor error: 0x%x\n", Descriptor->FLAGS));
144 break;
145 }
146
147 if(!((Descriptor->FLAGS & RD_STP) && (Descriptor->FLAGS & RD_ENP)))
148 {
149 PCNET_DbgPrint(("receive descriptor not start&end: 0x%x\n", Descriptor->FLAGS));
150 break;
151 }
152
153 Buffer = Adapter->ReceiveBufferPtrVirt + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE;
154 ByteCount = Descriptor->MCNT & 0xfff;
155
156 PCNET_DbgPrint(("Indicating a %d-byte packet (index %d)\n", ByteCount, Adapter->CurrentReceiveDescriptorIndex));
157
158 NdisMEthIndicateReceive(Adapter->MiniportAdapterHandle, 0, Buffer, 14, Buffer+14, ByteCount-14, ByteCount-14);
159
160 memset(Descriptor, 0, sizeof(RECEIVE_DESCRIPTOR));
161 Descriptor->RBADR =
162 (ULONG)(Adapter->ReceiveBufferPtrPhys + Adapter->CurrentReceiveDescriptorIndex * BUFFER_SIZE);
163 Descriptor->BCNT = (-BUFFER_SIZE) | 0xf000;
164 Descriptor->FLAGS &= RD_OWN;
165
166 Adapter->CurrentReceiveDescriptorIndex++;
167
168 if(Adapter->CurrentReceiveDescriptorIndex == NUMBER_OF_BUFFERS)
169 Adapter->CurrentReceiveDescriptorIndex = 0;
170 }
171 }
172 else
173 {
174 PCNET_DbgPrint(("UNHANDLED INTERRUPT\n"));
175 __asm__("int $3\n");
176 }
177
178 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
179 }
180
181 /* re-enable interrupts */
182 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_IENA);
183
184 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
185 PCNET_DbgPrint(("CSR0 is now 0x%x\n", Data));
186 }
187
188 \f
189 NDIS_STATUS
190 MiQueryCard(
191 IN PADAPTER Adapter)
192 /*
193 * FUNCTION: Detect the PCNET NIC in the configured slot and query its I/O address and interrupt vector
194 * ARGUMENTS:
195 * MiniportAdapterContext: context supplied to NdisMSetAttributes
196 * RETURNS:
197 * NDIS_STATUS_FAILURE on a general error
198 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
199 * NDIS_STATUS_SUCCESS on succes
200 */
201 {
202 ULONG buf32 = 0;
203 UCHAR buf8 = 0;
204 NDIS_STATUS Status;
205
206 /* Detect the card in the configured slot */
207 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_PCIID, &buf32, 4);
208 if(Status != 4)
209 {
210 Status = NDIS_STATUS_FAILURE;
211 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
212 BREAKPOINT;
213 return Status;
214 }
215
216 if(buf32 != PCI_ID)
217 {
218 Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
219 PCNET_DbgPrint(("card in slot 0x%x isn't us: 0x%x\n", Adapter->SlotNumber, buf32));
220 BREAKPOINT;
221 return Status;
222 }
223
224 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber,
225 PCI_COMMAND, &buf32, 4);
226 if(Status != 4)
227 {
228 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
229 BREAKPOINT;
230 return NDIS_STATUS_FAILURE;
231 }
232
233 PCNET_DbgPrint(("config/status register: 0x%x\n", buf32));
234
235 if(buf32 & 0x1)
236 {
237 PCNET_DbgPrint(("io space access is enabled.\n"));
238 }
239 else
240 {
241 PCNET_DbgPrint(("io space is NOT enabled!\n"));
242 BREAKPOINT;
243 return NDIS_STATUS_FAILURE;
244 }
245
246 /* get IO base physical address */
247 buf32 = 0;
248 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_IOBAR, &buf32, 4);
249 if(Status != 4)
250 {
251 Status = NDIS_STATUS_FAILURE;
252 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
253 BREAKPOINT;
254 return Status;
255 }
256
257 if(!buf32)
258 {
259 PCNET_DbgPrint(("No base i/o address set\n"));
260 return NDIS_STATUS_FAILURE;
261 }
262
263 buf32 &= ~1; /* even up address - comes out odd for some reason */
264
265 PCNET_DbgPrint(("detected io address 0x%x\n", buf32));
266 Adapter->IoBaseAddress = buf32;
267
268 /* get interrupt vector */
269 Status = NdisReadPciSlotInformation(Adapter->MiniportAdapterHandle, Adapter->SlotNumber, PCI_ILR, &buf8, 1);
270 if(Status != 1)
271 {
272 Status = NDIS_STATUS_FAILURE;
273 PCNET_DbgPrint(("NdisReadPciSlotInformation failed\n"));
274 BREAKPOINT;
275 return Status;
276 }
277
278 PCNET_DbgPrint(("interrupt: 0x%x\n", buf8));
279 Adapter->InterruptVector = buf8;
280
281 return NDIS_STATUS_SUCCESS;
282 }
283
284 \f
285 NDIS_STATUS
286 MiGetConfig(
287 PADAPTER Adapter,
288 NDIS_HANDLE WrapperConfigurationContext)
289 /*
290 * FUNCTION: Get configuration parameters from the registry
291 * ARGUMENTS:
292 * Adapter: pointer to the Adapter struct for this NIC
293 * WrapperConfigurationContext: Context passed into MiniportInitialize
294 * RETURNS:
295 * NDIS_STATUS_SUCCESS on success
296 * NDIS_STATUS_{something} on failure (return val from other Ndis calls)
297 */
298 {
299 PNDIS_CONFIGURATION_PARAMETER Parameter;
300 NDIS_HANDLE ConfigurationHandle = 0;
301 UNICODE_STRING Keyword;
302 NDIS_STATUS Status;
303
304 NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext);
305 if(Status != NDIS_STATUS_SUCCESS)
306 {
307 PCNET_DbgPrint(("Unable to open configuration: 0x%x\n", Status));
308 BREAKPOINT;
309 return Status;
310 }
311
312 RtlInitUnicodeString(&Keyword, L"SlotNumber");
313 NdisReadConfiguration(&Status, &Parameter, ConfigurationHandle, &Keyword, NdisParameterInteger);
314 if(Status != NDIS_STATUS_SUCCESS)
315 {
316 PCNET_DbgPrint(("Unable to read slot number: 0x%x\n", Status));
317 BREAKPOINT;
318 }
319 else
320 Adapter->SlotNumber = Parameter->ParameterData.IntegerData;
321
322 NdisCloseConfiguration(ConfigurationHandle);
323
324 return NDIS_STATUS_SUCCESS;
325 }
326
327 \f
328 NDIS_STATUS
329 MiAllocateSharedMemory(
330 PADAPTER Adapter)
331 /*
332 * FUNCTION: Allocate all shared memory used by the miniport
333 * ARGUMENTS:
334 * Adapter: Pointer to the miniport's adapter object
335 * RETURNS:
336 * NDIS_STATUS_RESOURCES on insufficient memory
337 * NDIS_STATUS_SUCCESS on success
338 */
339 {
340 PTRANSMIT_DESCRIPTOR TransmitDescriptor;
341 PRECEIVE_DESCRIPTOR ReceiveDescriptor;
342 NDIS_PHYSICAL_ADDRESS PhysicalAddress;
343 ULONG i;
344
345 /* allocate the initialization block */
346 Adapter->InitializationBlockLength = sizeof(INITIALIZATION_BLOCK);
347 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
348 FALSE, (PVOID *)&Adapter->InitializationBlockVirt, &PhysicalAddress);
349 if(!Adapter->InitializationBlockVirt)
350 {
351 PCNET_DbgPrint(("insufficient resources\n"));
352 BREAKPOINT;
353 return NDIS_STATUS_RESOURCES;
354 }
355
356 if(((ULONG)Adapter->InitializationBlockVirt & 0x00000003) != 0)
357 {
358 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->InitializationBlockVirt));
359 BREAKPOINT;
360 return NDIS_STATUS_RESOURCES;
361 }
362
363 Adapter->InitializationBlockPhys = (PINITIALIZATION_BLOCK)NdisGetPhysicalAddressLow(PhysicalAddress);
364 memset(Adapter->InitializationBlockVirt, 0, sizeof(INITIALIZATION_BLOCK));
365
366 /* allocate the transport descriptor ring */
367 Adapter->TransmitDescriptorRingLength = sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS;
368 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
369 FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, &PhysicalAddress);
370 if(!Adapter->TransmitDescriptorRingVirt)
371 {
372 PCNET_DbgPrint(("insufficient resources\n"));
373 BREAKPOINT;
374 return NDIS_STATUS_RESOURCES;
375 }
376
377 if(((ULONG)Adapter->TransmitDescriptorRingVirt & 0x00000003) != 0)
378 {
379 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->TransmitDescriptorRingVirt));
380 BREAKPOINT;
381 return NDIS_STATUS_RESOURCES;
382 }
383
384 Adapter->TransmitDescriptorRingPhys = (PTRANSMIT_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
385 memset(Adapter->TransmitDescriptorRingVirt, 0, sizeof(TRANSMIT_DESCRIPTOR) * NUMBER_OF_BUFFERS);
386
387 /* allocate the receive descriptor ring */
388 Adapter->ReceiveDescriptorRingLength = sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS;
389 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
390 FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, &PhysicalAddress);
391 if(!Adapter->ReceiveDescriptorRingVirt)
392 {
393 PCNET_DbgPrint(("insufficient resources\n"));
394 BREAKPOINT;
395 return NDIS_STATUS_RESOURCES;
396 }
397
398 if(((ULONG)Adapter->ReceiveDescriptorRingVirt & 0x00000003) != 0)
399 {
400 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->ReceiveDescriptorRingVirt));
401 BREAKPOINT;
402 return NDIS_STATUS_RESOURCES;
403 }
404
405 Adapter->ReceiveDescriptorRingPhys = (PRECEIVE_DESCRIPTOR)NdisGetPhysicalAddressLow(PhysicalAddress);
406 memset(Adapter->ReceiveDescriptorRingVirt, 0, sizeof(RECEIVE_DESCRIPTOR) * NUMBER_OF_BUFFERS);
407
408 /* allocate transmit buffers */
409 Adapter->TransmitBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
410 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
411 FALSE, (PVOID *)&Adapter->TransmitBufferPtrVirt, &PhysicalAddress);
412 if(!Adapter->TransmitBufferPtrVirt)
413 {
414 PCNET_DbgPrint(("insufficient resources\n"));
415 BREAKPOINT;
416 return NDIS_STATUS_RESOURCES;
417 }
418
419 if(((ULONG)Adapter->TransmitBufferPtrVirt & 0x00000003) != 0)
420 {
421 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->TransmitBufferPtrVirt));
422 BREAKPOINT;
423 return NDIS_STATUS_RESOURCES;
424 }
425
426 Adapter->TransmitBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
427 memset(Adapter->TransmitBufferPtrVirt, 0, BUFFER_SIZE * NUMBER_OF_BUFFERS);
428
429 /* allocate receive buffers */
430 Adapter->ReceiveBufferLength = BUFFER_SIZE * NUMBER_OF_BUFFERS;
431 NdisMAllocateSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
432 FALSE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, &PhysicalAddress);
433 if(!Adapter->ReceiveBufferPtrVirt)
434 {
435 PCNET_DbgPrint(("insufficient resources\n"));
436 BREAKPOINT;
437 return NDIS_STATUS_RESOURCES;
438 }
439
440 if(((ULONG)Adapter->ReceiveBufferPtrVirt & 0x00000003) != 0)
441 {
442 PCNET_DbgPrint(("address 0x%x not dword-aligned\n", Adapter->ReceiveBufferPtrVirt));
443 BREAKPOINT;
444 return NDIS_STATUS_RESOURCES;
445 }
446
447 Adapter->ReceiveBufferPtrPhys = (PCHAR)NdisGetPhysicalAddressLow(PhysicalAddress);
448 memset(Adapter->ReceiveBufferPtrVirt, 0, BUFFER_SIZE * NUMBER_OF_BUFFERS);
449
450 /* initialize tx descriptors */
451 TransmitDescriptor = Adapter->TransmitDescriptorRingVirt;
452 for(i = 0; i < NUMBER_OF_BUFFERS; i++)
453 {
454 (TransmitDescriptor+i)->TBADR = (ULONG)Adapter->TransmitBufferPtrPhys + i * BUFFER_SIZE;
455 (TransmitDescriptor+i)->BCNT = 0xf000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */
456 (TransmitDescriptor+i)->FLAGS = TD1_STP | TD1_ENP;
457 }
458
459 PCNET_DbgPrint(("transmit ring initialized\n"));
460
461 /* initialize rx */
462 ReceiveDescriptor = Adapter->ReceiveDescriptorRingVirt;
463 for(i = 0; i < NUMBER_OF_BUFFERS; i++)
464 {
465 (ReceiveDescriptor+i)->RBADR = (ULONG)Adapter->ReceiveBufferPtrPhys + i * BUFFER_SIZE;
466 (ReceiveDescriptor+i)->BCNT = 0xf0000 | -BUFFER_SIZE; /* 2's compliment + set top 4 bits */
467 (ReceiveDescriptor+i)->FLAGS |= RD_OWN;
468 }
469
470 PCNET_DbgPrint(("receive ring initialized\n"));
471
472 return NDIS_STATUS_SUCCESS;
473 }
474
475 \f
476 VOID
477 MiPrepareInitializationBlock(
478 PADAPTER Adapter)
479 /*
480 * FUNCTION: Initialize the initialization block
481 * ARGUMENTS:
482 * Adapter: pointer to the miniport's adapter object
483 */
484 {
485 ULONG i = 0;
486
487 /* read burned-in address from card */
488 for(i = 0; i < 6; i++)
489 NdisRawReadPortUchar(Adapter->PortOffset + i, Adapter->InitializationBlockVirt->PADR + i);
490
491 /* set up receive ring */
492 PCNET_DbgPrint(("Receive ring physical address: 0x%x\n", Adapter->ReceiveDescriptorRingPhys));
493 Adapter->InitializationBlockVirt->RDRA = (ULONG)Adapter->ReceiveDescriptorRingPhys;
494 Adapter->InitializationBlockVirt->RLEN = (LOG_NUMBER_OF_BUFFERS << 4) & 0xf0;
495
496 /* set up transmit ring */
497 PCNET_DbgPrint(("Transmit ring physical address: 0x%x\n", Adapter->TransmitDescriptorRingPhys));
498 Adapter->InitializationBlockVirt->TDRA = (ULONG)Adapter->TransmitDescriptorRingPhys;
499 Adapter->InitializationBlockVirt->TLEN = (LOG_NUMBER_OF_BUFFERS << 4) & 0xf0;
500 }
501
502 \f
503 VOID
504 MiFreeSharedMemory(
505 PADAPTER Adapter)
506 /*
507 * FUNCTION: Free all allocated shared memory
508 * ARGUMENTS:
509 * Adapter: pointer to the miniport's adapter struct
510 */
511 {
512 NDIS_PHYSICAL_ADDRESS PhysicalAddress;
513
514 PhysicalAddress.u.HighPart = 0;
515
516 if(Adapter->InitializationBlockVirt)
517 {
518 PhysicalAddress.u.LowPart = (ULONG)Adapter->InitializationBlockPhys;
519 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->InitializationBlockLength,
520 FALSE, (PVOID *)&Adapter->InitializationBlockVirt, PhysicalAddress);
521 }
522
523 if(Adapter->TransmitDescriptorRingVirt)
524 {
525 PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitDescriptorRingPhys;
526 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitDescriptorRingLength,
527 FALSE, (PVOID *)&Adapter->TransmitDescriptorRingVirt, PhysicalAddress);
528 }
529
530 if(Adapter->ReceiveDescriptorRingVirt)
531 {
532 PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveDescriptorRingPhys;
533 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveDescriptorRingLength,
534 FALSE, (PVOID *)&Adapter->ReceiveDescriptorRingVirt, PhysicalAddress);
535 }
536
537 if(Adapter->TransmitBufferPtrVirt)
538 {
539 PhysicalAddress.u.LowPart = (ULONG)Adapter->TransmitBufferPtrPhys;
540 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->TransmitBufferLength,
541 FALSE, (PVOID *)&Adapter->TransmitBufferPtrVirt, PhysicalAddress);
542 }
543
544 if(Adapter->ReceiveBufferPtrVirt)
545 {
546 PhysicalAddress.u.LowPart = (ULONG)Adapter->ReceiveBufferPtrPhys;
547 NdisMFreeSharedMemory(Adapter->MiniportAdapterHandle, Adapter->ReceiveBufferLength,
548 FALSE, (PVOID *)&Adapter->ReceiveBufferPtrVirt, PhysicalAddress);
549 }
550 }
551
552 \f
553 VOID
554 MiInitChip(
555 PADAPTER Adapter)
556 /*
557 * FUNCTION: Initialize and start the PCNET chip
558 * ARGUMENTS:
559 * Adapter: pointer to the miniport's adapter struct
560 * NOTES:
561 * - should be coded to detect failure and return an error
562 * - the vmware virtual lance chip doesn't support 32-bit i/o so don't do that.
563 */
564 {
565 USHORT Data = 0;
566
567 PCNET_DbgPrint(("Called\n"));
568
569 /*
570 * first reset the chip - 32-bit reset followed by 16-bit reset. if it's in 32-bit mode, it'll reset
571 * twice. if it's in 16-bit mode, the first read will be nonsense and the second will be a reset. the
572 * card is reset by reading from the reset register. on reset it's in 16-bit i/o mode.
573 */
574 NdisRawReadPortUshort(Adapter->PortOffset + RESET32, &Data);
575 NdisRawReadPortUshort(Adapter->PortOffset + RESET16, &Data);
576
577 /* stop the chip */
578 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
579 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STOP);
580
581 /* pause for 1ms so the chip will have time to reset */
582 NdisStallExecution(1);
583
584 PCNET_DbgPrint(("chip stopped\n"));
585
586 /* set the software style to 2 (32 bits) */
587 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR58);
588 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
589
590 Data |= SW_STYLE_2;
591
592 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
593
594 /* set up csr4: auto transmit pad, disable polling, disable transmit interrupt, dmaplus */
595 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
596 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
597
598 Data |= CSR4_APAD_XMT | /* CSR4_DPOLL |*/ CSR4_TXSTRTM | CSR4_DMAPLUS;
599 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
600
601 /* set up bcr18: burst read/write enable */
602 NdisRawWritePortUshort(Adapter->PortOffset + RAP, BCR18);
603 NdisRawReadPortUshort(Adapter->PortOffset + BDP, &Data);
604
605 Data |= BCR18_BREADE | BCR18_BWRITE ;
606 NdisRawWritePortUshort(Adapter->PortOffset + BDP, Data);
607
608 /* set up csr1 and csr2 with init block */
609 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR1);
610 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys & 0xffff));
611 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR2);
612 NdisRawWritePortUshort(Adapter->PortOffset + RDP, (USHORT)((ULONG)Adapter->InitializationBlockPhys >> 16) & 0xffff);
613
614 PCNET_DbgPrint(("programmed with init block\n"));
615
616 /* Set mode to 0 */
617 Data = 0;
618 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR15);
619 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
620
621 /* load init block and start the card */
622 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
623 NdisRawWritePortUshort(Adapter->PortOffset + RDP, CSR0_STRT|CSR0_INIT|CSR0_IENA);
624
625 PCNET_DbgPrint(("card started\n"));
626
627 Adapter->Flags &= ~RESET_IN_PROGRESS;
628 }
629
630 \f
631 BOOLEAN
632 MiTestCard(
633 PADAPTER Adapter)
634 /*
635 * FUNCTION: Test the NIC
636 * ARGUMENTS:
637 * Adapter: pointer to the miniport's adapter struct
638 * RETURNS:
639 * TRUE if the test succeeds
640 * FALSE otherwise
641 * NOTES:
642 * - this is where to add diagnostics. This is called
643 * at the very end of initialization.
644 */
645 {
646 int i = 0;
647 UCHAR address[6];
648 USHORT Data = 0;
649
650 /* see if we can read/write now */
651 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
652 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
653 PCNET_DbgPrint(("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));
654
655 /* read the BIA */
656 for(i = 0; i < 6; i++)
657 NdisRawReadPortUchar(Adapter->PortOffset + i, &address[i]);
658
659 PCNET_DbgPrint(("burned-in address: %x:%x:%x:%x:%x:%x\n", address[0], address[1], address[2], address[3], address[4], address[5]));
660 /* Read status flags from CSR0 */
661 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
662 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
663 PCNET_DbgPrint(("CSR0: 0x%x\n", Data));
664
665 /* Read status flags from CSR3 */
666 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR3);
667 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
668
669 PCNET_DbgPrint(("CSR3: 0x%x\n", Data));
670 /* Read status flags from CSR4 */
671 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
672 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
673 PCNET_DbgPrint(("CSR4: 0x%x\n", Data));
674
675 /* Read status flags from CSR5 */
676 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR5);
677 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
678 PCNET_DbgPrint(("CSR5: 0x%x\n", Data));
679
680 /* Read status flags from CSR6 */
681 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR6);
682 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
683 PCNET_DbgPrint(("CSR6: 0x%x\n", Data));
684
685 /* finally, fire a test interrupt to test the ISR */
686 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR4);
687 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
688 Data |= CSR4_UINTCMD;
689 NdisRawWritePortUshort(Adapter->PortOffset + RDP, Data);
690 PCNET_DbgPrint(("just wrote 0x%x to CSR4 for test interrupt\n", Data));
691
692 return TRUE;
693 }
694
695 \f
696 NDIS_STATUS
697 STDCALL
698 MiniportInitialize(
699 OUT PNDIS_STATUS OpenErrorStatus,
700 OUT PUINT SelectedMediumIndex,
701 IN PNDIS_MEDIUM MediumArray,
702 IN UINT MediumArraySize,
703 IN NDIS_HANDLE MiniportAdapterHandle,
704 IN NDIS_HANDLE WrapperConfigurationContext)
705 /*
706 * FUNCTION: Initialize a new miniport
707 * ARGUMENTS:
708 * OpenErrorStatus: pointer to a var to return status info in
709 * SelectedMediumIndex: index of the selected medium (will be NdisMedium802_3)
710 * MediumArray: array of media that we can pick from
711 * MediumArraySize: size of MediumArray
712 * MiniportAdapterHandle: NDIS-assigned handle for this miniport instance
713 * WrapperConfigurationContext: temporary NDIS-assigned handle for passing
714 * to configuration APIs
715 * RETURNS:
716 * NDIS_STATUS_SUCCESS on success
717 * NDIS_STATUS_FAILURE on general failure
718 * NDIS_STATUS_UNSUPPORTED_MEDIA on not finding 802_3 in the MediaArray
719 * NDIS_STATUS_RESOURCES on insufficient system resources
720 * NDIS_STATUS_ADAPTER_NOT_FOUND on not finding the adapter
721 * NOTES:
722 * - Called by NDIS at PASSIVE_LEVEL, once per detected card
723 * - Will int 3 on failure of MiTestCard if DBG=1
724 */
725 {
726 UINT i = 0;
727 PADAPTER Adapter = 0;
728 NDIS_STATUS Status = NDIS_STATUS_FAILURE;
729 BOOLEAN InterruptRegistered = FALSE;
730
731 /* Pick a medium */
732 for(i = 0; i < MediumArraySize; i++)
733 if(MediumArray[i] == NdisMedium802_3)
734 break;
735
736 if(i == MediumArraySize)
737 {
738 Status = NDIS_STATUS_UNSUPPORTED_MEDIA;
739 PCNET_DbgPrint(("unsupported media\n"));
740 BREAKPOINT;
741 *OpenErrorStatus = Status;
742 return Status;
743 }
744
745 *SelectedMediumIndex = i;
746
747 /* allocate our adapter struct */
748 Status = NdisAllocateMemoryWithTag((PVOID *)&Adapter, sizeof(ADAPTER), PCNET_TAG);
749 if(Status != NDIS_STATUS_SUCCESS)
750 {
751 Status = NDIS_STATUS_RESOURCES;
752 PCNET_DbgPrint(("Insufficient resources\n"));
753 BREAKPOINT;
754 *OpenErrorStatus = Status;
755 return Status;
756 }
757
758 memset(Adapter,0,sizeof(ADAPTER));
759
760 Adapter->MiniportAdapterHandle = MiniportAdapterHandle;
761
762 /* register our adapter structwith ndis */
763 NdisMSetAttributesEx(Adapter->MiniportAdapterHandle, Adapter, 0, NDIS_ATTRIBUTE_BUS_MASTER, NdisInterfacePci);
764
765 do
766 {
767 /* get registry config */
768 Status = MiGetConfig(Adapter, WrapperConfigurationContext);
769 if(Status != NDIS_STATUS_SUCCESS)
770 {
771 PCNET_DbgPrint(("MiGetConfig failed\n"));
772 Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
773 BREAKPOINT;
774 break;
775 }
776
777 /* Card-specific detection and setup */
778 Status = MiQueryCard(Adapter);
779 if(Status != NDIS_STATUS_SUCCESS)
780 {
781 PCNET_DbgPrint(("MiQueryCard failed\n"));
782 Status = NDIS_STATUS_ADAPTER_NOT_FOUND;
783 BREAKPOINT;
784 break;
785 }
786
787 /* register an IO port range */
788 Status = NdisMRegisterIoPortRange(&Adapter->PortOffset, Adapter->MiniportAdapterHandle,
789 Adapter->IoBaseAddress, NUMBER_OF_PORTS);
790 if(Status != NDIS_STATUS_SUCCESS)
791 {
792 PCNET_DbgPrint(("NdisMRegisterIoPortRange failed: 0x%x\n", Status));
793 BREAKPOINT
794 break;
795 }
796
797 /* Allocate map registers */
798 Status = NdisMAllocateMapRegisters(Adapter->MiniportAdapterHandle, 0,
799 NDIS_DMA_32BITS, 8, BUFFER_SIZE);
800 if(Status != NDIS_STATUS_SUCCESS)
801 {
802 PCNET_DbgPrint(("NdisMAllocateMapRegisters failed: 0x%x\n", Status));
803 BREAKPOINT
804 break;
805 }
806
807 /* set up the interrupt */
808 memset(&Adapter->InterruptObject, 0, sizeof(NDIS_MINIPORT_INTERRUPT));
809 Status = NdisMRegisterInterrupt(&Adapter->InterruptObject, Adapter->MiniportAdapterHandle, Adapter->InterruptVector,
810 Adapter->InterruptVector, FALSE, TRUE, NdisInterruptLevelSensitive);
811 if(Status != NDIS_STATUS_SUCCESS)
812 {
813 PCNET_DbgPrint(("NdisMRegisterInterrupt failed: 0x%x\n", Status));
814 BREAKPOINT
815 break;
816 }
817
818 InterruptRegistered = TRUE;
819
820 /* Allocate and initialize shared data structures */
821 Status = MiAllocateSharedMemory(Adapter);
822 if(Status != NDIS_STATUS_SUCCESS)
823 {
824 Status = NDIS_STATUS_RESOURCES;
825 PCNET_DbgPrint(("MiAllocateSharedMemory failed", Status));
826 BREAKPOINT
827 break;
828 }
829
830 /* set up the initialization block */
831 MiPrepareInitializationBlock(Adapter);
832
833 PCNET_DbgPrint(("Interrupt registered successfully\n"));
834
835 /* Initialize and start the chip */
836 MiInitChip(Adapter);
837
838 Status = NDIS_STATUS_SUCCESS;
839 }
840 while(0);
841
842 if(Status != NDIS_STATUS_SUCCESS && Adapter)
843 {
844 PCNET_DbgPrint(("Error; freeing stuff\n"));
845
846 NdisMFreeMapRegisters(Adapter->MiniportAdapterHandle); /* doesn't hurt to free if we never alloc'd? */
847
848 if(Adapter->PortOffset)
849 NdisMDeregisterIoPortRange(Adapter->MiniportAdapterHandle, Adapter->IoBaseAddress, NUMBER_OF_PORTS, Adapter->PortOffset);
850
851 if(InterruptRegistered)
852 NdisMDeregisterInterrupt(&Adapter->InterruptObject);
853
854 MiFreeSharedMemory(Adapter);
855
856 NdisFreeMemory(Adapter, 0, 0);
857 }
858
859 #if DBG
860 if(!MiTestCard(Adapter))
861 __asm__("int $3\n");
862 #endif
863
864 PCNET_DbgPrint(("returning 0x%x\n", Status));
865 *OpenErrorStatus = Status;
866 return Status;
867 }
868
869 \f
870 VOID
871 STDCALL
872 MiniportISR(
873 OUT PBOOLEAN InterruptRecognized,
874 OUT PBOOLEAN QueueMiniportHandleInterrupt,
875 IN NDIS_HANDLE MiniportAdapterContext)
876 /*
877 * FUNCTION: Miniport interrupt service routine
878 * ARGUMENTS:
879 * InterruptRecognized: the interrupt was ours
880 * QueueMiniportHandleInterrupt: whether to queue a DPC to handle this interrupt
881 * MiniportAdapterContext: the context originally passed to NdisMSetAttributes
882 * NOTES:
883 * - called by NDIS at DIRQL
884 * - by setting QueueMiniportHandleInterrupt to TRUE, MiniportHandleInterrupt
885 * will be called
886 */
887 {
888 USHORT Data;
889 USHORT Rap;
890 PADAPTER Adapter = (PADAPTER)MiniportAdapterContext;
891
892 PCNET_DbgPrint(("Called\n"));
893
894 /* save the old RAP value */
895 NdisRawReadPortUshort(Adapter->PortOffset + RAP, &Rap);
896
897 /* is this ours? */
898 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
899 NdisRawReadPortUshort(Adapter->PortOffset + RDP, &Data);
900
901 if(!(Data & CSR0_INTR))
902 {
903 PCNET_DbgPrint(("not our interrupt.\n"));
904 *InterruptRecognized = FALSE;
905 *QueueMiniportHandleInterrupt = FALSE;
906 }
907 else
908 {
909 PCNET_DbgPrint(("detected our interrupt\n"));
910
911 /* disable interrupts */
912 NdisRawWritePortUshort(Adapter->PortOffset + RAP, CSR0);
913 NdisRawWritePortUshort(Adapter->PortOffset + RDP, 0);
914
915 *InterruptRecognized = TRUE;
916 *QueueMiniportHandleInterrupt = TRUE;
917 }
918
919 /* restore the rap */
920 NdisRawWritePortUshort(Adapter->PortOffset + RAP, Rap);
921 }
922
923 \f
924 NDIS_STATUS
925 STDCALL
926 MiniportQueryInformation(
927 IN NDIS_HANDLE MiniportAdapterContext,
928 IN NDIS_OID Oid,
929 IN PVOID InformationBuffer,
930 IN ULONG InformationBufferLength,
931 OUT PULONG BytesWritten,
932 OUT PULONG BytesNeeded)
933 /*
934 * FUNCTION: Query an OID from the driver
935 * ARGUMENTS:
936 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
937 * Oid: OID NDIS is querying
938 * InformationBuffer: pointer to buffer into which to write the results of the query
939 * InformationBufferLength: size in bytes of InformationBuffer
940 * BytesWritten: number of bytes written into InformationBuffer in response to the query
941 * BytesNeeded: number of bytes needed to answer the query
942 * RETURNS:
943 * NDIS_STATUS_SUCCESS on all queries
944 * NOTES:
945 * - Called by NDIS at PASSIVE_LEVEL
946 * - If InformationBufferLength is insufficient to store the results, return the amount
947 * needed in BytesNeeded and return NDIS_STATUS_INVALID_LENGTH
948 */
949 {
950 PCNET_DbgPrint(("Called\n"));
951 return NDIS_STATUS_SUCCESS;
952 }
953
954 \f
955 NDIS_STATUS
956 STDCALL
957 MiniportReset(
958 OUT PBOOLEAN AddressingReset,
959 IN NDIS_HANDLE MiniportAdapterContext)
960 /*
961 * FUNCTION: Reset the miniport
962 * ARGUMENTS:
963 * AddressingReset: Whether or not we want NDIS to subsequently call MiniportSetInformation
964 * to reset our addresses and filters
965 * MiniportAdapterContext: context originally passed to NdisMSetAttributes
966 * RETURNS:
967 * NDIS_STATUS_SUCCESS on all requests
968 * Notes:
969 * - Called by NDIS at PASSIVE_LEVEL when it thinks we need a reset
970 */
971 {
972 PCNET_DbgPrint(("Called\n"));
973 return NDIS_STATUS_SUCCESS;
974 }
975
976 \f
977 NDIS_STATUS
978 STDCALL
979 MiniportSetInformation(
980 IN NDIS_HANDLE MiniportAdapterContext,
981 IN NDIS_OID Oid,
982 IN PVOID InformationBuffer,
983 IN ULONG InformationBufferLength,
984 OUT PULONG BytesRead,
985 OUT PULONG BytesNeeded)
986 /*
987 * FUNCTION: Set a miniport variable (OID)
988 * ARGUMENTS:
989 * MiniportAdapterContext: context originally passed into NdisMSetAttributes
990 * Oid: the variable being set
991 * InformationBuffer: the data to set the variable to
992 * InformationBufferLength: number of bytes in InformationBuffer
993 * BytesRead: number of bytes read by us out of the buffer
994 * BytesNeeded: number of bytes required to satisfy the request if InformationBufferLength
995 * is insufficient
996 * RETURNS:
997 * NDIS_STATUS_SUCCESS on all requests
998 * NOTES:
999 * - Called by NDIS at PASSIVE_LEVEL
1000 */
1001 {
1002 PCNET_DbgPrint(("Called\n"));
1003 return NDIS_STATUS_SUCCESS;
1004 }
1005
1006 \f
1007 NDIS_STATUS
1008 STDCALL
1009 MiniportSend(
1010 IN NDIS_HANDLE MiniportAdapterContext,
1011 IN PNDIS_PACKET Packet,
1012 IN UINT Flags)
1013 /*
1014 * FUNCTION: Called by NDIS when it has a packet for the NIC to send out
1015 * ARGUMENTS:
1016 * MiniportAdapterContext: context originally input to NdisMSetAttributes
1017 * Packet: The NDIS_PACKET to be sent
1018 * Flags: Flags associated with Packet
1019 * RETURNS:
1020 * NDIS_STATUS_SUCCESS on all requests
1021 * NOTES:
1022 * - Called by NDIS at DISPATCH_LEVEL
1023 */
1024 {
1025 PCNET_DbgPrint(("Called\n"));
1026 return NDIS_STATUS_SUCCESS;
1027 }
1028
1029 \f
1030 NTSTATUS
1031 STDCALL
1032 DriverEntry(
1033 IN PDRIVER_OBJECT DriverObject,
1034 IN PUNICODE_STRING RegistryPath)
1035 /*
1036 * FUNCTION: Start this driver
1037 * ARGUMENTS:
1038 * DriverObject: Pointer to the system-allocated driver object
1039 * RegistryPath: Pointer to our SCM database entry
1040 * RETURNS:
1041 * NDIS_STATUS_SUCCESS on success
1042 * NDIS_STATUS_FAILURE on failure
1043 * NOTES:
1044 * - Called by the I/O manager when the driver starts at PASSIVE_LEVEL
1045 * - TODO: convert this to NTSTATUS return values
1046 */
1047 {
1048 NDIS_HANDLE WrapperHandle;
1049 NDIS_MINIPORT_CHARACTERISTICS Characteristics;
1050 NDIS_STATUS Status;
1051
1052 memset(&Characteristics, 0, sizeof(Characteristics));
1053 Characteristics.MajorNdisVersion = 4;
1054 Characteristics.HaltHandler = MiniportHalt;
1055 Characteristics.HandleInterruptHandler = MiniportHandleInterrupt;
1056 Characteristics.InitializeHandler = MiniportInitialize;
1057 Characteristics.ISRHandler = MiniportISR;
1058 Characteristics.QueryInformationHandler = MiniportQueryInformation;
1059 Characteristics.ResetHandler = MiniportReset;
1060 Characteristics.SetInformationHandler = MiniportSetInformation;
1061 Characteristics.u1.SendHandler = MiniportSend;
1062
1063 NdisMInitializeWrapper(&WrapperHandle, DriverObject, RegistryPath, 0);
1064
1065 Status = NdisMRegisterMiniport(WrapperHandle, &Characteristics, sizeof(Characteristics));
1066 if(Status != NDIS_STATUS_SUCCESS)
1067 {
1068 NdisTerminateWrapper(WrapperHandle, 0);
1069 return NDIS_STATUS_FAILURE;
1070 }
1071
1072 return NDIS_STATUS_SUCCESS;
1073 }
1074