~ubuntu-branches/ubuntu/vivid/oss4/vivid

« back to all changes in this revision

Viewing changes to kernel/drv/oss_hdaudio/hdaudio_generic.c

  • Committer: Bazaar Package Importer
  • Author(s): Romain Beauxis, Samuel Thibault, Romain Beauxis, Sebastien NOEL
  • Date: 2011-06-14 10:06:56 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110614100656-cx4oc7u426zn812z
Tags: 4.2-build2004-1
[ Samuel Thibault ]
* debian/control: Add liboss4-salsa2, liboss4-salsa-dev and
  liboss4-salsa-asound2 packages, equivalent to (and will replace) those from
  the oss-libsalsa package (Closes: #589127).
* debian/patches/liboss4-salsa.patch: New patch to rename libsalsa into
  liboss4-salsa to avoid conflicts in the archive for no good reason.
* debian/rules: Make in libOSSlib and libsalsa.
* debian/liboss4-salsa-dev.install, debian/liboss4-salsa2.install,
  debian/liboss4-salsa-asound2.links, debian/liboss4-salsa-dev.links:
  Install liboss4-salsa libraries like was done in the oss-libsalsa package.
* include-alsa: Add a copy of ALSA 1.0.5 headers: Cf ALSA_1.0.* symbols in
  libsalsa, this is the roughly supported version.
* debian/copyright: Update for new include-alsa files.
* alsa.pc: New file for compatibility with libasound-dev.
* debian/control:
  - Add Vcs-Browser and Vcs-Svn fields.
  - Use linux-any instead of the list of Linux archs (Closes: #604679).
  - Make dkms dependency linux-any only.
* debian/patches/hurd_iot.patch: New patch to fix soundcard.h usage in
  libsalsa on hurd-i386.
* debian/patches/libsalsa_fixes.patch: New patch to fix some printf usages
  and ioctl declaration in libsalsa.
* debian/patches/no_EBADE.patch: New patch to cope with hurd-i386 not having
  EBADE.
* debian/patches/CFLAGS.patch: New patch to make oss4 take debian/rules
  CFLAGS into account.
* debian/patches/snd_asoundlib_version.patch: New patch to add
  snd_asoundlib_version().
* debian/patches/generic_srccconf.patch: New patch to fix source
  configuration on unknown archs.

[ Romain Beauxis ]
* Fixed README.Debian to only mention dkms' modules.
* Switch to dpkg-source 3.0 (quilt) format
* Added DM-Upload-Allowed: yes

[ Sebastien NOEL ]
* New upstream release (Closes: #595298, #619272).
* Fix typo in initscript (Closes: #627149).
* debian/control: adjust linux-headers dependencies (Closes: #628879).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Purpose: Default mixer/control panel driver for HDA codecs
 
3
 *
 
4
 * This generic driver is used to create mixer/control panels for HDaudio
 
5
 * codec chips that don't have any dedicated driver available.
 
6
 *
 
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.
 
10
 *
 
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.
 
19
 */
 
20
/*
 
21
 *
 
22
 * This file is part of Open Sound System.
 
23
 *
 
24
 * Copyright (C) 4Front Technologies 1996-2008.
 
25
 *
 
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.
 
29
 *
 
30
 */
 
31
 
 
32
#include "oss_hdaudio_cfg.h"
 
33
#include "hdaudio.h"
 
34
#include "hdaudio_codec.h"
 
35
 
 
36
extern int hdaudio_snoopy;
 
37
extern int hdaudio_jacksense;
 
38
extern int hdaudio_noskip;
 
39
 
 
40
static int
 
41
count_linked_controls (hdaudio_mixer_t * mixer, codec_t * codec,
 
42
                       widget_t * widget, int recursive)
 
43
{
 
44
/*
 
45
 * This function counts the number of mixer control elements this
 
46
 * widget has.
 
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.
 
51
 *
 
52
 * Note! The policies used by this function must match exactly the policies 
 
53
 *       used by follow_widget_chain()
 
54
 */
 
55
  int count = 0;
 
56
 
 
57
  if (widget->skip)
 
58
    return 0;
 
59
 
 
60
  /*
 
61
   * Output amp?
 
62
   */
 
63
  if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
 
64
    count += 1;
 
65
 
 
66
  /*
 
67
   * Input amp(s)?
 
68
   */
 
69
  if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
 
70
    {
 
71
      if (widget->wid_type == NT_MIXER)
 
72
        count += widget->nconn;
 
73
      else
 
74
        count++;
 
75
    }
 
76
 
 
77
  /*
 
78
   * Input selector?
 
79
   */
 
80
  if (widget->wid_type == NT_SELECT && widget->nconn > 1)
 
81
    count += 1;
 
82
 
 
83
  if (recursive)
 
84
    if (widget->nconn == 1)     /* Exactly one input wource */
 
85
      count +=
 
86
        count_linked_controls (mixer, codec,
 
87
                               &codec->widgets[widget->connections[0]],
 
88
                               recursive);
 
89
 
 
90
  return count;
 
91
}
 
92
 
 
93
/*ARGSUSED*/
 
94
static int
 
95
attach_amplifiers (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
96
                   widget_t * widget, int group, int group_mode)
 
97
{
 
98
  int i, cnum, ninputs;
 
99
  int g = group;
 
100
  int use_mutegroup = 0;
 
101
  oss_mixext *ent;
 
102
 
 
103
/*
 
104
 * Control for input amplifier(s)
 
105
 */
 
106
  if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
 
107
    {
 
108
      if (widget->wid_type == NT_MIXER)
 
109
        ninputs = widget->nconn;
 
110
      else
 
111
        ninputs = 1;
 
112
 
 
113
      /* 
 
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.
 
116
       */
 
117
      if (!(widget->inamp_caps & ~AMPCAP_MUTE)
 
118
          && (widget->inamp_caps & AMPCAP_MUTE) && ninputs > 2)
 
119
        {
 
120
          use_mutegroup = 1;
 
121
          if ((g =
 
122
               mixer_ext_create_group (mixer->mixer_dev, group, "mute")) < 0)
 
123
            return g;
 
124
        }
 
125
 
 
126
      for (i = 0; i < ninputs; i++)     /* All inputs */
 
127
        {
 
128
          char tmpname[32], tmp[40];
 
129
          char *name = codec->widgets[widget->connections[i]].name;
 
130
 
 
131
          if (ninputs == 1)     /* Hide name */
 
132
            name = "-";
 
133
 
 
134
          if (codec->widgets[widget->connections[i]].skip)
 
135
            continue;
 
136
 
 
137
          if (widget->inamp_caps & ~AMPCAP_MUTE)        /* Supports gain control */
 
138
            {
 
139
              int typ, num, maxval, val, range, step;
 
140
              range =
 
141
                ((widget->
 
142
                  outamp_caps >> AMPCAP_NUMSTEPS_SHIFT) &
 
143
                 AMPCAP_NUMSTEPS_MASK) + 1;
 
144
              step =
 
145
                ((widget->
 
146
                  outamp_caps >> AMPCAP_STEPSIZE_SHIFT) &
 
147
                 AMPCAP_STEPSIZE_MASK) + 1;
 
148
 
 
149
              if (step > 20 /* 5dB */  && range < 5)
 
150
                {
 
151
                  create_ingain_selector (mixer, codec, widget, group, i,
 
152
                                          name);
 
153
                  continue;
 
154
                }
 
155
              maxval = hdaudio_amp_maxval (widget->inamp_caps);
 
156
 
 
157
              if (widget->widget_caps & WCAP_STEREO)
 
158
                {
 
159
                  typ = MIXT_STEREOSLIDER16;
 
160
                  num = MIXNUM (widget, CT_INSTEREO, i);
 
161
                }
 
162
              else
 
163
                {
 
164
                  typ = MIXT_MONOSLIDER16;
 
165
                  num = MIXNUM (widget, CT_INMONO, i);
 
166
                }
 
167
 
 
168
              if (hdaudio_snoopy > 0)
 
169
                {
 
170
                  sprintf (tmp, "%s:R%x", name, widget->wid);
 
171
                  name = tmp;
 
172
                }
 
173
 
 
174
              if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
 
175
                                                   group,
 
176
                                                   num,
 
177
                                                   hdaudio_set_control,
 
178
                                                   typ,
 
179
                                                   name, maxval,
 
180
                                                   MIXF_READABLE |
 
181
                                                   MIXF_WRITEABLE |
 
182
                                                   MIXF_CENTIBEL)) < 0)
 
183
                return cnum;
 
184
 
 
185
              /* Copy RGB color */
 
186
              if (widget->rgbcolor != 0)
 
187
              if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
188
                 ent->rgbcolor = widget->rgbcolor;
 
189
 
 
190
              /* Setup initial volume */
 
191
              val = (maxval * 8) / 10;  /* 80% of the maximum */
 
192
              val = val | (val << 16);
 
193
 
 
194
              hdaudio_set_control (mixer->mixer_dev, num, SNDCTL_MIX_WRITE,
 
195
                                   val);
 
196
              continue;         /* Skip to the next input */
 
197
            }
 
198
 
 
199
          if (widget->inamp_caps & AMPCAP_MUTE) /* Supports only mute */
 
200
            {
 
201
              if (use_mutegroup)
 
202
                strcpy (tmpname, name);
 
203
              else
 
204
                sprintf (tmpname, "%s-mute", name);
 
205
              name = tmpname;
 
206
 
 
207
              if (hdaudio_snoopy > 0)
 
208
                {
 
209
                  sprintf (tmp, "%s:Q%x", name, widget->wid);
 
210
                  name = tmp;
 
211
                }
 
212
 
 
213
              if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
 
214
                                                   g,
 
215
                                                   MIXNUM (widget,
 
216
                                                           CT_INMUTE, i),
 
217
                                                   hdaudio_set_control,
 
218
                                                   MIXT_MUTE, name, 2,
 
219
                                                   MIXF_READABLE |
 
220
                                                   MIXF_WRITEABLE)) < 0)
 
221
                return cnum;
 
222
              /* Copy RGB color */
 
223
              if (widget->rgbcolor != 0)
 
224
              if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
225
                 ent->rgbcolor = widget->rgbcolor;
 
226
 
 
227
              hdaudio_set_control (mixer->mixer_dev,
 
228
                                   MIXNUM (widget, CT_INMUTE, i),
 
229
                                   SNDCTL_MIX_WRITE, 0);
 
230
            }
 
231
 
 
232
        }
 
233
    }
 
