diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index f46c4b63f778..ddbf6625aca8 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -41,9 +41,10 @@ struct snddev_channel { struct snddev_info { SLIST_HEAD(, snddev_channel) channels; struct pcm_channel *fakechan; - unsigned devcount, reccount, chancount, vchancount; + unsigned devcount, playcount, reccount, vchancount; unsigned flags; int inprog; + unsigned int bufsz; void *devinfo; device_t dev; char status[SND_STATUSLEN]; @@ -339,19 +340,25 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c { struct pcm_channel *ch; char *dirs; - int err; + int err, *pnum; switch(dir) { case PCMDIR_PLAY: dirs = "play"; + pnum = &d->playcount; break; + case PCMDIR_REC: dirs = "record"; + pnum = &d->reccount; break; + case PCMDIR_VIRTUAL: dirs = "virtual"; dir = PCMDIR_PLAY; + pnum = &d->vchancount; break; + default: return NULL; } @@ -363,19 +370,24 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK); if (!ch->methods) { free(ch, M_DEVBUF); + return NULL; } + ch->num = (*pnum)++; + ch->pid = -1; ch->parentsnddev = d; ch->parentchannel = parent; - snprintf(ch->name, 32, "%s:%d:%s", device_get_nameunit(d->dev), d->chancount, dirs); + snprintf(ch->name, 32, "%s:%s:%d", device_get_nameunit(d->dev), dirs, ch->num); err = chn_init(ch, devinfo, dir); if (err) { - device_printf(d->dev, "chn_init() for channel %d (%s) failed: err = %d\n", d->chancount, dirs, 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); + (*pnum)--; + return NULL; } @@ -385,14 +397,23 @@ pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t c int pcm_chn_destroy(struct pcm_channel *ch) { + struct snddev_info *d; int err; + d = ch->parentsnddev; err = chn_kill(ch); if (err) { - device_printf(ch->parentsnddev->dev, "chn_kill() for %s failed, err = %d\n", ch->name, err); + device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err); return err; } + if (ch->direction == PCMDIR_REC) + d->reccount--; + else if (ch->flags & CHN_F_VIRTUAL) + d->vchancount--; + else + d->playcount--; + kobj_delete(ch->methods, M_DEVBUF); free(ch, M_DEVBUF); @@ -424,21 +445,11 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev) SLIST_INSERT_AFTER(after, sce, link); } - if (ch->direction == PCMDIR_REC) - ch->num = d->reccount++; -/* - else - ch->num = d->playcount++; -*/ - if (mkdev) { dsp_register(unit, d->devcount++); if (ch->direction == PCMDIR_REC) dsp_registerrec(unit, ch->num); } - d->chancount++; - if (ch->flags & CHN_F_VIRTUAL) - d->vchancount++; snd_mtxunlock(d->lock); @@ -459,16 +470,13 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev) snd_mtxunlock(d->lock); return EINVAL; gotit: - if (ch->flags & CHN_F_VIRTUAL) - d->vchancount--; - d->chancount--; SLIST_REMOVE(&d->channels, sce, snddev_channel, link); free(sce, M_DEVBUF); if (rmdev) { dsp_unregister(unit, --d->devcount); if (ch->direction == PCMDIR_REC) - dsp_unregisterrec(unit, --d->reccount); + dsp_unregisterrec(unit, ch->num); } snd_mtxunlock(d->lock); @@ -555,6 +563,22 @@ pcm_getdevinfo(device_t dev) return d->devinfo; } +unsigned int +pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max) +{ + struct snddev_info *d = device_get_softc(dev); + int sz; + + sz = 0; + if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) + RANGE(sz, min, max); + else + sz = deflt; + d->bufsz = sz; + + return sz; +} + int pcm_register(device_t dev, void *devinfo, int numplay, int numrec) { @@ -568,7 +592,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) d->devinfo = devinfo; d->devcount = 0; d->reccount = 0; - d->chancount = 0; + d->playcount = 0; d->vchancount = 0; d->inprog = 0; @@ -587,6 +611,8 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) sysctl_ctx_free(&d->sysctl_tree); goto no; } + SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), + OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, ""); #endif if (numplay > 0) vchan_initsys(dev); @@ -606,6 +632,7 @@ pcm_unregister(device_t dev) { struct snddev_info *d = device_get_softc(dev); struct snddev_channel *sce; + struct pcm_channel *ch; snd_mtxlock(d->lock); if (d->inprog) { @@ -619,8 +646,9 @@ pcm_unregister(device_t dev) return EBUSY; } SLIST_FOREACH(sce, &d->channels, link) { - if (sce->channel->refcount > 0) { - device_printf(dev, "unregister: channel busy\n"); + ch = sce->channel; + if (ch->refcount > 0) { + device_printf(dev, "unregister: channel %s busy (pid %d)", ch->name, ch->pid); snd_mtxunlock(d->lock); return EBUSY; } @@ -677,7 +705,7 @@ sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) } else rc++; } - sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", pc, rc, vc, + sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount, (d->flags & SD_F_SIMPLEX)? "" : " duplex", #ifdef USING_DEVFS (device_get_unit(dev) == snd_unit)? " default" : "" diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index c19a5bbc6e4f..5c22ad376fd3 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -232,6 +232,7 @@ int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev); int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev); int pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo); +unsigned int pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max); int pcm_register(device_t dev, void *devinfo, int numplay, int numrec); int pcm_unregister(device_t dev); int pcm_setstatus(device_t dev, char *str);