2
* Purpose: Default mixer/control panel driver for HDA codecs
4
* This generic driver is used to create mixer/control panels for HDaudio
5
* codec chips that don't have any dedicated driver available.
7
* This drivere will obtain the widget definitions from the codec and then
8
* try to guess a mixer layout that makes some sense. However this approach
9
* works properly only with a small set of codecs.
11
* Most codecs are unbearably complex and provide loads of redundant
12
* functionality. The generic driver approach will not properly work with them
13
* because the mixer (GUI) layout will become too large to fit on any screen.
14
* In addtion such automatically generated mixer controls will not make any
15
* sense to the users. So in the future the only possible approach will be
16
* creating dedicated mixer drivers for all possible codecs in the market.
17
* Unfortunately in some cases the driver may even need to be motherboard
18
* specific. Apparently this is going to be enormous task.
22
* This file is part of Open Sound System.
24
* Copyright (C) 4Front Technologies 1996-2008.
26
* This this source file is released under GPL v2 license (no other versions).
27
* See the COPYING file included in the main directory of this source
28
* distribution for the license terms and conditions.
32
#include "oss_hdaudio_cfg.h"
34
#include "hdaudio_codec.h"
36
extern int hdaudio_snoopy;
37
extern int hdaudio_jacksense;
38
extern int hdaudio_noskip;
41
count_linked_controls (hdaudio_mixer_t * mixer, codec_t * codec,
42
widget_t * widget, int recursive)
45
* This function counts the number of mixer control elements this
47
* If recursive==1 then control counts of the previous widgets in the
48
* processing chain will be counted if number of inputs is exactly 1.
49
* Input sources are not checked if number of connections is larger than 1
50
* because separate mixer group is required for such widgets.
52
* Note! The policies used by this function must match exactly the policies
53
* used by follow_widget_chain()
63
if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
69
if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
71
if (widget->wid_type == NT_MIXER)
72
count += widget->nconn;
80
if (widget->wid_type == NT_SELECT && widget->nconn > 1)
84
if (widget->nconn == 1) /* Exactly one input wource */
86
count_linked_controls (mixer, codec,
87
&codec->widgets[widget->connections[0]],
95
attach_amplifiers (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
96
widget_t * widget, int group, int group_mode)
100
int use_mutegroup = 0;
104
* Control for input amplifier(s)
106
if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
108
if (widget->wid_type == NT_MIXER)
109
ninputs = widget->nconn;
114
* Check if it's possible to save horizontal space by creating a separate
115
* mute group. In this way the names of mute selectors become shorter.
117
if (!(widget->inamp_caps & ~AMPCAP_MUTE)
118
&& (widget->inamp_caps & AMPCAP_MUTE) && ninputs > 2)
122
mixer_ext_create_group (mixer->mixer_dev, group, "mute")) < 0)
126
for (i = 0; i < ninputs; i++) /* All inputs */
128
char tmpname[32], tmp[40];
129
char *name = codec->widgets[widget->connections[i]].name;
131
if (ninputs == 1) /* Hide name */
134
if (codec->widgets[widget->connections[i]].skip)
137
if (widget->inamp_caps & ~AMPCAP_MUTE) /* Supports gain control */
139
int typ, num, maxval, val, range, step;
142
outamp_caps >> AMPCAP_NUMSTEPS_SHIFT) &
143
AMPCAP_NUMSTEPS_MASK) + 1;
146
outamp_caps >> AMPCAP_STEPSIZE_SHIFT) &
147
AMPCAP_STEPSIZE_MASK) + 1;
149
if (step > 20 /* 5dB */ && range < 5)
151
create_ingain_selector (mixer, codec, widget, group, i,
155
maxval = hdaudio_amp_maxval (widget->inamp_caps);
157
if (widget->widget_caps & WCAP_STEREO)
159
typ = MIXT_STEREOSLIDER16;
160
num = MIXNUM (widget, CT_INSTEREO, i);
164
typ = MIXT_MONOSLIDER16;
165
num = MIXNUM (widget, CT_INMONO, i);
168
if (hdaudio_snoopy > 0)
170
sprintf (tmp, "%s:R%x", name, widget->wid);
174
if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
186
if (widget->rgbcolor != 0)
187
if ((ent = mixer_find_ext (dev, cnum)) != NULL)
188
ent->rgbcolor = widget->rgbcolor;
190
/* Setup initial volume */
191
val = (maxval * 8) / 10; /* 80% of the maximum */
192
val = val | (val << 16);
194
hdaudio_set_control (mixer->mixer_dev, num, SNDCTL_MIX_WRITE,
196
continue; /* Skip to the next input */
199
if (widget->inamp_caps & AMPCAP_MUTE) /* Supports only mute */
202
strcpy (tmpname, name);
204
sprintf (tmpname, "%s-mute", name);
207
if (hdaudio_snoopy > 0)
209
sprintf (tmp, "%s:Q%x", name, widget->wid);
213
if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
220
MIXF_WRITEABLE)) < 0)
223
if (widget->rgbcolor != 0)
224
if ((ent = mixer_find_ext (dev, cnum)) != NULL)
225
ent->rgbcolor = widget->rgbcolor;
227
hdaudio_set_control (mixer->mixer_dev,
228
MIXNUM (widget, CT_INMUTE, i),
229
SNDCTL_MIX_WRITE, 0);
236
* Output amplifier control
239
if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
247
if (widget->outamp_caps & ~AMPCAP_MUTE) /* Has gain control */
249
int range, step, typ, num, maxval, val;
252
outamp_caps >> AMPCAP_NUMSTEPS_SHIFT) & AMPCAP_NUMSTEPS_MASK) +
256
outamp_caps >> AMPCAP_STEPSIZE_SHIFT) & AMPCAP_STEPSIZE_MASK) +
259
if (step > 20 /* 5dB */ && range < 5)
261
create_outgain_selector (mixer, widget, group, name);
266
maxval = hdaudio_amp_maxval (widget->outamp_caps);
268
if (widget->widget_caps & WCAP_STEREO)
270
typ = MIXT_STEREOSLIDER16;
271
num = MIXNUM (widget, CT_OUTSTEREO, 0);
275
typ = MIXT_MONOSLIDER16;
276
num = MIXNUM (widget, CT_OUTMONO, 0);
279
if (hdaudio_snoopy > 0)
281
sprintf (tmp, "%s:V%x", name, widget->wid);
286
sprintf (tmp, "%s", widget->name);
290
if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
292
num, hdaudio_set_control,
301
if (widget->rgbcolor != 0)
302
if ((ent = mixer_find_ext (dev, cnum)) != NULL)
303
ent->rgbcolor = widget->rgbcolor;
306
val = (maxval * 8) / 10; /* 80% of the maximum */
307
val = val | (val << 16);
308
hdaudio_set_control (mixer->mixer_dev, num, SNDCTL_MIX_WRITE,
312
else if (widget->outamp_caps & AMPCAP_MUTE) /* Only mute control */
316
if (hdaudio_snoopy > 0)
318
sprintf (tmpname, "%s:U%x", name, widget->wid);
322
if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
329
MIXF_WRITEABLE)) < 0)
333
if (widget->rgbcolor != 0)
334
if ((ent = mixer_find_ext (dev, cnum)) != NULL)
335
ent->rgbcolor = widget->rgbcolor;
337
hdaudio_set_control (mixer->mixer_dev,
338
MIXNUM (widget, CT_OUTMUTE, 0),
339
SNDCTL_MIX_WRITE, 0);
348
attach_selector (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
349
widget_t * widget, int group, int group_mode)
355
char tmp[256], *t = tmp;
361
* first check to see if there are more that 2 valid options to create a
364
for (i = 0; i < widget->nconn; i++)
365
if (!codec->widgets[widget->connections[i]].skip
366
&& codec->widgets[widget->connections[i]].sensed_pin != PIN_OUT)
375
if (corb_read (mixer, widget->cad, widget->wid, 0, GET_SELECTOR, 0, &c, &b))
376
widget->current_selector = c;
378
if (hdaudio_snoopy > 0)
380
sprintf (tmp, "%s:%x", name, widget->wid);
385
if ((ctl = mixer_ext_create_control (mixer->mixer_dev,
387
MIXNUM (widget, CT_SELECT, 0),
392
MIXF_READABLE | MIXF_WRITEABLE)) < 0)
396
ext = mixer_find_ext (mixer->mixer_dev, ctl);
400
cmn_err (CE_WARN, "Cannot locate the mixer extension (a)\n");
405
ext->rgbcolor = widget->rgbcolor;
407
memset (ext->enum_present, 0, sizeof (ext->enum_present));
409
for (i = 0; i < widget->nconn; i++)
414
* ensure that the connection list has a valid widget id - some
415
* devices have bogus connection lists
417
if (codec->widgets[widget->connections[i]].wid < codec->first_node)
420
s = codec->widgets[widget->connections[i]].name;
421
if (strlen (tmp) + strlen (s) + 1 < sizeof (tmp) - 1)
426
if (hdaudio_snoopy > 0)
427
sprintf (t, "A%s:%x", s,
428
mixer->codecs[widget->cad]->widgets[widget->
429
connections[i]].wid);
433
* Show only widgets that are not marked to be ignored.
434
* Also hide I/O pins that are known to be outputs.
436
if (!codec->widgets[widget->connections[i]].skip
437
&& codec->widgets[widget->connections[i]].sensed_pin != PIN_OUT)
438
ext->enum_present[i / 8] |= (1 << (i % 8));
441
if (widget->current_selector == i)
442
widget->current_selector++;
446
mixer_ext_set_strings (mixer->mixer_dev, ctl, tmp, 0);
448
if (widget->current_selector >= widget->nconn)
449
widget->current_selector = 0;
450
corb_write (mixer, widget->cad, widget->wid, 0, SET_SELECTOR,
451
widget->current_selector);
457
follow_widget_chain (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
458
widget_t * widget, int group)
462
if (widget->used) /* Already handled */
467
if (widget->nconn >= 1)
469
follow_widget_chain (dev, mixer, codec,
470
&codec->widgets[widget->connections[0]],
474
if ((err = attach_amplifiers (dev, mixer, codec, widget, group, 1)) < 0)
477
if (widget->wid_type == NT_SELECT)
478
if ((err = attach_selector (dev, mixer, codec, widget, group, 1)) < 0)
485
attach_pin_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
486
widget_t * widget, int parent_group)
488
int group = parent_group, g;
489
unsigned int b, c, conf;
491
int inselects = 0, outselects = 0, linked_controls = 0;
493
char tmp[256], *t = tmp;
496
if (widget->pincaps & PINCAP_OUTPUT_CAPABLE)
498
outselects = widget->nconn;
500
if (widget->nconn == 1) /* Exactly one connection */
503
count_linked_controls (mixer, codec,
504
&codec->widgets[widget->connections[0]],
509
if (widget->pincaps & PINCAP_INPUT_CAPABLE)
511
if (!(widget->widget_caps & WCAP_DIGITAL)) /* Analog pin */
517
if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
522
if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
527
if ((inselects + outselects > 1) || num_amps > 0 || linked_controls > 0) /* Have something to control */
529
if (widget->color[0] == 0) /* Empty name */
530
sprintf (widget->color, "jack%02x", widget->wid);
532
mixer_ext_create_group (mixer->mixer_dev, group,
537
(mixer, widget->cad, widget->wid, 0, GET_SELECTOR, 0, &c, &b))
538
widget->current_selector = c;
540
if (inselects + outselects > 1)
542
if ((ctl = mixer_ext_create_control (mixer->mixer_dev,
544
MIXNUM (widget, CT_SELECT, 0),
548
inselects + outselects,
550
MIXF_WRITEABLE)) < 0)
554
ext = mixer_find_ext (mixer->mixer_dev, ctl);
558
cmn_err (CE_WARN, "Cannot locate the mixer extension (b)\n");
562
ext->rgbcolor = widget->rgbcolor;
564
memset (ext->enum_present, 0, sizeof (ext->enum_present));
566
for (i = 0; i < widget->nconn; i++)
570
s = codec->widgets[widget->connections[i]].name;
571
if (strlen (tmp) + strlen (s) + 1 < sizeof (tmp) - 1)
576
if (hdaudio_snoopy > 0)
577
sprintf (t, "A%s:%x", s,
578
mixer->codecs[widget->cad]->widgets[widget->
584
* Show only widgets that are not marked to be ignored.
586
if (!codec->widgets[widget->connections[i]].skip)
587
ext->enum_present[i / 8] |= (1 << (i % 8));
590
if (widget->current_selector == i)
591
widget->current_selector++;
597
* Use the default sequence as an index to the output source selectors.
599
if (widget->sensed_pin == PIN_OUT)
601
(mixer, widget->cad, widget->wid, 0, GET_CONFIG_DEFAULT, 0,
604
int association, sequence;
606
association = (conf >> 4) & 0x0f;
607
sequence = conf & 0x0f;
609
if (association != 0)
611
widget->current_selector = sequence;
616
if (widget->current_selector >= widget->nconn)
617
widget->current_selector = 0;
619
if (inselects > 0) /* Input capable */
632
ext->enum_present[i / 8] |= (1 << (i % 8));
635
if (widget->pin_type == PIN_IN)
636
widget->current_selector = widget->nconn;
639
mixer_ext_set_strings (mixer->mixer_dev, ctl, tmp, 0);
642
hdaudio_set_control (mixer->mixer_dev,
643
MIXNUM (widget, CT_SELECT, 0),
644
SNDCTL_MIX_WRITE, widget->current_selector);
646
if ((err = attach_amplifiers (dev, mixer, codec, widget, g, 0)) < 0)
649
if (widget->nconn == 1)
651
follow_widget_chain (dev, mixer, codec,
652
&codec->widgets[widget->connections[0]],
661
attach_record_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
662
widget_t * widget, int parent_group)
664
int group = parent_group, g;
666
int linked_controls = 0;
669
if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
674
if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
679
if (widget->nconn == 1) /* Exactly one connection */
682
count_linked_controls (mixer, codec,
683
&codec->widgets[widget->connections[0]], 1);
686
if (num_amps > 0 || linked_controls > 1) /* Have something to control */
689
mixer_ext_create_group (mixer->mixer_dev, group,
693
if (widget->nconn == 1)
695
follow_widget_chain (dev, mixer, codec,
696
&codec->widgets[widget->connections[0]],
700
if ((err = attach_amplifiers (dev, mixer, codec, widget, g, 0)) < 0)
702
if ((err = attach_selector (dev, mixer, codec, widget, g, 0)) < 0)
710
attach_misc_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
711
widget_t * widget, int parent_group)
717
if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
722
if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
727
if ((widget->wid_type == NT_SELECT || widget->wid_type == NT_MIXER)
728
&& widget->nconn > 0)
729
nselect = widget->nconn;
731
if (num_amps > 0 || nselect > 1) /* Have something to control */
735
mixer_ext_create_group (mixer->mixer_dev, group,
740
attach_amplifiers (dev, mixer, codec, widget, parent_group,
746
attach_selector (dev, mixer, codec, widget, parent_group,
755
hdaudio_generic_mixer_init (int dev, hdaudio_mixer_t * mixer, int cad,
758
unsigned int vendorid, b;
763
int group = parent_group;
765
if (mixer->codecs[cad] == NULL)
767
cmn_err (CE_WARN, "Bad codec %d\n", cad);
770
codec = mixer->codecs[cad];
772
if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_VENDOR, &vendorid, &b))
774
cmn_err (CE_WARN, "Cannot get codec ID\n");
779
* First handle all the PIN widgets
783
for (wid = 0; wid < codec->nwidgets; wid++)
785
widget = &codec->widgets[wid];
787
if (widget->wid_type != NT_PIN) /* Not a pin widget */
792
if (widget->skip) /* Unused/unconnected PIN widget */
800
mixer_ext_create_group (mixer->mixer_dev, parent_group,
806
if ((err = attach_pin_widget (dev, mixer, codec, widget, group)) < 0)
811
* Next handle all the ADC widgets
814
for (wid = 0; wid < codec->nwidgets; wid++)
816
widget = &codec->widgets[wid];
818
if (widget->wid_type != NT_ADC) /* Not a pin widget */
829
mixer_ext_create_group (mixer->mixer_dev, parent_group,
834
if ((err = attach_record_widget (dev, mixer, codec, widget, group)) < 0)
839
* Finally handle all the widgets that heve not been attached yet
843
for (wid = 0; wid < codec->nwidgets; wid++)
845
widget = &codec->widgets[wid];
850
if (widget->used) /* Already handled */
855
if (count_linked_controls (mixer, codec, widget, 0) > 0)
859
mixer_ext_create_group (mixer->mixer_dev, parent_group,
864
if ((err = attach_misc_widget (dev, mixer, codec, widget, group)) < 0)