234
 
 
235
/*
 
236
 * Output amplifier control
 
237
 */
 
238
 
 
239
  if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
 
240
    {
 
241
      char tmp[32];
 
242
      char *name = "-";
 
243
 
 
244
      if (hdaudio_snoopy)
 
245
        name = "outamp";
 
246
 
 
247
      if (widget->outamp_caps & ~AMPCAP_MUTE)   /* Has gain control */
 
248
        {
 
249
          int range, step, typ, num, maxval, val;
 
250
          range =
 
251
            ((widget->
 
252
              outamp_caps >> AMPCAP_NUMSTEPS_SHIFT) & AMPCAP_NUMSTEPS_MASK) +
 
253
            1;
 
254
          step =
 
255
            ((widget->
 
256
              outamp_caps >> AMPCAP_STEPSIZE_SHIFT) & AMPCAP_STEPSIZE_MASK) +
 
257
            1;
 
258
 
 
259
          if (step > 20 /* 5dB */  && range < 5)
 
260
            {
 
261
              create_outgain_selector (mixer, widget, group, name);
 
262
            }
 
263
          else
 
264
            {
 
265
 
 
266
              maxval = hdaudio_amp_maxval (widget->outamp_caps);
 
267
 
 
268
              if (widget->widget_caps & WCAP_STEREO)
 
269
                {
 
270
                  typ = MIXT_STEREOSLIDER16;
 
271
                  num = MIXNUM (widget, CT_OUTSTEREO, 0);
 
272
                }
 
273
              else
 
274
                {
 
275
                  typ = MIXT_MONOSLIDER16;
 
276
                  num = MIXNUM (widget, CT_OUTMONO, 0);
 
277
                }
 
278
 
 
279
              if (hdaudio_snoopy > 0)
 
280
                {
 
281
                  sprintf (tmp, "%s:V%x", name, widget->wid);
 
282
                  name = tmp;
 
283
                }
 
284
              else
 
285
                {
 
286
                  sprintf (tmp, "%s", widget->name);
 
287
                  name = tmp;
 
288
                }
 
289
 
 
290
              if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
 
291
                                                   group,
 
292
                                                   num, hdaudio_set_control,
 
293
                                                   typ,
 
294
                                                   name, maxval,
 
295
                                                   MIXF_READABLE |
 
296
                                                   MIXF_WRITEABLE |
 
297
                                                   MIXF_CENTIBEL)) < 0)
 
