summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorJacob Meuser <jakemsr@cvs.openbsd.org>2009-05-29 17:54:09 +0000
committerJacob Meuser <jakemsr@cvs.openbsd.org>2009-05-29 17:54:09 +0000
commitd5618b247036ee08ac332f4946afccd707badb26 (patch)
treedfa6baada07d3efcd0608462f541988e8f98a786 /sys/dev
parent1cdf63c3986c5c1476a7f88386079e30b18667aa (diff)
- if a codec is capable of multichannel playback, try to connect
the output jacks to different DACs. - multichannel codecs often have a front headphone jack that is intended to be used separately from the multichannel jacks. if a front headphone jack exists, try to connect it to a DAC not used by the multichannel jacks.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/pci/azalia.c103
-rw-r--r--sys/dev/pci/azalia.h4
2 files changed, 102 insertions, 5 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c
index 75fc7a754ec..ffb35836e15 100644
--- a/sys/dev/pci/azalia.c
+++ b/sys/dev/pci/azalia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.c,v 1.133 2009/05/29 02:49:30 jakemsr Exp $ */
+/* $OpenBSD: azalia.c,v 1.134 2009/05/29 17:54:08 jakemsr Exp $ */
/* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */
/*-
@@ -212,6 +212,7 @@ int azalia_codec_find_defadc_sub(codec_t *, nid_t, int, int);
int azalia_codec_init_volgroups(codec_t *);
int azalia_codec_sort_pins(codec_t *);
int azalia_codec_select_micadc(codec_t *);
+int azalia_codec_select_dacs(codec_t *);
int azalia_codec_select_spkrdac(codec_t *);
int azalia_codec_find_inputmixer(codec_t *);
@@ -1282,6 +1283,7 @@ azalia_codec_init(codec_t *this)
this->na_adcs = this->na_adcs_d = 0;
this->speaker = this->spkr_dac = this->mic = this->mic_adc = -1;
this->nsense_pins = 0;
+ this->nout_jacks = 0;
FOR_EACH_WIDGET(this, i) {
if (!this->w[i].enable)
continue;
@@ -1329,6 +1331,8 @@ azalia_codec_init(codec_t *this)
}
break;
case CORB_CD_JACK:
+ if (this->w[i].d.pin.device == CORB_CD_LINEOUT)
+ this->nout_jacks++;
if (this->nsense_pins >= HDA_MAX_SENSE_PINS ||
!(this->w[i].d.pin.cap & COP_PINCAP_PRESENCE))
break;
@@ -1361,6 +1365,17 @@ azalia_codec_init(codec_t *this)
if (err)
return err;
+ /* If the codec can do multichannel, select different DACs for
+ * the multichannel jack group. Also select a unique DAC for
+ * the front headphone jack, if one exists.
+ */
+ this->fhp_dac = -1;
+ if (this->na_dacs >= 3 && this->nopins >= 3) {
+ err = azalia_codec_select_dacs(this);
+ if (err)
+ return err;
+ }
+
err = azalia_codec_select_spkrdac(this);
if (err)
return err;
@@ -1489,7 +1504,7 @@ azalia_codec_sort_pins(codec_t *this)
struct io_pin opins[MAX_PINS], opins_d[MAX_PINS];
struct io_pin ipins[MAX_PINS], ipins_d[MAX_PINS];
int nopins, nopins_d, nipins, nipins_d;
- int prio, add, nd, conv;
+ int prio, loc, add, nd, conv;
int i, j, k;
nopins = nopins_d = nipins = nipins_d = 0;
@@ -1499,6 +1514,10 @@ azalia_codec_sort_pins(codec_t *this)
if (!w->enable || w->type != COP_AWTYPE_PIN_COMPLEX)
continue;
+ loc = 0;
+ if (this->na_dacs >= 3 && this->nout_jacks < 3)
+ loc = CORB_CD_LOC_GEO(w->d.pin.config);
+
prio = w->d.pin.association << 4 | w->d.pin.sequence;
conv = -1;
@@ -1529,7 +1548,8 @@ azalia_codec_sort_pins(codec_t *this)
if (add && nopins < MAX_PINS) {
opins[nopins].nid = w->nid;
opins[nopins].conv = conv;
- opins[nopins].prio = prio | (nd << 8);
+ prio |= (nd << 8) | (loc << 9);
+ opins[nopins].prio = prio;
nopins++;
}
}
@@ -1695,6 +1715,80 @@ azalia_codec_sort_pins(codec_t *this)
#undef MAX_PINS
}
+int
+azalia_codec_select_dacs(codec_t *this)
+{
+ widget_t *w;
+ nid_t *convs;
+ int nconv, conv;
+ int i, j, k, err, isfhp;
+
+ convs = malloc(this->na_dacs * sizeof(nid_t), M_DEVBUF,
+ M_NOWAIT | M_ZERO);
+ if (convs == NULL)
+ return(ENOMEM);
+
+ nconv = 0;
+ for (i = 0; i < this->nopins; i++) {
+ isfhp = 0;
+ w = &this->w[this->opins[i].nid];
+
+ if (w->d.pin.device == CORB_CD_HEADPHONE &&
+ CORB_CD_LOC_GEO(w->d.pin.config) == CORB_CD_FRONT) {
+ isfhp = 1;
+ }
+
+ conv = this->opins[i].conv;
+ for (j = 0; j < nconv; j++) {
+ if (conv == convs[j])
+ break;
+ }
+ if (j == nconv) {
+ convs[nconv++] = conv;
+ if (isfhp)
+ this->fhp_dac = conv;
+ if (nconv >= this->na_dacs) {
+ return(0);
+ }
+ } else {
+ /* find a different dac */
+ conv = -1;
+ for (j = 0; j < w->nconnections; j++) {
+ if (!azalia_widget_enabled(this,
+ w->connections[j]))
+ continue;
+ conv = azalia_codec_find_defdac(this,
+ w->connections[j], 1);
+ if (conv == -1)
+ continue;
+ for (k = 0; k < nconv; k++) {
+ if (conv == convs[k])
+ break;
+ }
+ if (k == nconv)
+ break;
+ }
+ if (j < w->nconnections && conv != -1) {
+ err = this->comresp(this, w->nid,
+ CORB_SET_CONNECTION_SELECT_CONTROL, j, 0);
+ if (err)
+ return(err);
+ w->selected = j;
+ this->opins[i].conv = conv;
+ if (isfhp)
+ this->fhp_dac = conv;
+ convs[nconv++] = conv;
+ if (nconv >= this->na_dacs)
+ return(0);
+ }
+ }
+ }
+
+ free(convs, M_DEVBUF);
+
+ return(0);
+}
+
/* Connect the speaker to a DAC that no other output pin is connected
* to by default. If that is not possible, connect to a DAC other
* than the one the first output pin is connected to.
@@ -2324,7 +2418,8 @@ azalia_codec_connect_stream(codec_t *this, int dir, uint16_t fmt, int number)
stream_chan = (number << 4);
if (curchan < nchan) {
stream_chan |= curchan;
- } else if (w->nid == this->spkr_dac) {
+ } else if (w->nid == this->spkr_dac ||
+ w->nid == this->fhp_dac) {
stream_chan |= 0; /* first channel(s) */
} else
stream_chan = 0; /* idle stream */
diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h
index 867b38d3479..921c8d6530d 100644
--- a/sys/dev/pci/azalia.h
+++ b/sys/dev/pci/azalia.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.h,v 1.46 2009/05/29 02:38:01 jakemsr Exp $ */
+/* $OpenBSD: azalia.h,v 1.47 2009/05/29 17:54:08 jakemsr Exp $ */
/* $NetBSD: azalia.h,v 1.6 2006/01/16 14:15:26 kent Exp $ */
/*-
@@ -670,6 +670,8 @@ typedef struct codec_t {
nid_t speaker; /* fixed (internal) speaker */
nid_t spkr_dac;
nid_t input_mixer;
+ nid_t fhp_dac;
+ int nout_jacks; /* number of default output jacks */
int spkr_muters;
int spkr_mute_method;