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.

2562 lines
84 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: kmxluser.c
  4. //
  5. // Description:
  6. // Contains the handlers for the ring 3 mixer line api functions.
  7. //
  8. //
  9. //@@BEGIN_MSINTERNAL
  10. // Development Team:
  11. // D. Baumberger
  12. //
  13. // History: Date Author Comment
  14. //
  15. //@@END_MSINTERNAL
  16. //
  17. //---------------------------------------------------------------------------
  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) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  25. //
  26. //---------------------------------------------------------------------------
  27. ///////////////////////////////////////////////////////////////////////
  28. ///////////////////////////////////////////////////////////////////////
  29. // //
  30. // I N C L U D E S //
  31. // //
  32. ///////////////////////////////////////////////////////////////////////
  33. ///////////////////////////////////////////////////////////////////////
  34. #include "WDMSYS.H"
  35. FAST_MUTEX ReferenceCountMutex;
  36. ULONG ReferenceCount = 0;
  37. #define NOT16( di ) if( di->dwFormat == ANSI_TAG ) DPF(DL_WARNING|FA_USER,("Invalid dwFormat.") );
  38. #pragma PAGEABLE_CODE
  39. ///////////////////////////////////////////////////////////////////////
  40. //
  41. // kmxlInitializeMixer
  42. //
  43. // Queries SysAudio to find the number of devices and builds the mixer
  44. // line structures for each of those devices.
  45. //
  46. //
  47. NTSTATUS
  48. kmxlInitializeMixer(
  49. PWDMACONTEXT pWdmaContext,
  50. PCWSTR DeviceInterface,
  51. ULONG cDevices
  52. )
  53. {
  54. NTSTATUS Status;
  55. ULONG Device;
  56. BOOLEAN Error = FALSE;
  57. // PFILE_OBJECT pfo;
  58. PMIXERDEVICE pmxd;
  59. PAGED_CODE();
  60. ExInitializeFastMutex( &ReferenceCountMutex );
  61. DPF(DL_TRACE|FA_USER, ("Found %d mixer devices for DI: %ls", cDevices, DeviceInterface));
  62. //
  63. // Current limitation is MAXNUMDEVS. If more devices are supported
  64. // than that, limit it to the first MAXNUMDEVS.
  65. //
  66. if( cDevices > MAXNUMDEVS ) {
  67. cDevices = MAXNUMDEVS;
  68. }
  69. for( Device = 0; Device < cDevices; Device++ ) {
  70. DWORD TranslatedDeviceNumber;
  71. TranslatedDeviceNumber =
  72. wdmaudTranslateDeviceNumber(pWdmaContext,
  73. MixerDevice,
  74. DeviceInterface,
  75. Device);
  76. if(TranslatedDeviceNumber == MAXULONG) {
  77. continue;
  78. }
  79. pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];
  80. //
  81. // Open SysAudio
  82. //
  83. DPFASSERT(pmxd->pfo == NULL);
  84. pmxd->pfo = kmxlOpenSysAudio();
  85. if( pmxd->pfo == NULL ) {
  86. DPF(DL_WARNING|FA_USER,( "failed to open SYSAUDIO!" ) );
  87. RETURN( STATUS_UNSUCCESSFUL );
  88. }
  89. //
  90. // Set the current device instance in SysAudio.
  91. //
  92. Status = SetSysAudioProperty(
  93. pmxd->pfo,
  94. KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
  95. sizeof( pmxd->Device ),
  96. &pmxd->Device
  97. );
  98. if( !NT_SUCCESS( Status ) ) {
  99. DPF(DL_WARNING|FA_USER, ( "failed to set SYSAUDIO device instance" ) );
  100. // DPF(DL_ERROR|FA_ALL,("If fo is NULL, we must exit here!") );
  101. kmxlCloseSysAudio( pmxd->pfo );
  102. pmxd->pfo=NULL;
  103. Error = TRUE;
  104. } else {
  105. //
  106. // Initialize the topology for this device
  107. //
  108. Status = kmxlInit( pmxd->pfo, pmxd );
  109. if( !NT_SUCCESS( Status ) ) {
  110. DPF(DL_WARNING|FA_USER, ( "failed to initialize topology for device %d (%x)!",
  111. TranslatedDeviceNumber, Status ) );
  112. Error = TRUE;
  113. } else {
  114. //
  115. // Here we want to optimize out the restoring of values on the mixer
  116. // device. If we find that there is another mixer device in some
  117. // other open context, then we will NOT call kmxlRetrieveAll to
  118. // set the values on the device.
  119. //
  120. DPF(DL_TRACE|FA_USER,( "Looking for Mixer: %S",pmxd->DeviceInterface ) );
  121. if( !NT_SUCCESS(EnumFsContext( HasMixerBeenInitialized, pmxd, pWdmaContext )) )
  122. {
  123. //
  124. // Here we find that this device was not found, thus this is
  125. // the first time through. Set the defaults here.
  126. //
  127. DPF(DL_TRACE|FA_USER,( "Did not find Mixer - initializing: %S",pmxd->DeviceInterface ) );
  128. kmxlRetrieveAll( pmxd->pfo, pmxd );
  129. } else {
  130. DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxd->DeviceInterface ) );
  131. }
  132. }
  133. }
  134. }
  135. if( Error ) {
  136. RETURN( STATUS_UNSUCCESSFUL );
  137. } else {
  138. return( STATUS_SUCCESS );
  139. }
  140. }
  141. //
  142. // This routine looks in the WDMACONTEXT structure to see if this mixer device
  143. // has already been initialized. It does this by walking the MixerDevice list and
  144. // checking to see if there are any devices that match this mixer devices's
  145. // DeviceInterface string. If it finds that there is a match, it routines
  146. // STATUS_SUCCESS, else it returns STATUS_MORE_ENTRIES so that the enum function
  147. // will call it again until the list is empty.
  148. //
  149. NTSTATUS
  150. HasMixerBeenInitialized(
  151. PWDMACONTEXT pContext,
  152. PVOID pvoidRefData,
  153. PVOID pvoidRefData2
  154. )
  155. {
  156. NTSTATUS Status;
  157. PMIXERDEVICE pmxdMatch;
  158. PMIXERDEVICE pmxd;
  159. DWORD TranslatedDeviceNumber;
  160. ULONG Device;
  161. PWDMACONTEXT pCurContext;
  162. //
  163. // Default is that we did not find this entry in the list.
  164. //
  165. Status = STATUS_MORE_ENTRIES;
  166. //
  167. // The reference data is a PMIXERDEVICE.
  168. //
  169. pmxdMatch = (PMIXERDEVICE)pvoidRefData;
  170. pCurContext = (PWDMACONTEXT)pvoidRefData2;
  171. if( pCurContext != pContext )
  172. {
  173. for( Device = 0; Device < MAXNUMDEVS; Device++ )
  174. {
  175. //
  176. // If this mixer device translates, that means that it can
  177. // be found in this context.
  178. //
  179. TranslatedDeviceNumber =
  180. wdmaudTranslateDeviceNumber(pContext,
  181. MixerDevice,
  182. pmxdMatch->DeviceInterface,
  183. Device);
  184. //
  185. // If it doesn't, we'll keep looking.
  186. //
  187. if( MAXULONG != TranslatedDeviceNumber )
  188. {
  189. DPF(DL_TRACE|FA_USER,( "Found Mixer: %S",pmxdMatch->DeviceInterface ) );
  190. Status = STATUS_SUCCESS;
  191. break;
  192. }
  193. }
  194. } else {
  195. DPF(DL_TRACE|FA_USER,( "Same context: %x",pCurContext ) );
  196. }
  197. return Status;
  198. }
  199. ///////////////////////////////////////////////////////////////////////
  200. //
  201. // kmxlOpenHandler
  202. //
  203. // Handles the MXDM_OPEN message. Copies the callback info from the
  204. // caller and opens an instance of SysAudio set to the device number
  205. // the caller has selected.
  206. //
  207. //
  208. NTSTATUS
  209. kmxlOpenHandler(
  210. IN PWDMACONTEXT pWdmaContext,
  211. IN LPDEVICEINFO DeviceInfo, // Info structure
  212. IN LPVOID DataBuffer // Unused
  213. )
  214. {
  215. NTSTATUS Status = STATUS_SUCCESS;
  216. PMIXERDEVICE pmxd;
  217. PAGED_CODE();
  218. ASSERT( DeviceInfo );
  219. //
  220. // BUGBUG: we should not need this any more!
  221. //
  222. ASSERT( DeviceInfo->dwInstance == 0 );
  223. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  224. if( pmxd == NULL ) {
  225. goto exit;
  226. }
  227. DPF(DL_TRACE|FA_INSTANCE,( "param=( %d ) = pmxd = %X",
  228. DeviceInfo->DeviceNumber,pmxd));
  229. ExAcquireFastMutex( &ReferenceCountMutex );
  230. ++ReferenceCount;
  231. ExReleaseFastMutex( &ReferenceCountMutex );
  232. DeviceInfo->mmr = MMSYSERR_NOERROR;
  233. exit:
  234. return( STATUS_SUCCESS );
  235. }
  236. ///////////////////////////////////////////////////////////////////////
  237. //
  238. // kmxlCloseHandler
  239. //
  240. // Handles the MXDM_CLOSE message. Clears the callback info and
  241. // closes the handle to SysAudio.
  242. //
  243. //
  244. NTSTATUS
  245. kmxlCloseHandler(
  246. IN LPDEVICEINFO DeviceInfo, // Info structure
  247. IN LPVOID DataBuffer // Unused
  248. )
  249. {
  250. PAGED_CODE();
  251. ASSERT( DeviceInfo );
  252. ASSERT( DeviceInfo->dwInstance );
  253. DPF(DL_TRACE|FA_INSTANCE,( "kmxlCloseHandler"));
  254. ExAcquireFastMutex( &ReferenceCountMutex );
  255. --ReferenceCount;
  256. ExReleaseFastMutex( &ReferenceCountMutex );
  257. DeviceInfo->mmr = MMSYSERR_NOERROR;
  258. return( STATUS_SUCCESS );
  259. }
  260. ///////////////////////////////////////////////////////////////////////
  261. //
  262. // kmxlGetLineInfoHandler
  263. //
  264. // Handles the MXDM_GETLINEINFO message. Determines which query
  265. // is requested by looking at dwFlags and performs that query.
  266. //
  267. //
  268. NTSTATUS
  269. kmxlGetLineInfoHandler(
  270. IN PWDMACONTEXT pWdmaContext,
  271. IN LPDEVICEINFO DeviceInfo, // Device Info structure
  272. IN LPVOID DataBuffer // MIXERLINE(16) to fill
  273. )
  274. {
  275. MIXERLINE ml;
  276. PAGED_CODE();
  277. ASSERT( DeviceInfo );
  278. if( DataBuffer == NULL ) {
  279. DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL" ));
  280. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  281. return( STATUS_SUCCESS );
  282. }
  283. ml.cbStruct = sizeof( MIXERLINE );
  284. switch( DeviceInfo->dwFlags & MIXER_GETLINEINFOF_QUERYMASK ) {
  285. ///////////////////////////////////////////////////////////////
  286. case MIXER_GETLINEINFOF_COMPONENTTYPE:
  287. ///////////////////////////////////////////////////////////////
  288. // Valid fields: //
  289. // cbStruct //
  290. // dwComponentType //
  291. ///////////////////////////////////////////////////////////////
  292. NOT16( DeviceInfo );
  293. ml.cbStruct = sizeof( MIXERLINE );
  294. ml.dwComponentType = ( (LPMIXERLINE) DataBuffer) ->dwComponentType;
  295. DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByComponent( %s )",
  296. ComponentTypeToString( ml.dwComponentType ) ));
  297. return( kmxlGetLineInfoByComponent( pWdmaContext,
  298. DeviceInfo,
  299. DataBuffer,
  300. ml.dwComponentType
  301. )
  302. );
  303. ///////////////////////////////////////////////////////////////
  304. case MIXER_GETLINEINFOF_DESTINATION:
  305. ///////////////////////////////////////////////////////////////
  306. // Valid fields: //
  307. // cbStruct //
  308. // dwDestination //
  309. ///////////////////////////////////////////////////////////////
  310. NOT16( DeviceInfo );
  311. ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;
  312. DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
  313. -1, ml.dwDestination ));
  314. return( kmxlGetLineInfoByID( pWdmaContext,
  315. DeviceInfo,
  316. DataBuffer,
  317. (WORD) -1,
  318. (WORD) ml.dwDestination ) );
  319. ///////////////////////////////////////////////////////////////
  320. case MIXER_GETLINEINFOF_LINEID:
  321. ///////////////////////////////////////////////////////////////
  322. // Valid fields: //
  323. // cbStruct //
  324. // dwLineID //
  325. ///////////////////////////////////////////////////////////////
  326. NOT16( DeviceInfo );
  327. ml.dwLineID = ( (LPMIXERLINE) DataBuffer)->dwLineID;
  328. DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
  329. HIWORD( ml.dwLineID ), LOWORD( ml.dwLineID ) ));
  330. return( kmxlGetLineInfoByID( pWdmaContext,
  331. DeviceInfo,
  332. DataBuffer,
  333. HIWORD( ml.dwLineID ),
  334. LOWORD( ml.dwLineID ) ) );
  335. ///////////////////////////////////////////////////////////////
  336. case MIXER_GETLINEINFOF_SOURCE:
  337. ///////////////////////////////////////////////////////////////
  338. // Valid fields: //
  339. // cbStruct //
  340. // dwSource //
  341. // dwDestination //
  342. ///////////////////////////////////////////////////////////////
  343. NOT16( DeviceInfo );
  344. ml.dwSource = ( (LPMIXERLINE) DataBuffer)->dwSource;
  345. ml.dwDestination = ( (LPMIXERLINE) DataBuffer)->dwDestination;
  346. DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoById( S=%08X, D=%08X )",
  347. ml.dwSource, ml.dwDestination ));
  348. return( kmxlGetLineInfoByID( pWdmaContext,
  349. DeviceInfo,
  350. DataBuffer,
  351. (WORD) ml.dwSource,
  352. (WORD) ml.dwDestination ) );
  353. ///////////////////////////////////////////////////////////////
  354. case MIXER_GETLINEINFOF_TARGETTYPE:
  355. ///////////////////////////////////////////////////////////////
  356. // Valid fields: //
  357. // cbStruct //
  358. // Target.dwType //
  359. // Target.wMid //
  360. // Target.wPid //
  361. // Target.vDriverVersion //
  362. // Target.szPname //
  363. ///////////////////////////////////////////////////////////////
  364. NOT16( DeviceInfo );
  365. ml.Target.dwType = ((LPMIXERLINE) DataBuffer)->Target.dwType;
  366. DPF(DL_TRACE|FA_USER,( "kmxlGetLineInfoByType( %x -- %s )",
  367. ml.Target.dwType,
  368. TargetTypeToString( ml.Target.dwType ) ));
  369. return( kmxlGetLineInfoByType( pWdmaContext,
  370. DeviceInfo,
  371. DataBuffer,
  372. ml.Target.dwType ) );
  373. ///////////////////////////////////////////////////////////////
  374. default:
  375. ///////////////////////////////////////////////////////////////
  376. DPF(DL_WARNING|FA_USER,( "invalid flags ( %x )", DeviceInfo->dwFlags ));
  377. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  378. return( STATUS_SUCCESS );
  379. }
  380. DPF(DL_WARNING|FA_USER,("Unmatched di->dwFlag") );
  381. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  382. return( STATUS_SUCCESS );
  383. }
  384. ///////////////////////////////////////////////////////////////////////
  385. //
  386. // kmxlGetLineControlsHandler
  387. //
  388. // Handles the MXDM_GETLINECONTROLS message. Determines the query
  389. // requested and finds the controls.
  390. //
  391. //
  392. NTSTATUS
  393. kmxlGetLineControlsHandler(
  394. IN PWDMACONTEXT pWdmaContext,
  395. IN LPDEVICEINFO DeviceInfo, // Device Info structure
  396. IN LPVOID DataBuffer, // MIXERLINECONTROLS(16) to fill
  397. IN LPVOID pamxctrl
  398. )
  399. {
  400. PMIXERDEVICE pmxd;
  401. PMXLLINE pLine;
  402. PMXLCONTROL pControl;
  403. ULONG Count;
  404. DWORD dwLineID,
  405. dwControlID,
  406. dwControlType,
  407. cControls,
  408. cbmxctrl;
  409. PAGED_CODE();
  410. ASSERT( DeviceInfo );
  411. //
  412. // Check some pre-conditions so we don't blow up later.
  413. //
  414. if( DataBuffer == NULL ) {
  415. DPF(DL_WARNING|FA_USER,( "DataBuffer is NULL!" ));
  416. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  417. return( STATUS_SUCCESS );
  418. }
  419. if( pamxctrl == NULL ) {
  420. DPF(DL_WARNING|FA_USER,( "pamxctrl is NULL!" ));
  421. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  422. return( STATUS_SUCCESS );
  423. }
  424. if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
  425. DPF(DL_WARNING|FA_USER,( "device Id is invalid!" ));
  426. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  427. return( STATUS_SUCCESS );
  428. }
  429. //
  430. // Get a instance reference
  431. //
  432. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  433. if( pmxd == NULL ) {
  434. return( STATUS_SUCCESS );
  435. }
  436. //
  437. // Copy out some parameters necessary to find the controls
  438. //
  439. NOT16( DeviceInfo );
  440. dwLineID = ((LPMIXERLINECONTROLS) DataBuffer)->dwLineID;
  441. dwControlID = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlID;
  442. dwControlType = ((LPMIXERLINECONTROLS) DataBuffer)->dwControlType;
  443. cControls = ((LPMIXERLINECONTROLS) DataBuffer)->cControls;
  444. cbmxctrl = ((LPMIXERLINECONTROLS) DataBuffer)->cbmxctrl;
  445. switch( DeviceInfo->dwFlags & MIXER_GETLINECONTROLSF_QUERYMASK ) {
  446. ///////////////////////////////////////////////////////////////
  447. case MIXER_GETLINECONTROLSF_ALL:
  448. ///////////////////////////////////////////////////////////////
  449. //
  450. // Find the line that matches the dwLineID field
  451. //
  452. DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ALL, %08X )",dwLineID ));
  453. pLine = kmxlFindLine( pmxd, dwLineID );
  454. if( pLine == NULL ) {
  455. DPF(DL_WARNING|FA_USER,( "ALL - invalid line Id %x!",dwLineID ));
  456. DeviceInfo->mmr = MIXERR_INVALLINE;
  457. return( STATUS_SUCCESS );
  458. }
  459. //
  460. // Loop through the controls, copying them into the user buffer.
  461. //
  462. Count = 0;
  463. pControl = kmxlFirstInList( pLine->Controls );
  464. while( pControl && Count < cControls ) {
  465. NOT16( DeviceInfo );
  466. RtlCopyMemory(
  467. &((LPMIXERCONTROL) pamxctrl)[ Count ],
  468. &pControl->Control,
  469. min(cbmxctrl,sizeof(MIXERCONTROL)) );
  470. pControl = kmxlNextControl( pControl );
  471. ++Count;
  472. }
  473. DeviceInfo->mmr = MMSYSERR_NOERROR;
  474. return( STATUS_SUCCESS );
  475. ///////////////////////////////////////////////////////////////
  476. case MIXER_GETLINECONTROLSF_ONEBYID:
  477. ///////////////////////////////////////////////////////////////
  478. pControl = kmxlFindControl( pmxd, dwControlID );
  479. pLine = kmxlFindLineForControl(
  480. pControl,
  481. pmxd->listLines
  482. );
  483. if( pLine == NULL ) {
  484. DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid control Id %x!", dwControlID ));
  485. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  486. return( STATUS_SUCCESS );
  487. }
  488. DPF(DL_TRACE|FA_USER,( "kmxlGetLineControls( ONEBYID, Ctrl=%08X, Line=%08X )",
  489. dwControlID, pLine->Line.dwLineID ));
  490. if( pControl ) {
  491. NOT16( DeviceInfo );
  492. RtlCopyMemory((LPMIXERLINECONTROLS) pamxctrl,
  493. &pControl->Control,
  494. min(cbmxctrl,sizeof(MIXERCONTROL)) );
  495. ((PMIXERLINECONTROLS) DataBuffer)->dwLineID =
  496. (DWORD) pLine->Line.dwLineID;
  497. DeviceInfo->mmr = MMSYSERR_NOERROR;
  498. return( STATUS_SUCCESS );
  499. } else {
  500. DPF(DL_WARNING|FA_USER,( "ONEBYID - invalid dwControlID %08X!", dwControlID ));
  501. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  502. return( STATUS_SUCCESS );
  503. }
  504. ///////////////////////////////////////////////////////////////
  505. case MIXER_GETLINECONTROLSF_ONEBYTYPE:
  506. ///////////////////////////////////////////////////////////////
  507. //
  508. // Find the line that matches the dwLineID field
  509. //
  510. pLine = kmxlFindLine( pmxd, dwLineID );
  511. if( pLine == NULL ) {
  512. DPF(DL_WARNING|FA_USER,( "ONEBYTYPE - invalid dwLineID %08X!", dwControlType ));
  513. DeviceInfo->mmr = MIXERR_INVALLINE;
  514. return( STATUS_SUCCESS );
  515. }
  516. DPF(DL_TRACE|FA_USER, ("kmxlGetLineControls( ONEBYTYPE, Type=%s, Line=%08X )",
  517. ControlTypeToString( dwControlType ),
  518. pLine->Line.dwLineID ));
  519. //
  520. // Now look through the controls and find the control that
  521. // matches the type the caller has passed.
  522. //
  523. pControl = kmxlFirstInList( pLine->Controls );
  524. while( pControl ) {
  525. if( pControl->Control.dwControlType == dwControlType )
  526. {
  527. NOT16 ( DeviceInfo );
  528. RtlCopyMemory((LPMIXERCONTROL) pamxctrl,
  529. &pControl->Control,
  530. min(cbmxctrl,sizeof(MIXERCONTROL)) );
  531. DeviceInfo->mmr = MMSYSERR_NOERROR;
  532. return( STATUS_SUCCESS );
  533. }
  534. pControl = kmxlNextControl( pControl );
  535. }
  536. DPF(DL_WARNING|FA_USER,( "(ONEBYTYPE,Type=%x,Line=%08X ) no such control type on line",
  537. dwControlType, pLine->Line.dwLineID ));
  538. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  539. return( STATUS_SUCCESS );
  540. ///////////////////////////////////////////////////////////////
  541. default:
  542. ///////////////////////////////////////////////////////////////
  543. DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
  544. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  545. return( STATUS_SUCCESS );
  546. }
  547. }
  548. ///////////////////////////////////////////////////////////////////////
  549. //
  550. // kmxlGetControlDetailsHandler
  551. //
  552. // Determines which control is being queried and calls the appropriate
  553. // handler to perform the get property.
  554. //
  555. //
  556. NTSTATUS
  557. kmxlGetControlDetailsHandler(
  558. IN PWDMACONTEXT pWdmaContext,
  559. IN LPDEVICEINFO DeviceInfo, // Device Info Structure
  560. IN LPVOID DataBuffer, // MIXERCONTROLDETAILS structure
  561. IN LPVOID paDetails // Flat pointer to details struct(s)
  562. )
  563. {
  564. LPMIXERCONTROLDETAILS pmcd = (LPMIXERCONTROLDETAILS) DataBuffer;
  565. PMXLCONTROL pControl;
  566. PMIXERDEVICE pmxd;
  567. NTSTATUS Status;
  568. PMXLLINE pLine;
  569. PAGED_CODE();
  570. ASSERT( DeviceInfo );
  571. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  572. if( pmxd == NULL ) {
  573. return( STATUS_SUCCESS );
  574. }
  575. pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
  576. if( pControl == NULL ) {
  577. DPF(DL_WARNING|FA_USER,( "control %x not found",pmcd->dwControlID ));
  578. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  579. return( STATUS_SUCCESS );
  580. }
  581. pLine = kmxlFindLineForControl(
  582. pControl,
  583. pmxd->listLines
  584. );
  585. if( pLine == NULL ) {
  586. DPF(DL_WARNING|FA_USER,( "invalid control id %x!",pmcd->dwControlID ));
  587. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  588. return( STATUS_SUCCESS );
  589. }
  590. if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
  591. ( pmcd->cChannels != 1 ) &&
  592. ( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
  593. DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %x!",
  594. pmcd->cChannels, pmcd->dwControlID ));
  595. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  596. return( STATUS_SUCCESS );
  597. }
  598. if( pmcd->cChannels > pLine->Line.cChannels ) {
  599. DPF(DL_WARNING|FA_USER,( "incorrect number of channels( %d )!",pmcd->cChannels ));
  600. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  601. return( STATUS_SUCCESS );
  602. }
  603. if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
  604. DPF(DL_WARNING|FA_USER,( "incorrect number of items( %d )!",pmcd->cMultipleItems ));
  605. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  606. return( STATUS_SUCCESS );
  607. }
  608. switch( DeviceInfo->dwFlags & MIXER_GETCONTROLDETAILSF_QUERYMASK ) {
  609. ///////////////////////////////////////////////////////////////
  610. case MIXER_GETCONTROLDETAILSF_LISTTEXT:
  611. ///////////////////////////////////////////////////////////////
  612. {
  613. ULONG cMultipleItems;
  614. LPMIXERCONTROLDETAILS_LISTTEXT lplt;
  615. DPF(DL_TRACE|FA_USER,( "kmxlGetControlDetails( Ctrl=%d )",
  616. pControl->Control.dwControlID ));
  617. NOT16( DeviceInfo );
  618. lplt = (LPMIXERCONTROLDETAILS_LISTTEXT) paDetails;
  619. for( cMultipleItems = 0;
  620. cMultipleItems < pmcd->cMultipleItems;
  621. cMultipleItems++ )
  622. {
  623. RtlCopyMemory(
  624. &lplt[ cMultipleItems ],
  625. &pControl->Parameters.lpmcd_lt[ cMultipleItems ],
  626. sizeof( MIXERCONTROLDETAILS_LISTTEXT )
  627. );
  628. }
  629. }
  630. DeviceInfo->mmr = MMSYSERR_NOERROR;
  631. break;
  632. ///////////////////////////////////////////////////////////////
  633. case MIXER_GETCONTROLDETAILSF_VALUE:
  634. ///////////////////////////////////////////////////////////////
  635. switch( pControl->Control.dwControlType ) {
  636. ///////////////////////////////////////////////////////
  637. case MIXERCONTROL_CONTROLTYPE_MIXER:
  638. ///////////////////////////////////////////////////////
  639. DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
  640. DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
  641. break;
  642. ///////////////////////////////////////////////////////
  643. case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
  644. ///////////////////////////////////////////////////////
  645. Status = kmxlHandleGetUnsigned(
  646. DeviceInfo,
  647. pmxd,
  648. pControl,
  649. pControl->PropertyId,
  650. (LPMIXERCONTROLDETAILS) DataBuffer,
  651. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  652. MIXER_FLAG_SCALE
  653. );
  654. break;
  655. ///////////////////////////////////////////////////////
  656. case MIXERCONTROL_CONTROLTYPE_MUTE:
  657. ///////////////////////////////////////////////////////
  658. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
  659. Status = kmxlHandleGetUnsigned(
  660. DeviceInfo,
  661. pmxd,
  662. pControl,
  663. KSPROPERTY_AUDIO_MUTE,
  664. (LPMIXERCONTROLDETAILS) DataBuffer,
  665. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  666. 0
  667. );
  668. } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
  669. Status = kmxlHandleGetMuteFromSuperMix(
  670. DeviceInfo,
  671. pmxd,
  672. pControl,
  673. (LPMIXERCONTROLDETAILS) DataBuffer,
  674. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  675. 0
  676. );
  677. } else {
  678. DPF(DL_WARNING|FA_USER,("Unmatched GUID") );
  679. }
  680. break;
  681. ///////////////////////////////////////////////////////
  682. case MIXERCONTROL_CONTROLTYPE_VOLUME:
  683. //////////////////////////////////////////////////////
  684. #ifdef SUPERMIX_AS_VOL
  685. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
  686. #endif
  687. Status = kmxlHandleGetUnsigned(
  688. DeviceInfo,
  689. pmxd,
  690. pControl,
  691. pControl->PropertyId,
  692. (LPMIXERCONTROLDETAILS) DataBuffer,
  693. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  694. MIXER_FLAG_SCALE
  695. );
  696. #ifdef SUPERMIX_AS_VOL
  697. } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
  698. Status = kmxlHandleGetVolumeFromSuperMix(
  699. DeviceInfo,
  700. pmxd,
  701. pControl,
  702. (LPMIXERCONTROLDETAILS) DataBuffer,
  703. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  704. MIXER_FLAG_SCALE
  705. );
  706. } else {
  707. DPF(DL_WARNING|FA_USER,("Invalid GUID for Control.") );
  708. }
  709. #endif // SUPERMIX_AS_VOL
  710. break;
  711. ///////////////////////////////////////////////////////
  712. case MIXERCONTROL_CONTROLTYPE_TREBLE:
  713. case MIXERCONTROL_CONTROLTYPE_BASS:
  714. ///////////////////////////////////////////////////////
  715. // These all take 32-bit parameters per channel but //
  716. // need to be scale from dB to linear //
  717. ///////////////////////////////////////////////////////
  718. Status = kmxlHandleGetUnsigned(
  719. DeviceInfo,
  720. pmxd,
  721. pControl,
  722. pControl->PropertyId,
  723. (LPMIXERCONTROLDETAILS) DataBuffer,
  724. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  725. MIXER_FLAG_SCALE
  726. );
  727. break;
  728. ///////////////////////////////////////////////////////
  729. case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
  730. case MIXERCONTROL_CONTROLTYPE_ONOFF:
  731. case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
  732. case MIXERCONTROL_CONTROLTYPE_MUX:
  733. case MIXERCONTROL_CONTROLTYPE_FADER:
  734. case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
  735. ///////////////////////////////////////////////////////
  736. // These all take up to 32-bit parameters per channel//
  737. ///////////////////////////////////////////////////////
  738. Status = kmxlHandleGetUnsigned(
  739. DeviceInfo,
  740. pmxd,
  741. pControl,
  742. pControl->PropertyId,
  743. (LPMIXERCONTROLDETAILS) DataBuffer,
  744. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  745. 0
  746. );
  747. break;
  748. ///////////////////////////////////////////////////////
  749. default:
  750. ///////////////////////////////////////////////////////
  751. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  752. break;
  753. }
  754. break;
  755. ///////////////////////////////////////////////////////////////
  756. default:
  757. ///////////////////////////////////////////////////////////////
  758. DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
  759. break;
  760. }
  761. return( STATUS_SUCCESS );
  762. }
  763. ///////////////////////////////////////////////////////////////////////
  764. //
  765. // kmxlSetControlDetailsHandler
  766. //
  767. // Determines which control is being set and calls the appropriate
  768. // handler to perform the set property.
  769. //
  770. //
  771. NTSTATUS
  772. kmxlSetControlDetailsHandler(
  773. IN PWDMACONTEXT pWdmaContext,
  774. IN OUT LPDEVICEINFO DeviceInfo, // Device Info structure
  775. IN LPVOID DataBuffer, // MIXERCONTROLDETAILS structure
  776. IN LPVOID paDetails, // Flat pointer to detail struct(s)
  777. IN ULONG Flags
  778. )
  779. {
  780. LPMIXERCONTROLDETAILS pmcd = (LPMIXERCONTROLDETAILS) DataBuffer;
  781. PMXLCONTROL pControl;
  782. NTSTATUS Status;
  783. PMIXERDEVICE pmxd;
  784. PMXLLINE pLine;
  785. PAGED_CODE();
  786. ASSERT( DeviceInfo );
  787. //
  788. // Get a instance reference
  789. //
  790. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  791. if( pmxd == NULL ) {
  792. return( STATUS_SUCCESS );
  793. }
  794. pControl = kmxlFindControl( pmxd, pmcd->dwControlID );
  795. if( pControl == NULL ) {
  796. DPF(DL_WARNING|FA_USER,( "control %d not found",pmcd->dwControlID ));
  797. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  798. return( STATUS_SUCCESS );
  799. }
  800. pLine = kmxlFindLineForControl(
  801. pControl,
  802. pmxd->listLines
  803. );
  804. if( pLine == NULL ) {
  805. DPF(DL_WARNING|FA_USER,( "invalid control id %d",pControl->Control.dwControlID ));
  806. DeviceInfo->mmr = MIXERR_INVALCONTROL;
  807. return( STATUS_SUCCESS );
  808. }
  809. if( ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) &&
  810. ( pmcd->cChannels != 1 ) &&
  811. ( pControl->Control.dwControlType != MIXERCONTROL_CONTROLTYPE_MUX )) {
  812. DPF(DL_WARNING|FA_USER,( "incorrect cChannels ( %d ) on UNIFORM control %d",
  813. pmcd->cChannels,
  814. pControl->Control.dwControlID ));
  815. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  816. return( STATUS_SUCCESS );
  817. }
  818. if( pmcd->cChannels > pLine->Line.cChannels ) {
  819. DPF(DL_WARNING|FA_USER,( "incorrect number of channels ( %d ) on line %08x",
  820. pmcd->cChannels,
  821. pLine->Line.dwLineID ));
  822. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  823. return( STATUS_SUCCESS );
  824. }
  825. if( pmcd->cMultipleItems != pControl->Control.cMultipleItems ) {
  826. DPF(DL_WARNING|FA_USER,( "incorrect number of items ( %d ) on control %d ( %d )",
  827. pmcd->cMultipleItems,
  828. pControl->Control.dwControlID,
  829. pControl->Control.cMultipleItems ));
  830. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  831. return( STATUS_SUCCESS );
  832. }
  833. switch( DeviceInfo->dwFlags & MIXER_SETCONTROLDETAILSF_QUERYMASK ) {
  834. ///////////////////////////////////////////////////////////////
  835. case MIXER_SETCONTROLDETAILSF_VALUE:
  836. ///////////////////////////////////////////////////////////////
  837. switch( pControl->Control.dwControlType ) {
  838. ///////////////////////////////////////////////////////
  839. case MIXERCONTROL_CONTROLTYPE_MIXER:
  840. ///////////////////////////////////////////////////////
  841. DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
  842. DPF(DL_WARNING|FA_USER,( "mixers are not supported" ));
  843. break;
  844. ///////////////////////////////////////////////////////
  845. case MIXERCONTROL_CONTROLTYPE_PEAKMETER:
  846. ///////////////////////////////////////////////////////
  847. Status = kmxlHandleSetUnsigned(
  848. DeviceInfo,
  849. pmxd,
  850. pControl,
  851. pControl->PropertyId,
  852. (LPMIXERCONTROLDETAILS) DataBuffer,
  853. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  854. Flags | MIXER_FLAG_SCALE
  855. );
  856. break;
  857. ///////////////////////////////////////////////////////
  858. case MIXERCONTROL_CONTROLTYPE_MUTE:
  859. ///////////////////////////////////////////////////////
  860. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUTE ) ) {
  861. Status = kmxlHandleSetUnsigned(
  862. DeviceInfo,
  863. pmxd,
  864. pControl,
  865. KSPROPERTY_AUDIO_MUTE,
  866. (LPMIXERCONTROLDETAILS) DataBuffer,
  867. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  868. Flags
  869. );
  870. } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
  871. Status = kmxlHandleSetMuteFromSuperMix(
  872. DeviceInfo,
  873. pmxd,
  874. pControl,
  875. (LPMIXERCONTROLDETAILS) DataBuffer,
  876. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  877. Flags
  878. );
  879. } else {
  880. DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Mute.") );
  881. }
  882. kmxlNotifyLineChange(
  883. DeviceInfo,
  884. pmxd,
  885. pLine,
  886. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails
  887. );
  888. break;
  889. ///////////////////////////////////////////////////////
  890. case MIXERCONTROL_CONTROLTYPE_VOLUME:
  891. ///////////////////////////////////////////////////////
  892. #ifdef SUPERMIX_AS_VOL
  893. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_VOLUME ) ) {
  894. #endif // SUPERMIX_AS_VOL
  895. Status = kmxlHandleSetUnsigned(
  896. DeviceInfo,
  897. pmxd,
  898. pControl,
  899. pControl->PropertyId,
  900. (LPMIXERCONTROLDETAILS) DataBuffer,
  901. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  902. Flags | MIXER_FLAG_SCALE
  903. );
  904. #ifdef SUPERMIX_AS_VOL
  905. } else if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
  906. Status = kmxlHandleSetVolumeFromSuperMix(
  907. DeviceInfo,
  908. pmxd,
  909. pControl,
  910. (LPMIXERCONTROLDETAILS) DataBuffer,
  911. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  912. Flags | MIXER_FLAG_SCALE
  913. );
  914. } else {
  915. DPF(DL_WARNING|FA_USER,("Invalid GUID for Control Type Volume.") );
  916. }
  917. #endif
  918. break;
  919. ///////////////////////////////////////////////////////
  920. case MIXERCONTROL_CONTROLTYPE_TREBLE:
  921. case MIXERCONTROL_CONTROLTYPE_BASS:
  922. ///////////////////////////////////////////////////////
  923. // These all take 32-bit parameters per channel but //
  924. // need to be scale from linear to dB //
  925. ///////////////////////////////////////////////////////
  926. Status = kmxlHandleSetUnsigned(
  927. DeviceInfo,
  928. pmxd,
  929. pControl,
  930. pControl->PropertyId,
  931. (LPMIXERCONTROLDETAILS) DataBuffer,
  932. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  933. Flags | MIXER_FLAG_SCALE
  934. );
  935. break;
  936. ///////////////////////////////////////////////////////
  937. case MIXERCONTROL_CONTROLTYPE_LOUDNESS:
  938. case MIXERCONTROL_CONTROLTYPE_ONOFF:
  939. case MIXERCONTROL_CONTROLTYPE_BOOLEAN:
  940. case MIXERCONTROL_CONTROLTYPE_MUX:
  941. case MIXERCONTROL_CONTROLTYPE_FADER:
  942. case MIXERCONTROL_CONTROLTYPE_BASS_BOOST:
  943. ///////////////////////////////////////////////////////
  944. // These all take up to 32-bit parameters per channel//
  945. ///////////////////////////////////////////////////////
  946. Status = kmxlHandleSetUnsigned(
  947. DeviceInfo,
  948. pmxd,
  949. pControl,
  950. pControl->PropertyId,
  951. (LPMIXERCONTROLDETAILS) DataBuffer,
  952. (LPMIXERCONTROLDETAILS_UNSIGNED) paDetails,
  953. Flags
  954. );
  955. break;
  956. ///////////////////////////////////////////////////////
  957. default:
  958. ///////////////////////////////////////////////////////
  959. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  960. break;
  961. }
  962. break;
  963. ///////////////////////////////////////////////////////////////
  964. default:
  965. ///////////////////////////////////////////////////////////////
  966. DPF(DL_WARNING|FA_USER,( "invalid flags %x",DeviceInfo->dwFlags ));
  967. DeviceInfo->mmr = MMSYSERR_NOTSUPPORTED;
  968. break;
  969. }
  970. return( STATUS_SUCCESS );
  971. }
  972. ///////////////////////////////////////////////////////////////////////
  973. //
  974. // kmxlFindControl
  975. //
  976. //
  977. PMXLCONTROL
  978. kmxlFindControl(
  979. IN PMIXERDEVICE pmxd, // The mixer instance to search
  980. IN DWORD dwControlID // The control ID to find
  981. )
  982. {
  983. PMXLLINE pLine;
  984. PMXLCONTROL pControl;
  985. PAGED_CODE();
  986. pLine = kmxlFirstInList( pmxd->listLines );
  987. while( pLine ) {
  988. pControl = kmxlFirstInList( pLine->Controls );
  989. while( pControl ) {
  990. if( pControl->Control.dwControlID == dwControlID ) {
  991. return( pControl );
  992. }
  993. pControl = kmxlNextControl( pControl );
  994. }
  995. pLine = kmxlNextLine( pLine );
  996. }
  997. return( NULL );
  998. }
  999. ///////////////////////////////////////////////////////////////////////
  1000. //
  1001. // kmxlFindLine
  1002. //
  1003. // For the given line ID, kmxlFindLine will find the matching
  1004. // MXLLINE structure for it.
  1005. //
  1006. //
  1007. PMXLLINE
  1008. kmxlFindLine(
  1009. IN PMIXERDEVICE pmxd,
  1010. IN DWORD dwLineID // The line ID to find
  1011. )
  1012. {
  1013. PMXLLINE pLine;
  1014. PAGED_CODE();
  1015. pLine = kmxlFirstInList( pmxd->listLines );
  1016. while( pLine ) {
  1017. if( pLine->Line.dwLineID == dwLineID ) {
  1018. return( pLine );
  1019. }
  1020. pLine = kmxlNextLine( pLine );
  1021. }
  1022. return( NULL );
  1023. }
  1024. ///////////////////////////////////////////////////////////////////////
  1025. //
  1026. // kmxlGetLineInfoByID
  1027. //
  1028. // Loops through the lines looking for a line that has a matching
  1029. // source and destination Id.
  1030. //
  1031. //
  1032. NTSTATUS
  1033. kmxlGetLineInfoByID(
  1034. IN PWDMACONTEXT pWdmaContext,
  1035. IN LPDEVICEINFO DeviceInfo, // Device Info structure
  1036. IN LPVOID DataBuffer, // MIXERLINE(16) structure
  1037. IN WORD Source, // Source line id
  1038. IN WORD Destination // Destination line id
  1039. )
  1040. {
  1041. PMIXERDEVICE pmxd;
  1042. PMXLLINE pLine;
  1043. BOOL bDestination;
  1044. PAGED_CODE();
  1045. ASSERT( DeviceInfo );
  1046. ASSERT( DataBuffer );
  1047. if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
  1048. DPF(DL_WARNING|FA_USER,( "invalid device number %d",DeviceInfo->DeviceNumber ));
  1049. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1050. return( STATUS_SUCCESS );
  1051. }
  1052. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  1053. if( pmxd == NULL ) {
  1054. return( STATUS_SUCCESS );
  1055. }
  1056. //
  1057. // If the source is -1 (0xFFFF), then this line is a destination.
  1058. //
  1059. if( Source == (WORD) -1 ) {
  1060. bDestination = TRUE;
  1061. Source = 0;
  1062. } else {
  1063. bDestination = FALSE;
  1064. }
  1065. pLine = kmxlFirstInList( pmxd->listLines );
  1066. while( pLine ) {
  1067. if( ( bDestination &&
  1068. ( pLine->Line.dwDestination == Destination ) &&
  1069. ( pLine->Line.cConnections > 0 ) ) ||
  1070. ( ( pLine->Line.dwSource == Source ) &&
  1071. ( pLine->Line.dwDestination == Destination ) ) )
  1072. {
  1073. NOT16( DeviceInfo );
  1074. RtlCopyMemory((LPMIXERLINE) DataBuffer,
  1075. &pLine->Line,
  1076. sizeof( MIXERLINE ) );
  1077. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1078. return( STATUS_SUCCESS );
  1079. }
  1080. pLine = kmxlNextLine( pLine );
  1081. }
  1082. //
  1083. // There are no lines for the device number.
  1084. //
  1085. DPF(DL_WARNING|FA_USER,( "no matching lines for (S=%08X, D=%08X)",
  1086. Source,
  1087. Destination ));
  1088. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1089. return( STATUS_SUCCESS );
  1090. }
  1091. ///////////////////////////////////////////////////////////////////////
  1092. //
  1093. // kmxlGetLineInfoByType
  1094. //
  1095. // Loops through all the lines looking for the first line that matches
  1096. // the Target type specified. Note that this will always only find the
  1097. // first one!
  1098. //
  1099. //
  1100. NTSTATUS
  1101. kmxlGetLineInfoByType(
  1102. IN PWDMACONTEXT pWdmaContext,
  1103. IN LPDEVICEINFO DeviceInfo, // Device info structure
  1104. IN LPVOID DataBuffer, // MIXERLINE(16) structure
  1105. IN DWORD dwType // Line type to search for
  1106. )
  1107. {
  1108. PMXLLINE pLine;
  1109. PMIXERDEVICE pmxd;
  1110. PAGED_CODE();
  1111. ASSERT( DeviceInfo );
  1112. ASSERT( DataBuffer );
  1113. if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
  1114. DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
  1115. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1116. return( STATUS_SUCCESS );
  1117. }
  1118. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  1119. if( pmxd == NULL ) {
  1120. return( STATUS_SUCCESS );
  1121. }
  1122. //
  1123. // Loop through all the lines looking for a line that has the
  1124. // specified target type. Note that this will only return the
  1125. // first one.
  1126. //
  1127. pLine = kmxlFirstInList( pmxd->listLines );
  1128. while( pLine ) {
  1129. if( pLine->Line.Target.dwType == dwType ) {
  1130. LPMIXERLINE lpMxl = (LPMIXERLINE) DataBuffer;
  1131. NOT16( DeviceInfo );
  1132. if( lpMxl->Target.wMid != pLine->Line.Target.wMid ) {
  1133. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1134. return( STATUS_SUCCESS );
  1135. }
  1136. if( lpMxl->Target.wPid != pLine->Line.Target.wPid ) {
  1137. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1138. return( STATUS_SUCCESS );
  1139. }
  1140. if( wcscmp( pLine->Line.Target.szPname, lpMxl->Target.szPname ) )
  1141. {
  1142. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1143. return( STATUS_SUCCESS );
  1144. }
  1145. RtlCopyMemory((LPMIXERLINE) DataBuffer,
  1146. &pLine->Line,
  1147. sizeof( MIXERLINE ) );
  1148. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1149. return( STATUS_SUCCESS );
  1150. }
  1151. pLine = kmxlNextLine( pLine );
  1152. }
  1153. //
  1154. // The line was not found. Return invalid parameter.
  1155. //
  1156. DPF(DL_WARNING|FA_USER,( "no matching line found for %x",dwType ));
  1157. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1158. return( STATUS_SUCCESS );
  1159. }
  1160. ///////////////////////////////////////////////////////////////////////
  1161. //
  1162. // kmxlGetLineInfoByComponent
  1163. //
  1164. // Loops through the list of lines looking for a line that has a matching
  1165. // dwComponentType. Note that this will always find only the first!
  1166. //
  1167. //
  1168. NTSTATUS
  1169. kmxlGetLineInfoByComponent(
  1170. IN PWDMACONTEXT pWdmaContext,
  1171. IN LPDEVICEINFO DeviceInfo, // Device Info structure
  1172. IN LPVOID DataBuffer, // MIXERLINE(16) structure
  1173. IN DWORD dwComponentType // Component type to search for
  1174. )
  1175. {
  1176. PMXLLINE pLine;
  1177. PMIXERDEVICE pmxd;
  1178. PAGED_CODE();
  1179. ASSERT( DeviceInfo );
  1180. ASSERT( DataBuffer );
  1181. if( DeviceInfo->DeviceNumber > MAXNUMDEVS ) {
  1182. DPF(DL_WARNING|FA_USER,( "invalid device id %x",DeviceInfo->DeviceNumber ));
  1183. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1184. return( STATUS_SUCCESS );
  1185. }
  1186. pmxd = kmxlReferenceMixerDevice( pWdmaContext, DeviceInfo );
  1187. if( pmxd == NULL ) {
  1188. return( STATUS_SUCCESS );
  1189. }
  1190. //
  1191. // Loop through all the lines looking for a line that has a component
  1192. // type matching what the user requested.
  1193. //
  1194. pLine = kmxlFirstInList( pmxd->listLines );
  1195. while( pLine ) {
  1196. if( pLine->Line.dwComponentType == dwComponentType ) {
  1197. //
  1198. // Copy the data into the user buffer
  1199. //
  1200. NOT16( DeviceInfo );
  1201. RtlCopyMemory((LPMIXERLINE) DataBuffer,
  1202. &pLine->Line,
  1203. sizeof( MIXERLINE ) );
  1204. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1205. return( STATUS_SUCCESS );
  1206. }
  1207. pLine = kmxlNextLine( pLine );
  1208. }
  1209. DPF(DL_WARNING|FA_USER,( "no matching line found for type %x",dwComponentType ));
  1210. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1211. return( STATUS_SUCCESS );
  1212. }
  1213. ///////////////////////////////////////////////////////////////////////
  1214. //
  1215. // kmxlGetNumDestinations
  1216. //
  1217. // Returns the number of destinations stored in the mixer device
  1218. //
  1219. //
  1220. DWORD
  1221. kmxlGetNumDestinations(
  1222. IN PMIXERDEVICE pMixerDevice // The device
  1223. )
  1224. {
  1225. PAGED_CODE();
  1226. return( pMixerDevice->cDestinations );
  1227. }
  1228. ///////////////////////////////////////////////////////////////////////
  1229. ///////////////////////////////////////////////////////////////////////
  1230. // //
  1231. // I N S T A N C E R O U T I N E S //
  1232. // //
  1233. ///////////////////////////////////////////////////////////////////////
  1234. ///////////////////////////////////////////////////////////////////////
  1235. /////////////////////////////////////////////////////////////////////////////
  1236. //
  1237. // kmxlReferenceInstance
  1238. //
  1239. // Determines if the dwInstance field of the DeviceInfo structure
  1240. // is valid. If not, it creates a valid instance and sets a
  1241. // reference count of 1 on it.
  1242. //
  1243. //
  1244. LONG nextinstanceid=0;
  1245. DWORD kmxlUniqueInstanceId(VOID)
  1246. {
  1247. PAGED_CODE();
  1248. // Update our next valid instance id. Do NOT allow zero.
  1249. // Since that is used to signal that we want to allocate
  1250. // a new instance.
  1251. if (0==InterlockedIncrement(&nextinstanceid))
  1252. InterlockedIncrement(&nextinstanceid);
  1253. return nextinstanceid;
  1254. }
  1255. /////////////////////////////////////////////////////////////////////////////
  1256. //
  1257. // kmxlReferenceMixerDevice
  1258. //
  1259. // This routine Translates the device number and makes sure that there is a
  1260. // open SysAudio PFILE_OBJECT in this mixier device. This will be the FILE_OBJECT
  1261. // that we use to talk to this mixer device.
  1262. //
  1263. // return: PMIXERDEVICE on success NULL otherwise.
  1264. //
  1265. PMIXERDEVICE
  1266. kmxlReferenceMixerDevice(
  1267. IN PWDMACONTEXT pWdmaContext,
  1268. IN OUT LPDEVICEINFO DeviceInfo // Device Information
  1269. )
  1270. {
  1271. NTSTATUS Status;
  1272. DWORD TranslatedDeviceNumber;
  1273. PMIXERDEVICE pmxd;
  1274. PAGED_CODE();
  1275. DPFASSERT(IsValidDeviceInfo(DeviceInfo));
  1276. TranslatedDeviceNumber =
  1277. wdmaudTranslateDeviceNumber(pWdmaContext,
  1278. DeviceInfo->DeviceType,
  1279. DeviceInfo->wstrDeviceInterface,
  1280. DeviceInfo->DeviceNumber);
  1281. if( TranslatedDeviceNumber == MAXULONG ) {
  1282. DPF(DL_WARNING|FA_INSTANCE,("Could not translate DeviceNumber! DT=%08X, DI=%08X, DN=%08X",
  1283. DeviceInfo->DeviceType,
  1284. DeviceInfo->wstrDeviceInterface,
  1285. DeviceInfo->DeviceNumber) );
  1286. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1287. return( NULL );
  1288. }
  1289. pmxd = &pWdmaContext->MixerDevs[ TranslatedDeviceNumber ];
  1290. if( pmxd->pfo == NULL )
  1291. {
  1292. DPF(DL_WARNING|FA_NOTE,("pmxd->pfo should have been set!") );
  1293. //
  1294. // This is the first time through this code. Open SysAudio on this device
  1295. // and set the mixer device.
  1296. //
  1297. // set the SysAudio file object
  1298. if( NULL==(pmxd->pfo=kmxlOpenSysAudio())) {
  1299. DPF(DL_WARNING|FA_INSTANCE,("OpenSysAudio failed") );
  1300. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1301. return( NULL );
  1302. }
  1303. Status = SetSysAudioProperty(
  1304. pmxd->pfo,
  1305. KSPROPERTY_SYSAUDIO_DEVICE_INSTANCE,
  1306. sizeof( pmxd->Device ),
  1307. &pmxd->Device
  1308. );
  1309. if( !NT_SUCCESS( Status ) ) {
  1310. kmxlCloseSysAudio( pmxd->pfo );
  1311. pmxd->pfo=NULL;
  1312. DPF(DL_WARNING|FA_INSTANCE,("SetSysAudioProperty DEVICE_INSTANCE failed %X",Status) );
  1313. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1314. return( NULL );
  1315. }
  1316. }
  1317. //
  1318. // BUGBUG: we should not need this any more.
  1319. //
  1320. DeviceInfo->dwInstance=kmxlUniqueInstanceId();;
  1321. return pmxd;
  1322. }
  1323. ///////////////////////////////////////////////////////////////////////
  1324. ///////////////////////////////////////////////////////////////////////
  1325. // //
  1326. // G E T / S E T D E T A I L H A N D L E R S //
  1327. // //
  1328. ///////////////////////////////////////////////////////////////////////
  1329. ///////////////////////////////////////////////////////////////////////
  1330. ///////////////////////////////////////////////////////////////////////
  1331. //
  1332. // kmxlIsSpeakerDestinationVolume
  1333. //
  1334. // Returns TRUE if the control is a volume control on the Speakers
  1335. // destination.
  1336. //
  1337. //
  1338. BOOL
  1339. kmxlIsSpeakerDestinationVolume(
  1340. IN PMIXERDEVICE pmxd, // The mixer
  1341. IN PMXLCONTROL pControl // The control to check
  1342. )
  1343. {
  1344. PMXLLINE pLine;
  1345. PAGED_CODE();
  1346. DPFASSERT( IsValidMixerDevice(pmxd) );
  1347. DPFASSERT( IsValidControl(pControl) );
  1348. //
  1349. // Find a line for this control. If none is found, then this can't
  1350. // be a destination volume.
  1351. //
  1352. pLine = kmxlFindLineForControl( pControl, pmxd->listLines );
  1353. if( !pLine ) {
  1354. return( FALSE );
  1355. }
  1356. if( pLine->Line.dwComponentType == MIXERLINE_COMPONENTTYPE_DST_SPEAKERS ) {
  1357. return( TRUE );
  1358. } else {
  1359. return( FALSE );
  1360. }
  1361. }
  1362. ///////////////////////////////////////////////////////////////////////
  1363. //
  1364. // kmxlHandleGetUnsigned
  1365. //
  1366. //
  1367. // Handles getting an unsigned (32-bit) value for a control. Note
  1368. // that signed 32-bit and boolean values are also retrieved via this
  1369. // handler.
  1370. //
  1371. //
  1372. NTSTATUS
  1373. kmxlHandleGetUnsigned(
  1374. IN LPDEVICEINFO DeviceInfo,
  1375. IN PMIXERDEVICE pmxd,
  1376. IN PMXLCONTROL pControl,
  1377. IN ULONG ulProperty,
  1378. IN LPMIXERCONTROLDETAILS pmcd,
  1379. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  1380. IN ULONG Flags
  1381. )
  1382. {
  1383. NTSTATUS Status = STATUS_SUCCESS;
  1384. LONG Level;
  1385. DWORD dwLevel;
  1386. ULONG i;
  1387. ULONG Channel;
  1388. MIXERMAPPING Mapping = MIXER_MAPPING_LOGRITHMIC;
  1389. PAGED_CODE();
  1390. DPFASSERT( IsValidMixerDevice(pmxd) );
  1391. DPFASSERT( IsValidControl(pControl) );
  1392. if( paDetails == NULL ) {
  1393. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1394. return( STATUS_SUCCESS );
  1395. }
  1396. //
  1397. // Use a different mapping algorithm if this is a speaker
  1398. // dest volume control.
  1399. //
  1400. if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
  1401. Mapping = pmxd->Mapping;
  1402. }
  1403. //
  1404. // Service the Mux
  1405. //
  1406. if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {
  1407. Status = kmxlGetNodeProperty(
  1408. pmxd->pfo,
  1409. &KSPROPSETID_Audio,
  1410. pControl->PropertyId,
  1411. pControl->Id,
  1412. 0,
  1413. NULL,
  1414. &Level,
  1415. sizeof( Level )
  1416. );
  1417. if( !NT_SUCCESS( Status ) ) {
  1418. DPF(DL_WARNING|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) failed GET on MUX with %x",
  1419. pControl->Control.dwControlID,
  1420. pControl->Id,
  1421. Status ));
  1422. DeviceInfo->mmr = MMSYSERR_ERROR;
  1423. return( STATUS_SUCCESS );
  1424. }
  1425. DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) = %d [1]",
  1426. pControl->Control.dwControlID,
  1427. pControl->Id,
  1428. Level ));
  1429. for( i = 0; i < pControl->Parameters.Count; i++ ) {
  1430. if( (ULONG) Level == pControl->Parameters.pPins[ i ] ) {
  1431. // APITRACE(( "1" ));
  1432. paDetails[ i ].dwValue = 1;
  1433. } else {
  1434. paDetails[ i ].dwValue = 0;
  1435. // APITRACE(( "1" ));
  1436. }
  1437. }
  1438. // APITRACE(( "]\n" ));
  1439. }
  1440. else {
  1441. paDetails->dwValue = 0; // initialize to zero for now so that the coalesced case works
  1442. // Loop over the channels for now. Fix this so that only one request is made.
  1443. Channel = 0;
  1444. do
  1445. {
  1446. Status = kmxlGetAudioNodeProperty(
  1447. pmxd->pfo,
  1448. ulProperty,
  1449. pControl->Id,
  1450. Channel,
  1451. NULL, 0, // No extra input bytes
  1452. &Level, sizeof( Level )
  1453. );
  1454. if ( !NT_SUCCESS( Status ) ) {
  1455. DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on MASTER channel with %x",
  1456. pControl->Control.dwControlID,
  1457. ControlTypeToString( pControl->Control.dwControlType ),
  1458. pControl->Id,
  1459. Status ));
  1460. DPF(DL_WARNING|FA_PROPERTY,
  1461. ( "GetAudioNodeProp failed on MASTER channel with %X for %s!",
  1462. Status,
  1463. ControlTypeToString( pControl->Control.dwControlType ) ) );
  1464. DeviceInfo->mmr = MMSYSERR_ERROR;
  1465. return( STATUS_SUCCESS );
  1466. }
  1467. if ( pControl->bScaled ) {
  1468. dwLevel = kmxlVolLogToLinear( pControl, Level, Mapping, Channel );
  1469. } else {
  1470. dwLevel = (DWORD)Level;
  1471. }
  1472. if( ( pmcd->cChannels == 1 ) &&
  1473. !( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ) {
  1474. //
  1475. // Coalesce values: If the user requests only 1 channel for a N channel
  1476. // control, then return the greatest channel value.
  1477. //
  1478. if (dwLevel > paDetails->dwValue) {
  1479. paDetails->dwValue = dwLevel;
  1480. }
  1481. } else if (Channel < pmcd->cChannels) {
  1482. paDetails[ Channel ].dwValue = dwLevel;
  1483. DPF(DL_TRACE|FA_USER,( "kmxlHandleGetUnsigned( Ctrl=%d, Id=%d ) returning (Chan#%d) = (%x)",
  1484. pControl->Control.dwControlID,
  1485. pControl->Id,
  1486. Channel,
  1487. paDetails[ Channel ].dwValue
  1488. ));
  1489. } else {
  1490. // No need to keep trying
  1491. break;
  1492. }
  1493. Channel++;
  1494. } while ( Channel < pControl->NumChannels );
  1495. }
  1496. if( NT_SUCCESS( Status ) ) {
  1497. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1498. } else {
  1499. DeviceInfo->mmr = MMSYSERR_ERROR;
  1500. }
  1501. return( STATUS_SUCCESS );
  1502. }
  1503. ///////////////////////////////////////////////////////////////////////
  1504. //
  1505. // kmxlHandleGetMuteFromSuperMix
  1506. //
  1507. // Handles getting the mute state from a supermix node.
  1508. //
  1509. NTSTATUS
  1510. kmxlHandleGetMuteFromSuperMix(
  1511. IN LPDEVICEINFO DeviceInfo,
  1512. IN PMIXERDEVICE pmxd,
  1513. IN PMXLCONTROL pControl,
  1514. IN LPMIXERCONTROLDETAILS pmcd,
  1515. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  1516. IN ULONG Flags
  1517. )
  1518. {
  1519. NTSTATUS Status;
  1520. ULONG i;
  1521. BOOL bMute = FALSE;
  1522. PAGED_CODE();
  1523. DPFASSERT( IsValidMixerDevice(pmxd) );
  1524. ASSERT( pControl );
  1525. ASSERT( pControl->Parameters.pMixCaps );
  1526. ASSERT( pControl->Parameters.pMixLevels );
  1527. //
  1528. // Read the current state of the supermix
  1529. //
  1530. Status = kmxlGetNodeProperty(
  1531. pmxd->pfo,
  1532. &KSPROPSETID_Audio,
  1533. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1534. pControl->Id,
  1535. 0,
  1536. NULL,
  1537. pControl->Parameters.pMixLevels,
  1538. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1539. );
  1540. if( !NT_SUCCESS( Status ) ) {
  1541. DPF(DL_WARNING|FA_USER,( "kmxlHandleGetMuteFromSupermix ( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
  1542. pControl->Control.dwControlID,
  1543. ControlTypeToString( pControl->Control.dwControlType ),
  1544. pControl->Id,
  1545. Status
  1546. ));
  1547. DeviceInfo->mmr = MMSYSERR_ERROR;
  1548. return( STATUS_SUCCESS );
  1549. }
  1550. for( i = 0; i < pControl->Parameters.Size; i++ ) {
  1551. if( pControl->Parameters.pMixLevels[ i ].Mute )
  1552. {
  1553. bMute = TRUE;
  1554. continue;
  1555. }
  1556. if( pControl->Parameters.pMixLevels[ i ].Level == LONG_MIN )
  1557. {
  1558. bMute = TRUE;
  1559. continue;
  1560. }
  1561. bMute = FALSE;
  1562. break;
  1563. }
  1564. paDetails->dwValue = (DWORD) bMute;
  1565. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1566. return( STATUS_SUCCESS );
  1567. }
  1568. ///////////////////////////////////////////////////////////////////////
  1569. //
  1570. // kmxlHandleSetUnsigned
  1571. //
  1572. // Handles setting an unsigned (32-bit) value for a control. Note
  1573. // that signed 32-bit and boolean values are also set via this
  1574. // handler.
  1575. //
  1576. //
  1577. NTSTATUS
  1578. kmxlHandleSetUnsigned(
  1579. IN OUT LPDEVICEINFO DeviceInfo,
  1580. IN PMIXERDEVICE pmxd,
  1581. IN PMXLCONTROL pControl,
  1582. IN ULONG ulProperty,
  1583. IN LPMIXERCONTROLDETAILS pmcd,
  1584. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  1585. IN ULONG Flags
  1586. )
  1587. {
  1588. NTSTATUS Status = STATUS_SUCCESS;
  1589. LONG Level, Current;
  1590. DWORD dwValue;
  1591. BOOL bUniform, bEqual = TRUE;
  1592. ULONG i;
  1593. ULONG Channel;
  1594. MIXERMAPPING Mapping = MIXER_MAPPING_LOGRITHMIC;
  1595. PAGED_CODE();
  1596. DPFASSERT( IsValidMixerDevice(pmxd) );
  1597. ASSERT( pControl );
  1598. if( paDetails == NULL ) {
  1599. DPF(DL_WARNING|FA_USER,( "paDetails is NULL" ));
  1600. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1601. return( STATUS_INVALID_PARAMETER );
  1602. }
  1603. bUniform = ( pControl->Control.fdwControl & MIXERCONTROL_CONTROLF_UNIFORM ) ||
  1604. ( pmcd->cChannels == 1 );
  1605. //
  1606. // Use a different mapping if this control is a speaker destination
  1607. // volume control.
  1608. //
  1609. if( kmxlIsSpeakerDestinationVolume( pmxd, pControl ) ) {
  1610. Mapping = pmxd->Mapping;
  1611. }
  1612. //
  1613. // Service the mux
  1614. //
  1615. if ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX) {
  1616. // Proken APITRACE statement.
  1617. //DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d, " ));
  1618. // First validate the paDetails parameter and make sure it has the correct
  1619. // format. If not, then punt with an invalid parameter error.
  1620. {
  1621. LONG selectcount=0;
  1622. for( i = 0; i < pmcd->cMultipleItems; i++ ) {
  1623. if( paDetails[ i ].dwValue ) {
  1624. selectcount++;
  1625. // APITRACE(( "1" ));
  1626. } else {
  1627. // APITRACE(( "0" ));
  1628. }
  1629. }
  1630. if (selectcount!=1) {
  1631. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) invalid paDetails parameter for SET on MUX",
  1632. pControl->Control.dwControlID,
  1633. ControlTypeToString( pControl->Control.dwControlType ),
  1634. pControl->Id));
  1635. DeviceInfo->mmr = MMSYSERR_INVALPARAM;
  1636. return( STATUS_SUCCESS );
  1637. }
  1638. }
  1639. for( i = 0; i < pmcd->cMultipleItems; i++ ) {
  1640. if( paDetails[ i ].dwValue ) {
  1641. // APITRACE(( "1" ));
  1642. Level = pControl->Parameters.pPins[ i ];
  1643. } else {
  1644. // APITRACE(( "0" ));
  1645. }
  1646. }
  1647. // APITRACE(( " ). Setting pin %d on MUX.\n", Level ));
  1648. Status = kmxlSetNodeProperty(
  1649. pmxd->pfo,
  1650. &KSPROPSETID_Audio,
  1651. pControl->PropertyId,
  1652. pControl->Id,
  1653. 0,
  1654. NULL,
  1655. &Level,
  1656. sizeof( Level )
  1657. );
  1658. if( !NT_SUCCESS( Status ) ) {
  1659. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed SET on MUX with %x",
  1660. pControl->Control.dwControlID,
  1661. ControlTypeToString( pControl->Control.dwControlType ),
  1662. pControl->Id,
  1663. Status ));
  1664. DeviceInfo->mmr = MMSYSERR_ERROR;
  1665. return( STATUS_SUCCESS );
  1666. }
  1667. bEqual = FALSE;
  1668. }
  1669. else {
  1670. // Loop over the channels for now. Fix this so that only one request is made.
  1671. Channel = 0;
  1672. do
  1673. {
  1674. if( bUniform ) {
  1675. //
  1676. // Some controls are mono in the eyes of SNDVOL but are in
  1677. // fact stereo. This hack fixes this problem.
  1678. //
  1679. dwValue = paDetails[ 0 ].dwValue;
  1680. } else if (Channel < pmcd->cChannels) {
  1681. dwValue = paDetails[ Channel ].dwValue;
  1682. } else {
  1683. // No need to keep trying
  1684. break;
  1685. }
  1686. if( pControl->bScaled ) {
  1687. Level = kmxlVolLinearToLog( pControl, dwValue, Mapping, Channel );
  1688. } else {
  1689. Level = (LONG)dwValue;
  1690. }
  1691. Status = kmxlGetAudioNodeProperty(
  1692. pmxd->pfo,
  1693. ulProperty,
  1694. pControl->Id,
  1695. Channel,
  1696. NULL, 0, // No extra input bytes
  1697. &Current, sizeof( Current )
  1698. );
  1699. if( !NT_SUCCESS( Status ) ) {
  1700. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%d ) failed GET on channel %d with %x",
  1701. pControl->Control.dwControlID,
  1702. ControlTypeToString( pControl->Control.dwControlType ),
  1703. pControl->Id,
  1704. Channel,
  1705. Status ));
  1706. DeviceInfo->mmr = MMSYSERR_ERROR;
  1707. return( STATUS_SUCCESS );
  1708. }
  1709. if( Level != Current ) {
  1710. bEqual = FALSE;
  1711. Status = kmxlSetAudioNodeProperty(
  1712. pmxd->pfo,
  1713. ulProperty,
  1714. pControl->Id,
  1715. Channel,
  1716. NULL, 0, // No extra input bytes
  1717. &Level, sizeof( Level )
  1718. );
  1719. if( !NT_SUCCESS( Status ) ) {
  1720. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d [%s], Id=%x ) failed SET on channel %d with %x",
  1721. pControl->Control.dwControlID,
  1722. ControlTypeToString( pControl->Control.dwControlType ),
  1723. pControl->Id,
  1724. Channel,
  1725. Status ));
  1726. DeviceInfo->mmr = MMSYSERR_ERROR;
  1727. return( STATUS_SUCCESS );
  1728. }
  1729. DPF(DL_TRACE|FA_USER,( "kmxlHandleSetUnsigned( Ctrl=%d, Id=%d ) using (%x) on Chan#%d",
  1730. pControl->Control.dwControlID,
  1731. pControl->Id,
  1732. paDetails[ Channel ].dwValue,
  1733. Channel
  1734. ));
  1735. }
  1736. Channel++;
  1737. } while ( Channel < pControl->NumChannels );
  1738. }
  1739. if( NT_SUCCESS( Status ) ) {
  1740. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1741. if( Flags & MIXER_FLAG_PERSIST ) {
  1742. kmxlPersistControl(
  1743. pmxd->pfo,
  1744. pmxd,
  1745. pControl,
  1746. paDetails
  1747. );
  1748. }
  1749. if( !bEqual && !( Flags & MIXER_FLAG_NOCALLBACK ) ) {
  1750. kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
  1751. }
  1752. } else {
  1753. DeviceInfo->mmr = MMSYSERR_ERROR;
  1754. }
  1755. return( STATUS_SUCCESS );
  1756. }
  1757. ///////////////////////////////////////////////////////////////////////
  1758. //
  1759. // kmxlHandleSetMuteFromSuperMix
  1760. //
  1761. // Handles setting the mute state using a supermixer.
  1762. //
  1763. //
  1764. NTSTATUS
  1765. kmxlHandleSetMuteFromSuperMix(
  1766. IN OUT LPDEVICEINFO DeviceInfo,
  1767. IN PMIXERDEVICE pmxd,
  1768. IN PMXLCONTROL pControl,
  1769. IN LPMIXERCONTROLDETAILS pmcd,
  1770. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  1771. IN ULONG Flags
  1772. )
  1773. {
  1774. NTSTATUS Status;
  1775. ULONG i;
  1776. PAGED_CODE();
  1777. DPFASSERT( IsValidMixerDevice(pmxd) );
  1778. ASSERT( pControl );
  1779. ASSERT( pControl->Parameters.pMixCaps );
  1780. ASSERT( pControl->Parameters.pMixLevels );
  1781. if( paDetails->dwValue ) {
  1782. //
  1783. // Query the current values from the supermix and save those away.
  1784. // These values will be used to restore the supermix to the state
  1785. // we found it prior to muting.
  1786. //
  1787. Status = kmxlGetNodeProperty(
  1788. pmxd->pfo,
  1789. &KSPROPSETID_Audio,
  1790. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1791. pControl->Id,
  1792. 0,
  1793. NULL,
  1794. pControl->Parameters.pMixLevels,
  1795. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1796. );
  1797. if( !NT_SUCCESS( Status ) ) {
  1798. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
  1799. pControl->Control.dwControlID,
  1800. ControlTypeToString( pControl->Control.dwControlType ),
  1801. pControl->Id,
  1802. Status ));
  1803. DeviceInfo->mmr = MMSYSERR_ERROR;
  1804. return( STATUS_SUCCESS );
  1805. }
  1806. //
  1807. // For any entry in the table that supports muting, mute it.
  1808. //
  1809. for( i = 0; i < pControl->Parameters.Size; i++ ) {
  1810. if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
  1811. pControl->Parameters.pMixLevels[ i ].Mute = TRUE;
  1812. }
  1813. }
  1814. //
  1815. // Set this new supermixer state.
  1816. //
  1817. Status = kmxlSetNodeProperty(
  1818. pmxd->pfo,
  1819. &KSPROPSETID_Audio,
  1820. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1821. pControl->Id,
  1822. 0,
  1823. NULL,
  1824. pControl->Parameters.pMixLevels,
  1825. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1826. );
  1827. if( !NT_SUCCESS( Status ) ) {
  1828. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
  1829. pControl->Control.dwControlID,
  1830. ControlTypeToString( pControl->Control.dwControlType ),
  1831. pControl->Id,
  1832. Status ));
  1833. DeviceInfo->mmr = MMSYSERR_ERROR;
  1834. return( STATUS_SUCCESS );
  1835. }
  1836. } else {
  1837. Status = kmxlGetNodeProperty(
  1838. pmxd->pfo,
  1839. &KSPROPSETID_Audio,
  1840. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1841. pControl->Id,
  1842. 0,
  1843. NULL,
  1844. pControl->Parameters.pMixLevels,
  1845. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1846. );
  1847. if( !NT_SUCCESS( Status ) ) {
  1848. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
  1849. pControl->Control.dwControlID,
  1850. ControlTypeToString( pControl->Control.dwControlType ),
  1851. pControl->Id,
  1852. Status ));
  1853. DeviceInfo->mmr = MMSYSERR_ERROR;
  1854. return( STATUS_SUCCESS );
  1855. }
  1856. //
  1857. // For any entry in the table that supports muting, mute it.
  1858. //
  1859. for( i = 0; i < pControl->Parameters.Size; i++ ) {
  1860. if( pControl->Parameters.pMixCaps->Capabilities[ i ].Mute ) {
  1861. pControl->Parameters.pMixLevels[ i ].Mute = FALSE;
  1862. }
  1863. }
  1864. //
  1865. // Set this new supermixer state.
  1866. //
  1867. Status = kmxlSetNodeProperty(
  1868. pmxd->pfo,
  1869. &KSPROPSETID_Audio,
  1870. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1871. pControl->Id,
  1872. 0,
  1873. NULL,
  1874. pControl->Parameters.pMixLevels,
  1875. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1876. );
  1877. if( !NT_SUCCESS( Status ) ) {
  1878. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetMuteFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
  1879. pControl->Control.dwControlID,
  1880. ControlTypeToString( pControl->Control.dwControlType ),
  1881. pControl->Id,
  1882. Status ));
  1883. DeviceInfo->mmr = MMSYSERR_ERROR;
  1884. return( STATUS_SUCCESS );
  1885. }
  1886. }
  1887. if( NT_SUCCESS( Status ) ) {
  1888. if( Flags & MIXER_FLAG_PERSIST ) {
  1889. kmxlPersistControl(
  1890. pmxd->pfo,
  1891. pmxd,
  1892. pControl,
  1893. paDetails
  1894. );
  1895. }
  1896. kmxlNotifyControlChange( DeviceInfo, pmxd, pControl );
  1897. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1898. } else {
  1899. DeviceInfo->mmr = MMSYSERR_ERROR;
  1900. }
  1901. return( STATUS_SUCCESS );
  1902. }
  1903. #ifdef SUPERMIX_AS_VOL
  1904. ///////////////////////////////////////////////////////////////////////
  1905. //
  1906. // kmxlHandleGetVolumeFromSuperMix
  1907. //
  1908. //
  1909. NTSTATUS
  1910. kmxlHandleGetVolumeFromSuperMix(
  1911. IN LPDEVICEINFO DeviceInfo,
  1912. IN PMIXERDEVICE pmxd,
  1913. IN PMXLCONTROL pControl,
  1914. IN LPMIXERCONTROLDETAILS pmcd,
  1915. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  1916. IN ULONG Flags
  1917. )
  1918. {
  1919. NTSTATUS Status;
  1920. ULONG i, Channels, Index, MaxChannel = 0;
  1921. LONG Max = LONG_MIN; // -Inf dB
  1922. PAGED_CODE();
  1923. DPFASSERT( IsValidMixerDevice(pmxd) );
  1924. ASSERT( pControl );
  1925. ASSERT( pmcd );
  1926. ASSERT( paDetails );
  1927. Status = kmxlGetNodeProperty(
  1928. pmxd->pfo,
  1929. &KSPROPSETID_Audio,
  1930. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  1931. pControl->Id,
  1932. 0,
  1933. NULL,
  1934. pControl->Parameters.pMixLevels,
  1935. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  1936. );
  1937. if( !NT_SUCCESS( Status ) ) {
  1938. DPF(DL_WARNING|FA_USER,( "kmxlHandleGetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
  1939. pControl->Control.dwControlID,
  1940. ControlTypeToString( pControl->Control.dwControlType ),
  1941. pControl->Id,
  1942. Status ));
  1943. DeviceInfo->mmr = MMSYSERR_ERROR;
  1944. return( STATUS_SUCCESS );
  1945. }
  1946. //
  1947. // Count the number of channels
  1948. //
  1949. for( i = 0, Channels = 0;
  1950. i < pControl->Parameters.Size;
  1951. i += pControl->Parameters.pMixCaps->OutputChannels + 1,
  1952. Channels++ )
  1953. {
  1954. if( pControl->Parameters.pMixLevels[ i ].Level > Max ) {
  1955. Max = pControl->Parameters.pMixLevels[ i ].Level;
  1956. MaxChannel = Channels;
  1957. }
  1958. }
  1959. //
  1960. // Return the translated volume levels
  1961. //
  1962. if( ( pmcd->cChannels == 1 ) && ( Channels > 1 ) ) {
  1963. //
  1964. // As per SB16 sample, if the caller wants only 1 channel but
  1965. // the control is multichannel, return the maximum of all the
  1966. // channels.
  1967. //
  1968. paDetails->dwValue = kmxlVolLogToLinear(
  1969. pControl,
  1970. Max,
  1971. MIXER_MAPPING_LOGRITHMIC,
  1972. MaxChannel
  1973. );
  1974. } else {
  1975. //
  1976. // Translate each of the channel value into linear and
  1977. // store them away.
  1978. //
  1979. for( i = 0; i < pmcd->cChannels; i++ ) {
  1980. Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
  1981. paDetails[ i ].dwValue = kmxlVolLogToLinear(
  1982. pControl,
  1983. pControl->Parameters.pMixLevels[ Index ].Level,
  1984. MIXER_MAPPING_LOGRITHMIC,
  1985. i
  1986. );
  1987. }
  1988. }
  1989. DeviceInfo->mmr = MMSYSERR_NOERROR;
  1990. return( STATUS_SUCCESS );
  1991. }
  1992. ///////////////////////////////////////////////////////////////////////
  1993. //
  1994. // kmxlHandleSetVolumeFromSuperMix
  1995. //
  1996. //
  1997. NTSTATUS
  1998. kmxlHandleSetVolumeFromSuperMix(
  1999. IN LPDEVICEINFO DeviceInfo,
  2000. IN PMIXERDEVICE pmxd,
  2001. IN PMXLCONTROL pControl,
  2002. IN LPMIXERCONTROLDETAILS pmcd,
  2003. IN OUT LPMIXERCONTROLDETAILS_UNSIGNED paDetails,
  2004. IN ULONG Flags
  2005. )
  2006. {
  2007. NTSTATUS Status;
  2008. ULONG i, Index;
  2009. PAGED_CODE();
  2010. DPFASSERT( IsValidMixerDevice(pmxd) );
  2011. ASSERT( pControl );
  2012. ASSERT( pmcd );
  2013. ASSERT( paDetails );
  2014. //
  2015. // Query the current values for the mix levels.
  2016. //
  2017. Status = kmxlGetNodeProperty(
  2018. pmxd->pfo,
  2019. &KSPROPSETID_Audio,
  2020. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  2021. pControl->Id,
  2022. 0,
  2023. NULL,
  2024. pControl->Parameters.pMixLevels,
  2025. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  2026. );
  2027. if( !NT_SUCCESS( Status ) ) {
  2028. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed GET on MIX_LEVEL_TABLE with %x",
  2029. pControl->Control.dwControlID,
  2030. ControlTypeToString( pControl->Control.dwControlType ),
  2031. pControl->Id,
  2032. Status ));
  2033. DeviceInfo->mmr = MMSYSERR_ERROR;
  2034. return( STATUS_SUCCESS );
  2035. }
  2036. //
  2037. // Adjust the values on the diagonal to those the user specified.
  2038. //
  2039. for( i = 0; i < pmcd->cChannels; i++ ) {
  2040. Index = i * ( pControl->Parameters.pMixCaps->OutputChannels + 1 );
  2041. pControl->Parameters.pMixLevels[ Index ].Level = kmxlVolLinearToLog(
  2042. pControl,
  2043. paDetails[ i ].dwValue,
  2044. MIXER_MAPPING_LOGRITHMIC,
  2045. i
  2046. );
  2047. }
  2048. //
  2049. // Set these new values.
  2050. //
  2051. Status = kmxlSetNodeProperty(
  2052. pmxd->pfo,
  2053. &KSPROPSETID_Audio,
  2054. KSPROPERTY_AUDIO_MIX_LEVEL_TABLE,
  2055. pControl->Id,
  2056. 0,
  2057. NULL,
  2058. pControl->Parameters.pMixLevels,
  2059. pControl->Parameters.Size * sizeof( KSAUDIO_MIXLEVEL )
  2060. );
  2061. if( NT_SUCCESS( Status ) ) {
  2062. DeviceInfo->mmr = MMSYSERR_NOERROR;
  2063. } else {
  2064. DPF(DL_WARNING|FA_USER,( "kmxlHandleSetVolumeFromSuperMix( Ctrl=%d [%s], Id=%d ) failed SET on MIX_LEVEL_TABLE with %x",
  2065. pControl->Control.dwControlID,
  2066. ControlTypeToString( pControl->Control.dwControlType ),
  2067. pControl->Id,
  2068. Status ));
  2069. DeviceInfo->mmr = MMSYSERR_ERROR;
  2070. }
  2071. return( STATUS_SUCCESS );
  2072. }
  2073. #endif // SUPERMIX_AS_VOL
  2074. ///////////////////////////////////////////////////////////////////////
  2075. //
  2076. // kmxlNotifyLineChange
  2077. //
  2078. //
  2079. VOID
  2080. kmxlNotifyLineChange(
  2081. OUT LPDEVICEINFO DeviceInfo,
  2082. IN PMIXERDEVICE pmxd,
  2083. IN PMXLLINE pLine,
  2084. IN LPMIXERCONTROLDETAILS_UNSIGNED paDetails
  2085. )
  2086. {
  2087. PAGED_CODE();
  2088. ASSERT( (DeviceInfo->dwCallbackType&MIXER_LINE_CALLBACK) == 0 );
  2089. DeviceInfo->dwLineID=pLine->Line.dwLineID;
  2090. DeviceInfo->dwCallbackType|=MIXER_LINE_CALLBACK;
  2091. }
  2092. ///////////////////////////////////////////////////////////////////////
  2093. //
  2094. // kmxlNotifyControlChange
  2095. //
  2096. //
  2097. VOID
  2098. kmxlNotifyControlChange(
  2099. OUT LPDEVICEINFO DeviceInfo,
  2100. IN PMIXERDEVICE pmxd,
  2101. IN PMXLCONTROL pControl
  2102. )
  2103. {
  2104. WRITE_CONTEXT* pwc;
  2105. PAGED_CODE();
  2106. //
  2107. // If there are no open instances, there is no reason to even attempt
  2108. // a callback... no one is listening.
  2109. //
  2110. ExAcquireFastMutex( &ReferenceCountMutex );
  2111. if( ReferenceCount == 0 ) {
  2112. ExReleaseFastMutex( &ReferenceCountMutex );
  2113. return;
  2114. }
  2115. ExReleaseFastMutex( &ReferenceCountMutex );
  2116. {
  2117. PMXLLINE pLine;
  2118. PMXLCONTROL pCtrl;
  2119. LONG callbackcount;
  2120. callbackcount=0;
  2121. pLine = kmxlFirstInList( pmxd->listLines );
  2122. while( pLine ) {
  2123. pCtrl = kmxlFirstInList( pLine->Controls );
  2124. while( pCtrl ) {
  2125. if ( pCtrl->Id == pControl->Id ) {
  2126. //ASSERT( (DeviceInfo->dwCallbackType&MIXER_CONTROL_CALLBACK) == 0 );
  2127. ASSERT( callbackcount < MAXCALLBACKS );
  2128. if ( callbackcount < MAXCALLBACKS ) {
  2129. (DeviceInfo->dwID)[callbackcount++]=pCtrl->Control.dwControlID;
  2130. }
  2131. DeviceInfo->dwCallbackType|=MIXER_CONTROL_CALLBACK;
  2132. }
  2133. pCtrl = kmxlNextControl( pCtrl );
  2134. }
  2135. pLine = kmxlNextLine( pLine );
  2136. }
  2137. DeviceInfo->ControlCallbackCount=callbackcount;
  2138. }
  2139. }