diff options
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r-- | sys/dev/sound/pcm/ac97.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/buffer.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/channel.c | 8 | ||||
-rw-r--r-- | sys/dev/sound/pcm/dsp.c | 112 | ||||
-rw-r--r-- | sys/dev/sound/pcm/fake.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder_fmt.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/feeder_rate.c | 4 | ||||
-rw-r--r-- | sys/dev/sound/pcm/mixer.c | 10 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sndstat.c | 279 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.c | 352 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.h | 66 | ||||
-rw-r--r-- | sys/dev/sound/pcm/vchan.c | 97 | ||||
-rw-r--r-- | sys/dev/sound/pcm/vchan.h | 2 |
14 files changed, 633 insertions, 317 deletions
diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c index 5e07fe2..bb29063 100644 --- a/sys/dev/sound/pcm/ac97.c +++ b/sys/dev/sound/pcm/ac97.c @@ -22,8 +22,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> @@ -31,6 +29,8 @@ #include "mixer_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + MALLOC_DEFINE(M_AC97, "ac97", "ac97 codec"); struct ac97mixtable_entry { diff --git a/sys/dev/sound/pcm/buffer.c b/sys/dev/sound/pcm/buffer.c index 3cdbf0a..e40c9fd 100644 --- a/sys/dev/sound/pcm/buffer.c +++ b/sys/dev/sound/pcm/buffer.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + #define MIN(x, y) (((x) < (y))? (x) : (y)) #define SNDBUF_NAMELEN 48 diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c index 9d9fa8f..6f4893a 100644 --- a/sys/dev/sound/pcm/channel.c +++ b/sys/dev/sound/pcm/channel.c @@ -23,14 +23,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + #define MIN_CHUNK_SIZE 256 /* for uiomove etc. */ #define DMA_ALIGN_THRESHOLD 4 #define DMA_ALIGN_MASK (~(DMA_ALIGN_THRESHOLD - 1)) @@ -276,7 +276,7 @@ chn_write(struct pcm_channel *c, struct uio *buf) if (count <= 0) { c->flags |= CHN_F_DEAD; - device_printf(c->parentsnddev->dev, "play interrupt timeout, channel dead\n"); + printf("play interrupt timeout, channel dead\n", c->name); } return ret; @@ -396,7 +396,7 @@ chn_read(struct pcm_channel *c, struct uio *buf) if (count <= 0) { c->flags |= CHN_F_DEAD; - device_printf(c->parentsnddev->dev, "record interrupt timeout, channel dead\n"); + printf("%s record interrupt timeout, channel dead\n", c->name); } return ret; diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c index 94b1274..d1ae32f 100644 --- a/sys/dev/sound/pcm/dsp.c +++ b/sys/dev/sound/pcm/dsp.c @@ -22,8 +22,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <sys/param.h> @@ -31,6 +29,8 @@ #include <dev/sound/pcm/sound.h> +SND_DECLARE_FILE("$FreeBSD$"); + #define OLDPCM_IOCTL static d_open_t dsp_open; @@ -75,6 +75,34 @@ dsp_get_info(dev_t dev) return d; } +static u_int32_t +dsp_get_flags(dev_t dev) +{ + device_t bdev; + int unit; + + unit = PCMUNIT(dev); + if (unit >= devclass_get_maxunit(pcm_devclass)) + return 0xffffffff; + bdev = devclass_get_device(pcm_devclass, unit); + + return pcm_getflags(bdev); +} + +static void +dsp_set_flags(dev_t dev, u_int32_t flags) +{ + device_t bdev; + int unit; + + unit = PCMUNIT(dev); + if (unit >= devclass_get_maxunit(pcm_devclass)) + return; + bdev = devclass_get_device(pcm_devclass, unit); + + pcm_setflags(bdev, flags); +} + /* * return the channels channels associated with an open device instance. * set the priority if the device is simplex and one direction (only) is @@ -85,37 +113,41 @@ static int getchns(dev_t dev, struct pcm_channel **rdch, struct pcm_channel **wrch, u_int32_t prio) { struct snddev_info *d; + u_int32_t flags; + flags = dsp_get_flags(dev); d = dsp_get_info(dev); - snd_mtxlock(d->lock); - d->inprog++; - KASSERT((d->flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ + pcm_lock(d); + pcm_inprog(d, 1); + KASSERT((flags & SD_F_PRIO_SET) != SD_F_PRIO_SET, \ ("getchns: read and write both prioritised")); - if ((d->flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) - d->flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR); + if ((flags & SD_F_PRIO_SET) == 0 && (prio != (SD_F_PRIO_RD | SD_F_PRIO_WR))) { + flags |= prio & (SD_F_PRIO_RD | SD_F_PRIO_WR); + dsp_set_flags(dev, flags); + } *rdch = dev->si_drv1; *wrch = dev->si_drv2; - if ((d->flags & SD_F_SIMPLEX) && (d->flags & SD_F_PRIO_SET)) { + if ((flags & SD_F_SIMPLEX) && (flags & SD_F_PRIO_SET)) { if (prio) { - if (*rdch && d->flags & SD_F_PRIO_WR) { + if (*rdch && flags & SD_F_PRIO_WR) { dev->si_drv1 = NULL; - *rdch = d->fakechan; - } else if (*wrch && d->flags & SD_F_PRIO_RD) { + *rdch = pcm_getfakechan(d); + } else if (*wrch && flags & SD_F_PRIO_RD) { dev->si_drv2 = NULL; - *wrch = d->fakechan; + *wrch = pcm_getfakechan(d); } } - d->fakechan->flags |= CHN_F_BUSY; + pcm_getfakechan(d)->flags |= CHN_F_BUSY; } + pcm_unlock(d); - if (*rdch && *rdch != d->fakechan && (prio & SD_F_PRIO_RD)) + if (*rdch && *rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) CHN_LOCK(*rdch); - if (*wrch && *wrch != d->fakechan && (prio & SD_F_PRIO_WR)) + if (*wrch && *wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) CHN_LOCK(*wrch); - snd_mtxunlock(d->lock); return 0; } @@ -127,13 +159,13 @@ relchns(dev_t dev, struct pcm_channel *rdch, struct pcm_channel *wrch, u_int32_t struct snddev_info *d; d = dsp_get_info(dev); - if (wrch && wrch != d->fakechan && (prio & SD_F_PRIO_WR)) + if (wrch && wrch != pcm_getfakechan(d) && (prio & SD_F_PRIO_WR)) CHN_UNLOCK(wrch); - if (rdch && rdch != d->fakechan && (prio & SD_F_PRIO_RD)) + if (rdch && rdch != pcm_getfakechan(d) && (prio & SD_F_PRIO_RD)) CHN_UNLOCK(rdch); - snd_mtxlock(d->lock); - d->inprog--; - snd_mtxunlock(d->lock); + pcm_lock(d); + pcm_inprog(d, -1); + pcm_unlock(d); } static int @@ -172,10 +204,10 @@ dsp_open(dev_t i_dev, int flags, int mode, struct proc *p) } /* lock snddev so nobody else can monkey with it */ - snd_mtxlock(d->lock); - if ((d->flags & SD_F_SIMPLEX) && (i_dev->si_drv1 || i_dev->si_drv2)) { + pcm_lock(d); + if ((dsp_get_flags(i_dev) & SD_F_SIMPLEX) && (i_dev->si_drv1 || i_dev->si_drv2)) { /* simplex device, already open, exit */ - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return EBUSY; } @@ -191,14 +223,14 @@ dsp_open(dev_t i_dev, int flags, int mode, struct proc *p) rdch = pcm_chnalloc(d, PCMDIR_REC, p->p_pid); if (!rdch) { /* no channel available, exit */ - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return EBUSY; } /* got a channel, already locked for us */ } else { /* already open for read, exit */ - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return EBUSY; } @@ -216,7 +248,7 @@ dsp_open(dev_t i_dev, int flags, int mode, struct proc *p) pcm_chnrelease(rdch); } /* exit */ - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return EBUSY; } @@ -228,7 +260,7 @@ dsp_open(dev_t i_dev, int flags, int mode, struct proc *p) pcm_chnrelease(rdch); } /* exit */ - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return EBUSY; } @@ -236,7 +268,7 @@ dsp_open(dev_t i_dev, int flags, int mode, struct proc *p) i_dev->si_drv1 = rdch; i_dev->si_drv2 = wrch; - snd_mtxunlock(d->lock); + pcm_unlock(d); /* finished with snddev, new channels still locked */ /* bump refcounts, reset and unlock any channels that we just opened */ @@ -276,7 +308,7 @@ dsp_close(dev_t i_dev, int flags, int mode, struct proc *p) s = spltty(); d = dsp_get_info(i_dev); - snd_mtxlock(d->lock); + pcm_lock(d); rdch = i_dev->si_drv1; wrch = i_dev->si_drv2; @@ -298,21 +330,21 @@ dsp_close(dev_t i_dev, int flags, int mode, struct proc *p) } } if (exit) { - snd_mtxunlock(d->lock); + pcm_unlock(d); splx(s); return 0; } /* both refcounts are zero, abort and release */ - if (d->fakechan) - d->fakechan->flags = 0; + if (pcm_getfakechan(d)) + pcm_getfakechan(d)->flags = 0; i_dev->si_drv1 = NULL; i_dev->si_drv2 = NULL; - d->flags &= ~SD_F_TRANSIENT; - snd_mtxunlock(d->lock); + dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT); + pcm_unlock(d); if (rdch) { chn_abort(rdch); /* won't sleep */ @@ -425,10 +457,6 @@ dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) if (kill & 2) rdch = NULL; - /* - * all routines are called with int. blocked. Make sure that - * ints are re-enabled when calling slow or blocking functions! - */ switch(cmd) { #ifdef OLDPCM_IOCTL /* @@ -527,8 +555,8 @@ dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) p->formats = (rdch? chn_getformats(rdch) : 0xffffffff) & (wrch? chn_getformats(wrch) : 0xffffffff); if (rdch && wrch) - p->formats |= (d->flags & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX; - pdev = makedev(SND_CDEV_MAJOR, PCMMKMINOR(device_get_unit(d->dev), SND_DEV_CTL, 0)); + p->formats |= (dsp_get_flags(i_dev) & SD_F_SIMPLEX)? 0 : AFMT_FULLDUPLEX; + pdev = makedev(SND_CDEV_MAJOR, PCMMKMINOR(PCMUNIT(i_dev), SND_DEV_CTL, 0)); p->mixers = 1; /* default: one mixer */ p->inputs = pdev->si_drv1? mix_getdevs(pdev->si_drv1) : 0; p->left = p->right = 100; @@ -842,7 +870,7 @@ dsp_ioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc *p) case SNDCTL_DSP_GETCAPS: *arg_i = DSP_CAP_REALTIME | DSP_CAP_MMAP | DSP_CAP_TRIGGER; - if (rdch && wrch && !(d->flags & SD_F_SIMPLEX)) + if (rdch && wrch && !(dsp_get_flags(i_dev) & SD_F_SIMPLEX)) *arg_i |= DSP_CAP_DUPLEX; break; diff --git a/sys/dev/sound/pcm/fake.c b/sys/dev/sound/pcm/fake.c index aeb47ef..8c4ba77 100644 --- a/sys/dev/sound/pcm/fake.c +++ b/sys/dev/sound/pcm/fake.c @@ -22,12 +22,12 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> +SND_DECLARE_FILE("$FreeBSD$"); + static u_int32_t fk_fmt[] = { AFMT_U8, AFMT_STEREO | AFMT_U8, diff --git a/sys/dev/sound/pcm/feeder.c b/sys/dev/sound/pcm/feeder.c index fabf239..102bab2 100644 --- a/sys/dev/sound/pcm/feeder.c +++ b/sys/dev/sound/pcm/feeder.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + MALLOC_DEFINE(M_FEEDER, "feeder", "pcm feeder"); #define MAXFEEDERS 256 diff --git a/sys/dev/sound/pcm/feeder_fmt.c b/sys/dev/sound/pcm/feeder_fmt.c index 735a5ac..6c8c92a 100644 --- a/sys/dev/sound/pcm/feeder_fmt.c +++ b/sys/dev/sound/pcm/feeder_fmt.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + MALLOC_DEFINE(M_FMTFEEDER, "fmtfeed", "pcm format feeder"); #define FEEDBUFSZ 8192 diff --git a/sys/dev/sound/pcm/feeder_rate.c b/sys/dev/sound/pcm/feeder_rate.c index 264f643..0cd8a6b 100644 --- a/sys/dev/sound/pcm/feeder_rate.c +++ b/sys/dev/sound/pcm/feeder_rate.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + MALLOC_DEFINE(M_RATEFEEDER, "ratefeed", "pcm rate feeder"); #define FEEDBUFSZ 8192 diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c index 1fe610f..ba8a473 100644 --- a/sys/dev/sound/pcm/mixer.c +++ b/sys/dev/sound/pcm/mixer.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include "mixer_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + MALLOC_DEFINE(M_MIXER, "mixer", "mixer"); #define MIXER_NAMELEN 16 @@ -320,11 +320,9 @@ sysctl_hw_snd_hwvol_mixer(SYSCTL_HANDLER_ARGS) int mixer_hwvol_init(device_t dev) { - struct snddev_info *d; struct snd_mixer *m; dev_t pdev; - d = device_get_softc(dev); pdev = mixer_get_devt(dev); m = pdev->si_drv1; snd_mtxlock(m->lock); @@ -332,9 +330,9 @@ mixer_hwvol_init(device_t dev) m->hwvol_mixer = SOUND_MIXER_VOLUME; m->hwvol_step = 5; #ifdef SND_DYNSYSCTL - SYSCTL_ADD_INT(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), + SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), OID_AUTO, "hwvol_step", CTLFLAG_RW, &m->hwvol_step, 0, ""); - SYSCTL_ADD_PROC(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), + SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0, sysctl_hw_snd_hwvol_mixer, "A", "") #endif diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c index 6792700..dd786e9 100644 --- a/sys/dev/sound/pcm/sndstat.c +++ b/sys/dev/sound/pcm/sndstat.c @@ -22,15 +22,19 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/vchan.h> -#include <sys/sbuf.h> -#include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + +#define SS_TYPE_MODULE 0 +#define SS_TYPE_FIRST 1 +#define SS_TYPE_PCM 1 +#define SS_TYPE_MIDI 2 +#define SS_TYPE_SEQUENCER 3 +#define SS_TYPE_LAST 3 static d_open_t sndstat_open; static d_close_t sndstat_close; @@ -52,16 +56,31 @@ static struct cdevsw sndstat_cdevsw = { /* flags */ 0, }; +struct sndstat_entry { + SLIST_ENTRY(sndstat_entry) link; + device_t dev; + char *str; + sndstat_handler handler; + int type, unit; +}; + +#ifdef USING_MUTEX +static struct mtx sndstat_lock; +#endif static struct sbuf sndstat_sbuf; static dev_t sndstat_dev = 0; static int sndstat_isopen = 0; static int sndstat_bufptr; +static int sndstat_maxunit = -1; +static int sndstat_files = 0; -static int sndstat_verbose = 0; +static SLIST_HEAD(, sndstat_entry) sndstat_devlist = SLIST_HEAD_INITIALIZER(none); + +static int sndstat_verbose = 1; #ifdef USING_MUTEX TUNABLE_INT("hw.snd.verbose", &sndstat_verbose); #else -TUNABLE_INT_DECL("hw.snd.verbose", 0, sndstat_verbose); +TUNABLE_INT_DECL("hw.snd.verbose", 1, sndstat_verbose); #endif static int sndstat_prepare(struct sbuf *s); @@ -69,15 +88,20 @@ static int sndstat_prepare(struct sbuf *s); static int sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS) { + intrmask_t s; int error, verbose; verbose = sndstat_verbose; error = sysctl_handle_int(oidp, &verbose, sizeof(verbose), req); if (error == 0 && req->newptr != NULL) { - if (verbose == 0 || verbose == 1) - sndstat_verbose = verbose; - else + s = spltty(); + mtx_lock(&sndstat_lock); + if (verbose < 0 || verbose > 3) error = EINVAL; + else + sndstat_verbose = verbose; + mtx_unlock(&sndstat_lock); + splx(s); } return error; } @@ -91,11 +115,14 @@ sndstat_open(dev_t i_dev, int flags, int mode, struct proc *p) int err; s = spltty(); + mtx_lock(&sndstat_lock); if (sndstat_isopen) { + mtx_unlock(&sndstat_lock); splx(s); return EBUSY; } if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL) { + mtx_unlock(&sndstat_lock); splx(s); return ENXIO; } @@ -104,6 +131,7 @@ sndstat_open(dev_t i_dev, int flags, int mode, struct proc *p) if (!err) sndstat_isopen = 1; + mtx_unlock(&sndstat_lock); splx(s); return err; } @@ -114,13 +142,16 @@ sndstat_close(dev_t i_dev, int flags, int mode, struct proc *p) intrmask_t s; s = spltty(); + mtx_lock(&sndstat_lock); if (!sndstat_isopen) { + mtx_unlock(&sndstat_lock); splx(s); return EBADF; } sbuf_delete(&sndstat_sbuf); sndstat_isopen = 0; + mtx_unlock(&sndstat_lock); splx(s); return 0; } @@ -132,7 +163,9 @@ sndstat_read(dev_t i_dev, struct uio *buf, int flag) int l, err; s = spltty(); + mtx_lock(&sndstat_lock); if (!sndstat_isopen) { + mtx_unlock(&sndstat_lock); splx(s); return EBADF; } @@ -140,85 +173,169 @@ sndstat_read(dev_t i_dev, struct uio *buf, int flag) err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0; sndstat_bufptr += l; + mtx_unlock(&sndstat_lock); splx(s); return err; } +/************************************************************************/ + +static struct sndstat_entry * +sndstat_find(int type, int unit) +{ + struct sndstat_entry *ent; + + SLIST_FOREACH(ent, &sndstat_devlist, link) { + if (ent->type == type && ent->unit == unit) + return ent; + } + + return NULL; +} + +int +sndstat_register(device_t dev, char *str, sndstat_handler handler) +{ + intrmask_t s; + struct sndstat_entry *ent; + const char *devtype; + int type, unit; + + if (dev) { + unit = device_get_unit(dev); + devtype = device_get_name(dev); + if (!strcmp(devtype, "pcm")) + type = SS_TYPE_PCM; + else if (!strcmp(devtype, "midi")) + type = SS_TYPE_MIDI; + else if (!strcmp(devtype, "sequencer")) + type = SS_TYPE_SEQUENCER; + else + return EINVAL; + } else { + type = SS_TYPE_MODULE; + unit = -1; + } + + ent = malloc(sizeof *ent, M_DEVBUF, M_ZERO | M_WAITOK); + if (!ent) + return ENOSPC; + + ent->dev = dev; + ent->str = str; + ent->type = type; + ent->unit = unit; + ent->handler = handler; + + s = spltty(); + mtx_lock(&sndstat_lock); + SLIST_INSERT_HEAD(&sndstat_devlist, ent, link); + if (type == SS_TYPE_MODULE) + sndstat_files++; + sndstat_maxunit = (unit > sndstat_maxunit)? unit : sndstat_maxunit; + mtx_unlock(&sndstat_lock); + splx(s); + + return 0; +} + +int +sndstat_registerfile(char *str) +{ + return sndstat_register(NULL, str, NULL); +} + +int +sndstat_unregister(device_t dev) +{ + intrmask_t s; + struct sndstat_entry *ent; + + s = spltty(); + mtx_lock(&sndstat_lock); + SLIST_FOREACH(ent, &sndstat_devlist, link) { + if (ent->dev == dev) { + SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); + free(ent, M_DEVBUF); + mtx_unlock(&sndstat_lock); + splx(s); + + return 0; + } + } + mtx_unlock(&sndstat_lock); + splx(s); + + return ENXIO; +} + +int +sndstat_unregisterfile(char *str) +{ + intrmask_t s; + struct sndstat_entry *ent; + + s = spltty(); + mtx_lock(&sndstat_lock); + SLIST_FOREACH(ent, &sndstat_devlist, link) { + if (ent->dev == NULL && ent->str == str) { + SLIST_REMOVE(&sndstat_devlist, ent, sndstat_entry, link); + free(ent, M_DEVBUF); + sndstat_files--; + mtx_unlock(&sndstat_lock); + splx(s); + + return 0; + } + } + mtx_unlock(&sndstat_lock); + splx(s); + + return ENXIO; +} + +/************************************************************************/ + static int sndstat_prepare(struct sbuf *s) { - int i, pc, rc, vc; - device_t dev; - struct snddev_info *d; - struct snddev_channel *sce; - struct pcm_channel *c; - struct pcm_feeder *f; - - sbuf_printf(s, "FreeBSD Audio Driver (newpcm) %s %s\n", __DATE__, __TIME__); - if (!pcm_devclass || devclass_get_maxunit(pcm_devclass) == 0) { + struct sndstat_entry *ent; + int i, j; + + sbuf_printf(s, "FreeBSD Audio Driver (newpcm)\n"); + if (SLIST_EMPTY(&sndstat_devlist)) { sbuf_printf(s, "No devices installed.\n"); sbuf_finish(s); return sbuf_len(s); - } else - sbuf_printf(s, "Installed devices:\n"); - - for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { - d = devclass_get_softc(pcm_devclass, i); - if (!d) - continue; - snd_mtxlock(d->lock); - dev = devclass_get_device(pcm_devclass, i); - sbuf_printf(s, "pcm%d: <%s> %s", i, device_get_desc(dev), d->status); - if (!SLIST_EMPTY(&d->channels)) { - pc = rc = vc = 0; - SLIST_FOREACH(sce, &d->channels, link) { - c = sce->channel; - if (c->direction == PCMDIR_PLAY) { - if (c->flags & CHN_F_VIRTUAL) - vc++; - else - pc++; - } else - rc++; - } - sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)\n", pc, rc, vc, - (d->flags & SD_F_SIMPLEX)? "" : " duplex", -#ifdef USING_DEVFS - (i == snd_unit)? " default" : "" -#else - "" -#endif - ); - if (!sndstat_verbose) - goto skipverbose; - SLIST_FOREACH(sce, &d->channels, link) { - c = sce->channel; - sbuf_printf(s, "\t%s[%s]: speed %d, format %08x, flags %08x", - c->parentchannel? c->parentchannel->name : "", - c->name, c->speed, c->format, c->flags); - if (c->pid != -1) - sbuf_printf(s, ", pid %d", c->pid); - sbuf_printf(s, "\n\t"); - f = c->feeder; - while (f) { - sbuf_printf(s, "%s", f->class->name); - if (f->desc->type == FEEDER_FMT) - sbuf_printf(s, "(%08x <- %08x)", f->desc->out, f->desc->in); - if (f->desc->type == FEEDER_RATE) - sbuf_printf(s, "(%d <- %d)", FEEDER_GET(f, FEEDRATE_DST), FEEDER_GET(f, FEEDRATE_SRC)); - if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER) - sbuf_printf(s, "(%08x)", f->desc->out); - if (f->source) - sbuf_printf(s, " <- "); - f = f->source; - } - sbuf_printf(s, "\n"); - } -skipverbose: - } else - sbuf_printf(s, " (mixer only)\n"); - snd_mtxunlock(d->lock); + } + + sbuf_printf(s, "Installed devices:\n"); + + for (i = 0; i <= sndstat_maxunit; i++) { + for (j = SS_TYPE_FIRST; j <= SS_TYPE_LAST; j++) { + ent = sndstat_find(j, i); + if (!ent) + continue; + sbuf_printf(s, "%s:", device_get_nameunit(ent->dev)); + sbuf_printf(s, " <%s>", device_get_desc(ent->dev)); + sbuf_printf(s, " %s", ent->str); + if (ent->handler) + ent->handler(s, ent->dev, sndstat_verbose); + else + sbuf_printf(s, " [no handler]"); + sbuf_printf(s, "\n"); + } } + + if (sndstat_verbose >= 3 && sndstat_files > 0) { + sbuf_printf(s, "\nFile Versions:\n"); + + SLIST_FOREACH(ent, &sndstat_devlist, link) { + if (ent->dev == NULL && ent->str != NULL) + sbuf_printf(s, "%s\n", ent->str); + } + } + sbuf_finish(s); return sbuf_len(s); } @@ -226,6 +343,7 @@ skipverbose: static int sndstat_init(void) { + mtx_init(&sndstat_lock, "sndstat", 0); sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, UID_ROOT, GID_WHEEL, 0444, "sndstat"); return (sndstat_dev != 0)? 0 : ENXIO; @@ -237,7 +355,9 @@ sndstat_uninit(void) intrmask_t s; s = spltty(); + mtx_lock(&sndstat_lock); if (sndstat_isopen) { + mtx_unlock(&sndstat_lock); splx(s); return EBUSY; } @@ -247,6 +367,7 @@ sndstat_uninit(void) sndstat_dev = 0; splx(s); + mtx_destroy(&sndstat_lock); return 0; } @@ -262,7 +383,7 @@ sndstat_sysuninit(void *p) sndstat_uninit(); } -SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sndstat_sysinit, NULL); -SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sndstat_sysuninit, NULL); +SYSINIT(sndstat_sysinit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysinit, NULL); +SYSUNINIT(sndstat_sysuninit, SI_SUB_DRIVERS, SI_ORDER_FIRST, sndstat_sysuninit, NULL); diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 793b48a..08da0a4 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -23,14 +23,35 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/vchan.h> #include <sys/sysctl.h> +#include "feeder_if.h" + +SND_DECLARE_FILE("$FreeBSD$"); + +struct snddev_channel { + SLIST_ENTRY(snddev_channel) link; + struct pcm_channel *channel; +}; + +struct snddev_info { + SLIST_HEAD(, snddev_channel) channels; + struct pcm_channel *fakechan; + unsigned devcount, chancount, vchancount; + unsigned flags; + int inprog; + void *devinfo; + device_t dev; + char status[SND_STATUSLEN]; + struct sysctl_ctx_list sysctl_tree; + struct sysctl_oid *sysctl_tree_top; + void *lock; +}; + devclass_t pcm_devclass; #ifdef USING_DEVFS @@ -38,18 +59,29 @@ int snd_unit = 0; TUNABLE_INT("hw.snd.unit", &snd_unit); #endif -int snd_autovchans = 0; -int snd_maxvchans = 0; -#if __FreeBSD_version > 500000 -TUNABLE_INT("hw.snd.autovchans", &snd_autovchans); -TUNABLE_INT("hw.snd.maxvchans", &snd_maxvchans); -#else -TUNABLE_INT("hw.snd.autovchans", 0, snd_autovchans); -TUNABLE_INT("hw.snd.maxvchans", 0, snd_maxvchans); -#endif +int snd_maxautovchans = 0; +TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); +static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); + +struct sysctl_ctx_list * +snd_sysctl_tree(device_t dev) +{ + struct snddev_info *d = device_get_softc(dev); + + return &d->sysctl_tree; +} + +struct sysctl_oid * +snd_sysctl_tree_top(device_t dev) +{ + struct snddev_info *d = device_get_softc(dev); + + return d->sysctl_tree_top; +} + void * snd_mtxcreate(const char *desc) { @@ -122,6 +154,24 @@ snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand return bus_setup_intr(dev, res, flags, hand, param, cookiep); } +void +pcm_lock(struct snddev_info *d) +{ + snd_mtxlock(d->lock); +} + +void +pcm_unlock(struct snddev_info *d) +{ + snd_mtxunlock(d->lock); +} + +struct pcm_channel * +pcm_getfakechan(struct snddev_info *d) +{ + return d->fakechan; +} + /* return a locked channel */ struct pcm_channel * pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid) @@ -146,7 +196,7 @@ pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid) /* no channel available */ if (direction == PCMDIR_PLAY) { - if ((d->vchancount > 0) && (d->vchancount < snd_maxvchans)) { + if ((d->vchancount > 0) && (d->vchancount < snd_maxautovchans)) { /* try to create a vchan */ SLIST_FOREACH(sce, &d->channels, link) { c = sce->channel; @@ -186,6 +236,53 @@ pcm_chnref(struct pcm_channel *c, int ref) return r; } +int +pcm_inprog(struct snddev_info *d, int delta) +{ + d->inprog += delta; + return d->inprog; +} + +static void +pcm_setmaxautovchans(struct snddev_info *d, int num) +{ + struct pcm_channel *c; + struct snddev_channel *sce; + int err, done; + + if (num > 0 && d->vchancount == 0) { + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + if ((c->direction == PCMDIR_PLAY) && !(c->flags & CHN_F_BUSY)) { + c->flags |= CHN_F_BUSY; + err = vchan_create(c); + if (err) { + device_printf(d->dev, "vchan_create(%s) == %d\n", c->name, err); + c->flags &= ~CHN_F_BUSY; + } + return; + } + } + } + if (num == 0 && d->vchancount > 0) { + done = 0; + while (!done) { + done = 1; + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + if ((c->flags & CHN_F_VIRTUAL) && !(c->flags & CHN_F_BUSY)) { + done = 0; + err = vchan_destroy(c); + if (err) + device_printf(d->dev, "vchan_destroy(%s) == %d\n", c->name, err); + goto restart; + } + } +restart: + } + } +} + #ifdef USING_DEVFS static int sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS) @@ -210,38 +307,30 @@ SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW, #endif static int -sysctl_hw_snd_autovchans(SYSCTL_HANDLER_ARGS) +sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) { - int v, error; - - v = snd_autovchans; - error = sysctl_handle_int(oidp, &v, sizeof(v), req); - if (error == 0 && req->newptr != NULL) { - if (v < 0 || v >= SND_MAXVCHANS) - return EINVAL; - snd_autovchans = v; - } - return (error); -} -SYSCTL_PROC(_hw_snd, OID_AUTO, autovchans, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(int), sysctl_hw_snd_autovchans, "I", ""); - -static int -sysctl_hw_snd_maxvchans(SYSCTL_HANDLER_ARGS) -{ - int v, error; + struct snddev_info *d; + int i, v, error; - v = snd_maxvchans; + v = snd_maxautovchans; error = sysctl_handle_int(oidp, &v, sizeof(v), req); if (error == 0 && req->newptr != NULL) { if (v < 0 || v >= SND_MAXVCHANS) return EINVAL; - snd_maxvchans = v; + if (v != snd_maxautovchans) { + for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { + d = devclass_get_softc(pcm_devclass, i); + if (!d) + continue; + pcm_setmaxautovchans(d, v); + } + } + snd_maxautovchans = v; } return (error); } -SYSCTL_PROC(_hw_snd, OID_AUTO, maxvchans, CTLTYPE_INT | CTLFLAG_RW, - 0, sizeof(int), sysctl_hw_snd_maxvchans, "I", ""); +SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, + 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", ""); struct pcm_channel * pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo) @@ -311,7 +400,7 @@ pcm_chn_destroy(struct pcm_channel *ch) int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev) { - struct snddev_channel *sce; + struct snddev_channel *sce, *tmp, *after; int unit = device_get_unit(d->dev); snd_mtxlock(d->lock); @@ -323,7 +412,15 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev) } sce->channel = ch; - SLIST_INSERT_HEAD(&d->channels, sce, link); + if (SLIST_EMPTY(&d->channels)) { + SLIST_INSERT_HEAD(&d->channels, sce, link); + } else { + after = NULL; + SLIST_FOREACH(tmp, &d->channels, link) { + after = tmp; + } + SLIST_INSERT_AFTER(after, sce, link); + } if (mkdev) dsp_register(unit, d->devcount++); @@ -367,9 +464,8 @@ int 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, *child; - struct pcmchan_children *pce; - int i, err; + struct pcm_channel *ch; + int err; ch = pcm_chn_create(d, NULL, cls, dir, devinfo); if (!ch) { @@ -384,17 +480,12 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) return err; } - if ((dir == PCMDIR_PLAY) && (d->flags & SD_F_AUTOVCHAN) && (snd_autovchans > 0)) { + if (snd_maxautovchans > 0 && (d->flags & SD_F_AUTOVCHAN)) { ch->flags |= CHN_F_BUSY; - for (i = 0; err == 0 && i < snd_autovchans; i++) - err = vchan_create(ch); + err = vchan_create(ch); if (err) { - device_printf(d->dev, "vchan_create(%d) failed, err=%d\n", i - 1, err); - SLIST_FOREACH(pce, &ch->children, link) { - child = pce->channel; - vchan_destroy(child); - } - return err; + device_printf(d->dev, "vchan_create(%s) == %d\n", ch->name, err); + ch->flags &= ~CHN_F_BUSY; } } @@ -449,7 +540,6 @@ pcm_getdevinfo(device_t dev) return d->devinfo; } -/* This is the generic init routine */ int pcm_register(device_t dev, void *devinfo, int numplay, int numrec) { @@ -483,11 +573,12 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec) } #endif if (numplay > 0) - vchan_initsys(d); + vchan_initsys(dev); if (numplay == 1) d->flags |= SD_F_AUTOVCHAN; snd_mtxunlock(d->lock); + sndstat_register(dev, d->status, sndstat_prepare_pcm); return 0; no: snd_mtxfree(d->lock); @@ -533,6 +624,165 @@ pcm_unregister(device_t dev) return 0; } +/************************************************************************/ + +static int +sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) +{ + struct snddev_info *d; + struct snddev_channel *sce; + struct pcm_channel *c; + struct pcm_feeder *f; + int pc, rc, vc; + + if (verbose < 1) + return 0; + + d = device_get_softc(dev); + if (!d) + return ENXIO; + + snd_mtxlock(d->lock); + if (!SLIST_EMPTY(&d->channels)) { + pc = rc = vc = 0; + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + if (c->direction == PCMDIR_PLAY) { + if (c->flags & CHN_F_VIRTUAL) + vc++; + else + pc++; + } else + rc++; + } + sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", pc, rc, vc, + (d->flags & SD_F_SIMPLEX)? "" : " duplex", +#ifdef USING_DEVFS + (device_get_unit(dev) == snd_unit)? " default" : "" +#else + "" +#endif + ); + if (verbose <= 1) + goto skipverbose; + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + sbuf_printf(s, "\n\t%s[%s]: speed %d, format %08x, flags %08x", + c->parentchannel? c->parentchannel->name : "", + c->name, c->speed, c->format, c->flags); + if (c->pid != -1) + sbuf_printf(s, ", pid %d", c->pid); + sbuf_printf(s, "\n\t"); + f = c->feeder; + while (f) { + sbuf_printf(s, "%s", f->class->name); + if (f->desc->type == FEEDER_FMT) + sbuf_printf(s, "(%08x <- %08x)", f->desc->out, f->desc->in); + if (f->desc->type == FEEDER_RATE) + sbuf_printf(s, "(%d <- %d)", FEEDER_GET(f, FEEDRATE_DST), FEEDER_GET(f, FEEDRATE_SRC)); + if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER) + sbuf_printf(s, "(%08x)", f->desc->out); + if (f->source) + sbuf_printf(s, " <- "); + f = f->source; + } + } +skipverbose: + } else + sbuf_printf(s, " (mixer only)"); + snd_mtxunlock(d->lock); + + return 0; +} + +/************************************************************************/ + +#ifdef SND_DYNSYSCTL +int +sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) +{ + struct snddev_info *d; + struct snddev_channel *sce; + struct pcm_channel *c; + int err, oldcnt, newcnt, cnt; + + d = oidp->oid_arg1; + + pcm_lock(d); + cnt = 0; + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) + cnt++; + } + oldcnt = cnt; + newcnt = cnt; + + err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req); + if (err == 0 && req->newptr != NULL) { + if (newcnt < 0 || newcnt > SND_MAXVCHANS) { + pcm_unlock(d); + return EINVAL; + } + + if (newcnt > cnt) { + /* add new vchans - find a parent channel first */ + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + /* not a candidate if not a play channel */ + if (c->direction != PCMDIR_PLAY) + goto addskip; + /* not a candidate if a virtual channel */ + if (c->flags & CHN_F_VIRTUAL) + goto addskip; + /* not a candidate if it's in use */ + if ((c->flags & CHN_F_BUSY) && (SLIST_EMPTY(&c->children))) + goto addskip; + /* + * if we get here we're a nonvirtual play channel, and either + * 1) not busy + * 2) busy with children, not directly open + * + * thus we can add children + */ + goto addok; +addskip: + } + pcm_unlock(d); + return EBUSY; +addok: + c->flags |= CHN_F_BUSY; + while (err == 0 && newcnt > cnt) { + err = vchan_create(c); + if (err == 0) + cnt++; + } + if (SLIST_EMPTY(&c->children)) + c->flags &= ~CHN_F_BUSY; + } else if (newcnt < cnt) { + while (err == 0 && newcnt < cnt) { + SLIST_FOREACH(sce, &d->channels, link) { + c = sce->channel; + if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL) + goto remok; + } + pcm_unlock(d); + return EINVAL; +remok: + err = vchan_destroy(c); + if (err == 0) + cnt--; + } + } + } + + pcm_unlock(d); + return err; +} +#endif + +/************************************************************************/ + static moduledata_t sndpcm_mod = { "snd_pcm", NULL, diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index 3bb0b27..6cc6371 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -62,6 +62,7 @@ #include <sys/rman.h> #include <sys/mman.h> #include <sys/poll.h> +#include <sys/sbuf.h> #include <sys/soundcard.h> #include <sys/sysctl.h> #include <isa/isavar.h> @@ -76,6 +77,7 @@ #define USING_MUTEX #define USING_DEVFS #endif + #define SND_DYNSYSCTL #ifndef INTR_MPSAFE @@ -86,18 +88,6 @@ #define INTR_MPSAFE 0 #endif -#else -struct isa_device { int dummy; }; -#define d_open_t void -#define d_close_t void -#define d_read_t void -#define d_write_t void -#define d_ioctl_t void -#define d_select_t void -#endif /* _KERNEL */ - -#endif /* _OS_H_ */ - struct pcm_channel; struct pcm_feeder; struct snd_dbuf; @@ -109,27 +99,10 @@ struct snd_mixer; #include <dev/sound/pcm/mixer.h> #include <dev/sound/pcm/dsp.h> -struct snddev_channel { - SLIST_ENTRY(snddev_channel) link; - struct pcm_channel *channel; -}; +#define PCM_SOFTC_SIZE 512 #define SND_STATUSLEN 64 /* descriptor of audio device */ -struct snddev_info { - SLIST_HEAD(, snddev_channel) channels; - struct pcm_channel *fakechan; - unsigned devcount, chancount, vchancount; - unsigned flags; - int inprog; - void *devinfo; - device_t dev; - char status[SND_STATUSLEN]; - struct sysctl_ctx_list sysctl_tree; - struct sysctl_oid *sysctl_tree_top; - void *lock; -}; - #ifndef ISADMA_WRITE #define ISADMA_WRITE B_WRITE #define ISADMA_READ B_READ @@ -224,8 +197,6 @@ int fkchan_kill(struct pcm_channel *c); #define ON 1 #define OFF 0 -#ifdef _KERNEL - extern int snd_unit; extern devclass_t pcm_devclass; @@ -243,9 +214,16 @@ extern devclass_t pcm_devclass; SYSCTL_DECL(_hw_snd); +struct sysctl_ctx_list *snd_sysctl_tree(device_t dev); +struct sysctl_oid *snd_sysctl_tree_top(device_t dev); + +void pcm_lock(struct snddev_info *d); +void pcm_unlock(struct snddev_info *d); +struct pcm_channel *pcm_getfakechan(struct snddev_info *d); struct pcm_channel *pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid); int pcm_chnrelease(struct pcm_channel *c); int pcm_chnref(struct pcm_channel *c, int ref); +int pcm_inprog(struct snddev_info *d, int delta); struct pcm_channel *pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo); int pcm_chn_destroy(struct pcm_channel *ch); @@ -268,7 +246,25 @@ void snd_mtxfree(void *m); void snd_mtxassert(void *m); void snd_mtxlock(void *m); void snd_mtxunlock(void *m); -#endif /* _KERNEL */ + +int sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS); + +typedef int (*sndstat_handler)(struct sbuf *s, device_t dev, int verbose); +int sndstat_register(device_t dev, char *str, sndstat_handler handler); +int sndstat_registerfile(char *str); +int sndstat_unregister(device_t dev); +int sndstat_unregisterfile(char *str); + +#define SND_DECLARE_FILE(version) \ + _SND_DECLARE_FILE(__LINE__, version) + +#define _SND_DECLARE_FILE(uniq, version) \ + __SND_DECLARE_FILE(uniq, version) + +#define __SND_DECLARE_FILE(uniq, version) \ + static char sndstat_vinfo[] = version; \ + SYSINIT(sdf_ ## uniq, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sndstat_registerfile, sndstat_vinfo); \ + SYSUNINIT(sdf_ ## uniq, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, sndstat_unregisterfile, sndstat_vinfo); /* usage of flags in device config entry (config file) */ #define DV_F_DRQ_MASK 0x00000007 /* mask for secondary drq */ @@ -277,3 +273,7 @@ void snd_mtxunlock(void *m); /* ought to be made obsolete */ #define DV_F_DEV_MASK 0x0000ff00 /* force device type/class */ #define DV_F_DEV_SHIFT 8 /* force device type/class */ + +#endif /* _KERNEL */ + +#endif /* _OS_H_ */ diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c index 7a8d41d..46b3061 100644 --- a/sys/dev/sound/pcm/vchan.c +++ b/sys/dev/sound/pcm/vchan.c @@ -22,14 +22,14 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include <dev/sound/pcm/sound.h> #include <dev/sound/pcm/vchan.h> #include "feeder_if.h" +SND_DECLARE_FILE("$FreeBSD$"); + struct vchinfo { u_int32_t spd, fmt, blksz, bps, run; struct pcm_channel *channel, *parent; @@ -42,7 +42,6 @@ static u_int32_t vchan_fmt[] = { 0 }; - static int vchan_mix_s16(int16_t *to, int16_t *tmp, unsigned int count) { @@ -327,98 +326,18 @@ gotch: return err; } -#ifdef SND_DYNSYSCTL -static int -sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) -{ - struct snddev_info *d; - struct snddev_channel *sce; - struct pcm_channel *c; - int err, oldcnt, newcnt, cnt; - - d = oidp->oid_arg1; - - snd_mtxlock(d->lock); - cnt = 0; - SLIST_FOREACH(sce, &d->channels, link) { - c = sce->channel; - if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) - cnt++; - } - oldcnt = cnt; - newcnt = cnt; - - err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req); - if (err == 0 && req->newptr != NULL) { - if (newcnt < 0 || newcnt > SND_MAXVCHANS) { - snd_mtxunlock(d->lock); - return EINVAL; - } - - if (newcnt > cnt) { - /* add new vchans - find a parent channel first */ - SLIST_FOREACH(sce, &d->channels, link) { - c = sce->channel; - /* not a candidate if not a play channel */ - if (c->direction != PCMDIR_PLAY) - goto addskip; - /* not a candidate if a virtual channel */ - if (c->flags & CHN_F_VIRTUAL) - goto addskip; - /* not a candidate if it's in use */ - if ((c->flags & CHN_F_BUSY) && (SLIST_EMPTY(&c->children))) - goto addskip; - /* - * if we get here we're a nonvirtual play channel, and either - * 1) not busy - * 2) busy with children, not directly open - * - * thus we can add children - */ - goto addok; -addskip: - } - snd_mtxunlock(d->lock); - return EBUSY; -addok: - c->flags |= CHN_F_BUSY; - while (err == 0 && newcnt > cnt) { - err = vchan_create(c); - if (err == 0) - cnt++; - } - if (SLIST_EMPTY(&c->children)) - c->flags &= ~CHN_F_BUSY; - } else if (newcnt < cnt) { - while (err == 0 && newcnt < cnt) { - SLIST_FOREACH(sce, &d->channels, link) { - c = sce->channel; - if ((c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL) - goto remok; - } - snd_mtxunlock(d->lock); - return EINVAL; -remok: - err = vchan_destroy(c); - if (err == 0) - cnt--; - } - } - } - - snd_mtxunlock(d->lock); - return err; -} -#endif - int -vchan_initsys(struct snddev_info *d) +vchan_initsys(device_t dev) { #ifdef SND_DYNSYSCTL - SYSCTL_ADD_PROC(&d->sysctl_tree, SYSCTL_CHILDREN(d->sysctl_tree_top), + struct snddev_info *d; + + d = device_get_softc(dev); + SYSCTL_ADD_PROC(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), OID_AUTO, "vchans", CTLTYPE_INT | CTLFLAG_RW, d, sizeof(d), sysctl_hw_snd_vchans, "I", "") #endif + return 0; } diff --git a/sys/dev/sound/pcm/vchan.h b/sys/dev/sound/pcm/vchan.h index 7e057ce..d3121e9 100644 --- a/sys/dev/sound/pcm/vchan.h +++ b/sys/dev/sound/pcm/vchan.h @@ -28,6 +28,6 @@ int vchan_create(struct pcm_channel *parent); int vchan_destroy(struct pcm_channel *c); -int vchan_initsys(struct snddev_info *d); +int vchan_initsys(device_t dev); |