summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorBrad Smith <brad@cvs.openbsd.org>2006-05-08 04:11:32 +0000
committerBrad Smith <brad@cvs.openbsd.org>2006-05-08 04:11:32 +0000
commitbd4d8b906fbec0d1cc4ce459a21b1f9ccf21557b (patch)
tree4ae72041797fe689be3dedac2dd02e06ffc776b1 /sys
parentb30b2046edf6b7efa6e243944c8fb3706d01ec73 (diff)
Don't crash when a connection list has invalid NIDs.
From NetBSD
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/pci/azalia.c68
-rw-r--r--sys/dev/pci/azalia.h6
2 files changed, 53 insertions, 21 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c
index bd694b061a7..77c6c5866b0 100644
--- a/sys/dev/pci/azalia.c
+++ b/sys/dev/pci/azalia.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.c,v 1.4 2006/05/08 03:59:09 brad Exp $ */
+/* $OpenBSD: azalia.c,v 1.5 2006/05/08 04:11:31 brad Exp $ */
/* $NetBSD: azalia.c,v 1.15 2005/09/29 04:14:03 kent Exp $ */
/*-
@@ -1072,6 +1072,10 @@ azalia_codec_init(codec_t *this)
COP_AMPCAP_NUMSTEPS(result), COP_AMPCAP_OFFSET(result)));
#endif
+ strlcpy(this->w[CORB_NID_ROOT].name, "root",
+ sizeof(this->w[CORB_NID_ROOT].name));
+ strlcpy(this->w[this->audiofunc].name, "hdaudio",
+ sizeof(this->w[this->audiofunc].name));
FOR_EACH_WIDGET(this, i) {
err = azalia_widget_init(&this->w[i], this, i);
if (err)
@@ -1377,7 +1381,7 @@ azalia_mixer_init(codec_t *this)
*/
mixer_item_t *m;
int nadcs;
- int err, i, j;
+ int err, i, j, k;
nadcs = 0;
this->maxmixers = 10;
@@ -1441,7 +1445,6 @@ azalia_mixer_init(codec_t *this)
FOR_EACH_WIDGET(this, i) {
const widget_t *w;
- DPRINTF(("%s: process w[%d]\n", __func__, i));
w = &this->w[i];
if (w->type == COP_AWTYPE_AUDIO_INPUT)
@@ -1463,15 +1466,18 @@ azalia_mixer_init(codec_t *this)
d->next = AUDIO_MIXER_LAST;
d->prev = AUDIO_MIXER_LAST;
m->target = MI_TARGET_CONNLIST;
- for (j = 0; j < w->nconnections && j < 32; j++) {
- d->un.e.member[j].ord = j;
+ for (j = 0, k = 0; j < w->nconnections && k < 32; j++) {
+ if (!VALID_WIDGET_NID(w->connections[j], this))
+ continue;
+ d->un.e.member[k].ord = k;
DPRINTF(("%s: selector %d=%s\n", __func__, j,
this->w[w->connections[j]].name));
- strlcpy(d->un.e.member[j].label.name,
+ strlcpy(d->un.e.member[k].label.name,
this->w[w->connections[j]].name,
MAX_AUDIO_DEV_LEN);
+ k++;
}
- d->un.e.num_mem = j;
+ d->un.e.num_mem = k;
this->nmixers++;
}
@@ -1542,6 +1548,8 @@ azalia_mixer_init(codec_t *this)
DPRINTF(("%s: input mute %s\n", __func__, w->name));
for (j = 0; j < w->nconnections; j++) {
MIXER_REG_PROLOG;
+ if (!VALID_WIDGET_NID(w->connections[j], this))
+ continue;
DPRINTF(("%s: input mute %s.%s\n", __func__,
w->name, this->w[w->connections[j]].name));
snprintf(d->label.name, sizeof(d->label.name),
@@ -1574,6 +1582,8 @@ azalia_mixer_init(codec_t *this)
DPRINTF(("%s: input gain %s\n", __func__, w->name));
for (j = 0; j < w->nconnections; j++) {
MIXER_REG_PROLOG;
+ if (!VALID_WIDGET_NID(w->connections[j], this))
+ continue;
DPRINTF(("%s: input gain %s.%s\n", __func__,
w->name, this->w[w->connections[j]].name));
snprintf(d->label.name, sizeof(d->label.name),
@@ -1870,11 +1880,18 @@ azalia_mixer_get(const codec_t *this, mixer_ctrl_t *mc)
/* selection */
else if (m->target == MI_TARGET_CONNLIST) {
+ int i;
err = this->comresp(this, m->nid,
CORB_GET_CONNECTION_SELECT_CONTROL, 0, &result);
if (err)
return err;
- mc->un.ord = CORB_CSC_INDEX(result);
+ result = CORB_CSC_INDEX(result);
+ mc->un.ord = -1;
+ for (i = 0; i <= result; i++) {
+ if (!VALID_WIDGET_NID(this->w[m->nid].connections[i], this))
+ continue;
+ mc->un.ord++;
+ }
}
/* pin I/O */
@@ -2093,10 +2110,18 @@ azalia_mixer_set(codec_t *this, const mixer_ctrl_t *mc)
/* selection */
else if (m->target == MI_TARGET_CONNLIST) {
- if (mc->un.ord >= this->w[m->nid].nconnections)
+ int i;
+ for (i = 0, value = 0; i < this->w[m->nid].nconnections; i++) {
+ if (!VALID_WIDGET_NID(this->w[m->nid].connections[i], this))
+ continue;
+ if (value == mc->un.ord)
+ break;
+ value++;
+ }
+ if (i >= this->w[m->nid].nconnections)
return EINVAL;
err = this->comresp(this, m->nid,
- CORB_SET_CONNECTION_SELECT_CONTROL, mc->un.ord, &result);
+ CORB_SET_CONNECTION_SELECT_CONTROL, i, &result);
if (err)
return err;
}
@@ -2501,31 +2526,35 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec)
length = COP_CLL_LENGTH(result);
if (length == 0)
return 0;
+ DPRINTF(("%s: CLE=0x%x\n", __func__, result));
this->nconnections = length;
- this->connections = malloc(sizeof(nid_t) * length, M_DEVBUF, M_NOWAIT);
+ this->connections = malloc(sizeof(nid_t) * (length + 3),
+ M_DEVBUF, M_NOWAIT);
if (this->connections == NULL) {
printf("%s: out of memory\n", XNAME(codec->az));
return ENOMEM;
}
if (longform) {
- for (i = 0; i < length; i += 2) {
+ for (i = 0; i < length;) {
err = codec->comresp(codec, this->nid,
CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
if (err)
return err;
- this->connections[i] = CORB_CLE_LONG_0(result);
- this->connections[i+1] = CORB_CLE_LONG_1(result);
+ DPRINTF(("%s: long[%d]=0x%x\n", __func__, i, result));
+ this->connections[i++] = CORB_CLE_LONG_0(result);
+ this->connections[i++] = CORB_CLE_LONG_1(result);
}
} else {
- for (i = 0; i < length; i += 4) {
+ for (i = 0; i < length;) {
err = codec->comresp(codec, this->nid,
CORB_GET_CONNECTION_LIST_ENTRY, i, &result);
if (err)
return err;
- this->connections[i] = CORB_CLE_SHORT_0(result);
- this->connections[i+1] = CORB_CLE_SHORT_1(result);
- this->connections[i+2] = CORB_CLE_SHORT_2(result);
- this->connections[i+3] = CORB_CLE_SHORT_3(result);
+ DPRINTF(("%s: short[%d]=0x%x\n", __func__, i, result));
+ this->connections[i++] = CORB_CLE_SHORT_0(result);
+ this->connections[i++] = CORB_CLE_SHORT_1(result);
+ this->connections[i++] = CORB_CLE_SHORT_2(result);
+ this->connections[i++] = CORB_CLE_SHORT_3(result);
}
}
if (length > 0) {
@@ -2540,7 +2569,6 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec)
return err;
this->selected = CORB_CSC_INDEX(result);
DPRINTF(("; selected=0x%x\n", this->connections[result]));
-
}
return 0;
}
diff --git a/sys/dev/pci/azalia.h b/sys/dev/pci/azalia.h
index 9051a67c46b..e5344c42980 100644
--- a/sys/dev/pci/azalia.h
+++ b/sys/dev/pci/azalia.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: azalia.h,v 1.3 2006/05/08 03:53:57 brad Exp $ */
+/* $OpenBSD: azalia.h,v 1.4 2006/05/08 04:11:31 brad Exp $ */
/* $NetBSD: azalia.h,v 1.3 2005/09/29 04:14:03 kent Exp $ */
/*-
@@ -508,6 +508,10 @@ typedef struct {
#define MI_TARGET_VOLUME 0x106
} mixer_item_t;
+#define VALID_WIDGET_NID(nid, codec) (nid == (codec)->audiofunc || \
+ (nid >= (codec)->wstart && \
+ nid < (codec)->wend))
+
typedef struct {
int nconv;
nid_t conv[HDA_MAX_CHANNELS];