/* * PROJECT: ReactOS Universal Audio Class Driver * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/usbaudio/filter.c * PURPOSE: USB Audio device driver. * PROGRAMMERS: * Johannes Anderwald (johannes.anderwald@reactos.org) */ #include "usbaudio.h" GUID NodeTypeMicrophone = { STATIC_KSNODETYPE_MICROPHONE }; GUID NodeTypeDesktopMicrophone = { STATIC_KSNODETYPE_DESKTOP_MICROPHONE }; GUID NodeTypePersonalMicrophone = { STATIC_KSNODETYPE_PERSONAL_MICROPHONE }; GUID NodeTypeOmmniMicrophone = { STATIC_KSNODETYPE_OMNI_DIRECTIONAL_MICROPHONE }; GUID NodeTypeArrayMicrophone = { STATIC_KSNODETYPE_MICROPHONE_ARRAY }; GUID NodeTypeProcessingArrayMicrophone = { STATIC_KSNODETYPE_PROCESSING_MICROPHONE_ARRAY }; GUID NodeTypeSpeaker = { STATIC_KSNODETYPE_SPEAKER }; GUID NodeTypeHeadphonesSpeaker = { STATIC_KSNODETYPE_HEADPHONES }; GUID NodeTypeHMDA = { STATIC_KSNODETYPE_HEAD_MOUNTED_DISPLAY_AUDIO }; GUID NodeTypeDesktopSpeaker = { STATIC_KSNODETYPE_DESKTOP_SPEAKER }; GUID NodeTypeRoomSpeaker = { STATIC_KSNODETYPE_ROOM_SPEAKER }; GUID NodeTypeCommunicationSpeaker = { STATIC_KSNODETYPE_COMMUNICATION_SPEAKER }; GUID NodeTypeSubwoofer = { STATIC_KSNODETYPE_LOW_FREQUENCY_EFFECTS_SPEAKER }; GUID NodeTypeCapture = { STATIC_PINNAME_CAPTURE }; GUID NodeTypePlayback = { STATIC_KSCATEGORY_AUDIO }; GUID GUID_KSCATEGORY_AUDIO = { STATIC_KSCATEGORY_AUDIO }; KSPIN_INTERFACE StandardPinInterface = { {STATIC_KSINTERFACESETID_Standard}, KSINTERFACE_STANDARD_STREAMING, 0 }; KSPIN_MEDIUM StandardPinMedium = { {STATIC_KSMEDIUMSETID_Standard}, KSMEDIUM_TYPE_ANYINSTANCE, 0 }; KSDATARANGE BridgePinAudioFormat[] = { { { sizeof(KSDATAFORMAT), 0, 0, 0, {STATIC_KSDATAFORMAT_TYPE_AUDIO}, {STATIC_KSDATAFORMAT_SUBTYPE_ANALOG}, {STATIC_KSDATAFORMAT_SPECIFIER_NONE} } } }; static PKSDATARANGE BridgePinAudioFormats[] = { &BridgePinAudioFormat[0] }; static LPWSTR ReferenceString = L"global"; NTSTATUS NTAPI USBAudioFilterCreate( PKSFILTER Filter, PIRP Irp); static KSFILTER_DISPATCH USBAudioFilterDispatch = { USBAudioFilterCreate, NULL, NULL, NULL }; static KSPIN_DISPATCH UsbAudioPinDispatch = { USBAudioPinCreate, USBAudioPinClose, USBAudioPinProcess, USBAudioPinReset, USBAudioPinSetDataFormat, USBAudioPinSetDeviceState, NULL, NULL, NULL, NULL }; NTSTATUS NTAPI FilterAudioVolumeHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data); NTSTATUS NTAPI FilterAudioMuteHandler(IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data); DEFINE_KSPROPERTY_TABLE_AUDIO_VOLUME(FilterAudioVolumePropertySet, FilterAudioVolumeHandler); DEFINE_KSPROPERTY_TABLE_AUDIO_MUTE(FilterAudioMutePropertySet, FilterAudioMuteHandler); static KSPROPERTY_SET FilterAudioVolumePropertySetArray[] = { { &KSPROPSETID_Audio, sizeof(FilterAudioVolumePropertySet) / sizeof(KSPROPERTY_ITEM), (const KSPROPERTY_ITEM*)&FilterAudioVolumePropertySet, 0, NULL } }; static KSPROPERTY_SET FilterAudioMutePropertySetArray[] = { { &KSPROPSETID_Audio, sizeof(FilterAudioMutePropertySet) / sizeof(KSPROPERTY_ITEM), (const KSPROPERTY_ITEM*)&FilterAudioMutePropertySet, 0, NULL } }; NTSTATUS UsbAudioGetSetProperty( IN PDEVICE_OBJECT DeviceObject, IN UCHAR Request, IN USHORT Value, IN USHORT Index, IN PVOID TransferBuffer, IN ULONG TransferBufferLength, IN ULONG TransferFlags) { PURB Urb; NTSTATUS Status; /* allocate urb */ Urb = AllocFunction(sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST)); if (!Urb) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } /* format urb */ UsbBuildVendorRequest(Urb, URB_FUNCTION_CLASS_INTERFACE, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST), TransferFlags, 0, Request, Value, Index, TransferBuffer, NULL, TransferBufferLength, NULL); /* submit urb */ Status = SubmitUrbSync(DeviceObject, Urb); FreeFunction(Urb); return Status; } PNODE_CONTEXT FindNodeContextWithNode( IN PNODE_CONTEXT NodeContext, IN ULONG NodeContextCount, IN ULONG NodeId) { ULONG Index, NodeIndex; for (Index = 0; Index < NodeContextCount; Index++) { for (NodeIndex = 0; NodeIndex < NodeContext[Index].NodeCount; NodeIndex++) { if (NodeContext[Index].Nodes[NodeIndex] == NodeId) { return &NodeContext[Index]; } } } return NULL; } NTSTATUS NTAPI FilterAudioMuteHandler( IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data) { PKSNODEPROPERTY_AUDIO_CHANNEL Property; PKSFILTER Filter; PFILTER_CONTEXT FilterContext; PNODE_CONTEXT NodeContext; PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor; NTSTATUS Status = STATUS_INVALID_PARAMETER; /* get filter from irp */ Filter = KsGetFilterFromIrp(Irp); if (Filter) { /* get property */ Property = (PKSNODEPROPERTY_AUDIO_CHANNEL)Request; /* get filter context */ FilterContext = (PFILTER_CONTEXT)Filter->Context; /* search for node context */ NodeContext = FindNodeContextWithNode(FilterContext->DeviceExtension->NodeContext, FilterContext->DeviceExtension->NodeContextCount, Property->NodeProperty.NodeId); if (NodeContext) { FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)NodeContext->Descriptor; if (Property->NodeProperty.Property.Flags & KSPROPERTY_TYPE_GET) { Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x81, 0x1 << 8, FeatureUnitDescriptor->bUnitID << 8, Data, 1, USBD_TRANSFER_DIRECTION_IN); Irp->IoStatus.Information = sizeof(BOOL); } else { Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x01, 0x1 << 8, FeatureUnitDescriptor->bUnitID << 8, Data, 1, USBD_TRANSFER_DIRECTION_OUT); } } } return Status; } NTSTATUS NTAPI FilterAudioVolumeHandler( IN PIRP Irp, IN PKSIDENTIFIER Request, IN OUT PVOID Data) { PKSNODEPROPERTY_AUDIO_CHANNEL Property; PKSFILTER Filter; PFILTER_CONTEXT FilterContext; PNODE_CONTEXT NodeContext; PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor; PSHORT TransferBuffer; LONG Value; NTSTATUS Status = STATUS_INVALID_PARAMETER; /* get filter from irp */ Filter = KsGetFilterFromIrp(Irp); if (Filter) { /* get property */ Property = (PKSNODEPROPERTY_AUDIO_CHANNEL)Request; /* get filter context */ FilterContext = (PFILTER_CONTEXT)Filter->Context; TransferBuffer = AllocFunction(sizeof(USHORT) * 3); ASSERT(TransferBuffer); Value = *(PLONG)Data; /* search for node context */ NodeContext = FindNodeContextWithNode(FilterContext->DeviceExtension->NodeContext, FilterContext->DeviceExtension->NodeContextCount, Property->NodeProperty.NodeId); if (NodeContext) { FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)NodeContext->Descriptor; if (Property->NodeProperty.Property.Flags & KSPROPERTY_TYPE_GET) { Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x81, 0x2 << 8, FeatureUnitDescriptor->bUnitID << 8, &TransferBuffer[0], sizeof(USHORT), USBD_TRANSFER_DIRECTION_IN); Value = (LONG)TransferBuffer[0] * 256; *(PLONG)Data = Value; Irp->IoStatus.Information = sizeof(BOOL); } else { /* downscale value */ Value /= 256; /* get minimum value */ UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x82, 0x2 << 8, FeatureUnitDescriptor->bUnitID << 8, &TransferBuffer[0], sizeof(USHORT), USBD_TRANSFER_DIRECTION_IN); /* get maximum value */ UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x83, 0x2 << 8, FeatureUnitDescriptor->bUnitID << 8, &TransferBuffer[1], sizeof(USHORT), USBD_TRANSFER_DIRECTION_IN); if (TransferBuffer[0] > Value) { /* use minimum value */ Value = TransferBuffer[0]; } if (TransferBuffer[1] < Value) { /* use maximum value */ Value = TransferBuffer[1]; } /* store value */ TransferBuffer[2] = Value; /* set volume request */ Status = UsbAudioGetSetProperty(FilterContext->DeviceExtension->LowerDevice, 0x01, 0x2 << 8, FeatureUnitDescriptor->bUnitID << 8, &TransferBuffer[2], sizeof(USHORT), USBD_TRANSFER_DIRECTION_OUT); if (NT_SUCCESS(Status)) { /* store number of bytes transferred*/ Irp->IoStatus.Information = sizeof(LONG); } } } /* free transfer buffer */ FreeFunction(TransferBuffer); } return Status; } ULONG CountTopologyComponents( IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, OUT PULONG OutDescriptorCount) { PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor; PUSB_COMMON_DESCRIPTOR CommonDescriptor; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor; PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor; PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR MixerUnitDescriptor; ULONG NodeCount = 0, Length, Index; ULONG DescriptorCount = 0; UCHAR Value; for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { NodeCount++; DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/) { FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)InputTerminalDescriptor; DescriptorCount++; /* get controls from all channels*/ Value = 0; Length = FeatureUnitDescriptor->bLength - 7; for (Index = 0; Index < Length; Index++) { Value |= FeatureUnitDescriptor->bmaControls[Index]; } if (Value & 0x01) /* MUTE*/ NodeCount++; if (Value & 0x02) /* VOLUME */ NodeCount++; if (Value & 0x04) /* BASS */ NodeCount++; if (Value & 0x08) /* MID */ NodeCount++; if (Value & 0x10) /* TREBLE */ NodeCount++; if (Value & 0x20) /* GRAPHIC EQUALIZER */ NodeCount++; if (Value & 0x40) /* AUTOMATIC GAIN */ NodeCount++; if (Value & 0x80) /* DELAY */ NodeCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */) { MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)InputTerminalDescriptor; DescriptorCount++; NodeCount += MixerUnitDescriptor->bNrInPins + 1; /* KSNODETYPE_SUPERMIX for each source pin and KSNODETYPE_SUM for target */ } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x05 /* SELECTOR_UNIT */) { DescriptorCount++; NodeCount++; } else { UNIMPLEMENTED; } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } } *OutDescriptorCount = DescriptorCount; return NodeCount; } PNODE_CONTEXT FindNodeContextWithId( IN PNODE_CONTEXT NodeContext, IN ULONG NodeContextCount, IN UCHAR TerminalId) { ULONG Index; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor; for (Index = 0; Index < NodeContextCount; Index++) { TerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)NodeContext[Index].Descriptor; if (TerminalDescriptor->bTerminalID == TerminalId) return &NodeContext[Index]; } return NULL; } NTSTATUS BuildUSBAudioFilterTopology( PKSDEVICE Device, PKSFILTER_DESCRIPTOR FilterDescriptor) { PDEVICE_EXTENSION DeviceExtension; ULONG NodeCount, Index, DescriptorCount, StreamingTerminalIndex, NonStreamingTerminalDescriptorCount, TotalTerminalDescriptorCount, StreamingTerminalPinOffset, ControlDescriptorCount, Length; UCHAR Value; PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor; PUSB_COMMON_DESCRIPTOR CommonDescriptor; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor; PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR FeatureUnitDescriptor; PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR MixerUnitDescriptor; PUSB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR OutputTerminalDescriptor; PUSB_AUDIO_CONTROL_SELECTOR_UNIT_DESCRIPTOR SelectorUnitDescriptor; PKSNODE_DESCRIPTOR NodeDescriptors; PNODE_CONTEXT NodeContext, PreviousNodeContext; PKSTOPOLOGY_CONNECTION Connections; PKSAUTOMATION_TABLE AutomationTable; /* get device extension */ DeviceExtension = Device->Context; /* count topology nodes */ NodeCount = CountTopologyComponents(DeviceExtension->ConfigurationDescriptor, &ControlDescriptorCount); /* init node descriptors*/ FilterDescriptor->NodeDescriptors = NodeDescriptors = AllocFunction(NodeCount * sizeof(KSNODE_DESCRIPTOR)); if (FilterDescriptor->NodeDescriptors == NULL) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } FilterDescriptor->NodeDescriptorSize = sizeof(KSNODE_DESCRIPTOR); DeviceExtension->NodeContext = NodeContext = AllocFunction(sizeof(NODE_CONTEXT) * ControlDescriptorCount); if (!NodeContext) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } DeviceExtension->NodeContextCount = ControlDescriptorCount; DescriptorCount = 0; /* first enumerate all topology nodes */ for (Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SRC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SRC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x200) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_ADC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_ADC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x300) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_DAC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_DAC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else { DPRINT1("Unexpected input terminal type %x\n", InputTerminalDescriptor->wTerminalType); } } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SRC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SRC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else if ((InputTerminalDescriptor->wTerminalType & 0xFF00) == 0x300) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_DAC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_DAC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else { DPRINT1("Unexpected output terminal type %x\n", InputTerminalDescriptor->wTerminalType); } } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/) { FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)CommonDescriptor; /* get controls from all channels*/ Value = 0; Length = FeatureUnitDescriptor->bLength - 7; for (Index = 0; Index < Length; Index++) { Value |= FeatureUnitDescriptor->bmaControls[Index]; } if (Value & 0x01) /* MUTE*/ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_MUTE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_MUTE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); if (AutomationTable) { AutomationTable->PropertySets = FilterAudioMutePropertySetArray; AutomationTable->PropertySetsCount = 1; AutomationTable->PropertyItemSize = sizeof(KSPROPERTY_ITEM); } /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x02) /* VOLUME */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_VOLUME; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_VOLUME; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); if (AutomationTable) { AutomationTable->PropertySets = FilterAudioVolumePropertySetArray; AutomationTable->PropertySetsCount = 1; AutomationTable->PropertyItemSize = sizeof(KSPROPERTY_ITEM); } /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x04) /* BASS */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x08) /* MID */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x10) /* TREBLE */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x20) /* GRAPHIC EQUALIZER */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x40) /* AUTOMATIC GAIN */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_AGC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_AGC; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } if (Value & 0x80) /* DELAY */ { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_TONE; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } NodeContext[DescriptorCount].Descriptor = CommonDescriptor; DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */) { MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)CommonDescriptor; for (Index = 0; Index < MixerUnitDescriptor->bNrInPins; Index++) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SUPERMIX; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SUPERMIX; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; FilterDescriptor->NodeDescriptorsCount++; } NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_SUM; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_SUM; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount] = FilterDescriptor->NodeDescriptorsCount; NodeContext[DescriptorCount].NodeCount++; NodeContext[DescriptorCount].Descriptor = CommonDescriptor; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x05 /* SELECTOR UNIT */) { NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Type = &KSNODETYPE_MUX; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].Name = &KSNODETYPE_MUX; NodeDescriptors[FilterDescriptor->NodeDescriptorsCount].AutomationTable = AllocFunction(sizeof(KSAUTOMATION_TABLE)); /* insert into node context*/ NodeContext[DescriptorCount].Descriptor = CommonDescriptor; NodeContext[DescriptorCount].NodeCount = 1; NodeContext[DescriptorCount].Nodes[0] = FilterDescriptor->NodeDescriptorsCount; DescriptorCount++; FilterDescriptor->NodeDescriptorsCount++; } else { UNIMPLEMENTED; } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } } /* FIXME determine connections count*/ FilterDescriptor->Connections = Connections = AllocFunction(sizeof(KSTOPOLOGY_CONNECTION) * FilterDescriptor->NodeDescriptorsCount * 2); if (!FilterDescriptor->Connections) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } FilterDescriptor->ConnectionsCount = 0; /* now build connections array */ DescriptorCount = 0; StreamingTerminalIndex = 0; NodeCount = 0; CountTerminalUnits(DeviceExtension->ConfigurationDescriptor, &NonStreamingTerminalDescriptorCount, &TotalTerminalDescriptorCount); StreamingTerminalPinOffset = TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount; for (Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(DeviceExtension->ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(DeviceExtension->ConfigurationDescriptor, DeviceExtension->ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { Connections[FilterDescriptor->ConnectionsCount].FromNode = KSFILTER_NODE; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = StreamingTerminalIndex; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0]; FilterDescriptor->ConnectionsCount++; StreamingTerminalIndex++; } else { Connections[FilterDescriptor->ConnectionsCount].FromNode = KSFILTER_NODE; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = StreamingTerminalPinOffset; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0]; FilterDescriptor->ConnectionsCount++; StreamingTerminalPinOffset++; } DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { OutputTerminalDescriptor = (PUSB_AUDIO_CONTROL_OUTPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, OutputTerminalDescriptor->bSourceID); if (PreviousNodeContext) { Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount - 1]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0]; FilterDescriptor->ConnectionsCount++; } if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[0]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = StreamingTerminalIndex; Connections[FilterDescriptor->ConnectionsCount].ToNode = KSFILTER_NODE; FilterDescriptor->ConnectionsCount++; StreamingTerminalIndex++; } else { Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[0]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = StreamingTerminalPinOffset; Connections[FilterDescriptor->ConnectionsCount].ToNode = KSFILTER_NODE; FilterDescriptor->ConnectionsCount++; StreamingTerminalPinOffset++; } DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x06 /* FEATURE_UNIT*/) { FeatureUnitDescriptor = (PUSB_AUDIO_CONTROL_FEATURE_UNIT_DESCRIPTOR)InputTerminalDescriptor; PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, FeatureUnitDescriptor->bSourceID); if (PreviousNodeContext) { Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount-1]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0]; FilterDescriptor->ConnectionsCount++; } for (Index = 1; Index < NodeContext[DescriptorCount].NodeCount; Index++) { Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[Index - 1]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[Index]; FilterDescriptor->ConnectionsCount++; } DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x04 /* MIXER_UNIT */) { MixerUnitDescriptor = (PUSB_AUDIO_CONTROL_MIXER_UNIT_DESCRIPTOR)InputTerminalDescriptor; for (Index = 0; Index < MixerUnitDescriptor->bNrInPins; Index++) { Value = MixerUnitDescriptor->baSourceID[Index]; PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, Value); if (PreviousNodeContext) { Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount - 1]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[Index]; FilterDescriptor->ConnectionsCount++; } Connections[FilterDescriptor->ConnectionsCount].FromNode = NodeContext[DescriptorCount].Nodes[Index]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1 + Index; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[NodeContext[DescriptorCount].NodeCount-1]; FilterDescriptor->ConnectionsCount++; } DescriptorCount++; } else if (InputTerminalDescriptor->bDescriptorSubtype == 0x05 /* SELECTOR_UNIT */) { SelectorUnitDescriptor = (PUSB_AUDIO_CONTROL_SELECTOR_UNIT_DESCRIPTOR)InputTerminalDescriptor; for (Index = 0; Index < SelectorUnitDescriptor->bNrInPins; Index++) { Value = SelectorUnitDescriptor->baSourceID[Index]; PreviousNodeContext = FindNodeContextWithId(NodeContext, ControlDescriptorCount, Value); if (PreviousNodeContext) { Connections[FilterDescriptor->ConnectionsCount].FromNode = PreviousNodeContext->Nodes[PreviousNodeContext->NodeCount - 1]; Connections[FilterDescriptor->ConnectionsCount].FromNodePin = 0; Connections[FilterDescriptor->ConnectionsCount].ToNodePin = 1; Connections[FilterDescriptor->ConnectionsCount].ToNode = NodeContext[DescriptorCount].Nodes[0]; FilterDescriptor->ConnectionsCount++; } } DescriptorCount++; } else { UNIMPLEMENTED; } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } } return STATUS_SUCCESS; } NTSTATUS NTAPI USBAudioFilterCreate( PKSFILTER Filter, PIRP Irp) { PKSFILTERFACTORY FilterFactory; PKSDEVICE Device; PFILTER_CONTEXT FilterContext; FilterFactory = KsGetParent(Filter); if (FilterFactory == NULL) { /* invalid parameter */ return STATUS_INVALID_PARAMETER; } Device = KsGetParent(FilterFactory); if (Device == NULL) { /* invalid parameter */ return STATUS_INVALID_PARAMETER; } /* alloc filter context */ FilterContext = AllocFunction(sizeof(FILTER_CONTEXT)); if (FilterContext == NULL) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } /* init context */ FilterContext->DeviceExtension = Device->Context; FilterContext->LowerDevice = Device->NextDeviceObject; Filter->Context = FilterContext; DPRINT("USBAudioFilterCreate FilterContext %p LowerDevice %p DeviceExtension %p\n", FilterContext, FilterContext->LowerDevice, FilterContext->DeviceExtension); KsAddItemToObjectBag(Filter->Bag, FilterContext, ExFreePool); return STATUS_SUCCESS; } VOID NTAPI CountTerminalUnits( IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, OUT PULONG NonStreamingTerminalDescriptorCount, OUT PULONG TotalTerminalDescriptorCount) { PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor; PUSB_COMMON_DESCRIPTOR CommonDescriptor; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor; ULONG NonStreamingTerminalCount = 0; ULONG TotalTerminalCount = 0; for(Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType != USB_AUDIO_STREAMING_TERMINAL_TYPE) { NonStreamingTerminalCount++; } TotalTerminalCount++; } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } else if (Descriptor->bInterfaceSubClass == 0x03) /* MIDI_STREAMING */ { UNIMPLEMENTED; } } *NonStreamingTerminalDescriptorCount = NonStreamingTerminalCount; *TotalTerminalDescriptorCount = TotalTerminalCount; } LPGUID UsbAudioGetPinCategoryFromTerminalDescriptor( IN PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor) { if (TerminalDescriptor->wTerminalType == USB_AUDIO_MICROPHONE_TERMINAL_TYPE) return &NodeTypeMicrophone; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_MICROPHONE_TERMINAL_TYPE) return &NodeTypeDesktopMicrophone; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_PERSONAL_MICROPHONE_TERMINAL_TYPE) return &NodeTypePersonalMicrophone; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_OMMNI_MICROPHONE_TERMINAL_TYPE) return &NodeTypeOmmniMicrophone; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_MICROPHONE_TERMINAL_TYPE) return &NodeTypeArrayMicrophone; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ARRAY_PROCESSING_MICROPHONE_TERMINAL_TYPE) return &NodeTypeProcessingArrayMicrophone; /* playback types */ if (TerminalDescriptor->wTerminalType == USB_AUDIO_SPEAKER_TERMINAL_TYPE) return &NodeTypeSpeaker; else if (TerminalDescriptor->wTerminalType == USB_HEADPHONES_SPEAKER_TERMINAL_TYPE) return &NodeTypeHeadphonesSpeaker; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_HMDA_TERMINAL_TYPE) return &NodeTypeHMDA; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_DESKTOP_SPEAKER_TERMINAL_TYPE) return &NodeTypeDesktopSpeaker; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_ROOM_SPEAKER_TERMINAL_TYPE) return &NodeTypeRoomSpeaker; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_COMMUNICATION_SPEAKER_TERMINAL_TYPE) return &NodeTypeCommunicationSpeaker; else if (TerminalDescriptor->wTerminalType == USB_AUDIO_SUBWOOFER_TERMINAL_TYPE) return &NodeTypeSubwoofer; if (TerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL) return &NodeTypeCapture; else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL) return &NodeTypePlayback; } return NULL; } PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR UsbAudioGetStreamingTerminalDescriptorByIndex( IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN ULONG Index) { PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor; PUSB_COMMON_DESCRIPTOR CommonDescriptor; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor; ULONG TerminalCount = 0; for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType == USB_AUDIO_STREAMING_TERMINAL_TYPE) { if (TerminalCount == Index) { return InputTerminalDescriptor; } TerminalCount++; } } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } } return NULL; } PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR UsbAudioGetNonStreamingTerminalDescriptorByIndex( IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN ULONG Index) { PUSB_INTERFACE_DESCRIPTOR Descriptor; PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR InterfaceHeaderDescriptor; PUSB_COMMON_DESCRIPTOR CommonDescriptor; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR InputTerminalDescriptor; ULONG TerminalCount = 0; for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x01) /* AUDIO_CONTROL */ { InterfaceHeaderDescriptor = (PUSB_AUDIO_CONTROL_INTERFACE_HEADER_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (InterfaceHeaderDescriptor != NULL) { CommonDescriptor = USBD_ParseDescriptors(InterfaceHeaderDescriptor, InterfaceHeaderDescriptor->wTotalLength, (PVOID)((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->bLength), USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); while (CommonDescriptor) { InputTerminalDescriptor = (PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR)CommonDescriptor; if (InputTerminalDescriptor->bDescriptorSubtype == 0x02 /* INPUT TERMINAL*/ || InputTerminalDescriptor->bDescriptorSubtype == 0x03 /* OUTPUT_TERMINAL*/) { if (InputTerminalDescriptor->wTerminalType != USB_AUDIO_STREAMING_TERMINAL_TYPE) { if (TerminalCount == Index) { return InputTerminalDescriptor; } TerminalCount++; } } CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength); if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)InterfaceHeaderDescriptor + InterfaceHeaderDescriptor->wTotalLength)) break; } } } } return NULL; } VOID UsbAudioGetDataRanges( IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, IN UCHAR bTerminalID, OUT PKSDATARANGE** OutDataRanges, OUT PULONG OutDataRangesCount) { PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR StreamingInterfaceDescriptor; PUSB_AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR StreamingFormatDescriptor; PUSB_INTERFACE_DESCRIPTOR Descriptor; PKSDATARANGE_AUDIO DataRangeAudio; PKSDATARANGE *DataRangeAudioArray; ULONG NumFrequency, DataRangeCount, DataRangeIndex, Index; /* count all data ranges */ DataRangeCount = 0; for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x02) /* AUDIO_STREAMING */ { StreamingInterfaceDescriptor = (PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (StreamingInterfaceDescriptor != NULL) { ASSERT(StreamingInterfaceDescriptor->bDescriptorSubtype == 0x01); ASSERT(StreamingInterfaceDescriptor->wFormatTag == WAVE_FORMAT_PCM); if (StreamingInterfaceDescriptor->bTerminalLink == bTerminalID) { DataRangeCount++; DPRINT1("StreamingInterfaceDescriptor %p TerminalID %x\n", StreamingInterfaceDescriptor, bTerminalID); } } Descriptor = (PUSB_INTERFACE_DESCRIPTOR)StreamingInterfaceDescriptor; } } DataRangeAudioArray = AllocFunction(sizeof(PVOID) * DataRangeCount); if (DataRangeAudioArray == NULL) { /* no memory */ return; } DataRangeIndex = 0; for (Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1); Descriptor != NULL; Descriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, (PVOID)((ULONG_PTR)Descriptor + Descriptor->bLength), -1, -1, USB_DEVICE_CLASS_AUDIO, -1, -1)) { if (Descriptor->bInterfaceSubClass == 0x02) /* AUDIO_STREAMING */ { StreamingInterfaceDescriptor = (PUSB_AUDIO_STREAMING_INTERFACE_DESCRIPTOR)USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, Descriptor, USB_AUDIO_CONTROL_TERMINAL_DESCRIPTOR_TYPE); if (StreamingInterfaceDescriptor != NULL) { ASSERT(StreamingInterfaceDescriptor->bDescriptorSubtype == 0x01); ASSERT(StreamingInterfaceDescriptor->wFormatTag == WAVE_FORMAT_PCM); if (StreamingInterfaceDescriptor->bTerminalLink == bTerminalID) { StreamingFormatDescriptor = (PUSB_AUDIO_STREAMING_FORMAT_TYPE_DESCRIPTOR)((ULONG_PTR)StreamingInterfaceDescriptor + StreamingInterfaceDescriptor->bLength); ASSERT(StreamingFormatDescriptor->bDescriptorType == 0x24); ASSERT(StreamingFormatDescriptor->bDescriptorSubtype == 0x02); ASSERT(StreamingFormatDescriptor->bFormatType == 0x01); DataRangeAudio = AllocFunction(sizeof(KSDATARANGE_AUDIO)); if (DataRangeAudio == NULL) { /* no memory*/ return; } DataRangeAudio->DataRange.FormatSize = sizeof(KSDATARANGE_AUDIO); DataRangeAudio->DataRange.MajorFormat = KSDATAFORMAT_TYPE_AUDIO; DataRangeAudio->DataRange.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; DataRangeAudio->DataRange.Specifier = KSDATAFORMAT_SPECIFIER_WAVEFORMATEX; DataRangeAudio->MaximumChannels = StreamingFormatDescriptor->bNrChannels; DataRangeAudio->MinimumBitsPerSample = StreamingFormatDescriptor->bBitResolution; DataRangeAudio->MaximumBitsPerSample = StreamingFormatDescriptor->bBitResolution; NumFrequency = StreamingFormatDescriptor->bSamFreqType; DataRangeAudio->MinimumSampleFrequency = MAXULONG; DataRangeAudio->MaximumSampleFrequency = 0; for (Index = 0; Index < NumFrequency; Index++) { DataRangeAudio->MinimumSampleFrequency = min(StreamingFormatDescriptor->tSamFreq[Index * 3] | StreamingFormatDescriptor->tSamFreq[(Index * 3) + 1] << 8 | StreamingFormatDescriptor->tSamFreq[(Index * 3) + 2] << 16, DataRangeAudio->MinimumSampleFrequency); DataRangeAudio->MaximumSampleFrequency = max(StreamingFormatDescriptor->tSamFreq[Index * 3] | StreamingFormatDescriptor->tSamFreq[(Index * 3) + 1] << 8 | StreamingFormatDescriptor->tSamFreq[(Index * 3) + 2] << 16, DataRangeAudio->MaximumSampleFrequency); } DataRangeAudioArray[DataRangeIndex] = (PKSDATARANGE)DataRangeAudio; DataRangeIndex++; } } Descriptor = (PUSB_INTERFACE_DESCRIPTOR)StreamingInterfaceDescriptor; } } *OutDataRanges = DataRangeAudioArray; *OutDataRangesCount = DataRangeCount; } NTSTATUS USBAudioPinBuildDescriptors( PKSDEVICE Device, PKSPIN_DESCRIPTOR_EX *PinDescriptors, PULONG PinDescriptorsCount, PULONG PinDescriptorSize) { PDEVICE_EXTENSION DeviceExtension; PKSPIN_DESCRIPTOR_EX Pins; ULONG TotalTerminalDescriptorCount = 0; ULONG NonStreamingTerminalDescriptorCount = 0; ULONG Index = 0; PUSB_AUDIO_CONTROL_INPUT_TERMINAL_DESCRIPTOR TerminalDescriptor = NULL; /* get device extension */ DeviceExtension = Device->Context; CountTerminalUnits(DeviceExtension->ConfigurationDescriptor, &NonStreamingTerminalDescriptorCount, &TotalTerminalDescriptorCount); DPRINT("TotalTerminalDescriptorCount %lu NonStreamingTerminalDescriptorCount %lu\n", TotalTerminalDescriptorCount, NonStreamingTerminalDescriptorCount); /* allocate pins */ Pins = AllocFunction(sizeof(KSPIN_DESCRIPTOR_EX) * TotalTerminalDescriptorCount); if (!Pins) { /* no memory*/ return STATUS_INSUFFICIENT_RESOURCES; } for (Index = 0; Index < TotalTerminalDescriptorCount; Index++) { if (Index < (TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount)) { /* irp sink pins*/ TerminalDescriptor = UsbAudioGetStreamingTerminalDescriptorByIndex(DeviceExtension->ConfigurationDescriptor, Index); ASSERT(TerminalDescriptor != NULL); Pins[Index].Dispatch = &UsbAudioPinDispatch; Pins[Index].PinDescriptor.InterfacesCount = 1; Pins[Index].PinDescriptor.Interfaces = &StandardPinInterface; Pins[Index].PinDescriptor.MediumsCount = 1; Pins[Index].PinDescriptor.Mediums = &StandardPinMedium; Pins[Index].PinDescriptor.Category = UsbAudioGetPinCategoryFromTerminalDescriptor(TerminalDescriptor); UsbAudioGetDataRanges(DeviceExtension->ConfigurationDescriptor, TerminalDescriptor->bTerminalID, (PKSDATARANGE**)&Pins[Index].PinDescriptor.DataRanges, &Pins[Index].PinDescriptor.DataRangesCount); if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL) { Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_BOTH; Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT; /* pin flags */ Pins[Index].Flags = KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY | KSFILTER_FLAG_CRITICAL_PROCESSING; } else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL) { Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_SINK; Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN; /* pin flags */ Pins[Index].Flags = KSPIN_FLAG_PROCESS_IN_RUN_STATE_ONLY | KSPIN_FLAG_GENERATE_EOS_EVENTS; } /* data intersect handler */ Pins[Index].IntersectHandler = UsbAudioPinDataIntersect; /* irp sinks / sources can be instantiated */ Pins[Index].InstancesPossible = 1; } else { /* bridge pins */ TerminalDescriptor = UsbAudioGetNonStreamingTerminalDescriptorByIndex(DeviceExtension->ConfigurationDescriptor, Index - (TotalTerminalDescriptorCount - NonStreamingTerminalDescriptorCount)); Pins[Index].PinDescriptor.InterfacesCount = 1; Pins[Index].PinDescriptor.Interfaces = &StandardPinInterface; Pins[Index].PinDescriptor.MediumsCount = 1; Pins[Index].PinDescriptor.Mediums = &StandardPinMedium; Pins[Index].PinDescriptor.DataRanges = BridgePinAudioFormats; Pins[Index].PinDescriptor.DataRangesCount = 1; Pins[Index].PinDescriptor.Communication = KSPIN_COMMUNICATION_BRIDGE; Pins[Index].PinDescriptor.Category = UsbAudioGetPinCategoryFromTerminalDescriptor(TerminalDescriptor); if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_INPUT_TERMINAL) { Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_IN; } else if (TerminalDescriptor->bDescriptorSubtype == USB_AUDIO_OUTPUT_TERMINAL) { Pins[Index].PinDescriptor.DataFlow = KSPIN_DATAFLOW_OUT; } } } *PinDescriptors = Pins; *PinDescriptorSize = sizeof(KSPIN_DESCRIPTOR_EX); *PinDescriptorsCount = TotalTerminalDescriptorCount; return STATUS_SUCCESS; } NTSTATUS NTAPI USBAudioGetDescriptor( IN PDEVICE_OBJECT DeviceObject, IN UCHAR DescriptorType, IN ULONG DescriptorLength, IN UCHAR DescriptorIndex, IN LANGID LanguageId, OUT PVOID *OutDescriptor) { PURB Urb; NTSTATUS Status; PVOID Descriptor; /* sanity checks */ ASSERT(DeviceObject); ASSERT(OutDescriptor); ASSERT(DescriptorLength); // // first allocate descriptor buffer // Descriptor = AllocFunction(DescriptorLength); if (!Descriptor) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } /* allocate urb */ Urb = (PURB)AllocFunction(sizeof(URB)); if (!Urb) { /* no memory */ FreeFunction(Descriptor); return STATUS_INSUFFICIENT_RESOURCES; } /* initialize urb */ UsbBuildGetDescriptorRequest(Urb, sizeof(Urb->UrbControlDescriptorRequest), DescriptorType, DescriptorIndex, LanguageId, Descriptor, NULL, DescriptorLength, NULL); /* submit urb */ Status = SubmitUrbSync(DeviceObject, Urb); /* free urb */ FreeFunction(Urb); if (NT_SUCCESS(Status)) { /* store result */ *OutDescriptor = Descriptor; } else { /* failed */ FreeFunction(Descriptor); } /* done */ return Status; } NTSTATUS NTAPI USBAudioGetStringDescriptor( IN PDEVICE_OBJECT DeviceObject, IN ULONG DescriptorLength, IN UCHAR DescriptorIndex, IN LANGID LanguageId, OUT PVOID *OutDescriptor) { NTSTATUS Status; /* retrieve descriptor */ Status = USBAudioGetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor); if (!NT_SUCCESS(Status)) { // failed return Status; } return STATUS_SUCCESS; } NTSTATUS USBAudioRegCreateMediaCategoriesKey( IN PUNICODE_STRING Name, OUT PHANDLE OutHandle) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; UNICODE_STRING DestinationString; HANDLE Handle; /* initialize root name*/ RtlInitUnicodeString(&DestinationString, L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Control\\MediaCategories\\"); /* initialize object attributes */ InitializeObjectAttributes(&ObjectAttributes, &DestinationString, OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, NULL, NULL); /* create the key */ Status = ZwOpenKey(&Handle, KEY_ALL_ACCESS, &ObjectAttributes); if (NT_SUCCESS(Status)) { /* initialize object attributes */ InitializeObjectAttributes(&ObjectAttributes, Name, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, Handle, NULL); Status = ZwCreateKey(OutHandle, KEY_ALL_ACCESS, &ObjectAttributes, 0, NULL, 0, NULL); ZwClose(Handle); } return Status; } NTSTATUS USBAudioInitComponentId( PKSDEVICE Device, IN PKSCOMPONENTID ComponentId) { PDEVICE_EXTENSION DeviceExtension; NTSTATUS Status; LPWSTR DescriptionBuffer; UNICODE_STRING GuidString; UNICODE_STRING Name; HANDLE hKey; GUID TempGuid; /* get device extension */ DeviceExtension = Device->Context; /* init component id */ ComponentId->Component = KSCOMPONENTID_USBAUDIO; ComponentId->Version = HIBYTE(DeviceExtension->DeviceDescriptor->bcdDevice); ComponentId->Revision = LOBYTE(DeviceExtension->DeviceDescriptor->bcdDevice); INIT_USBAUDIO_MID(&ComponentId->Manufacturer, DeviceExtension->DeviceDescriptor->idVendor); INIT_USBAUDIO_PID(&ComponentId->Product, DeviceExtension->DeviceDescriptor->idProduct); INIT_USBAUDIO_PRODUCT_NAME(&TempGuid, DeviceExtension->DeviceDescriptor->idVendor, DeviceExtension->DeviceDescriptor->idProduct, 0); if (DeviceExtension->DeviceDescriptor->iProduct) { Status = USBAudioGetStringDescriptor(DeviceExtension->LowerDevice, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iProduct, 0x0409 /* FIXME */, (PVOID*)&DescriptionBuffer); if (NT_SUCCESS(Status)) { Status = RtlStringFromGUID(&TempGuid, &GuidString); if (NT_SUCCESS(Status)) { Status = USBAudioRegCreateMediaCategoriesKey(&GuidString, &hKey); if (NT_SUCCESS(Status)) { RtlInitUnicodeString(&Name, L"Name"); ZwSetValueKey(hKey, &Name, 0, REG_SZ, DescriptionBuffer, (wcslen(DescriptionBuffer) + 1) * sizeof(WCHAR)); ZwClose(hKey); INIT_USBAUDIO_PRODUCT_NAME(&ComponentId->Name, DeviceExtension->DeviceDescriptor->idVendor, DeviceExtension->DeviceDescriptor->idProduct, 0); } RtlFreeUnicodeString(&GuidString); } FreeFunction(DescriptionBuffer); } } return STATUS_SUCCESS; } NTSTATUS NTAPI USBAudioCreateFilterContext( PKSDEVICE Device) { PKSFILTER_DESCRIPTOR FilterDescriptor; PKSCOMPONENTID ComponentId; NTSTATUS Status; /* allocate descriptor */ FilterDescriptor = AllocFunction(sizeof(KSFILTER_DESCRIPTOR)); if (!FilterDescriptor) { /* no memory */ return USBD_STATUS_INSUFFICIENT_RESOURCES; } /* init filter descriptor*/ FilterDescriptor->Version = KSFILTER_DESCRIPTOR_VERSION; FilterDescriptor->Flags = 0; FilterDescriptor->ReferenceGuid = &KSNAME_Filter; FilterDescriptor->Dispatch = &USBAudioFilterDispatch; FilterDescriptor->CategoriesCount = 1; FilterDescriptor->Categories = &GUID_KSCATEGORY_AUDIO; /* init component id*/ ComponentId = AllocFunction(sizeof(KSCOMPONENTID)); if (!ComponentId) { /* no memory */ return STATUS_INSUFFICIENT_RESOURCES; } Status = USBAudioInitComponentId(Device, ComponentId); if (!NT_SUCCESS(Status)) { /* failed*/ FreeFunction(ComponentId); return Status; } FilterDescriptor->ComponentId = ComponentId; /* build pin descriptors */ Status = USBAudioPinBuildDescriptors(Device, (PKSPIN_DESCRIPTOR_EX *)&FilterDescriptor->PinDescriptors, &FilterDescriptor->PinDescriptorsCount, &FilterDescriptor->PinDescriptorSize); if (!NT_SUCCESS(Status)) { /* failed*/ FreeFunction(ComponentId); return Status; } /* build topology */ Status = BuildUSBAudioFilterTopology(Device, FilterDescriptor); if (!NT_SUCCESS(Status)) { /* failed*/ FreeFunction(ComponentId); return Status; } /* lets create the filter */ Status = KsCreateFilterFactory(Device->FunctionalDeviceObject, FilterDescriptor, ReferenceString, NULL, KSCREATE_ITEM_FREEONSTOP, NULL, NULL, NULL); DPRINT("KsCreateFilterFactory: %x\n", Status); return Status; }