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 - * 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 - * 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 -#include -#include -#include -#include -#include - -#ifdef HAVE_KERNEL_OPTION_HEADERS -#include "opt_snd.h" -#endif - -#if defined(SND_DIAGNOSTIC) || defined(SND_DEBUG) -#include -#endif - -#include - -/* - * 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 @@ -43,6 +43,14 @@ #include #include +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 +61,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 +76,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 +86,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 +102,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 +123,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 +177,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 +205,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 +227,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 +282,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 +398,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 +450,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 +489,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 +507,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 +551,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 +572,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 +585,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 +617,7 @@ CHN_BROADCAST(&(*ch)->cv); - relchns(i_dev, rdch, wrch, prio); + relchns(priv, prio); PCM_GIANT_LEAVE(d); @@ -892,26 +627,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 +666,7 @@ *volch = NULL; - c = PCM_VOLCH(dev); + c = priv->volch; if (c != NULL) { if (!(c->feederflags & (1 << FEEDER_VOLUME))) return (-1); @@ -933,7 +678,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 +688,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 +702,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 +733,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 +842,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 +868,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 +916,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 +1621,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 +1955,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 +1988,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 +2012,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 +2042,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 +2070,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 +2081,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 +2105,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 +2141,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 +2229,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 #include #include -#include #include #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