diff options
author | Brad Smith <brad@cvs.openbsd.org> | 2006-06-16 06:00:47 +0000 |
---|---|---|
committer | Brad Smith <brad@cvs.openbsd.org> | 2006-06-16 06:00:47 +0000 |
commit | dbcb51ef451337383f1e6b8e11f42c5cae8c99ce (patch) | |
tree | cbfed563020fda7c9728c0150733af7537e38fc9 | |
parent | 35fe6bfeb3073abdd7086cd70bbd8366ffed4896 (diff) |
* support for multi-channel (>=3) recording with ALC880, ALC882, or STAC9221
* azalia_codec_init_vtbl()
recognize the name of AD1983
* azalia_generic_codec_find_dac()
check validity of a node in a connection list
* introduce MIXER_DELTA, and simplify the code with it
* codec-specific mixer initialization for STAC9220
From kent NetBSD
Tested by a few end-users.
-rw-r--r-- | sys/dev/pci/azalia.c | 46 | ||||
-rw-r--r-- | sys/dev/pci/azalia.h | 19 | ||||
-rw-r--r-- | sys/dev/pci/azalia_codec.c | 371 |
3 files changed, 267 insertions, 169 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 8f3dad2afda..28eeed4b7f2 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.12 2006/06/14 20:24:12 brad Exp $ */ +/* $OpenBSD: azalia.c,v 1.13 2006/06/16 06:00:46 brad Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -1063,18 +1063,19 @@ azalia_codec_init(codec_t *this) if (err) return err; #ifdef AZALIA_DEBUG - for (i = 0; i < this->ndacgroups; i++) { + for (i = 0; i < this->dacs.ngroups; i++) { DPRINTF(("%s: dacgroup[%d]:", __func__, i)); - for (n = 0; n < this->dacgroups[i].nconv; n++) { - DPRINTF((" %2.2x", this->dacgroups[i].conv[n])); + for (n = 0; n < this->dacs.groups[i].nconv; n++) { + DPRINTF((" %2.2x", this->dacs.groups[i].conv[n])); } DPRINTF(("\n")); } #endif - this->cur_dac = 0; - this->cur_adc = 0; - err = azalia_codec_construct_format(this); + /* set invalid values for azalia_codec_construct_format() to work */ + this->dacs.cur = -1; + this->adcs.cur = -1; + err = azalia_codec_construct_format(this, 0, 0); if (err) return err; @@ -1096,15 +1097,18 @@ azalia_codec_delete(codec_t *this) } int -azalia_codec_construct_format(codec_t *this) +azalia_codec_construct_format(codec_t *this, int newdac, int newadc) { const convgroup_t *group; uint32_t bits_rates; + int prev_dac, prev_adc; int pvariation, rvariation; int nbits, dac, chan, i, err; nid_t nid; - group = &this->dacgroups[this->cur_dac]; + prev_dac = this->dacs.cur; + this->dacs.cur = newdac; + group = &this->dacs.groups[this->dacs.cur]; bits_rates = this->w[group->conv[0]].d.audio.bits_rates; nbits = 0; if (bits_rates & COP_PCM_B8) @@ -1124,7 +1128,10 @@ azalia_codec_construct_format(codec_t *this) } pvariation = group->nconv * nbits; - bits_rates = this->w[this->adcs[this->cur_adc]].d.audio.bits_rates; + prev_adc = this->adcs.cur; + this->adcs.cur = newadc; + group = &this->adcs.groups[this->adcs.cur]; + bits_rates = this->w[group->conv[0]].d.audio.bits_rates; nbits = 0; if (bits_rates & COP_PCM_B8) nbits++; @@ -1159,6 +1166,7 @@ azalia_codec_construct_format(codec_t *this) (pvariation + rvariation)); /* register formats for playback */ + group = &this->dacs.groups[this->dacs.cur]; nid = group->conv[0]; chan = 0; bits_rates = this->w[nid].d.audio.bits_rates; @@ -1169,7 +1177,8 @@ azalia_codec_construct_format(codec_t *this) } /* register formats for recording */ - nid = this->adcs[this->cur_adc]; + group = &this->adcs.groups[this->adcs.cur]; + nid = group->conv[0]; chan = WIDGET_CHANNELS(&this->w[nid]); bits_rates = this->w[nid].d.audio.bits_rates; azalia_codec_add_bits(this, chan, bits_rates, AUMODE_RECORD); @@ -1278,17 +1287,10 @@ azalia_codec_connect_stream(codec_t *this, int dir, uint16_t fmt, int number) DPRINTF(("%s: fmt=0x%4.4x number=%d\n", __func__, fmt, number)); err = 0; - if (dir == AUMODE_RECORD) { - nid = this->adcs[this->cur_adc]; - DPRINTF(("%s: record: nid=0x%.2x\n", __func__, nid)); - err = this->comresp(this, nid, CORB_SET_CONVERTER_FORMAT, fmt, NULL); - if (err) - goto exit; - err = this->comresp(this, nid, CORB_SET_CONVERTER_STREAM_CHANNEL, - (number << 4) | 0, NULL); - goto exit; - } - group = &this->dacgroups[this->cur_dac]; + if (dir == AUMODE_RECORD) + group = &this->adcs.groups[this->adcs.cur]; + else + group = &this->dacs.groups[this->dacs.cur]; flag222 = group->nconv >= 3 && (WIDGET_CHANNELS(&this->w[group->conv[0]]) == 2) && (WIDGET_CHANNELS(&this->w[group->conv[1]]) == 2) && diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h index 0c79899a1ca..580637c9f94 100644 --- a/sys/dev/pci/azalia.h +++ b/sys/dev/pci/azalia.h @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.h,v 1.7 2006/06/14 19:34:52 brad Exp $ */ +/* $OpenBSD: azalia.h,v 1.8 2006/06/16 06:00:46 brad Exp $ */ /* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */ /*- @@ -511,8 +511,13 @@ typedef struct { typedef struct { int nconv; - nid_t conv[HDA_MAX_CHANNELS]; + nid_t conv[HDA_MAX_CHANNELS]; /* front, surround, clfe, side, ... */ } convgroup_t; +typedef struct { + int cur; + int ngroups; + convgroup_t groups[32]; +} convgroupset_t; typedef struct codec_t { int (*comresp)(const struct codec_t *, nid_t, uint32_t, uint32_t, uint32_t *); @@ -536,12 +541,8 @@ typedef struct codec_t { * w[0] to w[wstart-1] are unused. */ #define FOR_EACH_WIDGET(this, i) for (i = (this)->wstart; i < (this)->wend; i++) - int ndacgroups; - convgroup_t dacgroups[32]; - int cur_dac; /* currently selected DAC group index */ - int nadcs; - nid_t adcs[32]; - int cur_adc; /* currently selected ADC index */ + convgroupset_t dacs; + convgroupset_t adcs; int running; int nmixers, maxmixers; @@ -554,4 +555,4 @@ typedef struct codec_t { int azalia_codec_init_vtbl(codec_t *); -int azalia_codec_construct_format(codec_t *); +int azalia_codec_construct_format(codec_t *, int, int); diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c index 0ad32e529ea..457a29e4cb2 100644 --- a/sys/dev/pci/azalia_codec.c +++ b/sys/dev/pci/azalia_codec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia_codec.c,v 1.10 2006/06/14 20:24:12 brad Exp $ */ +/* $OpenBSD: azalia_codec.c,v 1.11 2006/06/16 06:00:46 brad Exp $ */ /* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */ /*- @@ -55,6 +55,11 @@ __KERNEL_RCSID(0, "$NetBSD: azalia_codec.c,v 1.3 2005/09/29 04:14:03 kent Exp $" #define AZ_CLASS_RECORD 2 #define ENUM_OFFON .un.e={2, {{{AudioNoff}, 0}, {{AudioNon}, 1}}} #define ENUM_IO .un.e={2, {{{"input"}, 0}, {{"output"}, 1}}} +#ifdef MAX_VOLUME_255 +# define MIXER_DELTA(n) (AUDIO_MAX_GAIN / (n)) +#else +# define MIXER_DELTA(n) (1) +#endif int azalia_generic_codec_init_dacgroup(codec_t *); @@ -73,6 +78,7 @@ u_char azalia_generic_mixer_from_device_value (const codec_t *, nid_t, int, uint32_t ); uint32_t azalia_generic_mixer_to_device_value (const codec_t *, nid_t, int, u_char); +uint32_t azalia_generic_mixer_max(const codec_t *, nid_t, int); boolean_t azalia_generic_mixer_validate_value (const codec_t *, nid_t, int, u_char); int azalia_generic_set_port(codec_t *, mixer_ctrl_t *); @@ -88,6 +94,7 @@ int azalia_alc882_init_widget(const codec_t *, widget_t *, nid_t); int azalia_ad1981hd_init_widget(const codec_t *, widget_t *, nid_t); #endif int azalia_stac9221_init_dacgroup(codec_t *); +int azalia_stac9220_mixer_init(codec_t *); int @@ -126,6 +133,10 @@ azalia_codec_init_vtbl(codec_t *this) this->init_widget = azalia_ad1981hd_init_widget; break; #endif + case 0x11d41983: + /* http://www.analog.com/en/prod/0,2877,AD1983,00.html */ + this->name = "Analog Devices AD1983"; + break; case 0x83847680: this->name = "Sigmatel STAC9221"; this->init_dacgroup = azalia_stac9221_init_dacgroup; @@ -136,6 +147,7 @@ azalia_codec_init_vtbl(codec_t *this) break; case 0x83847690: this->name = "Sigmatel STAC9220"; + this->mixer_init = azalia_stac9220_mixer_init; break; } return 0; @@ -157,7 +169,7 @@ azalia_generic_codec_init_dacgroup(codec_t *this) * [2] the 2nd assoc DACs * : */ - this->ndacgroups = 0; + this->dacs.ngroups = 0; for (assoc = 0; assoc < CORB_CD_ASSOCIATION_MAX; assoc++) { azalia_generic_codec_add_dacgroup(this, assoc, 0); azalia_generic_codec_add_dacgroup(this, assoc, COP_AWCAP_DIGITAL); @@ -171,35 +183,37 @@ azalia_generic_codec_init_dacgroup(codec_t *this) if (this->w[i].type != COP_AWTYPE_AUDIO_OUTPUT) continue; found = FALSE; - for (group = 0; group < this->ndacgroups; group++) { - for (j = 0; j < this->dacgroups[group].nconv; j++) { - if (i == this->dacgroups[group].conv[j]) { + for (group = 0; group < this->dacs.ngroups; group++) { + for (j = 0; j < this->dacs.groups[group].nconv; j++) { + if (i == this->dacs.groups[group].conv[j]) { found = TRUE; - group = this->ndacgroups; + group = this->dacs.ngroups; break; } } } if (found) continue; - if (this->ndacgroups >= 32) + if (this->dacs.ngroups >= 32) break; - this->dacgroups[this->ndacgroups].nconv = 1; - this->dacgroups[this->ndacgroups].conv[0] = i; - this->ndacgroups++; + this->dacs.groups[this->dacs.ngroups].nconv = 1; + this->dacs.groups[this->dacs.ngroups].conv[0] = i; + this->dacs.ngroups++; } - this->cur_dac = 0; + this->dacs.cur = 0; /* enumerate ADCs */ - this->nadcs = 0; + this->adcs.ngroups = 0; FOR_EACH_WIDGET(this, i) { if (this->w[i].type != COP_AWTYPE_AUDIO_INPUT) continue; - this->adcs[this->nadcs++] = i; - if (this->nadcs >= 32) + this->adcs.groups[this->adcs.ngroups].nconv = 1; + this->adcs.groups[this->adcs.ngroups].conv[0] = i; + this->adcs.ngroups++; + if (this->adcs.ngroups >= 32) break; } - this->cur_adc = 0; + this->adcs.cur = 0; return 0; } @@ -218,33 +232,33 @@ azalia_generic_codec_add_dacgroup(codec_t *this, int assoc, uint32_t digital) continue; /* duplication check */ for (j = 0; j < n; j++) { - if (this->dacgroups[this->ndacgroups].conv[j] == dac) + if (this->dacs.groups[this->dacs.ngroups].conv[j] == dac) break; } if (j < n) /* this group already has <dac> */ continue; - this->dacgroups[this->ndacgroups].conv[n++] = dac; + this->dacs.groups[this->dacs.ngroups].conv[n++] = dac; DPRINTF(("%s: assoc=%d seq=%d ==> g=%d n=%d\n", - __func__, assoc, seq, this->ndacgroups, n-1)); + __func__, assoc, seq, this->dacs.ngroups, n-1)); } if (n <= 0) /* no such DACs */ return 0; - this->dacgroups[this->ndacgroups].nconv = n; + this->dacs.groups[this->dacs.ngroups].nconv = n; /* check if the same combination is already registered */ - for (i = 0; i < this->ndacgroups; i++) { - if (n != this->dacgroups[i].nconv) + for (i = 0; i < this->dacs.ngroups; i++) { + if (n != this->dacs.groups[i].nconv) continue; for (j = 0; j < n; j++) { - if (this->dacgroups[this->ndacgroups].conv[j] != - this->dacgroups[i].conv[j]) + if (this->dacs.groups[this->dacs.ngroups].conv[j] != + this->dacs.groups[i].conv[j]) break; } if (j >= n) /* matched */ return 0; } /* found no equivalent group */ - this->ndacgroups++; + this->dacs.ngroups++; return 0; } @@ -286,15 +300,19 @@ azalia_generic_codec_find_dac(const codec_t *this, int index, int depth) } if (w->selected >= 0) { j = w->connections[w->selected]; - ret = azalia_generic_codec_find_dac(this, j, depth); - if (ret >= 0) { - DPRINTF(("%s: DAC path: nid=0x%x index=%d\n", - __func__, w->nid, index)); - return ret; + if (VALID_WIDGET_NID(j, this)) { + ret = azalia_generic_codec_find_dac(this, j, depth); + if (ret >= 0) { + DPRINTF(("%s: DAC path: nid=0x%x index=%d\n", + __func__, w->nid, index)); + return ret; + } } } for (i = 0; i < w->nconnections; i++) { j = w->connections[i]; + if (!VALID_WIDGET_NID(j, this)) + continue; ret = azalia_generic_codec_find_dac(this, j, depth); if (ret >= 0) { DPRINTF(("%s: DAC path: nid=0x%x index=%d\n", @@ -320,10 +338,8 @@ azalia_generic_mixer_init(codec_t *this) * selector "sel%2.2x" */ mixer_item_t *m; - int nadcs; int err, i, j, k; - nadcs = 0; this->maxmixers = 10; this->nmixers = 0; this->mixers = malloc(sizeof(mixer_item_t) * this->maxmixers, @@ -382,9 +398,6 @@ azalia_generic_mixer_init(codec_t *this) w = &this->w[i]; - if (w->type == COP_AWTYPE_AUDIO_INPUT) - nadcs++; - /* selector */ if (w->type != COP_AWTYPE_AUDIO_MIXER && w->nconnections >= 2) { MIXER_REG_PROLOG; @@ -461,13 +474,12 @@ azalia_generic_mixer_init(codec_t *this) d->un.v.num_channels = WIDGET_CHANNELS(w); #ifdef MAX_VOLUME_255 d->un.v.units.name[0] = 0; - d->un.v.delta = AUDIO_MAX_GAIN / - COP_AMPCAP_NUMSTEPS(w->outamp_cap); #else snprintf(d->un.v.units.name, sizeof(d->un.v.units.name), "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->outamp_cap)+1); - d->un.v.delta = 1; #endif + d->un.v.delta = + MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->outamp_cap)); this->nmixers++; } @@ -546,14 +558,13 @@ azalia_generic_mixer_init(codec_t *this) d->un.v.num_channels = WIDGET_CHANNELS(w); #ifdef MAX_VOLUME_255 d->un.v.units.name[0] = 0; - d->un.v.delta = AUDIO_MAX_GAIN / - COP_AMPCAP_NUMSTEPS(w->inamp_cap); #else snprintf(d->un.v.units.name, sizeof(d->un.v.units.name), "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->inamp_cap)+1); - d->un.v.delta = 1; #endif + d->un.v.delta = + MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); this->nmixers++; } else { for (j = 0; j < w->nconnections; j++) { @@ -576,14 +587,13 @@ azalia_generic_mixer_init(codec_t *this) d->un.v.num_channels = WIDGET_CHANNELS(w); #ifdef MAX_VOLUME_255 d->un.v.units.name[0] = 0; - d->un.v.delta = AUDIO_MAX_GAIN / - COP_AMPCAP_NUMSTEPS(w->inamp_cap); #else snprintf(d->un.v.units.name, sizeof(d->un.v.units.name), "0.25x%ddB", COP_AMPCAP_STEPSIZE(w->inamp_cap)+1); - d->un.v.delta = 1; #endif + d->un.v.delta = + MIXER_DELTA(COP_AMPCAP_NUMSTEPS(w->inamp_cap)); this->nmixers++; } } @@ -641,50 +651,51 @@ azalia_generic_mixer_init(codec_t *this) m->target = MI_TARGET_VOLUME; d->un.v.num_channels = 1; d->un.v.units.name[0] = 0; -#ifdef MAX_VOLUME_255 - d->un.v.delta = AUDIO_MAX_GAIN / - COP_VKCAP_NUMSTEPS(w->d.volume.cap); -#else - d->un.v.delta = 1; -#endif + d->un.v.delta = + MIXER_DELTA(COP_VKCAP_NUMSTEPS(w->d.volume.cap)); this->nmixers++; } } /* if the codec has multiple DAC groups, create "inputs.usingdac" */ - if (this->ndacgroups > 1) { + if (this->dacs.ngroups > 1) { MIXER_REG_PROLOG; DPRINTF(("%s: create inputs.usingdac\n", __func__)); strlcpy(d->label.name, "usingdac", sizeof(d->label.name)); d->type = AUDIO_MIXER_ENUM; d->mixer_class = AZ_CLASS_INPUT; m->target = MI_TARGET_DAC; - for (i = 0; i < this->ndacgroups && i < 32; i++) { + for (i = 0; i < this->dacs.ngroups && i < 32; i++) { d->un.e.member[i].ord = i; - for (j = 0; j < this->dacgroups[i].nconv; j++) { + for (j = 0; j < this->dacs.groups[i].nconv; j++) { if (j * 2 >= MAX_AUDIO_DEV_LEN) break; snprintf(d->un.e.member[i].label.name + j*2, MAX_AUDIO_DEV_LEN - j*2, "%2.2x", - this->dacgroups[i].conv[j]); + this->dacs.groups[i].conv[j]); } } d->un.e.num_mem = i; this->nmixers++; } - /* if the codec has multiple ADCs, create "record.usingadc" */ - if (this->nadcs > 1) { + /* if the codec has multiple ADC groups, create "record.usingadc" */ + if (this->adcs.ngroups > 1) { MIXER_REG_PROLOG; DPRINTF(("%s: create inputs.usingadc\n", __func__)); strlcpy(d->label.name, "usingadc", sizeof(d->label.name)); d->type = AUDIO_MIXER_ENUM; d->mixer_class = AZ_CLASS_RECORD; m->target = MI_TARGET_ADC; - for (i = 0; i < this->nadcs && i < 32; i++) { + for (i = 0; i < this->adcs.ngroups && i < 32; i++) { d->un.e.member[i].ord = i; - strlcpy(d->un.e.member[i].label.name, - this->w[this->adcs[i]].name, MAX_AUDIO_DEV_LEN); + for (j = 0; j < this->adcs.groups[i].nconv; j++) { + if (j * 2 >= MAX_AUDIO_DEV_LEN) + break; + snprintf(d->un.e.member[i].label.name + j*2, + MAX_AUDIO_DEV_LEN - j*2, "%2.2x", + this->adcs.groups[i].conv[j]); + } } d->un.e.num_mem = i; this->nmixers++; @@ -930,12 +941,12 @@ azalia_generic_mixer_get(const codec_t *this, nid_t nid, int target, mixer_ctrl_ /* DAC group selection */ else if (target == MI_TARGET_DAC) { - mc->un.ord = this->cur_dac; + mc->un.ord = this->dacs.cur; } /* ADC selection */ else if (target == MI_TARGET_ADC) { - mc->un.ord = this->cur_adc; + mc->un.ord = this->adcs.cur; } /* Volume knob */ @@ -1173,21 +1184,20 @@ azalia_generic_mixer_set(codec_t *this, nid_t nid, int target, const mixer_ctrl_ else if (target == MI_TARGET_DAC) { if (this->running) return EBUSY; - if (mc->un.ord >= this->ndacgroups) + if (mc->un.ord >= this->dacs.ngroups) return EINVAL; - this->cur_dac = mc->un.ord; - return azalia_codec_construct_format(this); + return azalia_codec_construct_format(this, + mc->un.ord, this->adcs.cur); } /* ADC selection */ else if (target == MI_TARGET_ADC) { if (this->running) return EBUSY; - if (mc->un.ord >= this->nadcs) + if (mc->un.ord >= this->adcs.ngroups) return EINVAL; - this->cur_adc = mc->un.ord; - /* use this->adcs[this->cur_adc] */ - return azalia_codec_construct_format(this); + return azalia_codec_construct_format(this, + this->dacs.cur, mc->un.ord); } /* Volume knob */ @@ -1259,12 +1269,11 @@ azalia_generic_mixer_to_device_value(const codec_t *this, nid_t nid, int target, #endif } -boolean_t -azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target, - u_char uv) +uint32_t +azalia_generic_mixer_max(const codec_t *this, nid_t nid, int target) { #ifdef MAX_VOLUME_255 - return TRUE; + return AUDIO_MAX_GAIN; #else uint32_t dmax; @@ -1274,7 +1283,18 @@ azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target, dmax = COP_AMPCAP_NUMSTEPS(this->w[nid].outamp_cap); else if (target == MI_TARGET_VOLUME) dmax = COP_VKCAP_NUMSTEPS(this->w[nid].d.volume.cap); - return uv <= dmax; + return dmax; +#endif +} + +boolean_t +azalia_generic_mixer_validate_value(const codec_t *this, nid_t nid, int target, + u_char uv) +{ +#ifdef MAX_VOLUME_255 + return TRUE; +#else + return uv <= generic_mixer_max(this, nid, target); #endif } @@ -1355,11 +1375,11 @@ static const mixer_item_t alc260_mixer_items[] = { {{0, {"mic1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)}, {{0, {"mic1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(0)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)}, {{0, {"mic2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(1)}, {{0, {"mic2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(1)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(1)}, {{0, {"line1.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(2)}, {{0, {"line1"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, @@ -1367,15 +1387,15 @@ static const mixer_item_t alc260_mixer_items[] = { {{0, {"line2.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(3)}, {{0, {"line2"}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(3)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(3)}, {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)}, {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(4)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)}, {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)}, {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(5)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)}, {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, .un.e={5, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2}, @@ -1383,8 +1403,8 @@ static const mixer_item_t alc260_mixer_items[] = { 0x04, MI_TARGET_CONNLIST}, {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)}, - {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, .un.v={{""}, 2, 7}}, - 0x04, MI_TARGET_INAMP(0)}, + {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, + .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)}, {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, .un.e={6, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{"line1"}, 2}, {{"line2"}, 3}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}}, @@ -1392,7 +1412,7 @@ static const mixer_item_t alc260_mixer_items[] = { {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)}, {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, - .un.v={{""}, 2, 7}}, 0x05, MI_TARGET_INAMP(0)}, + .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)}, {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, @@ -1421,29 +1441,29 @@ static const mixer_item_t alc260_loox_mixer_items[] = { {{0, {AudioNmicrophone".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(0)}, {{0, {AudioNmicrophone}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(0)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(0)}, {{0, {AudioNcd".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(4)}, {{0, {AudioNcd}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(4)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(4)}, {{0, {AudioNspeaker".mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, ENUM_OFFON}, 0x07, MI_TARGET_INAMP(5)}, {{0, {AudioNspeaker}, AUDIO_MIXER_VALUE, AZ_CLASS_INPUT, - 0, 0, .un.v={{""}, 2, 3}}, 0x07, MI_TARGET_INAMP(5)}, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(65)}}, 0x07, MI_TARGET_INAMP(5)}, {{0, {"adc04.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, .un.e={2, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}}}}, 0x04, MI_TARGET_CONNLIST}, {{0, {"adc04.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, ENUM_OFFON}, 0x04, MI_TARGET_INAMP(0)}, {{0, {"adc04"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, - .un.v={{""}, 2, 7}}, 0x04, MI_TARGET_INAMP(0)}, + .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x04, MI_TARGET_INAMP(0)}, {{0, {"adc05.source"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, .un.e={3, {{{AudioNmicrophone}, 0}, {{AudioNcd}, 4}, {{AudioNmixerout}, 5}}}}, 0x05, MI_TARGET_CONNLIST}, {{0, {"adc05.mute"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, 0, 0, ENUM_OFFON}, 0x05, MI_TARGET_INAMP(0)}, {{0, {"adc05"}, AUDIO_MIXER_VALUE, AZ_CLASS_RECORD, 0, 0, - .un.v={{""}, 2, 7}}, 0x05, MI_TARGET_INAMP(0)}, + .un.v={{""}, 2, MIXER_DELTA(35)}}, 0x05, MI_TARGET_INAMP(0)}, {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, 0, MI_TARGET_DAC}, @@ -1506,18 +1526,18 @@ azalia_alc260_mixer_init(codec_t *this) int azalia_alc260_init_dacgroup(codec_t *this) { - static const convgroup_t dacs[2] = { - {1, {0x02}}, /* analog 2ch */ - {1, {0x03}}}; /* digital */ - - this->ndacgroups = 2; - this->dacgroups[0] = dacs[0]; - this->dacgroups[1] = dacs[1]; - - this->nadcs = 3; - this->adcs[0] = 0x04; - this->adcs[1] = 0x05; - this->adcs[2] = 0x06; /* digital */ + static const convgroupset_t dacs = { + -1, 2, + {{1, {0x02}}, /* analog 2ch */ + {1, {0x03}}}}; /* digital */ + static const convgroupset_t adcs = { + -1, 3, + {{1, {0x04}}, /* analog 2ch */ + {1, {0x05}}, /* analog 2ch */ + {1, {0x06}}}}; /* digital */ + + this->dacs = dacs; + this->adcs = adcs; return 0; } @@ -1576,18 +1596,17 @@ azalia_alc260_set_port(codec_t *this, mixer_ctrl_t *mc) int azalia_alc880_init_dacgroup(codec_t *this) { - static const convgroup_t dacs[2] = { - {4, {0x02, 0x04, 0x03, 0x05}}, /* analog 8ch */ - {1, {0x06}}}; /* digital */ - - this->ndacgroups = 2; - this->dacgroups[0] = dacs[0]; - this->dacgroups[1] = dacs[1]; - - this->nadcs = 3; - this->adcs[0] = 0x08; - this->adcs[1] = 0x09; - this->adcs[2] = 0x0a; /* digital */ + static const convgroupset_t dacs = { + -1, 2, + {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ + {1, {0x06}}}}; /* digital */ + static const convgroupset_t adcs = { + -1, 2, + {{2, {0x08, 0x09}}, /* analog 4ch */ + {1, {0x0a}}}}; /* digital */ + + this->dacs = dacs; + this->adcs = adcs; return 0; } @@ -1598,21 +1617,18 @@ azalia_alc880_init_dacgroup(codec_t *this) int azalia_alc882_init_dacgroup(codec_t *this) { - static const convgroup_t dacs[3] = { - {4, {0x02, 0x04, 0x03, 0x05}}, /* analog 8ch */ - {1, {0x06}}, /* digital */ - {1, {0x25}}}; /* another analog */ - - this->ndacgroups = 3; - this->dacgroups[0] = dacs[0]; - this->dacgroups[1] = dacs[1]; - this->dacgroups[2] = dacs[2]; - - this->nadcs = 4; - this->adcs[0] = 0x07; - this->adcs[1] = 0x08; - this->adcs[2] = 0x09; - this->adcs[3] = 0x0a; /* digital */ + static const convgroupset_t dacs = { + -1, 3, + {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ + {1, {0x06}}, /* digital */ + {1, {0x25}}}}; /* another analog */ + static const convgroupset_t adcs = { + -1, 2, + {{3, {0x07, 0x08, 0x09}}, /* analog 6ch */ + {1, {0x0a}}}}; /* digital */ + + this->dacs = dacs; + this->adcs = adcs; return 0; } @@ -1706,19 +1722,98 @@ azalia_ad1981hd_init_widget(const codec_t *this, widget_t *w, nid_t nid) int azalia_stac9221_init_dacgroup(codec_t *this) { - static const convgroup_t dacs[3] = { - {4, {0x02, 0x03, 0x05, 0x04}}, /* analog 8ch */ - {1, {0x08}}, /* digital */ - {1, {0x1a}}}; /* another digital? */ - - this->ndacgroups = 3; - this->dacgroups[0] = dacs[0]; - this->dacgroups[1] = dacs[1]; - this->dacgroups[2] = dacs[2]; - - this->nadcs = 3; - this->adcs[0] = 6; /* XXX four channel recording */ - this->adcs[1] = 7; - this->adcs[2] = 9; /* digital */ + static const convgroupset_t dacs = { + -1, 3, + {{4, {0x02, 0x03, 0x04, 0x05}}, /* analog 8ch */ + {1, {0x08}}, /* digital */ + {1, {0x1a}}}}; /* another digital? */ + static const convgroupset_t adcs = { + -1, 2, + {{2, {0x06, 0x07}}, /* analog 4ch */ + {1, {0x09}}}}; /* digital */ + + this->dacs = dacs; + this->adcs = adcs; + return 0; +} + +/* ---------------------------------------------------------------- + * Sigmatel STAC9220 + * ---------------------------------------------------------------- */ + +static const mixer_item_t stac9220_mixer_items[] = { + {{AZ_CLASS_INPUT, {AudioCinputs}, AUDIO_MIXER_CLASS, AZ_CLASS_INPUT, 0, 0}, 0}, + {{AZ_CLASS_OUTPUT, {AudioCoutputs}, AUDIO_MIXER_CLASS, AZ_CLASS_OUTPUT, 0, 0}, 0}, + {{AZ_CLASS_RECORD, {AudioCrecord}, AUDIO_MIXER_CLASS, AZ_CLASS_RECORD, 0, 0}, 0}, + + {{0, {AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, .un.e={3, {{{AudioNdac}, 0}, {{"digital-in"}, 1}, {{"selector"}, 2}}}}, + 0x07, MI_TARGET_CONNLIST}, + {{0, {"digital."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, .un.e={2, {{{AudioNdac}, 0}, {{"selector"}, 1}}}}, + 0x09, MI_TARGET_CONNLIST}, /* AudioNdac is not accurate name */ + {{0, {"selector."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x0a, MI_TARGET_OUTAMP}, + {{0, {"selector"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(15)}}, 0x0a, MI_TARGET_OUTAMP}, + {{0, {AudioNmaster"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x0b, MI_TARGET_OUTAMP}, + {{0, {AudioNmaster}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, + 0, 0, .un.v={{""}, 2, MIXER_DELTA(31)}}, 0x0b, MI_TARGET_OUTAMP}, + {{0, {"selector."AudioNsource}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, + 0, 0, .un.e={3, {{{"mic1"}, 0}, {{"mic2"}, 1}, {{AudioNcd}, 4}}}}, + 0x0c, MI_TARGET_CONNLIST}, + {{0, {AudioNheadphone".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x0d, MI_TARGET_PINBOOST}, + {{0, {AudioNspeaker".boost"}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x0e, MI_TARGET_PINBOOST}, + {{0, {AudioNmono"."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x11, MI_TARGET_OUTAMP}, + {{0, {AudioNmono}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, + 0, 0, .un.v={{""}, 1, MIXER_DELTA(31)}}, 0x11, MI_TARGET_OUTAMP}, + {{0, {"beep."AudioNmute}, AUDIO_MIXER_ENUM, AZ_CLASS_OUTPUT, + 0, 0, ENUM_OFFON}, 0x14, MI_TARGET_OUTAMP}, + {{0, {"beep"}, AUDIO_MIXER_VALUE, AZ_CLASS_OUTPUT, + 0, 0, .un.v={{""}, 1, MIXER_DELTA(3)}}, 0x14, MI_TARGET_OUTAMP}, + {{0, {"usingdac"}, AUDIO_MIXER_ENUM, AZ_CLASS_INPUT, + 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, + 0, MI_TARGET_DAC}, + {{0, {"usingadc"}, AUDIO_MIXER_ENUM, AZ_CLASS_RECORD, + 0, 0, .un.e={2, {{{"analog"}, 0}, {{"digital"}, 1}}}}, + 0, MI_TARGET_ADC}, +}; + +int +azalia_stac9220_mixer_init(codec_t *this) +{ + mixer_ctrl_t mc; + + this->nmixers = sizeof(stac9220_mixer_items) / sizeof(mixer_item_t); + this->mixers = malloc(sizeof(mixer_item_t) * this->nmixers, + M_DEVBUF, M_NOWAIT); + if (this->mixers == NULL) { + printf("%s: out of memory in %s\n", XNAME(this), __func__); + return ENOMEM; + } + bzero(this->mixers, sizeof(mixer_item_t) * this->maxmixers); + memcpy(this->mixers, stac9220_mixer_items, + sizeof(mixer_item_t) * this->nmixers); + azalia_generic_mixer_fix_indexes(this); + azalia_generic_mixer_default(this); + + mc.dev = -1; /* no need for generic_mixer_set() */ + mc.type = AUDIO_MIXER_ENUM; + mc.un.ord = 1; /* pindir: output */ + azalia_generic_mixer_set(this, 0x0d, MI_TARGET_PINDIR, &mc); /* headphones */ + azalia_generic_mixer_set(this, 0x0e, MI_TARGET_PINDIR, &mc); /* speaker */ + mc.un.ord = 0; /* pindir: input */ + azalia_generic_mixer_set(this, 0x0f, MI_TARGET_PINDIR, &mc); /* mic2 */ + azalia_generic_mixer_set(this, 0x10, MI_TARGET_PINDIR, &mc); /* mic1 */ + mc.type = AUDIO_MIXER_VALUE; + mc.un.value.num_channels = 2; + mc.un.value.level[0] = azalia_generic_mixer_max(this, 0x0c, MI_TARGET_OUTAMP); + mc.un.value.level[1] = mc.un.value.level[0]; + azalia_generic_mixer_set(this, 0x0c, MI_TARGET_OUTAMP, &mc); + return 0; } |