298
                return cnum;
 
299
 
 
300
              /* Copy RGB color */
 
301
              if (widget->rgbcolor != 0)
 
302
              if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
303
                 ent->rgbcolor = widget->rgbcolor;
 
304
 
 
305
              /* setup volume */
 
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,
 
309
                                   val);
 
310
            }
 
311
        }
 
312
      else if (widget->outamp_caps & AMPCAP_MUTE)       /* Only mute control */
 
313
        {
 
314
          char tmpname[32];
 
315
          name = "mute";
 
316
          if (hdaudio_snoopy > 0)
 
317
            {
 
318
              sprintf (tmpname, "%s:U%x", name, widget->wid);
 
319
              name = tmpname;
 
320
            }
 
321
 
 
322
          if ((cnum = mixer_ext_create_control (mixer->mixer_dev,
 
323
                                               group,
 
324
                                               MIXNUM (widget,
 
325
                                                       CT_OUTMUTE, 0),
 
326
                                               hdaudio_set_control,
 
327
                                               MIXT_MUTE, name, 2,
 
328
                                               MIXF_READABLE |
 
329
                                               MIXF_WRITEABLE)) < 0)
 
330
            return cnum;
 
331
 
 
332
              /* Copy RGB color */
 
333
              if (widget->rgbcolor != 0)
 
334
              if ((ent = mixer_find_ext (dev, cnum)) != NULL)
 
335
                 ent->rgbcolor = widget->rgbcolor;
 
336
 
 
337
          hdaudio_set_control (mixer->mixer_dev,
 
338
                               MIXNUM (widget, CT_OUTMUTE, 0),
 
339
                               SNDCTL_MIX_WRITE, 0);
 
340
        }
 
