update for HEAD-2003091401
[reactos.git] / drivers / net / ndis / ndis / miniport.c
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS NDIS library
4  * FILE:        ndis/miniport.c
5  * PURPOSE:     Routines used by NDIS miniport drivers
6  * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7  *              Vizzini (vizzini@plasmic.com)
8  * REVISIONS:
9  *   CSH 01/08-2000 Created
10  *   8/20/2003 vizzini - DMA support
11  */
12 #include <miniport.h>
13 #include <protocol.h>
14 #ifdef DBG
15 #include <buffer.h>
16 #endif /* DBG */
17
18 /* Root of the scm database */
19 #define SERVICES_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
20
21 /* prefix for device object registration */
22 #define DEVICE_ROOT L"\\Device\\"
23
24 /*
25  * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
26  * for each new miniport starting up
27  */
28 #define BREAK_ON_MINIPORT_INIT 0
29
30 /* 
31  * This has to be big enough to hold the results of querying the Route value
32  * from the Linkage key.  Please re-code me to determine this dynamically.
33  */
34 #define ROUTE_DATA_SIZE 256
35
36 /* Number of media we know */
37 #define MEDIA_ARRAY_SIZE    15
38
39 static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] = {
40     NdisMedium802_3,
41     NdisMedium802_5,
42     NdisMediumFddi,
43     NdisMediumWan,
44     NdisMediumLocalTalk,
45     NdisMediumDix,
46     NdisMediumArcnetRaw,
47     NdisMediumArcnet878_2,
48     NdisMediumAtm,
49     NdisMediumWirelessWan,
50     NdisMediumIrda,
51     NdisMediumBpc,
52     NdisMediumCoWan,
53     NdisMedium1394,
54     NdisMediumMax
55 };
56
57 /* global list and lock of Miniports NDIS has registered */
58 LIST_ENTRY MiniportListHead;
59 KSPIN_LOCK MiniportListLock;
60
61 /* global list and lock of adapters NDIS has registered */
62 LIST_ENTRY AdapterListHead;
63 KSPIN_LOCK AdapterListLock;
64
65 /* global list and lock of orphan adapters waiting to be claimed by a miniport */
66 LIST_ENTRY OrphanAdapterListHead;
67 KSPIN_LOCK OrphanAdapterListLock;
68
69
70 #ifdef DBG
71 VOID
72 MiniDisplayPacket(
73     PNDIS_PACKET Packet)
74 {
75 #if 0
76     ULONG i, Length;
77     UCHAR Buffer[64];
78     if ((DebugTraceLevel | DEBUG_PACKET) > 0) {
79         Length = CopyPacketToBuffer(
80             (PUCHAR)&Buffer,
81             Packet,
82             0,
83             64);
84
85         DbgPrint("*** PACKET START ***");
86
87         for (i = 0; i < Length; i++) {
88             if (i % 12 == 0)
89                 DbgPrint("\n%04X ", i);
90             DbgPrint("%02X ", Buffer[i]);
91         }
92
93         DbgPrint("*** PACKET STOP ***\n");
94     }
95 #endif
96 }
97 #endif /* DBG */
98
99
100 VOID
101 MiniIndicateData(
102     PLOGICAL_ADAPTER    Adapter,
103     NDIS_HANDLE         MacReceiveContext,
104     PVOID               HeaderBuffer,
105     UINT                HeaderBufferSize,
106     PVOID               LookaheadBuffer,
107     UINT                LookaheadBufferSize,
108     UINT                PacketSize)
109 /*
110  * FUNCTION: Indicate received data to bound protocols
111  * ARGUMENTS:
112  *     Adapter             = Pointer to logical adapter
113  *     MacReceiveContext   = MAC receive context handle
114  *     HeaderBuffer        = Pointer to header buffer
115  *     HeaderBufferSize    = Size of header buffer
116  *     LookaheadBuffer     = Pointer to lookahead buffer
117  *     LookaheadBufferSize = Size of lookahead buffer
118  *     PacketSize          = Total size of received packet
119  */
120 {
121     KIRQL OldIrql;
122     PLIST_ENTRY CurrentEntry;
123     PADAPTER_BINDING AdapterBinding;
124
125     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X)  HeaderBuffer (0x%X)  "
126         "HeaderBufferSize (0x%X)  LookaheadBuffer (0x%X)  LookaheadBufferSize (0x%X).\n",
127         Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
128
129 #ifdef DBG
130 #if 0
131     if ((DebugTraceLevel | DEBUG_PACKET) > 0) {
132         ULONG i, Length;
133         PUCHAR p;
134
135         DbgPrint("*** RECEIVE PACKET START ***\n");
136         DbgPrint("HEADER:");
137         p = HeaderBuffer;
138         for (i = 0; i < HeaderBufferSize; i++) {
139             if (i % 16 == 0)
140                 DbgPrint("\n%04X ", i);
141             DbgPrint("%02X ", *p);
142             (ULONG_PTR)p += 1;
143         }
144
145         DbgPrint("\nFRAME:");
146
147         p = LookaheadBuffer;
148         Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
149         for (i = 0; i < Length; i++) {
150             if (i % 16 == 0)
151                 DbgPrint("\n%04X ", i);
152             DbgPrint("%02X ", *p);
153             (ULONG_PTR)p += 1;
154         }
155
156         DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
157     }
158 #endif
159 #endif /* DBG */
160
161     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
162     CurrentEntry = Adapter->ProtocolListHead.Flink;
163
164     if (CurrentEntry == &Adapter->ProtocolListHead) {
165         NDIS_DbgPrint(DEBUG_MINIPORT, ("WARNING: No upper protocol layer.\n"));
166     }
167
168     while (CurrentEntry != &Adapter->ProtocolListHead) {
169             AdapterBinding = CONTAINING_RECORD(CurrentEntry,
170                                            ADAPTER_BINDING,
171                                            AdapterListEntry);
172
173         KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
174
175         (*AdapterBinding->ProtocolBinding->Chars.u4.ReceiveHandler)(
176             AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
177             MacReceiveContext,
178             HeaderBuffer,
179             HeaderBufferSize,
180             LookaheadBuffer,
181             LookaheadBufferSize,
182             PacketSize);
183
184         KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
185
186         CurrentEntry = CurrentEntry->Flink;
187     }
188     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
189 }
190
191
192 VOID STDCALL
193 MiniIndicateReceivePacket(
194     IN  NDIS_HANDLE    Miniport,
195     IN  PPNDIS_PACKET  PacketArray,
196     IN  UINT           NumberOfPackets)
197 /*
198  * FUNCTION: receives miniport packet array indications
199  * ARGUMENTS:
200  *     Miniport: Miniport handle for the adapter
201  *     PacketArray: pointer to a list of packet pointers to indicate
202  *     NumberOfPackets: number of packets to indicate
203  */
204 {
205   NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
206 }
207
208
209 VOID
210 MiniEthReceiveComplete(
211     IN  PETH_FILTER Filter)
212 /*
213  * FUNCTION: Receive indication complete function for Ethernet devices
214  * ARGUMENTS:
215  *     Filter = Pointer to Ethernet filter
216  */
217 {
218     KIRQL OldIrql;
219     PLIST_ENTRY CurrentEntry;
220     PLOGICAL_ADAPTER Adapter;
221     PADAPTER_BINDING AdapterBinding;
222
223     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
224
225     Adapter = (PLOGICAL_ADAPTER)Filter->Miniport;
226
227     KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
228     CurrentEntry = Adapter->ProtocolListHead.Flink;
229     while (CurrentEntry != &Adapter->ProtocolListHead) {
230             AdapterBinding = CONTAINING_RECORD(CurrentEntry,
231                                            ADAPTER_BINDING,
232                                            AdapterListEntry);
233
234         KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
235
236         (*AdapterBinding->ProtocolBinding->Chars.ReceiveCompleteHandler)(
237             AdapterBinding->NdisOpenBlock.ProtocolBindingContext);
238
239         KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
240
241         CurrentEntry = CurrentEntry->Flink;
242     }
243     KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
244 }
245
246
247 VOID
248 MiniEthReceiveIndication(
249     IN  PETH_FILTER Filter,
250     IN  NDIS_HANDLE MacReceiveContext,
251     IN  PCHAR       Address,
252     IN  PVOID       HeaderBuffer,
253     IN  UINT        HeaderBufferSize,
254     IN  PVOID       LookaheadBuffer,
255     IN  UINT        LookaheadBufferSize,
256     IN  UINT        PacketSize)
257 /*
258  * FUNCTION: Receive indication function for Ethernet devices
259  * ARGUMENTS:
260  *     Filter              = Pointer to Ethernet filter
261  *     MacReceiveContext   = MAC receive context handle
262  *     Address             = Pointer to destination Ethernet address
263  *     HeaderBuffer        = Pointer to Ethernet header buffer
264  *     HeaderBufferSize    = Size of Ethernet header buffer
265  *     LookaheadBuffer     = Pointer to lookahead buffer
266  *     LookaheadBufferSize = Size of lookahead buffer
267  *     PacketSize          = Total size of received packet
268  */
269 {
270     MiniIndicateData((PLOGICAL_ADAPTER)Filter->Miniport,
271                      MacReceiveContext,
272                      HeaderBuffer,
273                      HeaderBufferSize,
274                      LookaheadBuffer,
275                      LookaheadBufferSize,
276                      PacketSize);
277 }
278
279
280 VOID
281 MiniResetComplete(
282     IN  NDIS_HANDLE MiniportAdapterHandle,
283     IN  NDIS_STATUS Status,
284     IN  BOOLEAN     AddressingReset)
285 {
286     UNIMPLEMENTED
287 }
288
289
290 VOID
291 MiniSendComplete(
292     IN  NDIS_HANDLE     MiniportAdapterHandle,
293     IN  PNDIS_PACKET    Packet,
294     IN  NDIS_STATUS     Status)
295 /*
296  * FUNCTION: Forwards a message to the initiating protocol saying
297  *           that a packet was handled
298  * ARGUMENTS:
299  *     NdisAdapterHandle = Handle input to MiniportInitialize
300  *     Packet            = Pointer to NDIS packet that was sent
301  *     Status            = Status of send operation
302  */
303 {
304     PADAPTER_BINDING AdapterBinding;
305
306     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
307
308     AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
309
310     (*AdapterBinding->ProtocolBinding->Chars.u2.SendCompleteHandler)(
311         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
312         Packet,
313         Status);
314 }
315
316
317 VOID
318 MiniSendResourcesAvailable(
319     IN  NDIS_HANDLE MiniportAdapterHandle)
320 {
321     UNIMPLEMENTED
322 }
323
324
325 VOID
326 MiniTransferDataComplete(
327     IN  NDIS_HANDLE     MiniportAdapterHandle,
328     IN  PNDIS_PACKET    Packet,
329     IN  NDIS_STATUS     Status,
330     IN  UINT            BytesTransferred)
331 {
332     PLOGICAL_ADAPTER Adapter        = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
333     PADAPTER_BINDING AdapterBinding = Adapter->MiniportAdapterBinding;
334
335     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
336
337     (*AdapterBinding->ProtocolBinding->Chars.u3.TransferDataCompleteHandler)(
338         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
339         Packet,
340         Status,
341         BytesTransferred);
342 }
343
344
345 BOOLEAN
346 MiniAdapterHasAddress(
347     PLOGICAL_ADAPTER Adapter,
348     PNDIS_PACKET Packet)
349 /*
350  * FUNCTION: Determines wether a packet has the same destination address as an adapter
351  * ARGUMENTS:
352  *     Adapter = Pointer to logical adapter object
353  *     Packet  = Pointer to NDIS packet
354  * RETURNS:
355  *     TRUE if the destination address is that of the adapter, FALSE if not
356  */
357 {
358     UINT Length;
359     PUCHAR Start1;
360     PUCHAR Start2;
361     PNDIS_BUFFER NdisBuffer;
362     UINT BufferLength;
363
364     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
365
366     Start1 = (PUCHAR)&Adapter->Address;
367     NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
368     if (!NdisBuffer) {
369         NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
370         return FALSE;
371     }
372
373     NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
374
375     /* FIXME: Should handle fragmented packets */
376
377     switch (Adapter->NdisMiniportBlock.MediaType) {
378     case NdisMedium802_3:
379         Length = ETH_LENGTH_OF_ADDRESS;
380         /* Destination address is the first field */
381         break;
382
383     default:
384         NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n",
385             Adapter->NdisMiniportBlock.MediaType));
386         return FALSE;
387     }
388
389     if (BufferLength < Length) {
390         NDIS_DbgPrint(MID_TRACE, ("Buffer is too small.\n"));
391         return FALSE;
392     }
393
394     return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
395 }
396
397
398 PLOGICAL_ADAPTER
399 MiniLocateDevice(
400     PNDIS_STRING AdapterName)
401 /*
402  * FUNCTION: Returns the logical adapter object for a specific adapter
403  * ARGUMENTS:
404  *     AdapterName = Pointer to name of adapter
405  * RETURNS:
406  *     Pointer to logical adapter object, or NULL if none was found.
407  *     If found, the adapter is referenced for the caller. The caller
408  *     is responsible for dereferencing after use
409  */
410 {
411     KIRQL OldIrql;
412     PLIST_ENTRY CurrentEntry;
413     PLOGICAL_ADAPTER Adapter;
414
415     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
416
417     KeAcquireSpinLock(&AdapterListLock, &OldIrql);
418     CurrentEntry = AdapterListHead.Flink;
419     while (CurrentEntry != &AdapterListHead) {
420             Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
421
422         if (RtlCompareUnicodeString(AdapterName, &Adapter->DeviceName, TRUE) == 0) {
423             ReferenceObject(Adapter);
424             KeReleaseSpinLock(&AdapterListLock, OldIrql);
425
426             NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at (0x%X).\n", Adapter));
427
428             return Adapter;
429         }
430
431         CurrentEntry = CurrentEntry->Flink;
432     }
433     KeReleaseSpinLock(&AdapterListLock, OldIrql);
434
435     NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
436
437     return NULL;
438 }
439
440
441 NDIS_STATUS
442 MiniQueryInformation(
443     PLOGICAL_ADAPTER    Adapter,
444     NDIS_OID            Oid,
445     ULONG               Size,
446     PULONG              BytesWritten)
447 /*
448  * FUNCTION: Queries a logical adapter for properties
449  * ARGUMENTS:
450  *     Adapter      = Pointer to the logical adapter object to query
451  *     Oid          = Specifies the Object ID to query for
452  *     Size         = If non-zero overrides the length in the adapter object
453  *     BytesWritten = Address of buffer to place number of bytes written
454  * NOTES:
455  *     If the specified buffer is too small, a new buffer is allocated,
456  *     and the query is attempted again
457  * RETURNS:
458  *     Status of operation
459  */
460 {
461     NDIS_STATUS NdisStatus;
462     ULONG BytesNeeded;
463
464     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
465
466     if (Adapter->QueryBufferLength == 0) {
467         Adapter->QueryBuffer = ExAllocatePool(NonPagedPool, (Size == 0)? 32 : Size);
468
469         if (!Adapter->QueryBuffer) {
470             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
471             return NDIS_STATUS_RESOURCES;
472         }
473
474         Adapter->QueryBufferLength = (Size == 0)? 32 : Size;
475     }
476
477     BytesNeeded = (Size == 0)? Adapter->QueryBufferLength : Size;
478
479     NdisStatus = (*Adapter->Miniport->Chars.QueryInformationHandler)(
480         Adapter->NdisMiniportBlock.MiniportAdapterContext,
481         Oid,
482         Adapter->QueryBuffer,
483         BytesNeeded,
484         BytesWritten,
485         &BytesNeeded);
486
487     if ((NT_SUCCESS(NdisStatus)) || (NdisStatus == NDIS_STATUS_PENDING)) {
488         NDIS_DbgPrint(DEBUG_MINIPORT, ("Miniport returned status (0x%X).\n", NdisStatus));
489         return NdisStatus;
490     }
491
492     if (NdisStatus == NDIS_STATUS_INVALID_LENGTH) {
493         ExFreePool(Adapter->QueryBuffer);
494
495         Adapter->QueryBufferLength += BytesNeeded;
496         Adapter->QueryBuffer = ExAllocatePool(NonPagedPool,
497                                               Adapter->QueryBufferLength);
498
499         if (!Adapter->QueryBuffer) {
500             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
501             return NDIS_STATUS_RESOURCES;
502         }
503
504         NdisStatus = (*Adapter->Miniport->Chars.QueryInformationHandler)(
505             Adapter->NdisMiniportBlock.MiniportAdapterContext,
506             Oid,
507             Adapter->QueryBuffer,
508             Size,
509             BytesWritten,
510             &BytesNeeded);
511     }
512
513     return NdisStatus;
514 }
515
516
517 NDIS_STATUS
518 FASTCALL
519 MiniQueueWorkItem(
520     PLOGICAL_ADAPTER    Adapter,
521     NDIS_WORK_ITEM_TYPE WorkItemType,
522     PVOID               WorkItemContext,
523     NDIS_HANDLE         Initiator)
524 /*
525  * FUNCTION: Queues a work item for execution at a later time
526  * ARGUMENTS:
527  *     Adapter         = Pointer to the logical adapter object to queue work item on
528  *     WorkItemType    = Type of work item to queue
529  *     WorkItemContext = Pointer to context information for work item
530  *     Initiator       = Pointer to ADAPTER_BINDING structure of initiating protocol
531  * NOTES:
532  *     Adapter lock must be held when called
533  * RETURNS:
534  *     Status of operation
535  */
536 {
537     PNDIS_MINIPORT_WORK_ITEM Item;
538
539     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
540
541     if (Adapter->WorkQueueLevel < NDIS_MINIPORT_WORK_QUEUE_SIZE - 1) {
542         Item = &Adapter->WorkQueue[Adapter->WorkQueueLevel];
543         Adapter->WorkQueueLevel++;
544     } else {
545         Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
546         if (Item) {
547             /* Set flag so we know that the buffer should be freed
548                when work item is dequeued */
549             Item->Allocated = TRUE;
550         } else {
551             NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
552             return NDIS_STATUS_RESOURCES;
553         }
554     }
555
556     Item->WorkItemType    = WorkItemType;
557     Item->WorkItemContext = WorkItemContext;
558     Item->Initiator       = Initiator;
559
560     Item->Link.Next = NULL;
561     if (!Adapter->WorkQueueHead) {
562         Adapter->WorkQueueHead = Item;
563     } else {
564         Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item;
565     }
566
567     KeInsertQueueDpc(&Adapter->MiniportDpc, NULL, NULL);
568
569     return NDIS_STATUS_SUCCESS;
570 }
571
572
573 NDIS_STATUS
574 FASTCALL
575 MiniDequeueWorkItem(
576     PLOGICAL_ADAPTER    Adapter,
577     NDIS_WORK_ITEM_TYPE *WorkItemType,
578     PVOID               *WorkItemContext,
579     NDIS_HANDLE         *Initiator)
580 /*
581  * FUNCTION: Dequeues a work item from the work queue of a logical adapter
582  * ARGUMENTS:
583  *     Adapter         = Pointer to the logical adapter object to dequeue work item from
584  *     WorkItemType    = Address of buffer for work item type
585  *     WorkItemContext = Address of buffer for pointer to context information
586  *     Initiator       = Address of buffer for initiator of the work (ADAPTER_BINDING)
587  * NOTES:
588  *     Adapter lock must be held when called
589  * RETURNS:
590  *     Status of operation
591  */
592 {
593     PNDIS_MINIPORT_WORK_ITEM Item;
594
595     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
596
597     Item = Adapter->WorkQueueHead;
598     if (Item) {
599         Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next;
600         if (Item == Adapter->WorkQueueTail)
601             Adapter->WorkQueueTail = NULL;
602
603         *WorkItemType    = Item->WorkItemType;
604         *WorkItemContext = Item->WorkItemContext;
605         *Initiator       = Item->Initiator;
606
607         if (Item->Allocated) {
608             ExFreePool(Item);
609         } else {
610             Adapter->WorkQueueLevel--;
611 #ifdef DBG
612             if (Adapter->WorkQueueLevel < 0) {
613                 NDIS_DbgPrint(MIN_TRACE, ("Adapter->WorkQueueLevel is < 0 (should be >= 0).\n"));
614             }
615 #endif
616         }
617
618         return NDIS_STATUS_SUCCESS;
619     }
620
621     return NDIS_STATUS_FAILURE;
622 }
623
624
625 NDIS_STATUS
626 MiniDoRequest(
627     PLOGICAL_ADAPTER Adapter,
628     PNDIS_REQUEST NdisRequest)
629 /*
630  * FUNCTION: Sends a request to a miniport
631  * ARGUMENTS:
632  *     Adapter     = Pointer to logical adapter object
633  *     NdisRequest = Pointer to NDIS request structure describing request
634  * RETURNS:
635  *     Status of operation
636  */
637 {
638     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
639
640     Adapter->NdisMiniportBlock.MediaRequest = NdisRequest;
641
642     switch (NdisRequest->RequestType) {
643     case NdisRequestQueryInformation:
644         return (*Adapter->Miniport->Chars.QueryInformationHandler)(
645             Adapter->NdisMiniportBlock.MiniportAdapterContext,
646             NdisRequest->DATA.QUERY_INFORMATION.Oid,
647             NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
648             NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
649             (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
650             (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
651         break;
652
653     case NdisRequestSetInformation:
654         return (*Adapter->Miniport->Chars.SetInformationHandler)(
655             Adapter->NdisMiniportBlock.MiniportAdapterContext,
656             NdisRequest->DATA.SET_INFORMATION.Oid,
657             NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
658             NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
659             (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead,
660             (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
661         break;
662
663     default:
664         return NDIS_STATUS_FAILURE;
665     }
666 }
667
668
669 VOID STDCALL MiniportDpc(
670     IN PKDPC Dpc,
671     IN PVOID DeferredContext,
672     IN PVOID SystemArgument1,
673     IN PVOID SystemArgument2)
674 /*
675  * FUNCTION: Deferred routine to handle serialization
676  * ARGUMENTS:
677  *     Dpc             = Pointer to DPC object
678  *     DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
679  *     SystemArgument1 = Unused
680  *     SystemArgument2 = Unused
681  */
682 {
683     NDIS_STATUS NdisStatus;
684     PVOID WorkItemContext;
685     NDIS_WORK_ITEM_TYPE WorkItemType;
686     PADAPTER_BINDING AdapterBinding;
687     PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
688
689     NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
690
691     NdisStatus = MiniDequeueWorkItem(Adapter,
692                                      &WorkItemType,
693                                      &WorkItemContext,
694                                      (PNDIS_HANDLE)&AdapterBinding);
695     if (NdisStatus == NDIS_STATUS_SUCCESS) {
696         Adapter->MiniportAdapterBinding = AdapterBinding;
697         switch (WorkItemType) {
698         case NdisWorkItemSend:
699 #ifdef DBG
700             MiniDisplayPacket((PNDIS_PACKET)WorkItemContext);
701 #endif
702             NdisStatus = (*Adapter->Miniport->Chars.u1.SendHandler)(
703                 Adapter->NdisMiniportBlock.MiniportAdapterContext,
704                 (PNDIS_PACKET)WorkItemContext,
705                 0);
706             if (NdisStatus != NDIS_STATUS_PENDING) {
707                 MiniSendComplete((NDIS_HANDLE)Adapter,
708                                  (PNDIS_PACKET)WorkItemContext,
709                                  NdisStatus);
710             }
711             break;
712
713         case NdisWorkItemSendLoopback:
714             NdisStatus = ProIndicatePacket(Adapter,
715                                            (PNDIS_PACKET)WorkItemContext);
716             MiniSendComplete((NDIS_HANDLE)Adapter,
717                              (PNDIS_PACKET)WorkItemContext,
718                              NdisStatus);
719             break;
720
721         case NdisWorkItemReturnPackets:
722             break;
723
724         case NdisWorkItemResetRequested:
725             break;
726
727         case NdisWorkItemResetInProgress:
728             break;
729
730         case NdisWorkItemHalt:
731             break;
732
733         case NdisWorkItemMiniportCallback:
734             break;
735
736         case NdisWorkItemRequest:
737             NdisStatus = MiniDoRequest(Adapter, (PNDIS_REQUEST)WorkItemContext);
738
739             if (NdisStatus == NDIS_STATUS_PENDING)
740                 break;
741
742             switch (((PNDIS_REQUEST)WorkItemContext)->RequestType) {
743             case NdisRequestQueryInformation:
744                 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
745                 break;
746
747             case NdisRequestSetInformation:
748                 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
749                 break;
750
751             default:
752                 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
753                 break;
754             }
755             break;
756
757         default:
758             NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
759             break;
760         }
761     }
762 }
763
764
765 /*
766  * @unimplemented
767  */
768 VOID
769 EXPORT
770 NdisMCloseLog(
771     IN  NDIS_HANDLE LogHandle)
772 {
773     UNIMPLEMENTED
774 }
775
776
777 /*
778  * @unimplemented
779  */
780 NDIS_STATUS
781 EXPORT
782 NdisMCreateLog(
783     IN  NDIS_HANDLE     MiniportAdapterHandle,
784     IN  UINT            Size,
785     OUT PNDIS_HANDLE    LogHandle)
786 {
787     UNIMPLEMENTED
788
789         return NDIS_STATUS_FAILURE;
790 }
791
792
793 /*
794  * @implemented
795  */
796 VOID
797 EXPORT
798 NdisMDeregisterAdapterShutdownHandler(
799     IN  NDIS_HANDLE MiniportHandle)
800 /*
801  * FUNCTION: de-registers a shutdown handler
802  * ARGUMENTS:  MiniportHandle:  Handle passed into MiniportInitialize
803  */
804 {
805   NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
806   PLOGICAL_ADAPTER  Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
807
808   if(Adapter->BugcheckContext->ShutdownHandler)
809     KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
810 }
811
812
813 /*
814  * @unimplemented
815  */
816 VOID
817 EXPORT
818 NdisMFlushLog(
819     IN  NDIS_HANDLE LogHandle)
820 {
821     UNIMPLEMENTED
822 }
823
824
825 /*
826  * @unimplemented
827  */
828 VOID
829 EXPORT
830 NdisMIndicateStatus(
831     IN  NDIS_HANDLE MiniportAdapterHandle,
832     IN  NDIS_STATUS GeneralStatus,
833     IN  PVOID       StatusBuffer,
834     IN  UINT        StatusBufferSize)
835 {
836     UNIMPLEMENTED
837 }
838
839
840 /*
841  * @unimplemented
842  */
843 VOID
844 EXPORT
845 NdisMIndicateStatusComplete(
846     IN  NDIS_HANDLE MiniportAdapterHandle)
847 {
848     UNIMPLEMENTED
849 }
850
851
852 /*
853  * @implemented
854  */
855 VOID
856 EXPORT
857 NdisInitializeWrapper(
858     OUT PNDIS_HANDLE    NdisWrapperHandle,
859     IN  PVOID           SystemSpecific1,
860     IN  PVOID           SystemSpecific2,
861     IN  PVOID           SystemSpecific3)
862 /*
863  * FUNCTION: Notifies the NDIS library that a new miniport is initializing
864  * ARGUMENTS:
865  *     NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
866  *     SystemSpecific1   = Pointer to the driver's driver object
867  *     SystemSpecific2   = Pointer to the driver's registry path
868  *     SystemSpecific3   = Always NULL
869  * NOTES:
870  *     - SystemSpecific2 goes invalid so we copy it
871  */
872 {
873     PMINIPORT_DRIVER Miniport;
874     PUNICODE_STRING RegistryPath;
875     WCHAR *RegistryBuffer;
876
877     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
878
879 #if BREAK_ON_MINIPORT_INIT
880   __asm__ ("int $3\n");
881 #endif
882
883     Miniport = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_DRIVER));
884     if (!Miniport) {
885         NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
886         *NdisWrapperHandle = NULL;
887         return;
888     }
889
890     RtlZeroMemory(Miniport, sizeof(MINIPORT_DRIVER));
891
892     KeInitializeSpinLock(&Miniport->Lock);
893
894     Miniport->RefCount = 1;
895
896     Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
897
898     /* set the miniport's driver registry path */
899     RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
900     if(!RegistryPath)
901     {
902        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
903        return;
904     }
905
906     RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
907     RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
908
909     RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->Length + sizeof(WCHAR));
910     if(!RegistryBuffer)
911     {
912        NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
913        return;
914     }
915
916     RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
917     RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
918
919     RegistryPath->Buffer = RegistryBuffer;
920     Miniport->RegistryPath = RegistryPath;
921
922     InitializeListHead(&Miniport->AdapterListHead);
923
924     /* Put miniport in global miniport list */
925     ExInterlockedInsertTailList(&MiniportListHead,
926                                 &Miniport->ListEntry,
927                                 &MiniportListLock);
928
929     *NdisWrapperHandle = Miniport;
930
931 }
932
933
934 /*
935  * @implemented
936  */
937 VOID
938 EXPORT
939 NdisMQueryInformationComplete(
940     IN  NDIS_HANDLE MiniportAdapterHandle,
941     IN  NDIS_STATUS Status)
942 {
943     PLOGICAL_ADAPTER Adapter        = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
944     PADAPTER_BINDING AdapterBinding = (PADAPTER_BINDING)Adapter->MiniportAdapterBinding;
945
946     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
947
948     (*AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler)(
949         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
950         Adapter->NdisMiniportBlock.MediaRequest,
951         Status);
952 }
953
954
955 VOID NdisIBugcheckCallback(
956     IN PVOID   Buffer,
957     IN ULONG   Length)
958 /*
959  * FUNCTION:  Internal callback for handling bugchecks - calls adapter's shutdown handler
960  * ARGUMENTS:
961  *     Buffer:  Pointer to a bugcheck callback context
962  *     Length:  Unused
963  */
964 {
965   PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
966   ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
967
968    NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
969
970   if(sh)
971     sh(Context->DriverContext);
972
973
974
975 /*
976  * @implemented
977  */
978 VOID
979 EXPORT
980 NdisMRegisterAdapterShutdownHandler(
981     IN  NDIS_HANDLE                 MiniportHandle,
982     IN  PVOID                       ShutdownContext,
983     IN  ADAPTER_SHUTDOWN_HANDLER    ShutdownHandler)
984 /*
985  * FUNCTION:  Register a shutdown handler for an adapter
986  * ARGUMENTS:
987  *     MiniportHandle:  Handle originally passed into MiniportInitialize
988  *     ShutdownContext:  Pre-initialized bugcheck context
989  *     ShutdownHandler:  Function to call to handle the bugcheck
990  * NOTES:
991  *     - I'm not sure about ShutdownContext
992  *     - FIXME - memory leak below
993  */
994 {
995   PLOGICAL_ADAPTER            Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
996   PMINIPORT_BUGCHECK_CONTEXT  BugcheckContext = Adapter->BugcheckContext;
997
998   NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
999
1000   if(BugcheckContext) 
1001     return;
1002
1003   BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1004   if(!BugcheckContext)
1005     {
1006       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1007       return;
1008     }
1009
1010   BugcheckContext->ShutdownHandler = ShutdownHandler;
1011   BugcheckContext->DriverContext = ShutdownContext;
1012
1013   /* not sure if this needs to be initialized or not... oh well, it's a leak. */
1014   BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1015
1016   KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback, 
1017       BugcheckContext, sizeof(BugcheckContext), "Ndis Miniport");
1018 }
1019
1020
1021 NDIS_STATUS
1022 DoQueries(
1023     PLOGICAL_ADAPTER Adapter,
1024     NDIS_OID AddressOID)
1025 /*
1026  * FUNCTION: Queries miniport for information
1027  * ARGUMENTS:
1028  *     Adapter    = Pointer to logical adapter
1029  *     AddressOID = OID to use to query for current address
1030  * RETURNS:
1031  *     Status of operation
1032  */
1033 {
1034     ULONG BytesWritten;
1035     NDIS_STATUS NdisStatus;
1036
1037     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1038
1039     /* Get MAC options for adapter */
1040     NdisStatus = MiniQueryInformation(Adapter,
1041                                       OID_GEN_MAC_OPTIONS,
1042                                       0,
1043                                       &BytesWritten);
1044     if (NdisStatus != NDIS_STATUS_SUCCESS) {
1045         NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1046         return NdisStatus;
1047     }
1048
1049     RtlCopyMemory(&Adapter->NdisMiniportBlock.MacOptions, Adapter->QueryBuffer, sizeof(UINT));
1050
1051     NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1052
1053     /* Get current hardware address of adapter */
1054     NdisStatus = MiniQueryInformation(Adapter,
1055                                       AddressOID,
1056                                       0,
1057                                       &BytesWritten);
1058     if (NdisStatus != NDIS_STATUS_SUCCESS) {
1059         NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n",
1060             AddressOID, NdisStatus));
1061         return NdisStatus;
1062     }
1063
1064     RtlCopyMemory(&Adapter->Address, Adapter->QueryBuffer, Adapter->AddressLength);
1065 #ifdef DBG
1066     {
1067         /* 802.3 only */
1068
1069         PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1070
1071         NDIS_DbgPrint(MAX_TRACE, ("Adapter address is (%02X %02X %02X %02X %02X %02X).\n",
1072             A[0], A[1], A[2], A[3], A[4], A[5]));
1073     }
1074 #endif /* DBG */
1075
1076     /* Get maximum lookahead buffer size of adapter */
1077     NdisStatus = MiniQueryInformation(Adapter,
1078                                       OID_GEN_MAXIMUM_LOOKAHEAD,
1079                                       0,
1080                                       &BytesWritten);
1081     if (NdisStatus != NDIS_STATUS_SUCCESS) {
1082         NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1083         return NdisStatus;
1084     }
1085
1086     Adapter->MaxLookaheadLength = *((PULONG)Adapter->QueryBuffer);
1087
1088     NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->MaxLookaheadLength));
1089
1090     /* Get current lookahead buffer size of adapter */
1091     NdisStatus = MiniQueryInformation(Adapter,
1092                                       OID_GEN_CURRENT_LOOKAHEAD,
1093                                       0,
1094                                       &BytesWritten);
1095     if (NdisStatus != NDIS_STATUS_SUCCESS) {
1096         NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1097         return NdisStatus;
1098     }
1099
1100     Adapter->CurLookaheadLength = *((PULONG)Adapter->QueryBuffer);
1101
1102     NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->CurLookaheadLength));
1103
1104     if (Adapter->MaxLookaheadLength != 0) {
1105         Adapter->LookaheadLength = Adapter->MaxLookaheadLength +
1106                                    Adapter->MediumHeaderSize;
1107         Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool,
1108                                                   Adapter->LookaheadLength);
1109         if (!Adapter->LookaheadBuffer)
1110             return NDIS_STATUS_RESOURCES;
1111     }
1112
1113     return STATUS_SUCCESS;
1114 }
1115
1116
1117 VOID
1118 NdisIStartAdapter(
1119     WCHAR *DeviceNameStr,
1120     UINT DeviceNameStrLength,
1121     PMINIPORT_DRIVER Miniport
1122 )
1123 /*
1124  * FUNCTION: Start an adapter
1125  * ARGUMENTS:
1126  *     DeviceNameStr: 0-terminated wide char string of name of device to start
1127  *     DeviceNameStrLength: length of DeviceNameStr *IN WCHARs*
1128  * NOTES:
1129  * TODO:
1130  *     - verify that all resources are properly freed on success & failure
1131  */
1132 {
1133   WCHAR *DeviceName;
1134   HANDLE RegKeyHandle;
1135   WCHAR *RegKeyPath;
1136   UNICODE_STRING RegKeyPathU;
1137   OBJECT_ATTRIBUTES RegKeyAttributes;
1138   NDIS_STATUS NdisStatus;
1139   NDIS_STATUS OpenErrorStatus;
1140   NTSTATUS Status;
1141   UINT SelectedMediumIndex = 0;
1142   PLOGICAL_ADAPTER Adapter = 0;
1143   NDIS_OID AddressOID;
1144   BOOLEAN MemError = FALSE;
1145   KIRQL OldIrql;
1146   PORPHAN_ADAPTER OrphanAdapter = 0;
1147
1148   NDIS_DbgPrint(MAX_TRACE, ("Called with %ws\n", DeviceNameStr));
1149   Adapter = ExAllocatePool(NonPagedPool, sizeof(LOGICAL_ADAPTER));
1150   if (!Adapter) 
1151     {
1152       NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1153       return; 
1154     }
1155
1156   /* This is very important */
1157   RtlZeroMemory(Adapter, sizeof(LOGICAL_ADAPTER));
1158
1159   DeviceName = ExAllocatePool(NonPagedPool, sizeof(DEVICE_ROOT) + DeviceNameStrLength * sizeof(WCHAR));
1160   if(!DeviceName)
1161     {
1162       NDIS_DbgPrint(MIN_TRACE,("Insufficient memory\n"));
1163       ExFreePool(Adapter);
1164       return;
1165     }
1166
1167   /* DEVICE_ROOT is a constant string defined above, incl. 0-term */
1168   wcscpy(DeviceName, DEVICE_ROOT);
1169
1170   /* reg_sz is 0-term by def */
1171   wcsncat(DeviceName, DeviceNameStr, DeviceNameStrLength); 
1172   RtlInitUnicodeString(&Adapter->DeviceName, DeviceName);
1173
1174   NDIS_DbgPrint(MAX_TRACE, ("creating device %ws\n", DeviceName));
1175
1176   Status = IoCreateDevice(Miniport->DriverObject, 0, &Adapter->DeviceName, FILE_DEVICE_PHYSICAL_NETCARD,
1177       0, FALSE, &Adapter->NdisMiniportBlock.DeviceObject);
1178   if (!NT_SUCCESS(Status)) 
1179     {
1180       NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1181       ExFreePool(Adapter);
1182       return;
1183     }
1184
1185   /* find out if there are any adapters in the orphans list and reserve resources */
1186   KeAcquireSpinLock(&OrphanAdapterListLock, &OldIrql);
1187   OrphanAdapter = (PORPHAN_ADAPTER)OrphanAdapterListHead.Flink;
1188   while(&OrphanAdapter->ListEntry != &OrphanAdapterListHead)
1189     {
1190       PORPHAN_ADAPTER TempAdapter;
1191       PCM_RESOURCE_LIST ResourceList;
1192       UINT i;
1193
1194       if(!RtlCompareUnicodeString(&OrphanAdapter->RegistryPath, Miniport->RegistryPath, TRUE))
1195         {
1196           OrphanAdapter = (PORPHAN_ADAPTER)OrphanAdapter->ListEntry.Flink;
1197           continue;
1198         }
1199
1200       NDIS_DbgPrint(MAX_TRACE, ("Found an orphan adapter for RegistryPath %wZ\n", Miniport->RegistryPath));
1201
1202       /* there is an orphan adapter for us */
1203       Adapter->SlotNumber = OrphanAdapter->SlotNumber;
1204       Adapter->BusNumber  = OrphanAdapter->BusNumber;
1205       Adapter->BusType    = OrphanAdapter->BusType;
1206
1207       Status = HalAssignSlotResources(Miniport->RegistryPath, 0, Miniport->DriverObject,
1208           Adapter->NdisMiniportBlock.DeviceObject, Adapter->BusType, Adapter->BusNumber, 
1209           Adapter->SlotNumber, &ResourceList);
1210
1211       if(!NT_SUCCESS(Status))
1212         {
1213           NDIS_DbgPrint(MIN_TRACE, ("HalAssignSlotResources broke: 0x%x\n", Status));
1214 #ifdef DBG
1215           __asm__ ("int $3\n");
1216 #endif
1217           /* i guess we should just give up on this adapter */
1218           break;
1219         }
1220
1221       /* go through the returned resource list and populate the Adapter */
1222       for(i = 0; i<ResourceList->Count; i++)
1223         {
1224           int j;
1225
1226           PCM_FULL_RESOURCE_DESCRIPTOR ResourceDescriptor = &ResourceList->List[i];
1227
1228           for(j=0; j<ResourceDescriptor->PartialResourceList.Count; j++)
1229             {
1230               PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResourceDescriptor = 
1231                   &ResourceDescriptor->PartialResourceList.PartialDescriptors[i];
1232
1233               switch(PartialResourceDescriptor->Type)
1234                 {
1235                 case CmResourceTypeInterrupt:
1236                   Adapter->Irql = PartialResourceDescriptor->u.Interrupt.Level;
1237                   Adapter->Vector = PartialResourceDescriptor->u.Interrupt.Vector;
1238                   Adapter->Affinity = PartialResourceDescriptor->u.Interrupt.Affinity;
1239                   break;
1240
1241                 case CmResourceTypePort:
1242                   Adapter->BaseIoAddress = PartialResourceDescriptor->u.Port.Start;
1243                   break;
1244
1245                 case CmResourceTypeMemory:
1246                   Adapter->BaseMemoryAddress = PartialResourceDescriptor->u.Memory.Start;
1247                   break;
1248
1249                 case CmResourceTypeDma:
1250                   Adapter->DmaPort = PartialResourceDescriptor->u.Dma.Port;
1251                   Adapter->DmaChannel = PartialResourceDescriptor->u.Dma.Channel;
1252                   break;
1253
1254                 case CmResourceTypeDeviceSpecific:
1255                 default:
1256                   break;
1257                 }
1258             }
1259         }
1260
1261       /* remove the adapter from the list */
1262       TempAdapter = (PORPHAN_ADAPTER)OrphanAdapter->ListEntry.Flink;
1263       RemoveEntryList(&OrphanAdapter->ListEntry);
1264       OrphanAdapter = TempAdapter;
1265     }
1266   KeReleaseSpinLock(&OrphanAdapterListLock, OldIrql);
1267
1268   /* includes room for a 0-term */
1269   RegKeyPath = ExAllocatePool(PagedPool, (wcslen(SERVICES_ROOT) + wcslen(DeviceNameStr) + 1) * sizeof(WCHAR));
1270   if(!RegKeyPath)
1271     {
1272       NDIS_DbgPrint(MIN_TRACE,("Insufficient resources\n"));
1273       ExFreePool(Adapter);
1274       return; 
1275     }
1276
1277   wcscpy(RegKeyPath, SERVICES_ROOT);
1278   wcscat(RegKeyPath, DeviceNameStr);
1279   RegKeyPath[wcslen(SERVICES_ROOT) + wcslen(DeviceNameStr)] = 0;
1280
1281   RtlInitUnicodeString(&RegKeyPathU, RegKeyPath);
1282   InitializeObjectAttributes(&RegKeyAttributes, &RegKeyPathU, OBJ_CASE_INSENSITIVE, NULL, NULL);
1283
1284   Status = ZwOpenKey(&RegKeyHandle, KEY_ALL_ACCESS, &RegKeyAttributes);
1285   if(Status != STATUS_SUCCESS)
1286     {
1287       NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key %ws\n", RegKeyPath));
1288       ExFreePool(Adapter);
1289       return;
1290     }
1291
1292   NDIS_DbgPrint(MAX_TRACE, ("opened device reg key: %wZ\n", &RegKeyPathU));
1293
1294   KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1295   InitializeListHead(&Adapter->ProtocolListHead);
1296   Adapter->RefCount = 1;
1297   Adapter->Miniport = Miniport;
1298
1299   /* Set handlers (some NDIS macros require these) */
1300
1301   Adapter->NdisMiniportBlock.EthRxCompleteHandler = MiniEthReceiveComplete;
1302   Adapter->NdisMiniportBlock.EthRxIndicateHandler = MiniEthReceiveIndication;
1303   Adapter->NdisMiniportBlock.SendCompleteHandler  = MiniSendComplete;
1304   Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1305   Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1306   Adapter->NdisMiniportBlock.TDCompleteHandler    = MiniTransferDataComplete;
1307   Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1308
1309   KeInitializeDpc(&Adapter->MiniportDpc, MiniportDpc, (PVOID)Adapter);
1310
1311   /* Put adapter in adapter list for this miniport */
1312   ExInterlockedInsertTailList(&Miniport->AdapterListHead, &Adapter->MiniportListEntry, &Miniport->Lock);
1313
1314   /* Put adapter in global adapter list */
1315   ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1316
1317   /* Call MiniportInitialize */
1318   NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1319   NdisStatus = (*Miniport->Chars.InitializeHandler)( &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1320       MEDIA_ARRAY_SIZE, Adapter, RegKeyHandle);
1321
1322   ZwClose(RegKeyHandle);
1323
1324   if ((NdisStatus == NDIS_STATUS_SUCCESS) && (SelectedMediumIndex < MEDIA_ARRAY_SIZE)) 
1325     {
1326       NDIS_DbgPrint(MID_TRACE,("successful return from MiniportInitialize\n"));
1327
1328       Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1329
1330       switch (Adapter->NdisMiniportBlock.MediaType) 
1331         {
1332         case NdisMedium802_3:
1333           Adapter->MediumHeaderSize = 14;       /* XXX figure out what to do about LLC */
1334           AddressOID = OID_802_3_CURRENT_ADDRESS;
1335           Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1336
1337           Adapter->NdisMiniportBlock.FilterDbs.u.EthDB = ExAllocatePool(NonPagedPool, sizeof(ETH_FILTER));
1338           if (Adapter->NdisMiniportBlock.FilterDbs.u.EthDB) 
1339             {
1340               RtlZeroMemory(Adapter->NdisMiniportBlock.FilterDbs.u.EthDB, sizeof(ETH_FILTER));
1341               Adapter->NdisMiniportBlock.FilterDbs.u.EthDB->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1342             } 
1343           else
1344             MemError = TRUE;
1345
1346           break;
1347
1348         default:
1349           /* FIXME: Support other types of media */
1350           ExFreePool(Adapter);
1351           ASSERT(FALSE);
1352           return;
1353         }
1354
1355       NdisStatus = DoQueries(Adapter, AddressOID);
1356     }
1357
1358   if ((MemError) || (NdisStatus != NDIS_STATUS_SUCCESS) || (SelectedMediumIndex >= MEDIA_ARRAY_SIZE)) 
1359     {
1360       NDIS_DbgPrint(MAX_TRACE, ("return from MiniportInitialize: NdisStatus 0x%x, SelectedMediumIndex 0x%x\n",
1361           NdisStatus, SelectedMediumIndex));
1362
1363       /* Remove adapter from adapter list for this miniport */
1364       KeAcquireSpinLock(&Miniport->Lock, &OldIrql);
1365       RemoveEntryList(&Adapter->MiniportListEntry);
1366       KeReleaseSpinLock(&Miniport->Lock, OldIrql);
1367
1368       /* Remove adapter from global adapter list */
1369       KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1370       RemoveEntryList(&Adapter->ListEntry);
1371       KeReleaseSpinLock(&AdapterListLock, OldIrql);
1372
1373       if (Adapter->LookaheadBuffer)
1374         ExFreePool(Adapter->LookaheadBuffer);
1375
1376       IoDeleteDevice(Adapter->NdisMiniportBlock.DeviceObject);
1377       ExFreePool(Adapter);
1378       NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1379     }
1380 }
1381
1382 /*
1383  * @implemented
1384  */
1385 NDIS_STATUS
1386 EXPORT
1387 NdisMRegisterMiniport(
1388     IN  NDIS_HANDLE                     NdisWrapperHandle,
1389     IN  PNDIS_MINIPORT_CHARACTERISTICS  MiniportCharacteristics,
1390     IN  UINT                            CharacteristicsLength)
1391 /*
1392  * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1393  * ARGUMENTS:
1394  *     NdisWrapperHandle       = Pointer to handle returned by NdisMInitializeWrapper
1395  *     MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1396  *     CharacteristicsLength   = Number of bytes in characteristics buffer
1397  * RETURNS:
1398  *     Status of operation       
1399  * NOTES:
1400  *     - To create device objects for the miniport, the Route value under Linkage is
1401  *       parsed.  I don't know if this is the way Microsoft does it or not.
1402  * TODO: 
1403  *     verify this algorithm by playing with nt
1404  */
1405 {
1406     UINT MinSize;
1407     NTSTATUS Status;
1408     PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1409     OBJECT_ATTRIBUTES DeviceKeyAttributes;
1410     OBJECT_ATTRIBUTES LinkageKeyAttributes;
1411     HANDLE DeviceKeyHandle;
1412     HANDLE LinkageKeyHandle;
1413     UNICODE_STRING RouteVal;
1414     UNICODE_STRING LinkageKeyName;
1415     KEY_VALUE_PARTIAL_INFORMATION *RouteData;
1416     ULONG RouteDataLength;
1417     UINT NextRouteOffset = 0;
1418
1419     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1420
1421     switch (MiniportCharacteristics->MajorNdisVersion) {
1422     case 0x03:
1423         MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS_S);
1424         break;
1425
1426     case 0x04:
1427         MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS_S);
1428         break;
1429
1430     case 0x05:
1431         MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS_S);
1432         break;
1433
1434     default:
1435         NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1436         return NDIS_STATUS_BAD_VERSION;
1437     }
1438
1439     if (CharacteristicsLength < MinSize) {
1440         NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1441         return NDIS_STATUS_BAD_CHARACTERISTICS;
1442     }
1443
1444     /* Check if mandatory MiniportXxx functions are specified */
1445     if ((!MiniportCharacteristics->HaltHandler) ||
1446         (!MiniportCharacteristics->InitializeHandler)||
1447         (!MiniportCharacteristics->QueryInformationHandler) ||
1448         (!MiniportCharacteristics->ResetHandler) ||
1449         (!MiniportCharacteristics->SetInformationHandler)) {
1450         NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1451         return NDIS_STATUS_BAD_CHARACTERISTICS;
1452     }
1453
1454     if (MiniportCharacteristics->MajorNdisVersion == 0x03) {
1455         if (!MiniportCharacteristics->u1.SendHandler) {
1456             NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1457             return NDIS_STATUS_BAD_CHARACTERISTICS;
1458         }
1459     } else if (MiniportCharacteristics->MajorNdisVersion >= 0x04) {
1460         /* NDIS 4.0+ */
1461         if ((!MiniportCharacteristics->u1.SendHandler) &&
1462             (!MiniportCharacteristics->SendPacketsHandler)) {
1463             NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1464             return NDIS_STATUS_BAD_CHARACTERISTICS;
1465         }
1466     }
1467
1468     /* TODO: verify NDIS5 and NDIS5.1 */
1469
1470     RtlCopyMemory(&Miniport->Chars, MiniportCharacteristics, MinSize);
1471
1472     /*
1473      * extract the list of bound adapters from the registry's Route value
1474      * for this adapter.  It seems under WinNT that the Route value in the
1475      * Linkage subkey holds an entry for each miniport instance we know about.
1476      * This surely isn't how Windows does it, but it's better than nothing.
1477      */
1478
1479     /* Read the miniport config from the registry */
1480     InitializeObjectAttributes(&DeviceKeyAttributes, Miniport->RegistryPath, OBJ_CASE_INSENSITIVE, NULL, NULL);
1481
1482     Status = ZwOpenKey(&DeviceKeyHandle, KEY_READ, &DeviceKeyAttributes);
1483     if(!NT_SUCCESS(Status))
1484     {
1485         NDIS_DbgPrint(MIN_TRACE,("Failed to open driver key: 0x%x\n", Status));
1486         return NDIS_STATUS_FAILURE;
1487     }
1488
1489     RtlInitUnicodeString(&LinkageKeyName, L"Linkage");
1490     InitializeObjectAttributes(&LinkageKeyAttributes, &LinkageKeyName, OBJ_CASE_INSENSITIVE, DeviceKeyHandle, NULL);
1491
1492     Status = ZwOpenKey(&LinkageKeyHandle, KEY_READ, &LinkageKeyAttributes);
1493     if(!NT_SUCCESS(Status))
1494     {
1495         NDIS_DbgPrint(MIN_TRACE,("Failed to open Linkage key: 0x%x\n", Status));
1496         ZwClose(DeviceKeyHandle);
1497         return NDIS_STATUS_FAILURE;
1498     }
1499
1500     RouteData = ExAllocatePool(PagedPool, ROUTE_DATA_SIZE);
1501     if(!RouteData)
1502     {
1503         NDIS_DbgPrint(MIN_TRACE,("Insufficient resources\n"));
1504         ZwClose(LinkageKeyHandle);
1505         ZwClose(DeviceKeyHandle);
1506         return NDIS_STATUS_RESOURCES;
1507     }
1508
1509     RtlInitUnicodeString(&RouteVal, L"Route");
1510
1511     Status = ZwQueryValueKey(LinkageKeyHandle, &RouteVal, KeyValuePartialInformation, RouteData, ROUTE_DATA_SIZE, &RouteDataLength);
1512     if(!NT_SUCCESS(Status))
1513     {
1514         NDIS_DbgPrint(MIN_TRACE,("Failed to query Route value\n"));
1515         ZwClose(LinkageKeyHandle);
1516         ZwClose(DeviceKeyHandle);
1517         ExFreePool(RouteData);
1518         return NDIS_STATUS_FAILURE;
1519     }
1520
1521     ZwClose(LinkageKeyHandle);
1522     ZwClose(DeviceKeyHandle);
1523
1524     /* route is a REG_MULTI_SZ with each nic object created by NDI - create an adapter for each */
1525   while(*(RouteData->Data + NextRouteOffset))
1526     {
1527       NDIS_DbgPrint(MID_TRACE, ("Starting adapter %ws\n", (WCHAR *)(RouteData->Data + NextRouteOffset)));
1528
1529       NdisIStartAdapter((WCHAR *)(RouteData->Data + NextRouteOffset), 
1530           wcslen((WCHAR *)(RouteData->Data + NextRouteOffset)), Miniport);
1531
1532       NextRouteOffset += wcslen((WCHAR *)(RouteData->Data + NextRouteOffset)); 
1533     }
1534
1535     ExFreePool(RouteData);
1536     return NDIS_STATUS_SUCCESS;
1537 }
1538
1539
1540 /*
1541  * @implemented
1542  */
1543 VOID
1544 EXPORT
1545 NdisMResetComplete(
1546     IN NDIS_HANDLE MiniportAdapterHandle,
1547     IN NDIS_STATUS Status,
1548     IN BOOLEAN     AddressingReset)
1549 {
1550     MiniResetComplete(MiniportAdapterHandle,
1551                       Status,
1552                       AddressingReset);
1553 }
1554
1555
1556 /*
1557  * @implemented
1558  */
1559 VOID
1560 EXPORT
1561 NdisMSendComplete(
1562     IN  NDIS_HANDLE     MiniportAdapterHandle,
1563     IN  PNDIS_PACKET    Packet,
1564     IN  NDIS_STATUS     Status)
1565 /*
1566  * FUNCTION: Forwards a message to the initiating protocol saying
1567  *           that a packet was handled
1568  * ARGUMENTS:
1569  *     NdisAdapterHandle = Handle input to MiniportInitialize
1570  *     Packet            = Pointer to NDIS packet that was sent
1571  *     Status            = Status of send operation
1572  */
1573 {
1574     MiniSendComplete(MiniportAdapterHandle,
1575                      Packet,
1576                      Status);
1577 }
1578
1579
1580 /*
1581  * @implemented
1582  */
1583 VOID
1584 EXPORT
1585 NdisMSendResourcesAvailable(
1586     IN  NDIS_HANDLE MiniportAdapterHandle)
1587 {
1588     MiniSendResourcesAvailable(MiniportAdapterHandle);
1589 }
1590
1591
1592 /*
1593  * @implemented
1594  */
1595 VOID
1596 EXPORT
1597 NdisMTransferDataComplete(
1598     IN  NDIS_HANDLE     MiniportAdapterHandle,
1599     IN  PNDIS_PACKET    Packet,
1600     IN  NDIS_STATUS     Status,
1601     IN  UINT            BytesTransferred)
1602 {
1603     MiniTransferDataComplete(MiniportAdapterHandle,
1604                              Packet,
1605                              Status,
1606                              BytesTransferred);
1607 }
1608
1609
1610 /*
1611  * @implemented
1612  */
1613 VOID
1614 EXPORT
1615 NdisMSetInformationComplete(
1616     IN  NDIS_HANDLE MiniportAdapterHandle,
1617     IN  NDIS_STATUS Status)
1618 {
1619     PLOGICAL_ADAPTER Adapter        = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
1620     PADAPTER_BINDING AdapterBinding = (PADAPTER_BINDING)Adapter->MiniportAdapterBinding;
1621
1622     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1623
1624     (*AdapterBinding->ProtocolBinding->Chars.RequestCompleteHandler)(
1625         AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
1626         Adapter->NdisMiniportBlock.MediaRequest,
1627         Status);
1628 }
1629
1630
1631 /*
1632  * @implemented
1633  */
1634 VOID
1635 EXPORT
1636 NdisMSetAttributes(
1637     IN  NDIS_HANDLE         MiniportAdapterHandle,
1638     IN  NDIS_HANDLE         MiniportAdapterContext,
1639     IN  BOOLEAN             BusMaster,
1640     IN  NDIS_INTERFACE_TYPE AdapterType)
1641 /*
1642  * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1643  * ARGUMENTS:
1644  *     MiniportAdapterHandle  = Handle input to MiniportInitialize
1645  *     MiniportAdapterContext = Pointer to context information
1646  *     BusMaster              = Specifies TRUE if the caller's NIC is a busmaster DMA device
1647  *     AdapterType            = Specifies the I/O bus interface of the caller's NIC
1648  */
1649 {
1650     PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
1651
1652     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1653
1654     Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
1655     Adapter->Attributes    = BusMaster? NDIS_ATTRIBUTE_BUS_MASTER : 0;
1656     Adapter->NdisMiniportBlock.AdapterType   = AdapterType;
1657     Adapter->AttributesSet = TRUE;
1658 }
1659
1660
1661 /*
1662  * @implemented
1663  */
1664 VOID
1665 EXPORT
1666 NdisMSetAttributesEx(
1667     IN  NDIS_HANDLE         MiniportAdapterHandle,
1668     IN  NDIS_HANDLE         MiniportAdapterContext,
1669     IN  UINT                CheckForHangTimeInSeconds   OPTIONAL,
1670     IN  ULONG               AttributeFlags,
1671     IN  NDIS_INTERFACE_TYPE     AdapterType)
1672 /*
1673  * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1674  * ARGUMENTS:
1675  *     MiniportAdapterHandle     = Handle input to MiniportInitialize
1676  *     MiniportAdapterContext    = Pointer to context information
1677  *     CheckForHangTimeInSeconds = Specifies interval in seconds at which
1678  *                                 MiniportCheckForHang should be called
1679  *     AttributeFlags            = Bitmask that indicates specific attributes
1680  *     AdapterType               = Specifies the I/O bus interface of the caller's NIC
1681  */
1682 {
1683         // Currently just like NdisMSetAttributesEx
1684         // TODO: Take CheckForHandTimeInSeconds into account!
1685         PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
1686
1687     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1688     NDIS_DbgPrint(MAX_TRACE, ("NdisMSetAttributesEx() is partly-implemented.\n"));
1689
1690     Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
1691
1692     /* don't know why this is here - anybody? */
1693     Adapter->Attributes = AttributeFlags & NDIS_ATTRIBUTE_BUS_MASTER;
1694     Adapter->NdisMiniportBlock.AdapterType   = AdapterType;
1695     Adapter->AttributesSet = TRUE;
1696
1697     if(AttributeFlags & NDIS_ATTRIBUTE_DESERIALIZE)
1698       {
1699         NDIS_DbgPrint(MIN_TRACE, ("Deserialized miniport - UNIMPLEMENTED\n"));
1700 #ifdef DBG
1701         __asm__("int $3\n");
1702 #endif
1703       }
1704 }
1705
1706
1707 /*
1708  * @unimplemented
1709  */
1710 VOID
1711 EXPORT
1712 NdisMSleep(
1713     IN  ULONG   MicrosecondsToSleep)
1714 {
1715     UNIMPLEMENTED
1716 }
1717
1718
1719 /*
1720  * @unimplemented
1721  */
1722 BOOLEAN
1723 EXPORT
1724 NdisMSynchronizeWithInterrupt(
1725     IN  PNDIS_MINIPORT_INTERRUPT    Interrupt,
1726     IN  PVOID                       SynchronizeFunction,
1727     IN  PVOID                       SynchronizeContext)
1728 {
1729     UNIMPLEMENTED
1730
1731     return FALSE;
1732 }
1733
1734
1735 /*
1736  * @unimplemented
1737  */
1738 NDIS_STATUS
1739 EXPORT
1740 NdisMWriteLogData(
1741     IN  NDIS_HANDLE LogHandle,
1742     IN  PVOID       LogBuffer,
1743     IN  UINT        LogBufferSize)
1744 {
1745     UNIMPLEMENTED
1746
1747         return NDIS_STATUS_FAILURE;
1748 }
1749
1750
1751 /*
1752  * @implemented
1753  */
1754 VOID
1755 EXPORT
1756 NdisTerminateWrapper(
1757     IN  NDIS_HANDLE NdisWrapperHandle,
1758     IN  PVOID       SystemSpecific)
1759 /*
1760  * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
1761  * ARGUMENTS:
1762  *     NdisWrapperHandle = Handle returned by NdisInitializeWrapper (MINIPORT_DRIVER)
1763  *     SystemSpecific    = Always NULL
1764  */
1765 {
1766     PMINIPORT_DRIVER Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1767
1768     NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1769
1770     ExFreePool(Miniport->RegistryPath->Buffer);
1771     ExFreePool(Miniport->RegistryPath);
1772     ExFreePool(Miniport);
1773 }
1774
1775 /* EOF */
1776 /* enum test */
1777          /*
1778     {
1779         ULONG KeyInformationSize;
1780         KEY_BASIC_INFORMATION *KeyInformation;
1781         int i;
1782
1783         KeyInformation = ExAllocatePool(PagedPool, 1024);
1784         ASSERT(KeyInformation);
1785
1786         RtlInitUnicodeString(&LinkageKeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NE2000");
1787         InitializeObjectAttributes(&LinkageKeyAttributes, &LinkageKeyName, OBJ_CASE_INSENSITIVE|OBJ_KERNEL_HANDLE, NULL, NULL);
1788
1789         Status = ZwOpenKey(&LinkageKeyHandle, KEY_READ, &LinkageKeyAttributes);
1790         if(!NT_SUCCESS(Status))
1791         {
1792                 DbgPrint("ndis!NdisMRegisterMiniport: Failed to open Linkage key: 0x%x\n", Status);
1793                 ASSERT(0);      
1794                 KeBugCheck(0);
1795         }
1796
1797         for(i=0;i<5;i++)
1798         {
1799             Status = ZwEnumerateKey(LinkageKeyHandle, i, KeyBasicInformation, KeyInformation, 1024, &KeyInformationSize);
1800             if(!NT_SUCCESS(Status))
1801             {
1802                 DbgPrint("ndis!NdisMRegisterMiniport: Failed to enumerate: 0x%x\n", Status);
1803                 break;
1804             }
1805            
1806             KeyInformation->Name[KeyInformation->NameLength/sizeof(WCHAR)] = 0;
1807             DbgPrint("ndis!NdisMRegisterMiniport: enumerated key %ws\n", KeyInformation->Name);
1808         }
1809
1810         ExFreePool(KeyInformation);
1811         KeBugCheck(0);
1812     }
1813          */