diff options
Diffstat (limited to 'audio/sysvad/adapter.cpp')
| -rw-r--r-- | audio/sysvad/adapter.cpp | 1079 |
1 files changed, 1079 insertions, 0 deletions
diff --git a/audio/sysvad/adapter.cpp b/audio/sysvad/adapter.cpp new file mode 100644 index 00000000..08e83a45 --- /dev/null +++ b/audio/sysvad/adapter.cpp @@ -0,0 +1,1079 @@ +/*++ + +Copyright (c) Microsoft Corporation All Rights Reserved + +Module Name: + + adapter.cpp + +Abstract: + + Setup and miniport installation. No resources are used by sysvad. + This sample is to demonstrate how to develop a full featured audio miniport driver. + +--*/ + +#pragma warning (disable : 4127) + +// +// All the GUIDS for all the miniports end up in this object. +// +#define PUT_GUIDS_HERE + +#include <sysvad.h> +#include <ContosoKeywordDetector.h> +#include "IHVPrivatePropertySet.h" + +#include "simple.h" +#include "minipairs.h" +#ifdef SYSVAD_BTH_BYPASS +#include "bthhfpminipairs.h" +#endif // SYSVAD_BTH_BYPASS + + + +typedef void (*fnPcDriverUnload) (PDRIVER_OBJECT); +fnPcDriverUnload gPCDriverUnloadRoutine = NULL; +extern "C" DRIVER_UNLOAD DriverUnload; + +#ifdef _USE_SingleComponentMultiFxStates +C_ASSERT(sizeof(POHANDLE) == sizeof(PVOID)); + +//============================================================================= +// +// The number of F-states, the transition latency and residency requirement values +// used here are for illustration purposes only. The driver should use values that +// are appropriate for its device. +// +#define SYSVAD_FSTATE_COUNT 4 + +#define SYSVAD_F0_LATENCY_IN_MS 0 +#define SYSVAD_F0_RESIDENCY_IN_SEC 0 + +#define SYSVAD_F1_LATENCY_IN_MS 200 +#define SYSVAD_F1_RESIDENCY_IN_SEC 3 + +#define SYSVAD_F2_LATENCY_IN_MS 400 +#define SYSVAD_F2_RESIDENCY_IN_SEC 6 + +#define SYSVAD_F3_LATENCY_IN_MS 800 +#define SYSVAD_F3_RESIDENCY_IN_SEC 12 + +#define SYSVAD_DEEPEST_FSTATE_LATENCY_IN_MS SYSVAD_F3_LATENCY_IN_MS +#define SYSVAD_DEEPEST_FSTATE_RESIDENCY_IN_SEC SYSVAD_F3_RESIDENCY_IN_SEC + + +//----------------------------------------------------------------------------- +// PoFx - Single Component - Multi Fx States support. +//----------------------------------------------------------------------------- + +PO_FX_COMPONENT_IDLE_STATE_CALLBACK PcPowerFxComponentIdleStateCallback; +PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK PcPowerFxComponentActiveConditionCallback; +PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK PcPowerFxComponentIdleConditionCallback; +PO_FX_POWER_CONTROL_CALLBACK PcPowerFxPowerControlCallback; +EVT_PC_POST_PO_FX_REGISTER_DEVICE PcPowerFxRegisterDevice; +EVT_PC_PRE_PO_FX_UNREGISTER_DEVICE PcPowerFxUnregisterDevice; + +#pragma code_seg("PAGE") +_Function_class_(EVT_PC_POST_PO_FX_REGISTER_DEVICE) +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +PcPowerFxRegisterDevice( + _In_ PVOID PoFxDeviceContext, + _In_ POHANDLE PoHandle + ) +{ + PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)PoFxDeviceContext; + PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension); + + PAGED_CODE(); + + DPF(D_VERBOSE, ("PcPowerFxRegisterDevice Context %p, PoHandle %p", PoFxDeviceContext, PoHandle)); + + pExtension->m_poHandle = PoHandle; + + // + // Set latency and residency hints so that the power framework chooses lower + // powered F-states when we are idle. + // The values used here are for illustration purposes only. The driver + // should use values that are appropriate for its device. + // + PoFxSetComponentLatency( + PoHandle, + 0, // Component + (WDF_ABS_TIMEOUT_IN_MS(SYSVAD_DEEPEST_FSTATE_LATENCY_IN_MS) + 1) + ); + PoFxSetComponentResidency( + PoHandle, + 0, // Component + (WDF_ABS_TIMEOUT_IN_SEC(SYSVAD_DEEPEST_FSTATE_RESIDENCY_IN_SEC) + 1) + ); + + return STATUS_SUCCESS; +} + +#pragma code_seg("PAGE") +_Function_class_(EVT_PC_PRE_PO_FX_UNREGISTER_DEVICE) +_IRQL_requires_same_ +_IRQL_requires_max_(PASSIVE_LEVEL) +VOID +PcPowerFxUnregisterDevice( + _In_ PVOID PoFxDeviceContext, + _In_ POHANDLE PoHandle + ) +{ + PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)PoFxDeviceContext; + PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension); + + UNREFERENCED_PARAMETER(PoHandle); + + PAGED_CODE(); + + DPF(D_VERBOSE, ("PcPowerFxUnregisterDevice Context %p, PoHandle %p", PoFxDeviceContext, PoHandle)); + + // + // Driver must not use the PoHandle after this call. + // + ASSERT(pExtension->m_poHandle == PoHandle); + pExtension->m_poHandle = NULL; +} + +#pragma code_seg() +__drv_functionClass(PO_FX_COMPONENT_IDLE_STATE_CALLBACK) +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +PcPowerFxComponentIdleStateCallback( + _In_ PVOID Context, + _In_ ULONG Component, + _In_ ULONG State + ) +{ + PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context; + PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension); + + UNREFERENCED_PARAMETER(State); + + DPF(D_VERBOSE, ("PcPowerFxComponentIdleStateCallback Context %p, Component %d, State %d", + Context, Component, State)); + + PoFxCompleteIdleState(pExtension->m_poHandle, Component); +} + +#pragma code_seg() +__drv_functionClass(PO_FX_COMPONENT_ACTIVE_CONDITION_CALLBACK) +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +PcPowerFxComponentActiveConditionCallback( + _In_ PVOID Context, + _In_ ULONG Component + ) +{ + UNREFERENCED_PARAMETER(Context); + UNREFERENCED_PARAMETER(Component); + + DPF(D_VERBOSE, ("PcPowerFxComponentActiveConditionCallback Context %p, Component %d", + Context, Component)); +} + +#pragma code_seg() +__drv_functionClass(PO_FX_COMPONENT_IDLE_CONDITION_CALLBACK) +_IRQL_requires_max_(DISPATCH_LEVEL) +VOID +PcPowerFxComponentIdleConditionCallback( + _In_ PVOID Context, + _In_ ULONG Component + ) +{ + PDEVICE_OBJECT DeviceObject = (PDEVICE_OBJECT)Context; + PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension); + + DPF(D_VERBOSE, ("PcPowerFxComponentIdleConditionCallback Context %p, Component %d", + Context, Component)); + + PoFxCompleteIdleCondition(pExtension->m_poHandle, Component); +} + +#pragma code_seg() +__drv_functionClass(PO_FX_POWER_CONTROL_CALLBACK) +_IRQL_requires_max_(DISPATCH_LEVEL) +NTSTATUS +PcPowerFxPowerControlCallback( + _In_ PVOID DeviceContext, + _In_ LPCGUID PowerControlCode, + _In_reads_bytes_opt_(InBufferSize) PVOID InBuffer, + _In_ SIZE_T InBufferSize, + _Out_writes_bytes_opt_(OutBufferSize) PVOID OutBuffer, + _In_ SIZE_T OutBufferSize, + _Out_opt_ PSIZE_T BytesReturned +) +{ + UNREFERENCED_PARAMETER(DeviceContext); + UNREFERENCED_PARAMETER(PowerControlCode); + UNREFERENCED_PARAMETER(InBuffer); + UNREFERENCED_PARAMETER(InBufferSize); + UNREFERENCED_PARAMETER(OutBuffer); + UNREFERENCED_PARAMETER(OutBufferSize); + UNREFERENCED_PARAMETER(BytesReturned); + + DPF(D_VERBOSE, ("PcPowerFxPowerControlCallback Context %p", DeviceContext)); + + return STATUS_SUCCESS; +} +#endif // _USE_SingleComponentMultiFxStates + +//----------------------------------------------------------------------------- +// Referenced forward. +//----------------------------------------------------------------------------- + +DRIVER_ADD_DEVICE AddDevice; + +NTSTATUS +StartDevice +( + _In_ PDEVICE_OBJECT, + _In_ PIRP, + _In_ PRESOURCELIST +); + +_Dispatch_type_(IRP_MJ_PNP) +DRIVER_DISPATCH PnpHandler; + +// +// Rendering streams are saved to a file by default. Use the registry value +// DoNotCreateDataFiles (DWORD) > 0 to override this default. +// +DWORD g_DoNotCreateDataFiles = 0; + + +#ifdef SYSVAD_BTH_BYPASS +// +// This driver listens for arrival/removal of the bth sco bypass interfaces by +// default. Use the registry value DisableBthScoBypass (DWORD) > 0 to override +// this default. +// +DWORD g_DisableBthScoBypass = 0; +#endif // SYSVAD_BTH_BYPASS + +//----------------------------------------------------------------------------- +// Functions +//----------------------------------------------------------------------------- + +//============================================================================= +#pragma code_seg("PAGE") +extern "C" +void DriverUnload +( + _In_ PDRIVER_OBJECT DriverObject +) +/*++ + +Routine Description: + + Our driver unload routine. This just frees the WDF driver object. + +Arguments: + + DriverObject - pointer to the driver object + +Environment: + + PASSIVE_LEVEL + +--*/ +{ + PAGED_CODE(); + + DPF(D_TERSE, ("[DriverUnload]")); + + if (DriverObject == NULL) + { + goto Done; + } + + // + // Invoke first the port unload. + // + if (gPCDriverUnloadRoutine != NULL) + { + gPCDriverUnloadRoutine(DriverObject); + } + + // + // Unload WDF driver object. + // + if (WdfGetDriver() != NULL) + { + WdfDriverMiniportUnload(WdfGetDriver()); + } + +Done: + return; +} + +//============================================================================= +#pragma code_seg("INIT") +__drv_requiresIRQL(PASSIVE_LEVEL) +NTSTATUS +GetRegistrySettings( + _In_ PUNICODE_STRING RegistryPath + ) +/*++ + +Routine Description: + + Initialize Driver Framework settings from the driver + specific registry settings under + + \REGISTRY\MACHINE\SYSTEM\ControlSetxxx\Services\<driver>\Parameters + +Arguments: + + RegistryPath - Registry path passed to DriverEntry + +Returns: + + NTSTATUS - SUCCESS if able to configure the framework + +--*/ + +{ + NTSTATUS ntStatus; + UNICODE_STRING parametersPath; + RTL_QUERY_REGISTRY_TABLE paramTable[4]; + + DPF(D_TERSE, ("[GetRegistrySettings]")); + + PAGED_CODE(); + + RtlInitUnicodeString(¶metersPath, NULL); + + parametersPath.MaximumLength = + RegistryPath->Length + sizeof(L"\\Parameters") + sizeof(WCHAR); + + parametersPath.Buffer = (PWCH) ExAllocatePoolWithTag(PagedPool, parametersPath.MaximumLength, MINADAPTER_POOLTAG); + if (parametersPath.Buffer == NULL) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + + RtlZeroMemory(parametersPath.Buffer, parametersPath.MaximumLength); + + RtlAppendUnicodeToString(¶metersPath, RegistryPath->Buffer); + RtlAppendUnicodeToString(¶metersPath, L"\\Parameters"); + + RtlZeroMemory(¶mTable[0], sizeof(paramTable)); + + g_DoNotCreateDataFiles = 0; // default is off. + + paramTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[0].Name = L"DoNotCreateDataFiles"; + paramTable[0].EntryContext = &g_DoNotCreateDataFiles; + paramTable[0].DefaultType = REG_DWORD; + paramTable[0].DefaultData = &g_DoNotCreateDataFiles; + paramTable[0].DefaultLength = sizeof(ULONG); + +#ifdef SYSVAD_BTH_BYPASS + g_DisableBthScoBypass = 0; // default is off. + + paramTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; + paramTable[1].Name = L"DisableBthScoBypass"; + paramTable[1].EntryContext = &g_DisableBthScoBypass; + paramTable[1].DefaultType = REG_DWORD; + paramTable[1].DefaultData = &g_DisableBthScoBypass; + paramTable[1].DefaultLength = sizeof(ULONG); +#endif // SYSVAD_BTH_BYPASS + + + ntStatus = RtlQueryRegistryValues( + RTL_REGISTRY_ABSOLUTE | RTL_REGISTRY_OPTIONAL, + parametersPath.Buffer, + ¶mTable[0], + NULL, + NULL + ); + + if (!NT_SUCCESS(ntStatus)) + { + DPF(D_VERBOSE, ("RtlQueryRegistryValues failed, using default values, 0x%x", ntStatus)); + // + // Don't return error because we will operate with default values. + // + } + + // + // Dump settings. + // + DPF(D_VERBOSE, ("DoNotCreateDataFiles: %u", g_DoNotCreateDataFiles)); +#ifdef SYSVAD_BTH_BYPASS + DPF(D_VERBOSE, ("DisableBthScoBypass: %u", g_DisableBthScoBypass)); +#endif // SYSVAD_BTH_BYPASS + + // + // Cleanup. + // + ExFreePool(parametersPath.Buffer); + + return STATUS_SUCCESS; +} + +#pragma code_seg("INIT") +extern "C" DRIVER_INITIALIZE DriverEntry; +extern "C" NTSTATUS +DriverEntry +( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPathName +) +{ +/*++ + +Routine Description: + + Installable driver initialization entry point. + This entry point is called directly by the I/O system. + + All audio adapter drivers can use this code without change. + +Arguments: + + DriverObject - pointer to the driver object + + RegistryPath - pointer to a unicode string representing the path, + to driver-specific key in the registry. + +Return Value: + + STATUS_SUCCESS if successful, + STATUS_UNSUCCESSFUL otherwise. + +--*/ + NTSTATUS ntStatus; + WDF_DRIVER_CONFIG config; + + DPF(D_TERSE, ("[DriverEntry]")); + + // + // Get registry configuration. + // + ntStatus = GetRegistrySettings(RegistryPathName); + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("Registry Configuration error 0x%x", ntStatus)), + Done); + + WDF_DRIVER_CONFIG_INIT(&config, WDF_NO_EVENT_CALLBACK); + // + // Set WdfDriverInitNoDispatchOverride flag to tell the framework + // not to provide dispatch routines for the driver. In other words, + // the framework must not intercept IRPs that the I/O manager has + // directed to the driver. In this case, they will be handled by Audio + // port driver. + // + config.DriverInitFlags |= WdfDriverInitNoDispatchOverride; + config.DriverPoolTag = MINADAPTER_POOLTAG; + + ntStatus = WdfDriverCreate(DriverObject, + RegistryPathName, + WDF_NO_OBJECT_ATTRIBUTES, + &config, + WDF_NO_HANDLE); + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("WdfDriverCreate failed, 0x%x", ntStatus)), + Done); + + // + // Tell the class driver to initialize the driver. + // + ntStatus = PcInitializeAdapterDriver(DriverObject, + RegistryPathName, + (PDRIVER_ADD_DEVICE)AddDevice); + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("PcInitializeAdapterDriver failed, 0x%x", ntStatus)), + Done); + + // + // To intercept stop/remove/surprise-remove. + // + DriverObject->MajorFunction[IRP_MJ_PNP] = PnpHandler; + + // + // Hook the port class unload function + // + gPCDriverUnloadRoutine = DriverObject->DriverUnload; + DriverObject->DriverUnload = DriverUnload; + + // + // All done. + // + ntStatus = STATUS_SUCCESS; + +Done: + + if (!NT_SUCCESS(ntStatus)) + { + if (WdfGetDriver() != NULL) + { + WdfDriverMiniportUnload(WdfGetDriver()); + } + } + + return ntStatus; +} // DriverEntry + +#pragma code_seg() +// disable prefast warning 28152 because +// DO_DEVICE_INITIALIZING is cleared in PcAddAdapterDevice +#pragma warning(disable:28152) +#pragma code_seg("PAGE") +//============================================================================= +NTSTATUS AddDevice +( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PDEVICE_OBJECT PhysicalDeviceObject +) +/*++ + +Routine Description: + + The Plug & Play subsystem is handing us a brand new PDO, for which we + (by means of INF registration) have been asked to provide a driver. + + We need to determine if we need to be in the driver stack for the device. + Create a function device object to attach to the stack + Initialize that device object + Return status success. + + All audio adapter drivers can use this code without change. + +Arguments: + + DriverObject - pointer to a driver object + + PhysicalDeviceObject - pointer to a device object created by the + underlying bus driver. + +Return Value: + + NT status code. + +--*/ +{ + PAGED_CODE(); + + NTSTATUS ntStatus; + ULONG maxObjects; + + DPF(D_TERSE, ("[AddDevice]")); + + maxObjects = g_MaxMiniports; + +#ifdef SYSVAD_BTH_BYPASS + // + // Allow three (3) Bluetooth hands-free profile devices. + // + maxObjects += g_MaxBthHfpMiniports * 3; +#endif // SYSVAD_BTH_BYPASS + + // Tell the class driver to add the device. + // + ntStatus = + PcAddAdapterDevice + ( + DriverObject, + PhysicalDeviceObject, + PCPFNSTARTDEVICE(StartDevice), + maxObjects, + 0 + ); + + + return ntStatus; +} // AddDevice + +#pragma code_seg() +NTSTATUS +_IRQL_requires_max_(DISPATCH_LEVEL) +PowerControlCallback +( + _In_ LPCGUID PowerControlCode, + _In_opt_ PVOID InBuffer, + _In_ SIZE_T InBufferSize, + _Out_writes_bytes_to_(OutBufferSize, *BytesReturned) PVOID OutBuffer, + _In_ SIZE_T OutBufferSize, + _Out_opt_ PSIZE_T BytesReturned, + _In_opt_ PVOID Context +) +{ + UNREFERENCED_PARAMETER(PowerControlCode); + UNREFERENCED_PARAMETER(BytesReturned); + UNREFERENCED_PARAMETER(InBuffer); + UNREFERENCED_PARAMETER(OutBuffer); + UNREFERENCED_PARAMETER(OutBufferSize); + UNREFERENCED_PARAMETER(InBufferSize); + UNREFERENCED_PARAMETER(Context); + + return STATUS_NOT_IMPLEMENTED; +} + +#pragma code_seg("PAGE") +NTSTATUS +InstallEndpointRenderFilters( + _In_ PDEVICE_OBJECT _pDeviceObject, + _In_ PIRP _pIrp, + _In_ PADAPTERCOMMON _pAdapterCommon, + _In_ PENDPOINT_MINIPAIR _pAeMiniports + ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + PUNKNOWN unknownTopology = NULL; + PUNKNOWN unknownWave = NULL; + PPORTCLSETWHELPER pPortClsEtwHelper = NULL; +#ifdef _USE_IPortClsRuntimePower + PPORTCLSRUNTIMEPOWER pPortClsRuntimePower = NULL; +#endif // _USE_IPortClsRuntimePower + PPORTCLSStreamResourceManager pPortClsResMgr = NULL; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(_pDeviceObject); + + ntStatus = _pAdapterCommon->InstallEndpointFilters( + _pIrp, + _pAeMiniports, + NULL, + &unknownTopology, + &unknownWave); + + if (unknownWave) // IID_IPortClsEtwHelper and IID_IPortClsRuntimePower interfaces are only exposed on the WaveRT port. + { + ntStatus = unknownWave->QueryInterface (IID_IPortClsEtwHelper, (PVOID *)&pPortClsEtwHelper); + if (NT_SUCCESS(ntStatus)) + { + _pAdapterCommon->SetEtwHelper(pPortClsEtwHelper); + ASSERT(pPortClsEtwHelper != NULL); + pPortClsEtwHelper->Release(); + } + +#ifdef _USE_IPortClsRuntimePower + // Let's get the runtime power interface on PortCls. + ntStatus = unknownWave->QueryInterface(IID_IPortClsRuntimePower, (PVOID *)&pPortClsRuntimePower); + if (NT_SUCCESS(ntStatus)) + { + // This interface would typically be stashed away for later use. Instead, + // let's just send an empty control with GUID_NULL. + NTSTATUS ntStatusTest = + pPortClsRuntimePower->SendPowerControl + ( + _pDeviceObject, + &GUID_NULL, + NULL, + 0, + NULL, + 0, + NULL + ); + + if (NT_SUCCESS(ntStatusTest) || STATUS_NOT_IMPLEMENTED == ntStatusTest || STATUS_NOT_SUPPORTED == ntStatusTest) + { + ntStatus = pPortClsRuntimePower->RegisterPowerControlCallback(_pDeviceObject, &PowerControlCallback, NULL); + if (NT_SUCCESS(ntStatus)) + { + ntStatus = pPortClsRuntimePower->UnregisterPowerControlCallback(_pDeviceObject); + } + } + else + { + ntStatus = ntStatusTest; + } + + pPortClsRuntimePower->Release(); + } +#endif // _USE_IPortClsRuntimePower + + // + // Test: add and remove current thread as streaming audio resource. + // In a real driver you should only add interrupts and driver-owned threads + // (i.e., do not add the current thread as streaming resource). + // + ntStatus = unknownWave->QueryInterface(IID_IPortClsStreamResourceManager, (PVOID *)&pPortClsResMgr); + if (NT_SUCCESS(ntStatus)) + { + PCSTREAMRESOURCE_DESCRIPTOR res; + PCSTREAMRESOURCE hRes = NULL; + PDEVICE_OBJECT pdo = NULL; + + PcGetPhysicalDeviceObject(_pDeviceObject, &pdo); + PCSTREAMRESOURCE_DESCRIPTOR_INIT(&res); + res.Pdo = pdo; + res.Type = ePcStreamResourceThread; + res.Resource.Thread = PsGetCurrentThread(); + + NTSTATUS ntStatusTest = pPortClsResMgr->AddStreamResource(NULL, &res, &hRes); + if (NT_SUCCESS(ntStatusTest)) + { + pPortClsResMgr->RemoveStreamResource(hRes); + hRes = NULL; + } + + pPortClsResMgr->Release(); + pPortClsResMgr = NULL; + } + } + + SAFE_RELEASE(unknownTopology); + SAFE_RELEASE(unknownWave); + + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS +InstallAllRenderFilters( + _In_ PDEVICE_OBJECT _pDeviceObject, + _In_ PIRP _pIrp, + _In_ PADAPTERCOMMON _pAdapterCommon + ) +{ + NTSTATUS ntStatus; + PENDPOINT_MINIPAIR* ppAeMiniports = g_RenderEndpoints; + + PAGED_CODE(); + + for(ULONG i = 0; i < g_cRenderEndpoints; ++i, ++ppAeMiniports) + { + ntStatus = InstallEndpointRenderFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports); + IF_FAILED_JUMP(ntStatus, Exit); + } + + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS +InstallEndpointCaptureFilters( + _In_ PDEVICE_OBJECT _pDeviceObject, + _In_ PIRP _pIrp, + _In_ PADAPTERCOMMON _pAdapterCommon, + _In_ PENDPOINT_MINIPAIR _pAeMiniports + ) +{ + NTSTATUS ntStatus = STATUS_SUCCESS; + + PAGED_CODE(); + + UNREFERENCED_PARAMETER(_pDeviceObject); + + ntStatus = _pAdapterCommon->InstallEndpointFilters( + _pIrp, + _pAeMiniports, + NULL, + NULL, + NULL); + + return ntStatus; +} + +#pragma code_seg("PAGE") +NTSTATUS +InstallAllCaptureFilters( + _In_ PDEVICE_OBJECT _pDeviceObject, + _In_ PIRP _pIrp, + _In_ PADAPTERCOMMON _pAdapterCommon + ) +{ + NTSTATUS ntStatus; + PENDPOINT_MINIPAIR* ppAeMiniports = g_CaptureEndpoints; + + PAGED_CODE(); + + for(ULONG i = 0; i < g_cCaptureEndpoints; ++i, ++ppAeMiniports) + { + ntStatus = InstallEndpointCaptureFilters(_pDeviceObject, _pIrp, _pAdapterCommon, *ppAeMiniports); + IF_FAILED_JUMP(ntStatus, Exit); + } + + ntStatus = STATUS_SUCCESS; + +Exit: + return ntStatus; +} + +#ifdef _USE_SingleComponentMultiFxStates +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +UseSingleComponentMultiFxStates( + _In_ PDEVICE_OBJECT DeviceObject + +) +{ + NTSTATUS status; + PC_POWER_FRAMEWORK_SETTINGS poFxSettings; + PO_FX_COMPONENT component; + PO_FX_COMPONENT_IDLE_STATE idleStates[SYSVAD_FSTATE_COUNT]; + + // + // Note that we initialize the 'idleStates' array below based on the + // assumption that SYSVAD_FSTATE_COUNT is 4. + // If we increase the value of SYSVAD_FSTATE_COUNT, we need to initialize those + // additional F-states below. If we decrease the value of SYSVAD_FSTATE_COUNT, + // we need to remove the corresponding initializations below. + // + C_ASSERT(SYSVAD_FSTATE_COUNT == 4); + + PAGED_CODE(); + + // + // Initialization + // + RtlZeroMemory(&component, sizeof(component)); + RtlZeroMemory(idleStates, sizeof(idleStates)); + + // + // F0 + // + idleStates[0].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(SYSVAD_F0_LATENCY_IN_MS); + idleStates[0].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(SYSVAD_F0_RESIDENCY_IN_SEC); + idleStates[0].NominalPower = 0; + + // + // F1 + // + idleStates[1].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(SYSVAD_F1_LATENCY_IN_MS); + idleStates[1].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(SYSVAD_F1_RESIDENCY_IN_SEC); + idleStates[1].NominalPower = 0; + + // + // F2 + // + idleStates[2].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(SYSVAD_F2_LATENCY_IN_MS); + idleStates[2].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(SYSVAD_F2_RESIDENCY_IN_SEC); + idleStates[2].NominalPower = 0; + + // + // F3 + // + idleStates[3].TransitionLatency = WDF_ABS_TIMEOUT_IN_MS(SYSVAD_F3_LATENCY_IN_MS); + idleStates[3].ResidencyRequirement = WDF_ABS_TIMEOUT_IN_SEC(SYSVAD_F3_RESIDENCY_IN_SEC); + idleStates[3].NominalPower = 0; + + // + // Component 0 (the only component) + // + component.IdleStateCount = SYSVAD_FSTATE_COUNT; + component.IdleStates = idleStates; + + PC_POWER_FRAMEWORK_SETTINGS_INIT(&poFxSettings); + + poFxSettings.EvtPcPostPoFxRegisterDevice = PcPowerFxRegisterDevice; + poFxSettings.EvtPcPrePoFxUnregisterDevice = PcPowerFxUnregisterDevice; + poFxSettings.ComponentIdleStateCallback = PcPowerFxComponentIdleStateCallback; + poFxSettings.ComponentActiveConditionCallback = PcPowerFxComponentActiveConditionCallback; + poFxSettings.ComponentIdleConditionCallback = PcPowerFxComponentIdleConditionCallback; + poFxSettings.PowerControlCallback = PcPowerFxPowerControlCallback; + + poFxSettings.Component = &component; + poFxSettings.PoFxDeviceContext = (PVOID) DeviceObject; + + status = PcAssignPowerFrameworkSettings(DeviceObject, &poFxSettings); + if (!NT_SUCCESS(status)) { + DPF(D_ERROR, ("PcAssignPowerFrameworkSettings failed with status 0x%x", status)); + } + + return status; +} +#endif // _USE_SingleComponentMultiFxStates + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +StartDevice +( + _In_ PDEVICE_OBJECT DeviceObject, + _In_ PIRP Irp, + _In_ PRESOURCELIST ResourceList +) +{ +/*++ + +Routine Description: + + This function is called by the operating system when the device is + started. + It is responsible for starting the miniports. This code is specific to + the adapter because it calls out miniports for functions that are specific + to the adapter. + +Arguments: + + DeviceObject - pointer to the driver object + + Irp - pointer to the irp + + ResourceList - pointer to the resource list assigned by PnP manager + +Return Value: + + NT status code. + +--*/ + UNREFERENCED_PARAMETER(ResourceList); + + PAGED_CODE(); + + ASSERT(DeviceObject); + ASSERT(Irp); + ASSERT(ResourceList); + + NTSTATUS ntStatus = STATUS_SUCCESS; + + PADAPTERCOMMON pAdapterCommon = NULL; + PUNKNOWN pUnknownCommon = NULL; + PortClassDeviceContext* pExtension = static_cast<PortClassDeviceContext*>(DeviceObject->DeviceExtension); + + DPF_ENTER(("[StartDevice]")); + + // + // create a new adapter common object + // + ntStatus = NewAdapterCommon( + &pUnknownCommon, + IID_IAdapterCommon, + NULL, + NonPagedPoolNx + ); + IF_FAILED_JUMP(ntStatus, Exit); + + ntStatus = pUnknownCommon->QueryInterface( IID_IAdapterCommon,(PVOID *) &pAdapterCommon); + IF_FAILED_JUMP(ntStatus, Exit); + + ntStatus = pAdapterCommon->Init(DeviceObject); + IF_FAILED_JUMP(ntStatus, Exit); + + // + // register with PortCls for power-management services + ntStatus = PcRegisterAdapterPowerManagement( PUNKNOWN(pAdapterCommon), DeviceObject); + IF_FAILED_JUMP(ntStatus, Exit); + + // + // Install wave+topology filters for render devices + // + ntStatus = InstallAllRenderFilters(DeviceObject, Irp, pAdapterCommon); + IF_FAILED_JUMP(ntStatus, Exit); + + // + // Install wave+topology filters for capture devices + // + ntStatus = InstallAllCaptureFilters(DeviceObject, Irp, pAdapterCommon); + IF_FAILED_JUMP(ntStatus, Exit); + +#ifdef SYSVAD_BTH_BYPASS + if (!g_DisableBthScoBypass) + { + // + // Init infrastructure for Bluetooth HFP - SCO Bypass devices. + // + ntStatus = pAdapterCommon->InitBthScoBypass(); + IF_FAILED_JUMP(ntStatus, Exit); + } +#endif // SYSVAD_BTH_BYPASS + +#ifdef _USE_SingleComponentMultiFxStates + // + // Init single component - multi Fx states + // + ntStatus = UseSingleComponentMultiFxStates(DeviceObject); + IF_FAILED_JUMP(ntStatus, Exit); +#endif // _USE_SingleComponentMultiFxStates + +Exit: + + // + // Stash the adapter common object in the device extension so + // we can access it for cleanup on stop/removal. + // + if (pAdapterCommon) + { + ASSERT(pExtension != NULL); + pExtension->m_pCommon = pAdapterCommon; + } + + // + // Release the adapter IUnknown interface. + // + SAFE_RELEASE(pUnknownCommon); + + return ntStatus; +} // StartDevice + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +PnpHandler +( + _In_ DEVICE_OBJECT *_DeviceObject, + _Inout_ IRP *_Irp +) +/*++ + +Routine Description: + + Handles PnP IRPs + +Arguments: + + _DeviceObject - Functional Device object pointer. + + _Irp - The Irp being passed + +Return Value: + + NT status code. + +--*/ +{ + NTSTATUS ntStatus = STATUS_UNSUCCESSFUL; + IO_STACK_LOCATION *stack; + PortClassDeviceContext *ext; + + PAGED_CODE(); + + ASSERT(_DeviceObject); + ASSERT(_Irp); + + // + // Check for the REMOVE_DEVICE irp. If we're being unloaded, + // uninstantiate our devices and release the adapter common + // object. + // + stack = IoGetCurrentIrpStackLocation(_Irp); + + + if ((IRP_MN_REMOVE_DEVICE == stack->MinorFunction) || + (IRP_MN_SURPRISE_REMOVAL == stack->MinorFunction) || + (IRP_MN_STOP_DEVICE == stack->MinorFunction)) + { + ext = static_cast<PortClassDeviceContext*>(_DeviceObject->DeviceExtension); + + if (ext->m_pCommon != NULL) + { + ext->m_pCommon->Cleanup(); + + ext->m_pCommon->Release(); + ext->m_pCommon = NULL; + } + } + + ntStatus = PcDispatchIrp(_DeviceObject, _Irp); + + return ntStatus; +} + +#pragma code_seg() + |
