diff options
Diffstat (limited to 'sys/dev/pci/azalia.c')
-rw-r--r-- | sys/dev/pci/azalia.c | 166 |
1 files changed, 101 insertions, 65 deletions
diff --git a/sys/dev/pci/azalia.c b/sys/dev/pci/azalia.c index 6e41212dd58..ea394c3c57c 100644 --- a/sys/dev/pci/azalia.c +++ b/sys/dev/pci/azalia.c @@ -1,4 +1,4 @@ -/* $OpenBSD: azalia.c,v 1.76 2008/11/28 21:33:26 jakemsr Exp $ */ +/* $OpenBSD: azalia.c,v 1.77 2008/11/30 03:50:29 jakemsr Exp $ */ /* $NetBSD: azalia.c,v 1.20 2006/05/07 08:31:44 kent Exp $ */ /*- @@ -1306,9 +1306,6 @@ azalia_codec_init(codec_t *this) } #endif - /* 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; @@ -1345,47 +1342,60 @@ azalia_codec_construct_format(codec_t *this, int newdac, int newadc) int nbits, c, chan, i, err; nid_t nid; - 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) - nbits++; - if (bits_rates & COP_PCM_B16) - nbits++; - if (bits_rates & COP_PCM_B20) - nbits++; - if (bits_rates & COP_PCM_B24) - nbits++; - if (bits_rates & COP_PCM_B32) - nbits++; - if (nbits == 0) { - printf("%s: invalid DAC PCM format: 0x%8.8x\n", - XNAME(this->az), bits_rates); - return -1; + variation = 0; + + if (this->dacs.ngroups > 0 && newdac < this->dacs.ngroups && + newdac >= 0) { + 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) + nbits++; + if (bits_rates & COP_PCM_B16) + nbits++; + if (bits_rates & COP_PCM_B20) + nbits++; + if (bits_rates & COP_PCM_B24) + nbits++; + if (bits_rates & COP_PCM_B32) + nbits++; + if (nbits == 0) { + printf("%s: invalid DAC PCM format: 0x%8.8x\n", + XNAME(this->az), bits_rates); + return -1; + } + variation += group->nconv * nbits; } - variation = group->nconv * nbits; - 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++; - if (bits_rates & COP_PCM_B16) - nbits++; - if (bits_rates & COP_PCM_B20) - nbits++; - if (bits_rates & COP_PCM_B24) - nbits++; - if (bits_rates & COP_PCM_B32) - nbits++; - if (nbits == 0) { - printf("%s: invalid ADC PCM format: 0x%8.8x\n", - XNAME(this->az), bits_rates); + if (this->adcs.ngroups > 0 && newadc < this->adcs.ngroups && + newadc >= 0) { + 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++; + if (bits_rates & COP_PCM_B16) + nbits++; + if (bits_rates & COP_PCM_B20) + nbits++; + if (bits_rates & COP_PCM_B24) + nbits++; + if (bits_rates & COP_PCM_B32) + nbits++; + if (nbits == 0) { + printf("%s: invalid ADC PCM format: 0x%8.8x\n", + XNAME(this->az), bits_rates); + return -1; + } + variation += group->nconv * nbits; + } + + if (variation == 0) { + DPRINTF(("%s: no converter groups\n", XNAME(this->az))); return -1; } - variation += group->nconv * nbits; if (this->formats != NULL) free(this->formats, M_DEVBUF); @@ -1399,29 +1409,35 @@ azalia_codec_construct_format(codec_t *this, int newdac, int newadc) } /* register formats for playback */ - group = &this->dacs.groups[this->dacs.cur]; - for (c = 0; c < group->nconv; c++) { - chan = 0; - bits_rates = ~0; - for (i = 0; i <= c; i++) { - nid = group->conv[i]; - chan += WIDGET_CHANNELS(&this->w[nid]); - bits_rates &= this->w[nid].d.audio.bits_rates; + if (this->dacs.ngroups > 0) { + group = &this->dacs.groups[this->dacs.cur]; + for (c = 0; c < group->nconv; c++) { + chan = 0; + bits_rates = ~0; + for (i = 0; i <= c; i++) { + nid = group->conv[i]; + chan += WIDGET_CHANNELS(&this->w[nid]); + bits_rates &= this->w[nid].d.audio.bits_rates; + } + azalia_codec_add_bits(this, chan, bits_rates, + AUMODE_PLAY); } - azalia_codec_add_bits(this, chan, bits_rates, AUMODE_PLAY); } /* register formats for recording */ - group = &this->adcs.groups[this->adcs.cur]; - for (c = 0; c < group->nconv; c++) { - chan = 0; - bits_rates = ~0; - for (i = 0; i <= c; i++) { - nid = group->conv[i]; - chan += WIDGET_CHANNELS(&this->w[nid]); - bits_rates &= this->w[nid].d.audio.bits_rates; + if (this->adcs.ngroups > 0) { + group = &this->adcs.groups[this->adcs.cur]; + for (c = 0; c < group->nconv; c++) { + chan = 0; + bits_rates = ~0; + for (i = 0; i <= c; i++) { + nid = group->conv[i]; + 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); } - azalia_codec_add_bits(this, chan, bits_rates, AUMODE_RECORD); } err = azalia_create_encodings(this); @@ -2312,6 +2328,12 @@ azalia_set_params_sub(codec_t *codec, int mode, audio_params_t *par) oenc = par->encoding; opre = par->precision; + if ((mode == AUMODE_PLAY && codec->dacs.ngroups == 0) || + (mode == AUMODE_RECORD && codec->adcs.ngroups == 0)) { + azalia_get_default_params(NULL, mode, par); + return 0; + } + i = azalia_match_format(codec, mode, par); if (i == codec->nformats && par->channels == 1) { /* find a 2 channel format and emulate mono */ @@ -2585,12 +2607,19 @@ azalia_trigger_output(void *v, void *start, void *end, int blk, int err; uint16_t fmt; + az = v; + + if (az->codecs[az->codecno].dacs.ngroups == 0) { + DPRINTF(("%s: can't play without a DAC\n", __func__)); + return ENXIO; + } + err = azalia_params2fmt(param, &fmt); if (err) return EINVAL; - az = v; - return azalia_stream_start(&az->pstream, start, end, blk, intr, arg, fmt); + return azalia_stream_start(&az->pstream, start, end, blk, intr, + arg, fmt); } int @@ -2601,16 +2630,23 @@ azalia_trigger_input(void *v, void *start, void *end, int blk, int err; uint16_t fmt; - DPRINTFN(1, ("%s: this=%p start=%p end=%p blk=%d {enc=%u %uch %u/%ubit %uHz}\n", + DPRINTFN(1, ("%s: this=%p start=%p end=%p blk=%d {enc=%u %uch %ubit %uHz}\n", __func__, v, start, end, blk, param->encoding, param->channels, - param->precision, param->precision, param->sample_rate)); + param->precision, param->sample_rate)); + + az = v; + + if (az->codecs[az->codecno].adcs.ngroups == 0) { + DPRINTF(("%s: can't record without an ADC\n", __func__)); + return ENXIO; + } err = azalia_params2fmt(param, &fmt); if (err) return EINVAL; - az = v; - return azalia_stream_start(&az->rstream, start, end, blk, intr, arg, fmt); + return azalia_stream_start(&az->rstream, start, end, blk, intr, + arg, fmt); } /* -------------------------------- |