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.

896 lines
26 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: notify.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. // Include safe string library for safe string manipulation.
  29. //
  30. #define STRSAFE_NO_DEPRECATE // Use safe and unsafe functions interchangeably.
  31. #include "strsafe.h"
  32. #define DEVICE_NAME_TAG L"\\\\?\\"
  33. //---------------------------------------------------------------------------
  34. //---------------------------------------------------------------------------
  35. CONST GUID *apguidCategories[] = {
  36. &KSCATEGORY_AUDIO,
  37. &KSCATEGORY_AUDIO_GFX,
  38. &KSCATEGORY_TOPOLOGY,
  39. &KSCATEGORY_BRIDGE,
  40. &KSCATEGORY_RENDER,
  41. &KSCATEGORY_CAPTURE,
  42. &KSCATEGORY_MIXER,
  43. &KSCATEGORY_DATATRANSFORM,
  44. &KSCATEGORY_ACOUSTIC_ECHO_CANCEL,
  45. &KSCATEGORY_INTERFACETRANSFORM,
  46. &KSCATEGORY_MEDIUMTRANSFORM,
  47. &KSCATEGORY_DATACOMPRESSOR,
  48. &KSCATEGORY_DATADECOMPRESSOR,
  49. &KSCATEGORY_COMMUNICATIONSTRANSFORM,
  50. &KSCATEGORY_SPLITTER,
  51. &KSCATEGORY_AUDIO_SPLITTER,
  52. &KSCATEGORY_SYNTHESIZER,
  53. &KSCATEGORY_DRM_DESCRAMBLE,
  54. &KSCATEGORY_MICROPHONE_ARRAY_PROCESSOR,
  55. };
  56. ULONG aulFilterType[] = {
  57. FILTER_TYPE_AUDIO,
  58. FILTER_TYPE_GFX,
  59. FILTER_TYPE_TOPOLOGY,
  60. FILTER_TYPE_BRIDGE,
  61. FILTER_TYPE_RENDERER,
  62. FILTER_TYPE_CAPTURER,
  63. FILTER_TYPE_MIXER,
  64. FILTER_TYPE_DATA_TRANSFORM,
  65. FILTER_TYPE_AEC,
  66. FILTER_TYPE_INTERFACE_TRANSFORM,
  67. FILTER_TYPE_MEDIUM_TRANSFORM,
  68. FILTER_TYPE_DATA_TRANSFORM,
  69. FILTER_TYPE_DATA_TRANSFORM,
  70. FILTER_TYPE_COMMUNICATION_TRANSFORM,
  71. FILTER_TYPE_SPLITTER,
  72. FILTER_TYPE_SPLITTER,
  73. FILTER_TYPE_SYNTHESIZER,
  74. FILTER_TYPE_DRM_DESCRAMBLE,
  75. FILTER_TYPE_MIC_ARRAY_PROCESSOR,
  76. };
  77. PVOID pNotificationHandle = NULL;
  78. //---------------------------------------------------------------------------
  79. //---------------------------------------------------------------------------
  80. NTSTATUS
  81. RegisterForPlugPlayNotifications(
  82. )
  83. {
  84. NTSTATUS Status;
  85. DPF(50, "RegisterForPlugPlayNotifications");
  86. ASSERT(gpDeviceInstance != NULL);
  87. ASSERT(gpDeviceInstance->pPhysicalDeviceObject != NULL);
  88. Status = IoRegisterPlugPlayNotification(
  89. EventCategoryDeviceInterfaceChange,
  90. PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
  91. (LPGUID)&KSCATEGORY_AUDIO,
  92. gpDeviceInstance->pPhysicalDeviceObject->DriverObject,
  93. (NTSTATUS (*)(PVOID, PVOID)) AudioDeviceInterfaceNotification,
  94. NULL,
  95. &pNotificationHandle);
  96. if(!NT_SUCCESS(Status)) {
  97. Trap();
  98. goto exit;
  99. }
  100. exit:
  101. return(Status);
  102. }
  103. VOID
  104. UnregisterForPlugPlayNotifications(
  105. )
  106. {
  107. if(pNotificationHandle != NULL) {
  108. IoUnregisterPlugPlayNotification(pNotificationHandle);
  109. }
  110. }
  111. VOID
  112. DecrementAddRemoveCount(
  113. )
  114. {
  115. if(InterlockedDecrement(&glPendingAddDelete) == 0) {
  116. DPF(50, "DecrementAddRemoveCount: sending event");
  117. KsGenerateEventList(
  118. NULL,
  119. KSEVENT_SYSAUDIO_ADDREMOVE_DEVICE,
  120. &gEventQueue,
  121. KSEVENTS_SPINLOCK,
  122. &gEventLock);
  123. }
  124. }
  125. NTSTATUS
  126. AddFilterWorker(
  127. PWSTR pwstrDeviceInterface,
  128. PVOID pReference
  129. )
  130. {
  131. AddFilter(pwstrDeviceInterface, NULL);
  132. ExFreePool(pwstrDeviceInterface);
  133. DecrementAddRemoveCount();
  134. // Dereference sysaudio PDO.
  135. KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  136. return(STATUS_SUCCESS);
  137. }
  138. NTSTATUS
  139. DeleteFilterWorker(
  140. PWSTR pwstrDeviceInterface,
  141. PVOID pReference
  142. )
  143. {
  144. DeleteFilter(pwstrDeviceInterface);
  145. ExFreePool(pwstrDeviceInterface);
  146. DecrementAddRemoveCount();
  147. // Dereference sysaudio PDO.
  148. KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  149. return(STATUS_SUCCESS);
  150. }
  151. NTSTATUS
  152. AudioDeviceInterfaceNotification(
  153. IN PDEVICE_INTERFACE_CHANGE_NOTIFICATION pNotification,
  154. IN PVOID Context
  155. )
  156. {
  157. NTSTATUS Status = STATUS_SUCCESS;
  158. PWSTR pwstrDeviceInterface;
  159. DPF1(50, "AudioDeviceInterfaceNotification: (%s)",
  160. DbgUnicode2Sz(pNotification->SymbolicLinkName->Buffer));
  161. //
  162. // SECURITY NOTE:
  163. // We trust the Buffer, because it is passed to us as part of notification
  164. // from PnP subsystem.
  165. //
  166. pwstrDeviceInterface = (PWSTR)
  167. ExAllocatePoolWithTag(
  168. PagedPool,
  169. (wcslen(pNotification->SymbolicLinkName->Buffer) + 1) * sizeof(WCHAR),
  170. POOLTAG_SYSA);
  171. if(pwstrDeviceInterface == NULL) {
  172. Status = STATUS_INSUFFICIENT_RESOURCES;
  173. goto exit;
  174. }
  175. // The notification sends null terminated unicode strings
  176. wcscpy(pwstrDeviceInterface, pNotification->SymbolicLinkName->Buffer);
  177. if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL)) {
  178. //
  179. // Keep a reference so that SWENUM does not REMOVE the device
  180. // when the Worker thread is running.
  181. // If the thread is scheduled successfully, it will remove the reference
  182. // when exiting.
  183. //
  184. Status = KsReferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  185. if(!NT_SUCCESS(Status)) {
  186. goto exit;
  187. }
  188. InterlockedIncrement(&glPendingAddDelete);
  189. Status = QueueWorkList(
  190. (UTIL_PFN)AddFilterWorker,
  191. pwstrDeviceInterface,
  192. NULL);
  193. if (!NT_SUCCESS(Status)) {
  194. KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  195. }
  196. }
  197. else if(IsEqualGUID(&pNotification->Event, &GUID_DEVICE_INTERFACE_REMOVAL)) {
  198. //
  199. // Keep a reference so that SWENUM does not REMOVE the device
  200. // when the Worker thread is running.
  201. // If the thread is scheduled successfully, it will remove the reference
  202. // when exiting.
  203. //
  204. Status = KsReferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  205. if(!NT_SUCCESS(Status)) {
  206. goto exit;
  207. }
  208. InterlockedIncrement(&glPendingAddDelete);
  209. Status = QueueWorkList(
  210. (UTIL_PFN)DeleteFilterWorker,
  211. pwstrDeviceInterface,
  212. NULL);
  213. if (!NT_SUCCESS(Status)) {
  214. KsDereferenceSoftwareBusObject(gpDeviceInstance->pDeviceHeader);
  215. }
  216. }
  217. else {
  218. //
  219. // SECURITY NOTE:
  220. // Sysaudio is registering only for EventCategoryDeviceInterfaceChange.
  221. // This should send ARRIVAL and REMOVAL.
  222. // If anything else comes up, we will return SUCCESS.
  223. // However we are making sure that pwstrDeviceInterface is not leaked.
  224. //
  225. if (pwstrDeviceInterface) {
  226. ExFreePool(pwstrDeviceInterface);
  227. pwstrDeviceInterface = NULL;
  228. }
  229. }
  230. exit:
  231. if (!NT_SUCCESS(Status))
  232. {
  233. if (pwstrDeviceInterface) {
  234. ExFreePool(pwstrDeviceInterface);
  235. pwstrDeviceInterface = NULL;
  236. }
  237. }
  238. return(Status);
  239. }
  240. NTSTATUS
  241. AddFilter(
  242. PWSTR pwstrDeviceInterface,
  243. PFILTER_NODE *ppFilterNode // if !NULL, physical connection addfilter
  244. )
  245. {
  246. PFILTER_NODE pFilterNodeDuplicate = NULL;
  247. PFILTER_NODE pFilterNode = NULL;
  248. UNICODE_STRING ustrFilterName;
  249. UNICODE_STRING ustrAliasName;
  250. UNICODE_STRING ustrName;
  251. NTSTATUS Status;
  252. ULONG fulType;
  253. int i;
  254. DPF1(50, "AddFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
  255. fulType = 0;
  256. RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
  257. //
  258. // For each Interface in apguidCategories, get interface alias of
  259. // the new device. Check for duplicate interfaces.
  260. //
  261. for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
  262. Status = IoGetDeviceInterfaceAlias(
  263. &ustrFilterName,
  264. apguidCategories[i],
  265. &ustrAliasName);
  266. if(NT_SUCCESS(Status)) {
  267. HANDLE hAlias;
  268. Status = OpenDevice(ustrAliasName.Buffer, &hAlias);
  269. if(NT_SUCCESS(Status)) {
  270. DPF2(100, "AddFilter: alias (%s) aulFilterType %08x",
  271. DbgUnicode2Sz(ustrAliasName.Buffer),
  272. aulFilterType[i]);
  273. fulType |= aulFilterType[i];
  274. ZwClose(hAlias);
  275. if(pFilterNodeDuplicate == NULL) {
  276. FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
  277. if(pFilterNode->GetDeviceInterface() == NULL) {
  278. continue;
  279. }
  280. RtlInitUnicodeString(
  281. &ustrName,
  282. pFilterNode->GetDeviceInterface());
  283. if(RtlEqualUnicodeString(
  284. &ustrAliasName,
  285. &ustrName,
  286. TRUE)) {
  287. DPF(50, "AddFilter: dup");
  288. pFilterNodeDuplicate = pFilterNode;
  289. break;
  290. }
  291. } END_EACH_LIST_ITEM
  292. }
  293. }
  294. else {
  295. DPF1(10, "AddFilter: OpenDevice FAILED on alias (%s)",
  296. DbgUnicode2Sz(ustrAliasName.Buffer));
  297. }
  298. RtlFreeUnicodeString(&ustrAliasName);
  299. }
  300. }
  301. pFilterNode = pFilterNodeDuplicate;
  302. Status = STATUS_SUCCESS;
  303. //
  304. // Create a new Filter_Node if this is not a duplicate.
  305. //
  306. if(pFilterNodeDuplicate == NULL) {
  307. pFilterNode = new FILTER_NODE(fulType);
  308. if(pFilterNode == NULL) {
  309. Status = STATUS_INSUFFICIENT_RESOURCES;
  310. Trap();
  311. goto exit;
  312. }
  313. Status = pFilterNode->Create(pwstrDeviceInterface);
  314. if(!NT_SUCCESS(Status)) {
  315. goto exit;
  316. }
  317. Status = pFilterNode->DuplicateForCapture();
  318. if(!NT_SUCCESS(Status)) {
  319. goto exit;
  320. }
  321. DPF1(50, "AddFilter: new CFilterNode fulType %08x", fulType);
  322. }
  323. //
  324. // If this is called from Interface Notification Callback,
  325. // create a new DeviceNode for the new FilterNode.
  326. //
  327. if(ppFilterNode == NULL) {
  328. if(pFilterNode->GetType() & FILTER_TYPE_ENDPOINT) {
  329. //
  330. // Check if a DeviceNode has already been created for
  331. // this FilterNode.
  332. //
  333. if (NULL != pFilterNodeDuplicate &&
  334. NULL != pFilterNodeDuplicate->pDeviceNode) {
  335. DPF1(5, "Duplicate FilterNode %X. Skip DeviceNode Create",
  336. pFilterNode);
  337. }
  338. else {
  339. pFilterNode->pDeviceNode = new DEVICE_NODE;
  340. if(pFilterNode->pDeviceNode == NULL) {
  341. Status = STATUS_INSUFFICIENT_RESOURCES;
  342. Trap();
  343. goto exit;
  344. }
  345. Status = pFilterNode->pDeviceNode->Create(pFilterNode);
  346. if(!NT_SUCCESS(Status)) {
  347. goto exit;
  348. }
  349. }
  350. }
  351. else {
  352. DPF(50, "AddFilter: DestroyAllGraphs");
  353. DestroyAllGraphs();
  354. }
  355. }
  356. exit:
  357. if(!NT_SUCCESS(Status)) {
  358. DPF2(5, "AddFilter: FAILED (%s) %08x",
  359. DbgUnicode2Sz(pwstrDeviceInterface),
  360. Status);
  361. if(pFilterNode != NULL && pFilterNodeDuplicate == NULL) {
  362. delete pFilterNode;
  363. pFilterNode = NULL;
  364. }
  365. }
  366. if(ppFilterNode != NULL) {
  367. *ppFilterNode = pFilterNode;
  368. }
  369. return(Status);
  370. }
  371. NTSTATUS
  372. DeleteFilter(
  373. PWSTR pwstrDeviceInterface
  374. )
  375. {
  376. UNICODE_STRING ustrFilterName;
  377. UNICODE_STRING ustrAliasName;
  378. UNICODE_STRING ustrName;
  379. PFILTER_NODE pFilterNode;
  380. NTSTATUS Status;
  381. int i;
  382. DPF1(50, "DeleteFilter: (%s)", DbgUnicode2Sz(pwstrDeviceInterface));
  383. RtlInitUnicodeString(&ustrFilterName, pwstrDeviceInterface);
  384. //
  385. // First delete all filter nodes which have the device interface which is
  386. // going away
  387. //
  388. FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
  389. if(pFilterNode->GetDeviceInterface() == NULL) {
  390. continue;
  391. }
  392. RtlInitUnicodeString(
  393. &ustrName,
  394. pFilterNode->GetDeviceInterface());
  395. if(RtlEqualUnicodeString(
  396. &ustrFilterName,
  397. &ustrName,
  398. TRUE)) {
  399. delete pFilterNode;
  400. DELETE_LIST_ITEM(gplstFilterNode);
  401. }
  402. } END_EACH_LIST_ITEM
  403. for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
  404. //
  405. // According to PnP group, it is perfectly safe to ask for aliases
  406. // during removal. The interface itself will be enabled or disabled. But
  407. // we will still get the correct aliases.
  408. //
  409. Status = IoGetDeviceInterfaceAlias(
  410. &ustrFilterName,
  411. apguidCategories[i],
  412. &ustrAliasName);
  413. if(NT_SUCCESS(Status)) {
  414. FOR_EACH_LIST_ITEM_DELETE(gplstFilterNode, pFilterNode) {
  415. if(pFilterNode->GetDeviceInterface() == NULL) {
  416. continue;
  417. }
  418. RtlInitUnicodeString(
  419. &ustrName,
  420. pFilterNode->GetDeviceInterface());
  421. if(RtlEqualUnicodeString(
  422. &ustrAliasName,
  423. &ustrName,
  424. TRUE)) {
  425. delete pFilterNode;
  426. DELETE_LIST_ITEM(gplstFilterNode);
  427. }
  428. } END_EACH_LIST_ITEM
  429. RtlFreeUnicodeString(&ustrAliasName);
  430. }
  431. }
  432. return(STATUS_SUCCESS);
  433. }
  434. #define GFX_VERBOSE_LEVEL 50
  435. //=============================================================================
  436. // Assumptions:
  437. // - SysaudioGfx.ulType has been already validated.
  438. //
  439. NTSTATUS AddGfx(
  440. PSYSAUDIO_GFX pSysaudioGfx,
  441. ULONG cbMaxLength
  442. )
  443. {
  444. NTSTATUS Status;
  445. PFILE_OBJECT pFileObject;
  446. PFILTER_NODE pFilterNode;
  447. ULONG Flags;
  448. PWSTR pwstrDeviceName;
  449. ULONG GfxOrderBase, GfxOrderCeiling;
  450. ASSERT(pSysaudioGfx);
  451. pFileObject = NULL;
  452. pwstrDeviceName = NULL;
  453. pFilterNode = NULL;
  454. GfxOrderBase = GfxOrderCeiling = 0;
  455. DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Request to add Gfx %x", pSysaudioGfx);
  456. DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
  457. DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
  458. DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
  459. DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
  460. //
  461. // Setup GFX Order's base & ceiling for future usage
  462. //
  463. if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
  464. GfxOrderBase = ORDER_RENDER_GFX_FIRST;
  465. GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
  466. }
  467. if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE) {
  468. GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
  469. GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
  470. }
  471. ASSERT(GfxOrderBase);
  472. ASSERT(GfxOrderCeiling);
  473. //
  474. // validate that order is within range
  475. //
  476. if (pSysaudioGfx->ulOrder >= (GfxOrderCeiling - GfxOrderBase)) {
  477. Status = STATUS_INVALID_PARAMETER;
  478. Trap();
  479. goto exit;
  480. }
  481. //
  482. // Allocate a Filter Node for the new GFX
  483. //
  484. pFilterNode = new FILTER_NODE(FILTER_TYPE_GFX);
  485. if(pFilterNode == NULL) {
  486. Trap();
  487. Status = STATUS_INSUFFICIENT_RESOURCES;
  488. goto exit;
  489. }
  490. pFilterNode->SetRenderCaptureFlags(pSysaudioGfx->ulType);
  491. //
  492. // Copy the Device Name (on which the gfx needs to be attached) into a local
  493. // copy for our own use
  494. //
  495. Status = SafeCopyDeviceName(
  496. (PWSTR) ((CHAR *) pSysaudioGfx + pSysaudioGfx->ulDeviceNameOffset),
  497. cbMaxLength,
  498. &pwstrDeviceName);
  499. if (!NT_SUCCESS(Status)) {
  500. goto exit;
  501. }
  502. DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
  503. //
  504. // Make sure that there are no other GFXes with the same order on this device
  505. //
  506. if ((FindGfx(pFilterNode,
  507. 0, // wild card for handle
  508. pwstrDeviceName,
  509. pSysaudioGfx->ulOrder+GfxOrderBase))) {
  510. delete [] pwstrDeviceName;
  511. Status = STATUS_INVALID_PARAMETER;
  512. goto exit;
  513. }
  514. //
  515. // Get the FileObject of the GFX for future use
  516. // SECURITY NOTE:
  517. // The handle is coming from UserMode. So we have to specify UserMode.
  518. // Also we are explicitly interested in FileObjects. The rest should be
  519. // rejected.
  520. //
  521. Status = ObReferenceObjectByHandle(
  522. pSysaudioGfx->hGfx,
  523. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  524. *IoFileObjectType,
  525. UserMode,
  526. (PVOID*)&pFileObject,
  527. NULL);
  528. if (!NT_SUCCESS(Status) || NULL == pFileObject) {
  529. DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: ObReference failed %x", Status);
  530. delete [] pwstrDeviceName;
  531. goto exit;
  532. }
  533. //
  534. // Add the device name string to global memory to be freed
  535. //
  536. Status = pFilterNode->lstFreeMem.AddList(pwstrDeviceName);
  537. if(!NT_SUCCESS(Status)) {
  538. Trap();
  539. delete [] pwstrDeviceName;
  540. goto exit;
  541. }
  542. //
  543. // Indicate that this Gfx needs be loaded only on the device pointed to be
  544. // pwstrDeviceName
  545. //
  546. Status = pFilterNode->AddDeviceInterfaceMatch(pwstrDeviceName);
  547. if(!NT_SUCCESS(Status)) {
  548. Trap();
  549. delete [] pwstrDeviceName;
  550. goto exit;
  551. }
  552. //
  553. // Set the Gfx order in the filter node
  554. //
  555. pFilterNode->SetOrder(pSysaudioGfx->ulOrder+GfxOrderBase);
  556. //
  557. // Profile the GFX and create pin infos, logical filter nodes etc
  558. //
  559. Status = pFilterNode->ProfileFilter(pFileObject);
  560. if(!NT_SUCCESS(Status)) {
  561. Trap();
  562. goto exit;
  563. }
  564. //
  565. // Fix the GFX glitching problem. Send the property blindly to GFX
  566. // filter. KS will handle the property.
  567. // Failures are not important, ignore them.
  568. //
  569. SetKsFrameHolding(pFileObject);
  570. exit:
  571. if(!NT_SUCCESS(Status)) {
  572. DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Failed, Status = %x", Status);
  573. if(pFilterNode != NULL) {
  574. delete pFilterNode;
  575. pFilterNode = NULL;
  576. }
  577. if(pFileObject != NULL) {
  578. ObDereferenceObject(pFileObject);
  579. }
  580. }
  581. else {
  582. DPF1(GFX_VERBOSE_LEVEL, "AddGfx :: Added GFX FilterNode %x", pFilterNode);
  583. DPF1(GFX_VERBOSE_LEVEL, " order = %x", pFilterNode->GetOrder());
  584. DPF1(GFX_VERBOSE_LEVEL, " type = %x", pFilterNode->GetType());
  585. DPF1(GFX_VERBOSE_LEVEL, " flags = %x", pFilterNode->GetFlags());
  586. //
  587. // Setup file handle details for later use of
  588. // the user mode handle passed in
  589. //
  590. pFilterNode->SetFileDetails(pSysaudioGfx->hGfx,
  591. pFileObject,
  592. PsGetCurrentProcess());
  593. //
  594. // Force a rebuild of graph nodes
  595. //
  596. DestroyAllGraphs();
  597. }
  598. return(Status);
  599. }
  600. //=============================================================================
  601. // Assumptions:
  602. // - SysaudioGfx.ulType has been already validated.
  603. //
  604. NTSTATUS RemoveGfx(
  605. PSYSAUDIO_GFX pSysaudioGfx,
  606. ULONG cbMaxLength
  607. )
  608. {
  609. NTSTATUS Status;
  610. PFILTER_NODE pFilterNode;
  611. PWSTR pwstrDeviceName;
  612. ULONG GfxOrderBase, GfxOrderCeiling;
  613. pFilterNode = NULL;
  614. GfxOrderBase = GfxOrderCeiling = 0;
  615. pwstrDeviceName = NULL;
  616. DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Request to remove Gfx %x", pSysaudioGfx);
  617. DPF1(GFX_VERBOSE_LEVEL, " hGfx = %x", pSysaudioGfx->hGfx);
  618. DPF1(GFX_VERBOSE_LEVEL, " ulOrder = %x", pSysaudioGfx->ulOrder);
  619. DPF1(GFX_VERBOSE_LEVEL, " ulType = %x", pSysaudioGfx->ulType);
  620. DPF1(GFX_VERBOSE_LEVEL, " Flags = %x", pSysaudioGfx->ulFlags);
  621. //
  622. // Setup GFX Order's base & ceiling for future usage
  623. //
  624. if (pSysaudioGfx->ulType == GFX_DEVICETYPE_RENDER) {
  625. GfxOrderBase = ORDER_RENDER_GFX_FIRST;
  626. GfxOrderCeiling = ORDER_RENDER_GFX_LAST;
  627. }
  628. if (pSysaudioGfx->ulType == GFX_DEVICETYPE_CAPTURE ) {
  629. GfxOrderBase = ORDER_CAPTURE_GFX_FIRST;
  630. GfxOrderCeiling = ORDER_CAPTURE_GFX_LAST;
  631. }
  632. ASSERT(GfxOrderBase);
  633. ASSERT(GfxOrderCeiling);
  634. //
  635. // Copy the Device Name (on which the gfx needs to be attached) into a local copy for our own use
  636. //
  637. Status = SafeCopyDeviceName(
  638. (PWSTR) ((CHAR *) pSysaudioGfx + pSysaudioGfx->ulDeviceNameOffset),
  639. cbMaxLength,
  640. &pwstrDeviceName);
  641. if (!NT_SUCCESS(Status)) {
  642. goto exit;
  643. }
  644. DPF1(GFX_VERBOSE_LEVEL, " On DI = %s", DbgUnicode2Sz(pwstrDeviceName));
  645. //
  646. // Find the FilterNode for the Gfx
  647. //
  648. if ((pFilterNode = FindGfx(NULL,
  649. pSysaudioGfx->hGfx,
  650. pwstrDeviceName,
  651. pSysaudioGfx->ulOrder+GfxOrderBase)) == NULL) {
  652. Status = STATUS_INVALID_PARAMETER;
  653. goto exit;
  654. }
  655. //
  656. // Should we validate the FileHandle Value?
  657. //
  658. //
  659. // Dereference the file object
  660. //
  661. pFilterNode->ClearFileDetails();
  662. exit:
  663. if(!NT_SUCCESS(Status)) {
  664. DPF1(GFX_VERBOSE_LEVEL, "RemoveGfx :: Failed, Status = %x", Status);
  665. Trap();
  666. }
  667. else {
  668. delete pFilterNode;
  669. }
  670. delete pwstrDeviceName;
  671. return(Status);
  672. }
  673. PFILTER_NODE
  674. FindGfx(
  675. PFILTER_NODE pnewFilterNode,
  676. HANDLE hGfx,
  677. PWSTR pwstrDeviceName,
  678. ULONG GfxOrder
  679. )
  680. {
  681. PFILTER_NODE pFilterNode;
  682. ULONG DeviceCount;
  683. UNICODE_STRING usInDevice, usfnDevice;
  684. PWSTR pwstr;
  685. DPF2(90, "FindGfx:: Looking for GFX with order = %x attached to %s)", GfxOrder, DbgUnicode2Sz(pwstrDeviceName));
  686. FOR_EACH_LIST_ITEM(gplstFilterNode, pFilterNode) {
  687. //
  688. // Skip the one we just added
  689. //
  690. if (pFilterNode == pnewFilterNode) {
  691. continue;
  692. }
  693. //
  694. // Check whether this pFilterNode matches the Gfx we are looking for
  695. //
  696. if (pFilterNode->DoesGfxMatch(hGfx, pwstrDeviceName, GfxOrder)) {
  697. return (pFilterNode);
  698. }
  699. } END_EACH_LIST_ITEM
  700. return(NULL);
  701. }
  702. //=============================================================================
  703. //
  704. // Copies a UNICODE DeviceName to a new location. The source string is coming
  705. // from user mode.
  706. // There are assumptions in the code that the size should be greater than 4
  707. // characters. (see DEVICE_NAME_TAG)
  708. // Caller must make sure that this is BUFFERRED IO.
  709. //
  710. NTSTATUS
  711. SafeCopyDeviceName(
  712. PWSTR pwstrDeviceName,
  713. ULONG cbMaxLength,
  714. PWSTR *String
  715. )
  716. {
  717. NTSTATUS ntStatus;
  718. ULONG cchLength;
  719. PWSTR pwstrString = NULL;
  720. *String = NULL;
  721. //
  722. // SECURITY_NOTE:
  723. // pwstrDeviceName points to a NULL-terminated UNICODE string.
  724. // The string is coming from user mode, through BUFFERRED IO. So try/
  725. // except is not necessary. Also Probe would not catch any errors.
  726. // The IRP OutputBufferLength limits, the size of the string.
  727. //
  728. if (S_OK !=
  729. StringCchLength(pwstrDeviceName, (size_t) cbMaxLength / sizeof(WCHAR), (size_t *) &cchLength))
  730. {
  731. DPF(5, "SafeCopyDeviceName: DeviceName is not zero-terminated.");
  732. ntStatus = STATUS_INVALID_PARAMETER;
  733. goto exit;
  734. }
  735. //
  736. // SECURITY NOTE:
  737. // There are assumptions further in the code about DeviceName string.
  738. // Make sure those assumptions hold.
  739. // One assumption is that DeviceName should be greater than 4
  740. // characters.
  741. //
  742. if (cchLength <= wcslen(DEVICE_NAME_TAG)) {
  743. DPF(5, "SafeCopyDeviceName: DeviceName is not well-formed");
  744. ntStatus = STATUS_INVALID_PARAMETER;
  745. goto exit;
  746. }
  747. pwstrString = new(WCHAR[cchLength + 1]) ;
  748. if(pwstrString == NULL) {
  749. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  750. goto exit;
  751. }
  752. //
  753. // SECURITY NOTE:
  754. // Note that Length does not include the terminating NULL.
  755. // Use n version of string copy in case the buffer changes.
  756. // Also make sure that the string is NULL terminated.
  757. //
  758. wcsncpy(pwstrString, pwstrDeviceName, cchLength);
  759. pwstrString[cchLength] = UNICODE_NULL;
  760. ntStatus = STATUS_SUCCESS;
  761. exit:
  762. *String = pwstrString;
  763. return ntStatus;
  764. }
  765. NTSTATUS
  766. GetFilterTypeFromGuid(
  767. IN LPGUID pguid,
  768. OUT PULONG pfulType
  769. )
  770. {
  771. int i;
  772. for(i = 0; i < SIZEOF_ARRAY(apguidCategories); i++) {
  773. if (memcmp (apguidCategories[i], pguid, sizeof(GUID)) == 0) {
  774. *pfulType |= aulFilterType[i];
  775. return(STATUS_SUCCESS);
  776. }
  777. }
  778. return(STATUS_INVALID_DEVICE_REQUEST);
  779. }
  780. //---------------------------------------------------------------------------
  781. // End of File: notify.cpp
  782. //---------------------------------------------------------------------------