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.

1601 lines
48 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Module: persist.c
  4. //
  5. // Description:
  6. //
  7. // Contains the routines that persist the mixer line driver settings.
  8. //
  9. //
  10. //@@BEGIN_MSINTERNAL
  11. // Development Team:
  12. // D. Baumberger
  13. //
  14. // History: Date Author Comment
  15. //
  16. //@@END_MSINTERNAL
  17. //
  18. //---------------------------------------------------------------------------
  19. //
  20. // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
  21. // KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  22. // IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
  23. // PURPOSE.
  24. //
  25. // Copyright (C) Microsoft Corporation, 1997 - 1999 All Rights Reserved.
  26. //
  27. //---------------------------------------------------------------------------
  28. #include "WDMSYS.H"
  29. #include "kmxluser.h"
  30. ///////////////////////////////////////////////////////////////////////
  31. //
  32. // kmxlGetInterfaceName
  33. //
  34. //
  35. NTSTATUS
  36. kmxlGetInterfaceName(
  37. IN PFILE_OBJECT pfo,
  38. IN ULONG Device,
  39. OUT PWCHAR* pszInterfaceName
  40. )
  41. {
  42. NTSTATUS Status = STATUS_SUCCESS;
  43. ULONG Size;
  44. WCHAR* szInterfaceName = NULL;
  45. PAGED_CODE();
  46. ASSERT( pfo );
  47. //
  48. // Retrieve the size of the internface name.
  49. //
  50. Status = GetSysAudioProperty(
  51. pfo,
  52. KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME,
  53. Device,
  54. sizeof( Size ),
  55. &Size
  56. );
  57. if( !NT_SUCCESS( Status ) ) {
  58. DPF(DL_WARNING|FA_PERSIST,("GetSysAudioProperty failed Status=%X",Status) );
  59. goto exit;
  60. }
  61. //
  62. // Allocate enough memory to hold the interface name
  63. //
  64. Status = AudioAllocateMemory_Paged(Size,
  65. TAG_Audp_NAME,
  66. ZERO_FILL_MEMORY | LIMIT_MEMORY,
  67. &szInterfaceName );
  68. if( !NT_SUCCESS( Status ) ) {
  69. goto exit;
  70. }
  71. ASSERT( szInterfaceName );
  72. //
  73. // Retieve the interface name for this device.
  74. //
  75. Status = GetSysAudioProperty(
  76. pfo,
  77. KSPROPERTY_SYSAUDIO_DEVICE_INTERFACE_NAME,
  78. Device,
  79. Size,
  80. szInterfaceName
  81. );
  82. if( !NT_SUCCESS( Status ) ) {
  83. DPF(DL_WARNING|FA_PERSIST,("GetSysAudioProperty failed Status=%X",Status) );
  84. goto exit;
  85. }
  86. exit:
  87. if( !NT_SUCCESS( Status ) ) {
  88. AudioFreeMemory_Unknown( &szInterfaceName );
  89. } else {
  90. *pszInterfaceName = szInterfaceName;
  91. }
  92. RETURN( Status );
  93. }
  94. ///////////////////////////////////////////////////////////////////////
  95. //
  96. // kmxlOpenInterfaceKey
  97. //
  98. //
  99. NTSTATUS
  100. kmxlOpenInterfaceKey(
  101. IN PFILE_OBJECT pfo,
  102. IN ULONG Device,
  103. OUT HANDLE* phKey
  104. )
  105. {
  106. NTSTATUS Status;
  107. HANDLE hKey;
  108. WCHAR* szName;
  109. UNICODE_STRING ustr;
  110. PAGED_CODE();
  111. Status = kmxlGetInterfaceName( pfo, Device, &szName );
  112. if( !NT_SUCCESS( Status ) ) {
  113. DPF(DL_WARNING|FA_PERSIST,("kmxlGetInterfaceName failed Status=%X",Status) );
  114. RETURN( Status );
  115. }
  116. RtlInitUnicodeString( &ustr, szName );
  117. Status = IoOpenDeviceInterfaceRegistryKey(
  118. &ustr,
  119. KEY_ALL_ACCESS,
  120. &hKey
  121. );
  122. if( !NT_SUCCESS( Status ) ) {
  123. AudioFreeMemory_Unknown( &szName );
  124. RETURN( Status );
  125. }
  126. *phKey = hKey;
  127. AudioFreeMemory_Unknown( &szName );
  128. return( STATUS_SUCCESS );
  129. }
  130. ///////////////////////////////////////////////////////////////////////
  131. //
  132. // kmxlRegCreateKey
  133. //
  134. //
  135. NTSTATUS
  136. kmxlRegCreateKey(
  137. IN HANDLE hRootKey,
  138. IN PWCHAR szKeyName,
  139. OUT PHANDLE phKey
  140. )
  141. {
  142. OBJECT_ATTRIBUTES ObjectAttributes;
  143. UNICODE_STRING ustr;
  144. ULONG Disposition;
  145. PAGED_CODE();
  146. RtlInitUnicodeString( &ustr, szKeyName );
  147. InitializeObjectAttributes(
  148. &ObjectAttributes,
  149. &ustr,
  150. OBJ_KERNEL_HANDLE, // Attributes
  151. hRootKey,
  152. NULL // Security
  153. );
  154. return( ZwCreateKey(
  155. phKey,
  156. KEY_ALL_ACCESS,
  157. &ObjectAttributes,
  158. 0, // TitleIndex
  159. NULL, // Class
  160. REG_OPTION_NON_VOLATILE,
  161. &Disposition
  162. )
  163. );
  164. }
  165. ///////////////////////////////////////////////////////////////////////
  166. //
  167. // kmxlRegOpenKey
  168. //
  169. //
  170. NTSTATUS
  171. kmxlRegOpenKey(
  172. IN HANDLE hRootKey,
  173. IN PWCHAR szKeyName,
  174. OUT PHANDLE phKey
  175. )
  176. {
  177. OBJECT_ATTRIBUTES ObjectAttributes;
  178. UNICODE_STRING ustr;
  179. PAGED_CODE();
  180. RtlInitUnicodeString( &ustr, szKeyName );
  181. InitializeObjectAttributes(
  182. &ObjectAttributes,
  183. &ustr,
  184. OBJ_KERNEL_HANDLE,
  185. hRootKey,
  186. NULL
  187. );
  188. return( ZwOpenKey(
  189. phKey,
  190. KEY_ALL_ACCESS,
  191. &ObjectAttributes
  192. )
  193. );
  194. }
  195. ///////////////////////////////////////////////////////////////////////
  196. //
  197. // kmxlRegSetValue
  198. //
  199. //
  200. NTSTATUS
  201. kmxlRegSetValue(
  202. IN HANDLE hKey,
  203. IN PWCHAR szValueName,
  204. IN ULONG Type,
  205. IN PVOID pData,
  206. IN ULONG cbData
  207. )
  208. {
  209. UNICODE_STRING ustr;
  210. PAGED_CODE();
  211. RtlInitUnicodeString( &ustr, szValueName );
  212. return( ZwSetValueKey(
  213. hKey,
  214. &ustr,
  215. 0,
  216. Type,
  217. pData,
  218. cbData
  219. )
  220. );
  221. }
  222. ///////////////////////////////////////////////////////////////////////
  223. //
  224. // kmxlRegQueryValue
  225. //
  226. //
  227. NTSTATUS
  228. kmxlRegQueryValue(
  229. IN HANDLE hKey,
  230. IN PWCHAR szValueName,
  231. IN PVOID pData,
  232. IN ULONG cbData,
  233. OUT PULONG pResultLength
  234. )
  235. {
  236. NTSTATUS Status;
  237. UNICODE_STRING ustr;
  238. KEY_VALUE_FULL_INFORMATION FullInfoHeader;
  239. PKEY_VALUE_FULL_INFORMATION FullInfoBuffer = NULL;
  240. PAGED_CODE();
  241. RtlInitUnicodeString( &ustr, szValueName );
  242. Status = ZwQueryValueKey(
  243. hKey,
  244. &ustr,
  245. KeyValueFullInformation,
  246. &FullInfoHeader,
  247. sizeof( FullInfoHeader ),
  248. pResultLength
  249. );
  250. if( !NT_SUCCESS( Status ) ) {
  251. if( Status == STATUS_BUFFER_OVERFLOW ) {
  252. if( !NT_SUCCESS( AudioAllocateMemory_Paged(*pResultLength,
  253. TAG_AudA_PROPERTY,
  254. ZERO_FILL_MEMORY,
  255. &FullInfoBuffer ) ) )
  256. {
  257. RETURN( STATUS_INSUFFICIENT_RESOURCES );
  258. }
  259. Status = ZwQueryValueKey(
  260. hKey,
  261. &ustr,
  262. KeyValueFullInformation,
  263. FullInfoBuffer,
  264. *pResultLength,
  265. pResultLength
  266. );
  267. if( NT_SUCCESS( Status ) ) {
  268. RtlCopyMemory(
  269. pData,
  270. (PUCHAR) FullInfoBuffer + FullInfoBuffer->DataOffset,
  271. cbData
  272. );
  273. }
  274. AudioFreeMemory_Unknown( &FullInfoBuffer );
  275. }
  276. }
  277. DPFRETURN( Status,(2,Status,STATUS_OBJECT_NAME_NOT_FOUND) );
  278. }
  279. ///////////////////////////////////////////////////////////////////////
  280. //
  281. // kmxlRegOpenMixerKey
  282. //
  283. //
  284. NTSTATUS
  285. kmxlRegOpenMixerKey(
  286. IN PFILE_OBJECT pfo,
  287. IN PMIXERDEVICE pmxd,
  288. OUT PHANDLE phMixerKey
  289. )
  290. {
  291. NTSTATUS Status;
  292. HANDLE hKey;
  293. PAGED_CODE();
  294. Status = kmxlOpenInterfaceKey( pfo, pmxd->Device, &hKey );
  295. if( !NT_SUCCESS( Status ) ) {
  296. RETURN( Status );
  297. }
  298. Status = kmxlRegOpenKey( hKey, MIXER_KEY_NAME, phMixerKey );
  299. if( NT_SUCCESS( Status ) ) {
  300. kmxlRegCloseKey( hKey );
  301. }
  302. RETURN( Status );
  303. }
  304. ///////////////////////////////////////////////////////////////////////
  305. //
  306. // kmxlFindDestById
  307. //
  308. //
  309. PMXLLINE
  310. kmxlFindDestById(
  311. IN LINELIST listLines,
  312. IN ULONG LineId
  313. )
  314. {
  315. PMXLLINE pLine;
  316. PAGED_CODE();
  317. pLine = kmxlFirstInList( listLines );
  318. while( pLine ) {
  319. if( pLine->Line.dwLineID == LineId ) {
  320. return( pLine );
  321. }
  322. pLine = kmxlNextLine( pLine );
  323. }
  324. return( NULL );
  325. }
  326. extern instancereleasedcount;
  327. ///////////////////////////////////////////////////////////////////////
  328. //
  329. //
  330. //
  331. NTSTATUS
  332. kmxlGetCurrentControlValue(
  333. IN PFILE_OBJECT pfo, // The instance to persist for
  334. IN PMIXERDEVICE pmxd,
  335. IN PMXLLINE pLine,
  336. IN PMXLCONTROL pControl, // The control to retrieve
  337. OUT PVOID* ppaDetails
  338. )
  339. {
  340. NTSTATUS Status;
  341. LPDEVICEINFO pDevInfo = NULL;
  342. MIXERCONTROLDETAILS mcd;
  343. PMIXERCONTROLDETAILS_UNSIGNED paDetails = NULL;
  344. ULONG Index;
  345. ULONG Devices;
  346. PAGED_CODE();
  347. *ppaDetails = NULL;
  348. //
  349. // Initialize a Device Info structure to make the query look like
  350. // it comes from user mode.
  351. //
  352. Status = kmxlAllocDeviceInfo(&pDevInfo, pmxd->DeviceInterface, MIXER_GETCONTROLDETAILSF_VALUE, TAG_AudD_DEVICEINFO );
  353. if (!NT_SUCCESS(Status)) {
  354. RETURN( Status );
  355. }
  356. for( Devices = 0, Index = 0; Devices < MAXNUMDEVS; Devices++ ) {
  357. if( pmxd == &pmxd->pWdmaContext->MixerDevs[ Devices ] ) {
  358. pDevInfo->DeviceNumber = Index;
  359. break;
  360. }
  361. if ( !MyWcsicmp(pmxd->DeviceInterface, pmxd->pWdmaContext->MixerDevs[ Devices ].DeviceInterface) ) {
  362. Index++;
  363. }
  364. }
  365. //
  366. // Create an MIXERCONTROLDETAILS structure for this query.
  367. //
  368. RtlZeroMemory( &mcd, sizeof( MIXERCONTROLDETAILS ) );
  369. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  370. mcd.dwControlID = pControl->Control.dwControlID;
  371. mcd.cMultipleItems = pControl->Control.cMultipleItems;
  372. mcd.cChannels = pControl->NumChannels;
  373. if( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ) {
  374. Status = AudioAllocateMemory_Paged(mcd.cMultipleItems * sizeof( MIXERCONTROLDETAILS_UNSIGNED ),
  375. TAG_Audd_DETAILS,
  376. ZERO_FILL_MEMORY,
  377. &paDetails );
  378. mcd.cbDetails = mcd.cMultipleItems * sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  379. } else {
  380. Status = AudioAllocateMemory_Paged(mcd.cChannels * sizeof( MIXERCONTROLDETAILS_UNSIGNED ),
  381. TAG_Audd_DETAILS,
  382. ZERO_FILL_MEMORY,
  383. &paDetails );
  384. mcd.cbDetails = mcd.cChannels * sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  385. }
  386. if (NT_SUCCESS(Status))
  387. {
  388. mcd.paDetails = paDetails;
  389. //
  390. // Make the actual query call.
  391. //
  392. Status = kmxlGetControlDetailsHandler(pmxd->pWdmaContext, pDevInfo, &mcd, paDetails);
  393. if( NT_SUCCESS( Status ) ) {
  394. *ppaDetails = paDetails;
  395. } else {
  396. AudioFreeMemory_Unknown( &paDetails );
  397. }
  398. }
  399. AudioFreeMemory_Unknown( &pDevInfo );
  400. RETURN( Status );
  401. }
  402. ///////////////////////////////////////////////////////////////////////
  403. //
  404. //
  405. //
  406. NTSTATUS
  407. kmxlSetCurrentControlValue(
  408. IN PFILE_OBJECT pfo, // The instance to persist for
  409. IN PMIXERDEVICE pmxd,
  410. IN PMXLLINE pLine,
  411. IN PMXLCONTROL pControl, // The control to retrieve
  412. IN PVOID paDetails
  413. )
  414. {
  415. NTSTATUS Status;
  416. LPDEVICEINFO pDevInfo = NULL;
  417. MIXERCONTROLDETAILS mcd;
  418. ULONG Index;
  419. ULONG Devices;
  420. PAGED_CODE();
  421. //
  422. // Initialize a Device Info structure to make the query look like
  423. // it comes from user mode.
  424. //
  425. Status = kmxlAllocDeviceInfo(&pDevInfo, pmxd->DeviceInterface, MIXER_SETCONTROLDETAILSF_VALUE, TAG_AudD_DEVICEINFO );
  426. if (!NT_SUCCESS(Status)) RETURN( Status );
  427. for( Devices = 0, Index = 0;
  428. Devices < MAXNUMDEVS;
  429. Devices++ ) {
  430. if( pmxd == &pmxd->pWdmaContext->MixerDevs[ Devices ] ) {
  431. pDevInfo->DeviceNumber = Index;
  432. break;
  433. }
  434. if ( !MyWcsicmp(pmxd->DeviceInterface, pmxd->pWdmaContext->MixerDevs[ Devices ].DeviceInterface) ) {
  435. Index++;
  436. }
  437. }
  438. //
  439. // Create an MIXERCONTROLDETAILS structure for this query.
  440. //
  441. RtlZeroMemory( &mcd, sizeof( MIXERCONTROLDETAILS ) );
  442. mcd.cMultipleItems = pControl->Control.cMultipleItems;
  443. mcd.cbStruct = sizeof( MIXERCONTROLDETAILS );
  444. mcd.dwControlID = pControl->Control.dwControlID;
  445. mcd.cChannels = pControl->NumChannels;
  446. //
  447. // For a MUX, we know that NumChannels will be zero and cChannels will be zero.
  448. //
  449. if( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ) {
  450. mcd.cbDetails = mcd.cMultipleItems * sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  451. } else {
  452. mcd.cbDetails = mcd.cChannels * sizeof( MIXERCONTROLDETAILS_UNSIGNED );
  453. }
  454. mcd.paDetails = paDetails;
  455. //
  456. // Make the actual query call.
  457. //
  458. Status = kmxlSetControlDetailsHandler( pmxd->pWdmaContext,
  459. pDevInfo,
  460. &mcd,
  461. paDetails,
  462. 0
  463. );
  464. //
  465. // workitem: Should map the error code here for invalid topologies!
  466. //
  467. AudioFreeMemory_Unknown(&pDevInfo);
  468. RETURN( Status );
  469. }
  470. ///////////////////////////////////////////////////////////////////////
  471. //
  472. // kmxlPersistAll
  473. //
  474. //
  475. NTSTATUS
  476. kmxlPersistAll(
  477. IN PFILE_OBJECT pfo, // The instance to persist
  478. IN PMIXERDEVICE pmxd
  479. )
  480. {
  481. NTSTATUS Status = STATUS_SUCCESS;
  482. HANDLE hKey = NULL,
  483. hMixerKey = NULL,
  484. hLineKey = NULL,
  485. hAllControlsKey = NULL,
  486. hControlKey = NULL;
  487. WCHAR sz[ 16 ];
  488. ULONG LineNum,
  489. ControlNum,
  490. i,
  491. Channels;
  492. PMXLLINE pLine;
  493. PMXLCONTROL pControl;
  494. PVOID paDetails;
  495. PCHANNEL_STEPPING pChannelStepping;
  496. BOOL bValidMultichannel;
  497. PAGED_CODE();
  498. ASSERT( pfo );
  499. ASSERT( pmxd );
  500. Status = kmxlOpenInterfaceKey( pfo, pmxd->Device, &hKey );
  501. if( !NT_SUCCESS( Status ) ) {
  502. goto exit;
  503. }
  504. Status = kmxlRegCreateKey(
  505. hKey,
  506. MIXER_KEY_NAME,
  507. &hMixerKey
  508. );
  509. if( !NT_SUCCESS( Status ) ) {
  510. goto exit;
  511. }
  512. kmxlRegCloseKey( hKey );
  513. i = kmxlListLength( pmxd->listLines );
  514. kmxlRegSetValue(
  515. hMixerKey,
  516. LINE_COUNT_VALUE_NAME,
  517. REG_DWORD,
  518. &i,
  519. sizeof( i )
  520. );
  521. LineNum = 0;
  522. pLine = kmxlFirstInList( pmxd->listLines );
  523. while( pLine ) {
  524. //
  525. // Store the line id as the key
  526. //
  527. swprintf( sz, LINE_KEY_NAME_FORMAT, LineNum++ );
  528. Status = kmxlRegCreateKey(
  529. hMixerKey,
  530. sz,
  531. &hLineKey
  532. );
  533. if( !NT_SUCCESS( Status ) ) {
  534. DPF(DL_WARNING|FA_PERSIST,("kmxlRegCreateKey failed Status=%X",Status) );
  535. goto exit;
  536. }
  537. kmxlRegSetValue(
  538. hLineKey,
  539. LINE_ID_VALUE_NAME,
  540. REG_DWORD,
  541. &pLine->Line.dwLineID,
  542. sizeof( pLine->Line.dwLineID )
  543. );
  544. //
  545. // Save the number of controls underneath the line id key
  546. //
  547. kmxlRegSetValue(
  548. hLineKey,
  549. CONTROL_COUNT_VALUE_NAME,
  550. REG_DWORD,
  551. &pLine->Line.cControls,
  552. sizeof( pLine->Line.cControls )
  553. );
  554. //
  555. // Save the source pin Id underneath the line id key
  556. //
  557. kmxlRegSetValue(
  558. hLineKey,
  559. SOURCE_ID_VALUE_NAME,
  560. REG_DWORD,
  561. &pLine->SourceId,
  562. sizeof( pLine->SourceId )
  563. );
  564. //
  565. // Save the destination pin Id underneath the line id key
  566. //
  567. kmxlRegSetValue(
  568. hLineKey,
  569. DEST_ID_VALUE_NAME,
  570. REG_DWORD,
  571. &pLine->DestId,
  572. sizeof( pLine->DestId )
  573. );
  574. //
  575. // Create the Controls key to store all the controls under
  576. //
  577. Status = kmxlRegCreateKey(
  578. hLineKey,
  579. CONTROLS_KEY_NAME,
  580. &hAllControlsKey
  581. );
  582. if( !NT_SUCCESS( Status ) ) {
  583. DPF(DL_WARNING|FA_PERSIST,("kmxlRegCreateKey failed Status=%X",Status) );
  584. goto exit;
  585. }
  586. kmxlRegCloseKey( hLineKey );
  587. //
  588. // Persist all the controls underneath the controls key
  589. //
  590. ControlNum = 0;
  591. pControl = kmxlFirstInList( pLine->Controls );
  592. while( pControl ) {
  593. swprintf( sz, CONTROL_KEY_NAME_FORMAT, ControlNum++ );
  594. Status = kmxlRegCreateKey(
  595. hAllControlsKey,
  596. sz,
  597. &hControlKey
  598. );
  599. if( !NT_SUCCESS( Status ) ) {
  600. DPF(DL_WARNING|FA_PERSIST,("kmxlRegCreateKey failed Status=%X",Status) );
  601. goto exit;
  602. }
  603. kmxlRegSetValue(
  604. hControlKey,
  605. CONTROL_TYPE_VALUE_NAME,
  606. REG_DWORD,
  607. &pControl->Control.dwControlType,
  608. sizeof( pControl->Control.dwControlType )
  609. );
  610. kmxlRegSetValue(
  611. hControlKey,
  612. CONTROL_MULTIPLEITEMS_VALUE_NAME,
  613. REG_DWORD,
  614. &pControl->Control.cMultipleItems,
  615. sizeof( pControl->Control.cMultipleItems )
  616. );
  617. //
  618. // As in kmxlRetrieveAll, this code should be in the control creation
  619. // code path as well as here. We should never write anything to the registry
  620. // that doesn't conform to what we understand.
  621. //
  622. if (pControl->pChannelStepping) {
  623. pChannelStepping = pControl->pChannelStepping;
  624. for (i = 0; i < pControl->NumChannels; i++, pChannelStepping++) {
  625. /*
  626. ASSERT ( pChannelStepping->MinValue >= -150*65536 && pChannelStepping->MinValue <= 150*65536 );
  627. ASSERT ( pChannelStepping->MaxValue >= -150*65536 && pChannelStepping->MaxValue <= 150*65536 );
  628. ASSERT ( pChannelStepping->Steps >= 0 && pChannelStepping->Steps <= 65535 );
  629. */
  630. if (!(pChannelStepping->MinValue >= -150*65536 && pChannelStepping->MinValue <= 150*65536)) {
  631. DPF(DL_WARNING|FA_PERSIST,
  632. ("MinValue %X of Control %X of type %X on Line %X Channel %X is out of range!",
  633. pChannelStepping->MinValue,
  634. pControl->Control.dwControlID,
  635. pControl->Control.dwControlType,
  636. pLine->Line.dwLineID,
  637. i) );
  638. pChannelStepping->MinValue = DEFAULT_RANGE_MIN;
  639. }
  640. if (!(pChannelStepping->MaxValue >= -150*65536 && pChannelStepping->MaxValue <= 150*65536)) {
  641. DPF(DL_WARNING|FA_PERSIST,
  642. ("MaxValue %X of Control %X of type %X on Line %X Channel %X is out of range!",
  643. pChannelStepping->MaxValue,
  644. pControl->Control.dwControlID,
  645. pControl->Control.dwControlType,
  646. pLine->Line.dwLineID,
  647. i) );
  648. pChannelStepping->MaxValue = DEFAULT_RANGE_MAX;
  649. }
  650. if (!(pChannelStepping->Steps >= 0 && pChannelStepping->Steps <= 65535)) {
  651. DPF(DL_WARNING|FA_PERSIST,
  652. ("Steps %X of Control %X of type %X on Line %X Channel %X is out of range!",
  653. pChannelStepping->Steps,
  654. pControl->Control.dwControlID,
  655. pControl->Control.dwControlType,
  656. pLine->Line.dwLineID,
  657. i) );
  658. pChannelStepping->Steps = DEFAULT_RANGE_STEPS;
  659. pControl->Control.Metrics.cSteps = DEFAULT_RANGE_STEPS;
  660. }
  661. }
  662. }
  663. Status = kmxlGetCurrentControlValue(
  664. pfo,
  665. pmxd,
  666. pLine,
  667. pControl,
  668. &paDetails
  669. );
  670. if( NT_SUCCESS( Status ) ) {
  671. if( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ) {
  672. for( i = 0; i < pControl->Control.cMultipleItems; i++ ) {
  673. swprintf( sz, MULTIPLEITEM_VALUE_NAME_FORMAT, i );
  674. Status = kmxlRegSetValue(
  675. hControlKey,
  676. sz,
  677. REG_DWORD,
  678. &((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ],
  679. sizeof( ((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ] )
  680. );
  681. if( !NT_SUCCESS( Status ) ) {
  682. AudioFreeMemory_Unknown( &paDetails );
  683. DPF(DL_WARNING|FA_PERSIST,("KmxlRegSetValue failed Status=%X",Status) );
  684. goto exit;
  685. }
  686. }
  687. } else {
  688. Channels = pControl->NumChannels;
  689. kmxlRegSetValue(
  690. hControlKey,
  691. CHANNEL_COUNT_VALUE_NAME,
  692. REG_DWORD,
  693. &Channels,
  694. sizeof( Channels )
  695. );
  696. for( i = 0; i < Channels; i++ ) {
  697. swprintf( sz, CHANNEL_VALUE_NAME_FORMAT, i );
  698. Status = kmxlRegSetValue(
  699. hControlKey,
  700. sz,
  701. REG_DWORD,
  702. &((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ],
  703. sizeof( ((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ] )
  704. );
  705. if( !NT_SUCCESS( Status ) ) {
  706. AudioFreeMemory_Unknown( &paDetails );
  707. DPF(DL_WARNING|FA_PERSIST,("KmxlRegSetValue failed Status=%X",Status) );
  708. goto exit;
  709. }
  710. }
  711. }
  712. AudioFreeMemory_Unknown( &paDetails );
  713. }
  714. kmxlRegCloseKey( hControlKey );
  715. pControl = kmxlNextControl( pControl );
  716. }
  717. kmxlRegCloseKey( hAllControlsKey );
  718. pLine = kmxlNextLine( pLine );
  719. }
  720. //
  721. // After all of the persisting is done, save out a value indicating that the channel
  722. // values are all valid for a multichannel restore. This is to avoid the situation
  723. // where the data for some of the channels is invalid.
  724. //
  725. bValidMultichannel = TRUE;
  726. kmxlRegSetValue(
  727. hMixerKey,
  728. VALID_MULTICHANNEL_MIXER_VALUE_NAME,
  729. REG_DWORD,
  730. &bValidMultichannel,
  731. sizeof( bValidMultichannel )
  732. );
  733. kmxlRegCloseKey( hMixerKey );
  734. exit:
  735. if( hControlKey ) {
  736. kmxlRegCloseKey( hControlKey );
  737. }
  738. if( hAllControlsKey ) {
  739. kmxlRegCloseKey( hAllControlsKey );
  740. }
  741. if( hLineKey ) {
  742. kmxlRegCloseKey( hLineKey );
  743. }
  744. if( hMixerKey ) {
  745. kmxlRegCloseKey( hMixerKey );
  746. }
  747. if( hKey ) {
  748. kmxlRegCloseKey( hKey );
  749. }
  750. RETURN( Status );
  751. }
  752. ///////////////////////////////////////////////////////////////////////
  753. //
  754. // kmxlRetrieveAll
  755. //
  756. //
  757. NTSTATUS
  758. kmxlRetrieveAll(
  759. IN PFILE_OBJECT pfo, // The instance to retrieve
  760. IN PMIXERDEVICE pmxd // Mixer device info
  761. )
  762. {
  763. NTSTATUS Status;
  764. WCHAR sz[ 16 ];
  765. HANDLE hMixerKey = NULL,
  766. hLineKey = NULL,
  767. hAllControlsKey = NULL,
  768. hControlKey = NULL;
  769. ULONG ResultLength, Value, NumChannels, ControlCount;
  770. ULONG LineCount = 0;
  771. ULONG i,j;
  772. BOOL bInvalidTopology = FALSE;
  773. PMXLLINE pLine;
  774. PMXLCONTROL pControl;
  775. MIXERCONTROLDETAILS_UNSIGNED* paDetails = NULL;
  776. PCHANNEL_STEPPING pChannelStepping;
  777. BOOL bValidMultichannel = FALSE;
  778. PAGED_CODE();
  779. //
  780. // Open the Mixer key under the interface key. If somethings goes
  781. // wrong here, this does not have a valid topology.
  782. //
  783. Status = kmxlRegOpenMixerKey( pfo, pmxd, &hMixerKey );
  784. if( !NT_SUCCESS( Status ) ) {
  785. DPF(DL_TRACE|FA_PERSIST,( "failed to open mixer reg key!" ) );
  786. bInvalidTopology = TRUE;
  787. goto exit;
  788. } // if
  789. //
  790. // Query for a valid multichannel mixer persistance
  791. //
  792. Status = kmxlRegQueryValue(
  793. hMixerKey,
  794. VALID_MULTICHANNEL_MIXER_VALUE_NAME,
  795. &bValidMultichannel,
  796. sizeof( bValidMultichannel ),
  797. &ResultLength
  798. );
  799. if( !NT_SUCCESS( Status ) ) {
  800. // This should be set to FALSE for upgrades from Win2000 where the registry
  801. // entries could be invalid for channels other than the first channel.
  802. bValidMultichannel = FALSE;
  803. } // if
  804. //
  805. // Query the total number of lines that have been persisted.
  806. //
  807. Status = kmxlRegQueryValue(
  808. hMixerKey,
  809. LINE_COUNT_VALUE_NAME,
  810. &LineCount,
  811. sizeof( LineCount ),
  812. &ResultLength
  813. );
  814. if( !NT_SUCCESS( Status ) ) {
  815. DPF(DL_TRACE|FA_PERSIST,( "failed to read number of persisted lines!" ) );
  816. bInvalidTopology = TRUE;
  817. goto exit;
  818. } // if
  819. //
  820. // Check to ensure the number of lines persisted is the same as
  821. // what is stored in memory.
  822. //
  823. if( LineCount != kmxlListLength( pmxd->listLines ) ) {
  824. DPF(DL_TRACE|FA_PERSIST,( "# of persisted lines does not match current topology!" ) );
  825. bInvalidTopology = TRUE;
  826. goto exit;
  827. } // if
  828. for( i = 0; i < LineCount; i++ ) {
  829. //
  830. // Construct the line key name and open the key.
  831. //
  832. swprintf( sz, LINE_KEY_NAME_FORMAT, i );
  833. Status = kmxlRegOpenKey(
  834. hMixerKey,
  835. sz,
  836. &hLineKey
  837. );
  838. if( !NT_SUCCESS( Status ) ) {
  839. break;
  840. } // if
  841. //
  842. // Query the line Id of this line.
  843. //
  844. Status = kmxlRegQueryValue(
  845. hLineKey,
  846. LINE_ID_VALUE_NAME,
  847. &Value,
  848. sizeof( Value ),
  849. &ResultLength
  850. );
  851. if( !NT_SUCCESS( Status ) ) {
  852. continue;
  853. } // if
  854. //
  855. // Verify the line Id is valid and retrieve a pointer to the line
  856. // structure.
  857. //
  858. pLine = kmxlFindDestById( pmxd->listLines, Value );
  859. if( pLine == NULL ) {
  860. DPF(DL_TRACE|FA_PERSIST,( "persisted line ID is invalid!" ) );
  861. bInvalidTopology = TRUE;
  862. break;
  863. } // if
  864. //
  865. // Retrieve the number of controls for this line.
  866. //
  867. Status = kmxlRegQueryValue(
  868. hLineKey,
  869. CONTROL_COUNT_VALUE_NAME,
  870. &Value,
  871. sizeof( Value ),
  872. &ResultLength
  873. );
  874. if( !NT_SUCCESS( Status ) ) {
  875. kmxlRegCloseKey( hLineKey );
  876. continue;
  877. } // if
  878. if( Value != pLine->Line.cControls ) {
  879. DPF(DL_TRACE|FA_PERSIST,( "the number of controls for line %x is invalid!",
  880. pLine->Line.dwLineID
  881. ) );
  882. bInvalidTopology = TRUE;
  883. break;
  884. } // if
  885. Status = kmxlRegOpenKey(
  886. hLineKey,
  887. CONTROLS_KEY_NAME,
  888. &hAllControlsKey
  889. );
  890. if( !NT_SUCCESS( Status ) ) {
  891. kmxlRegCloseKey( hLineKey );
  892. continue;
  893. } // if
  894. //
  895. // Query all the information for each control
  896. //
  897. ControlCount = 0;
  898. pControl = kmxlFirstInList( pLine->Controls );
  899. while( pControl ) {
  900. swprintf( sz, CONTROL_KEY_NAME_FORMAT, ControlCount++ );
  901. Status = kmxlRegOpenKey(
  902. hAllControlsKey,
  903. sz,
  904. &hControlKey
  905. );
  906. if( !NT_SUCCESS( Status ) ) {
  907. break;
  908. } // if
  909. Status = kmxlRegQueryValue(
  910. hControlKey,
  911. CHANNEL_COUNT_VALUE_NAME,
  912. &NumChannels,
  913. sizeof( NumChannels ),
  914. &ResultLength
  915. );
  916. if( !NT_SUCCESS( Status ) ) {
  917. if( pControl->Control.cMultipleItems == 0 ) {
  918. //
  919. // Controls that have multiple items (such as MUXes)
  920. // don't have channel counts. If this control does
  921. // not have multiple items, then there is a problem
  922. // in the registry.
  923. //
  924. kmxlRegCloseKey( hControlKey );
  925. pControl = kmxlNextControl( pControl );
  926. continue;
  927. }
  928. } // if
  929. if( ( NumChannels != pControl->NumChannels ) &&
  930. ( pControl->Control.cMultipleItems == 0 ) ) {
  931. DPF(DL_TRACE|FA_PERSIST,( "the number of channels for control %d on line %x is invalid.",
  932. pControl->Control.dwControlID,
  933. pLine->Line.dwLineID
  934. ) );
  935. bInvalidTopology = TRUE;
  936. goto exit;
  937. }
  938. Status = kmxlRegQueryValue(
  939. hControlKey,
  940. CONTROL_TYPE_VALUE_NAME,
  941. &Value,
  942. sizeof( Value ),
  943. &ResultLength
  944. );
  945. if( !NT_SUCCESS( Status ) ) {
  946. kmxlRegCloseKey( hControlKey );
  947. pControl = kmxlNextControl( pControl );
  948. continue;
  949. } // if
  950. if( Value != pControl->Control.dwControlType ) {
  951. kmxlRegCloseKey( hControlKey );
  952. pControl = kmxlNextControl( pControl );
  953. continue;
  954. } // if
  955. Status = kmxlRegQueryValue(
  956. hControlKey,
  957. CONTROL_MULTIPLEITEMS_VALUE_NAME,
  958. &Value,
  959. sizeof( Value ),
  960. &ResultLength
  961. );
  962. if( !NT_SUCCESS( Status ) ) {
  963. bInvalidTopology = TRUE;
  964. DPF(DL_TRACE|FA_PERSIST, ( "cMultipleItems value not found!" ) );
  965. goto exit;
  966. }
  967. if( Value != pControl->Control.cMultipleItems ) {
  968. bInvalidTopology = TRUE;
  969. DPF(DL_TRACE|FA_PERSIST, ( "cMultipleItems does not match for control %x!",
  970. pControl->Control.dwControlID
  971. ) );
  972. goto exit;
  973. }
  974. //
  975. // Allocate memory for the data structures and
  976. // set the value.
  977. //
  978. if( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ) {
  979. if( !NT_SUCCESS( AudioAllocateMemory_Paged(pControl->Control.cMultipleItems *
  980. sizeof( MIXERCONTROLDETAILS_UNSIGNED ),
  981. TAG_Audd_DETAILS,
  982. ZERO_FILL_MEMORY,
  983. &paDetails ) ) )
  984. {
  985. kmxlRegCloseKey( hControlKey );
  986. pControl = kmxlNextControl( pControl );
  987. continue;
  988. }
  989. for( Value = 0; Value < pControl->Control.cMultipleItems; Value++ ) {
  990. swprintf( sz, MULTIPLEITEM_VALUE_NAME_FORMAT, Value );
  991. Status = kmxlRegQueryValue(
  992. hControlKey,
  993. sz,
  994. &paDetails[ Value ].dwValue,
  995. sizeof( paDetails[ Value ].dwValue ),
  996. &ResultLength
  997. );
  998. if( !NT_SUCCESS( Status ) ) {
  999. break;
  1000. }
  1001. }
  1002. } else {
  1003. if( !NT_SUCCESS( AudioAllocateMemory_Paged(NumChannels * sizeof( MIXERCONTROLDETAILS_UNSIGNED ),
  1004. TAG_Audd_DETAILS,
  1005. ZERO_FILL_MEMORY,
  1006. &paDetails ) ) )
  1007. {
  1008. kmxlRegCloseKey( hControlKey );
  1009. pControl = kmxlNextControl( pControl );
  1010. continue;
  1011. } // if
  1012. for( Value = 0; Value < NumChannels; Value++ ) {
  1013. // check to see if the persisted values are valid for all channels
  1014. if ( ( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUTE ) &&
  1015. ( bValidMultichannel == FALSE ) )
  1016. {
  1017. swprintf( sz, CHANNEL_VALUE_NAME_FORMAT, 0 ); // Lock the persistance key to the first channel.
  1018. // This is the only channel that we know is valid
  1019. // at this time.
  1020. }
  1021. else
  1022. {
  1023. swprintf( sz, CHANNEL_VALUE_NAME_FORMAT, Value );
  1024. }
  1025. Status = kmxlRegQueryValue(
  1026. hControlKey,
  1027. sz,
  1028. &paDetails[ Value ].dwValue,
  1029. sizeof( paDetails[ Value ].dwValue ),
  1030. &ResultLength
  1031. );
  1032. if( !NT_SUCCESS( Status ) ) {
  1033. break;
  1034. } // if
  1035. } // for( Value );
  1036. }
  1037. if( NT_SUCCESS( Status ) ) {
  1038. //
  1039. // This correction code should be here along with in the control
  1040. // creation code. Basically, if we're reading something from the
  1041. // registry that doesn't conform, we fix it up, but, chances are
  1042. // it should be in the correct form.
  1043. //
  1044. if (pControl->pChannelStepping) {
  1045. pChannelStepping = pControl->pChannelStepping;
  1046. for (j = 0; j < pControl->NumChannels; j++, pChannelStepping++) {
  1047. /*
  1048. ASSERT ( pChannelStepping->MinValue >= -150*65536 && pChannelStepping->MinValue <= 150*65536 );
  1049. ASSERT ( pChannelStepping->MaxValue >= -150*65536 && pChannelStepping->MaxValue <= 150*65536 );
  1050. ASSERT ( pChannelStepping->Steps >= 0 && pChannelStepping->Steps <= 65535 );
  1051. */
  1052. if (!(pChannelStepping->MinValue >= -150*65536 && pChannelStepping->MinValue <= 150*65536)) {
  1053. DPF(DL_WARNING|FA_PERSIST,
  1054. ("MinValue %X of Control %X of type %X on Line %X Channel %X is out of range!",
  1055. pChannelStepping->MinValue,
  1056. pControl->Control.dwControlID,
  1057. pControl->Control.dwControlType,
  1058. pLine->Line.dwLineID,
  1059. j) );
  1060. pChannelStepping->MinValue = DEFAULT_RANGE_MIN;
  1061. }
  1062. if (!(pChannelStepping->MaxValue >= -150*65536 && pChannelStepping->MaxValue <= 150*65536)) {
  1063. DPF(DL_WARNING|FA_PERSIST,
  1064. ("MaxValue %X of Control %X of type %X on Line %X Channel %X is out of range!",
  1065. pChannelStepping->MaxValue,
  1066. pControl->Control.dwControlID,
  1067. pControl->Control.dwControlType,
  1068. pLine->Line.dwLineID,
  1069. j) );
  1070. pChannelStepping->MaxValue = DEFAULT_RANGE_MAX;
  1071. }
  1072. if (!(pChannelStepping->Steps >= 0 && pChannelStepping->Steps <= 65535)) {
  1073. DPF(DL_TRACE|FA_PERSIST,
  1074. ("Steps %X of Control %X of type %X on Line %X Channel %X is out of range!",
  1075. pChannelStepping->Steps,
  1076. pControl->Control.dwControlID,
  1077. pControl->Control.dwControlType,
  1078. pLine->Line.dwLineID,
  1079. j) );
  1080. pChannelStepping->Steps = DEFAULT_RANGE_STEPS;
  1081. pControl->Control.Metrics.cSteps = DEFAULT_RANGE_STEPS;
  1082. }
  1083. }
  1084. }
  1085. kmxlSetCurrentControlValue(
  1086. pfo,
  1087. pmxd,
  1088. pLine,
  1089. pControl,
  1090. paDetails
  1091. );
  1092. }
  1093. AudioFreeMemory_Unknown( &paDetails );
  1094. kmxlRegCloseKey( hControlKey );
  1095. pControl = kmxlNextControl( pControl );
  1096. } // while( pControl );
  1097. kmxlRegCloseKey( hAllControlsKey );
  1098. kmxlRegCloseKey( hLineKey );
  1099. } // for( i );
  1100. exit:
  1101. if( hLineKey ) {
  1102. kmxlRegCloseKey( hLineKey );
  1103. }
  1104. if( hMixerKey ) {
  1105. kmxlRegCloseKey( hMixerKey );
  1106. }
  1107. if( bInvalidTopology ) {
  1108. DPF(DL_TRACE|FA_PERSIST,( "Invalid topology persisted or key not found. Rebuilding." ) );
  1109. Status = kmxlRegOpenMixerKey( pfo, pmxd, &hMixerKey );
  1110. if( NT_SUCCESS( Status ) ) {
  1111. ZwDeleteKey( hMixerKey );
  1112. }
  1113. return( kmxlPersistAll( pfo, pmxd ) );
  1114. }
  1115. return( STATUS_SUCCESS );
  1116. }
  1117. ///////////////////////////////////////////////////////////////////////
  1118. //
  1119. // kmxlFindLineForControl
  1120. //
  1121. //
  1122. PMXLLINE
  1123. kmxlFindLineForControl(
  1124. IN PMXLCONTROL pControl,
  1125. IN LINELIST listLines
  1126. )
  1127. {
  1128. PMXLLINE pLine;
  1129. PMXLCONTROL pTControl;
  1130. PAGED_CODE();
  1131. if( pControl == NULL ) {
  1132. return( NULL );
  1133. }
  1134. if( listLines == NULL ) {
  1135. return( NULL );
  1136. }
  1137. pLine = kmxlFirstInList( listLines );
  1138. while( pLine ) {
  1139. pTControl = kmxlFirstInList( pLine->Controls );
  1140. while( pTControl ) {
  1141. if( pTControl == pControl ) {
  1142. return( pLine );
  1143. }
  1144. pTControl = kmxlNextControl( pTControl );
  1145. }
  1146. pLine = kmxlNextLine( pLine );
  1147. }
  1148. return( NULL );
  1149. }
  1150. ///////////////////////////////////////////////////////////////////////
  1151. //
  1152. // kmxlPersistSingleControl
  1153. //
  1154. //
  1155. NTSTATUS
  1156. kmxlPersistSingleControl(
  1157. IN PFILE_OBJECT pfo, // The instance to retrieve
  1158. IN PMIXERDEVICE pmxd, // Mixer device info
  1159. IN PMXLCONTROL pControl, // The control to persist
  1160. IN PVOID paDetails // The channel values to persist
  1161. )
  1162. {
  1163. NTSTATUS Status;
  1164. HANDLE hMixerKey = NULL,
  1165. hLineKey = NULL,
  1166. hAllControlsKey = NULL,
  1167. hControlKey = NULL;
  1168. PMXLLINE pTLine, pLine;
  1169. PMXLCONTROL pTControl;
  1170. ULONG LineNum, ControlNum, i, Channels;
  1171. WCHAR sz[ 16 ];
  1172. BOOL bPersistAll = FALSE;
  1173. BOOL bValidMultichannel = FALSE;
  1174. ULONG ResultLength;
  1175. PAGED_CODE();
  1176. Status = kmxlRegOpenMixerKey( pfo, pmxd, &hMixerKey );
  1177. if( !NT_SUCCESS( Status ) ) {
  1178. return( kmxlPersistAll( pfo, pmxd ) );
  1179. }
  1180. //
  1181. // If we've never written out valid multichannel mixer settings, go ahead and
  1182. // do it here.
  1183. //
  1184. Status = kmxlRegQueryValue(
  1185. hMixerKey,
  1186. VALID_MULTICHANNEL_MIXER_VALUE_NAME,
  1187. &bValidMultichannel,
  1188. sizeof( bValidMultichannel ),
  1189. &ResultLength
  1190. );
  1191. if( !NT_SUCCESS( Status ) || !(bValidMultichannel) ) {
  1192. return( kmxlPersistAll( pfo, pmxd ) );
  1193. }
  1194. pLine = kmxlFindLineForControl( pControl, pmxd->listLines );
  1195. if( pLine == NULL ) {
  1196. Status = STATUS_INVALID_PARAMETER;
  1197. DPF(DL_WARNING|FA_PERSIST,("KmxlFindLineForControl failed Status=%X",Status) );
  1198. goto exit;
  1199. }
  1200. LineNum = 0;
  1201. pTLine = kmxlFirstInList( pmxd->listLines );
  1202. while( pTLine ) {
  1203. if( pTLine == pLine ) {
  1204. swprintf( sz, LINE_KEY_NAME_FORMAT, LineNum );
  1205. Status = kmxlRegOpenKey( hMixerKey, sz, &hLineKey );
  1206. if( !NT_SUCCESS( Status ) ) {
  1207. bPersistAll = TRUE;
  1208. goto exit;
  1209. }
  1210. Status = kmxlRegOpenKey( hLineKey, CONTROLS_KEY_NAME, &hAllControlsKey );
  1211. if( !NT_SUCCESS( Status ) ) {
  1212. bPersistAll = TRUE;
  1213. goto exit;
  1214. }
  1215. ControlNum = 0;
  1216. pTControl = kmxlFirstInList( pTLine->Controls );
  1217. while( pTControl ) {
  1218. if( pTControl == pControl ) {
  1219. swprintf( sz, CONTROL_KEY_NAME_FORMAT, ControlNum );
  1220. Status = kmxlRegOpenKey( hAllControlsKey, sz, &hControlKey );
  1221. if( !NT_SUCCESS( Status ) ) {
  1222. bPersistAll = TRUE;
  1223. goto exit;
  1224. }
  1225. kmxlRegSetValue(
  1226. hControlKey,
  1227. CONTROL_TYPE_VALUE_NAME,
  1228. REG_DWORD,
  1229. &pControl->Control.dwControlType,
  1230. sizeof( pControl->Control.dwControlType )
  1231. );
  1232. Status = kmxlGetCurrentControlValue(
  1233. pfo,
  1234. pmxd,
  1235. pLine,
  1236. pControl,
  1237. &paDetails
  1238. );
  1239. if( NT_SUCCESS( Status ) ) {
  1240. if( pControl->Control.dwControlType == MIXERCONTROL_CONTROLTYPE_MUX ) {
  1241. for( i = 0; i < pControl->Control.cMultipleItems; i++ ) {
  1242. swprintf( sz, MULTIPLEITEM_VALUE_NAME_FORMAT, i );
  1243. Status = kmxlRegSetValue(
  1244. hControlKey,
  1245. sz,
  1246. REG_DWORD,
  1247. &((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ],
  1248. sizeof( ((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ] )
  1249. );
  1250. }
  1251. } else {
  1252. Channels = pControl->NumChannels;
  1253. kmxlRegSetValue(
  1254. hControlKey,
  1255. CHANNEL_COUNT_VALUE_NAME,
  1256. REG_DWORD,
  1257. &Channels,
  1258. sizeof( Channels )
  1259. );
  1260. for( i = 0; i < Channels; i++ ) {
  1261. swprintf( sz, CHANNEL_VALUE_NAME_FORMAT, i );
  1262. Status = kmxlRegSetValue(
  1263. hControlKey,
  1264. sz,
  1265. REG_DWORD,
  1266. &((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ],
  1267. sizeof( ((PMIXERCONTROLDETAILS_UNSIGNED) paDetails)[ i ] )
  1268. );
  1269. }
  1270. }
  1271. AudioFreeMemory_Unknown( &paDetails );
  1272. }
  1273. goto exit;
  1274. } else {
  1275. pTControl = kmxlNextControl( pTControl );
  1276. ++ControlNum;
  1277. }
  1278. }
  1279. Status = STATUS_SUCCESS;
  1280. goto exit;
  1281. } else {
  1282. pTLine = kmxlNextLine( pTLine );
  1283. ++LineNum;
  1284. }
  1285. }
  1286. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  1287. DPF(DL_WARNING|FA_PERSIST,("kmxlPersistSingleControl failing Status=%X",Status) );
  1288. exit:
  1289. if( hMixerKey ) {
  1290. kmxlRegCloseKey( hMixerKey );
  1291. }
  1292. if( hLineKey ) {
  1293. kmxlRegCloseKey( hLineKey );
  1294. }
  1295. if( hAllControlsKey ) {
  1296. kmxlRegCloseKey( hAllControlsKey );
  1297. }
  1298. if( hControlKey ) {
  1299. kmxlRegCloseKey( hControlKey );
  1300. }
  1301. if( bPersistAll ) {
  1302. return( kmxlPersistAll( pfo, pmxd ) );
  1303. }
  1304. RETURN( Status );
  1305. }
  1306. ///////////////////////////////////////////////////////////////////////
  1307. //
  1308. // kmxlPersistControl
  1309. //
  1310. //
  1311. NTSTATUS
  1312. kmxlPersistControl(
  1313. IN PFILE_OBJECT pfo, // The instance to retrieve
  1314. IN PMIXERDEVICE pmxd, // Mixer device info
  1315. IN PMXLCONTROL pControl, // The control to persist
  1316. IN PVOID paDetails // The channel values to persist
  1317. )
  1318. {
  1319. PMXLLINE pLine;
  1320. PMXLCONTROL pCtrl;
  1321. NTSTATUS Status;
  1322. NTSTATUS OverallStatus;
  1323. PAGED_CODE();
  1324. OverallStatus=STATUS_SUCCESS;
  1325. //
  1326. // Persist the control that just changed. Do not abort if this persist fails.
  1327. //
  1328. Status = kmxlPersistSingleControl( pfo, pmxd, pControl, paDetails );
  1329. if( !NT_SUCCESS( Status ) ) {
  1330. OverallStatus=Status;
  1331. }
  1332. //
  1333. // Check all other controls and see if another control shares the same
  1334. // node ID. If so, persist that control with the new value also.
  1335. // Again, do not abort if any of the persists fail. Simply return the last
  1336. // error status.
  1337. //
  1338. pLine = kmxlFirstInList( pmxd->listLines );
  1339. while( pLine ) {
  1340. pCtrl = kmxlFirstInList( pLine->Controls );
  1341. while( pCtrl ) {
  1342. if( pCtrl->Id==pControl->Id && pCtrl!=pControl ) {
  1343. Status = kmxlPersistSingleControl( pfo, pmxd, pCtrl, paDetails );
  1344. if( !NT_SUCCESS( Status ) ) {
  1345. OverallStatus=Status;
  1346. }
  1347. }
  1348. pCtrl = kmxlNextControl( pCtrl );
  1349. }
  1350. pLine = kmxlNextLine( pLine );
  1351. }
  1352. RETURN( OverallStatus );
  1353. }