xref: /reactos/drivers/ksfilter/ks/device.c (revision 9d3c3a75)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/device.c
5  * PURPOSE:         KS IKsDevice interface functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 NTSTATUS
15 NTAPI
16 IKsDevice_fnQueryInterface(
17     IN IKsDevice * iface,
18     REFIID refiid,
19     PVOID* Output)
20 {
21     NTSTATUS Status;
22     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
23 
24     if (IsEqualGUIDAligned(refiid, &IID_IUnknown))
25     {
26         *Output = &This->BasicHeader.OuterUnknown;
27         _InterlockedIncrement(&This->ref);
28         return STATUS_SUCCESS;
29     }
30 
31     if (This->BasicHeader.ClientAggregate)
32     {
33          /* using client aggregate */
34          Status = This->BasicHeader.ClientAggregate->lpVtbl->QueryInterface(This->BasicHeader.ClientAggregate, refiid, Output);
35 
36          if (NT_SUCCESS(Status))
37          {
38              /* client aggregate supports interface */
39              return Status;
40          }
41     }
42 
43     DPRINT("IKsDevice_fnQueryInterface no interface\n");
44     return STATUS_NOT_SUPPORTED;
45 }
46 
47 ULONG
48 NTAPI
49 IKsDevice_fnAddRef(
50     IN IKsDevice * iface)
51 {
52     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
53 
54     return InterlockedIncrement(&This->ref);
55 }
56 
57 ULONG
58 NTAPI
59 IKsDevice_fnRelease(
60     IN IKsDevice * iface)
61 {
62     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
63 
64     InterlockedDecrement(&This->ref);
65 
66     return This->ref;
67 }
68 
69 
70 
71 PKSDEVICE
72 NTAPI
73 IKsDevice_fnGetStruct(
74     IN IKsDevice * iface)
75 {
76     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
77 
78     return &This->KsDevice;
79 }
80 
81 NTSTATUS
82 NTAPI
83 IKsDevice_fnInitializeObjectBag(
84     IN IKsDevice * iface,
85     IN PKSIOBJECT_BAG Bag,
86     IN PRKMUTEX Mutex)
87 {
88     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
89 
90     if (!Mutex)
91     {
92         /* use device mutex */
93         Mutex = &This->BagMutex;
94     }
95 
96     /* initialize object bag */
97     Bag->BagMutex = Mutex;
98     Bag->DeviceHeader = (PKSIDEVICE_HEADER)This;
99     InitializeListHead(&Bag->ObjectList);
100 
101     /* insert bag into device list */
102     InsertTailList(&This->ObjectBags, &Bag->Entry);
103 
104     return STATUS_SUCCESS;
105 }
106 
107 NTSTATUS
108 NTAPI
109 IKsDevice_fnAcquireDevice(
110     IN IKsDevice * iface)
111 {
112     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
113 
114     return KeWaitForSingleObject(&This->DeviceMutex, Executive, KernelMode, FALSE, NULL);
115 }
116 
117 NTSTATUS
118 NTAPI
119 IKsDevice_fnReleaseDevice(
120     IN IKsDevice * iface)
121 {
122     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
123 
124     return KeReleaseMutex(&This->DeviceMutex, FALSE);
125 }
126 
127 NTSTATUS
128 NTAPI
129 IKsDevice_fnGetAdapterObject(
130     IN IKsDevice * iface,
131     IN PADAPTER_OBJECT * Object,
132     IN PULONG MaxMappingsByteCount,
133     IN PULONG MappingTableStride)
134 {
135     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
136 
137     *Object = This->AdapterObject;
138     *MaxMappingsByteCount = This->MaxMappingsByteCount;
139     *MappingTableStride = This->MappingTableStride;
140 
141     return STATUS_SUCCESS;
142 
143 }
144 
145 NTSTATUS
146 NTAPI
147 IKsDevice_fnAddPowerEntry(
148     IN IKsDevice * iface,
149     IN struct KSPOWER_ENTRY * Entry,
150     IN IKsPowerNotify* Notify)
151 {
152     //PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
153 
154     UNIMPLEMENTED;
155     return STATUS_NOT_IMPLEMENTED;
156 }
157 
158 NTSTATUS
159 NTAPI
160 IKsDevice_fnRemovePowerEntry(
161     IN IKsDevice * iface,
162     IN struct KSPOWER_ENTRY * Entry)
163 {
164     //PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
165 
166     UNIMPLEMENTED;
167     return STATUS_NOT_IMPLEMENTED;
168 
169 }
170 
171 NTSTATUS
172 NTAPI
173 IKsDevice_fnPinStateChange(
174     IN IKsDevice * iface,
175     IN KSPIN Pin,
176     IN PIRP Irp,
177     IN KSSTATE OldState,
178     IN KSSTATE NewState)
179 {
180     //PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
181 
182     UNIMPLEMENTED;
183     return STATUS_NOT_IMPLEMENTED;
184 
185 }
186 
187 NTSTATUS
188 NTAPI
189 IKsDevice_fnArbitrateAdapterChannel(
190     IN IKsDevice * iface,
191     IN ULONG NumberOfMapRegisters,
192     IN PDRIVER_CONTROL ExecutionRoutine,
193     IN PVOID Context)
194 {
195     PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
196     NTSTATUS Status;
197 
198     DPRINT("IKsDevice_fnArbitrateAdapterChannel NumberOfMapRegisters %lu ExecutionRoutine %p Context %p Irql %lu\n", NumberOfMapRegisters, ExecutionRoutine, Context, KeGetCurrentIrql());
199 
200     /* sanity check */
201     ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
202     ASSERT(This->AdapterObject);
203 
204     /* allocate adapter channel */
205     Status = IoAllocateAdapterChannel(This->AdapterObject, This->KsDevice.FunctionalDeviceObject, NumberOfMapRegisters, ExecutionRoutine, Context);
206 
207     /* done */
208     return Status;
209 }
210 
211 NTSTATUS
212 NTAPI
213 IKsDevice_fnCheckIoCapability(
214     IN IKsDevice * iface,
215     IN ULONG Unknown)
216 {
217     //PKSIDEVICE_HEADER This = (PKSIDEVICE_HEADER)CONTAINING_RECORD(iface, KSIDEVICE_HEADER, BasicHeader.OuterUnknown);
218 
219     UNIMPLEMENTED;
220     return STATUS_NOT_IMPLEMENTED;
221 }
222 
223 static IKsDeviceVtbl vt_IKsDevice =
224 {
225     IKsDevice_fnQueryInterface,
226     IKsDevice_fnAddRef,
227     IKsDevice_fnRelease,
228     IKsDevice_fnGetStruct,
229     IKsDevice_fnInitializeObjectBag,
230     IKsDevice_fnAcquireDevice,
231     IKsDevice_fnReleaseDevice,
232     IKsDevice_fnGetAdapterObject,
233     IKsDevice_fnAddPowerEntry,
234     IKsDevice_fnRemovePowerEntry,
235     IKsDevice_fnPinStateChange,
236     IKsDevice_fnArbitrateAdapterChannel,
237     IKsDevice_fnCheckIoCapability
238 };
239 
240 
241 VOID
242 NTAPI
243 IKsDevice_PnpPostStart(
244     IN PDEVICE_OBJECT  DeviceObject,
245     IN PVOID  Context)
246 {
247     NTSTATUS Status;
248     PPNP_POSTSTART_CONTEXT Ctx = (PPNP_POSTSTART_CONTEXT)Context;
249 
250     /* call driver pnp post routine */
251     Status = Ctx->DeviceHeader->KsDevice.Descriptor->Dispatch->PostStart(&Ctx->DeviceHeader->KsDevice);
252 
253     if (!NT_SUCCESS(Status))
254     {
255         /* set state to disabled */
256         Ctx->DeviceHeader->TargetState  = KSTARGET_STATE_DISABLED;
257     }
258     else
259     {
260         /* set state to enabled */
261         Ctx->DeviceHeader->TargetState = KSTARGET_STATE_ENABLED;
262         Status = KspSetFilterFactoriesState(Ctx->DeviceHeader, TRUE);
263     }
264 
265     /* free work item */
266     IoFreeWorkItem(Ctx->WorkItem);
267 
268     /* free work context */
269     FreeItem(Ctx);
270 
271     DPRINT("IKsDevice_PnpPostStart: PostStart Routine returned %x\n", Status);
272 }
273 
274 NTSTATUS
275 NTAPI
276 IKsDevice_PnpStartDevice(
277     IN PDEVICE_OBJECT  DeviceObject,
278     IN PIRP Irp)
279 {
280     PIO_STACK_LOCATION IoStack;
281     PDEVICE_EXTENSION DeviceExtension;
282     PKSIDEVICE_HEADER DeviceHeader;
283     PPNP_POSTSTART_CONTEXT Ctx = NULL;
284     NTSTATUS Status;
285     PCM_RESOURCE_LIST TranslatedResourceList;
286     PCM_RESOURCE_LIST UntranslatedResourceList;
287 
288     /* get current stack location */
289     IoStack = IoGetCurrentIrpStackLocation(Irp);
290     /* get device extension */
291     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
292     /* get device header */
293     DeviceHeader = DeviceExtension->DeviceHeader;
294 
295     DPRINT("IKsDevice_PnpStartDevice DeviceHeader %p\n", DeviceHeader);
296 
297     /* first forward irp to lower device object */
298     if (!IoForwardIrpSynchronously(DeviceHeader->KsDevice.NextDeviceObject, Irp))
299     {
300         Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
301     }
302     Status = Irp->IoStatus.Status;
303 
304     /* check for success */
305     if (!NT_SUCCESS(Status))
306     {
307         DPRINT1("NextDevice object failed to start with %x\n", Status);
308         CompleteRequest(Irp, IO_NO_INCREMENT);
309         return Status;
310     }
311 
312     TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
313     UntranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResources;
314 
315     ASSERT(DeviceHeader->KsDevice.Descriptor);
316 
317     /* do we have a device descriptor */
318     if (DeviceHeader->KsDevice.Descriptor)
319     {
320         /* does the device want pnp notifications */
321         if (DeviceHeader->KsDevice.Descriptor->Dispatch)
322         {
323             /* does the driver care about IRP_MN_START_DEVICE */
324             if (DeviceHeader->KsDevice.Descriptor->Dispatch->Start)
325             {
326                 /* call driver start device routine */
327                 Status = DeviceHeader->KsDevice.Descriptor->Dispatch->Start(&DeviceHeader->KsDevice, Irp,
328                                                                    TranslatedResourceList,
329                                                                    UntranslatedResourceList);
330 
331 
332                 DPRINT("IKsDevice_PnpStartDevice Start %p, Context %p\n", DeviceHeader->KsDevice.Descriptor->Dispatch->Start, DeviceHeader->KsDevice.Context);
333                 ASSERT(Status != STATUS_PENDING);
334 
335                 if (!NT_SUCCESS(Status))
336                 {
337                     DPRINT1("Driver: failed to start %x\n", Status);
338                     Irp->IoStatus.Status = Status;
339                     CompleteRequest(Irp, IO_NO_INCREMENT);
340                     return Status;
341                 }
342 
343                 /* set state to run */
344                 DeviceHeader->KsDevice.Started = TRUE;
345 
346             }
347 
348             /* does the driver need post start routine */
349             if (DeviceHeader->KsDevice.Descriptor->Dispatch->PostStart)
350             {
351                 /* allocate pnp post workitem context */
352                 Ctx = (PPNP_POSTSTART_CONTEXT)AllocateItem(NonPagedPool, sizeof(PNP_POSTSTART_CONTEXT));
353                 if (!Ctx)
354                 {
355                     /* no memory */
356                     Status = STATUS_INSUFFICIENT_RESOURCES;
357                 }
358                 else
359                 {
360                     /* allocate a work item */
361                     Ctx->WorkItem = IoAllocateWorkItem(DeviceObject);
362 
363                     if (!Ctx->WorkItem)
364                     {
365                          /* no memory */
366                         FreeItem(Ctx);
367                         Ctx = NULL;
368                         Status = STATUS_INSUFFICIENT_RESOURCES;
369                     }
370                     else
371                     {
372                         /* store device header for post-start pnp processing */
373                         Ctx->DeviceHeader = DeviceHeader;
374                     }
375                 }
376             }
377             else
378             {
379                 /* set state to enabled, IRP_MJ_CREATE request may now succeed */
380                 DeviceHeader->TargetState = KSTARGET_STATE_ENABLED;
381                 Status = KspSetFilterFactoriesState(DeviceHeader, TRUE);
382             }
383         }
384         else
385         {
386             /* set state to run */
387             DeviceHeader->KsDevice.Started = TRUE;
388         }
389     }
390 
391     /* store result */
392     Irp->IoStatus.Status = Status;
393     /* complete request */
394     CompleteRequest(Irp, IO_NO_INCREMENT);
395 
396     if (Ctx)
397     {
398         /* queue a work item for driver post start routine */
399         IoQueueWorkItem(Ctx->WorkItem, IKsDevice_PnpPostStart, DelayedWorkQueue, (PVOID)Ctx);
400     }
401 
402     /* return result */
403     DPRINT("IKsDevice_PnpStartDevice Status %x PostStartRoutine %p\n", Status, Ctx);
404     return Status;
405 }
406 
407 NTSTATUS
408 NTAPI
409 IKsDevice_Pnp(
410     IN PDEVICE_OBJECT  DeviceObject,
411     IN PIRP Irp)
412 {
413     PIO_STACK_LOCATION IoStack;
414     PDEVICE_EXTENSION DeviceExtension;
415     PKSIDEVICE_HEADER DeviceHeader;
416     PKSDEVICE_DISPATCH Dispatch = NULL;
417     NTSTATUS Status;
418 
419     /* get current stack location */
420     IoStack = IoGetCurrentIrpStackLocation(Irp);
421 
422     /* get device extension */
423     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
424     /* get device header */
425     DeviceHeader = DeviceExtension->DeviceHeader;
426 
427     /* do we have a device descriptor */
428     if (DeviceHeader->KsDevice.Descriptor && DeviceHeader->KsDevice.Descriptor->Dispatch)
429     {
430         /* does the device want pnp notifications */
431         Dispatch = (PKSDEVICE_DISPATCH)DeviceHeader->KsDevice.Descriptor->Dispatch;
432     }
433 
434     switch (IoStack->MinorFunction)
435     {
436         case IRP_MN_START_DEVICE:
437         {
438             return IKsDevice_PnpStartDevice(DeviceObject, Irp);
439         }
440 
441         case IRP_MN_QUERY_STOP_DEVICE:
442         {
443             Status = STATUS_SUCCESS;
444             /* check for pnp notification support */
445             if (Dispatch)
446             {
447                 /* check for query stop support */
448                 if (Dispatch->QueryStop)
449                 {
450                     /* call driver's query stop */
451                     Status = Dispatch->QueryStop(&DeviceHeader->KsDevice, Irp);
452                     ASSERT(Status != STATUS_PENDING);
453                 }
454             }
455 
456             if (!NT_SUCCESS(Status))
457             {
458                 DPRINT1("Driver: query stop failed %x\n", Status);
459                 Irp->IoStatus.Status = Status;
460                 CompleteRequest(Irp, IO_NO_INCREMENT);
461                 return Status;
462             }
463 
464             /* pass the irp down the driver stack */
465             IoSkipCurrentIrpStackLocation(Irp);
466             return IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
467         }
468 
469         case IRP_MN_REMOVE_DEVICE:
470         {
471             /* Clean up */
472             if (Dispatch)
473             {
474                 /* check for remove support */
475                 if (Dispatch->Remove)
476                 {
477                     /* call driver's stop routine */
478                     Dispatch->Remove(&DeviceHeader->KsDevice, Irp);
479                 }
480             }
481 
482             /* pass the irp down the driver stack */
483             IoSkipCurrentIrpStackLocation(Irp);
484             Status = IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
485             /* FIXME delete device resources */
486             return Status;
487         }
488         case IRP_MN_QUERY_INTERFACE:
489         {
490             Status = STATUS_UNSUCCESSFUL;
491             /* check for pnp notification support */
492             if (Dispatch)
493             {
494                 /* check for query interface support */
495                 if (Dispatch->QueryInterface)
496                 {
497                     /* call driver's query interface */
498                     Status = Dispatch->QueryInterface(&DeviceHeader->KsDevice, Irp);
499                     ASSERT(Status != STATUS_PENDING);
500                 }
501             }
502 
503             if (NT_SUCCESS(Status))
504             {
505                 /* driver supports a private interface */
506                 DPRINT1("IRP_MN_QUERY_INTERFACE Device supports interface\n");
507                 Irp->IoStatus.Status = Status;
508                 CompleteRequest(Irp, IO_NO_INCREMENT);
509                 return Status;
510             }
511 
512             /* pass the irp down the driver stack */
513             IoSkipCurrentIrpStackLocation(Irp);
514             return IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
515         }
516         case IRP_MN_QUERY_DEVICE_RELATIONS:
517         {
518             /* pass the irp down the driver stack */
519             IoSkipCurrentIrpStackLocation(Irp);
520             return IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
521         }
522         case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
523         {
524             /* pass the irp down the driver stack */
525             //Status = KspForwardIrpSynchronous(DeviceObject, Irp);
526             Status = Irp->IoStatus.Status;
527             DPRINT("IRP_MN_FILTER_RESOURCE_REQUIREMENTS Next Device: Status %x\n", Status);
528 
529             //Irp->IoStatus.Status = Status;
530             CompleteRequest(Irp, IO_NO_INCREMENT);
531             return Status;
532         }
533        case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
534        {
535             /* pass the irp down the driver stack */
536             IoSkipCurrentIrpStackLocation(Irp);
537             return IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
538        }
539        default:
540             DPRINT1("unhandled function %u\n", IoStack->MinorFunction);
541             /* pass the irp down the driver stack */
542             IoSkipCurrentIrpStackLocation(Irp);
543             return IoCallDriver(DeviceHeader->KsDevice.NextDeviceObject, Irp);
544     }
545 }
546 
547 NTSTATUS
548 NTAPI
549 IKsDevice_Power(
550     IN PDEVICE_OBJECT  DeviceObject,
551     IN PIRP Irp)
552 {
553     UNIMPLEMENTED;
554 
555     /* TODO */
556 
557     Irp->IoStatus.Status = STATUS_SUCCESS;
558     Irp->IoStatus.Information = 0;
559     CompleteRequest(Irp, IO_NO_INCREMENT);
560 
561     return STATUS_SUCCESS;
562 }
563 
564 NTSTATUS
565 NTAPI
566 IKsDevice_Create(
567     IN PDEVICE_OBJECT  DeviceObject,
568     IN PIRP Irp)
569 {
570     PCREATE_ITEM_ENTRY CreateItemEntry;
571     PIO_STACK_LOCATION IoStack;
572     PDEVICE_EXTENSION DeviceExtension;
573     PKSIDEVICE_HEADER DeviceHeader;
574     PKSIOBJECT_HEADER ObjectHeader;
575     NTSTATUS Status;
576 
577     DPRINT("IKsDevice_Create\n");
578     /* get current stack location */
579     IoStack = IoGetCurrentIrpStackLocation(Irp);
580     /* get device extension */
581     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
582     /* get device header */
583     DeviceHeader = DeviceExtension->DeviceHeader;
584 
585     if (IoStack->FileObject->FileName.Buffer == NULL)
586     {
587         // ReactOS PnPMgr still sucks
588         ASSERT(IoStack->FileObject->FileName.Length == 0);
589         Irp->IoStatus.Status = STATUS_SUCCESS;
590         IoCompleteRequest(Irp, IO_NO_INCREMENT);
591         DPRINT1("ReactOS PnP hack\n");
592         return STATUS_SUCCESS;
593     }
594 
595     /* acquire list lock */
596     IKsDevice_fnAcquireDevice((IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown);
597 
598     /* sanity check */
599     ASSERT(IoStack->FileObject);
600 
601     /* check if the request is relative */
602     if (IoStack->FileObject->RelatedFileObject != NULL)
603     {
604         /* request is to instantiate a pin / node / clock / allocator */
605         ObjectHeader = (PKSIOBJECT_HEADER)IoStack->FileObject->RelatedFileObject->FsContext2;
606 
607         /* sanity check */
608         ASSERT(ObjectHeader);
609 
610         /* find a matching a create item */
611         Status = FindMatchingCreateItem(&ObjectHeader->ItemList,
612                                         &IoStack->FileObject->FileName,
613                                         &CreateItemEntry);
614     }
615     else
616     {
617         /* request to create a filter */
618         Status = FindMatchingCreateItem(&DeviceHeader->ItemList,
619                                         &IoStack->FileObject->FileName,
620                                         &CreateItemEntry);
621     }
622 
623     if (NT_SUCCESS(Status))
624     {
625         /* set object create item */
626         KSCREATE_ITEM_IRP_STORAGE(Irp) = CreateItemEntry->CreateItem;
627 
628         /* call create function */
629         Status = CreateItemEntry->CreateItem->Create(DeviceObject, Irp);
630 
631         if (NT_SUCCESS(Status))
632         {
633             /* increment create item reference count */
634             InterlockedIncrement(&CreateItemEntry->ReferenceCount);
635         }
636     }
637 
638     /* release list lock */
639     IKsDevice_fnReleaseDevice((IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown);
640 
641     /* done */
642     return Status;
643 
644 
645 }
646 
647 /*
648     @implemented
649 */
650 KSDDKAPI
651 NTSTATUS
652 NTAPI
653 KsInitializeDevice(
654     IN PDEVICE_OBJECT FunctionalDeviceObject,
655     IN PDEVICE_OBJECT PhysicalDeviceObject,
656     IN PDEVICE_OBJECT NextDeviceObject,
657     IN const KSDEVICE_DESCRIPTOR* Descriptor OPTIONAL)
658 {
659     PDEVICE_EXTENSION DeviceExtension;
660     PKSIDEVICE_HEADER Header;
661     ULONG Index;
662     PKSIOBJECT_BAG Bag;
663     NTSTATUS Status = STATUS_SUCCESS;
664 
665     DPRINT1("KsInitializeDevice Descriptor %p\n", Descriptor);
666 
667     /* get device extension */
668     DeviceExtension = (PDEVICE_EXTENSION)FunctionalDeviceObject->DeviceExtension;
669 
670     /* first allocate device header */
671     Status = KsAllocateDeviceHeader((KSDEVICE_HEADER*)&DeviceExtension->DeviceHeader, 0, NULL);
672 
673     /* point to allocated header */
674     Header = DeviceExtension->DeviceHeader;
675 
676     DPRINT1("DeviceHeader %p\n", DeviceExtension->DeviceHeader);
677 
678     if (Descriptor && Descriptor->Dispatch)
679     {
680         DPRINT("Descriptor Add %p\n", Descriptor->Dispatch->Add);
681         DPRINT("Descriptor Start %p\n", Descriptor->Dispatch->Start);
682         DPRINT("Descriptor PostStart %p\n", Descriptor->Dispatch->PostStart);
683         DPRINT("Descriptor QueryStop %p\n", Descriptor->Dispatch->QueryStop);
684         DPRINT("Descriptor CancelStop %p\n", Descriptor->Dispatch->CancelStop);
685         DPRINT("Descriptor Stop %p\n", Descriptor->Dispatch->Stop);
686         DPRINT("Descriptor QueryRemove %p\n", Descriptor->Dispatch->QueryRemove);
687         DPRINT("Descriptor CancelRemove %p\n", Descriptor->Dispatch->CancelRemove);
688         DPRINT("Descriptor Remove %p\n", Descriptor->Dispatch->Remove);
689         DPRINT("Descriptor QueryCapabilities %p\n", Descriptor->Dispatch->QueryCapabilities);
690         DPRINT("Descriptor SurpriseRemoval %p\n", Descriptor->Dispatch->SurpriseRemoval);
691         DPRINT("Descriptor QueryPower %p\n", Descriptor->Dispatch->QueryPower);
692         DPRINT("Descriptor SetPower %p\n", Descriptor->Dispatch->SetPower);
693         DPRINT("Descriptor QueryInterface %p\n", Descriptor->Dispatch->QueryInterface);
694     }
695 
696     /* check for success */
697     if (!NT_SUCCESS(Status))
698     {
699         DPRINT1("KsInitializeDevice Failed to allocate device header with %x\n", Status);
700         return Status;
701     }
702 
703     /* initialize IKsDevice interface */
704     Header->BasicHeader.OuterUnknown = (PUNKNOWN)&vt_IKsDevice;
705     Header->ref = 1;
706 
707     /* allocate object bag */
708     Header->KsDevice.Bag = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_BAG));
709     if (!Header->KsDevice.Bag)
710     {
711         /* no memory */
712         KsFreeDeviceHeader((KSDEVICE_HEADER*)&DeviceExtension->DeviceHeader);
713         return STATUS_INSUFFICIENT_RESOURCES;
714     }
715 
716     /* initialize object bag */
717     KeInitializeMutex(&Header->BagMutex, 0);
718     KeInitializeMutex(&Header->DeviceMutex, 0);
719 
720     Bag = (PKSIOBJECT_BAG)Header->KsDevice.Bag;
721     Bag->BagMutex = &Header->BagMutex;
722     InitializeListHead(&Header->ObjectBags);
723     InitializeListHead(&Bag->ObjectList);
724     Bag->DeviceHeader = (PVOID)Header;
725 
726     /* insert bag into device list */
727     InsertTailList(&Header->ObjectBags, &Bag->Entry);
728 
729     /* initialize device header */
730     Header->KsDevice.FunctionalDeviceObject = FunctionalDeviceObject;
731     Header->KsDevice.PhysicalDeviceObject = PhysicalDeviceObject;
732     Header->KsDevice.NextDeviceObject = NextDeviceObject;
733     Header->KsDevice.Descriptor = Descriptor;
734     Header->KsDevice.SystemPowerState = PowerSystemWorking;
735     Header->KsDevice.DevicePowerState = PowerDeviceD0;
736     Header->KsDevice.Started = FALSE;
737     Header->KsDevice.Context = NULL;
738     KsSetDevicePnpAndBaseObject(Header, PhysicalDeviceObject, NextDeviceObject);
739 
740 
741 
742     if (Descriptor)
743     {
744         /* create a filter factory for each filter descriptor */
745         DPRINT("KsInitializeDevice FilterDescriptorCount %lu\n", Descriptor->FilterDescriptorsCount);
746         for(Index = 0; Index < Descriptor->FilterDescriptorsCount; Index++)
747         {
748             Status = KspCreateFilterFactory(FunctionalDeviceObject, Descriptor->FilterDescriptors[Index], NULL, NULL, 0, NULL, NULL, NULL);
749 
750             DPRINT("KsInitializeDevice Index %lu KspCreateFilterFactory Status %lx\n", Index, Status);
751             /* check for success */
752             if (!NT_SUCCESS(Status))
753             {
754                 DPRINT1("KspCreateFilterFactory failed with %x\n", Status);
755                 /* FIXME memory leak */
756                 return Status;
757             }
758         }
759 
760         /* does the driver care about the add device */
761         if (Descriptor->Dispatch && Descriptor->Dispatch->Add)
762         {
763             Status = Descriptor->Dispatch->Add(&Header->KsDevice);
764             DPRINT("Driver: AddHandler Status %x\n", Status);
765         }
766 
767         Header->KsDevice.Descriptor = Descriptor;
768     }
769 
770 
771    return Status;
772 }
773 
774 /*
775     @implemented
776 */
777 KSDDKAPI
778 NTSTATUS
779 NTAPI
780 KsReferenceSoftwareBusObject(
781     IN KSDEVICE_HEADER  Header)
782 {
783      IKsDevice * Device;
784      PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
785 
786      /* get device interface */
787      Device = (IKsDevice*)DeviceHeader->BasicHeader.OuterUnknown;
788 
789      if (Device)
790      {
791          /* reference device interface */
792          Device->lpVtbl->AddRef(Device);
793      }
794 
795     return STATUS_SUCCESS;
796 }
797 
798 /*
799     @implemented
800 */
801 KSDDKAPI
802 NTSTATUS
803 NTAPI
804 KsReferenceBusObject(
805     IN  KSDEVICE_HEADER Header)
806 {
807      IKsDevice * Device;
808      PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
809 
810      /* get device interface */
811      Device = (IKsDevice*)DeviceHeader->BasicHeader.OuterUnknown;
812 
813      if (Device)
814      {
815          /* reference device interface */
816          Device->lpVtbl->AddRef(Device);
817      }
818 
819     return STATUS_SUCCESS;
820 
821 }
822 
823 /*
824     @implemented
825 */
826 KSDDKAPI
827 VOID
828 NTAPI
829 KsDereferenceBusObject(
830     IN  KSDEVICE_HEADER Header)
831 {
832      IKsDevice * Device;
833      PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
834 
835      /* get device interface */
836      Device = (IKsDevice*)DeviceHeader->BasicHeader.OuterUnknown;
837 
838      if (Device)
839      {
840          /* release device interface */
841          Device->lpVtbl->Release(Device);
842      }
843 }
844 
845 /*
846     @implemented
847 */
848 KSDDKAPI
849 VOID
850 NTAPI
851 KsDereferenceSoftwareBusObject(
852     IN KSDEVICE_HEADER  Header)
853 {
854      IKsDevice * Device;
855      PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
856 
857      DPRINT("KsDereferenceSoftwareBusObject DeviceHeader %p\n", Header);
858 
859      /* get device interface */
860      Device = (IKsDevice*)DeviceHeader->BasicHeader.OuterUnknown;
861 
862      if (Device)
863      {
864          /* release device interface */
865          Device->lpVtbl->Release(Device);
866      }
867 }
868