update for HEAD-2003091401
[reactos.git] / drivers / net / dd / ne2000 / ne2000 / main.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS Novell Eagle 2000 driver
4  * FILE:        ne2000/main.c
5  * PURPOSE:     Driver entry point
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  * REVISIONS:
8  *   CSH 27/08-2000 Created
9  */
10 #include <ne2000.h>
11
12
13 #ifdef DBG
14
15 /* See debug.h for debug/trace constants */
16 ULONG DebugTraceLevel = MIN_TRACE;
17
18 #endif /* DBG */
19
20
21 /* List of supported OIDs */
22 static ULONG MiniportOIDList[] = {
23     OID_GEN_SUPPORTED_LIST,
24     OID_GEN_HARDWARE_STATUS,
25     OID_GEN_MEDIA_SUPPORTED,
26     OID_GEN_MEDIA_IN_USE,
27     OID_GEN_MAXIMUM_LOOKAHEAD,
28     OID_GEN_MAXIMUM_FRAME_SIZE,
29     OID_GEN_LINK_SPEED,
30     OID_GEN_TRANSMIT_BUFFER_SPACE,
31     OID_GEN_RECEIVE_BUFFER_SPACE,
32     OID_GEN_TRANSMIT_BLOCK_SIZE,
33     OID_GEN_RECEIVE_BLOCK_SIZE,
34     OID_GEN_VENDOR_ID,
35     OID_GEN_VENDOR_DESCRIPTION,
36     OID_GEN_VENDOR_DRIVER_VERSION,
37     OID_GEN_CURRENT_PACKET_FILTER,
38     OID_GEN_CURRENT_LOOKAHEAD,
39     OID_GEN_DRIVER_VERSION,
40     OID_GEN_MAXIMUM_TOTAL_SIZE,
41     OID_GEN_PROTOCOL_OPTIONS,
42     OID_GEN_MAC_OPTIONS,
43     OID_GEN_MEDIA_CONNECT_STATUS,
44     OID_GEN_MAXIMUM_SEND_PACKETS,
45     OID_802_3_PERMANENT_ADDRESS,
46     OID_802_3_CURRENT_ADDRESS,
47     OID_802_3_MULTICAST_LIST,
48     OID_802_3_MAXIMUM_LIST_SIZE,
49     OID_802_3_MAC_OPTIONS
50 };
51
52 DRIVER_INFORMATION      DriverInfo = {0};
53 NDIS_PHYSICAL_ADDRESS   HighestAcceptableMax = NDIS_PHYSICAL_ADDRESS_CONST(-1, -1);
54
55
56 BOOLEAN MiniportCheckForHang(
57     IN  NDIS_HANDLE MiniportAdapterContext)
58 /*
59  * FUNCTION: Examines if an adapter has hung
60  * ARGUMENTS:
61  *     MiniportAdapterContext = Pointer to adapter context area
62  * RETURNS:
63  *     TRUE if the adapter has hung, FALSE if not
64  */
65 {
66     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
67
68     return FALSE;
69 }
70
71
72 VOID MiniportDisableInterrupt(
73     IN  NDIS_HANDLE MiniportAdapterContext)
74 /*
75  * FUNCTION: Disables interrupts from an adapter
76  * ARGUMENTS:
77  *     MiniportAdapterContext = Pointer to adapter context area
78  */
79 {
80     NDIS_DbgPrint(MAX_TRACE, ("Called. (MiniportDisableInterrupt).\n"));
81 #ifndef NOCARD
82     NICDisableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
83 #endif
84 }
85
86
87 VOID MiniportEnableInterrupt(
88     IN  NDIS_HANDLE MiniportAdapterContext)
89 /*
90  * FUNCTION: Enables interrupts from an adapter
91  * ARGUMENTS:
92  *     MiniportAdapterContext = Pointer to adapter context area
93  */
94 {
95     NDIS_DbgPrint(MAX_TRACE, ("Called. (MiniportEnableInterrupt).\n"));
96 #ifndef NOCARD
97     NICEnableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
98 #endif
99 }
100
101
102 VOID MiniportHalt(
103     IN  NDIS_HANDLE MiniportAdapterContext)
104 /*
105  * FUNCTION: Deallocates resources for and halts an adapter
106  * ARGUMENTS:
107  *     MiniportAdapterContext = Pointer to adapter context area
108  */
109 {
110     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
111
112     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
113 #ifndef NOCARD
114     /* Stop the NIC */
115     NICStop(Adapter);
116 #endif
117     /* Wait for any DPCs to complete. FIXME: Use something else */
118     NdisStallExecution(250000);
119
120     if (Adapter->InterruptRegistered)
121         /* Deregister interrupt */
122         NdisMDeregisterInterrupt(&Adapter->Interrupt);
123
124     if (Adapter->IOPortRangeRegistered)
125         /* Deregister I/O port range */
126         NdisMDeregisterIoPortRange(
127             Adapter->MiniportAdapterHandle,
128             Adapter->IoBaseAddress,
129             0x20,
130             Adapter->IOBase);
131
132     /* Remove adapter from global adapter list */
133     if ((&Adapter->ListEntry)->Blink != NULL) {
134         RemoveEntryList(&Adapter->ListEntry);
135         }
136
137     /* Free adapter context area */
138     NdisFreeMemory(Adapter, sizeof(NIC_ADAPTER), 0);
139 }
140
141
142 NDIS_STATUS MiniportInitialize(
143     OUT PNDIS_STATUS    OpenErrorStatus,
144     OUT PUINT           SelectedMediumIndex,
145     IN  PNDIS_MEDIUM    MediumArray,
146     IN  UINT            MediumArraySize,
147     IN  NDIS_HANDLE     MiniportAdapterHandle,
148     IN  NDIS_HANDLE     WrapperConfigurationContext)
149 /*
150  * FUNCTION: Adapter initialization function
151  * ARGUMENTS:
152  *     OpenErrorStatus             = Address of buffer to place additional status information
153  *     SelectedMediumIndex         = Address of buffer to place selected medium index
154  *     MediumArray                 = Pointer to an array of NDIS_MEDIUMs
155  *     MediaArraySize              = Number of elements in MediumArray
156  *     MiniportAdapterHandle       = Miniport adapter handle assigned by NDIS
157  *     WrapperConfigurationContext = Handle used to identify configuration context
158  * RETURNS:
159  *     Status of operation
160  */
161 {
162     UINT i;
163     NDIS_STATUS Status;
164     PNIC_ADAPTER Adapter;
165
166     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
167
168     /* Search for 802.3 media which is the only one we support */
169     for (i = 0; i < MediumArraySize; i++) {
170         if (MediumArray[i] == NdisMedium802_3)
171             break;
172     }
173
174     if (i == MediumArraySize) {
175         NDIS_DbgPrint(MIN_TRACE, ("No supported media.\n"));
176         return NDIS_STATUS_UNSUPPORTED_MEDIA;
177     }
178
179     *SelectedMediumIndex = i;
180
181     Status = NdisAllocateMemory((PVOID)&Adapter,
182                                 sizeof(NIC_ADAPTER),
183                                 0,
184                                 HighestAcceptableMax);
185     if (Status != NDIS_STATUS_SUCCESS) {
186         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
187         return Status;
188     }
189
190     NdisZeroMemory(Adapter, sizeof(NIC_ADAPTER));
191     Adapter->MiniportAdapterHandle  = MiniportAdapterHandle;
192     Adapter->IoBaseAddress          = DRIVER_DEFAULT_IO_BASE_ADDRESS;
193     Adapter->InterruptNumber        = DRIVER_DEFAULT_INTERRUPT_NUMBER;
194     Adapter->MaxMulticastListSize   = DRIVER_MAX_MULTICAST_LIST_SIZE;
195     Adapter->InterruptMask          = DRIVER_INTERRUPT_MASK;
196     Adapter->LookaheadSize          = DRIVER_MAXIMUM_LOOKAHEAD;
197
198      /* get the port, irq, and MAC address from registry */
199     do
200     {
201         PNDIS_CONFIGURATION_PARAMETER ConfigurationParameter;
202         NDIS_HANDLE ConfigurationHandle;
203         UNICODE_STRING Keyword;
204         UINT *RegNetworkAddress = 0;
205         UINT RegNetworkAddressLength = 0;
206
207         NdisOpenConfiguration(&Status, &ConfigurationHandle, WrapperConfigurationContext);
208         if(Status != NDIS_STATUS_SUCCESS)
209         {
210             NDIS_DbgPrint(MIN_TRACE,("NdisOpenConfiguration returned error 0x%x\n", Status));
211             break;
212         }
213
214         NdisInitUnicodeString(&Keyword, L"Irq");
215         NdisReadConfiguration(&Status, &ConfigurationParameter, ConfigurationHandle, &Keyword, NdisParameterInteger);
216         if(Status == NDIS_STATUS_SUCCESS)
217         {
218             NDIS_DbgPrint(MID_TRACE,("NdisReadConfiguration for Irq returned successfully, irq 0x%x\n",
219                     ConfigurationParameter->ParameterData.IntegerData));
220             Adapter->InterruptNumber = ConfigurationParameter->ParameterData.IntegerData;
221         }
222
223         NdisInitUnicodeString(&Keyword, L"Port");
224         NdisReadConfiguration(&Status, &ConfigurationParameter, ConfigurationHandle, &Keyword, NdisParameterInteger);
225         if(Status == NDIS_STATUS_SUCCESS)
226         {
227             NDIS_DbgPrint(MID_TRACE,("NdisReadConfiguration for Port returned successfully, port 0x%x\n",
228                     ConfigurationParameter->ParameterData.IntegerData));
229             Adapter->IoBaseAddress = ConfigurationParameter->ParameterData.IntegerData;
230         }
231
232         /* the returned copy of the data is owned by NDIS and will be released on NdisCloseConfiguration */
233         NdisReadNetworkAddress(&Status, (PVOID *)&RegNetworkAddress, &RegNetworkAddressLength, ConfigurationHandle);
234         if(Status == NDIS_STATUS_SUCCESS && RegNetworkAddressLength == DRIVER_LENGTH_OF_ADDRESS)
235         {
236             int i;
237             NDIS_DbgPrint(MID_TRACE,("NdisReadNetworkAddress returned successfully, address %x:%x:%x:%x:%x:%x\n",
238                     RegNetworkAddress[0], RegNetworkAddress[1], RegNetworkAddress[2], RegNetworkAddress[3],
239                     RegNetworkAddress[4], RegNetworkAddress[5]));
240             for(i = 0; i < DRIVER_LENGTH_OF_ADDRESS; i++)
241                 Adapter->StationAddress[i] = RegNetworkAddress[i];
242         }
243
244         NdisCloseConfiguration(ConfigurationHandle);
245     } while(0);
246
247      /* find the nic */
248     if (!NICCheck(Adapter)) {
249         NDIS_DbgPrint(MID_TRACE, ("No adapter found at (0x%X).\n", Adapter->IOBase));
250         return NDIS_STATUS_ADAPTER_NOT_FOUND;
251     } else
252         NDIS_DbgPrint(MID_TRACE, ("Adapter found at (0x%X).\n", Adapter->IOBase));
253
254
255     NdisMSetAttributes(
256         MiniportAdapterHandle,
257         (NDIS_HANDLE)Adapter,
258         FALSE,
259         NdisInterfaceIsa);
260
261     Status = NdisMRegisterIoPortRange(
262         (PVOID*)&Adapter->IOBase,
263         MiniportAdapterHandle,
264         Adapter->IoBaseAddress,
265         0x20);
266
267     if (Status != NDIS_STATUS_SUCCESS) {
268         NDIS_DbgPrint(MIN_TRACE, ("Cannot register port range. Status (0x%X).\n", Status));
269         MiniportHalt((NDIS_HANDLE)Adapter);
270         return Status;
271     }
272
273     Adapter->IOPortRangeRegistered = TRUE;
274
275     /* Initialize NIC */
276 #ifndef NOCARD
277     Status = NICInitialize(Adapter);
278     if (Status != NDIS_STATUS_SUCCESS) {
279         NDIS_DbgPrint(MIN_TRACE,("No NE2000 or compatible network adapter found at address 0x%X.\n",
280             Adapter->IOBase));
281
282         NDIS_DbgPrint(MID_TRACE, ("Status (0x%X).\n", Status));
283         MiniportHalt((NDIS_HANDLE)Adapter);
284         return Status;
285     }
286
287     NDIS_DbgPrint(MID_TRACE, ("BOARDDATA:\n"));
288     for (i = 0; i < 4; i++) {
289         NDIS_DbgPrint(MID_TRACE, ("%02X %02X %02X %02X\n",
290             Adapter->SAPROM[i*4+0],
291             Adapter->SAPROM[i*4+1],
292             Adapter->SAPROM[i*4+2],
293             Adapter->SAPROM[i*4+3]));
294     }
295
296     /* Setup adapter structure */
297     Adapter->TXStart   = ((ULONG_PTR)Adapter->RamBase >> 8);
298     Adapter->TXCount   = DRIVER_DEFAULT_TX_BUFFER_COUNT;
299     Adapter->TXFree    = DRIVER_DEFAULT_TX_BUFFER_COUNT;
300     Adapter->TXCurrent = -1;
301     Adapter->PageStart = Adapter->TXStart + Adapter->TXCount;
302     Adapter->PageStop  = Adapter->TXStart + (Adapter->RamSize >> 8);
303
304     /* Initialize multicast address mask to accept all */
305     for (i = 0; i < 8; i++)
306         Adapter->MulticastAddressMask[i] = 0xFF;
307
308     /* Setup the NIC */
309     NICSetup(Adapter);
310
311     NDIS_DbgPrint(MID_TRACE, ("TXStart (0x%X)  TXCount (0x%X)  PageStart (0x%X)\n",
312         Adapter->TXStart,
313         Adapter->TXCount,
314         Adapter->PageStart));
315
316     NDIS_DbgPrint(MID_TRACE, ("PageStop (0x%X)  CurrentPage (0x%X)  NextPacket (0x%X).\n",
317         Adapter->PageStop,
318         Adapter->CurrentPage,
319         Adapter->NextPacket));
320 #endif
321     /* Register the interrupt */
322     Status = NdisMRegisterInterrupt(
323         &Adapter->Interrupt,
324         MiniportAdapterHandle,
325         Adapter->InterruptNumber,
326         Adapter->InterruptNumber,
327         FALSE,
328         FALSE,
329         NdisInterruptLatched);
330     if (Status != NDIS_STATUS_SUCCESS) {
331         NDIS_DbgPrint(MIN_TRACE, ("Cannot register interrupt. Status (0x%X).\n", Status));
332         MiniportHalt((NDIS_HANDLE)Adapter);
333         return Status;
334     }
335
336     Adapter->InterruptRegistered = TRUE;
337 #ifndef NOCARD
338     /* Start the NIC */
339     NICStart(Adapter);
340 #endif
341     /* Add adapter to the global adapter list */
342     InsertTailList(&DriverInfo.AdapterListHead, &Adapter->ListEntry);
343
344     NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
345
346     return NDIS_STATUS_SUCCESS;
347 }
348
349
350 VOID MiniportISR(
351     OUT PBOOLEAN    InterruptRecognized,
352     OUT PBOOLEAN    QueueMiniportHandleInterrupt,
353     IN  NDIS_HANDLE MiniportAdapterContext)
354 /*
355  * FUNCTION: Interrupt Service Routine for controlled adapters
356  * ARGUMENTS:
357  *     InterruptRecognized          = Address of buffer to place wether
358  *                                    the adapter generated the interrupt
359  *     QueueMiniportHandleInterrupt = Address of buffer to place wether
360  *                                    MiniportHandleInterrupt should be called
361  *     MiniportAdapterContext       = Pointer to adapter context area
362  * NOTES:
363  *     All pending interrupts are handled
364  */
365 {
366     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
367
368     NICDisableInterrupts((PNIC_ADAPTER)MiniportAdapterContext);
369
370     *InterruptRecognized          = TRUE;
371     *QueueMiniportHandleInterrupt = TRUE;
372 }
373
374
375 NDIS_STATUS MiniportQueryInformation(
376     IN  NDIS_HANDLE MiniportAdapterContext,
377     IN  NDIS_OID    Oid,
378     IN  PVOID       InformationBuffer,
379     IN  ULONG       InformationBufferLength,
380     OUT PULONG      BytesWritten,
381     OUT PULONG      BytesNeeded)
382 /*
383  * FUNCTION: Handler to process queries
384  * ARGUMENTS:
385  *     MiniportAdapterContext  = Pointer to adapter context area
386  *     Oid                     = OID code designating query operation
387  *     InformationBuffer       = Address of return buffer
388  *     InformationBufferLength = Length of return buffer
389  *     BytesWritten            = Address of buffer to place number of bytes returned
390  *     BytesNeeded             = Address of buffer to place number of bytes needed
391  *                               in InformationBuffer for specified OID
392  * RETURNS:
393  *     Status of operation
394  */
395 {
396     NDIS_STATUS Status;
397     PVOID CopyFrom;
398     UINT CopySize;
399     ULONG GenericULONG;
400     USHORT GenericUSHORT;
401     NDIS_MEDIUM Medium   = NdisMedium802_3;
402     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
403
404     NDIS_DbgPrint(MAX_TRACE, ("Called. Oid (0x%X).\n", Oid));
405
406     Status   = NDIS_STATUS_SUCCESS;
407     CopyFrom = (PVOID)&GenericULONG;
408     CopySize = sizeof(ULONG);
409
410     switch (Oid) {
411     case OID_GEN_SUPPORTED_LIST:
412         CopyFrom = (PVOID)&MiniportOIDList;
413         CopySize = sizeof(MiniportOIDList);
414         break;
415     case OID_GEN_HARDWARE_STATUS:
416         GenericULONG = (ULONG)NdisHardwareStatusReady;
417         break;
418     case OID_GEN_MEDIA_SUPPORTED:
419     case OID_GEN_MEDIA_IN_USE:
420         CopyFrom = (PVOID)&Medium;
421         CopySize = sizeof(NDIS_MEDIUM);
422         break;
423     case OID_GEN_MAXIMUM_LOOKAHEAD:
424         GenericULONG = DRIVER_MAXIMUM_LOOKAHEAD;
425         break;
426     case OID_GEN_MAXIMUM_FRAME_SIZE:
427         GenericULONG = DRIVER_FRAME_SIZE - DRIVER_HEADER_SIZE;
428         break;
429     case OID_GEN_LINK_SPEED:
430         GenericULONG = 100000;  /* 10Mbps */
431         break;
432     case OID_GEN_TRANSMIT_BUFFER_SPACE:
433         GenericULONG = Adapter->TXCount * DRIVER_BLOCK_SIZE;
434         break;
435     case OID_GEN_RECEIVE_BUFFER_SPACE:
436         GenericULONG = Adapter->RamSize -
437                        (ULONG_PTR)Adapter->RamBase -
438                        (Adapter->TXCount * DRIVER_BLOCK_SIZE);
439         break;
440     case OID_GEN_TRANSMIT_BLOCK_SIZE:
441         GenericULONG = DRIVER_BLOCK_SIZE;
442         break;
443     case OID_GEN_RECEIVE_BLOCK_SIZE:
444         GenericULONG = DRIVER_BLOCK_SIZE;
445         break;
446     case OID_GEN_VENDOR_ID:
447         NdisMoveMemory(&GenericULONG, &Adapter->PermanentAddress, 3);
448         GenericULONG &= 0xFFFFFF00;
449         GenericULONG |= 0x01;
450         break;
451     case OID_GEN_VENDOR_DESCRIPTION:
452         CopyFrom = (PVOID)&DRIVER_VENDOR_DESCRIPTION;
453         CopySize = sizeof(DRIVER_VENDOR_DESCRIPTION);
454         break;
455     case OID_GEN_VENDOR_DRIVER_VERSION:
456         GenericUSHORT = (USHORT)DRIVER_VENDOR_DRIVER_VERSION;
457         CopyFrom      = (PVOID)&GenericUSHORT;
458         CopySize      = sizeof(USHORT);
459         break;
460     case OID_GEN_CURRENT_PACKET_FILTER:
461         GenericULONG = Adapter->PacketFilter;
462         break;
463     case OID_GEN_CURRENT_LOOKAHEAD:
464         GenericULONG = Adapter->LookaheadSize;
465         break;
466     case OID_GEN_DRIVER_VERSION:
467         GenericUSHORT = ((USHORT)DRIVER_NDIS_MAJOR_VERSION << 8) | DRIVER_NDIS_MINOR_VERSION;
468         CopyFrom      = (PVOID)&GenericUSHORT;
469         CopySize      = sizeof(USHORT);
470         break;
471     case OID_GEN_MAXIMUM_TOTAL_SIZE:
472         GenericULONG = DRIVER_FRAME_SIZE;
473         break;
474     case OID_GEN_PROTOCOL_OPTIONS:
475         NDIS_DbgPrint(MID_TRACE, ("OID_GEN_PROTOCOL_OPTIONS.\n"));
476         Status = NDIS_STATUS_NOT_SUPPORTED;
477         break;
478     case OID_GEN_MAC_OPTIONS:
479         GenericULONG = NDIS_MAC_OPTION_COPY_LOOKAHEAD_DATA |
480                        NDIS_MAC_OPTION_RECEIVE_SERIALIZED  |           
481                        NDIS_MAC_OPTION_TRANSFERS_NOT_PEND  |
482                        NDIS_MAC_OPTION_NO_LOOPBACK;
483         break;
484     case OID_GEN_MEDIA_CONNECT_STATUS:
485         GenericULONG = (ULONG)NdisMediaStateConnected;
486         break;
487     case OID_GEN_MAXIMUM_SEND_PACKETS:
488         GenericULONG = 1;
489         break;
490     case OID_802_3_PERMANENT_ADDRESS:
491         CopyFrom = (PVOID)&Adapter->PermanentAddress;
492         CopySize = DRIVER_LENGTH_OF_ADDRESS;
493         break;
494     case OID_802_3_CURRENT_ADDRESS:
495         CopyFrom = (PVOID)&Adapter->StationAddress;
496         CopySize = DRIVER_LENGTH_OF_ADDRESS;
497         break;
498     case OID_802_3_MULTICAST_LIST:
499         NDIS_DbgPrint(MID_TRACE, ("OID_802_3_MULTICAST_LIST.\n"));
500         Status = NDIS_STATUS_NOT_SUPPORTED;
501         break;
502     case OID_802_3_MAXIMUM_LIST_SIZE:
503         GenericULONG = Adapter->MaxMulticastListSize;
504         break;
505     case OID_802_3_MAC_OPTIONS:
506         NDIS_DbgPrint(MID_TRACE, ("OID_802_3_MAC_OPTIONS.\n"));
507         Status = NDIS_STATUS_NOT_SUPPORTED;
508         break;
509     default:
510         NDIS_DbgPrint(MIN_TRACE, ("Unknown OID (0x%X).\n", Oid));
511         Status = NDIS_STATUS_INVALID_OID;
512         break;
513     }
514
515     if (Status == NDIS_STATUS_SUCCESS) {
516         if (CopySize > InformationBufferLength) {
517             *BytesNeeded  = (CopySize - InformationBufferLength);
518             *BytesWritten = 0;
519             Status        = NDIS_STATUS_INVALID_LENGTH;
520         } else {
521             NdisMoveMemory(InformationBuffer, CopyFrom, CopySize);
522             *BytesWritten = CopySize;
523             *BytesNeeded  = 0;
524          }
525     }
526
527     NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status is (0x%X).\n", Status));
528
529     return Status;
530 }
531
532
533 NDIS_STATUS MiniportReconfigure(
534     OUT PNDIS_STATUS    OpenErrorStatus,
535     IN  NDIS_HANDLE     MiniportAdapterContext,
536     IN  NDIS_HANDLE     WrapperConfigurationContext)
537 /*
538  * FUNCTION: Reconfigures an adapter
539  * ARGUMENTS:
540  *     OpenErrorStatus             = Address of buffer to place additional status information
541  *     MiniportAdapterContext      = Pointer to adapter context area
542  *     WrapperConfigurationContext = Handle used to identify configuration context
543  * RETURNS:
544  *     Status of operation
545  * NOTES:
546  *     Never called by NDIS library
547  */
548 {
549     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
550
551     return NDIS_STATUS_FAILURE;
552 }
553
554
555
556 NDIS_STATUS MiniportReset(
557     OUT PBOOLEAN    AddressingReset,
558     IN  NDIS_HANDLE MiniportAdapterContext)
559 /*
560  * FUNCTION: Resets an adapter
561  * ARGUMENTS:
562  *     AddressingReset        = Address of a buffer to place value indicating
563  *                              wether NDIS library should call MiniportSetInformation
564  *                              to restore addressing information
565  *     MiniportAdapterContext = Pointer to adapter context area
566  * RETURNS:
567  *     Status of operation
568  */
569 {
570     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
571
572     return NDIS_STATUS_FAILURE;
573 }
574
575
576 NDIS_STATUS MiniportSend(
577     IN  NDIS_HANDLE     MiniportAdapterContext,
578     IN  PNDIS_PACKET    Packet,
579     IN  UINT            Flags)
580 /*
581  * FUNCTION: Transmits a packet
582  * ARGUMENTS:
583  *     MiniportAdapterContext = Pointer to adapter context area
584  *     Packet                 = Pointer to a packet descriptor specifying
585  *                              the data to be transmitted
586  *     Flags                  = Specifies optional packet flags
587  * RETURNS:
588  *     Status of operation
589  */
590 {
591     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
592
593     NDIS_DbgPrint(MID_TRACE, ("Queueing packet.\n"));
594
595 #ifdef NOCARD
596     NdisMSendComplete(Adapter->MiniportAdapterHandle,
597                       Packet,
598                       NDIS_STATUS_SUCCESS);
599 #else
600     /* Queue the packet on the transmit queue */
601     RESERVED(Packet)->Next = NULL;
602     if (Adapter->TXQueueHead == NULL) {
603         Adapter->TXQueueHead = Packet;
604     } else {
605         RESERVED(Adapter->TXQueueTail)->Next = Packet;
606     }
607
608     Adapter->TXQueueTail = Packet;
609
610     /* Transmit the packet */
611     NICTransmit(Adapter);
612 #endif
613     return NDIS_STATUS_PENDING;
614 }
615
616
617 NDIS_STATUS MiniportSetInformation(
618     IN  NDIS_HANDLE MiniportAdapterContext,
619     IN  NDIS_OID    Oid,
620     IN  PVOID       InformationBuffer,
621     IN  ULONG       InformationBufferLength,
622     OUT PULONG      BytesRead,
623     OUT PULONG      BytesNeeded)
624 /*
625  * FUNCTION: Changes state information in the driver
626  * ARGUMENTS:
627  *     MiniportAdapterContext  = Pointer to adapter context area
628  *     Oid                     = OID code designating set operation
629  *     InformationBuffer       = Pointer to buffer with state information
630  *     InformationBufferLength = Length of InformationBuffer
631  *     BytesRead               = Address of buffer to place number of bytes read
632  *     BytesNeeded             = Address of buffer to place number of extra bytes
633  *                               needed in InformationBuffer for specified OID
634  * RETURNS:
635  *     Status of operation
636  */
637 {
638     ULONG GenericULONG;
639     NDIS_STATUS Status   = NDIS_STATUS_SUCCESS;
640     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
641
642     NDIS_DbgPrint(MAX_TRACE, ("Called. Oid (0x%X).\n", Oid));
643
644     switch (Oid) {
645     case OID_GEN_CURRENT_PACKET_FILTER:
646         /* Verify length */
647         if (InformationBufferLength < sizeof(ULONG)) {
648             *BytesRead   = 0;
649             *BytesNeeded = sizeof(ULONG) - InformationBufferLength;
650             Status       = NDIS_STATUS_INVALID_LENGTH;
651             break;
652         }
653
654         NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
655         /* Check for properties the driver don't support */
656         if (GenericULONG &
657            (NDIS_PACKET_TYPE_ALL_FUNCTIONAL |
658             NDIS_PACKET_TYPE_FUNCTIONAL     |
659             NDIS_PACKET_TYPE_GROUP          |
660             NDIS_PACKET_TYPE_MAC_FRAME      |
661             NDIS_PACKET_TYPE_SMT            |
662             NDIS_PACKET_TYPE_SOURCE_ROUTING)) {
663             *BytesRead   = 4;
664             *BytesNeeded = 0;
665             Status       = NDIS_STATUS_NOT_SUPPORTED;
666             break;
667         }
668             
669         Adapter->PacketFilter = GenericULONG;
670
671         /* FIXME: Set filter on hardware */
672
673         break;
674     case OID_GEN_CURRENT_LOOKAHEAD:
675         /* Verify length */
676         if (InformationBufferLength < sizeof(ULONG)) {
677             *BytesRead   = 0;
678             *BytesNeeded = sizeof(ULONG) - InformationBufferLength;
679             Status = NDIS_STATUS_INVALID_LENGTH;
680             break;
681         }
682
683         NdisMoveMemory(&GenericULONG, InformationBuffer, sizeof(ULONG));
684         if (GenericULONG > DRIVER_MAXIMUM_LOOKAHEAD)
685             Status = NDIS_STATUS_INVALID_LENGTH;
686         else
687             Adapter->LookaheadSize = GenericULONG;
688         break;
689     case OID_802_3_MULTICAST_LIST:
690         /* Verify length. Must be multiplum of hardware address length */
691         if ((InformationBufferLength % DRIVER_LENGTH_OF_ADDRESS) != 0) {
692             *BytesRead   = 0;
693             *BytesNeeded = 0;
694             Status       = NDIS_STATUS_INVALID_LENGTH;
695             break;
696         }
697
698         /* Set new multicast address list */
699         NdisMoveMemory(Adapter->Addresses, InformationBuffer, InformationBufferLength);
700
701         /* FIXME: Update hardware */
702
703         break;
704     default:
705         NDIS_DbgPrint(MIN_TRACE, ("Invalid object ID (0x%X).\n", Oid));
706         *BytesRead   = 0;
707         *BytesNeeded = 0;
708         Status       = NDIS_STATUS_INVALID_OID;
709         break;
710     }
711
712     if (Status == NDIS_STATUS_SUCCESS) {
713         *BytesRead   = InformationBufferLength;
714         *BytesNeeded = 0;
715     }
716
717     NDIS_DbgPrint(MAX_TRACE, ("Leaving. Status (0x%X).\n", Status));
718
719     return Status;
720 }
721
722
723 NDIS_STATUS MiniportTransferData(
724     OUT PNDIS_PACKET    Packet,
725     OUT PUINT           BytesTransferred,
726     IN  NDIS_HANDLE     MiniportAdapterContext,
727     IN  NDIS_HANDLE     MiniportReceiveContext,
728     IN  UINT            ByteOffset,
729     IN  UINT            BytesToTransfer)
730 /*
731  * FUNCTION: Transfers data from a received frame into an NDIS packet
732  * ARGUMENTS:
733  *     Packet                 = Address of packet to copy received data into
734  *     BytesTransferred       = Address of buffer to place number of bytes transmitted
735  *     MiniportAdapterContext = Pointer to adapter context area
736  *     MiniportReceiveContext = Pointer to receive context area (actually NULL)
737  *     ByteOffset             = Offset within received packet to begin copying
738  *     BytesToTransfer        = Number of bytes to copy into packet
739  * RETURNS:
740  *     Status of operation
741  */
742 {
743     PNDIS_BUFFER DstBuffer;
744     UINT BytesCopied, BytesToCopy, DstSize;
745     ULONG SrcData;
746     PUCHAR DstData;
747     UINT RecvStart;
748     UINT RecvStop;
749     PNIC_ADAPTER Adapter = (PNIC_ADAPTER)MiniportAdapterContext;
750
751     NDIS_DbgPrint(MAX_TRACE, ("Called. Packet (0x%X)  ByteOffset (0x%X)  BytesToTransfer (%d).\n",
752         Packet, ByteOffset, BytesToTransfer));
753
754     if (BytesToTransfer == 0) {
755         *BytesTransferred = 0;
756         return NDIS_STATUS_SUCCESS;
757     }
758
759     RecvStart = Adapter->PageStart * DRIVER_BLOCK_SIZE;
760     RecvStop  = Adapter->PageStop  * DRIVER_BLOCK_SIZE;
761
762     NdisQueryPacket(Packet, NULL, NULL, &DstBuffer, NULL);
763     NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
764
765     SrcData = Adapter->PacketOffset + sizeof(PACKET_HEADER) + ByteOffset;
766     if (ByteOffset + sizeof(PACKET_HEADER) + BytesToTransfer > Adapter->PacketHeader.PacketLength)
767         BytesToTransfer = Adapter->PacketHeader.PacketLength- sizeof(PACKET_HEADER) - ByteOffset;
768
769     /* Start copying the data */
770     BytesCopied = 0;
771     for (;;) {
772         BytesToCopy = (DstSize < BytesToTransfer)? DstSize : BytesToTransfer;
773         if (SrcData + BytesToCopy > RecvStop)
774             BytesToCopy = (RecvStop - SrcData);
775
776         NICReadData(Adapter, DstData, SrcData, BytesToCopy);
777
778         BytesCopied        += BytesToCopy;
779         SrcData            += BytesToCopy;
780         (ULONG_PTR)DstData += BytesToCopy;
781         BytesToTransfer    -= BytesToCopy;
782         if (BytesToTransfer == 0)
783             break;
784
785         DstSize -= BytesToCopy;
786         if (DstSize == 0) {
787             /* No more bytes in destination buffer. Proceed to
788                the next buffer in the destination buffer chain */
789             NdisGetNextBuffer(DstBuffer, &DstBuffer);
790             if (!DstBuffer)
791                 break;
792
793             NdisQueryBuffer(DstBuffer, (PVOID)&DstData, &DstSize);
794         }
795
796         if (SrcData == RecvStop)
797             SrcData = RecvStart;
798     }
799
800     NDIS_DbgPrint(MID_TRACE, ("Transferred (%d) bytes.\n", BytesToTransfer));
801
802     *BytesTransferred = BytesCopied;
803
804     return NDIS_STATUS_SUCCESS;
805 }
806
807
808 NTSTATUS
809 #ifndef _MSC_VER
810 STDCALL
811 #endif
812 DriverEntry(
813     PDRIVER_OBJECT DriverObject,
814     PUNICODE_STRING RegistryPath)
815 /*
816  * FUNCTION: Main driver entry point
817  * ARGUMENTS:
818  *     DriverObject = Pointer to a driver object for this driver
819  *     RegistryPath = Registry node for configuration parameters
820  * RETURNS:
821  *     Status of driver initialization
822  */
823 {
824     NDIS_STATUS Status;
825     NDIS_HANDLE NdisWrapperHandle;
826     NDIS_MINIPORT_CHARACTERISTICS Miniport;
827
828     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
829
830     NdisZeroMemory(&Miniport, sizeof(Miniport));
831     Miniport.MajorNdisVersion           = DRIVER_NDIS_MAJOR_VERSION;
832     Miniport.MinorNdisVersion           = DRIVER_NDIS_MINOR_VERSION;
833     Miniport.CheckForHangHandler        = NULL; //MiniportCheckForHang;
834     Miniport.DisableInterruptHandler    = MiniportDisableInterrupt;
835     Miniport.EnableInterruptHandler     = MiniportEnableInterrupt;
836     Miniport.HaltHandler                = MiniportHalt;
837     Miniport.HandleInterruptHandler     = MiniportHandleInterrupt;
838     Miniport.InitializeHandler          = MiniportInitialize;
839     Miniport.ISRHandler                 = MiniportISR;
840     Miniport.QueryInformationHandler    = MiniportQueryInformation;
841     Miniport.ReconfigureHandler         = MiniportReconfigure;
842     Miniport.ResetHandler               = MiniportReset;
843     Miniport.u1.SendHandler             = MiniportSend;
844     Miniport.SetInformationHandler      = MiniportSetInformation;
845     Miniport.u2.TransferDataHandler     = MiniportTransferData;
846
847     NdisMInitializeWrapper(&NdisWrapperHandle,
848                            DriverObject,
849                            RegistryPath,
850                            NULL);
851
852     DriverInfo.NdisWrapperHandle = NdisWrapperHandle;
853     DriverInfo.NdisMacHandle     = NULL;
854     InitializeListHead(&DriverInfo.AdapterListHead);
855
856     Status = NdisMRegisterMiniport(NdisWrapperHandle,
857                                    &Miniport,
858                                    sizeof(NDIS_MINIPORT_CHARACTERISTICS));
859     if (Status != NDIS_STATUS_SUCCESS) {
860         NDIS_DbgPrint(MIN_TRACE, ("NdisMRegisterMiniport() failed with status code (0x%X).\n", Status));
861         NdisTerminateWrapper(NdisWrapperHandle, NULL);
862         return STATUS_UNSUCCESSFUL;
863     }
864
865     return STATUS_SUCCESS;
866 }
867
868 #if 0
869         /* while i'm here - some basic registry sanity checks */
870         {
871             /* write tests */
872             NDIS_CONFIGURATION_PARAMETER ParameterValue;
873
874             ParameterValue.ParameterType = NdisParameterInteger;
875             ParameterValue.ParameterData.IntegerData = 0x12345678;
876             NdisInitUnicodeString(&Keyword, L"DwordTest");
877             NdisWriteConfiguration(&Status, ConfigurationHandle, &Keyword, &ParameterValue);
878
879             if(Status != NDIS_STATUS_SUCCESS)
880             {
881                 DbgPrint("ne2000!MiniportInitialize: failed to set DwordTest: 0x%x\n", Status);
882                 KeBugCheck(0);
883             }
884             
885             DbgPrint("ne2000!MiniportInitialize: DwordTest successfully set\n");
886             
887             NdisInitUnicodeString(&Keyword, L"StringTest");
888             ParameterValue.ParameterType = NdisParameterString;
889             NdisInitUnicodeString(&ParameterValue.ParameterData.StringData, L"Testing123");
890
891             NdisWriteConfiguration(&Status, ConfigurationHandle, &Keyword, &ParameterValue);
892
893             if(Status != NDIS_STATUS_SUCCESS)
894             {
895                 DbgPrint("ne2000!MiniportInitialize: failed to set StringTest: 0x%x\n", Status);
896                 KeBugCheck(0);
897             }
898             
899             DbgPrint("ne2000!MiniportInitialize: StringTest successfully set\n");
900         }
901
902         {
903             /* read back the test values */
904             NDIS_CONFIGURATION_PARAMETER *ParameterValue = 0;
905
906             NdisInitUnicodeString(&Keyword, L"DwordTest");
907             NdisReadConfiguration(&Status, &ParameterValue, ConfigurationHandle, &Keyword, NdisParameterInteger);
908
909             if(Status != NDIS_STATUS_SUCCESS)
910             {
911                 DbgPrint("ne2000!MiniportInitialize: failed to read DwordTest: 0x%x\n", Status);
912                 KeBugCheck(0);
913             }
914
915             if(ParameterValue->ParameterData.IntegerData != 0x12345678)
916             {
917                 DbgPrint("ne2000!MiniportInitialize: DwordTest value is wrong: 0x%x\n",
918                     ParameterValue->ParameterData.IntegerData);
919                 KeBugCheck(0);
920             }
921
922             DbgPrint("ne2000!MiniportInitialize: DwordTest value was correctly read\n");
923
924             NdisInitUnicodeString(&Keyword, L"StringTest");
925             NdisReadConfiguration(&Status, &ParameterValue, ConfigurationHandle, &Keyword, NdisParameterString);
926
927             if(Status != NDIS_STATUS_SUCCESS)
928             {
929                 DbgPrint("ne2000!MiniportInitialize: failed to read StringTest: 0x%x\n", Status);
930                 KeBugCheck(0);
931             }
932
933             if(wcsncmp(ParameterValue->ParameterData.StringData.Buffer, L"Testing123",
934                     wcslen(L"Testing123")))
935             {
936                 DbgPrint("ne2000!MiniportInitialize: StringTest value is wrong: %wZ\n",
937                     &ParameterValue->ParameterData.StringData);
938                 KeBugCheck(0);
939             }
940
941             DbgPrint("ne2000!MiniportInitialize: StringTest value was correctly read\n");
942         }
943
944 #endif
945 /* EOF */