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 ...