summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r--sys/dev/sound/pcm/ac97.c4
-rw-r--r--sys/dev/sound/pcm/buffer.c4
-rw-r--r--sys/dev/sound/pcm/channel.c8
-rw-r--r--sys/dev/sound/pcm/dsp.c112
-rw-r--r--sys/dev/sound/pcm/fake.c4
-rw-r--r--sys/dev/sound/pcm/feeder.c4
-rw-r--r--sys/dev/sound/pcm/feeder_fmt.c4
-rw-r--r--sys/dev/sound/pcm/feeder_rate.c4
-rw-r--r--sys/dev/sound/pcm/mixer.c10
-rw-r--r--sys/dev/sound/pcm/sndstat.c279
-rw-r--r--sys/dev/sound/pcm/sound.c352
-rw-r--r--sys/dev/sound/pcm/sound.h66
-rw-r--r--sys/dev/sound/pcm/vchan.c97
-rw-r--r--sys/dev/sound/pcm/vchan.h2
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);
OpenPOWER on IntegriCloud