https://git.reactos.org/?p=reactos.git;a=commitdiff;h=9c79a7982b1627151045b…
commit 9c79a7982b1627151045b130627f63963fc88d63
Author:     Obaid51 <16-se-51(a)students.uettaxila.edu.pk>
AuthorDate: Tue Jan 4 12:16:01 2022 +0500
Commit:     Victor Perevertkin <victor.perevertkin(a)reactos.org>
CommitDate: Wed Feb 16 01:31:28 2022 +0300
    [AC97] Import the AC97 driver sample
    The source code is licensed under MIT license, taken from
    "MSDN Code Gallery Microsoft Samples" repository
    (
https://github.com/microsoftarchive/msdn-code-gallery-microsoft)
    The original license was MS-PL, but the driver was later relicensed
    as MIT.
    Adopted to ReactOS code base by Michael Stamper.
    Co-authored-by: Michael Stamper <michaelstamper1(a)gmail.com>
---
 drivers/wdm/audio/drivers/CMakeLists.txt           |    1 +
 drivers/wdm/audio/drivers/ac97/CMakeLists.txt      |   30 +
 drivers/wdm/audio/drivers/ac97/ac97.inf            |  482 ++++
 drivers/wdm/audio/drivers/ac97/ac97.rc             |   24 +
 drivers/wdm/audio/drivers/ac97/ac97reg.h           |  170 ++
 drivers/wdm/audio/drivers/ac97/adapter.cpp         |  583 +++++
 drivers/wdm/audio/drivers/ac97/adapter.h           |   71 +
 drivers/wdm/audio/drivers/ac97/common.cpp          | 2309 ++++++++++++++++++++
 drivers/wdm/audio/drivers/ac97/common.h            |  387 ++++
 drivers/wdm/audio/drivers/ac97/debug.h             |   93 +
 drivers/wdm/audio/drivers/ac97/guids.h             |  188 ++
 drivers/wdm/audio/drivers/ac97/ichreg.h            |  107 +
 drivers/wdm/audio/drivers/ac97/license.txt         |   21 +
 drivers/wdm/audio/drivers/ac97/miniport.cpp        | 1462 +++++++++++++
 drivers/wdm/audio/drivers/ac97/miniport.h          |  145 ++
 drivers/wdm/audio/drivers/ac97/mintopo.cpp         | 2129 ++++++++++++++++++
 drivers/wdm/audio/drivers/ac97/mintopo.h           |  339 +++
 drivers/wdm/audio/drivers/ac97/prophnd.cpp         | 1824 ++++++++++++++++
 drivers/wdm/audio/drivers/ac97/rtminiport.cpp      |  252 +++
 drivers/wdm/audio/drivers/ac97/rtminiport.h        |  155 ++
 drivers/wdm/audio/drivers/ac97/rtstream.cpp        |  425 ++++
 drivers/wdm/audio/drivers/ac97/rtstream.h          |  118 +
 drivers/wdm/audio/drivers/ac97/shared.h            |  504 +++++
 drivers/wdm/audio/drivers/ac97/stream.cpp          |  634 ++++++
 drivers/wdm/audio/drivers/ac97/stream.h            |  200 ++
 drivers/wdm/audio/drivers/ac97/stream2.cpp         |  159 ++
 .../wdm/audio/drivers/ac97/wavecyclicminiport.cpp  |  182 ++
 .../wdm/audio/drivers/ac97/wavecyclicminiport.h    |   77 +
 .../wdm/audio/drivers/ac97/wavecyclicstream.cpp    |  230 ++
 drivers/wdm/audio/drivers/ac97/wavecyclicstream.h  |  116 +
 drivers/wdm/audio/drivers/ac97/wavepciminiport.cpp |  214 ++
 drivers/wdm/audio/drivers/ac97/wavepciminiport.h   |   79 +
 drivers/wdm/audio/drivers/ac97/wavepcistream.cpp   |  885 ++++++++
 drivers/wdm/audio/drivers/ac97/wavepcistream.h     |  138 ++
 media/doc/3rd Party Files.txt                      |    6 +
 35 files changed, 14739 insertions(+)
diff --git a/drivers/wdm/audio/drivers/CMakeLists.txt
b/drivers/wdm/audio/drivers/CMakeLists.txt
index 2f2f8289a9d..009a279a4a4 100644
--- a/drivers/wdm/audio/drivers/CMakeLists.txt
+++ b/drivers/wdm/audio/drivers/CMakeLists.txt
@@ -1,2 +1,3 @@
+add_subdirectory(ac97)
 add_subdirectory(CMIDriver)
diff --git a/drivers/wdm/audio/drivers/ac97/CMakeLists.txt
b/drivers/wdm/audio/drivers/ac97/CMakeLists.txt
new file mode 100644
index 00000000000..ef182eee79e
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/CMakeLists.txt
@@ -0,0 +1,30 @@
+
+list(APPEND SOURCE
+    adapter.cpp
+    common.cpp
+    mintopo.cpp
+    prophnd.cpp
+    miniport.cpp
+    stream.cpp
+    stream2.cpp
+    rtminiport.cpp
+    rtstream.cpp
+    wavepciminiport.cpp
+    wavepcistream.cpp
+    wavecyclicminiport.cpp
+    wavecyclicstream.cpp)
+
+add_library(ac97 MODULE
+    ${SOURCE}
+    ac97.rc)
+
+target_link_libraries(ac97 stdunk libcntpr uuid)
+set_module_type(ac97 wdmdriver)
+add_importlibs(ac97 portcls hal ntoskrnl)
+
+if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_C_COMPILER_ID STREQUAL
"Clang")
+    target_compile_options(ac97 PRIVATE -Wno-write-strings -Wno-switch)
+endif()
+
+add_cd_file(TARGET ac97 DESTINATION reactos/system32/drivers FOR all)
+add_driver_inf(ac97 ac97.inf)
diff --git a/drivers/wdm/audio/drivers/ac97/ac97.inf
b/drivers/wdm/audio/drivers/ac97/ac97.inf
new file mode 100644
index 00000000000..abf1920b71c
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/ac97.inf
@@ -0,0 +1,482 @@
+;Copyright (c) 1998-2000 Microsoft Corporation All rights Reserved
+;
+;Module Name:
+;   ac97.INF
+;
+;Abstract:
+;    INF file for installing AC97 WDM Driver
+;
+;
+; During upgrade from Win98SE or Win ME, the default upgrade behavior won't upgrade
the drivers
+; to Win2k or Windows XP. The inf has implemented what's mentioned in
+; WINDDK\..\src\setup\devupgrd\devupgrd.doc.
+; If your driver would never be installed under Win98SE or Win ME, you don't need
this new migrate.dll
+; stuff.
+
+
+[Version]
+Signature="$CHICAGO$"
+Class=MEDIA
+ClassGUID={4d36e96c-e325-11ce-bfc1-08002be10318}
+provider=%ProviderName%
+;;The following line is used only when the INF comes with the Windows system
+;;IHV needs to comment out the following line for their OEM redistributed disk.
+;;LayoutFile=layout.inf, layout1.inf, layout2.inf
+DriverVer=02/22/2007,6.00.6000.1
+CatalogFile=ac97.cat
+
+;You must specify which platform is supported by each SourceDisksNames section
+;Valid platform identifiers include .x86, .ia64, .alpha, .axp64
+[SourceDisksNames]
+222=%DiskDescription%,,,
+
+;You must also specify which platform is supported by each SourceDisksFiles section
+;Valid platform identifiers include .x86, .ia64, .alpha, .axp64
+[SourceDisksFiles]
+ac97.sys=222
+;ac97prop.dll=222
+;the entries below are used by the device migration dll, on Win95/98 to Win2K upgrades
+;Migrate.dll=222
+ac97.inf=222
+
+[Manufacturer]
+%MfgName%=Intel,NTAMD64,NTIA64,NTARM
+
+;; Excluding drivers from the "Add New Hardware" list.
+[ControlFlags]
+ExcludeFromSelect = *
+
+[Intel]
+%ac97_AA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2415
+%ac97_AB.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2425
+%ac97_BA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2445
+
+;; This section enables installing on x64 systems
+
+[Intel.NTAMD64]
+%ac97_AA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2415
+%ac97_AB.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2425
+%ac97_BA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2445
+
+;;  This section enables installing on Itanium systems
+
+[Intel.NTIA64]
+%ac97_AA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2415
+%ac97_AB.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2425
+%ac97_BA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2445
+
+;; This section enables installing on ARM systems
+
+[Intel.NTARM]
+%ac97_AA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2415
+%ac97_AB.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2425
+%ac97_BA.DeviceDesc%=ac97, PCI\VEN_8086&DEV_2445
+
+[DestinationDirs]
+ac97.CopyList=10,system32\drivers
+;AC97PROP.CopyList=10,system32
+
+DevUpgrd_Files = 10, win9xmig\DevUpgrd
+WDMDriver_Files = 10, win9xmig\DevUpgrd\AC97WDM ; Replace "AC97WDM" with your
favorite vendor related name
+
+[ac97]
+;;This inf is intended for use by IHV. So, it's going to be used as from OEM
distributed disk
+;;This is why AlsoInstall got used instead if Needs & Include
+AlsoInstall=KS.Registration(ks.inf), WDMAUDIO.Registration(wdmaudio.inf)
+CopyFiles=ac97.CopyList, DevUpgrd_Files, WDMDriver_Files
+AddReg=ac97.AddReg,ac97_NAMES.AddReg,ac97_OEM.AddReg,DevUpgrd_AddReg
+KnownRegEntries=AC97.KnownRegEntries
+;;Exclude driver installation for those PnP ID's.
+;;This PnP ID is an example of a machine where the driver won't work correctly
+ExcludeId=PCI\VEN_8086&DEV_2415&SUBSYS_536011D4&REV_00
+
+[AC97.KnownRegEntries]
+IsWin98Gold=keep
+
+[IsWin98Gold]
+1=HKLM,Software\Microsoft\Windows\CurrentVersion,VersionNumber,0,4.10.1998
+
+[ac97.CopyList]
+ac97.sys
+
+[DevUpgrd_Files]
+;;This migrate.dll can be found in the DDK (beta2 or after) under src\setup\devupgrd
+;Migrate.dll
+
+[WDMDriver_Files]
+ac97.inf    ; Name of your INF goes here
+ac97.sys    ; Name of your driver file(s) goes here
+;ac97prop.dll
+
+
+
+[ac97.Interfaces]
+AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_RENDER%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_CAPTURE%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_REALTIME%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,ac97.Interface.Topology
+
+[ac97.Interface.Wave]
+AddReg=ac97.I.Wave.AddReg
+
+[ac97.I.Wave.AddReg]
+HKR,,CLSID,,%Proxy.CLSID%
+HKR,,FriendlyName,,%ac97.Wave.szPname%
+
+[ac97.Interface.Topology]
+AddReg=ac97.I.Topo.AddReg
+
+[ac97.I.Topo.AddReg]
+HKR,,CLSID,,%Proxy.CLSID%
+HKR,,FriendlyName,,%ac97.Topology.szPname%
+
+[ac97.AddReg]
+HKR,,AssociatedFilters,,"wdmaud,swmidi,redbook"
+HKR,,Driver,,ac97.sys
+HKR,,NTMPDriver,,"ac97.sys,sbemul.sys"
+
+HKR,Drivers,SubClasses,,"wave,midi,mixer"
+
+HKR,Drivers\wave\wdmaud.drv,Driver,,wdmaud.drv
+HKR,Drivers\midi\wdmaud.drv,Driver,,wdmaud.drv
+HKR,Drivers\mixer\wdmaud.drv,Driver,,wdmaud.drv
+
+HKR,Drivers\wave\wdmaud.drv,Description,,%ac97.DeviceDesc%
+HKR,Drivers\midi\wdmaud.drv, Description,,%ac97.DeviceDesc%
+HKR,Drivers\mixer\wdmaud.drv,Description,,%ac97.DeviceDesc%
+
+
+[DevUpgrd_AddReg]
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Setup\Migration
DLLs","Microsoft Device Upgrade Pack",,%10%\win9xmig\DevUpgrd
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Setup\UpgradeDrivers","PCI\VEN_8086&DEV_2415",,%10%\win9xmig\DevUpgrd\AC97WDM\ac97.inf
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Setup\UpgradeDrivers","PCI\VEN_8086&DEV_2425",,%10%\win9xmig\DevUpgrd\AC97WDM\ac97.inf
+HKLM,"Software\Microsoft\Windows\CurrentVersion\Setup\UpgradeDrivers","PCI\VEN_8086&DEV_2445",,%10%\win9xmig\DevUpgrd\AC97WDM\ac97.inf
+
+
+[ac97.Services]
+AddService = ac97, 0x00000002, ac97_Service_Inst
+
+[ac97_Service_Inst]
+DisplayName   = %ac97.SvcDesc%
+ServiceType   = 1                  ; SERVICE_KERNEL_DRIVER
+StartType     = 3                  ; SERVICE_DEMAND_START
+ErrorControl  = 1                  ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\system32\drivers\ac97.sys
+
+[ac97_NAMES.AddReg]
+;; Nodes
+HKLM,%MediaCategories%\%ICHGUID.PhoneVolume%,Name,,%ICHNode.PhoneVolume%
+HKLM,%MediaCategories%\%ICHGUID.PhoneVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.PhoneMute%,Name,,%ICHNode.PhoneMute%
+HKLM,%MediaCategories%\%ICHGUID.PhoneMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.LineInMute%,Name,,%ICHNode.LineInMute%
+HKLM,%MediaCategories%\%ICHGUID.LineInMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MainMix%,Name,,%ICHNode.MainMix%
+HKLM,%MediaCategories%\%ICHGUID.MainMix%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.3DBypass%,Name,,%ICHNode.3DBypass%
+HKLM,%MediaCategories%\%ICHGUID.3DBypass%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.3DEnable%,Name,,%ICHNode.3DEnable%
+HKLM,%MediaCategories%\%ICHGUID.3DEnable%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.BeepMix%,Name,,%ICHNode.BeepMix%
+HKLM,%MediaCategories%\%ICHGUID.BeepMix%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.HPVolume%,Name,,%ICHNode.HPVolume%
+HKLM,%MediaCategories%\%ICHGUID.HPVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.HPMute%,Name,,%ICHNode.HPMute%
+HKLM,%MediaCategories%\%ICHGUID.HPMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MonoOutSelect%,Name,,%ICHNode.MonoOutSelect%
+HKLM,%MediaCategories%\%ICHGUID.MonoOutSelect%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.WaveInSelect%,Name,,%ICHNode.WaveInSelect%
+HKLM,%MediaCategories%\%ICHGUID.WaveInSelect%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MasterInVolume%,Name,,%ICHNode.MasterInVolume%
+HKLM,%MediaCategories%\%ICHGUID.MasterInVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MasterInMute%,Name,,%ICHNode.MasterInMute%
+HKLM,%MediaCategories%\%ICHGUID.MasterInMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MicInVolume%,Name,,%ICHNode.MicInVolume%
+HKLM,%MediaCategories%\%ICHGUID.MicInVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.MicInMute%,Name,,%ICHNode.MicInMute%
+HKLM,%MediaCategories%\%ICHGUID.MicInMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.SimulStereo%,Name,,%ICHNode.SimulStereo%
+HKLM,%MediaCategories%\%ICHGUID.SimulStereo%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.SurroundVolume%,Name,,%ICHNode.SurroundVolume%
+HKLM,%MediaCategories%\%ICHGUID.SurroundVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.SurroundMute%,Name,,%ICHNode.SurroundMute%
+HKLM,%MediaCategories%\%ICHGUID.SurroundMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.CenterVolume%,Name,,%ICHNode.CenterVolume%
+HKLM,%MediaCategories%\%ICHGUID.CenterVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.CenterMute%,Name,,%ICHNode.CenterMute%
+HKLM,%MediaCategories%\%ICHGUID.CenterMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.LFEVolume%,Name,,%ICHNode.LFEVolume%
+HKLM,%MediaCategories%\%ICHGUID.LFEVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.LFEMute%,Name,,%ICHNode.LFEMute%
+HKLM,%MediaCategories%\%ICHGUID.LFEMute%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.FrontVolume%,Name,,%ICHNode.FrontVolume%
+HKLM,%MediaCategories%\%ICHGUID.FrontVolume%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.FrontMute%,Name,,%ICHNode.FrontMute%
+HKLM,%MediaCategories%\%ICHGUID.FrontMute%,Display,1,00,00,00,00
+;; Pins
+HKLM,%MediaCategories%\%ICHGUID.Surround%,Name,,%ICHPin.Surround%
+HKLM,%MediaCategories%\%ICHGUID.Surround%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.Center%,Name,,%ICHPin.Center%
+HKLM,%MediaCategories%\%ICHGUID.Center%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.LFE%,Name,,%ICHPin.LFE%
+HKLM,%MediaCategories%\%ICHGUID.LFE%,Display,1,00,00,00,00
+HKLM,%MediaCategories%\%ICHGUID.Front%,Name,,%ICHPin.Front%
+HKLM,%MediaCategories%\%ICHGUID.Front%,Display,1,00,00,00,00
+
+
+[ac97_OEM.AddReg]
+;;Default register value at driver startup
+;;Uncomment some one of the lines if you want to overwrite the default setting
+;;The value in these outcommented lines is the driver default. You can change
+;;the register values (and uncomment the line) to overwrite the driver default.
+;;low byte comes first, values are hexadezimal.
+;HKR,Settings,MasterVolume,1,0,0        ;0dB
+;HKR,Settings,HeadphoneVolume,1,0,0     ;0dB
+;HKR,Settings,MonooutVolume,1,0,0       ;0dB
+;HKR,Settings,ToneControls,1,F,F        ;bypass
+;HKR,Settings,BeepVolume,1,0,0          ;0dB
+;HKR,Settings,PhoneVolume,1,8,80        ;muted
+;HKR,Settings,MicVolume,1,8,80          ;muted
+;HKR,Settings,LineInVolume,1,8,8        ;0dB
+;HKR,Settings,CDVolume,1,8,8            ;0dB
+;HKR,Settings,VideoVolume,1,8,8         ;0dB
+;HKR,Settings,AUXVolume,1,8,8           ;0dB
+;HKR,Settings,WaveOutVolume,1,8,8       ;0dB. This register is never touched by the
system.
+;HKR,Settings,RecordSelect,1,4,4        ;select LiniIn
+;HKR,Settings,RecordGain,1,0,0          ;0dB
+;HKR,Settings,RecordGainMic,1,0,0       ;0dB
+;HKR,Settings,GeneralPurpose,1,0,0      ;pre 3D, 3D off, loudness off, mono=mix, mic1
+;HKR,Settings,3DControl,1,0,0           ;0%
+;HKR,Settings,PowerDown,1,0,0           ;no power down
+;HKR,Settings,ExtAudioCtrl,1,01,40      ;VRA, DACs on, MicIn off
+;HKR,Settings,CenterLFEVolume,1,0,0     ;0dB
+;HKR,Settings,SurroundVolume,1,0,0              ;0dB
+
+;;Configuration
+;;You can disable some of the input lines by outcommenting some of the lines
+;;below. This could be necessary if you have a AC97 codec on board that for
+;;example supports Video input, but you don't have the Video input accessable
+;;for the user (no plug in).
+;HKR,Settings,DisablePCBeep,1,1
+;HKR,Settings,DisablePhone,1,1
+;HKR,Settings,DisableMic2,1,1
+;HKR,Settings,DisableVideo,1,1
+;HKR,Settings,DisableAUX,1,1
+;HKR,Settings,DisableHeadphone,1,1
+;HKR,Settings,DisableMonoOut,1,1
+HKR,Settings,DisableMicIn,1,1
+;HKR,Settings,DisableMic,1,1            ;disables all MIC lines, including MIC record.
+;HKR,Settings,DisableLineIn,1,1
+;HKR,Settings,DisableCD,1,1
+;HKR,Settings,DisableSurround,1,1
+HKR,Settings,DisableCenterLFE,1,1       ;6ch playback is not supported.
+;HKR,Settings,ChannelConfig,1,3,0,0,0   ;ChannelConfig set to stereo speakers.
+
+;;================= Windows NT ====================
+[ac97.NTX86]
+Include=ks.inf,wdmaudio.inf
+Needs=KS.Registration,WDMAUDIO.Registration
+CopyFiles=ac97.CopyList
+;,AC97PROP.CopyList
+AddReg=ac97.AddReg,ac97_NAMES.AddReg,ac97_OEM.AddReg
+;,AC97PROP.AddReg
+;;Exclude driver installation for those PnP ID's.
+;;This PnP ID is an example of a machine where the driver won't work correctly
+ExcludeId=PCI\VEN_8086&DEV_2415&SUBSYS_536011D4&REV_00
+
+[ac97.NTX86.Interfaces]
+AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_RENDER%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_CAPTURE%,%KSNAME_Wave%,ac97.Interface.Wave
+AddInterface=%KSCATEGORY_AUDIO%,%KSNAME_Topology%,ac97.Interface.Topology
+
+[ac97.NTX86.Services]
+AddService = ac97, 0x00000002, ac97_Service_Inst
+
+;[AC97PROP.CopyList]
+;ac97prop.dll
+
+;[AC97PROP.AddReg]
+;HKR,,EnumPropPages32,,"ac97prop.dll,AC97PropPageProvider"
+
+
+[Strings]
+ProviderName="FooProviderName"
+MfgName="Intel"
+DiskDescription="AC'97 WDM Driver Disk"
+
+ac97_AA.DeviceDesc="Intel 82801AA AC'97 Audio Controller"
+ac97_AB.DeviceDesc="Intel 82801AB AC'97 Audio Controller"
+ac97_BA.DeviceDesc="Intel 82801BA/BAM AC'97 Audio Controller"
+ac97.DeviceDesc="Intel 82801 AC'97 Audio Controller"
+
+ac97.Wave.szPname="AC'97 Sound Card"
+ac97.Topology.szPname="AC'97 Mixer"
+
+MediaCategories="SYSTEM\CurrentControlSet\Control\MediaCategories"
+
+Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
+KSCATEGORY_AUDIO="{6994AD04-93EF-11D0-A3CC-00A0C9223196}"
+KSCATEGORY_RENDER="{65E8773E-8F56-11D0-A3B9-00A0C9223196}"
+KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
+KSCATEGORY_REALTIME="{EB115FFC-10C8-4964-831D-6DCB02E6F23F}"
+KSNAME_Wave="Wave"
+KSNAME_Topology="Topology"
+
+ac97.SvcDesc = "Service for AC'97 Driver (WDM)"
+
+;; Nodes (non-localizeable)
+ICHGUID.PhoneVolume     ="{0A8C1A87-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.PhoneMute       ="{0A8C1A88-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.LineInMute      ="{0A8C1A91-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MainMix         ="{0A8C1A9B-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.3DBypass        ="{0A8C1A9E-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.3DEnable        ="{766DB5A4-6E94-11D2-9ADE-00C04F8EFB68}"
+ICHGUID.BeepMix         ="{0A8C1A9F-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.HPVolume        ="{0A8C1AA5-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.HPMute          ="{0A8C1AA6-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MonoOutSelect   ="{0A8C1AA9-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.WaveInSelect    ="{0A8C1AAE-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MasterInVolume  ="{0A8C1AAF-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MasterInMute    ="{0A8C1AB0-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MicInVolume     ="{0A8C1AB2-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MicInMute       ="{0A8C1AB3-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.SimulStereo     ="{B3AD50B5-3849-4983-ADD7-25E6268F912D}"
+ICHGUID.SurroundVolume  ="{A4B68BA4-6958-4ab4-BB01-E23C6F027C88}"
+ICHGUID.SurroundMute    ="{22654FBC-AC8F-4224-B19F-D858D2E10BDD}"
+ICHGUID.CenterVolume    ="{9B0F1946-ABD2-47a8-A778-BB86CDE1A167}"
+ICHGUID.CenterMute      ="{BEEF51ED-1041-43f8-9B96-5863D0A9342D}"
+ICHGUID.LFEVolume       ="{455FA6F2-21EC-4df4-B1E4-3155209797F3}"
+ICHGUID.LFEMute         ="{4A4D9210-C780-4768-BFD2-525FDBF4FCB4}"
+ICHGUID.FrontVolume     ="{9F4801BD-F746-4c7a-8A9D-F6E99004CC98}"
+ICHGUID.FrontMute       ="{C8E03B2A-EBD9-4554-A750-8E4472750A5B}"
+
+;; Pins (non-localizeable)
+ICHGUID.Surround        ="{81FBB14B-1BEE-4bf5-92EE-FFC4F75F326D}"
+ICHGUID.Center          ="{2D97372F-9CF6-4fd6-9E56-C68BACDF360D}"
+ICHGUID.LFE             ="{B60C4274-3BFD-430b-8364-D947E7D304B1}"
+ICHGUID.Front           ="{070395E2-BE7C-4b4d-B529-40CB9BFCF995}"
+
+
+;; Nodes (localizeable)
+ICHNode.PhoneVolume     ="Phone Volume"
+ICHNode.PhoneMute       ="Phone Mute"
+ICHNode.LineInMute      ="Line In Mute"
+ICHNode.MainMix         ="Main Mix"
+ICHNode.3DBypass        ="3D Bypass"
+ICHNode.3DEnable        ="3D Enable"
+ICHNode.BeepMix         ="Beep Mix"
+ICHNode.HPVolume        ="Headphone Volume"
+ICHNode.HPMute          ="Headphone Mute"
+ICHNode.MonoOutSelect   ="Mono Out Select"
+ICHNode.WaveInSelect    ="Wave In Select"
+ICHNode.MasterInVolume  ="Wave In Volume"
+ICHNode.MasterInMute    ="Wave In Mute"
+ICHNode.MicInVolume     ="Mic In Volume"
+ICHNode.MicInMute       ="Mic In Mute"
+ICHNode.SimulStereo     ="Simulated Stereo"
+ICHNode.SurroundVolume  ="Rear Speaker Volume"
+ICHNode.SurroundMute    ="Rear Speaker Mute"
+ICHNode.CenterVolume    ="Center Volume"
+ICHNode.CenterMute      ="Center Mute"
+ICHNode.LFEVolume       ="Subwoofer Volume"
+ICHNode.LFEMute         ="Subwoofer Mute"
+ICHNode.FrontVolume     ="Front Volume"
+ICHNode.FrontMute       ="Front Mute"
+
+;; Pins
+ICHPin.Surround         ="Rear Speaker"
+ICHPin.Center           ="Center"
+ICHPin.LFE              ="Subwoofer"
+ICHPin.Front            ="Front Speaker"
+
+[Strings.0407]
+ProviderName="FooProviderName"
+MfgName="Intel"
+
+DiskDescription="Diskette für AC'97 WDM Treiberbeispiel"
+ac97_AA.DeviceDesc="Intel 82801AA AC'97 Audiocontroller"
+ac97_AB.DeviceDesc="Intel 82801AB AC'97 Audiocontroller"
+ac97_BA.DeviceDesc="Intel 82801BA/BAM AC'97 Audiocontroller"
+ac97.DeviceDesc="Intel 82801 AC'97 Audiocontroller"
+
+ac97.Wave.szPname="AC'97 Musikkarte"
+ac97.Topology.szPname="AC'97 Mixer"
+
+MediaCategories="SYSTEM\CurrentControlSet\Control\MediaCategories"
+
+Proxy.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
+KSCATEGORY_AUDIO="{6994AD04-93EF-11D0-A3CC-00A0C9223196}"
+KSCATEGORY_RENDER="{65E8773E-8F56-11D0-A3B9-00A0C9223196}"
+KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
+KSCATEGORY_REALTIME="{EB115FFC-10C8-4964-831D-6DCB02E6F23F}"
+KSNAME_Wave="Wave"
+KSNAME_Topology="Topology"
+
+ac97.SvcDesc = "Installationshilfe für AC'97 Treiberbeispiel (WDM)"
+
+
+;; Nodes (non-localizeable)
+ICHGUID.PhoneVolume     ="{0A8C1A87-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.PhoneMute       ="{0A8C1A88-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.LineInMute      ="{0A8C1A91-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MainMix         ="{0A8C1A9B-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.3DBypass        ="{0A8C1A9E-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.3DEnable        ="{766DB5A4-6E94-11D2-9ADE-00C04F8EFB68}"
+ICHGUID.BeepMix         ="{0A8C1A9F-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.HPVolume        ="{0A8C1AA5-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.HPMute          ="{0A8C1AA6-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MonoOutSelect   ="{0A8C1AA9-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.WaveInSelect    ="{0A8C1AAE-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MasterInVolume  ="{0A8C1AAF-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MasterInMute    ="{0A8C1AB0-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MicInVolume     ="{0A8C1AB2-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.MicInMute       ="{0A8C1AB3-42B0-11D2-95D2-00C04FB925D3}"
+ICHGUID.SimulStereo     ="{B3AD50B5-3849-4983-ADD7-25E6268F912D}"
+ICHGUID.SurroundVolume  ="{A4B68BA4-6958-4ab4-BB01-E23C6F027C88}"
+ICHGUID.SurroundMute    ="{22654FBC-AC8F-4224-B19F-D858D2E10BDD}"
+ICHGUID.CenterVolume    ="{9B0F1946-ABD2-47a8-A778-BB86CDE1A167}"
+ICHGUID.CenterMute      ="{BEEF51ED-1041-43f8-9B96-5863D0A9342D}"
+ICHGUID.LFEVolume       ="{455FA6F2-21EC-4df4-B1E4-3155209797F3}"
+ICHGUID.LFEMute         ="{4A4D9210-C780-4768-BFD2-525FDBF4FCB4}"
+ICHGUID.FrontVolume     ="{9F4801BD-F746-4c7a-8A9D-F6E99004CC98}"
+ICHGUID.FrontMute       ="{C8E03B2A-EBD9-4554-A750-8E4472750A5B}"
+
+;; Pins (non-localizeable)
+ICHGUID.Surround        ="{81FBB14B-1BEE-4bf5-92EE-FFC4F75F326D}"
+ICHGUID.Center          ="{2D97372F-9CF6-4fd6-9E56-C68BACDF360D}"
+ICHGUID.LFE             ="{B60C4274-3BFD-430b-8364-D947E7D304B1}"
+ICHGUID.Front           ="{070395E2-BE7C-4b4d-B529-40CB9BFCF995}"
+
+;; Nodes (localizeable)
+
+ICHNode.PhoneVolume     ="Phone Lautstärke"
+ICHNode.PhoneMute       ="Phone Aus"
+ICHNode.LineInMute      ="Line In Aus"
+ICHNode.MainMix         ="Hauptmixer"
+ICHNode.3DBypass        ="3D umgehen"
+ICHNode.3DEnable        ="3D Aktivieren"
+ICHNode.BeepMix         ="Piepmixer"
+ICHNode.MonoOutSelect   ="Mono Ausgang Selektor"
+ICHNode.WaveInSelect    ="Aufnahme Selektor"
+ICHNode.MasterInVolume  ="Aufnahme Lautstärke"
+ICHNode.MasterInMute    ="Aufnahme unterdrücken"
+ICHNode.MicInVolume     ="Mic In Lautstärke"
+ICHNode.MicInMute       ="Mic In Aus"
+ICHNode.SimulStereo     ="Simuliertes Stereo"
+ICHNode.SurroundVolume  ="Lautsprecherlautstärke Hinten"
+ICHNode.SurroundMute    ="Lautsprecher Hinten Aus"
+ICHNode.CenterVolume    ="Lautsprecherlautstärke Mitte"
+ICHNode.CenterMute      ="Lautsprecher Mitte Aus"
+ICHNode.LFEVolume       ="Bass Lautsprecherlautstärke"
+ICHNode.LFEMute         ="Bass Lautsprecher Aus"
+ICHNode.FrontVolume     ="Lautsprecherlautstärke Vorne"
+ICHNode.HPVolume        ="Kopfh�rer Lautst�rke"
+ICHNode.HPMute          ="Kopfh�rer Aus"
+
+;; Pins
+ICHPin.Surround         ="Lautsprecher Hinten"
+ICHPin.Center           ="Lautsprecher Mitte"
+ICHPin.LFE              ="Bass Lautsprecher"
+ICHPin.Front            ="Lautsprecher Vorne"
diff --git a/drivers/wdm/audio/drivers/ac97/ac97.rc
b/drivers/wdm/audio/drivers/ac97/ac97.rc
new file mode 100644
index 00000000000..87c817afc40
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/ac97.rc
@@ -0,0 +1,24 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file ac97smpl.rc was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE                    VFT_DRV
+#define VER_FILESUBTYPE                 VFT2_DRV_SOUND
+#define VER_FILEDESCRIPTION_STR         "Integrated Controller Hub Audio Driver
(WDM)"
+#define VER_INTERNALNAME_STR            "ac97smpl.sys"
+#define VER_ORIGINALFILENAME_STR        "ac97smpl.sys"
+
+#define VER_LEGALCOPYRIGHT_YEARS        "1998-2003"
+#define VER_LEGALCOPYRIGHT_STR          "Copyright (c) Microsoft Corp."
VER_LEGALCOPYRIGHT_YEARS
+
+#include "common.ver"
+
diff --git a/drivers/wdm/audio/drivers/ac97/ac97reg.h
b/drivers/wdm/audio/drivers/ac97/ac97reg.h
new file mode 100644
index 00000000000..8361ef5fb88
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/ac97reg.h
@@ -0,0 +1,170 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file ac97reg.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _AC97REG_H_
+#define _AC97REG_H_
+
+// We use enum types cause the compiler can check variable passing if it is
+// an enum (otherwise you could pass any value). That doesn't save us from
+// doing reasonable run time checks in that range.
+enum AC97Register
+{
+    AC97REG_RESET = 0,
+    AC97REG_MASTER_VOLUME,
+    AC97REG_HPHONE_VOLUME,
+    AC97REG_MMONO_VOLUME,
+    AC97REG_MASTER_TONE,
+    AC97REG_BEEP_VOLUME,
+    AC97REG_PHONE_VOLUME,
+    AC97REG_MIC_VOLUME,
+    AC97REG_LINE_IN_VOLUME,
+    AC97REG_CD_VOLUME,
+    AC97REG_VIDEO_VOLUME,
+    AC97REG_AUX_VOLUME,
+    AC97REG_PCM_OUT_VOLUME,
+    AC97REG_RECORD_SELECT,
+    AC97REG_RECORD_GAIN,
+    AC97REG_RECORD_GAIN_MIC,
+    AC97REG_GENERAL,
+    AC97REG_3D_CONTROL,
+    AC97REG_RESERVED,
+    AC97REG_POWERDOWN,
+
+    // AC97-2.0 registers
+    AC97REG_EXT_AUDIO_ID,
+    AC97REG_EXT_AUDIO_CTRL,
+    AC97REG_FRONT_SAMPLERATE,
+    AC97REG_SURROUND_SAMPLERATE,
+    AC97REG_LFE_SAMPLERATE,
+    AC97REG_RECORD_SAMPLERATE,
+    AC97REG_MIC_SAMPLERATE,
+    AC97REG_CENTER_LFE_VOLUME,
+    AC97REG_SURROUND_VOLUME,
+    AC97REG_RESERVED2,
+
+    // Modem registers from 0x3C to 0x58 (next 15 enums)
+    // Vendor Reserved = 0x5A-0x7A (next 16 enums)
+
+    // Vendor IDs
+    AC97REG_VENDOR_ID1 = 0x3E,      // thats register address 0x7C
+    AC97REG_VENDOR_ID2,
+
+    // Defines an invalid register. Likewise, this is the highest
+    // possible value that can be used.
+    AC97REG_INVALID
+};
+
+#if (DBG)
+// Note: This array only has the first 29 registers defined.
+//       There are many more.
+const PCHAR RegStrings[] =
+{
+    "REG_RESET",
+    "REG_MASTER_VOLUME",
+    "REG_HPHONE_VOLUME",
+    "REG_MMONO_VOLUME",
+    "REG_MASTER_TONE",
+    "REG_BEEP_VOLUME",
+    "REG_PHONE_VOLUME",
+    "REG_MIC_VOLUME",
+    "REG_LINEIN_VOLUME",
+    "REG_CD_VOLUME",
+    "REG_VIDEO_VOLUME",
+    "REG_AUX_VOLUME",
+    "REG_PCMOUT_VOLUME",
+    "REG_RECORD_SELECT",
+    "REG_RECORD_GAIN",
+    "REG_RECORD_GAIN_MIC",
+    "REG_GENERAL",
+    "REG_3D_CONTROL",
+    "REG_RESERVED",
+    "REG_POWERDOWN",
+    "REG_EXT_AUDIO_ID",
+    "REG_EXT_AUDIO_CTRL",
+    "REG_FRONT_SAMPLERATE",
+    "REG_SURROUND_SAMPLERATE",
+    "REG_LFE_SAMPLERATE",
+    "REG_RECORD_SAMPLERATE",
+    "REG_MIC_SAMPLERATE",
+    "REG_CENTER_LFE_VOLUME",
+    "REG_SURROUND_VOLUME",
+    "REG_RESERVED2"
+};
+#endif
+
+// This array maps the node controls to the AC97 registers.
+// E.g. if you mute the master volume control you should modify AC97
+// register AC97REG_MASTER_VOLUME
+typedef struct {
+    AC97Register    reg;    // we would only need one byte, but enums are int
+    WORD            mask;   // registers are 16 bit.
+} tMapNodeToReg;
+
+const tMapNodeToReg stMapNodeToReg[] =
+{
+    // TODO: loopback
+    {AC97REG_PCM_OUT_VOLUME, 0x1F1F},   // NODE_WAVEOUT_VOLUME
+    {AC97REG_PCM_OUT_VOLUME, 0x8000},   // NODE_WAVEOUT_MUTE
+    {AC97REG_GENERAL, 0x8000},          // NODE_VIRT_WAVEOUT_3D_BYPASS
+    {AC97REG_BEEP_VOLUME, 0x001E},      // NODE_PCBEEP_VOLUME
+    {AC97REG_BEEP_VOLUME, 0x8000},      // NODE_PCBEEP_MUTE
+    {AC97REG_PHONE_VOLUME, 0x001F},     // NODE_PHONE_VOLUME
+    {AC97REG_PHONE_VOLUME, 0x8000},     // NODE_PHONE_MUTE
+    {AC97REG_GENERAL, 0x0100},          // NODE_MIC_SELECT
+    {AC97REG_MIC_VOLUME, 0x0040},       // NODE_MIC_BOOST
+    {AC97REG_MIC_VOLUME, 0x001F},       // NODE_MIC_VOLUME
+    {AC97REG_MIC_VOLUME, 0x8000},       // NODE_MIC_MUTE
+    {AC97REG_LINE_IN_VOLUME, 0x1F1F},   // NODE_LINEIN_VOLUME
+    {AC97REG_LINE_IN_VOLUME, 0x8000},   // NODE_LINEIN_MUTE
+    {AC97REG_CD_VOLUME, 0x1F1F},        // NODE_CD_VOLUME
+    {AC97REG_CD_VOLUME, 0x8000},        // NODE_CD_MUTE
+    {AC97REG_VIDEO_VOLUME, 0x1F1F},     // NODE_VIDEO_VOLUME
+    {AC97REG_VIDEO_VOLUME, 0x8000},     // NODE_VIDEO_MUTE
+    {AC97REG_AUX_VOLUME, 0x1F1F},       // NODE_AUX_VOLUME
+    {AC97REG_AUX_VOLUME, 0x8000},       // NODE_AUX_MUTE
+    {AC97REG_INVALID, 0x0000},          // NODE_MAIN_MIX doesn't has controls
+    {AC97REG_3D_CONTROL, 0x0F00},       // NODE_VIRT_3D_CENTER
+    {AC97REG_3D_CONTROL, 0x000F},       // NODE_VIRT_3D_DEPTH
+    {AC97REG_GENERAL, 0x2000},          // NODE_VIRT_3D_ENABLE
+    {AC97REG_INVALID, 0x0000},          // NODE_BEEP_MIX doesn't has controls
+    {AC97REG_MASTER_TONE, 0x0F00},      // NODE_BASS
+    {AC97REG_MASTER_TONE, 0x000F},      // NODE_TREBLE
+    {AC97REG_GENERAL, 0x1000},          // NODE_LOUDNESS
+    {AC97REG_GENERAL, 0x4000},          // NODE_SIMUL_STEREO
+    {AC97REG_MASTER_VOLUME, 0x3F3F},    // NODE_MASTEROUT_VOLUME
+    {AC97REG_MASTER_VOLUME, 0x8000},    // NODE_MASTEROUT_MUTE
+    {AC97REG_HPHONE_VOLUME, 0x3F3F},    // NODE_HPHONE_VOLUME
+    {AC97REG_HPHONE_VOLUME, 0x8000},    // NODE_HPHONE_MUTE
+    {AC97REG_GENERAL, 0x0200},          // NODE_MONOOUT_SELECT
+    {AC97REG_MMONO_VOLUME, 0x803F},     // NODE_VIRT_MONOOUT_VOLUME1
+    {AC97REG_MMONO_VOLUME, 0x803F},     // NODE_VIRT_MONOOUT_VOLUME2
+    {AC97REG_RECORD_SELECT, 0x0707},    // NODE_WAVEIN_SELECT
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME1
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME2
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME3
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME4
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME5
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME6
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME7
+    {AC97REG_RECORD_GAIN, 0x0F0F},      // NODE_VIRT_MASTER_INPUT_VOLUME8
+    {AC97REG_RECORD_GAIN_MIC, 0x000F},  // NODE_MICIN_VOLUME
+    {AC97REG_RECORD_GAIN_MIC, 0x8000},  // NODE_MICIN_MUTE
+    {AC97REG_SURROUND_VOLUME, 0x3F3F},  // NODE_SURROUND_VOLUME
+    {AC97REG_SURROUND_VOLUME, 0x8080},  // NODE_SURROUND_MUTE
+    {AC97REG_CENTER_LFE_VOLUME, 0x3F00},// NODE_CENTER_VOLUME
+    {AC97REG_CENTER_LFE_VOLUME, 0x8000},// NODE_CENTER_MUTE
+    {AC97REG_CENTER_LFE_VOLUME, 0x003F},// NODE_LFE_VOLUME
+    {AC97REG_CENTER_LFE_VOLUME, 0x0080},// NODE_LFE_MUTE
+    {AC97REG_MASTER_VOLUME, 0x3F3F},    // NODE_FRONT_VOLUME
+    {AC97REG_MASTER_VOLUME, 0x8000},    // NODE_FRONT_MUTE
+    {AC97REG_INVALID, 0x0000},          // NODE_VIRT_MASTERMONO_VOLUME doesn't have
controls
+    {AC97REG_INVALID, 0x0000}           // NODE_VIRT_MASTERMONO_MUTE doesn't have
controls
+};
+
+#endif  //_AC97REG_H_
diff --git a/drivers/wdm/audio/drivers/ac97/adapter.cpp
b/drivers/wdm/audio/drivers/ac97/adapter.cpp
new file mode 100644
index 00000000000..341abf7ea13
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/adapter.cpp
@@ -0,0 +1,583 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file adapter.cpp was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+//
+// The name that is printed in debug output messages
+//
+#define STR_MODULENAME "AC97 Adapter: "
+
+//
+// All the GUIDs from portcls and your own defined GUIDs end up in this object.
+//
+#define PUT_GUIDS_HERE
+
+//
+// We want the global debug variables here.
+//
+#define DEFINE_DEBUG_VARS
+
+#include "adapter.h"
+
+
+/*****************************************************************************
+ * Referenced forward
+ */
+DRIVER_ADD_DEVICE AddDevice;
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * InstallSubdevice
+ *****************************************************************************
+ * This function creates and registers a subdevice consisting of a port
+ * driver, a minport driver and a set of resources bound together.  It will
+ * also optionally place a pointer to an interface on the port driver in a
+ * specified location before initializing the port driver.  This is done so
+ * that a common ISR can have access to the port driver during initialization,
+ * when the ISR might fire.
+ * This function is internally used and validates no parameters.
+ */
+NTSTATUS InstallSubdevice
+(
+    _In_      PDEVICE_OBJECT      DeviceObject,
+    _In_      PIRP                Irp,
+    _In_      PWSTR               Name,
+    _In_      REFGUID             PortClassId,
+    _In_      REFGUID             MiniportClassId,
+    _In_opt_  PFNCREATEMINIPORT   MiniportCreate,
+    _In_opt_  PUNKNOWN            UnknownAdapter,
+    _In_opt_  PRESOURCELIST       ResourceList,
+    _In_opt_  REFGUID             PortInterfaceId,
+    _Out_opt_ PMINIPORT *         OutMiniport,
+    _Out_opt_ PUNKNOWN *          OutPortUnknown
+)
+{
+    PAGED_CODE ();
+
+    NTSTATUS    ntStatus;
+    PPORT       port;
+    PMINIPORT   miniport;
+
+    DOUT (DBG_PRINT, ("[InstallSubdevice]"));
+
+#ifndef __REACTOS__
+    UNREFERENCED_PARAMETER(PortInterfaceId);
+#endif
+
+    //
+    // Create the port driver object
+    //
+    ntStatus = PcNewPort (&port,PortClassId);
+
+    //
+    // return immediately in case of an error
+    //
+    if (!NT_SUCCESS (ntStatus))
+       return ntStatus;
+
+    //
+    // Create the miniport object
+    //
+    if (MiniportCreate)
+    {
+        ntStatus = MiniportCreate ((PUNKNOWN*)&miniport, MiniportClassId,
+                                   NULL, NonPagedPool);
+    }
+    else
+    {
+        ntStatus = PcNewMiniport (&miniport,MiniportClassId);
+    }
+
+    //
+    // return immediately in case of an error
+    //
+    if (!NT_SUCCESS (ntStatus))
+    {
+        port->Release ();
+        return ntStatus;
+    }
+
+    //
+    // Init the port driver and miniport in one go.
+    //
+#ifdef _MSC_VER
+#pragma warning(push)
+#endif
+    // IPort::Init's annotation on ResourceList requires it to be non-NULL.  However,
+    // for dynamic devices, we may no longer have the resource list and this should
+    // still succeed.
+    //
+#ifdef _MSC_VER
+#pragma warning(disable:6387)
+#endif
+    ntStatus = port->Init (DeviceObject, Irp, miniport, UnknownAdapter,
+                           ResourceList);
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+    if (NT_SUCCESS (ntStatus))
+    {
+        //
+        // Register the subdevice (port/miniport combination).
+        //
+        ntStatus = PcRegisterSubdevice (DeviceObject, Name, port);
+
+        //
+        // Deposit the port as an unknown if it's needed.
+        //
+        if (OutPortUnknown && NT_SUCCESS (ntStatus))
+        {
+            ntStatus = port->QueryInterface (IID_IUnknown,
+                                             (PVOID *)OutPortUnknown);
+        }
+
+        //
+        // Deposit the miniport as an IMiniport if it's needed.
+        //
+        if ( OutMiniport && NT_SUCCESS (ntStatus) )
+        {
+            ntStatus = miniport->QueryInterface (IID_IMiniport,
+                                                (PVOID *)OutMiniport);
+        }
+    }
+
+    //
+    // Release the reference for the port and miniport. This is the right
+    // thing to do, regardless of the outcome.
+    //
+    miniport->Release ();
+    port->Release ();
+
+
+    return ntStatus;
+}
+
+
+/*****************************************************************************
+ * ValidateResources
+ *****************************************************************************
+ * This function validates the list of resources for the various functions on
+ * the card.  This code is specific to the adapter.
+ * This function doesn't check the ResourceList parameter and returns
+ * STATUS_SUCCESS when the resources are valid.
+ */
+NTSTATUS ValidateResources
+(
+    IN      PRESOURCELIST   ResourceList    // All resources.
+)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[ValidateResources]"));
+
+    //
+    // Get counts for the types of resources.
+    //
+    ULONG countIO  = ResourceList->NumberOfPorts ();
+    ULONG countIRQ = ResourceList->NumberOfInterrupts ();
+    ULONG countDMA = ResourceList->NumberOfDmas ();
+
+    // validate resources
+    if ((countIO != 2) || (countIRQ != 1) || (countDMA != 0))
+    {
+        DOUT (DBG_ERROR, ("Unknown configuration:\n"
+                          "   IO  count: %d\n"
+                          "   IRQ count: %d\n"
+                          "   DMA count: %d",
+                          countIO, countIRQ, countDMA));
+        return STATUS_DEVICE_CONFIGURATION_ERROR;
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ * StartDevice
+ *****************************************************************************
+ * This function is called by the operating system when the device is started.
+ * It is responsible for starting the miniports.  This code is specific to
+ * the adapter because it calls out miniports for functions that are specific
+ * to the adapter.
+ */
+NTSTATUS GZCALL StartDevice
+(
+    IN  PDEVICE_OBJECT  DeviceObject,   // Device object.
+    IN  PIRP            Irp,            // IO request packet.
+    IN  PRESOURCELIST   ResourceList    // List of hardware resources.
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (DeviceObject);
+    ASSERT (Irp);
+    ASSERT (ResourceList);
+
+    NTSTATUS ntStatus;
+
+    DOUT (DBG_PRINT, ("[StartDevice]"));
+
+    //
+    // Determine which version of the OS we are running under.  We don't want
+    // to run under Win98G.
+    //
+
+    // create a wave cyclic port
+    PPORT pPort = 0;
+    ntStatus = PcNewPort (&pPort,CLSID_PortWaveCyclic);
+
+    // check error code
+    if (NT_SUCCESS (ntStatus))
+    {
+        // query for the event interface which is not supported in Win98 gold.
+        PPORTEVENTS pPortEvents = 0;
+        ntStatus = pPort->QueryInterface (IID_IPortEvents,
+                                         (PVOID *)&pPortEvents);
+        if (!NT_SUCCESS (ntStatus))
+        {
+            DOUT (DBG_ERROR, ("This driver is not for Win98 Gold!"));
+            ntStatus = STATUS_UNSUCCESSFUL;     // change error code.
+        }
+        else
+        {
+            pPortEvents->Release ();
+        }
+        pPort->Release ();
+    }
+
+    // now return in case it was Win98 Gold.
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Validate the resources.
+    // We don't have to split the resources into several resource lists cause
+    // the topology miniport doesn't need a resource list, the wave pci miniport
+    // needs all resources like the adapter common object.
+    //
+    ntStatus = ValidateResources (ResourceList);
+
+    //
+    // return immediately in case of an error
+    //
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // If the adapter has the right resources...
+    //
+    PADAPTERCOMMON pAdapterCommon = NULL;
+    PUNKNOWN       pUnknownCommon;
+
+    // create a new adapter common object
+    ntStatus = NewAdapterCommon (&pUnknownCommon, IID_IAC97AdapterCommon,
+                                 NULL, NonPagedPool);
+
+    if (NT_SUCCESS (ntStatus))
+    {
+        // query for the IAC97AdapterCommon interface
+        ntStatus = pUnknownCommon->QueryInterface (IID_IAC97AdapterCommon,
+                                                   (PVOID *)&pAdapterCommon);
+        if (NT_SUCCESS (ntStatus))
+        {
+            // Initialize the object
+            ntStatus = pAdapterCommon->Init (ResourceList, DeviceObject);
+
+            if (NT_SUCCESS (ntStatus))
+            {
+                // register with PortCls for power-management services
+                ntStatus = PcRegisterAdapterPowerManagement ((PUNKNOWN)pAdapterCommon,
+                                                             DeviceObject);
+            }
+        }
+
+        // release the IID_IAC97AdapterCommon on adapter common
+        pUnknownCommon->Release ();
+    }
+
+    // print error message.
+    if (!NT_SUCCESS (ntStatus))
+    {
+        DOUT (DBG_ERROR, ("Could not create or query AdapterCommon."));
+    }
+
+    //
+    // These are the port driver pointers we are keeping around for registering
+    // physical connections.
+    //
+    PMINIPORT               miniTopology            = NULL;
+    PUNKNOWN                unknownWave             = NULL;
+    PUNKNOWN                unknownTopology         = NULL;
+    PAC97MINIPORTTOPOLOGY   pMiniportTopology       = NULL;
+
+    //
+    // Start the topology miniport.
+    //
+    if (NT_SUCCESS (ntStatus))
+    {
+        ntStatus = InstallSubdevice (DeviceObject,
+                                     Irp,
+                                     L"Topology",
+                                     CLSID_PortTopology,
+                                     CLSID_PortTopology, // not used
+                                     CreateAC97MiniportTopology,
+                                     pAdapterCommon,
+                                     NULL,
+                                     GUID_NULL,
+                                     &miniTopology,
+                                     &unknownTopology);
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // query for the IAC97MiniportTopology interface
+            ntStatus = miniTopology->QueryInterface (IID_IAC97MiniportTopology,
+                                                    (PVOID *)&pMiniportTopology);
+            miniTopology->Release ();
+            miniTopology = NULL;
+        }
+
+        // print error message.
+        if (!NT_SUCCESS (ntStatus))
+        {
+            DOUT (DBG_ERROR, ("Could not create or query TopologyICH"));
+        }
+    }
+
+    //
+    // Start the wave miniport.
+    //
+    if (NT_SUCCESS (ntStatus))
+    {
+#if (NTDDI_VERSION >= NTDDI_VISTA)
+        ntStatus = InstallSubdevice (DeviceObject,
+                                     Irp,
+                                     L"Wave",
+                                     CLSID_PortWaveRT,
+                                     CLSID_PortWaveRT,      // not used
+                                     CreateAC97MiniportWaveRT,
+                                     pAdapterCommon,
+                                     ResourceList,
+                                     IID_IPortWaveRT,
+                                     NULL,
+                                     &unknownWave);
+
+        if (!NT_SUCCESS (ntStatus))
+        {
+#endif
+            //
+            // If creation of the RT port failed we can fall back to the WavePCI
+            // or WaveCyc port of portcls. In this case, we try the WavePCI port.
+            //
+#if 1
+            ntStatus = InstallSubdevice (DeviceObject,
+                                         Irp,
+                                         L"Wave",
+                                         CLSID_PortWaveCyclic,
+                                         CLSID_PortWaveCyclic,   // not used
+                                         CreateAC97MiniportWaveCyclic,
+                                         pAdapterCommon,
+                                         ResourceList,
+                                         IID_IPortWaveCyclic,
+                                         NULL,
+                                         &unknownWave);
+#else
+            ntStatus = InstallSubdevice (DeviceObject,
+                                         Irp,
+                                         L"Wave",
+                                         CLSID_PortWavePci,
+                                         CLSID_PortWavePci,   // not used
+                                         CreateAC97MiniportWavePCI,
+                                         pAdapterCommon,
+                                         ResourceList,
+                                         IID_IPortWavePci,
+                                         NULL,
+                                         &unknownWave);
+#endif
+
+
+#if (NTDDI_VERSION >= NTDDI_VISTA)
+        }
+#endif
+        // print error message.
+        if (!NT_SUCCESS (ntStatus))
+        {
+            DOUT (DBG_ERROR, ("WaveRT and WavePCI miniport installation
failed!"));
+        }
+    }
+
+    //
+    // Establish physical connections between filters as shown.
+    //
+    //              +------+    +------+
+    //              | Wave |    | Topo |
+    //  Capture <---|2    3|<===|x     |<--- CD
+    //              |      |    |      |
+    //   Render --->|0    1|===>|y     |<--- Line In
+    //              |      |    |      |
+    //      Mic <---|4    5|<===|z     |<--- Mic
+    //              +------+    |      |
+    //                          |      |---> Line Out
+    //                          +------+
+    //
+    // Note that the pin numbers for the nodes to be connected
+    // vary depending on the hardware/codec configuration.
+    // Also, the mic input may or may not be present.
+    //
+    // So,
+    //      Do a QI on unknownTopology to get an interface to call
+    //          a method on to get the topology miniport pin IDs.
+
+    if (NT_SUCCESS (ntStatus))
+    {
+        ULONG ulWaveOut, ulWaveIn, ulMicIn;
+
+        // get the pin numbers.
+        DOUT (DBG_PRINT, ("Connecting topo and wave."));
+        ntStatus = pMiniportTopology->GetPhysicalConnectionPins (&ulWaveOut,
+                                            &ulWaveIn, &ulMicIn);
+
+        // register wave render connection
+        if (NT_SUCCESS (ntStatus))
+        {
+            ntStatus = PcRegisterPhysicalConnection (DeviceObject,
+                                                     unknownWave,
+                                                     PIN_WAVEOUT_BRIDGE,
+                                                     unknownTopology,
+                                                     ulWaveOut);
+            // print error message.
+            if (!NT_SUCCESS (ntStatus))
+            {
+                DOUT (DBG_ERROR, ("Cannot connect topology and wave miniport"
+                                  " (render)!"));
+            }
+        }
+
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // register wave capture connection
+            ntStatus = PcRegisterPhysicalConnection (DeviceObject,
+                                                     unknownTopology,
+                                                     ulWaveIn,
+                                                     unknownWave,
+                                                     PIN_WAVEIN_BRIDGE);
+            // print error message.
+            if (!NT_SUCCESS (ntStatus))
+            {
+                DOUT (DBG_ERROR, ("Cannot connect topology and wave miniport"
+                                  " (capture)!"));
+            }
+        }
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // register mic capture connection
+            if (pAdapterCommon->GetPinConfig (PINC_MICIN_PRESENT))
+            {
+                ntStatus = PcRegisterPhysicalConnection (DeviceObject,
+                                                         unknownTopology,
+                                                         ulMicIn,
+                                                         unknownWave,
+                                                         PIN_MICIN_BRIDGE);
+                // print error message.
+                if (!NT_SUCCESS (ntStatus))
+                {
+                    DOUT (DBG_ERROR, ("Cannot connect topology and wave
miniport"
+                                      " (MIC)!"));
+                }
+            }
+        }
+    }
+
+    //
+    // Release the adapter common object.  It either has other references,
+    // or we need to delete it anyway.
+    //
+    if (pAdapterCommon)
+        pAdapterCommon->Release ();
+
+    //
+    // Release the unknowns.
+    //
+    if (unknownTopology)
+        unknownTopology->Release ();
+    if (unknownWave)
+        unknownWave->Release ();
+
+    // and the AC97 miniport.
+    if (pMiniportTopology)
+        pMiniportTopology->Release ();
+
+
+    return ntStatus;    // whatever this is ...
+}
+
+/*****************************************************************************
+ * AddDevice
+ *****************************************************************************
+ * This function is called by the operating system when the device is added.
+ * All adapter drivers can use this code without change.
+ */
+// disable prefast warning 28152 because
+// DO_DEVICE_INITIALIZING is cleared in PcAddAdapterDevice
+#ifdef _MSC_VER
+#pragma warning(disable:28152)
+#endif
+NTSTATUS GZCALL AddDevice
+(
+    IN PDRIVER_OBJECT   DriverObject,
+    IN PDEVICE_OBJECT   PhysicalDeviceObject
+)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[AddDevice]"));
+
+
+    //
+    // Tell portcls (the class driver) to add the device.
+    //
+    return PcAddAdapterDevice (DriverObject,
+                               PhysicalDeviceObject,
+                               (PCPFNSTARTDEVICE)StartDevice,
+                               MAX_MINIPORTS,
+                               0);
+}
+
+/*****************************************************************************
+ * DriverEntry
+ *****************************************************************************
+ * This function is called by the operating system when the driver is loaded.
+ * All adapter drivers can use this code without change.
+ */
+extern "C" DRIVER_INITIALIZE DriverEntry;
+extern "C" NTSTATUS GZCALL DriverEntry
+(
+    IN PDRIVER_OBJECT   DriverObject,
+    IN PUNICODE_STRING  RegistryPathName
+)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[DriverEntry]"));
+
+    //
+    // Tell the class driver to initialize the driver.
+    //
+    NTSTATUS RetValue = PcInitializeAdapterDriver (DriverObject,
+                                          RegistryPathName,
+                                          (PDRIVER_ADD_DEVICE)AddDevice);
+
+
+    return RetValue;
+}
+
+
+
diff --git a/drivers/wdm/audio/drivers/ac97/adapter.h
b/drivers/wdm/audio/drivers/ac97/adapter.h
new file mode 100644
index 00000000000..f5d5d4c2892
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/adapter.h
@@ -0,0 +1,71 @@
+/********************************************************************************
+**    Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file adapter.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _ADAPTER_H_
+#define _ADAPTER_H_
+
+#include "shared.h"
+
+/*****************************************************************************
+ * Defines
+ *****************************************************************************
+ */
+const ULONG MAX_MINIPORTS = 2;
+
+/*****************************************************************************
+ * Functions
+ *****************************************************************************
+ */
+//
+// both wave & topology miniport create function prototypes have this form:
+//
+typedef HRESULT (*PFNCREATEMINIPORT)(
+    OUT PUNKNOWN *  Unknown,
+    IN  REFCLSID    ClassId,
+    IN  PUNKNOWN    OuterUnknown        OPTIONAL,
+    IN  POOL_TYPE   PoolType
+);
+
+/*****************************************************************************
+ * Externals
+ *****************************************************************************
+ */
+extern NTSTATUS CreateAC97MiniportWaveRT
+(
+    OUT     PUNKNOWN *  Unknown,
+    IN      REFCLSID,
+    IN      PUNKNOWN    UnknownOuter    OPTIONAL,
+    IN      POOL_TYPE   PoolType
+);
+
+extern NTSTATUS CreateAC97MiniportWavePCI
+(
+    OUT     PUNKNOWN *  Unknown,
+    IN      REFCLSID,
+    IN      PUNKNOWN    UnknownOuter    OPTIONAL,
+    IN      POOL_TYPE   PoolType
+);
+
+extern NTSTATUS CreateAC97MiniportWaveCyclic
+(
+    OUT     PUNKNOWN *  Unknown,
+    IN      REFCLSID,
+    IN      PUNKNOWN    UnknownOuter    OPTIONAL,
+    IN      POOL_TYPE   PoolType
+);
+
+extern NTSTATUS CreateAC97MiniportTopology
+(
+    OUT     PUNKNOWN *  Unknown,
+    IN      REFCLSID,
+    IN      PUNKNOWN    UnknownOuter    OPTIONAL,
+    IN      POOL_TYPE   PoolType
+);
+
+#endif  //_ADAPTER_H_
diff --git a/drivers/wdm/audio/drivers/ac97/common.cpp
b/drivers/wdm/audio/drivers/ac97/common.cpp
new file mode 100644
index 00000000000..fd55d166d8c
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/common.cpp
@@ -0,0 +1,2309 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file common.cpp was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+// Every debug output has "Modulname text"
+#define STR_MODULENAME "AC97 Common: "
+
+#include "common.h"
+
+
+/*****************************************************************************
+ * Static Members
+ *****************************************************************************
+ */
+
+//
+// This is the register cache including registry names and default values. The
+// first WORD contains the register value and the second WORD contains a flag.
+// Currently, we only set SHREG_INVALID if we have to read the register at
+// startup (that's true when there is no constant default value for the
+// register).  Note that we cache the registers only to prevent read access to
+// the AC97 CoDec during runtime, because this is slow (40us).
+// We only set SHREG_INIT if we want to set the register to default at driver
+// startup.  If needed, the third field contains the registry name and the
+// forth field contains a default value that is used when there is no registry
+// entry.
+// The flag SHREG_NOCACHE is used when we don't want to cache the register
+// at all.  This is neccessary for status registers and sample rate registers.
+//
+tAC97Registers CAC97AdapterCommon::m_stAC97Registers[] =
+{
+{0x0000, SHREG_INVALID, NULL,               0},         // AC97REG_RESET
+{0x8000, SHREG_INIT,    L"MasterVolume",    0x0000},    //
AC97REG_MASTER_VOLUME
+{0x8000, SHREG_INIT,    L"HeadphoneVolume", 0x0000},    //
AC97REG_HPHONE_VOLUME
+{0x8000, SHREG_INIT,    L"MonooutVolume",   0x0000},    // AC97REG_MMONO_VOLUME
+{0x0F0F, SHREG_INIT,    L"ToneControls",    0x0F0F},    // AC97REG_MASTER_TONE
+{0x0000, SHREG_INVALID |
+         SHREG_INIT,    L"BeepVolume",      0x0000},    // AC97REG_BEEP_VOLUME
+{0x8008, SHREG_INIT,    L"PhoneVolume",     0x8008},    // AC97REG_PHONE_VOLUME
+{0x8008, SHREG_INIT,    L"MicVolume",       0x8008},    // AC97REG_MIC_VOLUME
+{0x8808, SHREG_INIT,    L"LineInVolume",    0x0808},    //
AC97REG_LINE_IN_VOLUME
+{0x8808, SHREG_INIT,    L"CDVolume",        0x0808},    // AC97REG_CD_VOLUME
+{0x8808, SHREG_INIT,    L"VideoVolume",     0x0808},    // AC97REG_VIDEO_VOLUME
+{0x8808, SHREG_INIT,    L"AUXVolume",       0x0808},    // AC97REG_AUX_VOLUME
+{0x8808, SHREG_INIT,    L"WaveOutVolume",   0x0808},    //
AC97REG_PCM_OUT_VOLUME
+{0x0000, SHREG_INIT,    L"RecordSelect",    0x0404},    //
AC97REG_RECORD_SELECT
+{0x8000, SHREG_INIT,    L"RecordGain",      0x0000},    // AC97REG_RECORD_GAIN
+{0x8000, SHREG_INIT,    L"RecordGainMic",   0x0000},    //
AC97REG_RECORD_GAIN_MIC
+{0x0000, SHREG_INIT,    L"GeneralPurpose",  0x0000},    // AC97REG_GENERAL
+{0x0000, SHREG_INIT,    L"3DControl",       0x0000},    // AC97REG_3D_CONTROL
+{0x0000, SHREG_NOCACHE, NULL,               0},         // AC97REG_RESERVED
+{0x0000, SHREG_NOCACHE |
+         SHREG_INIT,    L"PowerDown",       0},         // AC97REG_POWERDOWN
+// AC97-2.0 registers
+{0x0000, SHREG_INVALID, NULL,               0},         // AC97REG_EXT_AUDIO_ID
+{0x0000, SHREG_NOCACHE |
+         SHREG_INIT,    L"ExtAudioCtrl",    0x4001},    //
AC97REG_EXT_AUDIO_CTRL
+{0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_FRONT_SAMPLERATE
+{0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_SURROUND_SAMPLERATE
+{0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_LFE_SAMPLERATE
+{0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_RECORD_SAMPLERATE
+{0xBB80, SHREG_NOCACHE, NULL,               0},         // AC97REG_MIC_SAMPLERATE
+{0x8080, SHREG_INIT,    L"CenterLFEVolume", 0x0000},    //
AC97REG_CENTER_LFE_VOLUME
+{0x8080, SHREG_INIT,    L"SurroundVolume",  0x0000},    //
AC97REG_SURROUND_VOLUME
+{0x0000, SHREG_NOCACHE, NULL,               0}          // AC97REG_RESERVED2
+
+// We leave the other values blank.  There would be a huge gap with 31
+// elements that are currently unused, and then there would be 2 other
+// (used) values, the vendor IDs.  We just force a read from the vendor
+// IDs in the end of ProbeHWConfig to fill the cache.
+};
+
+
+//
+// This is the hardware configuration information.  The first struct is for
+// nodes, which we default to FALSE.  The second struct is for Pins, which
+// contains the configuration (FALSE) and the registry string which is the
+// reason for making a static struct so we can just fill in the name.
+//
+tHardwareConfig CAC97AdapterCommon::m_stHardwareConfig =
+{
+    // Nodes
+    {{FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE},
+     {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE}, {FALSE},
+     {FALSE}},
+    // Pins
+    {{FALSE, L"DisablePCBeep"},     // PINC_PCBEEP_PRESENT
+     {FALSE, L"DisablePhone"},      // PINC_PHONE_PRESENT
+     {FALSE, L"DisableMic2"},       // PINC_MIC2_PRESENT
+     {FALSE, L"DisableVideo"},      // PINC_VIDEO_PRESENT
+     {FALSE, L"DisableAUX"},        // PINC_AUX_PRESENT
+     {FALSE, L"DisableHeadphone"},  // PINC_HPOUT_PRESENT
+     {FALSE, L"DisableMonoOut"},    // PINC_MONOOUT_PRESENT
+     {FALSE, L"DisableMicIn"},      // PINC_MICIN_PRESENT
+     {FALSE, L"DisableMic"},        // PINC_MIC_PRESENT
+     {FALSE, L"DisableLineIn"},     // PINC_LINEIN_PRESENT
+     {FALSE, L"DisableCD"},         // PINC_CD_PRESENT
+     {FALSE, L"DisableSurround"},   // PINC_SURROUND_PRESENT
+     {FALSE, L"DisableCenterLFE"}}  // PINC_CENTER_LFE_PRESENT
+};
+
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * NewAdapterCommon
+ *****************************************************************************
+ * Create a new adapter common object.
+ */
+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
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (Unknown);
+
+    DOUT (DBG_PRINT, ("[NewAdapterCommon]"));
+
+    STD_CREATE_BODY_WITH_TAG_(CAC97AdapterCommon,Unknown,UnknownOuter,PoolType,
+                              PoolTag, PADAPTERCOMMON);
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::Init
+ *****************************************************************************
+ * Initialize the adapter common object -> initialize and probe HW.
+ * Pass only checked resources.
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::Init
+(
+    IN  PRESOURCELIST   ResourceList,
+    IN  PDEVICE_OBJECT  DeviceObject
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (ResourceList);
+    ASSERT (DeviceObject);
+
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::Init]"));
+
+    //
+    // Set the topology pointer to NULL.
+    //
+    m_Topology = NULL;
+
+    //
+    // Save the device object
+    //
+    m_pDeviceObject = DeviceObject;
+
+    //
+    // Get the base address for the AC97 codec and bus master.
+    //
+    ASSERT (ResourceList->FindTranslatedPort (0));
+    m_pCodecBase = (PUSHORT)ResourceList->FindTranslatedPort (0)->
+                           u.Port.Start.QuadPart;
+
+    ASSERT (ResourceList->FindTranslatedPort (1));
+    m_pBusMasterBase = (PUCHAR)ResourceList->FindTranslatedPort (1)->
+                              u.Port.Start.QuadPart;
+
+    DOUT (DBG_SYSINFO, ("Configuration:\n"
+                        "   Bus Master = 0x%p\n"
+                        "   Codec      = 0x%p",
+                        m_pBusMasterBase, m_pCodecBase));
+
+    //
+    // Set m_bDirectRead to TRUE so that all AC97 register read and
+    // writes are going directly to the HW
+    //
+    m_bDirectRead = TRUE;
+
+    //
+    // Initialize the hardware.
+    //
+    ntStatus = InitAC97 ();
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Probe hardware configuration
+    //
+    ntStatus = ProbeHWConfig ();
+    if (!NT_SUCCESS (ntStatus))
+    {
+        DOUT (DBG_ERROR, ("Probing of hardware configuration failed!"));
+        return ntStatus;
+    }
+
+    //
+    // Now, every AC97 read access goes to the cache.
+    //
+    m_bDirectRead = FALSE;
+
+    //
+    // Restore the AC97 registers now.
+    //
+#if (DBG)
+    DumpConfig ();
+#endif
+    ntStatus = SetAC97Default ();
+
+    //
+    // Initialize the device state.
+    //
+    m_PowerState = PowerDeviceD0;
+
+    return ntStatus;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::~CAC97AdapterCommon
+ *****************************************************************************
+ * Destructor.
+ */
+CAC97AdapterCommon::~CAC97AdapterCommon ()
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::~CAC97AdapterCommon]"));
+}
+
+
+#if (DBG)
+/*****************************************************************************
+ * CAC97AdapterCommon::DumpConfig
+ *****************************************************************************
+ * Dumps the HW configuration for the AC97 codec.
+ */
+void CAC97AdapterCommon::DumpConfig (void)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::DumpConfig]"));
+
+    //
+    // Print debug output for MICIN.
+    //
+    if (GetPinConfig (PINC_MICIN_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("MICIN found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No MICIN found"));
+    }
+
+    //
+    // Print debug output for tone controls.
+    //
+    if (GetNodeConfig (NODEC_TONE_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("Tone controls found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No tone controls found"));
+    }
+
+    //
+    // Print debug output for mono out.
+    //
+    if (!GetPinConfig (PINC_MONOOUT_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("No mono out found"));
+    }
+
+    //
+    // Print debug output for headphones.
+    //
+    if (!GetPinConfig (PINC_HPOUT_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("No headphone out found"));
+    }
+
+    //
+    // Print debug output for loudness.
+    //
+    if (GetNodeConfig (NODEC_LOUDNESS_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("Loudness found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No Loudness found"));
+    }
+
+    //
+    // Print debug output for 3D.
+    //
+    if (GetNodeConfig (NODEC_3D_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("3D controls found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No 3D controls found"));
+    }
+
+    //
+    // Print debug output for pc beep.
+    //
+    if (GetPinConfig (PINC_PCBEEP_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("PC beep found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No PC beep found"));
+    }
+
+    //
+    // Print debug output for phone line (or mono line input).
+    //
+    if (GetPinConfig (PINC_PHONE_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("Phone found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No Phone found"));
+    }
+
+    //
+    // Print debug output for video.
+    //
+    if (GetPinConfig (PINC_VIDEO_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("Video in found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No Video in found"));
+    }
+
+    //
+    // Print debug output for AUX.
+    //
+    if (GetPinConfig (PINC_AUX_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("AUX in found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No AUX in found"));
+    }
+
+    //
+    // Print debug output for second miorophone.
+    //
+    if (GetPinConfig (PINC_MIC2_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("MIC2 found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("No MIC2 found"));
+    }
+
+    //
+    // Print debug output for 3D stuff.
+    //
+    if (GetNodeConfig (NODEC_3D_PRESENT))
+    {
+        if (GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE))
+        {
+            DOUT (DBG_PROBE, ("Adjustable 3D center control found"));
+        }
+        if (GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE))
+        {
+            DOUT (DBG_PROBE, ("Nonadjustable 3D depth control found"));
+        }
+    }
+
+    //
+    // Print debug output for quality of master volume.
+    //
+    if (GetNodeConfig (NODEC_6BIT_MASTER_VOLUME))
+    {
+        DOUT (DBG_PROBE, ("6bit master out found"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("5bit master out found"));
+    }
+
+    //
+    // Print debug output for quality of headphones volume.
+    //
+    if (GetPinConfig (PINC_HPOUT_PRESENT))
+    {
+        if (GetNodeConfig (NODEC_6BIT_HPOUT_VOLUME))
+        {
+            DOUT (DBG_PROBE, ("6bit headphone out found"));
+        }
+        else
+        {
+            DOUT (DBG_PROBE, ("5bit headphone out found"));
+        }
+    }
+
+    //
+    // Print debug output for quality of mono out volume.
+    //
+    if (GetPinConfig (PINC_MONOOUT_PRESENT))
+    {
+        if (GetNodeConfig (NODEC_6BIT_MONOOUT_VOLUME))
+        {
+            DOUT (DBG_PROBE, ("6bit mono out found"));
+        }
+        else
+        {
+            DOUT (DBG_PROBE, ("5bit mono out found"));
+        }
+    }
+
+    //
+    // Print sample rate information.
+    //
+    if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
+    {
+        DOUT (DBG_PROBE, ("PCM variable sample rate supported"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("only 48KHz PCM supported"));
+    }
+
+    //
+    // Print double rate information.
+    //
+    if (GetNodeConfig (NODEC_PCM_DOUBLERATE_SUPPORTED))
+    {
+        DOUT (DBG_PROBE, ("PCM double sample rate supported"));
+    }
+
+    //
+    // Print mic rate information.
+    //
+    if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
+    {
+        DOUT (DBG_PROBE, ("MIC variable sample rate supported"));
+    }
+    else
+    {
+        DOUT (DBG_PROBE, ("only 48KHz MIC supported"));
+    }
+
+    // print DAC information
+    if (GetNodeConfig (NODEC_CENTER_DAC_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("center DAC found"));
+    }
+    if (GetNodeConfig (NODEC_SURROUND_DAC_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("surround DAC found"));
+    }
+    if (GetNodeConfig (NODEC_LFE_DAC_PRESENT))
+    {
+        DOUT (DBG_PROBE, ("LFE DAC found"));
+    }
+}
+#endif
+
+/*****************************************************************************
+ * CAC97AdapterCommon::NonDelegatingQueryInterface
+ *****************************************************************************
+ * Obtains an interface.  This function works just like a COM QueryInterface
+ * call and is used if the object is not being aggregated.
+ * We basically just check any GUID we know and return this object in case we
+ * know it.
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::NonDelegatingQueryInterface
+(
+    _In_         REFIID  Interface,
+    _COM_Outptr_ PVOID * Object
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (Object);
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::NonDelegatingQueryInterface]"));
+
+    // Is it IID_IUnknown?
+    if (IsEqualGUIDAligned (Interface, IID_IUnknown))
+    {
+        *Object = (PVOID)(PUNKNOWN)(PADAPTERCOMMON)this;
+    }
+    else
+    // or IID_IAC97AdapterCommon ...
+    if (IsEqualGUIDAligned (Interface, IID_IAC97AdapterCommon))
+    {
+        *Object = (PVOID)(PADAPTERCOMMON)this;
+    }
+    else
+    // or IID_IAdapterPowerManagement ...
+    if (IsEqualGUIDAligned (Interface, IID_IAdapterPowerManagement))
+    {
+        *Object = (PVOID)(PADAPTERPOWERMANAGEMENT)this;
+    }
+    else
+    {
+        // nothing found, must be an unknown interface.
+        *Object = NULL;
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    //
+    // We reference the interface for the caller.
+    //
+    ((PUNKNOWN)*Object)->AddRef ();
+    return STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::InitAC97
+ *****************************************************************************
+ * Initialize the AC97 (without hosing the modem if it got installed first).
+ */
+NTSTATUS CAC97AdapterCommon::InitAC97 (void)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::InitAC97]"));
+
+    //
+    // First check if there is an AC link to the primary CoDec.
+    //
+    NTSTATUS ntStatus = PrimaryCodecReady ();
+    if (NT_SUCCESS (ntStatus))
+    {
+        //
+        // Second, reset this primary CoDec; If this is a AMC97 CoDec, only
+        // the audio registers are reset. If this is a MC97 CoDec, the CoDec
+        // should ignore the reset (according to the spec).
+        //
+        WriteCodecRegister (AC97REG_RESET, 0x00, 0xFFFF);
+
+        ntStatus = PowerUpCodec ();
+    }
+    else
+    {
+        DOUT (DBG_ERROR, ("Initialization of AC97 CoDec failed."));
+    }
+
+    return ntStatus;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::Check6thBitSupport
+ *****************************************************************************
+ * Probes for 6th bit volume control support.
+ * The passed parameters are the AC97 register that has the volume control and
+ * the node config that should be set in this case.
+ */
+NTSTATUS CAC97AdapterCommon::Check6thBitSupport
+(
+    IN AC97Register AC97Reg,
+    IN TopoNodeConfig Config
+)
+{
+    PAGED_CODE();
+
+    NTSTATUS    ntStatus;
+    WORD        wCodecReg;
+    WORD        wOriginal;
+
+    // Read the current value.
+    ntStatus = ReadCodecRegister (AC97Reg, &wOriginal);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Write the 6th bit; for mono controls we write 0x20, for stereo
+    // controls 0x2020.
+    ntStatus = WriteCodecRegister (AC97Reg,
+                    (AC97Reg == AC97REG_MMONO_VOLUME) ? 0x0020 : 0x2020, 0xFFFF);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // And read back.
+    ntStatus = ReadCodecRegister (AC97Reg, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Check return. For mono 0x20 and for stereo 0x2020.
+    if (((wCodecReg & 0x0020) && (AC97Reg == AC97REG_MMONO_VOLUME)) ||
+        (wCodecReg & 0x2020))
+    {
+        SetNodeConfig (Config, TRUE);
+    }
+    else
+    {
+        SetNodeConfig (Config, FALSE);
+    }
+
+    // Restore original value.
+    WriteCodecRegister (AC97Reg, wOriginal, 0xFFFF);
+
+    return ntStatus;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ProbeHWConfig
+ *****************************************************************************
+ * Probes the hardware configuration.
+ * If this function returns with an error, then the configuration is not
+ * complete! Probing the registers is done by reading them (and comparing with
+ * the HW default value) or when the default is unknown, writing to them and
+ * reading back + restoring.
+ * Additionally, we read the registry so that a HW vendor can overwrite (means
+ * disable) found registers in case the adapter (e.g. video) is not visible to
+ * the user (he can't plug in a video audio there).
+ *
+ * This is a very long function with all of the error checking!
+ */
+NTSTATUS CAC97AdapterCommon::ProbeHWConfig (void)
+{
+    PAGED_CODE ();
+
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+    DWORD    dwGlobalStatus;
+    WORD     wCodecID;
+    WORD     wCodecReg;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ProbeHWConfig]"));
+
+    //
+    // Wait for the whatever 97 to complete reset and establish a link.
+    //
+    ntStatus = PrimaryCodecReady ();
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Master volume is one of the supported registers on an AC97
+    //
+    ntStatus = ReadCodecRegister (AC97REG_MASTER_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Default is x8000.
+    if (wCodecReg != 0x8000)
+        return STATUS_NO_SUCH_DEVICE;
+
+    //
+    // This gives us information about the AC97 CoDec
+    //
+    ntStatus = ReadCodecRegister (AC97REG_RESET, &wCodecID);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Fill out the configuration stuff.
+    //
+
+    SetPinConfig (PINC_MICIN_PRESENT, wCodecID & 0x0001);
+
+    // Check if OEM wants to disable MIC record line.
+    if (DisableAC97Pin (PINC_MICIN_PRESENT))
+        SetPinConfig (PINC_MICIN_PRESENT, FALSE);
+
+    // If we still have MIC record line, enable the DAC in ext. audio register.
+    if (GetPinConfig (PINC_MICIN_PRESENT))
+        // Enable ADC MIC.
+        WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, 0, 0x4000);
+    else
+        // Disable ADC MIC.
+        WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, 0x4000, 0x4000);
+
+    //
+    // Continue setting configuration information.
+    //
+
+    SetNodeConfig (NODEC_TONE_PRESENT, wCodecID & 0x0004);
+    SetNodeConfig (NODEC_SIMUL_STEREO_PRESENT, wCodecID & 0x0008);
+    SetPinConfig (PINC_HPOUT_PRESENT, wCodecID & 0x0010);
+
+    // Check if OEM wants to disable headphone output.
+    if (DisableAC97Pin (PINC_HPOUT_PRESENT))
+        SetPinConfig (PINC_HPOUT_PRESENT, FALSE);
+
+    SetNodeConfig (NODEC_LOUDNESS_PRESENT, wCodecID & 0x0020);
+    SetNodeConfig (NODEC_3D_PRESENT, wCodecID & 0x7C00);
+
+    //
+    // Test for the input pins that are always there but could be disabled
+    // by the HW vender
+    //
+
+    // Check if OEM wants to disable mic input.
+    SetPinConfig (PINC_MIC_PRESENT, !DisableAC97Pin (PINC_MIC_PRESENT));
+
+    // Check if OEM wants to disable line input.
+    SetPinConfig (PINC_LINEIN_PRESENT, !DisableAC97Pin (PINC_LINEIN_PRESENT));
+
+    // Check if OEM wants to disable CD input.
+    SetPinConfig (PINC_CD_PRESENT, !DisableAC97Pin (PINC_CD_PRESENT));
+
+
+    //
+    // For the rest, we have to probe the registers.
+    //
+
+    //
+    // Test for Mono out.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_MMONO_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Default is x8000.
+    SetPinConfig (PINC_MONOOUT_PRESENT, (wCodecReg == 0x8000));
+
+    // Check if OEM wants to disable mono output.
+    if (DisableAC97Pin (PINC_MONOOUT_PRESENT))
+        SetPinConfig (PINC_MONOOUT_PRESENT, FALSE);
+
+    //
+    // Test for PC beeper support.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_BEEP_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // default is x0 or x8000. If it's 0x8000 then we know for sure that the
+    // CoDec has a PcBeep, otherwise we have to check the register
+    if (wCodecReg == 0x8000)
+        SetPinConfig (PINC_PCBEEP_PRESENT, TRUE);
+    else if (!wCodecReg)
+    {
+        // mute the pc beeper.
+        ntStatus = WriteCodecRegister (AC97REG_BEEP_VOLUME, 0x8000, 0xFFFF);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        // read back
+        ntStatus = ReadCodecRegister (AC97REG_BEEP_VOLUME, &wCodecReg);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        if (wCodecReg == 0x8000)
+        {
+            // yep, we have support.
+            SetPinConfig (PINC_PCBEEP_PRESENT, TRUE);
+            // reset to default value.
+            WriteCodecRegister (AC97REG_BEEP_VOLUME, 0x0, 0xFFFF);
+        }
+        else
+            // nope, not present
+            SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
+    }
+    else
+        // any other value then 0x0 and 0x8000.
+        SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
+
+    // Check if OEM wants to disable beeper support.
+    if (DisableAC97Pin (PINC_PCBEEP_PRESENT))
+        SetPinConfig (PINC_PCBEEP_PRESENT, FALSE);
+
+    //
+    // Test for phone support.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_PHONE_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Default is x8008.
+    SetPinConfig (PINC_PHONE_PRESENT, (wCodecReg == 0x8008));
+
+    // Check if OEM wants to disable phone input.
+    if (DisableAC97Pin (PINC_PHONE_PRESENT))
+        SetPinConfig (PINC_PHONE_PRESENT, FALSE);
+
+    //
+    // Test for video support.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_VIDEO_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Default is x8808.
+    SetPinConfig (PINC_VIDEO_PRESENT, (wCodecReg == 0x8808));
+
+    // Check if OEM wants to disable video input.
+    if (DisableAC97Pin (PINC_VIDEO_PRESENT))
+        SetPinConfig (PINC_VIDEO_PRESENT, FALSE);
+
+    //
+    // Test for Aux support.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_AUX_VOLUME, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Default is 0x8808.
+    SetPinConfig (PINC_AUX_PRESENT, (wCodecReg == 0x8808));
+
+    // Check if OEM wants to disable aux input.
+    if (DisableAC97Pin (PINC_AUX_PRESENT))
+        SetPinConfig (PINC_AUX_PRESENT, FALSE);
+
+    //
+    // Test for Mic2 source.
+    //
+    ntStatus = ReadCodecRegister (AC97REG_GENERAL, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    // Test for Mic2 select bit.
+    if (wCodecReg & 0x0100)
+        SetPinConfig (PINC_MIC2_PRESENT, TRUE);
+    else
+    {
+        // Select Mic2 as source.
+        ntStatus = WriteCodecRegister (AC97REG_GENERAL, 0x0100, 0x0100);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        // Read back.
+        ntStatus = ReadCodecRegister (AC97REG_GENERAL, &wCodecReg);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        if (wCodecReg & 0x0100)
+        {
+            // Yep, we have support so set it to the default value.
+            SetPinConfig (PINC_MIC2_PRESENT, TRUE);
+            // reset to default value.
+            WriteCodecRegister (AC97REG_GENERAL, 0, 0x0100);
+        }
+        else
+            SetPinConfig (PINC_MIC2_PRESENT, FALSE);
+    }
+
+    // Check if OEM wants to disable mic2 input.
+    if (DisableAC97Pin (PINC_MIC2_PRESENT))
+        SetPinConfig (PINC_MIC2_PRESENT, FALSE);
+
+    //
+    // Test the 3D controls.
+    //
+    if (GetNodeConfig (NODEC_3D_PRESENT))
+    {
+        //
+        // First test for fixed 3D controls. Write default value ...
+        //
+        ntStatus = WriteCodecRegister (AC97REG_3D_CONTROL, 0, 0xFFFF);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        // Read 3D register. Default is 0 when adjustable, otherwise it is
+        // a fixed value.
+        ntStatus = ReadCodecRegister (AC97REG_3D_CONTROL, &wCodecReg);
+        if (!NT_SUCCESS (ntStatus))
+            return ntStatus;
+
+        //
+        // Check center and depth separately.
+        //
+
+        // For center
+        SetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE, !(wCodecReg & 0x0F00));
+
+        // For depth
+        SetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE, !(wCodecReg & 0x000F));
+
+        //
+        // Test for adjustable controls.
+        //
+        WriteCodecRegister (AC97REG_3D_CONTROL, 0x0A0A, 0xFFFF);
+
+        // Read 3D register. Now it should be 0x0A0A for adjustable controls,
+        // otherwise it is a fixed control or simply not there.
+        ReadCodecRegister (AC97REG_3D_CONTROL, &wCodecReg);
+
+        // Restore the default value
+        WriteCodecRegister (AC97REG_3D_CONTROL, 0, 0xFFFF);
+
+        // Check the center control for beeing adjustable
+        if (GetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE) &&
+            (wCodecReg & 0x0F00) != 0x0A00)
+        {
+            SetNodeConfig (NODEC_3D_CENTER_ADJUSTABLE, FALSE);
+        }
+
+        // Check the depth control for beeing adjustable
+        if (GetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE) &&
+            (wCodecReg & 0x000F) != 0x000A)
+        {
+            SetNodeConfig (NODEC_3D_DEPTH_ADJUSTABLE, FALSE);
+        }
+    }
+
+    //
+    // Check for 6th bit support in volume controls.  To check the 6th bit,
+    // we first have to write a value (with 6th bit set) and then read it
+    // back.  After that, we should restore the register to its default value.
+    //
+
+    //
+    // Start with the master volume.
+    //
+    Check6thBitSupport (AC97REG_MASTER_VOLUME, NODEC_6BIT_MASTER_VOLUME);
+
+    //
+    // Check for a headphone volume control.
+    //
+    if (GetPinConfig (PINC_HPOUT_PRESENT))
+    {
+        Check6thBitSupport (AC97REG_HPHONE_VOLUME, NODEC_6BIT_HPOUT_VOLUME);
+    }
+
+    //
+    // Mono out there?
+    //
+    if (GetPinConfig (PINC_MONOOUT_PRESENT))
+    {
+        Check6thBitSupport (AC97REG_MMONO_VOLUME, NODEC_6BIT_MONOOUT_VOLUME);
+    }
+
+    //
+    // Get extended AC97 V2.0 information
+    //
+    ntStatus = ReadCodecRegister (AC97REG_EXT_AUDIO_ID, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Store the information
+    //
+    SetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED, wCodecReg & 0x0001);
+    SetNodeConfig (NODEC_PCM_DOUBLERATE_SUPPORTED, wCodecReg & 0x0002);
+    SetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED, wCodecReg & 0x0008);
+    SetNodeConfig (NODEC_CENTER_DAC_PRESENT, wCodecReg & 0x0040);
+    SetNodeConfig (NODEC_SURROUND_DAC_PRESENT, wCodecReg & 0x0080);
+    SetNodeConfig (NODEC_LFE_DAC_PRESENT, wCodecReg & 0x0100);
+
+    //
+    // In case we have some features get some more information and program
+    // the codec.
+    //
+    if (wCodecReg)
+    {
+        //
+        // Enable variable sample rate in the control register and disable
+        // double rate. Also enable all DACs.
+        //
+        WriteCodecRegister (AC97REG_EXT_AUDIO_CTRL, wCodecReg & 0x0009, 0x380B);
+
+        //
+        // Check for codecs that have only one sample rate converter. These
+        // codecs will stick registers AC97REG_FRONT_SAMPLERATE and
+        // AC97REG_RECORD_SAMPLERATE together.
+        //
+        if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
+        {
+            // The default of the sample rate registers should be 0xBB80.
+            WriteCodecRegister (AC97REG_FRONT_SAMPLERATE, 0xBB80, 0xFFFF);
+
+            // Write 44.1KHz into record VSR, then check playback again.
+            WriteCodecRegister (AC97REG_RECORD_SAMPLERATE, 0xAC44, 0xFFFF);
+            ntStatus = ReadCodecRegister (AC97REG_FRONT_SAMPLERATE, &wCodecReg);
+            WriteCodecRegister (AC97REG_RECORD_SAMPLERATE, 0xBB80, 0xFFFF);
+            if (!NT_SUCCESS (ntStatus))
+                return ntStatus;
+
+            //
+            // Set the flag accordingly
+            //
+            SetNodeConfig (NODEC_PCM_VSR_INDEPENDENT_RATES, (wCodecReg == 0xBB80));
+        }
+
+        //
+        // Check multichanel support on the AC97.
+        //
+        if (GetNodeConfig (NODEC_SURROUND_DAC_PRESENT))
+        {
+            dwGlobalStatus = ReadBMControlRegister32 (GLOB_STA);
+
+            //
+            // Codec supports >2 chanel, does AC97 too?
+            //
+            if ((GetNodeConfig (NODEC_CENTER_DAC_PRESENT) ||
+                GetNodeConfig (NODEC_LFE_DAC_PRESENT)) &&
+                (dwGlobalStatus & GLOB_STA_MC6))
+            {
+                SetPinConfig (PINC_CENTER_LFE_PRESENT, TRUE);
+            }
+            else
+            {
+                SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
+            }
+
+            //
+            // Do we support at least 4 channels?
+            //
+            SetPinConfig (PINC_SURROUND_PRESENT, (dwGlobalStatus & GLOB_STA_MC4));
+        }
+        else
+        {
+            //
+            // Only 2 channel (stereo) support.
+            //
+            SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
+            SetPinConfig (PINC_SURROUND_PRESENT, FALSE);
+        }
+    }
+
+    // Check if OEM wants to disable surround output.
+    if (DisableAC97Pin (PINC_SURROUND_PRESENT))
+        SetPinConfig (PINC_SURROUND_PRESENT, FALSE);
+
+    // Check if OEM wants to disable center and LFE output.
+    if (DisableAC97Pin (PINC_CENTER_LFE_PRESENT))
+        SetPinConfig (PINC_CENTER_LFE_PRESENT, FALSE);
+
+    //
+    // Check the 6th bit support for the additional channels.
+    //
+    if (GetPinConfig (PINC_SURROUND_PRESENT))
+        Check6thBitSupport (AC97REG_SURROUND_VOLUME, NODEC_6BIT_SURROUND_VOLUME);
+
+    if (GetPinConfig (PINC_CENTER_LFE_PRESENT))
+        Check6thBitSupport (AC97REG_CENTER_LFE_VOLUME, NODEC_6BIT_CENTER_LFE_VOLUME);
+
+    //
+    // We read these registers because they are dependent on the codec.
+    //
+    ReadCodecRegister (AC97REG_VENDOR_ID1, &wCodecReg);
+    ReadCodecRegister (AC97REG_VENDOR_ID2, &wCodecReg);
+
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::AcquireCodecSemiphore
+ *****************************************************************************
+ * Acquires the AC97 semiphore.  This can not be called at dispatch level
+ * because it can timeout if a lower IRQL thread has the semaphore.
+ */
+NTSTATUS CAC97AdapterCommon::AcquireCodecSemiphore ()
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::AcquireCodecSemiphore]"));
+
+    ULONG ulCount = 0;
+    while (READ_PORT_UCHAR (m_pBusMasterBase + CAS) & CAS_CAS)
+    {
+        //
+        // Do we want to give up??
+        //
+        if (ulCount++ > 100)
+        {
+            DOUT (DBG_ERROR, ("Cannot acquire semaphore."));
+            return STATUS_IO_TIMEOUT;
+        }
+
+        //
+        // Let's wait a little, 40us and then try again.
+        //
+        KeStallExecutionProcessor (40L);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ReadCodecRegister
+ *****************************************************************************
+ * Reads a AC97 register. Don't call at PASSIVE_LEVEL.
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::ReadCodecRegister
+(
+    _In_range_(0, AC97REG_INVALID)  AC97Register reg,
+    _Out_ PWORD wData
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (wData);
+    ASSERT (reg < AC97REG_INVALID);    // audio can only be in the primary codec
+    _Analysis_assume_(reg < AC97REG_INVALID);
+
+    NTSTATUS ntStatus;
+    ULONG    Status;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadCodecRegister]"));
+
+    //
+    // Check if we have to access the HW directly.
+    //
+    if (m_bDirectRead || (m_stAC97Registers[reg].wFlags & SHREG_INVALID) ||
+        (m_stAC97Registers[reg].wFlags & SHREG_NOCACHE))
+    {
+        //
+        // Grab the codec access semiphore.
+        //
+        ntStatus = AcquireCodecSemiphore ();
+        if (!NT_SUCCESS (ntStatus))
+        {
+            DOUT (DBG_ERROR, ("ReadCodecRegister couldn't acquire the
semiphore"
+                " for reg. %s", reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+                                reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+                                reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
+                                "REG_INVALID"));
+            return ntStatus;
+        }
+
+        //
+        // Read the data.
+        //
+        *wData = READ_PORT_USHORT (m_pCodecBase + reg);
+
+        //
+        // Check to see if the read was successful.
+        //
+        Status = READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA));
+        if (Status & GLOB_STA_RCS)
+        {
+            //
+            // clear the timeout bit
+            //
+            WRITE_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA), Status);
+            *wData = 0;
+            DOUT (DBG_ERROR, ("ReadCodecRegister timed out for register %s",
+                    reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+                    reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+                    reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
+                    "REG_INVALID"));
+            return STATUS_IO_TIMEOUT;
+        }
+
+        //
+        // Clear invalid flag
+        //
+        m_stAC97Registers[reg].wCache = *wData;
+        m_stAC97Registers[reg].wFlags &= ~SHREG_INVALID;
+
+        DOUT (DBG_REGS, ("AC97READ: %s = 0x%04x (HW)",
+                reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+                reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+                reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
+                "REG_INVALID", *wData));
+    }
+    else
+    {
+        //
+        // Otherwise, use the value in the cache.
+        //
+        *wData = m_stAC97Registers[reg].wCache;
+        DOUT (DBG_REGS, ("AC97READ: %s = 0x%04x (C)",
+                reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+                reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+                reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
+                "REG_INVALID", *wData));
+    }
+
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::WriteCodecRegister
+ *****************************************************************************
+ * Writes to a AC97 register.  This can only be done at passive level because
+ * the AcquireCodecSemiphore call could fail!
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::WriteCodecRegister
+(
+    _In_range_(0, AC97REG_INVALID)  AC97Register reg,
+    _In_  WORD wData,
+    _In_  WORD wMask
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (reg < AC97REG_INVALID);    // audio can only be in the primary codec
+
+    WORD TempData = 0;
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteCodecRegister]"));
+
+    //
+    // No mask?  Could happen when you try to prg. left channel of a
+    // mono volume.
+    //
+    if (!wMask)
+        return STATUS_SUCCESS;
+
+    //
+    // Check to see if we are only writing specific bits.  If so, we want
+    // to leave some bits in the register alone.
+    //
+    if (wMask != 0xffff)
+    {
+        //
+        // Read the current register contents.
+        //
+        ntStatus = ReadCodecRegister (reg, &TempData);
+        if (!NT_SUCCESS (ntStatus))
+        {
+            DOUT (DBG_ERROR, ("WriteCodecRegiser read for mask failed"));
+            return ntStatus;
+        }
+
+        //
+        // Do the masking.
+        //
+        TempData &= ~wMask;
+        TempData |= (wMask & wData);
+    }
+    else
+    {
+        TempData = wData;
+    }
+
+
+    //
+    // Grab the codec access semiphore.
+    //
+    ntStatus = AcquireCodecSemiphore ();
+    if (!NT_SUCCESS (ntStatus))
+    {
+        DOUT (DBG_ERROR, ("WriteCodecRegister failed for register %s",
+            reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+            reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+            reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
"REG_INVALID"));
+        return ntStatus;
+    }
+
+    //
+    // Write the data.
+    //
+    WRITE_PORT_USHORT (m_pCodecBase + reg, TempData);
+
+    //
+    // Update cache.
+    //
+    _Analysis_assume_(reg < AC97REG_INVALID);
+    m_stAC97Registers[reg].wCache = TempData;
+
+    DOUT (DBG_REGS, ("AC97WRITE: %s -> 0x%04x",
+                   reg <= AC97REG_RESERVED2 ? RegStrings[reg] :
+                   reg == AC97REG_VENDOR_ID1 ? "REG_VENDOR_ID1" :
+                   reg == AC97REG_VENDOR_ID2 ? "REG_VENDOR_ID2" :
+                   "REG_INVALID", TempData));
+
+
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::PrimaryCodecReady
+ *****************************************************************************
+ * Checks whether the primary codec is present and ready.  This may take
+ * awhile if we are bringing it up from a cold reset so give it a second
+ * before giving up.
+ */
+NTSTATUS CAC97AdapterCommon::PrimaryCodecReady (void)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PrimaryCodecReady]"));
+
+
+    //
+    // Enable the AC link and raise the reset line.
+    //
+    DWORD dwRegValue = ReadBMControlRegister32 (GLOB_CNT);
+
+    // If someone enabled GPI Interrupt Enable, then he hopefully handles that
+    // too.
+    dwRegValue = (dwRegValue | GLOB_CNT_COLD) & ~(GLOB_CNT_ACLOFF | GLOB_CNT_PRIE);
+    WriteBMControlRegister (GLOB_CNT, dwRegValue);
+
+    //
+    // Wait for the Codec to be ready.
+    //
+    ULONG           WaitCycles = 200;
+    LARGE_INTEGER   WaitTime;
+
+    WaitTime.QuadPart = (-50000);   // wait 5000us (5ms) relative
+
+    do
+    {
+        if (READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + GLOB_STA)) &
+            GLOB_STA_PCR)
+        {
+            return STATUS_SUCCESS;
+        }
+
+        KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
+    } while (WaitCycles--);
+
+    DOUT (DBG_ERROR, ("PrimaryCodecReady timed out!"));
+    return STATUS_IO_TIMEOUT;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::PowerUpCodec
+ *****************************************************************************
+ * Sets the Codec to the highest power state and waits until the Codec reports
+ * that the power state is reached.
+ */
+NTSTATUS CAC97AdapterCommon::PowerUpCodec (void)
+{
+    PAGED_CODE ();
+
+    WORD        wCodecReg;
+    NTSTATUS    ntStatus;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PowerUpCodec]"));
+
+    //
+    // Power up the Codec.
+    //
+    WriteCodecRegister (AC97REG_POWERDOWN, 0x00, 0xFFFF);
+
+    //
+    // Wait for the Codec to be powered up.
+    //
+    ULONG           WaitCycles = 200;
+    LARGE_INTEGER   WaitTime;
+
+    WaitTime.QuadPart = (-50000);   // wait 5000us (5ms) relative
+
+    do
+    {
+        //
+        // Read the power management register.
+        //
+        ntStatus = ReadCodecRegister (AC97REG_POWERDOWN, &wCodecReg);
+        if (!NT_SUCCESS (ntStatus))
+        {
+            wCodecReg = 0;      // Will cause an error.
+            break;
+        }
+
+        //
+        // Check the power state. Should be ready.
+        //
+        if ((wCodecReg & 0x0f) == 0x0f)
+            break;
+
+        //
+        // Let's wait a little, 5ms and then try again.
+        //
+        KeDelayExecutionThread (KernelMode, FALSE, &WaitTime);
+    } while (WaitCycles--);
+
+    // Check if we timed out.
+    if ((wCodecReg & 0x0f) != 0x0f)
+    {
+        DOUT (DBG_ERROR, ("PowerUpCodec timed out. CoDec not powered up."));
+        ntStatus = STATUS_DEVICE_NOT_READY;
+    }
+
+    return ntStatus;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ProgramSampleRate
+ *****************************************************************************
+ * Programs the sample rate. If the rate cannot be programmed, the routine
+ * restores the register and returns STATUS_UNSUCCESSFUL.
+ * We don't handle double rate sample rates here, because the Intel AC97 con-
+ * troller cannot serve CoDecs with double rate or surround sound. If you want
+ * to modify this driver for another AC97 controller, then you might want to
+ * change this function too.
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::ProgramSampleRate
+(
+    IN  AC97Register    Register,
+    IN  DWORD           dwSampleRate
+)
+{
+    PAGED_CODE ();
+
+    WORD     wOldRateReg, wCodecReg;
+    NTSTATUS ntStatus;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ProgramSampleRate]"));
+
+    //
+    // Check if we support variable sample rate.
+    //
+    switch(Register)
+    {
+        case AC97REG_MIC_SAMPLERATE:
+            //
+            // Variable sample rate supported?
+            //
+            if (GetNodeConfig (NODEC_MIC_VARIABLERATE_SUPPORTED))
+            {
+                // Range supported?
+                if (dwSampleRate > 48000ul)
+                {
+                    // Not possible.
+                    DOUT (DBG_VSR, ("Samplerate %d not supported",
dwSampleRate));
+                    return STATUS_NOT_SUPPORTED;
+                }
+            }
+            else
+            {
+                // Only 48000KHz possible.
+                if (dwSampleRate != 48000ul)
+                {
+                    DOUT (DBG_VSR, ("Samplerate %d not supported",
dwSampleRate));
+                    return STATUS_NOT_SUPPORTED;
+                }
+
+                return STATUS_SUCCESS;
+            }
+            break;
+
+        case AC97REG_FRONT_SAMPLERATE:
+        case AC97REG_SURROUND_SAMPLERATE:
+        case AC97REG_LFE_SAMPLERATE:
+        case AC97REG_RECORD_SAMPLERATE:
+            //
+            // Variable sample rate supported?
+            //
+            if (GetNodeConfig (NODEC_PCM_VARIABLERATE_SUPPORTED))
+            {
+                //
+                // Check range supported
+                //
+                if (dwSampleRate > 48000ul)
+                {
+                    DOUT (DBG_VSR, ("Samplerate %d not supported",
dwSampleRate));
+                    return STATUS_NOT_SUPPORTED;
+                }
+            }
+            else
+            {
+                // Only 48KHz possible.
+                if (dwSampleRate != 48000ul)
+                {
+                    DOUT (DBG_VSR, ("Samplerate %d not supported",
dwSampleRate));
+                    return STATUS_NOT_SUPPORTED;
+                }
+
+                return STATUS_SUCCESS;
+            }
+            break;
+
+        default:
+            DOUT (DBG_ERROR, ("Invalid sample rate register!"));
+            return STATUS_UNSUCCESSFUL;
+    }
+
+
+    //
+    // Save the old sample rate register.
+    //
+    ntStatus = ReadCodecRegister (Register, &wOldRateReg);
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // program the rate.
+    //
+    ntStatus = WriteCodecRegister (Register, (WORD)dwSampleRate, 0xFFFF);
+    if (!NT_SUCCESS (ntStatus))
+    {
+        DOUT (DBG_ERROR, ("Cannot program sample rate."));
+        return ntStatus;
+    }
+
+    //
+    // Read it back.
+    //
+    ntStatus = ReadCodecRegister (Register, &wCodecReg);
+    if (!NT_SUCCESS (ntStatus))
+    {
+        DOUT (DBG_ERROR, ("Cannot read sample rate."));
+        return ntStatus;
+    }
+
+    //
+    // Validate.
+    //
+    if (wCodecReg != dwSampleRate)
+    {
+        //
+        // restore sample rate and ctrl register.
+        //
+        WriteCodecRegister (Register, wOldRateReg, 0xFFFF);
+
+        DOUT (DBG_VSR, ("Samplerate %d not supported", dwSampleRate));
+        return STATUS_NOT_SUPPORTED;
+    }
+
+    DOUT (DBG_VSR, ("Samplerate changed to %d.", dwSampleRate));
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::PowerChangeState
+ *****************************************************************************
+ * Change power state for the device.  We handle the codec, PowerChangeNotify
+ * in the wave miniport handles the DMA registers.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::PowerChangeState
+(
+    _In_  POWER_STATE NewState
+)
+{
+    PAGED_CODE ();
+
+    NTSTATUS ntStatus = STATUS_SUCCESS;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::PowerChangeNotify]"));
+
+    //
+    // Check to see if this is the current power state.
+    //
+    if (NewState.DeviceState == m_PowerState)
+    {
+        DOUT (DBG_POWER, ("New device state equals old state."));
+        return;
+    }
+
+    //
+    // Check the new device state.
+    //
+    if ((NewState.DeviceState < PowerDeviceD0) ||
+        (NewState.DeviceState > PowerDeviceD3))
+    {
+        DOUT (DBG_ERROR, ("Unknown device state: D%d.",
+             (ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
+        return;
+    }
+
+    DOUT (DBG_POWER, ("Changing state to D%d.", (ULONG)NewState.DeviceState -
+                    (ULONG)PowerDeviceD0));
+
+    //
+    // Switch on new state.
+    //
+    switch (NewState.DeviceState)
+    {
+        case PowerDeviceD0:
+            //
+            // If we are coming from D2 or D3 we have to restore the registers cause
+            // there might have been a power loss.
+            //
+            if ((m_PowerState == PowerDeviceD3) || (m_PowerState == PowerDeviceD2))
+            {
+                //
+                // Reset AD3 to indicate that we are now awake.
+                // Because the system has only one power irp at a time, we are sure
+                // that the modem driver doesn't get called while we are restoring
+                // power.
+                //
+                WriteBMControlRegister (GLOB_STA,
+                    ReadBMControlRegister32 (GLOB_STA) & ~GLOB_STA_AD3);
+
+                //
+                // Restore codec registers.
+                //
+                ntStatus = RestoreCodecRegisters ();
+            }
+            else        // We are coming from power state D1
+            {
+                ntStatus = PowerUpCodec ();
+            }
+
+            // Print error code.
+            if (!NT_SUCCESS (ntStatus))
+            {
+                DOUT (DBG_ERROR, ("PowerChangeState failed to restore the
codec."));
+            }
+            break;
+
+        case PowerDeviceD1:
+            //
+            // This sleep state is the lowest latency sleep state with respect
+            // to the latency time required to return to D0. If the
+            // driver is not being used an inactivity timer in portcls will
+            // place the driver in this state after a timeout period
+            // controllable via the registry.
+            //
+
+            // Let's power down the DAC/ADC's and analog mixer.
+            WriteCodecRegister (AC97REG_POWERDOWN, 0x0700, 0xFFFF);
+            break;
+
+        case PowerDeviceD2:
+        case PowerDeviceD3:
+            //
+            // This is a full hibernation state and is the longest latency sleep
+            // state. In this modes the power could be removed or reduced that
+            // much that the AC97 controller looses information, so we save
+            // whatever we have to save.
+            //
+
+            //
+            // Powerdown ADC, DAC, Mixer, Vref, HP amp, and Exernal Amp but not
+            // AC-link and Clk
+            //
+            WriteCodecRegister (AC97REG_POWERDOWN, 0xCF00, 0xFFFF);
+
+            //
+            // Only in D3 mode we set the AD3 bit and evtl. shut off the AC link.
+            //
+            if (NewState.DeviceState == PowerDeviceD3)
+            {
+                //
+                // Set the AD3 bit.
+                //
+                ULONG ulReg = ReadBMControlRegister32 (GLOB_STA);
+                WriteBMControlRegister (GLOB_STA, ulReg | GLOB_STA_AD3);
+
+                //
+                // We check if the modem is sleeping. If it is, we can shut off the
+                // AC link also. We shut off the AC link also if the modem is not
+                // there.
+                //
+                if ((ulReg & GLOB_STA_MD3) || !(ulReg & GLOB_STA_SCR))
+                {
+                    // Set Codec to super sleep
+                    WriteCodecRegister (AC97REG_POWERDOWN, 0xFF00, 0xFFFF);
+
+                    // Disable the AC-link signals
+                    ulReg = ReadBMControlRegister32 (GLOB_CNT);
+                    WriteBMControlRegister (GLOB_CNT, (ulReg | GLOB_CNT_ACLOFF) &
~GLOB_CNT_COLD);
+                }
+            }
+            break;
+    }
+
+    //
+    // Save the new state.  This local value is used to determine when to
+    // cache property accesses and when to permit the driver from accessing
+    // the hardware.
+    //
+    m_PowerState = NewState.DeviceState;
+    DOUT (DBG_POWER, ("Entering D%d", (ULONG)m_PowerState -
+                      (ULONG)PowerDeviceD0));
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::QueryPowerChangeState
+ *****************************************************************************
+ * Query to see if the device can change to this power state
+ */
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::QueryPowerChangeState
+(
+    _In_  POWER_STATE NewState
+)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::QueryPowerChangeState]"));
+
+    // Check here to see of a legitimate state is being requested
+    // based on the device state and fail the call if the device/driver
+    // cannot support the change requested.  Otherwise, return STATUS_SUCCESS.
+    // Note: A QueryPowerChangeState() call is not guaranteed to always preceed
+    // a PowerChangeState() call.
+
+    // check the new state being requested
+    switch (NewState.DeviceState)
+    {
+        case PowerDeviceD0:
+        case PowerDeviceD1:
+        case PowerDeviceD2:
+        case PowerDeviceD3:
+            return STATUS_SUCCESS;
+
+        default:
+            DOUT (DBG_ERROR, ("Unknown device state: D%d.",
+                 (ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
+            return STATUS_NOT_IMPLEMENTED;
+    }
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::QueryDeviceCapabilities
+ *****************************************************************************
+ * Called at startup to get the caps for the device.  This structure provides
+ * the system with the mappings between system power state and device power
+ * state.  This typically will not need modification by the driver.
+ * If the driver modifies these mappings then the driver is not allowed to
+ * change the mapping to a weaker power state (e.g. from S1->D3 to S1->D1).
+ *
+ */
+_Use_decl_annotations_
+STDMETHODIMP_(NTSTATUS) CAC97AdapterCommon::QueryDeviceCapabilities
+(
+    PDEVICE_CAPABILITIES PowerDeviceCaps
+)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::QueryDeviceCapabilities]"));
+
+    UNREFERENCED_PARAMETER(PowerDeviceCaps);
+
+    return STATUS_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::RestoreAC97Registers
+ *****************************************************************************
+ * Preset the AC97 registers with default values. The routine first checks if
+ * There are registry entries for the default values. If not, we have hard
+ * coded values too ;)
+ */
+NTSTATUS CAC97AdapterCommon::SetAC97Default (void)
+{
+    PAGED_CODE ();
+
+    PREGISTRYKEY    DriverKey;
+    PREGISTRYKEY    SettingsKey;
+    UNICODE_STRING  sKeyName;
+    ULONG           ulDisposition;
+    ULONG           ulResultLength;
+    PVOID           KeyInfo = NULL;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::SetAC97Default]"));
+
+    // open the driver registry key
+    NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
+                                          NULL,              // OuterUnknown
+                                          DriverRegistryKey, // Registry key type
+                                          KEY_READ,          // Access flags
+                                          m_pDeviceObject,   // Device object
+                                          NULL,              // Subdevice
+                                          NULL,              // ObjectAttributes
+                                          0,                 // Create options
+                                          NULL);             // Disposition
+    if (NT_SUCCESS (ntStatus))
+    {
+        // make a unicode string for the subkey name
+        RtlInitUnicodeString (&sKeyName, L"Settings");
+
+        // open the settings subkey
+        ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
+                                         NULL,                    // OuterUnknown
+                                         KEY_READ,                // Access flags
+                                         &sKeyName,               // Subkey name
+                                         REG_OPTION_NON_VOLATILE, // Create options
+                                         &ulDisposition);
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // allocate data to hold key info
+            KeyInfo = ExAllocatePoolWithTag (PagedPool,
+                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                      sizeof(WORD), PoolTag);
+            if (NULL != KeyInfo)
+            {
+                // loop through all mixer settings
+                for (AC97Register i = AC97REG_RESET; i <= AC97REG_RESERVED2;
+                    i = (AC97Register)(i + 1))
+                {
+                    if (m_stAC97Registers[i].wFlags & SHREG_INIT)
+                    {
+                        // init key name
+                        RtlInitUnicodeString (&sKeyName,
+                                              m_stAC97Registers[i].sRegistryName);
+
+                        // query the value key
+                        ntStatus = SettingsKey->QueryValueKey (&sKeyName,
+                                        KeyValuePartialInformation,
+                                        KeyInfo,
+                                        sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                            sizeof(WORD),
+                                        &ulResultLength);
+                        if (NT_SUCCESS (ntStatus))
+                        {
+                            PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
+                                        (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
+
+                            if (PartialInfo->DataLength == sizeof(WORD))
+                            {
+                                // set mixer register to registry value
+                                WriteCodecRegister
+                                    (i, *(PWORD)PartialInfo->Data, 0xFFFF);
+                            }
+                            else    // write the hard coded default
+                            {
+                                // if key access failed, set to default
+                                WriteCodecRegister
+                                    (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
+                            }
+                        }
+                        else  // write the hard coded default
+                        {
+                            // if key access failed, set to default
+                            WriteCodecRegister
+                                (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
+                        }
+                    }
+                }
+
+                // we want to return status success even if the last QueryValueKey
+                // failed.
+                ntStatus = STATUS_SUCCESS;
+
+                // free the key info
+                ExFreePoolWithTag (KeyInfo,PoolTag);
+            }
+            else
+            {
+                ntStatus = STATUS_INSUFFICIENT_RESOURCES;
+            }
+
+            // release the settings key
+            SettingsKey->Release ();
+        }
+
+        // release the driver key
+        DriverKey->Release ();
+    }
+
+
+    // in case we did not query the registry (cause of lack of resources)
+    // restore default values and return insufficient resources.
+    if (!NT_SUCCESS (ntStatus))
+    {
+        // copy hard coded default settings
+        for (AC97Register i = AC97REG_RESET; i < AC97REG_RESERVED2;
+             i = (AC97Register)(i + 1))
+        {
+            if (m_stAC97Registers[i].wFlags & SHREG_INIT)
+            {
+                WriteCodecRegister (i, m_stAC97Registers[i].wWantedDefault, 0xFFFF);
+            }
+        }
+    }
+
+    return ntStatus;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::DisableAC97Pin
+ *****************************************************************************
+ * Returns TRUE when the HW vendor wants to disable the pin. A disabled pin is
+ * not shown to the user (means it is not included in the topology). The
+ * reason for doing this could be that some of the input lines like Aux or
+ * Video are not available to the user (to plug in something) but the codec
+ * can handle those lines.
+ */
+BOOL CAC97AdapterCommon::DisableAC97Pin
+(
+    IN  TopoPinConfig pin
+)
+{
+    PAGED_CODE ();
+
+    PREGISTRYKEY    DriverKey;
+    PREGISTRYKEY    SettingsKey;
+    UNICODE_STRING  sKeyName;
+    ULONG           ulDisposition;
+    ULONG           ulResultLength;
+    PVOID           KeyInfo = NULL;
+    BOOL            bDisable = FALSE;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::DisableAC97Pin]"));
+
+    // open the driver registry key
+    NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
+                                          NULL,              // OuterUnknown
+                                          DriverRegistryKey, // Registry key type
+                                          KEY_READ,          // Access flags
+                                          m_pDeviceObject,   // Device object
+                                          NULL,              // Subdevice
+                                          NULL,              // ObjectAttributes
+                                          0,                 // Create options
+                                          NULL);             // Disposition
+    if (NT_SUCCESS (ntStatus))
+    {
+        // make a unicode string for the subkey name
+        RtlInitUnicodeString (&sKeyName, L"Settings");
+
+        // open the settings subkey
+        ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
+                                         NULL,                    // OuterUnknown
+                                         KEY_READ,                // Access flags
+                                         &sKeyName,               // Subkey name
+                                         REG_OPTION_NON_VOLATILE, // Create options
+                                         &ulDisposition);
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // allocate data to hold key info
+            KeyInfo = ExAllocatePoolWithTag (PagedPool,
+                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                      sizeof(BYTE), PoolTag);
+            if (NULL != KeyInfo)
+            {
+                // init key name
+                RtlInitUnicodeString (&sKeyName, m_stHardwareConfig.
+                                            Pins[pin].sRegistryName);
+
+                // query the value key
+                ntStatus = SettingsKey->QueryValueKey (&sKeyName,
+                                   KeyValuePartialInformation,
+                                   KeyInfo,
+                                   sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                        sizeof(BYTE),
+                                   &ulResultLength );
+                if (NT_SUCCESS (ntStatus))
+                {
+                    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
+                                (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
+
+                    if (PartialInfo->DataLength == sizeof(BYTE))
+                    {
+                        // store the value
+                        if (*(PBYTE)PartialInfo->Data)
+                            bDisable = TRUE;
+                        else
+                            bDisable = FALSE;
+                    }
+                }
+
+                // free the key info
+                ExFreePoolWithTag (KeyInfo,PoolTag);
+            }
+
+            // release the settings key
+            SettingsKey->Release ();
+        }
+
+        // release the driver key
+        DriverKey->Release ();
+    }
+
+    // if one of the stuff above fails we return the default, which is FALSE.
+    return bDisable;
+}
+
+
+/*****************************************************************************
+ * CAC97AdapterCommon::RestoreCodecRegisters
+ *****************************************************************************
+ * write back cached mixer values to codec registers
+ */
+NTSTATUS CAC97AdapterCommon::RestoreCodecRegisters (void)
+{
+    PAGED_CODE ();
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::RestoreCodecRegisters]"));
+
+    //
+    // Initialize the AC97 codec.
+    //
+    NTSTATUS ntStatus = InitAC97 ();
+    if (!NT_SUCCESS (ntStatus))
+        return ntStatus;
+
+    //
+    // Restore all codec registers.  Failure is not critical.
+    //
+    for (AC97Register i = AC97REG_MASTER_VOLUME; i < AC97REG_RESERVED2;
+        i = (AC97Register)(i + 1))
+    {
+        WriteCodecRegister (i, m_stAC97Registers[i].wCache, 0xFFFF);
+    }
+
+    return STATUS_SUCCESS;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ReadChannelConfigDefault
+ *****************************************************************************
+ * This function reads the default channel config from the registry. The
+ * registry entry "ChannelConfig" is set every every time we get a
+ * KSPROPERTY_AUDIO_CHANNEL_CONFIG for the DAC node.
+ * In case the key doesn't exist we assume a channel config of stereo speakers,
+ * cause that is the default of DSOUND.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::ReadChannelConfigDefault
+(
+    PDWORD  pdwChannelConfig,
+    PWORD   pwChannels
+)
+{
+    PAGED_CODE ();
+
+    PREGISTRYKEY    DriverKey;
+    PREGISTRYKEY    SettingsKey;
+    UNICODE_STRING  sKeyName;
+    ULONG           ulDisposition;
+    ULONG           ulResultLength;
+    PVOID           KeyInfo = NULL;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadChannelConfigDefault]"));
+
+    // This is the default: 2 speakers, stereo.
+    *pdwChannelConfig = KSAUDIO_SPEAKER_STEREO;
+    *pwChannels = 2;
+
+    // open the driver registry key
+    NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
+                                          NULL,              // OuterUnknown
+                                          DriverRegistryKey, // Registry key type
+                                          KEY_READ,          // Access flags
+                                          m_pDeviceObject,   // Device object
+                                          NULL,              // Subdevice
+                                          NULL,              // ObjectAttributes
+                                          0,                 // Create options
+                                          NULL);             // Disposition
+    if (NT_SUCCESS (ntStatus))
+    {
+        // make a unicode string for the subkey name
+        RtlInitUnicodeString (&sKeyName, L"Settings");
+
+        // open the settings subkey
+        ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
+                                         NULL,                    // OuterUnknown
+                                         KEY_READ,                // Access flags
+                                         &sKeyName,               // Subkey name
+                                         REG_OPTION_NON_VOLATILE, // Create options
+                                         &ulDisposition);
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // allocate data to hold key info
+            KeyInfo = ExAllocatePoolWithTag (PagedPool,
+                                      sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                      sizeof(DWORD), PoolTag);
+            if (NULL != KeyInfo)
+            {
+                // init key name
+                RtlInitUnicodeString (&sKeyName, L"ChannelConfig");
+
+                // query the value key
+                ntStatus = SettingsKey->QueryValueKey (&sKeyName,
+                                   KeyValuePartialInformation,
+                                   KeyInfo,
+                                   sizeof(KEY_VALUE_PARTIAL_INFORMATION) +
+                                        sizeof(DWORD),
+                                   &ulResultLength );
+                if (NT_SUCCESS (ntStatus))
+                {
+                    PKEY_VALUE_PARTIAL_INFORMATION PartialInfo =
+                                (PKEY_VALUE_PARTIAL_INFORMATION)KeyInfo;
+
+                    if (PartialInfo->DataLength == sizeof(DWORD))
+                    {
+                        switch (*(PLONG)PartialInfo->Data)
+                        {
+                        case KSAUDIO_SPEAKER_QUAD:
+                        case KSAUDIO_SPEAKER_SURROUND:
+                            if (GetPinConfig (PINC_SURROUND_PRESENT))
+                            {
+                                *pdwChannelConfig = *(PDWORD)PartialInfo->Data;
+                                *pwChannels = 4;
+                            }
+                            break;
+
+                        case KSAUDIO_SPEAKER_5POINT1:
+                            if (GetPinConfig (PINC_SURROUND_PRESENT) &&
+                                GetPinConfig (PINC_CENTER_LFE_PRESENT))
+                            {
+                                *pdwChannelConfig = *(PDWORD)PartialInfo->Data;
+                                *pwChannels = 6;
+                            }
+                            break;
+                        }
+                    }
+                }
+
+                // free the key info
+                ExFreePoolWithTag (KeyInfo,PoolTag);
+            }
+
+            // release the settings key
+            SettingsKey->Release ();
+        }
+
+        // release the driver key
+        DriverKey->Release ();
+    }
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::WriteChannelConfigDefault
+ *****************************************************************************
+ * This function writes the default channel config to the registry. The
+ * registry entry "ChannelConfig" is set every every time we get a
+ * KSPROPERTY_AUDIO_CHANNEL_CONFIG for the DAC node.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::WriteChannelConfigDefault (DWORD dwChannelConfig)
+{
+    PAGED_CODE ();
+
+    PREGISTRYKEY    DriverKey;
+    PREGISTRYKEY    SettingsKey;
+    UNICODE_STRING  sKeyName;
+    ULONG           ulDisposition;
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteChannelConfigDefault]"));
+
+    // open the driver registry key
+    NTSTATUS ntStatus = PcNewRegistryKey (&DriverKey,        // IRegistryKey
+                                          NULL,              // OuterUnknown
+                                          DriverRegistryKey, // Registry key type
+                                          KEY_WRITE,         // Access flags
+                                          m_pDeviceObject,   // Device object
+                                          NULL,              // Subdevice
+                                          NULL,              // ObjectAttributes
+                                          0,                 // Create options
+                                          NULL);             // Disposition
+    if (NT_SUCCESS (ntStatus))
+    {
+        // make a unicode string for the subkey name
+        RtlInitUnicodeString (&sKeyName, L"Settings");
+
+        // open the settings subkey
+        ntStatus = DriverKey->NewSubKey (&SettingsKey,            // Subkey
+                                         NULL,                    // OuterUnknown
+                                         KEY_WRITE,               // Access flags
+                                         &sKeyName,               // Subkey name
+                                         REG_OPTION_NON_VOLATILE, // Create options
+                                         &ulDisposition);
+
+        if (NT_SUCCESS (ntStatus))
+        {
+            // init key name
+            RtlInitUnicodeString (&sKeyName, L"ChannelConfig");
+
+            // query the value key
+            ntStatus = SettingsKey->SetValueKey (&sKeyName,
+                                                 REG_DWORD,
+                                                 &dwChannelConfig,
+                                                 sizeof (DWORD));
+            if (!NT_SUCCESS (ntStatus))
+            {
+                DOUT (DBG_ERROR, ("Could not write the ChannelConfig to
registry."));
+            }
+
+            // release the settings key
+            SettingsKey->Release ();
+        }
+
+        // release the driver key
+        DriverKey->Release ();
+    }
+}
+
+/*****************************************************************************
+ * Non paged code begins here
+ *****************************************************************************
+ */
+
+#ifdef _MSC_VER
+#pragma code_seg()
+#endif
+/*****************************************************************************
+ * CAC97AdapterCommon::WriteBMControlRegister
+ *****************************************************************************
+ * Writes a byte (UCHAR) to BusMaster Control register.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
+(
+    IN  ULONG ulOffset,
+    IN  UCHAR ucValue
+)
+{
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister] (UCHAR)"));
+
+    WRITE_PORT_UCHAR ((PUCHAR)(m_pBusMasterBase + ulOffset), ucValue);
+
+    DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%2x to 0x%4p.",
+                   ucValue, m_pBusMasterBase + ulOffset));
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::WriteBMControlRegister
+ *****************************************************************************
+ * Writes a word (USHORT) to BusMaster Control register.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
+(
+    IN  ULONG ulOffset,
+    IN  USHORT usValue
+)
+{
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister
(USHORT)]"));
+
+    WRITE_PORT_USHORT ((PUSHORT)(m_pBusMasterBase + ulOffset), usValue);
+
+    DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%4x to 0x%4p",
+                   usValue, m_pBusMasterBase + ulOffset));
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::WriteBMControlRegister
+ *****************************************************************************
+ * Writes a DWORD (ULONG) to BusMaster Control register.
+ */
+STDMETHODIMP_(void) CAC97AdapterCommon::WriteBMControlRegister
+(
+    IN  ULONG ulOffset,
+    IN  ULONG ulValue
+)
+{
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::WriteBMControlRegister (ULONG)]"));
+
+    WRITE_PORT_ULONG ((PULONG)(m_pBusMasterBase + ulOffset), ulValue);
+
+    DOUT (DBG_REGS, ("WriteBMControlRegister wrote 0x%8x to 0x%4p.",
+                   ulValue, m_pBusMasterBase + ulOffset));
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ReadBMControlRegister8
+ *****************************************************************************
+ * Read a byte (UCHAR) from BusMaster Control register.
+ */
+STDMETHODIMP_(UCHAR) CAC97AdapterCommon::ReadBMControlRegister8
+(
+    IN  ULONG ulOffset
+)
+{
+    UCHAR ucValue = UCHAR(-1);
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister8]"));
+
+    ucValue = READ_PORT_UCHAR ((PUCHAR)(m_pBusMasterBase + ulOffset));
+
+    DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%2x from 0x%4p.", ucValue,
+                   m_pBusMasterBase + ulOffset));
+
+    return ucValue;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ReadBMControlRegister16
+ *****************************************************************************
+ * Read a word (USHORT) from BusMaster Control register.
+ */
+STDMETHODIMP_(USHORT) CAC97AdapterCommon::ReadBMControlRegister16
+(
+    IN  ULONG ulOffset
+)
+{
+    USHORT usValue = USHORT(-1);
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister16]"));
+
+    usValue = READ_PORT_USHORT ((PUSHORT)(m_pBusMasterBase + ulOffset));
+
+    DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%4x = 0x%4p", usValue,
+                   m_pBusMasterBase + ulOffset));
+
+    return usValue;
+}
+
+/*****************************************************************************
+ * CAC97AdapterCommon::ReadBMControlRegister32
+ *****************************************************************************
+ * Read a dword (ULONG) from BusMaster Control register.
+ */
+STDMETHODIMP_(ULONG) CAC97AdapterCommon::ReadBMControlRegister32
+(
+    IN  ULONG ulOffset
+)
+{
+    ULONG ulValue = ULONG(-1);
+
+    DOUT (DBG_PRINT, ("[CAC97AdapterCommon::ReadBMControlRegister32]"));
+
+    ulValue = READ_PORT_ULONG ((PULONG)(m_pBusMasterBase + ulOffset));
+
+    DOUT (DBG_REGS, ("ReadBMControlRegister read 0x%8x = 0x%4p", ulValue,
+                   m_pBusMasterBase + ulOffset));
+
+    return ulValue;
+}
+
diff --git a/drivers/wdm/audio/drivers/ac97/common.h
b/drivers/wdm/audio/drivers/ac97/common.h
new file mode 100644
index 00000000000..8b5162ddffa
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/common.h
@@ -0,0 +1,387 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file common.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _COMMON_H_
+#define _COMMON_H_
+
+#include "shared.h"
+
+/*****************************************************************************
+ * Structs
+ *****************************************************************************
+ */
+
+//
+// Contains pin and node configuration of the AC97 codec.
+//
+typedef struct
+{
+    // For nodes.
+    struct
+    {
+        BOOL    bNodeConfig;
+    } Nodes[NODEC_TOP_ELEMENT];
+
+    // For pins.
+    struct
+    {
+        BOOL    bPinConfig;
+        PWCHAR  sRegistryName;
+    } Pins[PINC_TOP_ELEMENT];
+} tHardwareConfig;
+
+//
+// We cache the AC97 registers.  Additionally, we want some default values
+// when the driver comes up first that are different from the HW default
+// values. The string in the structure is the name of the registry entry
+// that can be used instead of the hard coded default value.
+//
+typedef struct
+{
+    WORD    wCache;
+    WORD    wFlags;
+    PWCHAR  sRegistryName;
+    WORD    wWantedDefault;
+} tAC97Registers;
+
+
+/*****************************************************************************
+ * Constants
+ *****************************************************************************
+ */
+
+//
+// This means shadow register are to be read at least once to initialize.
+//
+const WORD SHREG_INVALID = 0x0001;
+
+//
+// This means shadow register should be overwritten with default value at
+// driver init.
+//
+const WORD SHREG_INIT = 0x0002;
+
+//
+// This constant is used to prevent register caching.
+//
+const WORD SHREG_NOCACHE = 0x0004;
+
+
+/*****************************************************************************
+ * Classes
+ *****************************************************************************
+ */
+
+/*****************************************************************************
+ * CAC97AdapterCommon
+ *****************************************************************************
+ * This is the common adapter object shared by all miniports to access the
+ * hardware.
+ */
+class CAC97AdapterCommon : public IAC97AdapterCommon,
+                       public IAdapterPowerManagement,
+                       public CUnknown
+{
+private:
+    static tAC97Registers m_stAC97Registers[64];    // The shadow registers.
+    static tHardwareConfig m_stHardwareConfig;      // The hardware configuration.
+    PDEVICE_OBJECT m_pDeviceObject;     // Device object used for registry access.
+    PWORD          m_pCodecBase;        // The AC97 I/O port address.
+    PUCHAR         m_pBusMasterBase;    // The Bus Master base address.
+    BOOL           m_bDirectRead;       // Used during init time.
+    DEVICE_POWER_STATE   m_PowerState;  // Current power state of the device.
+    PAC97MINIPORTTOPOLOGY m_Topology;    // Miniport Topology pointer.
+
+
+    /*************************************************************************
+     * CAC97AdapterCommon methods
+     *************************************************************************
+     */
+
+    //
+    // Resets AC97 audio registers.
+    //
+    NTSTATUS InitAC97 (void);
+
+    //
+    // Checks for existance of registers.
+    //
+    NTSTATUS ProbeHWConfig (void);
+
+    //
+    // Checks for 6th bit support in the volume control.
+    //
+    NTSTATUS Check6thBitSupport (IN AC97Register, IN TopoNodeConfig);
+
+    //
+    // Returns true if you should disable the input or output pin.
+    //
+    BOOL DisableAC97Pin (IN  TopoPinConfig);
+
+#if (DBG)
+    //
+    // Dumps the probed configuration.
+    //
+    void DumpConfig (void);
+#endif
+
+    //
+    // Sets AC97 registers to default.
+    //
+    NTSTATUS SetAC97Default (void);
+
+    //
+    // Aquires the semaphore for AC97 register access.
+    //
+    NTSTATUS AcquireCodecSemiphore (void);
+
+    //
+    // Checks if there is a AC97 link between AC97 and codec.
+    //
+    NTSTATUS PrimaryCodecReady (void);
+
+    //
+    // Powers up the Codec.
+    //
+    NTSTATUS PowerUpCodec (void);
+
+    //
+    // Saves native audio bus master control registers values to be used
+    // upon suspend.
+    //
+    NTSTATUS ReadNABMCtrlRegs (void);
+
+    //
+    // Writes back native audio bus master control resgister to be used upon
+    // resume.
+    //
+    NTSTATUS RestoreNABMCtrlRegs (void);
+
+public:
+    DECLARE_STD_UNKNOWN();
+    DEFINE_STD_CONSTRUCTOR(CAC97AdapterCommon);
+    ~CAC97AdapterCommon();
+
+    /*************************************************************************
+     * IAdapterPowerManagement methods
+     *************************************************************************
+     */
+    IMP_IAdapterPowerManagement;
+
+    /*************************************************************************
+     * IAC97AdapterCommon methods
+     *************************************************************************
+     */
+
+    //
+    // Initialize the adapter common object -> initialize and probe HW.
+    //
+    STDMETHODIMP_(NTSTATUS) Init
+    (
+        IN  PRESOURCELIST ResourceList,
+        IN  PDEVICE_OBJECT DeviceObject
+    );
+
+    //
+    // Returns if pin exists.
+    //
+    STDMETHODIMP_(BOOL) GetPinConfig
+    (
+        IN  TopoPinConfig pin
+    )
+    {
+        return m_stHardwareConfig.Pins[pin].bPinConfig;
+    };
+
+    //
+    // Sets the pin configuration (exist/not exist).
+    //
+    STDMETHODIMP_(void) SetPinConfig
+    (
+        IN  TopoPinConfig pin,
+        IN  BOOL config
+    )
+    {
+        m_stHardwareConfig.Pins[pin].bPinConfig = config;
+    };
+
+    //
+    // Return if node exists.
+    //
+    STDMETHODIMP_(BOOL) GetNodeConfig
+    (
+        IN  TopoNodeConfig node
+    )
+    {
+        return m_stHardwareConfig.Nodes[node].bNodeConfig;
+    };
+
+    //
+    // Sets the node configuration (exist/not exist).
+    //
+    STDMETHODIMP_(void) SetNodeConfig
+    (
+        IN  TopoNodeConfig node,
+        IN  BOOL config
+    )
+    {
+        m_stHardwareConfig.Nodes[node].bNodeConfig = config;
+    };
+
+    //
+    // Returns the AC97 register that is assosiated with the node.
+    //
+    STDMETHODIMP_(AC97Register) GetNodeReg
+    (   IN  TopoNodes node
+    )
+    {
+        return stMapNodeToReg[node].reg;
+    };
+
+    //
+    // Returns the AC97 register mask that is assosiated with the node.
+    //
+    STDMETHODIMP_(WORD) GetNodeMask
+    (
+        IN  TopoNodes node
+    )
+    {
+        return stMapNodeToReg[node].mask;
+    };
+
+    //
+    // Reads a AC97 register.
+    //
+    STDMETHODIMP_(NTSTATUS) ReadCodecRegister
+    (
+        _In_range_(0, AC97REG_INVALID)  AC97Register Register,
+        _Out_ PWORD wData
+    );
+
+    //
+    // Writes a AC97 register.
+    //
+    STDMETHODIMP_(NTSTATUS) WriteCodecRegister
+    (
+        _In_range_(0, AC97REG_INVALID)  AC97Register Register,
+        _In_  WORD wData,
+        _In_  WORD wMask
+    );
+
+    //
+    // Reads a 8 bit AC97 bus master register.
+    //
+    STDMETHODIMP_(UCHAR) ReadBMControlRegister8
+    (
+        IN  ULONG ulOffset
+    );
+
+    //
+    // Reads a 16 bit AC97 bus master register.
+    //
+    STDMETHODIMP_(USHORT) ReadBMControlRegister16
+    (
+        IN  ULONG ulOffset
+    );
+
+    //
+    // Reads a 32 bit AC97 bus master register.
+    //
+    STDMETHODIMP_(ULONG) ReadBMControlRegister32
+    (
+        IN  ULONG ulOffset
+    );
+
+    //
+    // Writes a 8 bit AC97 bus master register.
+    //
+    STDMETHODIMP_(void) WriteBMControlRegister
+    (
+        IN  ULONG ulOffset,
+        IN  UCHAR Value
+    );
+
+    //
+    // writes a 16 bit AC97 bus master register.
+    //
+    STDMETHODIMP_(void) WriteBMControlRegister
+    (
+        IN  ULONG ulOffset,
+        IN  USHORT Value
+    );
+
+    // writes a 32 bit AC97 bus master register.
+    STDMETHODIMP_(void) WriteBMControlRegister
+    (
+        IN  ULONG ulOffset,
+        IN  ULONG Value
+    );
+
+    //
+    // Write back cached mixer values to codec registers.
+    //
+    STDMETHODIMP_(NTSTATUS) RestoreCodecRegisters();
+
+    //
+    // Programs a sample rate.
+    //
+    STDMETHODIMP_(NTSTATUS) ProgramSampleRate
+    (
+        IN  AC97Register Register,
+        IN  DWORD dwSampleRate
+    );
+
+    //
+    // Stores the topology pointer. Used for DRM only.
+    //
+    STDMETHODIMP_(void) SetMiniportTopology (PAC97MINIPORTTOPOLOGY topo)
+    {
+        m_Topology = topo;
+    };
+
+    //
+    // Returns the topology pointer. Used for DRM only.
+    //
+    STDMETHODIMP_(PAC97MINIPORTTOPOLOGY) GetMiniportTopology (void)
+    {
+        return m_Topology;
+    };
+
+    //
+    // This function reads the default channel config and is called only by the
+    // wave miniport.
+    //
+    STDMETHODIMP_(void) ReadChannelConfigDefault
+    (
+        PDWORD  pdwChannelConfig,
+        PWORD   pwChannels
+    );
+
+    //
+    // This function writes the default channel config and is called only by the
+    // wave miniport.
+    //
+    STDMETHODIMP_(void) WriteChannelConfigDefault
+    (
+        DWORD   dwChannelConfig
+    );
+
+    /*************************************************************************
+     * Friends
+     *************************************************************************
+     */
+
+    friend NTSTATUS NewAdapterCommon
+    (
+        OUT PADAPTERCOMMON *OutAdapterCommon,
+        IN  PRESOURCELIST ResourceList
+    );
+};
+
+#endif  //_COMMON_H_
diff --git a/drivers/wdm/audio/drivers/ac97/debug.h
b/drivers/wdm/audio/drivers/ac97/debug.h
new file mode 100644
index 00000000000..78c5335c16d
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/debug.h
@@ -0,0 +1,93 @@
+/********************************************************************************
+**    Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file debug.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _DEBUG_H_
+#define _DEBUG_H_
+
+//
+// Modified version of ksdebug.h to support runtime debug level changes.
+//
+const int DBG_NONE     = 0x00000000;
+const int DBG_PRINT    = 0x00000001; // Blabla. Function entries for example
+const int DBG_WARNING  = 0x00000002; // warning level
+const int DBG_ERROR    = 0x00000004; // this doesn't generate a breakpoint
+
+// specific debug output; you don't have to enable DBG_PRINT for this.
+const int DBG_STREAM   = 0x00000010; // Enables stream output.
+const int DBG_POWER    = 0x00000020; // Enables power management output.
+const int DBG_DMA      = 0x00000040; // Enables DMA engine output.
+const int DBG_REGS     = 0x00000080; // Enables register outout.
+const int DBG_PROBE    = 0x00000100; // Enables hardware probing output.
+const int DBG_SYSINFO  = 0x00000200; // Enables system info output.
+const int DBG_VSR      = 0x00000400; // Enables variable sample rate output.
+const int DBG_PROPERTY = 0x00000800; // Enables property handler output
+const int DBG_POSITION = 0x00001000; // Enables printing of position on GetPosition
+const int DBG_PINS     = 0x10000000; // Enables dump of created pins in topology
+const int DBG_NODES    = 0x20000000; // Enables dump of created nodes in topology
+const int DBG_CONNS    = 0x40000000; // Enables dump of the connections in topology
+
+const int DBG_ALL      = 0xFFFFFFFF;
+
+//
+// The default statements that will print are warnings (DBG_WARNING) and
+// errors (DBG_ERROR).
+//
+const int DBG_DEFAULT = 0x00000004;  // Errors only.
+
+
+//
+// Define global debug variable.
+//
+#ifdef DEFINE_DEBUG_VARS
+#if (DBG)
+unsigned long ulDebugOut = DBG_DEFAULT;
+#endif
+
+#else // !DEFINED_DEBUG_VARS
+#if (DBG)
+extern unsigned long ulDebugOut;
+#endif
+#endif
+
+
+//
+// Define the print statement.
+//
+#if defined(__cplusplus)
+extern "C" {
+#endif // #if defined(__cplusplus)
+
+//
+// DBG is 1 in checked builds
+//
+#if (DBG)
+#define DOUT(lvl, strings)          \
+    if ((lvl) & ulDebugOut)         \
+    {                               \
+        DbgPrint(STR_MODULENAME);   \
+        DbgPrint  strings;          \
+        DbgPrint("\n");             \
+    }
+
+#define BREAK()                     \
+    DbgBreakPoint()
+
+#else // if (!DBG)
+#define DOUT(lvl, strings)
+#define BREAK()
+#endif // !DBG
+
+
+#if defined(__cplusplus)
+}
+#endif // #if defined(__cplusplus)
+
+
+
+#endif
diff --git a/drivers/wdm/audio/drivers/ac97/guids.h
b/drivers/wdm/audio/drivers/ac97/guids.h
new file mode 100644
index 00000000000..8230403da81
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/guids.h
@@ -0,0 +1,188 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file guids.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _GUIDS_H_
+#define _GUIDS_H_
+
+
+/*****************************************************************************
+ * GUIDs
+ *****************************************************************************
+ * GUIDs for friendly names.
+ */
+
+// PHONE Volume Name
+#define STATIC_MYKSNAME_PHONE_VOLUME\
+    0x0A8C1A87, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A87-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_PHONE_VOLUME);
+#define MYKSNAME_PHONE_VOLUME DEFINE_GUIDNAMED(MYKSNAME_PHONE_VOLUME)
+
+// PHONE Mute Name
+#define STATIC_MYKSNAME_PHONE_MUTE\
+    0x0A8C1A88, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A88-42B0-11D2-95D2-00C04FB925D3", MYKSNAME_PHONE_MUTE);
+#define MYKSNAME_PHONE_MUTE DEFINE_GUIDNAMED(MYKSNAME_PHONE_MUTE)
+
+// LINEIN Mute Name
+#define STATIC_MYKSNAME_LINEIN_MUTE\
+    0x0A8C1A91, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A91-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_LINEIN_MUTE);
+#define MYKSNAME_LINEIN_MUTE DEFINE_GUIDNAMED(MYKSNAME_LINEIN_MUTE)
+
+// Main Mix Name
+#define STATIC_MYKSNAME_MAIN_MIX\
+    0x0A8C1A9B, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A9B-42B0-11D2-95D2-00C04FB925D3", MYKSNAME_MAIN_MIX);
+#define MYKSNAME_MAIN_MIX DEFINE_GUIDNAMED(MYKSNAME_MAIN_MIX)
+
+// 3D Bypass Name
+#define STATIC_MYKSNAME_WAVEOUT_3D_BYPASS\
+    0x0A8C1A9E, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A9E-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_WAVEOUT_3D_BYPASS);
+#define MYKSNAME_WAVEOUT_3D_BYPASS DEFINE_GUIDNAMED(MYKSNAME_WAVEOUT_3D_BYPASS)
+
+// 3D Enable Name
+#define STATIC_MYKSNAME_3D_ENABLE\
+    0x766db5a4, 0x6e94, 0x11d2, 0x9a, 0xde, 0x0, 0xc0, 0x4f, 0x8e, 0xfb, 0x68
+DEFINE_GUIDSTRUCT("766DB5A4-6E94-11d2-9ADE-00C04F8EFB68", MYKSNAME_3D_ENABLE);
+#define MYKSNAME_3D_ENABLE DEFINE_GUIDNAMED(MYKSNAME_3D_ENABLE)
+
+// Beep Mix Name
+#define STATIC_MYKSNAME_BEEP_MIX\
+    0x0A8C1A9F, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1A9F-42B0-11D2-95D2-00C04FB925D3", MYKSNAME_BEEP_MIX);
+#define MYKSNAME_BEEP_MIX DEFINE_GUIDNAMED(MYKSNAME_BEEP_MIX)
+
+// HPOUT Volume Name
+#define STATIC_MYKSNAME_HPOUT_VOLUME\
+    0x0A8C1AA5, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AA5-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_HPOUT_VOLUME);
+#define MYKSNAME_HPOUT_VOLUME DEFINE_GUIDNAMED(MYKSNAME_HPOUT_VOLUME)
+
+// HPOUT Mute Name
+#define STATIC_MYKSNAME_HPOUT_MUTE\
+    0x0A8C1AA6, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AA6-42B0-11D2-95D2-00C04FB925D3", MYKSNAME_HPOUT_MUTE);
+#define MYKSNAME_HPOUT_MUTE DEFINE_GUIDNAMED(MYKSNAME_HPOUT_MUTE)
+
+// MONOOUT Select Name
+#define STATIC_MYKSNAME_MONOOUT_SELECT\
+    0x0A8C1AA9, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AA9-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_MONOOUT_SELECT);
+#define MYKSNAME_MONOOUT_SELECT DEFINE_GUIDNAMED(MYKSNAME_MONOOUT_SELECT)
+
+// WAVEIN Select Name
+#define STATIC_MYKSNAME_WAVEIN_SELECT\
+    0x0A8C1AAE, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AAE-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_WAVEIN_SELECT);
+#define MYKSNAME_WAVEIN_SELECT DEFINE_GUIDNAMED(MYKSNAME_WAVEIN_SELECT)
+
+// MASTER INPUT Volume Name
+#define STATIC_MYKSNAME_MASTER_INPUT_VOLUME\
+    0x0A8C1AAF, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AAF-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_MASTER_INPUT_VOLUME);
+#define MYKSNAME_MASTER_INPUT_VOLUME DEFINE_GUIDNAMED(MYKSNAME_MASTER_INPUT_VOLUME)
+
+// MASTER INPUT Mute Name
+#define STATIC_MYKSNAME_MASTER_INPUT_MUTE\
+    0x0A8C1AB0, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AB0-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_MASTER_INPUT_MUTE);
+#define MYKSNAME_MASTER_INPUT_MUTE DEFINE_GUIDNAMED(MYKSNAME_MASTER_INPUT_MUTE)
+
+// MICIN Volume Name
+#define STATIC_MYKSNAME_MICIN_VOLUME\
+    0x0A8C1AB2, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AB2-42B0-11D2-95D2-00C04FB925D3",
MYKSNAME_MICIN_VOLUME);
+#define MYKSNAME_MICIN_VOLUME DEFINE_GUIDNAMED(MYKSNAME_MICIN_VOLUME)
+
+// MICIN Mute Name
+#define STATIC_MYKSNAME_MICIN_MUTE\
+    0x0A8C1AB3, 0x42B0, 0x11D2, 0x95, 0xD2, 0x00, 0xC0, 0x4F, 0xB9, 0x25, 0xD3
+DEFINE_GUIDSTRUCT("0A8C1AB3-42B0-11D2-95D2-00C04FB925D3", MYKSNAME_MICIN_MUTE);
+#define MYKSNAME_MICIN_MUTE DEFINE_GUIDNAMED(MYKSNAME_MICIN_MUTE)
+
+// Simulated Stereo Name
+#define STATIC_MYKSNAME_SIMUL_STEREO\
+    0xB3AD50B5, 0x3849, 0x4983, 0xAD, 0xD7, 0x25, 0xE6, 0x26, 0x8F, 0x91, 0x2D
+DEFINE_GUIDSTRUCT("B3AD50B5-3849-4983-ADD7-25E6268F912D",
MYKSNAME_SIMUL_STEREO);
+#define MYKSNAME_SIMUL_STEREO DEFINE_GUIDNAMED(MYKSNAME_SIMUL_STEREO)
+
+// Surround Volume Name
+#define STATIC_MYKSNAME_SURROUND_VOLUME\
+    0xa4b68ba4, 0x6958, 0x4ab4, 0xbb, 0x1, 0xe2, 0x3c, 0x6f, 0x2, 0x7c, 0x88
+DEFINE_GUIDSTRUCT("A4B68BA4-6958-4ab4-BB01-E23C6F027C88",
MYKSNAME_SURROUND_VOLUME);
+#define MYKSNAME_SURROUND_VOLUME DEFINE_GUIDNAMED(MYKSNAME_SURROUND_VOLUME)
+
+// Surround Mute Name
+#define STATIC_MYKSNAME_SURROUND_MUTE\
+    0x22654fbc, 0xac8f, 0x4224, 0xb1, 0x9f, 0xd8, 0x58, 0xd2, 0xe1, 0xb, 0xdd
+DEFINE_GUIDSTRUCT("22654FBC-AC8F-4224-B19F-D858D2E10BDD",
MYKSNAME_SURROUND_MUTE);
+#define MYKSNAME_SURROUND_MUTE DEFINE_GUIDNAMED(MYKSNAME_SURROUND_MUTE)
+
+// Center Volume Name
+#define STATIC_MYKSNAME_CENTER_VOLUME\
+    0x9b0f1946, 0xabd2, 0x47a8, 0xa7, 0x78, 0xbb, 0x86, 0xcd, 0xe1, 0xa1, 0x67
+DEFINE_GUIDSTRUCT("9B0F1946-ABD2-47a8-A778-BB86CDE1A167",
MYKSNAME_CENTER_VOLUME);
+#define MYKSNAME_CENTER_VOLUME DEFINE_GUIDNAMED(MYKSNAME_CENTER_VOLUME)
+
+// Center Mute Name
+#define STATIC_MYKSNAME_CENTER_MUTE\
+    0xbeef51ed, 0x1041, 0x43f8, 0x9b, 0x96, 0x58, 0x63, 0xd0, 0xa9, 0x34, 0x2d
+DEFINE_GUIDSTRUCT("BEEF51ED-1041-43f8-9B96-5863D0A9342D",
MYKSNAME_CENTER_MUTE);
+#define MYKSNAME_CENTER_MUTE DEFINE_GUIDNAMED(MYKSNAME_CENTER_MUTE)
+
+// LFE Volume Name
+#define STATIC_MYKSNAME_LFE_VOLUME\
+    0x455fa6f2, 0x21ec, 0x4df4, 0xb1, 0xe4, 0x31, 0x55, 0x20, 0x97, 0x97, 0xf3
+DEFINE_GUIDSTRUCT("455FA6F2-21EC-4df4-B1E4-3155209797F3", MYKSNAME_LFE_VOLUME);
+#define MYKSNAME_LFE_VOLUME DEFINE_GUIDNAMED(MYKSNAME_LFE_VOLUME)
+
+// LFE Mute Name
+#define STATIC_MYKSNAME_LFE_MUTE\
+    0x4a4d9210, 0xc780, 0x4768, 0xbf, 0xd2, 0x52, 0x5f, 0xdb, 0xf4, 0xfc, 0xb4
+DEFINE_GUIDSTRUCT("4A4D9210-C780-4768-BFD2-525FDBF4FCB4", MYKSNAME_LFE_MUTE);
+#define MYKSNAME_LFE_MUTE DEFINE_GUIDNAMED(MYKSNAME_LFE_MUTE)
+
+// Front Volume Name
+#define STATIC_MYKSNAME_FRONT_VOLUME\
+    0x9f4801bd, 0xf746, 0x4c7a, 0x8a, 0x9d, 0xf6, 0xe9, 0x90, 0x4, 0xcc, 0x98
+DEFINE_GUIDSTRUCT("9F4801BD-F746-4c7a-8A9D-F6E99004CC98",
MYKSNAME_FRONT_VOLUME);
+#define MYKSNAME_FRONT_VOLUME DEFINE_GUIDNAMED(MYKSNAME_FRONT_VOLUME)
+
+// Front Mute Name
+#define STATIC_MYKSNAME_FRONT_MUTE\
+    0xc8e03b2a, 0xebd9, 0x4554, 0xa7, 0x50, 0x8e, 0x44, 0x72, 0x75, 0xa, 0x5b
+DEFINE_GUIDSTRUCT("C8E03B2A-EBD9-4554-A750-8E4472750A5B", MYKSNAME_FRONT_MUTE);
+#define MYKSNAME_FRONT_MUTE DEFINE_GUIDNAMED(MYKSNAME_FRONT_MUTE)
+
+// Surround Pin Name
+#define STATIC_MYKSNAME_SURROUND\
+    0x81fbb14b, 0x1bee, 0x4bf5, 0x92, 0xee, 0xff, 0xc4, 0xf7, 0x5f, 0x32, 0x6d
+DEFINE_GUIDSTRUCT("81FBB14B-1BEE-4bf5-92EE-FFC4F75F326D", MYKSNAME_SURROUND);
+#define MYKSNAME_SURROUND DEFINE_GUIDNAMED(MYKSNAME_SURROUND)
+
+// Center Pin Name
+#define STATIC_MYKSNAME_CENTER\
+    0x2d97372f, 0x9cf6, 0x4fd6, 0x9e, 0x56, 0xc6, 0x8b, 0xac, 0xdf, 0x36, 0xd
+DEFINE_GUIDSTRUCT("2D97372F-9CF6-4fd6-9E56-C68BACDF360D", MYKSNAME_CENTER);
+#define MYKSNAME_CENTER DEFINE_GUIDNAMED(MYKSNAME_CENTER)
+
+// LFE Pin Name
+#define STATIC_MYKSNAME_LFE\
+    0xb60c4274, 0x3bfd, 0x430b, 0x83, 0x64, 0xd9, 0x47, 0xe7, 0xd3, 0x4, 0xb1
+DEFINE_GUIDSTRUCT("B60C4274-3BFD-430b-8364-D947E7D304B1", MYKSNAME_LFE);
+#define MYKSNAME_LFE DEFINE_GUIDNAMED(MYKSNAME_LFE)
+
+// Front Pin Name
+#define STATIC_MYKSNAME_FRONT\
+    0x70395e2, 0xbe7c, 0x4b4d, 0xb5, 0x29, 0x40, 0xcb, 0x9b, 0xfc, 0xf9, 0x95
+DEFINE_GUIDSTRUCT("070395E2-BE7C-4b4d-B529-40CB9BFCF995", MYKSNAME_FRONT);
+#define MYKSNAME_FRONT DEFINE_GUIDNAMED(MYKSNAME_FRONT)
+
+#endif  // _GUIDS_H_
diff --git a/drivers/wdm/audio/drivers/ac97/ichreg.h
b/drivers/wdm/audio/drivers/ac97/ichreg.h
new file mode 100644
index 00000000000..504a2260c5a
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/ichreg.h
@@ -0,0 +1,107 @@
+/********************************************************************************
+**    Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
+**
+**       Portions Copyright (c) 1998-1999 Intel Corporation
+**
+********************************************************************************/
+
+/* The file ichreg.h was reviewed by LCA in June 2011 and is acceptable for use by
Microsoft. */
+
+#ifndef _ICHREG_H_
+#define _ICHREG_H_
+
+// We define the offsets like PI_BDBAR as ULONG (instead of UCHAR) for run
+// time efficiency.
+
+// CoDec AC97 register space offsets
+const ULONG PRIMARY_CODEC   = 0x00;
+const ULONG SECONDARY_CODEC = 0x80;
+
+// Native audio bus master control registers (offsets)
+const ULONG PI_BDBAR        = 0x00; // PCM In Buffer Descriptor Base Address Register
+const ULONG PI_CIV          = 0x04; // PCM In Current Index Value
+const ULONG PI_LVI          = 0x05; // PCM In Last Valid Index
+const ULONG PI_SR           = 0x06; // PCM In Status Register
+const ULONG PI_PICB         = 0x08; // PCM In Position In Current Buffer
+const ULONG PI_PIV          = 0x0A; // PCM In Prefetch Index Value
+const ULONG PI_CR           = 0x0B; // PCM In Control Register
+const ULONG PO_BDBAR        = 0x10; // PCM Out Buffer Descriptor Base Address Register
+const ULONG PO_CIV          = 0x14; // PCM Out Current Index Value
+const ULONG PO_LVI          = 0x15; // PCM Out Last Valid Index
+const ULONG PO_SR           = 0x16; // PCM Out Status Register
+const ULONG PO_PICB         = 0x18; // PCM Out Position In Current Buffer
+const ULONG PO_PIV          = 0x1A; // PCM Out Prefetch Index Value
+const ULONG PO_CR           = 0x1B; // PCM Out Control Register
+const ULONG MC_BDBAR        = 0x20; // Mic In Buffer Descriptor Base Address Register
+const ULONG MC_CIV          = 0x24; // Mic In Current Index Value
+const ULONG MC_LVI          = 0x25; // Mic In Last Valid Index
+const ULONG MC_SR           = 0x26; // Mic In Status Register
+const ULONG MC_PICB         = 0x28; // Mic In Position In Current Buffer
+const ULONG MC_PIV          = 0x2A; // Mic In Prefetch Index Value
+const ULONG MC_CR           = 0x2B; // Mic In Control Register
+const ULONG GLOB_CNT        = 0x2C; // Global Control
+const ULONG GLOB_STA        = 0x30; // Global Status
+const ULONG CAS             = 0x34; // Codec Access Semiphore
+
+// Defines for relative accesses (offsets)
+const ULONG X_PI_BASE       = 0x00; // PCM In Base
+const ULONG X_PO_BASE       = 0x10; // PCM Out Base
+const ULONG X_MC_BASE       = 0x20; // Mic In Base
+const ULONG X_BDBAR         = 0x00; // Buffer Descriptor Base Address Register
+const ULONG X_CIV           = 0x04; // Current Index Value
+const ULONG X_LVI           = 0x05; // Last Valid Index
+const ULONG X_SR            = 0x06; // Status Register
+const ULONG X_PICB          = 0x08; // Position In Current Buffer
+const ULONG X_PIV           = 0x0A; // Prefetch Index Value
+const ULONG X_CR            = 0x0B; // Control Register
+
+// Bits defined in satatus register (*_SR)
+const USHORT SR_FIFOE       = 0x0010;   // FIFO error
+const USHORT SR_BCIS        = 0x0008;   // Buffer Completeion Interrupt Status
+const USHORT SR_LVBCI       = 0x0004;   // Last Valid Buffer Completion Interrupt
+const USHORT SR_CELV        = 0x0002;   // Last Valid Buffer Completion Interrupt
+
+// Global Control bit defines (GLOB_CNT)
+const ULONG GLOB_CNT_PCM6   = 0x00200000;   // 6 Channel Mode bit
+const ULONG GLOB_CNT_PCM4   = 0x00100000;   // 4 Channel Mode bit
+const ULONG GLOB_CNT_SRIE   = 0x00000020;   // Secondary Resume Interrupt Enable
+const ULONG GLOB_CNT_PRIE   = 0x00000010;   // Primary Resume Interrupt Enable
+const ULONG GLOB_CNT_ACLOFF = 0x00000008;   // ACLINK Off
+const ULONG GLOB_CNT_WARM   = 0x00000004;   // AC97 Warm Reset
+const ULONG GLOB_CNT_COLD   = 0x00000002;   // AC97 Cold Reset
+const ULONG GLOB_CNT_GIE    = 0x00000001;   // GPI Interrupt Enable
+
+// Global Status bit defines (GLOB_STA)
+const ULONG GLOB_STA_MC6    = 0x00200000;   // Multichannel Capability 6 channel
+const ULONG GLOB_STA_MC4    = 0x00100000;   // Multichannel Capability 4 channel
+const ULONG GLOB_STA_MD3    = 0x00020000;   // Modem Power Down Semiphore
+const ULONG GLOB_STA_AD3    = 0x00010000;   // Audio Power Down Semiphore
+const ULONG GLOB_STA_RCS    = 0x00008000;   // Read Completion Status
+const ULONG GLOB_STA_B3S12  = 0x00004000;   // Bit 3 Slot 12
+const ULONG GLOB_STA_B2S12  = 0x00002000;   // Bit 2 Slot 12
+const ULONG GLOB_STA_B1S12  = 0x00001000;   // Bit 1 Slot 12
+const ULONG GLOB_STA_SRI    = 0x00000800;   // Secondary Resume Interrupt
+const ULONG GLOB_STA_PRI    = 0x00000400;   // Primary Resume Interrupt
+const ULONG GLOB_STA_SCR    = 0x00000200;   // Secondary Codec Ready
+const ULONG GLOB_STA_PCR    = 0x00000100;   // Primary Codec Ready
+const ULONG GLOB_STA_MINT   = 0x00000080;   // Mic In Interrupt
+const ULONG GLOB_STA_POINT  = 0x00000040;   // PCM Out Interrupt
+const ULONG GLOB_STA_PIINT  = 0x00000020;   // PCM In Interrupt
+const ULONG GLOB_STA_MOINT  = 0x00000004;   // Modem Out Interrupt
+
+// CoDec Access Semiphore bit defines (CAS)
+const UCHAR CAS_CAS         = 0x01; // Codec Access Semiphore Bit
+
+// DMA Engine Control Register (*_CR) bit defines
+const UCHAR CR_IOCE         = 0x10; // Interrupt On Completion Enable
+const UCHAR CR_FEIE         = 0x08; // FIFO Error Interrupt Enable
+const UCHAR CR_LVBIE        = 0x04; // Last Valid Buffer Interrupt Enable
+const UCHAR CR_RPBM         = 0x01; // Run/Pause Bus Master
+const UCHAR CR_RR           = 0x02; // Reset Registers (RR)
+
+// BDL policy bits
+const USHORT IOC_ENABLE     = 0x8000;
+const USHORT BUP_SET        = 0x4000;
+
+#endif  //_ICHREG_H_
+
diff --git a/drivers/wdm/audio/drivers/ac97/license.txt
b/drivers/wdm/audio/drivers/ac97/license.txt
new file mode 100644
index 00000000000..9e841e7a26e
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/license.txt
@@ -0,0 +1,21 @@
+    MIT License
+
+    Copyright (c) Microsoft Corporation.
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to
deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all
+    copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE
diff --git a/drivers/wdm/audio/drivers/ac97/miniport.cpp
b/drivers/wdm/audio/drivers/ac97/miniport.cpp
new file mode 100644
index 00000000000..83bb53d9d3c
--- /dev/null
+++ b/drivers/wdm/audio/drivers/ac97/miniport.cpp
@@ -0,0 +1,1462 @@
+// Every debug output has "Modulname text"
+#define STR_MODULENAME "AC97 Miniport: "
+
+//#include "shared.h"
+//#include "miniport.h"
+#include "wavepciminiport.h"
+
+/*****************************************************************************
+ * PinDataRangesPCMStream
+ *****************************************************************************
+ * The next 3 arrays contain information about the data ranges of the pin for
+ * wave capture, wave render and mic capture.
+ * These arrays are filled dynamically by BuildDataRangeInformation().
+ */
+
+static KSDATARANGE_AUDIO PinDataRangesPCMStreamRender[WAVE_SAMPLERATES_TESTED];
+static KSDATARANGE_AUDIO PinDataRangesPCMStreamCapture[WAVE_SAMPLERATES_TESTED];
+static KSDATARANGE_AUDIO PinDataRangesMicStream[MIC_SAMPLERATES_TESTED];
+
+static KSDATARANGE PinDataRangesAnalogBridge[] =
+{
+   {
+      sizeof(KSDATARANGE),
+      0,
+      0,
+      0,
+      STATICGUIDOF(KSDATAFORMAT_TYPE_AUDIO),
+      STATICGUIDOF(KSDATAFORMAT_SUBTYPE_ANALOG),
+      STATICGUIDOF(KSDATAFORMAT_SPECIFIER_NONE)
+   }
+};
+
+/*****************************************************************************
+ * PinDataRangesPointersPCMStream
+ *****************************************************************************
+ * The next 3 arrays contain the pointers to the data range information of
+ * the pin for wave capture, wave render and mic capture.
+ * These arrays are filled dynamically by BuildDataRangeInformation().
+ */
+static PKSDATARANGE PinDataRangePointersPCMStreamRender[WAVE_SAMPLERATES_TESTED];
+static PKSDATARANGE PinDataRangePointersPCMStreamCapture[WAVE_SAMPLERATES_TESTED];
+static PKSDATARANGE PinDataRangePointersMicStream[MIC_SAMPLERATES_TESTED];
+
+/*****************************************************************************
+ * PinDataRangePointerAnalogStream
+ *****************************************************************************
+ * This structure pointers to the data range structures for the wave pins.
+ */
+static PKSDATARANGE PinDataRangePointersAnalogBridge[] =
+{
+    (PKSDATARANGE) PinDataRangesAnalogBridge
+};
+
+
+/*****************************************************************************
+ * Wave Miniport Topology
+ *========================
+ *
+ *                              +-----------+
+ *                              |           |
+ *    Capture (PIN_WAVEIN)  <---|2 --ADC-- 3|<=== (PIN_WAVEIN_BRIDGE)
+ *                              |           |
+ *     Render (PIN_WAVEOUT) --->|0 --DAC-- 1|===> (PIN_WAVEOUT_BRIDGE)
+ *                              |           |
+ *        Mic (PIN_MICIN)   <---|4 --ADC-- 5|<=== (PIN_MICIN_BRIDGE)
+ *                              +-----------+
+ *
+ * Note that the exposed pins (left side) have to be a multiple of 2
+ * since there are some dependencies in the stream object.
+ */
+
+/*****************************************************************************
+ * MiniportPins
+ *****************************************************************************
+ * This structure describes pin (stream) types provided by this miniport.
+ * The field that sets the number of data range entries (SIZEOF_ARRAY) is
+ * overwritten by BuildDataRangeInformation().
+ */
+static PCPIN_DESCRIPTOR MiniportPins[] =
+{
+    // PIN_WAVEOUT
+    {
+        1,1,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersPCMStreamRender),  // DataRangesCount
+            PinDataRangePointersPCMStreamRender,                // DataRanges
+            KSPIN_DATAFLOW_IN,                          // DataFlow
+            KSPIN_COMMUNICATION_SINK,                   // Communication
+            (GUID *) &KSCATEGORY_AUDIO,                 // Category
+            NULL,                                       // Name
+            0                                           // Reserved
+        }
+    },
+
+    // PIN_WAVEOUT_BRIDGE
+    {
+        0,0,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersAnalogBridge),    // DataRangesCount
+            PinDataRangePointersAnalogBridge,                  // DataRanges
+            KSPIN_DATAFLOW_OUT,                         // DataFlow
+            KSPIN_COMMUNICATION_NONE,                   // Communication
+            (GUID *) &KSCATEGORY_AUDIO,                 // Category
+            NULL,                                       // Name
+            0                                           // Reserved
+        }
+    },
+
+    // PIN_WAVEIN
+    {
+        1,1,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersPCMStreamCapture), // DataRangesCount
+            PinDataRangePointersPCMStreamCapture,               // DataRanges
+            KSPIN_DATAFLOW_OUT,                         // DataFlow
+            KSPIN_COMMUNICATION_SINK,                   // Communication
+            (GUID *) &PINNAME_CAPTURE,                  // Category
+            &KSAUDFNAME_RECORDING_CONTROL,              // Name
+            0                                           // Reserved
+        }
+    },
+
+    // PIN_WAVEIN_BRIDGE
+    {
+        0,0,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersAnalogBridge),    // DataRangesCount
+            PinDataRangePointersAnalogBridge,                  // DataRanges
+            KSPIN_DATAFLOW_IN,                          // DataFlow
+            KSPIN_COMMUNICATION_NONE,                   // Communication
+            (GUID *) &KSCATEGORY_AUDIO,                 // Category
+            NULL,                                       // Name
+            0                                           // Reserved
+        }
+    },
+
+    //
+    // The Microphone pins are not used if PINC_MICIN_PRESENT is not set.
+    // To remove them, Init() will reduce the "PinCount" in the
+    // MiniportFilterDescriptor.
+    //
+    // PIN_MICIN
+    {
+        1,1,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersMicStream),// DataRangesCount
+            PinDataRangePointersMicStream,              // DataRanges
+            KSPIN_DATAFLOW_OUT,                         // DataFlow
+            KSPIN_COMMUNICATION_SINK,                   // Communication
+            (GUID *) &KSCATEGORY_AUDIO,                 // Category
+            NULL,                                       // Name
+            0                                           // Reserved
+        }
+    },
+
+    // PIN_MICIN_BRIDGE
+    {
+        0,0,0,  // InstanceCount
+        NULL,   // AutomationTable
+        {       // KsPinDescriptor
+            0,                                          // InterfacesCount
+            NULL,                                       // Interfaces
+            0,                                          // MediumsCount
+            NULL,                                       // Mediums
+            SIZEOF_ARRAY(PinDataRangePointersAnalogBridge),    // DataRangesCount
+            PinDataRangePointersAnalogBridge,                  // DataRanges
+            KSPIN_DATAFLOW_IN,                          // DataFlow
+            KSPIN_COMMUNICATION_NONE,                   // Communication
+            (GUID *) &KSCATEGORY_AUDIO,                 // Category
+            NULL,                                       // Name
+            0                                           // Reserved
+        }
+    }
+};
+
+/*****************************************************************************
+ * PropertiesDAC
+ *****************************************************************************
+ * Properties for the DAC node.
+ */
+static PCPROPERTY_ITEM PropertiesDAC[] =
+{
+    {
+        &KSPROPSETID_Audio,
+        KSPROPERTY_AUDIO_CHANNEL_CONFIG,
+        KSPROPERTY_TYPE_SET,
+        CMiniport::PropertyChannelConfig
+    }
+};
+
+/*****************************************************************************
+ * AutomationVolume
+ *****************************************************************************
+ * Automation table for volume controls.
+ */
+DEFINE_PCAUTOMATION_TABLE_PROP (AutomationDAC, PropertiesDAC);
+
+/*****************************************************************************
+ * TopologyNodes
+ *****************************************************************************
+ * List of nodes.
+ */
+static PCNODE_DESCRIPTOR MiniportNodes[] =
+{
+    // NODE_WAVEOUT_DAC
+    {
+        0,                      // Flags
+        &AutomationDAC,         // AutomationTable
+        &KSNODETYPE_DAC,        // Type
+        NULL                    // Name
+    },
+    // NODE_WAVEIN_ADC
+    {
+        0,                      // Flags
+        NULL,                   // AutomationTable
+        &KSNODETYPE_ADC,        // Type
+        NULL                    // Name
+    },
+    //
+    // The Microphone node is not used if PINC_MICIN_PRESENT is not set.
+    // To remove them, Init() will reduce the "NodeCount" in the
+    // MiniportFilterDescriptor.
+    //
+    //  NODE_MICIN_ADC
+    {
+        0,                      // Flags
+        NULL,                   // AutomationTable
+        &KSNODETYPE_ADC,        // Type
+        NULL                    // Name
+    }
+};
+
+/*****************************************************************************
+ * MiniportConnections
+ *****************************************************************************
+ * This structure identifies the connections between filter pins and
+ * node pins.
+ */
+static PCCONNECTION_DESCRIPTOR MiniportConnections[] =
+{
+    //from_node             from_pin            to_node             to_pin
+    { PCFILTER_NODE,        PIN_WAVEOUT,        NODE_WAVEOUT_DAC,   1},
+    { NODE_WAVEOUT_DAC,     0,                  PCFILTER_NODE,      PIN_WAVEOUT_BRIDGE},
+    { PCFILTER_NODE,        PIN_WAVEIN_BRIDGE,  NODE_WAVEIN_ADC,    1},
+    { NODE_WAVEIN_ADC,      0,                  PCFILTER_NODE,      PIN_WAVEIN},
+    //
+    // The Microphone connection is not used if PINC_MICIN_PRESENT is not set.
+    // To remove them, Init() will reduce the "ConnectionCount" in the
+    // MiniportFilterDescriptor.
+    //
+    { PCFILTER_NODE,        PIN_MICIN_BRIDGE,   NODE_MICIN_ADC,     1},
+    { NODE_MICIN_ADC,       0,                  PCFILTER_NODE,      PIN_MICIN}
+};
+
+/*****************************************************************************
+ * MiniportFilterDescriptor
+ *****************************************************************************
+ * Complete miniport description.
+ * Init() modifies the pin count, node count and connection count in absence
+ * of the MicIn recording line.
+ */
+static PCFILTER_DESCRIPTOR MiniportFilterDescriptor =
+{
+    0,                                  // Version
+    NULL,                               // AutomationTable
+    sizeof(PCPIN_DESCRIPTOR),           // PinSize
+    SIZEOF_ARRAY(MiniportPins),         // PinCount
+    MiniportPins,                       // Pins
+    sizeof(PCNODE_DESCRIPTOR),          // NodeSize
+    SIZEOF_ARRAY(MiniportNodes),        // NodeCount
+    MiniportNodes,                      // Nodes
+    SIZEOF_ARRAY(MiniportConnections),  // ConnectionCount
+    MiniportConnections,                // Connections
+    0,                                  // CategoryCount
+    NULL                                // Categories: NULL->use defaults (audio,
render, capture)
+};
+
+#ifdef _MSC_VER
+#pragma code_seg("PAGE")
+#endif
+/*****************************************************************************
+ * CMiniport::PropertyChannelConfig
+ *****************************************************************************
+ * This is the property handler for KSPROPERTY_AUDIO_CHANNEL_CONFIG of the
+ * DAC node. It sets the channel configuration (how many channels, how user
+ * was setting up the speakers).
+ */
+NTSTATUS CMiniport::PropertyChannelConfig
+(
+    IN      PPCPROPERTY_REQUEST PropertyRequest
+)
+{
+    PAGED_CODE ();
+
+    ASSERT (PropertyRequest);
+
+    DOUT (DBG_PRINT, ("[CMiniport::PropertyChannelConfig]"));
+
+    NTSTATUS        ntStatus = STATUS_INVALID_PARAMETER;
+
+    // The major target is the object pointer to the wave miniport.
+    // HACK ALERT - unsafe pointer cast - HACK ALERT
+    CMiniport *that = (CMiniport *)(CMiniportWaveICH*)
+        (PMINIPORTWAVEPCI)PropertyRequest->MajorTarget;
+
+    ASSERT (that);
+
+    // We only have a set defined.
+    if (PropertyRequest->Verb & KSPROPERTY_TYPE_SET)
+    {
+        // validate buffer size.
+        if (PropertyRequest->ValueSize < sizeof(LONG))
+            return ntStatus;
+
+        // The "Value" is the input buffer with the channel config.
+        if (PropertyRequest->Value)
+        {
+            // We can accept different channel configurations, depending
+            // on the number of channels we can play.
+            if (that->AdapterCommon->GetPinConfig (PINC_SURROUND_PRESENT))
+            {
+                if (that->AdapterCommon->GetPinConfig (PINC_CENTER_LFE_PRESENT))
+                {
+                    // we accept 5.1
+                    if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_5POINT1)
+                    {
+                        that->m_dwChannelMask =  *(PLONG)PropertyRequest->Value;
+                        that->m_wChannels = 6;
+                        that->AdapterCommon->WriteChannelConfigDefault
(that->m_dwChannelMask);
+                        ntStatus = STATUS_SUCCESS;
+                    }
+                }
+
+                // accept also surround or quad.
+                if ((*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_QUAD) ||
+                    (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_SURROUND))
+                {
+                    that->m_dwChannelMask =  *(PLONG)PropertyRequest->Value;
+                    that->m_wChannels = 4;
+                    that->AdapterCommon->WriteChannelConfigDefault
(that->m_dwChannelMask);
+                    ntStatus = STATUS_SUCCESS;
+                }
+            }
+
+            // accept also stereo speakers.
+            if (*(PLONG)PropertyRequest->Value == KSAUDIO_SPEAKER_STEREO)
+            {
+                that->m_dwChannelMask =  *(PLONG)PropertyRequest->Value;
+                that->m_wChannels = 2;
+                that->AdapterCommon->WriteChannelConfigDefault
(that->m_dwChannelMask);
+                ntStatus = STATUS_SUCCESS;
+            }
+        }
+    }
+
+    return ntStatus;
+}
+
+
+/*****************************************************************************
+ * CMiniport::BuildDataRangeInformation
+ *****************************************************************************
+ * This function dynamically build the data range information for the pins.
+ * It also connects the static arrays with the data range information
+ * structure.
+ * If this function returns with an error the miniport should be destroyed.
+ *
+ * To build the data range information, we test the most popular sample rates,
... 10011 lines suppressed ...