1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/port_topology.cpp 5 * PURPOSE: Topology 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 CPortTopology : public IPortTopology, 18 public ISubdevice, 19 public IPortEvents 20 { 21 public: 22 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 23 24 STDMETHODIMP_(ULONG) AddRef() 25 { 26 InterlockedIncrement(&m_Ref); 27 return m_Ref; 28 } 29 STDMETHODIMP_(ULONG) Release() 30 { 31 InterlockedDecrement(&m_Ref); 32 33 if (!m_Ref) 34 { 35 delete this; 36 return 0; 37 } 38 return m_Ref; 39 } 40 IMP_IPortTopology; 41 IMP_ISubdevice; 42 IMP_IPortEvents; 43 CPortTopology(IUnknown *OuterUnknown){} 44 virtual ~CPortTopology(){} 45 46 protected: 47 BOOL m_bInitialized; 48 49 PMINIPORTTOPOLOGY m_pMiniport; 50 PDEVICE_OBJECT m_pDeviceObject; 51 PPINCOUNT m_pPinCount; 52 PPOWERNOTIFY m_pPowerNotify; 53 54 PPCFILTER_DESCRIPTOR m_pDescriptor; 55 PSUBDEVICE_DESCRIPTOR m_SubDeviceDescriptor; 56 IPortFilterTopology * m_Filter; 57 58 LONG m_Ref; 59 60 friend PMINIPORTTOPOLOGY GetTopologyMiniport(PPORTTOPOLOGY Port); 61 62 }; 63 64 static GUID InterfaceGuids[2] = 65 { 66 { 67 /// KS_CATEGORY_AUDIO 68 0x6994AD04, 0x93EF, 0x11D0, {0xA3, 0xCC, 0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96} 69 }, 70 { 71 /// KS_CATEGORY_TOPOLOGY 72 0xDDA54A40, 0x1E4C, 0x11D1, {0xA0, 0x50, 0x40, 0x57, 0x05, 0xC1, 0x00, 0x00} 73 } 74 }; 75 76 DEFINE_KSPROPERTY_TOPOLOGYSET(PortFilterTopologyTopologySet, TopologyPropertyHandler); 77 DEFINE_KSPROPERTY_PINPROPOSEDATAFORMAT(PortFilterTopologyPinSet, PinPropertyHandler, PinPropertyHandler, PinPropertyHandler); 78 79 KSPROPERTY_SET TopologyPropertySet[] = 80 { 81 { 82 &KSPROPSETID_Topology, 83 sizeof(PortFilterTopologyTopologySet) / sizeof(KSPROPERTY_ITEM), 84 (const KSPROPERTY_ITEM*)&PortFilterTopologyTopologySet, 85 0, 86 NULL 87 }, 88 { 89 &KSPROPSETID_Pin, 90 sizeof(PortFilterTopologyPinSet) / sizeof(KSPROPERTY_ITEM), 91 (const KSPROPERTY_ITEM*)&PortFilterTopologyPinSet, 92 0, 93 NULL 94 } 95 }; 96 97 //--------------------------------------------------------------- 98 // IPortEvents 99 // 100 101 102 void 103 NTAPI 104 CPortTopology::AddEventToEventList( 105 IN PKSEVENT_ENTRY EventEntry) 106 { 107 UNIMPLEMENTED; 108 } 109 110 void 111 NTAPI 112 CPortTopology::GenerateEventList( 113 IN GUID* Set OPTIONAL, 114 IN ULONG EventId, 115 IN BOOL PinEvent, 116 IN ULONG PinId, 117 IN BOOL NodeEvent, 118 IN ULONG NodeId) 119 { 120 UNIMPLEMENTED; 121 } 122 123 124 //--------------------------------------------------------------- 125 // IUnknown interface functions 126 // 127 128 NTSTATUS 129 NTAPI 130 CPortTopology::QueryInterface( 131 IN REFIID refiid, 132 OUT PVOID* Output) 133 { 134 UNICODE_STRING GuidString; 135 136 DPRINT("IPortTopology_fnQueryInterface\n"); 137 138 if (IsEqualGUIDAligned(refiid, IID_IPortTopology) || 139 IsEqualGUIDAligned(refiid, IID_IPort) || 140 IsEqualGUIDAligned(refiid, IID_IUnknown)) 141 { 142 *Output = PVOID(PUNKNOWN((IPortTopology*)this)); 143 PUNKNOWN(*Output)->AddRef(); 144 return STATUS_SUCCESS; 145 } 146 else if (IsEqualGUIDAligned(refiid, IID_IPortEvents)) 147 { 148 *Output = PVOID(PPORTEVENTS(this)); 149 PUNKNOWN(*Output)->AddRef(); 150 return STATUS_SUCCESS; 151 } 152 else if (IsEqualGUIDAligned(refiid, IID_ISubdevice)) 153 { 154 *Output = PVOID(PSUBDEVICE(this)); 155 PUNKNOWN(*Output)->AddRef(); 156 return STATUS_SUCCESS; 157 } 158 else if (IsEqualGUIDAligned(refiid, IID_IPortClsVersion)) 159 { 160 return NewPortClsVersion((PPORTCLSVERSION*)Output); 161 } 162 else if (IsEqualGUIDAligned(refiid, IID_IDrmPort) || 163 IsEqualGUIDAligned(refiid, IID_IDrmPort2)) 164 { 165 return NewIDrmPort((PDRMPORT2*)Output); 166 } 167 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterSubdevice)) 168 { 169 return NewIUnregisterSubdevice((PUNREGISTERSUBDEVICE*)Output); 170 } 171 else if (IsEqualGUIDAligned(refiid, IID_IUnregisterPhysicalConnection)) 172 { 173 return NewIUnregisterPhysicalConnection((PUNREGISTERPHYSICALCONNECTION*)Output); 174 } 175 176 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) 177 { 178 DPRINT1("IPortTopology_fnQueryInterface no interface!!! iface %S\n", GuidString.Buffer); 179 RtlFreeUnicodeString(&GuidString); 180 } 181 return STATUS_UNSUCCESSFUL; 182 } 183 184 //--------------------------------------------------------------- 185 // IPort interface functions 186 // 187 188 NTSTATUS 189 NTAPI 190 CPortTopology::GetDeviceProperty( 191 IN DEVICE_REGISTRY_PROPERTY DeviceRegistryProperty, 192 IN ULONG BufferLength, 193 OUT PVOID PropertyBuffer, 194 OUT PULONG ReturnLength) 195 { 196 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 197 198 if (!m_bInitialized) 199 { 200 DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n"); 201 return STATUS_UNSUCCESSFUL; 202 } 203 204 return IoGetDeviceProperty(m_pDeviceObject, DeviceRegistryProperty, BufferLength, PropertyBuffer, ReturnLength); 205 } 206 207 NTSTATUS 208 NTAPI 209 CPortTopology::Init( 210 IN PDEVICE_OBJECT DeviceObject, 211 IN PIRP Irp, 212 IN PUNKNOWN UnknownMiniport, 213 IN PUNKNOWN UnknownAdapter OPTIONAL, 214 IN PRESOURCELIST ResourceList) 215 { 216 IMiniportTopology * Miniport; 217 NTSTATUS Status; 218 219 DPRINT("IPortTopology_fnInit entered This %p DeviceObject %p Irp %p UnknownMiniport %p UnknownAdapter %p ResourceList %p\n", 220 this, DeviceObject, Irp, UnknownMiniport, UnknownAdapter, ResourceList); 221 222 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 223 224 if (m_bInitialized) 225 { 226 DPRINT("IPortTopology_Init called again\n"); 227 return STATUS_SUCCESS; 228 } 229 230 Status = UnknownMiniport->QueryInterface(IID_IMiniportTopology, (PVOID*)&Miniport); 231 if (!NT_SUCCESS(Status)) 232 { 233 DPRINT("IPortTopology_Init called with invalid IMiniport adapter\n"); 234 return STATUS_INVALID_PARAMETER; 235 } 236 237 // Initialize port object 238 m_pMiniport = Miniport; 239 m_pDeviceObject = DeviceObject; 240 m_bInitialized = TRUE; 241 242 // now initialize the miniport driver 243 Status = Miniport->Init(UnknownAdapter, ResourceList, this); 244 if (!NT_SUCCESS(Status)) 245 { 246 DPRINT("IPortTopology_Init failed with %x\n", Status); 247 m_bInitialized = FALSE; 248 Miniport->Release(); 249 return Status; 250 } 251 252 // get the miniport device descriptor 253 Status = Miniport->GetDescription(&m_pDescriptor); 254 if (!NT_SUCCESS(Status)) 255 { 256 DPRINT("failed to get description\n"); 257 Miniport->Release(); 258 m_bInitialized = FALSE; 259 return Status; 260 } 261 262 // create the subdevice descriptor 263 Status = PcCreateSubdeviceDescriptor(&m_SubDeviceDescriptor, 264 2, 265 InterfaceGuids, 266 0, 267 NULL, 268 2, 269 TopologyPropertySet, 270 0, 271 0, 272 0, 273 NULL, 274 0, 275 NULL, 276 m_pDescriptor); 277 278 279 DPRINT("IPortTopology_fnInit success\n"); 280 if (NT_SUCCESS(Status)) 281 { 282 // store for node property requests 283 m_SubDeviceDescriptor->UnknownMiniport = UnknownMiniport; 284 } 285 286 return STATUS_SUCCESS; 287 } 288 289 290 NTSTATUS 291 NTAPI 292 CPortTopology::NewRegistryKey( 293 OUT PREGISTRYKEY *OutRegistryKey, 294 IN PUNKNOWN OuterUnknown OPTIONAL, 295 IN ULONG RegistryKeyType, 296 IN ACCESS_MASK DesiredAccess, 297 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 298 IN ULONG CreateOptions OPTIONAL, 299 OUT PULONG Disposition OPTIONAL) 300 { 301 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 302 303 if (!m_bInitialized) 304 { 305 DPRINT("IPortTopology_fnNewRegistryKey called w/o initialized\n"); 306 return STATUS_UNSUCCESSFUL; 307 } 308 return PcNewRegistryKey(OutRegistryKey, 309 OuterUnknown, 310 RegistryKeyType, 311 DesiredAccess, 312 m_pDeviceObject, 313 (ISubdevice*)this, 314 ObjectAttributes, 315 CreateOptions, 316 Disposition); 317 } 318 319 //--------------------------------------------------------------- 320 // ISubdevice interface 321 // 322 323 NTSTATUS 324 NTAPI 325 CPortTopology::NewIrpTarget( 326 OUT struct IIrpTarget **OutTarget, 327 IN PCWSTR Name, 328 IN PUNKNOWN Unknown, 329 IN POOL_TYPE PoolType, 330 IN PDEVICE_OBJECT DeviceObject, 331 IN PIRP Irp, 332 IN KSOBJECT_CREATE *CreateObject) 333 { 334 NTSTATUS Status; 335 IPortFilterTopology * Filter; 336 337 // is there already an instance of the filter 338 if (m_Filter) 339 { 340 // it is, let's return the result 341 *OutTarget = (IIrpTarget*)m_Filter; 342 343 // increment reference 344 m_Filter->AddRef(); 345 return STATUS_SUCCESS; 346 } 347 348 // create new instance of filter 349 Status = NewPortFilterTopology(&Filter); 350 if (!NT_SUCCESS(Status)) 351 { 352 // not enough memory 353 return Status; 354 } 355 356 // initialize the filter 357 Status = Filter->Init((IPortTopology*)this); 358 if (!NT_SUCCESS(Status)) 359 { 360 // destroy filter 361 Filter->Release(); 362 // return status 363 return Status; 364 } 365 366 // store result 367 *OutTarget = (IIrpTarget*)Filter; 368 // store for later re-use 369 m_Filter = Filter; 370 // return status 371 return Status; 372 } 373 374 NTSTATUS 375 NTAPI 376 CPortTopology::ReleaseChildren() 377 { 378 DPRINT("ISubDevice_fnReleaseChildren\n"); 379 380 // release the filter 381 m_Filter->Release(); 382 383 // release the miniport 384 DPRINT("Refs %u\n", m_pMiniport->Release()); 385 386 return STATUS_SUCCESS; 387 } 388 389 NTSTATUS 390 NTAPI 391 CPortTopology::GetDescriptor( 392 IN SUBDEVICE_DESCRIPTOR ** Descriptor) 393 { 394 DPRINT("ISubDevice_GetDescriptor this %p Descp %p\n", this, m_SubDeviceDescriptor); 395 *Descriptor = m_SubDeviceDescriptor; 396 return STATUS_SUCCESS; 397 } 398 399 NTSTATUS 400 NTAPI 401 CPortTopology::DataRangeIntersection( 402 IN ULONG PinId, 403 IN PKSDATARANGE DataRange, 404 IN PKSDATARANGE MatchingDataRange, 405 IN ULONG OutputBufferLength, 406 OUT PVOID ResultantFormat OPTIONAL, 407 OUT PULONG ResultantFormatLength) 408 { 409 DPRINT("ISubDevice_DataRangeIntersection this %p\n", this); 410 411 if (m_pMiniport) 412 { 413 return m_pMiniport->DataRangeIntersection (PinId, DataRange, MatchingDataRange, OutputBufferLength, ResultantFormat, ResultantFormatLength); 414 } 415 416 return STATUS_UNSUCCESSFUL; 417 } 418 419 NTSTATUS 420 NTAPI 421 CPortTopology::PowerChangeNotify( 422 IN POWER_STATE PowerState) 423 { 424 if (m_pPowerNotify) 425 { 426 m_pPowerNotify->PowerChangeNotify(PowerState); 427 } 428 429 return STATUS_SUCCESS; 430 } 431 432 NTSTATUS 433 NTAPI 434 CPortTopology::PinCount( 435 IN ULONG PinId, 436 IN OUT PULONG FilterNecessary, 437 IN OUT PULONG FilterCurrent, 438 IN OUT PULONG FilterPossible, 439 IN OUT PULONG GlobalCurrent, 440 IN OUT PULONG GlobalPossible) 441 { 442 if (m_pPinCount) 443 { 444 m_pPinCount->PinCount(PinId, FilterNecessary, FilterCurrent, FilterPossible, GlobalCurrent, GlobalPossible); 445 return STATUS_SUCCESS; 446 } 447 448 // FIXME 449 // scan filter descriptor 450 451 return STATUS_UNSUCCESSFUL; 452 } 453 454 455 NTSTATUS 456 NTAPI 457 PcCreatePinDispatch( 458 IN PDEVICE_OBJECT DeviceObject, 459 IN PIRP Irp) 460 { 461 NTSTATUS Status; 462 IIrpTarget *Filter; 463 IIrpTarget *Pin; 464 PKSOBJECT_CREATE_ITEM CreateItem; 465 466 // access the create item 467 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp); 468 // sanity check 469 PC_ASSERT(CreateItem); 470 471 DPRINT("PcCreatePinDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer); 472 473 Filter = (IIrpTarget*)CreateItem->Context; 474 475 // sanity checks 476 PC_ASSERT(Filter != NULL); 477 PC_ASSERT_IRQL(PASSIVE_LEVEL); 478 479 480 #if KS_IMPLEMENTED 481 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader); 482 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED) 483 { 484 DPRINT("PcCreatePinDispatch failed to reference device header\n"); 485 486 FreeItem(Entry, TAG_PORTCLASS); 487 goto cleanup; 488 } 489 #endif 490 491 Status = Filter->NewIrpTarget(&Pin, 492 KSSTRING_Pin, 493 NULL, 494 NonPagedPool, 495 DeviceObject, 496 Irp, 497 NULL); 498 499 DPRINT("PcCreatePinDispatch Status %x\n", Status); 500 501 if (NT_SUCCESS(Status)) 502 { 503 // create the dispatch object 504 // FIXME need create item for clock 505 Status = NewDispatchObject(Irp, Pin, 0, NULL); 506 DPRINT("Pin %p\n", Pin); 507 } 508 509 DPRINT("CreatePinWorkerRoutine completing irp %p\n", Irp); 510 // save status in irp 511 Irp->IoStatus.Status = Status; 512 Irp->IoStatus.Information = 0; 513 // complete the request 514 IoCompleteRequest(Irp, IO_NO_INCREMENT); 515 return Status; 516 } 517 518 NTSTATUS 519 NTAPI 520 PcCreateItemDispatch( 521 IN PDEVICE_OBJECT DeviceObject, 522 IN PIRP Irp) 523 { 524 NTSTATUS Status; 525 ISubdevice * SubDevice; 526 IIrpTarget *Filter; 527 PKSOBJECT_CREATE_ITEM CreateItem, PinCreateItem; 528 529 // access the create item 530 CreateItem = KSCREATE_ITEM_IRP_STORAGE(Irp); 531 532 DPRINT("PcCreateItemDispatch called DeviceObject %p %S Name\n", DeviceObject, CreateItem->ObjectClass.Buffer); 533 534 // get the subdevice 535 SubDevice = (ISubdevice*)CreateItem->Context; 536 537 // sanity checks 538 PC_ASSERT(SubDevice != NULL); 539 540 541 #if KS_IMPLEMENTED 542 Status = KsReferenceSoftwareBusObject(DeviceExt->KsDeviceHeader); 543 if (!NT_SUCCESS(Status) && Status != STATUS_NOT_IMPLEMENTED) 544 { 545 DPRINT("PcCreateItemDispatch failed to reference device header\n"); 546 547 FreeItem(Entry, TAG_PORTCLASS); 548 goto cleanup; 549 } 550 #endif 551 552 // get filter object 553 Status = SubDevice->NewIrpTarget(&Filter, 554 NULL, 555 NULL, 556 NonPagedPool, 557 DeviceObject, 558 Irp, 559 NULL); 560 if (!NT_SUCCESS(Status)) 561 { 562 DPRINT("Failed to get filter object\n"); 563 Irp->IoStatus.Status = Status; 564 IoCompleteRequest(Irp, IO_NO_INCREMENT); 565 return Status; 566 } 567 568 // allocate pin create item 569 PinCreateItem = (PKSOBJECT_CREATE_ITEM)AllocateItem(NonPagedPool, sizeof(KSOBJECT_CREATE_ITEM), TAG_PORTCLASS); 570 if (!PinCreateItem) 571 { 572 // not enough memory 573 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES; 574 IoCompleteRequest(Irp, IO_NO_INCREMENT); 575 return STATUS_INSUFFICIENT_RESOURCES; 576 } 577 578 // initialize pin create item 579 PinCreateItem->Context = (PVOID)Filter; 580 PinCreateItem->Create = PcCreatePinDispatch; 581 RtlInitUnicodeString(&PinCreateItem->ObjectClass, KSSTRING_Pin); 582 // FIXME copy security descriptor 583 584 // now allocate a dispatch object 585 Status = NewDispatchObject(Irp, Filter, 1, PinCreateItem); 586 587 // complete request 588 Irp->IoStatus.Status = Status; 589 IoCompleteRequest(Irp, IO_NO_INCREMENT); 590 591 return STATUS_SUCCESS; 592 } 593 594 595 NTSTATUS 596 NewPortTopology( 597 OUT PPORT* OutPort) 598 { 599 CPortTopology * This; 600 NTSTATUS Status; 601 602 This= new(NonPagedPool, TAG_PORTCLASS) CPortTopology(NULL); 603 if (!This) 604 return STATUS_INSUFFICIENT_RESOURCES; 605 606 Status = This->QueryInterface(IID_IPort, (PVOID*)OutPort); 607 608 if (!NT_SUCCESS(Status)) 609 { 610 delete This; 611 } 612 613 DPRINT("NewPortTopology %p Status %x\n", *OutPort, Status); 614 return Status; 615 } 616 617 618 PMINIPORTTOPOLOGY 619 GetTopologyMiniport( 620 PPORTTOPOLOGY Port) 621 { 622 CPortTopology * This = (CPortTopology*)Port; 623 return This->m_pMiniport; 624 } 625