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.

1520 lines
61 KiB

  1. /*****************************************************************************
  2. * mintopo.cpp - SB16 topology miniport implementation
  3. *****************************************************************************
  4. * Copyright (c) 1997-2000 Microsoft Corporation. All Rights Reserved.
  5. */
  6. #include "limits.h"
  7. #include "mintopo.h"
  8. #define STR_MODULENAME "sb16topo: "
  9. #define CHAN_LEFT 0
  10. #define CHAN_RIGHT 1
  11. #define CHAN_MASTER (-1)
  12. #pragma code_seg("PAGE")
  13. /*****************************************************************************
  14. * CreateMiniportTopologySB16()
  15. *****************************************************************************
  16. * Creates a topology miniport object for the SB16 adapter. This uses a
  17. * macro from STDUNK.H to do all the work.
  18. */
  19. NTSTATUS
  20. CreateMiniportTopologySB16
  21. (
  22. OUT PUNKNOWN * Unknown,
  23. IN REFCLSID,
  24. IN PUNKNOWN UnknownOuter OPTIONAL,
  25. IN POOL_TYPE PoolType
  26. )
  27. {
  28. PAGED_CODE();
  29. ASSERT(Unknown);
  30. STD_CREATE_BODY_(CMiniportTopologySB16,Unknown,UnknownOuter,PoolType,PMINIPORTTOPOLOGY);
  31. }
  32. /*****************************************************************************
  33. * CMiniportTopologySB16::NonDelegatingQueryInterface()
  34. *****************************************************************************
  35. * Obtains an interface. This function works just like a COM QueryInterface
  36. * call and is used if the object is not being aggregated.
  37. */
  38. STDMETHODIMP
  39. CMiniportTopologySB16::
  40. NonDelegatingQueryInterface
  41. (
  42. IN REFIID Interface,
  43. OUT PVOID * Object
  44. )
  45. {
  46. PAGED_CODE();
  47. ASSERT(Object);
  48. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::NonDelegatingQueryInterface]"));
  49. if (IsEqualGUIDAligned(Interface,IID_IUnknown))
  50. {
  51. *Object = PVOID(PUNKNOWN(PMINIPORTTOPOLOGY(this)));
  52. }
  53. else
  54. if (IsEqualGUIDAligned(Interface,IID_IMiniport))
  55. {
  56. *Object = PVOID(PMINIPORT(this));
  57. }
  58. else
  59. if (IsEqualGUIDAligned(Interface,IID_IMiniportTopology))
  60. {
  61. *Object = PVOID(PMINIPORTTOPOLOGY(this));
  62. }
  63. else
  64. {
  65. *Object = NULL;
  66. }
  67. if (*Object)
  68. {
  69. //
  70. // We reference the interface for the caller.
  71. //
  72. PUNKNOWN(*Object)->AddRef();
  73. return STATUS_SUCCESS;
  74. }
  75. return STATUS_INVALID_PARAMETER;
  76. }
  77. /*****************************************************************************
  78. * CMiniportTopologySB16::~CMiniportTopologySB16()
  79. *****************************************************************************
  80. * Destructor.
  81. */
  82. CMiniportTopologySB16::
  83. ~CMiniportTopologySB16
  84. ( void
  85. )
  86. {
  87. PAGED_CODE();
  88. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::~CMiniportTopologySB16]"));
  89. if (AdapterCommon)
  90. {
  91. #ifdef EVENT_SUPPORT
  92. AdapterCommon->SetTopologyMiniport (NULL);
  93. #endif
  94. AdapterCommon->SaveMixerSettingsToRegistry();
  95. AdapterCommon->Release();
  96. }
  97. #ifdef EVENT_SUPPORT
  98. if (PortEvents)
  99. {
  100. PortEvents->Release ();
  101. PortEvents = NULL;
  102. }
  103. #endif
  104. }
  105. /*****************************************************************************
  106. * CMiniportTopologySB16::Init()
  107. *****************************************************************************
  108. * Initializes a the miniport.
  109. */
  110. STDMETHODIMP
  111. CMiniportTopologySB16::
  112. Init
  113. (
  114. IN PUNKNOWN UnknownAdapter,
  115. IN PRESOURCELIST ResourceList,
  116. IN PPORTTOPOLOGY Port
  117. )
  118. {
  119. PAGED_CODE();
  120. ASSERT(UnknownAdapter);
  121. ASSERT(Port);
  122. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::Init]"));
  123. NTSTATUS ntStatus =
  124. UnknownAdapter->QueryInterface
  125. (
  126. IID_IAdapterCommon,
  127. (PVOID *) &AdapterCommon
  128. );
  129. if (NT_SUCCESS(ntStatus))
  130. {
  131. #ifdef EVENT_SUPPORT
  132. //
  133. // Get the port event interface.
  134. //
  135. NTSTATUS ntStatus2 = Port->QueryInterface (IID_IPortEvents, (PVOID *)&PortEvents);
  136. if (NT_SUCCESS(ntStatus2))
  137. {
  138. //
  139. // We need to notify AdapterCommon of the miniport interface.
  140. // AdapterCommon needs this in his ISR to fire the event.
  141. //
  142. AdapterCommon->SetTopologyMiniport ((PTOPOMINIPORTSB16)this);
  143. //
  144. // Enable external volume control interrupt.
  145. //
  146. BYTE bIntrMask = AdapterCommon->MixerRegRead (0x83);
  147. bIntrMask |= 0x10;
  148. AdapterCommon->MixerRegWrite (0x83, bIntrMask);
  149. }
  150. #endif
  151. AdapterCommon->MixerReset();
  152. }
  153. return ntStatus;
  154. }
  155. /*****************************************************************************
  156. * CMiniportTopologySB16::GetDescription()
  157. *****************************************************************************
  158. * Gets the topology.
  159. */
  160. STDMETHODIMP
  161. CMiniportTopologySB16::
  162. GetDescription
  163. (
  164. OUT PPCFILTER_DESCRIPTOR * OutFilterDescriptor
  165. )
  166. {
  167. PAGED_CODE();
  168. ASSERT(OutFilterDescriptor);
  169. _DbgPrintF(DEBUGLVL_VERBOSE,("[CMiniportTopologySB16::GetDescription]"));
  170. *OutFilterDescriptor = &MiniportFilterDescriptor;
  171. return STATUS_SUCCESS;
  172. }
  173. /*****************************************************************************
  174. * PropertyHandler_OnOff()
  175. *****************************************************************************
  176. * Accesses a KSAUDIO_ONOFF value property.
  177. */
  178. static
  179. NTSTATUS
  180. PropertyHandler_OnOff
  181. (
  182. IN PPCPROPERTY_REQUEST PropertyRequest
  183. )
  184. {
  185. PAGED_CODE();
  186. ASSERT(PropertyRequest);
  187. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_OnOff]"));
  188. CMiniportTopologySB16 *that =
  189. (CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
  190. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  191. BYTE data;
  192. LONG channel;
  193. // validate node
  194. if (PropertyRequest->Node != ULONG(-1))
  195. {
  196. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  197. {
  198. // get the instance channel parameter
  199. if(PropertyRequest->InstanceSize >= sizeof(LONG))
  200. {
  201. channel = *(PLONG(PropertyRequest->Instance));
  202. // validate and get the output parameter
  203. if (PropertyRequest->ValueSize >= sizeof(BOOL))
  204. {
  205. PBOOL OnOff = PBOOL(PropertyRequest->Value);
  206. // switch on node id
  207. switch(PropertyRequest->Node)
  208. {
  209. case MIC_AGC: // Microphone AGC Control (mono)
  210. // check if AGC property request on mono/left channel
  211. if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC ) &&
  212. ( channel == CHAN_LEFT ) )
  213. {
  214. data = that->ReadBitsFromMixer( DSP_MIX_AGCIDX,
  215. 1,
  216. MIXBIT_MIC_AGC );
  217. *OnOff = data ? FALSE : TRUE;
  218. PropertyRequest->ValueSize = sizeof(BOOL);
  219. ntStatus = STATUS_SUCCESS;
  220. }
  221. break;
  222. case MIC_LINEOUT_MUTE: // Microphone Lineout Mute Control (mono)
  223. // check if MUTE property request on mono/left channel
  224. if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE ) &&
  225. ( channel == CHAN_LEFT ) )
  226. {
  227. data = that->ReadBitsFromMixer( DSP_MIX_OUTMIXIDX,
  228. 1,
  229. MIXBIT_MIC_LINEOUT );
  230. *OnOff = data ? FALSE : TRUE;
  231. PropertyRequest->ValueSize = sizeof(BOOL);
  232. ntStatus = STATUS_SUCCESS;
  233. }
  234. break;
  235. }
  236. }
  237. }
  238. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
  239. {
  240. // get the instance channel parameter
  241. if(PropertyRequest->InstanceSize >= sizeof(LONG))
  242. {
  243. channel = *(PLONG(PropertyRequest->Instance));
  244. // validate and get the input parameter
  245. if (PropertyRequest->ValueSize == sizeof(BOOL))
  246. {
  247. BYTE value = *(PBOOL(PropertyRequest->Value)) ? 0 : 1;
  248. // switch on the node id
  249. switch(PropertyRequest->Node)
  250. {
  251. case MIC_AGC: // Microphone AGC Control (mono)
  252. // check if AGC property request on mono/left channel
  253. if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC ) &&
  254. ( channel == CHAN_LEFT ) )
  255. {
  256. that->WriteBitsToMixer( DSP_MIX_AGCIDX,
  257. 1,
  258. MIXBIT_MIC_AGC,
  259. value );
  260. ntStatus = STATUS_SUCCESS;
  261. }
  262. break;
  263. case MIC_LINEOUT_MUTE: // Microphone Lineout Mute Control (mono)
  264. // check if MUTE property request on mono/left channel
  265. if( ( PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE ) &&
  266. ( channel == CHAN_LEFT ) )
  267. {
  268. that->WriteBitsToMixer( DSP_MIX_OUTMIXIDX,
  269. 1,
  270. MIXBIT_MIC_LINEOUT,
  271. value );
  272. ntStatus = STATUS_SUCCESS;
  273. }
  274. break;
  275. }
  276. }
  277. }
  278. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  279. {
  280. if ( ( (PropertyRequest->Node == MIC_AGC) && (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_AGC) ) ||
  281. ( (PropertyRequest->Node == MIC_LINEOUT_MUTE) && (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_MUTE) ) )
  282. {
  283. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  284. {
  285. // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
  286. PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
  287. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  288. KSPROPERTY_TYPE_GET |
  289. KSPROPERTY_TYPE_SET;
  290. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
  291. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  292. PropDesc->PropTypeSet.Id = VT_BOOL;
  293. PropDesc->PropTypeSet.Flags = 0;
  294. PropDesc->MembersListCount = 0;
  295. PropDesc->Reserved = 0;
  296. // set the return value size
  297. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  298. ntStatus = STATUS_SUCCESS;
  299. } else if(PropertyRequest->ValueSize >= sizeof(ULONG))
  300. {
  301. // if return buffer can hold a ULONG, return the access flags
  302. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  303. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  304. KSPROPERTY_TYPE_GET |
  305. KSPROPERTY_TYPE_SET;
  306. // set the return value size
  307. PropertyRequest->ValueSize = sizeof(ULONG);
  308. ntStatus = STATUS_SUCCESS;
  309. }
  310. }
  311. }
  312. }
  313. return ntStatus;
  314. }
  315. /*****************************************************************************
  316. * BasicSupportHandler()
  317. *****************************************************************************
  318. * Assists in BASICSUPPORT accesses on level properties
  319. */
  320. static
  321. NTSTATUS
  322. BasicSupportHandler
  323. (
  324. IN PPCPROPERTY_REQUEST PropertyRequest
  325. )
  326. {
  327. PAGED_CODE();
  328. ASSERT(PropertyRequest);
  329. _DbgPrintF(DEBUGLVL_VERBOSE,("[BasicSupportHandler]"));
  330. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  331. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  332. {
  333. // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
  334. PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
  335. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  336. KSPROPERTY_TYPE_GET |
  337. KSPROPERTY_TYPE_SET;
  338. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION) +
  339. sizeof(KSPROPERTY_MEMBERSHEADER) +
  340. sizeof(KSPROPERTY_STEPPING_LONG);
  341. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  342. PropDesc->PropTypeSet.Id = VT_I4;
  343. PropDesc->PropTypeSet.Flags = 0;
  344. PropDesc->MembersListCount = 1;
  345. PropDesc->Reserved = 0;
  346. // if return buffer cn also hold a range description, return it too
  347. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION) +
  348. sizeof(KSPROPERTY_MEMBERSHEADER) +
  349. sizeof(KSPROPERTY_STEPPING_LONG)))
  350. {
  351. // fill in the members header
  352. PKSPROPERTY_MEMBERSHEADER Members = PKSPROPERTY_MEMBERSHEADER(PropDesc + 1);
  353. Members->MembersFlags = KSPROPERTY_MEMBER_STEPPEDRANGES;
  354. Members->MembersSize = sizeof(KSPROPERTY_STEPPING_LONG);
  355. Members->MembersCount = 1;
  356. Members->Flags = 0;
  357. // fill in the stepped range
  358. PKSPROPERTY_STEPPING_LONG Range = PKSPROPERTY_STEPPING_LONG(Members + 1);
  359. switch(PropertyRequest->Node)
  360. {
  361. case WAVEOUT_VOLUME:
  362. case SYNTH_VOLUME:
  363. case CD_VOLUME:
  364. case LINEIN_VOLUME:
  365. case MIC_VOLUME:
  366. case LINEOUT_VOL:
  367. Range->Bounds.SignedMaximum = 0; // 0 (dB) * 0x10000
  368. Range->Bounds.SignedMinimum = 0xFFC20000; // -62 (dB) * 0x10000
  369. Range->SteppingDelta = 0x20000; // 2 (dB) * 0x10000
  370. break;
  371. case LINEOUT_GAIN:
  372. case WAVEIN_GAIN:
  373. Range->Bounds.SignedMaximum = 0x120000; // 18 (dB) * 0x10000
  374. Range->Bounds.SignedMinimum = 0; // 0 (dB) * 0x10000
  375. Range->SteppingDelta = 0x60000; // 6 (dB) * 0x10000
  376. break;
  377. case LINEOUT_BASS:
  378. case LINEOUT_TREBLE:
  379. Range->Bounds.SignedMaximum = 0xE0000; // 14 (dB) * 0x10000
  380. Range->Bounds.SignedMinimum = 0xFFF20000; // -14 (dB) * 0x10000
  381. Range->SteppingDelta = 0x20000; // 2 (dB) * 0x10000
  382. break;
  383. }
  384. Range->Reserved = 0;
  385. _DbgPrintF(DEBUGLVL_BLAB, ("---Node: %d Max: 0x%X Min: 0x%X Step: 0x%X",PropertyRequest->Node,
  386. Range->Bounds.SignedMaximum,
  387. Range->Bounds.SignedMinimum,
  388. Range->SteppingDelta));
  389. // set the return value size
  390. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION) +
  391. sizeof(KSPROPERTY_MEMBERSHEADER) +
  392. sizeof(KSPROPERTY_STEPPING_LONG);
  393. } else
  394. {
  395. // set the return value size
  396. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  397. }
  398. ntStatus = STATUS_SUCCESS;
  399. } else if(PropertyRequest->ValueSize >= sizeof(ULONG))
  400. {
  401. // if return buffer can hold a ULONG, return the access flags
  402. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  403. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  404. KSPROPERTY_TYPE_GET |
  405. KSPROPERTY_TYPE_SET;
  406. // set the return value size
  407. PropertyRequest->ValueSize = sizeof(ULONG);
  408. ntStatus = STATUS_SUCCESS;
  409. }
  410. return ntStatus;
  411. }
  412. /*****************************************************************************
  413. * PropertyHandler_Level()
  414. *****************************************************************************
  415. * Accesses a KSAUDIO_LEVEL property.
  416. */
  417. static
  418. NTSTATUS
  419. PropertyHandler_Level
  420. (
  421. IN PPCPROPERTY_REQUEST PropertyRequest
  422. )
  423. {
  424. PAGED_CODE();
  425. ASSERT(PropertyRequest);
  426. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_Level]"));
  427. CMiniportTopologySB16 *that =
  428. (CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
  429. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  430. ULONG count;
  431. LONG channel;
  432. // validate node
  433. if(PropertyRequest->Node != ULONG(-1))
  434. {
  435. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  436. {
  437. // get the instance channel parameter
  438. if(PropertyRequest->InstanceSize >= sizeof(LONG))
  439. {
  440. channel = *(PLONG(PropertyRequest->Instance));
  441. // only support get requests on either mono/left (0) or right (1) channels
  442. if ( (channel == CHAN_LEFT) || (channel == CHAN_RIGHT) )
  443. {
  444. // validate and get the output parameter
  445. if (PropertyRequest->ValueSize >= sizeof(LONG))
  446. {
  447. PLONG Level = (PLONG)PropertyRequest->Value;
  448. // switch on node if
  449. switch(PropertyRequest->Node)
  450. {
  451. case WAVEOUT_VOLUME:
  452. case SYNTH_VOLUME:
  453. case CD_VOLUME:
  454. case LINEIN_VOLUME:
  455. case MIC_VOLUME:
  456. case LINEOUT_VOL:
  457. // check if volume property request
  458. if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
  459. {
  460. // bail out if a right channel request on the mono mic volume
  461. if( (PropertyRequest->Node == MIC_VOLUME) && (channel != CHAN_LEFT) )
  462. {
  463. break;
  464. }
  465. *Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
  466. #ifdef EVENT_SUPPORT
  467. //
  468. // see if there is a volume changed, update if neccessary.
  469. //
  470. BYTE data = that->ReadBitsFromMixer (
  471. BYTE(AccessParams[PropertyRequest->Node].BaseRegister
  472. +channel+DSP_MIX_BASEIDX),
  473. 5, 3);
  474. //
  475. // Convert the dB value into a register value. No boundary check.
  476. // Register is 0 - 31 representing -62dB - 0dB.
  477. //
  478. if (data != ((*Level >> 17) + 31))
  479. {
  480. //
  481. // Convert the register into dB value.
  482. // Register is 0 - 31 representing -62dB - 0dB.
  483. //
  484. *Level = (data - 31) << 17;
  485. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel] = *Level;
  486. }
  487. #endif
  488. PropertyRequest->ValueSize = sizeof(LONG);
  489. ntStatus = STATUS_SUCCESS;
  490. }
  491. break;
  492. case LINEOUT_GAIN:
  493. case WAVEIN_GAIN:
  494. // check if volume property request
  495. if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
  496. {
  497. *Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
  498. PropertyRequest->ValueSize = sizeof(LONG);
  499. ntStatus = STATUS_SUCCESS;
  500. }
  501. break;
  502. case LINEOUT_BASS:
  503. case LINEOUT_TREBLE:
  504. if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
  505. (PropertyRequest->Node == LINEOUT_BASS) ) ||
  506. ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
  507. (PropertyRequest->Node == LINEOUT_TREBLE) ) )
  508. {
  509. *Level = ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + channel ];
  510. PropertyRequest->ValueSize = sizeof(LONG);
  511. ntStatus = STATUS_SUCCESS;
  512. }
  513. break;
  514. }
  515. }
  516. }
  517. }
  518. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
  519. {
  520. // get the instance channel parameter
  521. if(PropertyRequest->InstanceSize >= sizeof(LONG))
  522. {
  523. channel = *(PLONG(PropertyRequest->Instance));
  524. // only support set requests on either mono/left (0), right (1), or master (-1) channels
  525. if ( (channel == CHAN_LEFT) || (channel == CHAN_RIGHT) || (channel == CHAN_MASTER))
  526. {
  527. // validate and get the input parameter
  528. if (PropertyRequest->ValueSize == sizeof(LONG))
  529. {
  530. PLONG Level = (PLONG)PropertyRequest->Value;
  531. // switch on the node id
  532. switch(PropertyRequest->Node)
  533. {
  534. case WAVEOUT_VOLUME:
  535. case SYNTH_VOLUME:
  536. case CD_VOLUME:
  537. case LINEIN_VOLUME:
  538. case MIC_VOLUME:
  539. case LINEOUT_VOL:
  540. if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
  541. {
  542. // convert the level to register bits
  543. if(*Level <= (-62 << 16))
  544. {
  545. count = 0;
  546. } else if(*Level >= 0)
  547. {
  548. count = 0x1F;
  549. } else
  550. {
  551. count = ((*Level >> 17) + 31) & 0x1F;
  552. }
  553. // set right channel if channel requested is right or master
  554. // and node is not mic volume (mono)
  555. if ( ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) ) &&
  556. ( PropertyRequest->Node != MIC_VOLUME ) )
  557. {
  558. // cache the commanded control value
  559. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
  560. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister+1,
  561. 5,
  562. 3,
  563. BYTE(count) );
  564. ntStatus = STATUS_SUCCESS;
  565. }
  566. // set the left channel if channel requested is left or master
  567. if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
  568. {
  569. // cache the commanded control value
  570. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
  571. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
  572. 5,
  573. 3,
  574. BYTE(count) );
  575. ntStatus = STATUS_SUCCESS;
  576. }
  577. }
  578. break;
  579. case LINEOUT_GAIN:
  580. case WAVEIN_GAIN:
  581. if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
  582. {
  583. // determine register bits
  584. if(*Level >= (18 << 16))
  585. {
  586. count = 0x3;
  587. } else if(*Level <= 0)
  588. {
  589. count = 0;
  590. } else
  591. {
  592. count = (*Level >> 17) / 3;
  593. }
  594. // set right channel if channel requested is right or master
  595. if ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) )
  596. {
  597. // cache the commanded control value
  598. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
  599. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister+1,
  600. 2,
  601. 6,
  602. BYTE(count) );
  603. ntStatus = STATUS_SUCCESS;
  604. }
  605. // set the left channel if channel requested is left or master
  606. if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
  607. {
  608. // cache the commanded control value
  609. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
  610. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
  611. 2,
  612. 6,
  613. BYTE(count) );
  614. ntStatus = STATUS_SUCCESS;
  615. }
  616. }
  617. break;
  618. case LINEOUT_BASS:
  619. case LINEOUT_TREBLE:
  620. if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
  621. (PropertyRequest->Node == LINEOUT_BASS) ) ||
  622. ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
  623. (PropertyRequest->Node == LINEOUT_TREBLE) ) )
  624. {
  625. // determine register bits
  626. if(*Level <= (-14 << 16))
  627. {
  628. count = 0;
  629. } else if(*Level >= (14 << 16))
  630. {
  631. count = 0xF;
  632. } else
  633. {
  634. count = ((*Level >> 16) + 14) >> 1;
  635. }
  636. // set right channel if channel requested is right or master
  637. if ( (channel == CHAN_RIGHT) || (channel == CHAN_MASTER) )
  638. {
  639. // cache the commanded control value
  640. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_RIGHT ] = *Level;
  641. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister + 1,
  642. 4,
  643. 4,
  644. BYTE(count) );
  645. ntStatus = STATUS_SUCCESS;
  646. }
  647. // set the left channel if channel requested is left or master
  648. if ( (channel == CHAN_LEFT) || (channel == CHAN_MASTER) )
  649. {
  650. // cache the commanded control value
  651. ControlValueCache[ AccessParams[PropertyRequest->Node].CacheOffset + CHAN_LEFT ] = *Level;
  652. that->WriteBitsToMixer( AccessParams[PropertyRequest->Node].BaseRegister,
  653. 4,
  654. 4,
  655. BYTE(count) );
  656. ntStatus = STATUS_SUCCESS;
  657. }
  658. }
  659. break;
  660. }
  661. }
  662. }
  663. }
  664. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  665. {
  666. // service basic support request
  667. switch(PropertyRequest->Node)
  668. {
  669. case WAVEOUT_VOLUME:
  670. case SYNTH_VOLUME:
  671. case CD_VOLUME:
  672. case LINEIN_VOLUME:
  673. case MIC_VOLUME:
  674. case LINEOUT_VOL:
  675. case LINEOUT_GAIN:
  676. case WAVEIN_GAIN:
  677. if(PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_VOLUMELEVEL)
  678. {
  679. ntStatus = BasicSupportHandler(PropertyRequest);
  680. }
  681. break;
  682. case LINEOUT_BASS:
  683. case LINEOUT_TREBLE:
  684. if( ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_BASS) &&
  685. (PropertyRequest->Node == LINEOUT_BASS) ) ||
  686. ( (PropertyRequest->PropertyItem->Id == KSPROPERTY_AUDIO_TREBLE) &&
  687. (PropertyRequest->Node == LINEOUT_TREBLE) ) )
  688. {
  689. ntStatus = BasicSupportHandler(PropertyRequest);
  690. }
  691. break;
  692. }
  693. }
  694. }
  695. return ntStatus;
  696. }
  697. /*****************************************************************************
  698. * PropertyHandler_SuperMixCaps()
  699. *****************************************************************************
  700. * Handles supermixer caps accesses
  701. */
  702. static
  703. NTSTATUS
  704. PropertyHandler_SuperMixCaps
  705. (
  706. IN PPCPROPERTY_REQUEST PropertyRequest
  707. )
  708. {
  709. PAGED_CODE();
  710. ASSERT(PropertyRequest);
  711. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_SuperMixCaps]"));
  712. CMiniportTopologySB16 *that =
  713. (CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
  714. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  715. ULONG count;
  716. // validate node
  717. if(PropertyRequest->Node != ULONG(-1))
  718. {
  719. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  720. {
  721. switch(PropertyRequest->Node)
  722. {
  723. // Full 2x2 Switches
  724. case SYNTH_WAVEIN_SUPERMIX:
  725. case CD_WAVEIN_SUPERMIX:
  726. case LINEIN_WAVEIN_SUPERMIX:
  727. if(!PropertyRequest->ValueSize)
  728. {
  729. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
  730. ntStatus = STATUS_BUFFER_OVERFLOW;
  731. } else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
  732. {
  733. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  734. MixCaps->InputChannels = 2;
  735. MixCaps->OutputChannels = 2;
  736. ntStatus = STATUS_SUCCESS;
  737. } else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS))
  738. {
  739. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
  740. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  741. MixCaps->InputChannels = 2;
  742. MixCaps->OutputChannels = 2;
  743. for(count = 0; count < 4; count++)
  744. {
  745. MixCaps->Capabilities[count].Mute = TRUE;
  746. MixCaps->Capabilities[count].Minimum = 0;
  747. MixCaps->Capabilities[count].Maximum = 0;
  748. MixCaps->Capabilities[count].Reset = 0;
  749. }
  750. ntStatus = STATUS_SUCCESS;
  751. }
  752. break;
  753. // Limited 2x2 Switches
  754. case CD_LINEOUT_SUPERMIX:
  755. case LINEIN_LINEOUT_SUPERMIX:
  756. if(!PropertyRequest->ValueSize)
  757. {
  758. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
  759. ntStatus = STATUS_BUFFER_OVERFLOW;
  760. } else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
  761. {
  762. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  763. MixCaps->InputChannels = 2;
  764. MixCaps->OutputChannels = 2;
  765. ntStatus = STATUS_SUCCESS;
  766. } else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS))
  767. {
  768. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 4 * sizeof(KSAUDIO_MIX_CAPS);
  769. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  770. MixCaps->InputChannels = 2;
  771. MixCaps->OutputChannels = 2;
  772. for(count = 0; count < 4; count++)
  773. {
  774. if((count == 0) || (count == 3))
  775. {
  776. MixCaps->Capabilities[count].Mute = TRUE;
  777. MixCaps->Capabilities[count].Minimum = 0;
  778. MixCaps->Capabilities[count].Maximum = 0;
  779. MixCaps->Capabilities[count].Reset = 0;
  780. } else
  781. {
  782. MixCaps->Capabilities[count].Mute = FALSE;
  783. MixCaps->Capabilities[count].Minimum = LONG_MIN;
  784. MixCaps->Capabilities[count].Maximum = LONG_MIN;
  785. MixCaps->Capabilities[count].Reset = LONG_MIN;
  786. }
  787. }
  788. ntStatus = STATUS_SUCCESS;
  789. }
  790. break;
  791. // 1x2 Switch
  792. case MIC_WAVEIN_SUPERMIX:
  793. if(!PropertyRequest->ValueSize)
  794. {
  795. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS);
  796. ntStatus = STATUS_BUFFER_OVERFLOW;
  797. } else if(PropertyRequest->ValueSize == 2 * sizeof(ULONG))
  798. {
  799. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  800. MixCaps->InputChannels = 1;
  801. MixCaps->OutputChannels = 2;
  802. ntStatus = STATUS_SUCCESS;
  803. } else if(PropertyRequest->ValueSize >= 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS))
  804. {
  805. PropertyRequest->ValueSize = 2 * sizeof(ULONG) + 2 * sizeof(KSAUDIO_MIX_CAPS);
  806. PKSAUDIO_MIXCAP_TABLE MixCaps = (PKSAUDIO_MIXCAP_TABLE)PropertyRequest->Value;
  807. MixCaps->InputChannels = 1;
  808. MixCaps->OutputChannels = 2;
  809. for(count = 0; count < 2; count++)
  810. {
  811. MixCaps->Capabilities[count].Mute = TRUE;
  812. MixCaps->Capabilities[count].Minimum = 0;
  813. MixCaps->Capabilities[count].Maximum = 0;
  814. MixCaps->Capabilities[count].Reset = 0;
  815. }
  816. ntStatus = STATUS_SUCCESS;
  817. }
  818. break;
  819. }
  820. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  821. {
  822. // service basic support request
  823. switch(PropertyRequest->Node)
  824. {
  825. case SYNTH_WAVEIN_SUPERMIX:
  826. case CD_WAVEIN_SUPERMIX:
  827. case LINEIN_WAVEIN_SUPERMIX:
  828. case CD_LINEOUT_SUPERMIX:
  829. case LINEIN_LINEOUT_SUPERMIX:
  830. case MIC_WAVEIN_SUPERMIX:
  831. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  832. {
  833. // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
  834. PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
  835. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  836. KSPROPERTY_TYPE_GET;
  837. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
  838. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  839. PropDesc->PropTypeSet.Id = VT_ARRAY;
  840. PropDesc->PropTypeSet.Flags = 0;
  841. PropDesc->MembersListCount = 0;
  842. PropDesc->Reserved = 0;
  843. // set the return value size
  844. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  845. ntStatus = STATUS_SUCCESS;
  846. } else if(PropertyRequest->ValueSize >= sizeof(ULONG))
  847. {
  848. // if return buffer can hold a ULONG, return the access flags
  849. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  850. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  851. KSPROPERTY_TYPE_GET;
  852. // set the return value size
  853. PropertyRequest->ValueSize = sizeof(ULONG);
  854. ntStatus = STATUS_SUCCESS;
  855. }
  856. ntStatus = STATUS_SUCCESS;
  857. break;
  858. }
  859. }
  860. }
  861. return ntStatus;
  862. }
  863. /*****************************************************************************
  864. * PropertyHandler_SuperMixTable()
  865. *****************************************************************************
  866. * Handles supermixer level accesses
  867. */
  868. static
  869. NTSTATUS
  870. PropertyHandler_SuperMixTable
  871. (
  872. IN PPCPROPERTY_REQUEST PropertyRequest
  873. )
  874. {
  875. PAGED_CODE();
  876. ASSERT(PropertyRequest);
  877. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_SuperMixTable]"));
  878. CMiniportTopologySB16 *that =
  879. (CMiniportTopologySB16 *) ((PMINIPORTTOPOLOGY) PropertyRequest->MajorTarget);
  880. NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;
  881. BYTE dataL,dataR;
  882. // validate node
  883. if(PropertyRequest->Node != ULONG(-1))
  884. {
  885. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  886. {
  887. switch(PropertyRequest->Node)
  888. {
  889. // Full 2x2 Switches
  890. case SYNTH_WAVEIN_SUPERMIX:
  891. case CD_WAVEIN_SUPERMIX:
  892. case LINEIN_WAVEIN_SUPERMIX:
  893. if(!PropertyRequest->ValueSize)
  894. {
  895. PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
  896. ntStatus = STATUS_BUFFER_OVERFLOW;
  897. } else if(PropertyRequest->ValueSize >= 4 * sizeof(KSAUDIO_MIXLEVEL))
  898. {
  899. PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
  900. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  901. dataL = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_L,
  902. 2,
  903. AccessParams[PropertyRequest->Node].BaseRegister );
  904. dataR = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_R,
  905. 2,
  906. AccessParams[PropertyRequest->Node].BaseRegister );
  907. MixLevel[0].Mute = dataL & 0x2 ? FALSE : TRUE; // left to left mute
  908. MixLevel[0].Level = 0;
  909. MixLevel[1].Mute = dataR & 0x2 ? FALSE : TRUE; // left to right mute
  910. MixLevel[1].Level = 0;
  911. MixLevel[2].Mute = dataL & 0x1 ? FALSE : TRUE; // right to left mute
  912. MixLevel[2].Level = 0;
  913. MixLevel[3].Mute = dataR & 0x1 ? FALSE : TRUE; // right to right mute
  914. MixLevel[3].Level = 0;
  915. ntStatus = STATUS_SUCCESS;
  916. }
  917. break;
  918. // Limited 2x2 Switches
  919. case CD_LINEOUT_SUPERMIX:
  920. case LINEIN_LINEOUT_SUPERMIX:
  921. if(!PropertyRequest->ValueSize)
  922. {
  923. PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
  924. ntStatus = STATUS_BUFFER_OVERFLOW;
  925. } else if(PropertyRequest->ValueSize >= 4 * sizeof(KSAUDIO_MIXLEVEL))
  926. {
  927. PropertyRequest->ValueSize = 4 * sizeof(KSAUDIO_MIXLEVEL);
  928. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  929. dataL = that->ReadBitsFromMixer( DSP_MIX_OUTMIXIDX,
  930. 2,
  931. AccessParams[PropertyRequest->Node].BaseRegister );
  932. MixLevel[0].Mute = dataL & 0x2 ? FALSE : TRUE; // left to left mute
  933. MixLevel[0].Level = 0;
  934. MixLevel[1].Mute = FALSE;
  935. MixLevel[1].Level = LONG_MIN;
  936. MixLevel[2].Mute = FALSE;
  937. MixLevel[2].Level = LONG_MIN;
  938. MixLevel[3].Mute = dataL & 0x1 ? FALSE : TRUE; // right to right mute
  939. MixLevel[3].Level = 0;
  940. ntStatus = STATUS_SUCCESS;
  941. }
  942. break;
  943. // 1x2 Switch
  944. case MIC_WAVEIN_SUPERMIX:
  945. if(!PropertyRequest->ValueSize)
  946. {
  947. PropertyRequest->ValueSize = 2 * sizeof(KSAUDIO_MIXLEVEL);
  948. ntStatus = STATUS_BUFFER_OVERFLOW;
  949. } else if(PropertyRequest->ValueSize >= 2 * sizeof(KSAUDIO_MIXLEVEL))
  950. {
  951. PropertyRequest->ValueSize = 2 * sizeof(KSAUDIO_MIXLEVEL);
  952. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  953. dataL = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_L,
  954. 1,
  955. MIXBIT_MIC_WAVEIN );
  956. dataR = that->ReadBitsFromMixer( DSP_MIX_ADCMIXIDX_R,
  957. 1,
  958. MIXBIT_MIC_WAVEIN );
  959. MixLevel[0].Mute = dataL & 0x1 ? FALSE : TRUE; // mono to left mute
  960. MixLevel[0].Level = 0;
  961. MixLevel[1].Mute = dataR & 0x1 ? FALSE : TRUE; // mono to right mute
  962. MixLevel[1].Level = 0;
  963. ntStatus = STATUS_SUCCESS;
  964. }
  965. break;
  966. }
  967. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
  968. {
  969. switch(PropertyRequest->Node)
  970. {
  971. // Full 2x2 Switches
  972. case SYNTH_WAVEIN_SUPERMIX:
  973. case CD_WAVEIN_SUPERMIX:
  974. case LINEIN_WAVEIN_SUPERMIX:
  975. if(PropertyRequest->ValueSize == 4 * sizeof(KSAUDIO_MIXLEVEL))
  976. {
  977. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  978. dataL = MixLevel[0].Mute ? 0x0 : 0x2;
  979. dataL |= MixLevel[2].Mute ? 0x0 : 0x1;
  980. dataR = MixLevel[1].Mute ? 0x0 : 0x2;
  981. dataR |= MixLevel[3].Mute ? 0x0 : 0x1;
  982. that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_L,
  983. 2,
  984. AccessParams[PropertyRequest->Node].BaseRegister,
  985. dataL );
  986. that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_R,
  987. 2,
  988. AccessParams[PropertyRequest->Node].BaseRegister,
  989. dataR );
  990. ntStatus = STATUS_SUCCESS;
  991. }
  992. break;
  993. // Limited 2x2 Switches
  994. case CD_LINEOUT_SUPERMIX:
  995. case LINEIN_LINEOUT_SUPERMIX:
  996. if(PropertyRequest->ValueSize == 4 * sizeof(KSAUDIO_MIXLEVEL))
  997. {
  998. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  999. dataL = MixLevel[0].Mute ? 0x0 : 0x2;
  1000. dataL |= MixLevel[3].Mute ? 0x0 : 0x1;
  1001. that->WriteBitsToMixer( DSP_MIX_OUTMIXIDX,
  1002. 2,
  1003. AccessParams[PropertyRequest->Node].BaseRegister,
  1004. dataL );
  1005. ntStatus = STATUS_SUCCESS;
  1006. }
  1007. break;
  1008. // 1x2 Switch
  1009. case MIC_WAVEIN_SUPERMIX:
  1010. if(PropertyRequest->ValueSize == 2 * sizeof(KSAUDIO_MIXLEVEL))
  1011. {
  1012. PKSAUDIO_MIXLEVEL MixLevel = (PKSAUDIO_MIXLEVEL)PropertyRequest->Value;
  1013. dataL = MixLevel[0].Mute ? 0x0 : 0x1;
  1014. dataR = MixLevel[1].Mute ? 0x0 : 0x1;
  1015. that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_L,
  1016. 1,
  1017. MIXBIT_MIC_WAVEIN,
  1018. dataL );
  1019. that->WriteBitsToMixer( DSP_MIX_ADCMIXIDX_R,
  1020. 1,
  1021. MIXBIT_MIC_WAVEIN,
  1022. dataR );
  1023. ntStatus = STATUS_SUCCESS;
  1024. }
  1025. break;
  1026. }
  1027. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1028. {
  1029. // service basic support request
  1030. switch(PropertyRequest->Node)
  1031. {
  1032. case SYNTH_WAVEIN_SUPERMIX:
  1033. case CD_WAVEIN_SUPERMIX:
  1034. case LINEIN_WAVEIN_SUPERMIX:
  1035. case CD_LINEOUT_SUPERMIX:
  1036. case LINEIN_LINEOUT_SUPERMIX:
  1037. case MIC_WAVEIN_SUPERMIX:
  1038. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  1039. {
  1040. // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
  1041. PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
  1042. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  1043. KSPROPERTY_TYPE_GET |
  1044. KSPROPERTY_TYPE_SET;
  1045. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
  1046. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  1047. PropDesc->PropTypeSet.Id = VT_ARRAY;
  1048. PropDesc->PropTypeSet.Flags = 0;
  1049. PropDesc->MembersListCount = 0;
  1050. PropDesc->Reserved = 0;
  1051. // set the return value size
  1052. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  1053. ntStatus = STATUS_SUCCESS;
  1054. } else if(PropertyRequest->ValueSize >= sizeof(ULONG))
  1055. {
  1056. // if return buffer can hold a ULONG, return the access flags
  1057. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  1058. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  1059. KSPROPERTY_TYPE_GET |
  1060. KSPROPERTY_TYPE_SET;
  1061. // set the return value size
  1062. PropertyRequest->ValueSize = sizeof(ULONG);
  1063. ntStatus = STATUS_SUCCESS;
  1064. }
  1065. break;
  1066. }
  1067. }
  1068. }
  1069. return ntStatus;
  1070. }
  1071. /*****************************************************************************
  1072. * PropertyHandler_CpuResources()
  1073. *****************************************************************************
  1074. * Processes a KSPROPERTY_AUDIO_CPU_RESOURCES request
  1075. */
  1076. static
  1077. NTSTATUS
  1078. PropertyHandler_CpuResources
  1079. (
  1080. IN PPCPROPERTY_REQUEST PropertyRequest
  1081. )
  1082. {
  1083. PAGED_CODE();
  1084. ASSERT(PropertyRequest);
  1085. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_CpuResources]"));
  1086. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1087. // validate node
  1088. if(PropertyRequest->Node != ULONG(-1))
  1089. {
  1090. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1091. {
  1092. if(PropertyRequest->ValueSize >= sizeof(LONG))
  1093. {
  1094. *(PLONG(PropertyRequest->Value)) = KSAUDIO_CPU_RESOURCES_NOT_HOST_CPU;
  1095. PropertyRequest->ValueSize = sizeof(LONG);
  1096. ntStatus = STATUS_SUCCESS;
  1097. } else
  1098. {
  1099. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1100. }
  1101. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1102. {
  1103. if(PropertyRequest->ValueSize >= (sizeof(KSPROPERTY_DESCRIPTION)))
  1104. {
  1105. // if return buffer can hold a KSPROPERTY_DESCRIPTION, return it
  1106. PKSPROPERTY_DESCRIPTION PropDesc = PKSPROPERTY_DESCRIPTION(PropertyRequest->Value);
  1107. PropDesc->AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  1108. KSPROPERTY_TYPE_GET;
  1109. PropDesc->DescriptionSize = sizeof(KSPROPERTY_DESCRIPTION);
  1110. PropDesc->PropTypeSet.Set = KSPROPTYPESETID_General;
  1111. PropDesc->PropTypeSet.Id = VT_I4;
  1112. PropDesc->PropTypeSet.Flags = 0;
  1113. PropDesc->MembersListCount = 0;
  1114. PropDesc->Reserved = 0;
  1115. // set the return value size
  1116. PropertyRequest->ValueSize = sizeof(KSPROPERTY_DESCRIPTION);
  1117. ntStatus = STATUS_SUCCESS;
  1118. } else if(PropertyRequest->ValueSize >= sizeof(ULONG))
  1119. {
  1120. // if return buffer can hold a ULONG, return the access flags
  1121. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  1122. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  1123. KSPROPERTY_TYPE_GET |
  1124. KSPROPERTY_TYPE_SET;
  1125. // set the return value size
  1126. PropertyRequest->ValueSize = sizeof(ULONG);
  1127. ntStatus = STATUS_SUCCESS;
  1128. }
  1129. }
  1130. }
  1131. return ntStatus;
  1132. }
  1133. /*****************************************************************************
  1134. * PropertyHandler_ComponentId()
  1135. *****************************************************************************
  1136. * Processes a KSPROPERTY_GENERAL_COMPONENTID request
  1137. */
  1138. NTSTATUS
  1139. PropertyHandler_ComponentId
  1140. (
  1141. IN PPCPROPERTY_REQUEST PropertyRequest
  1142. )
  1143. {
  1144. PAGED_CODE();
  1145. ASSERT(PropertyRequest);
  1146. _DbgPrintF(DEBUGLVL_VERBOSE,("[PropertyHandler_ComponentId]"));
  1147. NTSTATUS ntStatus = STATUS_INVALID_DEVICE_REQUEST;
  1148. if(PropertyRequest->Verb & KSPROPERTY_TYPE_GET)
  1149. {
  1150. if(PropertyRequest->ValueSize >= sizeof(KSCOMPONENTID))
  1151. {
  1152. PKSCOMPONENTID pComponentId = (PKSCOMPONENTID)
  1153. PropertyRequest->Value;
  1154. INIT_MMREG_MID(&pComponentId->Manufacturer, MM_MICROSOFT);
  1155. pComponentId->Product = PID_MSSB16;
  1156. pComponentId->Name = NAME_MSSB16;
  1157. pComponentId->Component = GUID_NULL; // Not used for extended caps.
  1158. pComponentId->Version = MSSB16_VERSION;
  1159. pComponentId->Revision = MSSB16_REVISION;
  1160. PropertyRequest->ValueSize = sizeof(KSCOMPONENTID);
  1161. ntStatus = STATUS_SUCCESS;
  1162. } else if(PropertyRequest->ValueSize == 0)
  1163. {
  1164. PropertyRequest->ValueSize = sizeof(KSCOMPONENTID);
  1165. ntStatus = STATUS_BUFFER_OVERFLOW;
  1166. } else
  1167. {
  1168. PropertyRequest->ValueSize = 0;
  1169. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1170. }
  1171. } else if(PropertyRequest->Verb & KSPROPERTY_TYPE_BASICSUPPORT)
  1172. {
  1173. if(PropertyRequest->ValueSize >= sizeof(ULONG))
  1174. {
  1175. // if return buffer can hold a ULONG, return the access flags
  1176. PULONG AccessFlags = PULONG(PropertyRequest->Value);
  1177. *AccessFlags = KSPROPERTY_TYPE_BASICSUPPORT |
  1178. KSPROPERTY_TYPE_GET;
  1179. // set the return value size
  1180. PropertyRequest->ValueSize = sizeof(ULONG);
  1181. ntStatus = STATUS_SUCCESS;
  1182. } else
  1183. {
  1184. PropertyRequest->ValueSize = 0;
  1185. ntStatus = STATUS_BUFFER_TOO_SMALL;
  1186. }
  1187. }
  1188. return ntStatus;
  1189. }
  1190. /*****************************************************************************
  1191. * ThisManyOnes()
  1192. *****************************************************************************
  1193. * Returns a byte with the indicated number of ones in the low end.
  1194. */
  1195. inline
  1196. BYTE
  1197. ThisManyOnes
  1198. (
  1199. IN BYTE Ones
  1200. )
  1201. {
  1202. return ~(BYTE(0xff) << Ones);
  1203. }
  1204. /*****************************************************************************
  1205. * CMiniportTopologySB16::ReadBitsFromMixer()
  1206. *****************************************************************************
  1207. * Reads specified bits from a mixer register.
  1208. */
  1209. BYTE
  1210. CMiniportTopologySB16::
  1211. ReadBitsFromMixer
  1212. (
  1213. BYTE Reg,
  1214. BYTE Bits,
  1215. BYTE Shift
  1216. )
  1217. {
  1218. BYTE data = AdapterCommon->MixerRegRead(Reg);
  1219. return( data >> Shift) & ThisManyOnes(Bits);
  1220. }
  1221. /*****************************************************************************
  1222. * CMiniportTopologySB16::WriteBitsToMixer()
  1223. *****************************************************************************
  1224. * Writes specified bits to a mixer register.
  1225. */
  1226. void
  1227. CMiniportTopologySB16::
  1228. WriteBitsToMixer
  1229. (
  1230. BYTE Reg,
  1231. BYTE Bits,
  1232. BYTE Shift,
  1233. BYTE Value
  1234. )
  1235. {
  1236. BYTE mask = ThisManyOnes(Bits) << Shift;
  1237. BYTE data = AdapterCommon->MixerRegRead(Reg);
  1238. if(Reg < DSP_MIX_MAXREGS)
  1239. {
  1240. AdapterCommon->MixerRegWrite( Reg,
  1241. (data & ~mask) | ( (Value << Shift) & mask));
  1242. }
  1243. }
  1244. #ifdef EVENT_SUPPORT
  1245. /*****************************************************************************
  1246. * CMiniportTopologySB16::EventHandler
  1247. *****************************************************************************
  1248. * This is the generic event handler.
  1249. */
  1250. NTSTATUS CMiniportTopologySB16::EventHandler
  1251. (
  1252. IN PPCEVENT_REQUEST EventRequest
  1253. )
  1254. {
  1255. PAGED_CODE();
  1256. ASSERT(EventRequest);
  1257. _DbgPrintF (DEBUGLVL_VERBOSE, ("CMiniportTopologyICH::EventHandler"));
  1258. // The major target is the object pointer to the topology miniport.
  1259. CMiniportTopologySB16 *that =
  1260. (CMiniportTopologySB16 *)(PMINIPORTTOPOLOGY(EventRequest->MajorTarget));
  1261. ASSERT (that);
  1262. // Validate the node.
  1263. if (EventRequest->Node != LINEOUT_VOL)
  1264. return STATUS_INVALID_PARAMETER;
  1265. // What is to do?
  1266. switch (EventRequest->Verb)
  1267. {
  1268. // Do we support event handling?!?
  1269. case PCEVENT_VERB_SUPPORT:
  1270. _DbgPrintF (DEBUGLVL_VERBOSE, ("BasicSupport Query for Event."));
  1271. break;
  1272. // We should add the event now!
  1273. case PCEVENT_VERB_ADD:
  1274. _DbgPrintF (DEBUGLVL_VERBOSE, ("Adding Event."));
  1275. // If we have the interface and EventEntry is defined ...
  1276. if ((EventRequest->EventEntry) && (that->PortEvents))
  1277. {
  1278. that->PortEvents->AddEventToEventList (EventRequest->EventEntry);
  1279. }
  1280. else
  1281. {
  1282. return STATUS_UNSUCCESSFUL;
  1283. }
  1284. break;
  1285. case PCEVENT_VERB_REMOVE:
  1286. // We cannot remove the event but we can stop generating the
  1287. // events. However, it also doesn't hurt to always generate them ...
  1288. _DbgPrintF (DEBUGLVL_VERBOSE, ("Removing Event."));
  1289. break;
  1290. default:
  1291. return STATUS_INVALID_PARAMETER;
  1292. }
  1293. return STATUS_SUCCESS;
  1294. }
  1295. #pragma code_seg()
  1296. /*****************************************************************************
  1297. * CMiniportTopologySB16::ServiceEvent()
  1298. *****************************************************************************
  1299. * This routine is called by the ISR to handle the event (volume) interrupt.
  1300. */
  1301. STDMETHODIMP_(void) CMiniportTopologySB16::ServiceEvent (void)
  1302. {
  1303. //
  1304. // Generate an event for the master volume (as an example)
  1305. //
  1306. if (PortEvents)
  1307. {
  1308. PortEvents->GenerateEventList (NULL, KSEVENT_CONTROL_CHANGE,
  1309. FALSE, ULONG(-1), TRUE,
  1310. LINEOUT_VOL);
  1311. }
  1312. }
  1313. #endif // EVENT_SUPPORT