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.

554 lines
13 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: dn.cpp
  4. //
  5. // Description:
  6. //
  7. // DeviceNode Class
  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. //---------------------------------------------------------------------------
  30. PLIST_DEVICE_NODE gplstDeviceNode = NULL;
  31. //---------------------------------------------------------------------------
  32. //---------------------------------------------------------------------------
  33. #pragma INIT_CODE
  34. #pragma INIT_DATA
  35. NTSTATUS
  36. InitializeDeviceNode(
  37. )
  38. {
  39. if(gplstDeviceNode == NULL) {
  40. gplstDeviceNode = new LIST_DEVICE_NODE;
  41. if(gplstDeviceNode == NULL) {
  42. return(STATUS_INSUFFICIENT_RESOURCES);
  43. }
  44. }
  45. #ifdef DEBUG
  46. if(gplstConnectNode == NULL) {
  47. gplstConnectNode = new LIST_CONNECT_NODE;
  48. if(gplstConnectNode == NULL) {
  49. return(STATUS_INSUFFICIENT_RESOURCES);
  50. }
  51. }
  52. if(gplstPinNodeInstance == NULL) {
  53. gplstPinNodeInstance = new LIST_PIN_NODE_INSTANCE;
  54. if(gplstPinNodeInstance == NULL) {
  55. return(STATUS_INSUFFICIENT_RESOURCES);
  56. }
  57. }
  58. if(gplstFilterInstance == NULL) {
  59. gplstFilterInstance = new LIST_DATA_FILTER_INSTANCE;
  60. if(gplstFilterInstance == NULL) {
  61. return(STATUS_INSUFFICIENT_RESOURCES);
  62. }
  63. }
  64. #endif
  65. return(STATUS_SUCCESS);
  66. }
  67. #pragma PAGEABLE_CODE
  68. #pragma PAGEABLE_DATA
  69. VOID
  70. UninitializeDeviceNode(
  71. )
  72. {
  73. delete gplstDeviceNode;
  74. gplstDeviceNode = NULL;
  75. #ifdef DEBUG
  76. ASSERT(gplstConnectNode->IsLstEmpty());
  77. delete gplstConnectNode;
  78. gplstConnectNode = NULL;
  79. ASSERT(gplstPinNodeInstance->IsLstEmpty());
  80. delete gplstPinNodeInstance;
  81. gplstPinNodeInstance = NULL;
  82. delete gplstFilterInstance;
  83. gplstFilterInstance = NULL;
  84. #endif
  85. }
  86. //---------------------------------------------------------------------------
  87. CDeviceNode::CDeviceNode(
  88. )
  89. {
  90. ASSERT(gplstDeviceNode != NULL);
  91. AddListEnd(gplstDeviceNode);
  92. DPF1(50, "CDeviceNode: %08x", this);
  93. }
  94. CDeviceNode::~CDeviceNode(
  95. )
  96. {
  97. PFILTER_INSTANCE pFilterInstance;
  98. ULONG i;
  99. Assert(this);
  100. RemoveList();
  101. if (pFilterNode) {
  102. pFilterNode->pDeviceNode = NULL;
  103. }
  104. delete pShingleInstance;
  105. FOR_EACH_LIST_ITEM_DELETE(&lstFilterInstance, pFilterInstance) {
  106. ASSERT(pFilterInstance->GetDeviceNode() == this);
  107. pFilterInstance->SetDeviceNode(NULL);
  108. } END_EACH_LIST_ITEM
  109. if(papVirtualSourceData != NULL) {
  110. for(i = 0; i < cVirtualSourceData; i++) {
  111. delete papVirtualSourceData[i];
  112. }
  113. delete papVirtualSourceData;
  114. }
  115. for(i = 0; i < MAX_SYSAUDIO_DEFAULT_TYPE; i++) {
  116. if(apShingleInstance[i] != NULL) {
  117. if(apShingleInstance[i]->GetDeviceNode() == this) {
  118. apShingleInstance[i]->SetDeviceNode(NULL);
  119. }
  120. }
  121. }
  122. delete pFilterNodeVirtual;
  123. DPF1(50, "~CFilterNode: %08x", this);
  124. }
  125. NTSTATUS
  126. CDeviceNode::Create(
  127. PFILTER_NODE pFilterNode
  128. )
  129. {
  130. NTSTATUS Status = STATUS_SUCCESS;
  131. Assert(this);
  132. Assert(pFilterNode);
  133. this->pFilterNode = pFilterNode;
  134. Status = Update();
  135. if(!NT_SUCCESS(Status)) {
  136. goto exit;
  137. }
  138. pShingleInstance = new SHINGLE_INSTANCE(FLAGS_COMBINE_PINS);
  139. if(pShingleInstance == NULL) {
  140. Status = STATUS_INSUFFICIENT_RESOURCES;
  141. goto exit;
  142. }
  143. Status = pShingleInstance->Create(this, (LPGUID)&KSCATEGORY_AUDIO_DEVICE);
  144. if(!NT_SUCCESS(Status)) {
  145. goto exit;
  146. }
  147. exit:
  148. return(Status);
  149. }
  150. NTSTATUS
  151. CDeviceNode::Update(
  152. )
  153. {
  154. NTSTATUS Status = STATUS_SUCCESS;
  155. PFILTER_NODE pFilterNodeNext;
  156. ULONG i;
  157. Assert(this);
  158. Assert(pFilterNode);
  159. DPF2(50, "CDeviceNode::Update DN %08x %s", this, DumpName());
  160. lstGraphNode.DestroyList();
  161. lstLogicalFilterNode.DestroyList();
  162. delete pFilterNodeVirtual;
  163. pFilterNodeVirtual = NULL;
  164. if(papVirtualSourceData != NULL) {
  165. for(i = 0; i < cVirtualSourceData; i++) {
  166. delete papVirtualSourceData[i];
  167. }
  168. delete papVirtualSourceData;
  169. papVirtualSourceData = NULL;
  170. }
  171. if(gcVirtualSources != 0) {
  172. papVirtualSourceData = new PVIRTUAL_SOURCE_DATA[gcVirtualSources];
  173. if(papVirtualSourceData == NULL) {
  174. Trap();
  175. Status = STATUS_INSUFFICIENT_RESOURCES;
  176. goto exit;
  177. }
  178. for(i = 0; i < gcVirtualSources; i++) {
  179. papVirtualSourceData[i] = new VIRTUAL_SOURCE_DATA(this);
  180. if(papVirtualSourceData[i] == NULL) {
  181. Trap();
  182. Status = STATUS_INSUFFICIENT_RESOURCES;
  183. goto exit;
  184. }
  185. }
  186. }
  187. cVirtualSourceData = gcVirtualSources;
  188. Status = AddLogicalFilterNode(pFilterNode);
  189. if(!NT_SUCCESS(Status)) {
  190. Trap();
  191. goto exit;
  192. }
  193. FOR_EACH_LIST_ITEM(&pFilterNode->lstConnectedFilterNode, pFilterNodeNext) {
  194. Status = AddLogicalFilterNode(pFilterNodeNext);
  195. if(!NT_SUCCESS(Status)) {
  196. Trap();
  197. goto exit;
  198. }
  199. } END_EACH_LIST_ITEM
  200. Status = CreateVirtualMixer(this);
  201. if(!NT_SUCCESS(Status)) {
  202. Trap();
  203. goto exit;
  204. }
  205. if(pShingleInstance != NULL) {
  206. Status = pShingleInstance->SetDeviceNode(this);
  207. if(!NT_SUCCESS(Status)) {
  208. Trap();
  209. goto exit;
  210. }
  211. }
  212. exit:
  213. return(Status);
  214. }
  215. NTSTATUS
  216. CDeviceNode::AddLogicalFilterNode(
  217. PFILTER_NODE pFilterNode
  218. )
  219. {
  220. PLOGICAL_FILTER_NODE pLogicalFilterNode;
  221. NTSTATUS Status = STATUS_SUCCESS;
  222. Status = VirtualizeTopology(this, pFilterNode);
  223. if(!NT_SUCCESS(Status)) {
  224. Trap();
  225. goto exit;
  226. }
  227. FOR_EACH_LIST_ITEM(
  228. &pFilterNode->lstLogicalFilterNode,
  229. pLogicalFilterNode) {
  230. DPF2(60, "AddLogicalFilterNode: %08x, DN: %08x",
  231. pLogicalFilterNode,
  232. this);
  233. Status = pLogicalFilterNode->AddList(&lstLogicalFilterNode);
  234. if(!NT_SUCCESS(Status)) {
  235. Trap();
  236. goto exit;
  237. }
  238. pLogicalFilterNode->RemoveList(gplstLogicalFilterNode);
  239. } END_EACH_LIST_ITEM
  240. exit:
  241. return(Status);
  242. }
  243. NTSTATUS
  244. CDeviceNode::CreateGraphNodes(
  245. )
  246. {
  247. PGRAPH_NODE pGraphNode, pGraphNodeMixer;
  248. NTSTATUS Status = STATUS_SUCCESS;
  249. Assert(this);
  250. if(lstGraphNode.IsLstEmpty()) {
  251. pGraphNode = new GRAPH_NODE(this, 0);
  252. if(pGraphNode == NULL) {
  253. Status = STATUS_INSUFFICIENT_RESOURCES;
  254. Trap();
  255. goto exit;
  256. }
  257. Status = pGraphNode->Create();
  258. if(!NT_SUCCESS(Status)) {
  259. Trap();
  260. goto exit;
  261. }
  262. //
  263. // Create a special GraphNode that points to the same renderer or
  264. // capturer, but is marked with the "mixer topology" flag so the
  265. // pins and topology created for this GraphNode is the virtual mixer
  266. // topology for the mixer driver.
  267. //
  268. pGraphNodeMixer = new GRAPH_NODE(this, FLAGS_MIXER_TOPOLOGY);
  269. if(pGraphNodeMixer == NULL) {
  270. Status = STATUS_INSUFFICIENT_RESOURCES;
  271. Trap();
  272. goto exit;
  273. }
  274. Status = pGraphNodeMixer->Create();
  275. if(!NT_SUCCESS(Status)) {
  276. Trap();
  277. goto exit;
  278. }
  279. }
  280. exit:
  281. if(!NT_SUCCESS(Status)) {
  282. Trap();
  283. lstGraphNode.DestroyList();
  284. }
  285. return(Status);
  286. }
  287. NTSTATUS
  288. CDeviceNode::GetIndexByDevice(
  289. OUT PULONG pIndex
  290. )
  291. {
  292. NTSTATUS Status = STATUS_INVALID_DEVICE_REQUEST;
  293. PDEVICE_NODE pDeviceNode;
  294. UINT iDevice;
  295. if(this == NULL) {
  296. ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
  297. goto exit;
  298. }
  299. iDevice = 0;
  300. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  301. if(pDeviceNode == this) { // This is the one!
  302. *pIndex = iDevice;
  303. Status = STATUS_SUCCESS;
  304. goto exit;
  305. }
  306. iDevice++;
  307. } END_EACH_LIST_ITEM
  308. ASSERT(Status == STATUS_INVALID_DEVICE_REQUEST);
  309. exit:
  310. return(Status);
  311. }
  312. VOID
  313. CDeviceNode::SetPreferredStatus(
  314. KSPROPERTY_SYSAUDIO_DEFAULT_TYPE DeviceType,
  315. BOOL Enable
  316. )
  317. {
  318. PFILTER_NODE_INSTANCE pFilterNodeInstance=NULL;
  319. KSAUDIO_PREFERRED_STATUS PreferredStatus;
  320. PFILE_OBJECT pFileObject;
  321. KSPROPERTY PreferredStatusProperty;
  322. NTSTATUS Status;
  323. ULONG BytesReturned;
  324. Status = CFilterNodeInstance::Create(&pFilterNodeInstance, this->pFilterNode);
  325. if (!NT_SUCCESS(Status)) {
  326. DPF1(0, "SetPreferredStatus : Create filterinstance failed with status = 0x%08x", Status);
  327. goto exit;
  328. }
  329. pFileObject = pFilterNodeInstance->pFileObject;
  330. ASSERT(pFileObject);
  331. //
  332. // Form the IOCTL packet & send it down
  333. //
  334. PreferredStatusProperty.Set = KSPROPSETID_Audio;
  335. PreferredStatusProperty.Id = KSPROPERTY_AUDIO_PREFERRED_STATUS;
  336. PreferredStatusProperty.Flags = KSPROPERTY_TYPE_SET;
  337. PreferredStatus.Enable = Enable;
  338. PreferredStatus.DeviceType = DeviceType;
  339. PreferredStatus.Flags = 0;
  340. PreferredStatus.Reserved = 0;
  341. DPF(60,"Sending preferred Status to:");
  342. DPF1(60," FriendlyName = %s", DbgUnicode2Sz(this->pFilterNode->GetFriendlyName()));
  343. DPF1(60," DI = %s", DbgUnicode2Sz(this->pFilterNode->GetDeviceInterface()));
  344. DPF1(60," Enable = 0x%08x", Enable);
  345. DPF1(60," DeviceType = 0x%08x", DeviceType);
  346. //
  347. // We actually throw away the status we got back from the device.
  348. // Even if this failed we will still continue setting the device to be the
  349. // preferred device
  350. //
  351. Status = KsSynchronousIoControlDevice(pFileObject,
  352. KernelMode,
  353. IOCTL_KS_PROPERTY,
  354. &PreferredStatusProperty,
  355. sizeof(PreferredStatusProperty),
  356. &PreferredStatus,
  357. sizeof(PreferredStatus),
  358. &BytesReturned);
  359. exit:
  360. if (pFilterNodeInstance) {
  361. pFilterNodeInstance->Destroy();
  362. }
  363. }
  364. NTSTATUS
  365. GetDeviceByIndex(
  366. IN UINT Index,
  367. OUT PDEVICE_NODE *ppDeviceNode
  368. )
  369. {
  370. PDEVICE_NODE pDeviceNode;
  371. NTSTATUS Status;
  372. UINT iDevice;
  373. iDevice = 0;
  374. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  375. if(iDevice++ == Index) { // This is the one!
  376. *ppDeviceNode = pDeviceNode;
  377. Status = STATUS_SUCCESS;
  378. goto exit;
  379. }
  380. } END_EACH_LIST_ITEM
  381. Status = STATUS_INVALID_DEVICE_REQUEST;
  382. exit:
  383. return(Status);
  384. }
  385. //---------------------------------------------------------------------------
  386. VOID
  387. DestroyAllGraphs(
  388. )
  389. {
  390. PDEVICE_NODE pDeviceNode;
  391. DPF(50, "DestroyAllGraphs");
  392. FOR_EACH_LIST_ITEM(gplstDeviceNode, pDeviceNode) {
  393. pDeviceNode->lstGraphNode.DestroyList();
  394. } END_EACH_LIST_ITEM
  395. #ifdef DEBUG
  396. ASSERT(gplstConnectNode->IsLstEmpty());
  397. ASSERT(gplstPinNodeInstance->IsLstEmpty());
  398. #endif
  399. }
  400. //---------------------------------------------------------------------------
  401. #ifdef DEBUG
  402. ULONG nDevice = 0;
  403. ENUMFUNC
  404. CDeviceNode::Dump()
  405. {
  406. // .sd .si .sg
  407. if(ulDebugFlags &
  408. (DEBUG_FLAGS_DEVICE |
  409. DEBUG_FLAGS_INSTANCE |
  410. DEBUG_FLAGS_GRAPH |
  411. DEBUG_FLAGS_OBJECT)) {
  412. if(ulDebugNumber == MAXULONG || ulDebugNumber == nDevice) {
  413. if(ulDebugFlags & DEBUG_FLAGS_ADDRESS) {
  414. dprintf("%d: %08x %s\n", nDevice, this, DumpName());
  415. }
  416. else {
  417. dprintf("%d: %s\n", nDevice, DumpName());
  418. }
  419. if(ulDebugFlags & (DEBUG_FLAGS_DEVICE | DEBUG_FLAGS_OBJECT)) {
  420. // .sdv
  421. if(ulDebugFlags & (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_OBJECT)) {
  422. dprintf("DN: %08x FN %08x SHI %08x FNV %08x\n",
  423. this,
  424. pFilterNode,
  425. pShingleInstance,
  426. pFilterNodeVirtual);
  427. dprintf(" %s\n", DumpDeviceInterface());
  428. // .sdv no l
  429. if((ulDebugFlags & DEBUG_FLAGS_LOGICAL_FILTER) == 0) {
  430. dprintf(" lstLFN:");
  431. lstLogicalFilterNode.DumpAddress();
  432. dprintf("\n");
  433. }
  434. // .sdv no g
  435. if((ulDebugFlags & DEBUG_FLAGS_GRAPH) == 0) {
  436. dprintf(" lstGN:");
  437. lstGraphNode.DumpAddress();
  438. dprintf("\n");
  439. }
  440. // .sdv no i
  441. if((ulDebugFlags & DEBUG_FLAGS_INSTANCE) == 0) {
  442. dprintf(" lstFI:");
  443. lstFilterInstance.DumpAddress();
  444. dprintf("\n");
  445. }
  446. dprintf(" papVSD: ");
  447. // .sdvx
  448. if(ulDebugFlags & DEBUG_FLAGS_DETAILS) {
  449. dprintf("\n");
  450. for(ULONG i = 0; i < cVirtualSourceData; i++) {
  451. papVirtualSourceData[i]->Dump();
  452. }
  453. }
  454. else {
  455. for(ULONG i = 0; i < cVirtualSourceData; i++) {
  456. dprintf("%08x ", papVirtualSourceData[i]);
  457. }
  458. dprintf("\n");
  459. }
  460. }
  461. // .sdl
  462. if(ulDebugFlags & DEBUG_FLAGS_LOGICAL_FILTER) {
  463. lstLogicalFilterNode.Dump();
  464. }
  465. }
  466. // .sg
  467. if(ulDebugFlags & DEBUG_FLAGS_GRAPH) {
  468. lstGraphNode.Dump();
  469. }
  470. // .si
  471. if(ulDebugFlags & DEBUG_FLAGS_INSTANCE) {
  472. lstFilterInstance.Dump();
  473. }
  474. if(ulDebugFlags &
  475. (DEBUG_FLAGS_VERBOSE | DEBUG_FLAGS_PIN | DEBUG_FLAGS_TOPOLOGY)) {
  476. dprintf("\n");
  477. }
  478. }
  479. nDevice++;
  480. }
  481. return(STATUS_CONTINUE);
  482. }
  483. #endif
  484. //---------------------------------------------------------------------------