xref: /reactos/drivers/ksfilter/ks/api.c (revision 845faec4)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/api.c
5  * PURPOSE:         KS API functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 const GUID GUID_NULL              = {0x00000000L, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
15 const GUID KSMEDIUMSETID_Standard = {0x4747B320L, 0x62CE, 0x11CF, {0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00}};
16 
17 /*
18     @implemented
19 */
20 KSDDKAPI
21 NTSTATUS
22 NTAPI
23 KsAcquireResetValue(
24     IN  PIRP Irp,
25     OUT KSRESET* ResetValue)
26 {
27     PIO_STACK_LOCATION IoStack;
28     KSRESET* Value;
29     NTSTATUS Status = STATUS_SUCCESS;
30 
31     /* get current irp stack */
32     IoStack = IoGetCurrentIrpStackLocation(Irp);
33 
34     /* check if there is reset value provided */
35     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSRESET))
36         return STATUS_INVALID_PARAMETER;
37 
38     if (Irp->RequestorMode == UserMode)
39     {
40         /* need to probe the buffer */
41         _SEH2_TRY
42         {
43             ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSRESET), sizeof(UCHAR));
44             Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
45             *ResetValue = *Value;
46         }
47         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
48         {
49             /* Exception, get the error code */
50             Status = _SEH2_GetExceptionCode();
51         }
52         _SEH2_END;
53     }
54     else
55     {
56         Value = (KSRESET*)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
57         *ResetValue = *Value;
58     }
59 
60     return Status;
61 }
62 
63 /*
64     @implemented
65 */
66 KSDDKAPI
67 VOID
68 NTAPI
69 KsAcquireDeviceSecurityLock(
70     IN KSDEVICE_HEADER DevHeader,
71     IN BOOLEAN Exclusive)
72 {
73     PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
74 
75     KeEnterCriticalRegion();
76 
77     if (Exclusive)
78     {
79         ExAcquireResourceExclusiveLite(&Header->SecurityLock, TRUE);
80     }
81     else
82     {
83         ExAcquireResourceSharedLite(&Header->SecurityLock, TRUE);
84     }
85 }
86 
87 /*
88     @implemented
89 */
90 KSDDKAPI
91 VOID
92 NTAPI
93 KsReleaseDeviceSecurityLock(
94     IN KSDEVICE_HEADER DevHeader)
95 {
96     PKSIDEVICE_HEADER Header = (PKSIDEVICE_HEADER)DevHeader;
97 
98     DPRINT("KsReleaseDevice\n");
99 
100     ExReleaseResourceLite(&Header->SecurityLock);
101     KeLeaveCriticalRegion();
102 }
103 
104 /*
105     @implemented
106 */
107 KSDDKAPI
108 NTSTATUS
109 NTAPI
110 KsDefaultDispatchPnp(
111     IN  PDEVICE_OBJECT DeviceObject,
112     IN  PIRP Irp)
113 {
114     PDEVICE_EXTENSION DeviceExtension;
115     PKSIDEVICE_HEADER DeviceHeader;
116     PIO_STACK_LOCATION IoStack;
117     PDEVICE_OBJECT PnpDeviceObject;
118     NTSTATUS Status;
119     ULONG MinorFunction;
120 
121     /* get current irp stack */
122     IoStack = IoGetCurrentIrpStackLocation(Irp);
123 
124     /* caller wants to add the target device */
125     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
126 
127     /* get device header */
128     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
129 
130     /* backup PnpBaseObject */
131     PnpDeviceObject = DeviceHeader->PnpDeviceObject;
132 
133 
134     /* backup minor function code */
135     MinorFunction = IoStack->MinorFunction;
136 
137     if(MinorFunction == IRP_MN_REMOVE_DEVICE)
138     {
139         /* remove the device */
140         KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
141     }
142 
143     /* skip current irp stack */
144     IoSkipCurrentIrpStackLocation(Irp);
145 
146     /* call attached pnp device object */
147     Status = IoCallDriver(PnpDeviceObject, Irp);
148 
149     if (MinorFunction == IRP_MN_REMOVE_DEVICE)
150     {
151         /* time is over */
152         IoDetachDevice(PnpDeviceObject);
153         /* delete device */
154         IoDeleteDevice(DeviceObject);
155     }
156     /* done */
157     return Status;
158 }
159 
160 /*
161     @implemented
162 */
163 KSDDKAPI
164 NTSTATUS
165 NTAPI
166 KsDefaultDispatchPower(
167     IN  PDEVICE_OBJECT DeviceObject,
168     IN  PIRP Irp)
169 {
170     PDEVICE_EXTENSION DeviceExtension;
171     PKSIDEVICE_HEADER DeviceHeader;
172     PKSIOBJECT_HEADER ObjectHeader;
173     //PIO_STACK_LOCATION IoStack;
174     PLIST_ENTRY ListEntry;
175     NTSTATUS Status;
176 
177     /* get current irp stack */
178     //IoStack = IoGetCurrentIrpStackLocation(Irp);
179 
180     /* caller wants to add the target device */
181     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
182 
183     /* get device header */
184     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
185 
186     /* FIXME locks */
187 
188     /* loop our power dispatch list and call registered notification functions */
189     ListEntry = DeviceHeader->PowerDispatchList.Flink;
190     /* let's go */
191     while(ListEntry != &DeviceHeader->PowerDispatchList)
192     {
193         /* get object header */
194         ObjectHeader = (PKSIOBJECT_HEADER)CONTAINING_RECORD(ListEntry, KSIOBJECT_HEADER, PowerDispatchEntry);
195 
196         /* does it have still a cb */
197         if (ObjectHeader->PowerDispatch)
198         {
199             /* call the power cb */
200             Status = ObjectHeader->PowerDispatch(ObjectHeader->PowerContext, Irp);
201             ASSERT(NT_SUCCESS(Status));
202         }
203 
204         /* iterate to next entry */
205         ListEntry = ListEntry->Flink;
206     }
207 
208     /* start next power irp */
209     PoStartNextPowerIrp(Irp);
210 
211     /* skip current irp stack location */
212     IoSkipCurrentIrpStackLocation(Irp);
213 
214     /* let's roll */
215     Status = PoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
216 
217     /* done */
218     return Status;
219 }
220 
221 /*
222     @implemented
223 */
224 KSDDKAPI
225 NTSTATUS
226 NTAPI
227 KsDefaultForwardIrp(
228     IN PDEVICE_OBJECT DeviceObject,
229     IN PIRP Irp)
230 {
231     PDEVICE_EXTENSION DeviceExtension;
232     PKSIDEVICE_HEADER DeviceHeader;
233     //PIO_STACK_LOCATION IoStack;
234     NTSTATUS Status;
235 
236     /* get current irp stack */
237     //IoStack = IoGetCurrentIrpStackLocation(Irp);
238 
239     /* caller wants to add the target device */
240     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
241 
242     /* get device header */
243     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
244 
245     /* forward the request to the PDO */
246     Status = IoCallDriver(DeviceHeader->PnpDeviceObject, Irp);
247 
248     return Status;
249 }
250 
251 /*
252     @implemented
253 */
254 KSDDKAPI
255 VOID
256 NTAPI
257 KsSetDevicePnpAndBaseObject(
258     IN  KSDEVICE_HEADER Header,
259     IN  PDEVICE_OBJECT PnpDeviceObject,
260     IN  PDEVICE_OBJECT BaseDevice)
261 {
262     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
263 
264     DeviceHeader->PnpDeviceObject = PnpDeviceObject;
265     DeviceHeader->BaseDevice = BaseDevice;
266 }
267 
268 /*
269     @implemented
270 */
271 KSDDKAPI
272 PDEVICE_OBJECT
273 NTAPI
274 KsQueryDevicePnpObject(
275     IN  KSDEVICE_HEADER Header)
276 {
277     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
278 
279     /* return PnpDeviceObject */
280     return DeviceHeader->PnpDeviceObject;
281 
282 }
283 
284 /*
285     @implemented
286 */
287 KSDDKAPI
288 ACCESS_MASK
289 NTAPI
290 KsQueryObjectAccessMask(
291     IN KSOBJECT_HEADER Header)
292 {
293     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
294 
295     /* return access mask */
296     return ObjectHeader->AccessMask;
297 
298 }
299 
300 /*
301     @unimplemented
302 */
303 KSDDKAPI
304 VOID
305 NTAPI
306 KsRecalculateStackDepth(
307     IN  KSDEVICE_HEADER Header,
308     IN  BOOLEAN ReuseStackLocation)
309 {
310     UNIMPLEMENTED;
311 }
312 
313 
314 /*
315     @implemented
316 */
317 KSDDKAPI
318 VOID
319 NTAPI
320 KsSetTargetState(
321     IN  KSOBJECT_HEADER Header,
322     IN  KSTARGET_STATE TargetState)
323 {
324     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)Header;
325 
326     /* set target state */
327     DeviceHeader->TargetState = TargetState;
328 }
329 
330 /*
331     @implemented
332 */
333 KSDDKAPI
334 VOID
335 NTAPI
336 KsSetTargetDeviceObject(
337     IN  KSOBJECT_HEADER Header,
338     IN  PDEVICE_OBJECT TargetDevice OPTIONAL)
339 {
340     PDEVICE_EXTENSION DeviceExtension;
341     PKSIDEVICE_HEADER DeviceHeader;
342     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
343 
344     if(ObjectHeader->TargetDevice)
345     {
346         /* there is already a target device set */
347         if (!TargetDevice)
348         {
349             /* caller wants to remove the target device */
350             DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->TargetDevice->DeviceExtension;
351 
352             /* get device header */
353             DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
354 
355             /* acquire lock */
356             KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
357 
358             /* remove entry */
359             RemoveEntryList(&ObjectHeader->TargetDeviceListEntry);
360 
361             /* remove device pointer */
362             ObjectHeader->TargetDevice = NULL;
363 
364             /* release lock */
365             KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
366         }
367     }
368     else
369     {
370         /* no target device yet set */
371         if (TargetDevice)
372         {
373             /* caller wants to add the target device */
374             DeviceExtension = (PDEVICE_EXTENSION)TargetDevice->DeviceExtension;
375 
376             /* get device header */
377             DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
378 
379             /* acquire lock */
380             KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
381 
382             /* insert list entry */
383             InsertTailList(&DeviceHeader->TargetDeviceList, &ObjectHeader->TargetDeviceListEntry);
384 
385             /* store target device */
386             ObjectHeader->TargetDevice = TargetDevice;
387 
388             /* release lock */
389             KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
390         }
391     }
392 
393 }
394 
395 /*
396     @implemented
397 */
398 KSDDKAPI
399 VOID
400 NTAPI
401 KsSetPowerDispatch(
402     IN  KSOBJECT_HEADER Header,
403     IN  PFNKSCONTEXT_DISPATCH PowerDispatch OPTIONAL,
404     IN  PVOID PowerContext OPTIONAL)
405 {
406     PDEVICE_EXTENSION DeviceExtension;
407     PKSIDEVICE_HEADER DeviceHeader;
408     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
409 
410     /* caller wants to add the target device */
411     DeviceExtension = (PDEVICE_EXTENSION)ObjectHeader->ParentDeviceObject->DeviceExtension;
412 
413     /* get device header */
414     DeviceHeader = (PKSIDEVICE_HEADER)DeviceExtension->DeviceHeader;
415 
416     /* acquire lock */
417     KsAcquireDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader, FALSE);
418 
419     if (PowerDispatch)
420     {
421         /* add power dispatch entry */
422         InsertTailList(&DeviceHeader->PowerDispatchList, &ObjectHeader->PowerDispatchEntry);
423 
424        /* store function and context */
425        ObjectHeader->PowerDispatch = PowerDispatch;
426        ObjectHeader->PowerContext = PowerContext;
427     }
428     else
429     {
430         /* remove power dispatch entry */
431         RemoveEntryList(&ObjectHeader->PowerDispatchEntry);
432 
433        /* store function and context */
434        ObjectHeader->PowerDispatch = NULL;
435        ObjectHeader->PowerContext = NULL;
436 
437     }
438 
439     /* release lock */
440     KsReleaseDeviceSecurityLock((KSDEVICE_HEADER)DeviceHeader);
441 }
442 
443 
444 /*
445     @implemented
446 */
447 KSDDKAPI
448 PKSOBJECT_CREATE_ITEM
449 NTAPI
450 KsQueryObjectCreateItem(
451     IN KSOBJECT_HEADER Header)
452 {
453     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER)Header;
454     return ObjectHeader->OriginalCreateItem;
455 }
456 
457 NTSTATUS
458 KspAddCreateItemToList(
459     OUT PLIST_ENTRY ListHead,
460     IN ULONG ItemsCount,
461     IN  PKSOBJECT_CREATE_ITEM ItemsList)
462 {
463     ULONG Index;
464     PCREATE_ITEM_ENTRY Entry;
465 
466     /* add the items */
467     for(Index = 0; Index < ItemsCount; Index++)
468     {
469         /* allocate item */
470         Entry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
471         if (!Entry)
472         {
473             /* no memory */
474             return STATUS_INSUFFICIENT_RESOURCES;
475         }
476 
477         /* initialize entry */
478         InitializeListHead(&Entry->ObjectItemList);
479         Entry->CreateItem = &ItemsList[Index];
480         Entry->ReferenceCount = 0;
481         Entry->ItemFreeCallback = NULL;
482 
483         InsertTailList(ListHead, &Entry->Entry);
484     }
485     return STATUS_SUCCESS;
486 }
487 
488 VOID
489 KspFreeCreateItems(
490     PLIST_ENTRY ListHead)
491 {
492     PCREATE_ITEM_ENTRY Entry;
493 
494     while(!IsListEmpty(ListHead))
495     {
496         /* remove create item from list */
497         Entry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(RemoveHeadList(ListHead), CREATE_ITEM_ENTRY, Entry);
498 
499         /* caller shouldnt have any references */
500         //ASSERT(Entry->ReferenceCount == 0);
501         //ASSERT(IsListEmpty(&Entry->ObjectItemList));
502 
503         /* does the creator wish notification */
504         if (Entry->ItemFreeCallback)
505         {
506             /* notify creator */
507             Entry->ItemFreeCallback(Entry->CreateItem);
508         }
509 
510         /* free create item entry */
511          FreeItem(Entry);
512     }
513 
514 }
515 
516 /*
517     @implemented
518 */
519 KSDDKAPI
520 NTSTATUS
521 NTAPI
522 KsAllocateDeviceHeader(
523     OUT KSDEVICE_HEADER* OutHeader,
524     IN  ULONG ItemsCount,
525     IN  PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL)
526 {
527     NTSTATUS Status = STATUS_SUCCESS;
528     PKSIDEVICE_HEADER Header;
529 
530     if (!OutHeader)
531         return STATUS_INVALID_PARAMETER;
532 
533     /* allocate a device header */
534     Header = AllocateItem(PagedPool, sizeof(KSIDEVICE_HEADER));
535 
536     /* check for success */
537     if (!Header)
538         return STATUS_INSUFFICIENT_RESOURCES;
539 
540     /* clear all memory */
541     RtlZeroMemory(Header, sizeof(KSIDEVICE_HEADER));
542 
543     /* initialize device mutex */
544     KeInitializeMutex(&Header->DeviceMutex, 0);
545 
546     /* initialize target device list */
547     InitializeListHead(&Header->TargetDeviceList);
548     /* initialize power dispatch list */
549     InitializeListHead(&Header->PowerDispatchList);
550     /* initialize object bag lists */
551     InitializeListHead(&Header->ObjectBags);
552 
553     /* initialize create item list */
554     InitializeListHead(&Header->ItemList);
555 
556     /* initialize basic header */
557     Header->BasicHeader.Type = KsObjectTypeDevice;
558     Header->BasicHeader.KsDevice = &Header->KsDevice;
559     Header->BasicHeader.Parent.KsDevice = &Header->KsDevice;
560 
561     /* are there any create items provided */
562     if (ItemsCount && ItemsList)
563     {
564         Status = KspAddCreateItemToList(&Header->ItemList, ItemsCount, ItemsList);
565 
566         if (NT_SUCCESS(Status))
567         {
568             /* store item count */
569             Header->ItemListCount = ItemsCount;
570         }
571         else
572         {
573             /* release create items */
574             KspFreeCreateItems(&Header->ItemList);
575         }
576     }
577 
578     /* store result */
579     *OutHeader = Header;
580 
581     return Status;
582 }
583 
584 /*
585     @implemented
586 */
587 KSDDKAPI
588 VOID
589 NTAPI
590 KsFreeDeviceHeader(
591     IN  KSDEVICE_HEADER DevHeader)
592 {
593     PKSIDEVICE_HEADER Header;
594 
595     Header = (PKSIDEVICE_HEADER)DevHeader;
596 
597     if (!DevHeader)
598         return;
599 
600     KspFreeCreateItems(&Header->ItemList);
601     FreeItem(Header);
602 }
603 
604 /*
605     @implemented
606 */
607 KSDDKAPI
608 NTSTATUS
609 NTAPI
610 KsAllocateObjectHeader(
611     OUT KSOBJECT_HEADER *Header,
612     IN  ULONG ItemsCount,
613     IN  PKSOBJECT_CREATE_ITEM ItemsList OPTIONAL,
614     IN  PIRP Irp,
615     IN  KSDISPATCH_TABLE* Table)
616 {
617     PIO_STACK_LOCATION IoStack;
618     //PDEVICE_EXTENSION DeviceExtension;
619     //PKSIDEVICE_HEADER DeviceHeader;
620     PKSIOBJECT_HEADER ObjectHeader;
621     //PKSOBJECT_CREATE_ITEM CreateItem;
622     NTSTATUS Status;
623 
624     if (!Header)
625         return STATUS_INVALID_PARAMETER_1;
626 
627     if (!Irp)
628         return STATUS_INVALID_PARAMETER_4;
629 
630     if (!Table)
631         return STATUS_INVALID_PARAMETER_5;
632 
633     /* get current stack location */
634     IoStack = IoGetCurrentIrpStackLocation(Irp);
635     /* get device extension */
636     //DeviceExtension = (PDEVICE_EXTENSION)IoStack->DeviceObject->DeviceExtension;
637     /* get device header */
638     //DeviceHeader = DeviceExtension->DeviceHeader;
639 
640     /* sanity check */
641     ASSERT(IoStack->FileObject);
642     /* check for an file object */
643 
644     /* allocate the object header */
645     ObjectHeader = AllocateItem(NonPagedPool, sizeof(KSIOBJECT_HEADER));
646     if (!ObjectHeader)
647         return STATUS_INSUFFICIENT_RESOURCES;
648 
649     /* initialize object header */
650     RtlZeroMemory(ObjectHeader, sizeof(KSIOBJECT_HEADER));
651 
652     /* initialize create item list */
653     InitializeListHead(&ObjectHeader->ItemList);
654 
655     /* get create item */
656     //CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
657 
658     /* do we have a name */
659     if (IoStack->FileObject->FileName.Buffer)
660     {
661         /* copy object class */
662         ObjectHeader->ObjectClass.MaximumLength = IoStack->FileObject->FileName.MaximumLength;
663         ObjectHeader->ObjectClass.Buffer = AllocateItem(NonPagedPool, ObjectHeader->ObjectClass.MaximumLength);
664         if (!ObjectHeader->ObjectClass.Buffer)
665         {
666             FreeItem(ObjectHeader);
667             return STATUS_INSUFFICIENT_RESOURCES;
668         }
669         RtlCopyUnicodeString(&ObjectHeader->ObjectClass, &IoStack->FileObject->FileName);
670     }
671 
672     /* copy dispatch table */
673     RtlCopyMemory(&ObjectHeader->DispatchTable, Table, sizeof(KSDISPATCH_TABLE));
674 
675     /* store create items */
676     if (ItemsCount && ItemsList)
677     {
678         Status = KspAddCreateItemToList(&ObjectHeader->ItemList, ItemsCount, ItemsList);
679 
680         if (NT_SUCCESS(Status))
681         {
682             /* store item count */
683             ObjectHeader->ItemListCount = ItemsCount;
684         }
685         else
686         {
687             /* destroy header*/
688             KsFreeObjectHeader(ObjectHeader);
689             return Status;
690         }
691     }
692     /* store the object in the file object */
693     IoStack->FileObject->FsContext2 = ObjectHeader;
694 
695     /* store parent device */
696     ObjectHeader->ParentDeviceObject = IoGetRelatedDeviceObject(IoStack->FileObject);
697 
698     /* store originating create item */
699     ObjectHeader->OriginalCreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp);
700 
701     /* FIXME store access mask see KsQueryObjectAccessMask */
702     ObjectHeader->AccessMask = IoStack->Parameters.Create.SecurityContext->DesiredAccess;
703 
704 
705     /* store result */
706     *Header = ObjectHeader;
707 
708     DPRINT("KsAllocateObjectHeader ObjectClass %S FileObject %p, ObjectHeader %p\n", ObjectHeader->ObjectClass.Buffer, IoStack->FileObject, ObjectHeader);
709 
710     return STATUS_SUCCESS;
711 
712 }
713 
714 /*
715     @implemented
716 */
717 KSDDKAPI
718 VOID
719 NTAPI
720 KsFreeObjectHeader(
721     IN  PVOID Header)
722 {
723     PKSIOBJECT_HEADER ObjectHeader = (PKSIOBJECT_HEADER) Header;
724 
725     DPRINT("KsFreeObjectHeader Header %p Class %wZ\n", Header, &ObjectHeader->ObjectClass);
726 
727     if (ObjectHeader->ObjectClass.Buffer)
728     {
729         /* release object class buffer */
730         FreeItem(ObjectHeader->ObjectClass.Buffer);
731     }
732 
733     if (ObjectHeader->Unknown)
734     {
735         /* release associated object */
736         ObjectHeader->Unknown->lpVtbl->Release(ObjectHeader->Unknown);
737     }
738 
739     /* free create items */
740     KspFreeCreateItems(&ObjectHeader->ItemList);
741 
742     /* free object header */
743     FreeItem(ObjectHeader);
744 
745 }
746 
747 NTSTATUS
748 KspAddObjectCreateItemToList(
749     PLIST_ENTRY ListHead,
750     IN  PDRIVER_DISPATCH Create,
751     IN  PVOID Context,
752     IN  PWCHAR ObjectClass,
753     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
754 {
755    PLIST_ENTRY Entry;
756    PCREATE_ITEM_ENTRY CreateEntry;
757 
758     /* point to first entry */
759     Entry = ListHead->Flink;
760 
761     while(Entry != ListHead)
762     {
763         /* get create entry */
764         CreateEntry = (PCREATE_ITEM_ENTRY)CONTAINING_RECORD(Entry, CREATE_ITEM_ENTRY, Entry);
765         /* if the create item has no create routine, then it is free to use */
766         if (CreateEntry->CreateItem->Create == NULL)
767         {
768             /* sanity check */
769             ASSERT(IsListEmpty(&CreateEntry->ObjectItemList));
770             ASSERT(CreateEntry->ReferenceCount == 0);
771             /* use free entry */
772             CreateEntry->CreateItem->Context = Context;
773             CreateEntry->CreateItem->Create = Create;
774             RtlInitUnicodeString(&CreateEntry->CreateItem->ObjectClass, ObjectClass);
775             CreateEntry->CreateItem->SecurityDescriptor = SecurityDescriptor;
776 
777             return STATUS_SUCCESS;
778         }
779 
780         if (!wcsicmp(ObjectClass, CreateEntry->CreateItem->ObjectClass.Buffer))
781         {
782             /* the same object class already exists */
783             return STATUS_OBJECT_NAME_COLLISION;
784         }
785 
786         /* iterate to next entry */
787         Entry = Entry->Flink;
788     }
789     return STATUS_ALLOTTED_SPACE_EXCEEDED;
790 }
791 
792 /*
793     @implemented
794 */
795 KSDDKAPI
796 NTSTATUS
797 NTAPI
798 KsAddObjectCreateItemToDeviceHeader(
799     IN  KSDEVICE_HEADER DevHeader,
800     IN  PDRIVER_DISPATCH Create,
801     IN  PVOID Context,
802     IN  PWCHAR ObjectClass,
803     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
804 {
805     PKSIDEVICE_HEADER Header;
806     NTSTATUS Status;
807 
808     Header = (PKSIDEVICE_HEADER)DevHeader;
809 
810     DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
811 
812      /* check if a device header has been provided */
813     if (!DevHeader)
814         return STATUS_INVALID_PARAMETER_1;
815 
816     /* check if a create item has been provided */
817     if (!Create)
818         return STATUS_INVALID_PARAMETER_2;
819 
820     /* check if a object class has been provided */
821     if (!ObjectClass)
822         return STATUS_INVALID_PARAMETER_4;
823 
824     /* let others do the work */
825     Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
826 
827     if (NT_SUCCESS(Status))
828     {
829         /* increment create item count */
830         InterlockedIncrement(&Header->ItemListCount);
831     }
832     DPRINT("KsAddObjectCreateItemToDeviceHeader Status %x\n", Status);
833     return Status;
834 }
835 
836 /*
837     @implemented
838 */
839 KSDDKAPI
840 NTSTATUS
841 NTAPI
842 KsAddObjectCreateItemToObjectHeader(
843     IN  KSOBJECT_HEADER ObjectHeader,
844     IN  PDRIVER_DISPATCH Create,
845     IN  PVOID Context,
846     IN  PWCHAR ObjectClass,
847     IN  PSECURITY_DESCRIPTOR SecurityDescriptor)
848 {
849     PKSIOBJECT_HEADER Header;
850     NTSTATUS Status;
851 
852     Header = (PKSIOBJECT_HEADER)ObjectHeader;
853 
854     DPRINT("KsAddObjectCreateItemToDeviceHeader entered\n");
855 
856      /* check if a device header has been provided */
857     if (!Header)
858         return STATUS_INVALID_PARAMETER_1;
859 
860     /* check if a create item has been provided */
861     if (!Create)
862         return STATUS_INVALID_PARAMETER_2;
863 
864     /* check if a object class has been provided */
865     if (!ObjectClass)
866         return STATUS_INVALID_PARAMETER_4;
867 
868     /* let's work */
869     Status = KspAddObjectCreateItemToList(&Header->ItemList, Create, Context, ObjectClass, SecurityDescriptor);
870 
871     if (NT_SUCCESS(Status))
872     {
873         /* increment create item count */
874         InterlockedIncrement(&Header->ItemListCount);
875     }
876 
877     return Status;
878 }
879 
880 /*
881     @implemented
882 */
883 KSDDKAPI
884 NTSTATUS
885 NTAPI
886 KsAllocateObjectCreateItem(
887     IN  KSDEVICE_HEADER DevHeader,
888     IN  PKSOBJECT_CREATE_ITEM CreateItem,
889     IN  BOOLEAN AllocateEntry,
890     IN  PFNKSITEMFREECALLBACK ItemFreeCallback OPTIONAL)
891 {
892     PCREATE_ITEM_ENTRY CreateEntry;
893     PKSIDEVICE_HEADER Header;
894     PKSOBJECT_CREATE_ITEM Item;
895 
896     Header = (PKSIDEVICE_HEADER)DevHeader;
897 
898     if (!DevHeader)
899         return STATUS_INVALID_PARAMETER_1;
900 
901     if (!CreateItem)
902         return STATUS_INVALID_PARAMETER_2;
903 
904     /* first allocate a create entry */
905     CreateEntry = AllocateItem(NonPagedPool, sizeof(CREATE_ITEM_ENTRY));
906 
907     /* check for allocation success */
908     if (!CreateEntry)
909     {
910         /* not enough resources */
911         return STATUS_INSUFFICIENT_RESOURCES;
912     }
913 
914 
915     if (AllocateEntry)
916     {
917         /* allocate create item */
918         Item = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
919         if (!Item)
920         {
921             /* no memory */
922             FreeItem(CreateEntry);
923             return STATUS_INSUFFICIENT_RESOURCES;
924         }
925 
926         /* initialize descriptor */
927         Item->Context = CreateItem->Context;
928         Item->Create = CreateItem->Create;
929         Item->Flags = CreateItem->Flags;
930         Item->SecurityDescriptor = CreateItem->SecurityDescriptor;
931         Item->ObjectClass.Length = 0;
932         Item->ObjectClass.MaximumLength = CreateItem->ObjectClass.MaximumLength;
933 
934         /* copy object class */
935         Item->ObjectClass.Buffer = AllocateItem(NonPagedPool, Item->ObjectClass.MaximumLength);
936         if (!Item->ObjectClass.Buffer)
937         {
938             /* release resources */
939             FreeItem(Item);
940             FreeItem(CreateEntry);
941 
942             return STATUS_INSUFFICIENT_RESOURCES;
943         }
944         RtlCopyUnicodeString(&Item->ObjectClass, &CreateItem->ObjectClass);
945     }
946     else
947     {
948         if (ItemFreeCallback)
949         {
950             /* callback is only accepted when the create item is copied */
951             ItemFreeCallback = NULL;
952         }
953         /* use passed create item */
954         Item = CreateItem;
955     }
956 
957     /* initialize create item entry */
958     InitializeListHead(&CreateEntry->ObjectItemList);
959     CreateEntry->ItemFreeCallback = ItemFreeCallback;
960     CreateEntry->CreateItem = Item;
961     CreateEntry->ReferenceCount = 0;
962 
963     /* now insert the create item entry */
964     InsertTailList(&Header->ItemList, &CreateEntry->Entry);
965 
966     /* increment item count */
967     InterlockedIncrement(&Header->ItemListCount);
968 
969     return STATUS_SUCCESS;
970 }
971 
972 NTSTATUS
973 KspObjectFreeCreateItems(
974     IN  KSDEVICE_HEADER Header,
975     IN  PKSOBJECT_CREATE_ITEM CreateItem)
976 {
977     UNIMPLEMENTED;
978     return STATUS_NOT_IMPLEMENTED;
979 }
980 
981 /*
982     @implemented
983 */
984 KSDDKAPI
985 NTSTATUS
986 NTAPI
987 KsFreeObjectCreateItem(
988     IN  KSDEVICE_HEADER Header,
989     IN  PUNICODE_STRING CreateItem)
990 {
991     KSOBJECT_CREATE_ITEM Item;
992 
993     RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
994     RtlInitUnicodeString(&Item.ObjectClass, CreateItem->Buffer);
995 
996     return KspObjectFreeCreateItems(Header, &Item);
997 }
998 
999 
1000 /*
1001     @implemented
1002 */
1003 KSDDKAPI
1004 NTSTATUS
1005 NTAPI
1006 KsFreeObjectCreateItemsByContext(
1007     IN  KSDEVICE_HEADER Header,
1008     IN  PVOID Context)
1009 {
1010     KSOBJECT_CREATE_ITEM Item;
1011 
1012     RtlZeroMemory(&Item, sizeof(KSOBJECT_CREATE_ITEM));
1013 
1014     Item.Context = Context;
1015 
1016     return KspObjectFreeCreateItems(Header, &Item);
1017 }
1018 
1019 /*
1020     @implemented
1021 */
1022 KSDDKAPI
1023 NTSTATUS
1024 NTAPI
1025 KsCreateDefaultSecurity(
1026     IN PSECURITY_DESCRIPTOR ParentSecurity OPTIONAL,
1027     OUT PSECURITY_DESCRIPTOR* DefaultSecurity)
1028 {
1029     PGENERIC_MAPPING Mapping;
1030     SECURITY_SUBJECT_CONTEXT SubjectContext;
1031     NTSTATUS Status;
1032 
1033     /* start capturing security context of calling thread */
1034     SeCaptureSubjectContext(&SubjectContext);
1035     /* get generic mapping */
1036     Mapping = IoGetFileObjectGenericMapping();
1037     /* build new descriptor */
1038     Status = SeAssignSecurity(ParentSecurity, NULL, DefaultSecurity, FALSE, &SubjectContext, Mapping, NonPagedPool);
1039     /* release security descriptor */
1040     SeReleaseSubjectContext(&SubjectContext);
1041     /* done */
1042     return Status;
1043 }
1044 
1045 /*
1046     @unimplemented
1047 */
1048 KSDDKAPI
1049 NTSTATUS
1050 NTAPI
1051 KsForwardIrp(
1052     IN  PIRP Irp,
1053     IN  PFILE_OBJECT FileObject,
1054     IN  BOOLEAN ReuseStackLocation)
1055 {
1056     UNIMPLEMENTED;
1057     return STATUS_UNSUCCESSFUL;
1058 }
1059 
1060 
1061 /*
1062     @unimplemented
1063 */
1064 KSDDKAPI
1065 NTSTATUS
1066 NTAPI
1067 KsForwardAndCatchIrp(
1068     IN  PDEVICE_OBJECT DeviceObject,
1069     IN  PIRP Irp,
1070     IN  PFILE_OBJECT FileObject,
1071     IN  KSSTACK_USE StackUse)
1072 {
1073     UNIMPLEMENTED;
1074     return STATUS_UNSUCCESSFUL;
1075 }
1076 
1077 
1078 NTSTATUS
1079 NTAPI
1080 KspSynchronousIoControlDeviceCompletion(
1081     IN PDEVICE_OBJECT  DeviceObject,
1082     IN PIRP  Irp,
1083     IN PVOID  Context)
1084 {
1085     PIO_STATUS_BLOCK IoStatusBlock = (PIO_STATUS_BLOCK)Context;
1086 
1087     IoStatusBlock->Information = Irp->IoStatus.Information;
1088     IoStatusBlock->Status = Irp->IoStatus.Status;
1089 
1090     return STATUS_SUCCESS;
1091 }
1092 
1093 /*
1094     @implemented
1095 */
1096 KSDDKAPI
1097 NTSTATUS
1098 NTAPI
1099 KsSynchronousIoControlDevice(
1100     IN  PFILE_OBJECT FileObject,
1101     IN  KPROCESSOR_MODE RequestorMode,
1102     IN  ULONG IoControl,
1103     IN  PVOID InBuffer,
1104     IN  ULONG InSize,
1105     OUT PVOID OutBuffer,
1106     IN  ULONG OutSize,
1107     OUT PULONG BytesReturned)
1108 {
1109     PKSIOBJECT_HEADER ObjectHeader;
1110     PDEVICE_OBJECT DeviceObject;
1111     KEVENT Event;
1112     PIRP Irp;
1113     IO_STATUS_BLOCK IoStatusBlock;
1114     PIO_STACK_LOCATION IoStack;
1115     NTSTATUS Status;
1116 
1117     /* check for valid file object */
1118     if (!FileObject)
1119         return STATUS_INVALID_PARAMETER;
1120 
1121     /* get device object to send the request to */
1122     DeviceObject = IoGetRelatedDeviceObject(FileObject);
1123     if (!DeviceObject)
1124         return STATUS_UNSUCCESSFUL;
1125 
1126 
1127     /* get object header */
1128     ObjectHeader = (PKSIOBJECT_HEADER)FileObject->FsContext2;
1129 
1130     /* check if there is fast device io function */
1131     if (ObjectHeader && ObjectHeader->DispatchTable.FastDeviceIoControl)
1132     {
1133         IoStatusBlock.Status = STATUS_UNSUCCESSFUL;
1134         IoStatusBlock.Information = 0;
1135 
1136         /* send the request */
1137         Status = ObjectHeader->DispatchTable.FastDeviceIoControl(FileObject, TRUE, InBuffer, InSize, OutBuffer, OutSize, IoControl, &IoStatusBlock, DeviceObject);
1138         /* check if the request was handled */
1139         //DPRINT("Handled %u Status %x Length %u\n", Status, IoStatusBlock.Status, IoStatusBlock.Information);
1140         if (Status)
1141         {
1142             /* store bytes returned */
1143             *BytesReturned = (ULONG)IoStatusBlock.Information;
1144             /* return status */
1145             return IoStatusBlock.Status;
1146         }
1147     }
1148 
1149     /* initialize the event */
1150     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1151 
1152     /* create the irp */
1153     Irp =  IoBuildDeviceIoControlRequest(IoControl, DeviceObject, InBuffer, InSize, OutBuffer, OutSize, FALSE, &Event, &IoStatusBlock);
1154 
1155     if (!Irp)
1156     {
1157         /* no memory to allocate the irp */
1158         return STATUS_INSUFFICIENT_RESOURCES;
1159     }
1160 
1161 
1162     /* Store Fileobject */
1163     IoStack = IoGetNextIrpStackLocation(Irp);
1164     IoStack->FileObject = FileObject;
1165 
1166     if (IoControl == IOCTL_KS_WRITE_STREAM)
1167     {
1168         Irp->AssociatedIrp.SystemBuffer = OutBuffer;
1169     }
1170     else if (IoControl == IOCTL_KS_READ_STREAM)
1171     {
1172         Irp->AssociatedIrp.SystemBuffer = InBuffer;
1173     }
1174 
1175     IoSetCompletionRoutine(Irp, KspSynchronousIoControlDeviceCompletion, (PVOID)&IoStatusBlock, TRUE, TRUE, TRUE);
1176 
1177     Status = IoCallDriver(DeviceObject, Irp);
1178     if (Status == STATUS_PENDING)
1179     {
1180         KeWaitForSingleObject(&Event, Executive, RequestorMode, FALSE, NULL);
1181         Status = IoStatusBlock.Status;
1182     }
1183 
1184     *BytesReturned = (ULONG)IoStatusBlock.Information;
1185     return Status;
1186 }
1187 
1188 /*
1189     @unimplemented
1190 */
1191 KSDDKAPI
1192 NTSTATUS
1193 NTAPI
1194 KsUnserializeObjectPropertiesFromRegistry(
1195     IN PFILE_OBJECT FileObject,
1196     IN HANDLE ParentKey OPTIONAL,
1197     IN PUNICODE_STRING RegistryPath OPTIONAL)
1198 {
1199     UNIMPLEMENTED;
1200     return STATUS_NOT_IMPLEMENTED;
1201 }
1202 
1203 
1204 /*
1205     @implemented
1206 */
1207 KSDDKAPI
1208 NTSTATUS
1209 NTAPI
1210 KsCacheMedium(
1211     IN  PUNICODE_STRING SymbolicLink,
1212     IN  PKSPIN_MEDIUM Medium,
1213     IN  ULONG PinDirection)
1214 {
1215     HANDLE hKey;
1216     UNICODE_STRING Path;
1217     UNICODE_STRING BasePath = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediumCache\\");
1218     UNICODE_STRING GuidString;
1219     NTSTATUS Status;
1220     OBJECT_ATTRIBUTES ObjectAttributes;
1221     BOOLEAN PathAdjusted = FALSE;
1222     ULONG Value = 0;
1223 
1224     /* first check if the medium is standard */
1225     if (IsEqualGUIDAligned(&KSMEDIUMSETID_Standard, &Medium->Set) ||
1226         IsEqualGUIDAligned(&GUID_NULL, &Medium->Set))
1227     {
1228         /* no need to cache that */
1229         return STATUS_SUCCESS;
1230     }
1231 
1232     /* convert guid to string */
1233     Status = RtlStringFromGUID(&Medium->Set, &GuidString);
1234     if (!NT_SUCCESS(Status))
1235         return Status;
1236 
1237     /* allocate path buffer */
1238     Path.Length = 0;
1239     Path.MaximumLength = BasePath.MaximumLength + GuidString.MaximumLength + 10 * sizeof(WCHAR);
1240     Path.Buffer = AllocateItem(PagedPool, Path.MaximumLength);
1241     if (!Path.Buffer)
1242     {
1243         /* not enough resources */
1244         RtlFreeUnicodeString(&GuidString);
1245         return STATUS_INSUFFICIENT_RESOURCES;
1246     }
1247 
1248     RtlAppendUnicodeStringToString(&Path, &BasePath);
1249     RtlAppendUnicodeStringToString(&Path, &GuidString);
1250     RtlAppendUnicodeToString(&Path, L"-");
1251     /* FIXME append real instance id */
1252     RtlAppendUnicodeToString(&Path, L"0");
1253     RtlAppendUnicodeToString(&Path, L"-");
1254     /* FIXME append real instance id */
1255     RtlAppendUnicodeToString(&Path, L"0");
1256 
1257     /* free guid string */
1258     RtlFreeUnicodeString(&GuidString);
1259 
1260     /* initialize object attributes */
1261     InitializeObjectAttributes(&ObjectAttributes, &Path, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
1262     /* create the key */
1263     Status = ZwCreateKey(&hKey, GENERIC_WRITE, &ObjectAttributes, 0, NULL, 0, NULL);
1264 
1265     /* free path buffer */
1266     FreeItem(Path.Buffer);
1267 
1268     if (NT_SUCCESS(Status))
1269     {
1270         /* store symbolic link */
1271         if (SymbolicLink->Buffer[1] == L'?' && SymbolicLink->Buffer[2] == L'?')
1272         {
1273             /* replace kernel path with user mode path */
1274             SymbolicLink->Buffer[1] = L'\\';
1275             PathAdjusted = TRUE;
1276         }
1277 
1278         /* store the key */
1279         Status = ZwSetValueKey(hKey, SymbolicLink, 0, REG_DWORD, &Value, sizeof(ULONG));
1280 
1281         if (PathAdjusted)
1282         {
1283             /* restore kernel path */
1284             SymbolicLink->Buffer[1] = L'?';
1285         }
1286 
1287         ZwClose(hKey);
1288     }
1289 
1290     /* done */
1291     return Status;
1292 }
1293 
1294 /*
1295     @implemented
1296 */
1297 NTSTATUS
1298 NTAPI
1299 DllInitialize(
1300     PUNICODE_STRING  RegistryPath)
1301 {
1302     return STATUS_SUCCESS;
1303 }
1304 
1305 
1306 NTSTATUS
1307 NTAPI
1308 KopDispatchClose(
1309     IN PDEVICE_OBJECT DeviceObject,
1310     IN PIRP Irp)
1311 {
1312     PKO_OBJECT_HEADER Header;
1313     PIO_STACK_LOCATION IoStack;
1314     PDEVICE_EXTENSION DeviceExtension;
1315 
1316     /* get current irp stack location */
1317     IoStack = IoGetCurrentIrpStackLocation(Irp);
1318 
1319     /* get ko object header */
1320     Header = (PKO_OBJECT_HEADER)IoStack->FileObject->FsContext2;
1321 
1322     /* free ks object header */
1323     KsFreeObjectHeader(Header->ObjectHeader);
1324 
1325     /* free ko object header */
1326     FreeItem(Header);
1327 
1328     /* get device extension */
1329     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1330 
1331     /* release bus object */
1332     KsDereferenceBusObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
1333 
1334     /* complete request */
1335     Irp->IoStatus.Status = STATUS_SUCCESS;
1336     CompleteRequest(Irp, IO_NO_INCREMENT);
1337 
1338     return STATUS_SUCCESS;
1339 }
1340 
1341 
1342 
1343 static KSDISPATCH_TABLE KoDispatchTable =
1344 {
1345     KsDispatchInvalidDeviceRequest,
1346     KsDispatchInvalidDeviceRequest,
1347     KsDispatchInvalidDeviceRequest,
1348     KsDispatchInvalidDeviceRequest,
1349     KopDispatchClose,
1350     KsDispatchQuerySecurity,
1351     KsDispatchSetSecurity,
1352     KsDispatchFastIoDeviceControlFailure,
1353     KsDispatchFastReadFailure,
1354     KsDispatchFastReadFailure,
1355 };
1356 
1357 
1358 NTSTATUS
1359 NTAPI
1360 KopDispatchCreate(
1361     IN PDEVICE_OBJECT DeviceObject,
1362     IN PIRP Irp)
1363 {
1364     PKO_OBJECT_HEADER Header = NULL;
1365     PIO_STACK_LOCATION IoStack;
1366     PKO_DRIVER_EXTENSION DriverObjectExtension;
1367     NTSTATUS Status;
1368 
1369     /* get current irp stack location */
1370     IoStack = IoGetCurrentIrpStackLocation(Irp);
1371 
1372     if (!IoStack->FileObject)
1373     {
1374         DPRINT1("FileObject not attached!\n");
1375         Status = STATUS_UNSUCCESSFUL;
1376         goto cleanup;
1377     }
1378 
1379     /* get driver object extension */
1380     DriverObjectExtension = (PKO_DRIVER_EXTENSION)IoGetDriverObjectExtension(DeviceObject->DriverObject, (PVOID)KoDriverInitialize);
1381     if (!DriverObjectExtension)
1382     {
1383         DPRINT1("No DriverObjectExtension!\n");
1384         Status = STATUS_UNSUCCESSFUL;
1385         goto cleanup;
1386     }
1387 
1388     /* allocate ko object header */
1389     Header = (PKO_OBJECT_HEADER)AllocateItem(NonPagedPool, sizeof(KO_OBJECT_HEADER));
1390     if (!Header)
1391     {
1392         DPRINT1("failed to allocate KO_OBJECT_HEADER\n");
1393         Status = STATUS_INSUFFICIENT_RESOURCES;
1394         goto cleanup;
1395     }
1396 
1397     /* initialize create item */
1398     Header->CreateItem.Create = KopDispatchCreate;
1399     RtlInitUnicodeString(&Header->CreateItem.ObjectClass, KOSTRING_CreateObject);
1400 
1401 
1402     /* now allocate the object header */
1403     Status = KsAllocateObjectHeader(&Header->ObjectHeader, 1, &Header->CreateItem, Irp, &KoDispatchTable);
1404     if (!NT_SUCCESS(Status))
1405     {
1406         /* failed */
1407         goto cleanup;
1408     }
1409 
1410     /* FIXME
1411      * extract clsid and interface id from irp
1412      * call the standard create handler
1413      */
1414 
1415     UNIMPLEMENTED;
1416 
1417     IoStack->FileObject->FsContext2 = (PVOID)Header;
1418 
1419     Irp->IoStatus.Status = Status;
1420     CompleteRequest(Irp, IO_NO_INCREMENT);
1421 
1422     return Status;
1423 
1424 cleanup:
1425 
1426     if (Header && Header->ObjectHeader)
1427         KsFreeObjectHeader(Header->ObjectHeader);
1428 
1429     if (Header)
1430         FreeItem(Header);
1431 
1432     Irp->IoStatus.Status = Status;
1433     CompleteRequest(Irp, IO_NO_INCREMENT);
1434     return Status;
1435 }
1436 
1437 
1438 
1439 NTSTATUS
1440 NTAPI
1441 KopAddDevice(
1442     IN PDRIVER_OBJECT DriverObject,
1443     IN PDEVICE_OBJECT PhysicalDeviceObject)
1444 {
1445     NTSTATUS Status = STATUS_DEVICE_REMOVED;
1446     PDEVICE_OBJECT FunctionalDeviceObject= NULL;
1447     PDEVICE_OBJECT NextDeviceObject;
1448     PDEVICE_EXTENSION DeviceExtension;
1449     PKSOBJECT_CREATE_ITEM CreateItem;
1450 
1451     /* create the device object */
1452     Status = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), NULL, FILE_DEVICE_KS, FILE_DEVICE_SECURE_OPEN, FALSE, &FunctionalDeviceObject);
1453     if (!NT_SUCCESS(Status))
1454         return Status;
1455 
1456     /* allocate the create item */
1457     CreateItem = AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM));
1458 
1459     if (!CreateItem)
1460     {
1461         /* not enough memory */
1462         IoDeleteDevice(FunctionalDeviceObject);
1463         return STATUS_INSUFFICIENT_RESOURCES;
1464     }
1465 
1466     /* initialize create item */
1467     CreateItem->Create = KopDispatchCreate;
1468     RtlInitUnicodeString(&CreateItem->ObjectClass, KOSTRING_CreateObject);
1469 
1470     /* get device extension */
1471     DeviceExtension = (PDEVICE_EXTENSION)FunctionalDeviceObject->DeviceExtension;
1472 
1473     /* now allocate the device header */
1474     Status = KsAllocateDeviceHeader((KSDEVICE_HEADER*)&DeviceExtension->DeviceHeader, 1, CreateItem);
1475     if (!NT_SUCCESS(Status))
1476     {
1477         /* failed */
1478         IoDeleteDevice(FunctionalDeviceObject);
1479         FreeItem(CreateItem);
1480         return Status;
1481     }
1482 
1483     /* now attach to device stack */
1484     NextDeviceObject = IoAttachDeviceToDeviceStack(FunctionalDeviceObject, PhysicalDeviceObject);
1485     if (NextDeviceObject)
1486     {
1487         /* store pnp base object */
1488          KsSetDevicePnpAndBaseObject((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, NextDeviceObject, FunctionalDeviceObject);
1489         /* set device flags */
1490         FunctionalDeviceObject->Flags |= DO_DIRECT_IO | DO_POWER_PAGABLE;
1491         FunctionalDeviceObject->Flags &= ~ DO_DEVICE_INITIALIZING;
1492     }
1493     else
1494     {
1495         /* failed */
1496         KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader);
1497         FreeItem(CreateItem);
1498         IoDeleteDevice(FunctionalDeviceObject);
1499         Status =  STATUS_DEVICE_REMOVED;
1500     }
1501 
1502     /* return result */
1503     return Status;
1504 }
1505 
1506 
1507 /*
1508     @implemented
1509 */
1510 COMDDKAPI
1511 NTSTATUS
1512 NTAPI
1513 KoDeviceInitialize(
1514     IN PDEVICE_OBJECT DeviceObject)
1515 {
1516     PDEVICE_EXTENSION DeviceExtension;
1517 
1518     /* get device extension */
1519     DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1520 
1521     return KsAddObjectCreateItemToDeviceHeader((KSDEVICE_HEADER)DeviceExtension->DeviceHeader, KopDispatchCreate, NULL, KOSTRING_CreateObject, NULL);
1522 }
1523 
1524 /*
1525     @implemented
1526 */
1527 COMDDKAPI
1528 NTSTATUS
1529 NTAPI
1530 KoDriverInitialize(
1531     IN PDRIVER_OBJECT DriverObject,
1532     IN PUNICODE_STRING RegistryPathName,
1533     IN KoCreateObjectHandler CreateObjectHandler)
1534 {
1535     PKO_DRIVER_EXTENSION DriverObjectExtension;
1536     NTSTATUS Status;
1537 
1538     /* allocate driver object extension */
1539     Status = IoAllocateDriverObjectExtension(DriverObject, (PVOID)KoDriverInitialize, sizeof(KO_DRIVER_EXTENSION), (PVOID*)&DriverObjectExtension);
1540 
1541     /* did it work */
1542     if (NT_SUCCESS(Status))
1543     {
1544         /* store create handler */
1545         DriverObjectExtension->CreateObjectHandler = CreateObjectHandler;
1546 
1547          /* Setting our IRP handlers */
1548         DriverObject->MajorFunction[IRP_MJ_PNP] = KsDefaultDispatchPnp;
1549         DriverObject->MajorFunction[IRP_MJ_POWER] = KsDefaultDispatchPower;
1550         DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = KsDefaultForwardIrp;
1551 
1552         /* The driver unload routine */
1553         DriverObject->DriverUnload = KsNullDriverUnload;
1554 
1555         /* The driver-supplied AddDevice */
1556         DriverObject->DriverExtension->AddDevice = KopAddDevice;
1557 
1558         /* KS handles these */
1559         DPRINT1("Setting KS function handlers\n");
1560         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CREATE);
1561         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_CLOSE);
1562         KsSetMajorFunctionHandler(DriverObject, IRP_MJ_DEVICE_CONTROL);
1563 
1564     }
1565 
1566     return Status;
1567 }
1568 
1569 /*
1570     @unimplemented
1571 */
1572 COMDDKAPI
1573 VOID
1574 NTAPI
1575 KoRelease(
1576     IN REFCLSID ClassId)
1577 {
1578 
1579 }
1580 
1581 /*
1582     @implemented
1583 */
1584 KSDDKAPI
1585 VOID
1586 NTAPI
1587 KsAcquireControl(
1588     IN PVOID Object)
1589 {
1590     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1591 
1592     /* sanity check */
1593     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1594 
1595     KeWaitForSingleObject(BasicHeader->ControlMutex, Executive, KernelMode, FALSE, NULL);
1596 
1597 }
1598 
1599 /*
1600     @implemented
1601 */
1602 VOID
1603 NTAPI
1604 KsReleaseControl(
1605     IN PVOID  Object)
1606 {
1607     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1608 
1609     /* sanity check */
1610     ASSERT(BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1611 
1612     KeReleaseMutex(BasicHeader->ControlMutex, FALSE);
1613 }
1614 
1615 
1616 
1617 /*
1618     @implemented
1619 */
1620 KSDDKAPI
1621 VOID
1622 NTAPI
1623 KsAcquireDevice(
1624     IN PKSDEVICE Device)
1625 {
1626     IKsDevice *KsDevice;
1627     PKSIDEVICE_HEADER DeviceHeader;
1628 
1629     DPRINT("KsAcquireDevice\n");
1630     DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1631 
1632     /* get device interface*/
1633     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1634 
1635     /* acquire device mutex */
1636     KsDevice->lpVtbl->AcquireDevice(KsDevice);
1637 }
1638 
1639 /*
1640     @implemented
1641 */
1642 VOID
1643 NTAPI
1644 KsReleaseDevice(
1645     IN PKSDEVICE  Device)
1646 {
1647     IKsDevice *KsDevice;
1648     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1649 
1650     /* get device interface*/
1651     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1652 
1653     /* release device mutex */
1654     KsDevice->lpVtbl->ReleaseDevice(KsDevice);
1655 }
1656 
1657 /*
1658     @implemented
1659 */
1660 KSDDKAPI
1661 VOID
1662 NTAPI
1663 KsTerminateDevice(
1664     IN PDEVICE_OBJECT DeviceObject)
1665 {
1666     IKsDevice *KsDevice;
1667     PKSIDEVICE_HEADER DeviceHeader;
1668     PDEVICE_EXTENSION DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
1669 
1670     /* get device header */
1671     DeviceHeader = DeviceExtension->DeviceHeader;
1672 
1673     /* get device interface*/
1674     KsDevice = (IKsDevice*)&DeviceHeader->BasicHeader.OuterUnknown;
1675 
1676     /* now free device header */
1677     KsFreeDeviceHeader((KSDEVICE_HEADER)DeviceHeader);
1678 
1679     /* release interface when available */
1680     if (KsDevice)
1681     {
1682         /* delete IKsDevice interface */
1683         KsDevice->lpVtbl->Release(KsDevice);
1684     }
1685 }
1686 
1687 /*
1688     @implemented
1689 */
1690 KSDDKAPI
1691 VOID
1692 NTAPI
1693 KsCompletePendingRequest(
1694     IN PIRP Irp)
1695 {
1696     PIO_STACK_LOCATION IoStack;
1697 
1698     /* get current irp stack location */
1699     IoStack = IoGetCurrentIrpStackLocation(Irp);
1700 
1701     /* sanity check */
1702     ASSERT(Irp->IoStatus.Status != STATUS_PENDING);
1703 
1704     if (IoStack->MajorFunction != IRP_MJ_CLOSE)
1705     {
1706         /* can be completed immediately */
1707         CompleteRequest(Irp, IO_NO_INCREMENT);
1708         return;
1709     }
1710 
1711     /* did close operation fail */
1712     if (!NT_SUCCESS(Irp->IoStatus.Status))
1713     {
1714         /* closing failed, complete irp */
1715         CompleteRequest(Irp, IO_NO_INCREMENT);
1716         return;
1717     }
1718 
1719     /* FIXME
1720      * delete object / device header
1721      * remove dead pin / filter instance
1722      */
1723     UNIMPLEMENTED;
1724 
1725 }
1726 
1727 NTSTATUS
1728 NTAPI
1729 KspSetGetBusDataCompletion(
1730     IN PDEVICE_OBJECT  DeviceObject,
1731     IN PIRP  Irp,
1732     IN PVOID  Context)
1733 {
1734     /* signal completion */
1735     KeSetEvent((PRKEVENT)Context, IO_NO_INCREMENT, FALSE);
1736 
1737     /* more work needs be done, so dont free the irp */
1738     return STATUS_MORE_PROCESSING_REQUIRED;
1739 
1740 }
1741 
1742 NTSTATUS
1743 KspDeviceSetGetBusData(
1744     IN PDEVICE_OBJECT DeviceObject,
1745     IN ULONG DataType,
1746     IN PVOID Buffer,
1747     IN ULONG Offset,
1748     IN ULONG Length,
1749     IN BOOL bGet)
1750 {
1751     PIO_STACK_LOCATION IoStack;
1752     PIRP Irp;
1753     NTSTATUS Status;
1754     KEVENT Event;
1755 
1756     /* allocate the irp */
1757     Irp = IoAllocateIrp(1, /*FIXME */
1758                         FALSE);
1759 
1760     if (!Irp)
1761         return STATUS_INSUFFICIENT_RESOURCES;
1762 
1763     /* initialize the event */
1764     KeInitializeEvent(&Event, NotificationEvent, FALSE);
1765 
1766     /* get next stack location */
1767     IoStack = IoGetNextIrpStackLocation(Irp);
1768 
1769     /* setup a completion routine */
1770     IoSetCompletionRoutine(Irp, KspSetGetBusDataCompletion, (PVOID)&Event, TRUE, TRUE, TRUE);
1771 
1772     /* setup parameters */
1773     IoStack->Parameters.ReadWriteConfig.Buffer = Buffer;
1774     IoStack->Parameters.ReadWriteConfig.Length = Length;
1775     IoStack->Parameters.ReadWriteConfig.Offset = Offset;
1776     IoStack->Parameters.ReadWriteConfig.WhichSpace = DataType;
1777     /* setup function code */
1778     IoStack->MajorFunction = IRP_MJ_PNP;
1779     IoStack->MinorFunction = (bGet ? IRP_MN_READ_CONFIG : IRP_MN_WRITE_CONFIG);
1780 
1781     /* lets call the driver */
1782     Status = IoCallDriver(DeviceObject, Irp);
1783 
1784     /* is the request still pending */
1785     if (Status == STATUS_PENDING)
1786     {
1787         /* have a nap */
1788         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1789         /* update status */
1790         Status = Irp->IoStatus.Status;
1791     }
1792 
1793     /* free the irp */
1794     IoFreeIrp(Irp);
1795     /* done */
1796     return Status;
1797 }
1798 
1799 /*
1800     @implemented
1801 */
1802 KSDDKAPI
1803 ULONG
1804 NTAPI
1805 KsDeviceSetBusData(
1806     IN PKSDEVICE Device,
1807     IN ULONG DataType,
1808     IN PVOID Buffer,
1809     IN ULONG Offset,
1810     IN ULONG Length)
1811 {
1812     return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
1813                                   DataType, Buffer, Offset, Length, FALSE);
1814 }
1815 
1816 
1817 /*
1818     @implemented
1819 */
1820 KSDDKAPI
1821 ULONG
1822 NTAPI
1823 KsDeviceGetBusData(
1824     IN PKSDEVICE Device,
1825     IN ULONG DataType,
1826     IN PVOID Buffer,
1827     IN ULONG Offset,
1828     IN ULONG Length)
1829 {
1830     return KspDeviceSetGetBusData(Device->PhysicalDeviceObject, /* is this right? */
1831                                   DataType, Buffer, Offset, Length, TRUE);
1832 
1833 }
1834 
1835 /*
1836     @implemented
1837 */
1838 KSDDKAPI
1839 void
1840 NTAPI
1841 KsDeviceRegisterAdapterObject(
1842     IN PKSDEVICE Device,
1843     IN PADAPTER_OBJECT AdapterObject,
1844     IN ULONG MaxMappingsByteCount,
1845     IN ULONG MappingTableStride)
1846 {
1847     PKSIDEVICE_HEADER DeviceHeader = (PKSIDEVICE_HEADER)CONTAINING_RECORD(Device, KSIDEVICE_HEADER, KsDevice);
1848 
1849     DeviceHeader->AdapterObject = AdapterObject;
1850     DeviceHeader->MaxMappingsByteCount = MaxMappingsByteCount;
1851     DeviceHeader->MappingTableStride = MappingTableStride;
1852 
1853 }
1854 
1855 
1856 /*
1857     @implemented
1858 */
1859 KSDDKAPI
1860 PVOID
1861 NTAPI
1862 KsGetFirstChild(
1863     IN PVOID Object)
1864 {
1865     PKSBASIC_HEADER BasicHeader;
1866 
1867     /* get the basic header */
1868     BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1869 
1870     /* type has to be either a device or a filter factory */
1871     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory);
1872 
1873     return (PVOID)BasicHeader->FirstChild.Filter;
1874 }
1875 
1876 /*
1877     @implemented
1878 */
1879 KSDDKAPI
1880 PVOID
1881 NTAPI
1882 KsGetNextSibling(
1883     IN PVOID Object)
1884 {
1885     PKSBASIC_HEADER BasicHeader;
1886 
1887     /* get the basic header */
1888     BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
1889 
1890     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
1891            BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
1892 
1893     return (PVOID)BasicHeader->Next.Pin;
1894 }
1895 
1896 ULONG
1897 KspCountMethodSets(
1898     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1899     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1900 {
1901     ULONG Index, SubIndex, Count;
1902     BOOL bFound;
1903 
1904     if (!AutomationTableA)
1905         return AutomationTableB->MethodSetsCount;
1906 
1907     if (!AutomationTableB)
1908         return AutomationTableA->MethodSetsCount;
1909 
1910 
1911     DPRINT("AutomationTableA MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableA->MethodItemSize, AutomationTableA->MethodSetsCount);
1912     DPRINT("AutomationTableB MethodItemSize %lu MethodSetsCount %lu\n", AutomationTableB->MethodItemSize, AutomationTableB->MethodSetsCount);
1913 
1914     if (AutomationTableA->MethodItemSize && AutomationTableB->MethodItemSize)
1915     {
1916         /* sanity check */
1917         ASSERT(AutomationTableA->MethodItemSize  == AutomationTableB->MethodItemSize);
1918     }
1919 
1920     /* now iterate all property sets and compare their guids */
1921     Count = AutomationTableA->MethodSetsCount;
1922 
1923     for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
1924     {
1925         /* set found to false */
1926         bFound = FALSE;
1927 
1928         for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
1929         {
1930             if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
1931             {
1932                 /* same property set found */
1933                 bFound = TRUE;
1934                 break;
1935             }
1936         }
1937 
1938         if (!bFound)
1939             Count++;
1940     }
1941 
1942     return Count;
1943 }
1944 
1945 ULONG
1946 KspCountEventSets(
1947     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1948     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1949 {
1950     ULONG Index, SubIndex, Count;
1951     BOOL bFound;
1952 
1953     if (!AutomationTableA)
1954         return AutomationTableB->EventSetsCount;
1955 
1956     if (!AutomationTableB)
1957         return AutomationTableA->EventSetsCount;
1958 
1959     DPRINT("AutomationTableA EventItemSize %lu EventSetsCount %lu\n", AutomationTableA->EventItemSize, AutomationTableA->EventSetsCount);
1960     DPRINT("AutomationTableB EventItemSize %lu EventSetsCount %lu\n", AutomationTableB->EventItemSize, AutomationTableB->EventSetsCount);
1961 
1962     if (AutomationTableA->EventItemSize && AutomationTableB->EventItemSize)
1963     {
1964         /* sanity check */
1965         ASSERT(AutomationTableA->EventItemSize == AutomationTableB->EventItemSize);
1966     }
1967 
1968     /* now iterate all Event sets and compare their guids */
1969     Count = AutomationTableA->EventSetsCount;
1970 
1971     for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
1972     {
1973         /* set found to false */
1974         bFound = FALSE;
1975 
1976         for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
1977         {
1978             if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
1979             {
1980                 /* same Event set found */
1981                 bFound = TRUE;
1982                 break;
1983             }
1984         }
1985 
1986         if (!bFound)
1987             Count++;
1988     }
1989 
1990     return Count;
1991 }
1992 
1993 
1994 ULONG
1995 KspCountPropertySets(
1996     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
1997     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
1998 {
1999     ULONG Index, SubIndex, Count;
2000     BOOL bFound;
2001 
2002     if (!AutomationTableA)
2003         return AutomationTableB->PropertySetsCount;
2004 
2005     if (!AutomationTableB)
2006         return AutomationTableA->PropertySetsCount;
2007 
2008     /* sanity check */
2009     DPRINT("AutomationTableA PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableA->PropertyItemSize, AutomationTableA->PropertySetsCount);
2010     DPRINT("AutomationTableB PropertyItemSize %lu PropertySetsCount %lu\n", AutomationTableB->PropertyItemSize, AutomationTableB->PropertySetsCount);
2011     ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
2012 
2013     /* now iterate all property sets and compare their guids */
2014     Count = AutomationTableA->PropertySetsCount;
2015 
2016     for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
2017     {
2018         /* set found to false */
2019         bFound = FALSE;
2020 
2021         for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
2022         {
2023             if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
2024             {
2025                 /* same property set found */
2026                 bFound = TRUE;
2027                 break;
2028             }
2029         }
2030 
2031         if (!bFound)
2032             Count++;
2033     }
2034 
2035     return Count;
2036 }
2037 
2038 NTSTATUS
2039 KspCopyMethodSets(
2040     OUT PKSAUTOMATION_TABLE  Table,
2041     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2042     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
2043 {
2044     ULONG Index, SubIndex, Count;
2045     BOOL bFound;
2046 
2047     if (!AutomationTableA)
2048     {
2049         /* copy of property set */
2050         RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableB->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableB->MethodSetsCount);
2051         return STATUS_SUCCESS;
2052     }
2053     else if (!AutomationTableB)
2054     {
2055         /* copy of property set */
2056         RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
2057         return STATUS_SUCCESS;
2058     }
2059 
2060     /* first copy all property items from dominant table */
2061     RtlMoveMemory((PVOID)Table->MethodSets, AutomationTableA->MethodSets, sizeof(KSMETHOD_SET) * AutomationTableA->MethodSetsCount);
2062     /* set counter */
2063     Count = AutomationTableA->MethodSetsCount;
2064 
2065     /* now copy entries which aren't available in the dominant table */
2066     for(Index = 0; Index < AutomationTableB->MethodSetsCount; Index++)
2067     {
2068         /* set found to false */
2069         bFound = FALSE;
2070 
2071         for(SubIndex = 0; SubIndex < AutomationTableA->MethodSetsCount; SubIndex++)
2072         {
2073             if (IsEqualGUIDAligned(AutomationTableB->MethodSets[Index].Set, AutomationTableA->MethodSets[SubIndex].Set))
2074             {
2075                 /* same property set found */
2076                 bFound = TRUE;
2077                 break;
2078             }
2079         }
2080 
2081         if (!bFound)
2082         {
2083             /* copy new property item set */
2084             RtlMoveMemory((PVOID)&Table->MethodSets[Count], &AutomationTableB->MethodSets[Index], sizeof(KSMETHOD_SET));
2085             Count++;
2086         }
2087     }
2088 
2089     return STATUS_SUCCESS;
2090 }
2091 
2092 VOID
2093 KspAddPropertyItem(
2094     OUT PKSPROPERTY_SET OutPropertySet,
2095     IN PKSPROPERTY_ITEM PropertyItem,
2096     IN ULONG PropertyItemSize)
2097 {
2098     PKSPROPERTY_ITEM CurrentPropertyItem;
2099     ULONG Index;
2100 
2101     // check if the property item is already present
2102     CurrentPropertyItem = (PKSPROPERTY_ITEM)OutPropertySet->PropertyItem;
2103     for(Index = 0; Index < OutPropertySet->PropertiesCount; Index++)
2104     {
2105         if (CurrentPropertyItem->PropertyId == PropertyItem->PropertyId)
2106         {
2107             // item already present
2108             return;
2109         }
2110 
2111         // next item
2112         CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + PropertyItemSize);
2113     }
2114     // add item
2115     RtlCopyMemory(CurrentPropertyItem, PropertyItem, PropertyItemSize);
2116     OutPropertySet->PropertiesCount++;
2117 }
2118 
2119 NTSTATUS
2120 KspMergePropertySet(
2121     OUT PKSAUTOMATION_TABLE  Table,
2122     OUT PKSPROPERTY_SET OutPropertySet,
2123     IN PKSPROPERTY_SET PropertySetA,
2124     IN PKSPROPERTY_SET PropertySetB,
2125     IN KSOBJECT_BAG  Bag OPTIONAL)
2126 {
2127     ULONG PropertyCount, Index;
2128     PKSPROPERTY_ITEM PropertyItem, CurrentPropertyItem;
2129     NTSTATUS Status;
2130 
2131     // max properties
2132     PropertyCount = PropertySetA->PropertiesCount + PropertySetB->PropertiesCount;
2133 
2134     // allocate items
2135     PropertyItem = AllocateItem(NonPagedPool, Table->PropertyItemSize * PropertyCount);
2136     if (!PropertyItem)
2137         return STATUS_INSUFFICIENT_RESOURCES;
2138 
2139     if (Bag)
2140     {
2141         /* add table to object bag */
2142         Status = KsAddItemToObjectBag(Bag, PropertyItem, NULL);
2143         /* check for success */
2144         if (!NT_SUCCESS(Status))
2145         {
2146             /* free table */
2147             FreeItem(Table);
2148             return Status;
2149         }
2150     }
2151 
2152     // copy entries from dominant table
2153     RtlCopyMemory(PropertyItem, PropertySetA->PropertyItem, Table->PropertyItemSize * PropertySetA->PropertiesCount);
2154 
2155     // init property set
2156     OutPropertySet->PropertiesCount = PropertySetA->PropertiesCount;
2157     OutPropertySet->PropertyItem = PropertyItem;
2158 
2159     // copy other entries
2160     CurrentPropertyItem = (PKSPROPERTY_ITEM)PropertySetB->PropertyItem;
2161     for(Index = 0; Index < PropertySetB->PropertiesCount; Index++)
2162     {
2163 
2164         // add entries
2165         KspAddPropertyItem(OutPropertySet, CurrentPropertyItem, Table->PropertyItemSize);
2166 
2167         // next entry
2168         CurrentPropertyItem = (PKSPROPERTY_ITEM)((ULONG_PTR)CurrentPropertyItem + Table->PropertyItemSize);
2169     }
2170 
2171     // done
2172     return STATUS_SUCCESS;
2173 }
2174 
2175 
2176 NTSTATUS
2177 KspCopyPropertySets(
2178     OUT PKSAUTOMATION_TABLE  Table,
2179     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2180     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL,
2181     IN KSOBJECT_BAG  Bag OPTIONAL)
2182 {
2183     ULONG Index, SubIndex, Count;
2184     BOOL bFound;
2185     NTSTATUS Status;
2186 
2187     if (!AutomationTableA)
2188     {
2189         /* copy of property set */
2190         RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableB->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableB->PropertySetsCount);
2191         return STATUS_SUCCESS;
2192     }
2193     else if (!AutomationTableB)
2194     {
2195         /* copy of property set */
2196         RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
2197         return STATUS_SUCCESS;
2198     }
2199 
2200     /* first copy all property items from dominant table */
2201     RtlMoveMemory((PVOID)Table->PropertySets, AutomationTableA->PropertySets, sizeof(KSPROPERTY_SET) * AutomationTableA->PropertySetsCount);
2202     /* set counter */
2203     Count = AutomationTableA->PropertySetsCount;
2204 
2205     /* now copy entries which aren't available in the dominant table */
2206     for(Index = 0; Index < AutomationTableB->PropertySetsCount; Index++)
2207     {
2208         /* set found to false */
2209         bFound = FALSE;
2210 
2211         for(SubIndex = 0; SubIndex < AutomationTableA->PropertySetsCount; SubIndex++)
2212         {
2213             if (IsEqualGUIDAligned(AutomationTableB->PropertySets[Index].Set, AutomationTableA->PropertySets[SubIndex].Set))
2214             {
2215                 /* same property set found */
2216                 bFound = TRUE;
2217                 break;
2218             }
2219         }
2220 
2221         if (!bFound)
2222         {
2223             /* copy new property item set */
2224             RtlMoveMemory((PVOID)&Table->PropertySets[Count], &AutomationTableB->PropertySets[Index], sizeof(KSPROPERTY_SET));
2225             Count++;
2226         }
2227         else
2228         {
2229             // merge property sets
2230             Status = KspMergePropertySet(Table, (PKSPROPERTY_SET)&Table->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableA->PropertySets[SubIndex], (PKSPROPERTY_SET)&AutomationTableB->PropertySets[Index], Bag);
2231             if (!NT_SUCCESS(Status))
2232             {
2233                 // failed to merge
2234                 DPRINT1("[KS] Failed to merge %x\n", Status);
2235                 return Status;
2236             }
2237         }
2238     }
2239 
2240     return STATUS_SUCCESS;
2241 }
2242 
2243 NTSTATUS
2244 KspCopyEventSets(
2245     OUT PKSAUTOMATION_TABLE  Table,
2246     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2247     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL)
2248 {
2249     ULONG Index, SubIndex, Count;
2250     BOOL bFound;
2251 
2252     if (!AutomationTableA)
2253     {
2254         /* copy of Event set */
2255         RtlMoveMemory((PVOID)Table->EventSets, AutomationTableB->EventSets, sizeof(KSEVENT_SET) * AutomationTableB->EventSetsCount);
2256         return STATUS_SUCCESS;
2257     }
2258     else if (!AutomationTableB)
2259     {
2260         /* copy of Event set */
2261         RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
2262         return STATUS_SUCCESS;
2263     }
2264 
2265     /* first copy all Event items from dominant table */
2266     RtlMoveMemory((PVOID)Table->EventSets, AutomationTableA->EventSets, sizeof(KSEVENT_SET) * AutomationTableA->EventSetsCount);
2267     /* set counter */
2268     Count = AutomationTableA->EventSetsCount;
2269 
2270     /* now copy entries which aren't available in the dominant table */
2271     for(Index = 0; Index < AutomationTableB->EventSetsCount; Index++)
2272     {
2273         /* set found to false */
2274         bFound = FALSE;
2275 
2276         for(SubIndex = 0; SubIndex < AutomationTableA->EventSetsCount; SubIndex++)
2277         {
2278             if (IsEqualGUIDAligned(AutomationTableB->EventSets[Index].Set, AutomationTableA->EventSets[SubIndex].Set))
2279             {
2280                 /* same Event set found */
2281                 bFound = TRUE;
2282                 break;
2283             }
2284         }
2285 
2286         if (!bFound)
2287         {
2288             /* copy new Event item set */
2289             RtlMoveMemory((PVOID)&Table->EventSets[Count], &AutomationTableB->EventSets[Index], sizeof(KSEVENT_SET));
2290             Count++;
2291         }
2292     }
2293 
2294     return STATUS_SUCCESS;
2295 }
2296 
2297 
2298 /*
2299     @implemented
2300 */
2301 NTSTATUS
2302 NTAPI
2303 KsMergeAutomationTables(
2304     OUT PKSAUTOMATION_TABLE  *AutomationTableAB,
2305     IN PKSAUTOMATION_TABLE  AutomationTableA OPTIONAL,
2306     IN PKSAUTOMATION_TABLE  AutomationTableB OPTIONAL,
2307     IN KSOBJECT_BAG  Bag OPTIONAL)
2308 {
2309     PKSAUTOMATION_TABLE Table;
2310     NTSTATUS Status = STATUS_SUCCESS;
2311 
2312     if (!AutomationTableA && !AutomationTableB)
2313     {
2314         /* nothing to merge */
2315         return STATUS_SUCCESS;
2316     }
2317 
2318     /* allocate an automation table */
2319     Table = AllocateItem(NonPagedPool, sizeof(KSAUTOMATION_TABLE));
2320     if (!Table)
2321         return STATUS_INSUFFICIENT_RESOURCES;
2322 
2323     if (Bag)
2324     {
2325         /* add table to object bag */
2326         Status = KsAddItemToObjectBag(Bag, Table, NULL);
2327         /* check for success */
2328         if (!NT_SUCCESS(Status))
2329         {
2330             /* free table */
2331             FreeItem(Table);
2332             return Status;
2333         }
2334     }
2335 
2336     /* count property sets */
2337     Table->PropertySetsCount = KspCountPropertySets(AutomationTableA, AutomationTableB);
2338 
2339     if (Table->PropertySetsCount)
2340     {
2341         if (AutomationTableA)
2342         {
2343             /* use item size from dominant automation table */
2344             Table->PropertyItemSize = AutomationTableA->PropertyItemSize;
2345         }
2346         else
2347         {
2348             /* use item size from 2nd automation table */
2349             Table->PropertyItemSize = AutomationTableB->PropertyItemSize;
2350         }
2351 
2352         if (AutomationTableA && AutomationTableB)
2353         {
2354             // FIXME handle different property item sizes
2355             ASSERT(AutomationTableA->PropertyItemSize == AutomationTableB->PropertyItemSize);
2356         }
2357 
2358         /* now allocate the property sets */
2359         Table->PropertySets = AllocateItem(NonPagedPool, sizeof(KSPROPERTY_SET) * Table->PropertySetsCount);
2360 
2361         if (!Table->PropertySets)
2362         {
2363             /* not enough memory */
2364             goto cleanup;
2365         }
2366 
2367         if (Bag)
2368         {
2369             /* add set to property bag */
2370             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->PropertySets, NULL);
2371             /* check for success */
2372             if (!NT_SUCCESS(Status))
2373             {
2374                 /* cleanup table */
2375                 goto cleanup;
2376             }
2377         }
2378         /* now copy the property sets */
2379         Status = KspCopyPropertySets(Table, AutomationTableA, AutomationTableB, Bag);
2380         if(!NT_SUCCESS(Status))
2381             goto cleanup;
2382 
2383     }
2384 
2385     /* now count the method sets */
2386     Table->MethodSetsCount = KspCountMethodSets(AutomationTableA, AutomationTableB);
2387 
2388     if (Table->MethodSetsCount)
2389     {
2390         if (AutomationTableA)
2391         {
2392             /* use item size from dominant automation table */
2393             Table->MethodItemSize  = AutomationTableA->MethodItemSize;
2394         }
2395         else
2396         {
2397             /* use item size from 2nd automation table */
2398             Table->MethodItemSize = AutomationTableB->MethodItemSize;
2399         }
2400 
2401         /* now allocate the property sets */
2402         Table->MethodSets = AllocateItem(NonPagedPool, sizeof(KSMETHOD_SET) * Table->MethodSetsCount);
2403 
2404         if (!Table->MethodSets)
2405         {
2406             /* not enough memory */
2407             goto cleanup;
2408         }
2409 
2410         if (Bag)
2411         {
2412             /* add set to property bag */
2413             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->MethodSets, NULL);
2414             /* check for success */
2415             if (!NT_SUCCESS(Status))
2416             {
2417                 /* cleanup table */
2418                 goto cleanup;
2419             }
2420         }
2421         /* now copy the property sets */
2422         Status = KspCopyMethodSets(Table, AutomationTableA, AutomationTableB);
2423         if(!NT_SUCCESS(Status))
2424             goto cleanup;
2425     }
2426 
2427 
2428     /* now count the event sets */
2429     Table->EventSetsCount = KspCountEventSets(AutomationTableA, AutomationTableB);
2430 
2431     if (Table->EventSetsCount)
2432     {
2433         if (AutomationTableA)
2434         {
2435             /* use item size from dominant automation table */
2436             Table->EventItemSize  = AutomationTableA->EventItemSize;
2437         }
2438         else
2439         {
2440             /* use item size from 2nd automation table */
2441             Table->EventItemSize = AutomationTableB->EventItemSize;
2442         }
2443 
2444         /* now allocate the property sets */
2445         Table->EventSets = AllocateItem(NonPagedPool, sizeof(KSEVENT_SET) * Table->EventSetsCount);
2446 
2447         if (!Table->EventSets)
2448         {
2449             /* not enough memory */
2450             goto cleanup;
2451         }
2452 
2453         if (Bag)
2454         {
2455             /* add set to property bag */
2456             Status = KsAddItemToObjectBag(Bag, (PVOID)Table->EventSets, NULL);
2457             /* check for success */
2458             if (!NT_SUCCESS(Status))
2459             {
2460                 /* cleanup table */
2461                 goto cleanup;
2462             }
2463         }
2464         /* now copy the property sets */
2465         Status = KspCopyEventSets(Table, AutomationTableA, AutomationTableB);
2466         if(!NT_SUCCESS(Status))
2467             goto cleanup;
2468     }
2469 
2470     /* store result */
2471     *AutomationTableAB = Table;
2472 
2473     return Status;
2474 
2475 
2476 cleanup:
2477 
2478     if (Table)
2479     {
2480         if (Table->PropertySets)
2481         {
2482             /* clean property sets */
2483             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->PropertySets, TRUE)))
2484                 FreeItem((PVOID)Table->PropertySets);
2485         }
2486 
2487         if (Table->MethodSets)
2488         {
2489             /* clean property sets */
2490             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->MethodSets, TRUE)))
2491                 FreeItem((PVOID)Table->MethodSets);
2492         }
2493 
2494         if (Table->EventSets)
2495         {
2496             /* clean property sets */
2497             if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, (PVOID)Table->EventSets, TRUE)))
2498                 FreeItem((PVOID)Table->EventSets);
2499         }
2500 
2501         if (!Bag || !NT_SUCCESS(KsRemoveItemFromObjectBag(Bag, Table, TRUE)))
2502                 FreeItem(Table);
2503     }
2504 
2505     return STATUS_INSUFFICIENT_RESOURCES;
2506 }
2507 
2508 /*
2509     @unimplemented
2510 */
2511 KSDDKAPI
2512 PUNKNOWN
2513 NTAPI
2514 KsRegisterAggregatedClientUnknown(
2515     IN PVOID  Object,
2516     IN PUNKNOWN  ClientUnknown)
2517 {
2518     PKSBASIC_HEADER BasicHeader = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
2519 
2520     /* sanity check */
2521     ASSERT(BasicHeader->Type == KsObjectTypeDevice || BasicHeader->Type == KsObjectTypeFilterFactory ||
2522            BasicHeader->Type == KsObjectTypeFilter || BasicHeader->Type == KsObjectTypePin);
2523 
2524     if (BasicHeader->ClientAggregate)
2525     {
2526         /* release existing aggregate */
2527         BasicHeader->ClientAggregate->lpVtbl->Release(BasicHeader->ClientAggregate);
2528     }
2529 
2530     /* increment reference count */
2531     ClientUnknown->lpVtbl->AddRef(ClientUnknown);
2532 
2533     /* store client aggregate */
2534     BasicHeader->ClientAggregate = ClientUnknown;
2535 
2536     /* return objects outer unknown */
2537     return BasicHeader->OuterUnknown;
2538 }
2539 
2540 /*
2541     @unimplemented
2542 */
2543 NTSTATUS
2544 NTAPI
2545 KsRegisterFilterWithNoKSPins(
2546     IN PDEVICE_OBJECT  DeviceObject,
2547     IN const GUID*  InterfaceClassGUID,
2548     IN ULONG  PinCount,
2549     IN BOOL*  PinDirection,
2550     IN KSPIN_MEDIUM*  MediumList,
2551     IN GUID*  CategoryList OPTIONAL)
2552 {
2553     ULONG Size, Index;
2554     NTSTATUS Status;
2555     PWSTR SymbolicLinkList;
2556     //PUCHAR Buffer;
2557     HANDLE hKey;
2558     UNICODE_STRING InterfaceString;
2559     //UNICODE_STRING FilterData = RTL_CONSTANT_STRING(L"FilterData");
2560 
2561     if (!InterfaceClassGUID || !PinCount || !PinDirection || !MediumList)
2562     {
2563         /* all these parameters are required */
2564         return STATUS_INVALID_PARAMETER;
2565     }
2566 
2567     /* calculate filter data value size */
2568     Size = PinCount * sizeof(KSPIN_MEDIUM);
2569     if (CategoryList)
2570     {
2571         /* add category list */
2572         Size += PinCount * sizeof(GUID);
2573     }
2574 
2575     /* FIXME generate filter data blob */
2576     UNIMPLEMENTED;
2577 
2578     /* get symbolic link list */
2579     Status = IoGetDeviceInterfaces(InterfaceClassGUID, DeviceObject, DEVICE_INTERFACE_INCLUDE_NONACTIVE, &SymbolicLinkList);
2580     if (NT_SUCCESS(Status))
2581     {
2582         /* initialize first symbolic link */
2583         RtlInitUnicodeString(&InterfaceString, SymbolicLinkList);
2584 
2585         /* open first device interface registry key */
2586         Status = IoOpenDeviceInterfaceRegistryKey(&InterfaceString, GENERIC_WRITE, &hKey);
2587 
2588         if (NT_SUCCESS(Status))
2589         {
2590             /* write filter data */
2591             //Status = ZwSetValueKey(hKey, &FilterData, 0, REG_BINARY, Buffer, Size);
2592 
2593             /* close the key */
2594             ZwClose(hKey);
2595         }
2596 
2597         if (PinCount)
2598         {
2599             /* update medium cache */
2600             for(Index = 0; Index < PinCount; Index++)
2601             {
2602                 KsCacheMedium(&InterfaceString, &MediumList[Index], PinDirection[Index]);
2603             }
2604         }
2605 
2606         /* free the symbolic link list */
2607         FreeItem(SymbolicLinkList);
2608     }
2609 
2610     return Status;
2611 }
2612