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.

1125 lines
35 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: sysaudio.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "redbook.h"
  11. #include "proto.h"
  12. #include <wdmguid.h>
  13. #include <ksmedia.h>
  14. #ifdef _USE_ETW
  15. #include "sysaudio.tmh"
  16. #endif // _USE_ETW
  17. //////////////////////////////////////////////////////////////////////
  18. #ifdef ALLOC_PRAGMA
  19. #pragma alloc_text(PAGE, AttachVirtualSource)
  20. #pragma alloc_text(PAGE, CloseSysAudio)
  21. #pragma alloc_text(PAGE, GetPinProperty)
  22. #pragma alloc_text(PAGE, GetVolumeNodeId)
  23. #pragma alloc_text(PAGE, InitializeVirtualSource)
  24. #pragma alloc_text(PAGE, OpenInterfaceByGuid)
  25. #pragma alloc_text(PAGE, OpenSysAudio)
  26. #pragma alloc_text(PAGE, RedBookKsSetVolume)
  27. #pragma alloc_text(PAGE, SetNextDeviceState)
  28. #pragma alloc_text(PAGE, SysAudioPnpNotification)
  29. #pragma alloc_text(PAGE, UninitializeVirtualSource)
  30. #endif // ALLOC_PRAGMA
  31. //////////////////////////////////////////////////////////////////////
  32. NTSTATUS
  33. OpenSysAudio(
  34. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  35. )
  36. /*++
  37. Routine Description:
  38. This routine is a wrapper around all the work that must be done
  39. just to open sysaudio for playback. the code was swiped from
  40. Win98, and then translated into CSN (Cutler Standard Notation)
  41. Arguments:
  42. DeviceExtensionPinConnect - if successful, this will be the pin to send data to
  43. PinFileObject - if successful, the file object this pin is associated
  44. with is returned in this structure
  45. PinDeviceObject - if successful, the device object this pin is
  46. associated with is returned in this structure
  47. VolumeNodeId - ?? No idea what this is... yet.
  48. Return Value:
  49. status
  50. --*/
  51. {
  52. PFILE_OBJECT guidFileObject;
  53. PFILE_OBJECT pinFileObject;
  54. HANDLE deviceHandle;
  55. NTSTATUS status;
  56. HANDLE pinHandle;
  57. ULONG volumeNodeId;
  58. ULONG mixerPinId;
  59. ULONG pins, pinId;
  60. PAGED_CODE();
  61. VerifyCalledByThread(DeviceExtension);
  62. guidFileObject = NULL;
  63. pinFileObject = NULL;
  64. deviceHandle = NULL;
  65. status = STATUS_SUCCESS;
  66. pinHandle = NULL;
  67. volumeNodeId = -1;
  68. mixerPinId = DeviceExtension->Stream.MixerPinId;
  69. TRY {
  70. ASSERT( mixerPinId != MAXULONG );
  71. //
  72. // Note dependency on IoRegisterPlugPlayNotification() in pnp.c
  73. //
  74. status = OpenInterfaceByGuid(
  75. //&KSCATEGORY_SYSAUDIO,
  76. &KSCATEGORY_PREFERRED_WAVEOUT_DEVICE,
  77. &deviceHandle,
  78. &guidFileObject);
  79. if (!NT_SUCCESS(status)) {
  80. LEAVE;
  81. }
  82. //
  83. // Get the number of pins
  84. //
  85. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  86. "SysAudio => Getting Pin Property PIN_CTYPES\n"));
  87. status = GetPinProperty(guidFileObject,
  88. KSPROPERTY_PIN_CTYPES,
  89. 0, // doesn't matter for ctypes
  90. sizeof(pins),
  91. &pins);
  92. if (!NT_SUCCESS(status)) {
  93. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  94. "SysAudio !! Unable to get number of pins %lx\n",
  95. status));
  96. RedBookLogError(DeviceExtension,
  97. REDBOOK_ERR_CANNOT_GET_NUMBER_OF_PINS,
  98. status);
  99. LEAVE;
  100. }
  101. //
  102. // Try to get a matching pin -- brute force method
  103. //
  104. for( pinId = 0; pinId < pins; pinId++) {
  105. KSPIN_COMMUNICATION communication;
  106. KSPIN_DATAFLOW dataFlow;
  107. //
  108. // check communication of the pin. accept either
  109. // a sink or a pin that is both a source and sink
  110. //
  111. status = GetPinProperty(guidFileObject,
  112. KSPROPERTY_PIN_COMMUNICATION,
  113. pinId,
  114. sizeof(communication),
  115. &communication);
  116. if (!NT_SUCCESS(status)) {
  117. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  118. "SysAudio !! Pin %d communication query "
  119. "failed %lx\n", pinId, status ));
  120. continue;
  121. }
  122. if ( communication != KSPIN_COMMUNICATION_SINK &&
  123. communication != KSPIN_COMMUNICATION_BOTH ) continue;
  124. //
  125. // only use this pin if it accepts incoming data
  126. //
  127. status = GetPinProperty(guidFileObject,
  128. KSPROPERTY_PIN_DATAFLOW,
  129. pinId,
  130. sizeof(dataFlow),
  131. &dataFlow);
  132. if (!NT_SUCCESS(status)) {
  133. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  134. "SysAudio !! Pin %d dataflow query failed %lx\n",
  135. pinId, status));
  136. continue;
  137. }
  138. if (dataFlow != KSPIN_DATAFLOW_IN) continue;
  139. //
  140. // we have found a matching pin, so attempt to connect
  141. //
  142. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  143. "SysAudio => Attempt to connect to pin %d\n", pinId));
  144. DeviceExtension->Stream.Connect.PinId = pinId;
  145. DeviceExtension->Stream.Connect.PinToHandle = NULL;
  146. status = KsCreatePin(deviceHandle,
  147. &DeviceExtension->Stream.Connect,
  148. GENERIC_WRITE, // FILE_WRITE_ACCESS
  149. &pinHandle);
  150. if (!NT_SUCCESS(status)) {
  151. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  152. "SysAudio => Cannot create a writable pin %d\n",
  153. pinId));
  154. continue;
  155. }
  156. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  157. "SysAudio => Connected to pin %d\n", pinId ));
  158. //
  159. // get the object associated with the pinHandle just created
  160. // so we can then get other information about the pin
  161. //
  162. status = ObReferenceObjectByHandle(pinHandle,
  163. GENERIC_READ | GENERIC_WRITE,
  164. NULL,
  165. KernelMode,
  166. &pinFileObject,
  167. NULL);
  168. if (!NT_SUCCESS(status)) {
  169. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  170. "SysAudio !! Object from handle for pin "
  171. "failed %lx\n", status));
  172. LEAVE;
  173. }
  174. //
  175. // this allows us to change our output volume
  176. // this just sends a ks ioctl, no referencing done here
  177. //
  178. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  179. "SysAudio => Getting VolumeNodeId\n"));
  180. status = GetVolumeNodeId(pinFileObject,
  181. &volumeNodeId);
  182. if (!NT_SUCCESS(status)) {
  183. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  184. "SysAudio !! Unable to get volume node "
  185. "id %lx\n", status));
  186. LEAVE;
  187. }
  188. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  189. "SysAudio => Attaching PinFileObject %p "
  190. "to MixerPinId %d\n", pinFileObject,
  191. mixerPinId));
  192. //
  193. // this just sends a ks ioctl, no referencing done here
  194. //
  195. status = AttachVirtualSource(pinFileObject, mixerPinId);
  196. if (!NT_SUCCESS(status)) {
  197. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  198. "SysAudio !! Unable to attach virtual "
  199. "source %lx\n", status));
  200. LEAVE;
  201. }
  202. //
  203. // successful completion
  204. //
  205. status = STATUS_SUCCESS;
  206. LEAVE;
  207. }
  208. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  209. "Sysaudio !! Unable to connect to any pins\n"));
  210. RedBookLogError(DeviceExtension,
  211. REDBOOK_ERR_CANNOT_CONNECT_TO_PLAYBACK_PINS,
  212. status);
  213. //
  214. // no pin succeeded, so set status to failure
  215. //
  216. status = STATUS_INVALID_DEVICE_REQUEST;
  217. LEAVE;
  218. } FINALLY {
  219. //
  220. // the pin handle is not required, as we've referenced
  221. // the pin in pinFileObject. close it here.
  222. //
  223. if (pinHandle != NULL) {
  224. ZwClose(pinHandle);
  225. pinHandle = NULL;
  226. }
  227. //
  228. // the device handle is only required to create
  229. // the actual pin. close it here.
  230. //
  231. if (deviceHandle != NULL) {
  232. ZwClose(deviceHandle);
  233. deviceHandle = NULL;
  234. }
  235. //
  236. // the guidFileObject is also only required to query
  237. // and create the pins. close it here.
  238. //
  239. // (pinFileObject is still important)
  240. //
  241. if (guidFileObject != NULL) {
  242. ObDereferenceObject(guidFileObject);
  243. guidFileObject = NULL;
  244. }
  245. if (!NT_SUCCESS(status)) {
  246. if (pinFileObject != NULL) {
  247. ObDereferenceObject(pinFileObject);
  248. pinFileObject = NULL;
  249. }
  250. }
  251. }
  252. //
  253. // the MixerPinId should not have changed in this function
  254. //
  255. ASSERT(mixerPinId == DeviceExtension->Stream.MixerPinId);
  256. if (NT_SUCCESS(status)) {
  257. DeviceExtension->Stream.PinFileObject = pinFileObject;
  258. DeviceExtension->Stream.PinDeviceObject =
  259. IoGetRelatedDeviceObject(pinFileObject);
  260. DeviceExtension->Stream.VolumeNodeId = volumeNodeId;
  261. } else {
  262. DeviceExtension->Stream.PinFileObject = NULL;
  263. DeviceExtension->Stream.PinDeviceObject = NULL;
  264. DeviceExtension->Stream.VolumeNodeId = -1;
  265. }
  266. return status;
  267. }
  268. NTSTATUS
  269. CloseSysAudio(
  270. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  271. )
  272. {
  273. PAGED_CODE();
  274. VerifyCalledByThread(DeviceExtension);
  275. ASSERT(DeviceExtension->Stream.PinFileObject);
  276. ASSERT(DeviceExtension->Stream.PinDeviceObject);
  277. ObDereferenceObject(DeviceExtension->Stream.PinFileObject);
  278. DeviceExtension->Stream.PinDeviceObject = NULL;
  279. DeviceExtension->Stream.PinFileObject = NULL;
  280. return STATUS_SUCCESS;
  281. }
  282. NTSTATUS
  283. GetPinProperty(
  284. IN PFILE_OBJECT FileObject,
  285. IN ULONG PropertyId,
  286. IN ULONG PinId,
  287. IN ULONG PropertySize,
  288. OUT PVOID Property
  289. )
  290. /*++
  291. Routine Description:
  292. another wrapper to hide getting pin properties
  293. Arguments:
  294. FileObject - file object to query
  295. PropertyId - what property to query
  296. PinId - which pin to query
  297. PropertySize - size of output buffer
  298. Property - output buffer for property
  299. Return Value:
  300. status
  301. --*/
  302. {
  303. ULONG bytesReturned;
  304. KSP_PIN prop = {0};
  305. NTSTATUS status;
  306. PAGED_CODE();
  307. prop.Property.Set = KSPROPSETID_Pin;
  308. prop.Property.Id = PropertyId;
  309. prop.Property.Flags = KSPROPERTY_TYPE_GET;
  310. prop.PinId = PinId;
  311. prop.Reserved = 0;
  312. status = KsSynchronousIoControlDevice( FileObject,
  313. KernelMode,
  314. IOCTL_KS_PROPERTY,
  315. &prop,
  316. sizeof(prop),
  317. Property,
  318. PropertySize,
  319. &bytesReturned
  320. );
  321. if ( !NT_SUCCESS(status) ) {
  322. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  323. "GetPinProperty !! fileobj %p property %p "
  324. "pin %d status %lx\n",
  325. FileObject, Property, PinId, status));
  326. return status;
  327. }
  328. ASSERT( bytesReturned == PropertySize );
  329. return status;
  330. }
  331. NTSTATUS
  332. GetVolumeNodeId(
  333. IN PFILE_OBJECT FileObject,
  334. OUT PULONG VolumeNodeId
  335. )
  336. /*++
  337. Routine Description:
  338. Gets the pin to set the volume for playback
  339. Arguments:
  340. FileObject - The fileobject which contains the pin
  341. VolumeNodeId - id of the volume node
  342. Return Value:
  343. status
  344. --*/
  345. {
  346. KSPROPERTY property = {0};
  347. ULONG bytesReturned;
  348. NTSTATUS status;
  349. PAGED_CODE();
  350. property.Set = KSPROPSETID_Sysaudio_Pin;
  351. property.Id = KSPROPERTY_SYSAUDIO_PIN_VOLUME_NODE;
  352. property.Flags = KSPROPERTY_TYPE_GET;
  353. status = KsSynchronousIoControlDevice( FileObject,
  354. KernelMode,
  355. IOCTL_KS_PROPERTY,
  356. &property,
  357. sizeof(property),
  358. VolumeNodeId,
  359. sizeof(ULONG),
  360. &bytesReturned
  361. );
  362. if ( !NT_SUCCESS(status) ) {
  363. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  364. "GetVolumeNodeId !! fileobj %p status %lx\n",
  365. FileObject, status));
  366. return status;
  367. }
  368. ASSERT(bytesReturned == sizeof(ULONG));
  369. return(status);
  370. }
  371. NTSTATUS
  372. UninitializeVirtualSource(
  373. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  374. )
  375. {
  376. ULONG state;
  377. PAGED_CODE();
  378. VerifyCalledByThread(DeviceExtension);
  379. ASSERT(DeviceExtension->Stream.MixerPinId != -1);
  380. ASSERT(DeviceExtension->Stream.MixerFileObject != NULL);
  381. state = GetCdromState(DeviceExtension);
  382. ASSERT(state == CD_STOPPED);
  383. DeviceExtension->Stream.MixerPinId = -1;
  384. ObDereferenceObject(DeviceExtension->Stream.MixerFileObject);
  385. DeviceExtension->Stream.MixerFileObject = NULL;
  386. return STATUS_SUCCESS;
  387. }
  388. NTSTATUS
  389. InitializeVirtualSource(
  390. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  391. )
  392. /*++
  393. Routine Description:
  394. Arguments:
  395. MixerPinId - initialized to the correct pin id of mixer
  396. Return Value:
  397. status
  398. --*/
  399. {
  400. SYSAUDIO_CREATE_VIRTUAL_SOURCE createVirtualSource = {0};
  401. PFILE_OBJECT fileObject;
  402. NTSTATUS status;
  403. HANDLE deviceHandle;
  404. ULONG bytesReturned;
  405. ULONG mixerPinId;
  406. ULONG state;
  407. PAGED_CODE();
  408. VerifyCalledByThread(DeviceExtension);
  409. ASSERT(DeviceExtension->Stream.MixerPinId == -1);
  410. ASSERT(DeviceExtension->Stream.MixerFileObject == NULL);
  411. state = GetCdromState(DeviceExtension);
  412. ASSERT(state == CD_STOPPED);
  413. fileObject = NULL;
  414. status = STATUS_SUCCESS;
  415. deviceHandle = NULL;
  416. mixerPinId = -1;
  417. //
  418. // use IoGetDeviceInterfaces()
  419. //
  420. status = OpenInterfaceByGuid(&KSCATEGORY_SYSAUDIO,
  421. &deviceHandle,
  422. &fileObject);
  423. if ( !NT_SUCCESS(status) ) {
  424. RedBookLogError(DeviceExtension,
  425. REDBOOK_ERR_CANNOT_OPEN_SYSAUDIO_MIXER,
  426. status);
  427. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  428. "CreateVirtSource !! Unable to open sysaudio\\mixer %lx\n",
  429. status));
  430. goto exit;
  431. }
  432. createVirtualSource.Property.Set = KSPROPSETID_Sysaudio;
  433. createVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_CREATE_VIRTUAL_SOURCE;
  434. createVirtualSource.Property.Flags = KSPROPERTY_TYPE_GET;
  435. createVirtualSource.PinCategory = KSNODETYPE_CD_PLAYER;
  436. createVirtualSource.PinName = KSNODETYPE_CD_PLAYER;
  437. status = KsSynchronousIoControlDevice(fileObject,
  438. KernelMode,
  439. IOCTL_KS_PROPERTY,
  440. &createVirtualSource,
  441. sizeof(createVirtualSource),
  442. &mixerPinId,
  443. sizeof(ULONG), // MixerPinId
  444. &bytesReturned
  445. );
  446. if ( !NT_SUCCESS(status) ) {
  447. RedBookLogError(DeviceExtension,
  448. REDBOOK_ERR_CANNOT_CREATE_VIRTUAL_SOURCE,
  449. status);
  450. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  451. "CreateVirtSource !! creating virtual source "
  452. "failed %lx\n", status));
  453. goto exit;
  454. }
  455. ASSERT( bytesReturned == sizeof(ULONG) );
  456. exit:
  457. if (NT_SUCCESS(status)) {
  458. DeviceExtension->Stream.MixerPinId = mixerPinId;
  459. DeviceExtension->Stream.MixerFileObject = fileObject;
  460. } else if (fileObject != NULL) {
  461. //
  462. // failed to open, so deref object if non-null
  463. //
  464. ObDereferenceObject(fileObject);
  465. fileObject = NULL;
  466. }
  467. if (deviceHandle != NULL) {
  468. ZwClose(deviceHandle);
  469. deviceHandle = NULL;
  470. }
  471. return status;
  472. }
  473. NTSTATUS
  474. AttachVirtualSource(
  475. IN PFILE_OBJECT PinFileObject,
  476. IN ULONG MixerPinId
  477. )
  478. /*++
  479. Routine Description:
  480. Arguments:
  481. FileObject - ??
  482. MixerPinId - ??
  483. Return Value:
  484. status
  485. --*/
  486. {
  487. SYSAUDIO_ATTACH_VIRTUAL_SOURCE attachVirtualSource = {0};
  488. NTSTATUS status;
  489. ULONG bytesReturned;
  490. PAGED_CODE();
  491. //
  492. // if the source hasn't been initialized, reject this
  493. // request as invalid
  494. //
  495. if(MixerPinId == MAXULONG) {
  496. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  497. "AttatchVirtSource !! Mixer Pin uninitialized\n"));
  498. ASSERT(!"Mixer Pin Uninitialized");
  499. return STATUS_INVALID_DEVICE_REQUEST;
  500. }
  501. attachVirtualSource.Property.Set = KSPROPSETID_Sysaudio_Pin;
  502. attachVirtualSource.Property.Id = KSPROPERTY_SYSAUDIO_ATTACH_VIRTUAL_SOURCE;
  503. attachVirtualSource.Property.Flags = KSPROPERTY_TYPE_SET;
  504. attachVirtualSource.MixerPinId = MixerPinId;
  505. status = KsSynchronousIoControlDevice(PinFileObject,
  506. KernelMode,
  507. IOCTL_KS_PROPERTY,
  508. &attachVirtualSource,
  509. sizeof(attachVirtualSource),
  510. NULL,
  511. 0,
  512. &bytesReturned
  513. );
  514. if (!NT_SUCCESS(status)) {
  515. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  516. "AttachVirtSource !! Couldn't attatch %lx\n", status));
  517. return status;
  518. }
  519. return status;
  520. }
  521. VOID
  522. SetNextDeviceState(
  523. PREDBOOK_DEVICE_EXTENSION DeviceExtension,
  524. KSSTATE State
  525. )
  526. /*++
  527. Routine Description:
  528. Arguments:
  529. Return Value:
  530. --*/
  531. {
  532. KSIDENTIFIER stateProperty = {0};
  533. NTSTATUS status;
  534. ULONG bytesReturned;
  535. KSSTATE acquireState;
  536. PFILE_OBJECT fileObject;
  537. PAGED_CODE();
  538. VerifyCalledByThread(DeviceExtension);
  539. fileObject = DeviceExtension->Stream.PinFileObject;
  540. acquireState = KSSTATE_ACQUIRE;
  541. stateProperty.Set = KSPROPSETID_Connection;
  542. stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
  543. stateProperty.Flags = KSPROPERTY_TYPE_SET;
  544. ASSERT(fileObject);
  545. status = KsSynchronousIoControlDevice(fileObject,
  546. KernelMode,
  547. IOCTL_KS_PROPERTY,
  548. &stateProperty,
  549. sizeof(stateProperty),
  550. &acquireState,
  551. sizeof(acquireState),
  552. &bytesReturned
  553. );
  554. if (!NT_SUCCESS(status)) {
  555. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  556. "SetDeviceState => (1) Audio device error %x. need to "
  557. "stop playback AND change audio devices\n", status));
  558. }
  559. //
  560. // now that it's acquired, set the new state
  561. //
  562. stateProperty.Set = KSPROPSETID_Connection;
  563. stateProperty.Id = KSPROPERTY_CONNECTION_STATE;
  564. stateProperty.Flags = KSPROPERTY_TYPE_SET;
  565. status = KsSynchronousIoControlDevice(fileObject,
  566. KernelMode,
  567. IOCTL_KS_PROPERTY,
  568. &stateProperty,
  569. sizeof(stateProperty),
  570. &State,
  571. sizeof(State),
  572. &bytesReturned
  573. );
  574. if (!NT_SUCCESS(status)) {
  575. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugError, "[redbook] "
  576. "SetDeviceState => (2) Audio device error %x. need to "
  577. "stop playback AND change audio devices\n", status));
  578. }
  579. return;
  580. }
  581. //////////////////////////////////////////////////////////////////////
  582. // //
  583. // this table is in 1/65536 decibles for a UCHAR setting: //
  584. // 20 * log10( Level / 256 ) * 65536 //
  585. // //
  586. //////////////////////////////////////////////////////////////////////
  587. AttenuationTable[] = {
  588. 0x7fffffff, 0xffcfd5d0, 0xffd5db16, 0xffd960ad, // 0- 3
  589. 0xffdbe05c, 0xffddd08a, 0xffdf65f3, 0xffe0bcb7, // 4- 7
  590. 0xffe1e5a2, 0xffe2eb89, 0xffe3d5d0, 0xffe4a9be, // 8- b
  591. 0xffe56b39, 0xffe61d34, 0xffe6c1fd, 0xffe75b67, // c- f
  592. 0xffe7eae8, 0xffe871b6, 0xffe8f0cf, 0xffe96908, // 10-13
  593. 0xffe9db16, 0xffea4793, 0xffeaaf04, 0xffeb11dc, // 14-17
  594. 0xffeb707f, 0xffebcb44, 0xffec227a, 0xffec7665, // 18-1b
  595. 0xffecc743, 0xffed154b, 0xffed60ad, 0xffeda996, // 1c-1f
  596. 0xffedf02e, 0xffee349b, 0xffee76fc, 0xffeeb771, // 20-23
  597. 0xffeef615, 0xffef3302, 0xffef6e4e, 0xffefa810, // 24-27
  598. 0xffefe05c, 0xfff01744, 0xfff04cda, 0xfff0812c, // 28-2b
  599. 0xfff0b44b, 0xfff0e643, 0xfff11722, 0xfff146f4, // 2c-2f
  600. 0xfff175c5, 0xfff1a39e, 0xfff1d08a, 0xfff1fc93, // 30-33
  601. 0xfff227c0, 0xfff2521b, 0xfff27bab, 0xfff2a478, // 34-37
  602. 0xfff2cc89, 0xfff2f3e5, 0xfff31a91, 0xfff34093, // 38-3b
  603. 0xfff365f3, 0xfff38ab4, 0xfff3aedc, 0xfff3d270, // 3c-3f
  604. 0xfff3f574, 0xfff417ee, 0xfff439e1, 0xfff45b51, // 40-43
  605. 0xfff47c42, 0xfff49cb8, 0xfff4bcb7, 0xfff4dc42, // 44-47
  606. 0xfff4fb5b, 0xfff51a07, 0xfff53848, 0xfff55621, // 48-4b
  607. 0xfff57394, 0xfff590a5, 0xfff5ad56, 0xfff5c9aa, // 4c-4f
  608. 0xfff5e5a2, 0xfff60142, 0xfff61c8a, 0xfff6377e, // 50-53
  609. 0xfff65220, 0xfff66c70, 0xfff68672, 0xfff6a027, // 54-57
  610. 0xfff6b991, 0xfff6d2b1, 0xfff6eb89, 0xfff7041b, // 58-5b
  611. 0xfff71c68, 0xfff73472, 0xfff74c3a, 0xfff763c2, // 5c-5f
  612. 0xfff77b0b, 0xfff79216, 0xfff7a8e4, 0xfff7bf77, // 60-63
  613. 0xfff7d5d0, 0xfff7ebf0, 0xfff801d9, 0xfff8178a, // 64-67
  614. 0xfff82d06, 0xfff8424d, 0xfff85761, 0xfff86c42, // 68-6b
  615. 0xfff880f1, 0xfff89570, 0xfff8a9be, 0xfff8bdde, // 6c-6f
  616. 0xfff8d1cf, 0xfff8e593, 0xfff8f92b, 0xfff90c96, // 70-73
  617. 0xfff91fd7, 0xfff932ed, 0xfff945d9, 0xfff9589d, // 74-77
  618. 0xfff96b39, 0xfff97dad, 0xfff98ffa, 0xfff9a221, // 78-7b
  619. 0xfff9b422, 0xfff9c5fe, 0xfff9d7b6, 0xfff9e94a, // 7c-7f
  620. 0xfff9faba, 0xfffa0c08, 0xfffa1d34, 0xfffa2e3e, // 80-83
  621. 0xfffa3f27, 0xfffa4fef, 0xfffa6097, 0xfffa711f, // 84-87
  622. 0xfffa8188, 0xfffa91d3, 0xfffaa1ff, 0xfffab20d, // 88-8b
  623. 0xfffac1fd, 0xfffad1d1, 0xfffae188, 0xfffaf122, // 8c-8f
  624. 0xfffb00a1, 0xfffb1004, 0xfffb1f4d, 0xfffb2e7a, // 90-93
  625. 0xfffb3d8e, 0xfffb4c87, 0xfffb5b67, 0xfffb6a2d, // 94-97
  626. 0xfffb78da, 0xfffb876f, 0xfffb95eb, 0xfffba450, // 98-9b
  627. 0xfffbb29c, 0xfffbc0d2, 0xfffbcef0, 0xfffbdcf7, // 9c-9f
  628. 0xfffbeae8, 0xfffbf8c3, 0xfffc0688, 0xfffc1437, // a0-a3
  629. 0xfffc21d0, 0xfffc2f55, 0xfffc3cc4, 0xfffc4a1f, // a4-a7
  630. 0xfffc5766, 0xfffc6498, 0xfffc71b6, 0xfffc7ec1, // a8-ab
  631. 0xfffc8bb8, 0xfffc989c, 0xfffca56d, 0xfffcb22b, // ac-af
  632. 0xfffcbed7, 0xfffccb70, 0xfffcd7f7, 0xfffce46c, // b0-b3
  633. 0xfffcf0cf, 0xfffcfd21, 0xfffd0961, 0xfffd1590, // b4-b7
  634. 0xfffd21ae, 0xfffd2dbc, 0xfffd39b8, 0xfffd45a4, // b8-bb
  635. 0xfffd5180, 0xfffd5d4c, 0xfffd6908, 0xfffd74b4, // bc-bf
  636. 0xfffd8051, 0xfffd8bde, 0xfffd975c, 0xfffda2ca, // c0-c3
  637. 0xfffdae2a, 0xfffdb97b, 0xfffdc4bd, 0xfffdcff1, // c4-c7
  638. 0xfffddb16, 0xfffde62d, 0xfffdf136, 0xfffdfc31, // c8-cb
  639. 0xfffe071f, 0xfffe11fe, 0xfffe1cd0, 0xfffe2795, // cc-cf
  640. 0xfffe324c, 0xfffe3cf6, 0xfffe4793, 0xfffe5224, // d0-d3
  641. 0xfffe5ca7, 0xfffe671e, 0xfffe7188, 0xfffe7be6, // d4-d7
  642. 0xfffe8637, 0xfffe907d, 0xfffe9ab6, 0xfffea4e3, // d8-db
  643. 0xfffeaf04, 0xfffeb91a, 0xfffec324, 0xfffecd22, // dc-df
  644. 0xfffed715, 0xfffee0fd, 0xfffeead9, 0xfffef4aa, // e0-e3
  645. 0xfffefe71, 0xffff082c, 0xffff11dc, 0xffff1b82, // e4-e7
  646. 0xffff251d, 0xffff2ead, 0xffff3833, 0xffff41ae, // e8-eb
  647. 0xffff4b1f, 0xffff5486, 0xffff5de3, 0xffff6736, // ec-ef
  648. 0xffff707f, 0xffff79be, 0xffff82f3, 0xffff8c1e, // f0-f3
  649. 0xffff9540, 0xffff9e58, 0xffffa767, 0xffffb06c, // f4-f7
  650. 0xffffb968, 0xffffc25b, 0xffffcb44, 0xffffd425, // f8-fb
  651. 0xffffdcfc, 0xffffe5ca, 0xffffee90, 0x00000000, // fc-ff
  652. };
  653. #define DA_CHANNEL_LEFT 0
  654. #define DA_CHANNEL_RIGHT 1
  655. #define DA_CHANNEL_MAX 2
  656. VOID
  657. RedBookKsSetVolume(
  658. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  659. )
  660. /*++
  661. Routine Description:
  662. Arguments:
  663. Return Value:
  664. --*/
  665. {
  666. KSNODEPROPERTY_AUDIO_CHANNEL volumeProperty = {0};
  667. VOLUME_CONTROL volume = {0};
  668. NTSTATUS status;
  669. ULONG32 channel;
  670. ULONG32 bytesReturned = 0;
  671. BOOLEAN mute;
  672. PAGED_CODE();
  673. VerifyCalledByThread(DeviceExtension);
  674. volume = DeviceExtension->CDRom.Volume;
  675. //
  676. // These settings are common for all the sets
  677. //
  678. volumeProperty.NodeProperty.Property.Set = KSPROPSETID_Audio;
  679. volumeProperty.NodeProperty.Property.Flags = KSPROPERTY_TYPE_SET |
  680. KSPROPERTY_TYPE_TOPOLOGY;
  681. volumeProperty.NodeProperty.NodeId = DeviceExtension->Stream.VolumeNodeId;
  682. //
  683. // Do both Left and right channels
  684. //
  685. for ( channel = 0; channel < DA_CHANNEL_MAX; channel++ ) {
  686. //
  687. // handle the correct channel
  688. //
  689. volumeProperty.Channel = channel;
  690. //
  691. // if not muting the channel, set the volume
  692. //
  693. if ( volume.PortVolume[channel] != 0 ) {
  694. ULONG32 level;
  695. ULONG32 index;
  696. volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_VOLUMELEVEL;
  697. level = AttenuationTable[ volume.PortVolume[channel] ];
  698. ASSERT(DeviceExtension->Stream.PinFileObject);
  699. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  700. "SetVolume => Setting channel %d to %lx\n",
  701. channel, level ));
  702. status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
  703. KernelMode,
  704. IOCTL_KS_PROPERTY,
  705. &volumeProperty,
  706. sizeof(volumeProperty),
  707. &level,
  708. sizeof(level),
  709. &bytesReturned
  710. );
  711. // ASSERT( NT_SUCCESS(status) );
  712. mute = FALSE;
  713. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  714. "SetVolume => Un-Muting channel %d\n", channel));
  715. } else {
  716. mute = TRUE;
  717. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  718. "SetVolume => Muting channel %d\n", channel));
  719. }
  720. volumeProperty.NodeProperty.Property.Id = KSPROPERTY_AUDIO_MUTE;
  721. status = KsSynchronousIoControlDevice(DeviceExtension->Stream.PinFileObject,
  722. KernelMode,
  723. IOCTL_KS_PROPERTY,
  724. &volumeProperty,
  725. sizeof(volumeProperty),
  726. &mute,
  727. sizeof(mute),
  728. &bytesReturned
  729. );
  730. // ASSERT( NT_SUCCESS(status) );
  731. }
  732. //
  733. // End of all channels
  734. //
  735. return;
  736. }
  737. NTSTATUS
  738. OpenInterfaceByGuid(
  739. IN CONST GUID * InterfaceClassGuid,
  740. OUT HANDLE * Handle,
  741. OUT PFILE_OBJECT * FileObject
  742. )
  743. {
  744. PWSTR tempString;
  745. PWSTR symbolicLinkList;
  746. HANDLE localHandle;
  747. PFILE_OBJECT localFileObject;
  748. NTSTATUS status;
  749. PAGED_CODE();
  750. localHandle = NULL;
  751. tempString = NULL;
  752. symbolicLinkList = NULL;
  753. *Handle = NULL;
  754. *FileObject = NULL;
  755. status = IoGetDeviceInterfaces(InterfaceClassGuid,
  756. // currently, the GUID is one of
  757. // KSCATEGORY_PREFERRED_WAVEOUT_DEVICE
  758. // or KSCATEGORY_SYSAUDIO
  759. NULL, // no preferred device object
  760. 0,
  761. &symbolicLinkList);
  762. if (!NT_SUCCESS(status)) {
  763. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  764. "OpenDevice !! IoGetDeviceInterfaces failed %x\n",
  765. status));
  766. return status;
  767. }
  768. #if DBG
  769. tempString = symbolicLinkList;
  770. while (*tempString != UNICODE_NULL) {
  771. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  772. "OpenDevice => Possible Device: %ws\n", tempString));
  773. //
  774. // get the next symbolic link
  775. //
  776. while(*tempString++ != UNICODE_NULL) {
  777. NOTHING;
  778. }
  779. }
  780. #endif
  781. //
  782. // this code is proudly propogated from wdmaud.sys
  783. //
  784. tempString = symbolicLinkList;
  785. while (*tempString != UNICODE_NULL) {
  786. IO_STATUS_BLOCK ioStatusBlock;
  787. UNICODE_STRING deviceString;
  788. OBJECT_ATTRIBUTES objectAttributes;
  789. RtlInitUnicodeString( &deviceString, tempString);
  790. InitializeObjectAttributes(&objectAttributes,
  791. &deviceString,
  792. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  793. NULL,
  794. NULL
  795. );
  796. //
  797. // could use IoCreateFile(), based on
  798. // ntos\dd\wdm\audio\legacy\wdmaud.sys\sysaudio.c:OpenDevice()
  799. //
  800. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  801. "OpenDevice => Opening %ws\n", tempString));
  802. status = ZwCreateFile(&localHandle,
  803. GENERIC_READ | GENERIC_WRITE,
  804. &objectAttributes,
  805. &ioStatusBlock,
  806. NULL, // ignored on non-create
  807. FILE_ATTRIBUTE_NORMAL,
  808. 0, // no share access
  809. FILE_OPEN, // open the existing file
  810. 0, NULL, 0 // options
  811. );
  812. if (NT_SUCCESS(status)) {
  813. ASSERT(localHandle != NULL);
  814. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  815. "OpenDevice => Opened %ws\n", tempString));
  816. break; // out of the while loop
  817. }
  818. ASSERT(localHandle == NULL);
  819. //
  820. // get the next symbolic link
  821. //
  822. while(*tempString++ != UNICODE_NULL) {
  823. NOTHING;
  824. }
  825. }
  826. if (symbolicLinkList != NULL) {
  827. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  828. "OpenDevice => Freeing list from IoGetDevInt...\n"));
  829. ExFreePool(symbolicLinkList);
  830. symbolicLinkList = NULL;
  831. tempString = NULL;
  832. }
  833. //
  834. // if succeeded to open the file, try to get
  835. // the FileObject that is related to this handle.
  836. //
  837. if (localHandle != NULL) {
  838. status = ObReferenceObjectByHandle(localHandle,
  839. GENERIC_READ | GENERIC_WRITE,
  840. NULL,
  841. KernelMode,
  842. &localFileObject, // double pointer
  843. NULL);
  844. if (NT_SUCCESS(status)) {
  845. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugSysaudio, "[redbook] "
  846. "OpenDevice => Succeeded\n"));
  847. *Handle = localHandle;
  848. *FileObject = localFileObject;
  849. return status; // Exit point for success
  850. }
  851. ZwClose(localHandle);
  852. localHandle = NULL;
  853. }
  854. KdPrintEx((DPFLTR_REDBOOK_ID, RedbookDebugWarning, "[redbook] "
  855. "OpenDevice => unable to open any audio devices\n"));
  856. status = STATUS_NO_SUCH_DEVICE;
  857. return status;
  858. }
  859. NTSTATUS
  860. SysAudioPnpNotification(
  861. PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification,
  862. PREDBOOK_DEVICE_EXTENSION DeviceExtension
  863. )
  864. {
  865. NTSTATUS status = STATUS_SUCCESS;
  866. PAGED_CODE();
  867. InterlockedExchange(&DeviceExtension->Stream.UpdateMixerPin, 1);
  868. return STATUS_SUCCESS;
  869. }