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.

1816 lines
72 KiB

  1. /********************************************************************************
  2. ** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
  3. **
  4. ** Portions Copyright (c) 1998-1999 Intel Corporation
  5. **
  6. ********************************************************************************/
  7. // Every debug output has "Modulname text".
  8. static char STR_MODULENAME[] = "prophnd: ";
  9. #include <limits.h>
  10. #include "mintopo.h"
  11. // These are the values passed to the property handler in the instance
  12. // parameter that normally represents the channel.
  13. const LONG CHAN_LEFT = 0;
  14. const LONG CHAN_RIGHT = 1;
  15. const LONG CHAN_MASTER = -1;
  16. // paged code goes here.
  17. #pragma code_seg("PAGE")
  18. /*****************************************************************************
  19. * CMiniportTopologyICH::SetMultichannelMute
  20. *****************************************************************************
  21. * This function is used to set one of the multichannel mutes.
  22. * It takes the master mono into account when calculating the mute.
  23. * Make sure that you updated the stNodeCache before calling this function.
  24. */
  25. NTSTATUS CMiniportTopologyICH::SetMultichannelMute
  26. (
  27. IN CMiniportTopologyICH *that,
  28. IN TopoNodes Mute
  29. )
  30. {
  31. NTSTATUS ntStatus = STATUS_SUCCESS;
  32. BOOL bMute;
  33. // The first calls to SetMultichannelMute could be without valid
  34. // cache information because WDMAUD might currently query the nodes
  35. // (this is at system startup). When WDMAUD queried all nodes then
  36. // all cache information will be valid.
  37. if (that->stNodeCache[NODE_VIRT_MASTERMONO_MUTE].bLeftValid &&
  38. that->stNodeCache[Mute].bLeftValid)
  39. {
  40. // We get the master mono mute and the mute that is to change.
  41. // Then we "or" them and write the value to the register.
  42. bMute = that->stNodeCache[NODE_VIRT_MASTERMONO_MUTE].lLeft ||
  43. that->stNodeCache[Mute].lLeft;
  44. ntStatus = that->AdapterCommon->WriteCodecRegister (
  45. that->AdapterCommon->GetNodeReg (Mute),
  46. bMute ? -1 : 0,
  47. that->AdapterCommon->GetNodeMask (Mute));
  48. DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x", NodeStrings[Mute], (int)bMute));
  49. }
  50. return ntStatus;
  51. }
  52. /*****************************************************************************
  53. * CMiniportTopologyICH::SetMultichannelVolume
  54. *****************************************************************************
  55. * This function is used to set one of the multichannel volumes.
  56. * It takes the master mono into account when calculating the volume.
  57. * Make sure that you updated the stNodeCache before calling this function.
  58. */
  59. NTSTATUS CMiniportTopologyICH::SetMultichannelVolume
  60. (
  61. IN CMiniportTopologyICH *that,
  62. IN TopoNodes Volume
  63. )
  64. {
  65. NTSTATUS ntStatus = STATUS_SUCCESS;
  66. LONG lMinimum, lMaximum;
  67. ULONG uStep;
  68. LONG lLevel;
  69. WORD wRegister;
  70. // The first calls to SetMultichannelMute could be without valid
  71. // cache information because WDMAUD might currently query the nodes
  72. // (this is at system startup). When WDMAUD queried all nodes then
  73. // all cache information will be valid.
  74. if (that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].bLeftValid &&
  75. that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].bRightValid &&
  76. that->stNodeCache[Volume].bLeftValid &&
  77. that->stNodeCache[Volume].bRightValid)
  78. {
  79. // We get the master mono volume and the volume that is to change.
  80. // Then we substract master mono from it and write the value to the
  81. // register.
  82. lLevel = that->stNodeCache[Volume].lLeft +
  83. that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lLeft;
  84. // Translate the dB value into a register value.
  85. // Get the registered DB values
  86. ntStatus = GetDBValues (that->AdapterCommon, Volume,
  87. &lMinimum, &lMaximum, &uStep);
  88. if (!NT_SUCCESS(ntStatus))
  89. return ntStatus;
  90. // Check borders.
  91. if (lLevel < lMinimum) lLevel = lMinimum;
  92. if (lLevel > lMaximum) lLevel = lMaximum;
  93. // Calculate the register value
  94. wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep) << 8;
  95. // Get the right value too.
  96. lLevel = that->stNodeCache[Volume].lRight +
  97. that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lRight;
  98. // Check borders.
  99. if (lLevel < lMinimum) lLevel = lMinimum;
  100. if (lLevel > lMaximum) lLevel = lMaximum;
  101. // Add it to the register value.
  102. wRegister += (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
  103. // Write it.
  104. ntStatus = that->AdapterCommon->WriteCodecRegister (
  105. that->AdapterCommon->GetNodeReg (Volume),
  106. wRegister,
  107. that->AdapterCommon->GetNodeMask (Volume));
  108. DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x/0x%x", NodeStrings[Volume],
  109. that->stNodeCache[Volume].lLeft +
  110. that->stNodeCache[NODE_VIRT_MASTERMONO_VOLUME].lLeft,
  111. lLevel));
  112. }
  113. return ntStatus;
  114. }
  115. /*****************************************************************************
  116. * CMiniportTopologyICH::GetDBValues
  117. *****************************************************************************
  118. * This function is used internally and does no parameter checking. The only
  119. * parameter that could be invalid is the node.
  120. * It returns the dB values (means minimum, maximum, step) of the node control,
  121. * mainly for the property call "basic support". Sure, the node must be a
  122. * volume or tone control node, not a mute or mux node.
  123. */
  124. NTSTATUS CMiniportTopologyICH::GetDBValues
  125. (
  126. IN PADAPTERCOMMON AdapterCommon,
  127. IN TopoNodes Node,
  128. OUT LONG *plMinimum,
  129. OUT LONG *plMaximum,
  130. OUT ULONG *puStep
  131. )
  132. {
  133. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::GetDBValues]"));
  134. // This is going to be simple. Check the node and return the parameters.
  135. switch (Node)
  136. {
  137. // These nodes could have 5bit or 6bit controls, so we first
  138. // have to check this.
  139. case NODE_MASTEROUT_VOLUME:
  140. case NODE_FRONT_VOLUME:
  141. case NODE_HPOUT_VOLUME:
  142. case NODE_SURROUND_VOLUME:
  143. case NODE_CENTER_VOLUME:
  144. case NODE_LFE_VOLUME:
  145. case NODE_VIRT_MONOOUT_VOLUME1:
  146. case NODE_VIRT_MONOOUT_VOLUME2:
  147. // needed for the config query
  148. TopoNodeConfig config;
  149. // which node to query?
  150. config = NODEC_6BIT_MONOOUT_VOLUME;
  151. if ((Node == NODE_MASTEROUT_VOLUME) || (Node == NODE_FRONT_VOLUME))
  152. config = NODEC_6BIT_MASTER_VOLUME;
  153. if (Node == NODE_HPOUT_VOLUME)
  154. config = NODEC_6BIT_HPOUT_VOLUME;
  155. if (Node == NODE_SURROUND_VOLUME)
  156. config = NODEC_6BIT_SURROUND_VOLUME;
  157. if ((Node == NODE_CENTER_VOLUME) || (Node == NODE_LFE_VOLUME))
  158. config = NODEC_6BIT_CENTER_LFE_VOLUME;
  159. // check if we have 6th bit support.
  160. if (AdapterCommon->GetNodeConfig (config))
  161. {
  162. // 6bit control
  163. *plMaximum = 0; // 0 dB
  164. *plMinimum = 0xFFA18000; // -94.5 dB
  165. *puStep = 0x00018000; // 1.5 dB
  166. }
  167. else
  168. {
  169. // 5bit control
  170. *plMaximum = 0; // 0 dB
  171. *plMinimum = 0xFFD18000; // -46.5 dB
  172. *puStep = 0x00018000; // 1.5 dB
  173. }
  174. break;
  175. case NODE_VIRT_MASTERMONO_VOLUME:
  176. // This virtual control gets added to the speaker volumes.
  177. // We assume 5-bit volumes.
  178. *plMaximum = 0; // 0 dB
  179. *plMinimum = 0xFFD18000; // -46.5 dB
  180. *puStep = 0x00018000; // 1.5 dB
  181. break;
  182. case NODE_PCBEEP_VOLUME:
  183. *plMaximum = 0; // 0 dB
  184. *plMinimum = 0xFFD30000; // -45 dB
  185. *puStep = 0x00030000; // 3 dB
  186. break;
  187. case NODE_PHONE_VOLUME:
  188. case NODE_MICIN_VOLUME:
  189. case NODE_LINEIN_VOLUME:
  190. case NODE_CD_VOLUME:
  191. case NODE_VIDEO_VOLUME:
  192. case NODE_AUX_VOLUME:
  193. case NODE_WAVEOUT_VOLUME:
  194. *plMaximum = 0x000C0000; // 12 dB
  195. *plMinimum = 0xFFDD8000; // -34.5 dB
  196. *puStep = 0x00018000; // 1.5 dB
  197. break;
  198. case NODE_VIRT_MASTER_INPUT_VOLUME1:
  199. case NODE_VIRT_MASTER_INPUT_VOLUME2:
  200. case NODE_VIRT_MASTER_INPUT_VOLUME3:
  201. case NODE_VIRT_MASTER_INPUT_VOLUME4:
  202. case NODE_VIRT_MASTER_INPUT_VOLUME5:
  203. case NODE_VIRT_MASTER_INPUT_VOLUME6:
  204. case NODE_VIRT_MASTER_INPUT_VOLUME7:
  205. case NODE_VIRT_MASTER_INPUT_VOLUME8:
  206. case NODE_MIC_VOLUME:
  207. *plMaximum = 0x00168000; // 22.5 dB
  208. *plMinimum = 0; // 0 dB
  209. *puStep = 0x00018000; // 1.5 dB
  210. break;
  211. case NODE_BASS:
  212. case NODE_TREBLE:
  213. *plMaximum = 0x000A8000; // 10.5 dB
  214. *plMinimum = 0xFFF58000; // -10.5 dB
  215. *puStep = 0x00018000; // 1.5 dB
  216. break;
  217. // These nodes can be fixed or variable.
  218. // Normally we won't display a fixed volume slider, but if 3D is
  219. // supported and both sliders are fixed, we have to display one fixed
  220. // slider for the advanced control panel.
  221. case NODE_VIRT_3D_CENTER:
  222. case NODE_VIRT_3D_DEPTH:
  223. if (AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE) &&
  224. (Node == NODE_VIRT_3D_CENTER))
  225. {
  226. *plMaximum = 0x000F0000; // +15 dB
  227. *plMinimum = 0x00000000; // 0 dB
  228. *puStep = 0x00010000; // 1 dB
  229. }
  230. else
  231. if (AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) &&
  232. (Node == NODE_VIRT_3D_DEPTH))
  233. {
  234. *plMaximum = 0x000F0000; // +15 dB
  235. *plMinimum = 0x00000000; // 0 dB
  236. *puStep = 0x00010000; // 1 dB
  237. }
  238. else
  239. {
  240. // In case it is fixed, read the value and return it.
  241. WORD wRegister;
  242. // read the register
  243. if (!NT_SUCCESS (AdapterCommon->ReadCodecRegister (
  244. AdapterCommon->GetNodeReg (Node), &wRegister)))
  245. wRegister = 0; // in case we fail.
  246. // mask out the control
  247. wRegister &= AdapterCommon->GetNodeMask (Node);
  248. if (Node == NODE_VIRT_3D_CENTER)
  249. {
  250. wRegister >>= 8;
  251. }
  252. // calculate the dB value.
  253. *plMaximum = (DWORD)(-wRegister) << 16; // fixed value
  254. *plMinimum = (DWORD)(-wRegister) << 16; // fixed value
  255. *puStep = 0x00010000; // 1 dB
  256. }
  257. break;
  258. case NODE_INVALID:
  259. default:
  260. // poeser pupe, tu.
  261. DOUT (DBG_ERROR, ("GetDBValues: Invalid node requested."));
  262. return STATUS_INVALID_PARAMETER;
  263. }
  264. return STATUS_SUCCESS;
  265. }
  266. /*****************************************************************************
  267. * CMiniportTopologyICH::PropertyHandler_OnOff
  268. *****************************************************************************
  269. * Accesses a KSAUDIO_ONOFF value property.
  270. * This function (property handler) is called by portcls every time there is a
  271. * get or a set request for the node. The connection between the node type and
  272. * the property handler is made in the automation table which is referenced
  273. * when you register the node.
  274. * We use this property handler for all nodes that have a checkbox, means mute
  275. * controls and the special checkbox controls under advanced properties, which
  276. * are AGC and LOUDNESS.
  277. */
  278. NTSTATUS CMiniportTopologyICH::PropertyHandler_OnOff
  279. (
  280. IN PPCPROPERTY_REQUEST PropertyRequest
  281. )
  282. {
  283. PAGED_CODE ();
  284. ASSERT (PropertyRequest);
  285. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  286. LONG channel;
  287. TopoNodes NodeDef;
  288. // The major target is the object pointer to the topology miniport.
  289. CMiniportTopologyICH *that =
  290. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  291. ASSERT (that);
  292. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_OnOff]"));
  293. // validate node
  294. if (PropertyRequest->Node == (ULONG)-1)
  295. return ntStatus;
  296. // do the appropriate action for the request.
  297. // we should do a get or a set?
  298. if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) ||
  299. (PropertyRequest->Verb & KSPROPERTY_TYPE_SET))
  300. {
  301. // validate parameters
  302. if ((PropertyRequest->InstanceSize < sizeof(LONG)) ||
  303. (PropertyRequest->ValueSize < sizeof(BOOL)))
  304. return ntStatus;
  305. // get channel
  306. channel = *(PLONG)PropertyRequest->Instance;
  307. // check channel types, return when unknown
  308. // as you can see, we have no multichannel support.
  309. if ((channel != CHAN_LEFT) &&
  310. (channel != CHAN_RIGHT) &&
  311. (channel != CHAN_MASTER))
  312. return ntStatus;
  313. // We have only mono mutes or On/Off checkboxes although they might control
  314. // a stereo path. For example, we have a 1-bit mute for CD Volume. This
  315. // mute controls both CD Volume channels.
  316. if (channel == CHAN_RIGHT)
  317. return ntStatus;
  318. // get the buffer
  319. PBOOL OnOff = (PBOOL)PropertyRequest->Value;
  320. // Switch on the node id. This is just for parameter checking.
  321. // If something goes wrong, we will immediately return with
  322. // ntStatus, which is STATUS_INVALID_PARAMETER.
  323. switch (NodeDef = that->TransNodeNrToNodeDef (PropertyRequest->Node))
  324. {
  325. // These are mutes for mono volumes.
  326. case NODE_PCBEEP_MUTE:
  327. case NODE_PHONE_MUTE:
  328. case NODE_MIC_MUTE:
  329. case NODE_MICIN_MUTE:
  330. case NODE_CENTER_MUTE:
  331. case NODE_LFE_MUTE:
  332. case NODE_VIRT_MASTERMONO_MUTE:
  333. // check type
  334. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_MUTE)
  335. return ntStatus;
  336. break;
  337. // Well, this one is a AGC, although there is no _automatic_ gain
  338. // control, but we have a mic boost (which is some kind of manual
  339. // gain control).
  340. // The 3D Bypass is a real fake, but that's how you get check boxes
  341. // on the advanced control panel.
  342. // Both controls are in a mono path.
  343. case NODE_VIRT_WAVEOUT_3D_BYPASS:
  344. case NODE_MIC_BOOST:
  345. // check type
  346. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_AGC)
  347. return ntStatus;
  348. break;
  349. // Simulated Stereo is a AGC control in a stereo path.
  350. case NODE_SIMUL_STEREO:
  351. // check type
  352. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_AGC)
  353. return ntStatus;
  354. break;
  355. // This is a loudness control in a stereo path. We have to check the
  356. // type.
  357. case NODE_LOUDNESS:
  358. // check type
  359. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_LOUDNESS)
  360. return ntStatus;
  361. break;
  362. // For 3D Enable and Mic are exposed as loudness in a mono path.
  363. case NODE_VIRT_3D_ENABLE:
  364. case NODE_MIC_SELECT:
  365. // check type
  366. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_LOUDNESS)
  367. return ntStatus;
  368. break;
  369. // These are mutes in a stereo path.
  370. // Because the HW has only one mute-bit for the stereo channel, we
  371. // expose the mute as mono. this works in current OS and hopefully
  372. // will work in future OS.
  373. case NODE_WAVEOUT_MUTE:
  374. case NODE_LINEIN_MUTE:
  375. case NODE_CD_MUTE:
  376. case NODE_VIDEO_MUTE:
  377. case NODE_AUX_MUTE:
  378. case NODE_MASTEROUT_MUTE:
  379. case NODE_FRONT_MUTE:
  380. case NODE_SURROUND_MUTE:
  381. case NODE_HPOUT_MUTE:
  382. // just check the type.
  383. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_MUTE)
  384. return ntStatus;
  385. break;
  386. case NODE_INVALID:
  387. default:
  388. // Ooops.
  389. DOUT (DBG_ERROR, ("PropertyHandler_OnOff: Invalid node requested."));
  390. return ntStatus;
  391. }
  392. // Now, do some action!
  393. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  394. {
  395. WORD wRegister;
  396. // Read the HW register for the node except NODE_VIRT_MASTERMONO_MUTE,
  397. // since this is pure virtual.
  398. if (NodeDef != NODE_VIRT_MASTERMONO_MUTE)
  399. {
  400. // get the register and read it.
  401. ntStatus = that->AdapterCommon->ReadCodecRegister (
  402. that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
  403. if (!NT_SUCCESS (ntStatus))
  404. return ntStatus;
  405. // Mask out every unused bit.
  406. wRegister &= that->AdapterCommon->GetNodeMask (NodeDef);
  407. // Store the value.
  408. *OnOff = wRegister ? TRUE : FALSE;
  409. }
  410. else
  411. {
  412. // Assume no mute for master mono.
  413. *OnOff = FALSE;
  414. }
  415. // When we have cache information then return this instead of the
  416. // calculated value. If we don't, store the calculated value.
  417. if (that->stNodeCache[NodeDef].bLeftValid)
  418. *OnOff = that->stNodeCache[NodeDef].lLeft;
  419. else
  420. {
  421. that->stNodeCache[NodeDef].lLeft = *OnOff;
  422. that->stNodeCache[NodeDef].bLeftValid = -1;
  423. }
  424. PropertyRequest->ValueSize = sizeof(BOOL);
  425. DOUT (DBG_PROPERTY, ("GET: %s = 0x%x", NodeStrings[NodeDef], *OnOff));
  426. // Set the return code here.
  427. ntStatus = STATUS_SUCCESS;
  428. }
  429. else // this must be a set.
  430. {
  431. // First update the node cache.
  432. that->stNodeCache[NodeDef].bLeftValid = -1;
  433. that->stNodeCache[NodeDef].lLeft = (*OnOff) ? TRUE : FALSE;
  434. //
  435. // If we have a master mono, then we have to program the speaker
  436. // mutes a little different.
  437. // Check for master mono (surround or headphone present) and
  438. // if one of the speaker mutes is requested.
  439. //
  440. if ((that->AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
  441. that->AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT)) &&
  442. ((NodeDef == NODE_VIRT_MASTERMONO_MUTE) || (NodeDef == NODE_LFE_MUTE) ||
  443. (NodeDef == NODE_CENTER_MUTE) || (NodeDef == NODE_FRONT_MUTE) ||
  444. (NodeDef == NODE_SURROUND_MUTE) || (NodeDef == NODE_HPOUT_MUTE)))
  445. {
  446. //
  447. // For master mono we have to update all speakers.
  448. //
  449. if (NodeDef == NODE_VIRT_MASTERMONO_MUTE)
  450. {
  451. // Update all speaker mutes.
  452. ntStatus = SetMultichannelMute (that, NODE_FRONT_MUTE);
  453. if (that->AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
  454. ntStatus = SetMultichannelMute (that, NODE_HPOUT_MUTE);
  455. if (that->AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
  456. ntStatus = SetMultichannelMute (that, NODE_SURROUND_MUTE);
  457. if (that->AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
  458. {
  459. ntStatus = SetMultichannelMute (that, NODE_CENTER_MUTE);
  460. ntStatus = SetMultichannelMute (that, NODE_LFE_MUTE);
  461. }
  462. }
  463. else // Update the individual speaker mute.
  464. {
  465. ntStatus = SetMultichannelMute (that, NodeDef);
  466. }
  467. }
  468. else
  469. {
  470. //
  471. // For all other mutes/checkboxes just write the value to the HW.
  472. //
  473. ntStatus = that->AdapterCommon->WriteCodecRegister (
  474. that->AdapterCommon->GetNodeReg (NodeDef),
  475. (*OnOff) ? -1 : 0,
  476. that->AdapterCommon->GetNodeMask (NodeDef));
  477. }
  478. DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x", NodeStrings[NodeDef], *OnOff));
  479. // ntStatus was set with the write call! whatever this is, return it.
  480. }
  481. }
  482. return ntStatus;
  483. }
  484. /*****************************************************************************
  485. * CMiniportTopologyICH::BasicSupportHandler
  486. *****************************************************************************
  487. * Assists in BASICSUPPORT accesses on level properties.
  488. * This function is called internally every time there is a "basic support"
  489. * request on a volume or tone control. The basic support is used to retrieve
  490. * some information about the range of the control (from - to dB, steps) and
  491. * which type of control (tone, volume).
  492. * Basically, this function just calls GetDBValues to get the range information
  493. * and fills the rest of the structure with some constants.
  494. */
  495. NTSTATUS CMiniportTopologyICH::BasicSupportHandler
  496. (
  497. IN PPCPROPERTY_REQUEST PropertyRequest
  498. )
  499. {
  500. PAGED_CODE ();
  501. ASSERT (PropertyRequest);
  502. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::BasicSupportHandler]"));
  503. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  504. // The major target is the object pointer to the topology miniport.
  505. CMiniportTopologyICH *that =
  506. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  507. ASSERT (that);
  508. // if there is enough space for a KSPROPERTY_DESCRIPTION information
  509. if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  510. {
  511. // we return a KSPROPERTY_DESCRIPTION structure.
  512. PKSPROPERTY_DESCRIPTION PropDesc = (PKSPROPERTY_DESCRIPTION)PropertyRequest->Value;
  513. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  514. KSPROPERTY_TYPE_GET |
  515. KSPROPERTY_TYPE_SET;
  516. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION) +
  517. sizeof(KSPROPERTY_MEMBERSHEADER) +
  518. sizeof(KSPROPERTY_STEPPING_LONG);
  519. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  520. PropDesc->PropTypeSet.Id = VT_I4;
  521. PropDesc->PropTypeSet.Flags = 0;
  522. PropDesc->MembersListCount = 1;
  523. PropDesc->Reserved = 0;
  524. // if return buffer can also hold a range description, return it too
  525. if (PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION) +
  526. sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_STEPPING_LONG)))
  527. {
  528. // fill in the members header
  529. PKSPROPERTY_MEMBERSHEADER Members = (PKSPROPERTY_MEMBERSHEADER)(PropDesc + 1);
  530. Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
  531. Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
  532. Members->MembersCount = 1;
  533. Members->Flags = 0;
  534. // fill in the stepped range
  535. PKSPROPERTY_STEPPING_LONG Range = (PKSPROPERTY_STEPPING_LONG)(Members + 1);
  536. ntStatus = GetDBValues (that->AdapterCommon,
  537. that->TransNodeNrToNodeDef (PropertyRequest->Node),
  538. &Range->Bounds.SignedMinimum,
  539. &Range->Bounds.SignedMaximum,
  540. &Range->SteppingDelta);
  541. Range->Reserved = 0;
  542. // set the return value size
  543. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
  544. sizeof(KSPROPERTY_MEMBERSHEADER) +
  545. sizeof(KSPROPERTY_STEPPING_LONG);
  546. DOUT (DBG_PROPERTY, ("BASIC_SUPPORT: %s max=0x%x min=0x%x step=0x%x",
  547. NodeStrings[that->TransNodeNrToNodeDef (PropertyRequest->Node)],
  548. Range->Bounds.SignedMaximum, Range->Bounds.SignedMinimum,
  549. Range->SteppingDelta));
  550. } else
  551. {
  552. // we hadn't enough space for the range information;
  553. // set the return value size
  554. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  555. }
  556. ntStatus = STATUS_SUCCESS;
  557. }
  558. else if (PropertyRequest->ValueSize >= sizeof(ULONG))
  559. {
  560. // if return buffer can hold a ULONG, return the access flags
  561. PULONG AccessFlags = (PULONG)PropertyRequest->Value;
  562. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  563. KSPROPERTY_TYPE_GET |
  564. KSPROPERTY_TYPE_SET;
  565. // set the return value size
  566. PropertyRequest->ValueSize = sizeof(ULONG);
  567. ntStatus = STATUS_SUCCESS;
  568. }
  569. // In case there was not even enough space for a ULONG in the return buffer,
  570. // we fail this request with STATUS_INVALID_DEVICE_REQUEST.
  571. // Any other case will return STATUS_SUCCESS.
  572. return ntStatus;
  573. }
  574. /*****************************************************************************
  575. * CMiniportTopologyICH::PropertyHandler_Level
  576. *****************************************************************************
  577. * Accesses a KSAUDIO_LEVEL property.
  578. * This function (property handler) is called by portcls every time there is a
  579. * get, set or basic support request for the node. The connection between the
  580. * node type and the property handler is made in the automation table which is
  581. * referenced when you register the node.
  582. * We use this property handler for all volume controls (and virtual volume
  583. * controls for recording).
  584. */
  585. NTSTATUS CMiniportTopologyICH::PropertyHandler_Level
  586. (
  587. IN PPCPROPERTY_REQUEST PropertyRequest
  588. )
  589. {
  590. PAGED_CODE ();
  591. ASSERT (PropertyRequest);
  592. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_Level]"));
  593. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  594. TopoNodes NodeDef;
  595. LONG channel;
  596. LONG lMinimum, lMaximum;
  597. ULONG uStep;
  598. // The major target is the object pointer to the topology miniport.
  599. CMiniportTopologyICH *that =
  600. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  601. ASSERT (that);
  602. // validate node
  603. if (PropertyRequest->Node == (ULONG)-1)
  604. return ntStatus;
  605. // do the appropriate action for the request.
  606. // we should do a get or a set?
  607. if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) ||
  608. (PropertyRequest->Verb & KSPROPERTY_TYPE_SET))
  609. {
  610. // validate parameters
  611. if ((PropertyRequest->InstanceSize < sizeof(LONG)) ||
  612. (PropertyRequest->ValueSize < sizeof(LONG)))
  613. return ntStatus;
  614. // get channel information
  615. channel = *((PLONG)PropertyRequest->Instance);
  616. // check channel types, return when unknown
  617. // as you can see, we have no multichannel support.
  618. if ((channel != CHAN_LEFT) &&
  619. (channel != CHAN_RIGHT) &&
  620. (channel != CHAN_MASTER))
  621. return ntStatus;
  622. // get the buffer
  623. PLONG Level = (PLONG)PropertyRequest->Value;
  624. // Switch on the node id. This is just for parameter checking.
  625. // If something goes wrong, we will immideately return with
  626. // ntStatus, which is STATUS_INVALID_PARAMETER.
  627. switch(NodeDef = that->TransNodeNrToNodeDef (PropertyRequest->Node))
  628. {
  629. // these are mono channels, don't respond to a right channel
  630. // request.
  631. case NODE_PCBEEP_VOLUME:
  632. case NODE_PHONE_VOLUME:
  633. case NODE_MIC_VOLUME:
  634. case NODE_VIRT_MONOOUT_VOLUME1:
  635. case NODE_VIRT_MONOOUT_VOLUME2:
  636. case NODE_VIRT_MASTER_INPUT_VOLUME1:
  637. case NODE_VIRT_MASTER_INPUT_VOLUME7:
  638. case NODE_VIRT_MASTER_INPUT_VOLUME8:
  639. case NODE_MICIN_VOLUME:
  640. case NODE_VIRT_MASTERMONO_VOLUME:
  641. case NODE_CENTER_VOLUME:
  642. case NODE_LFE_VOLUME:
  643. // check type
  644. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_VOLUMELEVEL)
  645. return ntStatus;
  646. // check channel
  647. if (channel == CHAN_RIGHT)
  648. return ntStatus;
  649. // Well, this is a fake for the routine below that should work
  650. // for all nodes ... On AC97 the right channel are the LSBs and
  651. // mono channels have only LSBs used. Windows however thinks that
  652. // mono channels are left channels (only). So we could say here
  653. // we have a right channel request (to prg. the LSBs) instead of
  654. // a left channel request. But we have some controls that are HW-
  655. // stereo, but exposed to the system as mono. These are the virtual
  656. // volume controls in front of the wave-in muxer for the MIC, PHONE
  657. // and MONO MIX signals (see to the switch:
  658. // NODE_VIRT_MASTER_INPUT_VOLUME1, 7 and 8). Saying we have a MASTER
  659. // request makes sure the value is prg. for left and right channel,
  660. // but on HW-mono controls the right channel is prg. only, cause the
  661. // mask in ac97reg.h leads to a 0-mask for left channel prg. which
  662. // just does nothing ;)
  663. channel = CHAN_MASTER;
  664. break;
  665. // These are stereo channels.
  666. case NODE_MASTEROUT_VOLUME:
  667. case NODE_FRONT_VOLUME:
  668. case NODE_SURROUND_VOLUME:
  669. case NODE_HPOUT_VOLUME:
  670. case NODE_LINEIN_VOLUME:
  671. case NODE_CD_VOLUME:
  672. case NODE_VIDEO_VOLUME:
  673. case NODE_AUX_VOLUME:
  674. case NODE_WAVEOUT_VOLUME:
  675. case NODE_VIRT_MASTER_INPUT_VOLUME2:
  676. case NODE_VIRT_MASTER_INPUT_VOLUME3:
  677. case NODE_VIRT_MASTER_INPUT_VOLUME4:
  678. case NODE_VIRT_MASTER_INPUT_VOLUME5:
  679. case NODE_VIRT_MASTER_INPUT_VOLUME6:
  680. // check type
  681. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_VOLUMELEVEL)
  682. return ntStatus;
  683. // check channel; we don't support a get with master
  684. if ((channel == CHAN_MASTER) &&
  685. (PropertyRequest->Verb & KSPROPERTY_TYPE_GET))
  686. return ntStatus;
  687. break;
  688. case NODE_INVALID:
  689. default:
  690. // Ooops
  691. DOUT (DBG_ERROR, ("PropertyHandler_Level: Invalid node requested."));
  692. return ntStatus;
  693. }
  694. // Now, do some action!
  695. // get the registered dB values.
  696. ntStatus = GetDBValues (that->AdapterCommon, NodeDef, &lMinimum,
  697. &lMaximum, &uStep);
  698. if (!NT_SUCCESS (ntStatus))
  699. return ntStatus;
  700. // do a get
  701. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  702. {
  703. WORD wRegister;
  704. // Read the HW register for the node except NODE_VIRT_MASTERMONO_VOLUME
  705. // since this is pure virtual.
  706. if (NodeDef != NODE_VIRT_MASTERMONO_VOLUME)
  707. {
  708. // Get the register and read it.
  709. ntStatus = that->AdapterCommon->ReadCodecRegister (
  710. that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
  711. if (!NT_SUCCESS (ntStatus))
  712. return ntStatus;
  713. // mask out every unused bit and rotate.
  714. if (channel == CHAN_LEFT)
  715. {
  716. wRegister = (wRegister & (that->AdapterCommon->GetNodeMask (NodeDef)
  717. & AC97REG_MASK_LEFT)) >> 8;
  718. }
  719. else // here goes mono or stereo-right
  720. {
  721. wRegister &= (that->AdapterCommon->GetNodeMask (NodeDef) &
  722. AC97REG_MASK_RIGHT);
  723. }
  724. // Oops - NODE_PCBEEP_VOLUME doesn't use bit0. We have to adjust.
  725. if (NodeDef == NODE_PCBEEP_VOLUME)
  726. wRegister >>= 1;
  727. // we have to translate the reg to dB.dB value.
  728. switch (NodeDef)
  729. {
  730. // for record, we calculate it reverse.
  731. case NODE_VIRT_MASTER_INPUT_VOLUME1:
  732. case NODE_VIRT_MASTER_INPUT_VOLUME2:
  733. case NODE_VIRT_MASTER_INPUT_VOLUME3:
  734. case NODE_VIRT_MASTER_INPUT_VOLUME4:
  735. case NODE_VIRT_MASTER_INPUT_VOLUME5:
  736. case NODE_VIRT_MASTER_INPUT_VOLUME6:
  737. case NODE_VIRT_MASTER_INPUT_VOLUME7:
  738. case NODE_VIRT_MASTER_INPUT_VOLUME8:
  739. case NODE_MICIN_VOLUME:
  740. *Level = lMinimum + uStep * wRegister;
  741. break;
  742. default:
  743. *Level = lMaximum - uStep * wRegister;
  744. break;
  745. }
  746. // For the virtual controls, which are in front of a muxer, there
  747. // is no mute control displayed. But we have a HW mute control, so
  748. // what we do is enabling this mute when the user moves the slider
  749. // down to the bottom and disabling it on every other position.
  750. // We will return a PROP_MOST_NEGATIVE value in case the slider
  751. // is moved to the bottom.
  752. // We do this only for the "mono muxer" since the volume there ranges
  753. // from 0 to -46.5dB. The record volumes only have a range from
  754. // 0 to +22.5dB and we cannot mute them when the slider is down.
  755. if ((NodeDef == NODE_VIRT_MONOOUT_VOLUME1) ||
  756. (NodeDef == NODE_VIRT_MONOOUT_VOLUME2))
  757. {
  758. // read the register again.
  759. ntStatus = that->AdapterCommon->ReadCodecRegister (
  760. that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
  761. if (!NT_SUCCESS (ntStatus))
  762. return ntStatus;
  763. // return most negative value in case it is checked.
  764. if (wRegister & AC97REG_MASK_MUTE)
  765. *Level = PROP_MOST_NEGATIVE;
  766. }
  767. }
  768. else // This is master mono volume.
  769. {
  770. // Assume 0dB for master mono volume.
  771. *Level = 0;
  772. }
  773. // when we have cache information then return this instead
  774. // of the calculated value. if we don't, store the calculated
  775. // value.
  776. // We do that twice for master because in case we didn't set
  777. // the NodeCache yet it will be set then.
  778. if ((channel == CHAN_LEFT) || (channel == CHAN_MASTER))
  779. {
  780. if (that->stNodeCache[NodeDef].bLeftValid)
  781. *Level = that->stNodeCache[NodeDef].lLeft;
  782. else
  783. {
  784. that->stNodeCache[NodeDef].lLeft = *Level;
  785. that->stNodeCache[NodeDef].bLeftValid = -1;
  786. }
  787. }
  788. if ((channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
  789. {
  790. if (that->stNodeCache[NodeDef].bRightValid)
  791. *Level = that->stNodeCache[NodeDef].lRight;
  792. else
  793. {
  794. that->stNodeCache[NodeDef].lRight = *Level;
  795. that->stNodeCache[NodeDef].bRightValid = -1;
  796. }
  797. }
  798. // thats all, good bye.
  799. PropertyRequest->ValueSize = sizeof(LONG);
  800. DOUT (DBG_PROPERTY, ("GET: %s(%s) = 0x%x",NodeStrings[NodeDef],
  801. channel==CHAN_LEFT ? "L" : "R", *Level));
  802. // ntStatus was set with the read call! whatever this is, return it.
  803. }
  804. else // this must be a set
  805. {
  806. WORD wRegister;
  807. LONG lLevel = *Level;
  808. //
  809. // Check borders.
  810. //
  811. // These 2 lines will have a special effect on sndvol32.
  812. // Whenever you move the balance slider on a volume, one channel
  813. // keeps the same and the other volume channel gets descreased.
  814. // With ac97 on recording controls, the default slider position
  815. // is at 0dB and the range of the volume is 0dB till +22.5dB.
  816. // That means that panning (moving the balance slider) is simply
  817. // impossible. If you would store the volume like sndvol gives it
  818. // to you and you return it on a get, then the balance slider
  819. // moves and stays at the position the user wanted it. However,
  820. // if you return the actual volume the balance slider will jump
  821. // back to the position that the HW can do (play with it to see
  822. // how it works).
  823. //
  824. if (lLevel > lMaximum) lLevel = lMaximum;
  825. if (lLevel < lMinimum) lLevel = lMinimum;
  826. // First update the node cache.
  827. if ((channel == CHAN_LEFT) || (channel == CHAN_MASTER))
  828. {
  829. that->stNodeCache[NodeDef].bLeftValid = -1;
  830. that->stNodeCache[NodeDef].lLeft = lLevel;
  831. }
  832. if ((channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
  833. {
  834. that->stNodeCache[NodeDef].bRightValid = -1;
  835. that->stNodeCache[NodeDef].lRight = lLevel;
  836. }
  837. //
  838. // If we have a master mono, then we have to program the speaker
  839. // volumes a little different.
  840. // Check for master mono (surround or headphone present) and
  841. // if one of the speaker volumes is requested.
  842. //
  843. if ((that->AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT) ||
  844. that->AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT)) &&
  845. ((NodeDef == NODE_VIRT_MASTERMONO_VOLUME) || (NodeDef == NODE_LFE_VOLUME) ||
  846. (NodeDef == NODE_CENTER_VOLUME) || (NodeDef == NODE_FRONT_VOLUME) ||
  847. (NodeDef == NODE_SURROUND_VOLUME) || (NodeDef == NODE_HPOUT_VOLUME)))
  848. {
  849. //
  850. // For master mono we have to update all speaker volumes.
  851. //
  852. if (NodeDef == NODE_VIRT_MASTERMONO_VOLUME)
  853. {
  854. // Update all speaker volumes.
  855. ntStatus = SetMultichannelVolume (that, NODE_FRONT_VOLUME);
  856. if (that->AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
  857. ntStatus = SetMultichannelVolume (that, NODE_HPOUT_VOLUME);
  858. if (that->AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
  859. ntStatus = SetMultichannelVolume (that, NODE_SURROUND_VOLUME);
  860. if (that->AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
  861. {
  862. ntStatus = SetMultichannelVolume (that, NODE_CENTER_VOLUME);
  863. ntStatus = SetMultichannelVolume (that, NODE_LFE_VOLUME);
  864. }
  865. }
  866. else // update the individual speaker volume only.
  867. {
  868. ntStatus = SetMultichannelVolume (that, NodeDef);
  869. }
  870. }
  871. else // This is for all other volumes (or no master mono present).
  872. {
  873. // calculate the dB.dB value.
  874. // The nodes are calculated differently.
  875. switch (NodeDef)
  876. {
  877. // for record controls we calculate it 'reverse'.
  878. case NODE_VIRT_MASTER_INPUT_VOLUME1:
  879. case NODE_VIRT_MASTER_INPUT_VOLUME2:
  880. case NODE_VIRT_MASTER_INPUT_VOLUME3:
  881. case NODE_VIRT_MASTER_INPUT_VOLUME4:
  882. case NODE_VIRT_MASTER_INPUT_VOLUME5:
  883. case NODE_VIRT_MASTER_INPUT_VOLUME6:
  884. case NODE_VIRT_MASTER_INPUT_VOLUME7:
  885. case NODE_VIRT_MASTER_INPUT_VOLUME8:
  886. // read the wavein selector.
  887. ntStatus = that->AdapterCommon->ReadCodecRegister (
  888. that->AdapterCommon->GetNodeReg (NODE_WAVEIN_SELECT),
  889. &wRegister);
  890. if (!NT_SUCCESS (ntStatus))
  891. return ntStatus;
  892. // mask out every unused bit.
  893. wRegister &= (that->AdapterCommon->GetNodeMask (
  894. NODE_WAVEIN_SELECT) & AC97REG_MASK_RIGHT);
  895. // check if the volume that we change belongs to the active
  896. // (selected) virtual channel.
  897. // Tricky: If the virtual nodes are not defined consecutively
  898. // this comparision will fail.
  899. if ((NodeDef - NODE_VIRT_MASTER_INPUT_VOLUME1) != wRegister)
  900. return ntStatus;
  901. // fall through for calculation.
  902. case NODE_MICIN_VOLUME:
  903. wRegister = (WORD)(((lLevel + uStep / 2) - lMinimum) / uStep);
  904. break;
  905. case NODE_VIRT_MONOOUT_VOLUME1:
  906. case NODE_VIRT_MONOOUT_VOLUME2:
  907. // read the monoout selector.
  908. ntStatus = that->AdapterCommon->ReadCodecRegister (
  909. that->AdapterCommon->GetNodeReg (NODE_MONOOUT_SELECT),
  910. &wRegister);
  911. if (!NT_SUCCESS (ntStatus))
  912. return ntStatus;
  913. // mask out every unused bit.
  914. wRegister &= that->AdapterCommon->GetNodeMask (NODE_MONOOUT_SELECT);
  915. // check if the volume that we change belongs to the active
  916. // (selected) virtual channel.
  917. // Note: Monout select is set if we want to prg. MIC (Volume2).
  918. if ((!wRegister && (NodeDef == NODE_VIRT_MONOOUT_VOLUME2)) ||
  919. (wRegister && (NodeDef == NODE_VIRT_MONOOUT_VOLUME1)))
  920. return ntStatus;
  921. // fall through for calculation.
  922. default:
  923. wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
  924. break;
  925. }
  926. // Oops - NODE_PCBEEP_VOLUME doesn't use bit0. We have to adjust.
  927. if (NodeDef == NODE_PCBEEP_VOLUME)
  928. wRegister <<= 1;
  929. // write the stuff (with mask!).
  930. // Note: mono channels are 'master' here (see fake above).
  931. // this makes sure that left and right channel is prg. for the virt.
  932. // controls. On controls that only have the right channel, the left
  933. // channel programming does nothing cause the mask will be zero.
  934. if ((channel == CHAN_LEFT) || (channel == CHAN_MASTER))
  935. {
  936. // write only left.
  937. ntStatus = that->AdapterCommon->WriteCodecRegister (
  938. that->AdapterCommon->GetNodeReg (NodeDef),
  939. wRegister << 8,
  940. that->AdapterCommon->GetNodeMask (NodeDef) & AC97REG_MASK_LEFT);
  941. // immediately return on error
  942. if (!NT_SUCCESS (ntStatus))
  943. return ntStatus;
  944. }
  945. if ((channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
  946. {
  947. // write only right.
  948. ntStatus = that->AdapterCommon->WriteCodecRegister (
  949. that->AdapterCommon->GetNodeReg (NodeDef),
  950. wRegister,
  951. that->AdapterCommon->GetNodeMask (NodeDef) & AC97REG_MASK_RIGHT);
  952. // immediately return on error
  953. if (!NT_SUCCESS (ntStatus))
  954. return ntStatus;
  955. }
  956. // For the virtual controls, which are in front of a muxer, there
  957. // is no mute control displayed. But we have a HW mute control, so
  958. // what we do is enabling this mute when the user moves the slider
  959. // down to the bottom and disabling it on every other position.
  960. // We do this only for the "mono muxer", the recording mutes will
  961. // never be muted.
  962. // Tricky: Master input virtual controls must be defined consecutively.
  963. if ((NodeDef >= NODE_VIRT_MASTER_INPUT_VOLUME1) &&
  964. (NodeDef <= NODE_VIRT_MASTER_INPUT_VOLUME8))
  965. {
  966. // disable the mute; this only works because the mute and volume
  967. // share the same register.
  968. ntStatus = that->AdapterCommon->WriteCodecRegister (
  969. that->AdapterCommon->GetNodeReg (NodeDef),
  970. 0, AC97REG_MASK_MUTE);
  971. // Just in case.
  972. that->UpdateRecordMute ();
  973. }
  974. if ((NodeDef == NODE_VIRT_MONOOUT_VOLUME1) ||
  975. (NodeDef == NODE_VIRT_MONOOUT_VOLUME2))
  976. {
  977. // these are only mono controls so checking one entry is enough.
  978. if ( that->stNodeCache[NodeDef].bLeftValid &&
  979. (that->stNodeCache[NodeDef].lLeft <= lMinimum))
  980. {
  981. // set the mute; this only works because the mute and volume
  982. // share the same register.
  983. ntStatus = that->AdapterCommon->WriteCodecRegister (
  984. that->AdapterCommon->GetNodeReg (NodeDef),
  985. AC97REG_MASK_MUTE, AC97REG_MASK_MUTE);
  986. }
  987. else
  988. {
  989. // clear the mute; this only works because the mute and volume
  990. // share the same register.
  991. ntStatus = that->AdapterCommon->WriteCodecRegister (
  992. that->AdapterCommon->GetNodeReg (NodeDef),
  993. 0, AC97REG_MASK_MUTE);
  994. }
  995. }
  996. }
  997. DOUT (DBG_PROPERTY, ("SET: %s(%s) -> 0x%x", NodeStrings[NodeDef],
  998. channel==CHAN_LEFT ? "L" : channel==CHAN_RIGHT ? "R" : "M",
  999. *Level));
  1000. // ntStatus was set with the read call! whatever this is, return it.
  1001. }
  1002. }
  1003. else
  1004. {
  1005. if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1006. {
  1007. ntStatus = BasicSupportHandler (PropertyRequest);
  1008. }
  1009. }
  1010. return ntStatus;
  1011. }
  1012. /*****************************************************************************
  1013. * CMiniportTopologyICH::PropertyHandler_Tone
  1014. *****************************************************************************
  1015. * Accesses a KSAUDIO_TONE property.
  1016. * This function (property handler) is called by portcls every time there is a
  1017. * get, set or basic support request for the node. The connection between the
  1018. * node type and the property handler is made in the automation table which is
  1019. * referenced when you register the node.
  1020. * We use this property handler for all tone controls displayed at the advanced
  1021. * property dialog in sndvol32 and the 3D controls displayed and exposed as
  1022. * normal volume controls.
  1023. */
  1024. NTSTATUS CMiniportTopologyICH::PropertyHandler_Tone
  1025. (
  1026. IN PPCPROPERTY_REQUEST PropertyRequest
  1027. )
  1028. {
  1029. PAGED_CODE ();
  1030. ASSERT (PropertyRequest);
  1031. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_Tone]"));
  1032. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  1033. TopoNodes NodeDef;
  1034. LONG lMinimum, lMaximum;
  1035. ULONG uStep;
  1036. // The major target is the object pointer to the topology miniport.
  1037. CMiniportTopologyICH *that =
  1038. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  1039. ASSERT (that);
  1040. // validate node
  1041. if (PropertyRequest->Node == (ULONG)-1)
  1042. return ntStatus;
  1043. // do the appropriate action for the request.
  1044. // we should do a get or a set?
  1045. if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) ||
  1046. (PropertyRequest->Verb & KSPROPERTY_TYPE_SET))
  1047. {
  1048. // validate parameters
  1049. if ((PropertyRequest->InstanceSize < sizeof(LONG)) ||
  1050. (PropertyRequest->ValueSize < sizeof(LONG)))
  1051. return ntStatus;
  1052. // get the buffer
  1053. PLONG Level = (PLONG)PropertyRequest->Value;
  1054. // Switch on the node id. This is just for parameter checking.
  1055. // If something goes wrong, we will immideately return with
  1056. // ntStatus, which is STATUS_INVALID_PARAMETER.
  1057. switch(NodeDef = that->TransNodeNrToNodeDef (PropertyRequest->Node))
  1058. {
  1059. case NODE_BASS:
  1060. // check type.
  1061. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_BASS)
  1062. return ntStatus;
  1063. break;
  1064. case NODE_TREBLE:
  1065. // check type.
  1066. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_TREBLE)
  1067. return ntStatus;
  1068. break;
  1069. case NODE_VIRT_3D_CENTER:
  1070. case NODE_VIRT_3D_DEPTH:
  1071. // check 3D control
  1072. if (!that->AdapterCommon->GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE)
  1073. && (NodeDef == NODE_VIRT_3D_CENTER))
  1074. return ntStatus;
  1075. if (!that->AdapterCommon->GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE)
  1076. && (NodeDef == NODE_VIRT_3D_DEPTH))
  1077. return ntStatus;
  1078. // check type
  1079. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_VOLUMELEVEL)
  1080. return ntStatus;
  1081. // check channel
  1082. if (*(PLONG(PropertyRequest->Instance)) == CHAN_RIGHT)
  1083. return ntStatus;
  1084. break;
  1085. case NODE_INVALID:
  1086. default:
  1087. // Ooops
  1088. DOUT (DBG_ERROR, ("PropertyHandler_Tone: Invalid node requested."));
  1089. return ntStatus;
  1090. }
  1091. // Now, do some action!
  1092. // get the registered DB values
  1093. ntStatus = GetDBValues (that->AdapterCommon, NodeDef, &lMinimum,
  1094. &lMaximum, &uStep);
  1095. if (!NT_SUCCESS (ntStatus))
  1096. return ntStatus;
  1097. // do a get
  1098. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1099. {
  1100. WORD wRegister;
  1101. // first get the stuff.
  1102. ntStatus = that->AdapterCommon->ReadCodecRegister (
  1103. that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
  1104. if (!NT_SUCCESS (ntStatus))
  1105. return ntStatus;
  1106. // mask out every unused bit.
  1107. wRegister &= that->AdapterCommon->GetNodeMask (NodeDef);
  1108. // rotate if bass tone control or 3D center control
  1109. if ((NodeDef == NODE_BASS) || (NodeDef == NODE_VIRT_3D_CENTER))
  1110. wRegister >>= 8;
  1111. // convert from reg to dB.dB value.
  1112. if ((NodeDef == NODE_VIRT_3D_CENTER) ||
  1113. (NodeDef == NODE_VIRT_3D_DEPTH))
  1114. {
  1115. // That's for the 3D controls
  1116. *Level = lMinimum + uStep * wRegister;
  1117. }
  1118. else
  1119. {
  1120. if (wRegister == 0x000F)
  1121. *Level = 0; // bypass
  1122. else
  1123. // And that's for the tone controls
  1124. *Level = lMaximum - uStep * wRegister;
  1125. }
  1126. // when we have cache information then return this instead
  1127. // of the calculated value. if we don't, store the calculated
  1128. // value.
  1129. if (that->stNodeCache[NodeDef].bLeftValid)
  1130. *Level = that->stNodeCache[NodeDef].lLeft;
  1131. else
  1132. {
  1133. that->stNodeCache[NodeDef].lLeft = *Level;
  1134. that->stNodeCache[NodeDef].bLeftValid = -1;
  1135. }
  1136. // we return a LONG
  1137. PropertyRequest->ValueSize = sizeof(LONG);
  1138. DOUT (DBG_PROPERTY, ("GET: %s = 0x%x", NodeStrings[NodeDef], *Level));
  1139. // ntStatus was set with the read call! whatever this is, return it.
  1140. }
  1141. else // that must be a set
  1142. {
  1143. WORD wRegister;
  1144. LONG lLevel = *Level;
  1145. // calculate the dB.dB value.
  1146. // check borders.
  1147. if (lLevel > lMaximum) lLevel = lMaximum;
  1148. if (lLevel < lMinimum) lLevel = lMinimum;
  1149. // write the value to the node cache.
  1150. that->stNodeCache[NodeDef].lLeft = *Level;
  1151. that->stNodeCache[NodeDef].bLeftValid = -1;
  1152. // convert from dB.dB value to reg.
  1153. if ((NodeDef == NODE_VIRT_3D_CENTER) ||
  1154. (NodeDef == NODE_VIRT_3D_DEPTH))
  1155. {
  1156. // For 3D controls
  1157. wRegister = (WORD)(((lLevel + uStep / 2) - lMinimum) / uStep);
  1158. }
  1159. else
  1160. {
  1161. // For tone controls
  1162. wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
  1163. // We don't prg. 0dB Bass or 0dB Treble, instead we smartly prg.
  1164. // a bypass which is reg. value 0x0F.
  1165. if (wRegister == 7) // 0 dB
  1166. wRegister = 0x000F; // bypass
  1167. }
  1168. // rotate if bass tone control or 3D center control
  1169. if ((NodeDef == NODE_BASS) || (NodeDef == NODE_VIRT_3D_CENTER))
  1170. wRegister <<= 8;
  1171. // write the stuff.
  1172. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1173. that->AdapterCommon->GetNodeReg (NodeDef),
  1174. wRegister,
  1175. that->AdapterCommon->GetNodeMask (NodeDef));
  1176. DOUT (DBG_PROPERTY,("SET: %s -> 0x%x", NodeStrings[NodeDef], *Level));
  1177. // ntStatus was set with the write call! whatever this is, return in.
  1178. }
  1179. }
  1180. else
  1181. {
  1182. if (PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1183. {
  1184. ntStatus = BasicSupportHandler (PropertyRequest);
  1185. }
  1186. }
  1187. return ntStatus;
  1188. }
  1189. /*****************************************************************************
  1190. * CMiniportTopologyICH::PropertyHandler_Ulong
  1191. *****************************************************************************
  1192. * Accesses a ULONG value property. For MUX and DEMUX.
  1193. * This function (property handler) is called by portcls every time there is a
  1194. * get, set or basic support request for the node. The connection between the
  1195. * node type and the property handler is made in the automation table which is
  1196. * referenced when you register the node.
  1197. * We use this property handler for all muxer controls.
  1198. */
  1199. NTSTATUS CMiniportTopologyICH::PropertyHandler_Ulong
  1200. (
  1201. IN PPCPROPERTY_REQUEST PropertyRequest
  1202. )
  1203. {
  1204. PAGED_CODE ();
  1205. ASSERT (PropertyRequest);
  1206. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_Ulong]"));
  1207. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  1208. TopoNodes NodeDef;
  1209. LONG lMinimum, lMaximum;
  1210. ULONG uStep;
  1211. // The major target is the object pointer to the topology miniport.
  1212. CMiniportTopologyICH *that =
  1213. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  1214. ASSERT (that);
  1215. // validate node instance
  1216. if (PropertyRequest->Node == (ULONG)-1)
  1217. return ntStatus;
  1218. // if we should do a get or set.
  1219. if ((PropertyRequest->Verb & KSPROPERTY_TYPE_GET) ||
  1220. (PropertyRequest->Verb & KSPROPERTY_TYPE_SET))
  1221. {
  1222. // validate buffer size.
  1223. if (PropertyRequest->ValueSize < sizeof(ULONG))
  1224. return ntStatus;
  1225. // get the pointer to the buffer.
  1226. PULONG PropValue = (PULONG)PropertyRequest->Value;
  1227. // Switch on the node id. This is just for parameter checking.
  1228. // If something goes wrong, we will immideately return with
  1229. // ntStatus, which is STATUS_INVALID_PARAMETER.
  1230. switch(NodeDef = that->TransNodeNrToNodeDef (PropertyRequest->Node))
  1231. {
  1232. case NODE_MONOOUT_SELECT:
  1233. case NODE_WAVEIN_SELECT:
  1234. // check the type
  1235. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AUDIO_MUX_SOURCE)
  1236. return ntStatus;
  1237. break;
  1238. case NODE_INVALID:
  1239. default:
  1240. // Ooops
  1241. DOUT (DBG_ERROR, ("PropertyHandler_Tone: Invalid node requested."));
  1242. return ntStatus;
  1243. }
  1244. // Now do some action!
  1245. // should we return the value?
  1246. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1247. {
  1248. WORD wRegister;
  1249. // first get the stuff.
  1250. ntStatus = that->AdapterCommon->ReadCodecRegister (
  1251. that->AdapterCommon->GetNodeReg (NodeDef), &wRegister);
  1252. if (!NT_SUCCESS (ntStatus))
  1253. return ntStatus;
  1254. // mask out every unused bit.
  1255. wRegister &= that->AdapterCommon->GetNodeMask (NodeDef);
  1256. // calculate the selected pin
  1257. if (NodeDef == NODE_MONOOUT_SELECT)
  1258. {
  1259. // for mono out we have just one bit
  1260. if (wRegister)
  1261. *PropValue = 2;
  1262. else
  1263. *PropValue = 1;
  1264. }
  1265. else
  1266. {
  1267. // the wave in muxer is a stereo muxer, so just return the
  1268. // right channel (gives values 0-7) and adjust it by adding 1.
  1269. *PropValue = (wRegister & AC97REG_MASK_RIGHT) + 1;
  1270. }
  1271. // we return a LONG
  1272. PropertyRequest->ValueSize = sizeof(LONG);
  1273. DOUT (DBG_PROPERTY, ("GET: %s = 0x%x", NodeStrings[NodeDef],
  1274. *PropValue));
  1275. // ntStatus was set with the read call! whatever this is, return it.
  1276. }
  1277. else // that must be a set
  1278. {
  1279. TopoNodes VirtNode;
  1280. WORD wRegister;
  1281. ULONG ulSelect = *PropValue;
  1282. LONG lLevel;
  1283. // Check the selection first.
  1284. if (NodeDef == NODE_MONOOUT_SELECT)
  1285. {
  1286. if ((ulSelect < 1) || (ulSelect > 2))
  1287. return ntStatus; // STATUS_INVALID_PARAMETER
  1288. }
  1289. else
  1290. {
  1291. if ((ulSelect < 1) || (ulSelect > 8))
  1292. return ntStatus; // STATUS_INVALID_PARAMETER
  1293. }
  1294. // calculate the register value for programming.
  1295. if (NodeDef == NODE_MONOOUT_SELECT)
  1296. {
  1297. // for mono out we have just one bit
  1298. if (ulSelect == 2)
  1299. // the mask will make sure we only prg. one bit.
  1300. wRegister = -1;
  1301. else
  1302. // ulSelect == 1
  1303. wRegister = 0;
  1304. }
  1305. else
  1306. {
  1307. // *257 is the same as: (ulSelect << 8) + ulSelect
  1308. wRegister = (WORD)(ulSelect - 1) * 257;
  1309. }
  1310. // write the stuff.
  1311. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1312. that->AdapterCommon->GetNodeReg (NodeDef),
  1313. wRegister,
  1314. that->AdapterCommon->GetNodeMask (NodeDef));
  1315. // Store the virt. node for later use.
  1316. // Tricky: Master input virtual controls must be defined consecutively.
  1317. if (NodeDef == NODE_MONOOUT_SELECT)
  1318. VirtNode = (TopoNodes)(NODE_VIRT_MONOOUT_VOLUME1 + (ulSelect - 1));
  1319. else
  1320. VirtNode = (TopoNodes)(NODE_VIRT_MASTER_INPUT_VOLUME1 + (ulSelect - 1));
  1321. // Virtual controls make our life more complicated. When the user
  1322. // changes the input source say from CD to LiniIn, then the system just
  1323. // sends a message to the input muxer that the selection changed.
  1324. // Cause we have only one HW register for the input muxer, all volumes
  1325. // displayed for the user are "virtualized", means they are not there,
  1326. // and when the selection changes, we have to prg. the volume of the
  1327. // selected input to the HW register. That's what we do now.
  1328. // get the registered DB values
  1329. ntStatus = GetDBValues (that->AdapterCommon, VirtNode,
  1330. &lMinimum, &lMaximum, &uStep);
  1331. if (!NT_SUCCESS (ntStatus))
  1332. return ntStatus;
  1333. // We can be lazy here and don't check for mono controls. Reason
  1334. // is that the level handler writes the volume value for mono
  1335. // controls into both the left and right node cache ;))
  1336. if (that->stNodeCache[VirtNode].bLeftValid &&
  1337. that->stNodeCache[VirtNode].bRightValid)
  1338. {
  1339. // prg. left channel
  1340. lLevel = that->stNodeCache[VirtNode].lLeft;
  1341. // calculate the dB.dB value.
  1342. if (NodeDef == NODE_MONOOUT_SELECT)
  1343. wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
  1344. else
  1345. wRegister = (WORD)(((lLevel + uStep / 2) - lMinimum) / uStep);
  1346. // write left channel.
  1347. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1348. that->AdapterCommon->GetNodeReg (VirtNode),
  1349. wRegister << 8,
  1350. that->AdapterCommon->GetNodeMask (VirtNode) & AC97REG_MASK_LEFT);
  1351. // prg. right channel
  1352. lLevel = that->stNodeCache[VirtNode].lRight;
  1353. // calculate the dB.dB value.
  1354. if (NodeDef == NODE_MONOOUT_SELECT)
  1355. wRegister = (WORD)(((lMaximum + uStep / 2) - lLevel) / uStep);
  1356. else
  1357. wRegister = (WORD)(((lLevel + uStep / 2) - lMinimum) / uStep);
  1358. // write right channel.
  1359. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1360. that->AdapterCommon->GetNodeReg (VirtNode),
  1361. wRegister,
  1362. that->AdapterCommon->GetNodeMask (VirtNode) & AC97REG_MASK_RIGHT);
  1363. // For the virtual controls, which are in front of a muxer, there
  1364. // is no mute control displayed. But we have a HW mute control, so
  1365. // what we do is enabling this mute when the user moves the slider
  1366. // down to the bottom and disabling it on every other position.
  1367. // We do this only for the "mono muxer", the recording mutes will
  1368. // never be muted.
  1369. if (NodeDef == NODE_WAVEIN_SELECT)
  1370. {
  1371. // disable the mute; this only works because the mute and volume
  1372. // share the same register.
  1373. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1374. that->AdapterCommon->GetNodeReg (VirtNode),
  1375. 0, AC97REG_MASK_MUTE);
  1376. that->UpdateRecordMute ();
  1377. }
  1378. if (NodeDef == NODE_MONOOUT_SELECT)
  1379. {
  1380. // these are only mono controls so checking one entry is enough.
  1381. if ( that->stNodeCache[VirtNode].bLeftValid &&
  1382. (that->stNodeCache[VirtNode].lLeft <= lMinimum))
  1383. {
  1384. // set the mute; this only works because the mute and volume
  1385. // share the same register.
  1386. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1387. that->AdapterCommon->GetNodeReg (VirtNode),
  1388. AC97REG_MASK_MUTE, AC97REG_MASK_MUTE);
  1389. }
  1390. else
  1391. {
  1392. // clear the mute; this only works because the mute and volume
  1393. // share the same register.
  1394. ntStatus = that->AdapterCommon->WriteCodecRegister (
  1395. that->AdapterCommon->GetNodeReg (VirtNode),
  1396. 0, AC97REG_MASK_MUTE);
  1397. }
  1398. }
  1399. }
  1400. DOUT (DBG_PROPERTY, ("SET: %s -> 0x%x", NodeStrings[NodeDef],
  1401. *PropValue));
  1402. // ntStatus was set with the write call! whatever this is, return it.
  1403. }
  1404. }
  1405. return ntStatus;
  1406. }
  1407. /*****************************************************************************
  1408. * CMiniportTopologyICH::PropertyHandler_CpuResources
  1409. *****************************************************************************
  1410. * Propcesses a KSPROPERTY_AUDIO_CPU_RESOURCES request
  1411. * This property handler is called by the system for every node and every node
  1412. * must support this property. Basically, this property is for performance
  1413. * monitoring and we just say here that every function we claim to have has HW
  1414. * support (which by the way is true).
  1415. */
  1416. NTSTATUS CMiniportTopologyICH::PropertyHandler_CpuResources
  1417. (
  1418. IN PPCPROPERTY_REQUEST PropertyRequest
  1419. )
  1420. {
  1421. PAGED_CODE ();
  1422. ASSERT (PropertyRequest);
  1423. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_CpuResources]"));
  1424. CMiniportTopologyICH *that =
  1425. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  1426. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1427. ASSERT (that);
  1428. // validate node
  1429. if (PropertyRequest->Node == (ULONG)-1)
  1430. return ntStatus;
  1431. // validate the node def.
  1432. if (that->TransNodeNrToNodeDef (PropertyRequest->Node) == NODE_INVALID)
  1433. return ntStatus;
  1434. // we should do a get
  1435. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1436. {
  1437. // just return the flag.
  1438. if (PropertyRequest->ValueSize >= sizeof(LONG))
  1439. {
  1440. *((PLONG)PropertyRequest->Value) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
  1441. PropertyRequest->ValueSize = sizeof(LONG);
  1442. ntStatus = STATUS_SUCCESS;
  1443. }
  1444. else // not enough buffer.
  1445. {
  1446. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1447. }
  1448. }
  1449. return ntStatus;
  1450. }
  1451. #ifdef INCLUDE_PRIVATE_PROPERTY
  1452. /*****************************************************************************
  1453. * CMiniportTopologyICH::PropertyHandler_Private
  1454. *****************************************************************************
  1455. * This is a private property that returns some AC97 codec features.
  1456. * This routine gets called whenever the topology filter gets a property
  1457. * request with KSPROSETPID_Private and KSPROPERTY_AC97_FEATURES set. It is not
  1458. * a node property but a filter property (you don't have to specify a node).
  1459. */
  1460. NTSTATUS CMiniportTopologyICH::PropertyHandler_Private
  1461. (
  1462. IN PPCPROPERTY_REQUEST PropertyRequest
  1463. )
  1464. {
  1465. PAGED_CODE ();
  1466. ASSERT (PropertyRequest);
  1467. DOUT (DBG_PRINT, ("[CMiniportTopologyICH::PropertyHandler_Private]"));
  1468. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  1469. // The major target is the object pointer to the topology miniport.
  1470. CMiniportTopologyICH *that =
  1471. (CMiniportTopologyICH *) PropertyRequest->MajorTarget;
  1472. ASSERT (that);
  1473. // We only have a get defined.
  1474. if (PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1475. {
  1476. // Check the ID ("function" in "group").
  1477. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AC97_FEATURES)
  1478. return ntStatus;
  1479. // validate buffer size.
  1480. if (PropertyRequest->ValueSize < sizeof (tAC97Features))
  1481. return ntStatus;
  1482. // The "Value" is the out buffer that you pass in DeviceIoControl call.
  1483. tAC97Features *pAC97Features = (tAC97Features *) PropertyRequest->Value;
  1484. // Check the buffer.
  1485. if (!pAC97Features)
  1486. return ntStatus;
  1487. //
  1488. // Fill the AC97Features structure.
  1489. //
  1490. // Set the volumes.
  1491. pAC97Features->MasterVolume = Volume5bit;
  1492. if (that->AdapterCommon->GetNodeConfig (NODEC_6BIT_MASTER_VOLUME))
  1493. pAC97Features->MasterVolume = Volume6bit;
  1494. pAC97Features->HeadphoneVolume = Volume5bit;
  1495. if (!that->AdapterCommon->GetPinConfig (PINC_HPOUT_PRESENT))
  1496. pAC97Features->HeadphoneVolume = VolumeDisabled;
  1497. else if (that->AdapterCommon->GetNodeConfig (NODEC_6BIT_HPOUT_VOLUME))
  1498. pAC97Features->HeadphoneVolume = Volume6bit;
  1499. pAC97Features->MonoOutVolume = Volume5bit;
  1500. if (!that->AdapterCommon->GetPinConfig (PINC_MONOOUT_PRESENT))
  1501. pAC97Features->MonoOutVolume = VolumeDisabled;
  1502. else if (that->AdapterCommon->GetNodeConfig (NODEC_6BIT_MONOOUT_VOLUME))
  1503. pAC97Features->MonoOutVolume = Volume6bit;
  1504. // The 18/20bit Resolution information.
  1505. WORD wCodecID;
  1506. // Read the reset register.
  1507. ntStatus = that->AdapterCommon->ReadCodecRegister (AC97REG_RESET, &wCodecID);
  1508. if (!NT_SUCCESS (ntStatus))
  1509. return ntStatus;
  1510. //
  1511. // Now check the DAC and ADC resolution.
  1512. //
  1513. // First the DAC.
  1514. pAC97Features->DAC = Resolution16bit;
  1515. if (wCodecID & 0x0040)
  1516. pAC97Features->DAC = Resolution18bit;
  1517. if (wCodecID & 0x0080)
  1518. pAC97Features->DAC = Resolution20bit;
  1519. // Then the ADC.
  1520. pAC97Features->ADC = Resolution16bit;
  1521. if (wCodecID & 0x0100)
  1522. pAC97Features->ADC = Resolution18bit;
  1523. if (wCodecID & 0x0200)
  1524. pAC97Features->ADC = Resolution20bit;
  1525. // 3D technique
  1526. pAC97Features->n3DTechnique = ((wCodecID & 0x7C00) >> 10);
  1527. // Set the flag for MicIn.
  1528. pAC97Features->bMicInPresent = that->AdapterCommon->
  1529. GetPinConfig (PINC_MICIN_PRESENT) ? TRUE : FALSE;
  1530. // Variable sample rate info.
  1531. pAC97Features->bVSRPCM = that->AdapterCommon->
  1532. GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED) ? TRUE : FALSE;
  1533. pAC97Features->bDSRPCM = that->AdapterCommon->
  1534. GetNodeConfig (NODEC_PCM_DOUBLERATE_SUPPORTED) ? TRUE : FALSE;
  1535. pAC97Features->bVSRMIC = that->AdapterCommon->
  1536. GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED) ? TRUE : FALSE;
  1537. // Additional DAC's
  1538. pAC97Features->bCenterDAC = that->AdapterCommon->
  1539. GetNodeConfig (NODEC_CENTER_DAC_PRESENT) ? TRUE : FALSE;
  1540. pAC97Features->bSurroundDAC = that->AdapterCommon->
  1541. GetNodeConfig (NODEC_SURROUND_DAC_PRESENT) ? TRUE : FALSE;
  1542. pAC97Features->bLFEDAC = that->AdapterCommon->
  1543. GetNodeConfig (NODEC_LFE_DAC_PRESENT) ? TRUE : FALSE;
  1544. // We filled out the structure.
  1545. PropertyRequest->ValueSize = sizeof (tAC97Features);
  1546. DOUT (DBG_PROPERTY, ("Get AC97Features succeeded."));
  1547. // ntStatus was set with the read call! whatever this is, return it.
  1548. }
  1549. #ifdef PROPERTY_SHOW_SET
  1550. else
  1551. {
  1552. // Just to show, we have a SET also.
  1553. if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
  1554. {
  1555. // This is the only property for a SET.
  1556. if (PropertyRequest->PropertyItem->Id != KSPROPERTY_AC97_SAMPLE_SET)
  1557. return ntStatus;
  1558. // validate buffer size.
  1559. if (PropertyRequest->ValueSize < sizeof (DWORD))
  1560. return ntStatus;
  1561. // Get the pointer to the DWORD.
  1562. DWORD *pTimerTick = (DWORD *)PropertyRequest->Value;
  1563. // Check the buffer.
  1564. if (!pTimerTick)
  1565. return ntStatus;
  1566. // Print the message.
  1567. DOUT (DBG_ALL, ("This computer is already %d ms running Windows!", *pTimerTick));
  1568. ntStatus = STATUS_SUCCESS;
  1569. }
  1570. }
  1571. #endif
  1572. return ntStatus;
  1573. }
  1574. #endif