Source code of Windows XP (NT5)
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.

655 lines
15 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: lfn.cpp
  4. //
  5. // Description:
  6. //
  7. //
  8. //@@BEGIN_MSINTERNAL
  9. // Development Team:
  10. // Mike McLaughlin
  11. //
  12. // History: Date Author Comment
  13. //
  14. // To Do: Date Author Comment
  15. //
  16. //@@END_MSINTERNAL
  17. //
  18. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  19. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  20. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  21. // PURPOSE.
  22. //
  23. // Copyright (c) 1996-1999 Microsoft Corporation. All Rights Reserved.
  24. //
  25. //---------------------------------------------------------------------------
  26. #include "common.h"
  27. //---------------------------------------------------------------------------
  28. //---------------------------------------------------------------------------
  29. ULONG gcMixers = 0;
  30. ULONG gcSplitters = 0;
  31. ULONG gcLogicalFilterNodes = 0;
  32. //---------------------------------------------------------------------------
  33. //---------------------------------------------------------------------------
  34. NTSTATUS
  35. CLogicalFilterNode::Create(
  36. OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode,
  37. IN PFILTER_NODE pFilterNode
  38. )
  39. {
  40. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  41. NTSTATUS Status;
  42. pLogicalFilterNode = new LOGICAL_FILTER_NODE(pFilterNode);
  43. if(pLogicalFilterNode == NULL) {
  44. Status = STATUS_INSUFFICIENT_RESOURCES;
  45. Trap();
  46. goto exit;
  47. }
  48. Status = pLogicalFilterNode->AddList(&pFilterNode->lstLogicalFilterNode);
  49. if(!NT_SUCCESS(Status)) {
  50. Trap();
  51. goto exit;
  52. }
  53. if(pLogicalFilterNode->GetType() & FILTER_TYPE_LOGICAL_FILTER) {
  54. Status = pLogicalFilterNode->AddListOrdered(
  55. gplstLogicalFilterNode,
  56. FIELD_OFFSET(LOGICAL_FILTER_NODE, ulOrder));
  57. if(!NT_SUCCESS(Status)) {
  58. Trap();
  59. goto exit;
  60. }
  61. }
  62. exit:
  63. *ppLogicalFilterNode = pLogicalFilterNode;
  64. return(Status);
  65. }
  66. CLogicalFilterNode::CLogicalFilterNode(
  67. PFILTER_NODE pFilterNode
  68. )
  69. {
  70. Assert(pFilterNode);
  71. this->pFilterNode = pFilterNode;
  72. // The type/order is the same as filter node
  73. SetType(pFilterNode->GetType());
  74. // Determine the overhead here, default to software (higher)
  75. ulOverhead = OVERHEAD_SOFTWARE;
  76. if(GetType() & FILTER_TYPE_ENDPOINT) {
  77. ulOverhead = OVERHEAD_HARDWARE;
  78. }
  79. // Count the mixers, splitters and lfns
  80. if(GetType() & FILTER_TYPE_MIXER) {
  81. ++gcMixers;
  82. }
  83. if(GetType() & FILTER_TYPE_SPLITTER) {
  84. ++gcSplitters;
  85. }
  86. ++gcLogicalFilterNodes;
  87. DPF3(60, "CLogicalFilterNode: %08x FN: %08x %s",
  88. this,
  89. pFilterNode,
  90. pFilterNode->DumpName());
  91. }
  92. CLogicalFilterNode::~CLogicalFilterNode(
  93. )
  94. {
  95. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  96. PDEVICE_NODE pDeviceNode;
  97. PGRAPH_NODE pGraphNode;
  98. PPIN_NODE pPinNode;
  99. BOOL fDestroy;
  100. Assert(this);
  101. DPF2(60, "~CLogicalFilterNode: %08x %s", this, pFilterNode->DumpName());
  102. //
  103. // Need to NULL the pPinNode's LFN field because it is used in AddPinNodes
  104. // to indicate that this PN hasn't been assigned a LFN yet.
  105. //
  106. FOR_EACH_LIST_ITEM(&lstPinNode, pPinNode) {
  107. Assert(pPinNode);
  108. if(pPinNode->pLogicalFilterNode == this) {
  109. pPinNode->pLogicalFilterNode = NULL;
  110. }
  111. } END_EACH_LIST_ITEM
  112. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  113. fDestroy = FALSE;
  114. FOR_EACH_LIST_ITEM(
  115. &pDeviceNode->lstLogicalFilterNode,
  116. pLogicalFilterNode) {
  117. if(pLogicalFilterNode == this) {
  118. DPF2(50, "~CLogicalFilterNode: %08x GN %08x Destroy",
  119. pLogicalFilterNode,
  120. pGraphNode);
  121. fDestroy = TRUE;
  122. break;
  123. }
  124. } END_EACH_LIST_ITEM
  125. if(!fDestroy) {
  126. FOR_EACH_LIST_ITEM(&pDeviceNode->lstGraphNode, pGraphNode) {
  127. FOR_EACH_LIST_ITEM(
  128. &pGraphNode->lstLogicalFilterNode,
  129. pLogicalFilterNode) {
  130. if(pLogicalFilterNode == this) {
  131. DPF2(50, "~CLogicalFilterNode: %08x GN %08x Destroy",
  132. pLogicalFilterNode,
  133. pGraphNode);
  134. fDestroy = TRUE;
  135. break;
  136. }
  137. } END_EACH_LIST_ITEM
  138. } END_EACH_LIST_ITEM
  139. }
  140. if(fDestroy) {
  141. pDeviceNode->lstGraphNode.DestroyList();
  142. }
  143. } END_EACH_LIST_ITEM
  144. if(GetType() & FILTER_TYPE_MIXER) {
  145. --gcMixers;
  146. }
  147. if(GetType() & FILTER_TYPE_SPLITTER) {
  148. --gcSplitters;
  149. }
  150. --gcLogicalFilterNodes;
  151. }
  152. VOID
  153. CLogicalFilterNode::SetType(
  154. ULONG fulType
  155. )
  156. {
  157. pFilterNode->SetType(fulType);
  158. SetOrder(pFilterNode->GetOrder());
  159. ulFlags = 0;
  160. if(GetType() & FILTER_TYPE_RENDER) {
  161. ulFlags |= LFN_FLAGS_CONNECT_RENDER;
  162. }
  163. if(GetType() & FILTER_TYPE_CAPTURE) {
  164. ulFlags |= LFN_FLAGS_CONNECT_CAPTURE;
  165. }
  166. if(GetType() & FILTER_TYPE_NORMAL_TOPOLOGY) {
  167. ulFlags |= LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY;
  168. }
  169. if(GetType() & FILTER_TYPE_MIXER_TOPOLOGY) {
  170. ulFlags |= LFN_FLAGS_CONNECT_MIXER_TOPOLOGY;
  171. }
  172. if(GetType() & FILTER_TYPE_NO_BYPASS) {
  173. ulFlags |= LFN_FLAGS_NO_BYPASS;
  174. }
  175. if(GetType() & FILTER_TYPE_NOT_SELECT) {
  176. ulFlags |= LFN_FLAGS_NOT_SELECT;
  177. }
  178. if(pFilterNode->GetFlags() & FN_FLAGS_RENDER) {
  179. ulFlags |= LFN_FLAGS_CONNECT_RENDER;
  180. }
  181. if(pFilterNode->GetFlags() & FN_FLAGS_NO_RENDER) {
  182. ulFlags &= ~LFN_FLAGS_CONNECT_RENDER;
  183. }
  184. if(pFilterNode->GetFlags() & FN_FLAGS_CAPTURE) {
  185. ulFlags |= LFN_FLAGS_CONNECT_CAPTURE;
  186. }
  187. if(pFilterNode->GetFlags() & FN_FLAGS_NO_CAPTURE) {
  188. ulFlags &= ~LFN_FLAGS_CONNECT_CAPTURE;
  189. }
  190. }
  191. NTSTATUS
  192. SwitchLogicalFilterNodes(
  193. IN PLOGICAL_FILTER_NODE pLogicalFilterNode,
  194. IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
  195. )
  196. {
  197. NTSTATUS Status = STATUS_SUCCESS;
  198. PTOPOLOGY_NODE pTopologyNode;
  199. PPIN_NODE pPinNode;
  200. Assert(pLogicalFilterNode);
  201. Assert(*ppLogicalFilterNode);
  202. if(pLogicalFilterNode != *ppLogicalFilterNode) {
  203. FOR_EACH_LIST_ITEM(&(*ppLogicalFilterNode)->lstPinNode, pPinNode) {
  204. Assert(pPinNode);
  205. pPinNode->pLogicalFilterNode = pLogicalFilterNode;
  206. } END_EACH_LIST_ITEM
  207. pLogicalFilterNode->lstPinNode.JoinList(
  208. &(*ppLogicalFilterNode)->lstPinNode);
  209. FOR_EACH_LIST_ITEM(
  210. &(*ppLogicalFilterNode)->lstTopologyNode,
  211. pTopologyNode) {
  212. Assert(pTopologyNode);
  213. (*ppLogicalFilterNode)->RemoveList(
  214. &pTopologyNode->lstLogicalFilterNode);
  215. Status = pLogicalFilterNode->AddList(
  216. &pTopologyNode->lstLogicalFilterNode);
  217. if(!NT_SUCCESS(Status)) {
  218. Trap();
  219. goto exit;
  220. }
  221. Status = pLogicalFilterNode->lstTopologyNode.AddList(pTopologyNode);
  222. if(!NT_SUCCESS(Status)) {
  223. Trap();
  224. goto exit;
  225. }
  226. } END_EACH_LIST_ITEM
  227. pLogicalFilterNode->lstTopologyConnection.JoinList(
  228. &(*ppLogicalFilterNode)->lstTopologyConnection);
  229. delete *ppLogicalFilterNode;
  230. *ppLogicalFilterNode = pLogicalFilterNode;
  231. }
  232. exit:
  233. return(Status);
  234. }
  235. NTSTATUS
  236. AddPinNodes(
  237. IN PPIN_INFO pPinInfo,
  238. IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
  239. )
  240. {
  241. NTSTATUS Status = STATUS_SUCCESS;
  242. PPIN_NODE pPinNode;
  243. Assert(pPinInfo);
  244. Assert(*ppLogicalFilterNode);
  245. FOR_EACH_LIST_ITEM(&pPinInfo->lstPinNode, pPinNode) {
  246. if(pPinNode->pLogicalFilterNode == NULL) {
  247. pPinNode->pLogicalFilterNode = *ppLogicalFilterNode;
  248. }
  249. else {
  250. Status = SwitchLogicalFilterNodes(
  251. pPinNode->pLogicalFilterNode,
  252. ppLogicalFilterNode);
  253. if(!NT_SUCCESS(Status)) {
  254. Trap();
  255. goto exit;
  256. }
  257. }
  258. Status = (*ppLogicalFilterNode)->lstPinNode.AddList(pPinNode);
  259. if(!NT_SUCCESS(Status)) {
  260. Trap();
  261. goto exit;
  262. }
  263. DPF2(100, "AddPinNodes: add PN %08x LFN %08x",
  264. pPinNode,
  265. *ppLogicalFilterNode);
  266. } END_EACH_LIST_ITEM
  267. exit:
  268. return(Status);
  269. }
  270. NTSTATUS
  271. CLogicalFilterNode::EnumerateFilterTopology(
  272. IN PTOPOLOGY_CONNECTION pTopologyConnection,
  273. IN BOOL fToDirection,
  274. IN OUT PLOGICAL_FILTER_NODE *ppLogicalFilterNode
  275. )
  276. {
  277. PTOPOLOGY_NODE pTopologyNode;
  278. NTSTATUS Status;
  279. Assert(pTopologyConnection);
  280. DPF5(100, "EFT: PIF %08x PIT %08x TPF %08x TPT %08x f %x",
  281. pTopologyConnection->pPinInfoFrom,
  282. pTopologyConnection->pPinInfoTo,
  283. pTopologyConnection->pTopologyPinFrom,
  284. pTopologyConnection->pTopologyPinTo,
  285. fToDirection);
  286. if(!fToDirection) {
  287. Status = STATUS_DEAD_END;
  288. goto exit;
  289. }
  290. if(IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
  291. if(pTopologyConnection->pPinInfoFrom != NULL) {
  292. Assert(pTopologyConnection->pPinInfoFrom);
  293. if(*ppLogicalFilterNode == NULL) {
  294. Status = CLogicalFilterNode::Create(
  295. ppLogicalFilterNode,
  296. pTopologyConnection->pPinInfoFrom->pFilterNode);
  297. if(!NT_SUCCESS(Status)) {
  298. Trap();
  299. goto exit;
  300. }
  301. }
  302. Status = AddPinNodes(
  303. pTopologyConnection->pPinInfoFrom,
  304. ppLogicalFilterNode);
  305. if(!NT_SUCCESS(Status)) {
  306. Trap();
  307. goto exit;
  308. }
  309. DPF2(100, "EFT: add from PI %08x LFN %08x",
  310. pTopologyConnection->pPinInfoFrom,
  311. *ppLogicalFilterNode);
  312. }
  313. ASSERT(*ppLogicalFilterNode != NULL);
  314. Assert(*ppLogicalFilterNode);
  315. if(pTopologyConnection->pPinInfoTo != NULL) {
  316. Status = AddPinNodes(
  317. pTopologyConnection->pPinInfoTo,
  318. ppLogicalFilterNode);
  319. if(!NT_SUCCESS(Status)) {
  320. Trap();
  321. goto exit;
  322. }
  323. DPF2(100, "EFT: add to PI %08x LFN %08x",
  324. pTopologyConnection->pPinInfoTo,
  325. *ppLogicalFilterNode);
  326. }
  327. if(pTopologyConnection->pTopologyPinTo != NULL) {
  328. Assert(pTopologyConnection->pTopologyPinTo);
  329. pTopologyNode = pTopologyConnection->pTopologyPinTo->pTopologyNode;
  330. Assert(pTopologyNode);
  331. Status = (*ppLogicalFilterNode)->lstTopologyNode.AddList(
  332. pTopologyNode);
  333. if(!NT_SUCCESS(Status)) {
  334. Trap();
  335. goto exit;
  336. }
  337. if(IsEqualGUID(
  338. &KSNODETYPE_ACOUSTIC_ECHO_CANCEL,
  339. pTopologyNode->pguidType)) {
  340. Assert(*ppLogicalFilterNode);
  341. (*ppLogicalFilterNode)->SetType(FILTER_TYPE_AEC);
  342. if(pTopologyConnection->pTopologyPinTo->ulPinNumber ==
  343. KSNODEPIN_AEC_RENDER_IN) {
  344. (*ppLogicalFilterNode)->SetRenderOnly();
  345. }
  346. else {
  347. ASSERT(
  348. pTopologyConnection->pTopologyPinTo->ulPinNumber ==
  349. KSNODEPIN_AEC_CAPTURE_IN);
  350. (*ppLogicalFilterNode)->SetCaptureOnly();
  351. }
  352. Status = (*ppLogicalFilterNode)->AddList(
  353. &pTopologyNode->lstLogicalFilterNode);
  354. if(!NT_SUCCESS(Status)) {
  355. Trap();
  356. goto exit;
  357. }
  358. }
  359. else {
  360. if(pTopologyNode->lstLogicalFilterNode.IsLstEmpty()) {
  361. Assert(*ppLogicalFilterNode);
  362. Status = (*ppLogicalFilterNode)->AddList(
  363. &pTopologyNode->lstLogicalFilterNode);
  364. if(!NT_SUCCESS(Status)) {
  365. Trap();
  366. goto exit;
  367. }
  368. }
  369. else {
  370. Status = SwitchLogicalFilterNodes(
  371. (PLOGICAL_FILTER_NODE)
  372. pTopologyNode->lstLogicalFilterNode.GetListFirstData(),
  373. ppLogicalFilterNode);
  374. if(!NT_SUCCESS(Status)) {
  375. Trap();
  376. goto exit;
  377. }
  378. }
  379. }
  380. DPF2(100, "EFT: add to PI %08x LFN %08x",
  381. pTopologyConnection->pPinInfoTo,
  382. *ppLogicalFilterNode);
  383. }
  384. }
  385. Status = pTopologyConnection->AddList(
  386. &(*ppLogicalFilterNode)->lstTopologyConnection);
  387. if(!NT_SUCCESS(Status)) {
  388. Trap();
  389. goto exit;
  390. }
  391. if(IS_CONNECTION_TYPE(pTopologyConnection, FILTER)) {
  392. Status = STATUS_CONTINUE;
  393. }
  394. else {
  395. Status = STATUS_DEAD_END;
  396. }
  397. exit:
  398. return(Status);
  399. }
  400. NTSTATUS
  401. CLogicalFilterNode::CreateAll(
  402. PFILTER_NODE pFilterNode
  403. )
  404. {
  405. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  406. NTSTATUS Status = STATUS_SUCCESS;
  407. PPIN_INFO pPinInfo;
  408. PPIN_NODE pPinNode;
  409. DPF2(100, "CLFN::CreateAll: FN %08x %s",
  410. pFilterNode,
  411. pFilterNode->DumpName());
  412. //
  413. // Split up the filter into logical filter nodes.
  414. //
  415. FOR_EACH_LIST_ITEM(&pFilterNode->lstPinInfo, pPinInfo) {
  416. pLogicalFilterNode = NULL;
  417. Status = EnumerateTopology(
  418. pPinInfo,
  419. (TOP_PFN)EnumerateFilterTopology,
  420. &pLogicalFilterNode);
  421. if(Status == STATUS_CONTINUE) {
  422. Status = STATUS_SUCCESS;
  423. }
  424. else {
  425. if(!NT_SUCCESS(Status)) {
  426. goto exit;
  427. }
  428. }
  429. } END_EACH_LIST_ITEM
  430. //
  431. // Look at the pins of each LFN and determine if it could possibly
  432. // be a capture or render filter (or both).
  433. //
  434. FOR_EACH_LIST_ITEM(
  435. &pFilterNode->lstLogicalFilterNode,
  436. pLogicalFilterNode) {
  437. ULONG ulPossibleFlags;
  438. ulPossibleFlags = 0;
  439. pLogicalFilterNode->ulFlags |= LFN_FLAGS_REFLECT_DATARANGE;
  440. FOR_EACH_LIST_ITEM(&pLogicalFilterNode->lstPinNode, pPinNode) {
  441. // Don't care about the major format
  442. if(!IsEqualGUID(
  443. &pPinNode->pDataRange->SubFormat,
  444. &KSDATAFORMAT_SUBTYPE_WILDCARD) ||
  445. !IsEqualGUID(
  446. &pPinNode->pDataRange->Specifier,
  447. &KSDATAFORMAT_SPECIFIER_WILDCARD)) {
  448. pLogicalFilterNode->ulFlags &= ~LFN_FLAGS_REFLECT_DATARANGE;
  449. }
  450. switch(pPinNode->pPinInfo->Communication) {
  451. case KSPIN_COMMUNICATION_BOTH:
  452. ulPossibleFlags |=
  453. LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER;
  454. break;
  455. case KSPIN_COMMUNICATION_SOURCE:
  456. switch(pPinNode->pPinInfo->DataFlow) {
  457. case KSPIN_DATAFLOW_IN:
  458. ulPossibleFlags |= LFN_FLAGS_CONNECT_CAPTURE;
  459. break;
  460. case KSPIN_DATAFLOW_OUT:
  461. ulPossibleFlags |= LFN_FLAGS_CONNECT_RENDER;
  462. break;
  463. }
  464. break;
  465. case KSPIN_COMMUNICATION_SINK:
  466. switch(pPinNode->pPinInfo->DataFlow) {
  467. case KSPIN_DATAFLOW_IN:
  468. ulPossibleFlags |= LFN_FLAGS_CONNECT_RENDER;
  469. break;
  470. case KSPIN_DATAFLOW_OUT:
  471. ulPossibleFlags |= LFN_FLAGS_CONNECT_CAPTURE;
  472. break;
  473. }
  474. break;
  475. }
  476. if(ulPossibleFlags ==
  477. (LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER)) {
  478. break;
  479. }
  480. } END_EACH_LIST_ITEM
  481. pLogicalFilterNode->ulFlags =
  482. (ulPossibleFlags & pLogicalFilterNode->GetFlags()) |
  483. (pLogicalFilterNode->GetFlags() &
  484. ~(LFN_FLAGS_CONNECT_CAPTURE | LFN_FLAGS_CONNECT_RENDER));
  485. } END_EACH_LIST_ITEM
  486. exit:
  487. return(Status);
  488. }
  489. //---------------------------------------------------------------------------
  490. #ifdef DEBUG
  491. ULONG nLogicalFilter = 0;
  492. ENUMFUNC
  493. CLogicalFilterNode::Dump(
  494. )
  495. {
  496. Assert(this);
  497. // .slv
  498. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  499. dprintf("LFN: %08x FN %08x fulType %08x ulOrder %08x ulOverhead %08x\n",
  500. this,
  501. pFilterNode,
  502. pFilterNode->GetType(),
  503. ulOrder,
  504. ulOverhead);
  505. dprintf(" %s\n", pFilterNode->DumpName());
  506. dprintf(" fulType: ");
  507. DumpfulType(GetType());
  508. dprintf("\n ulFlags: ");
  509. if(ulFlags & LFN_FLAGS_CONNECT_CAPTURE) {
  510. dprintf("CAPTURE ");
  511. }
  512. if(ulFlags & LFN_FLAGS_CONNECT_RENDER) {
  513. dprintf("RENDER ");
  514. }
  515. if(ulFlags & LFN_FLAGS_CONNECT_NORMAL_TOPOLOGY) {
  516. dprintf("NORMAL_TOPOLOGY ");
  517. }
  518. if(ulFlags & LFN_FLAGS_CONNECT_MIXER_TOPOLOGY) {
  519. dprintf("MIXER_TOPOLOGY ");
  520. }
  521. if(ulFlags & LFN_FLAGS_TOP_DOWN) {
  522. dprintf("TOP_DOWN ");
  523. }
  524. if(ulFlags & LFN_FLAGS_NO_BYPASS) {
  525. dprintf("NO_BYPASS ");
  526. }
  527. if(ulFlags & LFN_FLAGS_NOT_SELECT) {
  528. dprintf("NOT_SELECT ");
  529. }
  530. if(ulFlags & LFN_FLAGS_REFLECT_DATARANGE) {
  531. dprintf("REFLECT_DATARANGE ");
  532. }
  533. dprintf("\n");
  534. // .slvx
  535. if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
  536. dprintf(" lstPN: ");
  537. lstPinNode.DumpAddress();
  538. dprintf("\n lstTN: ");
  539. lstTopologyNode.DumpAddress();
  540. dprintf("\n lstTC: ");
  541. lstTopologyConnection.DumpAddress();
  542. dprintf("\n lstFNI: ");
  543. lstFilterNodeInstance.DumpAddress();
  544. dprintf("\n");
  545. }
  546. }
  547. // .slp
  548. if(ulDebugFlags & DEBUG_FLAGS_PIN) {
  549. lstPinNode.Dump();
  550. }
  551. // .slt
  552. if(ulDebugFlags & DEBUG_FLAGS_TOPOLOGY) {
  553. lstTopologyNode.Dump();
  554. // .sltx
  555. if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
  556. lstTopologyConnection.Dump();
  557. }
  558. }
  559. if(ulDebugFlags &
  560. (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_PIN | DEBUG_FLAGS_TOPOLOGY)) {
  561. dprintf("\n");
  562. }
  563. return(STATUS_CONTINUE);
  564. }
  565. #endif