341
    }
 
342
 
 
343
  return 0;
 
344
}
 
345
 
 
346
/*ARGSUSED*/
 
347
static int
 
348
attach_selector (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
349
                 widget_t * widget, int group, int group_mode)
 
350
{
 
351
  unsigned int c, b;
 
352
  char *name = "src";
 
353
 
 
354
  int i, ctl;
 
355
  char tmp[256], *t = tmp;
 
356
  oss_mixext *ext;
 
357
  int count = 0;
 
358
 
 
359
 
 
360
  /* 
 
361
   * first check to see if there are more that 2 valid options to create a
 
362
   * selector for.
 
363
   */
 
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)
 
367
      count++;
 
368
 
 
369
  if (count < 2)
 
370
    return 0;
 
371
 
 
372
 
 
373
  name = widget->name;
 
374
 
 
375
  if (corb_read (mixer, widget->cad, widget->wid, 0, GET_SELECTOR, 0, &c, &b))
 
376
    widget->current_selector = c;
 
377
 
 
378
  if (hdaudio_snoopy > 0)
 
379
    {
 
380
      sprintf (tmp, "%s:%x", name, widget->wid);
 
381
      name = tmp;
 
382
    }
 
383
 
 
384
 
 
385
  if ((ctl = mixer_ext_create_control (mixer->mixer_dev,
 
386
                                       group,
 
387
                                       MIXNUM (widget, CT_SELECT, 0),
 
388
                                       hdaudio_set_control,
 
389
                                       MIXT_ENUM,
 
390
                                       name,
 
391
                                       widget->nconn,
 
392
                                       MIXF_READABLE | MIXF_WRITEABLE)) < 0)
 
393
    return ctl;
 
394
 
 
395
  *tmp = 0;
 
396
  ext = mixer_find_ext (mixer->mixer_dev, ctl);
 
397
 
 
398
  if (ext == NULL)
 
399
    {
 
400
      cmn_err (CE_WARN, "Cannot locate the mixer extension (a)\n");
 
401
      return OSS_EIO;
 
402
    }
 
