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