[KS]
[reactos.git] / reactos / 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 #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 propery 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 }