403
 
 
404
  /* Copy RGB color */
 
405
  ext->rgbcolor = widget->rgbcolor;
 
406
 
 
407
  memset (ext->enum_present, 0, sizeof (ext->enum_present));
 
408
 
 
409
  for (i = 0; i < widget->nconn; i++)
 
410
    {
 
411
      char *s;
 
412
 
 
413
      /*
 
414
       * ensure that the connection list has a valid widget id - some
 
415
       * devices have bogus connection lists 
 
416
       */
 
417
      if (codec->widgets[widget->connections[i]].wid < codec->first_node)
 
418
        continue;
 
419
 
 
420
      s = codec->widgets[widget->connections[i]].name;
 
421
      if (strlen (tmp) + strlen (s) + 1 < sizeof (tmp) - 1)
 
422
        {
 
423
          if (*tmp != 0)
 
424
            *t++ = ' ';
 
425
          strcpy (t, s);
 
426
          if (hdaudio_snoopy > 0)
 
427
            sprintf (t, "A%s:%x", s,
 
428
                     mixer->codecs[widget->cad]->widgets[widget->
 
429
                                                         connections[i]].wid);
 
430
          t += strlen (t);
 
431
 
 
432
          /*
 
433
           * Show only widgets that are not marked to be ignored.
 
434
           * Also hide I/O pins that are known to be outputs.
 
435
           */
 
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));
 
439
          else
 
440
            {
 
441
              if (widget->current_selector == i)
 
442
                widget->current_selector++;
 
443
            }
 
444
        }
 
445
    }
 
446
  mixer_ext_set_strings (mixer->mixer_dev, ctl, tmp, 0);
 
447
 
 
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);
 
452
 
 
453
  return 0;
 
454
}
 
455
 
 
456
static int
 
457
follow_widget_chain (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
458
                     widget_t * widget, int group)
 
459
{
 
460
  int err;
 
461
 
 
462
  if (widget->used)             /* Already handled */
 
463
    return 0;
 
464
 
 
465
  widget->used = 1;
 
466
 
 
467
  if (widget->nconn >= 1)
 
468
    if ((err =
 
469
         follow_widget_chain (dev, mixer, codec,
 
470
                              &codec->widgets[widget->connections[0]],
 
471
                              group)) < 0)
 
472
      return err;
 
473
 
 
474
  if ((err = attach_amplifiers (dev, mixer, codec, widget, group, 1)) < 0)
 
475
    return err;
 
476
 
 
477
  if (widget->wid_type == NT_SELECT)
 
478
    if ((err = attach_selector (dev, mixer, codec, widget, group, 1)) < 0)
 
479
      return err;
 
480
 
 
481
  return 0;
 
482
}
 
483
 
 
484
static int
 
485
attach_pin_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
486
                   widget_t * widget, int parent_group)
 
