- Implement KsEnableEvent, KsEnableEventWithAllocator, KsDiscardEvent
[PORTCLS]
- Fix signalling the event
- DirectSound clients can now use IDirectSoundNotify interface to be notified of a position change

svn path=/trunk/; revision=44100
This commit is contained in:
Johannes Anderwald 2009-11-11 09:04:42 +00:00
parent 008929cd36
commit 7d088d0725
2 changed files with 365 additions and 27 deletions

View file

@ -71,9 +71,312 @@ KspSynchronizedEventRoutine(
return Result;
}
BOOLEAN
NTAPI
SyncAddEvent(
PKSEVENT_CTX Context)
{
InsertTailList(Context->List, &Context->EventEntry->ListEntry);
return TRUE;
}
NTSTATUS
KspEnableEvent(
IN PIRP Irp,
IN ULONG EventSetsCount,
IN PKSEVENT_SET EventSet,
IN OUT PLIST_ENTRY EventsList OPTIONAL,
IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL,
IN PVOID EventsLock OPTIONAL,
IN PFNKSALLOCATOR Allocator OPTIONAL,
IN ULONG EventItemSize OPTIONAL)
{
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
KSEVENT Event;
PKSEVENT_ITEM EventItem, FoundEventItem;
PKSEVENTDATA EventData;
PKSEVENT_SET FoundEventSet;
PKSEVENT_ENTRY EventEntry;
ULONG Index, SubIndex, Size;
PVOID Object;
KSEVENT_CTX Ctx;
LPGUID Guid;
/* get current stack location */
IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IoStack->Parameters.DeviceIoControl.InputBufferLength < sizeof(KSEVENT))
{
/* invalid parameter */
return STATUS_NOT_SUPPORTED;
}
if (Irp->RequestorMode == UserMode)
{
_SEH2_TRY
{
ProbeForRead(IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT), sizeof(UCHAR));
ProbeForRead(Irp->UserBuffer, IoStack->Parameters.DeviceIoControl.OutputBufferLength, sizeof(UCHAR));
RtlMoveMemory(&Event, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT));
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
/* Exception, get the error code */
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed to probe parameters */
return Status;
}
}
else
{
/* copy event struct */
RtlMoveMemory(&Event, IoStack->Parameters.DeviceIoControl.Type3InputBuffer, sizeof(KSEVENT));
}
FoundEventItem = NULL;
FoundEventSet = NULL;
if (IsEqualGUIDAligned(&Event.Set, &GUID_NULL) && Event.Id == 0 && Event.Flags == KSEVENT_TYPE_SETSUPPORT)
{
// store output size
Irp->IoStatus.Information = sizeof(GUID) * EventSetsCount;
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < sizeof(GUID) * EventSetsCount)
{
// buffer too small
return STATUS_MORE_ENTRIES;
}
// get output buffer
Guid = (LPGUID)Irp->UserBuffer;
// copy property guids from property sets
for(Index = 0; Index < EventSetsCount; Index++)
{
RtlMoveMemory(&Guid[Index], EventSet[Index].Set, sizeof(GUID));
}
return STATUS_SUCCESS;
}
/* now try to find event set */
for(Index = 0; Index < EventSetsCount; Index++)
{
if (IsEqualGUIDAligned(&Event.Set, EventSet[Index].Set))
{
EventItem = (PKSEVENT_ITEM)EventSet[Index].EventItem;
/* sanity check */
ASSERT(EventSet[Index].EventsCount);
ASSERT(EventItem);
/* now find matching event id */
for(SubIndex = 0; SubIndex < EventSet[Index].EventsCount; SubIndex++)
{
if (EventItem[SubIndex].EventId == Event.Id)
{
/* found event item */
FoundEventItem = &EventItem[SubIndex];
FoundEventSet = &EventSet[Index];
break;
}
}
if (FoundEventSet)
break;
}
}
if (!FoundEventSet)
{
UNICODE_STRING GuidString;
RtlStringFromGUID(&Event.Set, &GuidString);
DPRINT("Guid %S Id %u Flags %x not found\n", GuidString.Buffer, Event.Id, Event.Flags);
RtlFreeUnicodeString(&GuidString);
return STATUS_PROPSET_NOT_FOUND;
}
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength < FoundEventItem->DataInput)
{
/* buffer too small */
DPRINT1("Got %u expected %u\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength, FoundEventItem->DataInput);
return STATUS_SUCCESS;
}
if (!FoundEventItem->AddHandler && !EventsList)
{
/* no add handler and no list to add the new entry to */
return STATUS_INVALID_PARAMETER;
}
/* get event data */
EventData = Irp->UserBuffer;
/* sanity check */
ASSERT(EventData);
if (Irp->RequestorMode == UserMode)
{
if (EventData->NotificationType == KSEVENTF_SEMAPHORE_HANDLE)
{
/* get semaphore object handle */
Status = ObReferenceObjectByHandle(EventData->SemaphoreHandle.Semaphore, SEMAPHORE_MODIFY_STATE, ExSemaphoreObjectType, Irp->RequestorMode, &Object, NULL);
if (!NT_SUCCESS(Status))
{
/* invalid semaphore handle */
return STATUS_INVALID_PARAMETER;
}
}
else if (EventData->NotificationType == KSEVENTF_EVENT_HANDLE)
{
/* get event object handle */
Status = ObReferenceObjectByHandle(EventData->EventHandle.Event, EVENT_MODIFY_STATE, ExEventObjectType, Irp->RequestorMode, &Object, NULL);
if (!NT_SUCCESS(Status))
{
/* invalid event handle */
return STATUS_INVALID_PARAMETER;
}
}
else
{
/* user mode client can only pass an event or semaphore handle */
return STATUS_INVALID_PARAMETER;
}
}
else
{
if (EventData->NotificationType != KSEVENTF_EVENT_OBJECT &&
EventData->NotificationType != KSEVENTF_SEMAPHORE_OBJECT &&
EventData->NotificationType != KSEVENTF_DPC &&
EventData->NotificationType != KSEVENTF_WORKITEM &&
EventData->NotificationType != KSEVENTF_KSWORKITEM)
{
/* invalid type requested */
return STATUS_INVALID_PARAMETER;
}
}
/* calculate request size */
Size = sizeof(KSEVENT_ENTRY) + FoundEventItem->ExtraEntryData;
/* do we have an allocator */
if (Allocator)
{
/* allocate event entry */
Status = Allocator(Irp, Size, FALSE);
if (!NT_SUCCESS(Status))
{
/* failed */
return Status;
}
/* assume the caller put it there */
EventEntry = KSEVENT_ENTRY_IRP_STORAGE(Irp);
}
else
{
/* allocate it from nonpaged pool */
EventEntry = ExAllocatePool(NonPagedPool, Size);
}
if (!EventEntry)
{
/* not enough memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* zero event entry */
RtlZeroMemory(EventEntry, Size);
/* initialize event entry */
EventEntry->EventData = EventData;
EventEntry->NotificationType = EventData->NotificationType;
EventEntry->EventItem = FoundEventItem;
EventEntry->EventSet = FoundEventSet;
EventEntry->FileObject = IoStack->FileObject;
switch(EventEntry->NotificationType)
{
case KSEVENTF_EVENT_HANDLE:
EventEntry->Object = Object;
EventEntry->Reserved = 0;
break;
case KSEVENTF_SEMAPHORE_HANDLE:
EventEntry->Object = Object;
EventEntry->SemaphoreAdjustment = EventData->SemaphoreHandle.Adjustment;
EventEntry->Reserved = 0;
break;
case KSEVENTF_EVENT_OBJECT:
EventEntry->Object = EventData->EventObject.Event;
EventEntry->Reserved = EventData->EventObject.Increment;
break;
case KSEVENTF_SEMAPHORE_OBJECT:
EventEntry->Object = EventData->SemaphoreObject.Semaphore;
EventEntry->SemaphoreAdjustment = EventData->SemaphoreObject.Adjustment;
EventEntry->Reserved = EventData->SemaphoreObject.Increment;
break;
case KSEVENTF_DPC:
EventEntry->Object = EventData->Dpc.Dpc;
EventData->Dpc.ReferenceCount = 0;
break;
case KSEVENTF_WORKITEM:
EventEntry->Object = EventData->WorkItem.WorkQueueItem;
EventEntry->BufferItem = (PKSBUFFER_ITEM)UlongToPtr(EventData->WorkItem.WorkQueueType);
break;
case KSEVENTF_KSWORKITEM:
EventEntry->Object = EventData->KsWorkItem.KsWorkerObject;
EventEntry->DpcItem = (PKSDPC_ITEM)EventData->KsWorkItem.WorkQueueItem;
break;
default:
/* should not happen */
ASSERT(0);
}
if (FoundEventItem->AddHandler)
{
/* now add the event */
Status = FoundEventItem->AddHandler(Irp, EventData, EventEntry);
if (!NT_SUCCESS(Status))
{
/* discard event entry */
KsDiscardEvent(EventEntry);
}
}
else
{
/* setup context */
Ctx.List = EventsList;
Ctx.EventEntry = EventEntry;
/* add the event */
(void)KspSynchronizedEventRoutine(EventsFlags, EventsLock, SyncAddEvent, &Ctx);
Status = STATUS_SUCCESS;
}
/* done */
return Status;
}
/*
@unimplemented
@implemented
*/
KSDDKAPI
NTSTATUS
@ -86,12 +389,11 @@ KsEnableEvent(
IN KSEVENTS_LOCKTYPE EventsFlags OPTIONAL,
IN PVOID EventsLock OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_SUCCESS;
return KspEnableEvent(Irp, EventSetsCount, EventSet, EventsList, EventsFlags, EventsLock, NULL, 0);
}
/*
@unimplemented
@implemented
*/
KSDDKAPI
NTSTATUS
@ -106,8 +408,7 @@ KsEnableEventWithAllocator(
IN PFNKSALLOCATOR Allocator OPTIONAL,
IN ULONG EventItemSize OPTIONAL)
{
UNIMPLEMENTED;
return STATUS_UNSUCCESSFUL;
return KspEnableEvent(Irp, EventSetsCount, EventSet, EventsList, EventsFlags, EventsLock, Allocator, EventItemSize);
}
BOOLEAN
@ -210,7 +511,7 @@ KsDisableEvent(
}
/*
@unimplemented
@implemented
*/
KSDDKAPI
VOID
@ -218,7 +519,17 @@ NTAPI
KsDiscardEvent(
IN PKSEVENT_ENTRY EventEntry)
{
//UNIMPLEMENTED;
/* sanity check */
ASSERT(EventEntry->Object);
if (EventEntry->NotificationType == KSEVENTF_SEMAPHORE_HANDLE || EventEntry->NotificationType == KSEVENTF_EVENT_HANDLE)
{
/* release object */
ObDereferenceObject(EventEntry->Object);
}
/* free event entry */
ExFreePool(EventEntry);
}
@ -295,33 +606,35 @@ KsGenerateEvent(
{
if (EntryEvent->NotificationType == KSEVENTF_EVENT_HANDLE || EntryEvent->NotificationType == KSEVENTF_EVENT_OBJECT)
{
// signal event
KeSetEvent(EntryEvent->Object, 0, FALSE);
/* signal event */
KeSetEvent(EntryEvent->Object, EntryEvent->Reserved, FALSE);
}
else if (EntryEvent->NotificationType == KSEVENTF_SEMAPHORE_HANDLE || EntryEvent->NotificationType == KSEVENTF_SEMAPHORE_OBJECT)
{
// release semaphore
KeReleaseSemaphore(EntryEvent->Object, 0, EntryEvent->SemaphoreAdjustment, FALSE);
/* release semaphore */
KeReleaseSemaphore(EntryEvent->Object, EntryEvent->Reserved, EntryEvent->SemaphoreAdjustment, FALSE);
}
else if (EntryEvent->NotificationType == KSEVENTF_DPC)
{
// queue dpc
/* increment reference count to indicate dpc is pending */
InterlockedIncrement((PLONG)&EntryEvent->EventData->Dpc.ReferenceCount);
/* queue dpc */
KeInsertQueueDpc((PRKDPC)EntryEvent->Object, NULL, NULL);
}
else if (EntryEvent->NotificationType == KSEVENTF_WORKITEM)
{
// queue work item
/* queue work item */
ExQueueWorkItem((PWORK_QUEUE_ITEM)EntryEvent->Object, PtrToUlong(EntryEvent->BufferItem));
}
else if (EntryEvent->NotificationType == KSEVENTF_KSWORKITEM)
{
// queue work item of ks worker
/* queue work item of ks worker */
return KsQueueWorkItem((PKSWORKER)EntryEvent->Object, (PWORK_QUEUE_ITEM)EntryEvent->DpcItem);
}
else
{
UNIMPLEMENTED;
return STATUS_UNSUCCESSFUL;
/* unsupported type requested */
return STATUS_INVALID_PARAMETER;
}
return STATUS_SUCCESS;

View file

@ -41,7 +41,7 @@ protected:
VOID UpdateCommonBuffer(ULONG Position, ULONG MaxTransferCount);
VOID UpdateCommonBufferOverlap(ULONG Position, ULONG MaxTransferCount);
VOID GeneratePositionEvents(IN ULONG OldCommonBufferOffset, IN ULONG NewCommonBufferOffset);
VOID GeneratePositionEvents(IN ULONGLONG OldOffset, IN ULONGLONG NewOffset);
NTSTATUS NTAPI HandleKsStream(IN PIRP Irp);
NTSTATUS NTAPI HandleKsProperty(IN PIRP Irp);
@ -261,6 +261,8 @@ PinWaveCyclicAddLoopedStreamEvent(
Entry->bLoopedStreaming = TRUE;
Entry->Position = Data->Position;
DPRINT1("Added event\n");
// insert item
(void)ExInterlockedInsertTailList(&Pin->m_EventList, &EventEntry->ListEntry, &Pin->m_EventListLock);
@ -342,7 +344,7 @@ PinWaveCyclicAudioPosition(
}
else if (Pin->m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
{
Position->PlayOffset = Pin->m_Position.PlayOffset % Pin->m_Position.WriteOffset;
Position->PlayOffset = Pin->m_Position.PlayOffset;
Position->WriteOffset = (ULONGLONG)Pin->m_IrpQueue->GetCurrentIrpOffset();
DPRINT("Play %lu Write %lu\n", Position->PlayOffset, Position->WriteOffset);
}
@ -540,8 +542,8 @@ PinWaveCyclicDataFormat(
VOID
CPortPinWaveCyclic::GeneratePositionEvents(
IN ULONG OldCommonBufferOffset,
IN ULONG NewCommonBufferOffset)
IN ULONGLONG OldOffset,
IN ULONGLONG NewOffset)
{
PLIST_ENTRY Entry;
PKSEVENT_ENTRY EventEntry;
@ -563,11 +565,15 @@ CPortPinWaveCyclic::GeneratePositionEvents(
if (Context->bLoopedStreaming == TRUE)
{
if (NewCommonBufferOffset > OldCommonBufferOffset)
if (NewOffset > OldOffset)
{
/* buffer progress no overlap */
if (OldCommonBufferOffset < Context->Position && Context->Position <= NewCommonBufferOffset)
if (OldOffset < Context->Position && Context->Position <= NewOffset)
{
/* when someone eventually fixes sprintf... */
DPRINT("Generating event at OldOffset %I64u\n", OldOffset);
DPRINT("Context->Position %I64u\n", Context->Position);
DPRINT("NewOffset %I64u\n", NewOffset);
/* generate event */
KsGenerateEvent(EventEntry);
}
@ -575,8 +581,12 @@ CPortPinWaveCyclic::GeneratePositionEvents(
else
{
/* buffer wrap-arround */
if (OldCommonBufferOffset < Context->Position || NewCommonBufferOffset > Context->Position)
if (OldOffset < Context->Position || NewOffset > Context->Position)
{
/* when someone eventually fixes sprintf... */
DPRINT("Generating event at OldOffset %I64u\n", OldOffset);
DPRINT("Context->Position %I64u\n", Context->Position);
DPRINT("NewOffset %I64u\n", NewOffset);
/* generate event */
KsGenerateEvent(EventEntry);
}
@ -627,6 +637,12 @@ CPortPinWaveCyclic::UpdateCommonBuffer(
BufferLength = Position - m_CommonBufferOffset;
m_Position.PlayOffset += BytesToCopy;
if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
{
// normalize position
m_Position.PlayOffset = m_Position.PlayOffset % m_Position.WriteOffset;
}
}
}
@ -670,6 +686,13 @@ CPortPinWaveCyclic::UpdateCommonBufferOverlap(
m_Position.PlayOffset += BytesToCopy;
BufferLength = m_CommonBufferSize - m_CommonBufferOffset;
if (m_ConnectDetails->Interface.Id == KSINTERFACE_STANDARD_LOOPED_STREAMING)
{
// normalize position
m_Position.PlayOffset = m_Position.PlayOffset % m_Position.WriteOffset;
}
}
if (Gap == Length)
@ -693,7 +716,7 @@ CPortPinWaveCyclic::RequestService()
NTSTATUS Status;
PUCHAR Buffer;
ULONG BufferSize;
ULONG OldCommonBufferOffset;
ULONGLONG OldOffset, NewOffset;
PC_ASSERT_IRQL(DISPATCH_LEVEL);
@ -706,7 +729,7 @@ CPortPinWaveCyclic::RequestService()
Status = m_Stream->GetPosition(&Position);
DPRINT("Position %u Buffer %p BufferSize %u ActiveIrpOffset %u Capture %u\n", Position, Buffer, m_CommonBufferSize, BufferSize, m_Capture);
OldCommonBufferOffset = m_CommonBufferOffset;
OldOffset = m_Position.PlayOffset;
if (Position < m_CommonBufferOffset)
{
@ -717,7 +740,9 @@ CPortPinWaveCyclic::RequestService()
UpdateCommonBuffer(Position, m_FrameSize);
}
GeneratePositionEvents(OldCommonBufferOffset, m_CommonBufferOffset);
NewOffset = m_Position.PlayOffset;
GeneratePositionEvents(OldOffset, NewOffset);
}
NTSTATUS