- Set MiniportBusy to TRUE if a request is pending
[reactos.git] / drivers / network / 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 * 20 Aug 2003 vizzini - DMA support
11 * 3 Oct 2003 vizzini - SendPackets support
12 */
13
14 #include "ndissys.h"
15 #include "efilter.h"
16
17 #ifdef DBG
18 #include <buffer.h>
19 #endif /* DBG */
20
21 #undef NdisMSendComplete
22 VOID
23 EXPORT
24 NdisMSendComplete(
25 IN NDIS_HANDLE MiniportAdapterHandle,
26 IN PNDIS_PACKET Packet,
27 IN NDIS_STATUS Status);
28
29 /* Root of the scm database */
30 #define SERVICES_ROOT L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
31
32 /*
33 * Define to 1 to get a debugger breakpoint at the end of NdisInitializeWrapper
34 * for each new miniport starting up
35 */
36 #define BREAK_ON_MINIPORT_INIT 0
37
38 /*
39 * This has to be big enough to hold the results of querying the Route value
40 * from the Linkage key. Please re-code me to determine this dynamically.
41 */
42 #define ROUTE_DATA_SIZE 256
43
44 /* Number of media we know */
45 #define MEDIA_ARRAY_SIZE 15
46
47 static NDIS_MEDIUM MediaArray[MEDIA_ARRAY_SIZE] =
48 {
49 NdisMedium802_3,
50 NdisMedium802_5,
51 NdisMediumFddi,
52 NdisMediumWan,
53 NdisMediumLocalTalk,
54 NdisMediumDix,
55 NdisMediumArcnetRaw,
56 NdisMediumArcnet878_2,
57 NdisMediumAtm,
58 NdisMediumWirelessWan,
59 NdisMediumIrda,
60 NdisMediumBpc,
61 NdisMediumCoWan,
62 NdisMedium1394,
63 NdisMediumMax
64 };
65
66 /* global list and lock of Miniports NDIS has registered */
67 LIST_ENTRY MiniportListHead;
68 KSPIN_LOCK MiniportListLock;
69
70 /* global list and lock of adapters NDIS has registered */
71 LIST_ENTRY AdapterListHead;
72 KSPIN_LOCK AdapterListLock;
73
74 VOID
75 MiniDisplayPacket(
76 PNDIS_PACKET Packet)
77 {
78 #ifdef DBG
79 ULONG i, Length;
80 UCHAR Buffer[64];
81 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
82 Length = CopyPacketToBuffer(
83 Buffer,
84 Packet,
85 0,
86 64);
87
88 DbgPrint("*** PACKET START ***");
89
90 for (i = 0; i < Length; i++) {
91 if (i % 12 == 0)
92 DbgPrint("\n%04X ", i);
93 DbgPrint("%02X ", Buffer[i]);
94 }
95
96 DbgPrint("*** PACKET STOP ***\n");
97 }
98 #endif /* DBG */
99 }
100
101 VOID
102 MiniDisplayPacket2(
103 PVOID HeaderBuffer,
104 UINT HeaderBufferSize,
105 PVOID LookaheadBuffer,
106 UINT LookaheadBufferSize)
107 {
108 #ifdef DBG
109 if ((DebugTraceLevel & DEBUG_PACKET) > 0) {
110 ULONG i, Length;
111 PUCHAR p;
112
113 DbgPrint("*** RECEIVE PACKET START ***\n");
114 DbgPrint("HEADER:");
115 p = HeaderBuffer;
116 for (i = 0; i < HeaderBufferSize; i++) {
117 if (i % 16 == 0)
118 DbgPrint("\n%04X ", i);
119 DbgPrint("%02X ", *p++);
120 }
121
122 DbgPrint("\nFRAME:");
123
124 p = LookaheadBuffer;
125 Length = (LookaheadBufferSize < 64)? LookaheadBufferSize : 64;
126 for (i = 0; i < Length; i++) {
127 if (i % 16 == 0)
128 DbgPrint("\n%04X ", i);
129 DbgPrint("%02X ", *p++);
130 }
131
132 DbgPrint("\n*** RECEIVE PACKET STOP ***\n");
133 }
134 #endif /* DBG */
135 }
136
137 \f
138 VOID
139 MiniIndicateData(
140 PLOGICAL_ADAPTER Adapter,
141 NDIS_HANDLE MacReceiveContext,
142 PVOID HeaderBuffer,
143 UINT HeaderBufferSize,
144 PVOID LookaheadBuffer,
145 UINT LookaheadBufferSize,
146 UINT PacketSize)
147 /*
148 * FUNCTION: Indicate received data to bound protocols
149 * ARGUMENTS:
150 * Adapter = Pointer to logical adapter
151 * MacReceiveContext = MAC receive context handle
152 * HeaderBuffer = Pointer to header buffer
153 * HeaderBufferSize = Size of header buffer
154 * LookaheadBuffer = Pointer to lookahead buffer
155 * LookaheadBufferSize = Size of lookahead buffer
156 * PacketSize = Total size of received packet
157 */
158 {
159 KIRQL OldIrql;
160 PLIST_ENTRY CurrentEntry;
161 PADAPTER_BINDING AdapterBinding;
162
163 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called. Adapter (0x%X) HeaderBuffer (0x%X) "
164 "HeaderBufferSize (0x%X) LookaheadBuffer (0x%X) LookaheadBufferSize (0x%X).\n",
165 Adapter, HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize));
166
167 MiniDisplayPacket2(HeaderBuffer, HeaderBufferSize, LookaheadBuffer, LookaheadBufferSize);
168
169 NDIS_DbgPrint(MAX_TRACE, ("acquiring miniport block lock\n"));
170 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
171 {
172 CurrentEntry = Adapter->ProtocolListHead.Flink;
173 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurrentEntry = %x\n", CurrentEntry));
174
175 if (CurrentEntry == &Adapter->ProtocolListHead)
176 {
177 NDIS_DbgPrint(DEBUG_MINIPORT, ("WARNING: No upper protocol layer.\n"));
178 }
179
180 while (CurrentEntry != &Adapter->ProtocolListHead)
181 {
182 AdapterBinding = CONTAINING_RECORD(CurrentEntry, ADAPTER_BINDING, AdapterListEntry);
183 NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterBinding = %x\n", AdapterBinding));
184
185 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
186
187 #ifdef DBG
188 if(!AdapterBinding)
189 {
190 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding was null\n"));
191 break;
192 }
193
194 if(!AdapterBinding->ProtocolBinding)
195 {
196 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding was null\n"));
197 break;
198 }
199
200 if(!AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)
201 {
202 NDIS_DbgPrint(MIN_TRACE, ("AdapterBinding->ProtocolBinding->Chars.ReceiveHandler was null\n"));
203 break;
204 }
205 #endif
206
207 NDIS_DbgPrint
208 (MID_TRACE,
209 ("XXX (%x) %x %x %x %x %x %x %x XXX\n",
210 *AdapterBinding->ProtocolBinding->Chars.ReceiveHandler,
211 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
212 MacReceiveContext,
213 HeaderBuffer,
214 HeaderBufferSize,
215 LookaheadBuffer,
216 LookaheadBufferSize,
217 PacketSize));
218
219 /* call the receive handler */
220 (*AdapterBinding->ProtocolBinding->Chars.ReceiveHandler)(
221 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
222 MacReceiveContext,
223 HeaderBuffer,
224 HeaderBufferSize,
225 LookaheadBuffer,
226 LookaheadBufferSize,
227 PacketSize);
228
229 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
230
231 CurrentEntry = CurrentEntry->Flink;
232 }
233 }
234 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
235
236 NDIS_DbgPrint(MAX_TRACE, ("Leaving.\n"));
237 }
238
239 \f
240 VOID NTAPI
241 MiniIndicateReceivePacket(
242 IN NDIS_HANDLE Miniport,
243 IN PPNDIS_PACKET PacketArray,
244 IN UINT NumberOfPackets)
245 /*
246 * FUNCTION: receives miniport packet array indications
247 * ARGUMENTS:
248 * Miniport: Miniport handle for the adapter
249 * PacketArray: pointer to a list of packet pointers to indicate
250 * NumberOfPackets: number of packets to indicate
251 * NOTES:
252 * - This currently is a big temporary hack. In the future this should
253 * call ProtocolReceivePacket() on each bound protocol if it exists.
254 * For now it just mimics NdisMEthIndicateReceive.
255 */
256 {
257 UINT i;
258
259 for(i = 0; i < NumberOfPackets; i++)
260 {
261 PCHAR PacketBuffer = 0;
262 UINT PacketLength = 0;
263 PNDIS_BUFFER NdisBuffer = 0;
264
265 #define PACKET_TAG (('k' << 24) + ('P' << 16) + ('D' << 8) + 'N')
266
267 NdisAllocateMemoryWithTag((PVOID)&PacketBuffer, 1518, PACKET_TAG);
268 if(!PacketBuffer)
269 {
270 NDIS_DbgPrint(MIN_TRACE, ("insufficient resources\n"));
271 return;
272 }
273
274 NdisQueryPacket(PacketArray[i], NULL, NULL, &NdisBuffer, NULL);
275
276 while(NdisBuffer)
277 {
278 PNDIS_BUFFER CurrentBuffer;
279 PVOID BufferVa;
280 UINT BufferLen;
281
282 NdisQueryBuffer(NdisBuffer, &BufferVa, &BufferLen);
283 memcpy(PacketBuffer + PacketLength, BufferVa, BufferLen);
284 PacketLength += BufferLen;
285
286 CurrentBuffer = NdisBuffer;
287 NdisGetNextBuffer(CurrentBuffer, &NdisBuffer);
288 }
289
290 NDIS_DbgPrint(MID_TRACE, ("indicating a %d-byte packet\n", PacketLength));
291
292 MiniIndicateData(Miniport, NULL, PacketBuffer, 14, PacketBuffer+14, PacketLength-14, PacketLength-14);
293
294 NdisFreeMemory(PacketBuffer, 0, 0);
295 }
296 }
297
298 \f
299 VOID NTAPI
300 MiniResetComplete(
301 IN NDIS_HANDLE MiniportAdapterHandle,
302 IN NDIS_STATUS Status,
303 IN BOOLEAN AddressingReset)
304 {
305 UNIMPLEMENTED
306 }
307
308
309 \f
310 VOID NTAPI
311 MiniRequestComplete(
312 IN PNDIS_HANDLE MiniportAdapterHandle,
313 IN PNDIS_REQUEST Request,
314 IN NDIS_STATUS Status)
315 {
316 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportAdapterHandle;
317 PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)Request->MacReserved;
318 KIRQL OldIrql;
319
320 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
321
322 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
323 if( MacBlock->Binding->RequestCompleteHandler ) {
324 (*MacBlock->Binding->RequestCompleteHandler)(
325 MacBlock->Binding->ProtocolBindingContext,
326 Request,
327 Status);
328 }
329 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
330 Adapter->MiniportBusy = FALSE;
331 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
332 KeLowerIrql(OldIrql);
333 }
334
335 VOID NTAPI
336 MiniSendComplete(
337 IN NDIS_HANDLE MiniportAdapterHandle,
338 IN PNDIS_PACKET Packet,
339 IN NDIS_STATUS Status)
340 /*
341 * FUNCTION: Forwards a message to the initiating protocol saying
342 * that a packet was handled
343 * ARGUMENTS:
344 * NdisAdapterHandle = Handle input to MiniportInitialize
345 * Packet = Pointer to NDIS packet that was sent
346 * Status = Status of send operation
347 */
348 {
349 PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
350 PADAPTER_BINDING AdapterBinding;
351 KIRQL OldIrql;
352
353 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
354
355 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
356
357 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
358 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
359 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
360 Packet,
361 Status);
362 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
363 Adapter->MiniportBusy = FALSE;
364 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
365 KeLowerIrql(OldIrql);
366 }
367
368
369 VOID NTAPI
370 MiniSendResourcesAvailable(
371 IN NDIS_HANDLE MiniportAdapterHandle)
372 {
373 /*
374 UNIMPLEMENTED
375 */
376 }
377
378
379 VOID NTAPI
380 MiniTransferDataComplete(
381 IN NDIS_HANDLE MiniportAdapterHandle,
382 IN PNDIS_PACKET Packet,
383 IN NDIS_STATUS Status,
384 IN UINT BytesTransferred)
385 {
386 PLOGICAL_ADAPTER Adapter = MiniportAdapterHandle;
387 PADAPTER_BINDING AdapterBinding;
388 KIRQL OldIrql;
389
390 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
391
392 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
393
394 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
395 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
396 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
397 Packet,
398 Status);
399 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
400 Adapter->MiniportBusy = FALSE;
401 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
402 KeLowerIrql(OldIrql);
403 }
404
405 \f
406 BOOLEAN
407 MiniAdapterHasAddress(
408 PLOGICAL_ADAPTER Adapter,
409 PNDIS_PACKET Packet)
410 /*
411 * FUNCTION: Determines whether a packet has the same destination address as an adapter
412 * ARGUMENTS:
413 * Adapter = Pointer to logical adapter object
414 * Packet = Pointer to NDIS packet
415 * RETURNS:
416 * TRUE if the destination address is that of the adapter, FALSE if not
417 */
418 {
419 UINT Length;
420 PUCHAR Start1;
421 PUCHAR Start2;
422 PNDIS_BUFFER NdisBuffer;
423 UINT BufferLength;
424
425 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
426
427 #ifdef DBG
428 if(!Adapter)
429 {
430 NDIS_DbgPrint(MID_TRACE, ("Adapter object was null\n"));
431 return FALSE;
432 }
433
434 if(!Packet)
435 {
436 NDIS_DbgPrint(MID_TRACE, ("Packet was null\n"));
437 return FALSE;
438 }
439 #endif
440
441 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
442
443 if (!NdisBuffer)
444 {
445 NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
446 return FALSE;
447 }
448
449 NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
450
451 /* FIXME: Should handle fragmented packets */
452
453 switch (Adapter->NdisMiniportBlock.MediaType)
454 {
455 case NdisMedium802_3:
456 Length = ETH_LENGTH_OF_ADDRESS;
457 /* Destination address is the first field */
458 break;
459
460 default:
461 NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
462 return FALSE;
463 }
464
465 if (BufferLength < Length)
466 {
467 NDIS_DbgPrint(MID_TRACE, ("Buffer is too small.\n"));
468 return FALSE;
469 }
470
471 Start1 = (PUCHAR)&Adapter->Address;
472 NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
473 *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
474 *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5))
475 );
476
477 return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
478 }
479
480 \f
481 PLOGICAL_ADAPTER
482 MiniLocateDevice(
483 PNDIS_STRING AdapterName)
484 /*
485 * FUNCTION: Finds an adapter object by name
486 * ARGUMENTS:
487 * AdapterName = Pointer to name of adapter
488 * RETURNS:
489 * Pointer to logical adapter object, or NULL if none was found.
490 * If found, the adapter is referenced for the caller. The caller
491 * is responsible for dereferencing after use
492 */
493 {
494 KIRQL OldIrql;
495 PLIST_ENTRY CurrentEntry;
496 PLOGICAL_ADAPTER Adapter = 0;
497
498 ASSERT(AdapterName);
499
500 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
501
502 if(IsListEmpty(&AdapterListHead))
503 {
504 NDIS_DbgPrint(DEBUG_MINIPORT, ("No registered miniports for protocol to bind to\n"));
505 return NULL;
506 }
507
508 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
509 {
510 CurrentEntry = AdapterListHead.Flink;
511
512 while (CurrentEntry != &AdapterListHead)
513 {
514 Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
515
516 ASSERT(Adapter);
517
518 NDIS_DbgPrint(DEBUG_MINIPORT, ("Examining adapter 0x%lx\n", Adapter));
519 NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
520 NDIS_DbgPrint(DEBUG_MINIPORT, ("DeviceName = %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
521
522 if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
523 {
524 break;
525 }
526
527 Adapter = NULL;
528 CurrentEntry = CurrentEntry->Flink;
529 }
530 }
531 KeReleaseSpinLock(&AdapterListLock, OldIrql);
532
533 if(Adapter)
534 {
535 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
536 }
537 else
538 {
539 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
540 }
541
542 return Adapter;
543 }
544
545 \f
546 NDIS_STATUS
547 MiniQueryInformation(
548 PLOGICAL_ADAPTER Adapter,
549 NDIS_OID Oid,
550 ULONG Size,
551 PVOID Buffer,
552 PULONG BytesWritten)
553 /*
554 * FUNCTION: Queries a logical adapter for properties
555 * ARGUMENTS:
556 * Adapter = Pointer to the logical adapter object to query
557 * Oid = Specifies the Object ID to query for
558 * Size = Size of the passed buffer
559 * Buffer = Buffer for the output
560 * BytesWritten = Address of buffer to place number of bytes written
561 * NOTES:
562 * If the specified buffer is too small, a new buffer is allocated,
563 * and the query is attempted again
564 * RETURNS:
565 * Status of operation
566 * TODO:
567 * Is there any way to use the buffer provided by the protocol?
568 */
569 {
570 NDIS_STATUS NdisStatus;
571 ULONG BytesNeeded;
572 KIRQL OldIrql;
573
574 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
575
576 /* call the miniport's queryinfo handler */
577 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
578 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
579 Adapter->NdisMiniportBlock.MiniportAdapterContext,
580 Oid,
581 Buffer,
582 Size,
583 BytesWritten,
584 &BytesNeeded);
585 KeLowerIrql(OldIrql);
586
587 /* FIXME: Wait in pending case! */
588
589 return NdisStatus;
590 }
591
592 BOOLEAN
593 MiniCheckForHang( PLOGICAL_ADAPTER Adapter )
594 /*
595 * FUNCTION: Checks to see if the miniport is hung
596 * ARGUMENTS:
597 * Adapter = Pointer to the logical adapter object
598 * RETURNS:
599 * TRUE if the miniport is hung
600 * FALSE if the miniport is not hung
601 */
602 {
603 BOOLEAN Ret = FALSE;
604 KIRQL OldIrql;
605
606 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
607 if (Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)
608 Ret = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.CheckForHangHandler)(
609 Adapter->NdisMiniportBlock.MiniportAdapterContext);
610 KeLowerIrql(OldIrql);
611
612 return Ret;
613 }
614
615 NDIS_STATUS
616 MiniReset(
617 PLOGICAL_ADAPTER Adapter,
618 PBOOLEAN AddressingReset)
619 /*
620 * FUNCTION: Resets the miniport
621 * ARGUMENTS:
622 * Adapter = Pointer to the logical adapter object
623 * AddressingReset = Set to TRUE if we need to call MiniportSetInformation later
624 * RETURNS:
625 * Status of the operation
626 */
627 {
628 NDIS_STATUS Status;
629 KIRQL OldIrql;
630
631 if (Adapter->MiniportBusy) {
632 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
633 MiniQueueWorkItem(Adapter, NdisWorkItemResetRequested, NULL);
634 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
635 return NDIS_STATUS_PENDING;
636 }
637
638 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
639 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
640 Adapter->NdisMiniportBlock.MiniportAdapterContext,
641 AddressingReset);
642 KeLowerIrql(OldIrql);
643
644 return Status;
645 }
646
647 VOID STDCALL
648 MiniportHangDpc(
649 PKDPC Dpc,
650 PVOID DeferredContext,
651 PVOID SystemArgument1,
652 PVOID SystemArgument2)
653 {
654 PLOGICAL_ADAPTER Adapter = DeferredContext;
655 BOOLEAN AddressingReset = FALSE;
656
657
658 if (MiniCheckForHang(Adapter)) {
659 NDIS_DbgPrint(MIN_TRACE, ("Miniport detected adapter hang\n"));
660 MiniReset(Adapter, &AddressingReset);
661 }
662
663 /* FIXME: We should call MiniportSetInformation if AddressingReset is TRUE */
664 }
665
666 \f
667 NDIS_STATUS
668 FASTCALL
669 MiniQueueWorkItem(
670 PLOGICAL_ADAPTER Adapter,
671 NDIS_WORK_ITEM_TYPE WorkItemType,
672 PVOID WorkItemContext)
673 /*
674 * FUNCTION: Queues a work item for execution at a later time
675 * ARGUMENTS:
676 * Adapter = Pointer to the logical adapter object to queue work item on
677 * WorkItemType = Type of work item to queue
678 * WorkItemContext = Pointer to context information for work item
679 * NOTES:
680 * Adapter lock must be held when called
681 * RETURNS:
682 * Status of operation
683 */
684 {
685 PNDIS_MINIPORT_WORK_ITEM Item;
686
687 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
688
689 ASSERT(Adapter);
690 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
691
692 Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
693 if (Item == NULL)
694 {
695 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
696 return NDIS_STATUS_RESOURCES;
697 }
698
699 Item->WorkItemType = WorkItemType;
700 Item->WorkItemContext = WorkItemContext;
701
702 /* safe due to adapter lock held */
703 Item->Link.Next = NULL;
704 if (!Adapter->WorkQueueHead)
705 {
706 Adapter->WorkQueueHead = Item;
707 Adapter->WorkQueueTail = Item;
708 }
709 else
710 {
711 Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item;
712 Adapter->WorkQueueTail = Item;
713 }
714
715 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
716
717 return NDIS_STATUS_SUCCESS;
718 }
719
720 \f
721 NDIS_STATUS
722 FASTCALL
723 MiniDequeueWorkItem(
724 PLOGICAL_ADAPTER Adapter,
725 NDIS_WORK_ITEM_TYPE *WorkItemType,
726 PVOID *WorkItemContext)
727 /*
728 * FUNCTION: Dequeues a work item from the work queue of a logical adapter
729 * ARGUMENTS:
730 * Adapter = Pointer to the logical adapter object to dequeue work item from
731 * AdapterBinding = Address of buffer for adapter binding for this request
732 * WorkItemType = Address of buffer for work item type
733 * WorkItemContext = Address of buffer for pointer to context information
734 * NOTES:
735 * Adapter lock must be held when called
736 * RETURNS:
737 * Status of operation
738 */
739 {
740 PNDIS_MINIPORT_WORK_ITEM Item;
741
742 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
743
744 if (Adapter->MiniportBusy) {
745 NDIS_DbgPrint(MID_TRACE, ("Waiting for miniport to become free.\n"));
746 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
747 return NDIS_STATUS_FAILURE;
748 }
749
750 Item = Adapter->WorkQueueHead;
751
752 if (Item)
753 {
754 /* safe due to adapter lock held */
755 Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next;
756
757 if (Item == Adapter->WorkQueueTail)
758 Adapter->WorkQueueTail = NULL;
759
760 *WorkItemType = Item->WorkItemType;
761 *WorkItemContext = Item->WorkItemContext;
762
763 ExFreePool(Item);
764
765 Adapter->MiniportBusy = TRUE;
766
767 return NDIS_STATUS_SUCCESS;
768 }
769
770 return NDIS_STATUS_FAILURE;
771 }
772
773 \f
774 NDIS_STATUS
775 MiniDoRequest(
776 PLOGICAL_ADAPTER Adapter,
777 PNDIS_REQUEST NdisRequest)
778 /*
779 * FUNCTION: Sends a request to a miniport
780 * ARGUMENTS:
781 * AdapterBinding = Pointer to binding used in the request
782 * NdisRequest = Pointer to NDIS request structure describing request
783 * RETURNS:
784 * Status of operation
785 */
786 {
787 NDIS_STATUS Status;
788 KIRQL OldIrql;
789 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
790
791 Adapter->NdisMiniportBlock.MediaRequest = NdisRequest;
792
793 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
794 switch (NdisRequest->RequestType)
795 {
796 case NdisRequestQueryInformation:
797 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
798 Adapter->NdisMiniportBlock.MiniportAdapterContext,
799 NdisRequest->DATA.QUERY_INFORMATION.Oid,
800 NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
801 NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
802 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
803 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
804 break;
805
806 case NdisRequestSetInformation:
807 Status = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SetInformationHandler)(
808 Adapter->NdisMiniportBlock.MiniportAdapterContext,
809 NdisRequest->DATA.SET_INFORMATION.Oid,
810 NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
811 NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
812 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead,
813 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
814 break;
815
816 default:
817 Status = NDIS_STATUS_FAILURE;
818 }
819
820 if (Status == NDIS_STATUS_PENDING) {
821 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
822 Adapter->MiniportBusy = TRUE;
823 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
824 }
825
826 KeLowerIrql(OldIrql);
827 return Status;
828 }
829
830 \f
831 /*
832 * @implemented
833 */
834 #undef NdisMQueryInformationComplete
835 VOID
836 EXPORT
837 NdisMQueryInformationComplete(
838 IN NDIS_HANDLE MiniportAdapterHandle,
839 IN NDIS_STATUS Status)
840 {
841 PLOGICAL_ADAPTER Adapter =
842 (PLOGICAL_ADAPTER)MiniportAdapterHandle;
843 KIRQL OldIrql;
844 ASSERT(Adapter);
845 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
846 if( Adapter->NdisMiniportBlock.QueryCompleteHandler )
847 (Adapter->NdisMiniportBlock.QueryCompleteHandler)(MiniportAdapterHandle, Status);
848 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
849 Adapter->MiniportBusy = FALSE;
850 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
851 KeLowerIrql(OldIrql);
852 }
853
854 VOID NTAPI MiniportWorker(IN PVOID WorkItem)
855 {
856 PNDIS_WORK_ITEM NdisWorkItem = WorkItem;
857 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(NdisWorkItem->Context);
858 KIRQL OldIrql, RaiseOldIrql;
859 NDIS_STATUS NdisStatus;
860 PVOID WorkItemContext;
861 NDIS_WORK_ITEM_TYPE WorkItemType;
862 BOOLEAN AddressingReset;
863
864 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
865
866 NdisStatus =
867 MiniDequeueWorkItem
868 (Adapter, &WorkItemType, &WorkItemContext);
869
870 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
871
872 if (NdisStatus == NDIS_STATUS_SUCCESS)
873 {
874 switch (WorkItemType)
875 {
876 case NdisWorkItemSend:
877 /*
878 * called by ProSend when protocols want to send packets to the miniport
879 */
880 #ifdef DBG
881 MiniDisplayPacket((PNDIS_PACKET)WorkItemContext);
882 #endif
883 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
884 {
885 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
886 {
887 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
888 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
889 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
890 NdisStatus = NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
891 }
892 else
893 {
894 /* SendPackets is called at DISPATCH_LEVEL for all serialized miniports */
895 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
896 {
897 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
898 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
899 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
900 }
901 KeLowerIrql(RaiseOldIrql);
902
903 NdisStatus = NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
904 if( NdisStatus == NDIS_STATUS_RESOURCES ) {
905 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
906 MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext);
907 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
908 break;
909 }
910 }
911 }
912 else
913 {
914 if(Adapter->NdisMiniportBlock.Flags & NDIS_ATTRIBUTE_DESERIALIZE)
915 {
916 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
917 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
918 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
919 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
920 }
921 else
922 {
923 /* Send is called at DISPATCH_LEVEL for all serialized miniports */
924 KeRaiseIrql(DISPATCH_LEVEL, &RaiseOldIrql);
925 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
926 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
927 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
928 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's send handler\n"));
929 KeLowerIrql(RaiseOldIrql);
930 if( NdisStatus == NDIS_STATUS_RESOURCES ) {
931 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
932 MiniQueueWorkItem(Adapter, WorkItemType, WorkItemContext);
933 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
934 break;
935 }
936 }
937 }
938
939 if( NdisStatus != NDIS_STATUS_PENDING ) {
940 NdisMSendComplete
941 ( Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus );
942 }
943 break;
944
945 case NdisWorkItemSendLoopback:
946 /*
947 * called by ProSend when protocols want to send loopback packets
948 */
949 /* XXX atm ProIndicatePacket sends a packet up via the loopback adapter only */
950 NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
951
952 if( NdisStatus != NDIS_STATUS_PENDING )
953 MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
954 break;
955
956 case NdisWorkItemReturnPackets:
957 break;
958
959 case NdisWorkItemResetRequested:
960 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
961 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.ResetHandler)(
962 Adapter->NdisMiniportBlock.MiniportAdapterContext,
963 &AddressingReset);
964 KeLowerIrql(OldIrql);
965
966 if (NdisStatus == NDIS_STATUS_PENDING)
967 break;
968
969 MiniResetComplete(Adapter, NdisStatus, AddressingReset);
970 break;
971
972 case NdisWorkItemResetInProgress:
973 break;
974
975 case NdisWorkItemMiniportCallback:
976 break;
977
978 case NdisWorkItemRequest:
979 NdisStatus = MiniDoRequest(Adapter, (PNDIS_REQUEST)WorkItemContext);
980
981 if (NdisStatus == NDIS_STATUS_PENDING)
982 break;
983
984 switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
985 {
986 case NdisRequestQueryInformation:
987 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
988 MiniRequestComplete( (NDIS_HANDLE)Adapter, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
989 break;
990
991 case NdisRequestSetInformation:
992 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
993 MiniRequestComplete( (NDIS_HANDLE)Adapter, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
994 break;
995
996 default:
997 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
998 break;
999 }
1000 break;
1001
1002 default:
1003 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
1004 break;
1005 }
1006 }
1007
1008 if( NdisStatus != NDIS_STATUS_PENDING ) {
1009 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
1010 Adapter->MiniportBusy = FALSE;
1011 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
1012 }
1013
1014 ExFreePool(WorkItem);
1015 }
1016
1017
1018 \f
1019 VOID NTAPI MiniportDpc(
1020 IN PKDPC Dpc,
1021 IN PVOID DeferredContext,
1022 IN PVOID SystemArgument1,
1023 IN PVOID SystemArgument2)
1024 /*
1025 * FUNCTION: Deferred routine to handle serialization
1026 * ARGUMENTS:
1027 * Dpc = Pointer to DPC object
1028 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
1029 * SystemArgument1 = Unused
1030 * SystemArgument2 = Unused
1031 */
1032 {
1033 PNDIS_WORK_ITEM NdisWorkItem;
1034 PWORK_QUEUE_ITEM WorkItem;
1035
1036 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1037
1038 NdisWorkItem = ExAllocatePool(NonPagedPool, sizeof(NDIS_WORK_ITEM));
1039 if (!NdisWorkItem) return;
1040
1041 WorkItem = (PWORK_QUEUE_ITEM)NdisWorkItem->WrapperReserved;
1042
1043 NdisWorkItem->Context = DeferredContext;
1044
1045 ExInitializeWorkItem(WorkItem, MiniportWorker, NdisWorkItem);
1046
1047 ExQueueWorkItem(WorkItem, CriticalWorkQueue);
1048 }
1049
1050 \f
1051 VOID
1052 NTAPI
1053 MiniStatus(
1054 IN NDIS_HANDLE MiniportHandle,
1055 IN NDIS_STATUS GeneralStatus,
1056 IN PVOID StatusBuffer,
1057 IN UINT StatusBufferSize)
1058 {
1059 UNIMPLEMENTED
1060 }
1061
1062 \f
1063 VOID
1064 NTAPI
1065 MiniStatusComplete(
1066 IN NDIS_HANDLE MiniportAdapterHandle)
1067 {
1068 UNIMPLEMENTED
1069 }
1070
1071 \f
1072 /*
1073 * @unimplemented
1074 */
1075 VOID
1076 EXPORT
1077 NdisMCloseLog(
1078 IN NDIS_HANDLE LogHandle)
1079 {
1080 UNIMPLEMENTED
1081 }
1082
1083 \f
1084 /*
1085 * @unimplemented
1086 */
1087 NDIS_STATUS
1088 EXPORT
1089 NdisMCreateLog(
1090 IN NDIS_HANDLE MiniportAdapterHandle,
1091 IN UINT Size,
1092 OUT PNDIS_HANDLE LogHandle)
1093 {
1094 UNIMPLEMENTED
1095
1096 return NDIS_STATUS_FAILURE;
1097 }
1098
1099 \f
1100 /*
1101 * @implemented
1102 */
1103 VOID
1104 EXPORT
1105 NdisMDeregisterAdapterShutdownHandler(
1106 IN NDIS_HANDLE MiniportHandle)
1107 /*
1108 * FUNCTION: de-registers a shutdown handler
1109 * ARGUMENTS: MiniportHandle: Handle passed into MiniportInitialize
1110 */
1111 {
1112 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1113
1114 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1115
1116 if(Adapter->BugcheckContext->ShutdownHandler)
1117 KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
1118 }
1119
1120 \f
1121 /*
1122 * @unimplemented
1123 */
1124 VOID
1125 EXPORT
1126 NdisMFlushLog(
1127 IN NDIS_HANDLE LogHandle)
1128 {
1129 UNIMPLEMENTED
1130 }
1131
1132 /*
1133 * @unimplemented
1134 */
1135 #undef NdisMIndicateStatus
1136 VOID
1137 EXPORT
1138 NdisMIndicateStatus(
1139 IN NDIS_HANDLE MiniportAdapterHandle,
1140 IN NDIS_STATUS GeneralStatus,
1141 IN PVOID StatusBuffer,
1142 IN UINT StatusBufferSize)
1143 {
1144 UNIMPLEMENTED
1145 }
1146
1147 /*
1148 * @unimplemented
1149 */
1150 #undef NdisMIndicateStatusComplete
1151 VOID
1152 EXPORT
1153 NdisMIndicateStatusComplete(
1154 IN NDIS_HANDLE MiniportAdapterHandle)
1155 {
1156 UNIMPLEMENTED
1157 }
1158
1159 \f
1160 /*
1161 * @implemented
1162 */
1163 VOID
1164 EXPORT
1165 NdisInitializeWrapper(
1166 OUT PNDIS_HANDLE NdisWrapperHandle,
1167 IN PVOID SystemSpecific1,
1168 IN PVOID SystemSpecific2,
1169 IN PVOID SystemSpecific3)
1170 /*
1171 * FUNCTION: Notifies the NDIS library that a new miniport is initializing
1172 * ARGUMENTS:
1173 * NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
1174 * SystemSpecific1 = Pointer to the driver's driver object
1175 * SystemSpecific2 = Pointer to the driver's registry path
1176 * SystemSpecific3 = Always NULL
1177 * NOTES:
1178 * - SystemSpecific2 goes invalid so we copy it
1179 */
1180 {
1181 PNDIS_M_DRIVER_BLOCK Miniport;
1182 PUNICODE_STRING RegistryPath;
1183 WCHAR *RegistryBuffer;
1184
1185 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1186
1187 ASSERT(NdisWrapperHandle);
1188
1189 *NdisWrapperHandle = NULL;
1190
1191 #if BREAK_ON_MINIPORT_INIT
1192 __asm__ ("int $3\n");
1193 #endif
1194
1195 Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));
1196
1197 if (!Miniport)
1198 {
1199 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1200 return;
1201 }
1202
1203 RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));
1204
1205 KeInitializeSpinLock(&Miniport->Lock);
1206
1207 Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
1208
1209 /* set the miniport's driver registry path */
1210 RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
1211 if(!RegistryPath)
1212 {
1213 ExFreePool(Miniport);
1214 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1215 return;
1216 }
1217
1218 RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
1219 RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
1220
1221 RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
1222 if(!RegistryBuffer)
1223 {
1224 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1225 ExFreePool(Miniport);
1226 ExFreePool(RegistryPath);
1227 return;
1228 }
1229
1230 RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
1231 RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
1232
1233 RegistryPath->Buffer = RegistryBuffer;
1234 Miniport->RegistryPath = RegistryPath;
1235
1236 InitializeListHead(&Miniport->DeviceList);
1237
1238 /* Put miniport in global miniport list */
1239 ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
1240
1241 *NdisWrapperHandle = Miniport;
1242 }
1243
1244 \f
1245 VOID NTAPI NdisIBugcheckCallback(
1246 IN PVOID Buffer,
1247 IN ULONG Length)
1248 /*
1249 * FUNCTION: Internal callback for handling bugchecks - calls adapter's shutdown handler
1250 * ARGUMENTS:
1251 * Buffer: Pointer to a bugcheck callback context
1252 * Length: Unused
1253 */
1254 {
1255 PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
1256 ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
1257
1258 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1259
1260 if(sh)
1261 sh(Context->DriverContext);
1262 }
1263
1264 \f
1265 /*
1266 * @implemented
1267 */
1268 VOID
1269 EXPORT
1270 NdisMRegisterAdapterShutdownHandler(
1271 IN NDIS_HANDLE MiniportHandle,
1272 IN PVOID ShutdownContext,
1273 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
1274 /*
1275 * FUNCTION: Register a shutdown handler for an adapter
1276 * ARGUMENTS:
1277 * MiniportHandle: Handle originally passed into MiniportInitialize
1278 * ShutdownContext: Pre-initialized bugcheck context
1279 * ShutdownHandler: Function to call to handle the bugcheck
1280 * NOTES:
1281 * - I'm not sure about ShutdownContext
1282 */
1283 {
1284 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1285 PMINIPORT_BUGCHECK_CONTEXT BugcheckContext = Adapter->BugcheckContext;
1286
1287 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1288
1289 if(BugcheckContext)
1290 return;
1291
1292 BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1293 if(!BugcheckContext)
1294 {
1295 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1296 return;
1297 }
1298
1299 BugcheckContext->ShutdownHandler = ShutdownHandler;
1300 BugcheckContext->DriverContext = ShutdownContext;
1301
1302 BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1303
1304 KeInitializeCallbackRecord(BugcheckContext->CallbackRecord);
1305
1306 KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
1307 BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
1308 }
1309
1310 \f
1311 NDIS_STATUS
1312 DoQueries(
1313 PLOGICAL_ADAPTER Adapter,
1314 NDIS_OID AddressOID)
1315 /*
1316 * FUNCTION: Queries miniport for information
1317 * ARGUMENTS:
1318 * Adapter = Pointer to logical adapter
1319 * AddressOID = OID to use to query for current address
1320 * RETURNS:
1321 * Status of operation
1322 */
1323 {
1324 ULONG BytesWritten;
1325 NDIS_STATUS NdisStatus;
1326
1327 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1328
1329 /* Get MAC options for adapter */
1330 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, sizeof(UINT),
1331 &Adapter->NdisMiniportBlock.MacOptions,
1332 &BytesWritten);
1333
1334 if (NdisStatus != NDIS_STATUS_SUCCESS)
1335 {
1336 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1337 return NdisStatus;
1338 }
1339
1340 NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1341
1342 /* Get current hardware address of adapter */
1343 NdisStatus = MiniQueryInformation(Adapter, AddressOID, Adapter->AddressLength,
1344 &Adapter->Address, &BytesWritten);
1345
1346 if (NdisStatus != NDIS_STATUS_SUCCESS)
1347 {
1348 NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
1349 return NdisStatus;
1350 }
1351
1352 #ifdef DBG
1353 {
1354 /* 802.3 only */
1355
1356 PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1357
1358 NDIS_DbgPrint(MAX_TRACE, ("Adapter address is (%02X %02X %02X %02X %02X %02X).\n", A[0], A[1], A[2], A[3], A[4], A[5]));
1359 }
1360 #endif /* DBG */
1361
1362 /* Get maximum lookahead buffer size of adapter */
1363 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, sizeof(ULONG),
1364 &Adapter->NdisMiniportBlock.MaximumLookahead, &BytesWritten);
1365
1366 if (NdisStatus != NDIS_STATUS_SUCCESS)
1367 {
1368 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1369 return NdisStatus;
1370 }
1371
1372 NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
1373
1374 /* Get current lookahead buffer size of adapter */
1375 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, sizeof(ULONG),
1376 &Adapter->NdisMiniportBlock.CurrentLookahead, &BytesWritten);
1377
1378 if (NdisStatus != NDIS_STATUS_SUCCESS)
1379 {
1380 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1381 return NdisStatus;
1382 }
1383
1384 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_SEND_PACKETS, sizeof(ULONG),
1385 &Adapter->NdisMiniportBlock.MaxSendPackets, &BytesWritten);
1386
1387 if (NdisStatus != NDIS_STATUS_SUCCESS)
1388 {
1389 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_SEND_PACKETS failed. NdisStatus (0x%X).\n", NdisStatus));
1390
1391 /* Set it to 1 if it fails because some drivers don't support this (?)*/
1392 Adapter->NdisMiniportBlock.MaxSendPackets = 1;
1393 }
1394
1395 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
1396
1397 if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
1398 {
1399 Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
1400 Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
1401
1402 if (!Adapter->LookaheadBuffer)
1403 return NDIS_STATUS_RESOURCES;
1404 }
1405
1406 return STATUS_SUCCESS;
1407 }
1408
1409 \f
1410 NTSTATUS
1411 NTAPI
1412 NdisIForwardIrpAndWaitCompletionRoutine(
1413 PDEVICE_OBJECT Fdo,
1414 PIRP Irp,
1415 PVOID Context)
1416 {
1417 PKEVENT Event = Context;
1418
1419 if (Irp->PendingReturned)
1420 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1421
1422 return STATUS_MORE_PROCESSING_REQUIRED;
1423 }
1424
1425 \f
1426 NTSTATUS
1427 NTAPI
1428 NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
1429 {
1430 KEVENT Event;
1431 NTSTATUS Status;
1432
1433 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1434 IoCopyCurrentIrpStackLocationToNext(Irp);
1435 IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
1436 TRUE, TRUE, TRUE);
1437 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1438 if (Status == STATUS_PENDING)
1439 {
1440 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1441 Status = Irp->IoStatus.Status;
1442 }
1443 return Status;
1444 }
1445
1446 \f
1447 NTSTATUS
1448 NTAPI
1449 NdisIPnPStartDevice(
1450 IN PDEVICE_OBJECT DeviceObject,
1451 PIRP Irp)
1452 /*
1453 * FUNCTION: Handle the PnP start device event
1454 * ARGUMENTS:
1455 * DeviceObejct = Functional Device Object
1456 * Irp = IRP_MN_START_DEVICE I/O request packet
1457 * RETURNS:
1458 * Status of operation
1459 */
1460 {
1461 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1462 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1463 NDIS_WRAPPER_CONTEXT WrapperContext;
1464 NDIS_STATUS NdisStatus;
1465 NDIS_STATUS OpenErrorStatus;
1466 NTSTATUS Status;
1467 UINT SelectedMediumIndex = 0;
1468 NDIS_OID AddressOID;
1469 BOOLEAN Success = FALSE;
1470 ULONG ResourceCount;
1471 ULONG ResourceListSize;
1472 UNICODE_STRING ParamName;
1473 PNDIS_CONFIGURATION_PARAMETER ConfigParam;
1474 NDIS_HANDLE ConfigHandle;
1475 ULONG Size;
1476 LARGE_INTEGER Timeout;
1477 /* FIXME - KIRQL OldIrql; */
1478
1479 /*
1480 * Prepare wrapper context used by HW and configuration routines.
1481 */
1482
1483 NDIS_DbgPrint(DEBUG_MINIPORT, ("Start Device %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
1484
1485 NDIS_DbgPrint(MAX_TRACE, ("Inserting adapter 0x%x into adapter list\n", Adapter));
1486
1487 /* Put adapter in global adapter list */
1488 ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1489
1490 Status = IoOpenDeviceRegistryKey(
1491 Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
1492 KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
1493 if (!NT_SUCCESS(Status))
1494 {
1495 NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
1496 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1497 return Status;
1498 }
1499
1500 NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
1501
1502 WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
1503
1504 /*
1505 * Store the adapter resources used by HW routines such as
1506 * NdisMQueryAdapterResources.
1507 */
1508
1509 if (Stack->Parameters.StartDevice.AllocatedResources != NULL)
1510 {
1511 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1512 PartialResourceList.Count;
1513 ResourceListSize =
1514 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1515 PartialDescriptors[ResourceCount]);
1516
1517 Adapter->NdisMiniportBlock.AllocatedResources =
1518 ExAllocatePool(PagedPool, ResourceListSize);
1519 if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
1520 {
1521 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1522 return STATUS_INSUFFICIENT_RESOURCES;
1523 }
1524
1525 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
1526 Stack->Parameters.StartDevice.AllocatedResources,
1527 ResourceListSize);
1528 }
1529
1530 if (Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
1531 {
1532 ResourceCount = Stack->Parameters.StartDevice.AllocatedResourcesTranslated->List[0].
1533 PartialResourceList.Count;
1534 ResourceListSize =
1535 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1536 PartialDescriptors[ResourceCount]);
1537
1538 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
1539 ExAllocatePool(PagedPool, ResourceListSize);
1540 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
1541 {
1542 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1543 return STATUS_INSUFFICIENT_RESOURCES;
1544 }
1545
1546 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
1547 Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
1548 ResourceListSize);
1549 }
1550
1551 /*
1552 * Store the Bus Type, Bus Number and Slot information. It's used by
1553 * the hardware routines then.
1554 */
1555
1556 NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
1557
1558 Size = sizeof(ULONG);
1559 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1560 DevicePropertyLegacyBusType, Size,
1561 &Adapter->NdisMiniportBlock.BusType, &Size);
1562 if (!NT_SUCCESS(Status) || (INTERFACE_TYPE)Adapter->NdisMiniportBlock.BusType == InterfaceTypeUndefined)
1563 {
1564 NdisInitUnicodeString(&ParamName, L"BusType");
1565 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1566 &ParamName, NdisParameterInteger);
1567 if (NdisStatus == NDIS_STATUS_SUCCESS)
1568 Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
1569 else
1570 Adapter->NdisMiniportBlock.BusType = Isa;
1571 }
1572
1573 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1574 DevicePropertyBusNumber, Size,
1575 &Adapter->NdisMiniportBlock.BusNumber, &Size);
1576 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == 0xFFFFFFF0)
1577 {
1578 NdisInitUnicodeString(&ParamName, L"BusNumber");
1579 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1580 &ParamName, NdisParameterInteger);
1581 if (NdisStatus == NDIS_STATUS_SUCCESS)
1582 Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
1583 else
1584 Adapter->NdisMiniportBlock.BusNumber = 0;
1585 }
1586 WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
1587
1588 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1589 DevicePropertyAddress, Size,
1590 &Adapter->NdisMiniportBlock.SlotNumber, &Size);
1591 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == (NDIS_INTERFACE_TYPE)-1)
1592 {
1593 NdisInitUnicodeString(&ParamName, L"SlotNumber");
1594 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1595 &ParamName, NdisParameterInteger);
1596 if (NdisStatus == NDIS_STATUS_SUCCESS)
1597 Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
1598 else
1599 Adapter->NdisMiniportBlock.SlotNumber = 0;
1600 }
1601 else
1602 {
1603 /* Convert slotnumber to PCI_SLOT_NUMBER */
1604 ULONG PciSlotNumber = Adapter->NdisMiniportBlock.SlotNumber;
1605 PCI_SLOT_NUMBER SlotNumber;
1606
1607 SlotNumber.u.AsULONG = 0;
1608 SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
1609 SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
1610
1611 Adapter->NdisMiniportBlock.SlotNumber = SlotNumber.u.AsULONG;
1612 }
1613 NdisCloseConfiguration(ConfigHandle);
1614
1615 /* Set handlers (some NDIS macros require these) */
1616 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1617 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1618 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1619 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1620 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1621 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1622 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1623 Adapter->NdisMiniportBlock.StatusHandler = MiniStatus;
1624 Adapter->NdisMiniportBlock.StatusCompleteHandler= MiniStatusComplete;
1625
1626 /*
1627 * Call MiniportInitialize.
1628 */
1629
1630 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1631 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
1632 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1633 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1634
1635 ZwClose(WrapperContext.RegistryHandle);
1636
1637 if (NdisStatus != NDIS_STATUS_SUCCESS ||
1638 SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1639 {
1640 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1641 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1642 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1643 return (NTSTATUS)NdisStatus;
1644 }
1645
1646 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1647
1648 switch (Adapter->NdisMiniportBlock.MediaType)
1649 {
1650 case NdisMedium802_3:
1651 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1652 AddressOID = OID_802_3_CURRENT_ADDRESS;
1653 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1654 NdisStatus = DoQueries(Adapter, AddressOID);
1655 if (NdisStatus == NDIS_STATUS_SUCCESS)
1656 {
1657 Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
1658 Adapter->Address.Type.Medium802_3,
1659 &Adapter->NdisMiniportBlock.EthDB);
1660 if (Success)
1661 ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1662 else
1663 NdisStatus = NDIS_STATUS_RESOURCES;
1664 }
1665 break;
1666
1667 default:
1668 /* FIXME: Support other types of media */
1669 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1670 ASSERT(FALSE);
1671 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1672 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1673 return STATUS_UNSUCCESSFUL;
1674 }
1675
1676 if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
1677 {
1678 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1679 if (Adapter->LookaheadBuffer)
1680 {
1681 ExFreePool(Adapter->LookaheadBuffer);
1682 Adapter->LookaheadBuffer = NULL;
1683 }
1684 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1685 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1686 return (NTSTATUS)NdisStatus;
1687 }
1688
1689 /* Check for a hang every two seconds if it wasn't set in MiniportInitialize */
1690 if (Adapter->NdisMiniportBlock.CheckForHangSeconds == 0)
1691 Adapter->NdisMiniportBlock.CheckForHangSeconds = 2;
1692
1693 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1694 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1695
1696 Timeout.QuadPart = (LONGLONG)Adapter->NdisMiniportBlock.CheckForHangSeconds * -1000000;
1697 KeSetTimerEx(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer, Timeout,
1698 Adapter->NdisMiniportBlock.CheckForHangSeconds * 1000,
1699 &Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc);
1700
1701 /* Put adapter in adapter list for this miniport */
1702 ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1703
1704 return STATUS_SUCCESS;
1705 }
1706
1707 \f
1708 NTSTATUS
1709 NTAPI
1710 NdisIPnPStopDevice(
1711 IN PDEVICE_OBJECT DeviceObject,
1712 PIRP Irp)
1713 /*
1714 * FUNCTION: Handle the PnP stop device event
1715 * ARGUMENTS:
1716 * DeviceObejct = Functional Device Object
1717 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1718 * RETURNS:
1719 * Status of operation
1720 */
1721 {
1722 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1723 KIRQL OldIrql;
1724
1725 /* Remove adapter from adapter list for this miniport */
1726 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, &OldIrql);
1727 RemoveEntryList(&Adapter->MiniportListEntry);
1728 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, OldIrql);
1729
1730 /* Remove adapter from global adapter list */
1731 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1732 RemoveEntryList(&Adapter->ListEntry);
1733 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1734
1735 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
1736
1737 if (Adapter->LookaheadBuffer)
1738 {
1739 ExFreePool(Adapter->LookaheadBuffer);
1740 Adapter->LookaheadBuffer = NULL;
1741 }
1742 if (Adapter->NdisMiniportBlock.AllocatedResources)
1743 {
1744 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1745 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1746 }
1747 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1748 {
1749 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1750 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1751 }
1752
1753 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1754 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1755
1756 KeCancelTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
1757
1758 return STATUS_SUCCESS;
1759 }
1760
1761 \f
1762 NTSTATUS
1763 NTAPI
1764 NdisIDispatchPnp(
1765 IN PDEVICE_OBJECT DeviceObject,
1766 PIRP Irp)
1767 {
1768 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1769 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1770 NTSTATUS Status;
1771
1772 switch (Stack->MinorFunction)
1773 {
1774 case IRP_MN_START_DEVICE:
1775 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1776 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1777 {
1778 Status = NdisIPnPStartDevice(DeviceObject, Irp);
1779 }
1780 Irp->IoStatus.Status = Status;
1781 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1782 break;
1783
1784 case IRP_MN_STOP_DEVICE:
1785 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1786 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1787 {
1788 Status = NdisIPnPStopDevice(DeviceObject, Irp);
1789 }
1790 Irp->IoStatus.Status = Status;
1791 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1792 break;
1793
1794 case IRP_MN_QUERY_DEVICE_RELATIONS:
1795 Status = STATUS_NOT_SUPPORTED;
1796 Irp->IoStatus.Status = Status;
1797 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1798 break;
1799
1800 default:
1801 IoSkipCurrentIrpStackLocation(Irp);
1802 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1803 break;
1804 }
1805
1806 return Status;
1807 }
1808
1809 \f
1810 NTSTATUS
1811 NTAPI
1812 NdisIAddDevice(
1813 IN PDRIVER_OBJECT DriverObject,
1814 IN PDEVICE_OBJECT PhysicalDeviceObject)
1815 /*
1816 * FUNCTION: Create a device for an adapter found using PnP
1817 * ARGUMENTS:
1818 * DriverObject = Pointer to the miniport driver object
1819 * PhysicalDeviceObject = Pointer to the PDO for our adapter
1820 */
1821 {
1822 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
1823 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
1824 PNDIS_M_DRIVER_BLOCK Miniport;
1825 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1826 WCHAR *LinkageKeyBuffer;
1827 ULONG DriverKeyLength;
1828 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1829 UNICODE_STRING ExportName;
1830 PDEVICE_OBJECT DeviceObject;
1831 PLOGICAL_ADAPTER Adapter;
1832 NTSTATUS Status;
1833
1834 /*
1835 * Gain the access to the miniport data structure first.
1836 */
1837
1838 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
1839 if (MiniportPtr == NULL)
1840 {
1841 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
1842 return STATUS_UNSUCCESSFUL;
1843 }
1844 Miniport = *MiniportPtr;
1845
1846 /*
1847 * Get name of the Linkage registry key for our adapter. It's located under
1848 * the driver key for our driver and so we have basicly two ways to do it.
1849 * Either we can use IoOpenDriverRegistryKey or compose it using information
1850 * gathered by IoGetDeviceProperty. I choosed the second because
1851 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
1852 */
1853
1854 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1855 0, NULL, &DriverKeyLength);
1856 if (Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_SUCCESS)
1857 {
1858 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
1859 return Status;
1860 }
1861
1862 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
1863 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
1864 if (LinkageKeyBuffer == NULL)
1865 {
1866 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
1867 return STATUS_INSUFFICIENT_RESOURCES;
1868 }
1869
1870 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1871 DriverKeyLength, LinkageKeyBuffer +
1872 (sizeof(ClassKeyName) / sizeof(WCHAR)),
1873 &DriverKeyLength);
1874 if (!NT_SUCCESS(Status))
1875 {
1876 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
1877 ExFreePool(LinkageKeyBuffer);
1878 return Status;
1879 }
1880
1881 /* Compose the linkage key name. */
1882 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
1883 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
1884 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
1885
1886 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
1887
1888 /*
1889 * Now open the linkage key and read the "Export" and "RootDevice" values
1890 * which contains device name and root service respectively.
1891 */
1892
1893 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1894 RtlInitUnicodeString(&ExportName, NULL);
1895 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1896 QueryTable[0].Name = L"Export";
1897 QueryTable[0].EntryContext = &ExportName;
1898
1899 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
1900 QueryTable, NULL, NULL);
1901 ExFreePool(LinkageKeyBuffer);
1902 if (!NT_SUCCESS(Status))
1903 {
1904 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
1905 return Status;
1906 }
1907
1908 /*
1909 * Create the device object.
1910 */
1911
1912 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
1913
1914 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
1915 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
1916 0, FALSE, &DeviceObject);
1917 if (!NT_SUCCESS(Status))
1918 {
1919 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1920 RtlFreeUnicodeString(&ExportName);
1921 return Status;
1922 }
1923
1924 /*
1925 * Initialize the adapter structure.
1926 */
1927
1928 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1929 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1930 InitializeListHead(&Adapter->ProtocolListHead);
1931 Adapter->NdisMiniportBlock.DriverHandle = Miniport;
1932
1933 Adapter->NdisMiniportBlock.MiniportName = ExportName;
1934
1935 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
1936 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
1937 Adapter->NdisMiniportBlock.NextDeviceObject =
1938 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
1939 PhysicalDeviceObject);
1940
1941 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
1942 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
1943
1944 KeInitializeTimer(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Timer);
1945 KeInitializeDpc(&Adapter->NdisMiniportBlock.WakeUpDpcTimer.Dpc, MiniportHangDpc, Adapter);
1946 KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, Adapter);
1947
1948 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1949
1950 return STATUS_SUCCESS;
1951 }
1952
1953 \f
1954 /*
1955 * @implemented
1956 */
1957 NDIS_STATUS
1958 EXPORT
1959 NdisMRegisterMiniport(
1960 IN NDIS_HANDLE NdisWrapperHandle,
1961 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
1962 IN UINT CharacteristicsLength)
1963 /*
1964 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1965 * ARGUMENTS:
1966 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
1967 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1968 * CharacteristicsLength = Number of bytes in characteristics buffer
1969 * RETURNS:
1970 * Status of operation
1971 */
1972 {
1973 UINT MinSize;
1974 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1975 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1976 NTSTATUS Status;
1977
1978 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1979
1980 switch (MiniportCharacteristics->MajorNdisVersion)
1981 {
1982 case 0x03:
1983 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
1984 break;
1985
1986 case 0x04:
1987 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
1988 break;
1989
1990 case 0x05:
1991 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
1992 break;
1993
1994 default:
1995 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1996 return NDIS_STATUS_BAD_VERSION;
1997 }
1998
1999 if (CharacteristicsLength < MinSize)
2000 {
2001 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2002 return NDIS_STATUS_BAD_CHARACTERISTICS;
2003 }
2004
2005 /* Check if mandatory MiniportXxx functions are specified */
2006 if ((!MiniportCharacteristics->HaltHandler) ||
2007 (!MiniportCharacteristics->InitializeHandler)||
2008 (!MiniportCharacteristics->QueryInformationHandler) ||
2009 (!MiniportCharacteristics->ResetHandler) ||
2010 (!MiniportCharacteristics->SetInformationHandler))
2011 {
2012 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2013 return NDIS_STATUS_BAD_CHARACTERISTICS;
2014 }
2015
2016 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
2017 {
2018 if (!MiniportCharacteristics->SendHandler)
2019 {
2020 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2021 return NDIS_STATUS_BAD_CHARACTERISTICS;
2022 }
2023 }
2024 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
2025 {
2026 /* NDIS 4.0+ */
2027 if ((!MiniportCharacteristics->SendHandler) &&
2028 (!MiniportCharacteristics->SendPacketsHandler))
2029 {
2030 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
2031 return NDIS_STATUS_BAD_CHARACTERISTICS;
2032 }
2033 }
2034
2035 /* TODO: verify NDIS5 and NDIS5.1 */
2036
2037 RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
2038
2039 /*
2040 * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
2041 * structure in the driver extension or what?
2042 */
2043
2044 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
2045 sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
2046 if (!NT_SUCCESS(Status))
2047 {
2048 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
2049 return NDIS_STATUS_RESOURCES;
2050 }
2051
2052 *MiniportPtr = Miniport;
2053
2054 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
2055 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
2056
2057 return NDIS_STATUS_SUCCESS;
2058 }
2059
2060 \f
2061 /*
2062 * @implemented
2063 */
2064 #undef NdisMResetComplete
2065 VOID
2066 EXPORT
2067 NdisMResetComplete(
2068 IN NDIS_HANDLE MiniportAdapterHandle,
2069 IN NDIS_STATUS Status,
2070 IN BOOLEAN AddressingReset)
2071 {
2072 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
2073 }
2074
2075 \f
2076 /*
2077 * @implemented
2078 */
2079 #undef NdisMSendComplete
2080 VOID
2081 EXPORT
2082 NdisMSendComplete(
2083 IN NDIS_HANDLE MiniportAdapterHandle,
2084 IN PNDIS_PACKET Packet,
2085 IN NDIS_STATUS Status)
2086 /*
2087 * FUNCTION: Forwards a message to the initiating protocol saying
2088 * that a packet was handled
2089 * ARGUMENTS:
2090 * NdisAdapterHandle = Handle input to MiniportInitialize
2091 * Packet = Pointer to NDIS packet that was sent
2092 * Status = Status of send operation
2093 */
2094 {
2095 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
2096 }
2097
2098 \f
2099 /*
2100 * @implemented
2101 */
2102 #undef NdisMSendResourcesAvailable
2103 VOID
2104 EXPORT
2105 NdisMSendResourcesAvailable(
2106 IN NDIS_HANDLE MiniportAdapterHandle)
2107 {
2108 MiniSendResourcesAvailable(MiniportAdapterHandle);
2109 }
2110
2111 \f
2112 /*
2113 * @implemented
2114 */
2115 #undef NdisMTransferDataComplete
2116 VOID
2117 EXPORT
2118 NdisMTransferDataComplete(
2119 IN NDIS_HANDLE MiniportAdapterHandle,
2120 IN PNDIS_PACKET Packet,
2121 IN NDIS_STATUS Status,
2122 IN UINT BytesTransferred)
2123 {
2124 MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
2125 }
2126
2127 \f
2128 /*
2129 * @implemented
2130 */
2131 #undef NdisMSetInformationComplete
2132 VOID
2133 EXPORT
2134 NdisMSetInformationComplete(
2135 IN NDIS_HANDLE MiniportAdapterHandle,
2136 IN NDIS_STATUS Status)
2137 {
2138 PLOGICAL_ADAPTER Adapter =
2139 (PLOGICAL_ADAPTER)MiniportAdapterHandle;
2140 KIRQL OldIrql;
2141 ASSERT(Adapter);
2142 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
2143 (Adapter->NdisMiniportBlock.SetCompleteHandler)(MiniportAdapterHandle, Status);
2144 KeAcquireSpinLockAtDpcLevel(&Adapter->NdisMiniportBlock.Lock);
2145 Adapter->MiniportBusy = FALSE;
2146 KeReleaseSpinLockFromDpcLevel(&Adapter->NdisMiniportBlock.Lock);
2147 KeLowerIrql(OldIrql);
2148 }
2149
2150 \f
2151 /*
2152 * @implemented
2153 */
2154 #undef NdisMSetAttributes
2155 VOID
2156 EXPORT
2157 NdisMSetAttributes(
2158 IN NDIS_HANDLE MiniportAdapterHandle,
2159 IN NDIS_HANDLE MiniportAdapterContext,
2160 IN BOOLEAN BusMaster,
2161 IN NDIS_INTERFACE_TYPE AdapterType)
2162 /*
2163 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2164 * ARGUMENTS:
2165 * MiniportAdapterHandle = Handle input to MiniportInitialize
2166 * MiniportAdapterContext = Pointer to context information
2167 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
2168 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2169 */
2170 {
2171 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2172 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
2173 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
2174 AdapterType);
2175 }
2176
2177 \f
2178 /*
2179 * @implemented
2180 */
2181 VOID
2182 EXPORT
2183 NdisMSetAttributesEx(
2184 IN NDIS_HANDLE MiniportAdapterHandle,
2185 IN NDIS_HANDLE MiniportAdapterContext,
2186 IN UINT CheckForHangTimeInSeconds OPTIONAL,
2187 IN ULONG AttributeFlags,
2188 IN NDIS_INTERFACE_TYPE AdapterType)
2189 /*
2190 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
2191 * ARGUMENTS:
2192 * MiniportAdapterHandle = Handle input to MiniportInitialize
2193 * MiniportAdapterContext = Pointer to context information
2194 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
2195 * MiniportCheckForHang should be called
2196 * AttributeFlags = Bitmask that indicates specific attributes
2197 * AdapterType = Specifies the I/O bus interface of the caller's NIC
2198 */
2199 {
2200 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
2201
2202 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2203
2204 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2205 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2206 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2207 if (CheckForHangTimeInSeconds > 0)
2208 Adapter->NdisMiniportBlock.CheckForHangSeconds = CheckForHangTimeInSeconds;
2209 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2210 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2211 }
2212
2213 \f
2214 /*
2215 * @implemented
2216 */
2217 VOID
2218 EXPORT
2219 NdisMSleep(
2220 IN ULONG MicrosecondsToSleep)
2221 /*
2222 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2223 * ARGUMENTS:
2224 * MicrosecondsToSleep: duh...
2225 * NOTES:
2226 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2227 */
2228 {
2229 KTIMER Timer;
2230 LARGE_INTEGER DueTime;
2231
2232 PAGED_CODE();
2233
2234 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2235
2236 KeInitializeTimer(&Timer);
2237 KeSetTimer(&Timer, DueTime, 0);
2238 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2239 }
2240
2241 \f
2242 /*
2243 * @implemented
2244 */
2245 BOOLEAN
2246 EXPORT
2247 NdisMSynchronizeWithInterrupt(
2248 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2249 IN PVOID SynchronizeFunction,
2250 IN PVOID SynchronizeContext)
2251 {
2252 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2253 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2254 SynchronizeContext));
2255 }
2256
2257 \f
2258 /*
2259 * @unimplemented
2260 */
2261 NDIS_STATUS
2262 EXPORT
2263 NdisMWriteLogData(
2264 IN NDIS_HANDLE LogHandle,
2265 IN PVOID LogBuffer,
2266 IN UINT LogBufferSize)
2267 {
2268 PUCHAR Buffer = LogBuffer;
2269 UINT i, j, idx;
2270
2271 UNIMPLEMENTED;
2272 for (i = 0; i < LogBufferSize; i += 16)
2273 {
2274 DbgPrint("%08x |", i);
2275 for (j = 0; j < 16; j++)
2276 {
2277 idx = i + j;
2278 if (idx < LogBufferSize)
2279 DbgPrint(" %02x", Buffer[idx]);
2280 else
2281 DbgPrint(" ");
2282 }
2283 DbgPrint(" | ");
2284 for (j = 0; j < 16; j++)
2285 {
2286 idx = i + j;
2287 if (idx == LogBufferSize)
2288 break;
2289 if (Buffer[idx] >= ' ') /* FIXME: not portable! replace by if (isprint(Buffer[idx])) ? */
2290 DbgPrint("%c", Buffer[idx]);
2291 else
2292 DbgPrint(".");
2293 }
2294 DbgPrint("\n");
2295 }
2296
2297 return NDIS_STATUS_FAILURE;
2298 }
2299
2300 \f
2301 /*
2302 * @implemented
2303 */
2304 VOID
2305 EXPORT
2306 NdisTerminateWrapper(
2307 IN NDIS_HANDLE NdisWrapperHandle,
2308 IN PVOID SystemSpecific)
2309 /*
2310 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2311 * ARGUMENTS:
2312 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
2313 * SystemSpecific = Always NULL
2314 */
2315 {
2316 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2317
2318 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2319
2320 ExFreePool(Miniport->RegistryPath->Buffer);
2321 ExFreePool(Miniport->RegistryPath);
2322 ExFreePool(Miniport);
2323 }
2324
2325 /* EOF */
2326