487
{
 
488
  int group = parent_group, g;
 
489
  unsigned int b, c, conf;
 
490
  int i, ctl, err;
 
491
  int inselects = 0, outselects = 0, linked_controls = 0;
 
492
  int num_amps = 0;
 
493
  char tmp[256], *t = tmp;
 
494
  oss_mixext *ext;
 
495
 
 
496
  if (widget->pincaps & PINCAP_OUTPUT_CAPABLE)
 
497
    {
 
498
      outselects = widget->nconn;
 
499
 
 
500
      if (widget->nconn == 1)   /* Exactly one connection */
 
501
        {
 
502
          linked_controls =
 
503
            count_linked_controls (mixer, codec,
 
504
                                   &codec->widgets[widget->connections[0]],
 
505
                                   1);
 
506
        }
 
507
    }
 
508
 
 
509
  if (widget->pincaps & PINCAP_INPUT_CAPABLE)
 
510
    {
 
511
      if (!(widget->widget_caps & WCAP_DIGITAL))        /* Analog pin */
 
512
        {
 
513
          inselects = 1;
 
514
        }
 
515
    }
 
516
 
 
517
  if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
 
518
    {
 
519
      num_amps++;
 
520
    }
 
521
 
 
522
  if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
 
523
    {
 
524
      num_amps++;
 
525
    }
 
526
 
 
527
  if ((inselects + outselects > 1) || num_amps > 0 || linked_controls > 0)      /* Have something to control */
 
528
    {
 
529
      if (widget->color[0] == 0)        /* Empty name */
 
530
        sprintf (widget->color, "jack%02x", widget->wid);
 
531
      if ((g =
 
532
           mixer_ext_create_group (mixer->mixer_dev, group,
 
533
                                   widget->color)) < 0)
 
534
        return g;
 
535
 
 
536
      if (corb_read
 
537
          (mixer, widget->cad, widget->wid, 0, GET_SELECTOR, 0, &c, &b))
 
538
        widget->current_selector = c;
 
539
 
 
540
      if (inselects + outselects > 1)
 
541
        {
 
542
          if ((ctl = mixer_ext_create_control (mixer->mixer_dev,
 
543
                                               g,
 
544
                                               MIXNUM (widget, CT_SELECT, 0),
 
545
                                               hdaudio_set_control,
 
546
                                               MIXT_ENUM,
 
547
                                               "mode",
 
548
                                               inselects + outselects,
 
549
                                               MIXF_READABLE |
 
550
                                               MIXF_WRITEABLE)) < 0)
 
551
            return ctl;
 
552
 
 
553
          *tmp = 0;
 
554
          ext = mixer_find_ext (mixer->mixer_dev, ctl);
 
555
 
 
556
          if (ext == NULL)
 
557
            {
 
558
              cmn_err (CE_WARN, "Cannot locate the mixer extension (b)\n");
 
559
              return OSS_EIO;
 
560
            }
 
561
          /* Copy RGB color */
 
562
          ext->rgbcolor = widget->rgbcolor;
 
563
 
 
564
          memset (ext->enum_present, 0, sizeof (ext->enum_present));
 
565
 
 
566
          for (i = 0; i < widget->nconn; i++)
 
567
            {
 
568
              char *s;
 
569
 
 
570
              s = codec->widgets[widget->connections[i]].name;
 
571
              if (strlen (tmp) + strlen (s) + 1 < sizeof (tmp) - 1)
 
572
                {
 
573
                  if (*tmp != 0)
 
574
                    *t++ = ' ';
 
575
                  strcpy (t, s);
 
576
                  if (hdaudio_snoopy > 0)
 
577
                    sprintf (t, "A%s:%x", s,
 
578
                             mixer->codecs[widget->cad]->widgets[widget->
 
579
                                                                 connections
 
580
                                                                 [i]].wid);
 
581
                  t += strlen (t);
 
582
 
 
583
                  /*
 
584
                   * Show only widgets that are not marked to be ignored.
 
585
                   */
 
586
                  if (!codec->widgets[widget->connections[i]].skip)
 
587
                    ext->enum_present[i / 8] |= (1 << (i % 8));
 
588
                  else
 
589
                    {
 
590
                      if (widget->current_selector == i)
 
591
                        widget->current_selector++;
 
592
                    }
 
593
                }
 
594
            }
 
595
 
 
596
/*
 
597
 * Use the default sequence as an index to the output source selectors.
 
598
 */
 
599
          if (widget->sensed_pin == PIN_OUT)
 
600
            if (corb_read
 
601
                (mixer, widget->cad, widget->wid, 0, GET_CONFIG_DEFAULT, 0,
 
602
                 &conf, &b))
 
603
              {
 
604
                int association, sequence;
 
605
 
 
606
                association = (conf >> 4) & 0x0f;
 
607
                sequence = conf & 0x0f;
 
608
 
 
609
                if (association != 0)
 
610
                  {
 
611
                    widget->current_selector = sequence;
 
612
                  }
 
613
 
 
614
              }
 
615
 
 
616
          if (widget->current_selector >= widget->nconn)
 
617
            widget->current_selector = 0;
 
618
 
 
619
          if (inselects > 0)    /* Input capable */
 
620
            {
 
621
              char *s;
 
622
 
 
623
              i = widget->nconn;
 
624
              s = widget->name;
 
625
 
 
626
              if (*tmp != 0)
 
627
                *t++ = ' ';
 
628
 
 
629
              strcpy (t, "input");
 
630
 
 
631
              t += strlen (t);
 
632
              ext->enum_present[i / 8] |= (1 << (i % 8));
 
633
              i++;
 
634
 
 
635
              if (widget->pin_type == PIN_IN)
 
636
                widget->current_selector = widget->nconn;
 
637
            }
 
638
 
 
639
          mixer_ext_set_strings (mixer->mixer_dev, ctl, tmp, 0);
 
640
        }
 
641
 
 
642
      hdaudio_set_control (mixer->mixer_dev,
 
643
                           MIXNUM (widget, CT_SELECT, 0),
 
644
                           SNDCTL_MIX_WRITE, widget->current_selector);
 
645
 
 
646
      if ((err = attach_amplifiers (dev, mixer, codec, widget, g, 0)) < 0)
 
647
        return err;
 
648
 
 
649
      if (widget->nconn == 1)
 
650
        if ((err =
 
651
             follow_widget_chain (dev, mixer, codec,
 
652
                                  &codec->widgets[widget->connections[0]],
 
653
                                  g)) < 0)
 
654
          return err;
 
655
    }
 
656
 
 
657
  return 0;
 
658
}
 
