/***************************************************************************** * event.cpp - event support ***************************************************************************** * Copyright (c) 1997-2000 Microsoft Corporation. All rights reserved. */ #include "private.h" /***************************************************************************** * Functions */ #pragma code_seg("PAGE") /***************************************************************************** * PcHandleEnableEventWithTable() ***************************************************************************** * Uses an event table to handle a KS enable event IOCTL. */ PORTCLASSAPI NTSTATUS NTAPI PcHandleEnableEventWithTable ( IN PIRP pIrp, IN PEVENT_CONTEXT pContext ) { PAGED_CODE(); ASSERT(pIrp); ASSERT(pContext); PIO_STACK_LOCATION IrpStack; ULONG InputBufferLength; NTSTATUS ntStatus = STATUS_SUCCESS; _DbgPrintF(DEBUGLVL_BLAB,("PcHandleEnableEventWithTable")); // deal with possible node events IrpStack = IoGetCurrentIrpStackLocation( pIrp ); InputBufferLength = IrpStack->Parameters.DeviceIoControl.InputBufferLength; if( InputBufferLength >= sizeof(KSE_NODE) ) { ULONG Flags; __try { // validate the pointers if we don't trust the client if( pIrp->RequestorMode != KernelMode ) { ProbeForRead( IrpStack->Parameters.DeviceIoControl.Type3InputBuffer, InputBufferLength, sizeof(BYTE)); } // get the flags Flags = ((PKSEVENT)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer)->Flags; if( Flags & KSEVENT_TYPE_TOPOLOGY ) { // get the node id pContext->pPropertyContext->ulNodeId = ((PKSE_NODE)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer)->NodeId; // mask off the flag bit ((PKSEVENT)IrpStack->Parameters.DeviceIoControl.Type3InputBuffer)->Flags &= ~KSEVENT_TYPE_TOPOLOGY; } } __except (EXCEPTION_EXECUTE_HANDLER) { ntStatus = GetExceptionCode (); } } if (NT_SUCCESS(ntStatus)) { pIrp->Tail.Overlay.DriverContext[3] = pContext; ntStatus = KsEnableEvent( pIrp, pContext->ulEventSetCount, pContext->pEventSets, NULL, KSEVENTS_NONE, NULL ); // restore ulNodeId pContext->pPropertyContext->ulNodeId = ULONG(-1); } return ntStatus; } /***************************************************************************** * PcHandleDisableEventWithTable() ***************************************************************************** * Uses an event table to handle a KS disable event IOCTL. */ PORTCLASSAPI NTSTATUS NTAPI PcHandleDisableEventWithTable ( IN PIRP pIrp, IN PEVENT_CONTEXT pContext ) { PAGED_CODE(); ASSERT(pIrp); ASSERT(pContext); _DbgPrintF(DEBUGLVL_VERBOSE,("PcHandleDisableEventWithTable")); pIrp->Tail.Overlay.DriverContext[3] = pContext; return KsDisableEvent( pIrp, &(pContext->pEventList->List), KSEVENTS_SPINLOCK, &(pContext->pEventList->ListLock) ); } /***************************************************************************** * EventItemAddHandler() ***************************************************************************** * KS-sytle event handler that handles Adds using the * PCEVENT_ITEM mechanism. Note that filter and pin events in the port do not * utilize this AddHandler, only events exposed by the miniport. */ NTSTATUS EventItemAddHandler ( IN PIRP pIrp, IN PKSEVENTDATA pEventData, IN PKSEVENT_ENTRY pEventEntry ) { PAGED_CODE(); ASSERT(pIrp); NTSTATUS ntStatus = STATUS_SUCCESS; _DbgPrintF(DEBUGLVL_VERBOSE,("EventItemAddHandler")); // get the IRP stack location PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( pIrp ); // get the event context PEVENT_CONTEXT pContext = PEVENT_CONTEXT(pIrp->Tail.Overlay.DriverContext[3]); // get the instance size ULONG ulInstanceSize = irpSp->Parameters.DeviceIoControl.InputBufferLength; ULONG AlignedBufferLength = (irpSp->Parameters.DeviceIoControl.OutputBufferLength + FILE_QUAD_ALIGNMENT) & ~FILE_QUAD_ALIGNMENT; // // Setup event request structure // PPCEVENT_REQUEST pPcEventRequest = new(NonPagedPool,'rEcP') PCEVENT_REQUEST; if( !pPcEventRequest ) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } else { // // Copy target information from the context structure // pPcEventRequest->MajorTarget = pContext->pPropertyContext->pUnknownMajorTarget; pPcEventRequest->MinorTarget = pContext->pPropertyContext->pUnknownMinorTarget; pPcEventRequest->Node = pContext->pPropertyContext->ulNodeId; pPcEventRequest->EventItem = NULL; // get the filter descriptor PPCFILTER_DESCRIPTOR pPcFilterDescriptor = pContext->pPropertyContext->pPcFilterDescriptor; if( ULONG(-1) == pPcEventRequest->Node ) { if( !pPcEventRequest->MinorTarget ) { // // FILTER EVENT // if( ( pPcFilterDescriptor ) && ( pPcFilterDescriptor->AutomationTable ) ) { // search the filter's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, *pEventEntry->EventSet->Set ) && pPcEventItem->Id == pEventEntry->EventItem->EventId ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } else { // // PIN EVENT // // validate the pin id if( ( pPcFilterDescriptor ) && ( pContext->ulPinId < pPcFilterDescriptor->PinCount ) && ( pPcFilterDescriptor->Pins[pContext->ulPinId].AutomationTable ) ) { // search the pin's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->Pins[pContext->ulPinId].AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, *pEventEntry->EventSet->Set ) && pPcEventItem->Id == pEventEntry->EventItem->EventId ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } } else { // // NODE EVENT // // validate the node id if( ( pPcFilterDescriptor ) && ( pPcEventRequest->Node < pPcFilterDescriptor->NodeCount ) && ( pPcFilterDescriptor->Nodes[pPcEventRequest->Node].AutomationTable ) ) { // search the node's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->Nodes[pPcEventRequest->Node].AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, *pEventEntry->EventSet->Set ) && pPcEventItem->Id == pEventEntry->EventItem->EventId ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } if( NT_SUCCESS(ntStatus) ) { // // call the handler if we have an event item with a handler if( pPcEventRequest->EventItem && pPcEventRequest->EventItem->Handler ) { PPCEVENT_ENTRY(pEventEntry)->EventItem = pPcEventRequest->EventItem; PPCEVENT_ENTRY(pEventEntry)->PinId = pContext->ulPinId; PPCEVENT_ENTRY(pEventEntry)->NodeId = pPcEventRequest->Node; PPCEVENT_ENTRY(pEventEntry)->pUnknownMajorTarget = pPcEventRequest->MajorTarget; PPCEVENT_ENTRY(pEventEntry)->pUnknownMinorTarget = pPcEventRequest->MinorTarget; pPcEventRequest->Verb = PCEVENT_VERB_ADD; pPcEventRequest->Irp = pIrp; pPcEventRequest->EventEntry = pEventEntry; // // call the handler // ntStatus = pPcEventRequest->EventItem->Handler( pPcEventRequest ); } else { ntStatus = STATUS_NOT_FOUND; } } // // delete the request structure unless we are pending // if( ntStatus != STATUS_PENDING ) { delete pPcEventRequest; } else { // // only requests with IRPs can be pending // ASSERT(pIrp); } } return ntStatus; } /***************************************************************************** * EventItemSupportHandler() ***************************************************************************** * KS-sytle event handler that handles Supports using the * PCEVENT_ITEM mechanism. */ NTSTATUS EventItemSupportHandler ( IN PIRP pIrp, IN PKSIDENTIFIER pRequest, IN OUT PVOID pData OPTIONAL ) { PAGED_CODE(); ASSERT(pIrp); ASSERT(pRequest); NTSTATUS ntStatus = STATUS_SUCCESS; _DbgPrintF(DEBUGLVL_BLAB,("EventItemSupportHandler")); // get the IRP stack location PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation( pIrp ); // get the property/event context PEVENT_CONTEXT pContext = PEVENT_CONTEXT(pIrp->Tail.Overlay.DriverContext[3]); // get the instance size ULONG ulInstanceSize = irpSp->Parameters.DeviceIoControl.InputBufferLength; // // Setup event request structure // PPCEVENT_REQUEST pPcEventRequest = new(NonPagedPool,'rEcP') PCEVENT_REQUEST; if( !pPcEventRequest ) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; } else { // // Copy target information from the context structure // pPcEventRequest->MajorTarget = pContext->pPropertyContext->pUnknownMajorTarget; pPcEventRequest->MinorTarget = pContext->pPropertyContext->pUnknownMinorTarget; pPcEventRequest->Node = pContext->pPropertyContext->ulNodeId; pPcEventRequest->EventItem = NULL; // get the filter descriptor PPCFILTER_DESCRIPTOR pPcFilterDescriptor = pContext->pPropertyContext->pPcFilterDescriptor; if( ULONG(-1) == pPcEventRequest->Node ) { if( !pPcEventRequest->MinorTarget ) { // // FILTER EVENT // if( ( pPcFilterDescriptor ) && ( pPcFilterDescriptor->AutomationTable ) ) { // search the filter's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, pRequest->Set ) && pPcEventItem->Id == pRequest->Id ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } else { // // PIN EVENT // // validate the pin id if( ( pPcFilterDescriptor ) && ( pContext->ulPinId < pPcFilterDescriptor->PinCount ) && ( pPcFilterDescriptor->Pins[pContext->ulPinId].AutomationTable ) ) { // search the pin's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->Pins[pContext->ulPinId].AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, pRequest->Set ) && pPcEventItem->Id == pRequest->Id ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } } else { // // NODE EVENT // // validate the node id if( ( pPcFilterDescriptor ) && ( pPcEventRequest->Node < pPcFilterDescriptor->NodeCount ) && ( pPcFilterDescriptor->Nodes[pPcEventRequest->Node].AutomationTable ) ) { // search the node's automation table for the event const PCAUTOMATION_TABLE *pPcAutomationTable = pPcFilterDescriptor->Nodes[pPcEventRequest->Node].AutomationTable; const PCEVENT_ITEM *pPcEventItem = pPcAutomationTable->Events; for(ULONG ul = pPcAutomationTable->EventCount; ul--; ) { if( IsEqualGUIDAligned( *pPcEventItem->Set, pRequest->Set ) && pPcEventItem->Id == pRequest->Id ) { pPcEventRequest->EventItem = pPcEventItem; break; } pPcEventItem = PPCEVENT_ITEM( PBYTE(pPcEventItem) + pPcAutomationTable->EventItemSize); } } } if(NT_SUCCESS(ntStatus)) { // // call the handler if we have an event item with a handler // if( pPcEventRequest->EventItem && pPcEventRequest->EventItem->Handler ) { pPcEventRequest->Verb = PCEVENT_VERB_SUPPORT; pPcEventRequest->Irp = pIrp; pPcEventRequest->EventEntry = NULL; // // call the handler // ntStatus = pPcEventRequest->EventItem->Handler( pPcEventRequest ); } else { ntStatus = STATUS_NOT_FOUND; } } // // delete the request structure unless we are pending // if( ntStatus != STATUS_PENDING ) { delete pPcEventRequest; } else { // // only requests with IRPs can be pending // ASSERT(pIrp); } } return ntStatus; } #pragma code_seg() /***************************************************************************** * EventItemRemoveHandler() ***************************************************************************** * */ void EventItemRemoveHandler ( IN PFILE_OBJECT pFileObject, IN PKSEVENT_ENTRY pEventEntry ) { ASSERT(pFileObject); ASSERT(pEventEntry); _DbgPrintF(DEBUGLVL_VERBOSE,("EventItemRemoveHandler")); PPCEVENT_ENTRY pPcEventEntry = PPCEVENT_ENTRY(pEventEntry); // // Setup event request structure // PPCEVENT_REQUEST pPcEventRequest = new(NonPagedPool,'rEcP') PCEVENT_REQUEST; if( pPcEventRequest ) { // // Fill out the event request for the miniport // pPcEventRequest->MajorTarget = pPcEventEntry->pUnknownMajorTarget; pPcEventRequest->MinorTarget = pPcEventEntry->pUnknownMinorTarget; pPcEventRequest->Node = pPcEventEntry->NodeId; pPcEventRequest->EventItem = pPcEventEntry->EventItem; pPcEventRequest->Verb = PCEVENT_VERB_REMOVE; pPcEventRequest->Irp = NULL; pPcEventRequest->EventEntry = pEventEntry; if( ( pPcEventEntry->EventItem ) && ( pPcEventEntry->EventItem->Handler ) ) { pPcEventEntry->EventItem->Handler( pPcEventRequest ); } delete pPcEventRequest; } RemoveEntryList( &(pEventEntry->ListEntry) ); } #pragma code_seg("PAGE") /***************************************************************************** * PcCompletePendingEventRequest() ***************************************************************************** * Completes a pending event request. */ PORTCLASSAPI NTSTATUS NTAPI PcCompletePendingEventRequest ( IN PPCEVENT_REQUEST EventRequest, IN NTSTATUS NtStatus ) { PAGED_CODE(); ASSERT(EventRequest); ASSERT(NtStatus != STATUS_PENDING); if (!NT_ERROR(NtStatus)) { EventRequest->Irp->IoStatus.Information = 0; } EventRequest->Irp->IoStatus.Status = NtStatus; IoCompleteRequest(EventRequest->Irp,IO_NO_INCREMENT); delete EventRequest; return STATUS_SUCCESS; } /***************************************************************************** * PcFreeEventTable() ***************************************************************************** * Frees allocated memory in a EVENT_TABLE structure. */ PORTCLASSAPI void NTAPI PcFreeEventTable ( IN PEVENT_TABLE EventTable ) { _DbgPrintF(DEBUGLVL_VERBOSE,("PcFreeEventTable")); PAGED_CODE(); ASSERT(EventTable); ASSERT((!EventTable->EventSets) == (!EventTable->EventSetCount)); // EventSets and EventSetCount must be non-NULL/non-zero, or NULL/zero ASSERT(EventTable->StaticSets == (!EventTable->StaticItems)); // StaticSets and StaticItems must be TRUE/NULL, or FALSE/non-null PBOOLEAN staticItem = EventTable->StaticItems; if (staticItem) { PKSEVENT_SET eventSet = EventTable->EventSets; if (eventSet) { for( ULONG count = EventTable->EventSetCount; count--; eventSet++, staticItem++) { if ((! *staticItem) && eventSet->EventItem) { ExFreePool(PVOID(eventSet->EventItem)); } } } ExFreePool(EventTable->StaticItems); EventTable->StaticItems = NULL; } if (EventTable->EventSets && !EventTable->StaticSets) { EventTable->EventSetCount = 0; ExFreePool(EventTable->EventSets); EventTable->EventSets = NULL; } EventTable->StaticSets = TRUE; } /***************************************************************************** * PcAddToEventTable() ***************************************************************************** * Adds an EVENT_ITEM event table to a EVENT_TABLE structure. */ PORTCLASSAPI NTSTATUS NTAPI PcAddToEventTable ( IN OUT PEVENT_TABLE EventTable, IN ULONG EventItemCount, IN const PCEVENT_ITEM * EventItems, IN ULONG EventItemSize, IN BOOLEAN NodeTable ) { PAGED_CODE(); ASSERT(EventTable); ASSERT(EventItems); ASSERT(EventItemSize >= sizeof(PCEVENT_ITEM)); _DbgPrintF(DEBUGLVL_VERBOSE,("PcAddToEventTable")); #define ADVANCE(item) (item = PPCEVENT_ITEM(PBYTE(item) + EventItemSize)) ASSERT((!EventTable->EventSets) == (!EventTable->EventSetCount)); // values must be non-NULL/non-zero, or NULL/zero. // // Determine how many sets we will end up with. // ULONG setCount = EventTable->EventSetCount; const PCEVENT_ITEM *item = EventItems; for (ULONG count = EventItemCount; count--; ADVANCE(item)) { BOOLEAN countThis = TRUE; // // See if it's already in the table. // PKSEVENT_SET eventSet = EventTable->EventSets; for ( ULONG count2 = EventTable->EventSetCount; count2--; eventSet++ ) { if (IsEqualGUIDAligned(*item->Set,*eventSet->Set)) { countThis = FALSE; break; } } if (countThis) { // // See if it's appeared in the list previously. // for ( const PCEVENT_ITEM *prevItem = EventItems; prevItem != item; ADVANCE(prevItem) ) { if (IsEqualGUIDAligned(*item->Set,*prevItem->Set)) { countThis = FALSE; break; } } } if (countThis) { setCount++; } } NTSTATUS ntStatus = STATUS_SUCCESS; // // Make a new set table. // ASSERT(setCount); ASSERT(setCount >= EventTable->EventSetCount); // // Allocate memory required for the set table. // PKSEVENT_SET newTable = PKSEVENT_SET ( ExAllocatePoolWithTag ( NonPagedPool, sizeof(KSEVENT_SET) * setCount, 'tEcP' ) ); // // Allocate memory for the static items flags. // PBOOLEAN newStaticItems = NULL; if (newTable) { newStaticItems = PBOOLEAN ( ExAllocatePoolWithTag ( PagedPool, sizeof(BOOLEAN) * setCount, 'bScP' ) ); if (! newStaticItems) { ExFreePool(newTable); newTable = NULL; } } if (newTable) { // // Initialize the new set table. // RtlZeroMemory ( PVOID(newTable), sizeof(KSEVENT_SET) * setCount ); if (EventTable->EventSetCount != 0) { RtlCopyMemory ( PVOID(newTable), PVOID(EventTable->EventSets), sizeof(KSEVENT_SET) * EventTable->EventSetCount ); } // // Initialize the new static items flags. // RtlFillMemory ( PVOID(newStaticItems), sizeof(BOOLEAN) * setCount, 0xff ); if (EventTable->StaticItems && EventTable->EventSetCount) { // // Flags existed before...copy them. // RtlCopyMemory ( PVOID(newStaticItems), PVOID(EventTable->StaticItems), sizeof(BOOLEAN) * EventTable->EventSetCount ); } // // Assign set GUIDs to the new set entries. // PKSEVENT_SET addHere = newTable + EventTable->EventSetCount; const PCEVENT_ITEM *item2 = EventItems; for (ULONG count = EventItemCount; count--; ADVANCE(item2)) { BOOLEAN addThis = TRUE; // // See if it's already in the table. // for( PKSEVENT_SET eventSet = newTable; eventSet != addHere; eventSet++) { if (IsEqualGUIDAligned(*item2->Set,*eventSet->Set)) { addThis = FALSE; break; } } if (addThis) { addHere->Set = item2->Set; addHere++; } } ASSERT(addHere == newTable + setCount); // // Free old allocated tables. // if (EventTable->EventSets && (!EventTable->StaticSets)) { ExFreePool(EventTable->EventSets); } if (EventTable->StaticItems) { ExFreePool(EventTable->StaticItems); } // // Install the new tables. // EventTable->EventSetCount = setCount; EventTable->EventSets = newTable; EventTable->StaticSets = FALSE; EventTable->StaticItems = newStaticItems; } else { // if allocations fail, return error and // keep sets and items as they were. ntStatus = STATUS_INSUFFICIENT_RESOURCES; } // // Now we have an event set table that contains all the sets we need. // if (NT_SUCCESS(ntStatus)) { // // For each set... // PKSEVENT_SET eventSet = EventTable->EventSets; PBOOLEAN staticItem = EventTable->StaticItems; for ( ULONG count = EventTable->EventSetCount; count--; eventSet++, staticItem++ ) { // // Check to see how many new items we have. // ULONG itemCount = eventSet->EventsCount; const PCEVENT_ITEM *item2 = EventItems; for (ULONG count2 = EventItemCount; count2--; ADVANCE(item2)) { if (IsEqualGUIDAligned(*item2->Set,*eventSet->Set)) { itemCount++; } } ASSERT(itemCount >= eventSet->EventsCount); if (itemCount != eventSet->EventsCount) { // // Allocate memory required for the items table. // PKSEVENT_ITEM newTable2 = PKSEVENT_ITEM ( ExAllocatePoolWithTag ( NonPagedPool, sizeof(KSEVENT_ITEM) * itemCount, 'iEcP' ) ); if (! newTable2) { ntStatus = STATUS_INSUFFICIENT_RESOURCES; break; } // // Initialize the table. // RtlZeroMemory ( PVOID(newTable2), sizeof(KSEVENT_ITEM) * itemCount ); if (eventSet->EventsCount) { RtlCopyMemory ( PVOID(newTable2), PVOID(eventSet->EventItem), sizeof(KSEVENT_ITEM) * eventSet->EventsCount ); } // // Create the new items. // PKSEVENT_ITEM addHere = newTable2 + eventSet->EventsCount; item2 = EventItems; for (count2 = EventItemCount; count2--; ADVANCE(item2)) { if (IsEqualGUIDAligned(*item2->Set,*eventSet->Set)) { addHere->EventId = item2->Id; addHere->DataInput = sizeof( KSEVENTDATA ); addHere->ExtraEntryData = sizeof( PCEVENT_ENTRY ) - sizeof( KSEVENT_ENTRY ); addHere->AddHandler = EventItemAddHandler; addHere->RemoveHandler = EventItemRemoveHandler; addHere->SupportHandler = EventItemSupportHandler; addHere++; } } ASSERT(addHere == newTable2 + itemCount); // // Free old allocated table. // if (eventSet->EventItem && ! *staticItem) { ExFreePool(PVOID(eventSet->EventItem)); } // // Install the new tables. // eventSet->EventsCount = itemCount; eventSet->EventItem = newTable2; *staticItem = FALSE; } } } return ntStatus; } #pragma code_seg() /***************************************************************************** * PcGenerateEventList() ***************************************************************************** * Walks an event list and generates desired events. */ PORTCLASSAPI void NTAPI PcGenerateEventList ( IN PINTERLOCKED_LIST EventList, IN GUID* Set OPTIONAL, IN ULONG EventId, IN BOOL PinEvent, IN ULONG PinId, IN BOOL NodeEvent, IN ULONG NodeId ) { ASSERT(EventList); KIRQL oldIrql; PLIST_ENTRY ListEntry; PKSEVENT_ENTRY EventEntry; if( EventList ) { ASSERT( KeGetCurrentIrql() <= DISPATCH_LEVEL ); // acquire the event list lock KeAcquireSpinLock( &(EventList->ListLock), &oldIrql ); // only walk a non-empty list if( !IsListEmpty( &(EventList->List) ) ) { for( ListEntry = EventList->List.Flink; ListEntry != &(EventList->List); ListEntry = ListEntry->Flink ) { EventEntry = (PKSEVENT_ENTRY) CONTAINING_RECORD( ListEntry, KSEVENT_ENTRY, ListEntry ); if( ( !Set || IsEqualGUIDAligned( *Set, *(EventEntry->EventSet->Set) ) ) && ( EventId == EventEntry->EventItem->EventId ) && ( !PinEvent || ( PinId == PPCEVENT_ENTRY(EventEntry)->PinId ) ) && ( !NodeEvent || ( NodeId == PPCEVENT_ENTRY(EventEntry)->NodeId ) ) ) { KsGenerateEvent( EventEntry ); } } } // release the event list lock KeReleaseSpinLock( &(EventList->ListLock), oldIrql ); } } /***************************************************************************** * PcGenerateEventDeferredRoutine() ***************************************************************************** * This DPC routine is used when GenerateEventList is called at greater * that DISPATCH_LEVEL. */ PORTCLASSAPI void NTAPI PcGenerateEventDeferredRoutine ( IN PKDPC Dpc, IN PVOID DeferredContext, // PEVENT_DPC_CONTEXT IN PVOID SystemArgument1, // PINTERLOCKED_LIST IN PVOID SystemArgument2 ) { ASSERT(Dpc); ASSERT(DeferredContext); ASSERT(SystemArgument1); PEVENT_DPC_CONTEXT Context = PEVENT_DPC_CONTEXT(DeferredContext); PINTERLOCKED_LIST EventList = PINTERLOCKED_LIST(SystemArgument1); if( Context && EventList ) { PcGenerateEventList( EventList, Context->Set, Context->EventId, Context->PinEvent, Context->PinId, Context->NodeEvent, Context->NodeId ); Context->ContextInUse = FALSE; } }