1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/port_dmus.cpp 5 * PURPOSE: DirectMusic Port driver 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "private.hpp" 10 11 #ifndef YDEBUG 12 #define NDEBUG 13 #endif 14 15 #include <debug.h> 16 17 class CPortDMus : public IPortDMus, 18 public ISubdevice 19 { 20 public: 21 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 22 23 STDMETHODIMP_(ULONG) AddRef() 24 { 25 InterlockedIncrement(&m_Ref); 26 return m_Ref; 27 } 28 STDMETHODIMP_(ULONG) Release() 29 { 30 InterlockedDecrement(&m_Ref); 31 32 if (!m_Ref) 33 { 34 delete this; 35 return 0; 36 } 37 return m_Ref; 38 } 39 IMP_IPortDMus; 40 IMP_ISubdevice; 41 CPortDMus(IUnknown *OuterUnknown){} 42 virtual ~CPortDMus(){} 43 44 protected: 45 46 BOOL m_bInitialized; 47 IMiniportDMus * m_pMiniport; 48 IMiniportMidi * m_pMiniportMidi; 49 DEVICE_OBJECT * m_pDeviceObject; 50 PSERVICEGROUP m_ServiceGroup; 51 PPINCOUNT m_pPinCount; 52 PPOWERNOTIFY m_pPowerNotify; 53 PPORTFILTERDMUS m_Filter; 54 55 PPCFILTER_DESCRIPTOR m_pDescriptor; 56 PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor; 57 58 LONG m_Ref; 59 60 friend VOID GetDMusMiniport(IN IPortDMus * iface, IN PMINIPORTDMUS * Miniport, IN PMINIPORTMIDI * MidiMiniport); 61 62 }; 63 64 static GUID InterfaceGuids[3] = 65 { 66 { 67 /// KS_CATEGORY_AUDIO 68 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} 69 }, 70 { 71 /// KS_CATEGORY_RENDER 72 0x65E8773E, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} 73 }, 74 { 75 /// KS_CATEGORY_CAPTURE 76 0x65E8773D, 0x8F56, 0x11D0, {0xA3, 0xB9, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} 77 } 78 }; 79 80 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterDMusTopologySet, TopologyPropertyHandler); 81 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterDMusPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler); 82 83 KSPROPERTY_SET PortDMusPropertySet[] = 84 { 85 { 86 &KSPROPSETID_Topology, 87 sizeof(PortFilterDMusTopologySet) / sizeof(KSPROPERTY_ITEM), 88 (const KSPROPERTY_ITEM*)&PortFilterDMusTopologySet, 89 0, 90 NULL 91 }, 92 { 93 &KSPROPSETID_Pin, 94 sizeof(PortFilterDMusPinSet) / sizeof(KSPROPERTY_ITEM), 95 (const KSPROPERTY_ITEM*)&PortFilterDMusPinSet, 96 0, 97 NULL 98 } 99 }; 100 101 102 //--------------------------------------------------------------- 103 // IUnknown interface functions 104 // 105 106 NTSTATUS 107 NTAPI 108 CPortDMus::QueryInterface( 109 IN REFIID refiid, 110 OUT PVOID* Output) 111 { 112 UNICODE_STRING GuidString; 113 114 if (IsEqualGUIDAligned(refiid, IID_IPortDMus) || 115 IsEqualGUIDAligned(refiid, IID_IPortMidi) || 116 IsEqualGUIDAligned(refiid, IID_IPort) || 117 IsEqualGUIDAligned(refiid, IID_IUnknown)) 118 { 119 *Output = PVOID(PUNKNOWN((IPortDMus*)this)); 120 PUNKNOWN(*Output)->AddRef(); 121 return STATUS_SUCCESS; 122 } 123 else if (IsEqualGUIDAligned(refiid, IID_ISubdevice)) 124 { 125 *Output = PVOID(PSUBDEVICE(this)); 126 PUNKNOWN(*Output)->AddRef(); 127 return STATUS_SUCCESS; 128 } 129 else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) || 130 IsEqualGUIDAligned(refiid, IID_IDrmPort2)) 131 { 132 return NewIDrmPort((PDRMPORT2*)Output); 133 } 134 else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion)) 135 { 136 return NewPortClsVersion((PPORTCLSVERSION*)Output); 137 } 138 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice)) 139 { 140 return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output); 141 } 142 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection)) 143 { 144 return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output); 145 } 146 147 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) 148 { 149 DPRINT("IPortMidi_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer); 150 RtlFreeUnicodeString(&GuidString); 151 } 152 return STATUS_UNSUCCESSFUL; 153 } 154 155 //--------------------------------------------------------------- 156 // IPort interface functions 157 // 158 159 NTSTATUS 160 NTAPI 161 CPortDMus::GetDeviceProperty( 162 IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty, 163 IN ULONG BufferLength, 164 OUT PVOID PropertyBuffer, 165 OUT PULONG ReturnLength) 166 { 167 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 168 169 if (!m_bInitialized) 170 { 171 DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n"); 172 return STATUS_UNSUCCESSFUL; 173 } 174 175 return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength); 176 } 177 178 NTSTATUS 179 NTAPI 180 CPortDMus::Init( 181 IN PDEVICE_OBJECT DeviceObject, 182 IN PIRP Irp, 183 IN PUNKNOWN UnknownMiniport, 184 IN PUNKNOWN UnknownAdapter OPTIONAL, 185 IN PRESOURCELIST ResourceList) 186 { 187 IMiniportDMus * Miniport = NULL; 188 IMiniportMidi * MidiMiniport = NULL; 189 NTSTATUS Status; 190 PSERVICEGROUP ServiceGroup = NULL; 191 PPINCOUNT PinCount; 192 PPOWERNOTIFY PowerNotify; 193 194 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 195 196 if (m_bInitialized) 197 { 198 DPRINT("IPortDMus_Init called again\n"); 199 return STATUS_SUCCESS; 200 } 201 202 Status = UnknownMiniport->QueryInterface(IID_IMiniportDMus, (PVOID*)&Miniport); 203 if (!NT_SUCCESS(Status)) 204 { 205 // check for legacy interface 206 Status = UnknownMiniport->QueryInterface(IID_IMiniportMidi, (PVOID*)&MidiMiniport); 207 if (!NT_SUCCESS(Status)) 208 { 209 DPRINT("IPortDMus_Init called with invalid IMiniport adapter\n"); 210 return STATUS_INVALID_PARAMETER; 211 } 212 } 213 214 // Initialize port object 215 m_pMiniport = Miniport; 216 m_pMiniportMidi = MidiMiniport; 217 m_pDeviceObject = DeviceObject; 218 m_bInitialized = TRUE; 219 220 if (Miniport) 221 { 222 // initialize IMiniportDMus 223 Status = Miniport->Init(UnknownAdapter, ResourceList, this, &ServiceGroup); 224 if (!NT_SUCCESS(Status)) 225 { 226 DPRINT("IMiniportDMus_Init failed with %x\n", Status); 227 m_bInitialized = FALSE; 228 return Status; 229 } 230 231 // get the miniport device descriptor 232 Status = Miniport->GetDescription(&m_pDescriptor); 233 if (!NT_SUCCESS(Status)) 234 { 235 DPRINT("failed to get description\n"); 236 Miniport->Release(); 237 m_bInitialized = FALSE; 238 return Status; 239 } 240 241 // increment reference on miniport adapter 242 Miniport->AddRef(); 243 244 } 245 else 246 { 247 // initialize IMiniportMidi 248 Status = MidiMiniport->Init(UnknownAdapter, ResourceList, (IPortMidi*)this, &ServiceGroup); 249 if (!NT_SUCCESS(Status)) 250 { 251 DPRINT("IMiniportMidi_Init failed with %x\n", Status); 252 m_bInitialized = FALSE; 253 return Status; 254 } 255 256 // get the miniport device descriptor 257 Status = MidiMiniport->GetDescription(&m_pDescriptor); 258 if (!NT_SUCCESS(Status)) 259 { 260 DPRINT("failed to get description\n"); 261 MidiMiniport->Release(); 262 m_bInitialized = FALSE; 263 return Status; 264 } 265 266 // increment reference on miniport adapter 267 MidiMiniport->AddRef(); 268 } 269 270 // create the subdevice descriptor 271 Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor, 272 3, 273 InterfaceGuids, 274 0, 275 NULL, 276 2, 277 PortDMusPropertySet, 278 0, 279 0, 280 0, 281 NULL, 282 0, 283 NULL, 284 m_pDescriptor); 285 286 if (!NT_SUCCESS(Status)) 287 { 288 DPRINT("Failed to create descriptor\n"); 289 290 if (Miniport) 291 Miniport->Release(); 292 else 293 MidiMiniport->Release(); 294 295 m_bInitialized = FALSE; 296 return Status; 297 } 298 299 if (m_ServiceGroup == NULL && ServiceGroup) 300 { 301 // register service group 302 m_ServiceGroup = ServiceGroup; 303 } 304 305 // check if it supports IPinCount interface 306 Status = UnknownMiniport->QueryInterface(IID_IPinCount, (PVOID*)&PinCount); 307 if (NT_SUCCESS(Status)) 308 { 309 // store IPinCount interface 310 m_pPinCount = PinCount; 311 } 312 313 // does the Miniport adapter support IPowerNotify interface*/ 314 Status = UnknownMiniport->QueryInterface(IID_IPowerNotify, (PVOID*)&PowerNotify); 315 if (NT_SUCCESS(Status)) 316 { 317 // store reference 318 m_pPowerNotify = PowerNotify; 319 } 320 321 return STATUS_SUCCESS; 322 } 323 324 325 NTSTATUS 326 NTAPI 327 CPortDMus::NewRegistryKey( 328 OUT PREGISTRYKEY *OutRegistryKey, 329 IN PUNKNOWN OuterUnknown OPTIONAL, 330 IN ULONG RegistryKeyType, 331 IN ACCESS_MASK DesiredAccess, 332 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 333 IN ULONG CreateOptions OPTIONAL, 334 OUT PULONG Disposition OPTIONAL) 335 { 336 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 337 338 if (!m_bInitialized) 339 { 340 DPRINT("IPortDMus_fnNewRegistryKey called w/o initialized\n"); 341 return STATUS_UNSUCCESSFUL; 342 } 343 344 return PcNewRegistryKey(OutRegistryKey, 345 OuterUnknown, 346 RegistryKeyType, 347 DesiredAccess, 348 m_pDeviceObject, 349 (ISubdevice*)this, 350 ObjectAttributes, 351 CreateOptions, 352 Disposition); 353 } 354 355 VOID 356 NTAPI 357 CPortDMus::Notify( 358 IN PSERVICEGROUP ServiceGroup OPTIONAL) 359 { 360 if (ServiceGroup) 361 { 362 ServiceGroup->RequestService (); 363 return; 364 } 365 366 PC_ASSERT(m_ServiceGroup); 367 368 // notify miniport service group 369 m_ServiceGroup->RequestService(); 370 371 // notify stream miniport service group 372 if (m_Filter) 373 { 374 m_Filter->NotifyPins(); 375 } 376 } 377 378 VOID 379 NTAPI 380 CPortDMus::RegisterServiceGroup( 381 IN PSERVICEGROUP ServiceGroup) 382 { 383 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 384 385 m_ServiceGroup = ServiceGroup; 386 387 ServiceGroup->AddMember(PSERVICESINK(this)); 388 } 389 //--------------------------------------------------------------- 390 // ISubdevice interface 391 // 392 393 NTSTATUS 394 NTAPI 395 CPortDMus::NewIrpTarget( 396 OUT struct IIrpTarget **OutTarget, 397 IN PCWSTR Name, 398 IN PUNKNOWN Unknown, 399 IN POOL_TYPE PoolType, 400 IN PDEVICE_OBJECT DeviceObject, 401 IN PIRP Irp, 402 IN KSOBJECT_CREATE *CreateObject) 403 { 404 NTSTATUS Status; 405 PPORTFILTERDMUS Filter; 406 407 DPRINT("ISubDevice_NewIrpTarget this %p\n", this); 408 409 if (m_Filter) 410 { 411 *OutTarget = (IIrpTarget*)m_Filter; 412 return STATUS_SUCCESS; 413 } 414 415 416 Status = NewPortFilterDMus(&Filter); 417 if (!NT_SUCCESS(Status)) 418 { 419 return Status; 420 } 421 422 Status = Filter->Init(PPORTDMUS(this)); 423 if (!NT_SUCCESS(Status)) 424 { 425 Filter->Release(); 426 return Status; 427 } 428 429 *OutTarget = (IIrpTarget*)Filter; 430 return Status; 431 } 432 433 NTSTATUS 434 NTAPI 435 CPortDMus::ReleaseChildren() 436 { 437 UNIMPLEMENTED; 438 return STATUS_UNSUCCESSFUL; 439 } 440 441 NTSTATUS 442 NTAPI 443 CPortDMus::GetDescriptor( 444 IN SUBDEVICE_DESCRIPTOR ** Descriptor) 445 { 446 DPRINT("ISubDevice_GetDescriptor this %p\n", this); 447 *Descriptor = m_SubDeviceDescriptor; 448 return STATUS_SUCCESS; 449 } 450 451 NTSTATUS 452 NTAPI 453 CPortDMus::DataRangeIntersection( 454 IN ULONG PinId, 455 IN PKSDATARANGE DataRange, 456 IN PKSDATARANGE MatchingDataRange, 457 IN ULONG OutputBufferLength, 458 OUT PVOID ResultantFormat OPTIONAL, 459 OUT PULONG ResultantFormatLength) 460 { 461 DPRINT("ISubDevice_DataRangeIntersection this %p\n", this); 462 463 if (m_pMiniport) 464 { 465 return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength); 466 } 467 468 return STATUS_UNSUCCESSFUL; 469 } 470 471 NTSTATUS 472 NTAPI 473 CPortDMus::PowerChangeNotify( 474 IN POWER_STATE PowerState) 475 { 476 if (m_pPowerNotify) 477 { 478 m_pPowerNotify->PowerChangeNotify(PowerState); 479 } 480 481 return STATUS_SUCCESS; 482 } 483 484 485 NTSTATUS 486 NTAPI 487 CPortDMus::PinCount( 488 IN ULONG PinId, 489 IN OUT PULONG FilterNecessary, 490 IN OUT PULONG FilterCurrent, 491 IN OUT PULONG FilterPossible, 492 IN OUT PULONG GlobalCurrent, 493 IN OUT PULONG GlobalPossible) 494 { 495 if (m_pPinCount) 496 { 497 m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible); 498 return STATUS_SUCCESS; 499 } 500 501 // FIXME 502 // scan filter descriptor 503 504 return STATUS_UNSUCCESSFUL; 505 } 506 507 508 509 NTSTATUS 510 NewPortDMus( 511 OUT PPORT* OutPort) 512 { 513 NTSTATUS Status; 514 CPortDMus * Port = new(NonPagedPool, TAG_PORTCLASS) CPortDMus(NULL); 515 if (!Port) 516 return STATUS_INSUFFICIENT_RESOURCES; 517 518 Status = Port->QueryInterface(IID_IPort, (PVOID*)OutPort); 519 520 if (!NT_SUCCESS(Status)) 521 { 522 delete Port; 523 } 524 525 DPRINT("NewPortDMus %p Status %u\n", Port, Status); 526 return Status; 527 528 } 529 530 531 532 VOID 533 GetDMusMiniport( 534 IN IPortDMus * iface, 535 IN PMINIPORTDMUS * Miniport, 536 IN PMINIPORTMIDI * MidiMiniport) 537 { 538 CPortDMus * This = (CPortDMus*)iface; 539 540 *Miniport = This->m_pMiniport; 541 *MidiMiniport = This->m_pMiniportMidi; 542 } 543