- Notifications
You must be signed in to change notification settings - Fork2
tiwai/hda-emu
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
HD-AUDIO EMULATOR=================GENERAL-------hda-emu ("HD-Audio EMUlator", or "Horribly Destructive AndEmbarrassingly Malfunctional Unit") is a program written for makingtest and debug of ALSA HD-audio driver easier. The source treecontains three things: the HD-audio controller/codec emulation codes,the build stub for codec parser codes in the kernel HD-audio drivertree, and a collection of codec proc files.This package itself doesn't contain the kernel driver code at all.You need to prepare the Linux kernel-tree to emulate, and pass theroot directory of Linux kernel to --with-kerneldir option of configurescript. For example, if you have linux-4.0 kernel in/somewhere/linux-4.0,% ./configure --with-kerneldir=/somewhere/linux-2.0Then it'll copy (symlink) the files from the given directory intokernel subdirectory.The wrapper of kernel functions can be found in include directory.There are several cheats and tricks there. Many codes are replacedwith other normal functions.The build is as usual -- configure and make. No special requirement,as far as I know.GETTING STARTED---------------Start hda-emu program with a codec proc file to emulate.% hda-emu my-proc-fileThe program will skip other lines than proc contents, so you can passalsa-info.sh output, too. If the file contains multiple codecs, youcan specify the codec index via -i option. As default, the firstcodec is used.% hda-emu -i 1 alsa-info.txtFor testing, just pick up one file found in codecs subdirectory.As default, the program is pretty verbose. When you start it up,you'll see a bunch of messages like:% hda-emu codecs/stac9200-dell-d820-laptop# Parsing..hda_codec: Unknown model for STAC9200, using BIOS defaultshda_codec: pin nid 08 bios pin config 40c003fa...The emulator prints all logs of snd_printdd() and snd_printd() in thedefault log level in addition to its own messages. To suppress thedriver log messages, pass -l option with an appropriate log level.The level 0 will suppress all messages except for errors.The level 1 will show snd_printd() and snd_printdd() messages as wellas basic messages of hda-emu itself.The level 2 will show each codec verbs in addition to messages shownvia the level 1.The program has a stupid dumb command shell, and will ask you a commandafter initializing and showing the messages.# Building controls...CTRL: add: Master Playback Volume:0...# Building PCMs...> At this point, you can give a command. For example, type "help" or"h" and enter,> helpAvailable commands: list get set dump jack option help verb pm \init fs quitRun "help CMD" for detailsNo surprise, huh?The basic commands are described in the next sections.BASIC COMMANDS--------------* list List the control (mixer) elements created by the driver.> list1: Master Playback Volume:0 (1)2: Master Playback Switch:0 (1)3: Input Source:0 (1)4: Capture Volume:0 (1)... The first number is the control element numid. This number is used in get and set commands to specify the element. Then the control element name follows. The number after colon (:) shows the element index. When multiple elements with the same name exists, there can be more than zero there. The last number in parentheses is the number of multi-elements. When this is more than 1, it means that there are multiple elements.* get Get the control element information. Pass the numid of the element to see.> get 11 Master Playback Volume:0MIN/MAX: 0/31, VAL: [0] [0] In this case, the element 1, "Master Playback Volume", takes an integer value between 0 and 31, and its current values are 0 and 0 (usually for left and right channels). Instead of the numid, you can pass the name string of the control element. Use single- or double quotes around the name.> get "Master Playback Volume"1 Master Playback Volume:0MIN/MAX: 0/31, VAL: [0] [0] If there are multiple control elements with the same name and different indices, pass the index number with ":" suffix.> get "Headphone Playback Switch:1"20 Headphone Playback Switch:1MIN/MAX: 0/1, VAL: [1] [1]* set Set the control element value. Pass the numid or the name string in the first argument, and pass and the value(s) in the rest.> set 1 10 4 or> set "Master Playback Volume" 10 4 When the log level is more than 1, you'll see the codec verbs such assend: NID=0xb, VERB=0x3a0(set_amp_gain_mute), PARM=0xasend: NID=0xb, VERB=0x390(set_amp_gain_mute), PARM=0x84* dump Dump the codec proc output. This is identical with proc file contents.> dumpCodec: SigmaTel STAC9200Address: 0Vendor Id: 0x83847690Subsystem Id: 0x102801cc... If you would like to show only a certain widget, you can pass the widget NID as the argument.> dump 0x10Node 0x10 [Pin Complex] wcaps 0x400181: Stereo Pincap 0x081737: IN OUT Pin Default 0x01a19021: [Jack] Mic at Ext Rear Conn = 1/8, Color = Pink Pin-ctls: 0x20: IN Connection: 1 Passing the value 0 to the first argument is equivalent without passing the argument, i.e. showing full dump. By passing the value 1, it dumps only the codec and FG information (e.g. codec name, vendor id, etc). Also, you can pass a file name to the second argument if you want to save the dump to the specifid file.* jack Get / set the jack plug state. When invoked without arguments, it lists the active pin NIDs.> jackNID 0x0d: cfg 0x032110f0: [Jack] HP Out at Ext LeftNID 0x0f: cfg 0x03a110f0: [Jack] Mic at Ext LeftNID 0x10: cfg 0x921701f0: [Fixed] Speaker at Int FrontNID 0x11: cfg 0x95a601f0: [Fixed] Mic at Int Top Usually this shows the jack status the driver keeps internally. If you'd need to look at the original default pincfg, pass -r option.> jack -rNID 0x0d: cfg 0x921701f0: [Fixed] Speaker at Int Front... (Note that the difference appears only with 3.8 or later kernel code. In the older kernels, both results with and without -r will show the same list.) When called with a widget numid, it shows the current jack state.> jack 0x0dJack state [0xd] = 0 To emulate the jack plug / unplug, set the value in the second argument, either 1 or 0. With the loglevel > 1, you'll see the codec verbs handled in the unsol_event handler.> jack 0x0d 1send: NID=0xd, VERB=0xf09(get_pin_sense), PARM=0x0receive: 0x80000000send: NID=0xd, VERB=0x707(set_pin_ctl), PARM=0xc0...* PCM List the registered PCM streams or test the PCM stream. When no argument is passed, hda-emu lists the all registered PCM streams. For example,> PCM0: STAC92xx Analog:0 (audio), play=1, capt=21: STAC92xx Digital:1 (SPDIF), play=1, capt=0 where the first number indicates the stream ID number. For testing a PCM stream, pass the ID number to the first argument, and the stream direction, either playback or capture (or 0, 1). Also, pass the sample rate (default = 48000), channels (default = 2), and format bits (default = 16) if you want to test with different values. Then hda-emu does a single-shot PCM test: open, prepare, cleanup and close.> PCM 0 p 48000 2 16Open PCM STAC92xx Analog for playsend: NID=0x21, VERB=0xf00(get_parameters), PARM=0xa(PCM)receive: 0xe07e0...Prepare PCM, rate=48000, channels=2, format=16 bitsPCM format_val = 0x11... A PCM substream can be specified as a style of "a:b". For example, passing 1:2 for the first argument means that the stream id 1, the substream id 2. This is useful to check when the driver supports the multiple-substreams. As default, PCM command simulates from open to close. When -s option is passed after "PCM", it operates only the open/prepare. When -e option is passed, it operates only the close procedure.* route Show the routes from/to the given widget.> route 0x28Pin[2c] -- Mix[21] -- Mix[1b] -> Pin[28]Out[08] -> Sel[34] -- Mix[1b] -> Pin[28]Pin[28] -- Mix[21] -- Mix[1c] -> Pin[29]Pin[28] -- Mix[21] -- Mix[1b] -> Pin[28]... When -x option is passed, it shows also the routes from/to inactive pins. As default, it shows only the active (i.e. currently connected) routes. When option -a is passed before the widget NID, it shows all routes even though the connection isn't active. (-a option includes -i option implicitly.)> route -a 0x28Pin[2c] -- Mix[21] -- Mix[1b] -> Pin[28]Out[08] -> Sel[34] -- Mix[1b] -> Pin[28]Pin[28] -- Mix[21] -x Sel[1f] -> In [11]Pin[28] -- Mix[21] -x Sel[1e] -> In [10]Pin[28] -- Mix[21] -- Mix[1c] -> Pin[29]Pin[28] -- Mix[21] -- Mix[1b] -> Pin[28]... The options -i and -o specify the direction of connection. When -i is passed, it shows only the routes ended to the given NID. When -o is passed, shows only the routes starting from the given NID. As default, both routes are shown. The option -m makes the mute flag appearing in the routes. When an input or an output amp is muted, the letter '|' appears in the path.* pm Simulate suspend/resume cycle. When option -i is given, the pin control values and the in/out amp values are reset to the initial state before resume. When option -r is given, the pin control values and the in/out amp values are set randomly before resume. These options are useful to check whether the resume procedure properly restores the values.* quit Quit the shell.ADVANCED COMMANDS-----------------* verb Execute a verb. Use as you like.> verb 0x0d 0xf07 0x00Command response:: 0xc0* unsol Issue an arbitrary unsolicited event. Pass the NID to issue an event. The tag is automatically obtained from the current widget status.* option Change the module option dynamically. Currently, only power_save option can be changed by this command.> option power_savePower-save = 0> option power_save 1> option power_savePower-save = 1* fs Access to sysfs file entry. This command takes a sub-command, either of "get", "set" and "list". Not all sysfs files are available yet. "fs list" shows the available sysfs file entries.> fs listAvailable sysfs entries: driver_pin_configs (R) init_pin_configs (R) ...> fs get init_pin_configs0x24 0x010140100x25 0x010110120x26 0x01016011...> fs set user_pin_configs 0x24 0x411111f0send: NID=0x24, VERB=0x71c(set_config_def_0), PARM=0xf0...> fs set hints jack_detect=false> fs get hintsjack_detect = false> fs set reconfig 1LOG FILE--------The messages can be saved to a file by starting with -o option.When -q option is given, the program doesn't echo the messages tostdout but outputs only to the log file. It's useful for automatingtest. The shell command can be fed from stdin, so you can write acommand sequence in a file and redirect it to hda-emu.MODEL OPTION------------If you need to give a certain "model" module option to the driver,e.g. if you need to debug the behavior of the driver withmodel=laptop, pass it via -m option to hda-emu. Also, the PCI SSIDcan be overridden by -p option.COLORED OUTPUT--------------As default, hda-emu outputs the lines in color using ANSI escapesequences. The escape sequences will be stripped in the log files,though. You can toggle color/non-color behavior via -C and -Moptions, respectively.INITIAL PIN-CONFIGURATION AND HINTS-----------------------------------As default, hda-emu takes the default pin-configurations as set in thegiven codec proc file (or the proc file content in the givenalsa-info.sh output). But the codec proc file might contain thestatus that is already overwritten by the driver or changed by user,which isn't identical with the real initial state.When the pin-config sysfs file is available, hda-emu can read it andinitialize the pin defaults accordingly via -P option. When the inputfile is a recent alsa-info.sh output containing sysfs file entries,pass like "-P hwC0D0/init_pin_configs". Then hda-emu will initializethe pin-default contents found in hwC0D0/init_pin_configs sysfs file.You can also pass an external file name to -P option instead of thesysfs files in the input file. The file must contain a pair ofregister and pin-config value in each line just like in *_pin_configssysfs files. Also, you can pass a pin config directly via -P optoin,e.g. -P 0x0a=0x12345678.For providing the user-defined pin configurations, use -U instead of-P option. The difference between these two options is that the pinconfiguration set via -P option may be overridden by the driver's ownsetup while the pin configuration set via -U remains over the driver'ssetup.Similarly, you can give the initial hints strings either from sysfsfile in alsa-info.sh output or an external file via -H option. Also,you can pass a hint directrly via -H option, e.g. -H "jack_detect=0".If you want to debug a certain jack-plug state at the initial time,pass the pin NID to turn on via -j option. When nothing is set, allpins are assumed to be unplugged at the start up.START WITHOUT CODEC PARSER--------------------------When you don't want to start the codec parser procedure, i.e. justprobe the codec and initializes the instance without invoking theparser, pass -n option. (This corresponds to probe_only=1 option forsnd-hda-intel module.)Then you can inspect the pin config, add hints or whatever, thentrigger the codec parser manually later by "fs set reconfig 1" command.DEBUGGING DRIVER WITH GDB-------------------------It's often useful to debug the driver behavior via gdb. When you pass-a option to hda-emu, it'll send SIGTRAP when the error is from thedriver; i.e. when printk(KERN_ERR ...) is issued. Then gdb will trapit and you can see the code path and invesitage there.The -a option doesn't affect operations when hda-emu isn't invoked ingdb or such, as SIGTRAP is ignored as default in hda-emu.DOWNLOAD--------The git tree is found at:git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/hda-emu.gitA backup repo is at:https://github.com/tiwai/hda-emuLICENSE-------GPL v2. See COPYING file.