mirror of
https://github.com/reactos/reactos.git
synced 2025-07-07 05:01:23 +00:00
[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@gmail.com>
This commit is contained in:
parent
0944f808f8
commit
9c79a7982b
35 changed files with 14739 additions and 0 deletions
|
@ -1,2 +1,3 @@
|
||||||
|
|
||||||
|
add_subdirectory(ac97)
|
||||||
add_subdirectory(CMIDriver)
|
add_subdirectory(CMIDriver)
|
||||||
|
|
30
drivers/wdm/audio/drivers/ac97/CMakeLists.txt
Normal file
30
drivers/wdm/audio/drivers/ac97/CMakeLists.txt
Normal file
|
@ -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)
|
482
drivers/wdm/audio/drivers/ac97/ac97.inf
Normal file
482
drivers/wdm/audio/drivers/ac97/ac97.inf
Normal file
|
@ -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"
|
24
drivers/wdm/audio/drivers/ac97/ac97.rc
Normal file
24
drivers/wdm/audio/drivers/ac97/ac97.rc
Normal file
|
@ -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"
|
||||||
|
|
170
drivers/wdm/audio/drivers/ac97/ac97reg.h
Normal file
170
drivers/wdm/audio/drivers/ac97/ac97reg.h
Normal file
|
@ -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_
|
583
drivers/wdm/audio/drivers/ac97/adapter.cpp
Normal file
583
drivers/wdm/audio/drivers/ac97/adapter.cpp
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
71
drivers/wdm/audio/drivers/ac97/adapter.h
Normal file
71
drivers/wdm/audio/drivers/ac97/adapter.h
Normal file
|
@ -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_
|
2309
drivers/wdm/audio/drivers/ac97/common.cpp
Normal file
2309
drivers/wdm/audio/drivers/ac97/common.cpp
Normal file
File diff suppressed because it is too large
Load diff
387
drivers/wdm/audio/drivers/ac97/common.h
Normal file
387
drivers/wdm/audio/drivers/ac97/common.h
Normal file
|
@ -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_
|
93
drivers/wdm/audio/drivers/ac97/debug.h
Normal file
93
drivers/wdm/audio/drivers/ac97/debug.h
Normal file
|
@ -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
|
188
drivers/wdm/audio/drivers/ac97/guids.h
Normal file
188
drivers/wdm/audio/drivers/ac97/guids.h
Normal file
|
@ -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_
|
107
drivers/wdm/audio/drivers/ac97/ichreg.h
Normal file
107
drivers/wdm/audio/drivers/ac97/ichreg.h
Normal file
|
@ -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_
|
||||||
|
|
21
drivers/wdm/audio/drivers/ac97/license.txt
Normal file
21
drivers/wdm/audio/drivers/ac97/license.txt
Normal file
|
@ -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
|
1462
drivers/wdm/audio/drivers/ac97/miniport.cpp
Normal file
1462
drivers/wdm/audio/drivers/ac97/miniport.cpp
Normal file
File diff suppressed because it is too large
Load diff
145
drivers/wdm/audio/drivers/ac97/miniport.h
Normal file
145
drivers/wdm/audio/drivers/ac97/miniport.h
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
#ifndef _MINIPORT_H_
|
||||||
|
#define _MINIPORT_H_
|
||||||
|
|
||||||
|
#ifndef PPORT_
|
||||||
|
#define PPORT_ PPORT
|
||||||
|
#define PPORTSTREAM_ PUNKNOWN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Constants
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
const int WAVE_SAMPLERATES_TESTED = 7;
|
||||||
|
const int MIC_SAMPLERATES_TESTED = 4;
|
||||||
|
|
||||||
|
const DWORD dwWaveSampleRates[WAVE_SAMPLERATES_TESTED] =
|
||||||
|
{48000, 44100, 32000, 22050, 16000, 11025, 8000};
|
||||||
|
const DWORD dwMicSampleRates[MIC_SAMPLERATES_TESTED] =
|
||||||
|
{48000, 32000, 16000, 8000};
|
||||||
|
|
||||||
|
const int PIN_WAVEOUT_OFFSET = (PIN_WAVEOUT / 2);
|
||||||
|
const int PIN_WAVEIN_OFFSET = (PIN_WAVEIN / 2);
|
||||||
|
const int PIN_MICIN_OFFSET = (PIN_MICIN / 2);
|
||||||
|
|
||||||
|
class CMiniportStream;
|
||||||
|
class CMiniport : public IPowerNotify
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CMiniportStream *Streams[PIN_MICIN_OFFSET + 1];
|
||||||
|
PPORT_ Port; // Port driver object.
|
||||||
|
PADAPTERCOMMON AdapterCommon; // Adapter common object.
|
||||||
|
PINTERRUPTSYNC InterruptSync; // Interrupt Sync.
|
||||||
|
PDMACHANNEL DmaChannel; // Bus master support.
|
||||||
|
DEVICE_POWER_STATE m_PowerState; // advanced power control.
|
||||||
|
DWORD m_dwChannelMask; // Channel config for speaker positions.
|
||||||
|
WORD m_wChannels; // Number of channels.
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CMiniportWaveICH methods
|
||||||
|
*************************************************************************
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* MINWAVE.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Checks and connects the miniport to the resources.
|
||||||
|
//
|
||||||
|
NTSTATUS ProcessResources
|
||||||
|
(
|
||||||
|
IN PRESOURCELIST ResourceList
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Tests the data format but not the sample rate.
|
||||||
|
//
|
||||||
|
NTSTATUS TestDataFormat
|
||||||
|
(
|
||||||
|
IN PKSDATAFORMAT Format,
|
||||||
|
IN WavePins Pin
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS ValidateFormat
|
||||||
|
(
|
||||||
|
IN PKSDATAFORMAT DataFormat,
|
||||||
|
IN WavePins Pin
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test for standard sample rate support and fill the data range information
|
||||||
|
// in the structures below.
|
||||||
|
NTSTATUS BuildDataRangeInformation (void);
|
||||||
|
|
||||||
|
IMP_IMiniport;
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPowerNotify methods
|
||||||
|
//
|
||||||
|
IMP_IPowerNotify;
|
||||||
|
|
||||||
|
//
|
||||||
|
// This static functions is the interrupt service routine which is
|
||||||
|
// not stream related, but services all streams at once.
|
||||||
|
//
|
||||||
|
static NTSTATUS NTAPI InterruptServiceRoutine
|
||||||
|
(
|
||||||
|
IN PINTERRUPTSYNC InterruptSync,
|
||||||
|
IN PVOID StaticContext
|
||||||
|
);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
~CMiniport();
|
||||||
|
|
||||||
|
STDMETHODIMP_(NTSTATUS) Init
|
||||||
|
(
|
||||||
|
_In_ PUNKNOWN UnknownAdapter,
|
||||||
|
_In_ PRESOURCELIST ResourceList,
|
||||||
|
_In_ PPORT Port_
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is the property handler for KSPROPERTY_AUDIO_CHANNEL_CONFIG of the
|
||||||
|
// DAC node.
|
||||||
|
//
|
||||||
|
static NTSTATUS NTAPI PropertyChannelConfig
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS NonDelegatingQueryInterface
|
||||||
|
(
|
||||||
|
_In_ REFIID Interface,
|
||||||
|
_COM_Outptr_ PVOID *Object,
|
||||||
|
_In_ REFIID iMiniPort,
|
||||||
|
_In_ PMINIPORT miniPort
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
#define IMP_CMiniport(cType, IID) \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::GetDescription( \
|
||||||
|
_Out_ PPCFILTER_DESCRIPTOR *OutFilterDescriptor)\
|
||||||
|
{ return CMiniport::GetDescription(OutFilterDescriptor); } \
|
||||||
|
\
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::DataRangeIntersection( \
|
||||||
|
IN ULONG PinId, \
|
||||||
|
IN PKSDATARANGE DataRange, \
|
||||||
|
IN PKSDATARANGE MatchingDataRange, \
|
||||||
|
IN ULONG OutputBufferLength, \
|
||||||
|
OUT PVOID ResultantFormat OPTIONAL, \
|
||||||
|
OUT PULONG ResultantFormatLength) \
|
||||||
|
{ return CMiniport::DataRangeIntersection(PinId, DataRange, \
|
||||||
|
MatchingDataRange, OutputBufferLength, ResultantFormat, \
|
||||||
|
ResultantFormatLength); } \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::NonDelegatingQueryInterface( \
|
||||||
|
_In_ REFIID Interface, \
|
||||||
|
_COM_Outptr_ PVOID *Object) \
|
||||||
|
{ return CMiniport::NonDelegatingQueryInterface( \
|
||||||
|
Interface, Object, IID, (PMINIPORT)this); }
|
||||||
|
|
||||||
|
|
||||||
|
void __fastcall obj_AddRef(PUNKNOWN obj, void **ppvObject);
|
||||||
|
void __fastcall obj_Release(void **ppvObject);
|
||||||
|
|
||||||
|
#include "stream.h"
|
||||||
|
#endif
|
2129
drivers/wdm/audio/drivers/ac97/mintopo.cpp
Normal file
2129
drivers/wdm/audio/drivers/ac97/mintopo.cpp
Normal file
File diff suppressed because it is too large
Load diff
339
drivers/wdm/audio/drivers/ac97/mintopo.h
Normal file
339
drivers/wdm/audio/drivers/ac97/mintopo.h
Normal file
|
@ -0,0 +1,339 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file mintopo.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _MINTOPO_H_
|
||||||
|
#define _MINTOPO_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "guids.h"
|
||||||
|
#ifdef INCLUDE_PRIVATE_PROPERTY
|
||||||
|
#include "prvprop.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Structures and Definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This structure is used to translate the TopoPins member to a (registered)
|
||||||
|
// system pin member or vice versa.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
TopoPins PinDef;
|
||||||
|
int PinNr;
|
||||||
|
} tPinTranslationTable;
|
||||||
|
|
||||||
|
|
||||||
|
// This structure is used to translate the TopoNodes member to a (registered)
|
||||||
|
// system node member or vice versa.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
TopoNodes NodeDef;
|
||||||
|
int NodeNr;
|
||||||
|
} tNodeTranslationTable;
|
||||||
|
|
||||||
|
// max. number of connections
|
||||||
|
const int TOPO_MAX_CONNECTIONS = 0x80;
|
||||||
|
|
||||||
|
// Looking at the structure stMapNodeToReg, it defines a mask for a node.
|
||||||
|
// A volume node for instance could be used to prg. the left or right channel,
|
||||||
|
// so we have to mask the mask in stMapNodeToReg with a "left channel mask"
|
||||||
|
// or a "right channel mask" to only prg. the left or right channel.
|
||||||
|
const WORD AC97REG_MASK_LEFT = 0x3F00;
|
||||||
|
const WORD AC97REG_MASK_RIGHT = 0x003F;
|
||||||
|
const WORD AC97REG_MASK_MUTE = 0x8000;
|
||||||
|
|
||||||
|
// When the user moves the fader of a volume control to the bottom, the
|
||||||
|
// system calls the property handler with a -MAXIMUM dB value. That's not
|
||||||
|
// what you returned at a basic support "data range", but the most negative
|
||||||
|
// value you can represent with a long.
|
||||||
|
const long PROP_MOST_NEGATIVE = (long)0x80000000;
|
||||||
|
|
||||||
|
// We must cache the values for the volume and tone controls. If we don't,
|
||||||
|
// the controls will "jump".
|
||||||
|
// We have around 50% volume controls in the nodes. One way would be to
|
||||||
|
// create a separate structure for the node cache and a second array for
|
||||||
|
// the mapping. But we just use one big array (that could cache mute controls
|
||||||
|
// too) and in that way simplify the code a little.
|
||||||
|
// We use the bLeftValid and bRightValid to indicate whether the values stored
|
||||||
|
// in lLeft and lRight are true - remember at startup we only write and
|
||||||
|
// initialize the AC97 registers and not this structure. But as soon as there
|
||||||
|
// is a property get or a property set, this element (node) will be stored here
|
||||||
|
// and marked valid.
|
||||||
|
// We don't have to save/restore the virtual controls for WaveIn and MonoOut
|
||||||
|
// in the registry, cause WDMAUD will do this for every node that is exposed
|
||||||
|
// in the topology. We can also be sure that this structure gets initialized at
|
||||||
|
// startup because WDMAUD will query every node that it finds.
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long lLeft;
|
||||||
|
long lRight;
|
||||||
|
BYTE bLeftValid;
|
||||||
|
BYTE bRightValid;
|
||||||
|
} tNodeCache;
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Classes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportTopology
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 topology miniport. This object is associated with the device and is
|
||||||
|
* created when the device is started. The class inherits IMiniportTopology
|
||||||
|
* so it can expose this interface and CUnknown so it automatically gets
|
||||||
|
* reference counting and aggregation support.
|
||||||
|
*/
|
||||||
|
class CAC97MiniportTopology : public IAC97MiniportTopology,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
PADAPTERCOMMON AdapterCommon; // Adapter common object
|
||||||
|
PPCFILTER_DESCRIPTOR FilterDescriptor; // Filter Descriptor
|
||||||
|
PPCPIN_DESCRIPTOR PinDescriptors; // Pin Descriptors
|
||||||
|
PPCNODE_DESCRIPTOR NodeDescriptors; // Node Descriptors
|
||||||
|
PPCCONNECTION_DESCRIPTOR ConnectionDescriptors; // Connection Descriptors
|
||||||
|
|
||||||
|
tPinTranslationTable stPinTrans[PIN_TOP_ELEMENT]; // pin translation table
|
||||||
|
tNodeTranslationTable stNodeTrans[NODE_TOP_ELEMENT]; // node translation table
|
||||||
|
tNodeCache stNodeCache[NODE_TOP_ELEMENT]; // cache for nodes.
|
||||||
|
BOOL m_bCopyProtectFlag; // Copy protect flag for DRM.
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CAC97MiniportTopology methods
|
||||||
|
*
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* MINIPORT.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// builds the topology.
|
||||||
|
NTSTATUS BuildTopology (void);
|
||||||
|
|
||||||
|
// registers (builds) the pins
|
||||||
|
NTSTATUS BuildPinDescriptors (void);
|
||||||
|
|
||||||
|
// registers (builds) the nodes
|
||||||
|
NTSTATUS BuildNodeDescriptors (void);
|
||||||
|
|
||||||
|
// registers (builds) the connection between the pin, nodes.
|
||||||
|
NTSTATUS BuildConnectionDescriptors (void);
|
||||||
|
|
||||||
|
#if (DBG)
|
||||||
|
// dumps the topology. you can specify if you want to dump pins, nodes,
|
||||||
|
// connections (see debug.h).
|
||||||
|
void DumpTopology (void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// translates the system node id to a TopoNode.
|
||||||
|
TopoNodes TransNodeNrToNodeDef (IN int Node)
|
||||||
|
{
|
||||||
|
#if (DBG)
|
||||||
|
TopoNodes n;
|
||||||
|
|
||||||
|
n = stNodeTrans[Node].NodeDef;
|
||||||
|
// check for invalid translation. could be caused by a connection
|
||||||
|
// to a not registered node or wrong use of nodes.
|
||||||
|
if (n == NODE_INVALID)
|
||||||
|
DOUT (DBG_ERROR, ("Invalid node nr %u.", Node));
|
||||||
|
return n;
|
||||||
|
#else
|
||||||
|
return stNodeTrans[Node].NodeDef;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// translates a TopoNode to a system node id.
|
||||||
|
int TransNodeDefToNodeNr (IN TopoNodes Node)
|
||||||
|
{
|
||||||
|
#if (DBG)
|
||||||
|
int n;
|
||||||
|
|
||||||
|
// check for invalid translation. could be caused by a connection
|
||||||
|
// to a not registered node or wrong use of nodes.
|
||||||
|
n = stNodeTrans[Node].NodeNr;
|
||||||
|
if (n == -1)
|
||||||
|
DOUT (DBG_ERROR, ("Invalid TopoNode %u.", Node));
|
||||||
|
return n;
|
||||||
|
#else
|
||||||
|
return stNodeTrans[Node].NodeNr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// translates a system pin id to a TopoPin.
|
||||||
|
TopoPins TransPinNrToPinDef (IN int Pin)
|
||||||
|
{
|
||||||
|
#if (DBG)
|
||||||
|
TopoPins p;
|
||||||
|
|
||||||
|
p = stPinTrans[Pin].PinDef;
|
||||||
|
// check for invalid translation. could be caused by a connection
|
||||||
|
// to a not registered pin or wrong use of pins.
|
||||||
|
if (p == PIN_INVALID)
|
||||||
|
DOUT (DBG_ERROR, ("Invalid pin nr %u.", Pin));
|
||||||
|
return p;
|
||||||
|
#else
|
||||||
|
return stPinTrans[Pin].PinDef;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// translates a TopoPin to a system pin id.
|
||||||
|
int TransPinDefToPinNr (IN TopoPins Pin)
|
||||||
|
{
|
||||||
|
#if (DBG)
|
||||||
|
int p;
|
||||||
|
|
||||||
|
p = stPinTrans[Pin].PinNr;
|
||||||
|
// check for invalid translation. could be caused by a connection
|
||||||
|
// to a not registered pin or wrong use of pins.
|
||||||
|
if (p == -1)
|
||||||
|
DOUT (DBG_ERROR, ("Invalid TopoPin %u.", Pin));
|
||||||
|
return p;
|
||||||
|
#else
|
||||||
|
return stPinTrans[Pin].PinNr;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
// sets one table entry for translation.
|
||||||
|
void SetNodeTranslation (IN int NodeNr, IN TopoNodes NodeDef)
|
||||||
|
{
|
||||||
|
stNodeTrans[NodeNr].NodeDef = NodeDef;
|
||||||
|
stNodeTrans[NodeDef].NodeNr = NodeNr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// sets one table entry for translation.
|
||||||
|
void SetPinTranslation (IN int PinNr, IN TopoPins PinDef)
|
||||||
|
{
|
||||||
|
stPinTrans[PinNr].PinDef = PinDef;
|
||||||
|
stPinTrans[PinDef].PinNr = PinNr;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Updates the record mute - used for DRM.
|
||||||
|
void UpdateRecordMute (void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in MINIPORT.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in MINIPORT.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CAC97MiniportTopology);
|
||||||
|
|
||||||
|
~CAC97MiniportTopology ();
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* include IMiniportTopology (public/exported) methods
|
||||||
|
*/
|
||||||
|
IMP_IMiniportTopology;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* IAC97MiniportTopology methods
|
||||||
|
*/
|
||||||
|
// returns the system pin id's for wave out, wave in and mic in.
|
||||||
|
STDMETHODIMP_(NTSTATUS) GetPhysicalConnectionPins
|
||||||
|
(
|
||||||
|
OUT PULONG WaveOutSource,
|
||||||
|
OUT PULONG WaveInDest,
|
||||||
|
OUT PULONG MicInDest
|
||||||
|
);
|
||||||
|
|
||||||
|
// sets the copy protect flag.
|
||||||
|
STDMETHODIMP_(void) SetCopyProtectFlag (BOOL flag)
|
||||||
|
{
|
||||||
|
if (m_bCopyProtectFlag != flag)
|
||||||
|
{
|
||||||
|
m_bCopyProtectFlag = flag;
|
||||||
|
UpdateRecordMute ();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* static functions for the property handler.
|
||||||
|
* They are not part of an COM interface and are called directly.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Get the data range of volume or tone controls in dB.
|
||||||
|
// Called by the property handler.
|
||||||
|
static NTSTATUS GetDBValues
|
||||||
|
(
|
||||||
|
IN PADAPTERCOMMON,
|
||||||
|
IN TopoNodes Node,
|
||||||
|
OUT LONG *plMinimum,
|
||||||
|
OUT LONG *plMaximum,
|
||||||
|
OUT ULONG *puStep
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculates the speaker mute with respect to master mono.
|
||||||
|
// Called by the property handler.
|
||||||
|
static NTSTATUS SetMultichannelMute
|
||||||
|
(
|
||||||
|
IN CAC97MiniportTopology *that,
|
||||||
|
IN TopoNodes Mute
|
||||||
|
);
|
||||||
|
|
||||||
|
// Calculates the speaker volume with respect to master mono.
|
||||||
|
// Called by the property handler.
|
||||||
|
static NTSTATUS SetMultichannelVolume
|
||||||
|
(
|
||||||
|
IN CAC97MiniportTopology *that,
|
||||||
|
IN TopoNodes Volume
|
||||||
|
);
|
||||||
|
|
||||||
|
// property handler for mute controls of checkboxes like Loudness.
|
||||||
|
static NTSTATUS NTAPI PropertyHandler_OnOff
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// This routine is the basic support handler for volume or tone controls.
|
||||||
|
static NTSTATUS BasicSupportHandler
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// property handler for all volume controls.
|
||||||
|
static NTSTATUS NTAPI PropertyHandler_Level
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// property handler for tone controls.
|
||||||
|
static NTSTATUS NTAPI PropertyHandler_Tone
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// property handler for muxer. we have just two muxer, one for recording
|
||||||
|
// and one for mono out.
|
||||||
|
static NTSTATUS NTAPI PropertyHandler_Ulong
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
// this says that audio is played and processed without CPU resources.
|
||||||
|
static NTSTATUS NTAPI PropertyHandler_CpuResources
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
|
||||||
|
#ifdef INCLUDE_PRIVATE_PROPERTY
|
||||||
|
// property handler for private properties. we currently have only
|
||||||
|
// one request defined (KSPROPERTY_AC97_FEATURES).
|
||||||
|
static NTSTATUS PropertyHandler_Private
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MINTOPO_H_
|
1824
drivers/wdm/audio/drivers/ac97/prophnd.cpp
Normal file
1824
drivers/wdm/audio/drivers/ac97/prophnd.cpp
Normal file
File diff suppressed because it is too large
Load diff
252
drivers/wdm/audio/drivers/ac97/rtminiport.cpp
Normal file
252
drivers/wdm/audio/drivers/ac97/rtminiport.cpp
Normal file
|
@ -0,0 +1,252 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file rtminiport.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 RT Miniport: "
|
||||||
|
|
||||||
|
#include "rtminiport.h"
|
||||||
|
#include "rtstream.h"
|
||||||
|
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IMP_CMiniport(CAC97MiniportWaveRT, IID_IMiniportRT)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateAC97MiniportWaveRT
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a RT miniport object for the AC97 adapter.
|
||||||
|
* This uses a macro from STDUNK.H to do all the work.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateAC97MiniportWaveRT
|
||||||
|
(
|
||||||
|
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, ("[CreateMiniportWaveRT]"));
|
||||||
|
|
||||||
|
STD_CREATE_BODY_WITH_TAG_(CAC97MiniportWaveRT,Unknown,UnknownOuter,PoolType,
|
||||||
|
PoolTag, PMINIPORTWAVERT);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRT::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* Initializes the miniport.
|
||||||
|
* Initializes variables and modifies the wave topology if needed.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRT::Init
|
||||||
|
(
|
||||||
|
_In_ PUNKNOWN UnknownAdapter,
|
||||||
|
_In_ PRESOURCELIST ResourceList,
|
||||||
|
_In_ PPORTWAVERT Port_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
return CMiniport::Init(
|
||||||
|
UnknownAdapter,
|
||||||
|
ResourceList,
|
||||||
|
Port_
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRT::ProcessResources
|
||||||
|
*****************************************************************************
|
||||||
|
* Processes the resource list, setting up helper objects accordingly.
|
||||||
|
* Sets up the Interrupt + Service routine and DMA.
|
||||||
|
*/
|
||||||
|
NTSTATUS CAC97MiniportWaveRT::ProcessResources
|
||||||
|
(
|
||||||
|
IN PRESOURCELIST ResourceList
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (ResourceList);
|
||||||
|
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CAC97MiniportWaveRT::ProcessResources]"));
|
||||||
|
|
||||||
|
|
||||||
|
ULONG countIRQ = ResourceList->NumberOfInterrupts ();
|
||||||
|
if (countIRQ < 1)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Unknown configuration for wave miniport!"));
|
||||||
|
return STATUS_DEVICE_CONFIGURATION_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create an interrupt sync object
|
||||||
|
//
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
ntStatus = PcNewInterruptSync (&InterruptSync,
|
||||||
|
NULL,
|
||||||
|
ResourceList,
|
||||||
|
0,
|
||||||
|
InterruptSyncModeNormal);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS (ntStatus) || !InterruptSync)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to create an interrupt sync!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register our ISR.
|
||||||
|
//
|
||||||
|
ntStatus = InterruptSync->RegisterServiceRoutine (InterruptServiceRoutine,
|
||||||
|
(PVOID)this, FALSE);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to register ISR!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Connect the interrupt.
|
||||||
|
//
|
||||||
|
ntStatus = InterruptSync->Connect ();
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to connect the ISR with InterruptSync!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// On failure object is destroyed which cleans up.
|
||||||
|
//
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRT::NewStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a new stream.
|
||||||
|
* This function is called when a streaming pin is created.
|
||||||
|
* It checks if the channel is already in use, tests the data format, creates
|
||||||
|
* and initializes the stream object.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP CAC97MiniportWaveRT::NewStream
|
||||||
|
(
|
||||||
|
_Out_ PMINIPORTWAVERTSTREAM *Stream,
|
||||||
|
_In_ PPORTWAVERTSTREAM PortStream,
|
||||||
|
_In_ ULONG Channel_,
|
||||||
|
_In_ BOOLEAN Capture,
|
||||||
|
_In_ PKSDATAFORMAT DataFormat
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (Stream);
|
||||||
|
ASSERT (PortStream);
|
||||||
|
ASSERT (DataFormat);
|
||||||
|
|
||||||
|
CAC97MiniportWaveRTStream *pStream = NULL;
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CAC97MiniportWaveRT::NewStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check parameters.
|
||||||
|
//
|
||||||
|
ntStatus = ValidateFormat (DataFormat, (WavePins)Channel_);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a new stream.
|
||||||
|
//
|
||||||
|
ntStatus = CreateAC97MiniportWaveRTStream (&pStream);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return in case of an error.
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to create stream!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the stream.
|
||||||
|
//
|
||||||
|
ntStatus = pStream->Init (this,
|
||||||
|
PortStream,
|
||||||
|
Channel,
|
||||||
|
Capture,
|
||||||
|
DataFormat);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Release the stream and clean up.
|
||||||
|
//
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to init stream!"));
|
||||||
|
pStream->Release ();
|
||||||
|
*Stream = NULL;
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save the pointers.
|
||||||
|
//
|
||||||
|
*Stream = (PMINIPORTWAVERTSTREAM)pStream;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRT::GetDeviceDescription
|
||||||
|
*****************************************************************************
|
||||||
|
* Gets the topology.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRT::GetDeviceDescription
|
||||||
|
(
|
||||||
|
_Out_ PDEVICE_DESCRIPTION DmaDeviceDescription
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (DmaDeviceDescription);
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CAC97MiniportWaveRT::GetDeviceDescription]"));
|
||||||
|
|
||||||
|
RtlZeroMemory (DmaDeviceDescription, sizeof (DEVICE_DESCRIPTION));
|
||||||
|
DmaDeviceDescription->Master = TRUE;
|
||||||
|
DmaDeviceDescription->ScatterGather = TRUE;
|
||||||
|
DmaDeviceDescription->Dma32BitAddresses = TRUE;
|
||||||
|
DmaDeviceDescription->InterfaceType = PCIBus;
|
||||||
|
DmaDeviceDescription->MaximumLength = 0x1FFFE;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
155
drivers/wdm/audio/drivers/ac97/rtminiport.h
Normal file
155
drivers/wdm/audio/drivers/ac97/rtminiport.h
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file rtminiport.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _RTMINIPORT_H_
|
||||||
|
#define _RTMINIPORT_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Constants
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
const int WAVE_SAMPLERATES_TESTED = 7;
|
||||||
|
const int MIC_SAMPLERATES_TESTED = 4;
|
||||||
|
|
||||||
|
const DWORD dwWaveSampleRates[WAVE_SAMPLERATES_TESTED] =
|
||||||
|
{48000, 44100, 32000, 22050, 16000, 11025, 8000};
|
||||||
|
const DWORD dwMicSampleRates[MIC_SAMPLERATES_TESTED] =
|
||||||
|
{48000, 32000, 16000, 8000};
|
||||||
|
|
||||||
|
const int PIN_WAVEOUT_OFFSET = (PIN_WAVEOUT / 2);
|
||||||
|
const int PIN_WAVEIN_OFFSET = (PIN_WAVEIN / 2);
|
||||||
|
const int PIN_MICIN_OFFSET = (PIN_MICIN / 2);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Forward References
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
class CAC97MiniportWaveRTStream;
|
||||||
|
|
||||||
|
extern NTSTATUS CreateAC97MiniportWaveRTStream
|
||||||
|
(
|
||||||
|
OUT CAC97MiniportWaveRTStream ** pRTStream
|
||||||
|
);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Classes
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRT
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave PCI miniport. This object is associated with the device and is
|
||||||
|
* created when the device is started. The class inherits IMiniportWaveRT
|
||||||
|
* so it can expose this interface, CUnknown so it automatically gets
|
||||||
|
* reference counting and aggregation support, and IPowerNotify for ACPI
|
||||||
|
* power management notification.
|
||||||
|
*/
|
||||||
|
class CAC97MiniportWaveRT : public IMiniportWaveRT,
|
||||||
|
public IPowerNotify,
|
||||||
|
public CUnknown
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// The stream class accesses a lot of private member variables.
|
||||||
|
// A better way would be to abstract the access through member
|
||||||
|
// functions which on the other hand would produce more overhead
|
||||||
|
// both in CPU time and programming time.
|
||||||
|
friend class CAC97MiniportWaveRTStream;
|
||||||
|
|
||||||
|
//
|
||||||
|
// CAC97MiniportWaveRT private variables
|
||||||
|
//
|
||||||
|
CAC97MiniportWaveRTStream *Streams[PIN_MICIN_OFFSET + 1];
|
||||||
|
PPORT Port; // Port driver object.
|
||||||
|
PADAPTERCOMMON AdapterCommon; // Adapter common object.
|
||||||
|
PINTERRUPTSYNC InterruptSync; // Interrupt Sync.
|
||||||
|
DEVICE_POWER_STATE m_PowerState; // advanced power control.
|
||||||
|
DWORD m_dwChannelMask; // Channel config for speaker positions.
|
||||||
|
WORD m_wChannels; // Number of channels.
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CAC97MiniportWaveRT methods
|
||||||
|
*************************************************************************
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* MINWAVE.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Checks and connects the miniport to the resources.
|
||||||
|
//
|
||||||
|
NTSTATUS ProcessResources
|
||||||
|
(
|
||||||
|
IN PRESOURCELIST ResourceList
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Tests the data format but not the sample rate.
|
||||||
|
//
|
||||||
|
NTSTATUS TestDataFormat
|
||||||
|
(
|
||||||
|
IN PKSDATAFORMAT Format,
|
||||||
|
IN WavePins Pin
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test for standard sample rate support and fill the data range information
|
||||||
|
// in the structures below.
|
||||||
|
NTSTATUS BuildDataRangeInformation (void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in MINWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in MINWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CAC97MiniportWaveRT);
|
||||||
|
~CAC97MiniportWaveRT ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Include IMiniportWaveRT (public/exported) methods
|
||||||
|
//
|
||||||
|
IMP_IMiniportWaveRT;
|
||||||
|
|
||||||
|
//
|
||||||
|
// IPowerNotify methods
|
||||||
|
//
|
||||||
|
IMP_IPowerNotify;
|
||||||
|
|
||||||
|
//
|
||||||
|
// This static functions is the interrupt service routine which is
|
||||||
|
// not stream related, but services all streams at once.
|
||||||
|
//
|
||||||
|
static NTSTATUS InterruptServiceRoutine
|
||||||
|
(
|
||||||
|
IN PINTERRUPTSYNC InterruptSync,
|
||||||
|
IN PVOID StaticContext
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is the property handler for KSPROPERTY_AUDIO_CHANNEL_CONFIG of the
|
||||||
|
// DAC node.
|
||||||
|
//
|
||||||
|
static NTSTATUS PropertyChannelConfig
|
||||||
|
(
|
||||||
|
IN PPCPROPERTY_REQUEST PropertyRequest
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
#endif // _RTMINIPORT_H_
|
||||||
|
|
425
drivers/wdm/audio/drivers/ac97/rtstream.cpp
Normal file
425
drivers/wdm/audio/drivers/ac97/rtstream.cpp
Normal file
|
@ -0,0 +1,425 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file rtstream.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 RT Stream: "
|
||||||
|
|
||||||
|
#include "rtminiport.h"
|
||||||
|
#include "rtstream.h"
|
||||||
|
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* General Info
|
||||||
|
*****************************************************************************
|
||||||
|
* To protect the stBDList structure that is used to store mappings, we use a
|
||||||
|
* spin lock called MapLock. This spin lock is also acquired when we change
|
||||||
|
* the DMA registers. Normally, changes in stBDList and the DMA registers go
|
||||||
|
* hand in hand. In case we only want to change the DMA registers, we need
|
||||||
|
* to acquire the spin lock!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateAC97MiniportWaveRTStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a wave miniport stream object for the AC97 audio adapter. This is
|
||||||
|
* (nearly) like the macro STD_CREATE_BODY_ from STDUNK.H.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateAC97MiniportWaveRTStream
|
||||||
|
(
|
||||||
|
OUT CAC97MiniportWaveRTStream **RTStream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CreateAC97MiniportWaveRTStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is basically like the macro at stdunk with the change that we
|
||||||
|
// don't cast to interface unknown but to interface CAC97MiniportWaveRTStream.
|
||||||
|
//
|
||||||
|
*RTStream = new (NonPagedPool, PoolTag) CAC97MiniportWaveRTStream (NULL);
|
||||||
|
if (*RTStream)
|
||||||
|
{
|
||||||
|
(*RTStream)->AddRef ();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::~CAC97MiniportWaveRTStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
CAC97MiniportWaveRTStream::~CAC97MiniportWaveRTStream ()
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CAC97MiniportWaveRTStream::~CAC97MiniportWaveRTStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delete the scatter gather list since it's not needed anymore
|
||||||
|
//
|
||||||
|
if (BDListMdl && BDList)
|
||||||
|
{
|
||||||
|
PortStream->UnmapAllocatedPages (BDList, BDListMdl);
|
||||||
|
PortStream->FreePagesFromMdl (BDListMdl);
|
||||||
|
BDListMdl = NULL;
|
||||||
|
BDList = NULL;
|
||||||
|
}
|
||||||
|
if (BDList)
|
||||||
|
{
|
||||||
|
ExFreePool (BDList);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release the port stream.
|
||||||
|
//
|
||||||
|
if (PortStream)
|
||||||
|
{
|
||||||
|
PortStream->Release ();
|
||||||
|
PortStream = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine initializes the stream object & allocates the BDL.
|
||||||
|
* It doesn't allocate the audio buffer or initialize the BDL.
|
||||||
|
*/
|
||||||
|
NTSTATUS CAC97MiniportWaveRTStream::Init
|
||||||
|
(
|
||||||
|
IN CAC97MiniportWaveRT *Miniport_,
|
||||||
|
IN PPORTWAVERTSTREAM PortStream_,
|
||||||
|
IN ULONG Channel_,
|
||||||
|
IN BOOLEAN Capture_,
|
||||||
|
IN PKSDATAFORMAT DataFormat_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CAC97MiniportWaveRTStream::Init]"));
|
||||||
|
|
||||||
|
ASSERT (Miniport_);
|
||||||
|
ASSERT (PortStream_);
|
||||||
|
ASSERT (DataFormat_);
|
||||||
|
|
||||||
|
//
|
||||||
|
// The rule here is that we return when we fail without a cleanup.
|
||||||
|
// The destructor will relase the allocated memory.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate memory for the BDL.
|
||||||
|
// First try the least expensive way, which is to allocate it from the pool.
|
||||||
|
// If that fails (it's outside of the controller's address range which can
|
||||||
|
// happen on 64bit machines or PAE) then use portcls's AllocatePagesForMdl.
|
||||||
|
//
|
||||||
|
BDList = (tBDEntry *)ExAllocatePoolWithTag (NonPagedPool,
|
||||||
|
MAX_BDL_ENTRIES * sizeof (tBDEntry), PoolTag);
|
||||||
|
if (!BDList)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to allocate the BD list!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check to see if our HW can access it.
|
||||||
|
// If the HW cannot see the memory, free it and use AllocatePagesForMdl
|
||||||
|
// which allocates always complete pages, so we have to waste some memory.
|
||||||
|
//
|
||||||
|
if (MmGetPhysicalAddress (BDList).HighPart != 0)
|
||||||
|
{
|
||||||
|
PHYSICAL_ADDRESS high;
|
||||||
|
|
||||||
|
high.HighPart = 0;
|
||||||
|
high.LowPart = MAXULONG;
|
||||||
|
ExFreePool (BDList);
|
||||||
|
BDListMdl = PortStream->AllocatePagesForMdl (high, PAGE_SIZE);
|
||||||
|
if (!BDListMdl)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to allocate page for BD list!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
BDList = (tBDEntry *)PortStream->MapAllocatedPages (BDListMdl, MmCached);
|
||||||
|
if (!BDList)
|
||||||
|
{
|
||||||
|
PortStream->FreePagesFromMdl (BDListMdl);
|
||||||
|
BDListMdl = NULL;
|
||||||
|
DOUT (DBG_ERROR, ("Failed to map the page for the BD list!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return CMiniportStream::Init(Miniport_,
|
||||||
|
Channel_,
|
||||||
|
Capture_,
|
||||||
|
DataFormat_,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::AllocateAudioBuffer
|
||||||
|
*****************************************************************************
|
||||||
|
* This functions allocates an audio buffer of the size specified and maps
|
||||||
|
* it into the scatter gather table of the AC97 DMA engine.
|
||||||
|
* Once audio is played the driver only changes the last valid index to make
|
||||||
|
* the DMA cycle through this buffer over and over again.
|
||||||
|
* The buffer needs to be freed when the stream gets destroyed.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRTStream::AllocateAudioBuffer
|
||||||
|
(
|
||||||
|
_In_ ULONG size,
|
||||||
|
_Out_ PMDL *userModeBuffer,
|
||||||
|
_Out_ ULONG *bufferSize,
|
||||||
|
_Out_ ULONG *bufferOffset,
|
||||||
|
_Out_ MEMORY_CACHING_TYPE *cacheType
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Make sure complete samples fit into the buffer.
|
||||||
|
//
|
||||||
|
if( size <= size % (NumberOfChannels * 2) )
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
size -= size % (NumberOfChannels * 2);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Validate that we're going to actually allocate a real amount of memory.
|
||||||
|
//
|
||||||
|
if (0 == size)
|
||||||
|
{
|
||||||
|
DOUT (DBG_WARNING, ("Zero byte memory allocation attempted."));
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Allocate the buffer.
|
||||||
|
// The AC97 has problems playing 6ch data on page breaks (a page is 4096 bytes
|
||||||
|
// and doesn't contain complete samples of 6ch 16bit audio data). We therefore
|
||||||
|
// allocate contiguous memory that fits complete 6ch 16bit samples, however,
|
||||||
|
// contiguous memory is a lot more expensive to get and you might not get it
|
||||||
|
// at all. Useing non-contiguous memory (AllocatePagesForMdl) is therefore much
|
||||||
|
// better if your HW does support it. It is highly recommended to build future
|
||||||
|
// HW so that it can map a variable amount of pages, that it can cycle through
|
||||||
|
// the scatter gather list automatically and that it handles that case where
|
||||||
|
// samples are "split" between 2 pages.
|
||||||
|
//
|
||||||
|
PHYSICAL_ADDRESS low;
|
||||||
|
PHYSICAL_ADDRESS high;
|
||||||
|
|
||||||
|
low.QuadPart = 0;
|
||||||
|
high.HighPart = 0, high.LowPart = MAXULONG;
|
||||||
|
PMDL audioBufferMdl = PortStream->AllocateContiguousPagesForMdl (low, high, size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if the allocation was successful.
|
||||||
|
//
|
||||||
|
if (!audioBufferMdl)
|
||||||
|
{
|
||||||
|
DOUT (DBG_WARNING, ("[AllocateAudioBuffer] Can not allocate RT buffer."));
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We got our memory. Program the BDL (scatter gather list) now.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Note that when you use AllocatePagesForMdl that you might get less memory
|
||||||
|
// back. In this case you need to check the byte count of the Mdl and continue
|
||||||
|
// with that size.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store the information for portcls so that the buffer can be mapped to
|
||||||
|
// the client.
|
||||||
|
//
|
||||||
|
*userModeBuffer = audioBufferMdl;
|
||||||
|
*bufferSize = size;
|
||||||
|
*bufferOffset = 0;
|
||||||
|
*cacheType = MmCached;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Program the BDL
|
||||||
|
//
|
||||||
|
for (UINT loop = 0; loop < MAX_BDL_ENTRIES; loop++)
|
||||||
|
{
|
||||||
|
BDList[loop].dwPtrToPhyAddress = PortStream->GetPhysicalPageAddress (audioBufferMdl, 0).LowPart;
|
||||||
|
BDList[loop].wLength = (WORD)size/2;
|
||||||
|
if ((loop == MAX_BDL_ENTRIES / 2) || (loop == MAX_BDL_ENTRIES - 1))
|
||||||
|
BDList[loop].wPolicyBits = IOC_ENABLE;
|
||||||
|
else
|
||||||
|
BDList[loop].wPolicyBits = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::FreeAudioBuffer
|
||||||
|
*****************************************************************************
|
||||||
|
* This functions frees the previously allocated audio buffer. We don't do
|
||||||
|
* anything special here. This callback is mainly in the case you would have
|
||||||
|
* to reprogram HW or do something fancy with it. In our case we just delete
|
||||||
|
* the audio buffer MDL and the scatter gather list we allocated.
|
||||||
|
*/
|
||||||
|
_Use_decl_annotations_
|
||||||
|
STDMETHODIMP_(VOID) CAC97MiniportWaveRTStream::FreeAudioBuffer
|
||||||
|
(
|
||||||
|
PMDL Mdl,
|
||||||
|
ULONG Size
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(Size);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Just delete the MDL that was allocated with AllocateContiguousPagesForMdl.
|
||||||
|
//
|
||||||
|
if (NULL != Mdl)
|
||||||
|
{
|
||||||
|
PortStream->FreePagesFromMdl (Mdl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::GetHWLatency
|
||||||
|
*****************************************************************************
|
||||||
|
* Returns the HW latency of the controller + codec.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(void) CAC97MiniportWaveRTStream::GetHWLatency
|
||||||
|
(
|
||||||
|
_Out_ PKSRTAUDIO_HWLATENCY hwLatency
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
hwLatency->FifoSize = 32; // 32 bytes I think
|
||||||
|
hwLatency->ChipsetDelay = 0; // PCI
|
||||||
|
hwLatency->CodecDelay = 4; // Wild guess. Take maximum.
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::GetPositionRegister
|
||||||
|
*****************************************************************************
|
||||||
|
* We can't support this property b/c we don't have a memory mapped position
|
||||||
|
* register.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRTStream::GetPositionRegister
|
||||||
|
(
|
||||||
|
_Out_ PKSRTAUDIO_HWREGISTER hwRegister
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(hwRegister);
|
||||||
|
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::GetClockRegister
|
||||||
|
*****************************************************************************
|
||||||
|
* We can't support this property b/c we don't have a memory mapped clock
|
||||||
|
* register.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRTStream::GetClockRegister
|
||||||
|
(
|
||||||
|
_Out_ PKSRTAUDIO_HWREGISTER hwRegister
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(hwRegister);
|
||||||
|
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream::GetPosition
|
||||||
|
*****************************************************************************
|
||||||
|
* Gets the stream position. This is a byte count of the current position of
|
||||||
|
* a stream running on a particular DMA engine. We must return a sample
|
||||||
|
* accurate count or the WaveDrv32 wave drift tests (35.2 & 36.2) will fail.
|
||||||
|
*
|
||||||
|
* The position is the sum of three parts:
|
||||||
|
* 1) The total number of bytes in released buffers
|
||||||
|
* 2) The position in the current buffer.
|
||||||
|
* 3) The total number of bytes in played but not yet released buffers
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CAC97MiniportWaveRTStream::GetPosition
|
||||||
|
(
|
||||||
|
_Out_ PKSAUDIO_POSITION Position
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UCHAR nCurrentIndex = 0;
|
||||||
|
DWORD bufferPos;
|
||||||
|
|
||||||
|
ASSERT (Position);
|
||||||
|
|
||||||
|
if (DMAEngineState == DMA_ENGINE_OFF)
|
||||||
|
{
|
||||||
|
Position->PlayOffset = 0;
|
||||||
|
Position->WriteOffset = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
nCurrentIndex = GetBuffPos(&bufferPos);
|
||||||
|
Position->PlayOffset = bufferPos;
|
||||||
|
Position->WriteOffset = bufferPos + NumberOfChannels * 2 * 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/*****************************************************************************
|
||||||
|
+ * Non paged code begins here
|
||||||
|
+ *****************************************************************************
|
||||||
|
+ */
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CMiniportWaveICHStream::InterruptServiceRoutine()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Update the LVI so that we cycle around in the scatter gather list.
|
||||||
|
//
|
||||||
|
UpdateLviCyclic();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // (NTDDI_VERSION >= NTDDI_VISTA)
|
118
drivers/wdm/audio/drivers/ac97/rtstream.h
Normal file
118
drivers/wdm/audio/drivers/ac97/rtstream.h
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file rtstream.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _RTSTREAM_H_
|
||||||
|
#define _RTSTREAM_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
|
||||||
|
#if (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Defines
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
//
|
||||||
|
// The scatter gather can (only) handle 32 entries
|
||||||
|
//
|
||||||
|
const int MAX_BDL_ENTRIES = 32;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mask for accessing the scatter gather entries with a counter.
|
||||||
|
//
|
||||||
|
const int BDL_MASK = 31;
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Classes
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave miniport stream.
|
||||||
|
*/
|
||||||
|
class CAC97MiniportWaveRTStream : public IMiniportWaveRTStream,
|
||||||
|
public CUnknown,
|
||||||
|
public CMiniportStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//
|
||||||
|
// CAC97MiniportWaveRTStream private variables
|
||||||
|
//
|
||||||
|
DEVICE_POWER_STATE m_PowerState; // Current power state of the device.
|
||||||
|
|
||||||
|
|
||||||
|
int mapEntries;
|
||||||
|
tBDEntry *BDList;
|
||||||
|
PMDL BDListMdl;
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* ICHWAVE.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in ICHWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in ICHWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CAC97MiniportWaveRTStream);
|
||||||
|
|
||||||
|
~CAC97MiniportWaveRTStream ();
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Include IMiniportWaveRTStream (public/exported) methods.
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
IMP_IMiniportWaveRTStream;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CAC97MiniportWaveRTStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializes the Stream object.
|
||||||
|
//
|
||||||
|
NTSTATUS Init
|
||||||
|
(
|
||||||
|
IN CAC97MiniportWaveRT *Miniport_,
|
||||||
|
IN PPORTWAVERTSTREAM PortStream,
|
||||||
|
IN ULONG Channel,
|
||||||
|
IN BOOLEAN Capture,
|
||||||
|
IN PKSDATAFORMAT DataFormat
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Friends
|
||||||
|
//
|
||||||
|
friend
|
||||||
|
NTSTATUS CAC97MiniportWaveRT::InterruptServiceRoutine
|
||||||
|
(
|
||||||
|
IN PINTERRUPTSYNC InterruptSync,
|
||||||
|
IN PVOID StaticContext
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // (NTDDI_VERSION >= NTDDI_VISTA)
|
||||||
|
|
||||||
|
#endif // _RTSTREAM_H_
|
||||||
|
|
||||||
|
|
504
drivers/wdm/audio/drivers/ac97/shared.h
Normal file
504
drivers/wdm/audio/drivers/ac97/shared.h
Normal file
|
@ -0,0 +1,504 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file shared.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _SHARED_H_
|
||||||
|
#define _SHARED_H_
|
||||||
|
|
||||||
|
#define PC_IMPLEMENTATION 1
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get the NTDDK headers instead of the WDM headers that portcls.h wants to include.
|
||||||
|
//
|
||||||
|
#define WIN9X_COMPAT_SPINLOCK
|
||||||
|
|
||||||
|
#ifdef UNDER_NT
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
#include <ntddk.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} // extern "C"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <portcls.h>
|
||||||
|
#include <stdunk.h>
|
||||||
|
#include "ichreg.h"
|
||||||
|
#include "ac97reg.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
#ifdef __REACTOS__
|
||||||
|
|
||||||
|
PVOID
|
||||||
|
operator new (
|
||||||
|
size_t size,
|
||||||
|
POOL_TYPE pool_type,
|
||||||
|
ULONG tag);
|
||||||
|
|
||||||
|
#define GZCALL NTAPI
|
||||||
|
#else
|
||||||
|
#define GZCALL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Structures and Typedefs
|
||||||
|
*/
|
||||||
|
|
||||||
|
const ULONG PoolTag = '79CA';
|
||||||
|
|
||||||
|
// This enum defines all the possible pin configurations. It is pretty easy,
|
||||||
|
// cause a pin can be there or not, depending if the CoDec supports it (like
|
||||||
|
// Headphone output (PINC_HPOUT_PRESENT)) or if the OEM disabled the feature
|
||||||
|
// with a private inf file.
|
||||||
|
// Look at common.h file for the registry string names.
|
||||||
|
// ATTN: Don't change without changing the static struct in common.cpp too.
|
||||||
|
enum TopoPinConfig
|
||||||
|
{
|
||||||
|
PINC_PCBEEP_PRESENT = 0,
|
||||||
|
PINC_PHONE_PRESENT,
|
||||||
|
PINC_MIC2_PRESENT,
|
||||||
|
PINC_VIDEO_PRESENT,
|
||||||
|
PINC_AUX_PRESENT,
|
||||||
|
PINC_HPOUT_PRESENT,
|
||||||
|
PINC_MONOOUT_PRESENT,
|
||||||
|
PINC_MICIN_PRESENT,
|
||||||
|
PINC_MIC_PRESENT,
|
||||||
|
PINC_LINEIN_PRESENT,
|
||||||
|
PINC_CD_PRESENT,
|
||||||
|
PINC_SURROUND_PRESENT,
|
||||||
|
PINC_CENTER_LFE_PRESENT,
|
||||||
|
PINC_TOP_ELEMENT // number of PINC's
|
||||||
|
};
|
||||||
|
|
||||||
|
// This enum defines the functional configuration, called nodes. Nodes are
|
||||||
|
// black boxes that implement a functionality like 3d (NODEC_3D_PRESENT).
|
||||||
|
// At startup, we probe the Codec for features (like the pins above) and
|
||||||
|
// initialize an array which holds the configuration.
|
||||||
|
enum TopoNodeConfig
|
||||||
|
{
|
||||||
|
NODEC_3D_PRESENT = 0,
|
||||||
|
NODEC_TONE_PRESENT,
|
||||||
|
NODEC_LOUDNESS_PRESENT,
|
||||||
|
NODEC_SIMUL_STEREO_PRESENT,
|
||||||
|
NODEC_6BIT_MASTER_VOLUME,
|
||||||
|
NODEC_6BIT_HPOUT_VOLUME,
|
||||||
|
NODEC_6BIT_MONOOUT_VOLUME,
|
||||||
|
NODEC_6BIT_SURROUND_VOLUME,
|
||||||
|
NODEC_6BIT_CENTER_LFE_VOLUME,
|
||||||
|
NODEC_3D_CENTER_ADJUSTABLE,
|
||||||
|
NODEC_3D_DEPTH_ADJUSTABLE,
|
||||||
|
NODEC_PCM_VARIABLERATE_SUPPORTED,
|
||||||
|
NODEC_PCM_VSR_INDEPENDENT_RATES,
|
||||||
|
NODEC_PCM_DOUBLERATE_SUPPORTED,
|
||||||
|
NODEC_MIC_VARIABLERATE_SUPPORTED,
|
||||||
|
NODEC_CENTER_DAC_PRESENT,
|
||||||
|
NODEC_SURROUND_DAC_PRESENT,
|
||||||
|
NODEC_LFE_DAC_PRESENT,
|
||||||
|
NODEC_TOP_ELEMENT // number of NODES's
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pin Defininition goes here
|
||||||
|
// We define all the possible pins in the AC97 CoDec and some "virtual" pins
|
||||||
|
// that are used for the topology to connect special functionality like 3D.
|
||||||
|
//
|
||||||
|
enum TopoPins
|
||||||
|
{
|
||||||
|
// Source is something that goes into the AC97, dest goes out.
|
||||||
|
PIN_WAVEOUT_SOURCE = 0,
|
||||||
|
PIN_PCBEEP_SOURCE,
|
||||||
|
PIN_PHONE_SOURCE,
|
||||||
|
PIN_MIC_SOURCE,
|
||||||
|
PIN_LINEIN_SOURCE,
|
||||||
|
PIN_CD_SOURCE,
|
||||||
|
PIN_VIDEO_SOURCE,
|
||||||
|
PIN_AUX_SOURCE,
|
||||||
|
PIN_VIRT_3D_CENTER_SOURCE,
|
||||||
|
PIN_VIRT_3D_DEPTH_SOURCE,
|
||||||
|
PIN_VIRT_3D_MIX_MONO_SOURCE,
|
||||||
|
PIN_VIRT_TONE_MIX_SOURCE,
|
||||||
|
PIN_VIRT_TONE_MIX_MONO_SOURCE,
|
||||||
|
PIN_VIRT_SURROUND_SOURCE,
|
||||||
|
PIN_VIRT_CENTER_SOURCE,
|
||||||
|
PIN_VIRT_LFE_SOURCE,
|
||||||
|
PIN_VIRT_FRONT_SOURCE,
|
||||||
|
PIN_MASTEROUT_DEST,
|
||||||
|
PIN_HPOUT_SOURCE,
|
||||||
|
PIN_MONOOUT_DEST,
|
||||||
|
PIN_WAVEIN_DEST,
|
||||||
|
PIN_MICIN_DEST,
|
||||||
|
PIN_TOP_ELEMENT, // number of pins
|
||||||
|
PIN_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (DBG)
|
||||||
|
// In case we print some debug information about the pins, we use the names
|
||||||
|
// defined here.
|
||||||
|
const PCHAR TopoPinStrings[] =
|
||||||
|
{
|
||||||
|
"PIN_WAVEOUT_SOURCE",
|
||||||
|
"PIN_PCBEEP_SOURCE",
|
||||||
|
"PIN_PHONE_SOURCE",
|
||||||
|
"PIN_MIC_SOURCE",
|
||||||
|
"PIN_LINEIN_SOURCE",
|
||||||
|
"PIN_CD_SOURCE",
|
||||||
|
"PIN_VIDEO_SOURCE",
|
||||||
|
"PIN_AUX_SOURCE",
|
||||||
|
"PIN_VIRT_3D_CENTER_SOURCE",
|
||||||
|
"PIN_VIRT_3D_DEPTH_SOURCE",
|
||||||
|
"PIN_VIRT_3D_MIX_MONO_SOURCE",
|
||||||
|
"PIN_VIRT_TONE_MIX_SOURCE",
|
||||||
|
"PIN_VIRT_TONE_MIX_MONO_SOURCE",
|
||||||
|
"PIN_VIRT_SURROUND_SOURCE",
|
||||||
|
"PIN_VIRT_CENTER_SOURCE",
|
||||||
|
"PIN_VIRT_LFE_SOURCE",
|
||||||
|
"PIN_VIRT_FRONT_SOURCE",
|
||||||
|
"PIN_MASTEROUT_DEST",
|
||||||
|
"PIN_HPOUT_SOURCE",
|
||||||
|
"PIN_MONOOUT_DEST",
|
||||||
|
"PIN_WAVEIN_DEST",
|
||||||
|
"PIN_MICIN_DEST",
|
||||||
|
"TOP_ELEMENT", // should never dump this
|
||||||
|
"INVALID" // or this either
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Node Definition goes here.
|
||||||
|
// We define all the possible nodes here (nodes are black boxes that represent
|
||||||
|
// a functional block like bass volume) and some virtual nodes, mainly volume
|
||||||
|
// controls, that are used to represent special functionality in the topology
|
||||||
|
// like 3D controls (exposed as volumes) or to give the user volume controls
|
||||||
|
// for each possible record line. In that case, the volume is placed in front
|
||||||
|
// of the record selector (mux). The topology is not parsed correctly if there
|
||||||
|
// are no volume controls between the pins and a muxer. Also, these virtual
|
||||||
|
// controls only represent volumes and no mutes, cause mutes wouldn't be dis-
|
||||||
|
// played by sndvol32.
|
||||||
|
// ATTN: DON'T change without first looking at the table in ac97reg.h!!!
|
||||||
|
enum TopoNodes
|
||||||
|
{
|
||||||
|
NODE_WAVEOUT_VOLUME = 0,
|
||||||
|
NODE_WAVEOUT_MUTE,
|
||||||
|
NODE_VIRT_WAVEOUT_3D_BYPASS, // exposed as AGC control
|
||||||
|
NODE_PCBEEP_VOLUME,
|
||||||
|
NODE_PCBEEP_MUTE,
|
||||||
|
NODE_PHONE_VOLUME,
|
||||||
|
NODE_PHONE_MUTE,
|
||||||
|
NODE_MIC_SELECT,
|
||||||
|
NODE_MIC_BOOST,
|
||||||
|
NODE_MIC_VOLUME,
|
||||||
|
NODE_MIC_MUTE,
|
||||||
|
NODE_LINEIN_VOLUME,
|
||||||
|
NODE_LINEIN_MUTE,
|
||||||
|
NODE_CD_VOLUME,
|
||||||
|
NODE_CD_MUTE,
|
||||||
|
NODE_VIDEO_VOLUME,
|
||||||
|
NODE_VIDEO_MUTE,
|
||||||
|
NODE_AUX_VOLUME,
|
||||||
|
NODE_AUX_MUTE,
|
||||||
|
NODE_MAIN_MIX,
|
||||||
|
NODE_VIRT_3D_CENTER, // we have no 3D control type, so we
|
||||||
|
NODE_VIRT_3D_DEPTH, // expose 2 volume controls and 2 mute
|
||||||
|
NODE_VIRT_3D_ENABLE, // checkboxs (the other is bypass).
|
||||||
|
NODE_BEEP_MIX,
|
||||||
|
NODE_BASS,
|
||||||
|
NODE_TREBLE,
|
||||||
|
NODE_LOUDNESS,
|
||||||
|
NODE_SIMUL_STEREO,
|
||||||
|
NODE_MASTEROUT_VOLUME,
|
||||||
|
NODE_MASTEROUT_MUTE,
|
||||||
|
NODE_HPOUT_VOLUME,
|
||||||
|
NODE_HPOUT_MUTE,
|
||||||
|
NODE_MONOOUT_SELECT,
|
||||||
|
NODE_VIRT_MONOOUT_VOLUME1, // each mono out must have volume
|
||||||
|
NODE_VIRT_MONOOUT_VOLUME2,
|
||||||
|
NODE_WAVEIN_SELECT,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME1, // boy, each master input must have a
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME2, // volume
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME3,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME4,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME5,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME6,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME7,
|
||||||
|
NODE_VIRT_MASTER_INPUT_VOLUME8,
|
||||||
|
NODE_MICIN_VOLUME,
|
||||||
|
NODE_MICIN_MUTE,
|
||||||
|
NODE_SURROUND_VOLUME,
|
||||||
|
NODE_SURROUND_MUTE,
|
||||||
|
NODE_CENTER_VOLUME,
|
||||||
|
NODE_CENTER_MUTE,
|
||||||
|
NODE_LFE_VOLUME,
|
||||||
|
NODE_LFE_MUTE,
|
||||||
|
NODE_FRONT_VOLUME,
|
||||||
|
NODE_FRONT_MUTE,
|
||||||
|
NODE_VIRT_MASTERMONO_VOLUME, // used for multichannel or headphone
|
||||||
|
NODE_VIRT_MASTERMONO_MUTE,
|
||||||
|
NODE_TOP_ELEMENT, // number of nodes
|
||||||
|
NODE_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
#if (DBG)
|
||||||
|
// In case we print some debug information about the nodes, we use names
|
||||||
|
// defined here.
|
||||||
|
const PCHAR NodeStrings[] =
|
||||||
|
{
|
||||||
|
"WAVEOUT_VOLUME",
|
||||||
|
"WAVEOUT_MUTE",
|
||||||
|
"WAVEOUT_3D_BYPASS",
|
||||||
|
"PCBEEP_VOLUME",
|
||||||
|
"PCBEEP_MUTE",
|
||||||
|
"PHONE_VOLUME",
|
||||||
|
"PHONE_MUTE",
|
||||||
|
"MIC_SELECT",
|
||||||
|
"MIC_BOOST",
|
||||||
|
"MIC_VOLUME",
|
||||||
|
"MIC_MUTE",
|
||||||
|
"LINEIN_VOLUME",
|
||||||
|
"LINEIN_MUTE",
|
||||||
|
"CD_VOLUME",
|
||||||
|
"CD_MUTE",
|
||||||
|
"VIDEO_VOLUME",
|
||||||
|
"VIDEO_MUTE",
|
||||||
|
"AUX_VOLUME",
|
||||||
|
"AUX_MUTE",
|
||||||
|
"MAIN_MIX",
|
||||||
|
"3D_CENTER",
|
||||||
|
"3D_DEPTH",
|
||||||
|
"3D_ENABLE",
|
||||||
|
"BEEP_MIX",
|
||||||
|
"BASS",
|
||||||
|
"TREBLE",
|
||||||
|
"LOUDNESS",
|
||||||
|
"SIMUL_STEREO",
|
||||||
|
"MASTER_VOLUME",
|
||||||
|
"MASTER_MUTE",
|
||||||
|
"HPOUT_VOLUME",
|
||||||
|
"HPOUT_MUTE",
|
||||||
|
"MONOOUT_SELECT",
|
||||||
|
"MONOOUT_VOLUME_3D_MIX",
|
||||||
|
"MONOOUT_VOLUME_MIC",
|
||||||
|
"WAVEIN_SELECT",
|
||||||
|
"MASTER_INPUT_VOLUME_MIC",
|
||||||
|
"MASTER_INPUT_VOLUME_CD",
|
||||||
|
"MASTER_INPUT_VOLUME_VIDEO",
|
||||||
|
"MASTER_INPUT_VOLUME_AUX",
|
||||||
|
"MASTER_INPUT_VOLUME_LINEIN",
|
||||||
|
"MASTER_INPUT_VOLUME_TONE_MIX",
|
||||||
|
"MASTER_INPUT_VOLUME_TONE_MIX_MONO",
|
||||||
|
"MASTER_INPUT_VOLUME_PHONE",
|
||||||
|
"MICIN_VOLUME",
|
||||||
|
"MICIN_MUTE",
|
||||||
|
"SURROUND_VOLUME",
|
||||||
|
"SURROUND_MUTE",
|
||||||
|
"CENTER_VOLUME",
|
||||||
|
"CENTER_MUTE",
|
||||||
|
"LFE_VOLUME",
|
||||||
|
"LFE_MUTE",
|
||||||
|
"FRONT_VOLUME",
|
||||||
|
"FRONT_MUTE",
|
||||||
|
"VIRT_MASTERMONO_VOLUME",
|
||||||
|
"VIRT_MASTERMONO_MUTE",
|
||||||
|
"TOP_ELEMENT", // should never dump this
|
||||||
|
"INVALID" // or this
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// The pins used for the wave miniport connection.
|
||||||
|
//
|
||||||
|
enum WavePins
|
||||||
|
{
|
||||||
|
PIN_WAVEOUT = 0,
|
||||||
|
PIN_WAVEOUT_BRIDGE,
|
||||||
|
PIN_WAVEIN,
|
||||||
|
PIN_WAVEIN_BRIDGE,
|
||||||
|
PIN_MICIN,
|
||||||
|
PIN_MICIN_BRIDGE
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// The nodes used for the wave miniport connection.
|
||||||
|
//
|
||||||
|
enum WaveNodes
|
||||||
|
{
|
||||||
|
NODE_WAVEOUT_DAC,
|
||||||
|
NODE_WAVEIN_ADC,
|
||||||
|
NODE_MICIN_ADC
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Function prototypes
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* 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
|
||||||
|
);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Class definitions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* IAC97MiniportTopology
|
||||||
|
*****************************************************************************
|
||||||
|
* Interface for topology miniport.
|
||||||
|
*/
|
||||||
|
DECLARE_INTERFACE_(IAC97MiniportTopology,IMiniportTopology)
|
||||||
|
{
|
||||||
|
STDMETHOD_(NTSTATUS,GetPhysicalConnectionPins)
|
||||||
|
( THIS_
|
||||||
|
OUT PULONG WaveOutSource,
|
||||||
|
OUT PULONG WaveInDest,
|
||||||
|
OUT PULONG MicInDest
|
||||||
|
) PURE;
|
||||||
|
// Used for DRM:
|
||||||
|
STDMETHOD_(void, SetCopyProtectFlag)
|
||||||
|
( THIS_
|
||||||
|
IN BOOL
|
||||||
|
) PURE;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IAC97MiniportTopology *PAC97MINIPORTTOPOLOGY;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* IAC97AdapterCommon
|
||||||
|
*****************************************************************************
|
||||||
|
* Interface for adapter common object.
|
||||||
|
*/
|
||||||
|
DECLARE_INTERFACE_(IAC97AdapterCommon,IUnknown)
|
||||||
|
{
|
||||||
|
STDMETHOD_(NTSTATUS,Init)
|
||||||
|
( THIS_
|
||||||
|
IN PRESOURCELIST ResourceList,
|
||||||
|
IN PDEVICE_OBJECT DeviceObject
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(BOOL,GetPinConfig)
|
||||||
|
( THIS_
|
||||||
|
IN TopoPinConfig
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void,SetPinConfig)
|
||||||
|
( THIS_
|
||||||
|
IN TopoPinConfig,
|
||||||
|
IN BOOL
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(BOOL,GetNodeConfig)
|
||||||
|
( THIS_
|
||||||
|
IN TopoNodeConfig
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void,SetNodeConfig)
|
||||||
|
( THIS_
|
||||||
|
IN TopoNodeConfig,
|
||||||
|
IN BOOL
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(AC97Register,GetNodeReg)
|
||||||
|
( THIS_
|
||||||
|
IN TopoNodes
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(WORD,GetNodeMask)
|
||||||
|
( THIS_
|
||||||
|
IN TopoNodes
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(NTSTATUS,ReadCodecRegister)
|
||||||
|
( THIS_
|
||||||
|
_In_range_(0, AC97REG_INVALID) IN AC97Register Register,
|
||||||
|
_Out_ OUT PWORD wData
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(NTSTATUS,WriteCodecRegister)
|
||||||
|
( THIS_
|
||||||
|
_In_range_(0, AC97REG_INVALID) IN AC97Register Register,
|
||||||
|
_In_ IN WORD wData,
|
||||||
|
_In_ IN WORD wMask
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(UCHAR,ReadBMControlRegister8)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(USHORT,ReadBMControlRegister16)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(ULONG,ReadBMControlRegister32)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void,WriteBMControlRegister)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset,
|
||||||
|
IN UCHAR Value
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void,WriteBMControlRegister)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset,
|
||||||
|
IN USHORT Value
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void,WriteBMControlRegister)
|
||||||
|
( THIS_
|
||||||
|
IN ULONG Offset,
|
||||||
|
IN ULONG Value
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(NTSTATUS, RestoreCodecRegisters)
|
||||||
|
( THIS_
|
||||||
|
void
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(NTSTATUS, ProgramSampleRate)
|
||||||
|
( THIS_
|
||||||
|
IN AC97Register Register,
|
||||||
|
IN DWORD dwSampleRate
|
||||||
|
) PURE;
|
||||||
|
// Used for DRM:
|
||||||
|
STDMETHOD_(void, SetMiniportTopology)
|
||||||
|
( THIS_
|
||||||
|
IN PAC97MINIPORTTOPOLOGY
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(PAC97MINIPORTTOPOLOGY, GetMiniportTopology)
|
||||||
|
( THIS_
|
||||||
|
void
|
||||||
|
) PURE;
|
||||||
|
// These are used by the wave miniport.
|
||||||
|
STDMETHOD_(void, ReadChannelConfigDefault)
|
||||||
|
( THIS_
|
||||||
|
PDWORD pwChannelConfig,
|
||||||
|
PWORD pwChannels
|
||||||
|
) PURE;
|
||||||
|
STDMETHOD_(void, WriteChannelConfigDefault)
|
||||||
|
( THIS_
|
||||||
|
DWORD dwChannelConfig
|
||||||
|
) PURE;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef IAC97AdapterCommon *PADAPTERCOMMON;
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Guids for the Interfaces
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
// {77481FA0-1EF2-11d2-883A-0080C765647D}
|
||||||
|
DEFINE_GUID(IID_IAC97AdapterCommon,
|
||||||
|
0x77481fa0, 0x1ef2, 0x11d2, 0x88, 0x3a, 0x0, 0x80, 0xc7, 0x65, 0x64, 0x7d);
|
||||||
|
|
||||||
|
// {245AE964-49C8-11d2-95D7-00C04FB925D3}
|
||||||
|
DEFINE_GUID(IID_IAC97MiniportTopology,
|
||||||
|
0x245ae964, 0x49c8, 0x11d2, 0x95, 0xd7, 0x0, 0xc0, 0x4f, 0xb9, 0x25, 0xd3);
|
||||||
|
|
||||||
|
#endif //_SHARED_H_
|
||||||
|
|
634
drivers/wdm/audio/drivers/ac97/stream.cpp
Normal file
634
drivers/wdm/audio/drivers/ac97/stream.cpp
Normal file
|
@ -0,0 +1,634 @@
|
||||||
|
// Every debug output has "Modulname text"
|
||||||
|
#define STR_MODULENAME "AC97 Stream: "
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::NonDelegatingQueryInterface
|
||||||
|
*****************************************************************************
|
||||||
|
* Obtains an interface. This function works just like a COM QueryInterface
|
||||||
|
* call and is used if the object is not being aggregated.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportStream::NonDelegatingQueryInterface
|
||||||
|
(
|
||||||
|
_In_ REFIID Interface,
|
||||||
|
_COM_Outptr_ PVOID * Object,
|
||||||
|
_In_ REFIID iStream,
|
||||||
|
_In_ PUNKNOWN stream
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (Object);
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::NonDelegatingQueryInterface]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Convert for IID_IMiniportXXXStream
|
||||||
|
//
|
||||||
|
if (IsEqualGUIDAligned (Interface, iStream))
|
||||||
|
{
|
||||||
|
*Object = (PVOID)stream;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Convert for IID_IDrmAudioStream
|
||||||
|
//
|
||||||
|
else if (IsEqualGUIDAligned (Interface, IID_IDrmAudioStream))
|
||||||
|
{
|
||||||
|
*Object = (PVOID)(PDRMAUDIOSTREAM)this;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
// Convert for IID_IUnknown
|
||||||
|
//
|
||||||
|
else if (IsEqualGUIDAligned (Interface, IID_IUnknown))
|
||||||
|
{
|
||||||
|
*Object = (PVOID)stream;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*Object = NULL;
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
|
((PUNKNOWN)*Object)->AddRef ();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS CMiniportStream::Init
|
||||||
|
(
|
||||||
|
IN CMiniport *Miniport_,
|
||||||
|
IN PUNKNOWN PortStream_,
|
||||||
|
IN WavePins Pin_,
|
||||||
|
IN BOOLEAN Capture_,
|
||||||
|
IN PKSDATAFORMAT DataFormat_,
|
||||||
|
OUT PSERVICEGROUP *ServiceGroup_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::Init]"));
|
||||||
|
|
||||||
|
ASSERT (Miniport_);
|
||||||
|
ASSERT (DataFormat_);
|
||||||
|
|
||||||
|
//
|
||||||
|
// The rule here is that we return when we fail without a cleanup.
|
||||||
|
// The destructor will relase the allocated memory.
|
||||||
|
//
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save miniport pointer and addref it.
|
||||||
|
//
|
||||||
|
obj_AddRef(Miniport_, (PVOID *)&Miniport);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save portstream interface pointer and addref it.
|
||||||
|
//
|
||||||
|
obj_AddRef(PortStream_, (PVOID *)&PortStream);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save channel ID and capture flag.
|
||||||
|
//
|
||||||
|
Pin = Pin_;
|
||||||
|
Capture = Capture_;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save data format and current sample rate.
|
||||||
|
//
|
||||||
|
DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)DataFormat_;
|
||||||
|
CurrentRate = DataFormat->WaveFormatEx.nSamplesPerSec;
|
||||||
|
NumberOfChannels = DataFormat->WaveFormatEx.nChannels;
|
||||||
|
|
||||||
|
|
||||||
|
if (ServiceGroup_)
|
||||||
|
{
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a service group (a DPC abstraction/helper) to help with
|
||||||
|
// interrupts.
|
||||||
|
//
|
||||||
|
ntStatus = PcNewServiceGroup (&ServiceGroup, NULL);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed to create a service group!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store the base address of this DMA engine.
|
||||||
|
//
|
||||||
|
if (Capture)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// could be PCM or MIC capture
|
||||||
|
//
|
||||||
|
if (Pin == PIN_WAVEIN)
|
||||||
|
{
|
||||||
|
// Base address for DMA registers.
|
||||||
|
m_ulBDAddr = PI_BDBAR;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Base address for DMA registers.
|
||||||
|
m_ulBDAddr = MC_BDBAR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // render
|
||||||
|
{
|
||||||
|
// Base address for DMA registers.
|
||||||
|
m_ulBDAddr = PO_BDBAR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset the DMA and set the BD list pointer.
|
||||||
|
//
|
||||||
|
ResetDMA ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Now set the requested sample rate. In case of a failure, the object
|
||||||
|
// gets destroyed and releases all memory etc.
|
||||||
|
//
|
||||||
|
ntStatus = SetFormat (DataFormat_);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Stream init SetFormat call failed!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the device state.
|
||||||
|
//
|
||||||
|
m_PowerState = PowerDeviceD0;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Call miniport specific init routine
|
||||||
|
//
|
||||||
|
ntStatus = Init_();
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup the Buffer Descriptor Base Address (BDBA) register.
|
||||||
|
//
|
||||||
|
WriteReg32(0, BDList_PhysAddr.LowPart);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Pass the ServiceGroup pointer to portcls.
|
||||||
|
//
|
||||||
|
obj_AddRef(ServiceGroup, (PVOID *)ServiceGroup_);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Store the stream pointer, it is used by the ISR.
|
||||||
|
//
|
||||||
|
Miniport->Streams[Pin/2] = this;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CMiniportStream::~CMiniportStream()
|
||||||
|
{
|
||||||
|
if (Miniport)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Disable interrupts and stop DMA just in case.
|
||||||
|
//
|
||||||
|
if (Miniport->AdapterCommon)
|
||||||
|
{
|
||||||
|
WriteReg8 (X_CR, (UCHAR)0);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Update also the topology miniport if this was the render stream.
|
||||||
|
//
|
||||||
|
if (Miniport->AdapterCommon->GetMiniportTopology () &&
|
||||||
|
(Pin == PIN_WAVEOUT))
|
||||||
|
{
|
||||||
|
Miniport->AdapterCommon->GetMiniportTopology ()->SetCopyProtectFlag (FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Remove stream from miniport Streams array.
|
||||||
|
//
|
||||||
|
if (Miniport->Streams[Pin/2] == this)
|
||||||
|
{
|
||||||
|
Miniport->Streams[Pin/2] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
obj_Release((PVOID *)&Miniport);
|
||||||
|
obj_Release((PVOID *)&ServiceGroup);
|
||||||
|
obj_Release((PVOID *)&PortStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::SetContentId
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine gets called by drmk.sys to pass the content to the driver.
|
||||||
|
* The driver has to enforce the rights passed.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportStream::SetContentId
|
||||||
|
(
|
||||||
|
_In_ ULONG contentId,
|
||||||
|
_In_ PCDRMRIGHTS drmRights
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::SetContentId]"));
|
||||||
|
|
||||||
|
UNREFERENCED_PARAMETER(contentId);
|
||||||
|
|
||||||
|
//
|
||||||
|
// If "drmRights->DigitalOutputDisable" is set, we need to disable S/P-DIF.
|
||||||
|
// Currently, we don't have knowledge about the S/P-DIF interface. However,
|
||||||
|
// in case you expanded the driver with S/P-DIF features you need to disable
|
||||||
|
// S/P-DIF or fail SetContentId. If you have HW that has S/P-DIF turned on
|
||||||
|
// by default and you don't know how to turn off (or you cannot do that)
|
||||||
|
// then you must fail SetContentId.
|
||||||
|
//
|
||||||
|
// In our case, we assume the codec has no S/P-DIF or disabled S/P-DIF by
|
||||||
|
// default, so we can ignore the flag.
|
||||||
|
//
|
||||||
|
// Store the copyright flag. We have to disable PCM recording if it's set.
|
||||||
|
//
|
||||||
|
if (!Miniport->AdapterCommon->GetMiniportTopology ())
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Topology pointer not set!"));
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Miniport->AdapterCommon->GetMiniportTopology ()->
|
||||||
|
SetCopyProtectFlag (drmRights->CopyProtect);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We assume that if we can enforce the rights, that the old content
|
||||||
|
// will be destroyed. We don't need to store the content id since we
|
||||||
|
// have only one playback channel, so we are finished here.
|
||||||
|
//
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMiniportStream::PowerChangeNotify
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::PowerChangeNotify]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// We don't have to check the power state, that's already done by the wave
|
||||||
|
// miniport.
|
||||||
|
//
|
||||||
|
|
||||||
|
DOUT (DBG_POWER, ("Changing state to D%d.",
|
||||||
|
(ULONG)NewState.DeviceState - (ULONG)PowerDeviceD0));
|
||||||
|
|
||||||
|
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))
|
||||||
|
{
|
||||||
|
PowerChangeNotify_(NewState);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PowerDeviceD1:
|
||||||
|
// Here we do nothing. The device has still enough power to keep all
|
||||||
|
// it's register values.
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PowerDeviceD2:
|
||||||
|
case PowerDeviceD3:
|
||||||
|
//
|
||||||
|
// If we power down to D2 or D3 we might loose power, so we have to be
|
||||||
|
// aware of the DMA engine resetting. In that case a play would start
|
||||||
|
// with scatter gather entry 0 (the current index is read only).
|
||||||
|
// This is fine with the RT port.
|
||||||
|
//
|
||||||
|
|
||||||
|
PowerChangeNotify_(NewState);
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine tests for proper data format (calls wave miniport) and sets
|
||||||
|
* or changes the stream data format.
|
||||||
|
* To figure out if the codec supports the sample rate, we just program the
|
||||||
|
* sample rate and read it back. If it matches we return happy, if not then
|
||||||
|
* we restore the sample rate and return unhappy.
|
||||||
|
* We fail this routine if we are currently running (playing or recording).
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportStream::SetFormat
|
||||||
|
(
|
||||||
|
_In_ PKSDATAFORMAT Format
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (Format);
|
||||||
|
|
||||||
|
ULONG TempRate;
|
||||||
|
DWORD dwControlReg;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::SetFormat]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Change sample rate when we are in the stop or pause states - not
|
||||||
|
// while running!
|
||||||
|
//
|
||||||
|
if (DMAEngineState == DMA_ENGINE_ON)
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Ensure format falls in proper range and is supported.
|
||||||
|
//
|
||||||
|
NTSTATUS ntStatus = Miniport->TestDataFormat (Format, Pin);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
return ntStatus;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Retrieve wave format portion.
|
||||||
|
//
|
||||||
|
PWAVEFORMATPCMEX waveFormat = (PWAVEFORMATPCMEX)(Format + 1);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save current rate in this context.
|
||||||
|
//
|
||||||
|
TempRate = waveFormat->Format.nSamplesPerSec;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if we have a codec with one sample rate converter and there are streams
|
||||||
|
// already open.
|
||||||
|
//
|
||||||
|
if (Miniport->Streams[PIN_WAVEIN_OFFSET] && Miniport->Streams[PIN_WAVEOUT_OFFSET] &&
|
||||||
|
!Miniport->AdapterCommon->GetNodeConfig (NODEC_PCM_VSR_INDEPENDENT_RATES))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Figure out at which sample rate the other stream is running.
|
||||||
|
//
|
||||||
|
ULONG ulFrequency;
|
||||||
|
|
||||||
|
if (Miniport->Streams[PIN_WAVEIN_OFFSET] == this)
|
||||||
|
ulFrequency = Miniport->Streams[PIN_WAVEOUT_OFFSET]->CurrentRate;
|
||||||
|
else
|
||||||
|
ulFrequency = Miniport->Streams[PIN_WAVEIN_OFFSET]->CurrentRate;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if this sample rate is requested sample rate.
|
||||||
|
//
|
||||||
|
if (ulFrequency != TempRate)
|
||||||
|
{
|
||||||
|
return STATUS_UNSUCCESSFUL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Program the AC97 to support n channels.
|
||||||
|
//
|
||||||
|
if (Pin == PIN_WAVEOUT)
|
||||||
|
{
|
||||||
|
dwControlReg = Miniport->AdapterCommon->ReadBMControlRegister32 (GLOB_CNT);
|
||||||
|
dwControlReg = (dwControlReg & 0x03F) |
|
||||||
|
(((waveFormat->Format.nChannels >> 1) - 1) * GLOB_CNT_PCM4);
|
||||||
|
Miniport->AdapterCommon->WriteBMControlRegister (GLOB_CNT, dwControlReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check for rate support by hardware. If it is supported, then update
|
||||||
|
// hardware registers else return not implemented and audio stack will
|
||||||
|
// handle it.
|
||||||
|
//
|
||||||
|
if (Capture)
|
||||||
|
{
|
||||||
|
if (Pin == PIN_WAVEIN)
|
||||||
|
{
|
||||||
|
ntStatus = Miniport->AdapterCommon->
|
||||||
|
ProgramSampleRate (AC97REG_RECORD_SAMPLERATE, TempRate);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ntStatus = Miniport->AdapterCommon->
|
||||||
|
ProgramSampleRate (AC97REG_MIC_SAMPLERATE, TempRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// In the playback case we might need to update several DACs
|
||||||
|
// with the new sample rate.
|
||||||
|
//
|
||||||
|
ntStatus = Miniport->AdapterCommon->
|
||||||
|
ProgramSampleRate (AC97REG_FRONT_SAMPLERATE, TempRate);
|
||||||
|
|
||||||
|
if (Miniport->AdapterCommon->GetNodeConfig (NODEC_SURROUND_DAC_PRESENT))
|
||||||
|
{
|
||||||
|
ntStatus = Miniport->AdapterCommon->
|
||||||
|
ProgramSampleRate (AC97REG_SURROUND_SAMPLERATE, TempRate);
|
||||||
|
}
|
||||||
|
if (Miniport->AdapterCommon->GetNodeConfig (NODEC_LFE_DAC_PRESENT))
|
||||||
|
{
|
||||||
|
ntStatus = Miniport->AdapterCommon->
|
||||||
|
ProgramSampleRate (AC97REG_LFE_SAMPLERATE, TempRate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// print information and save the format information.
|
||||||
|
//
|
||||||
|
DataFormat = (PKSDATAFORMAT_WAVEFORMATEX)Format;
|
||||||
|
CurrentRate = TempRate;
|
||||||
|
NumberOfChannels = waveFormat->Format.nChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
UCHAR CMiniportStream::UpdateDMA (void)
|
||||||
|
{
|
||||||
|
// get X_CR register value
|
||||||
|
UCHAR RegisterValue = ReadReg8(X_CR);
|
||||||
|
UCHAR RegisterValueNew = RegisterValue & ~CR_RPBM;
|
||||||
|
if(DMAEngineState == DMA_ENGINE_ON)
|
||||||
|
RegisterValueNew |= CR_RPBM;
|
||||||
|
|
||||||
|
// write X_CR register value
|
||||||
|
if(RegisterValue != RegisterValueNew)
|
||||||
|
WriteReg8(X_CR, RegisterValueNew);
|
||||||
|
return RegisterValueNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int CMiniportStream::GetBuffPos
|
||||||
|
(
|
||||||
|
DWORD* buffPos
|
||||||
|
)
|
||||||
|
{
|
||||||
|
int nCurrentIndex;
|
||||||
|
DWORD RegisterX_PICB;
|
||||||
|
|
||||||
|
if (DMAEngineState == DMA_ENGINE_OFF)
|
||||||
|
{
|
||||||
|
*buffPos = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Repeat this until we get the same reading twice. This will prevent
|
||||||
|
// jumps when we are near the end of the buffer.
|
||||||
|
//
|
||||||
|
do
|
||||||
|
{
|
||||||
|
nCurrentIndex = ReadReg8(X_CIV);
|
||||||
|
|
||||||
|
RegisterX_PICB = ReadReg16 (X_PICB);
|
||||||
|
} while (nCurrentIndex != (int)ReadReg8(X_CIV));
|
||||||
|
|
||||||
|
*buffPos = (BDList[nCurrentIndex].wLength - RegisterX_PICB) * 2;
|
||||||
|
return nCurrentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::ResetDMA
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine resets the Run/Pause bit in the control register. In addition, it
|
||||||
|
* resets all DMA registers contents.
|
||||||
|
|
||||||
|
*/
|
||||||
|
void CMiniportStream::ResetDMA (void)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("ResetDMA"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Turn off DMA engine (or make sure it's turned off)
|
||||||
|
//
|
||||||
|
DMAEngineState = DMA_ENGINE_OFF;
|
||||||
|
UCHAR RegisterValue = UpdateDMA();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Reset all register contents.
|
||||||
|
//
|
||||||
|
RegisterValue |= CR_RR;
|
||||||
|
WriteReg8(X_CR, RegisterValue);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Wait until reset condition is cleared by HW; should not take long.
|
||||||
|
//
|
||||||
|
ULONG count = 0;
|
||||||
|
BOOL bTimedOut = TRUE;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (!(ReadReg8(X_CR) & CR_RR))
|
||||||
|
{
|
||||||
|
bTimedOut = FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
KeStallExecutionProcessor (1);
|
||||||
|
} while (count++ < 10);
|
||||||
|
|
||||||
|
if (bTimedOut)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("ResetDMA TIMEOUT!!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// We only want interrupts upon completion.
|
||||||
|
//
|
||||||
|
RegisterValue = CR_IOCE | CR_LVBIE;
|
||||||
|
WriteReg8(X_CR, RegisterValue);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup the Buffer Descriptor Base Address (BDBA) register.
|
||||||
|
//
|
||||||
|
WriteReg32(0, BDList_PhysAddr.LowPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::ResumeDMA
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine sets the Run/Pause bit for the particular DMA engine to resume
|
||||||
|
* it after it's been paused. This assumes that DMA registers content have
|
||||||
|
* been preserved.
|
||||||
|
*/
|
||||||
|
void CMiniportStream::ResumeDMA (ULONG state)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("ResumeDMA"));
|
||||||
|
|
||||||
|
DMAEngineState |= state;
|
||||||
|
UpdateDMA();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::PauseDMA
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine pauses a hardware stream by reseting the Run/Pause bit in the
|
||||||
|
* control registers, leaving DMA registers content intact so that the stream
|
||||||
|
* can later be resumed.
|
||||||
|
*/
|
||||||
|
void CMiniportStream::PauseDMA (void)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("PauseDMA"));
|
||||||
|
|
||||||
|
DMAEngineState &= DMA_ENGINE_PAUSE;
|
||||||
|
UpdateDMA();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CMiniportStream::WriteReg8(ULONG addr, UCHAR data) { Miniport->AdapterCommon->
|
||||||
|
WriteBMControlRegister (m_ulBDAddr + addr, data); }
|
||||||
|
void CMiniportStream::WriteReg16(ULONG addr, USHORT data) { Miniport->AdapterCommon->
|
||||||
|
WriteBMControlRegister (m_ulBDAddr + addr, data); }
|
||||||
|
void CMiniportStream::WriteReg32(ULONG addr, ULONG data) { Miniport->AdapterCommon->
|
||||||
|
WriteBMControlRegister (m_ulBDAddr + addr, data); }
|
||||||
|
UCHAR CMiniportStream::ReadReg8(ULONG addr) { return Miniport->AdapterCommon->
|
||||||
|
ReadBMControlRegister8 (m_ulBDAddr + addr); }
|
||||||
|
USHORT CMiniportStream::ReadReg16(ULONG addr) { return Miniport->AdapterCommon->
|
||||||
|
ReadBMControlRegister16 (m_ulBDAddr + addr); }
|
||||||
|
ULONG CMiniportStream::ReadReg32(ULONG addr) { return Miniport->AdapterCommon->
|
||||||
|
ReadBMControlRegister32 (m_ulBDAddr + addr); }
|
200
drivers/wdm/audio/drivers/ac97/stream.h
Normal file
200
drivers/wdm/audio/drivers/ac97/stream.h
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
#ifndef _STREAM_H_
|
||||||
|
#define _STREAM_H_
|
||||||
|
|
||||||
|
const int DMA_ENGINE_OFF = 0;
|
||||||
|
const int DMA_ENGINE_PAUSE = 1;
|
||||||
|
const int DMA_ENGINE_PEND = 2;
|
||||||
|
const int DMA_ENGINE_ON = 3;
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Defines
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
//
|
||||||
|
// The scatter gather can (only) handle 32 entries
|
||||||
|
//
|
||||||
|
const int MAX_BDL_ENTRIES = 32;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mask for accessing the scatter gather entries with a counter.
|
||||||
|
//
|
||||||
|
const int BDL_MASK = 31;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structure to describe the AC97 Buffer Descriptor List (BDL).
|
||||||
|
// The AC97 can handle 32 entries, they are allocated at once in common
|
||||||
|
// memory (non-cached memory). To avoid slow-down of CPU, the additional
|
||||||
|
// information for handling this structure is stored in tBDList.
|
||||||
|
//
|
||||||
|
typedef struct tagBDEntry
|
||||||
|
{
|
||||||
|
DWORD dwPtrToPhyAddress;
|
||||||
|
WORD wLength;
|
||||||
|
WORD wPolicyBits;
|
||||||
|
} tBDEntry;
|
||||||
|
|
||||||
|
|
||||||
|
class CMiniportStream : public IDrmAudioStream
|
||||||
|
{
|
||||||
|
UCHAR UpdateDMA(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
CMiniport* Miniport;
|
||||||
|
WavePins Pin; // channel this stream handles.
|
||||||
|
BOOL Capture; // TRUE=Capture,FALSE=Render
|
||||||
|
WORD NumberOfChannels; // Number of channels
|
||||||
|
DEVICE_POWER_STATE m_PowerState; // Current power state of the device.
|
||||||
|
|
||||||
|
PPORTSTREAM_ PortStream;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
PKSDATAFORMAT_WAVEFORMATEX DataFormat; // Data Format
|
||||||
|
|
||||||
|
|
||||||
|
PSERVICEGROUP ServiceGroup; // service group helps with DPCs
|
||||||
|
ULONG CurrentRate; // Current Sample Rate
|
||||||
|
ULONG DMAEngineState; // DMA engine state
|
||||||
|
ULONG m_ulBDAddr; // Offset of the stream's DMA registers.
|
||||||
|
|
||||||
|
PHYSICAL_ADDRESS BDList_PhysAddr; // Physical address of BDList
|
||||||
|
tBDEntry *BDList; // Virtual Address of BDList
|
||||||
|
|
||||||
|
public:
|
||||||
|
~CMiniportStream();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// DMA start/stop/pause/reset routines.
|
||||||
|
//
|
||||||
|
void ResetDMA (void);
|
||||||
|
void PauseDMA (void);
|
||||||
|
void ResumeDMA (ULONG state = DMA_ENGINE_ON);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get playback position
|
||||||
|
//
|
||||||
|
int GetBuffPos
|
||||||
|
(
|
||||||
|
DWORD* buffPos
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Stream regiter read/write
|
||||||
|
//
|
||||||
|
void WriteReg8(ULONG addr, UCHAR data);
|
||||||
|
void WriteReg16(ULONG addr, USHORT data);
|
||||||
|
void WriteReg32(ULONG addr, ULONG data);
|
||||||
|
UCHAR ReadReg8(ULONG addr);
|
||||||
|
USHORT ReadReg16(ULONG addr);
|
||||||
|
ULONG ReadReg32(ULONG addr);
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Include IDrmAudioStream (public/exported) methods.
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
IMP_IDrmAudioStream;
|
||||||
|
|
||||||
|
|
||||||
|
STDMETHODIMP_(NTSTATUS) SetFormat
|
||||||
|
(
|
||||||
|
_In_ PKSDATAFORMAT Format
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// This method is called when the device changes power states.
|
||||||
|
//
|
||||||
|
void PowerChangeNotify
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
);
|
||||||
|
|
||||||
|
virtual void PowerChangeNotify_
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return the current sample rate.
|
||||||
|
//
|
||||||
|
ULONG GetCurrentSampleRate (void)
|
||||||
|
{
|
||||||
|
return CurrentRate;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS Init
|
||||||
|
(
|
||||||
|
IN CMiniport* Miniport_,
|
||||||
|
IN PUNKNOWN PortStream,
|
||||||
|
IN WavePins Pin_,
|
||||||
|
IN BOOLEAN Capture_,
|
||||||
|
IN PKSDATAFORMAT DataFormat_,
|
||||||
|
OUT PSERVICEGROUP *ServiceGroup_
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
virtual void InterruptServiceRoutine() PURE;
|
||||||
|
virtual NTSTATUS Init_() PURE;
|
||||||
|
|
||||||
|
NTSTATUS NonDelegatingQueryInterface
|
||||||
|
(
|
||||||
|
_In_ REFIID Interface,
|
||||||
|
_COM_Outptr_ PVOID * Object,
|
||||||
|
_In_ REFIID iStream,
|
||||||
|
_In_ PUNKNOWN stream
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
NTSTATUS SetState
|
||||||
|
(
|
||||||
|
_In_ KSSTATE State
|
||||||
|
);
|
||||||
|
|
||||||
|
NTSTATUS NormalizePhysicalPosition
|
||||||
|
(
|
||||||
|
_Inout_ PLONGLONG PhysicalPosition
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
PVOID BDList_Alloc();
|
||||||
|
void BDList_Free();
|
||||||
|
|
||||||
|
void UpdateLviCyclic()
|
||||||
|
{
|
||||||
|
UCHAR CIV = ReadReg8(X_CIV);
|
||||||
|
WriteReg8(X_LVI, (CIV-1) & BDL_MASK);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define IMP_CMiniportStream_SetFormat(cType) \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::SetFormat (_In_ PKSDATAFORMAT Format) \
|
||||||
|
{ return CMiniportStream::SetFormat(Format); }
|
||||||
|
|
||||||
|
#define IMP_CMiniportStream_QueryInterface(cType, sType) \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::NonDelegatingQueryInterface( \
|
||||||
|
_In_ REFIID Interface, \
|
||||||
|
_COM_Outptr_ PVOID *Object) \
|
||||||
|
{ return CMiniportStream::NonDelegatingQueryInterface( \
|
||||||
|
Interface, Object, IID_##sType, (sType*)this); }
|
||||||
|
|
||||||
|
#define IMP_CMiniport_SetState(cType) \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::SetState (_In_ KSSTATE State) \
|
||||||
|
{ return CMiniportStream::SetState(State); }
|
||||||
|
|
||||||
|
#define IMP_CMiniport_NormalizePhysicalPosition(cType) \
|
||||||
|
STDMETHODIMP_(NTSTATUS) cType::NormalizePhysicalPosition (_Inout_ PLONGLONG PhysicalPosition) \
|
||||||
|
{ return CMiniportStream::NormalizePhysicalPosition(PhysicalPosition); }
|
||||||
|
|
||||||
|
#endif
|
159
drivers/wdm/audio/drivers/ac97/stream2.cpp
Normal file
159
drivers/wdm/audio/drivers/ac97/stream2.cpp
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
// Every debug output has "Modulname text"
|
||||||
|
#define STR_MODULENAME "AC97 Stream2: "
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PVOID CMiniportStream::BDList_Alloc()
|
||||||
|
{
|
||||||
|
// get DMA_ADAPTER object
|
||||||
|
PDMA_ADAPTER AdapterObject = (PDMA_ADAPTER)
|
||||||
|
Miniport->DmaChannel->GetAdapterObject();
|
||||||
|
|
||||||
|
// allocate DBList
|
||||||
|
BDList = (tBDEntry *)AdapterObject->DmaOperations->
|
||||||
|
AllocateCommonBuffer (AdapterObject,
|
||||||
|
MAX_BDL_ENTRIES * sizeof (tBDEntry),
|
||||||
|
&BDList_PhysAddr, FALSE);
|
||||||
|
return BDList;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMiniportStream::BDList_Free()
|
||||||
|
{
|
||||||
|
if (BDList)
|
||||||
|
{
|
||||||
|
// get DMA_ADAPTER object
|
||||||
|
PDMA_ADAPTER AdapterObject = (PDMA_ADAPTER)
|
||||||
|
Miniport->DmaChannel->GetAdapterObject();
|
||||||
|
|
||||||
|
// free DBList
|
||||||
|
AdapterObject->DmaOperations->
|
||||||
|
FreeCommonBuffer (AdapterObject,
|
||||||
|
PAGE_SIZE,
|
||||||
|
BDList_PhysAddr,
|
||||||
|
(PVOID)BDList,
|
||||||
|
FALSE);
|
||||||
|
BDList = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::PowerChangeNotify
|
||||||
|
*****************************************************************************
|
||||||
|
* This functions saves and maintains the stream state through power changes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void CMiniportStream::PowerChangeNotify_
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if(NewState.DeviceState == PowerDeviceD0)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// The scatter gather list is already arranged. A reset of the DMA
|
||||||
|
// brings all pointers to the default state. From there we can start.
|
||||||
|
//
|
||||||
|
|
||||||
|
ResetDMA ();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Disable interrupts and stop DMA just in case.
|
||||||
|
Miniport->AdapterCommon->WriteBMControlRegister (m_ulBDAddr + X_CR, (UCHAR)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::SetState
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine sets/changes the DMA engine state to play, stop, or pause
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportStream::SetState
|
||||||
|
(
|
||||||
|
_In_ KSSTATE State
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportStream::SetState]"));
|
||||||
|
DOUT (DBG_STREAM, ("SetState to %d", State));
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start or stop the DMA engine dependent of the state.
|
||||||
|
//
|
||||||
|
switch (State)
|
||||||
|
{
|
||||||
|
case KSSTATE_STOP:
|
||||||
|
// We reset the DMA engine which will also reset the position pointers.
|
||||||
|
ResetDMA ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KSSTATE_ACQUIRE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KSSTATE_PAUSE:
|
||||||
|
// pause now.
|
||||||
|
PauseDMA ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KSSTATE_RUN:
|
||||||
|
//
|
||||||
|
// Let's rock.
|
||||||
|
//
|
||||||
|
// Make sure we are not running already.
|
||||||
|
if (DMAEngineState == DMA_ENGINE_ON)
|
||||||
|
{
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kick DMA again just in case.
|
||||||
|
ResumeDMA ();
|
||||||
|
UpdateLviCyclic();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportStream::NormalizePhysicalPosition
|
||||||
|
*****************************************************************************
|
||||||
|
* Given a physical position based on the actual number of bytes transferred,
|
||||||
|
* this function converts the position to a time-based value of 100ns units.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportStream::NormalizePhysicalPosition
|
||||||
|
(
|
||||||
|
_Inout_ PLONGLONG PhysicalPosition
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG SampleSize;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("NormalizePhysicalPosition"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Determine the sample size in bytes
|
||||||
|
//
|
||||||
|
SampleSize = DataFormat->WaveFormatEx.nChannels * 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Calculate the time in 100ns steps.
|
||||||
|
//
|
||||||
|
*PhysicalPosition = (_100NS_UNITS_PER_SECOND / SampleSize *
|
||||||
|
*PhysicalPosition) / CurrentRate;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
182
drivers/wdm/audio/drivers/ac97/wavecyclicminiport.cpp
Normal file
182
drivers/wdm/audio/drivers/ac97/wavecyclicminiport.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
// Every debug output has "Modulname text"
|
||||||
|
#define STR_MODULENAME "AC97 Wave Cyclic: "
|
||||||
|
|
||||||
|
#include "wavecyclicminiport.h"
|
||||||
|
#include "wavecyclicstream.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IMP_CMiniport(CMiniportWaveCyclic, IID_IMiniportWaveCyclic)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateAC97MiniportWaveCyclic
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a AC97 wave miniport object for the AC97 adapter.
|
||||||
|
* This uses a macro from STDUNK.H to do all the work.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateAC97MiniportWaveCyclic
|
||||||
|
(
|
||||||
|
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, ("[CreateAC97MiniportWaveCyclic]"));
|
||||||
|
|
||||||
|
STD_CREATE_BODY_WITH_TAG_(CMiniportWaveCyclic,Unknown,UnknownOuter,PoolType,
|
||||||
|
PoolTag, PMINIPORTWAVECYCLIC);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclic::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* Initializes the miniport.
|
||||||
|
* Initializes variables and modifies the wave topology if needed.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclic::Init
|
||||||
|
(
|
||||||
|
_In_ PUNKNOWN UnknownAdapter,
|
||||||
|
_In_ PRESOURCELIST ResourceList,
|
||||||
|
_In_ PPORTWAVECYCLIC Port_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
NTSTATUS ntStatus = CMiniport::Init(
|
||||||
|
UnknownAdapter,
|
||||||
|
ResourceList,
|
||||||
|
Port_
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the DMA Channel object.
|
||||||
|
//
|
||||||
|
ntStatus = Port->NewMasterDmaChannel (&DmaChannel, // OutDmaChannel
|
||||||
|
NULL, // OuterUnknown (opt)
|
||||||
|
NULL, // ResourceList (opt)
|
||||||
|
0x1FFFE, // MaximumLength
|
||||||
|
TRUE, // Dma32BitAddresses
|
||||||
|
FALSE, // Dma64BitAddresses
|
||||||
|
Width32Bits, // DmaWidth
|
||||||
|
MaximumDmaSpeed); // DmaSpeed
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed on NewMasterDmaChannel!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// On failure object is destroyed which cleans up.
|
||||||
|
//
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclic::NewStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a new stream.
|
||||||
|
* This function is called when a streaming pin is created.
|
||||||
|
* It checks if the channel is already in use, tests the data format, creates
|
||||||
|
* and initializes the stream object.
|
||||||
|
*/
|
||||||
|
_Use_decl_annotations_
|
||||||
|
STDMETHODIMP CMiniportWaveCyclic::NewStream
|
||||||
|
(
|
||||||
|
PMINIPORTWAVECYCLICSTREAM *Stream,
|
||||||
|
PUNKNOWN OuterUnknown,
|
||||||
|
POOL_TYPE PoolType,
|
||||||
|
ULONG Pin_,
|
||||||
|
BOOLEAN Capture,
|
||||||
|
PKSDATAFORMAT DataFormat,
|
||||||
|
PDMACHANNEL *DmaChannel_,
|
||||||
|
PSERVICEGROUP *ServiceGroup
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (Stream);
|
||||||
|
ASSERT (DataFormat);
|
||||||
|
ASSERT (DmaChannel_);
|
||||||
|
ASSERT (ServiceGroup);
|
||||||
|
|
||||||
|
CMiniportWaveCyclicStream *pWaveCyclicStream = NULL;
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveCyclic::NewStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check parameters.
|
||||||
|
//
|
||||||
|
ntStatus = ValidateFormat (DataFormat, (WavePins)Pin_);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a new stream.
|
||||||
|
//
|
||||||
|
ntStatus = CreateMiniportWaveCyclicStream (&pWaveCyclicStream, OuterUnknown,
|
||||||
|
PoolType);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return in case of an error.
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to create stream!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the stream.
|
||||||
|
//
|
||||||
|
|
||||||
|
ntStatus = pWaveCyclicStream->Init ((CMiniport*)this,
|
||||||
|
NULL,
|
||||||
|
(WavePins)Pin_,
|
||||||
|
Capture,
|
||||||
|
DataFormat,
|
||||||
|
ServiceGroup);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Release the stream and clean up.
|
||||||
|
//
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to init stream!"));
|
||||||
|
pWaveCyclicStream->Release ();
|
||||||
|
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save the pointers.
|
||||||
|
//
|
||||||
|
*Stream = (PMINIPORTWAVECYCLICSTREAM)pWaveCyclicStream;
|
||||||
|
obj_AddRef(DmaChannel, (PVOID *)DmaChannel_);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
77
drivers/wdm/audio/drivers/ac97/wavecyclicminiport.h
Normal file
77
drivers/wdm/audio/drivers/ac97/wavecyclicminiport.h
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _MINWAVE_H_
|
||||||
|
#define _MINWAVE_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#define PPORT_ PPORTWAVECYCLIC
|
||||||
|
#define PPORTSTREAM_ PUNKNOWN
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Forward References
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
class CMiniportWaveCyclicStream;
|
||||||
|
|
||||||
|
extern NTSTATUS CreateMiniportWaveCyclicStream
|
||||||
|
(
|
||||||
|
OUT CMiniportWaveCyclicStream ** pWaveIchStream,
|
||||||
|
IN PUNKNOWN pUnknown,
|
||||||
|
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
|
||||||
|
__drv_reportError("Must succeed pool allocations are forbidden. "
|
||||||
|
"Allocation failures cause a system crash"))
|
||||||
|
IN POOL_TYPE PoolType
|
||||||
|
);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Classes
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclic
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave PCI miniport. This object is associated with the device and is
|
||||||
|
* created when the device is started. The class inherits IMiniportWaveCyclic
|
||||||
|
* so it can expose this interface, CUnknown so it automatically gets
|
||||||
|
* reference counting and aggregation support, and IPowerNotify for ACPI
|
||||||
|
* power management notification.
|
||||||
|
*/
|
||||||
|
class CMiniportWaveCyclic : public IMiniportWaveCyclic,
|
||||||
|
public CUnknown,
|
||||||
|
public CMiniport
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// The stream class accesses a lot of private member variables.
|
||||||
|
// A better way would be to abstract the access through member
|
||||||
|
// functions which on the other hand would produce more overhead
|
||||||
|
// both in CPU time and programming time.
|
||||||
|
friend class CMiniportWaveCyclicStream;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in MINWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in MINWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CMiniportWaveCyclic);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Include IMiniportWaveCyclic (public/exported) methods
|
||||||
|
//
|
||||||
|
IMP_IMiniportWaveCyclic;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MINWAVE_H_
|
||||||
|
|
230
drivers/wdm/audio/drivers/ac97/wavecyclicstream.cpp
Normal file
230
drivers/wdm/audio/drivers/ac97/wavecyclicstream.cpp
Normal file
|
@ -0,0 +1,230 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
// Every debug output has "Modulname text"
|
||||||
|
#define STR_MODULENAME "AC97 Cyclic Stream: "
|
||||||
|
|
||||||
|
#include "wavecyclicminiport.h"
|
||||||
|
#include "wavecyclicstream.h"
|
||||||
|
#define BUFFERTIME 10
|
||||||
|
#define NBUFFERS 4
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IMP_CMiniportStream_QueryInterface(CMiniportWaveCyclicStream, IMiniportWavePciStream);
|
||||||
|
IMP_CMiniport_SetState(CMiniportWaveCyclicStream);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* General Info
|
||||||
|
*****************************************************************************
|
||||||
|
* To protect the stBDList structure that is used to store mappings, we use a
|
||||||
|
* spin lock called MapLock. This spin lock is also acquired when we change
|
||||||
|
* the DMA registers. Normally, changes in stBDList and the DMA registers go
|
||||||
|
* hand in hand. In case we only want to change the DMA registers, we need
|
||||||
|
* to acquire the spin lock!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateMiniportWaveCyclicStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a wave miniport stream object for the AC97 audio adapter. This is
|
||||||
|
* (nearly) like the macro STD_CREATE_BODY_ from STDUNK.H.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateMiniportWaveCyclicStream
|
||||||
|
(
|
||||||
|
OUT CMiniportWaveCyclicStream **MiniportCyclicStream,
|
||||||
|
IN PUNKNOWN pUnknownOuter,
|
||||||
|
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
|
||||||
|
__drv_reportError("Must succeed pool allocations are forbidden. "
|
||||||
|
"Allocation failures cause a system crash"))
|
||||||
|
IN POOL_TYPE PoolType
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CreateMiniportWaveCyclicStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is basically like the macro at stdunk with the change that we
|
||||||
|
// don't cast to interface unknown but to interface MiniportIchStream.
|
||||||
|
//
|
||||||
|
*MiniportCyclicStream = new (PoolType, PoolTag)
|
||||||
|
CMiniportWaveCyclicStream (pUnknownOuter);
|
||||||
|
if (*MiniportCyclicStream)
|
||||||
|
{
|
||||||
|
(*MiniportCyclicStream)->AddRef ();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream ()
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveCyclicStream::~CMiniportWaveCyclicStream]"));
|
||||||
|
|
||||||
|
// Release the scatter/gather table.
|
||||||
|
BDList_Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine initializes the stream object, sets up the BDL, and programs
|
||||||
|
* the buffer descriptor list base address register for the pin being
|
||||||
|
* initialized.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportWaveCyclicStream::Init_()
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveCyclicStream::Init]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup the Buffer Descriptor List (BDL)
|
||||||
|
// Allocate 32 entries of 8 bytes (one BDL entry).
|
||||||
|
// The pointer is aligned on a 8 byte boundary (that's what we need).
|
||||||
|
//
|
||||||
|
|
||||||
|
if (!BDList_Alloc())
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed AllocateCommonBuffer!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResizeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::SetFormat
|
||||||
|
(
|
||||||
|
_In_ PKSDATAFORMAT Format
|
||||||
|
)
|
||||||
|
{
|
||||||
|
NTSTATUS ntStatus = CMiniportStream::SetFormat(Format);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
return ntStatus;
|
||||||
|
return ResizeBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS CMiniportWaveCyclicStream::ResizeBuffer(void)
|
||||||
|
{
|
||||||
|
// calculate buffer size
|
||||||
|
DWORD nSamples = DataFormat->WaveFormatEx.nSamplesPerSec * BUFFERTIME / 1000;
|
||||||
|
DWORD bufferSize = DataFormat->WaveFormatEx.nBlockAlign * nSamples;
|
||||||
|
DWORD totalSize = bufferSize * NBUFFERS;
|
||||||
|
|
||||||
|
// allocate buffer
|
||||||
|
PDMACHANNEL DmaChannel = Miniport->DmaChannel;
|
||||||
|
DWORD allocSize = DmaChannel->AllocatedBufferSize();
|
||||||
|
if(totalSize > allocSize)
|
||||||
|
{
|
||||||
|
DmaChannel->FreeBuffer();
|
||||||
|
NTSTATUS ntStatus = DmaChannel->AllocateBuffer(totalSize, 0);
|
||||||
|
if (!NT_SUCCESS (ntStatus)) {
|
||||||
|
m_bufferSize = 0;
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DmaChannel->SetBufferSize(totalSize);
|
||||||
|
|
||||||
|
// initialize bdList
|
||||||
|
DWORD addr = DmaChannel->PhysicalAddress().LowPart;
|
||||||
|
for (UINT loop = 0; loop < MAX_BDL_ENTRIES; loop++)
|
||||||
|
{
|
||||||
|
BDList[loop].dwPtrToPhyAddress = addr + bufferSize * (loop % NBUFFERS);
|
||||||
|
BDList[loop].wLength = (WORD)bufferSize/2;
|
||||||
|
BDList[loop].wPolicyBits = BUP_SET | IOC_ENABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update buffer size
|
||||||
|
m_bufferSize = bufferSize;
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
STDMETHODIMP_(ULONG) CMiniportWaveCyclicStream::SetNotificationFreq
|
||||||
|
(
|
||||||
|
_In_ ULONG Interval,
|
||||||
|
_Out_ PULONG FrameSize
|
||||||
|
)
|
||||||
|
{
|
||||||
|
*FrameSize = m_bufferSize;
|
||||||
|
return BUFFERTIME;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IMP_CMiniport_NormalizePhysicalPosition(CMiniportWaveCyclicStream);
|
||||||
|
|
||||||
|
STDMETHODIMP_(void) CMiniportWaveCyclicStream::Silence
|
||||||
|
(
|
||||||
|
_In_ PVOID Buffer,
|
||||||
|
_In_ ULONG ByteCount
|
||||||
|
)
|
||||||
|
{
|
||||||
|
memset(Buffer, 0, ByteCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream::GetPosition
|
||||||
|
*****************************************************************************
|
||||||
|
* Gets the stream position. This is a byte count of the current position of
|
||||||
|
* a stream running on a particular DMA engine. We must return a sample
|
||||||
|
* accurate count or the MiniportDrv32 wave drift tests (35.2 & 36.2) will fail.
|
||||||
|
*
|
||||||
|
* The position is the sum of three parts:
|
||||||
|
* 1) The total number of bytes in released buffers
|
||||||
|
* 2) The position in the current buffer.
|
||||||
|
* 3) The total number of bytes in played but not yet released buffers
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveCyclicStream::GetPosition
|
||||||
|
(
|
||||||
|
_Out_ PULONG Position
|
||||||
|
)
|
||||||
|
{
|
||||||
|
UCHAR nCurrentIndex ;
|
||||||
|
|
||||||
|
ASSERT (Position);
|
||||||
|
|
||||||
|
nCurrentIndex = GetBuffPos((DWORD*)Position);
|
||||||
|
nCurrentIndex %= NBUFFERS;
|
||||||
|
*Position += nCurrentIndex * m_bufferSize;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CMiniportWaveCyclicStream::InterruptServiceRoutine()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Update the LVI so that we cycle around in the scatter gather list.
|
||||||
|
//
|
||||||
|
UpdateLviCyclic();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Request DPC service for PCM out.
|
||||||
|
//
|
||||||
|
Miniport->Port->Notify (ServiceGroup);
|
||||||
|
}
|
116
drivers/wdm/audio/drivers/ac97/wavecyclicstream.h
Normal file
116
drivers/wdm/audio/drivers/ac97/wavecyclicstream.h
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _ICHWAVE_H_
|
||||||
|
#define _ICHWAVE_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Data Structures and Typedefs
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is a description of one mapping entry. It contains information
|
||||||
|
// about the buffer and a tag which is used for "cancel mappings".
|
||||||
|
// For one mapping that is described here, there is an entry in the
|
||||||
|
// scatter gather engine.
|
||||||
|
//
|
||||||
|
typedef struct tagMapData
|
||||||
|
{
|
||||||
|
ULONG ulTag; //tag, a simple counter.
|
||||||
|
PHYSICAL_ADDRESS PhysAddr; //phys. addr. of buffer
|
||||||
|
PVOID pVirtAddr; //virt. addr. of buffer
|
||||||
|
ULONG ulBufferLength; //buffer length
|
||||||
|
} tMapData;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structure needed to keep track of the BDL tables.
|
||||||
|
// This structure is seperated from tBDEntry because we want to
|
||||||
|
// have it in cached memory (and not along with tBDEntry in non-
|
||||||
|
// cached memory).
|
||||||
|
//
|
||||||
|
typedef struct tagBDList
|
||||||
|
{
|
||||||
|
tBDEntry *pBDEntryBackup;// needed for rearranging the BDList
|
||||||
|
tMapData *pMapData; // mapping list
|
||||||
|
tMapData *pMapDataBackup;// needed for rearranging the BDList
|
||||||
|
int nHead; // index for the BDL Head
|
||||||
|
int nTail; // index for the BDL Tail
|
||||||
|
ULONG ulTagCounter; // the tag is a simple counter.
|
||||||
|
int nBDEntries; // number of entries.
|
||||||
|
} tBDList;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Classes
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave miniport stream.
|
||||||
|
*/
|
||||||
|
class CMiniportWaveCyclicStream : public IMiniportWaveCyclicStream,
|
||||||
|
public CUnknown,
|
||||||
|
public CMiniportStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
DWORD m_bufferSize;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* ICHWAVE.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
CMiniportWaveCyclic* Wave() {
|
||||||
|
return (CMiniportWaveCyclic*)Miniport; }
|
||||||
|
|
||||||
|
NTSTATUS ResizeBuffer(void);
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in ICHWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in ICHWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CMiniportWaveCyclicStream);
|
||||||
|
|
||||||
|
~CMiniportWaveCyclicStream ();
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Include IMiniportWaveCyclicStream (public/exported) methods.
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
IMP_IMiniportWaveCyclicStream;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CMiniportWaveCyclicStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializes the Stream object.
|
||||||
|
//
|
||||||
|
NTSTATUS Init_();
|
||||||
|
|
||||||
|
void InterruptServiceRoutine();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
214
drivers/wdm/audio/drivers/ac97/wavepciminiport.cpp
Normal file
214
drivers/wdm/audio/drivers/ac97/wavepciminiport.cpp
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file wavepciminiport.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 Wave: "
|
||||||
|
|
||||||
|
#include "wavepciminiport.h"
|
||||||
|
#include "wavepcistream.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
IMP_CMiniport(CMiniportWaveICH, IID_IMiniportWavePci)
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateAC97MiniportWavePCI
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a AC97 wave miniport object for the AC97 adapter.
|
||||||
|
* This uses a macro from STDUNK.H to do all the work.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateAC97MiniportWavePCI
|
||||||
|
(
|
||||||
|
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, ("[CreateAC97MiniportWavePCI]"));
|
||||||
|
|
||||||
|
STD_CREATE_BODY_WITH_TAG_(CMiniportWaveICH,Unknown,UnknownOuter,PoolType,
|
||||||
|
PoolTag, PMINIPORTWAVEPCI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICH::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* Initializes the miniport.
|
||||||
|
* Initializes variables and modifies the wave topology if needed.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICH::Init
|
||||||
|
(
|
||||||
|
_In_ PUNKNOWN UnknownAdapter,
|
||||||
|
_In_ PRESOURCELIST ResourceList,
|
||||||
|
_In_ PPORTWAVEPCI Port_,
|
||||||
|
_Out_ PSERVICEGROUP *ServiceGroup_
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// No miniport service group
|
||||||
|
//
|
||||||
|
*ServiceGroup_ = NULL;
|
||||||
|
|
||||||
|
NTSTATUS ntStatus = CMiniport::Init(
|
||||||
|
UnknownAdapter,
|
||||||
|
ResourceList,
|
||||||
|
Port_
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create the DMA Channel object.
|
||||||
|
//
|
||||||
|
ntStatus = Port->NewMasterDmaChannel (&DmaChannel, // OutDmaChannel
|
||||||
|
NULL, // OuterUnknown (opt)
|
||||||
|
NonPagedPool, // Pool Type
|
||||||
|
NULL, // ResourceList (opt)
|
||||||
|
TRUE, // ScatterGather
|
||||||
|
TRUE, // Dma32BitAddresses
|
||||||
|
FALSE, // Dma64BitAddresses
|
||||||
|
FALSE, // IgnoreCount
|
||||||
|
Width32Bits, // DmaWidth
|
||||||
|
MaximumDmaSpeed, // DmaSpeed
|
||||||
|
0x1FFFE, // MaximumLength (128KByte -2)
|
||||||
|
0); // DmaPort
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed on NewMasterDmaChannel!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// On failure object is destroyed which cleans up.
|
||||||
|
//
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICH::NewStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a new stream.
|
||||||
|
* This function is called when a streaming pin is created.
|
||||||
|
* It checks if the channel is already in use, tests the data format, creates
|
||||||
|
* and initializes the stream object.
|
||||||
|
*/
|
||||||
|
_Use_decl_annotations_
|
||||||
|
STDMETHODIMP CMiniportWaveICH::NewStream
|
||||||
|
(
|
||||||
|
PMINIPORTWAVEPCISTREAM *Stream,
|
||||||
|
PUNKNOWN OuterUnknown,
|
||||||
|
POOL_TYPE PoolType,
|
||||||
|
PPORTWAVEPCISTREAM PortStream,
|
||||||
|
ULONG Pin_,
|
||||||
|
BOOLEAN Capture,
|
||||||
|
PKSDATAFORMAT DataFormat,
|
||||||
|
PDMACHANNEL *DmaChannel_,
|
||||||
|
PSERVICEGROUP *ServiceGroup
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ASSERT (Stream);
|
||||||
|
ASSERT (PortStream);
|
||||||
|
ASSERT (DataFormat);
|
||||||
|
ASSERT (DmaChannel_);
|
||||||
|
ASSERT (ServiceGroup);
|
||||||
|
|
||||||
|
CMiniportWaveICHStream *pWaveICHStream = NULL;
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICH::NewStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check parameters.
|
||||||
|
//
|
||||||
|
ntStatus = ValidateFormat (DataFormat, (WavePins)Pin_);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create a new stream.
|
||||||
|
//
|
||||||
|
ntStatus = CreateMiniportWaveICHStream (&pWaveICHStream, OuterUnknown,
|
||||||
|
PoolType);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Return in case of an error.
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to create stream!"));
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the stream.
|
||||||
|
//
|
||||||
|
ntStatus = pWaveICHStream->Init ((CMiniport*)this,
|
||||||
|
PortStream,
|
||||||
|
(WavePins)Pin_,
|
||||||
|
Capture,
|
||||||
|
DataFormat,
|
||||||
|
ServiceGroup);
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Release the stream and clean up.
|
||||||
|
//
|
||||||
|
DOUT (DBG_ERROR, ("[NewStream] Failed to init stream!"));
|
||||||
|
pWaveICHStream->Release ();
|
||||||
|
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save the pointers.
|
||||||
|
//
|
||||||
|
*Stream = (PMINIPORTWAVEPCISTREAM)pWaveICHStream;
|
||||||
|
obj_AddRef(DmaChannel, (PVOID *)DmaChannel_);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICH::Service
|
||||||
|
*****************************************************************************
|
||||||
|
* Processing routine for dealing with miniport interrupts. This routine is
|
||||||
|
* called at DISPATCH_LEVEL.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(void) CMiniportWaveICH::Service (void)
|
||||||
|
{
|
||||||
|
// not needed
|
||||||
|
}
|
79
drivers/wdm/audio/drivers/ac97/wavepciminiport.h
Normal file
79
drivers/wdm/audio/drivers/ac97/wavepciminiport.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file wavepciminiport.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _MINWAVE_H_
|
||||||
|
#define _MINWAVE_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#define PPORT_ PPORTWAVEPCI
|
||||||
|
#define PPORTSTREAM_ PPORTWAVEPCISTREAM
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Forward References
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
class CMiniportWaveICHStream;
|
||||||
|
|
||||||
|
extern NTSTATUS CreateMiniportWaveICHStream
|
||||||
|
(
|
||||||
|
OUT CMiniportWaveICHStream ** pWaveIchStream,
|
||||||
|
IN PUNKNOWN pUnknown,
|
||||||
|
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
|
||||||
|
__drv_reportError("Must succeed pool allocations are forbidden. "
|
||||||
|
"Allocation failures cause a system crash"))
|
||||||
|
IN POOL_TYPE PoolType
|
||||||
|
);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Classes
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICH
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave PCI miniport. This object is associated with the device and is
|
||||||
|
* created when the device is started. The class inherits IMiniportWavePci
|
||||||
|
* so it can expose this interface, CUnknown so it automatically gets
|
||||||
|
* reference counting and aggregation support, and IPowerNotify for ACPI
|
||||||
|
* power management notification.
|
||||||
|
*/
|
||||||
|
class CMiniportWaveICH : public IMiniportWavePci,
|
||||||
|
public CUnknown,
|
||||||
|
public CMiniport
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// The stream class accesses a lot of private member variables.
|
||||||
|
// A better way would be to abstract the access through member
|
||||||
|
// functions which on the other hand would produce more overhead
|
||||||
|
// both in CPU time and programming time.
|
||||||
|
friend class CMiniportWaveICHStream;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in MINWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in MINWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CMiniportWaveICH);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Include IMiniportWavePci (public/exported) methods
|
||||||
|
//
|
||||||
|
IMP_IMiniportWavePci;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // _MINWAVE_H_
|
||||||
|
|
885
drivers/wdm/audio/drivers/ac97/wavepcistream.cpp
Normal file
885
drivers/wdm/audio/drivers/ac97/wavepcistream.cpp
Normal file
|
@ -0,0 +1,885 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file wavepcistream.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 Stream: "
|
||||||
|
|
||||||
|
#include "wavepciminiport.h"
|
||||||
|
#include "wavepcistream.h"
|
||||||
|
|
||||||
|
IMP_CMiniportStream_SetFormat(CMiniportWaveICHStream);
|
||||||
|
IMP_CMiniportStream_QueryInterface(CMiniportWaveICHStream, IMiniportWavePciStream);
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* General Info
|
||||||
|
*****************************************************************************
|
||||||
|
* To protect the stBDList structure that is used to store mappings, we use a
|
||||||
|
* spin lock called MapLock. This spin lock is also acquired when we change
|
||||||
|
* the DMA registers. Normally, changes in stBDList and the DMA registers go
|
||||||
|
* hand in hand. In case we only want to change the DMA registers, we need
|
||||||
|
* to acquire the spin lock!
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg("PAGE")
|
||||||
|
#endif
|
||||||
|
/*****************************************************************************
|
||||||
|
* CreateMiniportWaveICHStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Creates a wave miniport stream object for the AC97 audio adapter. This is
|
||||||
|
* (nearly) like the macro STD_CREATE_BODY_ from STDUNK.H.
|
||||||
|
*/
|
||||||
|
NTSTATUS CreateMiniportWaveICHStream
|
||||||
|
(
|
||||||
|
OUT CMiniportWaveICHStream **MiniportPCIStream,
|
||||||
|
IN PUNKNOWN pUnknownOuter,
|
||||||
|
_When_((PoolType & NonPagedPoolMustSucceed) != 0,
|
||||||
|
__drv_reportError("Must succeed pool allocations are forbidden. "
|
||||||
|
"Allocation failures cause a system crash"))
|
||||||
|
IN POOL_TYPE PoolType
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CreateMiniportWaveICHStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is basically like the macro at stdunk with the change that we
|
||||||
|
// don't cast to interface unknown but to interface MiniportIchStream.
|
||||||
|
//
|
||||||
|
*MiniportPCIStream = new (PoolType, PoolTag)
|
||||||
|
CMiniportWaveICHStream (pUnknownOuter);
|
||||||
|
if (*MiniportPCIStream)
|
||||||
|
{
|
||||||
|
(*MiniportPCIStream)->AddRef ();
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::~CMiniportWaveICHStream
|
||||||
|
*****************************************************************************
|
||||||
|
* Destructor
|
||||||
|
*/
|
||||||
|
CMiniportWaveICHStream::~CMiniportWaveICHStream ()
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::~CMiniportWaveICHStream]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Print information about the scatter gather list.
|
||||||
|
//
|
||||||
|
DOUT (DBG_DMA, ("Head %d, Tail %d, Entries %d.",
|
||||||
|
stBDList.nHead, stBDList.nTail,
|
||||||
|
stBDList.nBDEntries));
|
||||||
|
|
||||||
|
// Release the scatter/gather table.
|
||||||
|
BDList_Free();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::Init
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine initializes the stream object, sets up the BDL, and programs
|
||||||
|
* the buffer descriptor list base address register for the pin being
|
||||||
|
* initialized.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportWaveICHStream::Init_()
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::Init]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// The rule here is that we return when we fail without a cleanup.
|
||||||
|
// The destructor will relase the allocated memory.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialize the BDL spinlock.
|
||||||
|
//
|
||||||
|
KeInitializeSpinLock (&MapLock);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Setup the Buffer Descriptor List (BDL)
|
||||||
|
// Allocate 32 entries of 8 bytes (one BDL entry).
|
||||||
|
// The pointer is aligned on a 8 byte boundary (that's what we need).
|
||||||
|
//
|
||||||
|
|
||||||
|
if (!BDList_Alloc())
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("Failed AllocateCommonBuffer!"));
|
||||||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
}
|
||||||
|
|
||||||
|
PPREFETCHOFFSET PreFetchOffset;
|
||||||
|
//
|
||||||
|
// Query for the new interface "PreFetchOffset" and use
|
||||||
|
// function offered there in case the interface is offered.
|
||||||
|
//
|
||||||
|
if (NT_SUCCESS(PortStream->QueryInterface(IID_IPreFetchOffset, (PVOID *)&PreFetchOffset)))
|
||||||
|
{
|
||||||
|
// why don't we pad by 32 sample frames
|
||||||
|
PreFetchOffset->SetPreFetchOffset(32 * (DataFormat->WaveFormatEx.nChannels * 2));
|
||||||
|
PreFetchOffset->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::GetAllocatorFraming
|
||||||
|
*****************************************************************************
|
||||||
|
* Returns the framing requirements for this device.
|
||||||
|
* That is sample size (for one sample) and preferred frame (buffer) size.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetAllocatorFraming
|
||||||
|
(
|
||||||
|
_Out_ PKSALLOCATOR_FRAMING AllocatorFraming
|
||||||
|
)
|
||||||
|
{
|
||||||
|
PAGED_CODE ();
|
||||||
|
|
||||||
|
ULONG SampleSize;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::GetAllocatorFraming]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Determine sample size in bytes. Always number of
|
||||||
|
// channels * 2 (because 16-bit).
|
||||||
|
//
|
||||||
|
SampleSize = DataFormat->WaveFormatEx.nChannels * 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Report the suggested requirements.
|
||||||
|
//
|
||||||
|
AllocatorFraming->RequirementsFlags =
|
||||||
|
KSALLOCATOR_REQUIREMENTF_SYSTEM_MEMORY |
|
||||||
|
KSALLOCATOR_REQUIREMENTF_PREFERENCES_ONLY;
|
||||||
|
AllocatorFraming->Frames = 8;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Currently, arbitrarily selecting 10ms as the frame target size.
|
||||||
|
//
|
||||||
|
// This value needs to be sample block aligned for AC97 to work correctly.
|
||||||
|
// Assumes 100Hz minimum sample rate (otherwise FrameSize is 0 bytes)
|
||||||
|
//
|
||||||
|
AllocatorFraming->FrameSize = SampleSize * (DataFormat->WaveFormatEx.nSamplesPerSec / 100);
|
||||||
|
AllocatorFraming->FileAlignment = FILE_LONG_ALIGNMENT;
|
||||||
|
AllocatorFraming->PoolType = NonPagedPool;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::PowerChangeNotify_
|
||||||
|
*****************************************************************************
|
||||||
|
* This functions saves and maintains the stream state through power changes.
|
||||||
|
*/
|
||||||
|
void CMiniportWaveICHStream::PowerChangeNotify_
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
if(NewState.DeviceState == PowerDeviceD0)
|
||||||
|
{
|
||||||
|
ResetDMA ();
|
||||||
|
|
||||||
|
// Restore the remaining DMA registers, that is last valid index
|
||||||
|
// only if the index is not pointing to 0. Note that the index is
|
||||||
|
// equal to head + entries.
|
||||||
|
if (stBDList.nTail)
|
||||||
|
{
|
||||||
|
WriteReg8 (X_LVI, (UCHAR)((stBDList.nTail - 1) & BDL_MASK));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
// Disable interrupts and stop DMA just in case.
|
||||||
|
WriteReg8 (X_CR, (UCHAR)0);
|
||||||
|
|
||||||
|
// Get current index
|
||||||
|
// int nCurrentIndex = (int)ReadReg8 (X_CIV);
|
||||||
|
}
|
||||||
|
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::SetState
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine sets/changes the DMA engine state to play, stop, or pause
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::SetState
|
||||||
|
(
|
||||||
|
_In_ KSSTATE State
|
||||||
|
)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::SetState]"));
|
||||||
|
DOUT (DBG_STREAM, ("SetState to %d", State));
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start or stop the DMA engine dependent of the state.
|
||||||
|
//
|
||||||
|
switch (State)
|
||||||
|
{
|
||||||
|
case KSSTATE_STOP:
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
// Just pause DMA. If we have mappings left in our queue,
|
||||||
|
// portcls will call RevokeMappings to destroy them.
|
||||||
|
PauseDMA ();
|
||||||
|
|
||||||
|
// release the mapping spin lock
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
// Release processed mappings
|
||||||
|
ReleaseUsedMappings ();
|
||||||
|
|
||||||
|
// Reset the position counters.
|
||||||
|
TotalBytesMapped = TotalBytesReleased = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KSSTATE_ACQUIRE:
|
||||||
|
case KSSTATE_PAUSE:
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
// pause now.
|
||||||
|
PauseDMA ();
|
||||||
|
|
||||||
|
// release the mapping spin lock
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
// Release processed mappings
|
||||||
|
ReleaseUsedMappings ();
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case KSSTATE_RUN:
|
||||||
|
//
|
||||||
|
// Let's rock.
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
// Make sure we are not running already.
|
||||||
|
if (DMAEngineState & DMA_ENGINE_ON)
|
||||||
|
{
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release processed mappings.
|
||||||
|
ReleaseUsedMappings ();
|
||||||
|
|
||||||
|
// Get new mappings.
|
||||||
|
GetNewMappings ();
|
||||||
|
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
// Kick DMA again just in case.
|
||||||
|
ResumeDMA (DMA_ENGINE_PEND);
|
||||||
|
|
||||||
|
// release the mapping spin lock
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::Service
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine is called by the port driver in response to the interrupt
|
||||||
|
* service routine requesting service on the stream's service group.
|
||||||
|
* Requesting service on the service group results in a DPC being scheduled
|
||||||
|
* that calls this routine when it runs.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(void) CMiniportWaveICHStream::Service (void)
|
||||||
|
{
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("Service"));
|
||||||
|
|
||||||
|
// release all mappings
|
||||||
|
ReleaseUsedMappings ();
|
||||||
|
|
||||||
|
// get new mappings
|
||||||
|
GetNewMappings ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::NormalizePhysicalPosition
|
||||||
|
*****************************************************************************
|
||||||
|
* Given a physical position based on the actual number of bytes transferred,
|
||||||
|
* this function converts the position to a time-based value of 100ns units.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::NormalizePhysicalPosition
|
||||||
|
(
|
||||||
|
_Inout_ PLONGLONG PhysicalPosition
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ULONG SampleSize;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("NormalizePhysicalPosition"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Determine the sample size in bytes
|
||||||
|
//
|
||||||
|
SampleSize = DataFormat->WaveFormatEx.nChannels * 2;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Calculate the time in 100ns steps.
|
||||||
|
//
|
||||||
|
*PhysicalPosition = (_100NS_UNITS_PER_SECOND / SampleSize *
|
||||||
|
*PhysicalPosition) / CurrentRate;
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::GetPosition
|
||||||
|
*****************************************************************************
|
||||||
|
* Gets the stream position. This is a byte count of the current position of
|
||||||
|
* a stream running on a particular DMA engine. We must return a sample
|
||||||
|
* accurate count or the MiniportDrv32 wave drift tests (35.2 & 36.2) will fail.
|
||||||
|
*
|
||||||
|
* The position is the sum of three parts:
|
||||||
|
* 1) The total number of bytes in released buffers
|
||||||
|
* 2) The position in the current buffer.
|
||||||
|
* 3) The total number of bytes in played but not yet released buffers
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::GetPosition
|
||||||
|
(
|
||||||
|
_Out_ PULONGLONG Position
|
||||||
|
)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
UCHAR nCurrentIndex = 0;
|
||||||
|
DWORD buffPos;
|
||||||
|
|
||||||
|
ASSERT (Position);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Acquire the mapping spin lock.
|
||||||
|
//
|
||||||
|
KeAcquireSpinLock (&MapLock, &OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start with TotalBytesReleased (mappings released).
|
||||||
|
//
|
||||||
|
*Position = TotalBytesReleased;
|
||||||
|
|
||||||
|
//
|
||||||
|
// If we have entries in the list, we may have buffers that have not been
|
||||||
|
// released but have been at least partially played.
|
||||||
|
//
|
||||||
|
if (DMAEngineState != DMA_ENGINE_OFF)
|
||||||
|
{
|
||||||
|
nCurrentIndex = GetBuffPos(&buffPos);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add in our position in the current buffer
|
||||||
|
//
|
||||||
|
*Position += buffPos;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Total any buffers that have been played and not released.
|
||||||
|
//
|
||||||
|
if (nCurrentIndex != ((stBDList.nHead -1) & BDL_MASK))
|
||||||
|
{
|
||||||
|
int i = stBDList.nHead;
|
||||||
|
while (i != nCurrentIndex)
|
||||||
|
{
|
||||||
|
*Position += (ULONGLONG)stBDList.pMapData[i].ulBufferLength;
|
||||||
|
i = (i + 1) & BDL_MASK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DOUT (DBG_POSITION, ("[GetPosition] POS: %08x'%08x\n", (DWORD)(*Position >> 32), (DWORD)*Position));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release the mapping spin lock.
|
||||||
|
//
|
||||||
|
KeReleaseSpinLock (&MapLock, OldIrql);
|
||||||
|
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::RevokeMappings
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine is used by the port to revoke mappings previously delivered
|
||||||
|
* to the miniport stream that have not yet been unmapped. This would
|
||||||
|
* typically be called in response to an I/O cancellation request.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(NTSTATUS) CMiniportWaveICHStream::RevokeMappings
|
||||||
|
(
|
||||||
|
_In_ PVOID FirstTag,
|
||||||
|
_In_ PVOID LastTag,
|
||||||
|
_Out_ PULONG MappingsRevoked
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ASSERT (MappingsRevoked);
|
||||||
|
|
||||||
|
KIRQL OldIrql;
|
||||||
|
ULONG ulOldDMAEngineState;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::RevokeMappings]"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// print information about the scatter gather list.
|
||||||
|
//
|
||||||
|
DOUT (DBG_DMA, ("Head %d, Tail %d, Entries %d.",
|
||||||
|
stBDList.nHead, stBDList.nTail,
|
||||||
|
stBDList.nBDEntries));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Start accessing the mappings.
|
||||||
|
//
|
||||||
|
KeAcquireSpinLock (&MapLock, &OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save old DMA engine state.
|
||||||
|
//
|
||||||
|
ulOldDMAEngineState = DMAEngineState;
|
||||||
|
|
||||||
|
//
|
||||||
|
// First stop the DMA engine so it won't process the next buffer in the
|
||||||
|
// scatter gather list which might be one of the revoked buffers.
|
||||||
|
//
|
||||||
|
PauseDMA ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Mark items as revoked
|
||||||
|
//
|
||||||
|
|
||||||
|
for (intptr_t i = (intptr_t)FirstTag; i != (intptr_t)LastTag; i = (i + 1) & BDL_MASK)
|
||||||
|
{
|
||||||
|
if (stBDList.pMapData[i].ulState == 1)
|
||||||
|
{
|
||||||
|
stBDList.pMapData[i].ulState = 2;
|
||||||
|
BDList[i].wLength = 0;
|
||||||
|
BDList[i].wPolicyBits = 0;
|
||||||
|
*MappingsRevoked += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Just un-pause the DMA engine if it was running before
|
||||||
|
//
|
||||||
|
ResumeDMA(ulOldDMAEngineState);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release the mapping spin lock
|
||||||
|
//
|
||||||
|
KeReleaseSpinLock (&MapLock, OldIrql);
|
||||||
|
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::MappingAvailable
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine is called by the port driver to notify the stream that there
|
||||||
|
* are new mappings available. Note that this is ONLY called after the stream
|
||||||
|
* has previously had a GetMapping() call fail due to lack of available
|
||||||
|
* mappings.
|
||||||
|
*/
|
||||||
|
STDMETHODIMP_(void) CMiniportWaveICHStream::MappingAvailable (void)
|
||||||
|
{
|
||||||
|
DOUT (DBG_PRINT, ("MappingAvailable"));
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release processed mappings.
|
||||||
|
//
|
||||||
|
ReleaseUsedMappings ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Process the new mappings.
|
||||||
|
//
|
||||||
|
GetNewMappings ();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::GetNewMappings
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine is called when new mappings are available from the port driver.
|
||||||
|
* The routine places mappings into the input mapping queue. AC97 can handle up
|
||||||
|
* to 32 entries (descriptors). We program the DMA registers if we have at least
|
||||||
|
* one mapping in the queue. The mapping spin lock must be held when calling
|
||||||
|
* this routine.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportWaveICHStream::GetNewMappings (void)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
|
||||||
|
NTSTATUS ntStatus = STATUS_SUCCESS;
|
||||||
|
ULONG ulBytesMapped = 0;
|
||||||
|
int nInsertMappings = 0;
|
||||||
|
int nTail; // aut. variable
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::GetNewMappings]"));
|
||||||
|
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
// detect reentrance
|
||||||
|
if(m_inGetMapping) {
|
||||||
|
m_inGetMapping = 2;
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (DBG)
|
||||||
|
if (ReadReg16 (X_SR) & SR_CELV)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// We starve. :-(
|
||||||
|
//
|
||||||
|
DOUT (DBG_DMA, ("[GetNewMappings] We starved ... Head %d, Tail %d, Entries %d.",
|
||||||
|
stBDList.nHead, stBDList.nTail, stBDList.nBDEntries));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// Get available mappings up to the max of 31 that we can hold in the BDL.
|
||||||
|
//
|
||||||
|
while (stBDList.nBDEntries < (MAX_BDL_ENTRIES - 1))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Get the information from the list.
|
||||||
|
//
|
||||||
|
ULONG Flags;
|
||||||
|
ULONG ulTag = stBDList.nTail;
|
||||||
|
ULONG ulBufferLength;
|
||||||
|
PHYSICAL_ADDRESS PhysAddr;
|
||||||
|
PVOID VirtAddr;
|
||||||
|
|
||||||
|
|
||||||
|
// Release the mapping spin lock
|
||||||
|
NEW_MAPPINGS_AVAILBLE_MAYBE:
|
||||||
|
m_inGetMapping = TRUE;
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Try to get the mapping from the port.
|
||||||
|
// Here comes the problem: When calling GetMapping or ReleaseMapping we
|
||||||
|
// cannot hold our spin lock. So we need to buffer the return values and
|
||||||
|
// stick the information into the structure later when we have the spin
|
||||||
|
// lock acquired.
|
||||||
|
//
|
||||||
|
ntStatus = PortStream->GetMapping ((PVOID)ULongToPtr(ulTag),
|
||||||
|
(PPHYSICAL_ADDRESS)&PhysAddr,
|
||||||
|
&VirtAddr,
|
||||||
|
&ulBufferLength,
|
||||||
|
&Flags);
|
||||||
|
|
||||||
|
// Acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Quit this loop when we run out of mappings.
|
||||||
|
//
|
||||||
|
if (!NT_SUCCESS (ntStatus))
|
||||||
|
{
|
||||||
|
if(m_inGetMapping == 2)
|
||||||
|
goto NEW_MAPPINGS_AVAILBLE_MAYBE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sanity check: The audio stack will not give you data
|
||||||
|
// that you cannot handle, but an application could use
|
||||||
|
// DirectKS and send bad buffer down.
|
||||||
|
|
||||||
|
// One mapping needs to be <0x1FFFF bytes for mono
|
||||||
|
// streams on the AC97.
|
||||||
|
if (ulBufferLength > 0x1FFFE)
|
||||||
|
{
|
||||||
|
// That is a little too long. That should never happen.
|
||||||
|
DOUT (DBG_ERROR, ("[GetNewMappings] Buffer length too long!"));
|
||||||
|
ulBufferLength = 0x1FFFE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The AC97 can only handle WORD aligned buffers.
|
||||||
|
if (PhysAddr.LowPart & 0x01)
|
||||||
|
{
|
||||||
|
// we cannot play that! Set the buffer length to 0 so
|
||||||
|
// that the HW will skip the buffer.
|
||||||
|
DOUT (DBG_WARNING, ("[GetNewMappings] Buffer address unaligned!"));
|
||||||
|
ulBufferLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The AC97 cannot handle unaligned mappings with respect
|
||||||
|
// to the frame size (eg. 42 bytes on 4ch playback).
|
||||||
|
if (ulBufferLength % NumberOfChannels)
|
||||||
|
{
|
||||||
|
// modify the length (don't play the rest of the bytes)
|
||||||
|
DOUT (DBG_WARNING, ("[GetNewMappings] Buffer length unaligned!"));
|
||||||
|
ulBufferLength -= ulBufferLength % NumberOfChannels;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save the mapping.
|
||||||
|
//
|
||||||
|
nTail = stBDList.nTail;
|
||||||
|
stBDList.pMapData[nTail].ulBufferLength = ulBufferLength;
|
||||||
|
stBDList.pMapData[nTail].ulState = 1;
|
||||||
|
ulBytesMapped += ulBufferLength;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fill in the BDL entry with pointer to physical address and length.
|
||||||
|
//
|
||||||
|
BDList[nTail].dwPtrToPhyAddress = PhysAddr.LowPart;
|
||||||
|
BDList[nTail].wLength = (WORD)(ulBufferLength >> 1);
|
||||||
|
BDList[nTail].wPolicyBits = BUP_SET;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate an interrupt when portcls tells us to or roughly every 10ms.
|
||||||
|
//
|
||||||
|
if (Flags || (ulBytesMapped > (CurrentRate * NumberOfChannels * 2) / 100))
|
||||||
|
{
|
||||||
|
BDList[nTail].wPolicyBits |= IOC_ENABLE;
|
||||||
|
ulBytesMapped = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Take the new mapping into account.
|
||||||
|
//
|
||||||
|
stBDList.nTail = (stBDList.nTail + 1) & BDL_MASK;
|
||||||
|
stBDList.nBDEntries++;
|
||||||
|
TotalBytesMapped += (ULONGLONG)ulBufferLength;
|
||||||
|
nInsertMappings++;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set last valid index (LVI) register! We need to do this here to avoid inconsistency
|
||||||
|
// of the BDList with the HW. Note that we need to release spin locks every time
|
||||||
|
// we call into portcls, that means we can be interrupted by ReleaseUsedMappings.
|
||||||
|
//
|
||||||
|
WriteReg8 (X_LVI, (UCHAR)nTail);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// If there were processed mappings, print out some debug messages and eventually try to
|
||||||
|
// restart DMA engine.
|
||||||
|
//
|
||||||
|
if (nInsertMappings)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Print debug information ...
|
||||||
|
//
|
||||||
|
DOUT (DBG_DMA, ("[GetNewMappings] Got %d mappings.", nInsertMappings));
|
||||||
|
DOUT (DBG_DMA, ("[GetNewMappings] Head %d, Tail %d, Entries %d.",
|
||||||
|
stBDList.nHead, stBDList.nTail, stBDList.nBDEntries));
|
||||||
|
|
||||||
|
if(stBDList.nBDEntries >= 2)
|
||||||
|
ResumeDMA (DMA_ENGINE_PAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the mapping spin lock
|
||||||
|
m_inGetMapping = FALSE;
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
return ntStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream::ReleaseUsedMappings
|
||||||
|
*****************************************************************************
|
||||||
|
* This routine unmaps previously mapped memory that the hardware has
|
||||||
|
* completed processing on. This routine is typically called at DPC level
|
||||||
|
* from the stream deferred procedure call that results from a stream
|
||||||
|
* interrupt. The mapping spin lock must be held when calling this routine.
|
||||||
|
*/
|
||||||
|
NTSTATUS CMiniportWaveICHStream::ReleaseUsedMappings (void)
|
||||||
|
{
|
||||||
|
KIRQL OldIrql;
|
||||||
|
int nMappingsReleased = 0;
|
||||||
|
|
||||||
|
DOUT (DBG_PRINT, ("[CMiniportWaveICHStream::ReleaseUsedMappings]"));
|
||||||
|
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Clean up everything to that index.
|
||||||
|
//
|
||||||
|
while (stBDList.nBDEntries)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Get current index
|
||||||
|
//
|
||||||
|
int nCurrentIndex = (int)ReadReg8 (X_CIV);
|
||||||
|
|
||||||
|
//
|
||||||
|
// When CIV is == Head -1 we released all mappings.
|
||||||
|
//
|
||||||
|
if (nCurrentIndex == ((stBDList.nHead - 1) & BDL_MASK))
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check if CIV is between head and tail.
|
||||||
|
//
|
||||||
|
if (nCurrentIndex < stBDList.nHead)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Check for CIV being outside range.
|
||||||
|
//
|
||||||
|
if ((nCurrentIndex + MAX_BDL_ENTRIES) >=
|
||||||
|
(stBDList.nHead + stBDList.nBDEntries))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[ReleaseUsedMappings] CIV out of range!"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Check for CIV being outside range.
|
||||||
|
//
|
||||||
|
if (nCurrentIndex >= (stBDList.nHead + stBDList.nBDEntries))
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[ReleaseUsedMappings] CIV out of range!"));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check to see if we've released all the buffers.
|
||||||
|
//
|
||||||
|
if (stBDList.nHead == nCurrentIndex)
|
||||||
|
{
|
||||||
|
if (nCurrentIndex == ((stBDList.nTail - 1) & BDL_MASK))
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// A special case is starvation or stop of stream, when the
|
||||||
|
// DMA engine finished playing the buffers, CVI is equal LVI
|
||||||
|
// and SR_CELV is set.
|
||||||
|
//
|
||||||
|
if (!(ReadReg16 (X_SR) & SR_CELV))
|
||||||
|
{
|
||||||
|
// It is still playing the last buffer.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// In case the CVI=LVI bit is set, nBDEntries should be 1
|
||||||
|
//
|
||||||
|
if (stBDList.nBDEntries != 1)
|
||||||
|
{
|
||||||
|
DOUT (DBG_ERROR, ("[ReleaseUsedMappings] Inconsitency: Tail reached and Entries != 1."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Bail out. Current Index did not move.
|
||||||
|
//
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save the tag and remove the entry from the list.
|
||||||
|
//
|
||||||
|
ULONG ulTag = stBDList.nHead;
|
||||||
|
stBDList.nBDEntries--;
|
||||||
|
stBDList.nHead = (stBDList.nHead + 1) & BDL_MASK;
|
||||||
|
nMappingsReleased++;
|
||||||
|
|
||||||
|
// if entry has not been revoked
|
||||||
|
if(stBDList.pMapData[ulTag].ulState == 1)
|
||||||
|
{
|
||||||
|
TotalBytesReleased += (ULONGLONG)stBDList.pMapData[ulTag].ulBufferLength;
|
||||||
|
|
||||||
|
// Release the mapping spin lock
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Release this entry.
|
||||||
|
//
|
||||||
|
PortStream->ReleaseMapping ((PVOID)ULongToPtr(ulTag));
|
||||||
|
|
||||||
|
// acquire the mapping spin lock
|
||||||
|
KeAcquireSpinLock (&MapLock,&OldIrql);
|
||||||
|
}
|
||||||
|
|
||||||
|
stBDList.pMapData[ulTag].ulState = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Print some debug information in case we released mappings.
|
||||||
|
if (nMappingsReleased)
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Print release information and return.
|
||||||
|
//
|
||||||
|
DOUT (DBG_DMA, ("[ReleaseUsedMappings] Head %d, Tail %d, Entries %d.",
|
||||||
|
stBDList.nHead, stBDList.nTail, stBDList.nBDEntries));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release the mapping spin lock
|
||||||
|
KeReleaseSpinLock (&MapLock,OldIrql);
|
||||||
|
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Non paged code begins here
|
||||||
|
*****************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
#pragma code_seg()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void CMiniportWaveICHStream::InterruptServiceRoutine()
|
||||||
|
{
|
||||||
|
//
|
||||||
|
// Request DPC service for PCM out.
|
||||||
|
//
|
||||||
|
Miniport->Port->Notify (ServiceGroup);
|
||||||
|
}
|
138
drivers/wdm/audio/drivers/ac97/wavepcistream.h
Normal file
138
drivers/wdm/audio/drivers/ac97/wavepcistream.h
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
/********************************************************************************
|
||||||
|
** Copyright (c) 1998-2000 Microsoft Corporation. All Rights Reserved.
|
||||||
|
**
|
||||||
|
** Portions Copyright (c) 1998-1999 Intel Corporation
|
||||||
|
**
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
/* The file wavepcistream.h was reviewed by LCA in June 2011 and is acceptable for use by Microsoft. */
|
||||||
|
|
||||||
|
#ifndef _ICHWAVE_H_
|
||||||
|
#define _ICHWAVE_H_
|
||||||
|
|
||||||
|
#include "shared.h"
|
||||||
|
#include "miniport.h"
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Data Structures and Typedefs
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is a description of one mapping entry. It contains information
|
||||||
|
// about the buffer and a tag which is used for "cancel mappings".
|
||||||
|
// For one mapping that is described here, there is an entry in the
|
||||||
|
// scatter gather engine.
|
||||||
|
//
|
||||||
|
typedef struct tagMapData
|
||||||
|
{
|
||||||
|
ULONG ulBufferLength; //buffer length
|
||||||
|
ULONG ulState; //buffer state
|
||||||
|
} tMapData;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Structure needed to keep track of the BDL tables.
|
||||||
|
// This structure is seperated from tBDEntry because we want to
|
||||||
|
// have it in cached memory (and not along with tBDEntry in non-
|
||||||
|
// cached memory).
|
||||||
|
//
|
||||||
|
typedef struct tagBDList
|
||||||
|
{
|
||||||
|
int nHead; // index for the BDL Head
|
||||||
|
int nTail; // index for the BDL Tail
|
||||||
|
int nBDEntries; // number of entries.
|
||||||
|
tMapData pMapData[32]; // mapping list
|
||||||
|
} tBDList;
|
||||||
|
|
||||||
|
|
||||||
|
//*****************************************************************************
|
||||||
|
// Classes
|
||||||
|
//*****************************************************************************
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* CMiniportWaveICHStream
|
||||||
|
*****************************************************************************
|
||||||
|
* AC97 wave miniport stream.
|
||||||
|
*/
|
||||||
|
class CMiniportWaveICHStream : public IMiniportWavePciStream,
|
||||||
|
public CUnknown,
|
||||||
|
public CMiniportStream
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
//
|
||||||
|
// CMiniportWaveICHStream private variables
|
||||||
|
//
|
||||||
|
KSPIN_LOCK MapLock; // for processing mappings.
|
||||||
|
ULONGLONG TotalBytesMapped; // factor in position calculation
|
||||||
|
ULONGLONG TotalBytesReleased; // factor in position calculation
|
||||||
|
BOOL m_inGetMapping;
|
||||||
|
|
||||||
|
tBDList stBDList; // needed for scatter gather org.
|
||||||
|
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CMiniportWaveICHStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*
|
||||||
|
* These are private member functions used internally by the object. See
|
||||||
|
* ICHWAVE.CPP for specific descriptions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Called when new mappings have to be processed.
|
||||||
|
//
|
||||||
|
NTSTATUS GetNewMappings (void);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Called when we want to release some mappings.
|
||||||
|
//
|
||||||
|
NTSTATUS ReleaseUsedMappings (void);
|
||||||
|
|
||||||
|
CMiniportWaveICH* Wave() {
|
||||||
|
return (CMiniportWaveICH*)Miniport; }
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
/*************************************************************************
|
||||||
|
* The following two macros are from STDUNK.H. DECLARE_STD_UNKNOWN()
|
||||||
|
* defines inline IUnknown implementations that use CUnknown's aggregation
|
||||||
|
* support. NonDelegatingQueryInterface() is declared, but it cannot be
|
||||||
|
* implemented generically. Its definition appears in ICHWAVE.CPP.
|
||||||
|
* DEFINE_STD_CONSTRUCTOR() defines inline a constructor which accepts
|
||||||
|
* only the outer unknown, which is used for aggregation. The standard
|
||||||
|
* create macro (in ICHWAVE.CPP) uses this constructor.
|
||||||
|
*/
|
||||||
|
DECLARE_STD_UNKNOWN ();
|
||||||
|
DEFINE_STD_CONSTRUCTOR (CMiniportWaveICHStream);
|
||||||
|
|
||||||
|
~CMiniportWaveICHStream ();
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Include IMiniportWavePciStream (public/exported) methods.
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
IMP_IMiniportWavePciStream;
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* CMiniportWaveICHStream methods
|
||||||
|
*************************************************************************
|
||||||
|
*/
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initializes the Stream object.
|
||||||
|
//
|
||||||
|
NTSTATUS Init_();
|
||||||
|
|
||||||
|
//
|
||||||
|
// This method is called when the device changes power states.
|
||||||
|
//
|
||||||
|
void PowerChangeNotify_
|
||||||
|
(
|
||||||
|
IN POWER_STATE NewState
|
||||||
|
);
|
||||||
|
|
||||||
|
void InterruptServiceRoutine();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -151,6 +151,12 @@ Used Version: ???
|
||||||
License: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later.html)
|
License: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later.html)
|
||||||
URL: http://www.vmware.com/download/open_sources.html
|
URL: http://www.vmware.com/download/open_sources.html
|
||||||
|
|
||||||
|
Title: AC97 Sample Driver
|
||||||
|
Path: drivers/wdm/audio/drivers/ac97
|
||||||
|
Used Version: git commit 411c271
|
||||||
|
License: MIT (https://spdx.org/licenses/MIT.html)
|
||||||
|
URL: https://github.com/microsoftarchive/msdn-code-gallery-microsoft/tree/master/Official%20Windows%20Driver%20Kit%20Sample/Windows%20Driver%20Kit%20(WDK)%208.1%20Samples/%5BC%2B%2B%5D-windows-driver-kit-81-cpp/WDK%208.1%20C%2B%2B%20Samples/AC97%20Driver%20Sample/C%2B%2B
|
||||||
|
|
||||||
Title: Open Source WDM Drivers for C-Media 8738/8768 based soundcards
|
Title: Open Source WDM Drivers for C-Media 8738/8768 based soundcards
|
||||||
Path: drivers/wdm/audio/drivers/CMIDriver
|
Path: drivers/wdm/audio/drivers/CMIDriver
|
||||||
Used Version: 1.2.6
|
Used Version: 1.2.6
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue