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