Page MenuHomeFreeBSD

D44411.id136064.diff
No OneTemporary

D44411.id136064.diff

diff --git a/sys/conf/files b/sys/conf/files
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3056,7 +3056,6 @@
dev/smc/if_smc_acpi.c optional smc acpi
dev/smc/if_smc_fdt.c optional smc fdt
dev/snp/snp.c optional snp
-dev/sound/clone.c optional sound
dev/sound/unit.c optional sound
dev/sound/pci/als4000.c optional snd_als4000 pci
dev/sound/pci/atiixp.c optional snd_atiixp pci
diff --git a/sys/dev/sound/clone.h b/sys/dev/sound/clone.h
deleted file mode 100644
--- a/sys/dev/sound/clone.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
- * 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.
- */
-
-#ifndef _SND_CLONE_H_
-#define _SND_CLONE_H_
-
-struct snd_clone_entry;
-struct snd_clone;
-
-/*
- * 750 milisecond default deadline. Short enough to not cause excessive
- * garbage collection, long enough to indicate stalled VFS.
- */
-#define SND_CLONE_DEADLINE_DEFAULT 750
-
-/*
- * Fit within 24bit MAXMINOR.
- */
-#define SND_CLONE_MAXUNIT 0xffffff
-
-/*
- * Creation flags, mostly related to the behaviour of garbage collector.
- *
- * SND_CLONE_ENABLE - Enable clone allocation.
- * SND_CLONE_GC_ENABLE - Enable garbage collector operation, automatically
- * or if explicitly called upon.
- * SND_CLONE_GC_UNREF - Garbage collect during unref operation.
- * SND_CLONE_GC_LASTREF - Garbage collect during last reference
- * (refcount = 0)
- * SND_CLONE_GC_EXPIRED - Don't garbage collect unless the global clone
- * handler has been expired.
- * SND_CLONE_GC_REVOKE - Revoke clone invocation status which has been
- * expired instead of removing and freeing it.
- * SND_CLONE_WAITOK - malloc() is allowed to sleep while allocating
- * clone entry.
- */
-#define SND_CLONE_ENABLE 0x00000001
-#define SND_CLONE_GC_ENABLE 0x00000002
-#define SND_CLONE_GC_UNREF 0x00000004
-#define SND_CLONE_GC_LASTREF 0x00000008
-#define SND_CLONE_GC_EXPIRED 0x00000010
-#define SND_CLONE_GC_REVOKE 0x00000020
-#define SND_CLONE_WAITOK 0x80000000
-
-#define SND_CLONE_GC_MASK (SND_CLONE_GC_ENABLE | \
- SND_CLONE_GC_UNREF | \
- SND_CLONE_GC_LASTREF | \
- SND_CLONE_GC_EXPIRED | \
- SND_CLONE_GC_REVOKE)
-
-#define SND_CLONE_MASK (SND_CLONE_ENABLE | SND_CLONE_GC_MASK | \
- SND_CLONE_WAITOK)
-
-/*
- * Runtime clone device flags
- *
- * These are mostly private to the clone manager operation:
- *
- * SND_CLONE_NEW - New clone allocation in progress.
- * SND_CLONE_INVOKE - Cloning being invoked, waiting for next VFS operation.
- * SND_CLONE_BUSY - In progress, being referenced by living thread/proc.
- */
-#define SND_CLONE_NEW 0x00000001
-#define SND_CLONE_INVOKE 0x00000002
-#define SND_CLONE_BUSY 0x00000004
-
-/*
- * Nothing important, just for convenience.
- */
-#define SND_CLONE_ALLOC (SND_CLONE_NEW | SND_CLONE_INVOKE | \
- SND_CLONE_BUSY)
-
-#define SND_CLONE_DEVMASK SND_CLONE_ALLOC
-
-struct snd_clone *snd_clone_create(int, int, int, uint32_t);
-int snd_clone_busy(struct snd_clone *);
-int snd_clone_enable(struct snd_clone *);
-int snd_clone_disable(struct snd_clone *);
-int snd_clone_getsize(struct snd_clone *);
-int snd_clone_getmaxunit(struct snd_clone *);
-int snd_clone_setmaxunit(struct snd_clone *, int);
-int snd_clone_getdeadline(struct snd_clone *);
-int snd_clone_setdeadline(struct snd_clone *, int);
-uint32_t snd_clone_getflags(struct snd_clone *);
-uint32_t snd_clone_setflags(struct snd_clone *, uint32_t);
-uint32_t snd_clone_getdevflags(struct cdev *);
-uint32_t snd_clone_setdevflags(struct cdev *, uint32_t);
-int snd_clone_gc(struct snd_clone *);
-void snd_clone_destroy(struct snd_clone *);
-int snd_clone_acquire(struct cdev *);
-int snd_clone_release(struct cdev *);
-int snd_clone_ref(struct cdev *);
-int snd_clone_unref(struct cdev *);
-void snd_clone_register(struct snd_clone_entry *, struct cdev *);
-struct snd_clone_entry *snd_clone_alloc(struct snd_clone *, struct cdev **,
- int *, int);
-
-#define snd_clone_enabled(x) ((x) != NULL && \
- (snd_clone_getflags(x) & SND_CLONE_ENABLE))
-#define snd_clone_disabled(x) (!snd_clone_enabled(x))
-
-#endif /* !_SND_CLONE_H */
diff --git a/sys/dev/sound/clone.c b/sys/dev/sound/clone.c
deleted file mode 100644
--- a/sys/dev/sound/clone.c
+++ /dev/null
@@ -1,705 +0,0 @@
-/*-
- * SPDX-License-Identifier: BSD-2-Clause
- *
- * Copyright (c) 2007 Ariff Abdullah <ariff@FreeBSD.org>
- * 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.
- */
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/conf.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/proc.h>
-
-#ifdef HAVE_KERNEL_OPTION_HEADERS
-#include "opt_snd.h"
-#endif
-
-#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG)
-#include <dev/sound/pcm/sound.h>
-#endif
-
-#include <dev/sound/clone.h>
-
-/*
- * So here we go again, another clonedevs manager. Unlike default clonedevs,
- * this clone manager is designed to withstand various abusive behavior
- * (such as 'while : ; do ls /dev/whatever ; done', etc.), reusable object
- * after reaching certain expiration threshold, aggressive garbage collector,
- * transparent device allocator and concurrency handling across multiple
- * thread/proc. Due to limited information given by dev_clone EVENTHANDLER,
- * we don't have much clues whether the caller wants a real open() or simply
- * making fun of us with things like stat(), mtime() etc. Assuming that:
- * 1) Time window between dev_clone EH <-> real open() should be small
- * enough and 2) mtime()/stat() etc. always looks like a half way / stalled
- * operation, we can decide whether a new cdev must be created, old
- * (expired) cdev can be reused or an existing cdev can be shared.
- *
- * Most of the operations and logics are generic enough and can be applied
- * on other places (such as if_tap, snp, etc). Perhaps this can be
- * rearranged to complement clone_*(). However, due to this still being
- * specific to the sound driver (and as a proof of concept on how it can be
- * done), si_drv2 is used to keep the pointer of the clone list entry to
- * avoid expensive lookup.
- */
-
-/* clone entry */
-struct snd_clone_entry {
- TAILQ_ENTRY(snd_clone_entry) link;
- struct snd_clone *parent;
- struct cdev *devt;
- struct timespec tsp;
- uint32_t flags;
- pid_t pid;
- int unit;
-};
-
-/* clone manager */
-struct snd_clone {
- TAILQ_HEAD(link_head, snd_clone_entry) head;
- struct timespec tsp;
- int refcount;
- int size;
- int typemask;
- int maxunit;
- int deadline;
- uint32_t flags;
-};
-
-#ifdef SND_DIAGNOSTIC
-#define SND_CLONE_ASSERT(x, y) do { \
- if (!(x)) \
- panic y; \
-} while (0)
-#else
-#define SND_CLONE_ASSERT(...) KASSERT(__VA_ARGS__)
-#endif
-
-/*
- * snd_clone_create() : Return opaque allocated clone manager.
- */
-struct snd_clone *
-snd_clone_create(int typemask, int maxunit, int deadline, uint32_t flags)
-{
- struct snd_clone *c;
-
- SND_CLONE_ASSERT(!(typemask & ~SND_CLONE_MAXUNIT),
- ("invalid typemask: 0x%08x", typemask));
- SND_CLONE_ASSERT(maxunit == -1 ||
- !(maxunit & ~(~typemask & SND_CLONE_MAXUNIT)),
- ("maxunit overflow: typemask=0x%08x maxunit=%d",
- typemask, maxunit));
- SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
- ("invalid clone flags=0x%08x", flags));
-
- c = malloc(sizeof(*c), M_DEVBUF, M_WAITOK | M_ZERO);
- c->refcount = 0;
- c->size = 0;
- c->typemask = typemask;
- c->maxunit = (maxunit == -1) ? (~typemask & SND_CLONE_MAXUNIT) :
- maxunit;
- c->deadline = deadline;
- c->flags = flags;
- getnanouptime(&c->tsp);
- TAILQ_INIT(&c->head);
-
- return (c);
-}
-
-int
-snd_clone_busy(struct snd_clone *c)
-{
- struct snd_clone_entry *ce;
-
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- if (c->size == 0)
- return (0);
-
- TAILQ_FOREACH(ce, &c->head, link) {
- if ((ce->flags & SND_CLONE_BUSY) ||
- (ce->devt != NULL && ce->devt->si_threadcount != 0))
- return (EBUSY);
- }
-
- return (0);
-}
-
-/*
- * snd_clone_enable()/disable() : Suspend/resume clone allocation through
- * snd_clone_alloc(). Everything else will not be affected by this.
- */
-int
-snd_clone_enable(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- if (c->flags & SND_CLONE_ENABLE)
- return (EINVAL);
-
- c->flags |= SND_CLONE_ENABLE;
-
- return (0);
-}
-
-int
-snd_clone_disable(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- if (!(c->flags & SND_CLONE_ENABLE))
- return (EINVAL);
-
- c->flags &= ~SND_CLONE_ENABLE;
-
- return (0);
-}
-
-/*
- * Getters / Setters. Not worth explaining :)
- */
-int
-snd_clone_getsize(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- return (c->size);
-}
-
-int
-snd_clone_getmaxunit(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- return (c->maxunit);
-}
-
-int
-snd_clone_setmaxunit(struct snd_clone *c, int maxunit)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
- SND_CLONE_ASSERT(maxunit == -1 ||
- !(maxunit & ~(~c->typemask & SND_CLONE_MAXUNIT)),
- ("maxunit overflow: typemask=0x%08x maxunit=%d",
- c->typemask, maxunit));
-
- c->maxunit = (maxunit == -1) ? (~c->typemask & SND_CLONE_MAXUNIT) :
- maxunit;
-
- return (c->maxunit);
-}
-
-int
-snd_clone_getdeadline(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- return (c->deadline);
-}
-
-int
-snd_clone_setdeadline(struct snd_clone *c, int deadline)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- c->deadline = deadline;
-
- return (c->deadline);
-}
-
-uint32_t
-snd_clone_getflags(struct snd_clone *c)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- return (c->flags);
-}
-
-uint32_t
-snd_clone_setflags(struct snd_clone *c, uint32_t flags)
-{
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
- SND_CLONE_ASSERT(!(flags & ~SND_CLONE_MASK),
- ("invalid clone flags=0x%08x", flags));
-
- c->flags = flags;
-
- return (c->flags);
-}
-
-uint32_t
-snd_clone_getdevflags(struct cdev *dev)
-{
- struct snd_clone_entry *ce;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (0xffffffff);
-
- SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
-
- return (ce->flags);
-}
-
-uint32_t
-snd_clone_setdevflags(struct cdev *dev, uint32_t flags)
-{
- struct snd_clone_entry *ce;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
- SND_CLONE_ASSERT(!(flags & ~SND_CLONE_DEVMASK),
- ("invalid clone dev flags=0x%08x", flags));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (0xffffffff);
-
- SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
-
- ce->flags = flags;
-
- return (ce->flags);
-}
-
-/* Elapsed time conversion to ms */
-#define SND_CLONE_ELAPSED(x, y) \
- ((((x)->tv_sec - (y)->tv_sec) * 1000) + \
- (((y)->tv_nsec > (x)->tv_nsec) ? \
- (((1000000000L + (x)->tv_nsec - \
- (y)->tv_nsec) / 1000000) - 1000) : \
- (((x)->tv_nsec - (y)->tv_nsec) / 1000000)))
-
-#define SND_CLONE_EXPIRED(x, y, z) \
- ((x)->deadline < 1 || \
- ((y)->tv_sec - (z)->tv_sec) > ((x)->deadline / 1000) || \
- SND_CLONE_ELAPSED(y, z) > (x)->deadline)
-
-/*
- * snd_clone_gc() : Garbage collector for stalled, expired objects. Refer to
- * clone.h for explanations on GC settings.
- */
-int
-snd_clone_gc(struct snd_clone *c)
-{
- struct snd_clone_entry *ce, *tce;
- struct timespec now;
- int pruned;
-
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- if (!(c->flags & SND_CLONE_GC_ENABLE) || c->size == 0)
- return (0);
-
- getnanouptime(&now);
-
- /*
- * Bail out if the last clone handler was invoked below the deadline
- * threshold.
- */
- if ((c->flags & SND_CLONE_GC_EXPIRED) &&
- !SND_CLONE_EXPIRED(c, &now, &c->tsp))
- return (0);
-
- pruned = 0;
-
- /*
- * Visit each object in reverse order. If the object is still being
- * referenced by a valid open(), skip it. Look for expired objects
- * and either revoke its clone invocation status or mercilessly
- * throw it away.
- */
- TAILQ_FOREACH_REVERSE_SAFE(ce, &c->head, link_head, link, tce) {
- if (!(ce->flags & SND_CLONE_BUSY) &&
- (!(ce->flags & SND_CLONE_INVOKE) ||
- SND_CLONE_EXPIRED(c, &now, &ce->tsp))) {
- if ((c->flags & SND_CLONE_GC_REVOKE) ||
- ce->devt->si_threadcount != 0) {
- ce->flags &= ~SND_CLONE_INVOKE;
- ce->pid = -1;
- } else {
- TAILQ_REMOVE(&c->head, ce, link);
- destroy_dev(ce->devt);
- free(ce, M_DEVBUF);
- c->size--;
- }
- pruned++;
- }
- }
-
- /* return total pruned objects */
- return (pruned);
-}
-
-void
-snd_clone_destroy(struct snd_clone *c)
-{
- struct snd_clone_entry *ce, *tmp;
-
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
-
- ce = TAILQ_FIRST(&c->head);
- while (ce != NULL) {
- tmp = TAILQ_NEXT(ce, link);
- if (ce->devt != NULL)
- destroy_dev(ce->devt);
- free(ce, M_DEVBUF);
- ce = tmp;
- }
-
- free(c, M_DEVBUF);
-}
-
-/*
- * snd_clone_acquire() : The vital part of concurrency management. Must be
- * called somewhere at the beginning of open() handler. ENODEV is not really
- * fatal since it just tell the caller that this is not cloned stuff.
- * EBUSY is *real*, don't forget that!
- */
-int
-snd_clone_acquire(struct cdev *dev)
-{
- struct snd_clone_entry *ce;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (ENODEV);
-
- SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
-
- ce->flags &= ~SND_CLONE_INVOKE;
-
- if (ce->flags & SND_CLONE_BUSY)
- return (EBUSY);
-
- ce->flags |= SND_CLONE_BUSY;
-
- return (0);
-}
-
-/*
- * snd_clone_release() : Release busy status. Must be called somewhere at
- * the end of close() handler, or somewhere after fail open().
- */
-int
-snd_clone_release(struct cdev *dev)
-{
- struct snd_clone_entry *ce;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (ENODEV);
-
- SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
-
- ce->flags &= ~SND_CLONE_INVOKE;
-
- if (!(ce->flags & SND_CLONE_BUSY))
- return (EBADF);
-
- ce->flags &= ~SND_CLONE_BUSY;
- ce->pid = -1;
-
- return (0);
-}
-
-/*
- * snd_clone_ref/unref() : Garbage collector reference counter. To make
- * garbage collector run automatically, the sequence must be something like
- * this (both in open() and close() handlers):
- *
- * open() - 1) snd_clone_acquire()
- * 2) .... check check ... if failed, snd_clone_release()
- * 3) Success. Call snd_clone_ref()
- *
- * close() - 1) .... check check check ....
- * 2) Success. snd_clone_release()
- * 3) snd_clone_unref() . Garbage collector will run at this point
- * if this is the last referenced object.
- */
-int
-snd_clone_ref(struct cdev *dev)
-{
- struct snd_clone_entry *ce;
- struct snd_clone *c;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (0);
-
- c = ce->parent;
- SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
- SND_CLONE_ASSERT(c->refcount >= 0, ("refcount < 0"));
-
- return (++c->refcount);
-}
-
-int
-snd_clone_unref(struct cdev *dev)
-{
- struct snd_clone_entry *ce;
- struct snd_clone *c;
-
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
-
- ce = dev->si_drv2;
- if (ce == NULL)
- return (0);
-
- c = ce->parent;
- SND_CLONE_ASSERT(c != NULL, ("NULL parent"));
- SND_CLONE_ASSERT(c->refcount > 0, ("refcount <= 0"));
-
- c->refcount--;
-
- /*
- * Run automatic garbage collector, if needed.
- */
- if ((c->flags & SND_CLONE_GC_UNREF) &&
- (!(c->flags & SND_CLONE_GC_LASTREF) ||
- (c->refcount == 0 && (c->flags & SND_CLONE_GC_LASTREF))))
- (void)snd_clone_gc(c);
-
- return (c->refcount);
-}
-
-void
-snd_clone_register(struct snd_clone_entry *ce, struct cdev *dev)
-{
- SND_CLONE_ASSERT(ce != NULL, ("NULL snd_clone_entry"));
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev"));
- SND_CLONE_ASSERT(dev->si_drv2 == NULL, ("dev->si_drv2 not NULL"));
- SND_CLONE_ASSERT((ce->flags & SND_CLONE_ALLOC) == SND_CLONE_ALLOC,
- ("invalid clone alloc flags=0x%08x", ce->flags));
- SND_CLONE_ASSERT(ce->devt == NULL, ("ce->devt not NULL"));
- SND_CLONE_ASSERT(ce->unit == dev2unit(dev),
- ("invalid unit ce->unit=0x%08x dev2unit=0x%08x",
- ce->unit, dev2unit(dev)));
-
- SND_CLONE_ASSERT(ce->parent != NULL, ("NULL parent"));
-
- dev->si_drv2 = ce;
- ce->devt = dev;
- ce->flags &= ~SND_CLONE_ALLOC;
- ce->flags |= SND_CLONE_INVOKE;
-}
-
-struct snd_clone_entry *
-snd_clone_alloc(struct snd_clone *c, struct cdev **dev, int *unit, int tmask)
-{
- struct snd_clone_entry *ce, *after, *bce, *cce, *nce, *tce;
- struct timespec now;
- int cunit, allocunit;
- pid_t curpid;
-
- SND_CLONE_ASSERT(c != NULL, ("NULL snd_clone"));
- SND_CLONE_ASSERT(dev != NULL, ("NULL dev pointer"));
- SND_CLONE_ASSERT((c->typemask & tmask) == tmask,
- ("invalid tmask: typemask=0x%08x tmask=0x%08x",
- c->typemask, tmask));
- SND_CLONE_ASSERT(unit != NULL, ("NULL unit pointer"));
- SND_CLONE_ASSERT(*unit == -1 || !(*unit & (c->typemask | tmask)),
- ("typemask collision: typemask=0x%08x tmask=0x%08x *unit=%d",
- c->typemask, tmask, *unit));
-
- if (!(c->flags & SND_CLONE_ENABLE) ||
- (*unit != -1 && *unit > c->maxunit))
- return (NULL);
-
- ce = NULL;
- after = NULL;
- bce = NULL; /* "b"usy candidate */
- cce = NULL; /* "c"urthread/proc candidate */
- nce = NULL; /* "n"ull, totally unbusy candidate */
- tce = NULL; /* Last "t"ry candidate */
- cunit = 0;
- allocunit = (*unit == -1) ? 0 : *unit;
- curpid = curthread->td_proc->p_pid;
-
- getnanouptime(&now);
-
- TAILQ_FOREACH(ce, &c->head, link) {
- /*
- * Sort incrementally according to device type.
- */
- if (tmask > (ce->unit & c->typemask)) {
- if (cunit == 0)
- after = ce;
- continue;
- } else if (tmask < (ce->unit & c->typemask))
- break;
-
- /*
- * Shoot.. this is where the grumpiness begin. Just
- * return immediately.
- */
- if (*unit != -1 && *unit == (ce->unit & ~tmask))
- goto snd_clone_alloc_out;
-
- cunit++;
- /*
- * Simmilar device type. Sort incrementally according
- * to allocation unit. While here, look for free slot
- * and possible collision for new / future allocation.
- */
- if (*unit == -1 && (ce->unit & ~tmask) == allocunit)
- allocunit++;
- if ((ce->unit & ~tmask) < allocunit)
- after = ce;
- /*
- * Clone logic:
- * 1. Look for non busy, but keep track of the best
- * possible busy cdev.
- * 2. Look for the best (oldest referenced) entry that is
- * in a same process / thread.
- * 3. Look for the best (oldest referenced), absolute free
- * entry.
- * 4. Lastly, look for the best (oldest referenced)
- * any entries that doesn't fit with anything above.
- */
- if (ce->flags & SND_CLONE_BUSY) {
- if (ce->devt != NULL && (bce == NULL ||
- timespeccmp(&ce->tsp, &bce->tsp, <)))
- bce = ce;
- continue;
- }
- if (ce->pid == curpid &&
- (cce == NULL || timespeccmp(&ce->tsp, &cce->tsp, <)))
- cce = ce;
- else if (!(ce->flags & SND_CLONE_INVOKE) &&
- (nce == NULL || timespeccmp(&ce->tsp, &nce->tsp, <)))
- nce = ce;
- else if (tce == NULL || timespeccmp(&ce->tsp, &tce->tsp, <))
- tce = ce;
- }
- if (*unit != -1)
- goto snd_clone_alloc_new;
- else if (cce != NULL) {
- /* Same proc entry found, go for it */
- ce = cce;
- goto snd_clone_alloc_out;
- } else if (nce != NULL) {
- /*
- * Next, try absolute free entry. If the calculated
- * allocunit is smaller, create new entry instead.
- */
- if (allocunit < (nce->unit & ~tmask))
- goto snd_clone_alloc_new;
- ce = nce;
- goto snd_clone_alloc_out;
- } else if (allocunit > c->maxunit) {
- /*
- * Maximum allowable unit reached. Try returning any
- * available cdev and hope for the best. If the lookup is
- * done for things like stat(), mtime() etc. , things should
- * be ok. Otherwise, open() handler should do further checks
- * and decide whether to return correct error code or not.
- */
- if (tce != NULL) {
- ce = tce;
- goto snd_clone_alloc_out;
- } else if (bce != NULL) {
- ce = bce;
- goto snd_clone_alloc_out;
- }
- return (NULL);
- }
-
-snd_clone_alloc_new:
- /*
- * No free entries found, and we still haven't reached maximum
- * allowable units. Allocate, setup a minimal unique entry with busy
- * status so nobody will monkey on this new entry. Unit magic is set
- * right here to avoid collision with other contesting handler.
- * The caller must be carefull here to maintain its own
- * synchronization, as long as it will not conflict with malloc(9)
- * operations.
- *
- * That said, go figure.
- */
- ce = malloc(sizeof(*ce), M_DEVBUF,
- ((c->flags & SND_CLONE_WAITOK) ? M_WAITOK : M_NOWAIT) | M_ZERO);
- if (ce == NULL) {
- if (*unit != -1)
- return (NULL);
- /*
- * We're being dense, ignorance is bliss,
- * Super Regulatory Measure (TM).. TRY AGAIN!
- */
- if (nce != NULL) {
- ce = nce;
- goto snd_clone_alloc_out;
- } else if (tce != NULL) {
- ce = tce;
- goto snd_clone_alloc_out;
- } else if (bce != NULL) {
- ce = bce;
- goto snd_clone_alloc_out;
- }
- return (NULL);
- }
- /* Setup new entry */
- ce->parent = c;
- ce->unit = tmask | allocunit;
- ce->pid = curpid;
- ce->tsp = now;
- ce->flags |= SND_CLONE_ALLOC;
- if (after != NULL) {
- TAILQ_INSERT_AFTER(&c->head, after, ce, link);
- } else {
- TAILQ_INSERT_HEAD(&c->head, ce, link);
- }
- c->size++;
- c->tsp = now;
- /*
- * Save new allocation unit for caller which will be used
- * by make_dev().
- */
- *unit = allocunit;
-
- return (ce);
-
-snd_clone_alloc_out:
- /*
- * Set, mark, timestamp the entry if this is a truly free entry.
- * Leave busy entry alone.
- */
- if (!(ce->flags & SND_CLONE_BUSY)) {
- ce->pid = curpid;
- ce->tsp = now;
- ce->flags |= SND_CLONE_INVOKE;
- }
- c->tsp = now;
- *dev = ce->devt;
-
- return (NULL);
-}
diff --git a/sys/dev/sound/pcm/dsp.h b/sys/dev/sound/pcm/dsp.h
--- a/sys/dev/sound/pcm/dsp.h
+++ b/sys/dev/sound/pcm/dsp.h
@@ -33,12 +33,9 @@
extern struct cdevsw dsp_cdevsw;
-struct dsp_cdevinfo;
-
+int dsp_make_dev(device_t);
+void dsp_destroy_dev(device_t);
char *dsp_unit2name(char *, size_t, int);
int dsp_oss_audioinfo(struct cdev *, oss_audioinfo *);
-void dsp_cdevinfo_init(struct snddev_info *);
-void dsp_cdevinfo_flush(struct snddev_info *);
-
#endif /* !_PCMDSP_H_ */
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -37,12 +37,21 @@
#include <sys/lock.h>
#include <sys/rwlock.h>
#include <sys/sysent.h>
+#include <sys/sx.h>
#include <vm/vm.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pager.h>
+struct dsp_cdevpriv {
+ struct snddev_info *sc;
+ struct pcm_channel *rdch;
+ struct pcm_channel *wrch;
+ struct pcm_channel *volch;
+ int simplex;
+};
+
static int dsp_mmap_allow_prot_exec = 0;
SYSCTL_INT(_hw_snd, OID_AUTO, compat_linux_mmap, CTLFLAG_RWTUN,
&dsp_mmap_allow_prot_exec, 0,
@@ -53,27 +62,11 @@
&dsp_basename_clone, 0,
"DSP basename cloning (0: Disable; 1: Enabled)");
-struct dsp_cdevinfo {
- struct pcm_channel *rdch, *wrch;
- struct pcm_channel *volch;
- int busy, simplex;
- TAILQ_ENTRY(dsp_cdevinfo) link;
-};
-
-#define PCM_RDCH(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->rdch)
-#define PCM_WRCH(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->wrch)
-#define PCM_VOLCH(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->volch)
-#define PCM_SIMPLEX(x) (((struct dsp_cdevinfo *)(x)->si_drv1)->simplex)
-
-#define DSP_CDEVINFO_CACHESIZE 8
-
-#define DSP_REGISTERED(x, y) (PCM_REGISTERED(x) && \
- (y) != NULL && (y)->si_drv1 != NULL)
+#define DSP_REGISTERED(x, y) (PCM_REGISTERED(x) && (y) != NULL)
#define OLDPCM_IOCTL
static d_open_t dsp_open;
-static d_close_t dsp_close;
static d_read_t dsp_read;
static d_write_t dsp_write;
static d_ioctl_t dsp_ioctl;
@@ -84,7 +77,6 @@
struct cdevsw dsp_cdevsw = {
.d_version = D_VERSION,
.d_open = dsp_open,
- .d_close = dsp_close,
.d_read = dsp_read,
.d_write = dsp_write,
.d_ioctl = dsp_ioctl,
@@ -95,8 +87,6 @@
};
static eventhandler_tag dsp_ehtag = NULL;
-static int dsp_umax = -1;
-static int dsp_cmax = -1;
static int dsp_oss_syncgroup(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_syncgroup *group);
static int dsp_oss_syncstart(int sg_id);
@@ -113,12 +103,6 @@
static int dsp_oss_setname(struct pcm_channel *wrch, struct pcm_channel *rdch, oss_longname_t *name);
#endif
-static struct snddev_info *
-dsp_get_info(struct cdev *dev)
-{
- return (devclass_get_softc(pcm_devclass, PCMUNIT(dev)));
-}
-
static uint32_t
dsp_get_flags(struct cdev *dev)
{
@@ -140,22 +124,52 @@
pcm_setflags(bdev, flags);
}
-/*
- * return the channels associated with an open device instance.
- * lock channels specified.
- */
-static int
-getchns(struct cdev *dev, struct pcm_channel **rdch, struct pcm_channel **wrch,
- uint32_t prio)
+int
+dsp_make_dev(device_t dev)
+{
+ struct make_dev_args devargs;
+ struct snddev_info *sc;
+ int err, unit;
+
+ sc = device_get_softc(dev);
+ unit = device_get_unit(dev);
+
+ make_dev_args_init(&devargs);
+ devargs.mda_devsw = &dsp_cdevsw;
+ devargs.mda_uid = UID_ROOT;
+ devargs.mda_gid = GID_WHEEL;
+ devargs.mda_mode = 0600;
+ devargs.mda_si_drv1 = sc;
+ err = make_dev_s(&devargs, &sc->dsp_dev, "dsp%d", unit);
+ if (err != 0) {
+ device_printf(dev, "failed to create dsp%d", unit);
+ return (ENXIO);
+
+ }
+
+ return (0);
+}
+
+void
+dsp_destroy_dev(device_t dev)
+{
+ struct snddev_info *d;
+
+ d = device_get_softc(dev);
+ destroy_dev_sched(d->dsp_dev);
+}
+
+static void
+getchns(struct dsp_cdevpriv *priv, uint32_t prio)
{
struct snddev_info *d;
struct pcm_channel *ch;
uint32_t flags;
- if (PCM_SIMPLEX(dev) != 0) {
- d = dsp_get_info(dev);
+ if (priv->simplex) {
+ d = priv->sc;
if (!PCM_REGISTERED(d))
- return (ENXIO);
+ return;
PCM_LOCK(d);
PCM_WAIT(d);
PCM_ACQUIRE(d);
@@ -164,32 +178,25 @@
* pcm flags -> prio query flags -> wild guess
*/
ch = NULL;
- flags = dsp_get_flags(dev);
+ flags = dsp_get_flags(d->dsp_dev);
if (flags & SD_F_PRIO_WR) {
- ch = PCM_RDCH(dev);
- PCM_RDCH(dev) = NULL;
+ ch = priv->rdch;
} else if (flags & SD_F_PRIO_RD) {
- ch = PCM_WRCH(dev);
- PCM_WRCH(dev) = NULL;
+ ch = priv->wrch;
} else if (prio & SD_F_PRIO_WR) {
- ch = PCM_RDCH(dev);
- PCM_RDCH(dev) = NULL;
+ ch = priv->rdch;
flags |= SD_F_PRIO_WR;
} else if (prio & SD_F_PRIO_RD) {
- ch = PCM_WRCH(dev);
- PCM_WRCH(dev) = NULL;
+ ch = priv->wrch;
flags |= SD_F_PRIO_RD;
- } else if (PCM_WRCH(dev) != NULL) {
- ch = PCM_RDCH(dev);
- PCM_RDCH(dev) = NULL;
+ } else if (priv->wrch != NULL) {
+ ch = priv->rdch;
flags |= SD_F_PRIO_WR;
- } else if (PCM_RDCH(dev) != NULL) {
- ch = PCM_WRCH(dev);
- PCM_WRCH(dev) = NULL;
+ } else if (priv->rdch != NULL) {
+ ch = priv->wrch;
flags |= SD_F_PRIO_RD;
}
- PCM_SIMPLEX(dev) = 0;
- dsp_set_flags(dev, flags);
+ dsp_set_flags(d->dsp_dev, flags);
if (ch != NULL) {
CHN_LOCK(ch);
pcm_chnref(ch, -1);
@@ -199,166 +206,19 @@
PCM_UNLOCK(d);
}
- *rdch = PCM_RDCH(dev);
- *wrch = PCM_WRCH(dev);
-
- if (*rdch != NULL && (prio & SD_F_PRIO_RD))
- CHN_LOCK(*rdch);
- if (*wrch != NULL && (prio & SD_F_PRIO_WR))
- CHN_LOCK(*wrch);
-
- return (0);
-}
-
-/* unlock specified channels */
-static void
-relchns(struct cdev *dev, struct pcm_channel *rdch, struct pcm_channel *wrch,
- uint32_t prio)
-{
- if (wrch != NULL && (prio & SD_F_PRIO_WR))
- CHN_UNLOCK(wrch);
- if (rdch != NULL && (prio & SD_F_PRIO_RD))
- CHN_UNLOCK(rdch);
+ if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
+ CHN_LOCK(priv->rdch);
+ if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
+ CHN_LOCK(priv->wrch);
}
static void
-dsp_cdevinfo_alloc(struct cdev *dev,
- struct pcm_channel *rdch, struct pcm_channel *wrch,
- struct pcm_channel *volch)
+relchns(struct dsp_cdevpriv *priv, uint32_t prio)
{
- struct snddev_info *d;
- struct dsp_cdevinfo *cdi;
- int simplex;
-
- d = dsp_get_info(dev);
-
- KASSERT(PCM_REGISTERED(d) && dev != NULL && dev->si_drv1 == NULL &&
- ((rdch == NULL && wrch == NULL) || rdch != wrch),
- ("bogus %s(), what are you trying to accomplish here?", __func__));
- PCM_BUSYASSERT(d);
- PCM_LOCKASSERT(d);
-
- simplex = (dsp_get_flags(dev) & SD_F_SIMPLEX) ? 1 : 0;
-
- /*
- * Scan for free instance entry and put it into the end of list.
- * Create new one if necessary.
- */
- TAILQ_FOREACH(cdi, &d->dsp_cdevinfo_pool, link) {
- if (cdi->busy != 0)
- break;
- cdi->rdch = rdch;
- cdi->wrch = wrch;
- cdi->volch = volch;
- cdi->simplex = simplex;
- cdi->busy = 1;
- TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
- TAILQ_INSERT_TAIL(&d->dsp_cdevinfo_pool, cdi, link);
- dev->si_drv1 = cdi;
- return;
- }
- PCM_UNLOCK(d);
- cdi = malloc(sizeof(*cdi), M_DEVBUF, M_WAITOK | M_ZERO);
- PCM_LOCK(d);
- cdi->rdch = rdch;
- cdi->wrch = wrch;
- cdi->volch = volch;
- cdi->simplex = simplex;
- cdi->busy = 1;
- TAILQ_INSERT_TAIL(&d->dsp_cdevinfo_pool, cdi, link);
- dev->si_drv1 = cdi;
-}
-
-static void
-dsp_cdevinfo_free(struct cdev *dev)
-{
- struct snddev_info *d;
- struct dsp_cdevinfo *cdi, *tmp;
- uint32_t flags;
- int i;
-
- d = dsp_get_info(dev);
-
- KASSERT(PCM_REGISTERED(d) && dev != NULL && dev->si_drv1 != NULL &&
- PCM_RDCH(dev) == NULL && PCM_WRCH(dev) == NULL &&
- PCM_VOLCH(dev) == NULL,
- ("bogus %s(), what are you trying to accomplish here?", __func__));
- PCM_BUSYASSERT(d);
- PCM_LOCKASSERT(d);
-
- cdi = dev->si_drv1;
- dev->si_drv1 = NULL;
- cdi->rdch = NULL;
- cdi->wrch = NULL;
- cdi->volch = NULL;
- cdi->simplex = 0;
- cdi->busy = 0;
-
- /*
- * Once it is free, move it back to the beginning of list for
- * faster new entry allocation.
- */
- TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
- TAILQ_INSERT_HEAD(&d->dsp_cdevinfo_pool, cdi, link);
-
- /*
- * Scan the list, cache free entries up to DSP_CDEVINFO_CACHESIZE.
- * Reset simplex flags.
- */
- flags = dsp_get_flags(dev) & ~SD_F_PRIO_SET;
- i = DSP_CDEVINFO_CACHESIZE;
- TAILQ_FOREACH_SAFE(cdi, &d->dsp_cdevinfo_pool, link, tmp) {
- if (cdi->busy != 0) {
- if (cdi->simplex == 0) {
- if (cdi->rdch != NULL)
- flags |= SD_F_PRIO_RD;
- if (cdi->wrch != NULL)
- flags |= SD_F_PRIO_WR;
- }
- } else {
- if (i == 0) {
- TAILQ_REMOVE(&d->dsp_cdevinfo_pool, cdi, link);
- free(cdi, M_DEVBUF);
- } else
- i--;
- }
- }
- dsp_set_flags(dev, flags);
-}
-
-void
-dsp_cdevinfo_init(struct snddev_info *d)
-{
- struct dsp_cdevinfo *cdi;
- int i;
-
- KASSERT(d != NULL, ("NULL snddev_info"));
- PCM_BUSYASSERT(d);
- PCM_UNLOCKASSERT(d);
-
- TAILQ_INIT(&d->dsp_cdevinfo_pool);
- for (i = 0; i < DSP_CDEVINFO_CACHESIZE; i++) {
- cdi = malloc(sizeof(*cdi), M_DEVBUF, M_WAITOK | M_ZERO);
- TAILQ_INSERT_HEAD(&d->dsp_cdevinfo_pool, cdi, link);
- }
-}
-
-void
-dsp_cdevinfo_flush(struct snddev_info *d)
-{
- struct dsp_cdevinfo *cdi, *tmp;
-
- KASSERT(d != NULL, ("NULL snddev_info"));
- PCM_BUSYASSERT(d);
- PCM_UNLOCKASSERT(d);
-
- cdi = TAILQ_FIRST(&d->dsp_cdevinfo_pool);
- while (cdi != NULL) {
- tmp = TAILQ_NEXT(cdi, link);
- free(cdi, M_DEVBUF);
- cdi = tmp;
- }
- TAILQ_INIT(&d->dsp_cdevinfo_pool);
+ if (priv->rdch != NULL && (prio & SD_F_PRIO_RD))
+ CHN_UNLOCK(priv->rdch);
+ if (priv->wrch != NULL && (prio & SD_F_PRIO_WR))
+ CHN_UNLOCK(priv->wrch);
}
/* duplex / simplex cdev type */
@@ -368,12 +228,6 @@
DSP_CDEV_TYPE_RDWR /* duplex read, write, or both */
};
-enum {
- DSP_CDEV_VOLCTL_NONE,
- DSP_CDEV_VOLCTL_READ,
- DSP_CDEV_VOLCTL_WRITE
-};
-
#define DSP_F_VALID(x) ((x) & (FREAD | FWRITE))
#define DSP_F_DUPLEX(x) (((x) & (FREAD | FWRITE)) == (FREAD | FWRITE))
#define DSP_F_SIMPLEX(x) (!DSP_F_DUPLEX(x))
@@ -429,6 +283,110 @@
DSP_CDEV_TYPE_RDWR },
};
+static void
+dsp_close(void *data)
+{
+ struct dsp_cdevpriv *priv = data;
+ struct pcm_channel *rdch, *wrch, *volch;
+ struct snddev_info *d;
+ int sg_ids, rdref, wdref;
+
+ if (priv == NULL)
+ return;
+
+ d = priv->sc;
+ /* At this point pcm_unregister() will destroy all channels anyway. */
+ if (!PCM_REGISTERED(d))
+ goto skip;
+
+ PCM_GIANT_ENTER(d);
+
+ PCM_LOCK(d);
+ PCM_WAIT(d);
+ PCM_ACQUIRE(d);
+
+ rdch = priv->rdch;
+ wrch = priv->wrch;
+ volch = priv->volch;
+
+ rdref = -1;
+ wdref = -1;
+
+ if (volch != NULL) {
+ if (volch == rdch)
+ rdref--;
+ else if (volch == wrch)
+ wdref--;
+ else {
+ CHN_LOCK(volch);
+ pcm_chnref(volch, -1);
+ CHN_UNLOCK(volch);
+ }
+ }
+
+ if (rdch != NULL)
+ CHN_REMOVE(d, rdch, channels.pcm.opened);
+ if (wrch != NULL)
+ CHN_REMOVE(d, wrch, channels.pcm.opened);
+
+ if (rdch != NULL || wrch != NULL) {
+ PCM_UNLOCK(d);
+ if (rdch != NULL) {
+ /*
+ * The channel itself need not be locked because:
+ * a) Adding a channel to a syncgroup happens only
+ * in dsp_ioctl(), which cannot run concurrently
+ * to dsp_close().
+ * b) The syncmember pointer (sm) is protected by
+ * the global syncgroup list lock.
+ * c) A channel can't just disappear, invalidating
+ * pointers, unless it's closed/dereferenced
+ * first.
+ */
+ PCM_SG_LOCK();
+ sg_ids = chn_syncdestroy(rdch);
+ PCM_SG_UNLOCK();
+ if (sg_ids != 0)
+ free_unr(pcmsg_unrhdr, sg_ids);
+
+ CHN_LOCK(rdch);
+ pcm_chnref(rdch, rdref);
+ chn_abort(rdch); /* won't sleep */
+ rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
+ CHN_F_DEAD | CHN_F_EXCLUSIVE);
+ chn_reset(rdch, 0, 0);
+ pcm_chnrelease(rdch);
+ }
+ if (wrch != NULL) {
+ /*
+ * Please see block above.
+ */
+ PCM_SG_LOCK();
+ sg_ids = chn_syncdestroy(wrch);
+ PCM_SG_UNLOCK();
+ if (sg_ids != 0)
+ free_unr(pcmsg_unrhdr, sg_ids);
+
+ CHN_LOCK(wrch);
+ pcm_chnref(wrch, wdref);
+ chn_flush(wrch); /* may sleep */
+ wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
+ CHN_F_DEAD | CHN_F_EXCLUSIVE);
+ chn_reset(wrch, 0, 0);
+ pcm_chnrelease(wrch);
+ }
+ PCM_LOCK(d);
+ }
+
+ PCM_RELEASE(d);
+ PCM_UNLOCK(d);
+
+ PCM_GIANT_LEAVE(d);
+skip:
+ free(priv, M_DEVBUF);
+ priv = NULL;
+}
+
#define DSP_FIXUP_ERROR() do { \
prio = dsp_get_flags(i_dev); \
if (!DSP_F_VALID(flags)) \
@@ -441,49 +399,45 @@
((DSP_F_READ(flags) && (prio & SD_F_PRIO_WR)) || \
(DSP_F_WRITE(flags) && (prio & SD_F_PRIO_RD)))) \
error = EBUSY; \
- else if (DSP_REGISTERED(d, i_dev)) \
- error = EBUSY; \
} while (0)
static int
dsp_open(struct cdev *i_dev, int flags, int mode, struct thread *td)
{
+ struct dsp_cdevpriv *priv;
struct pcm_channel *rdch, *wrch;
struct snddev_info *d;
- uint32_t fmt, spd, prio, volctl;
- int i, error, rderror, wrerror, devtype, wdevunit, rdevunit;
+ uint32_t fmt, spd, prio;
+ int error, rderror, wrerror;
/* Kind of impossible.. */
if (i_dev == NULL || td == NULL)
return (ENODEV);
- d = dsp_get_info(i_dev);
+ d = i_dev->si_drv1;
if (PCM_DETACHING(d) || !PCM_REGISTERED(d))
return (EBADF);
+ priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK | M_ZERO);
+ priv->sc = d;
+ priv->rdch = NULL;
+ priv->wrch = NULL;
+ priv->volch = NULL;
+ priv->simplex = (dsp_get_flags(i_dev) & SD_F_SIMPLEX) ? 1 : 0;
+
+ error = devfs_set_cdevpriv(priv, dsp_close);
+ if (error != 0)
+ return (error);
+
PCM_GIANT_ENTER(d);
/* Lock snddev so nobody else can monkey with it. */
PCM_LOCK(d);
PCM_WAIT(d);
- /*
- * Try to acquire cloned device before someone else pick it.
- * ENODEV means this is not a cloned droids.
- */
- error = snd_clone_acquire(i_dev);
- if (!(error == 0 || error == ENODEV)) {
- DSP_FIXUP_ERROR();
- PCM_UNLOCK(d);
- PCM_GIANT_EXIT(d);
- return (error);
- }
-
error = 0;
DSP_FIXUP_ERROR();
-
if (error != 0) {
- (void)snd_clone_release(i_dev);
PCM_UNLOCK(d);
PCM_GIANT_EXIT(d);
return (error);
@@ -497,105 +451,38 @@
PCM_ACQUIRE(d);
PCM_UNLOCK(d);
- devtype = PCMDEV(i_dev);
- wdevunit = -1;
- rdevunit = -1;
- fmt = 0;
- spd = 0;
- volctl = DSP_CDEV_VOLCTL_NONE;
-
- for (i = 0; i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
- if (devtype != dsp_cdevs[i].type || dsp_cdevs[i].alias != NULL)
- continue;
- /*
- * Volume control only valid for DSPHW devices,
- * and it must be opened in opposite direction be it
- * simplex or duplex. Anything else will be handled
- * as usual.
- */
- if (dsp_cdevs[i].query == DSP_CDEV_TYPE_WRONLY) {
- if (dsp_cdevs[i].volctl != 0 &&
- DSP_F_READ(flags)) {
- volctl = DSP_CDEV_VOLCTL_WRITE;
- flags &= ~FREAD;
- flags |= FWRITE;
- }
- if (DSP_F_READ(flags)) {
- (void)snd_clone_release(i_dev);
- PCM_RELEASE_QUICK(d);
- PCM_GIANT_EXIT(d);
- return (ENOTSUP);
- }
- wdevunit = dev2unit(i_dev);
- } else if (dsp_cdevs[i].query == DSP_CDEV_TYPE_RDONLY) {
- if (dsp_cdevs[i].volctl != 0 &&
- DSP_F_WRITE(flags)) {
- volctl = DSP_CDEV_VOLCTL_READ;
- flags &= ~FWRITE;
- flags |= FREAD;
- }
- if (DSP_F_WRITE(flags)) {
- (void)snd_clone_release(i_dev);
- PCM_RELEASE_QUICK(d);
- PCM_GIANT_EXIT(d);
- return (ENOTSUP);
- }
- rdevunit = dev2unit(i_dev);
- }
- fmt = dsp_cdevs[i].fmt;
- spd = dsp_cdevs[i].spd;
- break;
- }
-
- /* No matching devtype? */
- if (fmt == 0 || spd == 0)
- panic("impossible devtype %d", devtype);
+ fmt = SND_FORMAT(AFMT_U8, 1, 0);
+ spd = DSP_DEFAULT_SPEED;
rdch = NULL;
wrch = NULL;
rderror = 0;
wrerror = 0;
- /*
- * if we get here, the open request is valid- either:
- * * we were previously not open
- * * we were open for play xor record and the opener wants
- * the non-open direction
- */
if (DSP_F_READ(flags)) {
/* open for read */
rderror = pcm_chnalloc(d, &rdch, PCMDIR_REC,
- td->td_proc->p_pid, td->td_proc->p_comm, rdevunit);
+ td->td_proc->p_pid, td->td_proc->p_comm, -1);
if (rderror == 0 && chn_reset(rdch, fmt, spd) != 0)
rderror = ENXIO;
- if (volctl == DSP_CDEV_VOLCTL_READ)
- rderror = 0;
-
if (rderror != 0) {
if (rdch != NULL)
pcm_chnrelease(rdch);
if (!DSP_F_DUPLEX(flags)) {
- (void)snd_clone_release(i_dev);
PCM_RELEASE_QUICK(d);
PCM_GIANT_EXIT(d);
return (rderror);
}
rdch = NULL;
- } else if (volctl == DSP_CDEV_VOLCTL_READ) {
- if (rdch != NULL) {
- pcm_chnref(rdch, 1);
- pcm_chnrelease(rdch);
- }
} else {
if (flags & O_NONBLOCK)
rdch->flags |= CHN_F_NBIO;
if (flags & O_EXCL)
rdch->flags |= CHN_F_EXCLUSIVE;
pcm_chnref(rdch, 1);
- if (volctl == DSP_CDEV_VOLCTL_NONE)
- chn_vpc_reset(rdch, SND_VOL_C_PCM, 0);
+ chn_vpc_reset(rdch, SND_VOL_C_PCM, 0);
CHN_UNLOCK(rdch);
}
}
@@ -603,14 +490,11 @@
if (DSP_F_WRITE(flags)) {
/* open for write */
wrerror = pcm_chnalloc(d, &wrch, PCMDIR_PLAY,
- td->td_proc->p_pid, td->td_proc->p_comm, wdevunit);
+ td->td_proc->p_pid, td->td_proc->p_comm, -1);
if (wrerror == 0 && chn_reset(wrch, fmt, spd) != 0)
wrerror = ENXIO;
- if (volctl == DSP_CDEV_VOLCTL_WRITE)
- wrerror = 0;
-
if (wrerror != 0) {
if (wrch != NULL)
pcm_chnrelease(wrch);
@@ -624,186 +508,40 @@
pcm_chnref(rdch, -1);
pcm_chnrelease(rdch);
}
- (void)snd_clone_release(i_dev);
PCM_RELEASE_QUICK(d);
PCM_GIANT_EXIT(d);
return (wrerror);
}
wrch = NULL;
- } else if (volctl == DSP_CDEV_VOLCTL_WRITE) {
- if (wrch != NULL) {
- pcm_chnref(wrch, 1);
- pcm_chnrelease(wrch);
- }
} else {
if (flags & O_NONBLOCK)
wrch->flags |= CHN_F_NBIO;
if (flags & O_EXCL)
wrch->flags |= CHN_F_EXCLUSIVE;
pcm_chnref(wrch, 1);
- if (volctl == DSP_CDEV_VOLCTL_NONE)
- chn_vpc_reset(wrch, SND_VOL_C_PCM, 0);
+ chn_vpc_reset(wrch, SND_VOL_C_PCM, 0);
CHN_UNLOCK(wrch);
}
}
PCM_LOCK(d);
- /*
- * We're done. Allocate channels information for this cdev.
- */
- switch (volctl) {
- case DSP_CDEV_VOLCTL_READ:
- KASSERT(wrch == NULL, ("wrch=%p not null!", wrch));
- dsp_cdevinfo_alloc(i_dev, NULL, NULL, rdch);
- break;
- case DSP_CDEV_VOLCTL_WRITE:
- KASSERT(rdch == NULL, ("rdch=%p not null!", rdch));
- dsp_cdevinfo_alloc(i_dev, NULL, NULL, wrch);
- break;
- case DSP_CDEV_VOLCTL_NONE:
- default:
- if (wrch == NULL && rdch == NULL) {
- (void)snd_clone_release(i_dev);
- PCM_RELEASE(d);
- PCM_UNLOCK(d);
- PCM_GIANT_EXIT(d);
- if (wrerror != 0)
- return (wrerror);
- if (rderror != 0)
- return (rderror);
- return (EINVAL);
- }
- dsp_cdevinfo_alloc(i_dev, rdch, wrch, NULL);
- if (rdch != NULL)
- CHN_INSERT_HEAD(d, rdch, channels.pcm.opened);
- if (wrch != NULL)
- CHN_INSERT_HEAD(d, wrch, channels.pcm.opened);
- break;
- }
-
- /*
- * Increase clone refcount for its automatic garbage collector.
- */
- (void)snd_clone_ref(i_dev);
-
- PCM_RELEASE(d);
- PCM_UNLOCK(d);
-
- PCM_GIANT_LEAVE(d);
-
- return (0);
-}
-
-static int
-dsp_close(struct cdev *i_dev, int flags, int mode, struct thread *td)
-{
- struct pcm_channel *rdch, *wrch, *volch;
- struct snddev_info *d;
- int sg_ids, rdref, wdref;
-
- d = dsp_get_info(i_dev);
- if (!DSP_REGISTERED(d, i_dev))
- return (EBADF);
-
- PCM_GIANT_ENTER(d);
-
- PCM_LOCK(d);
- PCM_WAIT(d);
- PCM_ACQUIRE(d);
-
- rdch = PCM_RDCH(i_dev);
- wrch = PCM_WRCH(i_dev);
- volch = PCM_VOLCH(i_dev);
-
- PCM_RDCH(i_dev) = NULL;
- PCM_WRCH(i_dev) = NULL;
- PCM_VOLCH(i_dev) = NULL;
-
- rdref = -1;
- wdref = -1;
-
- if (volch != NULL) {
- if (volch == rdch)
- rdref--;
- else if (volch == wrch)
- wdref--;
- else {
- CHN_LOCK(volch);
- pcm_chnref(volch, -1);
- CHN_UNLOCK(volch);
- }
+ if (wrch == NULL && rdch == NULL) {
+ PCM_RELEASE(d);
+ PCM_UNLOCK(d);
+ PCM_GIANT_EXIT(d);
+ if (wrerror != 0)
+ return (wrerror);
+ if (rderror != 0)
+ return (rderror);
+ return (EINVAL);
}
-
if (rdch != NULL)
- CHN_REMOVE(d, rdch, channels.pcm.opened);
+ CHN_INSERT_HEAD(d, rdch, channels.pcm.opened);
if (wrch != NULL)
- CHN_REMOVE(d, wrch, channels.pcm.opened);
-
- if (rdch != NULL || wrch != NULL) {
- PCM_UNLOCK(d);
- if (rdch != NULL) {
- /*
- * The channel itself need not be locked because:
- * a) Adding a channel to a syncgroup happens only
- * in dsp_ioctl(), which cannot run concurrently
- * to dsp_close().
- * b) The syncmember pointer (sm) is protected by
- * the global syncgroup list lock.
- * c) A channel can't just disappear, invalidating
- * pointers, unless it's closed/dereferenced
- * first.
- */
- PCM_SG_LOCK();
- sg_ids = chn_syncdestroy(rdch);
- PCM_SG_UNLOCK();
- if (sg_ids != 0)
- free_unr(pcmsg_unrhdr, sg_ids);
-
- CHN_LOCK(rdch);
- pcm_chnref(rdch, rdref);
- chn_abort(rdch); /* won't sleep */
- rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
- CHN_F_DEAD | CHN_F_EXCLUSIVE);
- chn_reset(rdch, 0, 0);
- pcm_chnrelease(rdch);
- }
- if (wrch != NULL) {
- /*
- * Please see block above.
- */
- PCM_SG_LOCK();
- sg_ids = chn_syncdestroy(wrch);
- PCM_SG_UNLOCK();
- if (sg_ids != 0)
- free_unr(pcmsg_unrhdr, sg_ids);
-
- CHN_LOCK(wrch);
- pcm_chnref(wrch, wdref);
- chn_flush(wrch); /* may sleep */
- wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MMAP |
- CHN_F_DEAD | CHN_F_EXCLUSIVE);
- chn_reset(wrch, 0, 0);
- pcm_chnrelease(wrch);
- }
- PCM_LOCK(d);
- }
-
- dsp_cdevinfo_free(i_dev);
- /*
- * Release clone busy state and unref it so the automatic
- * garbage collector will get the hint and do the remaining
- * cleanup process.
- */
- (void)snd_clone_release(i_dev);
-
- /*
- * destroy_dev() might sleep, so release pcm lock
- * here and rely on pcm cv serialization.
- */
- PCM_UNLOCK(d);
- (void)snd_clone_unref(i_dev);
- PCM_LOCK(d);
+ CHN_INSERT_HEAD(d, wrch, channels.pcm.opened);
+ priv->rdch = rdch;
+ priv->wrch = wrch;
PCM_RELEASE(d);
PCM_UNLOCK(d);
@@ -814,20 +552,20 @@
}
static __inline int
-dsp_io_ops(struct cdev *i_dev, struct uio *buf)
+dsp_io_ops(struct dsp_cdevpriv *priv, struct uio *buf)
{
struct snddev_info *d;
- struct pcm_channel **ch, *rdch, *wrch;
+ struct pcm_channel **ch;
int (*chn_io)(struct pcm_channel *, struct uio *);
int prio, ret;
pid_t runpid;
- KASSERT(i_dev != NULL && buf != NULL &&
+ KASSERT(priv != NULL && buf != NULL &&
(buf->uio_rw == UIO_READ || buf->uio_rw == UIO_WRITE),
("%s(): io train wreck!", __func__));
- d = dsp_get_info(i_dev);
- if (PCM_DETACHING(d) || !DSP_REGISTERED(d, i_dev))
+ d = priv->sc;
+ if (PCM_DETACHING(d) || !DSP_REGISTERED(d, d->dsp_dev))
return (EBADF);
PCM_GIANT_ENTER(d);
@@ -835,12 +573,12 @@
switch (buf->uio_rw) {
case UIO_READ:
prio = SD_F_PRIO_RD;
- ch = &rdch;
+ ch = &priv->rdch;
chn_io = chn_read;
break;
case UIO_WRITE:
prio = SD_F_PRIO_WR;
- ch = &wrch;
+ ch = &priv->wrch;
chn_io = chn_write;
break;
default:
@@ -848,22 +586,20 @@
break;
}
- rdch = NULL;
- wrch = NULL;
runpid = buf->uio_td->td_proc->p_pid;
- getchns(i_dev, &rdch, &wrch, prio);
+ getchns(priv, prio);
if (*ch == NULL || !((*ch)->flags & CHN_F_BUSY)) {
- if (rdch != NULL || wrch != NULL)
- relchns(i_dev, rdch, wrch, prio);
+ if (priv->rdch != NULL || priv->wrch != NULL)
+ relchns(priv, prio);
PCM_GIANT_EXIT(d);
return (EBADF);
}
if (((*ch)->flags & (CHN_F_MMAP | CHN_F_DEAD)) ||
(((*ch)->flags & CHN_F_RUNNING) && (*ch)->pid != runpid)) {
- relchns(i_dev, rdch, wrch, prio);
+ relchns(priv, prio);
PCM_GIANT_EXIT(d);
return (EINVAL);
} else if (!((*ch)->flags & CHN_F_RUNNING)) {
@@ -882,7 +618,7 @@
CHN_BROADCAST(&(*ch)->cv);
- relchns(i_dev, rdch, wrch, prio);
+ relchns(priv, prio);
PCM_GIANT_LEAVE(d);
@@ -892,26 +628,36 @@
static int
dsp_read(struct cdev *i_dev, struct uio *buf, int flag)
{
- return (dsp_io_ops(i_dev, buf));
+ struct dsp_cdevpriv *priv;
+ int err;
+
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ return (dsp_io_ops(priv, buf));
}
static int
dsp_write(struct cdev *i_dev, struct uio *buf, int flag)
{
- return (dsp_io_ops(i_dev, buf));
+ struct dsp_cdevpriv *priv;
+ int err;
+
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ return (dsp_io_ops(priv, buf));
}
static int
-dsp_get_volume_channel(struct cdev *dev, struct pcm_channel **volch)
+dsp_get_volume_channel(struct dsp_cdevpriv *priv, struct pcm_channel **volch)
{
struct snddev_info *d;
struct pcm_channel *c;
int unit;
- KASSERT(dev != NULL && volch != NULL,
- ("%s(): NULL query dev=%p volch=%p", __func__, dev, volch));
+ KASSERT(priv != NULL && volch != NULL,
+ ("%s(): NULL query priv=%p volch=%p", __func__, priv, volch));
- d = dsp_get_info(dev);
+ d = priv->sc;
if (!PCM_REGISTERED(d)) {
*volch = NULL;
return (EINVAL);
@@ -921,7 +667,7 @@
*volch = NULL;
- c = PCM_VOLCH(dev);
+ c = priv->volch;
if (c != NULL) {
if (!(c->feederflags & (1 << FEEDER_VOLUME)))
return (-1);
@@ -933,7 +679,7 @@
PCM_WAIT(d);
PCM_ACQUIRE(d);
- unit = dev2unit(dev);
+ unit = dev2unit(d->dsp_dev);
CHN_FOREACH(c, d, channels.pcm) {
CHN_LOCK(c);
@@ -943,7 +689,7 @@
}
*volch = c;
pcm_chnref(c, 1);
- PCM_VOLCH(dev) = c;
+ priv->volch = c;
CHN_UNLOCK(c);
PCM_RELEASE(d);
PCM_UNLOCK(d);
@@ -957,28 +703,28 @@
}
static int
-dsp_ioctl_channel(struct cdev *dev, struct pcm_channel *volch, u_long cmd,
- caddr_t arg)
+dsp_ioctl_channel(struct dsp_cdevpriv *priv, struct pcm_channel *volch,
+ u_long cmd, caddr_t arg)
{
struct snddev_info *d;
struct pcm_channel *rdch, *wrch;
int j, devtype, ret;
int left, right, center, mute;
- d = dsp_get_info(dev);
- if (!PCM_REGISTERED(d) || !(dsp_get_flags(dev) & SD_F_VPC))
+ d = priv->sc;
+ if (!PCM_REGISTERED(d) || !(dsp_get_flags(d->dsp_dev) & SD_F_VPC))
return (-1);
PCM_UNLOCKASSERT(d);
j = cmd & 0xff;
- rdch = PCM_RDCH(dev);
- wrch = PCM_WRCH(dev);
+ rdch = priv->rdch;
+ wrch = priv->wrch;
/* No specific channel, look into cache */
if (volch == NULL)
- volch = PCM_VOLCH(dev);
+ volch = priv->volch;
/* Look harder */
if (volch == NULL) {
@@ -988,13 +734,13 @@
volch = wrch;
}
- devtype = PCMDEV(dev);
+ devtype = PCMDEV(d->dsp_dev);
/* Look super harder */
if (volch == NULL &&
(devtype == SND_DEV_DSPHW_PLAY || devtype == SND_DEV_DSPHW_VPLAY ||
devtype == SND_DEV_DSPHW_REC || devtype == SND_DEV_DSPHW_VREC)) {
- ret = dsp_get_volume_channel(dev, &volch);
+ ret = dsp_get_volume_channel(priv, &volch);
if (ret != 0)
return (ret);
if (volch == NULL)
@@ -1097,13 +843,17 @@
dsp_ioctl(struct cdev *i_dev, u_long cmd, caddr_t arg, int mode,
struct thread *td)
{
+ struct dsp_cdevpriv *priv;
struct pcm_channel *chn, *rdch, *wrch;
struct snddev_info *d;
u_long xcmd;
- int *arg_i, ret, tmp;
+ int *arg_i, ret, tmp, err;
- d = dsp_get_info(i_dev);
- if (PCM_DETACHING(d) || !DSP_REGISTERED(d, i_dev))
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+
+ d = priv->sc;
+ if (PCM_DETACHING(d) || !DSP_REGISTERED(d, d->dsp_dev))
return (EBADF);
PCM_GIANT_ENTER(d);
@@ -1119,7 +869,7 @@
PCM_GIANT_EXIT(d);
return (0);
}
- ret = dsp_ioctl_channel(i_dev, PCM_VOLCH(i_dev), cmd, arg);
+ ret = dsp_ioctl_channel(priv, priv->volch, cmd, arg);
if (ret != -1) {
PCM_GIANT_EXIT(d);
return (ret);
@@ -1167,7 +917,9 @@
return (ret);
}
- getchns(i_dev, &rdch, &wrch, 0);
+ getchns(priv, 0);
+ rdch = priv->rdch;
+ wrch = priv->wrch;
if (wrch != NULL && (wrch->flags & CHN_F_DEAD))
wrch = NULL;
@@ -1870,7 +1622,7 @@
chn = wrch;
}
- ret = dsp_ioctl_channel(i_dev, chn, xcmd, arg);
+ ret = dsp_ioctl_channel(priv, chn, xcmd, arg);
if (ret != -1) {
PCM_GIANT_EXIT(d);
return (ret);
@@ -2204,23 +1956,26 @@
static int
dsp_poll(struct cdev *i_dev, int events, struct thread *td)
{
+ struct dsp_cdevpriv *priv;
struct snddev_info *d;
struct pcm_channel *wrch, *rdch;
- int ret, e;
+ int ret, e, err;
- d = dsp_get_info(i_dev);
- if (PCM_DETACHING(d) || !DSP_REGISTERED(d, i_dev)) {
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ d = priv->sc;
+ if (PCM_DETACHING(d) || !DSP_REGISTERED(d, d->dsp_dev)) {
/* XXX many clients don't understand POLLNVAL */
return (events & (POLLHUP | POLLPRI | POLLIN |
POLLRDNORM | POLLOUT | POLLWRNORM));
}
PCM_GIANT_ENTER(d);
- wrch = NULL;
- rdch = NULL;
ret = 0;
- getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ wrch = priv->wrch;
+ rdch = priv->rdch;
if (wrch != NULL && !(wrch->flags & CHN_F_DEAD)) {
e = (events & (POLLOUT | POLLWRNORM));
@@ -2234,7 +1989,7 @@
ret |= chn_poll(rdch, e, td);
}
- relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
PCM_GIANT_LEAVE(d);
@@ -2258,8 +2013,10 @@
dsp_mmap_single(struct cdev *i_dev, vm_ooffset_t *offset,
vm_size_t size, struct vm_object **object, int nprot)
{
+ struct dsp_cdevpriv *priv;
struct snddev_info *d;
struct pcm_channel *wrch, *rdch, *c;
+ int err;
/*
* Reject PROT_EXEC by default. It just doesn't makes sense.
@@ -2286,20 +2043,24 @@
if ((nprot & (PROT_READ | PROT_WRITE)) == 0)
return (EINVAL);
- d = dsp_get_info(i_dev);
- if (PCM_DETACHING(d) || !DSP_REGISTERED(d, i_dev))
+ if ((err = devfs_get_cdevpriv((void **)&priv)) != 0)
+ return (err);
+ d = priv->sc;
+ if (PCM_DETACHING(d) || !DSP_REGISTERED(d, d->dsp_dev))
return (EINVAL);
PCM_GIANT_ENTER(d);
- getchns(i_dev, &rdch, &wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ getchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ wrch = priv->wrch;
+ rdch = priv->rdch;
c = ((nprot & PROT_WRITE) != 0) ? wrch : rdch;
if (c == NULL || (c->flags & CHN_F_MMAP_INVALID) ||
(*offset + size) > sndbuf_getallocsize(c->bufsoft) ||
(wrch != NULL && (wrch->flags & CHN_F_MMAP_INVALID)) ||
(rdch != NULL && (rdch->flags & CHN_F_MMAP_INVALID))) {
- relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
PCM_GIANT_EXIT(d);
return (EINVAL);
}
@@ -2310,7 +2071,7 @@
rdch->flags |= CHN_F_MMAP;
*offset = (uintptr_t)sndbuf_getbufofs(c->bufsoft, *offset);
- relchns(i_dev, rdch, wrch, SD_F_PRIO_RD | SD_F_PRIO_WR);
+ relchns(priv, SD_F_PRIO_RD | SD_F_PRIO_WR);
*object = vm_pager_allocate(OBJT_DEVICE, i_dev,
size, nprot, *offset, curthread->td_ucred);
@@ -2321,194 +2082,21 @@
return (0);
}
-/* So much for dev_stdclone() */
-static int
-dsp_stdclone(char *name, char *namep, char *sep, int use_sep, int *u, int *c)
-{
- size_t len;
-
- len = strlen(namep);
- if (strncmp(name, namep, len) != 0)
- return (ENODEV);
-
- name += len;
-
- if (isdigit(*name) == 0)
- return (ENODEV);
-
- len = strlen(sep);
-
- if (*name == '0' && !(name[1] == '\0' || bcmp(name + 1, sep, len) == 0))
- return (ENODEV);
-
- for (*u = 0; isdigit(*name) != 0; name++) {
- *u *= 10;
- *u += *name - '0';
- if (*u > dsp_umax)
- return (ENODEV);
- }
-
- if (*name == '\0')
- return ((use_sep == 0) ? 0 : ENODEV);
-
- if (bcmp(name, sep, len) != 0 || isdigit(name[len]) == 0)
- return (ENODEV);
-
- name += len;
-
- if (*name == '0' && name[1] != '\0')
- return (ENODEV);
-
- for (*c = 0; isdigit(*name) != 0; name++) {
- *c *= 10;
- *c += *name - '0';
- if (*c > dsp_cmax)
- return (ENODEV);
- }
-
- if (*name != '\0')
- return (ENODEV);
-
- return (0);
-}
-
static void
-dsp_clone(void *arg,
- struct ucred *cred,
- char *name, int namelen, struct cdev **dev)
+dsp_clone(void *arg, struct ucred *cred, char *name, int namelen,
+ struct cdev **dev)
{
struct snddev_info *d;
- struct snd_clone_entry *ce;
- struct pcm_channel *c;
- int i, unit, udcmask, cunit, devtype, devhw, devcmax, tumax;
- char *devname, *devcmp, *devsep;
-
- KASSERT(dsp_umax >= 0 && dsp_cmax >= 0, ("Uninitialized unit!"));
if (*dev != NULL)
return;
-
- unit = -1;
- cunit = -1;
- devtype = -1;
- devhw = 0;
- devcmax = -1;
- tumax = -1;
- devname = NULL;
- devsep = NULL;
-
- for (i = 0; unit == -1 &&
- i < (sizeof(dsp_cdevs) / sizeof(dsp_cdevs[0])); i++) {
- devtype = dsp_cdevs[i].type;
- devcmp = dsp_cdevs[i].name;
- devsep = dsp_cdevs[i].sep;
- devname = dsp_cdevs[i].alias;
- if (devname == NULL)
- devname = devcmp;
- devhw = dsp_cdevs[i].hw;
- devcmax = dsp_cdevs[i].max - 1;
- if (strcmp(name, devcmp) == 0) {
- if (dsp_basename_clone != 0)
- unit = snd_unit;
- } else if (dsp_stdclone(name, devcmp, devsep,
- dsp_cdevs[i].use_sep, &unit, &cunit) != 0) {
- unit = -1;
- cunit = -1;
- }
- }
-
- d = devclass_get_softc(pcm_devclass, unit);
- if (!PCM_REGISTERED(d) || d->clones == NULL)
- return;
-
- /* XXX Need Giant magic entry ??? */
-
- PCM_LOCK(d);
- if (snd_clone_disabled(d->clones)) {
- PCM_UNLOCK(d);
- return;
- }
-
- PCM_WAIT(d);
- PCM_ACQUIRE(d);
- PCM_UNLOCK(d);
-
- udcmask = snd_u2unit(unit) | snd_d2unit(devtype);
-
- if (devhw != 0) {
- KASSERT(devcmax <= dsp_cmax,
- ("overflow: devcmax=%d, dsp_cmax=%d", devcmax, dsp_cmax));
- if (cunit > devcmax) {
- PCM_RELEASE_QUICK(d);
+ if (strcmp(name, "dsp") == 0 && dsp_basename_clone) {
+ d = devclass_get_softc(pcm_devclass, snd_unit);
+ if (!PCM_REGISTERED(d))
return;
- }
- udcmask |= snd_c2unit(cunit);
- CHN_FOREACH(c, d, channels.pcm) {
- CHN_LOCK(c);
- if (c->unit != udcmask) {
- CHN_UNLOCK(c);
- continue;
- }
- CHN_UNLOCK(c);
- udcmask &= ~snd_c2unit(cunit);
- /*
- * Temporarily increase clone maxunit to overcome
- * vchan flexibility.
- *
- * # sysctl dev.pcm.0.play.vchans=256
- * dev.pcm.0.play.vchans: 1 -> 256
- * # cat /dev/zero > /dev/dsp0.vp255 &
- * [1] 17296
- * # sysctl dev.pcm.0.play.vchans=0
- * dev.pcm.0.play.vchans: 256 -> 1
- * # fg
- * [1] + running cat /dev/zero > /dev/dsp0.vp255
- * ^C
- * # cat /dev/zero > /dev/dsp0.vp255
- * zsh: operation not supported: /dev/dsp0.vp255
- */
- tumax = snd_clone_getmaxunit(d->clones);
- if (cunit > tumax)
- snd_clone_setmaxunit(d->clones, cunit);
- else
- tumax = -1;
- goto dsp_clone_alloc;
- }
- /*
- * Ok, so we're requesting unallocated vchan, but still
- * within maximum vchan limit.
- */
- if (((devtype == SND_DEV_DSPHW_VPLAY && d->pvchancount > 0) ||
- (devtype == SND_DEV_DSPHW_VREC && d->rvchancount > 0)) &&
- cunit < snd_maxautovchans) {
- udcmask &= ~snd_c2unit(cunit);
- tumax = snd_clone_getmaxunit(d->clones);
- if (cunit > tumax)
- snd_clone_setmaxunit(d->clones, cunit);
- else
- tumax = -1;
- goto dsp_clone_alloc;
- }
- PCM_RELEASE_QUICK(d);
- return;
- }
-
-dsp_clone_alloc:
- ce = snd_clone_alloc(d->clones, dev, &cunit, udcmask);
- if (tumax != -1)
- snd_clone_setmaxunit(d->clones, tumax);
- if (ce != NULL) {
- udcmask |= snd_c2unit(cunit);
- *dev = make_dev(&dsp_cdevsw, PCMMINOR(udcmask),
- UID_ROOT, GID_WHEEL, 0666, "%s%d%s%d",
- devname, unit, devsep, cunit);
- snd_clone_register(ce, *dev);
- }
-
- PCM_RELEASE_QUICK(d);
-
- if (*dev != NULL)
+ *dev = d->dsp_dev;
dev_ref(*dev);
+ }
}
static void
@@ -2518,8 +2106,6 @@
return;
/* initialize unit numbering */
snd_unit_init();
- dsp_umax = PCMMAXUNIT;
- dsp_cmax = PCMMAXCHAN;
dsp_ehtag = EVENTHANDLER_REGISTER(dev_clone, dsp_clone, 0, 1000);
}
@@ -2556,6 +2142,19 @@
return (NULL);
}
+static int
+dsp_oss_audioinfo_cb(void *data, void *arg)
+{
+ struct dsp_cdevpriv *priv = data;
+ struct pcm_channel *ch = arg;
+
+ if (DSP_REGISTERED(priv->sc, priv->sc->dsp_dev) &&
+ (ch == priv->rdch || ch == priv->wrch))
+ return (1);
+
+ return (0);
+}
+
/**
* @brief Handler for SNDCTL_AUDIOINFO.
*
@@ -2631,9 +2230,8 @@
CHN_UNLOCKASSERT(ch);
CHN_LOCK(ch);
if (ai->dev == -1) {
- if (DSP_REGISTERED(d, i_dev) &&
- (ch == PCM_RDCH(i_dev) || /* record ch */
- ch == PCM_WRCH(i_dev))) { /* playback ch */
+ if (devfs_foreach_cdevpriv(i_dev,
+ dsp_oss_audioinfo_cb, ch) != 0) {
devname = dsp_unit2name(buf,
sizeof(buf), ch->unit);
}
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -88,7 +88,6 @@
#include <dev/sound/pcm/feeder.h>
#include <dev/sound/pcm/mixer.h>
#include <dev/sound/pcm/dsp.h>
-#include <dev/sound/clone.h>
#include <dev/sound/unit.h>
#define PCM_SOFTC_SIZE (sizeof(struct snddev_info))
@@ -374,8 +373,6 @@
} opened;
} pcm;
} channels;
- TAILQ_HEAD(dsp_cdevinfo_linkhead, dsp_cdevinfo) dsp_cdevinfo_pool;
- struct snd_clone *clones;
unsigned devcount, playcount, reccount, pvchancount, rvchancount ;
unsigned flags;
unsigned int bufsz;
@@ -384,6 +381,7 @@
char status[SND_STATUSLEN];
struct mtx *lock;
struct cdev *mixer_dev;
+ struct cdev *dsp_dev;
uint32_t pvchanrate, pvchanformat;
uint32_t rvchanrate, rvchanformat;
int32_t eqpreamp;
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -125,24 +125,6 @@
return bus_setup_intr(dev, res, flags, NULL, hand, param, cookiep);
}
-static void
-pcm_clonereset(struct snddev_info *d)
-{
- int cmax;
-
- PCM_BUSYASSERT(d);
-
- cmax = d->playcount + d->reccount - 1;
- if (d->pvchancount > 0)
- cmax += max(d->pvchancount, snd_maxautovchans) - 1;
- if (d->rvchancount > 0)
- cmax += max(d->rvchancount, snd_maxautovchans) - 1;
- if (cmax > PCMMAXCLONE)
- cmax = PCMMAXCLONE;
- (void)snd_clone_gc(d->clones);
- (void)snd_clone_setmaxunit(d->clones, cmax);
-}
-
int
pcm_setvchans(struct snddev_info *d, int direction, int newcnt, int num)
{
@@ -228,8 +210,6 @@
CHN_UNLOCK(ch);
if (err != 0)
return (err);
- else
- pcm_clonereset(d);
} else if (newcnt < vcnt) {
KASSERT(num == -1,
("bogus vchan_destroy() request num=%d", num));
@@ -260,7 +240,6 @@
CHN_UNLOCK(c);
break;
}
- pcm_clonereset(d);
}
return (0);
@@ -409,8 +388,6 @@
(void)pcm_setvchans(d, PCMDIR_REC, num, -1);
else if (num > 0 && d->rvchancount == 0)
(void)pcm_setvchans(d, PCMDIR_REC, 1, -1);
-
- pcm_clonereset(d);
}
static int
@@ -773,10 +750,6 @@
PCM_LOCK(d);
- /* Last stage, enable cloning. */
- if (d->clones != NULL)
- (void)snd_clone_enable(d->clones);
-
/* Done, we're ready.. */
d->flags |= SD_F_REGISTERED;
@@ -891,118 +864,6 @@
return (err);
}
-#ifdef SND_DEBUG
-static int
-sysctl_dev_pcm_clone_flags(SYSCTL_HANDLER_ARGS)
-{
- struct snddev_info *d;
- uint32_t flags;
- int err;
-
- d = oidp->oid_arg1;
- if (!PCM_REGISTERED(d) || d->clones == NULL)
- return (ENODEV);
-
- PCM_ACQUIRE_QUICK(d);
-
- flags = snd_clone_getflags(d->clones);
- err = sysctl_handle_int(oidp, &flags, 0, req);
-
- if (err == 0 && req->newptr != NULL) {
- if (flags & ~SND_CLONE_MASK)
- err = EINVAL;
- else
- (void)snd_clone_setflags(d->clones, flags);
- }
-
- PCM_RELEASE_QUICK(d);
-
- return (err);
-}
-
-static int
-sysctl_dev_pcm_clone_deadline(SYSCTL_HANDLER_ARGS)
-{
- struct snddev_info *d;
- int err, deadline;
-
- d = oidp->oid_arg1;
- if (!PCM_REGISTERED(d) || d->clones == NULL)
- return (ENODEV);
-
- PCM_ACQUIRE_QUICK(d);
-
- deadline = snd_clone_getdeadline(d->clones);
- err = sysctl_handle_int(oidp, &deadline, 0, req);
-
- if (err == 0 && req->newptr != NULL) {
- if (deadline < 0)
- err = EINVAL;
- else
- (void)snd_clone_setdeadline(d->clones, deadline);
- }
-
- PCM_RELEASE_QUICK(d);
-
- return (err);
-}
-
-static int
-sysctl_dev_pcm_clone_gc(SYSCTL_HANDLER_ARGS)
-{
- struct snddev_info *d;
- int err, val;
-
- d = oidp->oid_arg1;
- if (!PCM_REGISTERED(d) || d->clones == NULL)
- return (ENODEV);
-
- val = 0;
- err = sysctl_handle_int(oidp, &val, 0, req);
-
- if (err == 0 && req->newptr != NULL && val != 0) {
- PCM_ACQUIRE_QUICK(d);
- val = snd_clone_gc(d->clones);
- PCM_RELEASE_QUICK(d);
- if (bootverbose != 0 || snd_verbose > 3)
- device_printf(d->dev, "clone gc: pruned=%d\n", val);
- }
-
- return (err);
-}
-
-static int
-sysctl_hw_snd_clone_gc(SYSCTL_HANDLER_ARGS)
-{
- struct snddev_info *d;
- int i, err, val;
-
- val = 0;
- err = sysctl_handle_int(oidp, &val, 0, req);
-
- if (err == 0 && req->newptr != NULL && val != 0) {
- for (i = 0; pcm_devclass != NULL &&
- i < devclass_get_maxunit(pcm_devclass); i++) {
- d = devclass_get_softc(pcm_devclass, i);
- if (!PCM_REGISTERED(d) || d->clones == NULL)
- continue;
- PCM_ACQUIRE_QUICK(d);
- val = snd_clone_gc(d->clones);
- PCM_RELEASE_QUICK(d);
- if (bootverbose != 0 || snd_verbose > 3)
- device_printf(d->dev, "clone gc: pruned=%d\n",
- val);
- }
- }
-
- return (err);
-}
-SYSCTL_PROC(_hw_snd, OID_AUTO, clone_gc,
- CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_NEEDGIANT, 0, sizeof(int),
- sysctl_hw_snd_clone_gc, "I",
- "global clone garbage collector");
-#endif
-
static u_int8_t
pcm_mode_init(struct snddev_info *d)
{
@@ -1041,23 +902,6 @@
OID_AUTO, "mode", CTLFLAG_RD, NULL, mode,
"mode (1=mixer, 2=play, 4=rec. The values are OR'ed if more than one"
"mode is supported)");
-#ifdef SND_DEBUG
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "clone_flags", CTLTYPE_UINT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- d, sizeof(d), sysctl_dev_pcm_clone_flags, "IU",
- "clone flags");
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "clone_deadline", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE,
- d, sizeof(d), sysctl_dev_pcm_clone_deadline, "I",
- "clone expiration deadline (ms)");
- SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
- SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
- "clone_gc",
- CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, sizeof(d),
- sysctl_dev_pcm_clone_gc, "I", "clone garbage collector");
-#endif
if (d->flags & SD_F_AUTOVCHAN)
vchan_initsys(dev);
if (d->flags & SD_F_EQ)
@@ -1089,7 +933,6 @@
d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev");
cv_init(&d->cv, device_get_nameunit(dev));
PCM_ACQUIRE_QUICK(d);
- dsp_cdevinfo_init(d);
#if 0
/*
* d->flags should be cleared by the allocator of the softc.
@@ -1118,16 +961,6 @@
d->rvchanrate = 0;
d->rvchanformat = 0;
- /*
- * Create clone manager, disabled by default. Cloning will be
- * enabled during final stage of driver initialization through
- * pcm_setstatus().
- */
- d->clones = snd_clone_create(SND_U_MASK | SND_D_MASK, PCMMAXCLONE,
- SND_CLONE_DEADLINE_DEFAULT, SND_CLONE_WAITOK |
- SND_CLONE_GC_ENABLE | SND_CLONE_GC_UNREF |
- SND_CLONE_GC_LASTREF | SND_CLONE_GC_EXPIRED);
-
CHN_INIT(d, channels.pcm);
CHN_INIT(d, channels.pcm.busy);
CHN_INIT(d, channels.pcm.opened);
@@ -1150,7 +983,7 @@
sndstat_register(dev, d->status, sndstat_prepare_pcm);
- return 0;
+ return (dsp_make_dev(dev));
}
int
@@ -1187,23 +1020,11 @@
CHN_UNLOCK(ch);
}
- if (d->clones != NULL) {
- if (snd_clone_busy(d->clones) != 0) {
- device_printf(dev, "unregister: clone busy\n");
- PCM_RELEASE_QUICK(d);
- return (EBUSY);
- } else {
- PCM_LOCK(d);
- (void)snd_clone_disable(d->clones);
- PCM_UNLOCK(d);
- }
- }
+ dsp_destroy_dev(dev);
if (mixer_uninit(dev) == EBUSY) {
device_printf(dev, "unregister: mixer busy\n");
PCM_LOCK(d);
- if (d->clones != NULL)
- (void)snd_clone_enable(d->clones);
PCM_RELEASE(d);
PCM_UNLOCK(d);
return (EBUSY);
@@ -1217,15 +1038,6 @@
d->flags &= ~SD_F_REGISTERED;
PCM_UNLOCK(d);
- /*
- * No lock being held, so this thing can be flushed without
- * stucking into devdrn oblivion.
- */
- if (d->clones != NULL) {
- snd_clone_destroy(d->clones);
- d->clones = NULL;
- }
-
if (d->play_sysctl_tree != NULL) {
sysctl_ctx_free(&d->play_sysctl_ctx);
d->play_sysctl_tree = NULL;
@@ -1238,8 +1050,6 @@
while (!CHN_EMPTY(d, channels.pcm))
pcm_killchan(dev);
- dsp_cdevinfo_flush(d);
-
PCM_LOCK(d);
PCM_RELEASE(d);
cv_destroy(&d->cv);
diff --git a/sys/modules/sound/sound/Makefile b/sys/modules/sound/sound/Makefile
--- a/sys/modules/sound/sound/Makefile
+++ b/sys/modules/sound/sound/Makefile
@@ -16,7 +16,7 @@
SRCS+= feeder_eq_gen.h feeder_rate_gen.h snd_fxdiv_gen.h
SRCS+= mpu_if.h mpufoi_if.h synth_if.h
SRCS+= mpu_if.c mpufoi_if.c synth_if.c
-SRCS+= ac97.c ac97_patch.c buffer.c channel.c clone.c dsp.c
+SRCS+= ac97.c ac97_patch.c buffer.c channel.c dsp.c
SRCS+= mixer.c sndstat.c sound.c unit.c vchan.c
SRCS+= midi.c mpu401.c sequencer.c

File Metadata

Mime Type
text/plain
Expires
Fri, Oct 10, 2:10 AM (21 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
23514063
Default Alt Text
D44411.id136064.diff (67 KB)

Event Timeline