Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1344 lines
41 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: gni.cpp
  4. //
  5. // Description:
  6. //
  7. // Graph Node Instance
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // Mike McLaughlin
  12. //
  13. // History: Date Author Comment
  14. //
  15. // To Do: Date Author Comment
  16. //
  17. //@@END_MSINTERNAL
  18. //
  19. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  20. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  21. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  22. // PURPOSE.
  23. //
  24. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. #include "common.h"
  28. //---------------------------------------------------------------------------
  29. GUID aguidSysAudioCategories[] = {
  30. STATICGUIDOF(KSCATEGORY_SYSAUDIO)
  31. };
  32. //---------------------------------------------------------------------------
  33. //---------------------------------------------------------------------------
  34. CGraphNodeInstance::CGraphNodeInstance(
  35. PGRAPH_NODE pGraphNode,
  36. PFILTER_INSTANCE pFilterInstance
  37. )
  38. {
  39. Assert(pGraphNode);
  40. Assert(pFilterInstance);
  41. this->pFilterInstance = pFilterInstance;
  42. this->ulFlags = pFilterInstance->ulFlags;
  43. this->pGraphNode = pGraphNode;
  44. AddList(&pGraphNode->lstGraphNodeInstance);
  45. }
  46. CGraphNodeInstance::CGraphNodeInstance(
  47. PGRAPH_NODE pGraphNode
  48. )
  49. {
  50. Assert(pGraphNode);
  51. this->ulFlags = pGraphNode->ulFlags;
  52. this->pGraphNode = pGraphNode;
  53. AddList(&pGraphNode->lstGraphNodeInstance);
  54. }
  55. CGraphNodeInstance::~CGraphNodeInstance(
  56. )
  57. {
  58. Assert(this);
  59. RemoveList();
  60. if(pFilterInstance != NULL) {
  61. Assert(pFilterInstance);
  62. pFilterInstance->pGraphNodeInstance = NULL;
  63. pFilterInstance->ParentInstance.Invalidate();
  64. }
  65. DestroyPinDescriptors();
  66. DestroySysAudioTopology();
  67. delete[] paulNodeNumber;
  68. }
  69. NTSTATUS
  70. CGraphNodeInstance::Create(
  71. )
  72. {
  73. NTSTATUS Status = STATUS_SUCCESS;
  74. ULONG i, n;
  75. if(this == NULL) {
  76. Status = STATUS_NO_SUCH_DEVICE;
  77. goto exit;
  78. }
  79. Assert(this);
  80. Assert(pGraphNode);
  81. Status = CreatePinDescriptors();
  82. if(!NT_SUCCESS(Status)) {
  83. goto exit;
  84. }
  85. Status = CreateSysAudioTopology();
  86. if(!NT_SUCCESS(Status)) {
  87. goto exit;
  88. }
  89. if(gcVirtualSources != 0) {
  90. paulNodeNumber = new ULONG[gcVirtualSources];
  91. if(paulNodeNumber == NULL) {
  92. Trap();
  93. Status = STATUS_INSUFFICIENT_RESOURCES;
  94. goto exit;
  95. }
  96. for(i = 0; i < gcVirtualSources; i++) {
  97. for(n = 0; n < cTopologyNodes; n++) {
  98. if(pGraphNode->pDeviceNode->papVirtualSourceData[i]->
  99. pTopologyNode == papTopologyNode[n]) {
  100. paulNodeNumber[i] = n;
  101. break;
  102. }
  103. }
  104. }
  105. }
  106. exit:
  107. return(Status);
  108. }
  109. //---------------------------------------------------------------------------
  110. NTSTATUS
  111. CGraphNodeInstance::GetTopologyNodeFileObject(
  112. OUT PFILE_OBJECT *ppFileObject,
  113. IN ULONG NodeId
  114. )
  115. {
  116. NTSTATUS Status = STATUS_SUCCESS;
  117. if(this == NULL) {
  118. Status = STATUS_NO_SUCH_DEVICE;
  119. goto exit;
  120. }
  121. Assert(this);
  122. if(NodeId >= cTopologyNodes) {
  123. DPF2(100,
  124. "GetTopologyNodeFileObject: NodeId(%d) >= cTopologyNodes(%d)",
  125. NodeId,
  126. cTopologyNodes);
  127. Status = STATUS_INVALID_DEVICE_REQUEST;
  128. goto exit;
  129. }
  130. // If virtual topology node, return error
  131. if(papTopologyNode[NodeId]->ulRealNodeNumber == MAXULONG) {
  132. DPF(100, "GetTopologyNodeFileObject: ulRealNodeNumber == MAXULONG");
  133. Status = STATUS_INVALID_DEVICE_REQUEST;
  134. goto exit;
  135. }
  136. if(papFilterNodeInstanceTopologyTable == NULL) {
  137. Trap();
  138. Status = STATUS_INVALID_DEVICE_REQUEST;
  139. goto exit;
  140. }
  141. if(papFilterNodeInstanceTopologyTable[NodeId] == NULL) {
  142. Status = CFilterNodeInstance::Create(
  143. &papFilterNodeInstanceTopologyTable[NodeId],
  144. papTopologyNode[NodeId]->lstLogicalFilterNode.GetListFirstData(),
  145. pGraphNode->pDeviceNode,
  146. TRUE); // Reuse an instance
  147. if(!NT_SUCCESS(Status)) {
  148. goto exit;
  149. }
  150. }
  151. Assert(papFilterNodeInstanceTopologyTable[NodeId]);
  152. *ppFileObject = papFilterNodeInstanceTopologyTable[NodeId]->pFileObject;
  153. DPF1(110,
  154. "GetToplogyNodeFileObject: using filter for node: %d\n",
  155. NodeId);
  156. exit:
  157. return(Status);
  158. }
  159. //---------------------------------------------------------------------------
  160. NTSTATUS
  161. CGraphNodeInstance::CreateSysAudioTopology(
  162. )
  163. {
  164. NTSTATUS Status = STATUS_SUCCESS;
  165. Assert(this);
  166. ASSERT(Topology.TopologyNodes == NULL);
  167. ASSERT(Topology.TopologyConnections == NULL);
  168. ASSERT(papFilterNodeInstanceTopologyTable == NULL);
  169. Topology.CategoriesCount = SIZEOF_ARRAY(aguidSysAudioCategories);
  170. Topology.Categories = aguidSysAudioCategories;
  171. CreateTopologyTables();
  172. if(cTopologyNodes != 0) {
  173. Topology.TopologyNodes = new GUID[cTopologyNodes];
  174. if(Topology.TopologyNodes == NULL) {
  175. Status = STATUS_INSUFFICIENT_RESOURCES;
  176. goto exit;
  177. }
  178. papFilterNodeInstanceTopologyTable =
  179. new PFILTER_NODE_INSTANCE[cTopologyNodes];
  180. if(papFilterNodeInstanceTopologyTable == NULL) {
  181. Status = STATUS_INSUFFICIENT_RESOURCES;
  182. goto exit;
  183. }
  184. papTopologyNode = new PTOPOLOGY_NODE[cTopologyNodes];
  185. if(papTopologyNode == NULL) {
  186. Status = STATUS_INSUFFICIENT_RESOURCES;
  187. goto exit;
  188. }
  189. }
  190. if(cTopologyConnections != 0) {
  191. Topology.TopologyConnections =
  192. new KSTOPOLOGY_CONNECTION[cTopologyConnections];
  193. if(Topology.TopologyConnections == NULL) {
  194. Status = STATUS_INSUFFICIENT_RESOURCES;
  195. goto exit;
  196. }
  197. }
  198. CreateTopologyTables();
  199. exit:
  200. if(!NT_SUCCESS(Status)) {
  201. DestroySysAudioTopology();
  202. }
  203. return(Status);
  204. }
  205. VOID
  206. CGraphNodeInstance::DestroySysAudioTopology(
  207. )
  208. {
  209. ULONG n;
  210. delete[] (PVOID)Topology.TopologyNodes;
  211. Topology.TopologyNodes = NULL;
  212. delete[] (PVOID)Topology.TopologyConnections;
  213. Topology.TopologyConnections = NULL;
  214. delete[] papTopologyNode;
  215. papTopologyNode = NULL;
  216. if(papFilterNodeInstanceTopologyTable != NULL) {
  217. for(n = 0; n < cTopologyNodes; n++) {
  218. papFilterNodeInstanceTopologyTable[n]->Destroy();
  219. }
  220. delete[] papFilterNodeInstanceTopologyTable;
  221. papFilterNodeInstanceTopologyTable = NULL;
  222. }
  223. }
  224. typedef ENUMFUNC (CTopologyNode::*CLIST_TN_PFN2)(PVOID, PVOID);
  225. VOID
  226. CGraphNodeInstance::CreateTopologyTables(
  227. )
  228. {
  229. Assert(this);
  230. Assert(pGraphNode);
  231. cTopologyNodes = 0;
  232. cTopologyConnections = 0;
  233. // Initialize the "ulSysaudioNodeNumber" field in the TopologyNodes first
  234. ProcessLogicalFilterNodeTopologyNode(
  235. &pGraphNode->pDeviceNode->lstLogicalFilterNode,
  236. CTopologyNode::InitializeTopologyNode);
  237. ProcessLogicalFilterNodeTopologyNode(
  238. &pGraphNode->lstLogicalFilterNode,
  239. CTopologyNode::InitializeTopologyNode);
  240. // All the nodes need to be processed first so the ulSysaudioNodeNumber in
  241. // the TopologyNode is correct before any connections are processed.
  242. ProcessLogicalFilterNodeTopologyNode(
  243. &pGraphNode->pDeviceNode->lstLogicalFilterNode,
  244. CTopologyNode::AddTopologyNode);
  245. ProcessLogicalFilterNodeTopologyNode(
  246. &pGraphNode->lstLogicalFilterNode,
  247. CTopologyNode::AddTopologyNode);
  248. // Now process all the topology connection lists
  249. ProcessLogicalFilterNodeTopologyConnection(
  250. &pGraphNode->pDeviceNode->lstLogicalFilterNode,
  251. CTopologyConnection::ProcessTopologyConnection);
  252. ProcessLogicalFilterNodeTopologyConnection(
  253. &pGraphNode->lstLogicalFilterNode,
  254. CTopologyConnection::ProcessTopologyConnection);
  255. pGraphNode->lstTopologyConnection.EnumerateList(
  256. CTopologyConnection::ProcessTopologyConnection,
  257. (PVOID)this);
  258. }
  259. VOID
  260. CGraphNodeInstance::ProcessLogicalFilterNodeTopologyNode(
  261. PLIST_MULTI_LOGICAL_FILTER_NODE plstLogicalFilterNode,
  262. NTSTATUS (CTopologyNode::*Function)(
  263. PVOID pGraphNodeInstance
  264. )
  265. )
  266. {
  267. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  268. FOR_EACH_LIST_ITEM(
  269. plstLogicalFilterNode,
  270. pLogicalFilterNode) {
  271. Assert(pLogicalFilterNode);
  272. pLogicalFilterNode->lstTopologyNode.EnumerateList(Function, this);
  273. } END_EACH_LIST_ITEM
  274. }
  275. VOID
  276. CGraphNodeInstance::ProcessLogicalFilterNodeTopologyConnection(
  277. PLIST_MULTI_LOGICAL_FILTER_NODE plstLogicalFilterNode,
  278. NTSTATUS (CTopologyConnection::*Function)(
  279. PVOID pGraphNodeInstance
  280. )
  281. )
  282. {
  283. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  284. FOR_EACH_LIST_ITEM(
  285. plstLogicalFilterNode,
  286. pLogicalFilterNode) {
  287. Assert(pLogicalFilterNode);
  288. pLogicalFilterNode->lstTopologyConnection.EnumerateList(Function, this);
  289. } END_EACH_LIST_ITEM
  290. }
  291. ENUMFUNC
  292. CTopologyConnection::ProcessTopologyConnection(
  293. PVOID pReference
  294. )
  295. {
  296. PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference;
  297. PSTART_NODE pStartNode;
  298. ULONG ulFromPin;
  299. ULONG ulFromNode;
  300. ULONG ulToPin;
  301. ULONG ulToNode;
  302. ULONG PinId;
  303. Assert(this);
  304. Assert(pGraphNodeInstance);
  305. ulFromPin = MAXULONG;
  306. ulToPin = MAXULONG;
  307. #ifdef DEBUG
  308. ulFromNode = MAXULONG;
  309. ulToNode = MAXULONG;
  310. #endif
  311. // If the connection doesn't connect LFNs on this GraphNode, skip connection
  312. if(!IsTopologyConnectionOnGraphNode(pGraphNodeInstance->pGraphNode)) {
  313. DPF3(100, "ProcessTC: %s TC %08x GN %08x - skip TC",
  314. pGraphNodeInstance->pGraphNode->pDeviceNode->DumpName(),
  315. this,
  316. pGraphNodeInstance->pGraphNode);
  317. goto exit;
  318. }
  319. if(pTopologyPinFrom != NULL) {
  320. ulFromNode = pTopologyPinFrom->pTopologyNode->ulSysaudioNodeNumber;
  321. ulFromPin = pTopologyPinFrom->ulPinNumber;
  322. ASSERT(pPinInfoFrom == NULL);
  323. ASSERT(ulFromNode != MAXULONG);
  324. ASSERT(ulFromPin != MAXULONG);
  325. }
  326. if(pTopologyPinTo != NULL) {
  327. ulToNode = pTopologyPinTo->pTopologyNode->ulSysaudioNodeNumber;
  328. ulToPin = pTopologyPinTo->ulPinNumber;
  329. ASSERT(pPinInfoTo == NULL);
  330. ASSERT(ulToNode != MAXULONG);
  331. ASSERT(ulToPin != MAXULONG);
  332. }
  333. if(pGraphNodeInstance->aplstStartNode != NULL) {
  334. for(PinId = 0; PinId < pGraphNodeInstance->cPins; PinId++) {
  335. FOR_EACH_LIST_ITEM(
  336. pGraphNodeInstance->aplstStartNode[PinId],
  337. pStartNode) {
  338. Assert(pStartNode);
  339. if(pPinInfoFrom != NULL) {
  340. ASSERT(pTopologyPinFrom == NULL);
  341. if(pStartNode->pPinNode->pPinInfo == pPinInfoFrom) {
  342. // This code assumes that a filter's pininfo will show
  343. // up in one SAD pin. If a filter exposes more than one
  344. // major format on the same pin, that pininfo show on
  345. // two different SAD pins.
  346. ASSERT(ulFromNode == KSFILTER_NODE);
  347. ASSERT(ulFromPin == MAXULONG || ulFromPin == PinId);
  348. pStartNode->GetStartInfo()->
  349. ulTopologyConnectionTableIndex =
  350. pGraphNodeInstance->cTopologyConnections;
  351. ulFromNode = KSFILTER_NODE;
  352. ulFromPin = PinId;
  353. }
  354. }
  355. if(pPinInfoTo != NULL) {
  356. ASSERT(pTopologyPinTo == NULL);
  357. if(pStartNode->pPinNode->pPinInfo == pPinInfoTo) {
  358. // See above.
  359. ASSERT(ulToNode == KSFILTER_NODE);
  360. ASSERT(ulToPin == MAXULONG || ulToPin == PinId);
  361. pStartNode->GetStartInfo()->
  362. ulTopologyConnectionTableIndex =
  363. pGraphNodeInstance->cTopologyConnections;
  364. ulToNode = KSFILTER_NODE;
  365. ulToPin = PinId;
  366. }
  367. }
  368. } END_EACH_LIST_ITEM
  369. }
  370. }
  371. if(ulFromPin != MAXULONG && ulToPin != MAXULONG) {
  372. pGraphNodeInstance->AddTopologyConnection(
  373. ulFromNode,
  374. ulFromPin,
  375. ulToNode,
  376. ulToPin);
  377. }
  378. exit:
  379. return(STATUS_CONTINUE);
  380. }
  381. ENUMFUNC
  382. CTopologyNode::InitializeTopologyNode(
  383. PVOID pReference
  384. )
  385. {
  386. PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference;
  387. Assert(this);
  388. Assert(pGraphNodeInstance);
  389. ulSysaudioNodeNumber = MAXULONG;
  390. return(STATUS_CONTINUE);
  391. }
  392. ENUMFUNC
  393. CTopologyNode::AddTopologyNode(
  394. PVOID pReference
  395. )
  396. {
  397. PGRAPH_NODE_INSTANCE pGraphNodeInstance = (PGRAPH_NODE_INSTANCE)pReference;
  398. Assert(this);
  399. Assert(pGraphNodeInstance);
  400. // Skip duplicate TopologyNodes
  401. if(ulSysaudioNodeNumber != MAXULONG) {
  402. DPF1(100, "AddTopologyNode: dup TN: %08x", this);
  403. goto exit;
  404. }
  405. ulSysaudioNodeNumber = pGraphNodeInstance->cTopologyNodes;
  406. if(pGraphNodeInstance->papTopologyNode != NULL) {
  407. pGraphNodeInstance->papTopologyNode[
  408. pGraphNodeInstance->cTopologyNodes] = this;
  409. }
  410. if(pGraphNodeInstance->Topology.TopologyNodes != NULL) {
  411. ((GUID *)(pGraphNodeInstance->Topology.TopologyNodes))[
  412. pGraphNodeInstance->cTopologyNodes] = *pguidType;
  413. }
  414. DPF3(115, "AddTopologyNode: %02x GNI: %08x TN: %08x",
  415. pGraphNodeInstance->cTopologyNodes,
  416. pGraphNodeInstance,
  417. this);
  418. ++pGraphNodeInstance->cTopologyNodes;
  419. exit:
  420. return(STATUS_CONTINUE);
  421. }
  422. VOID
  423. CGraphNodeInstance::AddTopologyConnection(
  424. ULONG ulFromNode,
  425. ULONG ulFromPin,
  426. ULONG ulToNode,
  427. ULONG ulToPin
  428. )
  429. {
  430. Assert(this);
  431. if(Topology.TopologyConnections != NULL) {
  432. PKSTOPOLOGY_CONNECTION pKSTopologyConnection =
  433. (PKSTOPOLOGY_CONNECTION)&Topology.TopologyConnections[
  434. cTopologyConnections];
  435. pKSTopologyConnection->FromNode = ulFromNode;
  436. pKSTopologyConnection->FromNodePin = ulFromPin;
  437. pKSTopologyConnection->ToNode = ulToNode;
  438. pKSTopologyConnection->ToNodePin = ulToPin;
  439. }
  440. ++cTopologyConnections;
  441. DPF4(115, "AddTopologyConnection: FN:%02x FNP:%02x TN:%02x TNP:%02x",
  442. ulFromNode,
  443. ulFromPin,
  444. ulToNode,
  445. ulToPin);
  446. }
  447. //---------------------------------------------------------------------------
  448. NTSTATUS
  449. CGraphNodeInstance::CreatePinDescriptors(
  450. )
  451. {
  452. NTSTATUS Status = STATUS_SUCCESS;
  453. ListDataAssertLess<LIST_DATA_START_NODE> lstStartNodeLists;
  454. ListDataAssertLess<KSDATARANGE> lstDataRange;
  455. PLIST_DATA_START_NODE plstStartNodeOrdered;
  456. PSTART_NODE pStartNodeSorted;
  457. PSTART_NODE pStartNode;
  458. BOOL fSorted;
  459. ULONG PinId;
  460. Assert(this);
  461. Assert(pGraphNode);
  462. ASSERT(paPinDescriptors == NULL);
  463. ASSERT(aplstStartNode == NULL);
  464. ASSERT(palstTopologyNodeSelect == NULL);
  465. ASSERT(palstTopologyNodeNotSelect == NULL);
  466. ASSERT(pacPinInstances == NULL);
  467. ASSERT(pulPinFlags == NULL);
  468. ASSERT(cPins == 0);
  469. // Sort StartNodes by Communication, DataFlow and Major Format GUID
  470. FOR_EACH_LIST_ITEM(&pGraphNode->lstStartNode, pStartNode) {
  471. Assert(pStartNode->pPinNode);
  472. Assert(pStartNode->pPinNode->pPinInfo);
  473. // Skip any start nodes with no data range
  474. if(pStartNode->pPinNode->pDataRange == NULL) {
  475. Trap();
  476. continue;
  477. }
  478. // Skip any start nodes with no instances left on the pin
  479. if(ulFlags & FLAGS_COMBINE_PINS) {
  480. if(pStartNode->pPinNode->pPinInfo->Communication ==
  481. KSPIN_COMMUNICATION_SINK ||
  482. pStartNode->pPinNode->pPinInfo->Communication ==
  483. KSPIN_COMMUNICATION_SOURCE ||
  484. pStartNode->pPinNode->pPinInfo->Communication ==
  485. KSPIN_COMMUNICATION_BOTH) {
  486. if(!pStartNode->IsPossibleInstances()) {
  487. continue;
  488. }
  489. }
  490. }
  491. fSorted = FALSE;
  492. FOR_EACH_LIST_ITEM(&lstStartNodeLists, plstStartNodeOrdered) {
  493. FOR_EACH_LIST_ITEM(plstStartNodeOrdered, pStartNodeSorted) {
  494. Assert(pStartNodeSorted);
  495. Assert(pStartNodeSorted->pPinNode);
  496. Assert(pStartNodeSorted->pPinNode->pPinInfo);
  497. // If the same actual pin, combine the pin nodes
  498. if((pStartNode->pPinNode->pPinInfo ==
  499. pStartNodeSorted->pPinNode->pPinInfo) ||
  500. // Combine only if client wants it that way
  501. (ulFlags & FLAGS_COMBINE_PINS) &&
  502. // Combine only AUDIO major formats
  503. IsEqualGUID(
  504. &pStartNode->pPinNode->pDataRange->MajorFormat,
  505. &KSDATAFORMAT_TYPE_AUDIO) &&
  506. // Only combine SINK, SOURCE, BOTH StartNodes; keep
  507. // NONE and BRIDGE as separate SAD pins
  508. ((pStartNode->pPinNode->pPinInfo->Communication ==
  509. KSPIN_COMMUNICATION_SINK) ||
  510. (pStartNode->pPinNode->pPinInfo->Communication ==
  511. KSPIN_COMMUNICATION_SOURCE) ||
  512. (pStartNode->pPinNode->pPinInfo->Communication ==
  513. KSPIN_COMMUNICATION_BOTH)) &&
  514. // Combine if same data flow
  515. (pStartNode->pPinNode->pPinInfo->DataFlow ==
  516. pStartNodeSorted->pPinNode->pPinInfo->DataFlow) &&
  517. // Combine if same communication type OR
  518. ((pStartNode->pPinNode->pPinInfo->Communication ==
  519. pStartNodeSorted->pPinNode->pPinInfo->Communication) ||
  520. // Combine a SINK and a BOTH
  521. ((pStartNode->pPinNode->pPinInfo->Communication ==
  522. KSPIN_COMMUNICATION_SINK) &&
  523. (pStartNodeSorted->pPinNode->pPinInfo->Communication ==
  524. KSPIN_COMMUNICATION_BOTH)) ||
  525. // Combine a BOTH and a SINK
  526. ((pStartNode->pPinNode->pPinInfo->Communication ==
  527. KSPIN_COMMUNICATION_BOTH) &&
  528. (pStartNodeSorted->pPinNode->pPinInfo->Communication ==
  529. KSPIN_COMMUNICATION_SINK)) ||
  530. // Combine a SOURCE and a BOTH
  531. ((pStartNode->pPinNode->pPinInfo->Communication ==
  532. KSPIN_COMMUNICATION_SOURCE) &&
  533. (pStartNodeSorted->pPinNode->pPinInfo->Communication ==
  534. KSPIN_COMMUNICATION_BOTH)) ||
  535. // Combine a BOTH and a SOURCE
  536. ((pStartNode->pPinNode->pPinInfo->Communication ==
  537. KSPIN_COMMUNICATION_BOTH) &&
  538. (pStartNodeSorted->pPinNode->pPinInfo->Communication ==
  539. KSPIN_COMMUNICATION_SOURCE))) &&
  540. // Combine if major format is the same
  541. IsEqualGUID(
  542. &pStartNode->pPinNode->pDataRange->MajorFormat,
  543. &pStartNodeSorted->pPinNode->pDataRange->MajorFormat)) {
  544. Status = plstStartNodeOrdered->AddListOrdered(
  545. pStartNode,
  546. FIELD_OFFSET(START_NODE, ulOverhead));
  547. if(!NT_SUCCESS(Status)) {
  548. goto exit;
  549. }
  550. fSorted = TRUE;
  551. break;
  552. }
  553. } END_EACH_LIST_ITEM
  554. if(fSorted) {
  555. break;
  556. }
  557. } END_EACH_LIST_ITEM
  558. if(!fSorted) {
  559. plstStartNodeOrdered = new LIST_DATA_START_NODE;
  560. if(plstStartNodeOrdered == NULL) {
  561. Status = STATUS_INSUFFICIENT_RESOURCES;
  562. goto exit;
  563. }
  564. Status = plstStartNodeOrdered->AddListOrdered(
  565. pStartNode,
  566. FIELD_OFFSET(START_NODE, ulOverhead));
  567. if(!NT_SUCCESS(Status)) {
  568. goto exit;
  569. }
  570. Status = lstStartNodeLists.AddList(plstStartNodeOrdered);
  571. if(!NT_SUCCESS(Status)) {
  572. goto exit;
  573. }
  574. }
  575. } END_EACH_LIST_ITEM
  576. // Allocate the pin descriptors, pin instance and start node arrays
  577. cPins = lstStartNodeLists.CountList();
  578. // if there are no pins, exit
  579. if(cPins == 0) {
  580. goto exit;
  581. }
  582. paPinDescriptors = new KSPIN_DESCRIPTOR[cPins];
  583. if(paPinDescriptors == NULL) {
  584. Status = STATUS_INSUFFICIENT_RESOURCES;
  585. goto exit;
  586. }
  587. aplstStartNode = new PLIST_DATA_START_NODE[cPins];
  588. if(aplstStartNode == NULL) {
  589. Status = STATUS_INSUFFICIENT_RESOURCES;
  590. goto exit;
  591. }
  592. DPF1(100, "CreatePinDescriptors: cPins %d", cPins);
  593. // For each pin, create a list of interfaces, mediums and dataranges
  594. PinId = 0;
  595. FOR_EACH_LIST_ITEM(&lstStartNodeLists, plstStartNodeOrdered) {
  596. PKSDATARANGE pDataRange, *apDataRanges;
  597. BOOL fBoth = TRUE;
  598. ASSERT(PinId < cPins);
  599. ASSERT(!plstStartNodeOrdered->IsLstEmpty());
  600. aplstStartNode[PinId] = plstStartNodeOrdered;
  601. FOR_EACH_LIST_ITEM(plstStartNodeOrdered, pStartNode) {
  602. Assert(pStartNode);
  603. Assert(pStartNode->pPinNode);
  604. Assert(pStartNode->pPinNode->pPinInfo);
  605. paPinDescriptors[PinId].DataFlow =
  606. pStartNode->pPinNode->pPinInfo->DataFlow;
  607. if(pStartNode->pPinNode->pPinInfo->Communication !=
  608. KSPIN_COMMUNICATION_BOTH) {
  609. fBoth = FALSE;
  610. paPinDescriptors[PinId].Communication =
  611. pStartNode->pPinNode->pPinInfo->Communication;
  612. }
  613. if(paPinDescriptors[PinId].Category == NULL ||
  614. IsEqualGUID(
  615. paPinDescriptors[PinId].Category,
  616. &GUID_NULL)) {
  617. paPinDescriptors[PinId].Category =
  618. pStartNode->pPinNode->pPinInfo->pguidCategory;
  619. paPinDescriptors[PinId].Name =
  620. pStartNode->pPinNode->pPinInfo->pguidName;
  621. }
  622. } END_EACH_LIST_ITEM
  623. if(fBoth) {
  624. paPinDescriptors[PinId].Communication = KSPIN_COMMUNICATION_SINK;
  625. }
  626. // Make a list of all the DataRanges this pin will support
  627. Status = plstStartNodeOrdered->CreateUniqueList(
  628. &lstDataRange,
  629. (UNIQUE_LIST_PFN)GetStartNodeDataRange,
  630. (UNIQUE_LIST_PFN2)CompareDataRangeExact);
  631. if(!NT_SUCCESS(Status)) {
  632. goto exit;
  633. }
  634. // Put the number of data ranges into the pin descriptor
  635. paPinDescriptors[PinId].DataRangesCount = lstDataRange.CountList();
  636. if(paPinDescriptors[PinId].DataRangesCount != 0) {
  637. // Allocate the array of ptrs to DataRanges; put it into the desc
  638. paPinDescriptors[PinId].DataRanges = new PKSDATARANGE[
  639. paPinDescriptors[PinId].DataRangesCount];
  640. if(paPinDescriptors[PinId].DataRanges == NULL) {
  641. Status = STATUS_INSUFFICIENT_RESOURCES;
  642. goto exit;
  643. }
  644. // Put each data range pointer into the array
  645. apDataRanges = (PKSDATARANGE *)paPinDescriptors[PinId].DataRanges;
  646. FOR_EACH_LIST_ITEM(&lstDataRange, pDataRange) {
  647. *apDataRanges = pDataRange;
  648. apDataRanges++;
  649. } END_EACH_LIST_ITEM
  650. }
  651. // Destroy the data range list
  652. lstDataRange.DestroyList();
  653. // Create the interface array for the pin descriptor
  654. Status = CreateIdentifierArray(
  655. plstStartNodeOrdered,
  656. &paPinDescriptors[PinId].InterfacesCount,
  657. (PKSIDENTIFIER *)&paPinDescriptors[PinId].Interfaces,
  658. GetStartNodeInterface);
  659. if(!NT_SUCCESS(Status)) {
  660. goto exit;
  661. }
  662. // Create the medium array for the pin descriptor
  663. Status = CreateIdentifierArray(
  664. plstStartNodeOrdered,
  665. &paPinDescriptors[PinId].MediumsCount,
  666. (PKSIDENTIFIER *)&paPinDescriptors[PinId].Mediums,
  667. GetStartNodeMedium);
  668. if(!NT_SUCCESS(Status)) {
  669. goto exit;
  670. }
  671. DPF6(100, "PinId %d DataFlow %d cD %d cI %d cM %d cSN %d",
  672. PinId,
  673. paPinDescriptors[PinId].DataFlow,
  674. paPinDescriptors[PinId].DataRangesCount,
  675. paPinDescriptors[PinId].InterfacesCount,
  676. paPinDescriptors[PinId].MediumsCount,
  677. aplstStartNode[PinId]->CountList());
  678. // Next pin number
  679. PinId++;
  680. } END_EACH_LIST_ITEM
  681. if((ulFlags & FLAGS_MIXER_TOPOLOGY) == 0) {
  682. palstTopologyNodeSelect = new LIST_DATA_TOPOLOGY_NODE[cPins];
  683. if(palstTopologyNodeSelect == NULL) {
  684. Status = STATUS_INSUFFICIENT_RESOURCES;
  685. goto exit;
  686. }
  687. palstTopologyNodeNotSelect = new LIST_DATA_TOPOLOGY_NODE[cPins];
  688. if(palstTopologyNodeNotSelect == NULL) {
  689. Status = STATUS_INSUFFICIENT_RESOURCES;
  690. goto exit;
  691. }
  692. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  693. PTOPOLOGY_NODE pTopologyNode;
  694. FOR_EACH_LIST_ITEM(
  695. &pGraphNode->lstLogicalFilterNode,
  696. pLogicalFilterNode) {
  697. if(pLogicalFilterNode->GetFlags() & LFN_FLAGS_NOT_SELECT) {
  698. FOR_EACH_LIST_ITEM(
  699. &pLogicalFilterNode->lstTopologyNode,
  700. pTopologyNode) {
  701. for(PinId = 0; PinId < cPins; PinId++) {
  702. Status = palstTopologyNodeNotSelect[PinId].AddList(
  703. pTopologyNode);
  704. if(!NT_SUCCESS(Status)) {
  705. goto exit;
  706. }
  707. }
  708. } END_EACH_LIST_ITEM
  709. }
  710. } END_EACH_LIST_ITEM
  711. }
  712. pacPinInstances = new KSPIN_CINSTANCES[cPins];
  713. if(pacPinInstances == NULL) {
  714. Status = STATUS_INSUFFICIENT_RESOURCES;
  715. goto exit;
  716. }
  717. pulPinFlags = new ULONG[cPins];
  718. if (NULL == pulPinFlags) {
  719. Status = STATUS_INSUFFICIENT_RESOURCES;
  720. goto exit;
  721. }
  722. for(PinId = 0; PinId < cPins; PinId++) {
  723. LIST_DATA_GRAPH_PIN_INFO lstGraphPinInfo;
  724. PSTART_NODE pStartNode2;
  725. PPIN_INFO pPinInfo;
  726. BOOL fHWRender = TRUE;
  727. FOR_EACH_LIST_ITEM(aplstStartNode[PinId], pStartNode2) {
  728. PGRAPH_PIN_INFO pGraphPinInfo;
  729. pGraphPinInfo = pStartNode2->GetGraphPinInfo();
  730. Assert(pGraphPinInfo);
  731. //
  732. // Set pin type.
  733. // If all startnodes are connected directly to renderer.
  734. //
  735. pPinInfo = pGraphPinInfo->GetPinInfo();
  736. ASSERT(pPinInfo);
  737. if ((!(pPinInfo->pFilterNode->GetType() & FILTER_TYPE_RENDERER)) ||
  738. (KSPIN_DATAFLOW_IN != pPinInfo->DataFlow) ||
  739. (KSPIN_COMMUNICATION_SINK != pPinInfo->Communication)) {
  740. fHWRender = FALSE;
  741. }
  742. if(lstGraphPinInfo.CheckDupList(pGraphPinInfo)) {
  743. continue;
  744. }
  745. Status = lstGraphPinInfo.AddList(pGraphPinInfo);
  746. if(!NT_SUCCESS(Status)) {
  747. goto exit;
  748. }
  749. //
  750. // Set cinstances.
  751. //
  752. if(pGraphPinInfo->IsPinReserved()) {
  753. pacPinInstances[PinId].CurrentCount = 1;
  754. }
  755. if(pGraphPinInfo->GetPinInstances()->PossibleCount == MAXULONG) {
  756. pacPinInstances[PinId].PossibleCount = MAXULONG;
  757. break;
  758. }
  759. pacPinInstances[PinId].PossibleCount +=
  760. pGraphPinInfo->GetPinInstances()->PossibleCount;
  761. if (fHWRender) {
  762. fHWRender = (1 < pGraphPinInfo->GetPinInstances()->PossibleCount);
  763. }
  764. } END_EACH_LIST_ITEM
  765. pulPinFlags[PinId] = fHWRender;
  766. lstGraphPinInfo.DestroyList();
  767. }
  768. exit:
  769. if(!NT_SUCCESS(Status)) {
  770. DestroyPinDescriptors();
  771. }
  772. return(Status);
  773. }
  774. VOID
  775. CGraphNodeInstance::DestroyPinDescriptors(
  776. )
  777. {
  778. ULONG PinId;
  779. Assert(this);
  780. for(PinId = 0; PinId < cPins; PinId++) {
  781. if(paPinDescriptors != NULL) {
  782. delete (PVOID)paPinDescriptors[PinId].DataRanges;
  783. if(paPinDescriptors[PinId].InterfacesCount > 1) {
  784. delete (PVOID)paPinDescriptors[PinId].Interfaces;
  785. }
  786. if(paPinDescriptors[PinId].MediumsCount > 1) {
  787. delete (PVOID)paPinDescriptors[PinId].Mediums;
  788. }
  789. }
  790. if(aplstStartNode != NULL) {
  791. delete aplstStartNode[PinId];
  792. }
  793. }
  794. delete[cPins] aplstStartNode;
  795. aplstStartNode = NULL;
  796. delete[cPins] paPinDescriptors;
  797. paPinDescriptors = NULL;
  798. delete[cPins] palstTopologyNodeSelect;
  799. palstTopologyNodeSelect = NULL;
  800. delete[cPins] palstTopologyNodeNotSelect;
  801. palstTopologyNodeNotSelect = NULL;
  802. delete[cPins] pacPinInstances;
  803. pacPinInstances = NULL;
  804. delete[cPins] pulPinFlags;
  805. pulPinFlags = NULL;
  806. }
  807. NTSTATUS
  808. CreateIdentifierArray(
  809. PLIST_DATA_START_NODE plstStartNode,
  810. PULONG pulCount,
  811. PKSIDENTIFIER *ppIdentifier,
  812. PKSIDENTIFIER (*GetFunction)(
  813. PSTART_NODE pStartNode
  814. )
  815. )
  816. {
  817. NTSTATUS Status = STATUS_SUCCESS;
  818. KSIDENTIFIER *pIdentifier1, *pIdentifier2;
  819. ListDataAssertLess<KSIDENTIFIER> lstIdentifier;
  820. Status = plstStartNode->CreateUniqueList(
  821. &lstIdentifier,
  822. (UNIQUE_LIST_PFN)GetFunction,
  823. (UNIQUE_LIST_PFN2)CompareIdentifier);
  824. if(!NT_SUCCESS(Status)) {
  825. goto exit;
  826. }
  827. if((*pulCount = lstIdentifier.CountList()) == 0) {
  828. *ppIdentifier = NULL;
  829. }
  830. else {
  831. if(*pulCount == 1) {
  832. *ppIdentifier = lstIdentifier.GetListFirstData();
  833. }
  834. else {
  835. *ppIdentifier = new KSIDENTIFIER[*pulCount];
  836. if(*ppIdentifier == NULL) {
  837. Status = STATUS_INSUFFICIENT_RESOURCES;
  838. goto exit;
  839. }
  840. pIdentifier1 = *ppIdentifier;
  841. AssertAligned(pIdentifier1);
  842. FOR_EACH_LIST_ITEM(&lstIdentifier, pIdentifier2) {
  843. AssertAligned(pIdentifier1);
  844. AssertAligned(pIdentifier2);
  845. RtlCopyMemory(pIdentifier1, pIdentifier2, sizeof(KSIDENTIFIER));
  846. pIdentifier1++;
  847. } END_EACH_LIST_ITEM
  848. }
  849. }
  850. exit:
  851. return(Status);
  852. }
  853. PKSDATARANGE
  854. GetStartNodeDataRange(
  855. PSTART_NODE pStartNode
  856. )
  857. {
  858. return(pStartNode->pPinNode->pDataRange);
  859. }
  860. PKSIDENTIFIER
  861. GetStartNodeInterface(
  862. PSTART_NODE pStartNode
  863. )
  864. {
  865. return(pStartNode->pPinNode->pInterface);
  866. }
  867. PKSIDENTIFIER
  868. GetStartNodeMedium(
  869. PSTART_NODE pStartNode
  870. )
  871. {
  872. return(pStartNode->pPinNode->pMedium);
  873. }
  874. //---------------------------------------------------------------------------
  875. //
  876. // This functions checks whether a given TopologyNode is in the Topology
  877. // Connection list.
  878. //
  879. ENUMFUNC
  880. FindTopologyNode(
  881. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  882. IN BOOL fToDirection,
  883. IN PTOPOLOGY_NODE pTopologyNode
  884. )
  885. {
  886. Assert(pTopologyConnection);
  887. if(IS_CONNECTION_TYPE(pTopologyConnection, GRAPH)) {
  888. return(STATUS_DEAD_END);
  889. }
  890. if(fToDirection) {
  891. if(pTopologyConnection->pTopologyPinTo != NULL) {
  892. if(pTopologyNode ==
  893. pTopologyConnection->pTopologyPinTo->pTopologyNode) {
  894. return(STATUS_SUCCESS);
  895. }
  896. }
  897. }
  898. else {
  899. if(pTopologyConnection->pTopologyPinFrom != NULL) {
  900. if(pTopologyNode ==
  901. pTopologyConnection->pTopologyPinFrom->pTopologyNode) {
  902. return(STATUS_SUCCESS);
  903. }
  904. }
  905. }
  906. return(STATUS_CONTINUE);
  907. }
  908. BOOL
  909. CGraphNodeInstance::IsGraphValid(
  910. PSTART_NODE pStartNode,
  911. ULONG PinId
  912. )
  913. {
  914. PFILTER_INSTANCE pFilterInstance;
  915. PTOPOLOGY_NODE pTopologyNode;
  916. BOOL fCheck;
  917. Assert(this);
  918. Assert(pGraphNode);
  919. Assert(pStartNode);
  920. Assert(pStartNode->pPinNode);
  921. Assert(pStartNode->pPinNode->pPinInfo);
  922. Assert(pGraphNode->pDeviceNode);
  923. ASSERT(PinId < cPins);
  924. //
  925. // First make sure that all GlobalSelect nodes are in StartNode graph.
  926. //
  927. if(pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) {
  928. FOR_EACH_LIST_ITEM(
  929. &pGraphNode->pDeviceNode->lstFilterInstance,
  930. pFilterInstance) {
  931. if(pFilterInstance->pGraphNodeInstance == NULL) {
  932. continue;
  933. }
  934. Assert(pFilterInstance->pGraphNodeInstance);
  935. FOR_EACH_LIST_ITEM(
  936. &pFilterInstance->pGraphNodeInstance->lstTopologyNodeGlobalSelect,
  937. pTopologyNode) {
  938. if(EnumerateGraphTopology(
  939. pStartNode->GetStartInfo(),
  940. (TOP_PFN)FindTopologyNode,
  941. pTopologyNode) == STATUS_CONTINUE) {
  942. DPF2(80,
  943. "IsGraphValid: TN %08x SN %08x not found Global",
  944. pTopologyNode,
  945. pStartNode);
  946. return(FALSE);
  947. }
  948. } END_EACH_LIST_ITEM
  949. } END_EACH_LIST_ITEM
  950. }
  951. //
  952. // Make sure that all Selected nodes are in StartNode graph.
  953. //
  954. if (palstTopologyNodeSelect) {
  955. FOR_EACH_LIST_ITEM(&palstTopologyNodeSelect[PinId], pTopologyNode) {
  956. if(EnumerateGraphTopology(
  957. pStartNode->GetStartInfo(),
  958. (TOP_PFN)FindTopologyNode,
  959. pTopologyNode) == STATUS_CONTINUE) {
  960. DPF2(80, "IsGraphValid: TN %08x SN %08x not found Select",
  961. pTopologyNode,
  962. pStartNode);
  963. return(FALSE);
  964. }
  965. } END_EACH_LIST_ITEM
  966. }
  967. // If a NotSelectNode is in the GlobalSelectList of another FilterInstance,
  968. // don't consider this as an invalid Graph.
  969. // This behaves like an implicit SelectGraph.
  970. //
  971. if (palstTopologyNodeNotSelect) {
  972. PTOPOLOGY_NODE pDestroyTopologyNode = NULL;
  973. FOR_EACH_LIST_ITEM(&palstTopologyNodeNotSelect[PinId], pTopologyNode) {
  974. if (pDestroyTopologyNode)
  975. {
  976. DPF2(50, "Removing (1) TN %X %s",
  977. pDestroyTopologyNode,
  978. pDestroyTopologyNode->pFilterNode->DumpName());
  979. // Remove the topologynode from NotSelect list.
  980. palstTopologyNodeNotSelect[PinId].
  981. RemoveList(pDestroyTopologyNode);
  982. pDestroyTopologyNode = NULL;
  983. }
  984. fCheck = TRUE;
  985. if(pStartNode->pPinNode->pPinInfo->DataFlow == KSPIN_DATAFLOW_IN) {
  986. FOR_EACH_LIST_ITEM(
  987. &pGraphNode->pDeviceNode->lstFilterInstance,
  988. pFilterInstance) {
  989. if(pFilterInstance->pGraphNodeInstance == NULL) {
  990. continue;
  991. }
  992. Assert(pFilterInstance->pGraphNodeInstance);
  993. // Is this NotSelectNode in the GlobalSelectList of
  994. // another FilterInstance.
  995. // Remove it from NotSelectList and add it to
  996. // GlobalSelectList for this filter as well.
  997. //
  998. if(pFilterInstance->pGraphNodeInstance->
  999. lstTopologyNodeGlobalSelect.EnumerateList(
  1000. CTopologyNode::MatchTopologyNode,
  1001. pTopologyNode) == STATUS_SUCCESS) {
  1002. if (NT_SUCCESS(lstTopologyNodeGlobalSelect.
  1003. AddListDup(pTopologyNode))) {
  1004. // Mark the topologyNode for deletion.
  1005. pDestroyTopologyNode = pTopologyNode;
  1006. }
  1007. else {
  1008. DPF2(4, "Failed to add TN %X to GNI %X GlobalSelectList",
  1009. pTopologyNode,
  1010. this);
  1011. Trap();
  1012. }
  1013. fCheck = FALSE;
  1014. break;
  1015. }
  1016. } END_EACH_LIST_ITEM
  1017. }
  1018. if(fCheck) {
  1019. if(EnumerateGraphTopology(
  1020. pStartNode->GetStartInfo(),
  1021. (TOP_PFN)FindTopologyNode,
  1022. pTopologyNode) == STATUS_SUCCESS) {
  1023. DPF2(80, "IsGraphValid: TN %08x SN %08x found NotSelect",
  1024. pTopologyNode,
  1025. pStartNode);
  1026. return(FALSE);
  1027. }
  1028. }
  1029. } END_EACH_LIST_ITEM
  1030. if (pDestroyTopologyNode)
  1031. {
  1032. DPF2(50, "Removing (2) TN %X %s",
  1033. pDestroyTopologyNode,
  1034. pDestroyTopologyNode->pFilterNode->DumpName());
  1035. // Remove the topologynode from NotSelect list.
  1036. palstTopologyNodeNotSelect[PinId].
  1037. RemoveList(pDestroyTopologyNode);
  1038. }
  1039. }
  1040. return(TRUE);
  1041. }
  1042. NTSTATUS
  1043. CGraphNodeInstance::GetPinInstances(
  1044. PIRP pIrp,
  1045. PKSP_PIN pPin,
  1046. PKSPIN_CINSTANCES pcInstances
  1047. )
  1048. {
  1049. NTSTATUS Status;
  1050. ULONG ulPinId = pPin->PinId;
  1051. //
  1052. // For HW Accelerated pins, send the request to HW filter.
  1053. //
  1054. if (pulPinFlags[ulPinId]) {
  1055. PSTART_NODE pStartNode;
  1056. PPIN_INFO pPinInfo;
  1057. ULONG BytesReturned;
  1058. PIO_STACK_LOCATION pIrpStack;
  1059. PFILTER_NODE_INSTANCE pFilterNodeInstance = NULL;
  1060. pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
  1061. pStartNode = aplstStartNode[ulPinId]->GetListFirstData();
  1062. pPinInfo = pStartNode->pPinNode->pPinInfo;
  1063. Status = CFilterNodeInstance::Create(
  1064. &pFilterNodeInstance,
  1065. pStartNode->pPinNode->pLogicalFilterNode,
  1066. pGraphNode->pDeviceNode,
  1067. TRUE);
  1068. if(NT_SUCCESS(Status)) {
  1069. pPin->PinId = pPinInfo->PinId;
  1070. pPin->Property.Id = KSPROPERTY_PIN_CINSTANCES;
  1071. AssertFileObject(pFilterNodeInstance->pFileObject);
  1072. Status = KsSynchronousIoControlDevice(
  1073. pFilterNodeInstance->pFileObject,
  1074. KernelMode,
  1075. IOCTL_KS_PROPERTY,
  1076. pPin,
  1077. pIrpStack->Parameters.DeviceIoControl.InputBufferLength,
  1078. pcInstances,
  1079. pIrpStack->Parameters.DeviceIoControl.OutputBufferLength,
  1080. &BytesReturned);
  1081. if(NT_SUCCESS(Status)) {
  1082. pIrp->IoStatus.Information = BytesReturned;
  1083. }
  1084. if (pFilterNodeInstance) {
  1085. pFilterNodeInstance->Destroy();
  1086. }
  1087. }
  1088. else {
  1089. DPF2(10, "GetPinInstances FAILS %08x %s",
  1090. Status,
  1091. pPinInfo->pFilterNode->DumpName());
  1092. }
  1093. }
  1094. //
  1095. // For other pins use the cached instances
  1096. //
  1097. else {
  1098. Status = STATUS_SUCCESS;
  1099. *pcInstances = pacPinInstances[ulPinId];
  1100. }
  1101. return Status;
  1102. } // GetPinInstances
  1103. BOOL
  1104. CGraphNodeInstance::IsPinInstances(
  1105. ULONG ulPinId)
  1106. {
  1107. //
  1108. // For HW Accelerated pins, always allow further operations.
  1109. //
  1110. if (pulPinFlags[ulPinId]) {
  1111. return TRUE;
  1112. }
  1113. //
  1114. // For other pins check cached instances.
  1115. //
  1116. else
  1117. {
  1118. if(pacPinInstances[ulPinId].CurrentCount >=
  1119. pacPinInstances[ulPinId].PossibleCount) {
  1120. return FALSE;
  1121. }
  1122. }
  1123. return TRUE;
  1124. } // IsPinInstances
  1125. //---------------------------------------------------------------------------