diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -2040,6 +2040,32 @@ return (NULL); } +static void +dsp_oss_audioinfo_unavail(oss_audioinfo *ai, int unit) +{ + bzero((void *)ai, sizeof(oss_audioinfo)); + ai->dev = unit; + snprintf(ai->name, sizeof(ai->name), "pcm%d (unavailable)", unit); + ai->busy = 0; + ai->pid = -1; + ai->caps = 0; + ai->iformats = 0; + ai->oformats = 0; + ai->cmd[0] = '\0'; + ai->card_number = unit; + ai->port_number = unit; + ai->mixer_dev = -1; + ai->legacy_device = unit; + ai->devnode[0] = '\0'; + ai->enabled = 0; + ai->min_rate = 0; + ai->max_rate = 0; + ai->min_channels = 0; + ai->max_channels = 0; + ai->next_play_engine = 0; + ai->next_rec_engine = 0; +} + /** * @brief Handler for SNDCTL_AUDIOINFO. * @@ -2084,8 +2110,14 @@ unit < devclass_get_maxunit(pcm_devclass); unit++) { d = devclass_get_softc(pcm_devclass, unit); if (!PCM_REGISTERED(d)) { - d = NULL; - continue; + if ((ai->dev == -1 && unit == snd_unit) || + ai->dev == unit) { + dsp_oss_audioinfo_unavail(ai, unit); + return (0); + } else { + d = NULL; + continue; + } } PCM_UNLOCKASSERT(d); diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -1393,6 +1393,21 @@ SYSINIT(mixer_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysinit, NULL); SYSUNINIT(mixer_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, mixer_sysuninit, NULL); +static void +mixer_oss_mixerinfo_unavail(oss_mixerinfo *mi, int unit) +{ + bzero((void *)mi, sizeof(*mi)); + mi->dev = unit; + snprintf(mi->id, sizeof(mi->id), "mixer%d (n/a)", unit); + snprintf(mi->name, sizeof(mi->name), "pcm%d:mixer (unavailable)", unit); + mi->modify_counter = 0; + mi->card_number = unit; + mi->port_number = 0; + mi->enabled = 0; + mi->devnode[0] = '\0'; + mi->legacy_device = unit; +} + /** * @brief Handler for SNDCTL_MIXERINFO * @@ -1436,8 +1451,13 @@ for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); - if (!PCM_REGISTERED(d) || PCM_DETACHING(d)) - continue; + if (!PCM_REGISTERED(d) || PCM_DETACHING(d)) { + if ((mi->dev == -1 && i == snd_unit) || mi->dev == i) { + mixer_oss_mixerinfo_unavail(mi, i); + return (0); + } else + continue; + } /* XXX Need Giant magic entry */ @@ -1445,89 +1465,96 @@ PCM_UNLOCKASSERT(d); PCM_LOCK(d); - if (d->mixer_dev != NULL && d->mixer_dev->si_drv1 != NULL && - ((mi->dev == -1 && d->mixer_dev == i_dev) || + if (!((d->mixer_dev == i_dev && mi->dev == -1) || mi->dev == i)) { - m = d->mixer_dev->si_drv1; - mtx_lock(m->lock); - - /* - * At this point, the following synchronization stuff - * has happened: - * - a specific PCM device is locked. - * - a specific mixer device has been locked, so be - * sure to unlock when existing. - */ - bzero((void *)mi, sizeof(*mi)); - mi->dev = i; - snprintf(mi->id, sizeof(mi->id), "mixer%d", i); - strlcpy(mi->name, m->name, sizeof(mi->name)); - mi->modify_counter = m->modify_counter; - mi->card_number = i; - /* - * Currently, FreeBSD assumes 1:1 relationship between - * a pcm and mixer devices, so this is hardcoded to 0. - */ - mi->port_number = 0; - - /** - * @todo Fill in @sa oss_mixerinfo::mixerhandle. - * @note From 4Front: "mixerhandle is an arbitrary - * string that identifies the mixer better than - * the device number (mixerinfo.dev). Device - * numbers may change depending on the order the - * drivers are loaded. However the handle should - * remain the same provided that the sound card - * is not moved to another PCI slot." - */ - - /** - * @note - * @sa oss_mixerinfo::magic is a reserved field. - * - * @par - * From 4Front: "magic is usually 0. However some - * devices may have dedicated setup utilities and the - * magic field may contain an unique driver specific - * value (managed by [4Front])." - */ - - mi->enabled = device_is_attached(m->dev) ? 1 : 0; - /** - * The only flag for @sa oss_mixerinfo::caps is - * currently MIXER_CAP_VIRTUAL, which I'm not sure we - * really worry about. - */ - /** - * Mixer extensions currently aren't supported, so - * leave @sa oss_mixerinfo::nrext blank for now. - */ - - /** - * @todo Fill in @sa oss_mixerinfo::priority (requires - * touching drivers?) - * @note The priority field is for mixer applets to - * determine which mixer should be the default, with 0 - * being least preferred and 10 being most preferred. - * From 4Front: "OSS drivers like ICH use higher - * values (10) because such chips are known to be used - * only on motherboards. Drivers for high end pro - * devices use 0 because they will never be the - * default mixer. Other devices use values 1 to 9 - * depending on the estimated probability of being the - * default device. - */ - - snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i); - mi->legacy_device = i; + PCM_UNLOCK(d); + continue; + } - mtx_unlock(m->lock); + if (d->mixer_dev->si_drv1 == NULL) { + mixer_oss_mixerinfo_unavail(mi, i); + PCM_UNLOCK(d); + return (0); } + m = d->mixer_dev->si_drv1; + mtx_lock(m->lock); + + /* + * At this point, the following synchronization stuff + * has happened: + * - a specific PCM device is locked. + * - a specific mixer device has been locked, so be + * sure to unlock when existing. + */ + bzero((void *)mi, sizeof(*mi)); + mi->dev = i; + snprintf(mi->id, sizeof(mi->id), "mixer%d", i); + strlcpy(mi->name, m->name, sizeof(mi->name)); + mi->modify_counter = m->modify_counter; + mi->card_number = i; + /* + * Currently, FreeBSD assumes 1:1 relationship between + * a pcm and mixer devices, so this is hardcoded to 0. + */ + mi->port_number = 0; + + /** + * @todo Fill in @sa oss_mixerinfo::mixerhandle. + * @note From 4Front: "mixerhandle is an arbitrary + * string that identifies the mixer better than + * the device number (mixerinfo.dev). Device + * numbers may change depending on the order the + * drivers are loaded. However the handle should + * remain the same provided that the sound card + * is not moved to another PCI slot." + */ + + /** + * @note + * @sa oss_mixerinfo::magic is a reserved field. + * + * @par + * From 4Front: "magic is usually 0. However some + * devices may have dedicated setup utilities and the + * magic field may contain an unique driver specific + * value (managed by [4Front])." + */ + + mi->enabled = device_is_attached(m->dev) ? 1 : 0; + /** + * The only flag for @sa oss_mixerinfo::caps is + * currently MIXER_CAP_VIRTUAL, which I'm not sure we + * really worry about. + */ + /** + * Mixer extensions currently aren't supported, so + * leave @sa oss_mixerinfo::nrext blank for now. + */ + + /** + * @todo Fill in @sa oss_mixerinfo::priority (requires + * touching drivers?) + * @note The priority field is for mixer applets to + * determine which mixer should be the default, with 0 + * being least preferred and 10 being most preferred. + * From 4Front: "OSS drivers like ICH use higher + * values (10) because such chips are known to be used + * only on motherboards. Drivers for high end pro + * devices use 0 because they will never be the + * default mixer. Other devices use values 1 to 9 + * depending on the estimated probability of being the + * default device. + */ + + snprintf(mi->devnode, sizeof(mi->devnode), "/dev/mixer%d", i); + mi->legacy_device = i; + + mtx_unlock(m->lock); + PCM_UNLOCK(d); - if (m != NULL) - return (0); + return (0); } return (EINVAL); diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -802,23 +802,29 @@ for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { d = devclass_get_softc(pcm_devclass, i); - if (!PCM_REGISTERED(d)) - continue; - if (i != si->card) continue; - PCM_UNLOCKASSERT(d); - PCM_LOCK(d); - - strlcpy(si->shortname, device_get_nameunit(d->dev), - sizeof(si->shortname)); - strlcpy(si->longname, device_get_desc(d->dev), - sizeof(si->longname)); - strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); - si->intr_count = si->ack_count = 0; - - PCM_UNLOCK(d); + if (!PCM_REGISTERED(d)) { + snprintf(si->shortname, sizeof(si->shortname), + "pcm%d (n/a)", i); + strlcpy(si->longname, "Device unavailable", + sizeof(si->longname)); + si->hw_info[0] = '\0'; + si->intr_count = si->ack_count = 0; + } else { + PCM_UNLOCKASSERT(d); + PCM_LOCK(d); + + strlcpy(si->shortname, device_get_nameunit(d->dev), + sizeof(si->shortname)); + strlcpy(si->longname, device_get_desc(d->dev), + sizeof(si->longname)); + strlcpy(si->hw_info, d->status, sizeof(si->hw_info)); + si->intr_count = si->ack_count = 0; + + PCM_UNLOCK(d); + } return (0); }