659
 
 
660
static int
 
661
attach_record_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
662
                      widget_t * widget, int parent_group)
 
663
{
 
664
  int group = parent_group, g;
 
665
  int err;
 
666
  int linked_controls = 0;
 
667
  int num_amps = 0;
 
668
 
 
669
  if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
 
670
    {
 
671
      num_amps++;
 
672
    }
 
673
 
 
674
  if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
 
675
    {
 
676
      num_amps++;
 
677
    }
 
678
 
 
679
  if (widget->nconn == 1)       /* Exactly one connection */
 
680
    {
 
681
      linked_controls =
 
682
        count_linked_controls (mixer, codec,
 
683
                               &codec->widgets[widget->connections[0]], 1);
 
684
    }
 
685
 
 
686
  if (num_amps > 0 || linked_controls > 1)      /* Have something to control */
 
687
    {
 
688
      if ((g =
 
689
           mixer_ext_create_group (mixer->mixer_dev, group,
 
690
                                   widget->name)) < 0)
 
691
        return g;
 
692
 
 
693
      if (widget->nconn == 1)
 
694
        if ((err =
 
695
             follow_widget_chain (dev, mixer, codec,
 
696
                                  &codec->widgets[widget->connections[0]],
 
697
                                  g)) < 0)
 
698
          return err;
 
699
 
 
700
      if ((err = attach_amplifiers (dev, mixer, codec, widget, g, 0)) < 0)
 
701
        return err;
 
702
      if ((err = attach_selector (dev, mixer, codec, widget, g, 0)) < 0)
 
703
        return err;
 
704
    }
 
705
 
 
706
  return 0;
 
707
}
 
708
 
 
709
static int
 
710
attach_misc_widget (int dev, hdaudio_mixer_t * mixer, codec_t * codec,
 
711
                    widget_t * widget, int parent_group)
 
712
{
 
713
  int err;
 
714
  int nselect = 0;
 
715
  int num_amps = 0;
 
716
 
 
717
  if (widget->widget_caps & WCAP_INPUT_AMP_PRESENT)
 
718
    {
 
719
      num_amps++;
 
720
    }
 
721
 
 
722
  if (widget->widget_caps & WCAP_OUTPUT_AMP_PRESENT)
 
723
    {
 
724
      num_amps++;
 
725
    }
 
726
 
 
727
  if ((widget->wid_type == NT_SELECT || widget->wid_type == NT_MIXER)
 
728
      && widget->nconn > 0)
 
729
    nselect = widget->nconn;
 
730
 
 
731
  if (num_amps > 0 || nselect > 1)      /* Have something to control */
 
732
    {
 
733
#if 0
 
734
      if ((g =
 
735
           mixer_ext_create_group (mixer->mixer_dev, group,
 
736
                                   widget->name)) < 0)
 
737
        return g;
 
738
#endif
 
739
      if ((err =
 
740
           attach_amplifiers (dev, mixer, codec, widget, parent_group,
 
741
                              0)) < 0)
 
742
        return err;
 
743
 
 
744
      if (nselect > 1)
 
745
        if ((err =
 
746
             attach_selector (dev, mixer, codec, widget, parent_group,
 
747
                              0)) < 0)
 
748
          return err;
 
749
    }
 
750
 
 
751
  return 0;
 
752
}
 
