mirror of
https://github.com/reactos/reactos.git
synced 2025-05-06 10:28:45 +00:00

- Queue a dpc when IServiceGroup::RequestService is called above dispatch level - As a result writing to common buffer and completing irps can be done at the same time - Start the stream at PASSIVE_LEVEL - Check if key has been deleted in IRegistryKey object function - Implement IRegistryKey::QueryRegistryValues svn path=/trunk/; revision=40672
297 lines
6.7 KiB
C
297 lines
6.7 KiB
C
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS Kernel Streaming
|
|
* FILE: drivers/wdm/audio/backpln/portcls/service_group.c
|
|
* PURPOSE: ServiceGroup object implementation
|
|
* PROGRAMMER: Johannes Anderwald
|
|
*/
|
|
|
|
|
|
#include "private.h"
|
|
|
|
typedef struct
|
|
{
|
|
LIST_ENTRY Entry;
|
|
IN PSERVICESINK pServiceSink;
|
|
}GROUP_ENTRY, *PGROUP_ENTRY;
|
|
|
|
typedef struct
|
|
{
|
|
IServiceGroupVtbl *lpVtbl;
|
|
|
|
LONG ref;
|
|
LIST_ENTRY ServiceSinkHead;
|
|
|
|
BOOL Initialized;
|
|
BOOL TimerActive;
|
|
KTIMER Timer;
|
|
KDPC Dpc;
|
|
}IServiceGroupImpl;
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
// IUnknown methods
|
|
//
|
|
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IServiceGroup_fnQueryInterface(
|
|
IServiceGroup* iface,
|
|
IN REFIID refiid,
|
|
OUT PVOID* Output)
|
|
{
|
|
UNICODE_STRING GuidString;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
if (IsEqualGUIDAligned(refiid, &IID_IServiceGroup) ||
|
|
IsEqualGUIDAligned(refiid, &IID_IServiceSink) ||
|
|
IsEqualGUIDAligned(refiid, &IID_IUnknown))
|
|
{
|
|
*Output = &This->lpVtbl;
|
|
InterlockedIncrement(&This->ref);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS)
|
|
{
|
|
DPRINT1("IServiceGroup_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer);
|
|
RtlFreeUnicodeString(&GuidString);
|
|
}
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
IServiceGroup_fnAddRef(
|
|
IServiceGroup* iface)
|
|
{
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
return InterlockedIncrement(&This->ref);
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
IServiceGroup_fnRelease(
|
|
IServiceGroup* iface)
|
|
{
|
|
PLIST_ENTRY CurEntry;
|
|
PGROUP_ENTRY Entry;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
InterlockedDecrement(&This->ref);
|
|
|
|
if (This->ref == 0)
|
|
{
|
|
while(!IsListEmpty(&This->ServiceSinkHead))
|
|
{
|
|
CurEntry = RemoveHeadList(&This->ServiceSinkHead);
|
|
Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
|
|
Entry->pServiceSink->lpVtbl->Release(Entry->pServiceSink);
|
|
FreeItem(Entry, TAG_PORTCLASS);
|
|
}
|
|
KeCancelTimer(&This->Timer);
|
|
FreeItem(This, TAG_PORTCLASS);
|
|
return 0;
|
|
}
|
|
/* Return new reference count */
|
|
return This->ref;
|
|
}
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
// IServiceSink methods
|
|
//
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroup_fnRequestService(
|
|
IN IServiceGroup * iface)
|
|
{
|
|
KIRQL OldIrql;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
if (KeGetCurrentIrql() > DISPATCH_LEVEL)
|
|
{
|
|
KeInsertQueueDpc(&This->Dpc, NULL, NULL);
|
|
return;
|
|
}
|
|
|
|
KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
|
|
KeInsertQueueDpc(&This->Dpc, NULL, NULL);
|
|
KeLowerIrql(OldIrql);
|
|
}
|
|
|
|
//---------------------------------------------------------------
|
|
// IServiceGroup methods
|
|
//
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
IServiceGroup_fnAddMember(
|
|
IN IServiceGroup * iface,
|
|
IN PSERVICESINK pServiceSink)
|
|
{
|
|
PGROUP_ENTRY Entry;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
|
|
|
|
Entry = AllocateItem(NonPagedPool, sizeof(GROUP_ENTRY), TAG_PORTCLASS);
|
|
if (!Entry)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
Entry->pServiceSink = pServiceSink;
|
|
pServiceSink->lpVtbl->AddRef(pServiceSink);
|
|
|
|
InsertTailList(&This->ServiceSinkHead, &Entry->Entry);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroup_fnRemoveMember(
|
|
IN IServiceGroup * iface,
|
|
IN PSERVICESINK pServiceSink)
|
|
{
|
|
PLIST_ENTRY CurEntry;
|
|
PGROUP_ENTRY Entry;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
ASSERT_IRQL_EQUAL(PASSIVE_LEVEL);
|
|
|
|
CurEntry = This->ServiceSinkHead.Flink;
|
|
while (CurEntry != &This->ServiceSinkHead)
|
|
{
|
|
Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
|
|
if (Entry->pServiceSink == pServiceSink)
|
|
{
|
|
RemoveEntryList(&Entry->Entry);
|
|
pServiceSink->lpVtbl->Release(pServiceSink);
|
|
FreeItem(Entry, TAG_PORTCLASS);
|
|
return;
|
|
}
|
|
CurEntry = CurEntry->Flink;
|
|
}
|
|
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroupDpc(
|
|
IN struct _KDPC *Dpc,
|
|
IN PVOID DeferredContext,
|
|
IN PVOID SystemArgument1,
|
|
IN PVOID SystemArgument2
|
|
)
|
|
{
|
|
PLIST_ENTRY CurEntry;
|
|
PGROUP_ENTRY Entry;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)DeferredContext;
|
|
|
|
CurEntry = This->ServiceSinkHead.Flink;
|
|
while (CurEntry != &This->ServiceSinkHead)
|
|
{
|
|
Entry = CONTAINING_RECORD(CurEntry, GROUP_ENTRY, Entry);
|
|
Entry->pServiceSink->lpVtbl->RequestService(Entry->pServiceSink);
|
|
CurEntry = CurEntry->Flink;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroup_fnSupportDelayedService(
|
|
IN IServiceGroup * iface)
|
|
{
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
ASSERT_IRQL(DISPATCH_LEVEL);
|
|
|
|
if (!This->Initialized)
|
|
{
|
|
KeInitializeTimerEx(&This->Timer, NotificationTimer);
|
|
This->Initialized = TRUE;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroup_fnRequestDelayedService(
|
|
IN IServiceGroup * iface,
|
|
IN ULONGLONG ullDelay)
|
|
{
|
|
LARGE_INTEGER DueTime;
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
ASSERT_IRQL(DISPATCH_LEVEL);
|
|
|
|
DueTime.QuadPart = ullDelay;
|
|
|
|
if (This->Initialized)
|
|
{
|
|
if (KeGetCurrentIrql() <= DISPATCH_LEVEL)
|
|
KeSetTimer(&This->Timer, DueTime, &This->Dpc);
|
|
else
|
|
KeInsertQueueDpc(&This->Dpc, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
IServiceGroup_fnCancelDelayedService(
|
|
IN IServiceGroup * iface)
|
|
{
|
|
IServiceGroupImpl * This = (IServiceGroupImpl*)iface;
|
|
|
|
ASSERT_IRQL(DISPATCH_LEVEL);
|
|
|
|
if (This->Initialized)
|
|
{
|
|
KeCancelTimer(&This->Timer);
|
|
}
|
|
}
|
|
|
|
static IServiceGroupVtbl vt_IServiceGroup =
|
|
{
|
|
/* IUnknown methods */
|
|
IServiceGroup_fnQueryInterface,
|
|
IServiceGroup_fnAddRef,
|
|
IServiceGroup_fnRelease,
|
|
IServiceGroup_fnRequestService,
|
|
IServiceGroup_fnAddMember,
|
|
IServiceGroup_fnRemoveMember,
|
|
IServiceGroup_fnSupportDelayedService,
|
|
IServiceGroup_fnRequestDelayedService,
|
|
IServiceGroup_fnCancelDelayedService
|
|
};
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS NTAPI
|
|
PcNewServiceGroup(
|
|
OUT PSERVICEGROUP* OutServiceGroup,
|
|
IN PUNKNOWN OuterUnknown OPTIONAL)
|
|
{
|
|
IServiceGroupImpl * This;
|
|
|
|
DPRINT("PcNewServiceGroup entered\n");
|
|
|
|
This = AllocateItem(NonPagedPool, sizeof(IServiceGroupImpl), TAG_PORTCLASS);
|
|
if (!This)
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
This->lpVtbl = &vt_IServiceGroup;
|
|
This->ref = 1;
|
|
KeInitializeDpc(&This->Dpc, IServiceGroupDpc, (PVOID)This);
|
|
KeSetImportanceDpc(&This->Dpc, HighImportance);
|
|
InitializeListHead(&This->ServiceSinkHead);
|
|
*OutServiceGroup = (PSERVICEGROUP)&This->lpVtbl;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|