ReactOS  0.4.15-dev-4872-g8a3db97
common.cpp
Go to the documentation of this file.
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 //
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 //
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  */
117 (
119  IN REFCLSID,
120  IN PUNKNOWN UnknownOuter OPTIONAL,
122  __drv_reportError("Must succeed pool allocations are forbidden. "
123  "Allocation failures cause a system crash"))
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,
135 }
136 
137 
138 /*****************************************************************************
139  * CAC97AdapterCommon::Init
140  *****************************************************************************
141  * Initialize the adapter common object -> initialize and probe HW.
142  * Pass only checked resources.
143  */
145 (
148 )
149 {
150  PAGED_CODE ();
151 
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  //
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",
184 
185  //
186  // Set m_bDirectRead to TRUE so that all AC97 register read and
187  // writes are going directly to the HW
188  //
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  //
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  //
225 
226  return ntStatus;
227 }
228 
229 
230 /*****************************************************************************
231  * CAC97AdapterCommon::~CAC97AdapterCommon
232  *****************************************************************************
233  * Destructor.
234  */
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  */
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  */
492 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::NonDelegatingQueryInterface
493 (
496 )
497 {
498  PAGED_CODE ();
499 
500  ASSERT (Object);
501 
502  DOUT (DBG_PRINT, ("[CAC97AdapterCommon::NonDelegatingQueryInterface]"));
503 
504  // Is it 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  {
520  }
521  else
522  {
523  // nothing found, must be an unknown interface.
524  *Object = NULL;
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  */
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  */
577 (
578  IN AC97Register AC97Reg,
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  */
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.
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.
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.
712 
713  // Check if OEM wants to disable line input.
715 
716  // Check if OEM wants to disable CD input.
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.
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.
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.
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.
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.
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.
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  //
924 
925  //
926  // Check for a headphone volume control.
927  //
928  if (GetPinConfig (PINC_HPOUT_PRESENT))
929  {
931  }
932 
933  //
934  // Mono out there?
935  //
936  if (GetPinConfig (PINC_MONOOUT_PRESENT))
937  {
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.
1031  SetPinConfig (PINC_SURROUND_PRESENT, FALSE);
1032 
1033  // Check if OEM wants to disable center and LFE output.
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))
1042 
1043  if (GetPinConfig (PINC_CENTER_LFE_PRESENT))
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  */
1063 {
1064  PAGED_CODE ();
1065 
1066  DOUT (DBG_PRINT, ("[CAC97AdapterCommon::AcquireCodecSemiphore]"));
1067 
1068  ULONG ulCount = 0;
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  //
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  */
1095 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::ReadCodecRegister
1096 (
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
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  //
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  //
1136 
1137  //
1138  // Check to see if the read was successful.
1139  //
1141  if (Status & GLOB_STA_RCS)
1142  {
1143  //
1144  // clear the timeout bit
1145  //
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  //
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  //
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  */
1191 STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::WriteCodecRegister
1192 (
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  //
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  */
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  {
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  */
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  */
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  {
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 
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  */
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  //
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  */
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  */
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  */
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,
1783  sizeof(WORD), PoolTag);
1784  if (NULL != KeyInfo)
1785  {
1786  // loop through all mixer settings
1788  i = (AC97Register)(i + 1))
1789  {
1791  {
1792  // init key name
1793  RtlInitUnicodeString (&sKeyName,
1794  m_stAC97Registers[i].sRegistryName);
1795 
1796  // query the value key
1797  ntStatus = SettingsKey->QueryValueKey (&sKeyName,
1799  KeyInfo,
1801  sizeof(WORD),
1802  &ulResultLength);
1803  if (NT_SUCCESS (ntStatus))
1804  {
1805  PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
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
1857  i = (AC97Register)(i + 1))
1858  {
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  */
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,
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,
1934  KeyInfo,
1936  sizeof(BYTE),
1937  &ulResultLength );
1938  if (NT_SUCCESS (ntStatus))
1939  {
1940  PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
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  */
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  //
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  */
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,
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,
2067  KeyInfo,
2069  sizeof(DWORD),
2070  &ulResultLength );
2071  if (NT_SUCCESS (ntStatus))
2072  {
2073  PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
2075 
2076  if (PartialInfo->DataLength == sizeof(DWORD))
2077  {
2078  switch (*(PLONG)PartialInfo->Data)
2079  {
2080  case KSAUDIO_SPEAKER_QUAD:
2082  if (GetPinConfig (PINC_SURROUND_PRESENT))
2083  {
2084  *pdwChannelConfig = *(PDWORD)PartialInfo->Data;
2085  *pwChannels = 4;
2086  }
2087  break;
2088 
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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 
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble * u
Definition: glfuncs.h:240
const ULONG GLOB_STA_MD3
Definition: ichreg.h:77
PWORD pwChannels
Definition: common.h:364
NTSTATUS ProbeHWConfig(void)
Definition: common.cpp:636
#define IN
Definition: typedefs.h:39
DEVICE_POWER_STATE m_PowerState
Definition: common.h:98
return STATUS_NOT_SUPPORTED
#define REFIID
Definition: guiddef.h:118
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
NTSTATUS PowerUpCodec(void)
Definition: common.cpp:1331
#define __drv_reportError(why)
Definition: driverspecs.h:319
#define KSAUDIO_SPEAKER_STEREO
Definition: ksmedia.h:1454
#define _In_range_(lb, ub)
Definition: ms_sal.h:571
VOID NTAPI WRITE_PORT_USHORT(IN PUSHORT Port, IN USHORT Value)
Definition: portio.c:115
GLint x0
Definition: linetemp.h:95
#define _Out_
Definition: ms_sal.h:345
TopoPinConfig
Definition: shared.h:61
#define READ_PORT_UCHAR(p)
Definition: pc98vid.h:22
#define KEY_READ
Definition: nt_native.h:1023
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
IUnknown * PUNKNOWN
Definition: com_apitest.h:45
#define REFCLSID
Definition: guiddef.h:117
unsigned char * PUCHAR
Definition: retypes.h:3
const int DBG_PROBE
Definition: debug.h:26
const ULONG GLOB_CNT
Definition: ichreg.h:42
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS PrimaryCodecReady(void)
Definition: common.cpp:1284
IAC97AdapterCommon * PADAPTERCOMMON
Definition: shared.h:486
ULONG NTAPI READ_PORT_ULONG(IN PULONG Port)
Definition: portio.c:70
const ULONG GLOB_STA_AD3
Definition: ichreg.h:78
WORD wFlags
Definition: common.h:48
#define _When_(expr, annos)
Definition: ms_sal.h:254
BOOL Init(PUSERCONNECT UserCon)
Definition: dllmain.c:385
#define KSAUDIO_SPEAKER_SURROUND
Definition: ksmedia.h:1457
const UCHAR CAS_CAS
Definition: ichreg.h:93
#define KSAUDIO_SPEAKER_QUAD
Definition: ksmedia.h:1455
const WORD SHREG_INIT
Definition: common.h:68
#define DOUT(lvl, strings)
Definition: debug.h:82
const ULONG GLOB_CNT_ACLOFF
Definition: ichreg.h:69
_Must_inspect_result_ _In_ WDFIORESREQLIST _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFIORESLIST * ResourceList
Definition: wdfresource.h:304
const ULONG CAS
Definition: ichreg.h:44
const ULONG GLOB_STA_SCR
Definition: ichreg.h:85
#define _Use_decl_annotations_
Definition: ms_sal.h:275
PAC97MINIPORTTOPOLOGY m_Topology
Definition: common.h:99
#define IsEqualGUIDAligned(guid1, guid2)
Definition: wdm.template.h:235
Definition: regsvr.c:103
_In_ PDEVICE_OBJECT DeviceObject
Definition: wdfdevice.h:2055
return STATUS_NOT_IMPLEMENTED
#define _Analysis_assume_(expr)
Definition: ms_sal.h:2901
#define L(x)
Definition: ntvdm.h:50
VOID NTAPI WRITE_PORT_ULONG(IN PULONG Port, IN ULONG Value)
Definition: portio.c:123
#define FALSE
Definition: types.h:117
BOOL m_bDirectRead
Definition: common.h:97
unsigned int BOOL
Definition: ntddk_ex.h:94
NTSTATUS NTAPI KeDelayExecutionThread(IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Interval OPTIONAL)
Definition: wait.c:283
#define KSAUDIO_SPEAKER_5POINT1
Definition: ksmedia.h:1459
#define _In_
Definition: ms_sal.h:308
const int DBG_SYSINFO
Definition: debug.h:27
void * PVOID
Definition: retypes.h:9
WORD wCache
Definition: common.h:47
const ULONG GLOB_STA_MC6
Definition: ichreg.h:75
BOOL DisableAC97Pin(IN TopoPinConfig)
Definition: common.cpp:1880
const ULONG GLOB_CNT_COLD
Definition: ichreg.h:71
WORD * PWORD
Definition: pedump.c:67
Status
Definition: gdiplustypes.h:24
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1057
#define KEY_WRITE
Definition: nt_native.h:1031
NTSTATUS SetAC97Default(void)
Definition: common.cpp:1742
TopoNodeConfig
Definition: shared.h:83
static tHardwareConfig m_stHardwareConfig
Definition: common.h:93
IRegistryKey * PREGISTRYKEY
Definition: portcls.h:1009
#define ASSERT(a)
Definition: mode.c:44
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PDEVICE_OBJECT m_pDeviceObject
Definition: common.h:94
#define STATUS_NO_SUCH_DEVICE
Definition: udferr_usr.h:136
INT POOL_TYPE
Definition: typedefs.h:78
struct _KEY_VALUE_PARTIAL_INFORMATION * PKEY_VALUE_PARTIAL_INFORMATION
NTSTATUS InitAC97(void)
Definition: common.cpp:540
const GUID IID_IUnknown
AC97REG_INVALID AC97Register Register
Definition: common.h:263
IAdapterPowerManagement * PADAPTERPOWERMANAGEMENT
Definition: portcls.h:2039
unsigned short WORD
Definition: ntddk_ex.h:93
unsigned long DWORD
Definition: ntddk_ex.h:95
static int reg
Definition: i386-dis.c:1283
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _In_ _Strict_type_match_ POOL_TYPE _In_opt_ ULONG PoolTag
Definition: wdfmemory.h:159
const int DBG_REGS
Definition: debug.h:25
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
const int DBG_ERROR
Definition: debug.h:19
unsigned char UCHAR
Definition: xmlstorage.h:181
NTSTATUS AcquireCodecSemiphore(void)
Definition: common.cpp:1062
STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon
Definition: common.cpp:144
NTSTATUS NTAPI PcNewRegistryKey(OUT PREGISTRYKEY *OutRegistryKey, IN PUNKNOWN OuterUnknown OPTIONAL, IN ULONG RegistryKeyType, IN ACCESS_MASK DesiredAccess, IN PVOID DeviceObject OPTIONAL, IN PVOID SubDevice OPTIONAL, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN ULONG CreateOptions OPTIONAL, OUT PULONG Disposition OPTIONAL)
Definition: registry.cpp:268
#define WRITE_PORT_UCHAR(p, d)
Definition: pc98vid.h:21
const WORD SHREG_NOCACHE
Definition: common.h:73
const int DBG_POWER
Definition: debug.h:23
NTSTATUS Check6thBitSupport(IN AC97Register, IN TopoNodeConfig)
Definition: common.cpp:577
unsigned char BYTE
Definition: xxhash.c:193
* PDEVICE_CAPABILITIES
Definition: iotypes.h:965
_Must_inspect_result_ _In_ WDFCOLLECTION _In_ WDFOBJECT Object
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_CHILD_LIST_CONFIG Config
Definition: wdfchildlist.h:474
IResourceList * PRESOURCELIST
Definition: portcls.h:442
const ULONG GLOB_STA
Definition: ichreg.h:43
_In_ DWORD _Out_ _In_ WORD wFlags
Definition: wincon.h:531
const ULONG GLOB_CNT_PRIE
Definition: ichreg.h:68
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
IN PVOID IN PVOID IN USHORT IN USHORT IN PINTERFACE Interface
Definition: pci.h:361
const WORD SHREG_INVALID
Definition: common.h:62
unsigned short USHORT
Definition: pedump.c:61
NTSTATUS NewAdapterCommon(OUT PUNKNOWN *Unknown, IN REFCLSID, IN PUNKNOWN UnknownOuter OPTIONAL, _When_((PoolType &NonPagedPoolMustSucceed) !=0, __drv_reportError("Must succeed pool allocations are forbidden. " "Allocation failures cause a system crash")) IN POOL_TYPE PoolType)
Definition: common.cpp:117
static tAC97Registers m_stAC97Registers[64]
Definition: common.h:92
const int DBG_VSR
Definition: debug.h:28
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
PUCHAR m_pBusMasterBase
Definition: common.h:96
#define STATUS_IO_TIMEOUT
Definition: udferr_usr.h:163
DWORD * PDWORD
Definition: pedump.c:68
IN PDEVICE_OBJECT DeviceObject
Definition: common.h:189
#define OUT
Definition: typedefs.h:40
const ULONG GLOB_STA_MC4
Definition: ichreg.h:76
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ _Strict_type_match_ POOL_TYPE PoolType
Definition: wdfdevice.h:3810
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
IN DWORD dwSampleRate
Definition: common.h:338
#define STATUS_SUCCESS
Definition: shellext.h:65
AC97Register
Definition: ac97reg.h:16
USHORT NTAPI READ_PORT_USHORT(IN PUSHORT Port)
Definition: portio.c:63
PWORD m_pCodecBase
Definition: common.h:95
AC97REG_INVALID AC97Register _Out_ PWORD wData
Definition: common.h:263
#define REG_DWORD
Definition: sdbapi.c:596
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
signed int * PLONG
Definition: retypes.h:5
BYTE * PBYTE
Definition: pedump.c:66
const ULONG GLOB_STA_RCS
Definition: ichreg.h:79
const int DBG_PRINT
Definition: debug.h:17
unsigned short * PUSHORT
Definition: retypes.h:2
VOID NTAPI KeStallExecutionProcessor(IN ULONG MicroSeconds)
Definition: ntoskrnl.c:81
#define _COM_Outptr_
Definition: ms_sal.h:449
const ULONG GLOB_STA_PCR
Definition: ichreg.h:86
LONGLONG QuadPart
Definition: typedefs.h:114
AC97REG_INVALID AC97Register _In_ WORD _In_ WORD wMask
Definition: common.h:272
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:70
#define PAGED_CODE()
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68