753
 
 
754
int
 
755
hdaudio_generic_mixer_init (int dev, hdaudio_mixer_t * mixer, int cad,
 
756
                            int parent_group)
 
757
{
 
758
  unsigned int vendorid, b;
 
759
  int err;
 
760
  int wid, n;
 
761
  codec_t *codec;
 
762
  widget_t *widget;
 
763
  int group = parent_group;
 
764
 
 
765
  if (mixer->codecs[cad] == NULL)
 
766
    {
 
767
      cmn_err (CE_WARN, "Bad codec %d\n", cad);
 
768
      return OSS_EIO;
 
769
    }
 
770
  codec = mixer->codecs[cad];
 
771
 
 
772
  if (!corb_read (mixer, cad, 0, 0, GET_PARAMETER, HDA_VENDOR, &vendorid, &b))
 
773
    {
 
774
      cmn_err (CE_WARN, "Cannot get codec ID\n");
 
775
      return OSS_EIO;
 
776
    }
 
777
 
 
778
/*
 
779
 * First handle all the PIN widgets
 
780
 */
 
781
  n = 0;
 
782
 
 
783
  for (wid = 0; wid < codec->nwidgets; wid++)
 
784
    {
 
785
      widget = &codec->widgets[wid];
 
786
 
 
787
      if (widget->wid_type != NT_PIN)   /* Not a pin widget */
 
788
        continue;
 
789
 
 
790
      widget->used = 1;
 
791
 
 
792
      if (widget->skip)         /* Unused/unconnected PIN widget */
 
793
        {
 
794
          continue;
 
795
        }
 
796
 
 
797
      if ((n++ % 3) == 0)
 
798
        {
 
799
          if ((group =
 
800
               mixer_ext_create_group (mixer->mixer_dev, parent_group,
 
801
                                       "jack")) < 0)
 
802
            return group;
 
803
        }
 
804
 
 
805
 
 
806
      if ((err = attach_pin_widget (dev, mixer, codec, widget, group)) < 0)
 
807
        return err;
 
808
    }
 
809
 
 
810
/*
 
811
 * Next handle all the ADC widgets
 
812
 */
 
813
  n = 0;
 
814
  for (wid = 0; wid < codec->nwidgets; wid++)
 
815
    {
 
816
      widget = &codec->widgets[wid];
 
817
 
 
818
      if (widget->wid_type != NT_ADC)   /* Not a pin widget */
 
819
        continue;
 
820
 
 
821
      if (widget->skip)
 
822
        continue;
 
823
 
 
824
      widget->used = 1;
 
825
 
 
826
      if ((n++ % 3) == 0)
 
827
        {
 
828
          if ((group =
 
829
               mixer_ext_create_group (mixer->mixer_dev, parent_group,
 
830
                                       "record")) < 0)
 
831
            return group;
 
832
        }
 
833
 
 
834
      if ((err = attach_record_widget (dev, mixer, codec, widget, group)) < 0)
 
835
        return err;
 
836
    }
 
837
 
 
838
/*
 
839
 * Finally handle all the widgets that heve not been attached yet
 
840
 */
 
841
 
 
842
  n = 0;
 
843
  for (wid = 0; wid < codec->nwidgets; wid++)
 
844
    {
 
845
      widget = &codec->widgets[wid];
 
846
 
 
847
      if (widget->skip)
 
848
        continue;
 
849
 
 
850
      if (widget->used)         /* Already handled */
 
851
        continue;
 
852
 
 
853
      widget->used = 1;
 
854
 
 
855
      if (count_linked_controls (mixer, codec, widget, 0) > 0)
 
856
        if ((n++ % 4) == 0)
 
857
          {
 
858
            if ((group =
 
859
                 mixer_ext_create_group (mixer->mixer_dev, parent_group,
 
860
                                         "misc")) < 0)
 
861
              return group;
 
862
          }
 
863
 
 
864
      if ((err = attach_misc_widget (dev, mixer, codec, widget, group)) < 0)
 
865
        return err;
 
866
    }
 
867
  return 0;
 
868
}