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.

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