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