1 /********************************************************************************
2 **    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
3 **
4 **       Portions Copyright (c) 1998-1999 Intel Corporation
5 **
6 ********************************************************************************/
7 
8 /* The file common.cpp was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
9 
10 // Every debug output has "Modulname text"
11 #define STR_MODULENAME "AC97 Common: "
12 
13 #include "common.h"
14 
15 
16 /*****************************************************************************
17  * Static Members
18  *****************************************************************************
19  */
20 
21 //
22 // This is the register cache including registry names and default values. The
23 // first WORD contains the register value and the second WORD contains a flag.
24 // Currently, we only set SHREG_INVALID if we have to read the register at
25 // startup (that's true when there is no constant default value for the
26 // register).  Note that we cache the registers only to prevent read access to
27 // the AC97 CoDec during runtime, because this is slow (40us).
28 // We only set SHREG_INIT if we want to set the register to default at driver
29 // startup.  If needed, the third field contains the registry name and the
30 // forth field contains a default value that is used when there is no registry
31 // entry.
32 // The flag SHREG_NOCACHE is used when we don't want to cache the register
33 // at all.  This is neccessary for status registers and sample rate registers.
34 //
35 tAC97Registers CAC97AdapterCommon::m_stAC97Registers[] =
36 {
37 {0x0000, SHREG_INVALID, NULL,               0},         // AC97REG_RESET
38 {0x8000, SHREG_INIT,    L"MasterVolume",    0x0000},    // AC97REG_MASTER_VOLUME
39 {0x8000, SHREG_INIT,    L"HeadphoneVolume", 0x0000},    // AC97REG_HPHONE_VOLUME
40 {0x8000, SHREG_INIT,    L"MonooutVolume",   0x0000},    // AC97REG_MMONO_VOLUME
41 {0x0F0F, SHREG_INIT,    L"ToneControls",    0x0F0F},    // AC97REG_MASTER_TONE
42 {0x0000, SHREG_INVALID |
43          SHREG_INIT,    L"BeepVolume",      0x0000},    // AC97REG_BEEP_VOLUME
44 {0x8008, SHREG_INIT,    L"PhoneVolume",     0x8008},    // AC97REG_PHONE_VOLUME
45 {0x8008, SHREG_INIT,    L"MicVolume",       0x8008},    // AC97REG_MIC_VOLUME
46 {0x8808, SHREG_INIT,    L"LineInVolume",    0x0808},    // AC97REG_LINE_IN_VOLUME
47 {0x8808, SHREG_INIT,    L"CDVolume",        0x0808},    // AC97REG_CD_VOLUME
48 {0x8808, SHREG_INIT,    L"VideoVolume",     0x0808},    // AC97REG_VIDEO_VOLUME
49 {0x8808, SHREG_INIT,    L"AUXVolume",       0x0808},    // AC97REG_AUX_VOLUME
50 {0x8808, SHREG_INIT,    L"WaveOutVolume",   0x0808},    // AC97REG_PCM_OUT_VOLUME
51 {0x0000, SHREG_INIT,    L"RecordSelect",    0x0404},    // AC97REG_RECORD_SELECT
52 {0x8000, SHREG_INIT,    L"RecordGain",      0x0000},    // AC97REG_RECORD_GAIN
53 {0x8000, SHREG_INIT,    L"RecordGainMic",   0x0000},    // AC97REG_RECORD_GAIN_MIC
54 {0x0000, SHREG_INIT,    L"GeneralPurpose",  0x0000},    // AC97REG_GENERAL
55 {0x0000, SHREG_INIT,    L"3DControl",       0x0000},    // AC97REG_3D_CONTROL
56 {0x0000, SHREG_NOCACHE, NULL,               0},         // AC97REG_RESERVED
57 {0x0000, SHREG_NOCACHE |
58          SHREG_INIT,    L"PowerDown",       0},         // AC97REG_POWERDOWN
59 // AC97-2.0 registers
60 {0x0000, SHREG_INVALID, NULL,               0},         // AC97REG_EXT_AUDIO_ID
61 {0x0000, SHREG_NOCACHE |
62          SHREG_INIT,    L"ExtAudioCtrl",    0x4001},    // AC97REG_EXT_AUDIO_CTRL
63 {0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_FRONT_SAMPLERATE
64 {0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_SURROUND_SAMPLERATE
65 {0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_LFE_SAMPLERATE
66 {0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_RECORD_SAMPLERATE
67 {0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_MIC_SAMPLERATE
68 {0x8080, SHREG_INIT,    L"CenterLFEVolume", 0x0000},    // AC97REG_CENTER_LFE_VOLUME
69 {0x8080, SHREG_INIT,    L"SurroundVolume",  0x0000},    // AC97REG_SURROUND_VOLUME
70 {0x0000, SHREG_NOCACHE, NULL,               0}          // AC97REG_RESERVED2
71 
72 // We leave the other values blank.  There would be a huge gap with 31
73 // elements that are currently unused, and then there would be 2 other
74 // (used) values, the vendor IDs.  We just force a read from the vendor
75 // IDs in the end of ProbeHWConfig to fill the cache.
76 };
77 
78 
79 //
80 // This is the hardware configuration information.  The first struct is for
81 // nodes, which we default to FALSE.  The second struct is for Pins, which
82 // contains the configuration (FALSE) and the registry string which is the
83 // reason for making a static struct so we can just fill in the name.
84 //
85 tHardwareConfig CAC97AdapterCommon::m_stHardwareConfig =
86 {
87     // Nodes
88     {{FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE},
89      {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE},
90      {FALSE}},
91     // Pins
92     {{FALSE, L"DisablePCBeep"},     // PINC_PCBEEP_PRESENT
93      {FALSE, L"DisablePhone"},      // PINC_PHONE_PRESENT
94      {FALSE, L"DisableMic2"},       // PINC_MIC2_PRESENT
95      {FALSE, L"DisableVideo"},      // PINC_VIDEO_PRESENT
96      {FALSE, L"DisableAUX"},        // PINC_AUX_PRESENT
97      {FALSE, L"DisableHeadphone"},  // PINC_HPOUT_PRESENT
98      {FALSE, L"DisableMonoOut"},    // PINC_MONOOUT_PRESENT
99      {FALSE, L"DisableMicIn"},      // PINC_MICIN_PRESENT
100      {FALSE, L"DisableMic"},        // PINC_MIC_PRESENT
101      {FALSE, L"DisableLineIn"},     // PINC_LINEIN_PRESENT
102      {FALSE, L"DisableCD"},         // PINC_CD_PRESENT
103      {FALSE, L"DisableSurround"},   // PINC_SURROUND_PRESENT
104      {FALSE, L"DisableCenterLFE"}}  // PINC_CENTER_LFE_PRESENT
105 };
106 
107 
108 #ifdef _MSC_VER
109 #pragma code_seg("PAGE")
110 #endif
111 /*****************************************************************************
112  * NewAdapterCommon
113  *****************************************************************************
114  * Create a new adapter common object.
115  */
116 NTSTATUS NewAdapterCommon
117 (
118     OUT PUNKNOWN   *Unknown,
119     IN  REFCLSID,
120     IN  PUNKNOWN    UnknownOuter    OPTIONAL,
121     _When_((PoolType & NonPagedPoolMustSucceed) != 0,
122        __drv_reportError("Must succeed pool allocations are forbidden. "
123 			 "Allocation failures cause a system crash"))
124     IN  POOL_TYPE   PoolType
125 )
126 {
127     PAGED_CODE ();
128 
129     ASSERT (Unknown);
130 
131     DOUT (DBG_PRINT, ("[NewAdapterCommon]"));
132 
133     STD_CREATE_BODY_WITH_TAG_(CAC97AdapterCommon,Unknown,UnknownOuter,PoolType,
134                               PoolTag, PADAPTERCOMMON);
135 }
136 
137 
138 /*****************************************************************************
139  * CAC97AdapterCommon::Init
140  *****************************************************************************
141  * Initialize the adapter common object -> initialize and probe HW.
142  * Pass only checked resources.
143  */
STDMETHODIMP_(NTSTATUS)144 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::Init
145 (
146     IN  PRESOURCELIST   ResourceList,
147     IN  PDEVICE_OBJECT  DeviceObject
148 )
149 {
150     PAGED_CODE ();
151 
152     ASSERT (ResourceList);
153     ASSERT (DeviceObject);
154 
155     NTSTATUS ntStatus = STATUS_SUCCESS;
156 
157     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::Init]"));
158 
159     //
160     // Set the topology pointer to NULL.
161     //
162     m_Topology = NULL;
163 
164     //
165     // Save the device object
166     //
167     m_pDeviceObject = DeviceObject;
168 
169     //
170     // Get the base address for the AC97 codec and bus master.
171     //
172     ASSERT (ResourceList->FindTranslatedPort (0));
173     m_pCodecBase = (PUSHORT)ResourceList->FindTranslatedPort (0)->
174                            u.Port.Start.QuadPart;
175 
176     ASSERT (ResourceList->FindTranslatedPort (1));
177     m_pBusMasterBase = (PUCHAR)ResourceList->FindTranslatedPort (1)->
178                               u.Port.Start.QuadPart;
179 
180     DOUT (DBG_SYSINFO, ("Configuration:\n"
181                         "   Bus Master = 0x%p\n"
182                         "   Codec      = 0x%p",
183                         m_pBusMasterBase, m_pCodecBase));
184 
185     //
186     // Set m_bDirectRead to TRUE so that all AC97 register read and
187     // writes are going directly to the HW
188     //
189     m_bDirectRead = TRUE;
190 
191     //
192     // Initialize the hardware.
193     //
194     ntStatus = InitAC97 ();
195     if (!NT_SUCCESS (ntStatus))
196         return ntStatus;
197 
198     //
199     // Probe hardware configuration
200     //
201     ntStatus = ProbeHWConfig ();
202     if (!NT_SUCCESS (ntStatus))
203     {
204         DOUT (DBG_ERROR, ("Probing of hardware configuration failed!"));
205         return ntStatus;
206     }
207 
208     //
209     // Now, every AC97 read access goes to the cache.
210     //
211     m_bDirectRead = FALSE;
212 
213     //
214     // Restore the AC97 registers now.
215     //
216 #if (DBG)
217     DumpConfig ();
218 #endif
219     ntStatus = SetAC97Default ();
220 
221     //
222     // Initialize the device state.
223     //
224     m_PowerState = PowerDeviceD0;
225 
226     return ntStatus;
227 }
228 
229 
230 /*****************************************************************************
231  * CAC97AdapterCommon::~CAC97AdapterCommon
232  *****************************************************************************
233  * Destructor.
234  */
~CAC97AdapterCommon()235 CAC97AdapterCommon::~CAC97AdapterCommon ()
236 {
237     PAGED_CODE ();
238 
239     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::~CAC97AdapterCommon]"));
240 }
241 
242 
243 #if (DBG)
244 /*****************************************************************************
245  * CAC97AdapterCommon::DumpConfig
246  *****************************************************************************
247  * Dumps the HW configuration for the AC97 codec.
248  */
DumpConfig(void)249 void CAC97AdapterCommon::DumpConfig (void)
250 {
251     PAGED_CODE ();
252 
253     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::DumpConfig]"));
254 
255     //
256     // Print debug output for MICIN.
257     //
258     if (GetPinConfig (PINC_MICIN_PRESENT))
259     {
260         DOUT (DBG_PROBE, ("MICIN found"));
261     }
262     else
263     {
264         DOUT (DBG_PROBE, ("No MICIN found"));
265     }
266 
267     //
268     // Print debug output for tone controls.
269     //
270     if (GetNodeConfig (NODEC_TONE_PRESENT))
271     {
272         DOUT (DBG_PROBE, ("Tone controls found"));
273     }
274     else
275     {
276         DOUT (DBG_PROBE, ("No tone controls found"));
277     }
278 
279     //
280     // Print debug output for mono out.
281     //
282     if (!GetPinConfig (PINC_MONOOUT_PRESENT))
283     {
284         DOUT (DBG_PROBE, ("No mono out found"));
285     }
286 
287     //
288     // Print debug output for headphones.
289     //
290     if (!GetPinConfig (PINC_HPOUT_PRESENT))
291     {
292         DOUT (DBG_PROBE, ("No headphone out found"));
293     }
294 
295     //
296     // Print debug output for loudness.
297     //
298     if (GetNodeConfig (NODEC_LOUDNESS_PRESENT))
299     {
300         DOUT (DBG_PROBE, ("Loudness found"));
301     }
302     else
303     {
304         DOUT (DBG_PROBE, ("No Loudness found"));
305     }
306 
307     //
308     // Print debug output for 3D.
309     //
310     if (GetNodeConfig (NODEC_3D_PRESENT))
311     {
312         DOUT (DBG_PROBE, ("3D controls found"));
313     }
314     else
315     {
316         DOUT (DBG_PROBE, ("No 3D controls found"));
317     }
318 
319     //
320     // Print debug output for pc beep.
321     //
322     if (GetPinConfig (PINC_PCBEEP_PRESENT))
323     {
324         DOUT (DBG_PROBE, ("PC beep found"));
325     }
326     else
327     {
328         DOUT (DBG_PROBE, ("No PC beep found"));
329     }
330 
331     //
332     // Print debug output for phone line (or mono line input).
333     //
334     if (GetPinConfig (PINC_PHONE_PRESENT))
335     {
336         DOUT (DBG_PROBE, ("Phone found"));
337     }
338     else
339     {
340         DOUT (DBG_PROBE, ("No Phone found"));
341     }
342 
343     //
344     // Print debug output for video.
345     //
346     if (GetPinConfig (PINC_VIDEO_PRESENT))
347     {
348         DOUT (DBG_PROBE, ("Video in found"));
349     }
350     else
351     {
352         DOUT (DBG_PROBE, ("No Video in found"));
353     }
354 
355     //
356     // Print debug output for AUX.
357     //
358     if (GetPinConfig (PINC_AUX_PRESENT))
359     {
360         DOUT (DBG_PROBE, ("AUX in found"));
361     }
362     else
363     {
364         DOUT (DBG_PROBE, ("No AUX in found"));
365     }
366 
367     //
368     // Print debug output for second miorophone.
369     //
370     if (GetPinConfig (PINC_MIC2_PRESENT))
371     {
372         DOUT (DBG_PROBE, ("MIC2 found"));
373     }
374     else
375     {
376         DOUT (DBG_PROBE, ("No MIC2 found"));
377     }
378 
379     //
380     // Print debug output for 3D stuff.
381     //
382     if (GetNodeConfig (NODEC_3D_PRESENT))
383     {
384         if (GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE))
385         {
386             DOUT (DBG_PROBE, ("Adjustable 3D center control found"));
387         }
388         if (GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE))
389         {
390             DOUT (DBG_PROBE, ("Nonadjustable 3D depth control found"));
391         }
392     }
393 
394     //
395     // Print debug output for quality of master volume.
396     //
397     if (GetNodeConfig (NODEC_6BIT_MASTER_VOLUME))
398     {
399         DOUT (DBG_PROBE, ("6bit master out found"));
400     }
401     else
402     {
403         DOUT (DBG_PROBE, ("5bit master out found"));
404     }
405 
406     //
407     // Print debug output for quality of headphones volume.
408     //
409     if (GetPinConfig (PINC_HPOUT_PRESENT))
410     {
411         if (GetNodeConfig (NODEC_6BIT_HPOUT_VOLUME))
412         {
413             DOUT (DBG_PROBE, ("6bit headphone out found"));
414         }
415         else
416         {
417             DOUT (DBG_PROBE, ("5bit headphone out found"));
418         }
419     }
420 
421     //
422     // Print debug output for quality of mono out volume.
423     //
424     if (GetPinConfig (PINC_MONOOUT_PRESENT))
425     {
426         if (GetNodeConfig (NODEC_6BIT_MONOOUT_VOLUME))
427         {
428             DOUT (DBG_PROBE, ("6bit mono out found"));
429         }
430         else
431         {
432             DOUT (DBG_PROBE, ("5bit mono out found"));
433         }
434     }
435 
436     //
437     // Print sample rate information.
438     //
439     if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
440     {
441         DOUT (DBG_PROBE, ("PCM variable sample rate supported"));
442     }
443     else
444     {
445         DOUT (DBG_PROBE, ("only 48KHz PCM supported"));
446     }
447 
448     //
449     // Print double rate information.
450     //
451     if (GetNodeConfig (NODEC_PCM_DOUBLERATE_SUPPORTED))
452     {
453         DOUT (DBG_PROBE, ("PCM double sample rate supported"));
454     }
455 
456     //
457     // Print mic rate information.
458     //
459     if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
460     {
461         DOUT (DBG_PROBE, ("MIC variable sample rate supported"));
462     }
463     else
464     {
465         DOUT (DBG_PROBE, ("only 48KHz MIC supported"));
466     }
467 
468     // print DAC information
469     if (GetNodeConfig (NODEC_CENTER_DAC_PRESENT))
470     {
471         DOUT (DBG_PROBE, ("center DAC found"));
472     }
473     if (GetNodeConfig (NODEC_SURROUND_DAC_PRESENT))
474     {
475         DOUT (DBG_PROBE, ("surround DAC found"));
476     }
477     if (GetNodeConfig (NODEC_LFE_DAC_PRESENT))
478     {
479         DOUT (DBG_PROBE, ("LFE DAC found"));
480     }
481 }
482 #endif
483 
484 /*****************************************************************************
485  * CAC97AdapterCommon::NonDelegatingQueryInterface
486  *****************************************************************************
487  * Obtains an interface.  This function works just like a COM QueryInterface
488  * call and is used if the object is not being aggregated.
489  * We basically just check any GUID we know and return this object in case we
490  * know it.
491  */
STDMETHODIMP_(NTSTATUS)492 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::NonDelegatingQueryInterface
493 (
494     _In_         REFIID  Interface,
495     _COM_Outptr_ PVOID * Object
496 )
497 {
498     PAGED_CODE ();
499 
500     ASSERT (Object);
501 
502     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::NonDelegatingQueryInterface]"));
503 
504     // Is it IID_IUnknown?
505     if (IsEqualGUIDAligned (Interface, IID_IUnknown))
506     {
507         *Object = (PVOID)(PUNKNOWN)(PADAPTERCOMMON)this;
508     }
509     else
510     // or IID_IAC97AdapterCommon ...
511     if (IsEqualGUIDAligned (Interface, IID_IAC97AdapterCommon))
512     {
513         *Object = (PVOID)(PADAPTERCOMMON)this;
514     }
515     else
516     // or IID_IAdapterPowerManagement ...
517     if (IsEqualGUIDAligned (Interface, IID_IAdapterPowerManagement))
518     {
519         *Object = (PVOID)(PADAPTERPOWERMANAGEMENT)this;
520     }
521     else
522     {
523         // nothing found, must be an unknown interface.
524         *Object = NULL;
525         return STATUS_INVALID_PARAMETER;
526     }
527 
528     //
529     // We reference the interface for the caller.
530     //
531     ((PUNKNOWN)*Object)->AddRef ();
532     return STATUS_SUCCESS;
533 }
534 
535 /*****************************************************************************
536  * CAC97AdapterCommon::InitAC97
537  *****************************************************************************
538  * Initialize the AC97 (without hosing the modem if it got installed first).
539  */
InitAC97(void)540 NTSTATUS CAC97AdapterCommon::InitAC97 (void)
541 {
542     PAGED_CODE ();
543 
544     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::InitAC97]"));
545 
546     //
547     // First check if there is an AC link to the primary CoDec.
548     //
549     NTSTATUS ntStatus = PrimaryCodecReady ();
550     if (NT_SUCCESS (ntStatus))
551     {
552         //
553         // Second, reset this primary CoDec; If this is a AMC97 CoDec, only
554         // the audio registers are reset. If this is a MC97 CoDec, the CoDec
555         // should ignore the reset (according to the spec).
556         //
557         WriteCodecRegister (AC97REG_RESET, 0x00, 0xFFFF);
558 
559         ntStatus = PowerUpCodec ();
560     }
561     else
562     {
563         DOUT (DBG_ERROR, ("Initialization of AC97 CoDec failed."));
564     }
565 
566     return ntStatus;
567 }
568 
569 /*****************************************************************************
570  * CAC97AdapterCommon::Check6thBitSupport
571  *****************************************************************************
572  * Probes for 6th bit volume control support.
573  * The passed parameters are the AC97 register that has the volume control and
574  * the node config that should be set in this case.
575  */
Check6thBitSupport(IN AC97Register AC97Reg,IN TopoNodeConfig Config)576 NTSTATUS CAC97AdapterCommon::Check6thBitSupport
577 (
578     IN AC97Register AC97Reg,
579     IN TopoNodeConfig Config
580 )
581 {
582     PAGED_CODE();
583 
584     NTSTATUS    ntStatus;
585     WORD        wCodecReg;
586     WORD        wOriginal;
587 
588     // Read the current value.
589     ntStatus = ReadCodecRegister (AC97Reg, &wOriginal);
590     if (!NT_SUCCESS (ntStatus))
591         return ntStatus;
592 
593     // Write the 6th bit; for mono controls we write 0x20, for stereo
594     // controls 0x2020.
595     ntStatus = WriteCodecRegister (AC97Reg,
596                     (AC97Reg == AC97REG_MMONO_VOLUME) ? 0x0020 : 0x2020, 0xFFFF);
597     if (!NT_SUCCESS (ntStatus))
598         return ntStatus;
599 
600     // And read back.
601     ntStatus = ReadCodecRegister (AC97Reg, &wCodecReg);
602     if (!NT_SUCCESS (ntStatus))
603         return ntStatus;
604 
605     // Check return. For mono 0x20 and for stereo 0x2020.
606     if (((wCodecReg & 0x0020) && (AC97Reg == AC97REG_MMONO_VOLUME)) ||
607         (wCodecReg & 0x2020))
608     {
609         SetNodeConfig (Config, TRUE);
610     }
611     else
612     {
613         SetNodeConfig (Config, FALSE);
614     }
615 
616     // Restore original value.
617     WriteCodecRegister (AC97Reg, wOriginal, 0xFFFF);
618 
619     return ntStatus;
620 }
621 
622 /*****************************************************************************
623  * CAC97AdapterCommon::ProbeHWConfig
624  *****************************************************************************
625  * Probes the hardware configuration.
626  * If this function returns with an error, then the configuration is not
627  * complete! Probing the registers is done by reading them (and comparing with
628  * the HW default value) or when the default is unknown, writing to them and
629  * reading back + restoring.
630  * Additionally, we read the registry so that a HW vendor can overwrite (means
631  * disable) found registers in case the adapter (e.g. video) is not visible to
632  * the user (he can't plug in a video audio there).
633  *
634  * This is a very long function with all of the error checking!
635  */
ProbeHWConfig(void)636 NTSTATUS CAC97AdapterCommon::ProbeHWConfig (void)
637 {
638     PAGED_CODE ();
639 
640     NTSTATUS ntStatus = STATUS_SUCCESS;
641     DWORD    dwGlobalStatus;
642     WORD     wCodecID;
643     WORD     wCodecReg;
644 
645     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ProbeHWConfig]"));
646 
647     //
648     // Wait for the whatever 97 to complete reset and establish a link.
649     //
650     ntStatus = PrimaryCodecReady ();
651     if (!NT_SUCCESS (ntStatus))
652         return ntStatus;
653 
654     //
655     // Master volume is one of the supported registers on an AC97
656     //
657     ntStatus = ReadCodecRegister (AC97REG_MASTER_VOLUME, &wCodecReg);
658     if (!NT_SUCCESS (ntStatus))
659         return ntStatus;
660 
661     // Default is x8000.
662     if (wCodecReg != 0x8000)
663         return STATUS_NO_SUCH_DEVICE;
664 
665     //
666     // This gives us information about the AC97 CoDec
667     //
668     ntStatus = ReadCodecRegister (AC97REG_RESET, &wCodecID);
669     if (!NT_SUCCESS (ntStatus))
670         return ntStatus;
671 
672     //
673     // Fill out the configuration stuff.
674     //
675 
676     SetPinConfig (PINC_MICIN_PRESENT, wCodecID & 0x0001);
677 
678     // Check if OEM wants to disable MIC record line.
679     if (DisableAC97Pin (PINC_MICIN_PRESENT))
680         SetPinConfig (PINC_MICIN_PRESENT, FALSE);
681 
682     // If we still have MIC record line, enable the DAC in ext. audio register.
683     if (GetPinConfig (PINC_MICIN_PRESENT))
684         // Enable ADC MIC.
685         WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, 0, 0x4000);
686     else
687         // Disable ADC MIC.
688         WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, 0x4000, 0x4000);
689 
690     //
691     // Continue setting configuration information.
692     //
693 
694     SetNodeConfig (NODEC_TONE_PRESENT, wCodecID & 0x0004);
695     SetNodeConfig (NODEC_SIMUL_STEREO_PRESENT, wCodecID & 0x0008);
696     SetPinConfig (PINC_HPOUT_PRESENT, wCodecID & 0x0010);
697 
698     // Check if OEM wants to disable headphone output.
699     if (DisableAC97Pin (PINC_HPOUT_PRESENT))
700         SetPinConfig (PINC_HPOUT_PRESENT, FALSE);
701 
702     SetNodeConfig (NODEC_LOUDNESS_PRESENT, wCodecID & 0x0020);
703     SetNodeConfig (NODEC_3D_PRESENT, wCodecID & 0x7C00);
704 
705     //
706     // Test for the input pins that are always there but could be disabled
707     // by the HW vender
708     //
709 
710     // Check if OEM wants to disable mic input.
711     SetPinConfig (PINC_MIC_PRESENT, !DisableAC97Pin (PINC_MIC_PRESENT));
712 
713     // Check if OEM wants to disable line input.
714     SetPinConfig (PINC_LINEIN_PRESENT, !DisableAC97Pin (PINC_LINEIN_PRESENT));
715 
716     // Check if OEM wants to disable CD input.
717     SetPinConfig (PINC_CD_PRESENT, !DisableAC97Pin (PINC_CD_PRESENT));
718 
719 
720     //
721     // For the rest, we have to probe the registers.
722     //
723 
724     //
725     // Test for Mono out.
726     //
727     ntStatus = ReadCodecRegister (AC97REG_MMONO_VOLUME, &wCodecReg);
728     if (!NT_SUCCESS (ntStatus))
729         return ntStatus;
730 
731     // Default is x8000.
732     SetPinConfig (PINC_MONOOUT_PRESENT, (wCodecReg == 0x8000));
733 
734     // Check if OEM wants to disable mono output.
735     if (DisableAC97Pin (PINC_MONOOUT_PRESENT))
736         SetPinConfig (PINC_MONOOUT_PRESENT, FALSE);
737 
738     //
739     // Test for PC beeper support.
740     //
741     ntStatus = ReadCodecRegister (AC97REG_BEEP_VOLUME, &wCodecReg);
742     if (!NT_SUCCESS (ntStatus))
743         return ntStatus;
744 
745     // default is x0 or x8000. If it's 0x8000 then we know for sure that the
746     // CoDec has a PcBeep, otherwise we have to check the register
747     if (wCodecReg == 0x8000)
748         SetPinConfig (PINC_PCBEEP_PRESENT, TRUE);
749     else if (!wCodecReg)
750     {
751         // mute the pc beeper.
752         ntStatus = WriteCodecRegister (AC97REG_BEEP_VOLUME, 0x8000, 0xFFFF);
753         if (!NT_SUCCESS (ntStatus))
754             return ntStatus;
755 
756         // read back
757         ntStatus = ReadCodecRegister (AC97REG_BEEP_VOLUME, &wCodecReg);
758         if (!NT_SUCCESS (ntStatus))
759             return ntStatus;
760 
761         if (wCodecReg == 0x8000)
762         {
763             // yep, we have support.
764             SetPinConfig (PINC_PCBEEP_PRESENT, TRUE);
765             // reset to default value.
766             WriteCodecRegister (AC97REG_BEEP_VOLUME, 0x0, 0xFFFF);
767         }
768         else
769             // nope, not present
770             SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
771     }
772     else
773         // any other value then 0x0 and 0x8000.
774         SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
775 
776     // Check if OEM wants to disable beeper support.
777     if (DisableAC97Pin (PINC_PCBEEP_PRESENT))
778         SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
779 
780     //
781     // Test for phone support.
782     //
783     ntStatus = ReadCodecRegister (AC97REG_PHONE_VOLUME, &wCodecReg);
784     if (!NT_SUCCESS (ntStatus))
785         return ntStatus;
786 
787     // Default is x8008.
788     SetPinConfig (PINC_PHONE_PRESENT, (wCodecReg == 0x8008));
789 
790     // Check if OEM wants to disable phone input.
791     if (DisableAC97Pin (PINC_PHONE_PRESENT))
792         SetPinConfig (PINC_PHONE_PRESENT, FALSE);
793 
794     //
795     // Test for video support.
796     //
797     ntStatus = ReadCodecRegister (AC97REG_VIDEO_VOLUME, &wCodecReg);
798     if (!NT_SUCCESS (ntStatus))
799         return ntStatus;
800 
801     // Default is x8808.
802     SetPinConfig (PINC_VIDEO_PRESENT, (wCodecReg == 0x8808));
803 
804     // Check if OEM wants to disable video input.
805     if (DisableAC97Pin (PINC_VIDEO_PRESENT))
806         SetPinConfig (PINC_VIDEO_PRESENT, FALSE);
807 
808     //
809     // Test for Aux support.
810     //
811     ntStatus = ReadCodecRegister (AC97REG_AUX_VOLUME, &wCodecReg);
812     if (!NT_SUCCESS (ntStatus))
813         return ntStatus;
814 
815     // Default is 0x8808.
816     SetPinConfig (PINC_AUX_PRESENT, (wCodecReg == 0x8808));
817 
818     // Check if OEM wants to disable aux input.
819     if (DisableAC97Pin (PINC_AUX_PRESENT))
820         SetPinConfig (PINC_AUX_PRESENT, FALSE);
821 
822     //
823     // Test for Mic2 source.
824     //
825     ntStatus = ReadCodecRegister (AC97REG_GENERAL, &wCodecReg);
826     if (!NT_SUCCESS (ntStatus))
827         return ntStatus;
828 
829     // Test for Mic2 select bit.
830     if (wCodecReg & 0x0100)
831         SetPinConfig (PINC_MIC2_PRESENT, TRUE);
832     else
833     {
834         // Select Mic2 as source.
835         ntStatus = WriteCodecRegister (AC97REG_GENERAL, 0x0100, 0x0100);
836         if (!NT_SUCCESS (ntStatus))
837             return ntStatus;
838 
839         // Read back.
840         ntStatus = ReadCodecRegister (AC97REG_GENERAL, &wCodecReg);
841         if (!NT_SUCCESS (ntStatus))
842             return ntStatus;
843 
844         if (wCodecReg & 0x0100)
845         {
846             // Yep, we have support so set it to the default value.
847             SetPinConfig (PINC_MIC2_PRESENT, TRUE);
848             // reset to default value.
849             WriteCodecRegister (AC97REG_GENERAL, 0, 0x0100);
850         }
851         else
852             SetPinConfig (PINC_MIC2_PRESENT, FALSE);
853     }
854 
855     // Check if OEM wants to disable mic2 input.
856     if (DisableAC97Pin (PINC_MIC2_PRESENT))
857         SetPinConfig (PINC_MIC2_PRESENT, FALSE);
858 
859     //
860     // Test the 3D controls.
861     //
862     if (GetNodeConfig (NODEC_3D_PRESENT))
863     {
864         //
865         // First test for fixed 3D controls. Write default value ...
866         //
867         ntStatus = WriteCodecRegister (AC97REG_3D_CONTROL, 0, 0xFFFF);
868         if (!NT_SUCCESS (ntStatus))
869             return ntStatus;
870 
871         // Read 3D register. Default is 0 when adjustable, otherwise it is
872         // a fixed value.
873         ntStatus = ReadCodecRegister (AC97REG_3D_CONTROL, &wCodecReg);
874         if (!NT_SUCCESS (ntStatus))
875             return ntStatus;
876 
877         //
878         // Check center and depth separately.
879         //
880 
881         // For center
882         SetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE, !(wCodecReg & 0x0F00));
883 
884         // For depth
885         SetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE, !(wCodecReg & 0x000F));
886 
887         //
888         // Test for adjustable controls.
889         //
890         WriteCodecRegister (AC97REG_3D_CONTROL, 0x0A0A, 0xFFFF);
891 
892         // Read 3D register. Now it should be 0x0A0A for adjustable controls,
893         // otherwise it is a fixed control or simply not there.
894         ReadCodecRegister (AC97REG_3D_CONTROL, &wCodecReg);
895 
896         // Restore the default value
897         WriteCodecRegister (AC97REG_3D_CONTROL, 0, 0xFFFF);
898 
899         // Check the center control for beeing adjustable
900         if (GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE) &&
901             (wCodecReg & 0x0F00) != 0x0A00)
902         {
903             SetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE, FALSE);
904         }
905 
906         // Check the depth control for beeing adjustable
907         if (GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) &&
908             (wCodecReg & 0x000F) != 0x000A)
909         {
910             SetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE, FALSE);
911         }
912     }
913 
914     //
915     // Check for 6th bit support in volume controls.  To check the 6th bit,
916     // we first have to write a value (with 6th bit set) and then read it
917     // back.  After that, we should restore the register to its default value.
918     //
919 
920     //
921     // Start with the master volume.
922     //
923     Check6thBitSupport (AC97REG_MASTER_VOLUME, NODEC_6BIT_MASTER_VOLUME);
924 
925     //
926     // Check for a headphone volume control.
927     //
928     if (GetPinConfig (PINC_HPOUT_PRESENT))
929     {
930         Check6thBitSupport (AC97REG_HPHONE_VOLUME, NODEC_6BIT_HPOUT_VOLUME);
931     }
932 
933     //
934     // Mono out there?
935     //
936     if (GetPinConfig (PINC_MONOOUT_PRESENT))
937     {
938         Check6thBitSupport (AC97REG_MMONO_VOLUME, NODEC_6BIT_MONOOUT_VOLUME);
939     }
940 
941     //
942     // Get extended AC97 V2.0 information
943     //
944     ntStatus = ReadCodecRegister (AC97REG_EXT_AUDIO_ID, &wCodecReg);
945     if (!NT_SUCCESS (ntStatus))
946         return ntStatus;
947 
948     //
949     // Store the information
950     //
951     SetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED, wCodecReg & 0x0001);
952     SetNodeConfig (NODEC_PCM_DOUBLERATE_SUPPORTED, wCodecReg & 0x0002);
953     SetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED, wCodecReg & 0x0008);
954     SetNodeConfig (NODEC_CENTER_DAC_PRESENT, wCodecReg & 0x0040);
955     SetNodeConfig (NODEC_SURROUND_DAC_PRESENT, wCodecReg & 0x0080);
956     SetNodeConfig (NODEC_LFE_DAC_PRESENT, wCodecReg & 0x0100);
957 
958     //
959     // In case we have some features get some more information and program
960     // the codec.
961     //
962     if (wCodecReg)
963     {
964         //
965         // Enable variable sample rate in the control register and disable
966         // double rate. Also enable all DACs.
967         //
968         WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, wCodecReg & 0x0009, 0x380B);
969 
970         //
971         // Check for codecs that have only one sample rate converter. These
972         // codecs will stick registers AC97REG_FRONT_SAMPLERATE and
973         // AC97REG_RECORD_SAMPLERATE together.
974         //
975         if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
976         {
977             // The default of the sample rate registers should be 0xBB80.
978             WriteCodecRegister (AC97REG_FRONT_SAMPLERATE, 0xBB80, 0xFFFF);
979 
980             // Write 44.1KHz into record VSR, then check playback again.
981             WriteCodecRegister (AC97REG_RECORD_SAMPLERATE, 0xAC44, 0xFFFF);
982             ntStatus = ReadCodecRegister (AC97REG_FRONT_SAMPLERATE, &wCodecReg);
983             WriteCodecRegister (AC97REG_RECORD_SAMPLERATE, 0xBB80, 0xFFFF);
984             if (!NT_SUCCESS (ntStatus))
985                 return ntStatus;
986 
987             //
988             // Set the flag accordingly
989             //
990             SetNodeConfig (NODEC_PCM_VSR_INDEPENDENT_RATES, (wCodecReg == 0xBB80));
991         }
992 
993         //
994         // Check multichanel support on the AC97.
995         //
996         if (GetNodeConfig (NODEC_SURROUND_DAC_PRESENT))
997         {
998             dwGlobalStatus = ReadBMControlRegister32 (GLOB_STA);
999 
1000             //
1001             // Codec supports >2 chanel, does AC97 too?
1002             //
1003             if ((GetNodeConfig (NODEC_CENTER_DAC_PRESENT) ||
1004                 GetNodeConfig (NODEC_LFE_DAC_PRESENT)) &&
1005                 (dwGlobalStatus & GLOB_STA_MC6))
1006             {
1007                 SetPinConfig (PINC_CENTER_LFE_PRESENT, TRUE);
1008             }
1009             else
1010             {
1011                 SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
1012             }
1013 
1014             //
1015             // Do we support at least 4 channels?
1016             //
1017             SetPinConfig (PINC_SURROUND_PRESENT, (dwGlobalStatus & GLOB_STA_MC4));
1018         }
1019         else
1020         {
1021             //
1022             // Only 2 channel (stereo) support.
1023             //
1024             SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
1025             SetPinConfig (PINC_SURROUND_PRESENT, FALSE);
1026         }
1027     }
1028 
1029     // Check if OEM wants to disable surround output.
1030     if (DisableAC97Pin (PINC_SURROUND_PRESENT))
1031         SetPinConfig (PINC_SURROUND_PRESENT, FALSE);
1032 
1033     // Check if OEM wants to disable center and LFE output.
1034     if (DisableAC97Pin (PINC_CENTER_LFE_PRESENT))
1035         SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
1036 
1037     //
1038     // Check the 6th bit support for the additional channels.
1039     //
1040     if (GetPinConfig (PINC_SURROUND_PRESENT))
1041         Check6thBitSupport (AC97REG_SURROUND_VOLUME, NODEC_6BIT_SURROUND_VOLUME);
1042 
1043     if (GetPinConfig (PINC_CENTER_LFE_PRESENT))
1044         Check6thBitSupport (AC97REG_CENTER_LFE_VOLUME, NODEC_6BIT_CENTER_LFE_VOLUME);
1045 
1046     //
1047     // We read these registers because they are dependent on the codec.
1048     //
1049     ReadCodecRegister (AC97REG_VENDOR_ID1, &wCodecReg);
1050     ReadCodecRegister (AC97REG_VENDOR_ID2, &wCodecReg);
1051 
1052     return STATUS_SUCCESS;
1053 }
1054 
1055 
1056 /*****************************************************************************
1057  * CAC97AdapterCommon::AcquireCodecSemiphore
1058  *****************************************************************************
1059  * Acquires the AC97 semiphore.  This can not be called at dispatch level
1060  * because it can timeout if a lower IRQL thread has the semaphore.
1061  */
AcquireCodecSemiphore()1062 NTSTATUS CAC97AdapterCommon::AcquireCodecSemiphore ()
1063 {
1064     PAGED_CODE ();
1065 
1066     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::AcquireCodecSemiphore]"));
1067 
1068     ULONG ulCount = 0;
1069     while (READ_PORT_UCHAR (m_pBusMasterBase + CAS) & CAS_CAS)
1070     {
1071         //
1072         // Do we want to give up??
1073         //
1074         if (ulCount++ > 100)
1075         {
1076             DOUT (DBG_ERROR, ("Cannot acquire semaphore."));
1077             return STATUS_IO_TIMEOUT;
1078         }
1079 
1080         //
1081         // Let's wait a little, 40us and then try again.
1082         //
1083         KeStallExecutionProcessor (40L);
1084     }
1085 
1086     return STATUS_SUCCESS;
1087 }
1088 
1089 
1090 /*****************************************************************************
1091  * CAC97AdapterCommon::ReadCodecRegister
1092  *****************************************************************************
1093  * Reads a AC97 register. Don't call at PASSIVE_LEVEL.
1094  */
STDMETHODIMP_(NTSTATUS)1095 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::ReadCodecRegister
1096 (
1097     _In_range_(0, AC97REG_INVALID)  AC97Register reg,
1098     _Out_ PWORD wData
1099 )
1100 {
1101     PAGED_CODE ();
1102 
1103     ASSERT (wData);
1104     ASSERT (reg < AC97REG_INVALID);    // audio can only be in the primary codec
1105     _Analysis_assume_(reg < AC97REG_INVALID);
1106 
1107     NTSTATUS ntStatus;
1108     ULONG    Status;
1109 
1110     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadCodecRegister]"));
1111 
1112     //
1113     // Check if we have to access the HW directly.
1114     //
1115     if (m_bDirectRead || (m_stAC97Registers[reg].wFlags & SHREG_INVALID) ||
1116         (m_stAC97Registers[reg].wFlags & SHREG_NOCACHE))
1117     {
1118         //
1119         // Grab the codec access semiphore.
1120         //
1121         ntStatus = AcquireCodecSemiphore ();
1122         if (!NT_SUCCESS (ntStatus))
1123         {
1124             DOUT (DBG_ERROR, ("ReadCodecRegister couldn't acquire the semiphore"
1125                 " for reg. %s", reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1126                                 reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1127                                 reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
1128                                 "REG_INVALID"));
1129             return ntStatus;
1130         }
1131 
1132         //
1133         // Read the data.
1134         //
1135         *wData = READ_PORT_USHORT (m_pCodecBase + reg);
1136 
1137         //
1138         // Check to see if the read was successful.
1139         //
1140         Status = READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA));
1141         if (Status & GLOB_STA_RCS)
1142         {
1143             //
1144             // clear the timeout bit
1145             //
1146             WRITE_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA), Status);
1147             *wData = 0;
1148             DOUT (DBG_ERROR, ("ReadCodecRegister timed out for register %s",
1149                     reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1150                     reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1151                     reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
1152                     "REG_INVALID"));
1153             return STATUS_IO_TIMEOUT;
1154         }
1155 
1156         //
1157         // Clear invalid flag
1158         //
1159         m_stAC97Registers[reg].wCache = *wData;
1160         m_stAC97Registers[reg].wFlags &= ~SHREG_INVALID;
1161 
1162         DOUT (DBG_REGS, ("AC97READ: %s = 0x%04x (HW)",
1163                 reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1164                 reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1165                 reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
1166                 "REG_INVALID", *wData));
1167     }
1168     else
1169     {
1170         //
1171         // Otherwise, use the value in the cache.
1172         //
1173         *wData = m_stAC97Registers[reg].wCache;
1174         DOUT (DBG_REGS, ("AC97READ: %s = 0x%04x (C)",
1175                 reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1176                 reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1177                 reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
1178                 "REG_INVALID", *wData));
1179     }
1180 
1181     return STATUS_SUCCESS;
1182 }
1183 
1184 
1185 /*****************************************************************************
1186  * CAC97AdapterCommon::WriteCodecRegister
1187  *****************************************************************************
1188  * Writes to a AC97 register.  This can only be done at passive level because
1189  * the AcquireCodecSemiphore call could fail!
1190  */
STDMETHODIMP_(NTSTATUS)1191 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::WriteCodecRegister
1192 (
1193     _In_range_(0, AC97REG_INVALID)  AC97Register reg,
1194     _In_  WORD wData,
1195     _In_  WORD wMask
1196 )
1197 {
1198     PAGED_CODE ();
1199 
1200     ASSERT (reg < AC97REG_INVALID);    // audio can only be in the primary codec
1201 
1202     WORD TempData = 0;
1203     NTSTATUS ntStatus = STATUS_SUCCESS;
1204 
1205     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteCodecRegister]"));
1206 
1207     //
1208     // No mask?  Could happen when you try to prg. left channel of a
1209     // mono volume.
1210     //
1211     if (!wMask)
1212         return STATUS_SUCCESS;
1213 
1214     //
1215     // Check to see if we are only writing specific bits.  If so, we want
1216     // to leave some bits in the register alone.
1217     //
1218     if (wMask != 0xffff)
1219     {
1220         //
1221         // Read the current register contents.
1222         //
1223         ntStatus = ReadCodecRegister (reg, &TempData);
1224         if (!NT_SUCCESS (ntStatus))
1225         {
1226             DOUT (DBG_ERROR, ("WriteCodecRegiser read for mask failed"));
1227             return ntStatus;
1228         }
1229 
1230         //
1231         // Do the masking.
1232         //
1233         TempData &= ~wMask;
1234         TempData |= (wMask & wData);
1235     }
1236     else
1237     {
1238         TempData = wData;
1239     }
1240 
1241 
1242     //
1243     // Grab the codec access semiphore.
1244     //
1245     ntStatus = AcquireCodecSemiphore ();
1246     if (!NT_SUCCESS (ntStatus))
1247     {
1248         DOUT (DBG_ERROR, ("WriteCodecRegister failed for register %s",
1249             reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1250             reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1251             reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" : "REG_INVALID"));
1252         return ntStatus;
1253     }
1254 
1255     //
1256     // Write the data.
1257     //
1258     WRITE_PORT_USHORT (m_pCodecBase + reg, TempData);
1259 
1260     //
1261     // Update cache.
1262     //
1263     _Analysis_assume_(reg < AC97REG_INVALID);
1264     m_stAC97Registers[reg].wCache = TempData;
1265 
1266     DOUT (DBG_REGS, ("AC97WRITE: %s -> 0x%04x",
1267                    reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
1268                    reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
1269                    reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
1270                    "REG_INVALID", TempData));
1271 
1272 
1273     return STATUS_SUCCESS;
1274 }
1275 
1276 
1277 /*****************************************************************************
1278  * CAC97AdapterCommon::PrimaryCodecReady
1279  *****************************************************************************
1280  * Checks whether the primary codec is present and ready.  This may take
1281  * awhile if we are bringing it up from a cold reset so give it a second
1282  * before giving up.
1283  */
PrimaryCodecReady(void)1284 NTSTATUS CAC97AdapterCommon::PrimaryCodecReady (void)
1285 {
1286     PAGED_CODE ();
1287 
1288     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PrimaryCodecReady]"));
1289 
1290 
1291     //
1292     // Enable the AC link and raise the reset line.
1293     //
1294     DWORD dwRegValue = ReadBMControlRegister32 (GLOB_CNT);
1295 
1296     // If someone enabled GPI Interrupt Enable, then he hopefully handles that
1297     // too.
1298     dwRegValue = (dwRegValue | GLOB_CNT_COLD) & ~(GLOB_CNT_ACLOFF | GLOB_CNT_PRIE);
1299     WriteBMControlRegister (GLOB_CNT, dwRegValue);
1300 
1301     //
1302     // Wait for the Codec to be ready.
1303     //
1304     ULONG           WaitCycles = 200;
1305     LARGE_INTEGER   WaitTime;
1306 
1307     WaitTime.QuadPart = (-50000);   // wait 5000us (5ms) relative
1308 
1309     do
1310     {
1311         if (READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA)) &
1312             GLOB_STA_PCR)
1313         {
1314             return STATUS_SUCCESS;
1315         }
1316 
1317         KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
1318     } while (WaitCycles--);
1319 
1320     DOUT (DBG_ERROR, ("PrimaryCodecReady timed out!"));
1321     return STATUS_IO_TIMEOUT;
1322 }
1323 
1324 
1325 /*****************************************************************************
1326  * CAC97AdapterCommon::PowerUpCodec
1327  *****************************************************************************
1328  * Sets the Codec to the highest power state and waits until the Codec reports
1329  * that the power state is reached.
1330  */
PowerUpCodec(void)1331 NTSTATUS CAC97AdapterCommon::PowerUpCodec (void)
1332 {
1333     PAGED_CODE ();
1334 
1335     WORD        wCodecReg;
1336     NTSTATUS    ntStatus;
1337 
1338     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PowerUpCodec]"));
1339 
1340     //
1341     // Power up the Codec.
1342     //
1343     WriteCodecRegister (AC97REG_POWERDOWN, 0x00, 0xFFFF);
1344 
1345     //
1346     // Wait for the Codec to be powered up.
1347     //
1348     ULONG           WaitCycles = 200;
1349     LARGE_INTEGER   WaitTime;
1350 
1351     WaitTime.QuadPart = (-50000);   // wait 5000us (5ms) relative
1352 
1353     do
1354     {
1355         //
1356         // Read the power management register.
1357         //
1358         ntStatus = ReadCodecRegister (AC97REG_POWERDOWN, &wCodecReg);
1359         if (!NT_SUCCESS (ntStatus))
1360         {
1361             wCodecReg = 0;      // Will cause an error.
1362             break;
1363         }
1364 
1365         //
1366         // Check the power state. Should be ready.
1367         //
1368         if ((wCodecReg & 0x0f) == 0x0f)
1369             break;
1370 
1371         //
1372         // Let's wait a little, 5ms and then try again.
1373         //
1374         KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
1375     } while (WaitCycles--);
1376 
1377     // Check if we timed out.
1378     if ((wCodecReg & 0x0f) != 0x0f)
1379     {
1380         DOUT (DBG_ERROR, ("PowerUpCodec timed out. CoDec not powered up."));
1381         ntStatus = STATUS_DEVICE_NOT_READY;
1382     }
1383 
1384     return ntStatus;
1385 }
1386 
1387 
1388 /*****************************************************************************
1389  * CAC97AdapterCommon::ProgramSampleRate
1390  *****************************************************************************
1391  * Programs the sample rate. If the rate cannot be programmed, the routine
1392  * restores the register and returns STATUS_UNSUCCESSFUL.
1393  * We don't handle double rate sample rates here, because the Intel AC97 con-
1394  * troller cannot serve CoDecs with double rate or surround sound. If you want
1395  * to modify this driver for another AC97 controller, then you might want to
1396  * change this function too.
1397  */
STDMETHODIMP_(NTSTATUS)1398 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::ProgramSampleRate
1399 (
1400     IN  AC97Register    Register,
1401     IN  DWORD           dwSampleRate
1402 )
1403 {
1404     PAGED_CODE ();
1405 
1406     WORD     wOldRateReg, wCodecReg;
1407     NTSTATUS ntStatus;
1408 
1409     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ProgramSampleRate]"));
1410 
1411     //
1412     // Check if we support variable sample rate.
1413     //
1414     switch(Register)
1415     {
1416         case AC97REG_MIC_SAMPLERATE:
1417             //
1418             // Variable sample rate supported?
1419             //
1420             if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
1421             {
1422                 // Range supported?
1423                 if (dwSampleRate > 48000ul)
1424                 {
1425                     // Not possible.
1426                     DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
1427                     return STATUS_NOT_SUPPORTED;
1428                 }
1429             }
1430             else
1431             {
1432                 // Only 48000KHz possible.
1433                 if (dwSampleRate != 48000ul)
1434                 {
1435                     DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
1436                     return STATUS_NOT_SUPPORTED;
1437                 }
1438 
1439                 return STATUS_SUCCESS;
1440             }
1441             break;
1442 
1443         case AC97REG_FRONT_SAMPLERATE:
1444         case AC97REG_SURROUND_SAMPLERATE:
1445         case AC97REG_LFE_SAMPLERATE:
1446         case AC97REG_RECORD_SAMPLERATE:
1447             //
1448             // Variable sample rate supported?
1449             //
1450             if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
1451             {
1452                 //
1453                 // Check range supported
1454                 //
1455                 if (dwSampleRate > 48000ul)
1456                 {
1457                     DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
1458                     return STATUS_NOT_SUPPORTED;
1459                 }
1460             }
1461             else
1462             {
1463                 // Only 48KHz possible.
1464                 if (dwSampleRate != 48000ul)
1465                 {
1466                     DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
1467                     return STATUS_NOT_SUPPORTED;
1468                 }
1469 
1470                 return STATUS_SUCCESS;
1471             }
1472             break;
1473 
1474         default:
1475             DOUT (DBG_ERROR, ("Invalid sample rate register!"));
1476             return STATUS_UNSUCCESSFUL;
1477     }
1478 
1479 
1480     //
1481     // Save the old sample rate register.
1482     //
1483     ntStatus = ReadCodecRegister (Register, &wOldRateReg);
1484     if (!NT_SUCCESS (ntStatus))
1485         return ntStatus;
1486 
1487     //
1488     // program the rate.
1489     //
1490     ntStatus = WriteCodecRegister (Register, (WORD)dwSampleRate, 0xFFFF);
1491     if (!NT_SUCCESS (ntStatus))
1492     {
1493         DOUT (DBG_ERROR, ("Cannot program sample rate."));
1494         return ntStatus;
1495     }
1496 
1497     //
1498     // Read it back.
1499     //
1500     ntStatus = ReadCodecRegister (Register, &wCodecReg);
1501     if (!NT_SUCCESS (ntStatus))
1502     {
1503         DOUT (DBG_ERROR, ("Cannot read sample rate."));
1504         return ntStatus;
1505     }
1506 
1507     //
1508     // Validate.
1509     //
1510     if (wCodecReg != dwSampleRate)
1511     {
1512         //
1513         // restore sample rate and ctrl register.
1514         //
1515         WriteCodecRegister (Register, wOldRateReg, 0xFFFF);
1516 
1517         DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
1518         return STATUS_NOT_SUPPORTED;
1519     }
1520 
1521     DOUT (DBG_VSR, ("Samplerate changed to %d.", dwSampleRate));
1522     return STATUS_SUCCESS;
1523 }
1524 
1525 
1526 /*****************************************************************************
1527  * CAC97AdapterCommon::PowerChangeState
1528  *****************************************************************************
1529  * Change power state for the device.  We handle the codec, PowerChangeNotify
1530  * in the wave miniport handles the DMA registers.
1531  */
STDMETHODIMP_(void)1532 STDMETHODIMP_(void) CAC97AdapterCommon::PowerChangeState
1533 (
1534     _In_  POWER_STATE NewState
1535 )
1536 {
1537     PAGED_CODE ();
1538 
1539     NTSTATUS ntStatus = STATUS_SUCCESS;
1540 
1541     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PowerChangeNotify]"));
1542 
1543     //
1544     // Check to see if this is the current power state.
1545     //
1546     if (NewState.DeviceState == m_PowerState)
1547     {
1548         DOUT (DBG_POWER, ("New device state equals old state."));
1549         return;
1550     }
1551 
1552     //
1553     // Check the new device state.
1554     //
1555     if ((NewState.DeviceState < PowerDeviceD0) ||
1556         (NewState.DeviceState > PowerDeviceD3))
1557     {
1558         DOUT (DBG_ERROR, ("Unknown device state: D%d.",
1559              (ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
1560         return;
1561     }
1562 
1563     DOUT (DBG_POWER, ("Changing state to D%d.", (ULONG)NewState.DeviceState -
1564                     (ULONG)PowerDeviceD0));
1565 
1566     //
1567     // Switch on new state.
1568     //
1569     switch (NewState.DeviceState)
1570     {
1571         case PowerDeviceD0:
1572             //
1573             // If we are coming from D2 or D3 we have to restore the registers cause
1574             // there might have been a power loss.
1575             //
1576             if ((m_PowerState == PowerDeviceD3) || (m_PowerState == PowerDeviceD2))
1577             {
1578                 //
1579                 // Reset AD3 to indicate that we are now awake.
1580                 // Because the system has only one power irp at a time, we are sure
1581                 // that the modem driver doesn't get called while we are restoring
1582                 // power.
1583                 //
1584                 WriteBMControlRegister (GLOB_STA,
1585                     ReadBMControlRegister32 (GLOB_STA) & ~GLOB_STA_AD3);
1586 
1587                 //
1588                 // Restore codec registers.
1589                 //
1590                 ntStatus = RestoreCodecRegisters ();
1591             }
1592             else        // We are coming from power state D1
1593             {
1594                 ntStatus = PowerUpCodec ();
1595             }
1596 
1597             // Print error code.
1598             if (!NT_SUCCESS (ntStatus))
1599             {
1600                 DOUT (DBG_ERROR, ("PowerChangeState failed to restore the codec."));
1601             }
1602             break;
1603 
1604         case PowerDeviceD1:
1605             //
1606             // This sleep state is the lowest latency sleep state with respect
1607             // to the latency time required to return to D0. If the
1608             // driver is not being used an inactivity timer in portcls will
1609             // place the driver in this state after a timeout period
1610             // controllable via the registry.
1611             //
1612 
1613             // Let's power down the DAC/ADC's and analog mixer.
1614             WriteCodecRegister (AC97REG_POWERDOWN, 0x0700, 0xFFFF);
1615             break;
1616 
1617         case PowerDeviceD2:
1618         case PowerDeviceD3:
1619             //
1620             // This is a full hibernation state and is the longest latency sleep
1621             // state. In this modes the power could be removed or reduced that
1622             // much that the AC97 controller looses information, so we save
1623             // whatever we have to save.
1624             //
1625 
1626             //
1627             // Powerdown ADC, DAC, Mixer, Vref, HP amp, and Exernal Amp but not
1628             // AC-link and Clk
1629             //
1630             WriteCodecRegister (AC97REG_POWERDOWN, 0xCF00, 0xFFFF);
1631 
1632             //
1633             // Only in D3 mode we set the AD3 bit and evtl. shut off the AC link.
1634             //
1635             if (NewState.DeviceState == PowerDeviceD3)
1636             {
1637                 //
1638                 // Set the AD3 bit.
1639                 //
1640                 ULONG ulReg = ReadBMControlRegister32 (GLOB_STA);
1641                 WriteBMControlRegister (GLOB_STA, ulReg | GLOB_STA_AD3);
1642 
1643                 //
1644                 // We check if the modem is sleeping. If it is, we can shut off the
1645                 // AC link also. We shut off the AC link also if the modem is not
1646                 // there.
1647                 //
1648                 if ((ulReg & GLOB_STA_MD3) || !(ulReg & GLOB_STA_SCR))
1649                 {
1650                     // Set Codec to super sleep
1651                     WriteCodecRegister (AC97REG_POWERDOWN, 0xFF00, 0xFFFF);
1652 
1653                     // Disable the AC-link signals
1654                     ulReg = ReadBMControlRegister32 (GLOB_CNT);
1655                     WriteBMControlRegister (GLOB_CNT, (ulReg | GLOB_CNT_ACLOFF) & ~GLOB_CNT_COLD);
1656                 }
1657             }
1658             break;
1659     }
1660 
1661     //
1662     // Save the new state.  This local value is used to determine when to
1663     // cache property accesses and when to permit the driver from accessing
1664     // the hardware.
1665     //
1666     m_PowerState = NewState.DeviceState;
1667     DOUT (DBG_POWER, ("Entering D%d", (ULONG)m_PowerState -
1668                       (ULONG)PowerDeviceD0));
1669 }
1670 
1671 
1672 /*****************************************************************************
1673  * CAC97AdapterCommon::QueryPowerChangeState
1674  *****************************************************************************
1675  * Query to see if the device can change to this power state
1676  */
STDMETHODIMP_(NTSTATUS)1677 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::QueryPowerChangeState
1678 (
1679     _In_  POWER_STATE NewState
1680 )
1681 {
1682     PAGED_CODE ();
1683 
1684     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::QueryPowerChangeState]"));
1685 
1686     // Check here to see of a legitimate state is being requested
1687     // based on the device state and fail the call if the device/driver
1688     // cannot support the change requested.  Otherwise, return STATUS_SUCCESS.
1689     // Note: A QueryPowerChangeState() call is not guaranteed to always preceed
1690     // a PowerChangeState() call.
1691 
1692     // check the new state being requested
1693     switch (NewState.DeviceState)
1694     {
1695         case PowerDeviceD0:
1696         case PowerDeviceD1:
1697         case PowerDeviceD2:
1698         case PowerDeviceD3:
1699             return STATUS_SUCCESS;
1700 
1701         default:
1702             DOUT (DBG_ERROR, ("Unknown device state: D%d.",
1703                  (ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
1704             return STATUS_NOT_IMPLEMENTED;
1705     }
1706 }
1707 
1708 
1709 /*****************************************************************************
1710  * CAC97AdapterCommon::QueryDeviceCapabilities
1711  *****************************************************************************
1712  * Called at startup to get the caps for the device.  This structure provides
1713  * the system with the mappings between system power state and device power
1714  * state.  This typically will not need modification by the driver.
1715  * If the driver modifies these mappings then the driver is not allowed to
1716  * change the mapping to a weaker power state (e.g. from S1->D3 to S1->D1).
1717  *
1718  */
1719 _Use_decl_annotations_
STDMETHODIMP_(NTSTATUS)1720 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::QueryDeviceCapabilities
1721 (
1722     PDEVICE_CAPABILITIES PowerDeviceCaps
1723 )
1724 {
1725     PAGED_CODE ();
1726 
1727     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::QueryDeviceCapabilities]"));
1728 
1729     UNREFERENCED_PARAMETER(PowerDeviceCaps);
1730 
1731     return STATUS_SUCCESS;
1732 }
1733 
1734 
1735 /*****************************************************************************
1736  * CAC97AdapterCommon::RestoreAC97Registers
1737  *****************************************************************************
1738  * Preset the AC97 registers with default values. The routine first checks if
1739  * There are registry entries for the default values. If not, we have hard
1740  * coded values too ;)
1741  */
SetAC97Default(void)1742 NTSTATUS CAC97AdapterCommon::SetAC97Default (void)
1743 {
1744     PAGED_CODE ();
1745 
1746     PREGISTRYKEY    DriverKey;
1747     PREGISTRYKEY    SettingsKey;
1748     UNICODE_STRING  sKeyName;
1749     ULONG           ulDisposition;
1750     ULONG           ulResultLength;
1751     PVOID           KeyInfo = NULL;
1752 
1753     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::SetAC97Default]"));
1754 
1755     // open the driver registry key
1756     NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
1757                                           NULL,              // OuterUnknown
1758                                           DriverRegistryKey, // Registry key type
1759                                           KEY_READ,          // Access flags
1760                                           m_pDeviceObject,   // Device object
1761                                           NULL,              // Subdevice
1762                                           NULL,              // ObjectAttributes
1763                                           0,                 // Create options
1764                                           NULL);             // Disposition
1765     if (NT_SUCCESS (ntStatus))
1766     {
1767         // make a unicode string for the subkey name
1768         RtlInitUnicodeString (&sKeyName, L"Settings");
1769 
1770         // open the settings subkey
1771         ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
1772                                          NULL,                    // OuterUnknown
1773                                          KEY_READ,                // Access flags
1774                                          &sKeyName,               // Subkey name
1775                                          REG_OPTION_NON_VOLATILE, // Create options
1776                                          &ulDisposition);
1777 
1778         if (NT_SUCCESS (ntStatus))
1779         {
1780             // allocate data to hold key info
1781             KeyInfo = ExAllocatePoolWithTag (PagedPool,
1782                                       sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
1783                                       sizeof(WORD), PoolTag);
1784             if (NULL != KeyInfo)
1785             {
1786                 // loop through all mixer settings
1787                 for (AC97Register i = AC97REG_RESET; i <= AC97REG_RESERVED2;
1788                     i = (AC97Register)(i + 1))
1789                 {
1790                     if (m_stAC97Registers[i].wFlags & SHREG_INIT)
1791                     {
1792                         // init key name
1793                         RtlInitUnicodeString (&sKeyName,
1794                                               m_stAC97Registers[i].sRegistryName);
1795 
1796                         // query the value key
1797                         ntStatus = SettingsKey->QueryValueKey (&sKeyName,
1798                                         KeyValuePartialInformation,
1799                                         KeyInfo,
1800                                         sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
1801                                             sizeof(WORD),
1802                                         &ulResultLength);
1803                         if (NT_SUCCESS (ntStatus))
1804                         {
1805                             PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
1806                                         (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
1807 
1808                             if (PartialInfo->DataLength == sizeof(WORD))
1809                             {
1810                                 // set mixer register to registry value
1811                                 WriteCodecRegister
1812                                     (i, *(PWORD)PartialInfo->Data, 0xFFFF);
1813                             }
1814                             else    // write the hard coded default
1815                             {
1816                                 // if key access failed, set to default
1817                                 WriteCodecRegister
1818                                     (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
1819                             }
1820                         }
1821                         else  // write the hard coded default
1822                         {
1823                             // if key access failed, set to default
1824                             WriteCodecRegister
1825                                 (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
1826                         }
1827                     }
1828                 }
1829 
1830                 // we want to return status success even if the last QueryValueKey
1831                 // failed.
1832                 ntStatus = STATUS_SUCCESS;
1833 
1834                 // free the key info
1835                 ExFreePoolWithTag (KeyInfo,PoolTag);
1836             }
1837             else
1838             {
1839                 ntStatus = STATUS_INSUFFICIENT_RESOURCES;
1840             }
1841 
1842             // release the settings key
1843             SettingsKey->Release ();
1844         }
1845 
1846         // release the driver key
1847         DriverKey->Release ();
1848     }
1849 
1850 
1851     // in case we did not query the registry (cause of lack of resources)
1852     // restore default values and return insufficient resources.
1853     if (!NT_SUCCESS (ntStatus))
1854     {
1855         // copy hard coded default settings
1856         for (AC97Register i = AC97REG_RESET; i < AC97REG_RESERVED2;
1857              i = (AC97Register)(i + 1))
1858         {
1859             if (m_stAC97Registers[i].wFlags & SHREG_INIT)
1860             {
1861                 WriteCodecRegister (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
1862             }
1863         }
1864     }
1865 
1866     return ntStatus;
1867 }
1868 
1869 
1870 /*****************************************************************************
1871  * CAC97AdapterCommon::DisableAC97Pin
1872  *****************************************************************************
1873  * Returns TRUE when the HW vendor wants to disable the pin. A disabled pin is
1874  * not shown to the user (means it is not included in the topology). The
1875  * reason for doing this could be that some of the input lines like Aux or
1876  * Video are not available to the user (to plug in something) but the codec
1877  * can handle those lines.
1878  */
DisableAC97Pin(IN TopoPinConfig pin)1879 BOOL CAC97AdapterCommon::DisableAC97Pin
1880 (
1881     IN  TopoPinConfig pin
1882 )
1883 {
1884     PAGED_CODE ();
1885 
1886     PREGISTRYKEY    DriverKey;
1887     PREGISTRYKEY    SettingsKey;
1888     UNICODE_STRING  sKeyName;
1889     ULONG           ulDisposition;
1890     ULONG           ulResultLength;
1891     PVOID           KeyInfo = NULL;
1892     BOOL            bDisable = FALSE;
1893 
1894     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::DisableAC97Pin]"));
1895 
1896     // open the driver registry key
1897     NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
1898                                           NULL,              // OuterUnknown
1899                                           DriverRegistryKey, // Registry key type
1900                                           KEY_READ,          // Access flags
1901                                           m_pDeviceObject,   // Device object
1902                                           NULL,              // Subdevice
1903                                           NULL,              // ObjectAttributes
1904                                           0,                 // Create options
1905                                           NULL);             // Disposition
1906     if (NT_SUCCESS (ntStatus))
1907     {
1908         // make a unicode string for the subkey name
1909         RtlInitUnicodeString (&sKeyName, L"Settings");
1910 
1911         // open the settings subkey
1912         ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
1913                                          NULL,                    // OuterUnknown
1914                                          KEY_READ,                // Access flags
1915                                          &sKeyName,               // Subkey name
1916                                          REG_OPTION_NON_VOLATILE, // Create options
1917                                          &ulDisposition);
1918 
1919         if (NT_SUCCESS (ntStatus))
1920         {
1921             // allocate data to hold key info
1922             KeyInfo = ExAllocatePoolWithTag (PagedPool,
1923                                       sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
1924                                       sizeof(BYTE), PoolTag);
1925             if (NULL != KeyInfo)
1926             {
1927                 // init key name
1928                 RtlInitUnicodeString (&sKeyName, m_stHardwareConfig.
1929                                             Pins[pin].sRegistryName);
1930 
1931                 // query the value key
1932                 ntStatus = SettingsKey->QueryValueKey (&sKeyName,
1933                                    KeyValuePartialInformation,
1934                                    KeyInfo,
1935                                    sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
1936                                         sizeof(BYTE),
1937                                    &ulResultLength );
1938                 if (NT_SUCCESS (ntStatus))
1939                 {
1940                     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
1941                                 (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
1942 
1943                     if (PartialInfo->DataLength == sizeof(BYTE))
1944                     {
1945                         // store the value
1946                         if (*(PBYTE)PartialInfo->Data)
1947                             bDisable = TRUE;
1948                         else
1949                             bDisable = FALSE;
1950                     }
1951                 }
1952 
1953                 // free the key info
1954                 ExFreePoolWithTag (KeyInfo,PoolTag);
1955             }
1956 
1957             // release the settings key
1958             SettingsKey->Release ();
1959         }
1960 
1961         // release the driver key
1962         DriverKey->Release ();
1963     }
1964 
1965     // if one of the stuff above fails we return the default, which is FALSE.
1966     return bDisable;
1967 }
1968 
1969 
1970 /*****************************************************************************
1971  * CAC97AdapterCommon::RestoreCodecRegisters
1972  *****************************************************************************
1973  * write back cached mixer values to codec registers
1974  */
RestoreCodecRegisters(void)1975 NTSTATUS CAC97AdapterCommon::RestoreCodecRegisters (void)
1976 {
1977     PAGED_CODE ();
1978 
1979     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::RestoreCodecRegisters]"));
1980 
1981     //
1982     // Initialize the AC97 codec.
1983     //
1984     NTSTATUS ntStatus = InitAC97 ();
1985     if (!NT_SUCCESS (ntStatus))
1986         return ntStatus;
1987 
1988     //
1989     // Restore all codec registers.  Failure is not critical.
1990     //
1991     for (AC97Register i = AC97REG_MASTER_VOLUME; i < AC97REG_RESERVED2;
1992         i = (AC97Register)(i + 1))
1993     {
1994         WriteCodecRegister (i, m_stAC97Registers[i].wCache, 0xFFFF);
1995     }
1996 
1997     return STATUS_SUCCESS;
1998 }
1999 
2000 /*****************************************************************************
2001  * CAC97AdapterCommon::ReadChannelConfigDefault
2002  *****************************************************************************
2003  * This function reads the default channel config from the registry. The
2004  * registry entry "ChannelConfig" is set every every time we get a
2005  * KSPROPERTY_AUDIO_CHANNEL_CONFIG for the DAC node.
2006  * In case the key doesn't exist we assume a channel config of stereo speakers,
2007  * cause that is the default of DSOUND.
2008  */
STDMETHODIMP_(void)2009 STDMETHODIMP_(void) CAC97AdapterCommon::ReadChannelConfigDefault
2010 (
2011     PDWORD  pdwChannelConfig,
2012     PWORD   pwChannels
2013 )
2014 {
2015     PAGED_CODE ();
2016 
2017     PREGISTRYKEY    DriverKey;
2018     PREGISTRYKEY    SettingsKey;
2019     UNICODE_STRING  sKeyName;
2020     ULONG           ulDisposition;
2021     ULONG           ulResultLength;
2022     PVOID           KeyInfo = NULL;
2023 
2024     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadChannelConfigDefault]"));
2025 
2026     // This is the default: 2 speakers, stereo.
2027     *pdwChannelConfig = KSAUDIO_SPEAKER_STEREO;
2028     *pwChannels = 2;
2029 
2030     // open the driver registry key
2031     NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
2032                                           NULL,              // OuterUnknown
2033                                           DriverRegistryKey, // Registry key type
2034                                           KEY_READ,          // Access flags
2035                                           m_pDeviceObject,   // Device object
2036                                           NULL,              // Subdevice
2037                                           NULL,              // ObjectAttributes
2038                                           0,                 // Create options
2039                                           NULL);             // Disposition
2040     if (NT_SUCCESS (ntStatus))
2041     {
2042         // make a unicode string for the subkey name
2043         RtlInitUnicodeString (&sKeyName, L"Settings");
2044 
2045         // open the settings subkey
2046         ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
2047                                          NULL,                    // OuterUnknown
2048                                          KEY_READ,                // Access flags
2049                                          &sKeyName,               // Subkey name
2050                                          REG_OPTION_NON_VOLATILE, // Create options
2051                                          &ulDisposition);
2052 
2053         if (NT_SUCCESS (ntStatus))
2054         {
2055             // allocate data to hold key info
2056             KeyInfo = ExAllocatePoolWithTag (PagedPool,
2057                                       sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
2058                                       sizeof(DWORD), PoolTag);
2059             if (NULL != KeyInfo)
2060             {
2061                 // init key name
2062                 RtlInitUnicodeString (&sKeyName, L"ChannelConfig");
2063 
2064                 // query the value key
2065                 ntStatus = SettingsKey->QueryValueKey (&sKeyName,
2066                                    KeyValuePartialInformation,
2067                                    KeyInfo,
2068                                    sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
2069                                         sizeof(DWORD),
2070                                    &ulResultLength );
2071                 if (NT_SUCCESS (ntStatus))
2072                 {
2073                     PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
2074                                 (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
2075 
2076                     if (PartialInfo->DataLength == sizeof(DWORD))
2077                     {
2078                         switch (*(PLONG)PartialInfo->Data)
2079                         {
2080                         case KSAUDIO_SPEAKER_QUAD:
2081                         case KSAUDIO_SPEAKER_SURROUND:
2082                             if (GetPinConfig (PINC_SURROUND_PRESENT))
2083                             {
2084                                 *pdwChannelConfig = *(PDWORD)PartialInfo->Data;
2085                                 *pwChannels = 4;
2086                             }
2087                             break;
2088 
2089                         case KSAUDIO_SPEAKER_5POINT1:
2090                             if (GetPinConfig (PINC_SURROUND_PRESENT) &&
2091                                 GetPinConfig (PINC_CENTER_LFE_PRESENT))
2092                             {
2093                                 *pdwChannelConfig = *(PDWORD)PartialInfo->Data;
2094                                 *pwChannels = 6;
2095                             }
2096                             break;
2097                         }
2098                     }
2099                 }
2100 
2101                 // free the key info
2102                 ExFreePoolWithTag (KeyInfo,PoolTag);
2103             }
2104 
2105             // release the settings key
2106             SettingsKey->Release ();
2107         }
2108 
2109         // release the driver key
2110         DriverKey->Release ();
2111     }
2112 }
2113 
2114 /*****************************************************************************
2115  * CAC97AdapterCommon::WriteChannelConfigDefault
2116  *****************************************************************************
2117  * This function writes the default channel config to the registry. The
2118  * registry entry "ChannelConfig" is set every every time we get a
2119  * KSPROPERTY_AUDIO_CHANNEL_CONFIG for the DAC node.
2120  */
STDMETHODIMP_(void)2121 STDMETHODIMP_(void) CAC97AdapterCommon::WriteChannelConfigDefault (DWORD dwChannelConfig)
2122 {
2123     PAGED_CODE ();
2124 
2125     PREGISTRYKEY    DriverKey;
2126     PREGISTRYKEY    SettingsKey;
2127     UNICODE_STRING  sKeyName;
2128     ULONG           ulDisposition;
2129 
2130     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteChannelConfigDefault]"));
2131 
2132     // open the driver registry key
2133     NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
2134                                           NULL,              // OuterUnknown
2135                                           DriverRegistryKey, // Registry key type
2136                                           KEY_WRITE,         // Access flags
2137                                           m_pDeviceObject,   // Device object
2138                                           NULL,              // Subdevice
2139                                           NULL,              // ObjectAttributes
2140                                           0,                 // Create options
2141                                           NULL);             // Disposition
2142     if (NT_SUCCESS (ntStatus))
2143     {
2144         // make a unicode string for the subkey name
2145         RtlInitUnicodeString (&sKeyName, L"Settings");
2146 
2147         // open the settings subkey
2148         ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
2149                                          NULL,                    // OuterUnknown
2150                                          KEY_WRITE,               // Access flags
2151                                          &sKeyName,               // Subkey name
2152                                          REG_OPTION_NON_VOLATILE, // Create options
2153                                          &ulDisposition);
2154 
2155         if (NT_SUCCESS (ntStatus))
2156         {
2157             // init key name
2158             RtlInitUnicodeString (&sKeyName, L"ChannelConfig");
2159 
2160             // query the value key
2161             ntStatus = SettingsKey->SetValueKey (&sKeyName,
2162                                                  REG_DWORD,
2163                                                  &dwChannelConfig,
2164                                                  sizeof (DWORD));
2165             if (!NT_SUCCESS (ntStatus))
2166             {
2167                 DOUT (DBG_ERROR, ("Could not write the ChannelConfig to registry."));
2168             }
2169 
2170             // release the settings key
2171             SettingsKey->Release ();
2172         }
2173 
2174         // release the driver key
2175         DriverKey->Release ();
2176     }
2177 }
2178 
2179 /*****************************************************************************
2180  * Non paged code begins here
2181  *****************************************************************************
2182  */
2183 
2184 #ifdef _MSC_VER
2185 #pragma code_seg()
2186 #endif
2187 /*****************************************************************************
2188  * CAC97AdapterCommon::WriteBMControlRegister
2189  *****************************************************************************
2190  * Writes a byte (UCHAR) to BusMaster Control register.
2191  */
STDMETHODIMP_(void)2192 STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
2193 (
2194     IN  ULONG ulOffset,
2195     IN  UCHAR ucValue
2196 )
2197 {
2198     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister] (UCHAR)"));
2199 
2200     WRITE_PORT_UCHAR ((PUCHAR)(m_pBusMasterBase + ulOffset), ucValue);
2201 
2202     DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%2x to 0x%4p.",
2203                    ucValue, m_pBusMasterBase + ulOffset));
2204 }
2205 
2206 /*****************************************************************************
2207  * CAC97AdapterCommon::WriteBMControlRegister
2208  *****************************************************************************
2209  * Writes a word (USHORT) to BusMaster Control register.
2210  */
STDMETHODIMP_(void)2211 STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
2212 (
2213     IN  ULONG ulOffset,
2214     IN  USHORT usValue
2215 )
2216 {
2217     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister (USHORT)]"));
2218 
2219     WRITE_PORT_USHORT ((PUSHORT)(m_pBusMasterBase + ulOffset), usValue);
2220 
2221     DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%4x to 0x%4p",
2222                    usValue, m_pBusMasterBase + ulOffset));
2223 }
2224 
2225 /*****************************************************************************
2226  * CAC97AdapterCommon::WriteBMControlRegister
2227  *****************************************************************************
2228  * Writes a DWORD (ULONG) to BusMaster Control register.
2229  */
STDMETHODIMP_(void)2230 STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
2231 (
2232     IN  ULONG ulOffset,
2233     IN  ULONG ulValue
2234 )
2235 {
2236     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister (ULONG)]"));
2237 
2238     WRITE_PORT_ULONG ((PULONG)(m_pBusMasterBase + ulOffset), ulValue);
2239 
2240     DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%8x to 0x%4p.",
2241                    ulValue, m_pBusMasterBase + ulOffset));
2242 }
2243 
2244 /*****************************************************************************
2245  * CAC97AdapterCommon::ReadBMControlRegister8
2246  *****************************************************************************
2247  * Read a byte (UCHAR) from BusMaster Control register.
2248  */
STDMETHODIMP_(UCHAR)2249 STDMETHODIMP_(UCHAR) CAC97AdapterCommon::ReadBMControlRegister8
2250 (
2251     IN  ULONG ulOffset
2252 )
2253 {
2254     UCHAR ucValue = UCHAR(-1);
2255 
2256     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister8]"));
2257 
2258     ucValue = READ_PORT_UCHAR ((PUCHAR)(m_pBusMasterBase + ulOffset));
2259 
2260     DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%2x from 0x%4p.", ucValue,
2261                    m_pBusMasterBase + ulOffset));
2262 
2263     return ucValue;
2264 }
2265 
2266 /*****************************************************************************
2267  * CAC97AdapterCommon::ReadBMControlRegister16
2268  *****************************************************************************
2269  * Read a word (USHORT) from BusMaster Control register.
2270  */
STDMETHODIMP_(USHORT)2271 STDMETHODIMP_(USHORT) CAC97AdapterCommon::ReadBMControlRegister16
2272 (
2273     IN  ULONG ulOffset
2274 )
2275 {
2276     USHORT usValue = USHORT(-1);
2277 
2278     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister16]"));
2279 
2280     usValue = READ_PORT_USHORT ((PUSHORT)(m_pBusMasterBase + ulOffset));
2281 
2282     DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%4x = 0x%4p", usValue,
2283                    m_pBusMasterBase + ulOffset));
2284 
2285     return usValue;
2286 }
2287 
2288 /*****************************************************************************
2289  * CAC97AdapterCommon::ReadBMControlRegister32
2290  *****************************************************************************
2291  * Read a dword (ULONG) from BusMaster Control register.
2292  */
STDMETHODIMP_(ULONG)2293 STDMETHODIMP_(ULONG) CAC97AdapterCommon::ReadBMControlRegister32
2294 (
2295     IN  ULONG ulOffset
2296 )
2297 {
2298     ULONG ulValue = ULONG(-1);
2299 
2300     DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister32]"));
2301 
2302     ulValue = READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + ulOffset));
2303 
2304     DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%8x = 0x%4p", ulValue,
2305                    m_pBusMasterBase + ulOffset));
2306 
2307     return ulValue;
2308 }
2309 
2310