diff options
author | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2009-01-05 08:03:47 +0000 |
---|---|---|
committer | Jacob Meuser <jakemsr@cvs.openbsd.org> | 2009-01-05 08:03:47 +0000 |
commit | 945aa8749b920060b1fa63bc18e348f33afb0b57 (patch) | |
tree | 647c9e9aef8b2e0511a60074c9cab2e37909c462 /sys/dev/pci | |
parent | 66f4a68f9729a5bd45cd02552f7ffa7bacda1838 (diff) |
if the high bit is set in a connection list entry, it means the entry
is the end of a continuous list that started with the last entry.
while here, rewrite a bit so both long form and short form entries
are handled by the same code, and don't allocate more space than is
needed.
Diffstat (limited to 'sys/dev/pci')
-rw-r--r-- | sys/dev/pci/azalia.c | 52 |
1 files changed, 27 insertions, 25 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 2a1d667ba84..8deac922681 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.109 2009/01/04 23:42:39 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.110 2009/01/05 08:03:46 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -2308,8 +2308,8 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec) { uint32_t result; int err; - boolean_t longform; - int length, i; + int i, j, k; + int length, bits, conn, last; this->selected = -1; if ((this->widgetcap & COP_AWCAP_CONNLIST) == 0) @@ -2319,36 +2319,38 @@ azalia_widget_init_connection(widget_t *this, const codec_t *codec) COP_CONNECTION_LIST_LENGTH, &result); if (err) return err; - longform = (result & COP_CLL_LONG) != 0; + + bits = 8; + if (result & COP_CLL_LONG) + bits = 16; + length = COP_CLL_LENGTH(result); if (length == 0) return 0; + this->nconnections = length; - this->connections = malloc(sizeof(nid_t) * (length + 3), - M_DEVBUF, M_NOWAIT); + this->connections = malloc(sizeof(nid_t) * length, 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;) { - 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++] = CORB_CLE_LONG_1(result); - } - } else { - 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++] = CORB_CLE_SHORT_1(result); - this->connections[i++] = CORB_CLE_SHORT_2(result); - this->connections[i++] = CORB_CLE_SHORT_3(result); + for (i = 0; i < length;) { + err = codec->comresp(codec, this->nid, + CORB_GET_CONNECTION_LIST_ENTRY, i, &result); + if (err) + return err; + for (k = 0; i < length && (k < 32 / bits); k++) { + conn = (result >> (k * bits)) & ((1 << bits) - 1); + /* If high bit is set, this is the end of a continuous + * list that started with the last connection. + */ + if ((i > 0) && (conn & (1 << (bits - 1)))) { + last = this->connections[i - 1]; + for (j = 1; i < length && j <= conn - last; j++) + this->connections[i++] = last + j; + } else { + this->connections[i++] = conn; + } } } if (length > 0) { |