-
Notifications
You must be signed in to change notification settings - Fork 2
/
README
478 lines (340 loc) · 13.9 KB
/
README
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
HD-AUDIO EMULATOR
=================
GENERAL
-------
hda-emu ("HD-Audio EMUlator", or "Horribly Destructive And
Embarrassingly Malfunctional Unit") is a program written for making
test and debug of ALSA HD-audio driver easier. The source tree
contains three things: the HD-audio controller/codec emulation codes,
the build stub for codec parser codes in the kernel HD-audio driver
tree, 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 the
root directory of Linux kernel to --with-kerneldir option of configure
script. For example, if you have linux-4.0 kernel in
/somewhere/linux-4.0,
% ./configure --with-kerneldir=/somewhere/linux-2.0
Then it'll copy (symlink) the files from the given directory into
kernel subdirectory.
The wrapper of kernel functions can be found in include directory.
There are several cheats and tricks there. Many codes are replaced
with 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-file
The program will skip other lines than proc contents, so you can pass
alsa-info.sh output, too. If the file contains multiple codecs, you
can specify the codec index via -i option. As default, the first
codec is used.
% hda-emu -i 1 alsa-info.txt
For 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 defaults
hda_codec: pin nid 08 bios pin config 40c003fa
...
The emulator prints all logs of snd_printdd() and snd_printd() in the
default log level in addition to its own messages. To suppress the
driver 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 well
as basic messages of hda-emu itself.
The level 2 will show each codec verbs in addition to messages shown
via the level 1.
The program has a stupid dumb command shell, and will ask you a command
after 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,
> help
Available commands: list get set dump jack option help verb pm \
init fs quit
Run "help CMD" for details
No surprise, huh?
The basic commands are described in the next sections.
BASIC COMMANDS
--------------
* list
List the control (mixer) elements created by the driver.
> list
1: 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 1
1 Master Playback Volume:0
MIN/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:0
MIN/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:1
MIN/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
as
send: NID=0xb, VERB=0x3a0(set_amp_gain_mute), PARM=0xa
send: NID=0xb, VERB=0x390(set_amp_gain_mute), PARM=0x84
* dump
Dump the codec proc output. This is identical with proc file
contents.
> dump
Codec: SigmaTel STAC9200
Address: 0
Vendor Id: 0x83847690
Subsystem Id: 0x102801cc
...
If you would like to show only a certain widget, you can pass the
widget NID as the argument.
> dump 0x10
Node 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.
> jack
NID 0x0d: cfg 0x032110f0: [Jack] HP Out at Ext Left
NID 0x0f: cfg 0x03a110f0: [Jack] Mic at Ext Left
NID 0x10: cfg 0x921701f0: [Fixed] Speaker at Int Front
NID 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 -r
NID 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 0x0d
Jack 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 1
send: NID=0xd, VERB=0xf09(get_pin_sense), PARM=0x0
receive: 0x80000000
send: 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,
> PCM
0: STAC92xx Analog:0 (audio), play=1, capt=2
1: 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 16
Open PCM STAC92xx Analog for play
send: NID=0x21, VERB=0xf00(get_parameters), PARM=0xa(PCM)
receive: 0xe07e0
...
Prepare PCM, rate=48000, channels=2, format=16 bits
PCM 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 0x28
Pin[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 0x28
Pin[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 0x00
Command 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_save
Power-save = 0
> option power_save 1
> option power_save
Power-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 list
Available sysfs entries:
driver_pin_configs (R)
init_pin_configs (R)
...
> fs get init_pin_configs
0x24 0x01014010
0x25 0x01011012
0x26 0x01016011
...
> fs set user_pin_configs 0x24 0x411111f0
send: NID=0x24, VERB=0x71c(set_config_def_0), PARM=0xf0
...
> fs set hints jack_detect=false
> fs get hints
jack_detect = false
> fs set reconfig 1
LOG 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 to
stdout but outputs only to the log file. It's useful for automating
test. The shell command can be fed from stdin, so you can write a
command 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 with
model=laptop, pass it via -m option to hda-emu. Also, the PCI SSID
can be overridden by -p option.
COLORED OUTPUT
--------------
As default, hda-emu outputs the lines in color using ANSI escape
sequences. The escape sequences will be stripped in the log files,
though. You can toggle color/non-color behavior via -C and -M
options, respectively.
INITIAL PIN-CONFIGURATION AND HINTS
-----------------------------------
As default, hda-emu takes the default pin-configurations as set in the
given codec proc file (or the proc file content in the given
alsa-info.sh output). But the codec proc file might contain the
status 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 and
initialize the pin defaults accordingly via -P option. When the input
file is a recent alsa-info.sh output containing sysfs file entries,
pass like "-P hwC0D0/init_pin_configs". Then hda-emu will initialize
the pin-default contents found in hwC0D0/init_pin_configs sysfs file.
You can also pass an external file name to -P option instead of the
sysfs files in the input file. The file must contain a pair of
register and pin-config value in each line just like in *_pin_configs
sysfs 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 pin
configuration set via -P option may be overridden by the driver's own
setup while the pin configuration set via -U remains over the driver's
setup.
Similarly, you can give the initial hints strings either from sysfs
file 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, all
pins 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. just
probe the codec and initializes the instance without invoking the
parser, pass -n option. (This corresponds to probe_only=1 option for
snd-hda-intel module.)
Then you can inspect the pin config, add hints or whatever, then
trigger 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 the
driver; i.e. when printk(KERN_ERR ...) is issued. Then gdb will trap
it and you can see the code path and invesitage there.
The -a option doesn't affect operations when hda-emu isn't invoked in
gdb 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.git
A backup repo is at:
https://github.com/tiwai/hda-emu
LICENSE
-------
GPL v2. See COPYING file.