diff options
| author | Girish Pattabiraman <[email protected]> | 2018-11-12 18:08:19 -0800 |
|---|---|---|
| committer | Adonais Romero González <[email protected]> | 2018-11-12 18:08:19 -0800 |
| commit | 995e20f6dbca7ad10a039fa62a2de69eed092ffc (patch) | |
| tree | 67075f06fd8aaedad732d6c73b682c6e0fda9dba /audio/sysvad/common.cpp | |
| parent | c9110a3bc1634a5be8e7922119ad383311104095 (diff) | |
RS5 Updates (#311)
* Format Changes
==============
* Add KSEVENT_PINCAPS_FORMATCHANGE to Bluetooth HFP Endpoints
* Remove 8 bit formats from Bluetooth HFP Endpoints
Name Template
==============
* Bluetooth Endpoints are now based on templates in INF and then customized with endpoints specific data
Sideband Common Interface for future Sideband buses
===================================================
* Add ISidebandDevice
* Add current directory to TabletAudioSample include path. Remove unused compiler flags.
* RS4 bug fixes
* Replace FastMutex with Spinlock for DeviceFormatsAndModes to work well at DISPATCH_LEVEL
* Resync with Microsoft-master branch
* Replace FastMutex with Spinlock for DeviceFormatsAndModes to work well at DISPATCH_LEVEL
* RS5 updates:
- USB Sideband implementation
- Power management options: _USE_IPortClsRuntimePower, _USE_SingleComponentMultiFxStates
Diffstat (limited to 'audio/sysvad/common.cpp')
| -rw-r--r-- | audio/sysvad/common.cpp | 902 |
1 files changed, 902 insertions, 0 deletions
diff --git a/audio/sysvad/common.cpp b/audio/sysvad/common.cpp index a0e148ca..bccef495 100644 --- a/audio/sysvad/common.cpp +++ b/audio/sysvad/common.cpp @@ -30,6 +30,15 @@ Abstract: #include "BthhfpDevice.h" #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND +#include <usbspec.h> +#include <usb.h> +#include <SidebandAudio.h> +#include <USBSidebandAudio.h> +#include "UsbHsMinipairs.h" +#include "UsbHsDevice.h" +#endif // SYSVAD_USB_SIDEBAND + //----------------------------------------------------------------------------- // CSaveData statics //----------------------------------------------------------------------------- @@ -43,6 +52,10 @@ PDEVICE_OBJECT CSaveData::m_pDeviceObject = NULL; class BthHfpDevice; // Forward declaration. #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND +class UsbHsDevice; // Forward declaration. +#endif // SYSVAD_USB_SIDEBAND + /////////////////////////////////////////////////////////////////////////////// // CAdapterCommon // @@ -65,6 +78,16 @@ class CAdapterCommon : DWORD m_dwIdleRequests; +#ifdef SYSVAD_USB_SIDEBAND + typedef struct _SysvadPowerRelationsDo + { + LIST_ENTRY ListEntry; + PDEVICE_OBJECT Pdo; + }SysVadPowerRelationsDo, *PSysVadPowerRelationsDo; + LIST_ENTRY m_PowerRelations; + FAST_MUTEX m_PowerRelationsLock; +#endif//SYSVAD_USB_SIDEBAND + public: //===================================================================== // Default CUnknown @@ -258,7 +281,25 @@ class CAdapterCommon : STDMETHODIMP_(VOID) CleanupBthScoBypass(); #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND + STDMETHODIMP_(NTSTATUS) InitUsbSideband(); + + STDMETHODIMP_(VOID) CleanupUsbSideband(); + + STDMETHODIMP_(NTSTATUS) AddDeviceAsPowerDependency + ( + _In_ PDEVICE_OBJECT pdo + ); + + STDMETHODIMP_(NTSTATUS) RemoveDeviceAsPowerDependency + ( + _In_ PDEVICE_OBJECT pdo + ); +#endif // SYSVAD_USB_SIDEBAND + STDMETHODIMP_(VOID) Cleanup(); + + STDMETHODIMP_(NTSTATUS) UpdatePowerRelations(_In_ PIRP Irp); //===================================================================== // friends @@ -311,6 +352,45 @@ class CAdapterCommon : ); #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND + //===================================================================== + // USB Sideband Audio support. + + private: + PVOID m_UsbSidebandNotificationHandle; + FAST_MUTEX m_UsbSidebandFastMutex; // To serialize access. + WDFWORKITEM m_UsbSidebandWorkItem; // Async work-item. + LIST_ENTRY m_UsbSidebandWorkTasks; // Work-item's tasks. + LIST_ENTRY m_UsbSidebandDevices; // USB Sideband devices. + NPAGED_LOOKASIDE_LIST m_UsbSidebandWorkTaskPool; // LookasideList + size_t m_UsbSidebandWorkTaskPoolElementSize; + BOOL m_UsbSidebandEnableCleanup; // Do cleanup if true. + + private: + static + DRIVER_NOTIFICATION_CALLBACK_ROUTINE EvtUsbSidebandInterfaceChange; + + static + EVT_WDF_WORKITEM EvtUsbSidebandInterfaceWorkItem; + + protected: + UsbHsDevice * UsbSidebandDeviceFind + ( + _In_ PUNICODE_STRING SymbolicLinkName + ); + + NTSTATUS UsbSidebandInterfaceArrival + ( + _In_ PUNICODE_STRING SymbolicLinkName + ); + + NTSTATUS UsbSidebandInterfaceRemoval + ( + _In_ PUNICODE_STRING SymbolicLinkName + ); + +#endif // SYSVAD_USB_SIDEBAND + private: LIST_ENTRY m_SubdeviceCache; @@ -524,6 +604,7 @@ Return Value: InterlockedDecrement(&CAdapterCommon::m_AdapterInstances); ASSERT(CAdapterCommon::m_AdapterInstances == 0); + ASSERT(IsListEmpty(&m_PowerRelations)); } // ~CAdapterCommon //============================================================================= @@ -640,6 +721,10 @@ Return Value: m_BthHfpEnableCleanup = FALSE; #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND + m_UsbSidebandEnableCleanup = FALSE; +#endif // SYSVAD_USB_SIDEBAND + m_pServiceGroupWave = NULL; m_pDeviceObject = DeviceObject; m_pPhysicalDeviceObject = NULL; @@ -650,6 +735,11 @@ Return Value: InitializeListHead(&m_SubdeviceCache); +#ifdef SYSVAD_USB_SIDEBAND + InitializeListHead(&m_PowerRelations); + ExInitializeFastMutex(&m_PowerRelationsLock); +#endif//SYSVAD_USB_SIDEBAND + // // Get the PDO. // @@ -2193,11 +2283,145 @@ CAdapterCommon::Cleanup() CleanupBthScoBypass(); #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND + // + // This ensures USB Sideband notifications are turned off when port class + // cleanups and unregisters the static subdevices. + // + CleanupUsbSideband(); +#endif // SYSVAD_USB_SIDEBAND + EmptySubdeviceCache(); } //============================================================================= #pragma code_seg("PAGE") +NTSTATUS +CAdapterCommon::UpdatePowerRelations(_In_ PIRP Irp) +{ + PDEVICE_RELATIONS priorRelations = NULL; + PDEVICE_RELATIONS newRelations = NULL; + ULONG qprPdosCount = 0; + ULONG count = 0; + size_t size; + NTSTATUS status = STATUS_SUCCESS; + ULONG i = 0; + PLIST_ENTRY pe = NULL; + + ExAcquireFastMutex(&m_PowerRelationsLock); + + pe = m_PowerRelations.Flink; + while (pe != &m_PowerRelations) + { + pe = pe->Flink; + qprPdosCount++; + } + + if (0 == qprPdosCount) + { + DPF(D_ERROR, ("CAdapterCommon::UpdatePowerRelations: No PDOs in power relations")); + // Not an error. Just nothing to do. + newRelations = (PDEVICE_RELATIONS)(Irp->IoStatus.Information); + goto Exit; + } + + count = qprPdosCount; + + priorRelations = (PDEVICE_RELATIONS)Irp->IoStatus.Information; + if (priorRelations != NULL) + { + // + // Another driver in the stack may have added some entries. + // Make sure we allocate space for these additional entries. + // + count = priorRelations->Count + count; + } + + // + // Allocate space for the DEVICE_RELATIONS structure (which includes + // space for one PDEVICE_OBJECT, and then allocate enough additional + // space for the extra PDEVICE_OBJECTs we need. + // + size = sizeof(DEVICE_RELATIONS) + (count - 1) * sizeof(PDEVICE_OBJECT); + newRelations = (PDEVICE_RELATIONS)ExAllocatePoolWithTag(PagedPool, size, USBSIDEBANDTEST_POOLTAG015); + ASSERT(newRelations); + if (NULL == newRelations) + { + status = STATUS_INSUFFICIENT_RESOURCES; + DPF(D_ERROR, ("CAdapterCommon::UpdatePowerRelations: could not allocate memory")); + goto Exit; + } + + // + // If there was an existing device relations structure, copy + // the entries to the new structure. + // + RtlZeroMemory(newRelations, size); + if (priorRelations != NULL && priorRelations->Count > 0) + { + size = sizeof(DEVICE_RELATIONS) + (priorRelations->Count - 1) * sizeof(PDEVICE_OBJECT); + RtlCopyMemory(newRelations, priorRelations, size); + } + + // + // Add new relations to the DEVICE_RELATIONS structure. Pnp dictates that + // each PDO in the list be referenced. Pnp manager will deref the PDO. + // + pe = m_PowerRelations.Flink; + while (pe != &m_PowerRelations) + { + PSysVadPowerRelationsDo powerDepDo = CONTAINING_RECORD(pe, SysVadPowerRelationsDo, ListEntry); + pe = pe->Flink; + + newRelations->Objects[newRelations->Count] = powerDepDo->Pdo; + + // Add a reference on the PDO before returning it as a dependency. + // PnP will remove the reference when appropriate as per msdn. + // https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/irp-mn-query-device-relations#operation + ObReferenceObject(powerDepDo->Pdo); + + // + // update the count + // + newRelations->Count++; + } + +Exit: + ExReleaseFastMutex(&m_PowerRelationsLock); + + if (!NT_SUCCESS(status)) + { + // + // Dereference any previously reported relations before exiting. They + // are dereferenced here because the PNP manager will see error and not + // do anything while the driver which added these objects expects the + // pnp manager to do the dereference. Since this device is changing the + // status, it must act like the pnp manager. + // + if (priorRelations != NULL) + { + for (i = 0; i < priorRelations->Count; ++i) + { + ObDereferenceObject(priorRelations->Objects[i]); + } + } + + ASSERT(newRelations == NULL); + } + + if (priorRelations != NULL) + { + ExFreePool(priorRelations); + } + + Irp->IoStatus.Status = status; + Irp->IoStatus.Information = (ULONG_PTR)newRelations; + + return status; +} + +//============================================================================= +#pragma code_seg("PAGE") STDMETHODIMP_(NTSTATUS) CAdapterCommon::InstallEndpointFilters ( @@ -3149,6 +3373,684 @@ Routine Description: } #endif // SYSVAD_BTH_BYPASS +#ifdef SYSVAD_USB_SIDEBAND +// +// CAdapterCommon USB Sideband function implementation. +// + +//============================================================================= +#pragma code_seg("PAGE") +VOID +CAdapterCommon::EvtUsbSidebandInterfaceWorkItem +( + _In_ WDFWORKITEM WorkItem +) +/*++ + +Routine Description: + +The function handles the arrival or removal of a USB Sideband interface. + +Arguments: + +WorkItem - WDF work-item object. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[EvtUsbSidebandInterfaceWorkItem]")); + + CAdapterCommon * This; + + if (WorkItem == NULL) + { + return; + } + + This = GetUsbHsWorkItemContext(WorkItem)->Adapter; + ASSERT(This != NULL); + + for (;;) + { + PLIST_ENTRY le = NULL; + UsbHsWorkTask * task = NULL; + + // + // Retrieve a taask. + // + ExAcquireFastMutex(&This->m_UsbSidebandFastMutex); + if (!IsListEmpty(&This->m_UsbSidebandWorkTasks)) + { + le = RemoveHeadList(&This->m_UsbSidebandWorkTasks); + task = CONTAINING_RECORD(le, UsbHsWorkTask, ListEntry); + InitializeListHead(le); + } + ExReleaseFastMutex(&This->m_UsbSidebandFastMutex); + + if (task == NULL) + { + break; + } + + ASSERT(task->Device != NULL); + _Analysis_assume_(task->Device != NULL); + + // + // Process the task. + // + switch (task->Action) + { + case eUsbHsTaskStart: + task->Device->Start(); + break; + + case eUsbHsTaskStop: + task->Device->Stop(); + break; + + default: + DPF(D_ERROR, ("EvtUsbSidebandInterfaceWorkItem: invalid action %d", task->Action)); + break; + } + + // + // Release the ref we took on the device when we inserted the task in the queue. + // For a stop operation this may be the last reference. + // + SAFE_RELEASE(task->Device); + + // + // Free the task. + // + ExFreeToNPagedLookasideList(&This->m_UsbSidebandWorkTaskPool, task); + } +} + +//============================================================================= +#pragma code_seg("PAGE") +UsbHsDevice * +CAdapterCommon::UsbSidebandDeviceFind +( + _In_ PUNICODE_STRING SymbolicLinkName +) +/*++ + +Routine Description: + +The function looks for the specified device in the adapter's list. + +Arguments: + +SymbolicLinkName - interface's symbolic link. + +Return Value: + +UsbSidebandDevice pointer or NULL. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[CAdapterCommon::UsbSidebandDeviceFind]")); + + PLIST_ENTRY le = NULL; + UsbHsDevice * usbDevice = NULL; + + ExAcquireFastMutex(&m_UsbSidebandFastMutex); + + for (le = m_UsbSidebandDevices.Flink; le != &m_UsbSidebandDevices; le = le->Flink) + { + UsbHsDevice * tmpUsbHsDevice = UsbHsDevice::GetUsbHsDevice(le); + ASSERT(tmpUsbHsDevice != NULL); + + PUNICODE_STRING unicodeStr = tmpUsbHsDevice->GetSymbolicLinkName(); + ASSERT(unicodeStr != NULL); + + if (unicodeStr->Length == SymbolicLinkName->Length && + 0 == wcsncmp(unicodeStr->Buffer, SymbolicLinkName->Buffer, unicodeStr->Length / sizeof(WCHAR))) + { + // Found it! + usbDevice = tmpUsbHsDevice; + usbDevice->AddRef(); + break; + } + } + + ExReleaseFastMutex(&m_UsbSidebandFastMutex); + + return usbDevice; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CAdapterCommon::UsbSidebandInterfaceArrival +( + _In_ PUNICODE_STRING SymbolicLinkName +) +/*++ + +Routine Description: + +The function handles the arrival of a new USB Sideband interface. + +Arguments: + +SymbolicLinkName - new interface's symbolic link. + +Return Value: + +NT status code. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[CAdapterCommon::UsbSidebandInterfaceArrival]")); + + NTSTATUS ntStatus = STATUS_SUCCESS; + UsbHsDevice *usbHsDevice = NULL; + UsbHsWorkTask *usbHsWorkTask = NULL; + + DPF(D_VERBOSE, ("UsbSidebandInterfaceArrival: SymbolicLinkName %wZ", SymbolicLinkName)); + + // + // Check if the USB device is already present. + // According to the docs it is possible to receive two notifications for the same + // interface. + // + usbHsDevice = UsbSidebandDeviceFind(SymbolicLinkName); + if (usbHsDevice != NULL) + { + DPF(D_VERBOSE, ("UsbSidebandInterfaceArrival: USB device already present")); + SAFE_RELEASE(usbHsDevice); + ntStatus = STATUS_SUCCESS; + goto Done; + } + + // + // Alloc a new structure for this USB device. + // + usbHsDevice = new (NonPagedPoolNx, MINADAPTER_POOLTAG) UsbHsDevice(NULL); // NULL -> OuterUnknown + if (NULL == usbHsDevice) + { + DPF(D_ERROR, ("UsbSidebandInterfaceArrival: unable to allocate UsbSidebandDevice, out of memory")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + DPF(D_VERBOSE, ("UsbSidebandInterfaceArrival: created UsbSidebandDevice 0x%p ", usbHsDevice)); + + // + // Basic initialization of the USB Sideband interface. + // The audio miniport creation is done later by the UsbSidebandDevice.Start() + // which is invoked asynchronously by a worker thread. + // UsbSidebandDevice->Init() must be invoked just after the creation of the object. + // + ntStatus = usbHsDevice->Init(this, SymbolicLinkName); + IF_FAILED_JUMP(ntStatus, Done); + + // + // Get and init a work task. + // + usbHsWorkTask = (UsbHsWorkTask*)ExAllocateFromNPagedLookasideList(&m_UsbSidebandWorkTaskPool); + if (NULL == usbHsWorkTask) + { + DPF(D_ERROR, ("UsbSidebandInterfaceArrival: unable to allocate UsbSidebandWorkTask, out of memory")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // usbWorkTask->L.Size is set to sizeof(UsbSidebandWorkTask) in the Look Aside List configuration +#pragma warning(suppress: 6386) + RtlZeroMemory(usbHsWorkTask, sizeof(*usbHsWorkTask)); + usbHsWorkTask->Action = eUsbHsTaskStart; + InitializeListHead(&usbHsWorkTask->ListEntry); + // Note that usbDevice has one reference at this point. + usbHsWorkTask->Device = usbHsDevice; + + ExAcquireFastMutex(&m_UsbSidebandFastMutex); + + // + // Insert this new USB Sideband device in our list. + // + InsertTailList(&m_UsbSidebandDevices, usbHsDevice->GetListEntry()); + + // + // Add a new task for the worker thread. + // + InsertTailList(&m_UsbSidebandWorkTasks, &usbHsWorkTask->ListEntry); + usbHsDevice->AddRef(); // released when task runs. + + // + // Schedule a work-item if not already running. + // + WdfWorkItemEnqueue(m_UsbSidebandWorkItem); + + ExReleaseFastMutex(&m_UsbSidebandFastMutex); + +Done: + if (!NT_SUCCESS(ntStatus)) + { + // Release the last ref, this will delete the UsbSidebandDevice + SAFE_RELEASE(usbHsDevice); + + if (usbHsWorkTask != NULL) + { + ExFreeToNPagedLookasideList(&m_UsbSidebandWorkTaskPool, usbHsWorkTask); + usbHsWorkTask = NULL; + } + } + + return ntStatus; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CAdapterCommon::UsbSidebandInterfaceRemoval +( + _In_ PUNICODE_STRING SymbolicLinkName +) +/*++ + +Routine Description: + +The function handles the removal of a USB Sideband interface. + +Arguments: + +SymbolicLinkName - interface's symbolic link to remove. + +Return Value: + +NT status code. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[CAdapterCommon::UsbSidebandInterfaceRemoval]")); + + NTSTATUS ntStatus = STATUS_SUCCESS; + UsbHsDevice *usbHsDevice = NULL; + UsbHsWorkTask *usbHsWorkTask = NULL; + + DPF(D_VERBOSE, ("UsbSidebandInterfaceRemoval: SymbolicLinkName %wZ", SymbolicLinkName)); + + // + // Check if the USB device is present. + // + usbHsDevice = UsbSidebandDeviceFind(SymbolicLinkName); + if (usbHsDevice == NULL) + { + // This can happen if the init/start of the UsbSidebandDevice failed. + DPF(D_VERBOSE, ("UsbSidebandInterfaceRemoval: USB device not found")); + ntStatus = STATUS_SUCCESS; + goto Done; + } + + // + // Init a work task. + // + usbHsWorkTask = (UsbHsWorkTask*)ExAllocateFromNPagedLookasideList(&m_UsbSidebandWorkTaskPool); + if (NULL == usbHsWorkTask) + { + DPF(D_ERROR, ("UsbSidebandInterfaceRemoval: unable to allocate UsbSidebandWorkTask, out of memory")); + ntStatus = STATUS_INSUFFICIENT_RESOURCES; + goto Done; + } + + // usbWorkTask->L.Size is set to sizeof(UsbSidebandWorkTask) in the Look Aside List configuration +#pragma warning(suppress: 6386) + RtlZeroMemory(usbHsWorkTask, sizeof(*usbHsWorkTask)); + usbHsWorkTask->Action = eUsbHsTaskStop; + InitializeListHead(&usbHsWorkTask->ListEntry); + // Work-item callback will release the reference we got above from UsbSidebandDeviceFind. + usbHsWorkTask->Device = usbHsDevice; + + ExAcquireFastMutex(&m_UsbSidebandFastMutex); + + // + // Remove this USB device from our list and release the associated reference. + // + RemoveEntryList(usbHsDevice->GetListEntry()); + InitializeListHead(usbHsDevice->GetListEntry()); + usbHsDevice->Release(); // This is not the last ref. + + // + // Add a new task for the worker thread. + // + InsertTailList(&m_UsbSidebandWorkTasks, &usbHsWorkTask->ListEntry); + + // + // Schedule a work-item if not already running. + // + WdfWorkItemEnqueue(m_UsbSidebandWorkItem); + + ExReleaseFastMutex(&m_UsbSidebandFastMutex); + + // + // All done. + // + ntStatus = STATUS_SUCCESS; + +Done: + + if (!NT_SUCCESS(ntStatus)) + { + // Release the ref we got in find. + SAFE_RELEASE(usbHsDevice); + } + + return ntStatus; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CAdapterCommon::EvtUsbSidebandInterfaceChange( + _In_ PVOID NotificationPointer, + _Inout_opt_ PVOID Context +) +/*++ + +Routine Description: + +This callback is invoked when a new USB Sideband interface is added or removed. + +Arguments: +NotificationPointer - Interface change notification +Context - CAdapterCommon ptr. + +Return Value: + +NT status code. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[EvtUsbSidebandInterfaceChange]")); + + NTSTATUS ntStatus = STATUS_SUCCESS; + CAdapterCommon * This = NULL; + PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification = (PDEVICE_INTERFACE_CHANGE_NOTIFICATION)NotificationPointer; + + // + // Make sure this is the interface class we extect. Any other class guid + // is an error, but let it go since it is not fatal to the machine. + // + if (!IsEqualGUID(Notification->InterfaceClassGuid, GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HS_HCIBYPASS)) + { + DPF(D_VERBOSE, ("EvtUsbSidebandInterfaceChange: bad interface ClassGuid")); + ASSERTMSG("EvtUsbSidebandInterfaceChange: bad interface ClassGuid ", FALSE); + + goto Done; + } + + This = (CAdapterCommon *)Context; + ASSERT(This != NULL); + _Analysis_assume_(This != NULL); + + // + // Take action based on the event. Any other event type is an error, + // but let it go since it is not fatal to the machine. + // + if (IsEqualGUID(Notification->Event, GUID_DEVICE_INTERFACE_ARRIVAL)) + { + ntStatus = This->UsbSidebandInterfaceArrival(Notification->SymbolicLinkName); + } + else if (IsEqualGUID(Notification->Event, GUID_DEVICE_INTERFACE_REMOVAL)) + { + ntStatus = This->UsbSidebandInterfaceRemoval(Notification->SymbolicLinkName); + } + else + { + DPF(D_VERBOSE, ("EvtUsbSidebandInterfaceChange: bad " + "GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HCIBYPASS event")); + ASSERTMSG("EvtUsbSidebandInterfaceChange: bad " + "GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HCIBYPASS event ", FALSE); + + goto Done; + } + +Done: + return ntStatus; +} + +//============================================================================= +#pragma code_seg("PAGE") +NTSTATUS +CAdapterCommon::InitUsbSideband() +/*++ + +Routine Description: + +Initialize the USB Sideband environment. + +Return Value: + +NT status code. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[CAdapterCommon::InitUsbSideband]")); + + NTSTATUS ntStatus = STATUS_SUCCESS; + WDF_WORKITEM_CONFIG wiConfig; + WDF_OBJECT_ATTRIBUTES attributes; + UsbHsWorkItemContext * wiContext; + + // + // Init spin-lock, linked lists, work-item, event, etc. + // Init all members to default values. This basic init should not fail. + // + m_UsbSidebandWorkItem = NULL; + m_UsbSidebandNotificationHandle = NULL; + ExInitializeFastMutex(&m_UsbSidebandFastMutex); + InitializeListHead(&m_UsbSidebandWorkTasks); + InitializeListHead(&m_UsbSidebandDevices); + m_UsbSidebandWorkTaskPoolElementSize = sizeof(UsbHsWorkTask); + ExInitializeNPagedLookasideList(&m_UsbSidebandWorkTaskPool, + NULL, + NULL, + POOL_NX_ALLOCATION, + m_UsbSidebandWorkTaskPoolElementSize, + MINADAPTER_POOLTAG, + 0); + // + // Enable USB Sideband Cleanup. + // Do any allocation/initialization that can fail after this point. + // + m_UsbSidebandEnableCleanup = TRUE; + + // + // Allocate a WDF work-item. + // + WDF_WORKITEM_CONFIG_INIT(&wiConfig, EvtUsbSidebandInterfaceWorkItem); + wiConfig.AutomaticSerialization = FALSE; + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, UsbHsWorkItemContext); + attributes.ParentObject = GetWdfDevice(); + ntStatus = WdfWorkItemCreate(&wiConfig, + &attributes, + &m_UsbSidebandWorkItem); + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("InitUsbSideband: WdfWorkItemCreate failed: 0x%x", ntStatus)), + Done); + + wiContext = GetUsbHsWorkItemContext(m_UsbSidebandWorkItem); + wiContext->Adapter = this; // weak ref. + + // + // Register for USB Sideband interface changes. + // + ntStatus = IoRegisterPlugPlayNotification( + EventCategoryDeviceInterfaceChange, + PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES, + (PVOID)&GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HS_HCIBYPASS, + m_pDeviceObject->DriverObject, + EvtUsbSidebandInterfaceChange, + (PVOID)this, + &m_UsbSidebandNotificationHandle); + + IF_FAILED_ACTION_JUMP( + ntStatus, + DPF(D_ERROR, ("InitUsbSideband: IoRegisterPlugPlayNotification(GUID_DEVINTERFACE_USB_SIDEBAND_AUDIO_HCIBYPASS) failed: 0x%x", ntStatus)), + Done); + + // + // Initialization completed. + // + ntStatus = STATUS_SUCCESS; + +Done: + return ntStatus; +} + +//============================================================================= +#pragma code_seg() +NTSTATUS +CAdapterCommon::AddDeviceAsPowerDependency +( + _In_ PDEVICE_OBJECT pdo +) +{ + NTSTATUS status = STATUS_SUCCESS; + + // allocate SysVadPowerRelationsDo + PSysVadPowerRelationsDo powerDepDo = (PSysVadPowerRelationsDo)ExAllocatePoolWithTag(NonPagedPoolNx, sizeof(SysVadPowerRelationsDo), USBSIDEBANDTEST_POOLTAG014); + if (NULL == powerDepDo) + { + status = STATUS_INSUFFICIENT_RESOURCES; + DPF(D_ERROR, ("CAdapterCommon::AddDeviceAsPowerDependency could not allocate memory for list entry")); + goto exit; + } + + InitializeListHead(&powerDepDo->ListEntry); + powerDepDo->Pdo = pdo; + ObReferenceObject(pdo); + + // Add to list + ExAcquireFastMutex(&m_PowerRelationsLock); + + InsertTailList(&m_PowerRelations, &powerDepDo->ListEntry); + + ExReleaseFastMutex(&m_PowerRelationsLock); + + IoInvalidateDeviceRelations(m_pPhysicalDeviceObject, PowerRelations); + +exit: + return status; +} + +//============================================================================= +#pragma code_seg() +NTSTATUS +CAdapterCommon::RemoveDeviceAsPowerDependency +( + _In_ PDEVICE_OBJECT pdo +) +{ + NTSTATUS status = STATUS_SUCCESS; + + // Find in list + ExAcquireFastMutex(&m_PowerRelationsLock); + + PLIST_ENTRY pe = m_PowerRelations.Flink; + while (pe != &m_PowerRelations) + { + PSysVadPowerRelationsDo powerDepDo = CONTAINING_RECORD(pe, SysVadPowerRelationsDo, ListEntry); + pe = pe->Flink; + + if (powerDepDo->Pdo == pdo) + { + ObDereferenceObject(powerDepDo->Pdo); + RemoveEntryList(&powerDepDo->ListEntry); + ExFreePoolWithTag(powerDepDo, USBSIDEBANDTEST_POOLTAG014); + } + } + + ExReleaseFastMutex(&m_PowerRelationsLock); + + IoInvalidateDeviceRelations(m_pPhysicalDeviceObject, PowerRelations); + + return status; +} + +//============================================================================= +#pragma code_seg("PAGE") +VOID +CAdapterCommon::CleanupUsbSideband() +/*++ + +Routine Description: + +Cleanup the USB Sideband environment. + +--*/ +{ + PAGED_CODE(); + DPF_ENTER(("[CAdapterCommon::CleanupUsbSideband]")); + + // + // Do nothing if USB Sideband environment was not correctly initialized. + // + if (m_UsbSidebandEnableCleanup == FALSE) + { + return; + } + + // + // Unregister for USB Sideband interface changes. + // + if (m_UsbSidebandNotificationHandle != NULL) + { + (void)IoUnregisterPlugPlayNotificationEx(m_UsbSidebandNotificationHandle); + m_UsbSidebandNotificationHandle = NULL; + } + + // + // Wait for the USB Sideband worker thread to be done. + // + if (m_UsbSidebandWorkItem != NULL) + { + WdfWorkItemFlush(m_UsbSidebandWorkItem); + WdfObjectDelete(m_UsbSidebandWorkItem); + m_UsbSidebandWorkItem = NULL; + } + + ASSERT(IsListEmpty(&m_UsbSidebandWorkTasks)); + + // + // Stop and delete all UsbSidebandDevices. We are the only thread accessing this list, + // so there is no need to acquire the mutex. + // + while (!IsListEmpty(&m_UsbSidebandDevices)) + { + UsbHsDevice * usbHsDevice = NULL; + PLIST_ENTRY le = NULL; + + le = RemoveHeadList(&m_UsbSidebandDevices); + + usbHsDevice = UsbHsDevice::GetUsbHsDevice(le); + InitializeListHead(le); + + // usbDevice is invalid after this call. + usbHsDevice->Stop(); + + // This should be the last reference. + usbHsDevice->Release(); + } + + ASSERT(IsListEmpty(&m_UsbSidebandDevices)); + + // + // General cleanup. + // + ExDeleteNPagedLookasideList(&m_UsbSidebandWorkTaskPool); +} +#endif // SYSVAD_USB_SIDEBAND + #pragma code_seg("PAGE") NTSTATUS CopyRegistryValues(HANDLE _hSourceKey, HANDLE _hDestinationKey) |
