- We must call MiniDequeueWorkItem while holding a spin lock
[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_MINIPORT_BLOCK Adapter,
313 IN PNDIS_REQUEST Request,
314 IN NDIS_STATUS Status)
315 {
316 PNDIS_REQUEST_MAC_BLOCK MacBlock = (PNDIS_REQUEST_MAC_BLOCK)Request->MacReserved;
317 KIRQL OldIrql;
318
319 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
320
321 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
322 if( MacBlock->Binding->RequestCompleteHandler ) {
323 (*MacBlock->Binding->RequestCompleteHandler)(
324 MacBlock->Binding->ProtocolBindingContext,
325 Request,
326 Status);
327 }
328 KeLowerIrql(OldIrql);
329 }
330
331 VOID NTAPI
332 MiniSendComplete(
333 IN NDIS_HANDLE MiniportAdapterHandle,
334 IN PNDIS_PACKET Packet,
335 IN NDIS_STATUS Status)
336 /*
337 * FUNCTION: Forwards a message to the initiating protocol saying
338 * that a packet was handled
339 * ARGUMENTS:
340 * NdisAdapterHandle = Handle input to MiniportInitialize
341 * Packet = Pointer to NDIS packet that was sent
342 * Status = Status of send operation
343 */
344 {
345 PADAPTER_BINDING AdapterBinding;
346 KIRQL OldIrql;
347
348 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
349
350 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
351
352 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
353 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
354 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
355 Packet,
356 Status);
357 KeLowerIrql(OldIrql);
358 }
359
360
361 VOID NTAPI
362 MiniSendResourcesAvailable(
363 IN NDIS_HANDLE MiniportAdapterHandle)
364 {
365 /*
366 UNIMPLEMENTED
367 */
368 }
369
370
371 VOID NTAPI
372 MiniTransferDataComplete(
373 IN NDIS_HANDLE MiniportAdapterHandle,
374 IN PNDIS_PACKET Packet,
375 IN NDIS_STATUS Status,
376 IN UINT BytesTransferred)
377 {
378 PADAPTER_BINDING AdapterBinding;
379 KIRQL OldIrql;
380
381 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
382
383 AdapterBinding = (PADAPTER_BINDING)Packet->Reserved[0];
384
385 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
386 (*AdapterBinding->ProtocolBinding->Chars.SendCompleteHandler)(
387 AdapterBinding->NdisOpenBlock.ProtocolBindingContext,
388 Packet,
389 Status);
390 KeLowerIrql(OldIrql);
391 }
392
393 \f
394 BOOLEAN
395 MiniAdapterHasAddress(
396 PLOGICAL_ADAPTER Adapter,
397 PNDIS_PACKET Packet)
398 /*
399 * FUNCTION: Determines whether a packet has the same destination address as an adapter
400 * ARGUMENTS:
401 * Adapter = Pointer to logical adapter object
402 * Packet = Pointer to NDIS packet
403 * RETURNS:
404 * TRUE if the destination address is that of the adapter, FALSE if not
405 */
406 {
407 UINT Length;
408 PUCHAR Start1;
409 PUCHAR Start2;
410 PNDIS_BUFFER NdisBuffer;
411 UINT BufferLength;
412
413 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
414
415 #ifdef DBG
416 if(!Adapter)
417 {
418 NDIS_DbgPrint(MID_TRACE, ("Adapter object was null\n"));
419 return FALSE;
420 }
421
422 if(!Packet)
423 {
424 NDIS_DbgPrint(MID_TRACE, ("Packet was null\n"));
425 return FALSE;
426 }
427 #endif
428
429 NdisQueryPacket(Packet, NULL, NULL, &NdisBuffer, NULL);
430
431 if (!NdisBuffer)
432 {
433 NDIS_DbgPrint(MID_TRACE, ("Packet contains no buffers.\n"));
434 return FALSE;
435 }
436
437 NdisQueryBuffer(NdisBuffer, (PVOID)&Start2, &BufferLength);
438
439 /* FIXME: Should handle fragmented packets */
440
441 switch (Adapter->NdisMiniportBlock.MediaType)
442 {
443 case NdisMedium802_3:
444 Length = ETH_LENGTH_OF_ADDRESS;
445 /* Destination address is the first field */
446 break;
447
448 default:
449 NDIS_DbgPrint(MIN_TRACE, ("Adapter has unsupported media type (0x%X).\n", Adapter->NdisMiniportBlock.MediaType));
450 return FALSE;
451 }
452
453 if (BufferLength < Length)
454 {
455 NDIS_DbgPrint(MID_TRACE, ("Buffer is too small.\n"));
456 return FALSE;
457 }
458
459 Start1 = (PUCHAR)&Adapter->Address;
460 NDIS_DbgPrint(MAX_TRACE, ("packet address: %x:%x:%x:%x:%x:%x adapter address: %x:%x:%x:%x:%x:%x\n",
461 *((char *)Start1), *(((char *)Start1)+1), *(((char *)Start1)+2), *(((char *)Start1)+3), *(((char *)Start1)+4), *(((char *)Start1)+5),
462 *((char *)Start2), *(((char *)Start2)+1), *(((char *)Start2)+2), *(((char *)Start2)+3), *(((char *)Start2)+4), *(((char *)Start2)+5))
463 );
464
465 return (RtlCompareMemory((PVOID)Start1, (PVOID)Start2, Length) == Length);
466 }
467
468 \f
469 PLOGICAL_ADAPTER
470 MiniLocateDevice(
471 PNDIS_STRING AdapterName)
472 /*
473 * FUNCTION: Finds an adapter object by name
474 * ARGUMENTS:
475 * AdapterName = Pointer to name of adapter
476 * RETURNS:
477 * Pointer to logical adapter object, or NULL if none was found.
478 * If found, the adapter is referenced for the caller. The caller
479 * is responsible for dereferencing after use
480 */
481 {
482 KIRQL OldIrql;
483 PLIST_ENTRY CurrentEntry;
484 PLOGICAL_ADAPTER Adapter = 0;
485
486 ASSERT(AdapterName);
487
488 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
489
490 if(IsListEmpty(&AdapterListHead))
491 {
492 NDIS_DbgPrint(DEBUG_MINIPORT, ("No registered miniports for protocol to bind to\n"));
493 return NULL;
494 }
495
496 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
497 {
498 CurrentEntry = AdapterListHead.Flink;
499
500 while (CurrentEntry != &AdapterListHead)
501 {
502 Adapter = CONTAINING_RECORD(CurrentEntry, LOGICAL_ADAPTER, ListEntry);
503
504 ASSERT(Adapter);
505
506 NDIS_DbgPrint(DEBUG_MINIPORT, ("Examining adapter 0x%lx\n", Adapter));
507 NDIS_DbgPrint(DEBUG_MINIPORT, ("AdapterName = %wZ\n", AdapterName));
508 NDIS_DbgPrint(DEBUG_MINIPORT, ("DeviceName = %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
509
510 if (RtlCompareUnicodeString(AdapterName, &Adapter->NdisMiniportBlock.MiniportName, TRUE) == 0)
511 {
512 break;
513 }
514
515 Adapter = NULL;
516 CurrentEntry = CurrentEntry->Flink;
517 }
518 }
519 KeReleaseSpinLock(&AdapterListLock, OldIrql);
520
521 if(Adapter)
522 {
523 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving. Adapter found at 0x%x\n", Adapter));
524 }
525 else
526 {
527 NDIS_DbgPrint(DEBUG_MINIPORT, ("Leaving (adapter not found).\n"));
528 }
529
530 return Adapter;
531 }
532
533 \f
534 NDIS_STATUS
535 MiniQueryInformation(
536 PLOGICAL_ADAPTER Adapter,
537 NDIS_OID Oid,
538 ULONG Size,
539 PVOID Buffer,
540 PULONG BytesWritten)
541 /*
542 * FUNCTION: Queries a logical adapter for properties
543 * ARGUMENTS:
544 * Adapter = Pointer to the logical adapter object to query
545 * Oid = Specifies the Object ID to query for
546 * Size = Size of the passed buffer
547 * Buffer = Buffer for the output
548 * BytesWritten = Address of buffer to place number of bytes written
549 * NOTES:
550 * If the specified buffer is too small, a new buffer is allocated,
551 * and the query is attempted again
552 * RETURNS:
553 * Status of operation
554 * TODO:
555 * Is there any way to use the buffer provided by the protocol?
556 */
557 {
558 NDIS_STATUS NdisStatus;
559 ULONG BytesNeeded;
560 KIRQL OldIrql;
561
562 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
563
564 /* call the miniport's queryinfo handler */
565 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
566 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
567 Adapter->NdisMiniportBlock.MiniportAdapterContext,
568 Oid,
569 Buffer,
570 Size,
571 BytesWritten,
572 &BytesNeeded);
573 KeLowerIrql(OldIrql);
574
575 /* FIXME: Wait in pending case! */
576
577 return NdisStatus;
578 }
579
580 \f
581 NDIS_STATUS
582 FASTCALL
583 MiniQueueWorkItem(
584 PLOGICAL_ADAPTER Adapter,
585 NDIS_WORK_ITEM_TYPE WorkItemType,
586 PVOID WorkItemContext)
587 /*
588 * FUNCTION: Queues a work item for execution at a later time
589 * ARGUMENTS:
590 * Adapter = Pointer to the logical adapter object to queue work item on
591 * WorkItemType = Type of work item to queue
592 * WorkItemContext = Pointer to context information for work item
593 * NOTES:
594 * Adapter lock must be held when called
595 * RETURNS:
596 * Status of operation
597 */
598 {
599 PNDIS_MINIPORT_WORK_ITEM Item;
600
601 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
602
603 ASSERT(Adapter);
604 ASSERT(KeGetCurrentIrql() >= DISPATCH_LEVEL);
605
606 Item = ExAllocatePool(NonPagedPool, sizeof(NDIS_MINIPORT_WORK_ITEM));
607 if (Item == NULL)
608 {
609 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
610 return NDIS_STATUS_RESOURCES;
611 }
612
613 Item->WorkItemType = WorkItemType;
614 Item->WorkItemContext = WorkItemContext;
615
616 /* safe due to adapter lock held */
617 Item->Link.Next = NULL;
618 if (!Adapter->WorkQueueHead)
619 {
620 Adapter->WorkQueueHead = Item;
621 Adapter->WorkQueueTail = Item;
622 }
623 else
624 {
625 Adapter->WorkQueueTail->Link.Next = (PSINGLE_LIST_ENTRY)Item;
626 Adapter->WorkQueueTail = Item;
627 }
628
629 KeInsertQueueDpc(&Adapter->NdisMiniportBlock.DeferredDpc, NULL, NULL);
630
631 return NDIS_STATUS_SUCCESS;
632 }
633
634 \f
635 NDIS_STATUS
636 FASTCALL
637 MiniDequeueWorkItem(
638 PLOGICAL_ADAPTER Adapter,
639 NDIS_WORK_ITEM_TYPE *WorkItemType,
640 PVOID *WorkItemContext)
641 /*
642 * FUNCTION: Dequeues a work item from the work queue of a logical adapter
643 * ARGUMENTS:
644 * Adapter = Pointer to the logical adapter object to dequeue work item from
645 * AdapterBinding = Address of buffer for adapter binding for this request
646 * WorkItemType = Address of buffer for work item type
647 * WorkItemContext = Address of buffer for pointer to context information
648 * NOTES:
649 * Adapter lock must be held when called
650 * RETURNS:
651 * Status of operation
652 */
653 {
654 PNDIS_MINIPORT_WORK_ITEM Item;
655
656 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
657
658 Item = Adapter->WorkQueueHead;
659
660 if (Item)
661 {
662 /* safe due to adapter lock held */
663 Adapter->WorkQueueHead = (PNDIS_MINIPORT_WORK_ITEM)Item->Link.Next;
664
665 if (Item == Adapter->WorkQueueTail)
666 Adapter->WorkQueueTail = NULL;
667
668 *WorkItemType = Item->WorkItemType;
669 *WorkItemContext = Item->WorkItemContext;
670
671 ExFreePool(Item);
672
673 return NDIS_STATUS_SUCCESS;
674 }
675
676 return NDIS_STATUS_FAILURE;
677 }
678
679 \f
680 NDIS_STATUS
681 MiniDoRequest(
682 PNDIS_MINIPORT_BLOCK Adapter,
683 PNDIS_REQUEST NdisRequest)
684 /*
685 * FUNCTION: Sends a request to a miniport
686 * ARGUMENTS:
687 * AdapterBinding = Pointer to binding used in the request
688 * NdisRequest = Pointer to NDIS request structure describing request
689 * RETURNS:
690 * Status of operation
691 */
692 {
693 NDIS_STATUS Status;
694 KIRQL OldIrql;
695 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
696
697 Adapter->MediaRequest = NdisRequest;
698
699 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
700 switch (NdisRequest->RequestType)
701 {
702 case NdisRequestQueryInformation:
703 Status = (*Adapter->DriverHandle->MiniportCharacteristics.QueryInformationHandler)(
704 Adapter->MiniportAdapterContext,
705 NdisRequest->DATA.QUERY_INFORMATION.Oid,
706 NdisRequest->DATA.QUERY_INFORMATION.InformationBuffer,
707 NdisRequest->DATA.QUERY_INFORMATION.InformationBufferLength,
708 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesWritten,
709 (PULONG)&NdisRequest->DATA.QUERY_INFORMATION.BytesNeeded);
710 break;
711
712 case NdisRequestSetInformation:
713 Status = (*Adapter->DriverHandle->MiniportCharacteristics.SetInformationHandler)(
714 Adapter->MiniportAdapterContext,
715 NdisRequest->DATA.SET_INFORMATION.Oid,
716 NdisRequest->DATA.SET_INFORMATION.InformationBuffer,
717 NdisRequest->DATA.SET_INFORMATION.InformationBufferLength,
718 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesRead,
719 (PULONG)&NdisRequest->DATA.SET_INFORMATION.BytesNeeded);
720 break;
721
722 default:
723 Status = NDIS_STATUS_FAILURE;
724 }
725
726 KeLowerIrql(OldIrql);
727 return Status;
728 }
729
730 \f
731 /*
732 * @implemented
733 */
734 #undef NdisMQueryInformationComplete
735 VOID
736 EXPORT
737 NdisMQueryInformationComplete(
738 IN NDIS_HANDLE MiniportAdapterHandle,
739 IN NDIS_STATUS Status)
740 {
741 PNDIS_MINIPORT_BLOCK MiniportBlock =
742 (PNDIS_MINIPORT_BLOCK)MiniportAdapterHandle;
743 KIRQL OldIrql;
744 ASSERT(MiniportBlock);
745 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
746 if( MiniportBlock->QueryCompleteHandler )
747 (MiniportBlock->QueryCompleteHandler)(MiniportAdapterHandle, Status);
748 KeLowerIrql(OldIrql);
749 }
750
751 \f
752 VOID NTAPI MiniportDpc(
753 IN PKDPC Dpc,
754 IN PVOID DeferredContext,
755 IN PVOID SystemArgument1,
756 IN PVOID SystemArgument2)
757 /*
758 * FUNCTION: Deferred routine to handle serialization
759 * ARGUMENTS:
760 * Dpc = Pointer to DPC object
761 * DeferredContext = Pointer to context information (LOGICAL_ADAPTER)
762 * SystemArgument1 = Unused
763 * SystemArgument2 = Unused
764 */
765 {
766 NDIS_STATUS NdisStatus;
767 PVOID WorkItemContext;
768 NDIS_WORK_ITEM_TYPE WorkItemType;
769 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(DeferredContext);
770 KIRQL OldIrql;
771
772 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
773
774 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.Lock, &OldIrql);
775
776 NdisStatus =
777 MiniDequeueWorkItem
778 (Adapter, &WorkItemType, &WorkItemContext);
779
780 if (NdisStatus == NDIS_STATUS_SUCCESS)
781 {
782 switch (WorkItemType)
783 {
784 case NdisWorkItemSend:
785 /*
786 * called by ProSend when protocols want to send packets to the miniport
787 */
788 #ifdef DBG
789 MiniDisplayPacket((PNDIS_PACKET)WorkItemContext);
790 #endif
791 if(Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)
792 {
793 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's SendPackets handler\n"));
794
795 /*
796 * XXX assumes single-packet - prolly OK since we'll call something
797 * different on multi-packet sends
798 */
799 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendPacketsHandler)(
800 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PPNDIS_PACKET)&WorkItemContext, 1);
801 NdisStatus =
802 NDIS_GET_PACKET_STATUS((PNDIS_PACKET)WorkItemContext);
803
804 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's SendPackets handler\n"));
805 }
806 else
807 {
808 NDIS_DbgPrint(MAX_TRACE, ("Calling miniport's Send handler\n"));
809
810 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.SendHandler)(
811 Adapter->NdisMiniportBlock.MiniportAdapterContext, (PNDIS_PACKET)WorkItemContext, 0);
812
813 NDIS_DbgPrint(MAX_TRACE, ("back from miniport's Send handler\n"));
814 }
815 if( NdisStatus != NDIS_STATUS_PENDING ) {
816 NdisMSendComplete
817 ( Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus );
818 Adapter->MiniportBusy = FALSE;
819 }
820 break;
821
822 case NdisWorkItemSendLoopback:
823 /*
824 * called by ProSend when protocols want to send loopback packets
825 */
826 /* XXX atm ProIndicatePacket sends a packet up via the loopback adapter only */
827 NdisStatus = ProIndicatePacket(Adapter, (PNDIS_PACKET)WorkItemContext);
828 MiniSendComplete((NDIS_HANDLE)Adapter, (PNDIS_PACKET)WorkItemContext, NdisStatus);
829 break;
830
831 case NdisWorkItemReturnPackets:
832 break;
833
834 case NdisWorkItemResetRequested:
835 break;
836
837 case NdisWorkItemResetInProgress:
838 break;
839
840 case NdisWorkItemMiniportCallback:
841 break;
842
843 case NdisWorkItemRequest:
844 NdisStatus = MiniDoRequest(&Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext);
845
846 if (NdisStatus == NDIS_STATUS_PENDING)
847 break;
848
849 switch (((PNDIS_REQUEST)WorkItemContext)->RequestType)
850 {
851 case NdisRequestQueryInformation:
852 NdisMQueryInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
853 MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
854 break;
855
856 case NdisRequestSetInformation:
857 NdisMSetInformationComplete((NDIS_HANDLE)Adapter, NdisStatus);
858 MiniRequestComplete( &Adapter->NdisMiniportBlock, (PNDIS_REQUEST)WorkItemContext, NdisStatus );
859 break;
860
861 default:
862 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS request type.\n"));
863 break;
864 }
865 break;
866
867 default:
868 NDIS_DbgPrint(MIN_TRACE, ("Unknown NDIS work item type (%d).\n", WorkItemType));
869 break;
870 }
871 }
872
873 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql);
874 }
875
876 \f
877 VOID
878 NTAPI
879 MiniStatus(
880 IN NDIS_HANDLE MiniportHandle,
881 IN NDIS_STATUS GeneralStatus,
882 IN PVOID StatusBuffer,
883 IN UINT StatusBufferSize)
884 {
885 UNIMPLEMENTED
886 }
887
888 \f
889 VOID
890 NTAPI
891 MiniStatusComplete(
892 IN NDIS_HANDLE MiniportAdapterHandle)
893 {
894 UNIMPLEMENTED
895 }
896
897 \f
898 /*
899 * @unimplemented
900 */
901 VOID
902 EXPORT
903 NdisMCloseLog(
904 IN NDIS_HANDLE LogHandle)
905 {
906 UNIMPLEMENTED
907 }
908
909 \f
910 /*
911 * @unimplemented
912 */
913 NDIS_STATUS
914 EXPORT
915 NdisMCreateLog(
916 IN NDIS_HANDLE MiniportAdapterHandle,
917 IN UINT Size,
918 OUT PNDIS_HANDLE LogHandle)
919 {
920 UNIMPLEMENTED
921
922 return NDIS_STATUS_FAILURE;
923 }
924
925 \f
926 /*
927 * @implemented
928 */
929 VOID
930 EXPORT
931 NdisMDeregisterAdapterShutdownHandler(
932 IN NDIS_HANDLE MiniportHandle)
933 /*
934 * FUNCTION: de-registers a shutdown handler
935 * ARGUMENTS: MiniportHandle: Handle passed into MiniportInitialize
936 */
937 {
938 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
939
940 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
941
942 if(Adapter->BugcheckContext->ShutdownHandler)
943 KeDeregisterBugCheckCallback(Adapter->BugcheckContext->CallbackRecord);
944 }
945
946 \f
947 /*
948 * @unimplemented
949 */
950 VOID
951 EXPORT
952 NdisMFlushLog(
953 IN NDIS_HANDLE LogHandle)
954 {
955 UNIMPLEMENTED
956 }
957
958 /*
959 * @unimplemented
960 */
961 #undef NdisMIndicateStatus
962 VOID
963 EXPORT
964 NdisMIndicateStatus(
965 IN NDIS_HANDLE MiniportAdapterHandle,
966 IN NDIS_STATUS GeneralStatus,
967 IN PVOID StatusBuffer,
968 IN UINT StatusBufferSize)
969 {
970 UNIMPLEMENTED
971 }
972
973 /*
974 * @unimplemented
975 */
976 #undef NdisMIndicateStatusComplete
977 VOID
978 EXPORT
979 NdisMIndicateStatusComplete(
980 IN NDIS_HANDLE MiniportAdapterHandle)
981 {
982 UNIMPLEMENTED
983 }
984
985 \f
986 /*
987 * @implemented
988 */
989 VOID
990 EXPORT
991 NdisInitializeWrapper(
992 OUT PNDIS_HANDLE NdisWrapperHandle,
993 IN PVOID SystemSpecific1,
994 IN PVOID SystemSpecific2,
995 IN PVOID SystemSpecific3)
996 /*
997 * FUNCTION: Notifies the NDIS library that a new miniport is initializing
998 * ARGUMENTS:
999 * NdisWrapperHandle = Address of buffer to place NDIS wrapper handle
1000 * SystemSpecific1 = Pointer to the driver's driver object
1001 * SystemSpecific2 = Pointer to the driver's registry path
1002 * SystemSpecific3 = Always NULL
1003 * NOTES:
1004 * - SystemSpecific2 goes invalid so we copy it
1005 */
1006 {
1007 PNDIS_M_DRIVER_BLOCK Miniport;
1008 PUNICODE_STRING RegistryPath;
1009 WCHAR *RegistryBuffer;
1010
1011 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1012
1013 ASSERT(NdisWrapperHandle);
1014
1015 *NdisWrapperHandle = NULL;
1016
1017 #if BREAK_ON_MINIPORT_INIT
1018 __asm__ ("int $3\n");
1019 #endif
1020
1021 Miniport = ExAllocatePool(NonPagedPool, sizeof(NDIS_M_DRIVER_BLOCK));
1022
1023 if (!Miniport)
1024 {
1025 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1026 return;
1027 }
1028
1029 RtlZeroMemory(Miniport, sizeof(NDIS_M_DRIVER_BLOCK));
1030
1031 KeInitializeSpinLock(&Miniport->Lock);
1032
1033 Miniport->DriverObject = (PDRIVER_OBJECT)SystemSpecific1;
1034
1035 /* set the miniport's driver registry path */
1036 RegistryPath = ExAllocatePool(PagedPool, sizeof(UNICODE_STRING));
1037 if(!RegistryPath)
1038 {
1039 ExFreePool(Miniport);
1040 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1041 return;
1042 }
1043
1044 RegistryPath->Length = ((PUNICODE_STRING)SystemSpecific2)->Length;
1045 RegistryPath->MaximumLength = RegistryPath->Length + sizeof(WCHAR); /* room for 0-term */
1046
1047 RegistryBuffer = ExAllocatePool(PagedPool, RegistryPath->MaximumLength);
1048 if(!RegistryBuffer)
1049 {
1050 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1051 ExFreePool(Miniport);
1052 ExFreePool(RegistryPath);
1053 return;
1054 }
1055
1056 RtlCopyMemory(RegistryBuffer, ((PUNICODE_STRING)SystemSpecific2)->Buffer, RegistryPath->Length);
1057 RegistryBuffer[RegistryPath->Length/sizeof(WCHAR)] = 0;
1058
1059 RegistryPath->Buffer = RegistryBuffer;
1060 Miniport->RegistryPath = RegistryPath;
1061
1062 InitializeListHead(&Miniport->DeviceList);
1063
1064 /* Put miniport in global miniport list */
1065 ExInterlockedInsertTailList(&MiniportListHead, &Miniport->ListEntry, &MiniportListLock);
1066
1067 *NdisWrapperHandle = Miniport;
1068 }
1069
1070 \f
1071 VOID NTAPI NdisIBugcheckCallback(
1072 IN PVOID Buffer,
1073 IN ULONG Length)
1074 /*
1075 * FUNCTION: Internal callback for handling bugchecks - calls adapter's shutdown handler
1076 * ARGUMENTS:
1077 * Buffer: Pointer to a bugcheck callback context
1078 * Length: Unused
1079 */
1080 {
1081 PMINIPORT_BUGCHECK_CONTEXT Context = (PMINIPORT_BUGCHECK_CONTEXT)Buffer;
1082 ADAPTER_SHUTDOWN_HANDLER sh = (ADAPTER_SHUTDOWN_HANDLER)Context->ShutdownHandler;
1083
1084 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1085
1086 if(sh)
1087 sh(Context->DriverContext);
1088 }
1089
1090 \f
1091 /*
1092 * @implemented
1093 */
1094 VOID
1095 EXPORT
1096 NdisMRegisterAdapterShutdownHandler(
1097 IN NDIS_HANDLE MiniportHandle,
1098 IN PVOID ShutdownContext,
1099 IN ADAPTER_SHUTDOWN_HANDLER ShutdownHandler)
1100 /*
1101 * FUNCTION: Register a shutdown handler for an adapter
1102 * ARGUMENTS:
1103 * MiniportHandle: Handle originally passed into MiniportInitialize
1104 * ShutdownContext: Pre-initialized bugcheck context
1105 * ShutdownHandler: Function to call to handle the bugcheck
1106 * NOTES:
1107 * - I'm not sure about ShutdownContext
1108 * - FIXME - memory leak below
1109 */
1110 {
1111 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)MiniportHandle;
1112 PMINIPORT_BUGCHECK_CONTEXT BugcheckContext = Adapter->BugcheckContext;
1113
1114 NDIS_DbgPrint(DEBUG_MINIPORT, ("Called.\n"));
1115
1116 if(BugcheckContext)
1117 return;
1118
1119 BugcheckContext = ExAllocatePool(NonPagedPool, sizeof(MINIPORT_BUGCHECK_CONTEXT));
1120 if(!BugcheckContext)
1121 {
1122 NDIS_DbgPrint(MIN_TRACE, ("Insufficient resources.\n"));
1123 return;
1124 }
1125
1126 BugcheckContext->ShutdownHandler = ShutdownHandler;
1127 BugcheckContext->DriverContext = ShutdownContext;
1128
1129 /* not sure if this needs to be initialized or not... oh well, it's a leak. */
1130 BugcheckContext->CallbackRecord = ExAllocatePool(NonPagedPool, sizeof(KBUGCHECK_CALLBACK_RECORD));
1131
1132 KeRegisterBugCheckCallback(BugcheckContext->CallbackRecord, NdisIBugcheckCallback,
1133 BugcheckContext, sizeof(BugcheckContext), (PUCHAR)"Ndis Miniport");
1134 }
1135
1136 \f
1137 NDIS_STATUS
1138 DoQueries(
1139 PLOGICAL_ADAPTER Adapter,
1140 NDIS_OID AddressOID)
1141 /*
1142 * FUNCTION: Queries miniport for information
1143 * ARGUMENTS:
1144 * Adapter = Pointer to logical adapter
1145 * AddressOID = OID to use to query for current address
1146 * RETURNS:
1147 * Status of operation
1148 */
1149 {
1150 ULONG BytesWritten;
1151 NDIS_STATUS NdisStatus;
1152
1153 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1154
1155 /* Get MAC options for adapter */
1156 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAC_OPTIONS, sizeof(UINT),
1157 &Adapter->NdisMiniportBlock.MacOptions,
1158 &BytesWritten);
1159
1160 if (NdisStatus != NDIS_STATUS_SUCCESS)
1161 {
1162 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAC_OPTIONS failed. NdisStatus (0x%X).\n", NdisStatus));
1163 return NdisStatus;
1164 }
1165
1166 NDIS_DbgPrint(DEBUG_MINIPORT, ("MacOptions (0x%X).\n", Adapter->NdisMiniportBlock.MacOptions));
1167
1168 /* Get current hardware address of adapter */
1169 NdisStatus = MiniQueryInformation(Adapter, AddressOID, Adapter->AddressLength,
1170 &Adapter->Address, &BytesWritten);
1171
1172 if (NdisStatus != NDIS_STATUS_SUCCESS)
1173 {
1174 NDIS_DbgPrint(MIN_TRACE, ("Address OID (0x%X) failed. NdisStatus (0x%X).\n", AddressOID, NdisStatus));
1175 return NdisStatus;
1176 }
1177
1178 #ifdef DBG
1179 {
1180 /* 802.3 only */
1181
1182 PUCHAR A = (PUCHAR)&Adapter->Address.Type.Medium802_3;
1183
1184 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]));
1185 }
1186 #endif /* DBG */
1187
1188 /* Get maximum lookahead buffer size of adapter */
1189 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_MAXIMUM_LOOKAHEAD, sizeof(ULONG),
1190 &Adapter->NdisMiniportBlock.MaximumLookahead, &BytesWritten);
1191
1192 if (NdisStatus != NDIS_STATUS_SUCCESS)
1193 {
1194 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_MAXIMUM_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1195 return NdisStatus;
1196 }
1197
1198 NDIS_DbgPrint(DEBUG_MINIPORT, ("MaxLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.MaximumLookahead));
1199
1200 /* Get current lookahead buffer size of adapter */
1201 NdisStatus = MiniQueryInformation(Adapter, OID_GEN_CURRENT_LOOKAHEAD, sizeof(ULONG),
1202 &Adapter->NdisMiniportBlock.CurrentLookahead, &BytesWritten);
1203
1204 if (NdisStatus != NDIS_STATUS_SUCCESS)
1205 {
1206 NDIS_DbgPrint(MIN_TRACE, ("OID_GEN_CURRENT_LOOKAHEAD failed. NdisStatus (0x%X).\n", NdisStatus));
1207 return NdisStatus;
1208 }
1209
1210 NDIS_DbgPrint(DEBUG_MINIPORT, ("CurLookaheadLength (0x%X).\n", Adapter->NdisMiniportBlock.CurrentLookahead));
1211
1212 if (Adapter->NdisMiniportBlock.MaximumLookahead != 0)
1213 {
1214 Adapter->LookaheadLength = Adapter->NdisMiniportBlock.MaximumLookahead + Adapter->MediumHeaderSize;
1215 Adapter->LookaheadBuffer = ExAllocatePool(NonPagedPool, Adapter->LookaheadLength);
1216
1217 if (!Adapter->LookaheadBuffer)
1218 return NDIS_STATUS_RESOURCES;
1219 }
1220
1221 return STATUS_SUCCESS;
1222 }
1223
1224 \f
1225 NTSTATUS
1226 NTAPI
1227 NdisIForwardIrpAndWaitCompletionRoutine(
1228 PDEVICE_OBJECT Fdo,
1229 PIRP Irp,
1230 PVOID Context)
1231 {
1232 PKEVENT Event = Context;
1233
1234 if (Irp->PendingReturned)
1235 KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
1236
1237 return STATUS_MORE_PROCESSING_REQUIRED;
1238 }
1239
1240 \f
1241 NTSTATUS
1242 NTAPI
1243 NdisIForwardIrpAndWait(PLOGICAL_ADAPTER Adapter, PIRP Irp)
1244 {
1245 KEVENT Event;
1246 NTSTATUS Status;
1247
1248 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1249 IoCopyCurrentIrpStackLocationToNext(Irp);
1250 IoSetCompletionRoutine(Irp, NdisIForwardIrpAndWaitCompletionRoutine, &Event,
1251 TRUE, TRUE, TRUE);
1252 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1253 if (Status == STATUS_PENDING)
1254 {
1255 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1256 Status = Irp->IoStatus.Status;
1257 }
1258 return Status;
1259 }
1260
1261 \f
1262 NTSTATUS
1263 NTAPI
1264 NdisIPnPStartDevice(
1265 IN PDEVICE_OBJECT DeviceObject,
1266 PIRP Irp)
1267 /*
1268 * FUNCTION: Handle the PnP start device event
1269 * ARGUMENTS:
1270 * DeviceObejct = Functional Device Object
1271 * Irp = IRP_MN_START_DEVICE I/O request packet
1272 * RETURNS:
1273 * Status of operation
1274 */
1275 {
1276 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1277 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1278 NDIS_WRAPPER_CONTEXT WrapperContext;
1279 NDIS_STATUS NdisStatus;
1280 NDIS_STATUS OpenErrorStatus;
1281 NTSTATUS Status;
1282 UINT SelectedMediumIndex = 0;
1283 NDIS_OID AddressOID;
1284 BOOLEAN Success = FALSE;
1285 ULONG ResourceCount;
1286 ULONG ResourceListSize;
1287 UNICODE_STRING ParamName;
1288 PNDIS_CONFIGURATION_PARAMETER ConfigParam;
1289 NDIS_HANDLE ConfigHandle;
1290 ULONG Size;
1291 /* FIXME - KIRQL OldIrql; */
1292
1293 /*
1294 * Prepare wrapper context used by HW and configuration routines.
1295 */
1296
1297 NDIS_DbgPrint(DEBUG_MINIPORT, ("Start Device %wZ\n", &Adapter->NdisMiniportBlock.MiniportName));
1298
1299 NDIS_DbgPrint(MAX_TRACE, ("Inserting adapter 0x%x into adapter list\n", Adapter));
1300
1301 /* Put adapter in global adapter list */
1302 ExInterlockedInsertTailList(&AdapterListHead, &Adapter->ListEntry, &AdapterListLock);
1303
1304 Status = IoOpenDeviceRegistryKey(
1305 Adapter->NdisMiniportBlock.PhysicalDeviceObject, PLUGPLAY_REGKEY_DRIVER,
1306 KEY_ALL_ACCESS, &WrapperContext.RegistryHandle);
1307 if (!NT_SUCCESS(Status))
1308 {
1309 NDIS_DbgPrint(MIN_TRACE,("failed to open adapter-specific reg key\n"));
1310 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1311 return Status;
1312 }
1313
1314 NDIS_DbgPrint(MAX_TRACE, ("opened device reg key\n"));
1315
1316 WrapperContext.DeviceObject = Adapter->NdisMiniportBlock.DeviceObject;
1317
1318 /*
1319 * Store the adapter resources used by HW routines such as
1320 * NdisMQueryAdapterResources.
1321 */
1322
1323 if (Stack->Parameters.StartDevice.AllocatedResources != NULL)
1324 {
1325 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1326 PartialResourceList.Count;
1327 ResourceListSize =
1328 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1329 PartialDescriptors[ResourceCount]);
1330
1331 Adapter->NdisMiniportBlock.AllocatedResources =
1332 ExAllocatePool(PagedPool, ResourceListSize);
1333 if (Adapter->NdisMiniportBlock.AllocatedResources == NULL)
1334 {
1335 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1336 return STATUS_INSUFFICIENT_RESOURCES;
1337 }
1338
1339 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResources,
1340 Stack->Parameters.StartDevice.AllocatedResources,
1341 ResourceListSize);
1342 }
1343
1344 if (Stack->Parameters.StartDevice.AllocatedResourcesTranslated != NULL)
1345 {
1346 ResourceCount = Stack->Parameters.StartDevice.AllocatedResources->List[0].
1347 PartialResourceList.Count;
1348 ResourceListSize =
1349 FIELD_OFFSET(CM_RESOURCE_LIST, List[0].PartialResourceList.
1350 PartialDescriptors[ResourceCount]);
1351
1352 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated =
1353 ExAllocatePool(PagedPool, ResourceListSize);
1354 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated == NULL)
1355 {
1356 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1357 return STATUS_INSUFFICIENT_RESOURCES;
1358 }
1359
1360 RtlCopyMemory(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated,
1361 Stack->Parameters.StartDevice.AllocatedResourcesTranslated,
1362 ResourceListSize);
1363 }
1364
1365 /*
1366 * Store the Bus Type, Bus Number and Slot information. It's used by
1367 * the hardware routines then.
1368 */
1369
1370 NdisOpenConfiguration(&NdisStatus, &ConfigHandle, (NDIS_HANDLE)&WrapperContext);
1371
1372 Size = sizeof(ULONG);
1373 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1374 DevicePropertyLegacyBusType, Size,
1375 &Adapter->NdisMiniportBlock.BusType, &Size);
1376 if (!NT_SUCCESS(Status) || (INTERFACE_TYPE)Adapter->NdisMiniportBlock.BusType == InterfaceTypeUndefined)
1377 {
1378 NdisInitUnicodeString(&ParamName, L"BusType");
1379 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1380 &ParamName, NdisParameterInteger);
1381 if (NdisStatus == NDIS_STATUS_SUCCESS)
1382 Adapter->NdisMiniportBlock.BusType = ConfigParam->ParameterData.IntegerData;
1383 else
1384 Adapter->NdisMiniportBlock.BusType = Isa;
1385 }
1386
1387 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1388 DevicePropertyBusNumber, Size,
1389 &Adapter->NdisMiniportBlock.BusNumber, &Size);
1390 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.BusNumber == 0xFFFFFFF0)
1391 {
1392 NdisInitUnicodeString(&ParamName, L"BusNumber");
1393 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1394 &ParamName, NdisParameterInteger);
1395 if (NdisStatus == NDIS_STATUS_SUCCESS)
1396 Adapter->NdisMiniportBlock.BusNumber = ConfigParam->ParameterData.IntegerData;
1397 else
1398 Adapter->NdisMiniportBlock.BusNumber = 0;
1399 }
1400 WrapperContext.BusNumber = Adapter->NdisMiniportBlock.BusNumber;
1401
1402 Status = IoGetDeviceProperty(Adapter->NdisMiniportBlock.PhysicalDeviceObject,
1403 DevicePropertyAddress, Size,
1404 &Adapter->NdisMiniportBlock.SlotNumber, &Size);
1405 if (!NT_SUCCESS(Status) || Adapter->NdisMiniportBlock.SlotNumber == (NDIS_INTERFACE_TYPE)-1)
1406 {
1407 NdisInitUnicodeString(&ParamName, L"SlotNumber");
1408 NdisReadConfiguration(&NdisStatus, &ConfigParam, ConfigHandle,
1409 &ParamName, NdisParameterInteger);
1410 if (NdisStatus == NDIS_STATUS_SUCCESS)
1411 Adapter->NdisMiniportBlock.SlotNumber = ConfigParam->ParameterData.IntegerData;
1412 else
1413 Adapter->NdisMiniportBlock.SlotNumber = 0;
1414 }
1415 else
1416 {
1417 /* Convert slotnumber to PCI_SLOT_NUMBER */
1418 ULONG PciSlotNumber = Adapter->NdisMiniportBlock.SlotNumber;
1419 PCI_SLOT_NUMBER SlotNumber;
1420
1421 SlotNumber.u.AsULONG = 0;
1422 SlotNumber.u.bits.DeviceNumber = (PciSlotNumber >> 16) & 0xFFFF;
1423 SlotNumber.u.bits.FunctionNumber = PciSlotNumber & 0xFFFF;
1424
1425 Adapter->NdisMiniportBlock.SlotNumber = SlotNumber.u.AsULONG;
1426 }
1427 NdisCloseConfiguration(ConfigHandle);
1428
1429 /* Set handlers (some NDIS macros require these) */
1430 Adapter->NdisMiniportBlock.EthRxCompleteHandler = EthFilterDprIndicateReceiveComplete;
1431 Adapter->NdisMiniportBlock.EthRxIndicateHandler = EthFilterDprIndicateReceive;
1432 Adapter->NdisMiniportBlock.SendCompleteHandler = MiniSendComplete;
1433 Adapter->NdisMiniportBlock.SendResourcesHandler = MiniSendResourcesAvailable;
1434 Adapter->NdisMiniportBlock.ResetCompleteHandler = MiniResetComplete;
1435 Adapter->NdisMiniportBlock.TDCompleteHandler = MiniTransferDataComplete;
1436 Adapter->NdisMiniportBlock.PacketIndicateHandler= MiniIndicateReceivePacket;
1437 Adapter->NdisMiniportBlock.StatusHandler = MiniStatus;
1438 Adapter->NdisMiniportBlock.StatusCompleteHandler= MiniStatusComplete;
1439
1440 /*
1441 * Call MiniportInitialize.
1442 */
1443
1444 NDIS_DbgPrint(MID_TRACE, ("calling MiniportInitialize\n"));
1445 NdisStatus = (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.InitializeHandler)(
1446 &OpenErrorStatus, &SelectedMediumIndex, &MediaArray[0],
1447 MEDIA_ARRAY_SIZE, Adapter, (NDIS_HANDLE)&WrapperContext);
1448
1449 ZwClose(WrapperContext.RegistryHandle);
1450
1451 if (NdisStatus != NDIS_STATUS_SUCCESS ||
1452 SelectedMediumIndex >= MEDIA_ARRAY_SIZE)
1453 {
1454 NDIS_DbgPrint(MIN_TRACE, ("MiniportInitialize() failed for an adapter.\n"));
1455 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1456 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1457 return (NTSTATUS)NdisStatus;
1458 }
1459
1460 Adapter->NdisMiniportBlock.MediaType = MediaArray[SelectedMediumIndex];
1461
1462 switch (Adapter->NdisMiniportBlock.MediaType)
1463 {
1464 case NdisMedium802_3:
1465 Adapter->MediumHeaderSize = 14; /* XXX figure out what to do about LLC */
1466 AddressOID = OID_802_3_CURRENT_ADDRESS;
1467 Adapter->AddressLength = ETH_LENGTH_OF_ADDRESS;
1468 NdisStatus = DoQueries(Adapter, AddressOID);
1469 if (NdisStatus == NDIS_STATUS_SUCCESS)
1470 {
1471 Success = EthCreateFilter(32, /* FIXME: Query this from miniport. */
1472 Adapter->Address.Type.Medium802_3,
1473 &Adapter->NdisMiniportBlock.EthDB);
1474 if (Success)
1475 ((PETHI_FILTER)Adapter->NdisMiniportBlock.EthDB)->Miniport = (PNDIS_MINIPORT_BLOCK)Adapter;
1476 else
1477 NdisStatus = NDIS_STATUS_RESOURCES;
1478 }
1479 break;
1480
1481 default:
1482 /* FIXME: Support other types of media */
1483 NDIS_DbgPrint(MIN_TRACE, ("error: unsupported media\n"));
1484 ASSERT(FALSE);
1485 /* FIXME - KeReleaseSpinLock(&Adapter->NdisMiniportBlock.Lock, OldIrql); */
1486 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1487 return STATUS_UNSUCCESSFUL;
1488 }
1489
1490 if (!Success || NdisStatus != NDIS_STATUS_SUCCESS)
1491 {
1492 NDIS_DbgPrint(MAX_TRACE, ("couldn't create filter (%x)\n", NdisStatus));
1493 if (Adapter->LookaheadBuffer)
1494 {
1495 ExFreePool(Adapter->LookaheadBuffer);
1496 Adapter->LookaheadBuffer = NULL;
1497 }
1498 ExInterlockedRemoveEntryList( &Adapter->ListEntry, &AdapterListLock );
1499 if (NdisStatus == NDIS_STATUS_SUCCESS) NdisStatus = NDIS_STATUS_FAILURE;
1500 return (NTSTATUS)NdisStatus;
1501 }
1502
1503 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1504 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStarted;
1505
1506 /* Put adapter in adapter list for this miniport */
1507 ExInterlockedInsertTailList(&Adapter->NdisMiniportBlock.DriverHandle->DeviceList, &Adapter->MiniportListEntry, &Adapter->NdisMiniportBlock.DriverHandle->Lock);
1508
1509 return STATUS_SUCCESS;
1510 }
1511
1512 \f
1513 NTSTATUS
1514 NTAPI
1515 NdisIPnPStopDevice(
1516 IN PDEVICE_OBJECT DeviceObject,
1517 PIRP Irp)
1518 /*
1519 * FUNCTION: Handle the PnP stop device event
1520 * ARGUMENTS:
1521 * DeviceObejct = Functional Device Object
1522 * Irp = IRP_MN_STOP_DEVICE I/O request packet
1523 * RETURNS:
1524 * Status of operation
1525 */
1526 {
1527 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1528 KIRQL OldIrql;
1529
1530 /* Remove adapter from adapter list for this miniport */
1531 KeAcquireSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, &OldIrql);
1532 RemoveEntryList(&Adapter->MiniportListEntry);
1533 KeReleaseSpinLock(&Adapter->NdisMiniportBlock.DriverHandle->Lock, OldIrql);
1534
1535 /* Remove adapter from global adapter list */
1536 KeAcquireSpinLock(&AdapterListLock, &OldIrql);
1537 RemoveEntryList(&Adapter->ListEntry);
1538 KeReleaseSpinLock(&AdapterListLock, OldIrql);
1539
1540 (*Adapter->NdisMiniportBlock.DriverHandle->MiniportCharacteristics.HaltHandler)(Adapter);
1541
1542 if (Adapter->LookaheadBuffer)
1543 {
1544 ExFreePool(Adapter->LookaheadBuffer);
1545 Adapter->LookaheadBuffer = NULL;
1546 }
1547 if (Adapter->NdisMiniportBlock.AllocatedResources)
1548 {
1549 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResources);
1550 Adapter->NdisMiniportBlock.AllocatedResources = NULL;
1551 }
1552 if (Adapter->NdisMiniportBlock.AllocatedResourcesTranslated)
1553 {
1554 ExFreePool(Adapter->NdisMiniportBlock.AllocatedResourcesTranslated);
1555 Adapter->NdisMiniportBlock.AllocatedResourcesTranslated = NULL;
1556 }
1557
1558 Adapter->NdisMiniportBlock.OldPnPDeviceState = Adapter->NdisMiniportBlock.PnPDeviceState;
1559 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceStopped;
1560
1561 return STATUS_SUCCESS;
1562 }
1563
1564 \f
1565 NTSTATUS
1566 NTAPI
1567 NdisIDispatchPnp(
1568 IN PDEVICE_OBJECT DeviceObject,
1569 PIRP Irp)
1570 {
1571 PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
1572 PLOGICAL_ADAPTER Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1573 NTSTATUS Status;
1574
1575 switch (Stack->MinorFunction)
1576 {
1577 case IRP_MN_START_DEVICE:
1578 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1579 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1580 {
1581 Status = NdisIPnPStartDevice(DeviceObject, Irp);
1582 }
1583 Irp->IoStatus.Status = Status;
1584 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1585 break;
1586
1587 case IRP_MN_STOP_DEVICE:
1588 Status = NdisIForwardIrpAndWait(Adapter, Irp);
1589 if (NT_SUCCESS(Status) && NT_SUCCESS(Irp->IoStatus.Status))
1590 {
1591 Status = NdisIPnPStopDevice(DeviceObject, Irp);
1592 }
1593 Irp->IoStatus.Status = Status;
1594 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1595 break;
1596
1597 case IRP_MN_QUERY_DEVICE_RELATIONS:
1598 Status = STATUS_NOT_SUPPORTED;
1599 Irp->IoStatus.Status = Status;
1600 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1601 break;
1602
1603 default:
1604 IoSkipCurrentIrpStackLocation(Irp);
1605 Status = IoCallDriver(Adapter->NdisMiniportBlock.NextDeviceObject, Irp);
1606 break;
1607 }
1608
1609 return Status;
1610 }
1611
1612 \f
1613 NTSTATUS
1614 NTAPI
1615 NdisIAddDevice(
1616 IN PDRIVER_OBJECT DriverObject,
1617 IN PDEVICE_OBJECT PhysicalDeviceObject)
1618 /*
1619 * FUNCTION: Create a device for an adapter found using PnP
1620 * ARGUMENTS:
1621 * DriverObject = Pointer to the miniport driver object
1622 * PhysicalDeviceObject = Pointer to the PDO for our adapter
1623 */
1624 {
1625 static const WCHAR ClassKeyName[] = {'C','l','a','s','s','\\'};
1626 static const WCHAR LinkageKeyName[] = {'\\','L','i','n','k','a','g','e',0};
1627 PNDIS_M_DRIVER_BLOCK Miniport;
1628 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1629 WCHAR *LinkageKeyBuffer;
1630 ULONG DriverKeyLength;
1631 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
1632 UNICODE_STRING ExportName;
1633 PDEVICE_OBJECT DeviceObject;
1634 PLOGICAL_ADAPTER Adapter;
1635 NTSTATUS Status;
1636
1637 /*
1638 * Gain the access to the miniport data structure first.
1639 */
1640
1641 MiniportPtr = IoGetDriverObjectExtension(DriverObject, (PVOID)TAG('D','I','M','N'));
1642 if (MiniportPtr == NULL)
1643 {
1644 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get driver object extension.\n"));
1645 return STATUS_UNSUCCESSFUL;
1646 }
1647 Miniport = *MiniportPtr;
1648
1649 /*
1650 * Get name of the Linkage registry key for our adapter. It's located under
1651 * the driver key for our driver and so we have basicly two ways to do it.
1652 * Either we can use IoOpenDriverRegistryKey or compose it using information
1653 * gathered by IoGetDeviceProperty. I choosed the second because
1654 * IoOpenDriverRegistryKey wasn't implemented at the time of writing.
1655 */
1656
1657 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1658 0, NULL, &DriverKeyLength);
1659 if (Status != STATUS_BUFFER_TOO_SMALL && Status != STATUS_BUFFER_OVERFLOW && Status != STATUS_SUCCESS)
1660 {
1661 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key length.\n"));
1662 return Status;
1663 }
1664
1665 LinkageKeyBuffer = ExAllocatePool(PagedPool, DriverKeyLength +
1666 sizeof(ClassKeyName) + sizeof(LinkageKeyName));
1667 if (LinkageKeyBuffer == NULL)
1668 {
1669 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate memory for driver key name.\n"));
1670 return STATUS_INSUFFICIENT_RESOURCES;
1671 }
1672
1673 Status = IoGetDeviceProperty(PhysicalDeviceObject, DevicePropertyDriverKeyName,
1674 DriverKeyLength, LinkageKeyBuffer +
1675 (sizeof(ClassKeyName) / sizeof(WCHAR)),
1676 &DriverKeyLength);
1677 if (!NT_SUCCESS(Status))
1678 {
1679 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport driver key.\n"));
1680 ExFreePool(LinkageKeyBuffer);
1681 return Status;
1682 }
1683
1684 /* Compose the linkage key name. */
1685 RtlCopyMemory(LinkageKeyBuffer, ClassKeyName, sizeof(ClassKeyName));
1686 RtlCopyMemory(LinkageKeyBuffer + ((sizeof(ClassKeyName) + DriverKeyLength) /
1687 sizeof(WCHAR)) - 1, LinkageKeyName, sizeof(LinkageKeyName));
1688
1689 NDIS_DbgPrint(DEBUG_MINIPORT, ("LinkageKey: %S.\n", LinkageKeyBuffer));
1690
1691 /*
1692 * Now open the linkage key and read the "Export" and "RootDevice" values
1693 * which contains device name and root service respectively.
1694 */
1695
1696 RtlZeroMemory(QueryTable, sizeof(QueryTable));
1697 RtlInitUnicodeString(&ExportName, NULL);
1698 QueryTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED | RTL_QUERY_REGISTRY_DIRECT;
1699 QueryTable[0].Name = L"Export";
1700 QueryTable[0].EntryContext = &ExportName;
1701
1702 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, LinkageKeyBuffer,
1703 QueryTable, NULL, NULL);
1704 ExFreePool(LinkageKeyBuffer);
1705 if (!NT_SUCCESS(Status))
1706 {
1707 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't get miniport device name. (%x)\n", Status));
1708 return Status;
1709 }
1710
1711 /*
1712 * Create the device object.
1713 */
1714
1715 NDIS_DbgPrint(MAX_TRACE, ("creating device %wZ\n", &ExportName));
1716
1717 Status = IoCreateDevice(Miniport->DriverObject, sizeof(LOGICAL_ADAPTER),
1718 &ExportName, FILE_DEVICE_PHYSICAL_NETCARD,
1719 0, FALSE, &DeviceObject);
1720 if (!NT_SUCCESS(Status))
1721 {
1722 NDIS_DbgPrint(MIN_TRACE, ("Could not create device object.\n"));
1723 RtlFreeUnicodeString(&ExportName);
1724 return Status;
1725 }
1726
1727 /*
1728 * Initialize the adapter structure.
1729 */
1730
1731 Adapter = (PLOGICAL_ADAPTER)DeviceObject->DeviceExtension;
1732 KeInitializeSpinLock(&Adapter->NdisMiniportBlock.Lock);
1733 InitializeListHead(&Adapter->ProtocolListHead);
1734 Adapter->NdisMiniportBlock.DriverHandle = Miniport;
1735
1736 Adapter->NdisMiniportBlock.MiniportName = ExportName;
1737
1738 Adapter->NdisMiniportBlock.DeviceObject = DeviceObject;
1739 Adapter->NdisMiniportBlock.PhysicalDeviceObject = PhysicalDeviceObject;
1740 Adapter->NdisMiniportBlock.NextDeviceObject =
1741 IoAttachDeviceToDeviceStack(Adapter->NdisMiniportBlock.DeviceObject,
1742 PhysicalDeviceObject);
1743
1744 Adapter->NdisMiniportBlock.OldPnPDeviceState = 0;
1745 Adapter->NdisMiniportBlock.PnPDeviceState = NdisPnPDeviceAdded;
1746
1747 KeInitializeDpc(&Adapter->NdisMiniportBlock.DeferredDpc, MiniportDpc, (PVOID)Adapter);
1748
1749 DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
1750
1751 return STATUS_SUCCESS;
1752 }
1753
1754 \f
1755 /*
1756 * @implemented
1757 */
1758 NDIS_STATUS
1759 EXPORT
1760 NdisMRegisterMiniport(
1761 IN NDIS_HANDLE NdisWrapperHandle,
1762 IN PNDIS_MINIPORT_CHARACTERISTICS MiniportCharacteristics,
1763 IN UINT CharacteristicsLength)
1764 /*
1765 * FUNCTION: Registers a miniport's MiniportXxx entry points with the NDIS library
1766 * ARGUMENTS:
1767 * NdisWrapperHandle = Pointer to handle returned by NdisMInitializeWrapper
1768 * MiniportCharacteristics = Pointer to a buffer with miniport characteristics
1769 * CharacteristicsLength = Number of bytes in characteristics buffer
1770 * RETURNS:
1771 * Status of operation
1772 */
1773 {
1774 UINT MinSize;
1775 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
1776 PNDIS_M_DRIVER_BLOCK *MiniportPtr;
1777 NTSTATUS Status;
1778
1779 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1780
1781 switch (MiniportCharacteristics->MajorNdisVersion)
1782 {
1783 case 0x03:
1784 MinSize = sizeof(NDIS30_MINIPORT_CHARACTERISTICS);
1785 break;
1786
1787 case 0x04:
1788 MinSize = sizeof(NDIS40_MINIPORT_CHARACTERISTICS);
1789 break;
1790
1791 case 0x05:
1792 MinSize = sizeof(NDIS50_MINIPORT_CHARACTERISTICS);
1793 break;
1794
1795 default:
1796 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics version.\n"));
1797 return NDIS_STATUS_BAD_VERSION;
1798 }
1799
1800 if (CharacteristicsLength < MinSize)
1801 {
1802 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1803 return NDIS_STATUS_BAD_CHARACTERISTICS;
1804 }
1805
1806 /* Check if mandatory MiniportXxx functions are specified */
1807 if ((!MiniportCharacteristics->HaltHandler) ||
1808 (!MiniportCharacteristics->InitializeHandler)||
1809 (!MiniportCharacteristics->QueryInformationHandler) ||
1810 (!MiniportCharacteristics->ResetHandler) ||
1811 (!MiniportCharacteristics->SetInformationHandler))
1812 {
1813 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1814 return NDIS_STATUS_BAD_CHARACTERISTICS;
1815 }
1816
1817 if (MiniportCharacteristics->MajorNdisVersion == 0x03)
1818 {
1819 if (!MiniportCharacteristics->SendHandler)
1820 {
1821 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1822 return NDIS_STATUS_BAD_CHARACTERISTICS;
1823 }
1824 }
1825 else if (MiniportCharacteristics->MajorNdisVersion >= 0x04)
1826 {
1827 /* NDIS 4.0+ */
1828 if ((!MiniportCharacteristics->SendHandler) &&
1829 (!MiniportCharacteristics->SendPacketsHandler))
1830 {
1831 NDIS_DbgPrint(DEBUG_MINIPORT, ("Bad miniport characteristics.\n"));
1832 return NDIS_STATUS_BAD_CHARACTERISTICS;
1833 }
1834 }
1835
1836 /* TODO: verify NDIS5 and NDIS5.1 */
1837
1838 RtlCopyMemory(&Miniport->MiniportCharacteristics, MiniportCharacteristics, MinSize);
1839
1840 /*
1841 * NOTE: This is VERY unoptimal! Should we store the NDIS_M_DRIVER_BLOCK
1842 * structure in the driver extension or what?
1843 */
1844
1845 Status = IoAllocateDriverObjectExtension(Miniport->DriverObject, (PVOID)TAG('D','I','M','N'),
1846 sizeof(PNDIS_M_DRIVER_BLOCK), (PVOID*)&MiniportPtr);
1847 if (!NT_SUCCESS(Status))
1848 {
1849 NDIS_DbgPrint(DEBUG_MINIPORT, ("Can't allocate driver object extension.\n"));
1850 return NDIS_STATUS_RESOURCES;
1851 }
1852
1853 *MiniportPtr = Miniport;
1854
1855 Miniport->DriverObject->MajorFunction[IRP_MJ_PNP] = NdisIDispatchPnp;
1856 Miniport->DriverObject->DriverExtension->AddDevice = NdisIAddDevice;
1857
1858 return NDIS_STATUS_SUCCESS;
1859 }
1860
1861 \f
1862 /*
1863 * @implemented
1864 */
1865 #undef NdisMResetComplete
1866 VOID
1867 EXPORT
1868 NdisMResetComplete(
1869 IN NDIS_HANDLE MiniportAdapterHandle,
1870 IN NDIS_STATUS Status,
1871 IN BOOLEAN AddressingReset)
1872 {
1873 MiniResetComplete(MiniportAdapterHandle, Status, AddressingReset);
1874 }
1875
1876 \f
1877 /*
1878 * @implemented
1879 */
1880 #undef NdisMSendComplete
1881 VOID
1882 EXPORT
1883 NdisMSendComplete(
1884 IN NDIS_HANDLE MiniportAdapterHandle,
1885 IN PNDIS_PACKET Packet,
1886 IN NDIS_STATUS Status)
1887 /*
1888 * FUNCTION: Forwards a message to the initiating protocol saying
1889 * that a packet was handled
1890 * ARGUMENTS:
1891 * NdisAdapterHandle = Handle input to MiniportInitialize
1892 * Packet = Pointer to NDIS packet that was sent
1893 * Status = Status of send operation
1894 */
1895 {
1896 MiniSendComplete(MiniportAdapterHandle, Packet, Status);
1897 }
1898
1899 \f
1900 /*
1901 * @implemented
1902 */
1903 #undef NdisMSendResourcesAvailable
1904 VOID
1905 EXPORT
1906 NdisMSendResourcesAvailable(
1907 IN NDIS_HANDLE MiniportAdapterHandle)
1908 {
1909 MiniSendResourcesAvailable(MiniportAdapterHandle);
1910 }
1911
1912 \f
1913 /*
1914 * @implemented
1915 */
1916 #undef NdisMTransferDataComplete
1917 VOID
1918 EXPORT
1919 NdisMTransferDataComplete(
1920 IN NDIS_HANDLE MiniportAdapterHandle,
1921 IN PNDIS_PACKET Packet,
1922 IN NDIS_STATUS Status,
1923 IN UINT BytesTransferred)
1924 {
1925 MiniTransferDataComplete(MiniportAdapterHandle, Packet, Status, BytesTransferred);
1926 }
1927
1928 \f
1929 /*
1930 * @implemented
1931 */
1932 #undef NdisMSetInformationComplete
1933 VOID
1934 EXPORT
1935 NdisMSetInformationComplete(
1936 IN NDIS_HANDLE MiniportAdapterHandle,
1937 IN NDIS_STATUS Status)
1938 {
1939 KIRQL OldIrql;
1940 KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
1941 (*((PNDIS_MINIPORT_BLOCK)(MiniportAdapterHandle))->SetCompleteHandler)(MiniportAdapterHandle, Status);
1942 KeLowerIrql(OldIrql);
1943 }
1944
1945 \f
1946 /*
1947 * @implemented
1948 */
1949 #undef NdisMSetAttributes
1950 VOID
1951 EXPORT
1952 NdisMSetAttributes(
1953 IN NDIS_HANDLE MiniportAdapterHandle,
1954 IN NDIS_HANDLE MiniportAdapterContext,
1955 IN BOOLEAN BusMaster,
1956 IN NDIS_INTERFACE_TYPE AdapterType)
1957 /*
1958 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1959 * ARGUMENTS:
1960 * MiniportAdapterHandle = Handle input to MiniportInitialize
1961 * MiniportAdapterContext = Pointer to context information
1962 * BusMaster = Specifies TRUE if the caller's NIC is a busmaster DMA device
1963 * AdapterType = Specifies the I/O bus interface of the caller's NIC
1964 */
1965 {
1966 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
1967 NdisMSetAttributesEx(MiniportAdapterHandle, MiniportAdapterContext, 0,
1968 BusMaster ? NDIS_ATTRIBUTE_BUS_MASTER : 0,
1969 AdapterType);
1970 }
1971
1972 \f
1973 /*
1974 * @implemented
1975 */
1976 VOID
1977 EXPORT
1978 NdisMSetAttributesEx(
1979 IN NDIS_HANDLE MiniportAdapterHandle,
1980 IN NDIS_HANDLE MiniportAdapterContext,
1981 IN UINT CheckForHangTimeInSeconds OPTIONAL,
1982 IN ULONG AttributeFlags,
1983 IN NDIS_INTERFACE_TYPE AdapterType)
1984 /*
1985 * FUNCTION: Informs the NDIS library of significant features of the caller's NIC
1986 * ARGUMENTS:
1987 * MiniportAdapterHandle = Handle input to MiniportInitialize
1988 * MiniportAdapterContext = Pointer to context information
1989 * CheckForHangTimeInSeconds = Specifies interval in seconds at which
1990 * MiniportCheckForHang should be called
1991 * AttributeFlags = Bitmask that indicates specific attributes
1992 * AdapterType = Specifies the I/O bus interface of the caller's NIC
1993 */
1994 {
1995 /* TODO: Take CheckForHandTimeInSeconds into account! */
1996
1997 PLOGICAL_ADAPTER Adapter = GET_LOGICAL_ADAPTER(MiniportAdapterHandle);
1998
1999 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2000
2001 Adapter->NdisMiniportBlock.MiniportAdapterContext = MiniportAdapterContext;
2002 Adapter->NdisMiniportBlock.Flags = AttributeFlags;
2003 Adapter->NdisMiniportBlock.AdapterType = AdapterType;
2004 if (AttributeFlags & NDIS_ATTRIBUTE_INTERMEDIATE_DRIVER)
2005 NDIS_DbgPrint(MAX_TRACE, ("Intermediate drivers not supported yet.\n"));
2006 }
2007
2008 \f
2009 /*
2010 * @implemented
2011 */
2012 VOID
2013 EXPORT
2014 NdisMSleep(
2015 IN ULONG MicrosecondsToSleep)
2016 /*
2017 * FUNCTION: delay the thread's execution for MicrosecondsToSleep
2018 * ARGUMENTS:
2019 * MicrosecondsToSleep: duh...
2020 * NOTES:
2021 * - Because this is a blocking call, current IRQL must be < DISPATCH_LEVEL
2022 */
2023 {
2024 KTIMER Timer;
2025 LARGE_INTEGER DueTime;
2026
2027 PAGED_CODE();
2028
2029 DueTime.QuadPart = (-1) * 10 * MicrosecondsToSleep;
2030
2031 KeInitializeTimer(&Timer);
2032 KeSetTimer(&Timer, DueTime, 0);
2033 KeWaitForSingleObject(&Timer, Executive, KernelMode, FALSE, 0);
2034 }
2035
2036 \f
2037 /*
2038 * @implemented
2039 */
2040 BOOLEAN
2041 EXPORT
2042 NdisMSynchronizeWithInterrupt(
2043 IN PNDIS_MINIPORT_INTERRUPT Interrupt,
2044 IN PVOID SynchronizeFunction,
2045 IN PVOID SynchronizeContext)
2046 {
2047 return(KeSynchronizeExecution(Interrupt->InterruptObject,
2048 (PKSYNCHRONIZE_ROUTINE)SynchronizeFunction,
2049 SynchronizeContext));
2050 }
2051
2052 \f
2053 /*
2054 * @unimplemented
2055 */
2056 NDIS_STATUS
2057 EXPORT
2058 NdisMWriteLogData(
2059 IN NDIS_HANDLE LogHandle,
2060 IN PVOID LogBuffer,
2061 IN UINT LogBufferSize)
2062 {
2063 PUCHAR Buffer = LogBuffer;
2064 UINT i, j, idx;
2065
2066 UNIMPLEMENTED;
2067 for (i = 0; i < LogBufferSize; i += 16)
2068 {
2069 DbgPrint("%08x |", i);
2070 for (j = 0; j < 16; j++)
2071 {
2072 idx = i + j;
2073 if (idx < LogBufferSize)
2074 DbgPrint(" %02x", Buffer[idx]);
2075 else
2076 DbgPrint(" ");
2077 }
2078 DbgPrint(" | ");
2079 for (j = 0; j < 16; j++)
2080 {
2081 idx = i + j;
2082 if (idx == LogBufferSize)
2083 break;
2084 if (Buffer[idx] >= ' ') /* FIXME: not portable! replace by if (isprint(Buffer[idx])) ? */
2085 DbgPrint("%c", Buffer[idx]);
2086 else
2087 DbgPrint(".");
2088 }
2089 DbgPrint("\n");
2090 }
2091
2092 return NDIS_STATUS_FAILURE;
2093 }
2094
2095 \f
2096 /*
2097 * @implemented
2098 */
2099 VOID
2100 EXPORT
2101 NdisTerminateWrapper(
2102 IN NDIS_HANDLE NdisWrapperHandle,
2103 IN PVOID SystemSpecific)
2104 /*
2105 * FUNCTION: Releases resources allocated by a call to NdisInitializeWrapper
2106 * ARGUMENTS:
2107 * NdisWrapperHandle = Handle returned by NdisInitializeWrapper (NDIS_M_DRIVER_BLOCK)
2108 * SystemSpecific = Always NULL
2109 */
2110 {
2111 PNDIS_M_DRIVER_BLOCK Miniport = GET_MINIPORT_DRIVER(NdisWrapperHandle);
2112
2113 NDIS_DbgPrint(MAX_TRACE, ("Called.\n"));
2114
2115 ExFreePool(Miniport->RegistryPath->Buffer);
2116 ExFreePool(Miniport->RegistryPath);
2117 ExFreePool(Miniport);
2118 }
2119
2120 /* EOF */
2121