summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjakemsr <jakemsr@openbsd.org>2008-11-30 03:50:29 +0000
committerjakemsr <jakemsr@openbsd.org>2008-11-30 03:50:29 +0000
commit859f172e049ac14d6ca36ff71e1978c500e7395c (patch)
tree66b7ada2cccedafb8bb90f5e744498d68dc148c2
parentmake 'MAKEDEV all' create device nodes for 3 separate audio devices (diff)
downloadwireguard-openbsd-859f172e049ac14d6ca36ff71e1978c500e7395c.tar.xz
wireguard-openbsd-859f172e049ac14d6ca36ff71e1978c500e7395c.zip
- don't access nonexistent converter goups
- don't try to create formats for converter groups that don't exist - don't allow playback or recording if there is no corresponding converter group - don't try to set audio processing parameters on converter groups that don't exist allows playback (or record) only devices to work, such as the azalias found on ATI graphics devices. note, the ATI devices generally attach before the onboard devices do. that means they will be audio0 and onboard devices will be audio1. don't forget to make sure the /dev/{audio[ctl],mixer,sound} links point to the nodes of the device you want to be the default. tested by naddy@, thanks
-rw-r--r--sys/dev/pci/azalia.c166
-rw-r--r--sys/dev/pci/azalia_codec.c27
2 files changed, 119 insertions, 74 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);
}
/* --------------------------------
diff --git a/sys/dev/pci/azalia_codec.c b/sys/dev/pci/azalia_codec.c
index 0ed4acd20a5..3de3d109700 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.75 2008/11/28 21:50:05 jakemsr Exp $ */
+/* $OpenBSD: azalia_codec.c,v 1.76 2008/11/30 03:50:29 jakemsr Exp $ */
/* $NetBSD: azalia_codec.c,v 1.8 2006/05/10 11:17:27 kent Exp $ */
/*-
@@ -333,15 +333,18 @@ azalia_generic_codec_add_convgroup(codec_t *this, convgroupset_t *group,
digital ? "digital" : "analog",
(type == COP_AWTYPE_AUDIO_OUTPUT) ? "DACs" : "ADCs"));
+ nconvs = 0;
nall_convs = 0;
+
FOR_EACH_WIDGET(this, i) {
if (this->w[i].type == type &&
(this->w[i].widgetcap & COP_AWCAP_DIGITAL) == digital &&
nall_convs < HDA_MAX_CHANNELS)
all_convs[nall_convs++] = this->w[i].nid;
}
+ if (nall_convs == 0)
+ goto done;
- nconvs = 0;
for (assoc = 0; assoc <= CORB_CD_ASSOCIATION_MAX; assoc++) {
for (seq = 0; seq <= CORB_CD_SEQUENCE_MAX; seq++) {
FOR_EACH_WIDGET(this, i) {
@@ -523,17 +526,18 @@ azalia_generic_mixer_init(codec_t *this)
continue;
/* usable adcs - connections should be in AZ_CLASS_RECORD */
- if (w->type == COP_AWTYPE_AUDIO_INPUT) {
+ if (w->type == COP_AWTYPE_AUDIO_INPUT &&
+ this->adcs.ngroups > 0) {
const convgroupset_t *group;
group = &this->adcs;
+ k = 0;
for (j = 0; j < group->groups[group->cur].nconv; j++)
if (group->groups[group->cur].conv[j] == w->nid)
break;
- if (j == group->groups[group->cur].nconv)
- continue;
-
- for (j = 0; j < w->nconnections && naconns < 32; j++) {
+ if (j < group->groups[group->cur].nconv)
+ k = w->nconnections;
+ for (j = 0; j < k && naconns < 32; j++) {
k = azalia_nid_to_index(this,
w->connections[j]);
if (k == -1)
@@ -1038,10 +1042,15 @@ azalia_generic_mixer_create_virtual(codec_t *this, int pdac, int padc)
{
mixer_item_t *m;
mixer_devinfo_t *d;
- convgroup_t *cgdac = &this->dacs.groups[0];
- convgroup_t *cgadc = &this->adcs.groups[0];
+ convgroup_t *cgdac;
+ convgroup_t *cgadc;
int i, err, madc, mmaster;
+ if (this->dacs.ngroups > 0)
+ cgdac = &this->dacs.groups[0];
+ if (this->adcs.ngroups > 0)
+ cgadc = &this->adcs.groups[0];
+
/* Clear mixer indexes, to make generic_mixer_fix_index happy */
for (i = 0; i < this->nmixers; i++) {
d = &this->mixers[i].devinfo;