Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

558 lines
18 KiB

/*++
Copyright (C) Microsoft Corporation, 1996 - 1996
Module Name:
msmpu401.c
Abstract:
Pin property sets.
--*/
#include "common.h"
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE, PropertyConnectionGetState)
#pragma alloc_text(PAGE, PropertyConnectionGetPriority)
#pragma alloc_text(PAGE, PropertyConnectionSetPriority)
#pragma alloc_text(PAGE, PropertyConnectionGetDataFormat)
#pragma alloc_text(PAGE, MethodConnectionCancelIo)
#pragma alloc_text(PAGE, PinDispatchClose)
#pragma alloc_text(PAGE, PinDispatchCreate)
#pragma alloc_text(PAGE, PinDispatchIoControl)
#endif // ALLOC_PRAGMA
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg("PAGEDATA")
#endif // ALLOC_DATA_PRAGMA
static const KSDISPATCH_TABLE PinDispatchTable = {
0,
NULL,
PinDispatchIoControl,
NULL,
NULL,
PinDispatchClose
};
static const KSPROPERTY_ITEM ConnectionPropertyHandlers[] = {
{
KSPROPERTY_CONNECTION_STATE,
(PFNKSPROPERTYHANDLER)PropertyConnectionGetState,
sizeof(KSPROPERTY),
sizeof(KSSTATE),
(PFNKSPROPERTYHANDLER)PropertyConnectionSetState,
sizeof(KSPROPERTY),
sizeof(KSSTATE),
NULL, 0, NULL, NULL
},
{
KSPROPERTY_CONNECTION_PRIORITY,
(PFNKSPROPERTYHANDLER)PropertyConnectionGetPriority,
sizeof(KSPROPERTY),
sizeof(KSPRIORITY),
(PFNKSPROPERTYHANDLER)PropertyConnectionSetPriority,
sizeof(KSPROPERTY),
sizeof(KSPRIORITY),
NULL, 0, NULL, NULL
},
{
KSPROPERTY_CONNECTION_DATAFORMAT,
(PFNKSPROPERTYHANDLER)PropertyConnectionGetDataFormat,
sizeof(KSPROPERTY),
sizeof(KSDATAFORMAT),
NULL, 0, 0, NULL, 0, NULL, NULL
}
};
static const KSPROPERTY_ITEM LinearPropertyHandlers[] = {
{
KSPROPERTY_LINEAR_POSITION,
(PFNKSPROPERTYHANDLER)PropertyLinearGetPosition,
sizeof(KSPROPERTY),
sizeof(ULONGLONG),
NULL, 0, 0, NULL, 0, NULL, NULL
}
};
static const KSPROPERTY_SET PinPropertySets[] = {
{
&KSPROPSETID_Connection,
SIZEOF_ARRAY(ConnectionPropertyHandlers),
(PKSPROPERTY_ITEM)ConnectionPropertyHandlers,
0, NULL, 0, 0
},
{
&KSPROPSETID_Linear,
SIZEOF_ARRAY(LinearPropertyHandlers),
(PKSPROPERTY_ITEM)LinearPropertyHandlers,
0, NULL, 0, 0
}
};
static const KSEVENT_ITEM ConnectionEventItems[] = {
{
KSEVENT_CONNECTION_POSITIONUPDATE,
sizeof(KSEVENTDATA),
0, NULL, NULL, NULL
}
};
static const KSEVENT_SET EventSets[] = {
{
&KSEVENTSETID_Connection,
SIZEOF_ARRAY(ConnectionEventItems),
(PKSEVENT_ITEM)ConnectionEventItems
}
};
static const KSMETHOD_ITEM ConnectionMethodItems[] = {
{
KSMETHOD_CONNECTION_CANCELIO + KSMETHOD_TYPE_NONE,
MethodConnectionCancelIo,
sizeof(KSMETHOD),
0, NULL
},
};
static const KSMETHOD_SET MethodSets[] = {
{
&KSMETHODSETID_Connection,
SIZEOF_ARRAY(ConnectionMethodItems),
(PVOID)ConnectionMethodItems,
0, NULL, 0, 0
},
};
#ifdef ALLOC_DATA_PRAGMA
#pragma data_seg()
#endif // ALLOC_DATA_PRAGMA
VOID
PinGenerateEvent(
IN PPIN_INSTANCE PinInstance,
IN REFGUID EventSet,
IN ULONG EventId
)
{
PLIST_ENTRY ListEntry;
for (ListEntry = PinInstance->EventQueue.Flink; ListEntry != &PinInstance->EventQueue; ListEntry = ListEntry->Flink) {
PKSEVENT_ENTRY EventEntry;
EventEntry = (PKSEVENT_ENTRY)CONTAINING_RECORD(ListEntry, KSEVENT_ENTRY, ListEntry);
if (IsEqualGUIDAligned(EventSet, EventEntry->EventSet->Set))
if (EventId == EventEntry->EventItem->EventId)
switch (EventId) {
case KSEVENT_CONNECTION_POSITIONUPDATE:
KsEventGenerate(EventEntry);
break;
}
}
}
static
BOOLEAN
DpcCountSynchronize(
IN PDEVICE_INSTANCE DeviceInstance
)
{
return !DeviceInstance->DpcCount;
}
static
VOID
RundownProcessing(
IN PDEVICE_INSTANCE DeviceInstance,
IN PPIN_INSTANCE PinInstance
)
{
switch (PinInstance->PinId) {
case ID_MUSICCAPTURE_PIN:
while (!KeSynchronizeExecution(DeviceInstance->InterruptInfo.Interrupt, DpcCountSynchronize, DeviceInstance))
KeStallExecutionProcessor(1);
break;
case ID_MUSICPLAYBACK_PIN:
if (KeCancelTimer(&PinInstance->QueueTimer))
InterlockedDecrement(&PinInstance->TimerCount);
while (PinInstance->TimerCount)
KeStallExecutionProcessor(1);
break;
}
}
static
NTSTATUS
SetState(
IN PPIN_INSTANCE PinInstance,
IN KSSTATE State
)
{
ULONGLONG Time;
PDEVICE_INSTANCE DeviceInstance;
if (PinInstance->State == State)
return STATUS_SUCCESS;
DeviceInstance = (PDEVICE_INSTANCE)IoGetRelatedDeviceObject(PinInstance->FilterFileObject)->DeviceExtension;
switch (State) {
case KSSTATE_STOP:
InterlockedExchange((PLONG)&PinInstance->State, (LONG)KSSTATE_STOP);
RundownProcessing(DeviceInstance, PinInstance);
PinInstance->TimeBase = 0;
PinInstance->ByteIo = 0;
break;
case KSSTATE_PAUSE:
if (PinInstance->State == KSSTATE_RUN) {
InterlockedExchange((PLONG)&PinInstance->State, (LONG)KSSTATE_PAUSE);
RundownProcessing(DeviceInstance, PinInstance);
PinInstance->TimeBase = KeQueryPerformanceCounter(NULL).QuadPart - PinInstance->TimeBase;
} else
InterlockedExchange((PLONG)&PinInstance->State, (LONG)KSSTATE_PAUSE);
break;
case KSSTATE_RUN:
Time = KeQueryPerformanceCounter(NULL).QuadPart;
if (PinInstance->State == KSSTATE_STOP)
PinInstance->TimeBase = Time;
else
PinInstance->TimeBase = Time - PinInstance->TimeBase;
InterlockedExchange((PLONG)&PinInstance->State, (LONG)KSSTATE_RUN);
Time = 0;
if (!PinInstance->QueueTimer.Header.Inserted && !KeSetTimerEx(&PinInstance->QueueTimer, *(PLARGE_INTEGER)&Time, 0, &PinInstance->QueueDpc))
InterlockedIncrement(&PinInstance->TimerCount);
break;
}
return STATUS_SUCCESS;
}
NTSTATUS
PropertyConnectionGetState(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT PKSSTATE State
)
{
*State = ((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext)->State;
Irp->IoStatus.Information = sizeof(KSSTATE);
return STATUS_SUCCESS;
}
NTSTATUS
PropertyConnectionSetState(
IN PIRP Irp,
IN PKSPROPERTY Property,
IN PKSSTATE State
)
{
NTSTATUS Status;
PPIN_INSTANCE PinInstance;
KIRQL IrqlOld;
PinInstance = (PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext;
KeAcquireSpinLock(&PinInstance->StateLock, &IrqlOld);
Status = SetState(PinInstance, *State);
KeReleaseSpinLock(&PinInstance->StateLock, IrqlOld);
return Status;
}
NTSTATUS
PropertyConnectionGetPriority(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT PKSPRIORITY Priority
)
{
*Priority = ((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext)->Priority;
Irp->IoStatus.Information = sizeof(KSPRIORITY);
return STATUS_SUCCESS;
}
NTSTATUS
PropertyConnectionSetPriority(
IN PIRP Irp,
IN PKSPROPERTY Property,
IN PKSPRIORITY Priority
)
{
((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext)->Priority = *Priority;
return STATUS_SUCCESS;
}
NTSTATUS
PropertyConnectionGetDataFormat(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT PKSDATAFORMAT DataFormat
)
{
DataFormat->MajorFormat = KSDATAFORMAT_TYPE_MUSIC;
DataFormat->SubFormat = KSDATAFORMAT_SUBTYPE_MIDI;
DataFormat->Specifier = KSDATAFORMAT_FORMAT_NONE;
DataFormat->FormatSize = sizeof(KSDATAFORMAT);
Irp->IoStatus.Information = sizeof(KSDATAFORMAT);
return STATUS_SUCCESS;
}
NTSTATUS
PropertyLinearGetPosition(
IN PIRP Irp,
IN PKSPROPERTY Property,
OUT PULONGLONG Position
)
{
KIRQL IrqlOld;
IoAcquireCancelSpinLock(&IrqlOld);
*Position = ((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext)->ByteIo;
IoReleaseCancelSpinLock(IrqlOld);
Irp->IoStatus.Information = sizeof(ULONGLONG);
return STATUS_SUCCESS;
}
#if 0
NTSTATUS
propTimeBase(
IN PIRP Irp,
IN PKSPROPERTY Property,
IN OUT PVOID Data
)
{
PPIN_INSTANCE PinInstance;
KIRQL IrqlOld;
PinInstance = (PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext;
KeAcquireSpinLock(&PinInstance->StateLock, &IrqlOld);
switch (PinInstance->State) {
case KSSTATE_STOP:
case KSSTATE_PAUSE:
*(PULONGLONG)Data = KeQueryPerformanceCounter(NULL).QuadPart - pci->TimeBase;
break;
case KSSTATE_RUN:
*(PULONGLONG)Data = pci->TimeBase;
break;
}
KeReleaseSpinLock(&PinInstance->StateLock, IrqlOld);
Irp->IoStatus.Information = sizeof(ULONGLONG);
return STATUS_SUCCESS;
}
#endif // 0
NTSTATUS
MethodConnectionCancelIo(
IN PIRP Irp,
IN PKSMETHOD Method,
IN OUT PVOID Data
)
{
KsCancelIo(&((PPIN_INSTANCE)IoGetCurrentIrpStackLocation(Irp)->FileObject->FsContext)->IoQueue);
return STATUS_SUCCESS;
}
NTSTATUS PinDispatchClose(
IN PDEVICE_OBJECT pDeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpStack;
PDEVICE_INSTANCE DeviceInstance;
PPIN_INSTANCE PinInstance;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
PinInstance = (PPIN_INSTANCE)IrpStack->FileObject->FsContext;
SetState(PinInstance, KSSTATE_STOP);
KsEventFreeList(Irp, &PinInstance->EventQueue, KSEVENTS_SPINLOCK, &PinInstance->EventQueueLock);
DeviceInstance = (PDEVICE_INSTANCE)IrpStack->DeviceObject->DeviceExtension;
DeviceInstance->PinFileObjects[PinInstance->PinId] = NULL;
ObDereferenceObject(PinInstance->FilterFileObject);
ExFreePool(PinInstance);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS
PinDispatchCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
PKSPIN_CONNECT Connect;
PFILE_OBJECT FilterFileObject;
NTSTATUS Status;
Irp->IoStatus.Information = 0;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (NT_SUCCESS(Status = KsValidateConnectRequest(Irp, SIZEOF_ARRAY(FilterPinDescriptors), (PKSPIN_DESCRIPTOR)FilterPinDescriptors, &Connect, &FilterFileObject))) {
PDEVICE_INSTANCE DeviceInstance;
DeviceInstance = (PDEVICE_INSTANCE)DeviceObject->DeviceExtension;
ExAcquireFastMutexUnsafe(&DeviceInstance->ControlMutex);
if (!DeviceInstance->PinFileObjects[Connect->PinId]) {
PPIN_INSTANCE PinInstance;
if (PinInstance = (PPIN_INSTANCE)ExAllocatePool(NonPagedPool, sizeof(PIN_INSTANCE))) {
IrpStack->FileObject->FsContext = (PVOID)PinInstance;
PinInstance->DispatchTable = (PKSDISPATCH_TABLE)&PinDispatchTable;
KeQueryPerformanceCounter((PLARGE_INTEGER)&PinInstance->Frequency);
PinInstance->State = KSSTATE_STOP;
PinInstance->PinId = Connect->PinId;
InitializeListHead(&PinInstance->IoQueue);
InitializeListHead(&PinInstance->EventQueue);
KeInitializeSpinLock(&PinInstance->EventQueueLock);
PinInstance->TimeBase = 0;
PinInstance->ByteIo = 0;
KeInitializeSpinLock(&PinInstance->StateLock);
if (Connect->PinId == ID_MUSICPLAYBACK_PIN) {
KeInitializeTimerEx(&PinInstance->QueueTimer, NotificationTimer);
KeInitializeDpc(&PinInstance->QueueDpc, (PKDEFERRED_ROUTINE)HwDeferredWrite, DeviceObject);
PinInstance->TimerCount = 0;
}
PinInstance->FilterFileObject = FilterFileObject;
ObReferenceObject(FilterFileObject);
PinInstance->Priority = Connect->Priority;
DeviceInstance->PinFileObjects[Connect->PinId] = IrpStack->FileObject;
} else
Status = STATUS_NO_MEMORY;
} else
Status = STATUS_CONNECTION_REFUSED;
ExReleaseFastMutexUnsafe(&DeviceInstance->ControlMutex);
}
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
static
NTSTATUS
WriteStream(
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
NTSTATUS Status;
PULONG UserBuffer;
KIRQL IrqlOld;
PPIN_INSTANCE PinInstance;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Information = 0;
if (!IrpStack->Parameters.DeviceIoControl.InputBufferLength)
return STATUS_SUCCESS;
if (!NT_SUCCESS(Status = KsProbeStreamIrp(Irp, KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK)))
return Status;
UserBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
if ((ULONG)UserBuffer & FILE_LONG_ALIGNMENT)
return STATUS_DATATYPE_MISALIGNMENT;
if (((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->DataSize < 2 * sizeof(ULONG) + sizeof(UCHAR))
return STATUS_BUFFER_TOO_SMALL;
Irp->Tail.Overlay.AuxiliaryBuffer = (PUCHAR)UserBuffer;
Irp->IoStatus.Information = 2 * sizeof(ULONG);
IoMarkIrpPending(Irp);
Irp->IoStatus.Status = STATUS_PENDING;
IoAcquireCancelSpinLock(&IrqlOld);
IoSetCancelRoutine(Irp, HwCancelRoutine);
PinInstance = (PPIN_INSTANCE)IrpStack->FileObject->FsContext;
InsertTailList(&PinInstance->IoQueue, &Irp->Tail.Overlay.ListEntry);
KeAcquireSpinLockAtDpcLevel(&PinInstance->StateLock);
if ((PinInstance->State == KSSTATE_RUN) && !PinInstance->QueueTimer.Header.Inserted) {
ULONGLONG CurrentTime;
ULONGLONG NextTime;
CurrentTime = (KeQueryPerformanceCounter(NULL).QuadPart - PinInstance->TimeBase) * 10000000 / PinInstance->Frequency;
NextTime = ((PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer)->PresentationTime.Time + *UserBuffer * 10000;
if (NextTime < CurrentTime)
NextTime = 0;
else
NextTime = (ULONGLONG)-(LONGLONG)(NextTime - CurrentTime);
if (!KeSetTimerEx(&PinInstance->QueueTimer, *(PLARGE_INTEGER)&NextTime, 0, &PinInstance->QueueDpc))
InterlockedIncrement(&PinInstance->TimerCount);
}
KeReleaseSpinLockFromDpcLevel(&PinInstance->StateLock);
IoReleaseCancelSpinLock(IrqlOld);
return STATUS_PENDING;
}
static
NTSTATUS
ReadStream(
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
NTSTATUS Status;
PULONG UserBuffer;
PKSSTREAM_HEADER StreamHdr;
PPIN_INSTANCE PinInstance;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
if (IrpStack->Parameters.DeviceIoControl.InputBufferLength < 2 * sizeof(ULONG) + sizeof(UCHAR))
return STATUS_BUFFER_TOO_SMALL;
if (!NT_SUCCESS(Status = KsProbeStreamIrp(Irp, KSPROBE_ALLOCATEMDL | KSPROBE_PROBEANDLOCK)))
return Status;
UserBuffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
if ((ULONG)UserBuffer & FILE_LONG_ALIGNMENT)
return STATUS_DATATYPE_MISALIGNMENT;
MmGetSystemAddressForMdl(Irp->MdlAddress);
Irp->IoStatus.Information = sizeof(KSSTREAM_HEADER);
StreamHdr = (PKSSTREAM_HEADER)Irp->AssociatedIrp.SystemBuffer;
StreamHdr->PresentationTime.Time = 0;
StreamHdr->PresentationTime.Numerator = 1;
StreamHdr->PresentationTime.Denominator = 1;
StreamHdr->DataSize = 0;
StreamHdr->OptionsFlags = 0;
PinInstance = (PPIN_INSTANCE)IrpStack->FileObject->FsContext;
KsAddIrpToCancelableQueue(&PinInstance->IoQueue, Irp, FALSE, HwCancelRoutine);
return STATUS_PENDING;
}
NTSTATUS
PinDispatchIoControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IrpStack;
NTSTATUS Status;
PPIN_INSTANCE PinInstance;
IrpStack = IoGetCurrentIrpStackLocation(Irp);
PinInstance = (PPIN_INSTANCE)IrpStack->FileObject->FsContext;
switch (IrpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_KS_GET_PROPERTY:
case IOCTL_KS_SET_PROPERTY:
Status = KsPropertyHandler(Irp, SIZEOF_ARRAY(PinPropertySets), (PKSPROPERTY_SET)PinPropertySets);
break;
case IOCTL_KS_ENABLE_EVENT:
Status = KsEventEnable(Irp, SIZEOF_ARRAY(EventSets), (PKSEVENT_SET)EventSets, &PinInstance->EventQueue, KSEVENTS_SPINLOCK, &PinInstance->EventQueueLock);
break;
case IOCTL_KS_DISABLE_EVENT:
Status = KsEventDisable(Irp, &PinInstance->EventQueue, KSEVENTS_SPINLOCK, &PinInstance->EventQueueLock);
break;
case IOCTL_KS_METHOD:
Status = KsMethodHandler(Irp, SIZEOF_ARRAY(MethodSets), (PKSMETHOD_SET)MethodSets);
break;
case IOCTL_KS_READ_STREAM:
if (PinInstance->PinId == ID_MUSICCAPTURE_PIN)
Status = ReadStream(Irp);
else
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
case IOCTL_KS_WRITE_STREAM:
if (PinInstance->PinId == ID_MUSICPLAYBACK_PIN)
Status = WriteStream(Irp);
else
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
default:
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
if (Status != STATUS_PENDING) {
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
return Status;
}