2016-09-18 14:24:21 +00:00
|
|
|
/*
|
|
|
|
* PROJECT: ReactOS Universal Audio Class Driver
|
|
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
|
|
* FILE: drivers/usb/usbaudio/pin.c
|
|
|
|
* PURPOSE: USB Audio device driver.
|
|
|
|
* PROGRAMMERS:
|
|
|
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "usbaudio.h"
|
|
|
|
|
2016-09-29 22:19:34 +00:00
|
|
|
NTSTATUS
|
|
|
|
GetMaxPacketSizeForInterface(
|
|
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
|
|
|
|
IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
|
|
|
|
KSPIN_DATAFLOW DataFlow)
|
|
|
|
{
|
|
|
|
PUSB_COMMON_DESCRIPTOR CommonDescriptor;
|
|
|
|
PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
|
|
|
|
|
|
|
|
/* loop descriptors */
|
|
|
|
CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
|
|
|
|
ASSERT(InterfaceDescriptor->bNumEndpoints > 0);
|
|
|
|
while (CommonDescriptor)
|
|
|
|
{
|
|
|
|
if (CommonDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
|
|
|
|
{
|
|
|
|
EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CommonDescriptor;
|
|
|
|
return EndpointDescriptor->wMaxPacketSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CommonDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
|
|
|
|
{
|
|
|
|
/* reached next interface descriptor */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
|
|
|
|
break;
|
|
|
|
|
|
|
|
CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* default to 100 */
|
|
|
|
return 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
UsbAudioAllocCaptureUrbIso(
|
|
|
|
IN USBD_PIPE_HANDLE PipeHandle,
|
|
|
|
IN ULONG MaxPacketSize,
|
|
|
|
IN PVOID Buffer,
|
|
|
|
IN ULONG BufferLength,
|
|
|
|
OUT PURB * OutUrb)
|
|
|
|
{
|
|
|
|
PURB Urb;
|
|
|
|
ULONG PacketCount;
|
|
|
|
ULONG UrbSize;
|
|
|
|
ULONG Index;
|
|
|
|
|
|
|
|
/* calculate packet count */
|
|
|
|
PacketCount = BufferLength / MaxPacketSize;
|
|
|
|
|
|
|
|
/* calculate urb size*/
|
|
|
|
UrbSize = GET_ISO_URB_SIZE(PacketCount);
|
|
|
|
|
|
|
|
/* allocate urb */
|
|
|
|
Urb = AllocFunction(UrbSize);
|
|
|
|
if (!Urb)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init urb */
|
|
|
|
Urb->UrbIsochronousTransfer.Hdr.Function = URB_FUNCTION_ISOCH_TRANSFER;
|
|
|
|
Urb->UrbIsochronousTransfer.Hdr.Length = UrbSize;
|
|
|
|
Urb->UrbIsochronousTransfer.PipeHandle = PipeHandle;
|
|
|
|
Urb->UrbIsochronousTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_START_ISO_TRANSFER_ASAP;
|
|
|
|
Urb->UrbIsochronousTransfer.TransferBufferLength = BufferLength;
|
|
|
|
Urb->UrbIsochronousTransfer.TransferBuffer = Buffer;
|
|
|
|
Urb->UrbIsochronousTransfer.NumberOfPackets = PacketCount;
|
|
|
|
|
|
|
|
for (Index = 0; Index < PacketCount; Index++)
|
|
|
|
{
|
|
|
|
Urb->UrbIsochronousTransfer.IsoPacket[Index].Offset = Index * MaxPacketSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
*OutUrb = Urb;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-09-28 20:31:32 +00:00
|
|
|
NTSTATUS
|
|
|
|
UsbAudioSetFormat(
|
|
|
|
IN PKSPIN Pin)
|
|
|
|
{
|
|
|
|
PURB Urb;
|
|
|
|
PUCHAR SampleRateBuffer;
|
|
|
|
PPIN_CONTEXT PinContext;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PKSDATAFORMAT_WAVEFORMATEX WaveFormatEx;
|
|
|
|
|
|
|
|
/* allocate sample rate buffer */
|
|
|
|
SampleRateBuffer = AllocFunction(sizeof(ULONG));
|
|
|
|
if (!SampleRateBuffer)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsEqualGUIDAligned(&Pin->ConnectionFormat->MajorFormat, &KSDATAFORMAT_TYPE_AUDIO) &&
|
|
|
|
IsEqualGUIDAligned(&Pin->ConnectionFormat->SubFormat, &KSDATAFORMAT_SUBTYPE_PCM) &&
|
|
|
|
IsEqualGUIDAligned(&Pin->ConnectionFormat->Specifier, &KSDATAFORMAT_SPECIFIER_WAVEFORMATEX))
|
|
|
|
{
|
|
|
|
WaveFormatEx = (PKSDATAFORMAT_WAVEFORMATEX)Pin->ConnectionFormat;
|
2016-09-29 19:25:31 +00:00
|
|
|
SampleRateBuffer[2] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 16) & 0xFF;
|
2016-09-28 20:31:32 +00:00
|
|
|
SampleRateBuffer[1] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 8) & 0xFF;
|
2016-09-29 19:25:31 +00:00
|
|
|
SampleRateBuffer[0] = (WaveFormatEx->WaveFormatEx.nSamplesPerSec >> 0) & 0xFF;
|
2016-09-28 20:31:32 +00:00
|
|
|
|
|
|
|
/* TODO: verify connection format */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* not supported yet*/
|
|
|
|
UNIMPLEMENTED;
|
|
|
|
FreeFunction(SampleRateBuffer);
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate urb */
|
|
|
|
Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
|
|
|
|
if (!Urb)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
FreeFunction(SampleRateBuffer);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* format urb */
|
|
|
|
UsbBuildVendorRequest(Urb,
|
|
|
|
URB_FUNCTION_CLASS_ENDPOINT,
|
2016-09-29 19:25:31 +00:00
|
|
|
sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST),
|
2016-09-28 20:31:32 +00:00
|
|
|
USBD_TRANSFER_DIRECTION_OUT,
|
|
|
|
0,
|
|
|
|
0x01,
|
|
|
|
0x100,
|
|
|
|
0x81, //FIXME bEndpointAddress
|
|
|
|
SampleRateBuffer,
|
|
|
|
NULL,
|
|
|
|
3,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
/* get pin context */
|
|
|
|
PinContext = Pin->Context;
|
2016-09-29 19:25:31 +00:00
|
|
|
|
2016-09-28 20:31:32 +00:00
|
|
|
/* submit urb */
|
|
|
|
Status = SubmitUrbSync(PinContext->LowerDevice, Urb);
|
|
|
|
|
|
|
|
DPRINT1("USBAudioPinSetDataFormat Pin %p Status %x\n", Pin, Status);
|
|
|
|
FreeFunction(Urb);
|
|
|
|
FreeFunction(SampleRateBuffer);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
USBAudioSelectAudioStreamingInterface(
|
2016-09-29 22:19:34 +00:00
|
|
|
IN PPIN_CONTEXT PinContext,
|
2016-09-28 20:31:32 +00:00
|
|
|
IN PDEVICE_EXTENSION DeviceExtension,
|
|
|
|
IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
|
|
|
|
{
|
|
|
|
PURB Urb;
|
|
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
/* grab interface descriptor */
|
|
|
|
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
|
|
|
|
if (!InterfaceDescriptor)
|
|
|
|
{
|
|
|
|
/* no such interface */
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2016-09-29 22:19:34 +00:00
|
|
|
/* FIXME selects the first interface with audio streaming and non zero num of endpoints */
|
2016-09-28 20:31:32 +00:00
|
|
|
while (InterfaceDescriptor != NULL)
|
|
|
|
{
|
|
|
|
if (InterfaceDescriptor->bInterfaceSubClass == 0x02 /* AUDIO_STREAMING */ && InterfaceDescriptor->bNumEndpoints > 0)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!InterfaceDescriptor)
|
|
|
|
{
|
|
|
|
/* no such interface */
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
Urb = AllocFunction(GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints));
|
|
|
|
if (!Urb)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
return USBD_STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* now prepare interface urb */
|
|
|
|
UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
|
|
|
|
|
|
|
|
/* copy interface information */
|
|
|
|
RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInfo, DeviceExtension->InterfaceInfo->Length);
|
|
|
|
|
|
|
|
/* now select the interface */
|
|
|
|
Status = SubmitUrbSync(DeviceExtension->LowerDevice, Urb);
|
|
|
|
|
|
|
|
DPRINT1("USBAudioSelectAudioStreamingInterface Status %x UrbStatus %x\n", Status, Urb->UrbSelectInterface.Hdr.Status);
|
|
|
|
|
|
|
|
/* did it succeeed */
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* update configuration info */
|
|
|
|
ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInfo->Length);
|
|
|
|
RtlCopyMemory(DeviceExtension->InterfaceInfo, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
|
2016-09-29 22:19:34 +00:00
|
|
|
PinContext->InterfaceDescriptor = InterfaceDescriptor;
|
2016-09-28 20:31:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* free urb */
|
|
|
|
FreeFunction(Urb);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
InitCapturePin(
|
|
|
|
IN PKSPIN Pin)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2016-09-29 22:19:34 +00:00
|
|
|
ULONG Index;
|
|
|
|
ULONG BufferSize;
|
|
|
|
ULONG MaximumPacketSize;
|
|
|
|
PIRP Irp;
|
|
|
|
PURB Urb;
|
|
|
|
PPIN_CONTEXT PinContext;
|
|
|
|
PIO_STACK_LOCATION IoStack;
|
2016-09-28 20:31:32 +00:00
|
|
|
|
|
|
|
/* set sample rate */
|
|
|
|
Status = UsbAudioSetFormat(Pin);
|
2016-09-29 22:19:34 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* failed */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get pin context */
|
|
|
|
PinContext = Pin->Context;
|
|
|
|
DbgBreakPoint();
|
|
|
|
MaximumPacketSize = GetMaxPacketSizeForInterface(PinContext->DeviceExtension->ConfigurationDescriptor, PinContext->InterfaceDescriptor, Pin->DataFlow);
|
|
|
|
|
|
|
|
/* calculate buffer size 8 irps * 10 iso packets * max packet size */
|
|
|
|
BufferSize = 8 * 10 * MaximumPacketSize;
|
|
|
|
|
|
|
|
/* allocate pin capture buffer */
|
|
|
|
PinContext->Buffer = AllocFunction(BufferSize);
|
|
|
|
if (!PinContext->Buffer)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
KsAddItemToObjectBag(Pin->Bag, PinContext->Buffer, ExFreePool);
|
|
|
|
|
|
|
|
/* init irps */
|
|
|
|
for (Index = 0; Index < 8; Index++)
|
|
|
|
{
|
|
|
|
/* allocate irp */
|
|
|
|
Irp = IoAllocateIrp(PinContext->DeviceExtension->LowerDevice->StackSize, FALSE);
|
|
|
|
if (!Irp)
|
|
|
|
{
|
|
|
|
/* no memory */
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* insert into irp list */
|
|
|
|
InsertTailList(&PinContext->IrpListHead, &Irp->Tail.Overlay.ListEntry);
|
2016-09-28 20:31:32 +00:00
|
|
|
|
2016-09-29 22:19:34 +00:00
|
|
|
/* add to object bag*/
|
|
|
|
KsAddItemToObjectBag(Pin->Bag, Irp, IoFreeIrp);
|
|
|
|
|
|
|
|
Status = UsbAudioAllocCaptureUrbIso(PinContext->DeviceExtension->InterfaceInfo->Pipes[0].PipeHandle,
|
|
|
|
MaximumPacketSize,
|
|
|
|
&PinContext->Buffer[MaximumPacketSize * 10 * Index],
|
|
|
|
MaximumPacketSize * 10,
|
|
|
|
&Urb);
|
|
|
|
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* get next stack location */
|
|
|
|
IoStack = IoGetNextIrpStackLocation(Irp);
|
|
|
|
|
|
|
|
/* store urb */
|
|
|
|
IoStack->Parameters.Others.Argument1 = Urb;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* failed */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
2016-09-28 20:31:32 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
InitStreamPin(
|
|
|
|
IN PKSPIN Pin)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2016-09-24 08:35:25 +00:00
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinCreate(
|
|
|
|
_In_ PKSPIN Pin,
|
|
|
|
_In_ PIRP Irp)
|
|
|
|
{
|
2016-09-27 19:20:00 +00:00
|
|
|
PKSFILTER Filter;
|
|
|
|
PFILTER_CONTEXT FilterContext;
|
|
|
|
PPIN_CONTEXT PinContext;
|
2016-09-28 20:31:32 +00:00
|
|
|
NTSTATUS Status;
|
2016-09-27 19:20:00 +00:00
|
|
|
|
|
|
|
Filter = KsPinGetParentFilter(Pin);
|
|
|
|
if (Filter == NULL)
|
|
|
|
{
|
|
|
|
/* invalid parameter */
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* get filter context */
|
|
|
|
FilterContext = Filter->Context;
|
|
|
|
|
|
|
|
/* allocate pin context */
|
|
|
|
PinContext = AllocFunction(sizeof(PIN_CONTEXT));
|
|
|
|
if (!PinContext)
|
|
|
|
{
|
|
|
|
/* no memory*/
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* init pin context */
|
|
|
|
PinContext->DeviceExtension = FilterContext->DeviceExtension;
|
|
|
|
PinContext->LowerDevice = FilterContext->LowerDevice;
|
2016-09-29 22:19:34 +00:00
|
|
|
InitializeListHead(&PinContext->IrpListHead);
|
2016-09-27 19:20:00 +00:00
|
|
|
|
|
|
|
/* store pin context*/
|
|
|
|
Pin->Context = PinContext;
|
|
|
|
|
2016-09-28 20:31:32 +00:00
|
|
|
/* select streaming interface */
|
2016-09-29 22:19:34 +00:00
|
|
|
Status = USBAudioSelectAudioStreamingInterface(PinContext, PinContext->DeviceExtension, PinContext->DeviceExtension->ConfigurationDescriptor);
|
2016-09-28 20:31:32 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* failed */
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Pin->DataFlow == KSPIN_DATAFLOW_OUT)
|
|
|
|
{
|
|
|
|
/* init capture pin */
|
|
|
|
Status = InitCapturePin(Pin);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* audio streaming pin*/
|
|
|
|
Status = InitStreamPin(Pin);
|
|
|
|
}
|
|
|
|
|
2016-09-24 08:35:25 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinClose(
|
|
|
|
_In_ PKSPIN Pin,
|
|
|
|
_In_ PIRP Irp)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinProcess(
|
|
|
|
_In_ PKSPIN Pin)
|
|
|
|
{
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinReset(
|
|
|
|
_In_ PKSPIN Pin)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinSetDataFormat(
|
|
|
|
_In_ PKSPIN Pin,
|
|
|
|
_In_opt_ PKSDATAFORMAT OldFormat,
|
|
|
|
_In_opt_ PKSMULTIPLE_ITEM OldAttributeList,
|
|
|
|
_In_ const KSDATARANGE* DataRange,
|
|
|
|
_In_opt_ const KSATTRIBUTE_LIST* AttributeRange)
|
|
|
|
{
|
2016-09-28 20:31:32 +00:00
|
|
|
if (OldFormat == NULL)
|
2016-09-27 19:20:00 +00:00
|
|
|
{
|
2016-09-28 20:31:32 +00:00
|
|
|
/* TODO: verify connection format */
|
|
|
|
UNIMPLEMENTED
|
|
|
|
return STATUS_SUCCESS;
|
2016-09-27 19:20:00 +00:00
|
|
|
}
|
2016-09-24 08:35:25 +00:00
|
|
|
|
2016-09-28 20:31:32 +00:00
|
|
|
return UsbAudioSetFormat(Pin);
|
2016-09-27 19:20:00 +00:00
|
|
|
}
|
2016-09-24 08:35:25 +00:00
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
NTAPI
|
|
|
|
USBAudioPinSetDeviceState(
|
|
|
|
_In_ PKSPIN Pin,
|
|
|
|
_In_ KSSTATE ToState,
|
|
|
|
_In_ KSSTATE FromState)
|
|
|
|
{
|
|
|
|
UNIMPLEMENTED
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|