summaryrefslogtreecommitdiff
path: root/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
diff options
context:
space:
mode:
authorJ M Rossy <[email protected]>2015-07-29 15:40:09 -0700
committerJ M Rossy <[email protected]>2015-07-29 16:34:40 -0700
commit5d61a4a79a1e96dc5d9af1e5e712c84507307544 (patch)
tree49ed270893578cd18758b74ffcca16dc7ab948d6 /audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
parent5d41613e26e147d2300c786bb2b34cb4b4067a25 (diff)
Samples update for public Windows 10 release
Fix #2 Enabling WPP Recorder in Sensors Samples causes errors Fix #4 Add back fixed KMDOD sample Add new BarcodeScanner sample in pos folder Add new MagneticStripeReader sample in pos folder Add new SynpaticsTouch sample in input folder Add new Power Engine Plugin sample in pofx folder Add new DeviceMft sample in avstream folder Add new AvsCamera sample in root Add new SimBatt sample in root Add other pre-existing samples not yet released for Win10
Diffstat (limited to 'audio/sysvad/PhoneAudioSample/Cellulartopo.cpp')
-rw-r--r--audio/sysvad/PhoneAudioSample/Cellulartopo.cpp973
1 files changed, 973 insertions, 0 deletions
diff --git a/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp b/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
new file mode 100644
index 00000000..250a03ba
--- /dev/null
+++ b/audio/sysvad/PhoneAudioSample/Cellulartopo.cpp
@@ -0,0 +1,973 @@
+/*++
+
+Copyright (c) Microsoft Corporation All Rights Reserved
+
+Module Name:
+
+ cellulartopo.cpp
+
+Abstract:
+
+ Implementation of topology miniport for the cellular endpoint.
+
+--*/
+
+#pragma warning (disable : 4127)
+
+#include <sysvad.h>
+#include "simple.h"
+#include "mintopo.h"
+#include "cellulartopo.h"
+#include "cellulartoptable.h"
+#include <ntstrsafe.h>
+
+
+#pragma code_seg("PAGE")
+
+
+// table of valid render/capture combinations for cellular routing.
+// speaker and mic (speakerphone)
+// headset speaker and headset mic (wired headset)
+// headset speaker and mic (wired headset without microphone)
+// handset speaker and handset mic (handset)
+// HFP speaker and HFP mic (bluetooth hands free)
+// special host routing pair
+KSTOPOLOGY_ENDPOINTIDPAIR g_EndpointList[] =
+{
+ { HANDSET_SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, HANDSET_MIC_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
+ { SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_ARRAY1_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
+ { SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_HEADSET_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
+ { SPEAKER_HEADSET_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, MIC_ARRAY1_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
+ { HFP_SPEAKER_TOPONAME, KSPIN_TOPO_LINEOUT_DEST, HFP_MIC_TOPONAME, KSPIN_TOPO_MIC_ELEMENTS },
+ { HOSTRENDER_TOPONAME, HOSTRENDER_PIN, HOSTCAPTURE_TOPONAME, HOSTCAPTURE_PIN }
+};
+
+//=============================================================================
+NTSTATUS
+CreateCellularMiniportTopology
+(
+ _Out_ PUNKNOWN * Unknown,
+ _In_ REFCLSID,
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _When_((PoolType & NonPagedPoolMustSucceed) != 0,
+ __drv_reportError("Must succeed pool allocations are forbidden. "
+ "Allocation failures cause a system crash"))
+ _In_ POOL_TYPE PoolType,
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_opt_ PVOID DeviceContext,
+ _In_ PENDPOINT_MINIPAIR MiniportPair
+)
+/*++
+
+Routine Description:
+
+ Creates a new topology miniport.
+
+Arguments:
+
+ Unknown -
+
+ RefclsId -
+
+ UnknownOuter -
+
+ PoolType -
+
+ UnknownAdapter -
+
+ DeviceContext -
+
+ MiniportPair -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Unknown);
+ ASSERT(MiniportPair);
+
+ UNREFERENCED_PARAMETER(UnknownAdapter);
+ UNREFERENCED_PARAMETER(DeviceContext);
+
+ CCellularMiniportTopology *obj =
+ new (PoolType, MINWAVERT_POOLTAG)
+ CCellularMiniportTopology( UnknownOuter,
+ MiniportPair->TopoDescriptor,
+ MiniportPair->DeviceMaxChannels);
+ if (NULL == obj)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+
+ obj->AddRef();
+ *Unknown = reinterpret_cast<IUnknown*>(obj);
+
+ return STATUS_SUCCESS;
+} // CreateCellularMiniportTopology
+
+CCellularMiniportTopology::CCellularMiniportTopology
+(
+ _In_opt_ PUNKNOWN UnknownOuter,
+ _In_ PCFILTER_DESCRIPTOR *FilterDesc,
+ _In_ USHORT DeviceMaxChannels
+)
+: CUnknown(UnknownOuter),
+ CMiniportTopologySYSVAD(FilterDesc, DeviceMaxChannels),
+ m_CellularVolume(0)
+{
+ PAGED_CODE();
+
+ memcpy(&m_CellularRenderEndpoint, &(g_EndpointList[0].RenderEndpoint), sizeof(m_CellularRenderEndpoint));
+ memcpy(&m_CellularCaptureEndpoint, &(g_EndpointList[0].CaptureEndpoint), sizeof(m_CellularCaptureEndpoint));
+}
+
+
+//=============================================================================
+CCellularMiniportTopology::~CCellularMiniportTopology
+(
+ void
+)
+/*++
+
+Routine Description:
+
+ Topology miniport destructor
+
+Arguments:
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ DPF_ENTER(("[CCellularMiniportTopology::~CCellularMiniportTopology]"));
+} // ~CCellularMiniportTopology
+
+//=============================================================================
+NTSTATUS
+CCellularMiniportTopology::DataRangeIntersection
+(
+ _In_ ULONG PinId,
+ _In_ PKSDATARANGE ClientDataRange,
+ _In_ PKSDATARANGE MyDataRange,
+ _In_ ULONG OutputBufferLength,
+ _Out_writes_bytes_to_opt_(OutputBufferLength, *ResultantFormatLength)
+ PVOID ResultantFormat OPTIONAL,
+ _Out_ PULONG ResultantFormatLength
+)
+/*++
+
+Routine Description:
+
+ The DataRangeIntersection function determines the highest quality
+ intersection of two data ranges.
+
+Arguments:
+
+ PinId - Pin for which data intersection is being determined.
+
+ ClientDataRange - Pointer to KSDATARANGE structure which contains the data range
+ submitted by client in the data range intersection property
+ request.
+
+ MyDataRange - Pin's data range to be compared with client's data range.
+
+ OutputBufferLength - Size of the buffer pointed to by the resultant format
+ parameter.
+
+ ResultantFormat - Pointer to value where the resultant format should be
+ returned.
+
+ ResultantFormatLength - Actual length of the resultant format that is placed
+ at ResultantFormat. This should be less than or equal
+ to OutputBufferLength.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ return
+ CMiniportTopologySYSVAD::DataRangeIntersection
+ (
+ PinId,
+ ClientDataRange,
+ MyDataRange,
+ OutputBufferLength,
+ ResultantFormat,
+ ResultantFormatLength
+ );
+} // DataRangeIntersection
+
+//=============================================================================
+STDMETHODIMP
+CCellularMiniportTopology::GetDescription
+(
+ _Out_ PPCFILTER_DESCRIPTOR * OutFilterDescriptor
+)
+/*++
+
+Routine Description:
+
+ The GetDescription function gets a pointer to a filter description.
+ It provides a location to deposit a pointer in miniport's description
+ structure. This is the placeholder for the FromNode or ToNode fields in
+ connections which describe connections to the filter's pins.
+
+Arguments:
+
+ OutFilterDescriptor - Pointer to the filter description.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(OutFilterDescriptor);
+
+ return CMiniportTopologySYSVAD::GetDescription(OutFilterDescriptor);
+} // GetDescription
+
+//=============================================================================
+STDMETHODIMP
+CCellularMiniportTopology::Init
+(
+ _In_ PUNKNOWN UnknownAdapter,
+ _In_ PRESOURCELIST ResourceList,
+ _In_ PPORTTOPOLOGY Port_
+)
+/*++
+
+Routine Description:
+
+ The Init function initializes the miniport. Callers of this function
+ should run at IRQL PASSIVE_LEVEL
+
+Arguments:
+
+ UnknownAdapter - A pointer to the Iuknown interface of the adapter object.
+
+ ResourceList - Pointer to the resource list to be supplied to the miniport
+ during initialization. The port driver is free to examine the
+ contents of the ResourceList. The port driver will not be
+ modify the ResourceList contents.
+
+ Port - Pointer to the topology port object that is linked with this miniport.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ UNREFERENCED_PARAMETER(ResourceList);
+
+ PAGED_CODE();
+
+ ASSERT(UnknownAdapter);
+ ASSERT(Port_);
+
+ DPF_ENTER(("[CCellularMiniportTopology::Init]"));
+
+ NTSTATUS ntStatus;
+
+ ntStatus =
+ CMiniportTopologySYSVAD::Init
+ (
+ UnknownAdapter,
+ Port_
+ );
+
+ return ntStatus;
+} // Init
+
+//=============================================================================
+STDMETHODIMP
+CCellularMiniportTopology::NonDelegatingQueryInterface
+(
+ _In_ REFIID Interface,
+ _COM_Outptr_ PVOID * Object
+)
+/*++
+
+Routine Description:
+
+ QueryInterface for MiniportTopology
+
+Arguments:
+
+ Interface - GUID of the interface
+
+ Object - interface object to be returned.
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(Object);
+
+ if (IsEqualGUIDAligned(Interface, IID_IUnknown))
+ {
+ *Object = PVOID(PUNKNOWN(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniport))
+ {
+ *Object = PVOID(PMINIPORT(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_IMiniportTopology))
+ {
+ *Object = PVOID(PMINIPORTTOPOLOGY(this));
+ }
+ else if (IsEqualGUIDAligned(Interface, IID_ICellularTopology))
+ {
+ *Object = PVOID(PCELLULARTOPOLOGY(this));
+ }
+ else
+ {
+ *Object = NULL;
+ }
+
+ if (*Object)
+ {
+ // We reference the interface for the caller.
+ PUNKNOWN(*Object)->AddRef();
+ return(STATUS_SUCCESS);
+ }
+
+ return(STATUS_INVALID_PARAMETER);
+} // NonDelegatingQueryInterface
+
+//=============================================================================
+NTSTATUS
+CCellularMiniportTopology::PropertyHandlerJackDescription
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION )
+
+Arguments:
+
+ PropertyRequest
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription]"));
+
+ ULONG cJackDescriptions = ARRAYSIZE(CellularJackDescriptions);
+ PKSJACK_DESCRIPTION * JackDescriptions = CellularJackDescriptions;
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION pDesc = (PKSJACK_DESCRIPTION)(pMI+1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ RtlCopyMemory(pDesc, JackDescriptions[nPinId], sizeof(KSJACK_DESCRIPTION));
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CCellularMiniportTopology::PropertyHandlerJackDescription2
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_Jack, KSPROPERTY_JACK_DESCRIPTION2 )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerJackDescription2]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ ULONG nPinId = (ULONG)-1;
+
+ ULONG cJackDescriptions = ARRAYSIZE(CellularJackDescriptions);
+ PKSJACK_DESCRIPTION * JackDescriptions = CellularJackDescriptions;
+
+ if (PropertyRequest->InstanceSize >= sizeof(ULONG))
+ {
+ nPinId = *(PULONG(PropertyRequest->Instance));
+
+ if ((nPinId < cJackDescriptions) && (JackDescriptions[nPinId] != NULL))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupport
+ (
+ PropertyRequest,
+ KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_GET,
+ VT_ILLEGAL
+ );
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSMULTIPLE_ITEM) + sizeof(KSJACK_DESCRIPTION2);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSMULTIPLE_ITEM pMI = (PKSMULTIPLE_ITEM)PropertyRequest->Value;
+ PKSJACK_DESCRIPTION2 pDesc = (PKSJACK_DESCRIPTION2)(pMI+1);
+
+ pMI->Size = cbNeeded;
+ pMI->Count = 1;
+
+ RtlZeroMemory(pDesc, sizeof(KSJACK_DESCRIPTION2));
+
+ //
+ // Specifies the lower 16 bits of the DWORD parameter. This parameter indicates whether
+ // the jack is currently active, streaming, idle, or hardware not ready.
+ //
+ pDesc->DeviceStateInfo = 0;
+
+ //
+ // From MSDN:
+ // "If an audio device lacks jack presence detection, the IsConnected member of
+ // the KSJACK_DESCRIPTION structure must always be set to TRUE. To remove the
+ // ambiguity that results from this dual meaning of the TRUE value for IsConnected,
+ // a client application can call IKsJackDescription2::GetJackDescription2 to read
+ // the JackCapabilities flag of the KSJACK_DESCRIPTION2 structure. If this flag has
+ // the JACKDESC2_PRESENCE_DETECT_CAPABILITY bit set, it indicates that the endpoint
+ // does in fact support jack presence detection. In that case, the return value of
+ // the IsConnected member can be interpreted to accurately reflect the insertion status
+ // of the jack."
+ //
+ // Bit definitions:
+ // 0x00000001 - JACKDESC2_PRESENCE_DETECT_CAPABILITY
+ // 0x00000002 - JACKDESC2_DYNAMIC_FORMAT_CHANGE_CAPABILITY
+ //
+ pDesc->JackCapabilities = JACKDESC2_PRESENCE_DETECT_CAPABILITY;
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ }
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CCellularMiniportTopology::PropertyHandlerTelephonyEndpointIdPair
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_TelephonyTopology, KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerTelephonyEndpointIdPair]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ ULONG ulExpectedSize = (sizeof(KSPROPERTY_DESCRIPTION) + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(g_EndpointList));
+
+ if (PropertyRequest->ValueSize >= sizeof(KSPROPERTY_DESCRIPTION))
+ {
+ // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
+ //
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+
+ PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_SET |KSPROPERTY_TYPE_GET;
+ PropDesc->DescriptionSize = ulExpectedSize;
+ PropDesc->PropTypeSet.Set = KSPROPSETID_TelephonyTopology;
+ PropDesc->PropTypeSet.Id = KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR;
+ PropDesc->PropTypeSet.Flags = 0;
+ PropDesc->MembersListCount = 1;
+ PropDesc->Reserved = 0;
+
+ // buffer is big enough to hold the full data, add that
+ if (PropertyRequest->ValueSize >= ulExpectedSize)
+ {
+ PKSPROPERTY_MEMBERSHEADER MembersHeader =
+ PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
+
+ MembersHeader->MembersFlags = KSPROPERTY_MEMBER_VALUES;
+ MembersHeader->MembersSize = sizeof(KSTOPOLOGY_ENDPOINTIDPAIR);
+ MembersHeader->MembersCount = SIZEOF_ARRAY(g_EndpointList);
+ MembersHeader->Flags = 0;
+
+ memcpy(MembersHeader + 1, g_EndpointList, sizeof(g_EndpointList));
+
+ // tell them how much space we really used, which controls how much data is copied into the user buffer.
+ PropertyRequest->ValueSize = ulExpectedSize;
+ }
+ else
+ {
+ // tell them how much space we really used, which controls how much data is copied into the user buffer.
+ PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
+ }
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->ValueSize >= sizeof(ULONG))
+ {
+ // if return buffer can hold a ULONG, return the access flags.
+ *(PULONG(PropertyRequest->Value)) = KSPROPERTY_TYPE_SET |KSPROPERTY_TYPE_GET;
+ PropertyRequest->ValueSize = sizeof(ULONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = ulExpectedSize;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ }
+ else
+ {
+ ULONG cbNeeded = sizeof(KSTOPOLOGY_ENDPOINTIDPAIR);
+
+ if (PropertyRequest->ValueSize == 0)
+ {
+ PropertyRequest->ValueSize = cbNeeded;
+ ntStatus = STATUS_BUFFER_OVERFLOW;
+ }
+ else if (PropertyRequest->ValueSize < cbNeeded)
+ {
+ ntStatus = STATUS_BUFFER_TOO_SMALL;
+ }
+ else
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ PKSTOPOLOGY_ENDPOINTIDPAIR EndpointIdPair = static_cast<PKSTOPOLOGY_ENDPOINTIDPAIR>(PropertyRequest->Value);
+
+ // Return endpoints (render and capture) info where cellular audio is being routed to.
+ memcpy(&(EndpointIdPair->RenderEndpoint), &m_CellularRenderEndpoint, sizeof(m_CellularRenderEndpoint));
+ memcpy(&(EndpointIdPair->CaptureEndpoint), &m_CellularCaptureEndpoint, sizeof(m_CellularCaptureEndpoint));
+
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ PKSTOPOLOGY_ENDPOINTIDPAIR EndpointIdPair = static_cast<PKSTOPOLOGY_ENDPOINTIDPAIR>(PropertyRequest->Value);
+
+ // verify the requested combination is in the list of valid endpoint combinations, fail with
+ // invalid parameter if not found.
+ ntStatus = STATUS_INVALID_PARAMETER;
+ for (int i = 0; i < SIZEOF_ARRAY(g_EndpointList); i++)
+ {
+ if (g_EndpointList[i].RenderEndpoint.PinId == EndpointIdPair->RenderEndpoint.PinId &&
+ 0 == _wcsnicmp(g_EndpointList[i].RenderEndpoint.TopologyName, EndpointIdPair->RenderEndpoint.TopologyName, MAX_PATH) &&
+ g_EndpointList[i].CaptureEndpoint.PinId == EndpointIdPair->CaptureEndpoint.PinId &&
+ 0 == _wcsnicmp(g_EndpointList[i].CaptureEndpoint.TopologyName, EndpointIdPair->CaptureEndpoint.TopologyName, MAX_PATH))
+ {
+ if (HOSTRENDER_PIN == EndpointIdPair->RenderEndpoint.PinId &&
+ 0 == _wcsnicmp(HOSTRENDER_TOPONAME, EndpointIdPair->RenderEndpoint.TopologyName, MAX_PATH) &&
+ HOSTCAPTURE_PIN == EndpointIdPair->CaptureEndpoint.PinId &&
+ 0 == _wcsnicmp(HOSTCAPTURE_TOPONAME, EndpointIdPair->CaptureEndpoint.TopologyName, MAX_PATH))
+ {
+ // This is an indication that cellular audio is being routed through OS (For example, user plugs in USB headset
+ // for cellular audio) and driver must stop rendering cellular audio to any physical audio endpoint. Driver must
+ // also stop capturing data from any physical audio endpoint for cellular. This will update audio routing for
+ // all the active cellular calls.
+ }
+ else
+ {
+ // Route cellular audio to these new endpoints (render and capture). This will update audio routing for
+ // all the active cellular calls.
+ }
+
+ memcpy(&m_CellularRenderEndpoint, &(EndpointIdPair->RenderEndpoint), sizeof(m_CellularRenderEndpoint));
+ memcpy(&m_CellularCaptureEndpoint, &(EndpointIdPair->CaptureEndpoint), sizeof(m_CellularCaptureEndpoint));
+
+ // we found the entry, so return success
+ ntStatus = STATUS_SUCCESS;
+ break;
+ }
+ }
+
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+CCellularMiniportTopology::PropertyHandlerTelephonyVolume
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Handles ( KSPROPSETID_TelephonyTopology, KSPROPERTY_TELEPHONY_VOLUME )
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandlerTelephonyVolume]"));
+
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
+ {
+ ntStatus =
+ PropertyHandler_BasicSupportVolume
+ (
+ PropertyRequest,
+ 1 // Telephony audio is only ever 1 channel
+ );
+
+ ULONG cbFullProperty =
+ sizeof(KSPROPERTY_DESCRIPTION) +
+ sizeof(KSPROPERTY_MEMBERSHEADER) +
+ sizeof(KSPROPERTY_STEPPING_LONG);
+
+ if (NT_SUCCESS(ntStatus) && PropertyRequest->ValueSize >= cbFullProperty)
+ {
+ // Access proper values
+ PKSPROPERTY_DESCRIPTION PropDesc =
+ PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
+ PKSPROPERTY_MEMBERSHEADER Members =
+ PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
+ PKSPROPERTY_STEPPING_LONG Range =
+ PKSPROPERTY_STEPPING_LONG(Members + 1);
+
+ // Telephony volume is only ever single channel, so the
+ // MULTICHANNEL and UNIFORM flags are meaningless
+ Members->Flags = 0;
+
+ // Telephony Values that may be different from standard volume values
+ Range->Bounds.SignedMaximum = TELEPHONY_VOLUME_MAXIMUM;
+ Range->Bounds.SignedMinimum = TELEPHONY_VOLUME_MINIMUM;
+ Range->SteppingDelta = TELEPHONY_VOLUME_STEPPING;
+ }
+ }
+ else
+ {
+ ntStatus =
+ ValidatePropertyParams
+ (
+ PropertyRequest,
+ sizeof(LONG), // volume value is a LONG
+ 0 // there is no channel associated with telephony volume
+ );
+
+
+ if (NT_SUCCESS(ntStatus))
+ {
+ if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
+ {
+ LONG* volume = (LONG*)PropertyRequest->Value;
+ // Return current cellular volume (Incall volume).
+ *volume = m_CellularVolume;
+ PropertyRequest->ValueSize = sizeof(LONG);
+ ntStatus = STATUS_SUCCESS;
+ }
+ else if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+ {
+ LONG* volume = (LONG*)PropertyRequest->Value;
+
+ LONG normalizedVolume =
+ VALUE_NORMALIZE_IN_RANGE_EX
+ (
+ *volume,
+ TELEPHONY_VOLUME_MINIMUM,
+ TELEPHONY_VOLUME_MAXIMUM,
+ TELEPHONY_VOLUME_STEPPING
+ );
+ if (normalizedVolume == *volume)
+ {
+ // Update the cellular volume (Incall volume). This will update cellular volume for all the active cellular calls.
+ m_CellularVolume = *volume;
+ ntStatus = STATUS_SUCCESS;
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ ntStatus = STATUS_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return ntStatus;
+}
+
+//=============================================================================
+NTSTATUS
+PropertyHandler_CellularTopoFilter
+(
+ _In_ PPCPROPERTY_REQUEST PropertyRequest
+)
+/*++
+
+Routine Description:
+
+ Redirects property request to miniport object
+
+Arguments:
+
+ PropertyRequest -
+
+Return Value:
+
+ NT status code.
+
+--*/
+{
+ PAGED_CODE();
+
+ ASSERT(PropertyRequest);
+
+ DPF_ENTER(("[PropertyHandler_CellularTopoFilter]"));
+
+ // PropertryRequest structure is filled by portcls.
+ // MajorTarget is a pointer to miniport object for miniports.
+ //
+ NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
+ PCCellularMiniportTopology pMiniport = (PCCellularMiniportTopology)PropertyRequest->MajorTarget;
+
+ if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_Jack))
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription(PropertyRequest);
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_JACK_DESCRIPTION2)
+ {
+ ntStatus = pMiniport->PropertyHandlerJackDescription2(PropertyRequest);
+ }
+ }
+ else if (IsEqualGUIDAligned(*PropertyRequest->PropertyItem->Set, KSPROPSETID_TelephonyTopology))
+ {
+ if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_ENDPOINTIDPAIR)
+ {
+ ntStatus = pMiniport->PropertyHandlerTelephonyEndpointIdPair(PropertyRequest);
+ }
+ else if (PropertyRequest->PropertyItem->Id == KSPROPERTY_TELEPHONY_VOLUME)
+ {
+ ntStatus = pMiniport->PropertyHandlerTelephonyVolume(PropertyRequest);
+ }
+ }
+
+
+ return ntStatus;
+} // PropertyHandler_CellularTopoFilter
+
+#pragma code_seg("PAGE")
+STDMETHODIMP_(NTSTATUS)
+CCellularMiniportTopology::UpdateTopologyJackState
+(
+ _In_ ULONG TelephonyId,
+ _In_ BOOL NewState
+)
+{
+ PAGED_CODE ();
+
+ struct JackState
+ {
+ ULONG TelephonyId;
+ ULONG PinId;
+ PKSJACK_DESCRIPTION JackControl;
+ };
+
+ JackState Jacks[] =
+ {
+ {
+ 0,
+ KSPIN_TOPO_BIDI1,
+ &CellularJackDesc
+ },
+ {
+ 1,
+ KSPIN_TOPO_BIDI2,
+ &CellularJackDesc2
+ }
+ };
+
+ // Query the registry and update the jack state for all of the pins.
+ for (int i = 0; i < SIZEOF_ARRAY(Jacks); i++)
+ {
+ if (Jacks[i].TelephonyId == TelephonyId)
+ {
+ Jacks[i].JackControl->IsConnected = NewState;
+
+ // we have multiple pins which share the same jack state,
+ // notify for every pin using that jack state
+ GenerateEventList(
+ (GUID*)&KSEVENTSETID_PinCapsChange, // event set. NULL is a wild card for all events.
+ KSEVENT_PINCAPS_JACKINFOCHANGE, // event ID.
+ TRUE, // use pid ID.
+ Jacks[i].PinId, // pin ID.
+ FALSE, // do not use node ID.
+ ULONG(-1)); // node ID, not used.
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+#pragma code_seg()
+NTSTATUS CCellularMiniportWaveRT_EventHandler_JackState
+(
+ _In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ CCellularMiniportTopology* miniport = reinterpret_cast<CCellularMiniportTopology*>(EventRequest->MajorTarget);
+ return miniport->EventHandler_JackState(EventRequest);
+}
+
+NTSTATUS CCellularMiniportTopology::EventHandler_JackState
+(
+ _In_ PPCEVENT_REQUEST EventRequest
+)
+{
+ if (EventRequest->Verb == PCEVENT_VERB_ADD)
+ {
+ m_PortEvents->AddEventToEventList(EventRequest->EventEntry);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+