xref: /reactos/drivers/ksfilter/ks/event.c (revision 40462c92)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Kernel Streaming
4  * FILE:            drivers/ksfilter/ks/event.c
5  * PURPOSE:         KS Event functions
6  * PROGRAMMER:      Johannes Anderwald
7  */
8 
9 #include "precomp.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 BOOLEAN
15 KspSynchronizedEventRoutine(
16     IN KSEVENTS_LOCKTYPE EventsFlags,
17     IN PVOID EventsLock,
18     IN PKSEVENT_SYNCHRONIZED_ROUTINE SynchronizedRoutine,
19     IN PKSEVENT_CTX Ctx)
20 {
21     BOOLEAN Result = FALSE;
22     KIRQL OldLevel;
23 
24     if (EventsFlags == KSEVENTS_NONE)
25     {
26         /* no synchronization required */
27         Result = SynchronizedRoutine(Ctx);
28     }
29     else if (EventsFlags == KSEVENTS_SPINLOCK)
30     {
31         /* use spin lock */
32         KeAcquireSpinLock((PKSPIN_LOCK)EventsLock, &OldLevel);
33         Result = SynchronizedRoutine(Ctx);
34         KeReleaseSpinLock((PKSPIN_LOCK)EventsLock, OldLevel);
35     }
36     else if (EventsFlags == KSEVENTS_MUTEX)
37     {
38         /* use a mutex */
39         KeWaitForSingleObject(EventsLock, Executive, KernelMode, FALSE, NULL);
40         Result = SynchronizedRoutine(Ctx);
41         KeReleaseMutex((PRKMUTEX)EventsLock, FALSE);
42     }
43     else if (EventsFlags == KSEVENTS_FMUTEX)
44     {
45         /* use a fast mutex */
46         ExAcquireFastMutex((PFAST_MUTEX)EventsLock);
47         Result = SynchronizedRoutine(Ctx);
48         ExReleaseFastMutex((PFAST_MUTEX)EventsLock);
49     }
50     else if (EventsFlags == KSEVENTS_FMUTEXUNSAFE)
51     {
52         /* acquire fast mutex unsafe */
53         KeEnterCriticalRegion();
54         ExAcquireFastMutexUnsafe((PFAST_MUTEX)EventsLock);
55         Result = SynchronizedRoutine(Ctx);
56         ExReleaseFastMutexUnsafe((PFAST_MUTEX)EventsLock);
57         KeLeaveCriticalRegion();
58     }
59     else if (EventsFlags == KSEVENTS_INTERRUPT)
60     {
61         /* use interrupt for locking */
62         Result = KeSynchronizeExecution((PKINTERRUPT)EventsLock, (PKSYNCHRONIZE_ROUTINE)SynchronizedRoutine, (PVOID)Ctx);
63     }
64     else if (EventsFlags == KSEVENTS_ERESOURCE)
65     {
66         /* use an eresource */
67         KeEnterCriticalRegion();
68         ExAcquireResourceExclusiveLite((PERESOURCE)EventsLock, TRUE);
69         Result = SynchronizedRoutine(Ctx);
70         ExReleaseResourceLite((PERESOURCE)EventsLock);
71         KeLeaveCriticalRegion();
72     }
73 
74     return Result;
75 }
76 
77 BOOLEAN
78 NTAPI
79 SyncAddEvent(
80     PKSEVENT_CTX Context)
81 {
82     InsertTailList(Context->List, &Context->EventEntry->ListEntry);
83     return TRUE;
84 }
85 
86 NTSTATUS
87 KspEnableEvent(
88     IN  PIRP Irp,
89     IN  ULONG EventSetsCount,
90     IN  const KSEVENT_SET* EventSet,
91     IN  OUT PLIST_ENTRY EventsList OPTIONAL,
92     IN  KSEVENTS_LOCKTYPE EventsFlags OPTIONAL,
93     IN  PVOID EventsLock OPTIONAL,
94     IN  PFNKSALLOCATOR Allocator OPTIONAL,
95     IN  ULONG EventItemSize OPTIONAL)
96 {
97     PIO_STACK_LOCATION IoStack;
98     NTSTATUS Status;
99     KSEVENT Event;
100     PKSEVENT_ITEM EventItem, FoundEventItem;
101     PKSEVENTDATA EventData;
102     const KSEVENT_SET *FoundEventSet;
103     PKSEVENT_ENTRY EventEntry;
104     ULONG Index, SubIndex, Size;
105     PVOID Object;
106     KSEVENT_CTX Ctx;
107     LPGUID Guid;
108 
109     /* get current stack location */
110     IoStack = IoGetCurrentIrpStackLocation(Irp);
111 
112     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSEVENT))
113     {
114         /* invalid parameter */
115         return STATUS_NOT_SUPPORTED;
116     }
117 
118     if (Irp->RequestorMode == UserMode)
119     {
120         _SEH2_TRY
121         {
122            ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT), sizeof(UCHAR));
123            ProbeForRead(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(UCHAR));
124            RtlMoveMemory(&Event, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT));
125            Status = STATUS_SUCCESS;
126         }
127         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
128         {
129             /* Exception, get the error code */
130             Status = _SEH2_GetExceptionCode();
131         }
132         _SEH2_END;
133 
134         /* check for success */
135         if (!NT_SUCCESS(Status))
136         {
137             /* failed to probe parameters */
138             return Status;
139         }
140     }
141     else
142     {
143         /* copy event struct */
144         RtlMoveMemory(&Event, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT));
145     }
146 
147     FoundEventItem = NULL;
148     FoundEventSet = NULL;
149 
150 
151     if (IsEqualGUIDAligned(&Event.Set, &GUID_NULL) && Event.Id == 0 && Event.Flags == KSEVENT_TYPE_SETSUPPORT)
152     {
153         // store output size
154         Irp->IoStatus.Information = sizeof(GUID) * EventSetsCount;
155         if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * EventSetsCount)
156         {
157             // buffer too small
158             return STATUS_MORE_ENTRIES;
159         }
160 
161         // get output buffer
162         Guid = (LPGUID)Irp->UserBuffer;
163 
164        // copy property guids from property sets
165        for(Index = 0; Index < EventSetsCount; Index++)
166        {
167            RtlMoveMemory(&Guid[Index], EventSet[Index].Set, sizeof(GUID));
168        }
169        return STATUS_SUCCESS;
170     }
171 
172     /* now try to find event set */
173     for(Index = 0; Index < EventSetsCount; Index++)
174     {
175         if (IsEqualGUIDAligned(&Event.Set, EventSet[Index].Set))
176         {
177             EventItem = (PKSEVENT_ITEM)EventSet[Index].EventItem;
178 
179             /* sanity check */
180             ASSERT(EventSet[Index].EventsCount);
181             ASSERT(EventItem);
182 
183             /* now find matching event id */
184             for(SubIndex = 0; SubIndex < EventSet[Index].EventsCount; SubIndex++)
185             {
186                 if (EventItem[SubIndex].EventId == Event.Id)
187                 {
188                     /* found event item */
189                     FoundEventItem = &EventItem[SubIndex];
190                     FoundEventSet = &EventSet[Index];
191                     break;
192                 }
193             }
194 
195             if (FoundEventSet)
196                 break;
197         }
198     }
199 
200     if (!FoundEventSet)
201     {
202         UNICODE_STRING GuidString;
203 
204         RtlStringFromGUID(&Event.Set, &GuidString);
205 
206         DPRINT("Guid %S Id %u Flags %x not found\n", GuidString.Buffer, Event.Id, Event.Flags);
207         RtlFreeUnicodeString(&GuidString);
208         return STATUS_PROPSET_NOT_FOUND;
209 
210 
211     }
212 
213     if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < FoundEventItem->DataInput)
214     {
215         /* buffer too small */
216         DPRINT1("Got %u expected %u\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength, FoundEventItem->DataInput);
217         return STATUS_SUCCESS;
218     }
219 
220     if (!FoundEventItem->AddHandler && !EventsList)
221     {
222         /* no add handler and no list to add the new entry to */
223         return STATUS_INVALID_PARAMETER;
224     }
225 
226     /* get event data */
227     EventData = Irp->UserBuffer;
228 
229     /* sanity check */
230     ASSERT(EventData);
231 
232     if (Irp->RequestorMode == UserMode)
233     {
234         if (EventData->NotificationType == KSEVENTF_SEMAPHORE_HANDLE)
235         {
236             /* get semaphore object handle */
237             Status = ObReferenceObjectByHandle(EventData->SemaphoreHandle.Semaphore, SEMAPHORE_MODIFY_STATE, *ExSemaphoreObjectType, Irp->RequestorMode, &Object, NULL);
238 
239             if (!NT_SUCCESS(Status))
240             {
241                 /* invalid semaphore handle */
242                 return STATUS_INVALID_PARAMETER;
243             }
244         }
245         else if (EventData->NotificationType == KSEVENTF_EVENT_HANDLE)
246         {
247             /* get event object handle */
248             Status = ObReferenceObjectByHandle(EventData->EventHandle.Event, EVENT_MODIFY_STATE, *ExEventObjectType, Irp->RequestorMode, &Object, NULL);
249 
250             if (!NT_SUCCESS(Status))
251             {
252                 /* invalid event handle */
253                 return STATUS_INVALID_PARAMETER;
254             }
255         }
256         else
257         {
258             /* user mode client can only pass an event or semaphore handle */
259             return STATUS_INVALID_PARAMETER;
260         }
261     }
262     else
263     {
264         if (EventData->NotificationType != KSEVENTF_EVENT_OBJECT &&
265             EventData->NotificationType != KSEVENTF_SEMAPHORE_OBJECT &&
266             EventData->NotificationType != KSEVENTF_DPC &&
267             EventData->NotificationType != KSEVENTF_WORKITEM &&
268             EventData->NotificationType != KSEVENTF_KSWORKITEM)
269         {
270             /* invalid type requested */
271             return STATUS_INVALID_PARAMETER;
272         }
273     }
274 
275 
276     /* calculate request size */
277     Size = sizeof(KSEVENT_ENTRY) + FoundEventItem->ExtraEntryData;
278 
279     /* do we have an allocator */
280     if (Allocator)
281     {
282         /* allocate event entry */
283         Status = Allocator(Irp, Size, FALSE);
284 
285         if (!NT_SUCCESS(Status))
286         {
287             /* failed */
288             return Status;
289         }
290 
291         /* assume the caller put it there */
292         EventEntry = KSEVENT_ENTRY_IRP_STORAGE(Irp);
293 
294     }
295     else
296     {
297         /* allocate it from nonpaged pool */
298         EventEntry = AllocateItem(NonPagedPool, Size);
299     }
300 
301     if (!EventEntry)
302     {
303         /* not enough memory */
304         return STATUS_INSUFFICIENT_RESOURCES;
305     }
306 
307     /* zero event entry */
308     RtlZeroMemory(EventEntry, Size);
309 
310     /* initialize event entry */
311     EventEntry->EventData = EventData;
312     EventEntry->NotificationType = EventData->NotificationType;
313     EventEntry->EventItem = FoundEventItem;
314     EventEntry->EventSet = FoundEventSet;
315     EventEntry->FileObject = IoStack->FileObject;
316 
317     switch(EventEntry->NotificationType)
318     {
319         case KSEVENTF_EVENT_HANDLE:
320             EventEntry->Object = Object;
321             EventEntry->Reserved = 0;
322             break;
323         case KSEVENTF_SEMAPHORE_HANDLE:
324             EventEntry->Object = Object;
325             EventEntry->SemaphoreAdjustment = EventData->SemaphoreHandle.Adjustment;
326             EventEntry->Reserved = 0;
327             break;
328         case KSEVENTF_EVENT_OBJECT:
329             EventEntry->Object = EventData->EventObject.Event;
330             EventEntry->Reserved = EventData->EventObject.Increment;
331             break;
332         case KSEVENTF_SEMAPHORE_OBJECT:
333             EventEntry->Object = EventData->SemaphoreObject.Semaphore;
334             EventEntry->SemaphoreAdjustment = EventData->SemaphoreObject.Adjustment;
335             EventEntry->Reserved = EventData->SemaphoreObject.Increment;
336             break;
337         case KSEVENTF_DPC:
338             EventEntry->Object = EventData->Dpc.Dpc;
339             EventData->Dpc.ReferenceCount = 0;
340             break;
341         case KSEVENTF_WORKITEM:
342             EventEntry->Object = EventData->WorkItem.WorkQueueItem;
343             EventEntry->BufferItem = (PKSBUFFER_ITEM)UlongToPtr(EventData->WorkItem.WorkQueueType);
344             break;
345         case KSEVENTF_KSWORKITEM:
346             EventEntry->Object = EventData->KsWorkItem.KsWorkerObject;
347             EventEntry->DpcItem = (PKSDPC_ITEM)EventData->KsWorkItem.WorkQueueItem;
348             break;
349         default:
350             /* should not happen */
351             ASSERT(0);
352     }
353 
354     if (FoundEventItem->AddHandler)
355     {
356         /* now add the event */
357         Status = FoundEventItem->AddHandler(Irp, EventData, EventEntry);
358 
359         if (!NT_SUCCESS(Status))
360         {
361             /* discard event entry */
362             KsDiscardEvent(EventEntry);
363         }
364     }
365     else
366     {
367         /* setup context */
368         Ctx.List = EventsList;
369         Ctx.EventEntry = EventEntry;
370 
371          /* add the event */
372         (void)KspSynchronizedEventRoutine(EventsFlags, EventsLock, SyncAddEvent, &Ctx);
373 
374         Status = STATUS_SUCCESS;
375     }
376 
377     /* done */
378     return Status;
379 }
380 
381 /*
382     @implemented
383 */
384 KSDDKAPI
385 NTSTATUS
386 NTAPI
387 KsEnableEvent(
388     IN  PIRP Irp,
389     IN  ULONG EventSetsCount,
390     IN  KSEVENT_SET* EventSet,
391     IN  OUT PLIST_ENTRY EventsList OPTIONAL,
392     IN  KSEVENTS_LOCKTYPE EventsFlags OPTIONAL,
393     IN  PVOID EventsLock OPTIONAL)
394 {
395     return KspEnableEvent(Irp, EventSetsCount, EventSet, EventsList, EventsFlags, EventsLock, NULL, 0);
396 }
397 
398 /*
399     @implemented
400 */
401 _IRQL_requires_max_(PASSIVE_LEVEL)
402 KSDDKAPI
403 NTSTATUS
404 NTAPI
405 KsEnableEventWithAllocator(
406     _In_ PIRP Irp,
407     _In_ ULONG EventSetsCount,
408     _In_reads_(EventSetsCount) const KSEVENT_SET* EventSet,
409     _Inout_opt_ PLIST_ENTRY EventsList,
410     _In_opt_ KSEVENTS_LOCKTYPE EventsFlags,
411     _In_opt_ PVOID EventsLock,
412     _In_opt_ PFNKSALLOCATOR Allocator,
413     _In_opt_ ULONG EventItemSize)
414 {
415     return KspEnableEvent(Irp, EventSetsCount, EventSet, EventsList, EventsFlags, EventsLock, Allocator, EventItemSize);
416 }
417 
418 BOOLEAN
419 NTAPI
420 KspDisableEvent(
421     IN PKSEVENT_CTX Ctx)
422 {
423     PIO_STACK_LOCATION IoStack;
424     PKSEVENTDATA EventData;
425     PKSEVENT_ENTRY EventEntry;
426     PLIST_ENTRY Entry;
427 
428     if (!Ctx || !Ctx->List || !Ctx->FileObject || !Ctx->Irp)
429     {
430         /* invalid parameter */
431         return FALSE;
432     }
433 
434     /* get current irp stack location */
435     IoStack = IoGetCurrentIrpStackLocation(Ctx->Irp);
436 
437     /* get event data */
438     EventData = (PKSEVENTDATA)IoStack->Parameters.DeviceIoControl.Type3InputBuffer;
439 
440     /* point to first entry */
441     Entry = Ctx->List->Flink;
442 
443     while(Entry != Ctx->List)
444     {
445         /* get event entry */
446         EventEntry = (PKSEVENT_ENTRY)CONTAINING_RECORD(Entry, KSEVENT_ENTRY, ListEntry);
447 
448         if (EventEntry->EventData == EventData && EventEntry->FileObject == Ctx->FileObject)
449         {
450             /* found the entry */
451             RemoveEntryList(&EventEntry->ListEntry);
452             Ctx->EventEntry = EventEntry;
453             return TRUE;
454         }
455 
456         /* move to next item */
457         Entry = Entry->Flink;
458     }
459     /* entry not found */
460     return TRUE;
461 }
462 
463 /*
464     @implemented
465 */
466 KSDDKAPI
467 NTSTATUS
468 NTAPI
469 KsDisableEvent(
470     IN  PIRP Irp,
471     IN  OUT PLIST_ENTRY EventsList,
472     IN  KSEVENTS_LOCKTYPE EventsFlags,
473     IN  PVOID EventsLock)
474 {
475     PIO_STACK_LOCATION IoStack;
476     KSEVENT_CTX Ctx;
477 
478     /* get current irp stack location */
479     IoStack = IoGetCurrentIrpStackLocation(Irp);
480 
481     /* is there a event entry */
482     if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSEVENTDATA))
483     {
484         if (IoStack->Parameters.DeviceIoControl.InputBufferLength == 0)
485         {
486             /* caller wants to free event items */
487             KsFreeEventList(IoStack->FileObject, EventsList, EventsFlags, EventsLock);
488             return STATUS_SUCCESS;
489         }
490         /* invalid parameter */
491         return STATUS_INVALID_BUFFER_SIZE;
492     }
493 
494     /* setup event ctx */
495     Ctx.List = EventsList;
496     Ctx.FileObject = IoStack->FileObject;
497     Ctx.Irp = Irp;
498     Ctx.EventEntry = NULL;
499 
500     if (KspSynchronizedEventRoutine(EventsFlags, EventsLock, KspDisableEvent, &Ctx))
501     {
502         /* was the event entry found */
503         if (Ctx.EventEntry)
504         {
505             /* discard event */
506             KsDiscardEvent(Ctx.EventEntry);
507             return STATUS_SUCCESS;
508         }
509         /* event was not found */
510         return STATUS_UNSUCCESSFUL;
511     }
512 
513     /* invalid parameters */
514     return STATUS_INVALID_PARAMETER;
515 }
516 
517 /*
518     @implemented
519 */
520 KSDDKAPI
521 VOID
522 NTAPI
523 KsDiscardEvent(
524     IN  PKSEVENT_ENTRY EventEntry)
525 {
526     /* sanity check */
527     ASSERT(EventEntry->Object);
528 
529     if (EventEntry->NotificationType == KSEVENTF_SEMAPHORE_HANDLE || EventEntry->NotificationType == KSEVENTF_EVENT_HANDLE)
530     {
531         /* release object */
532         ObDereferenceObject(EventEntry->Object);
533     }
534 
535     /* free event entry */
536     FreeItem(EventEntry);
537 }
538 
539 
540 BOOLEAN
541 NTAPI
542 KspFreeEventList(
543     IN PKSEVENT_CTX Ctx)
544 {
545     PLIST_ENTRY Entry;
546     PKSEVENT_ENTRY EventEntry;
547 
548     /* check valid input */
549     if (!Ctx || !Ctx->List)
550         return FALSE;
551 
552     if (IsListEmpty(Ctx->List))
553         return FALSE;
554 
555     /* remove first entry */
556     Entry = RemoveHeadList(Ctx->List);
557     if (!Entry)
558     {
559         /* list is empty, bye-bye */
560         return FALSE;
561     }
562 
563     /* get event entry */
564     EventEntry = (PKSEVENT_ENTRY)CONTAINING_RECORD(Entry, KSEVENT_ENTRY, ListEntry);
565 
566     /* store event entry */
567     Ctx->EventEntry = EventEntry;
568     /* return success */
569     return TRUE;
570 }
571 
572 
573 /*
574     @implemented
575 */
576 KSDDKAPI
577 VOID
578 NTAPI
579 KsFreeEventList(
580     IN  PFILE_OBJECT FileObject,
581     IN  OUT PLIST_ENTRY EventsList,
582     IN  KSEVENTS_LOCKTYPE EventsFlags,
583     IN  PVOID EventsLock)
584 {
585     KSEVENT_CTX Ctx;
586 
587     /* setup event ctx */
588     Ctx.List = EventsList;
589     Ctx.FileObject = FileObject;
590     Ctx.EventEntry = NULL;
591 
592     while(KspSynchronizedEventRoutine(EventsFlags, EventsLock, KspFreeEventList, &Ctx))
593     {
594         if (Ctx.EventEntry)
595         {
596             KsDiscardEvent(Ctx.EventEntry);
597         }
598     }
599 }
600 
601 
602 /*
603     @implemented
604 */
605 KSDDKAPI
606 NTSTATUS
607 NTAPI
608 KsGenerateEvent(
609     IN  PKSEVENT_ENTRY EntryEvent)
610 {
611     if (EntryEvent->NotificationType == KSEVENTF_EVENT_HANDLE || EntryEvent->NotificationType == KSEVENTF_EVENT_OBJECT)
612     {
613         /* signal event */
614         KeSetEvent(EntryEvent->Object, EntryEvent->Reserved, FALSE);
615     }
616     else if (EntryEvent->NotificationType == KSEVENTF_SEMAPHORE_HANDLE || EntryEvent->NotificationType == KSEVENTF_SEMAPHORE_OBJECT)
617     {
618         /* release semaphore */
619         KeReleaseSemaphore(EntryEvent->Object, EntryEvent->Reserved, EntryEvent->SemaphoreAdjustment, FALSE);
620     }
621     else if (EntryEvent->NotificationType == KSEVENTF_DPC)
622     {
623         /* increment reference count to indicate dpc is pending */
624         InterlockedIncrement((PLONG)&EntryEvent->EventData->Dpc.ReferenceCount);
625         /* queue dpc */
626         KeInsertQueueDpc((PRKDPC)EntryEvent->Object, NULL, NULL);
627     }
628     else if (EntryEvent->NotificationType == KSEVENTF_WORKITEM)
629     {
630         /* queue work item */
631         ExQueueWorkItem((PWORK_QUEUE_ITEM)EntryEvent->Object, PtrToUlong(EntryEvent->BufferItem));
632     }
633     else if (EntryEvent->NotificationType == KSEVENTF_KSWORKITEM)
634     {
635         /* queue work item of ks worker */
636         return KsQueueWorkItem((PKSWORKER)EntryEvent->Object, (PWORK_QUEUE_ITEM)EntryEvent->DpcItem);
637     }
638     else
639     {
640         /* unsupported type requested */
641         return STATUS_INVALID_PARAMETER;
642     }
643 
644     return STATUS_SUCCESS;
645 }
646 
647 /*
648     @unimplemented
649 */
650 KSDDKAPI
651 NTSTATUS
652 NTAPI
653 KsGenerateDataEvent(
654     IN  PKSEVENT_ENTRY EventEntry,
655     IN  ULONG DataSize,
656     IN  PVOID Data)
657 {
658     UNIMPLEMENTED;
659     return STATUS_UNSUCCESSFUL;
660 }
661 
662 /*
663     @unimplemented
664 */
665 KSDDKAPI
666 VOID
667 NTAPI
668 KsGenerateEventList(
669     IN GUID* Set OPTIONAL,
670     IN ULONG EventId,
671     IN PLIST_ENTRY EventsList,
672     IN KSEVENTS_LOCKTYPE EventsFlags,
673     IN PVOID EventsLock)
674 {
675     UNIMPLEMENTED;
676 }
677 
678 /*
679     @implemented
680 */
681 KSDDKAPI
682 VOID
683 NTAPI
684 KsAddEvent(
685     IN PVOID Object,
686     IN PKSEVENT_ENTRY EventEntry)
687 {
688     PKSBASIC_HEADER Header = (PKSBASIC_HEADER)((ULONG_PTR)Object - sizeof(KSBASIC_HEADER));
689 
690     ExInterlockedInsertTailList(&Header->EventList, &EventEntry->ListEntry, &Header->EventListLock);
691 }
692 
693 /*
694     @implemented
695 */
696 NTSTATUS
697 NTAPI
698 KsDefaultAddEventHandler(
699     IN PIRP  Irp,
700     IN PKSEVENTDATA  EventData,
701     IN OUT PKSEVENT_ENTRY  EventEntry)
702 {
703     PIO_STACK_LOCATION IoStack;
704     PKSIOBJECT_HEADER ObjectHeader;
705     PKSBASIC_HEADER Header;
706 
707     /* first get the io stack location */
708     IoStack = IoGetCurrentIrpStackLocation(Irp);
709 
710     /* now get the object header */
711     ObjectHeader =(PKSIOBJECT_HEADER)IoStack->FileObject->FsContext2;
712 
713     /* sanity check */
714     ASSERT(ObjectHeader->ObjectType);
715 
716     /* obtain basic header */
717     Header = (PKSBASIC_HEADER)((ULONG_PTR)ObjectHeader->ObjectType - sizeof(KSBASIC_HEADER));
718 
719     /* now insert the event entry */
720     ExInterlockedInsertTailList(&Header->EventList, &EventEntry->ListEntry, &Header->EventListLock);
721 
722     /* done */
723     return STATUS_SUCCESS;
724 }
725 
726 
727 
728 /*
729     @unimplemented
730 */
731 KSDDKAPI
732 void
733 NTAPI
734 KsGenerateEvents(
735     IN PVOID Object,
736     IN const GUID* EventSet OPTIONAL,
737     IN ULONG EventId,
738     IN ULONG DataSize,
739     IN PVOID Data OPTIONAL,
740     IN PFNKSGENERATEEVENTCALLBACK CallBack OPTIONAL,
741     IN PVOID CallBackContext OPTIONAL)
742 {
743     UNIMPLEMENTED;
744 }
745