summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm/sndstat.c
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-06-16 21:25:10 +0000
committercg <cg@FreeBSD.org>2001-06-16 21:25:10 +0000
commit4a0664e88e403e97d641f7ad4fd6dab71095bd0b (patch)
treeb90a72aa9539fc95aa3dfcae3c1ed22290a8bec2 /sys/dev/sound/pcm/sndstat.c
parentb81ba90a5fa7778120861346194bdd1912baa63b (diff)
downloadFreeBSD-src-4a0664e88e403e97d641f7ad4fd6dab71095bd0b.zip
FreeBSD-src-4a0664e88e403e97d641f7ad4fd6dab71095bd0b.tar.gz
use a global devclass for all drivers - i'm not entirely sure why this
worked before. mixer, dsp and sndstat are seperate devices - give them their own cdevsws instead of demuxing requests sent to a single cdevsw. use the si_drv1/si_drv2 fields in dev_t structures for holding information specific to an open instance of mixer/dsp. nuke /dev/{dsp,dspW,audio}[0-9]* links - this functionality is now provided using cloning. various locking fixes.
Diffstat (limited to 'sys/dev/sound/pcm/sndstat.c')
-rw-r--r--sys/dev/sound/pcm/sndstat.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/sys/dev/sound/pcm/sndstat.c b/sys/dev/sound/pcm/sndstat.c
new file mode 100644
index 0000000..030b14b
--- /dev/null
+++ b/sys/dev/sound/pcm/sndstat.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2001 Cameron Grant <gandalf@vilnya.demon.co.uk>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * 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"
+
+static d_open_t sndstat_open;
+static d_close_t sndstat_close;
+static d_read_t sndstat_read;
+
+static struct cdevsw sndstat_cdevsw = {
+ /* open */ sndstat_open,
+ /* close */ sndstat_close,
+ /* read */ sndstat_read,
+ /* write */ nowrite,
+ /* ioctl */ noioctl,
+ /* poll */ nopoll,
+ /* mmap */ nommap,
+ /* strategy */ nostrategy,
+ /* name */ "sndstat",
+ /* maj */ SND_CDEV_MAJOR,
+ /* dump */ nodump,
+ /* psize */ nopsize,
+ /* flags */ 0,
+};
+
+static struct sbuf sndstat_sbuf;
+static dev_t sndstat_dev = 0;
+static int sndstat_isopen = 0;
+static int sndstat_bufptr;
+
+static int sndstat_verbose = 0;
+TUNABLE_INT("hw.snd.verbose", &sndstat_verbose);
+
+static int sndstat_prepare(struct sbuf *s);
+
+static int
+sysctl_hw_sndverbose(SYSCTL_HANDLER_ARGS)
+{
+ 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
+ error = EINVAL;
+ }
+ return error;
+}
+SYSCTL_PROC(_hw_snd, OID_AUTO, verbose, CTLTYPE_INT | CTLFLAG_RW,
+ 0, sizeof(int), sysctl_hw_sndverbose, "I", "");
+
+static int
+sndstat_open(dev_t i_dev, int flags, int mode, struct proc *p)
+{
+ int err;
+
+ if (sndstat_isopen)
+ return EBUSY;
+ if (sbuf_new(&sndstat_sbuf, NULL, 4096, 0) == NULL)
+ return ENXIO;
+ sndstat_bufptr = 0;
+ err = (sndstat_prepare(&sndstat_sbuf) > 0)? 0 : ENOMEM;
+ if (!err)
+ sndstat_isopen = 1;
+
+ return err;
+}
+
+static int
+sndstat_close(dev_t i_dev, int flags, int mode, struct proc *p)
+{
+ if (!sndstat_isopen)
+ return EBADF;
+ sbuf_delete(&sndstat_sbuf);
+ sndstat_isopen = 0;
+
+ return 0;
+}
+
+static int
+sndstat_read(dev_t i_dev, struct uio *buf, int flag)
+{
+ int l, err;
+
+ if (!sndstat_isopen)
+ return EBADF;
+ l = min(buf->uio_resid, sbuf_len(&sndstat_sbuf) - sndstat_bufptr);
+ err = (l > 0)? uiomove(sbuf_data(&sndstat_sbuf) + sndstat_bufptr, l, buf) : 0;
+ sndstat_bufptr += l;
+
+ return err;
+}
+
+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) {
+ 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 (d->chancount > 0) {
+ 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_finish(s);
+ return sbuf_len(s);
+}
+
+static int
+sndstat_init(void)
+{
+ sndstat_dev = make_dev(&sndstat_cdevsw, SND_DEV_STATUS, UID_ROOT, GID_WHEEL, 0444, "sndstat");
+
+ return (sndstat_dev != 0)? 0 : ENXIO;
+}
+
+static int
+sndstat_uninit(void)
+{
+ if (sndstat_isopen)
+ return EBUSY;
+
+ if (sndstat_dev)
+ destroy_dev(sndstat_dev);
+ sndstat_dev = 0;
+
+ return 0;
+}
+
+static void
+sndstat_sysinit(void *p)
+{
+ sndstat_init();
+}
+
+static void
+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);
+
+
OpenPOWER on IntegriCloud