diff options
Diffstat (limited to 'sys/dev/sound/pcm/sound.c')
-rw-r--r-- | sys/dev/sound/pcm/sound.c | 336 |
1 files changed, 16 insertions, 320 deletions
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 9d5eaf3f5ad7..e66462af2a71 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -41,7 +41,6 @@ #include <dev/sound/pcm/ac97.h> #include <dev/sound/pcm/vchan.h> #include <dev/sound/pcm/dsp.h> -#include <dev/sound/version.h> #include <sys/limits.h> #include <sys/sysctl.h> @@ -57,22 +56,11 @@ static int snd_unit_auto = -1; SYSCTL_INT(_hw_snd, OID_AUTO, default_auto, CTLFLAG_RWTUN, &snd_unit_auto, 0, "assign default unit to a newly attached device"); -int snd_maxautovchans = 16; - SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Sound driver"); static void pcm_sysinit(device_t); -/* - * XXX I've had enough with people not telling proper version/arch - * while reporting problems, not after 387397913213th questions/requests. - */ -static char snd_driver_version[] = - __XSTRING(SND_DRV_VERSION)"/"MACHINE_ARCH; -SYSCTL_STRING(_hw_snd, OID_AUTO, version, CTLFLAG_RD, &snd_driver_version, - 0, "driver version/arch"); - /** * @brief Unit number allocator for syncgroup IDs */ @@ -121,126 +109,6 @@ snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep); } -int -pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num) -{ - struct pcm_channel *c, *ch, *nch; - struct pcmchan_caps *caps; - int i, err, vcnt; - - PCM_BUSYASSERT(d); - - if ((direction == PCMDIR_PLAY && d->playcount < 1) || - (direction == PCMDIR_REC && d->reccount < 1)) - return (ENODEV); - - if (!(d->flags & SD_F_AUTOVCHAN)) - return (EINVAL); - - if (newcnt < 0 || newcnt > SND_MAXVCHANS) - return (E2BIG); - - if (direction == PCMDIR_PLAY) - vcnt = d->pvchancount; - else if (direction == PCMDIR_REC) - vcnt = d->rvchancount; - else - return (EINVAL); - - if (newcnt > vcnt) { - KASSERT(num == -1 || - (num >= 0 && num < SND_MAXVCHANS && (newcnt - 1) == vcnt), - ("bogus vchan_create() request num=%d newcnt=%d vcnt=%d", - num, newcnt, vcnt)); - /* add new vchans - find a parent channel first */ - ch = NULL; - CHN_FOREACH(c, d, channels.pcm) { - CHN_LOCK(c); - if (c->direction == direction && - ((c->flags & CHN_F_HAS_VCHAN) || (vcnt == 0 && - c->refcount < 1 && - !(c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL))))) { - /* - * Reuse hw channel with vchans already - * created. - */ - if (c->flags & CHN_F_HAS_VCHAN) { - ch = c; - break; - } - /* - * No vchans ever created, look for - * channels with supported formats. - */ - caps = chn_getcaps(c); - if (caps == NULL) { - CHN_UNLOCK(c); - continue; - } - for (i = 0; caps->fmtlist[i] != 0; i++) { - if (caps->fmtlist[i] & AFMT_CONVERTIBLE) - break; - } - if (caps->fmtlist[i] != 0) { - ch = c; - break; - } - } - CHN_UNLOCK(c); - } - if (ch == NULL) - return (EBUSY); - ch->flags |= CHN_F_BUSY; - err = 0; - while (err == 0 && newcnt > vcnt) { - err = vchan_create(ch, num); - if (err == 0) - vcnt++; - else if (err == E2BIG && newcnt > vcnt) - device_printf(d->dev, - "%s: err=%d Maximum channel reached.\n", - __func__, err); - } - if (vcnt == 0) - ch->flags &= ~CHN_F_BUSY; - CHN_UNLOCK(ch); - if (err != 0) - return (err); - } else if (newcnt < vcnt) { - KASSERT(num == -1, - ("bogus vchan_destroy() request num=%d", num)); - CHN_FOREACH(c, d, channels.pcm) { - CHN_LOCK(c); - if (c->direction != direction || - CHN_EMPTY(c, children) || - !(c->flags & CHN_F_HAS_VCHAN)) { - CHN_UNLOCK(c); - continue; - } - CHN_FOREACH_SAFE(ch, c, nch, children) { - CHN_LOCK(ch); - if (vcnt == 1 && c->refcount > 0) { - CHN_UNLOCK(ch); - break; - } - if (!(ch->flags & CHN_F_BUSY) && - ch->refcount < 1) { - err = vchan_destroy(ch); - if (err == 0) - vcnt--; - } else - CHN_UNLOCK(ch); - if (vcnt == newcnt) - break; - } - CHN_UNLOCK(c); - break; - } - } - - return (0); -} - /* return error status and a locked channel */ int pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, @@ -297,7 +165,7 @@ vchan_alloc: /* no channel available */ if (!(vchancount > 0 && vchancount < snd_maxautovchans)) return (err); - err = pcm_setvchans(d, direction, vchancount + 1, -1); + err = vchan_setnew(d, direction, vchancount + 1); if (err == 0) { retry = true; goto retry_chnalloc; @@ -306,25 +174,6 @@ vchan_alloc: return (err); } -static void -pcm_setmaxautovchans(struct snddev_info *d, int num) -{ - PCM_BUSYASSERT(d); - - if (num < 0) - return; - - if (num >= 0 && d->pvchancount > num) - (void)pcm_setvchans(d, PCMDIR_PLAY, num, -1); - else if (num > 0 && d->pvchancount == 0) - (void)pcm_setvchans(d, PCMDIR_PLAY, 1, -1); - - if (num >= 0 && d->rvchancount > num) - (void)pcm_setvchans(d, PCMDIR_REC, num, -1); - else if (num > 0 && d->rvchancount == 0) - (void)pcm_setvchans(d, PCMDIR_REC, 1, -1); -} - static int sysctl_hw_snd_default_unit(SYSCTL_HANDLER_ARGS) { @@ -348,148 +197,7 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, default_unit, sizeof(int), sysctl_hw_snd_default_unit, "I", "default sound device"); -static int -sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) -{ - struct snddev_info *d; - int i, v, error; - - v = snd_maxautovchans; - error = sysctl_handle_int(oidp, &v, 0, req); - if (error == 0 && req->newptr != NULL) { - if (v < 0) - v = 0; - if (v > SND_MAXVCHANS) - v = SND_MAXVCHANS; - snd_maxautovchans = v; - 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; - PCM_ACQUIRE_QUICK(d); - pcm_setmaxautovchans(d, v); - PCM_RELEASE_QUICK(d); - } - } - return (error); -} -SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, - CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int), - sysctl_hw_snd_maxautovchans, "I", - "maximum virtual channel"); - -struct pcm_channel * -pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, int num, void *devinfo) -{ - struct pcm_channel *ch; - int direction, err, rpnum, *pnum, max; - int type, unit; - char *dirs, *devname, buf[CHN_NAMELEN]; - - PCM_BUSYASSERT(d); - PCM_LOCKASSERT(d); - KASSERT(num >= -1, ("invalid num=%d", num)); - - switch (dir) { - case PCMDIR_PLAY: - dirs = "play"; - direction = PCMDIR_PLAY; - pnum = &d->playcount; - type = SND_DEV_DSPHW_PLAY; - max = SND_MAXHWCHAN; - break; - case PCMDIR_PLAY_VIRTUAL: - dirs = "virtual_play"; - direction = PCMDIR_PLAY; - pnum = &d->pvchancount; - type = SND_DEV_DSPHW_VPLAY; - max = SND_MAXVCHANS; - break; - case PCMDIR_REC: - dirs = "record"; - direction = PCMDIR_REC; - pnum = &d->reccount; - type = SND_DEV_DSPHW_REC; - max = SND_MAXHWCHAN; - break; - case PCMDIR_REC_VIRTUAL: - dirs = "virtual_record"; - direction = PCMDIR_REC; - pnum = &d->rvchancount; - type = SND_DEV_DSPHW_VREC; - max = SND_MAXVCHANS; - break; - default: - return (NULL); - } - - unit = (num == -1) ? 0 : num; - - if (*pnum >= max || unit >= max) - return (NULL); - - rpnum = 0; - - CHN_FOREACH(ch, d, channels.pcm) { - if (ch->type != type) - continue; - if (unit == ch->unit && num != -1) { - device_printf(d->dev, - "channel num=%d allocated!\n", unit); - return (NULL); - } - unit++; - if (unit >= max) { - device_printf(d->dev, - "chan=%d > %d\n", unit, max); - return (NULL); - } - rpnum++; - } - - if (*pnum != rpnum) { - device_printf(d->dev, - "%s(): WARNING: pnum screwed : dirs=%s pnum=%d rpnum=%d\n", - __func__, dirs, *pnum, rpnum); - return (NULL); - } - - PCM_UNLOCK(d); - ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); - ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK | M_ZERO); - ch->type = type; - ch->unit = unit; - ch->pid = -1; - strlcpy(ch->comm, CHN_COMM_UNUSED, sizeof(ch->comm)); - ch->parentsnddev = d; - ch->parentchannel = parent; - ch->dev = d->dev; - ch->trigger = PCMTRIG_STOP; - devname = dsp_unit2name(buf, sizeof(buf), ch); - if (devname == NULL) { - device_printf(d->dev, "Failed to query device name"); - kobj_delete(ch->methods, M_DEVBUF); - free(ch, M_DEVBUF); - return (NULL); - } - snprintf(ch->name, sizeof(ch->name), "%s:%s:%s", - device_get_nameunit(ch->dev), dirs, devname); - - err = chn_init(ch, devinfo, dir, direction); - PCM_LOCK(d); - if (err) { - device_printf(d->dev, "chn_init(%s) failed: err = %d\n", - ch->name, err); - kobj_delete(ch->methods, M_DEVBUF); - free(ch, M_DEVBUF); - return (NULL); - } - - return (ch); -} - -int +void pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) { PCM_BUSYASSERT(d); @@ -513,10 +221,8 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) d->rvchancount++; break; default: - break; + __assert_unreachable(); } - - return (0); } int @@ -553,7 +259,7 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) d->rvchancount--; break; default: - break; + __assert_unreachable(); } return (0); @@ -564,28 +270,22 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) { struct snddev_info *d = device_get_softc(dev); struct pcm_channel *ch; - int err; PCM_BUSYASSERT(d); PCM_LOCK(d); - ch = pcm_chn_create(d, NULL, cls, dir, -1, devinfo); + ch = chn_init(d, NULL, cls, dir, devinfo); if (!ch) { - device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", + device_printf(d->dev, "chn_init(%s, %d, %p) failed\n", cls->name, dir, devinfo); PCM_UNLOCK(d); return (ENODEV); } - err = pcm_chn_add(d, ch); + pcm_chn_add(d, ch); PCM_UNLOCK(d); - if (err) { - device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", - ch->name, err); - chn_kill(ch); - } - return (err); + return (0); } static void @@ -677,7 +377,7 @@ pcm_setstatus(device_t dev, char *str) if (d->playcount > 0 || d->reccount > 0) d->flags |= SD_F_AUTOVCHAN; - pcm_setmaxautovchans(d, snd_maxautovchans); + vchan_setmaxauto(d, snd_maxautovchans); strlcpy(d->status, str, SND_STATUSLEN); @@ -1008,9 +708,8 @@ sound_oss_sysinfo(oss_sysinfo *si) struct snddev_info *d; struct pcm_channel *c; - int i, j, ncards; - - ncards = 0; + int j; + size_t i; strlcpy(si->product, si_product, sizeof(si->product)); strlcpy(si->version, si_version, sizeof(si->version)); @@ -1019,7 +718,7 @@ sound_oss_sysinfo(oss_sysinfo *si) /* * Iterate over PCM devices and their channels, gathering up data - * for the numaudios, ncards, and openedaudio fields. + * for the numaudios and openedaudio fields. */ si->numaudios = 0; bzero((void *)&si->openedaudio, sizeof(si->openedaudio)); @@ -1039,7 +738,6 @@ sound_oss_sysinfo(oss_sysinfo *si) PCM_LOCK(d); si->numaudios += PCM_CHANCOUNT(d); - ++ncards; CHN_FOREACH(c, d, channels.pcm) { CHN_UNLOCKASSERT(c); @@ -1070,7 +768,7 @@ sound_oss_sysinfo(oss_sysinfo *si) si->nummidis = 0; si->numtimers = 0; si->nummixers = mixer_count; - si->numcards = ncards; + si->numcards = devclass_get_maxunit(pcm_devclass); /* OSSv4 docs: Intended only for test apps; API doesn't really have much of a concept of cards. Shouldn't be used by applications. */ @@ -1086,7 +784,7 @@ sound_oss_sysinfo(oss_sysinfo *si) * Si->filler is a reserved array, but according to docs each * element should be set to -1. */ - for (i = 0; i < sizeof(si->filler)/sizeof(si->filler[0]); i++) + for (i = 0; i < nitems(si->filler); i++) si->filler[i] = -1; } @@ -1094,9 +792,7 @@ int sound_oss_card_info(oss_card_info *si) { struct snddev_info *d; - int i, ncards; - - ncards = 0; + int i; for (i = 0; pcm_devclass != NULL && i < devclass_get_maxunit(pcm_devclass); i++) { @@ -1104,7 +800,7 @@ sound_oss_card_info(oss_card_info *si) if (!PCM_REGISTERED(d)) continue; - if (ncards++ != si->card) + if (i != si->card) continue; PCM_UNLOCKASSERT(d); |