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.

1142 lines
28 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: kmxlutil.c
  4. //
  5. // Description:
  6. // Utility routines used by the kernel mixer line driver (KMXL).
  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. #undef SUPER_DEBUG
  36. ///////////////////////////////////////////////////////////////////////
  37. ///////////////////////////////////////////////////////////////////////
  38. // //
  39. // U T I L I T Y F U N C T I O N S //
  40. // //
  41. ///////////////////////////////////////////////////////////////////////
  42. ///////////////////////////////////////////////////////////////////////
  43. ///////////////////////////////////////////////////////////////////////
  44. //
  45. // kmxlOpenSysAudio
  46. //
  47. // Opens the topology driver and dereferences the handle to get the
  48. // file object.
  49. //
  50. //
  51. PFILE_OBJECT
  52. kmxlOpenSysAudio(
  53. )
  54. {
  55. PFILE_OBJECT pfo = NULL;
  56. HANDLE hDevice = NULL;
  57. ULONG ulDefault;
  58. NTSTATUS Status;
  59. PAGED_CODE();
  60. //
  61. // Open the topology driver.
  62. //
  63. Status = OpenSysAudio(&hDevice, &pfo);
  64. if( !NT_SUCCESS( Status ) ) {
  65. DPF(DL_WARNING|FA_SYSAUDIO,("OpenSysAudio failed Status=%X",Status) );
  66. return( NULL );
  67. }
  68. //
  69. // The handle is no longer necessary so close it.
  70. //
  71. NtClose( hDevice );
  72. ulDefault = KSPROPERTY_SYSAUDIO_MIXER_DEFAULT;
  73. Status = SetSysAudioProperty(
  74. pfo,
  75. KSPROPERTY_SYSAUDIO_DEVICE_DEFAULT,
  76. sizeof(ulDefault),
  77. &ulDefault);
  78. if( !NT_SUCCESS( Status ) ) {
  79. DPF(DL_WARNING|FA_SYSAUDIO,("SetSysAudioProperty failed Status=%X",Status) );
  80. return( NULL );
  81. }
  82. return( pfo );
  83. }
  84. ///////////////////////////////////////////////////////////////////////
  85. //
  86. // kmxlCloseSysAudio
  87. //
  88. // Close the topology device by dereferencing the file object.
  89. //
  90. //
  91. VOID
  92. kmxlCloseSysAudio(
  93. IN PFILE_OBJECT pfo // Pointer to the file object to close
  94. )
  95. {
  96. PAGED_CODE();
  97. ObDereferenceObject( pfo );
  98. }
  99. ///////////////////////////////////////////////////////////////////////
  100. //
  101. // kmxlFindDestination
  102. //
  103. // In the list of destinations, it finds the destination matching
  104. // the given id.
  105. //
  106. //
  107. PMXLNODE
  108. kmxlFindDestination(
  109. IN NODELIST listDests, // The list of destinations to search
  110. IN ULONG Id // The node Id to look for in the list
  111. )
  112. {
  113. PMXLNODE pTemp = kmxlFirstInList( listDests );
  114. PAGED_CODE();
  115. while( pTemp ) {
  116. if( pTemp->Id == Id ) {
  117. return( pTemp );
  118. }
  119. pTemp = kmxlNextNode( pTemp );
  120. }
  121. return( NULL );
  122. }
  123. ///////////////////////////////////////////////////////////////////////
  124. //
  125. // kmxlAppendListToList
  126. //
  127. // Finds the end of the source list and makes the next element point
  128. // to the head of target list.
  129. //
  130. //
  131. VOID
  132. kmxlAppendListToList(
  133. IN OUT PSLIST* plistTarget, // The list to append to
  134. IN PSLIST listSource // the list to append
  135. )
  136. {
  137. PSLIST pTemp;
  138. PAGED_CODE();
  139. if( *plistTarget == NULL ) {
  140. *plistTarget = listSource;
  141. return;
  142. }
  143. //
  144. // If source is NULL, there's no need to append.
  145. //
  146. if( listSource == NULL ) {
  147. return;
  148. }
  149. //
  150. // First find the end of the source list. At this point,
  151. // listSource has at least 1 element.
  152. //
  153. pTemp = listSource;
  154. while( pTemp->Next ) {
  155. pTemp = pTemp->Next;
  156. }
  157. //
  158. // Attach the target list onto the end.
  159. //
  160. pTemp->Next = *plistTarget;
  161. *plistTarget = listSource;
  162. }
  163. ///////////////////////////////////////////////////////////////////////
  164. //
  165. // kmxlAppendListToEndOfList
  166. //
  167. // Finds the end of the target list and points the next to the source
  168. // list.
  169. //
  170. //
  171. VOID
  172. kmxlAppendListToEndOfList(
  173. IN OUT PSLIST* plistTarget, // The list to append to
  174. IN PSLIST listSource // the list to append
  175. )
  176. {
  177. PSLIST pTemp;
  178. PAGED_CODE();
  179. if( *plistTarget == NULL ) {
  180. *plistTarget = listSource;
  181. return;
  182. }
  183. //
  184. // Find the end of the target list. Target list must contain
  185. // at least one element at this point.
  186. //
  187. pTemp = *plistTarget;
  188. while( pTemp->Next ) {
  189. pTemp = pTemp->Next;
  190. }
  191. pTemp->Next = listSource;
  192. }
  193. ////////////////////////////////////////////////////////////////////////
  194. //
  195. // kmxlListCount
  196. //
  197. // Loops through the Next fields to count the elements.
  198. //
  199. //
  200. ULONG
  201. kmxlListCount(
  202. IN PSLIST pList // The list to count the elements of
  203. )
  204. {
  205. ULONG Count = 0;
  206. PSLIST pTemp = pList;
  207. PAGED_CODE();
  208. while( pTemp ) {
  209. ++Count;
  210. pTemp = pTemp->Next;
  211. }
  212. return( Count );
  213. }
  214. ///////////////////////////////////////////////////////////////////////
  215. //
  216. // kmxlInList
  217. //
  218. // Loops through the given list looking for pNewNode.
  219. //
  220. //
  221. BOOL
  222. kmxlInList(
  223. IN PEERLIST list, // The list to search
  224. IN PMXLNODE pNewNode // The new to search for
  225. )
  226. {
  227. PEERNODE* pTemp = kmxlFirstInList( list );
  228. PAGED_CODE();
  229. // Zing through the list checking to see if there is a node with
  230. // the same Id and Type. These two checks are suffient to ensure
  231. // uniquness. Ids are unique among all sources and destinations,
  232. // and Ids, or node numbers, are unique among all nodes. Note
  233. // that a source (or destination) node and a node can have the same
  234. // Id.
  235. while( pTemp ) {
  236. if( ( pTemp->pNode->Id == pNewNode->Id ) &&
  237. ( pTemp->pNode->Type == pNewNode->Type ) )
  238. return( TRUE );
  239. pTemp = kmxlNextPeerNode( pTemp );
  240. }
  241. // No match in the entire list, the new node is not already in the
  242. // list.
  243. return( FALSE );
  244. }
  245. ///////////////////////////////////////////////////////////////////////
  246. //
  247. // kmxlInChildList
  248. //
  249. // Calls kmxlInList on the child list of the node.
  250. //
  251. //
  252. BOOL
  253. kmxlInChildList(
  254. IN NODELIST list, // The list to search the parent list
  255. IN PMXLNODE pNewNode // The node to search for
  256. )
  257. {
  258. ASSERT( list ) ;
  259. ASSERT( pNewNode );
  260. PAGED_CODE();
  261. return( kmxlInList( list->Children, pNewNode ) );
  262. }
  263. ///////////////////////////////////////////////////////////////////////
  264. //
  265. // kmxlInParentList
  266. //
  267. // Calls kmxlInList on the parent list of the node.
  268. //
  269. //
  270. BOOL
  271. kmxlInParentList(
  272. IN NODELIST list, // The list to search the parent list
  273. IN PMXLNODE pNewNode // The node to search for
  274. )
  275. {
  276. ASSERT( list );
  277. ASSERT( pNewNode );
  278. PAGED_CODE();
  279. return( kmxlInList( list->Parents, pNewNode ) );
  280. }
  281. ///////////////////////////////////////////////////////////////////////
  282. //
  283. // kmxlFreePeerList
  284. //
  285. //
  286. // NOTES
  287. // This only frees the peer nodes in a peer list. The nodes pointed
  288. // to be the pNode member must be clean up in some other manner.
  289. //
  290. //
  291. VOID
  292. kmxlFreePeerList(
  293. IN PEERLIST list // The PeerList to free
  294. )
  295. {
  296. PEERNODE* pPeerNode = kmxlRemoveFirstPeerNode( list );
  297. PAGED_CODE();
  298. while( pPeerNode ) {
  299. AudioFreeMemory( sizeof(PEERNODE),&pPeerNode );
  300. pPeerNode = kmxlRemoveFirstPeerNode( list );
  301. }
  302. }
  303. ///////////////////////////////////////////////////////////////////////
  304. //
  305. // kmxlAllocateMixerControl
  306. //
  307. // Calls AudioAllocateMemory() to allocate and zero fill the MXLCONTROL.
  308. //
  309. //
  310. MXLCONTROL*
  311. kmxlAllocateControl(
  312. IN ULONG ultag
  313. )
  314. {
  315. MXLCONTROL* p = NULL;
  316. PAGED_CODE();
  317. if( NT_SUCCESS( AudioAllocateMemory_Paged(sizeof( MXLCONTROL ),
  318. ultag,
  319. ZERO_FILL_MEMORY,
  320. &p) ) )
  321. {
  322. #ifdef DEBUG
  323. p->Tag=CONTROL_TAG;
  324. #endif
  325. return( p );
  326. } else {
  327. return( NULL );
  328. }
  329. }
  330. ///////////////////////////////////////////////////////////////////////
  331. //
  332. // kmxlFreeControl
  333. //
  334. // Frees the memory associated with a control. It also checkes the
  335. // special cases for some controls that have special memory associated
  336. // with them. And, if the control supports change notifications, it gets
  337. // turned off here.
  338. //
  339. //
  340. VOID
  341. kmxlFreeControl(
  342. IN PMXLCONTROL pControl
  343. )
  344. {
  345. NTSTATUS Status;
  346. PAGED_CODE();
  347. DPFASSERT( IsValidControl( pControl ) );
  348. //
  349. // Need to disable change notifications on this node if it supported them!
  350. //
  351. kmxlDisableControlChangeNotifications(pControl);
  352. if( pControl->NodeType ) {
  353. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_MUX ) &&
  354. !pControl->Parameters.bHasCopy ) {
  355. AudioFreeMemory_Unknown( &pControl->Parameters.lpmcd_lt );
  356. AudioFreeMemory_Unknown( &pControl->Parameters.pPins );
  357. }
  358. if( IsEqualGUID( pControl->NodeType, &KSNODETYPE_SUPERMIX ) ) {
  359. if (InterlockedDecrement(pControl->Parameters.pReferenceCount)==0) {
  360. AudioFreeMemory_Unknown( &pControl->Parameters.pMixCaps );
  361. AudioFreeMemory_Unknown( &pControl->Parameters.pMixLevels );
  362. AudioFreeMemory( sizeof(LONG),&pControl->Parameters.pReferenceCount );
  363. }
  364. }
  365. }
  366. // Check that we're not in the case where Numchannels == 0 And we have a valid
  367. // pControl->pChannelStepping. If this were true, we'd end up leaking
  368. // pChannelStepping.
  369. ASSERT( !(pControl->pChannelStepping && pControl->NumChannels == 0) );
  370. if ( pControl->pChannelStepping && pControl->NumChannels > 0 ) {
  371. RtlZeroMemory( pControl->pChannelStepping, pControl->NumChannels * sizeof( CHANNEL_STEPPING ) );
  372. AudioFreeMemory_Unknown( &pControl->pChannelStepping );
  373. }
  374. //
  375. // Why do we zero the memory on this free?
  376. //
  377. RtlZeroMemory( pControl, sizeof( MXLCONTROL ) );
  378. AudioFreeMemory( sizeof( MXLCONTROL ),&pControl );
  379. }
  380. ///////////////////////////////////////////////////////////////////////
  381. //
  382. // kmxlAllocateLine
  383. //
  384. // Calls AudioAllocateMemory() to allocate and zero fill the MXLLINE.
  385. //
  386. //
  387. //
  388. // Workitem: Tag all these structures in debug!
  389. //
  390. MXLLINE*
  391. kmxlAllocateLine(
  392. IN ULONG ultag
  393. )
  394. {
  395. MXLLINE* p = NULL;
  396. PAGED_CODE();
  397. if( NT_SUCCESS( AudioAllocateMemory_Paged( sizeof( MXLLINE ),
  398. ultag,
  399. ZERO_FILL_MEMORY,
  400. &p ) ) )
  401. {
  402. p->SourceId = INVALID_ID;
  403. p->DestId = INVALID_ID;
  404. return( p );
  405. } else {
  406. return( NULL );
  407. }
  408. }
  409. ///////////////////////////////////////////////////////////////////////
  410. //
  411. // kmxlAllocateNode
  412. //
  413. // Calls AudioAllocateMemory() to allocate and zero fill the MXLNODE.
  414. //
  415. //
  416. MXLNODE*
  417. kmxlAllocateNode(
  418. IN ULONG ultag
  419. )
  420. {
  421. MXLNODE* p = NULL;
  422. PAGED_CODE();
  423. if( NT_SUCCESS( AudioAllocateMemory_Paged( sizeof( MXLNODE ),
  424. ultag,
  425. ZERO_FILL_MEMORY,
  426. &p ) ) )
  427. {
  428. return( p );
  429. } else {
  430. return( NULL );
  431. }
  432. }
  433. ///////////////////////////////////////////////////////////////////////
  434. //
  435. // kmxlAllocatePeerNode
  436. //
  437. // Calls AudioAllocateMemory() to allocate and zero fill the PEERNODE.
  438. //
  439. //
  440. PEERNODE*
  441. kmxlAllocatePeerNode(
  442. IN PMXLNODE pNode OPTIONAL, // The node to associate with the peer
  443. IN ULONG ultag
  444. )
  445. {
  446. PEERNODE* p = NULL;
  447. PAGED_CODE();
  448. if( NT_SUCCESS( AudioAllocateMemory_Paged( sizeof( PEERNODE ),
  449. ultag,
  450. ZERO_FILL_MEMORY,
  451. &p ) ) )
  452. {
  453. p->pNode = pNode;
  454. return( p );
  455. } else {
  456. return( NULL );
  457. }
  458. }
  459. ///////////////////////////////////////////////////////////////////////
  460. //
  461. // kmxlAddToEndOfList
  462. //
  463. // Finds the end of the list and sets the next field to the new element.
  464. //
  465. //
  466. VOID
  467. kmxlAddElemToEndOfList(
  468. IN OUT PSLIST* list, // The list to add to the end of
  469. IN PSLIST elem // The element or list to add
  470. )
  471. {
  472. PSLIST pTemp;
  473. PAGED_CODE();
  474. ASSERT( list );
  475. ASSERT( elem->Next == NULL );
  476. //
  477. // If the list doesn't have anything in it, the element becomes the
  478. // list.
  479. //
  480. if( *list == NULL ) {
  481. *list = elem;
  482. return;
  483. }
  484. //
  485. // Find the end of the list.
  486. //
  487. pTemp = *list;
  488. while( pTemp->Next ) {
  489. pTemp = pTemp->Next;
  490. }
  491. //
  492. // And attach the element to it.
  493. //
  494. pTemp->Next = elem;
  495. }
  496. #define LINEAR_RANGE 0xFFFF // 64k
  497. #define DFLINEAR_RANGE ( 96.0 * 65535.0 )
  498. #define NEG_INF_DB 0x80000000 // -32767 * 64k dB
  499. ///////////////////////////////////////////////////////////////////////
  500. //
  501. // kmxlVolLogToLinear
  502. //
  503. // Converts from the hardware range (dB) to the liner mixer line range (0-64k).
  504. //
  505. //
  506. DWORD
  507. kmxlVolLogToLinear(
  508. IN PMXLCONTROL pControl,
  509. IN LONG Value,
  510. IN MIXERMAPPING Mapping,
  511. IN ULONG Channel
  512. )
  513. {
  514. KFLOATING_SAVE FloatSave;
  515. double LinearRange;
  516. double dfValue;
  517. double dfResult;
  518. double dfRatio;
  519. DWORD Result;
  520. PCHANNEL_STEPPING pChannelStepping;
  521. PAGED_CODE();
  522. if( Value == NEG_INF_DB ) {
  523. return( 0 );
  524. }
  525. ASSERT( Channel < pControl->NumChannels );
  526. // Get the proper range for the specified channel
  527. pChannelStepping = &pControl->pChannelStepping[Channel];
  528. if( NT_SUCCESS( KeSaveFloatingPointState( &FloatSave ) ) ) {
  529. LinearRange = (double) LINEAR_RANGE;
  530. dfValue = (double) Value;
  531. switch( Mapping ) {
  532. ////////////////////////////////////////////////////////////
  533. case MIXER_MAPPING_LOGRITHMIC:
  534. ////////////////////////////////////////////////////////////
  535. dfRatio = ( (double) pChannelStepping->MaxValue -
  536. (double) pChannelStepping->MinValue ) / DFLINEAR_RANGE;
  537. if( dfRatio < 1.0 ) {
  538. dfRatio = 1.0;
  539. }
  540. dfValue = ( dfValue - pChannelStepping->MaxValue ) / LinearRange;
  541. dfResult = LinearRange * pow( 10.0, dfValue / ( 20.0 * dfRatio ) );
  542. if( dfResult >= LINEAR_RANGE ) {
  543. Result = LINEAR_RANGE;
  544. } else if ( dfResult < 0.0 ) {
  545. Result = 0;
  546. } else {
  547. Result = (DWORD) ( dfResult + 0.5 );
  548. }
  549. break;
  550. ////////////////////////////////////////////////////////////
  551. case MIXER_MAPPING_LINEAR:
  552. ////////////////////////////////////////////////////////////
  553. dfResult = ( LinearRange * ( dfValue - pChannelStepping->MinValue ) ) /
  554. ( pChannelStepping->MaxValue - pChannelStepping->MinValue );
  555. Result = (DWORD) ( dfResult + 0.5 );
  556. break;
  557. ////////////////////////////////////////////////////////////
  558. default:
  559. ////////////////////////////////////////////////////////////
  560. ASSERT( 0 );
  561. Result = 0;
  562. }
  563. KeRestoreFloatingPointState( &FloatSave );
  564. DPF(DL_TRACE|FA_MIXER,
  565. ( "kmxlVolLogToLinear( %x [%d] ) =%d= %x [%d]",
  566. Value,
  567. Value,
  568. Mapping,
  569. (WORD) Result,
  570. (WORD) Result
  571. ) );
  572. return( Result );
  573. } else {
  574. return( (DWORD) ( LINEAR_RANGE *
  575. ( (LONGLONG) Value - (LONGLONG) pChannelStepping->MinValue ) /
  576. ( (LONGLONG) pChannelStepping->MaxValue -
  577. (LONGLONG) pChannelStepping->MinValue ) ) );
  578. }
  579. #ifdef LEGACY_SCALE
  580. WORD Result;
  581. Result = VolLogToLinear( (WORD) ( Value / ( -1 * LINEAR_RANGE ) ) );
  582. #ifdef API_TRACE
  583. TRACE( "WDMAUD: kmxlVolLogToLinear( %x [%d] ) = %x [%d]\n",
  584. Value,
  585. Value,
  586. (WORD) Result,
  587. (WORD) Result
  588. );
  589. #endif
  590. return( Result );
  591. #endif // LEGACY_SCALE
  592. #ifdef LONG_CALC_SCALE
  593. LONGLONG ControlRange = (LONGLONG) pChannelStepping->MaxValue -
  594. (LONGLONG) pChannelStepping->MinValue;
  595. LONGLONG MinValue = (LONGLONG) pChannelStepping->MinValue;
  596. LONGLONG Result;
  597. ASSERT( ControlRange );
  598. Result = LINEAR_RANGE * ( (LONGLONG) Value - MinValue ) / ControlRange;
  599. #ifdef API_TRACE
  600. TRACE( "WDMAUD: kmxlVolLogToLinear( %x [%d] ) = %x [%d]\n",
  601. Value,
  602. Value,
  603. (WORD) Result,
  604. (WORD) Result
  605. );
  606. #endif
  607. return( (WORD) Result );
  608. #endif // LONG_CALC_SCALE
  609. }
  610. ///////////////////////////////////////////////////////////////////////
  611. //
  612. // kmxlVolLinearToLog
  613. //
  614. // Converts from the mixer line range (0-64k) to the hardware range (dB).
  615. //
  616. //
  617. LONG
  618. kmxlVolLinearToLog(
  619. IN PMXLCONTROL pControl,
  620. IN DWORD Value,
  621. IN MIXERMAPPING Mapping,
  622. IN ULONG Channel
  623. )
  624. {
  625. KFLOATING_SAVE FloatSave;
  626. double LinearRange;
  627. double dfValue;
  628. double dfResult;
  629. double dfRatio;
  630. LONG Result;
  631. PCHANNEL_STEPPING pChannelStepping;
  632. PAGED_CODE();
  633. if( Value == 0 ) {
  634. return( NEG_INF_DB );
  635. }
  636. ASSERT( Channel < pControl->NumChannels );
  637. // Get the proper range for the specified channel
  638. pChannelStepping = &pControl->pChannelStepping[Channel];
  639. if( NT_SUCCESS( KeSaveFloatingPointState( &FloatSave ) ) ) {
  640. LinearRange = (double) LINEAR_RANGE;
  641. dfValue = (double) Value;
  642. switch( Mapping ) {
  643. ////////////////////////////////////////////////////////////
  644. case MIXER_MAPPING_LOGRITHMIC:
  645. ////////////////////////////////////////////////////////////
  646. dfRatio = ( (double) pChannelStepping->MaxValue -
  647. (double) pChannelStepping->MinValue ) / DFLINEAR_RANGE;
  648. if( dfRatio < 1.0 ) {
  649. dfRatio = 1.0;
  650. }
  651. dfResult = LinearRange * dfRatio * 20.0 * log10( dfValue / LinearRange );
  652. if( dfResult < 0.0 ) {
  653. Result = (LONG) ( dfResult - 0.5 ) + pChannelStepping->MaxValue;
  654. } else {
  655. Result = (LONG) ( dfResult + 0.5 ) + pChannelStepping->MaxValue;
  656. }
  657. break;
  658. ////////////////////////////////////////////////////////////
  659. case MIXER_MAPPING_LINEAR:
  660. ////////////////////////////////////////////////////////////
  661. dfResult = ( dfValue * ( pChannelStepping->MaxValue - pChannelStepping->MinValue ) ) /
  662. LinearRange + pChannelStepping->MinValue;
  663. if( dfResult < 0.0 ) {
  664. Result = (LONG) ( dfResult - 0.5 );
  665. } else {
  666. Result = (LONG) ( dfResult + 0.5 );
  667. }
  668. break;
  669. ////////////////////////////////////////////////////////////
  670. default:
  671. ////////////////////////////////////////////////////////////
  672. ASSERT( 0 );
  673. Result = NEG_INF_DB;
  674. }
  675. KeRestoreFloatingPointState( &FloatSave );
  676. DPF(DL_TRACE|FA_MIXER,
  677. ( "kmxlVolLinearToLog( %x [%d]) =%d= %x [%d]",
  678. Value,
  679. Value,
  680. Mapping,
  681. (LONG) Result,
  682. (LONG) Result
  683. ) );
  684. return( Result );
  685. } else {
  686. return( (LONG)
  687. ( (LONGLONG) Value *
  688. (LONGLONG) ( pChannelStepping->MaxValue - pChannelStepping->MinValue )
  689. / ( LONGLONG ) LINEAR_RANGE + (LONGLONG) pChannelStepping->MinValue )
  690. );
  691. }
  692. #ifdef LEGACY_SCALE
  693. LONG Result;
  694. if( Value == 0 ) {
  695. Result = NEG_INF_DB;
  696. } else {
  697. Result = (LONG) VolLinearToLog( Value ) * -1 * (LONG) LINEAR_RANGE + pChannelStepping->MaxValue;
  698. }
  699. #ifdef API_TRACE
  700. TRACE( "WDMAUD: kmxlVolLinearToLog( %x [%d]) = %x [%d]\n",
  701. Value,
  702. Value,
  703. (LONG) Result,
  704. (LONG) Result
  705. );
  706. #endif
  707. return( Result );
  708. #endif // LEGACY_SCALE
  709. #ifdef LONG_CALC_SCALE
  710. LONGLONG ControlRange = (LONGLONG) pChannelStepping->MaxValue -
  711. (LONGLONG) pChannelStepping->MinValue;
  712. LONGLONG MinValue = pChannelStepping->MinValue;
  713. LONGLONG Result;
  714. ASSERT( ControlRange );
  715. Result = (LONGLONG) Value * ControlRange / LINEAR_RANGE + MinValue;
  716. #ifdef API_TRACE
  717. TRACE( "WDMAUD: kmxlVolLinearToLog( %x [%d]) = %x [%d]\n",
  718. Value,
  719. Value,
  720. (LONG) Result,
  721. (LONG) Result
  722. );
  723. #endif
  724. return( (LONG) Result );
  725. #endif // LONG_CALC_SCALE
  726. }
  727. ///////////////////////////////////////////////////////////////////////
  728. //
  729. // kmxlSortByDestination
  730. //
  731. // Performs a sort by destination in numerical increasing order.
  732. //
  733. //
  734. NTSTATUS
  735. kmxlSortByDestination(
  736. IN LINELIST* list // The pointer to the list to sort
  737. )
  738. {
  739. PMXLLINE pTemp1,
  740. pTemp2;
  741. MXLLINE Temp;
  742. ULONG Count = kmxlListLength( *list );
  743. PAGED_CODE();
  744. //
  745. // If there are only 0 or 1 elements, there's no reason to even try to
  746. // sort.
  747. //
  748. if( Count < 2 ) {
  749. return( STATUS_SUCCESS );
  750. }
  751. //
  752. // Pretty standard BubbleSort.
  753. //
  754. while( --Count ) {
  755. //
  756. // Loop over each element in the list.
  757. //
  758. pTemp1 = kmxlFirstInList( *list );
  759. while( pTemp1 ) {
  760. //
  761. // Loop over the remaining elements.
  762. //
  763. pTemp2 = kmxlNextLine( pTemp1 );
  764. while( pTemp2 ) {
  765. //
  766. // The destination is strictly bigger. Swap 'em.
  767. //
  768. if( pTemp1->DestId > pTemp2->DestId ) {
  769. SwapEm( pTemp1, pTemp2, &Temp, sizeof( MXLLINE ) );
  770. break;
  771. }
  772. //
  773. // The destinations are the same, but the source is
  774. // bigger. Swap 'em.
  775. //
  776. if( pTemp1->DestId == pTemp2->DestId ) {
  777. if( pTemp1->SourceId > pTemp2->SourceId ) {
  778. SwapEm( pTemp1, pTemp2, &Temp, sizeof( MXLLINE ) );
  779. break;
  780. }
  781. }
  782. pTemp2 = kmxlNextLine( pTemp2 );
  783. }
  784. pTemp1 = kmxlNextLine( pTemp1 );
  785. }
  786. }
  787. return( STATUS_SUCCESS );
  788. }
  789. ///////////////////////////////////////////////////////////////////////
  790. ///////////////////////////////////////////////////////////////////////
  791. // //
  792. // M I X E R L I N E W R A P P E R S //
  793. // //
  794. ///////////////////////////////////////////////////////////////////////
  795. ///////////////////////////////////////////////////////////////////////
  796. #pragma warning( disable : 4273 )
  797. ///////////////////////////////////////////////////////////////////////
  798. //
  799. // kmxlAllocDeviceInfo
  800. //
  801. // Note: when allocating DeviceInfo structure, we know that the structure's
  802. // definition includes one character for the DeviceInterface, so we only need
  803. // to allocate additional length for the string but not its NULL terminator
  804. //
  805. ///////////////////////////////////////////////////////////////////////
  806. NTSTATUS kmxlAllocDeviceInfo(
  807. LPDEVICEINFO *ppDeviceInfo,
  808. PCWSTR DeviceInterface,
  809. DWORD dwFlags,
  810. ULONG ultag
  811. )
  812. {
  813. NTSTATUS Status;
  814. PAGED_CODE();
  815. Status = AudioAllocateMemory_Paged(sizeof(**ppDeviceInfo)+(wcslen(DeviceInterface)*sizeof(WCHAR)),
  816. ultag,
  817. ZERO_FILL_MEMORY,
  818. ppDeviceInfo);
  819. if (NT_SUCCESS(Status))
  820. {
  821. wcscpy((*ppDeviceInfo)->wstrDeviceInterface, DeviceInterface);
  822. (*ppDeviceInfo)->DeviceType = MixerDevice;
  823. (*ppDeviceInfo)->dwFormat = UNICODE_TAG;
  824. (*ppDeviceInfo)->dwFlags = dwFlags;
  825. } else {
  826. *ppDeviceInfo = NULL;
  827. }
  828. return Status;
  829. }
  830. ///////////////////////////////////////////////////////////////////////
  831. //
  832. // mixerGetControlDetails
  833. //
  834. //
  835. MMRESULT
  836. WINAPI
  837. kmxlGetControlDetails(
  838. PWDMACONTEXT pWdmaContext,
  839. PCWSTR DeviceInterface,
  840. LPMIXERCONTROLDETAILS pmxcd,
  841. DWORD fdwDetails
  842. )
  843. {
  844. LPDEVICEINFO DeviceInfo = NULL;
  845. NTSTATUS Status;
  846. MMRESULT mmr;
  847. PAGED_CODE();
  848. if (!NT_SUCCESS(kmxlAllocDeviceInfo(&DeviceInfo, DeviceInterface, fdwDetails,TAG_AudD_DEVICEINFO))) {
  849. return MMSYSERR_NOMEM;
  850. }
  851. Status = kmxlGetControlDetailsHandler( pWdmaContext, DeviceInfo, pmxcd, pmxcd->paDetails );
  852. mmr = DeviceInfo->mmr;
  853. AudioFreeMemory_Unknown( &DeviceInfo);
  854. return mmr;
  855. }
  856. ///////////////////////////////////////////////////////////////////////
  857. //
  858. // mixerGetLineControls
  859. //
  860. //
  861. MMRESULT
  862. WINAPI
  863. kmxlGetLineControls(
  864. PWDMACONTEXT pWdmaContext,
  865. PCWSTR DeviceInterface,
  866. LPMIXERLINECONTROLS pmxlc,
  867. DWORD fdwControls
  868. )
  869. {
  870. LPDEVICEINFO DeviceInfo = NULL;
  871. NTSTATUS Status;
  872. MMRESULT mmr;
  873. PAGED_CODE();
  874. if (!NT_SUCCESS(kmxlAllocDeviceInfo(&DeviceInfo, DeviceInterface, fdwControls,TAG_AudD_DEVICEINFO))) {
  875. return MMSYSERR_NOMEM;
  876. }
  877. Status = kmxlGetLineControlsHandler( pWdmaContext, DeviceInfo, pmxlc, pmxlc->pamxctrl );
  878. mmr = DeviceInfo->mmr;
  879. AudioFreeMemory_Unknown(&DeviceInfo);
  880. return mmr;
  881. }
  882. ///////////////////////////////////////////////////////////////////////
  883. //
  884. // mixerGetLineInfo
  885. //
  886. //
  887. MMRESULT
  888. WINAPI
  889. kmxlGetLineInfo(
  890. PWDMACONTEXT pWdmaContext,
  891. PCWSTR DeviceInterface,
  892. LPMIXERLINE pmxl,
  893. DWORD fdwInfo
  894. )
  895. {
  896. LPDEVICEINFO DeviceInfo = NULL;
  897. NTSTATUS Status;
  898. MMRESULT mmr;
  899. PAGED_CODE();
  900. if (!NT_SUCCESS(kmxlAllocDeviceInfo(&DeviceInfo, DeviceInterface, fdwInfo, TAG_AudD_DEVICEINFO))) {
  901. return MMSYSERR_NOMEM;
  902. }
  903. Status = kmxlGetLineInfoHandler( pWdmaContext, DeviceInfo, pmxl );
  904. mmr = DeviceInfo->mmr;
  905. AudioFreeMemory_Unknown(&DeviceInfo);
  906. return mmr;
  907. }
  908. ///////////////////////////////////////////////////////////////////////
  909. //
  910. // mixerSetControlDetails
  911. //
  912. //
  913. MMRESULT
  914. WINAPI
  915. kmxlSetControlDetails(
  916. PWDMACONTEXT pWdmaContext,
  917. PCWSTR DeviceInterface,
  918. LPMIXERCONTROLDETAILS pmxcd,
  919. DWORD fdwDetails
  920. )
  921. {
  922. LPDEVICEINFO DeviceInfo = NULL;
  923. NTSTATUS Status;
  924. MMRESULT mmr;
  925. PAGED_CODE();
  926. if (!NT_SUCCESS(kmxlAllocDeviceInfo(&DeviceInfo, DeviceInterface, fdwDetails, TAG_AudD_DEVICEINFO))) {
  927. return MMSYSERR_NOMEM;
  928. }
  929. Status =
  930. kmxlSetControlDetailsHandler( pWdmaContext,
  931. DeviceInfo,
  932. pmxcd,
  933. pmxcd->paDetails,
  934. MIXER_FLAG_PERSIST
  935. );
  936. mmr = DeviceInfo->mmr;
  937. AudioFreeMemory_Unknown(&DeviceInfo);
  938. return mmr;
  939. }