mirror of
https://github.com/reactos/reactos.git
synced 2025-04-04 12:39:35 +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)
|
||||
|
|
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)
|
||||
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
|
||||
Path: drivers/wdm/audio/drivers/CMIDriver
|
||||
Used Version: 1.2.6
|
||||
|
|
Loading…
Reference in a new issue