+NTSTATUS NTAPI PinWavePciState(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciDataFormat(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciAudioPosition(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+NTSTATUS NTAPI PinWavePciAllocatorFraming(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data);
+
+DEFINE_KSPROPERTY_ALLOCATORFRAMING(PinWavePciConnectionSet, PinWavePciState, PinWavePciDataFormat, PinWavePciAllocatorFraming);
+DEFINE_KSPROPERTY_AUDIOSET(PinWavePciAudioSet, PinWavePciAudioPosition);
+
+KSPROPERTY_SET PinWavePciPropertySet[] =
+{
+ {
+ &KSPROPSETID_Connection,
+ sizeof(PinWavePciConnectionSet) / sizeof(KSPROPERTY_ITEM),
+ (const KSPROPERTY_ITEM*)&PinWavePciConnectionSet,
+ 0,
+ NULL
+ },
+ {
+ &KSPROPSETID_Audio,
+ sizeof(PinWavePciAudioSet) / sizeof(KSPROPERTY_ITEM),
+ (const KSPROPERTY_ITEM*)&PinWavePciAudioSet,
+ 0,
+ NULL
+ }
+};
+
+
+NTSTATUS
+NTAPI
+PinWavePciAllocatorFraming(
+ IN PIRP Irp,
+ IN PKSIDENTIFIER Request,
+ IN OUT PVOID Data)
+{
+ UNIMPLEMENTED
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+PinWavePciAudioPosition(
+ IN PIRP Irp,
+ IN PKSIDENTIFIER Request,
+ IN OUT PVOID Data)
+{
+ CPortPinWavePci *Pin;
+ PSUBDEVICE_DESCRIPTOR Descriptor;
+
+ // get sub device descriptor
+ Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+ // sanity check
+ PC_ASSERT(Descriptor);
+ PC_ASSERT(Descriptor->PortPin);
+ PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+ // cast to pin impl
+ Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+ //sanity check
+ PC_ASSERT(Pin->m_Stream);
+
+ if (Request->Flags & KSPROPERTY_TYPE_GET)
+ {
+ // FIXME non multithreading-safe
+ // copy audio position
+ RtlMoveMemory(Data, &Pin->m_Position, sizeof(KSAUDIO_POSITION));
+
+ DPRINT1("Play %lu Record %lu\n", Pin->m_Position.PlayOffset, Pin->m_Position.WriteOffset);
+ Irp->IoStatus.Information = sizeof(KSAUDIO_POSITION);
+ return STATUS_SUCCESS;
+ }
+
+ // not supported
+ return STATUS_NOT_SUPPORTED;
+}
+
+
+NTSTATUS
+NTAPI
+PinWavePciState(
+ IN PIRP Irp,
+ IN PKSIDENTIFIER Request,
+ IN OUT PVOID Data)
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ CPortPinWavePci *Pin;
+ PSUBDEVICE_DESCRIPTOR Descriptor;
+ PKSSTATE State = (PKSSTATE)Data;
+
+ // get sub device descriptor
+ Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+ // sanity check
+ PC_ASSERT(Descriptor);
+ PC_ASSERT(Descriptor->PortPin);
+ PC_ASSERT_IRQL(DISPATCH_LEVEL);
+
+ // cast to pin impl
+ Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+ //sanity check
+ PC_ASSERT(Pin->m_Stream);
+
+ if (Request->Flags & KSPROPERTY_TYPE_SET)
+ {
+ // try set stream
+ Status = Pin->m_Stream->SetState(*State);
+
+ DPRINT("Setting state %u %x\n", *State, Status);
+ if (NT_SUCCESS(Status))
+ {
+ // store new state
+ Pin->m_State = *State;
+ }
+ // store result
+ Irp->IoStatus.Information = sizeof(KSSTATE);
+ return Status;
+ }
+ else if (Request->Flags & KSPROPERTY_TYPE_GET)
+ {
+ // get current stream state
+ *State = Pin->m_State;
+ // store result
+ Irp->IoStatus.Information = sizeof(KSSTATE);
+
+ return STATUS_SUCCESS;
+ }
+
+ // unsupported request
+ return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+NTAPI
+PinWavePciDataFormat(
+ IN PIRP Irp,
+ IN PKSIDENTIFIER Request,
+ IN OUT PVOID Data)
+{
+ NTSTATUS Status = STATUS_UNSUCCESSFUL;
+ CPortPinWavePci *Pin;
+ PSUBDEVICE_DESCRIPTOR Descriptor;
+ PIO_STACK_LOCATION IoStack;
+
+ // get current irp stack location
+ IoStack = IoGetCurrentIrpStackLocation(Irp);
+
+ // get sub device descriptor
+ Descriptor = (PSUBDEVICE_DESCRIPTOR)KSPROPERTY_ITEM_IRP_STORAGE(Irp);
+
+ // sanity check
+ PC_ASSERT(Descriptor);
+ PC_ASSERT(Descriptor->PortPin);
+
+ // cast to pin impl
+ Pin = (CPortPinWavePci*)Descriptor->PortPin;
+
+ //sanity check
+ PC_ASSERT(Pin->m_Stream);
+ PC_ASSERT(Pin->m_Format);
+
+ if (Request->Flags & KSPROPERTY_TYPE_SET)
+ {
+ // try to change data format
+ PKSDATAFORMAT NewDataFormat, DataFormat = (PKSDATAFORMAT)Irp->UserBuffer;
+ ULONG Size = min(Pin->m_Format->FormatSize, DataFormat->FormatSize);
+
+ if (RtlCompareMemory(DataFormat, Pin->m_Format, Size) == Size)
+ {
+ // format is identical
+ Irp->IoStatus.Information = DataFormat->FormatSize;
+ return STATUS_SUCCESS;
+ }
+
+ // new change request
+ PC_ASSERT(Pin->m_State == KSSTATE_STOP);
+ // FIXME queue a work item when Irql != PASSIVE_LEVEL
+ PC_ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
+
+ // allocate new data format
+ NewDataFormat = (PKSDATAFORMAT)AllocateItem(NonPagedPool, DataFormat->FormatSize, TAG_PORTCLASS);
+ if (!NewDataFormat)
+ {
+ // not enough memory
+ return STATUS_NO_MEMORY;
+ }
+
+ // copy new data format
+ RtlMoveMemory(NewDataFormat, DataFormat, DataFormat->FormatSize);
+
+ // set new format
+ Status = Pin->m_Stream->SetFormat(NewDataFormat);
+ if (NT_SUCCESS(Status))
+ {
+ // free old format
+ FreeItem(Pin->m_Format, TAG_PORTCLASS);
+
+ // update irp queue with new format
+ Pin->m_IrpQueue->UpdateFormat((PKSDATAFORMAT)NewDataFormat);
+
+ // store new format
+ Pin->m_Format = NewDataFormat;
+ Irp->IoStatus.Information = NewDataFormat->FormatSize;
+
+#if 0
+ PC_ASSERT(NewDataFormat->FormatSize == sizeof(KSDATAFORMAT_WAVEFORMATEX));
+ PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.MajorFormat, KSDATAFORMAT_TYPE_AUDIO));
+ PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.SubFormat, KSDATAFORMAT_SUBTYPE_PCM));
+ PC_ASSERT(IsEqualGUIDAligned(((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->DataFormat.Specifier, KSDATAFORMAT_SPECIFIER_WAVEFORMATEX));
+
+
+ DPRINT1("NewDataFormat: Channels %u Bits %u Samples %u\n", ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nChannels,
+ ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.wBitsPerSample,
+ ((PKSDATAFORMAT_WAVEFORMATEX)NewDataFormat)->WaveFormatEx.nSamplesPerSec);
+#endif
+
+ }
+ else
+ {
+ // failed to set format
+ FreeItem(NewDataFormat, TAG_PORTCLASS);
+ }
+
+
+ // done
+ return Status;
+ }
+ else if (Request->Flags & KSPROPERTY_TYPE_GET)
+ {
+ // get current data format
+ PC_ASSERT(Pin->m_Format);
+
+ if (Pin->m_Format->FormatSize > IoStack->Parameters.DeviceIoControl.OutputBufferLength)
+ {
+ // buffer too small
+ Irp->IoStatus.Information = Pin->m_Format->FormatSize;
+ return STATUS_MORE_ENTRIES;
+ }
+ // copy data format
+ RtlMoveMemory(Data, Pin->m_Format, Pin->m_Format->FormatSize);
+ // store result size
+ Irp->IoStatus.Information = Pin->m_Format->FormatSize;
+
+ // done
+ return STATUS_SUCCESS;
+ }
+
+ // unsupported request
+ return STATUS_NOT_SUPPORTED;
+}
+
+