1098ca2bdSWarner Losh /*- 23f225978SCameron Grant * Copyright (c) 1999 Cameron Grant <cg@freebsd.org> 3987e5972SCameron Grant * (C) 1997 Luigi Rizzo (luigi@iet.unipi.it) 4987e5972SCameron Grant * All rights reserved. 5987e5972SCameron Grant * 6987e5972SCameron Grant * Redistribution and use in source and binary forms, with or without 7987e5972SCameron Grant * modification, are permitted provided that the following conditions 8987e5972SCameron Grant * are met: 9987e5972SCameron Grant * 1. Redistributions of source code must retain the above copyright 10987e5972SCameron Grant * notice, this list of conditions and the following disclaimer. 11987e5972SCameron Grant * 2. Redistributions in binary form must reproduce the above copyright 12987e5972SCameron Grant * notice, this list of conditions and the following disclaimer in the 13987e5972SCameron Grant * documentation and/or other materials provided with the distribution. 14987e5972SCameron Grant * 15987e5972SCameron Grant * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16987e5972SCameron Grant * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17987e5972SCameron Grant * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18987e5972SCameron Grant * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19987e5972SCameron Grant * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20987e5972SCameron Grant * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21987e5972SCameron Grant * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22987e5972SCameron Grant * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23987e5972SCameron Grant * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24987e5972SCameron Grant * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25987e5972SCameron Grant * SUCH DAMAGE. 26987e5972SCameron Grant */ 27987e5972SCameron Grant 28ef9308b1SCameron Grant #include <dev/sound/pcm/sound.h> 29285648f9SCameron Grant #include <dev/sound/pcm/vchan.h> 305ee30e27SMathew Kanner #include <dev/sound/pcm/dsp.h> 317c438dbeSCameron Grant #include <sys/sysctl.h> 32285648f9SCameron Grant 3367b1dce3SCameron Grant #include "feeder_if.h" 3467b1dce3SCameron Grant 3567b1dce3SCameron Grant SND_DECLARE_FILE("$FreeBSD$"); 3667b1dce3SCameron Grant 37d95502a8SCameron Grant devclass_t pcm_devclass; 3882db23e2SCameron Grant 39b8a36395SCameron Grant int pcm_veto_load = 1; 40b8a36395SCameron Grant 4182db23e2SCameron Grant #ifdef USING_DEVFS 42d95502a8SCameron Grant int snd_unit = 0; 4309786698SPeter Wemm TUNABLE_INT("hw.snd.unit", &snd_unit); 4482db23e2SCameron Grant #endif 45cbe7d6a3SCameron Grant 4667b1dce3SCameron Grant int snd_maxautovchans = 0; 4767b1dce3SCameron Grant TUNABLE_INT("hw.snd.maxautovchans", &snd_maxautovchans); 48987e5972SCameron Grant 4982db23e2SCameron Grant SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver"); 5082db23e2SCameron Grant 5167b1dce3SCameron Grant static int sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose); 5267b1dce3SCameron Grant 5367b1dce3SCameron Grant struct sysctl_ctx_list * 5467b1dce3SCameron Grant snd_sysctl_tree(device_t dev) 5567b1dce3SCameron Grant { 5667b1dce3SCameron Grant struct snddev_info *d = device_get_softc(dev); 5767b1dce3SCameron Grant 5867b1dce3SCameron Grant return &d->sysctl_tree; 5967b1dce3SCameron Grant } 6067b1dce3SCameron Grant 6167b1dce3SCameron Grant struct sysctl_oid * 6267b1dce3SCameron Grant snd_sysctl_tree_top(device_t dev) 6367b1dce3SCameron Grant { 6467b1dce3SCameron Grant struct snddev_info *d = device_get_softc(dev); 6567b1dce3SCameron Grant 6667b1dce3SCameron Grant return d->sysctl_tree_top; 6767b1dce3SCameron Grant } 6867b1dce3SCameron Grant 6937209180SCameron Grant void * 702c69ba87SJohn Baldwin snd_mtxcreate(const char *desc, const char *type) 7137209180SCameron Grant { 7237209180SCameron Grant #ifdef USING_MUTEX 7337209180SCameron Grant struct mtx *m; 7437209180SCameron Grant 75a163d034SWarner Losh m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO); 7637209180SCameron Grant if (m == NULL) 7737209180SCameron Grant return NULL; 7812e524a2SDon Lewis mtx_init(m, desc, type, MTX_DEF); 7912e524a2SDon Lewis return m; 8012e524a2SDon Lewis #else 8112e524a2SDon Lewis return (void *)0xcafebabe; 8212e524a2SDon Lewis #endif 8312e524a2SDon Lewis } 8412e524a2SDon Lewis 8537209180SCameron Grant void 8637209180SCameron Grant snd_mtxfree(void *m) 8737209180SCameron Grant { 8837209180SCameron Grant #ifdef USING_MUTEX 8937209180SCameron Grant struct mtx *mtx = m; 9037209180SCameron Grant 9167beb5a5SCameron Grant /* mtx_assert(mtx, MA_OWNED); */ 9237209180SCameron Grant mtx_destroy(mtx); 9337209180SCameron Grant free(mtx, M_DEVBUF); 9437209180SCameron Grant #endif 9537209180SCameron Grant } 9637209180SCameron Grant 9737209180SCameron Grant void 9837209180SCameron Grant snd_mtxassert(void *m) 9937209180SCameron Grant { 10037209180SCameron Grant #ifdef USING_MUTEX 101f00f162aSCameron Grant #ifdef INVARIANTS 10237209180SCameron Grant struct mtx *mtx = m; 10337209180SCameron Grant 10437209180SCameron Grant mtx_assert(mtx, MA_OWNED); 10537209180SCameron Grant #endif 106f00f162aSCameron Grant #endif 10737209180SCameron Grant } 10867beb5a5SCameron Grant /* 10937209180SCameron Grant void 11037209180SCameron Grant snd_mtxlock(void *m) 11137209180SCameron Grant { 11237209180SCameron Grant #ifdef USING_MUTEX 11337209180SCameron Grant struct mtx *mtx = m; 11437209180SCameron Grant 11537209180SCameron Grant mtx_lock(mtx); 11637209180SCameron Grant #endif 11737209180SCameron Grant } 11837209180SCameron Grant 11937209180SCameron Grant void 12037209180SCameron Grant snd_mtxunlock(void *m) 12137209180SCameron Grant { 12237209180SCameron Grant #ifdef USING_MUTEX 12337209180SCameron Grant struct mtx *mtx = m; 12437209180SCameron Grant 12537209180SCameron Grant mtx_unlock(mtx); 12637209180SCameron Grant #endif 12737209180SCameron Grant } 12867beb5a5SCameron Grant */ 12937209180SCameron Grant int 13037209180SCameron Grant snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep) 13137209180SCameron Grant { 13237209180SCameron Grant #ifdef USING_MUTEX 13337209180SCameron Grant flags &= INTR_MPSAFE; 13446700f12SPeter Wemm flags |= INTR_TYPE_AV; 13537209180SCameron Grant #else 13646700f12SPeter Wemm flags = INTR_TYPE_AV; 13737209180SCameron Grant #endif 13837209180SCameron Grant return bus_setup_intr(dev, res, flags, hand, param, cookiep); 13937209180SCameron Grant } 14037209180SCameron Grant 141a527dbc7SCameron Grant #ifndef PCM_DEBUG_MTX 14267b1dce3SCameron Grant void 14367b1dce3SCameron Grant pcm_lock(struct snddev_info *d) 14467b1dce3SCameron Grant { 14567b1dce3SCameron Grant snd_mtxlock(d->lock); 14667b1dce3SCameron Grant } 14767b1dce3SCameron Grant 14867b1dce3SCameron Grant void 14967b1dce3SCameron Grant pcm_unlock(struct snddev_info *d) 15067b1dce3SCameron Grant { 15167b1dce3SCameron Grant snd_mtxunlock(d->lock); 15267b1dce3SCameron Grant } 153a527dbc7SCameron Grant #endif 15467b1dce3SCameron Grant 15567b1dce3SCameron Grant struct pcm_channel * 15667b1dce3SCameron Grant pcm_getfakechan(struct snddev_info *d) 15767b1dce3SCameron Grant { 15867b1dce3SCameron Grant return d->fakechan; 15967b1dce3SCameron Grant } 16067b1dce3SCameron Grant 1613fdb3676SAriff Abdullah /* return error status and a locked channel */ 1623fdb3676SAriff Abdullah int 1633fdb3676SAriff Abdullah pcm_chnalloc(struct snddev_info *d, struct pcm_channel **ch, int direction, 1643fdb3676SAriff Abdullah pid_t pid, int chnum) 165285648f9SCameron Grant { 166285648f9SCameron Grant struct pcm_channel *c; 167285648f9SCameron Grant struct snddev_channel *sce; 1683fdb3676SAriff Abdullah int err, ret; 169285648f9SCameron Grant 1703fdb3676SAriff Abdullah retry_chnalloc: 1713fdb3676SAriff Abdullah ret = ENODEV; 172f637a36cSCameron Grant /* scan for a free channel */ 173285648f9SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 174285648f9SCameron Grant c = sce->channel; 17549c5e6e2SCameron Grant CHN_LOCK(c); 176285648f9SCameron Grant if ((c->direction == direction) && !(c->flags & CHN_F_BUSY)) { 1773fdb3676SAriff Abdullah if (chnum < 0 || sce->chan_num == chnum) { 178285648f9SCameron Grant c->flags |= CHN_F_BUSY; 179b8f0d9e0SCameron Grant c->pid = pid; 1803fdb3676SAriff Abdullah *ch = c; 1813fdb3676SAriff Abdullah return 0; 182285648f9SCameron Grant } 183506a5308SCameron Grant } 1843fdb3676SAriff Abdullah if (sce->chan_num == chnum) { 1853fdb3676SAriff Abdullah if (c->direction != direction) 1863fdb3676SAriff Abdullah err = EOPNOTSUPP; 1873fdb3676SAriff Abdullah else if (c->flags & CHN_F_BUSY) 1883fdb3676SAriff Abdullah err = EBUSY; 1893fdb3676SAriff Abdullah else 1903fdb3676SAriff Abdullah err = EINVAL; 1913fdb3676SAriff Abdullah CHN_UNLOCK(c); 1923fdb3676SAriff Abdullah return err; 1933fdb3676SAriff Abdullah } else if (c->direction == direction && (c->flags & CHN_F_BUSY)) 1943fdb3676SAriff Abdullah ret = EBUSY; 19549c5e6e2SCameron Grant CHN_UNLOCK(c); 196285648f9SCameron Grant } 197f637a36cSCameron Grant 198f637a36cSCameron Grant /* no channel available */ 1993fdb3676SAriff Abdullah if (chnum == -1 && direction == PCMDIR_PLAY && d->vchancount > 0 && 2007982e7a4SAriff Abdullah d->vchancount < snd_maxautovchans && 2017982e7a4SAriff Abdullah d->devcount <= PCMMAXCHAN) { 202f637a36cSCameron Grant /* try to create a vchan */ 203f637a36cSCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 204f637a36cSCameron Grant c = sce->channel; 20512e524a2SDon Lewis CHN_LOCK(c); 20697d69a96SAlexander Leidinger if ((c->flags & CHN_F_HAS_VCHAN) && 20797d69a96SAlexander Leidinger !SLIST_EMPTY(&c->children)) { 208f637a36cSCameron Grant err = vchan_create(c); 20912e524a2SDon Lewis CHN_UNLOCK(c); 2103fdb3676SAriff Abdullah if (!err) { 2113fdb3676SAriff Abdullah chnum = -2; 2123fdb3676SAriff Abdullah goto retry_chnalloc; 2133fdb3676SAriff Abdullah } else 2143fdb3676SAriff Abdullah device_printf(d->dev, "%s: vchan_create(%s) == %d\n", __func__, c->name, err); 21512e524a2SDon Lewis } else 21612e524a2SDon Lewis CHN_UNLOCK(c); 217f637a36cSCameron Grant } 218f637a36cSCameron Grant } 219f637a36cSCameron Grant 2203fdb3676SAriff Abdullah return ret; 221285648f9SCameron Grant } 222285648f9SCameron Grant 223b8f0d9e0SCameron Grant /* release a locked channel and unlock it */ 224285648f9SCameron Grant int 225b8f0d9e0SCameron Grant pcm_chnrelease(struct pcm_channel *c) 226285648f9SCameron Grant { 227b8f0d9e0SCameron Grant CHN_LOCKASSERT(c); 228285648f9SCameron Grant c->flags &= ~CHN_F_BUSY; 229b8f0d9e0SCameron Grant c->pid = -1; 23049c5e6e2SCameron Grant CHN_UNLOCK(c); 231285648f9SCameron Grant return 0; 232285648f9SCameron Grant } 233285648f9SCameron Grant 234285648f9SCameron Grant int 235285648f9SCameron Grant pcm_chnref(struct pcm_channel *c, int ref) 236285648f9SCameron Grant { 23749c5e6e2SCameron Grant int r; 23849c5e6e2SCameron Grant 239b8f0d9e0SCameron Grant CHN_LOCKASSERT(c); 240285648f9SCameron Grant c->refcount += ref; 24149c5e6e2SCameron Grant r = c->refcount; 24249c5e6e2SCameron Grant return r; 243285648f9SCameron Grant } 244285648f9SCameron Grant 24567b1dce3SCameron Grant int 24667b1dce3SCameron Grant pcm_inprog(struct snddev_info *d, int delta) 24767b1dce3SCameron Grant { 248a527dbc7SCameron Grant int r; 249a527dbc7SCameron Grant 250a527dbc7SCameron Grant if (delta == 0) 25167b1dce3SCameron Grant return d->inprog; 252a527dbc7SCameron Grant 253a527dbc7SCameron Grant /* backtrace(); */ 254a527dbc7SCameron Grant pcm_lock(d); 255a527dbc7SCameron Grant d->inprog += delta; 256a527dbc7SCameron Grant r = d->inprog; 257a527dbc7SCameron Grant pcm_unlock(d); 258a527dbc7SCameron Grant return r; 25967b1dce3SCameron Grant } 26067b1dce3SCameron Grant 26167b1dce3SCameron Grant static void 26267b1dce3SCameron Grant pcm_setmaxautovchans(struct snddev_info *d, int num) 26367b1dce3SCameron Grant { 26497d69a96SAlexander Leidinger struct pcm_channel *c, *ch; 26567b1dce3SCameron Grant struct snddev_channel *sce; 26667b1dce3SCameron Grant int err, done; 26767b1dce3SCameron Grant 26897d69a96SAlexander Leidinger /* 26997d69a96SAlexander Leidinger * XXX WOAH... NEED SUPER CLEANUP!!! 27097d69a96SAlexander Leidinger * Robust, yet confusing. Understanding these will 27197d69a96SAlexander Leidinger * cause your brain spinning like a Doki Doki Dynamo. 27297d69a96SAlexander Leidinger */ 27367b1dce3SCameron Grant if (num > 0 && d->vchancount == 0) { 27467b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 27567b1dce3SCameron Grant c = sce->channel; 27612e524a2SDon Lewis CHN_LOCK(c); 27797d69a96SAlexander Leidinger if ((c->direction == PCMDIR_PLAY) && 2783fdb3676SAriff Abdullah (c->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == 0 && 27997d69a96SAlexander Leidinger SLIST_EMPTY(&c->children)) { 28067b1dce3SCameron Grant c->flags |= CHN_F_BUSY; 28167b1dce3SCameron Grant err = vchan_create(c); 28267b1dce3SCameron Grant if (err) { 28367b1dce3SCameron Grant c->flags &= ~CHN_F_BUSY; 2843fdb3676SAriff Abdullah device_printf(d->dev, "%s: vchan_create(%s) == %d\n", __func__, c->name, err); 2853fdb3676SAriff Abdullah } else { 28612e524a2SDon Lewis CHN_UNLOCK(c); 28767b1dce3SCameron Grant return; 28867b1dce3SCameron Grant } 2893fdb3676SAriff Abdullah } 29012e524a2SDon Lewis CHN_UNLOCK(c); 29167b1dce3SCameron Grant } 29297d69a96SAlexander Leidinger return; 29367b1dce3SCameron Grant } 29467b1dce3SCameron Grant if (num == 0 && d->vchancount > 0) { 29597d69a96SAlexander Leidinger /* 29697d69a96SAlexander Leidinger * XXX Keep retrying... 29797d69a96SAlexander Leidinger */ 29897d69a96SAlexander Leidinger for (done = 0; done < 1024; done++) { 29997d69a96SAlexander Leidinger ch = NULL; 30067b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 30167b1dce3SCameron Grant c = sce->channel; 30297d69a96SAlexander Leidinger CHN_LOCK(c); 30397d69a96SAlexander Leidinger if (c->direction == PCMDIR_PLAY && 30497d69a96SAlexander Leidinger !(c->flags & CHN_F_BUSY) && 30597d69a96SAlexander Leidinger (c->flags & CHN_F_VIRTUAL)) { 30697d69a96SAlexander Leidinger ch = c; 30797d69a96SAlexander Leidinger break; 30897d69a96SAlexander Leidinger } 30997d69a96SAlexander Leidinger CHN_UNLOCK(c); 31097d69a96SAlexander Leidinger } 31197d69a96SAlexander Leidinger if (ch != NULL) { 31297d69a96SAlexander Leidinger CHN_UNLOCK(ch); 313a527dbc7SCameron Grant snd_mtxlock(d->lock); 31497d69a96SAlexander Leidinger err = vchan_destroy(ch); 31567b1dce3SCameron Grant if (err) 31697d69a96SAlexander Leidinger device_printf(d->dev, "vchan_destroy(%s) == %d\n", 31797d69a96SAlexander Leidinger ch->name, err); 31897d69a96SAlexander Leidinger snd_mtxunlock(d->lock); 31997d69a96SAlexander Leidinger } else 32097d69a96SAlexander Leidinger return; 32167b1dce3SCameron Grant } 32297d69a96SAlexander Leidinger return; 32367b1dce3SCameron Grant } 32467b1dce3SCameron Grant } 32567b1dce3SCameron Grant 32682db23e2SCameron Grant #ifdef USING_DEVFS 32733dbf14aSCameron Grant static int 328cd9766c5SCameron Grant sysctl_hw_snd_unit(SYSCTL_HANDLER_ARGS) 32933dbf14aSCameron Grant { 330b8f0d9e0SCameron Grant struct snddev_info *d; 33133dbf14aSCameron Grant int error, unit; 33233dbf14aSCameron Grant 33333dbf14aSCameron Grant unit = snd_unit; 33433dbf14aSCameron Grant error = sysctl_handle_int(oidp, &unit, sizeof(unit), req); 33533dbf14aSCameron Grant if (error == 0 && req->newptr != NULL) { 33674ffd138SCameron Grant if (unit < 0 || unit >= devclass_get_maxunit(pcm_devclass)) 337b8f0d9e0SCameron Grant return EINVAL; 338b8f0d9e0SCameron Grant d = devclass_get_softc(pcm_devclass, unit); 339faeebea2SCameron Grant if (d == NULL || SLIST_EMPTY(&d->channels)) 340b8f0d9e0SCameron Grant return EINVAL; 34133dbf14aSCameron Grant snd_unit = unit; 34233dbf14aSCameron Grant } 34333dbf14aSCameron Grant return (error); 34433dbf14aSCameron Grant } 345b3b7ccfeSJohn Baldwin SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW, 346cd9766c5SCameron Grant 0, sizeof(int), sysctl_hw_snd_unit, "I", ""); 34782db23e2SCameron Grant #endif 348987e5972SCameron Grant 349cd9766c5SCameron Grant static int 35067b1dce3SCameron Grant sysctl_hw_snd_maxautovchans(SYSCTL_HANDLER_ARGS) 351cd9766c5SCameron Grant { 35267b1dce3SCameron Grant struct snddev_info *d; 35367b1dce3SCameron Grant int i, v, error; 354cd9766c5SCameron Grant 35567b1dce3SCameron Grant v = snd_maxautovchans; 356cd9766c5SCameron Grant error = sysctl_handle_int(oidp, &v, sizeof(v), req); 357cd9766c5SCameron Grant if (error == 0 && req->newptr != NULL) { 3583fdb3676SAriff Abdullah if (v < 0 || v > (PCMMAXCHAN + 1)) 359cd9766c5SCameron Grant return EINVAL; 3603fdb3676SAriff Abdullah if (pcm_devclass != NULL && v != snd_maxautovchans) { 36167b1dce3SCameron Grant for (i = 0; i < devclass_get_maxunit(pcm_devclass); i++) { 36267b1dce3SCameron Grant d = devclass_get_softc(pcm_devclass, i); 36367b1dce3SCameron Grant if (!d) 36467b1dce3SCameron Grant continue; 36597d69a96SAlexander Leidinger if (d->flags & SD_F_AUTOVCHAN) { 36697d69a96SAlexander Leidinger if (pcm_inprog(d, 1) == 1) 36767b1dce3SCameron Grant pcm_setmaxautovchans(d, v); 36897d69a96SAlexander Leidinger pcm_inprog(d, -1); 36997d69a96SAlexander Leidinger } 37067b1dce3SCameron Grant } 37167b1dce3SCameron Grant } 37267b1dce3SCameron Grant snd_maxautovchans = v; 373cd9766c5SCameron Grant } 374cd9766c5SCameron Grant return (error); 375cd9766c5SCameron Grant } 37667b1dce3SCameron Grant SYSCTL_PROC(_hw_snd, OID_AUTO, maxautovchans, CTLTYPE_INT | CTLFLAG_RW, 37767b1dce3SCameron Grant 0, sizeof(int), sysctl_hw_snd_maxautovchans, "I", ""); 378f637a36cSCameron Grant 379285648f9SCameron Grant struct pcm_channel * 380285648f9SCameron Grant pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo) 381987e5972SCameron Grant { 3823fdb3676SAriff Abdullah struct snddev_channel *sce; 3833fdb3676SAriff Abdullah struct pcm_channel *ch, *tmpch; 38433dbf14aSCameron Grant char *dirs; 3853fdb3676SAriff Abdullah u_int32_t flsearch = 0; 3863fdb3676SAriff Abdullah int direction, err, rpnum, *pnum; 387987e5972SCameron Grant 388285648f9SCameron Grant switch(dir) { 389285648f9SCameron Grant case PCMDIR_PLAY: 390285648f9SCameron Grant dirs = "play"; 391a3193a9cSDon Lewis direction = PCMDIR_PLAY; 392a67fe5c1SCameron Grant pnum = &d->playcount; 393285648f9SCameron Grant break; 394a67fe5c1SCameron Grant 395285648f9SCameron Grant case PCMDIR_REC: 396285648f9SCameron Grant dirs = "record"; 397a3193a9cSDon Lewis direction = PCMDIR_REC; 398a67fe5c1SCameron Grant pnum = &d->reccount; 399285648f9SCameron Grant break; 400a67fe5c1SCameron Grant 401285648f9SCameron Grant case PCMDIR_VIRTUAL: 402285648f9SCameron Grant dirs = "virtual"; 403a3193a9cSDon Lewis direction = PCMDIR_PLAY; 404a67fe5c1SCameron Grant pnum = &d->vchancount; 4053fdb3676SAriff Abdullah flsearch = CHN_F_VIRTUAL; 406285648f9SCameron Grant break; 407a67fe5c1SCameron Grant 408285648f9SCameron Grant default: 409285648f9SCameron Grant return NULL; 4109c326820SCameron Grant } 411285648f9SCameron Grant 412a163d034SWarner Losh ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO); 413285648f9SCameron Grant if (!ch) 414285648f9SCameron Grant return NULL; 415285648f9SCameron Grant 416a163d034SWarner Losh ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK); 417285648f9SCameron Grant if (!ch->methods) { 418285648f9SCameron Grant free(ch, M_DEVBUF); 419a67fe5c1SCameron Grant 420285648f9SCameron Grant return NULL; 421285648f9SCameron Grant } 422285648f9SCameron Grant 42367beb5a5SCameron Grant snd_mtxlock(d->lock); 4243fdb3676SAriff Abdullah ch->num = 0; 4253fdb3676SAriff Abdullah rpnum = 0; 4263fdb3676SAriff Abdullah SLIST_FOREACH(sce, &d->channels, link) { 4273fdb3676SAriff Abdullah if (sce == NULL || sce->channel == NULL) 4283fdb3676SAriff Abdullah continue; 4293fdb3676SAriff Abdullah tmpch = sce->channel; 4303fdb3676SAriff Abdullah if (direction != tmpch->direction || 4313fdb3676SAriff Abdullah (tmpch->flags & CHN_F_VIRTUAL) != flsearch) 4323fdb3676SAriff Abdullah continue; 4333fdb3676SAriff Abdullah if (ch->num == tmpch->num) 4343fdb3676SAriff Abdullah ch->num++; 4353fdb3676SAriff Abdullah else { 4363fdb3676SAriff Abdullah /* 4373fdb3676SAriff Abdullah * Channel numbering screwed. Bail out, and do the 4383fdb3676SAriff Abdullah * hard way lookup. 4393fdb3676SAriff Abdullah */ 4403fdb3676SAriff Abdullah device_printf(d->dev, 4413fdb3676SAriff Abdullah "%s: channel numbering dirs=%s screwed.\n", 4423fdb3676SAriff Abdullah __func__, dirs); 4433fdb3676SAriff Abdullah ch->num = 0; 4443fdb3676SAriff Abdullah goto retry_num_search; 4453fdb3676SAriff Abdullah } 4463fdb3676SAriff Abdullah rpnum++; 4473fdb3676SAriff Abdullah } 4483fdb3676SAriff Abdullah goto retry_num_search_out; 4493fdb3676SAriff Abdullah retry_num_search: 4503fdb3676SAriff Abdullah rpnum = 0; 4513fdb3676SAriff Abdullah SLIST_FOREACH(sce, &d->channels, link) { 4523fdb3676SAriff Abdullah if (sce == NULL || sce->channel == NULL) 4533fdb3676SAriff Abdullah continue; 4543fdb3676SAriff Abdullah tmpch = sce->channel; 4553fdb3676SAriff Abdullah if (direction != tmpch->direction || 4563fdb3676SAriff Abdullah (tmpch->flags & CHN_F_VIRTUAL) != flsearch) 4573fdb3676SAriff Abdullah continue; 4583fdb3676SAriff Abdullah if (ch->num == tmpch->num) { 4593fdb3676SAriff Abdullah ch->num++; 4603fdb3676SAriff Abdullah goto retry_num_search; 4613fdb3676SAriff Abdullah } 4623fdb3676SAriff Abdullah rpnum++; 4633fdb3676SAriff Abdullah } 4643fdb3676SAriff Abdullah retry_num_search_out: 4653fdb3676SAriff Abdullah if (*pnum != rpnum) { 4663fdb3676SAriff Abdullah device_printf(d->dev, 4673fdb3676SAriff Abdullah "%s: pnum screwed : dirs=%s, pnum=%d, rpnum=%d\n", 4683fdb3676SAriff Abdullah __func__, dirs, *pnum, rpnum); 4693fdb3676SAriff Abdullah *pnum = rpnum; 4703fdb3676SAriff Abdullah } 4713fdb3676SAriff Abdullah (*pnum)++; 47267beb5a5SCameron Grant snd_mtxunlock(d->lock); 473a67fe5c1SCameron Grant 474285648f9SCameron Grant ch->pid = -1; 475285648f9SCameron Grant ch->parentsnddev = d; 476285648f9SCameron Grant ch->parentchannel = parent; 477436c9b65SScott Long ch->dev = d->dev; 4783fdb3676SAriff Abdullah snprintf(ch->name, CHN_NAMELEN, "%s:%s:%d", device_get_nameunit(ch->dev), dirs, ch->num); 479285648f9SCameron Grant 480a3193a9cSDon Lewis err = chn_init(ch, devinfo, dir, direction); 4810f55ac6cSCameron Grant if (err) { 482a67fe5c1SCameron Grant device_printf(d->dev, "chn_init(%s) failed: err = %d\n", ch->name, err); 483285648f9SCameron Grant kobj_delete(ch->methods, M_DEVBUF); 484285648f9SCameron Grant free(ch, M_DEVBUF); 48567beb5a5SCameron Grant snd_mtxlock(d->lock); 486a67fe5c1SCameron Grant (*pnum)--; 48767beb5a5SCameron Grant snd_mtxunlock(d->lock); 488a67fe5c1SCameron Grant 489285648f9SCameron Grant return NULL; 490bbb5bf3dSCameron Grant } 491285648f9SCameron Grant 492285648f9SCameron Grant return ch; 493285648f9SCameron Grant } 494285648f9SCameron Grant 495285648f9SCameron Grant int 496285648f9SCameron Grant pcm_chn_destroy(struct pcm_channel *ch) 497285648f9SCameron Grant { 498a67fe5c1SCameron Grant struct snddev_info *d; 499285648f9SCameron Grant int err; 500285648f9SCameron Grant 501a67fe5c1SCameron Grant d = ch->parentsnddev; 502285648f9SCameron Grant err = chn_kill(ch); 503285648f9SCameron Grant if (err) { 504a67fe5c1SCameron Grant device_printf(d->dev, "chn_kill(%s) failed, err = %d\n", ch->name, err); 505285648f9SCameron Grant return err; 506285648f9SCameron Grant } 507285648f9SCameron Grant 508285648f9SCameron Grant kobj_delete(ch->methods, M_DEVBUF); 509285648f9SCameron Grant free(ch, M_DEVBUF); 510285648f9SCameron Grant 511285648f9SCameron Grant return 0; 512285648f9SCameron Grant } 513285648f9SCameron Grant 514285648f9SCameron Grant int 5155ee30e27SMathew Kanner pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch) 516285648f9SCameron Grant { 51767b1dce3SCameron Grant struct snddev_channel *sce, *tmp, *after; 5183fdb3676SAriff Abdullah unsigned rdevcount; 5195ee30e27SMathew Kanner int device = device_get_unit(d->dev); 5203fdb3676SAriff Abdullah int stop; 5213fdb3676SAriff Abdullah size_t namelen; 5225ee30e27SMathew Kanner 5235ee30e27SMathew Kanner /* 5245ee30e27SMathew Kanner * Note it's confusing nomenclature. 5255ee30e27SMathew Kanner * dev_t 5265ee30e27SMathew Kanner * device -> pcm_device 5275ee30e27SMathew Kanner * unit -> pcm_channel 5285ee30e27SMathew Kanner * channel -> snddev_channel 5295ee30e27SMathew Kanner * device_t 5305ee30e27SMathew Kanner * unit -> pcm_device 5315ee30e27SMathew Kanner */ 532b8f0d9e0SCameron Grant 533a163d034SWarner Losh sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO); 534285648f9SCameron Grant if (!sce) { 535285648f9SCameron Grant return ENOMEM; 536285648f9SCameron Grant } 537285648f9SCameron Grant 5387cf0e77aSOrion Hodson snd_mtxlock(d->lock); 539285648f9SCameron Grant sce->channel = ch; 5407982e7a4SAriff Abdullah sce->chan_num = 0; 5413fdb3676SAriff Abdullah after = NULL; 5423fdb3676SAriff Abdullah stop = 0; 5433fdb3676SAriff Abdullah retry_chan_num_search: 5443fdb3676SAriff Abdullah /* 5453fdb3676SAriff Abdullah * Look for possible channel numbering collision. This may not 5463fdb3676SAriff Abdullah * be optimized, but it will ensure that no collision occured. 5473fdb3676SAriff Abdullah * Creating maximum possible channels (256 channels) will cost 5483fdb3676SAriff Abdullah * us at most 32895 cycles, but this can be considered cheap 5493fdb3676SAriff Abdullah * since none of the locking/unlocking operations involved. 5503fdb3676SAriff Abdullah * 5513fdb3676SAriff Abdullah * Micro optimization, channel ordering: 5523fdb3676SAriff Abdullah * hw,hw,hw,vch,vch,vch,rec 5533fdb3676SAriff Abdullah */ 5543fdb3676SAriff Abdullah rdevcount = 0; 5557982e7a4SAriff Abdullah SLIST_FOREACH(tmp, &d->channels, link) { 5563fdb3676SAriff Abdullah if (tmp == NULL || tmp->channel == NULL) 5577982e7a4SAriff Abdullah continue; 5587982e7a4SAriff Abdullah if (sce->chan_num == tmp->chan_num) { 5597982e7a4SAriff Abdullah sce->chan_num++; 5603fdb3676SAriff Abdullah after = NULL; 5613fdb3676SAriff Abdullah stop = 0; 5623fdb3676SAriff Abdullah goto retry_chan_num_search; 5637982e7a4SAriff Abdullah } 5643fdb3676SAriff Abdullah if (stop == 0) { 5653fdb3676SAriff Abdullah if (ch->flags & CHN_F_VIRTUAL) { 5663fdb3676SAriff Abdullah if (tmp->channel->direction == PCMDIR_REC) 5673fdb3676SAriff Abdullah stop = 1; 5683fdb3676SAriff Abdullah else 5693fdb3676SAriff Abdullah after = tmp; 5703fdb3676SAriff Abdullah } else if (ch->direction == PCMDIR_REC) { 5713fdb3676SAriff Abdullah after = tmp; 5723fdb3676SAriff Abdullah } else { 5733fdb3676SAriff Abdullah if (tmp->channel->direction != PCMDIR_PLAY || 5743fdb3676SAriff Abdullah (tmp->channel->flags & CHN_F_VIRTUAL)) { 5753fdb3676SAriff Abdullah stop = 1; 5763fdb3676SAriff Abdullah } else { 5773fdb3676SAriff Abdullah after = tmp; 5783fdb3676SAriff Abdullah } 5793fdb3676SAriff Abdullah } 5803fdb3676SAriff Abdullah } 5813fdb3676SAriff Abdullah rdevcount++; 5827982e7a4SAriff Abdullah } 5837982e7a4SAriff Abdullah /* 5847982e7a4SAriff Abdullah * Don't overflow PCMMKMINOR / PCMMAXCHAN. 5857982e7a4SAriff Abdullah */ 5867982e7a4SAriff Abdullah if (sce->chan_num > PCMMAXCHAN) { 5877982e7a4SAriff Abdullah snd_mtxunlock(d->lock); 5887982e7a4SAriff Abdullah device_printf(d->dev, 5897982e7a4SAriff Abdullah "%s: WARNING: sce->chan_num overflow! (%d)\n", 5907982e7a4SAriff Abdullah __func__, sce->chan_num); 5917982e7a4SAriff Abdullah free(sce, M_DEVBUF); 5927982e7a4SAriff Abdullah return E2BIG; 5937982e7a4SAriff Abdullah } 5943fdb3676SAriff Abdullah if (d->devcount != rdevcount) { 5953fdb3676SAriff Abdullah device_printf(d->dev, 5963fdb3676SAriff Abdullah "%s: WARNING: devcount screwed! d->devcount=%u, rdevcount=%u\n", 5973fdb3676SAriff Abdullah __func__, d->devcount, rdevcount); 5983fdb3676SAriff Abdullah d->devcount = rdevcount; 59997d69a96SAlexander Leidinger } 6003fdb3676SAriff Abdullah d->devcount++; 60197d69a96SAlexander Leidinger if (after == NULL) { 60297d69a96SAlexander Leidinger SLIST_INSERT_HEAD(&d->channels, sce, link); 60397d69a96SAlexander Leidinger } else { 60467b1dce3SCameron Grant SLIST_INSERT_AFTER(after, sce, link); 60567b1dce3SCameron Grant } 6063fdb3676SAriff Abdullah 6073fdb3676SAriff Abdullah namelen = strlen(ch->name); 6083fdb3676SAriff Abdullah if ((CHN_NAMELEN - namelen) > 10) { /* ":dspXX.YYY" */ 6093fdb3676SAriff Abdullah snprintf(ch->name + namelen, 6103fdb3676SAriff Abdullah CHN_NAMELEN - namelen, ":dsp%d.%d", 6113fdb3676SAriff Abdullah device, sce->chan_num); 61297d69a96SAlexander Leidinger } 61367beb5a5SCameron Grant snd_mtxunlock(d->lock); 6145ee30e27SMathew Kanner sce->dsp_devt = make_dev(&dsp_cdevsw, 6155ee30e27SMathew Kanner PCMMKMINOR(device, SND_DEV_DSP, sce->chan_num), 6165ee30e27SMathew Kanner UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", 6175ee30e27SMathew Kanner device, sce->chan_num); 618285648f9SCameron Grant 6195ee30e27SMathew Kanner sce->dspW_devt = make_dev(&dsp_cdevsw, 6205ee30e27SMathew Kanner PCMMKMINOR(device, SND_DEV_DSP16, sce->chan_num), 6215ee30e27SMathew Kanner UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", 6225ee30e27SMathew Kanner device, sce->chan_num); 6235ee30e27SMathew Kanner 6245ee30e27SMathew Kanner sce->audio_devt = make_dev(&dsp_cdevsw, 6255ee30e27SMathew Kanner PCMMKMINOR(device, SND_DEV_AUDIO, sce->chan_num), 6265ee30e27SMathew Kanner UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", 6275ee30e27SMathew Kanner device, sce->chan_num); 6285ee30e27SMathew Kanner 629506a5308SCameron Grant if (ch->direction == PCMDIR_REC) 6305ee30e27SMathew Kanner sce->dspr_devt = make_dev(&dsp_cdevsw, 6315ee30e27SMathew Kanner PCMMKMINOR(device, SND_DEV_DSPREC, 6325ee30e27SMathew Kanner sce->chan_num), UID_ROOT, GID_WHEEL, 6335ee30e27SMathew Kanner 0666, "dspr%d.%d", device, sce->chan_num); 634b8f0d9e0SCameron Grant 63533dbf14aSCameron Grant return 0; 63633dbf14aSCameron Grant } 63733dbf14aSCameron Grant 638285648f9SCameron Grant int 6395ee30e27SMathew Kanner pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch) 64033dbf14aSCameron Grant { 641285648f9SCameron Grant struct snddev_channel *sce; 64245550658SPoul-Henning Kamp #if 0 643a527dbc7SCameron Grant int ourlock; 64433dbf14aSCameron Grant 645a527dbc7SCameron Grant ourlock = 0; 646a527dbc7SCameron Grant if (!mtx_owned(d->lock)) { 64749c5e6e2SCameron Grant snd_mtxlock(d->lock); 648a527dbc7SCameron Grant ourlock = 1; 649a527dbc7SCameron Grant } 65045550658SPoul-Henning Kamp #endif 651a527dbc7SCameron Grant 652285648f9SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 653285648f9SCameron Grant if (sce->channel == ch) 654285648f9SCameron Grant goto gotit; 65533dbf14aSCameron Grant } 65645550658SPoul-Henning Kamp #if 0 657a527dbc7SCameron Grant if (ourlock) 65849c5e6e2SCameron Grant snd_mtxunlock(d->lock); 65945550658SPoul-Henning Kamp #endif 660285648f9SCameron Grant return EINVAL; 661285648f9SCameron Grant gotit: 662285648f9SCameron Grant SLIST_REMOVE(&d->channels, sce, snddev_channel, link); 66367beb5a5SCameron Grant 66497d69a96SAlexander Leidinger if (ch->flags & CHN_F_VIRTUAL) 66567beb5a5SCameron Grant d->vchancount--; 66697d69a96SAlexander Leidinger else if (ch->direction == PCMDIR_REC) 66797d69a96SAlexander Leidinger d->reccount--; 66867beb5a5SCameron Grant else 66967beb5a5SCameron Grant d->playcount--; 67067beb5a5SCameron Grant 67145550658SPoul-Henning Kamp #if 0 672a527dbc7SCameron Grant if (ourlock) 67349c5e6e2SCameron Grant snd_mtxunlock(d->lock); 67445550658SPoul-Henning Kamp #endif 67567beb5a5SCameron Grant free(sce, M_DEVBUF); 676285648f9SCameron Grant 677987e5972SCameron Grant return 0; 678987e5972SCameron Grant } 679987e5972SCameron Grant 680987e5972SCameron Grant int 681285648f9SCameron Grant pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo) 682285648f9SCameron Grant { 683285648f9SCameron Grant struct snddev_info *d = device_get_softc(dev); 68467b1dce3SCameron Grant struct pcm_channel *ch; 68567b1dce3SCameron Grant int err; 686285648f9SCameron Grant 687285648f9SCameron Grant ch = pcm_chn_create(d, NULL, cls, dir, devinfo); 688285648f9SCameron Grant if (!ch) { 689285648f9SCameron Grant device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo); 690285648f9SCameron Grant return ENODEV; 691285648f9SCameron Grant } 692cd9766c5SCameron Grant 6935ee30e27SMathew Kanner err = pcm_chn_add(d, ch); 694285648f9SCameron Grant if (err) { 695285648f9SCameron Grant device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err); 696285648f9SCameron Grant pcm_chn_destroy(ch); 697cd9766c5SCameron Grant return err; 698cd9766c5SCameron Grant } 699cd9766c5SCameron Grant 700285648f9SCameron Grant return err; 701285648f9SCameron Grant } 702285648f9SCameron Grant 703285648f9SCameron Grant static int 704285648f9SCameron Grant pcm_killchan(device_t dev) 705285648f9SCameron Grant { 706285648f9SCameron Grant struct snddev_info *d = device_get_softc(dev); 707285648f9SCameron Grant struct snddev_channel *sce; 708e33bee07SOlivier Houchard struct pcm_channel *ch; 709e33bee07SOlivier Houchard int error = 0; 710285648f9SCameron Grant 711285648f9SCameron Grant sce = SLIST_FIRST(&d->channels); 712e33bee07SOlivier Houchard ch = sce->channel; 713285648f9SCameron Grant 7145ee30e27SMathew Kanner error = pcm_chn_remove(d, sce->channel); 715e33bee07SOlivier Houchard if (error) 716e33bee07SOlivier Houchard return (error); 717e33bee07SOlivier Houchard return (pcm_chn_destroy(ch)); 718285648f9SCameron Grant } 719285648f9SCameron Grant 720285648f9SCameron Grant int 721987e5972SCameron Grant pcm_setstatus(device_t dev, char *str) 722987e5972SCameron Grant { 72366ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 7243fdb3676SAriff Abdullah struct snddev_channel *sce; 7253fdb3676SAriff Abdullah struct pcm_channel *ch; 7263fdb3676SAriff Abdullah int err; 72749c5e6e2SCameron Grant 72849c5e6e2SCameron Grant snd_mtxlock(d->lock); 729987e5972SCameron Grant strncpy(d->status, str, SND_STATUSLEN); 73049c5e6e2SCameron Grant snd_mtxunlock(d->lock); 7313fdb3676SAriff Abdullah if (snd_maxautovchans > 0 && (d->flags & SD_F_AUTOVCHAN) && 7323fdb3676SAriff Abdullah d->vchancount == 0) { 7333fdb3676SAriff Abdullah SLIST_FOREACH(sce, &d->channels, link) { 7343fdb3676SAriff Abdullah if (sce == NULL || sce->channel == NULL) 7353fdb3676SAriff Abdullah continue; 7363fdb3676SAriff Abdullah ch = sce->channel; 7373fdb3676SAriff Abdullah CHN_LOCK(ch); 7383fdb3676SAriff Abdullah if (ch->direction == PCMDIR_PLAY && 7393fdb3676SAriff Abdullah (ch->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == 0 && 7403fdb3676SAriff Abdullah SLIST_EMPTY(&ch->children)) { 7413fdb3676SAriff Abdullah ch->flags |= CHN_F_BUSY; 7423fdb3676SAriff Abdullah err = vchan_create(ch); 7433fdb3676SAriff Abdullah if (err) { 7443fdb3676SAriff Abdullah ch->flags &= ~CHN_F_BUSY; 7453fdb3676SAriff Abdullah device_printf(d->dev, "%s: vchan_create(%s) == %d\n", 7463fdb3676SAriff Abdullah __func__, ch->name, err); 7473fdb3676SAriff Abdullah } else { 7483fdb3676SAriff Abdullah CHN_UNLOCK(ch); 7493fdb3676SAriff Abdullah return 0; 7503fdb3676SAriff Abdullah } 7513fdb3676SAriff Abdullah } 7523fdb3676SAriff Abdullah CHN_UNLOCK(ch); 7533fdb3676SAriff Abdullah } 7543fdb3676SAriff Abdullah } 755987e5972SCameron Grant return 0; 756987e5972SCameron Grant } 757987e5972SCameron Grant 758987e5972SCameron Grant u_int32_t 759987e5972SCameron Grant pcm_getflags(device_t dev) 760987e5972SCameron Grant { 76166ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 76249c5e6e2SCameron Grant 763987e5972SCameron Grant return d->flags; 764987e5972SCameron Grant } 765987e5972SCameron Grant 766987e5972SCameron Grant void 767987e5972SCameron Grant pcm_setflags(device_t dev, u_int32_t val) 768987e5972SCameron Grant { 76966ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 770d95502a8SCameron Grant 771987e5972SCameron Grant d->flags = val; 772987e5972SCameron Grant } 773987e5972SCameron Grant 77439004e69SCameron Grant void * 77539004e69SCameron Grant pcm_getdevinfo(device_t dev) 77639004e69SCameron Grant { 77766ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 77849c5e6e2SCameron Grant 77939004e69SCameron Grant return d->devinfo; 78039004e69SCameron Grant } 78139004e69SCameron Grant 782a67fe5c1SCameron Grant unsigned int 783a67fe5c1SCameron Grant pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max) 784a67fe5c1SCameron Grant { 785a67fe5c1SCameron Grant struct snddev_info *d = device_get_softc(dev); 7864e60be34SCameron Grant int sz, x; 787a67fe5c1SCameron Grant 788a67fe5c1SCameron Grant sz = 0; 7894e60be34SCameron Grant if (resource_int_value(device_get_name(dev), device_get_unit(dev), "buffersize", &sz) == 0) { 7904e60be34SCameron Grant x = sz; 791a67fe5c1SCameron Grant RANGE(sz, min, max); 7924e60be34SCameron Grant if (x != sz) 7934e60be34SCameron Grant device_printf(dev, "'buffersize=%d' hint is out of range (%d-%d), using %d\n", x, min, max, sz); 7944e60be34SCameron Grant x = min; 7954e60be34SCameron Grant while (x < sz) 7964e60be34SCameron Grant x <<= 1; 7974e60be34SCameron Grant if (x > sz) 7984e60be34SCameron Grant x >>= 1; 7994e60be34SCameron Grant if (x != sz) { 8004e60be34SCameron Grant device_printf(dev, "'buffersize=%d' hint is not a power of 2, using %d\n", sz, x); 8014e60be34SCameron Grant sz = x; 8024e60be34SCameron Grant } 8034e60be34SCameron Grant } else { 804a67fe5c1SCameron Grant sz = deflt; 8054e60be34SCameron Grant } 8064e60be34SCameron Grant 807a67fe5c1SCameron Grant d->bufsz = sz; 808a67fe5c1SCameron Grant 809a67fe5c1SCameron Grant return sz; 810a67fe5c1SCameron Grant } 811a67fe5c1SCameron Grant 812987e5972SCameron Grant int 813987e5972SCameron Grant pcm_register(device_t dev, void *devinfo, int numplay, int numrec) 814987e5972SCameron Grant { 81566ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 816987e5972SCameron Grant 817b8a36395SCameron Grant if (pcm_veto_load) { 818b8a36395SCameron Grant device_printf(dev, "disabled due to an error while initialising: %d\n", pcm_veto_load); 819b8a36395SCameron Grant 820b8a36395SCameron Grant return EINVAL; 821b8a36395SCameron Grant } 822b8a36395SCameron Grant 8232c69ba87SJohn Baldwin d->lock = snd_mtxcreate(device_get_nameunit(dev), "sound cdev"); 824285648f9SCameron Grant 8257233ababSAlexander Leidinger #if 0 8267233ababSAlexander Leidinger /* 8277233ababSAlexander Leidinger * d->flags should be cleared by the allocator of the softc. 8287233ababSAlexander Leidinger * We cannot clear this field here because several devices set 8297233ababSAlexander Leidinger * this flag before calling pcm_register(). 8307233ababSAlexander Leidinger */ 831cd9766c5SCameron Grant d->flags = 0; 8327233ababSAlexander Leidinger #endif 833e4d5b250SCameron Grant d->dev = dev; 834987e5972SCameron Grant d->devinfo = devinfo; 835f637a36cSCameron Grant d->devcount = 0; 836506a5308SCameron Grant d->reccount = 0; 837a67fe5c1SCameron Grant d->playcount = 0; 838f637a36cSCameron Grant d->vchancount = 0; 839d95502a8SCameron Grant d->inprog = 0; 840833f7023SCameron Grant 84145550658SPoul-Henning Kamp SLIST_INIT(&d->channels); 84245550658SPoul-Henning Kamp 843d95502a8SCameron Grant if (((numplay == 0) || (numrec == 0)) && (numplay != numrec)) 844285648f9SCameron Grant d->flags |= SD_F_SIMPLEX; 845d95502a8SCameron Grant 846285648f9SCameron Grant d->fakechan = fkchan_setup(dev); 847a3193a9cSDon Lewis chn_init(d->fakechan, NULL, 0, 0); 848987e5972SCameron Grant 84982db23e2SCameron Grant #ifdef SND_DYNSYSCTL 850cc486d80SJohn Baldwin sysctl_ctx_init(&d->sysctl_tree); 851cc486d80SJohn Baldwin d->sysctl_tree_top = SYSCTL_ADD_NODE(&d->sysctl_tree, 852a3e893e0SJohn Baldwin SYSCTL_STATIC_CHILDREN(_hw_snd), OID_AUTO, 853cc486d80SJohn Baldwin device_get_nameunit(dev), CTLFLAG_RD, 0, ""); 854a3e893e0SJohn Baldwin if (d->sysctl_tree_top == NULL) { 855cc486d80SJohn Baldwin sysctl_ctx_free(&d->sysctl_tree); 856cc486d80SJohn Baldwin goto no; 857cc486d80SJohn Baldwin } 858a67fe5c1SCameron Grant SYSCTL_ADD_INT(snd_sysctl_tree(dev), SYSCTL_CHILDREN(snd_sysctl_tree_top(dev)), 859a67fe5c1SCameron Grant OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, ""); 86082db23e2SCameron Grant #endif 86197d69a96SAlexander Leidinger if (numplay > 0) { 862cd9766c5SCameron Grant d->flags |= SD_F_AUTOVCHAN; 8633fdb3676SAriff Abdullah vchan_initsys(dev); 86497d69a96SAlexander Leidinger } 865cd9766c5SCameron Grant 86667b1dce3SCameron Grant sndstat_register(dev, d->status, sndstat_prepare_pcm); 867987e5972SCameron Grant return 0; 868987e5972SCameron Grant no: 86949c5e6e2SCameron Grant snd_mtxfree(d->lock); 870987e5972SCameron Grant return ENXIO; 871987e5972SCameron Grant } 872987e5972SCameron Grant 87333dbf14aSCameron Grant int 87433dbf14aSCameron Grant pcm_unregister(device_t dev) 8757c438dbeSCameron Grant { 87666ef8af5SCameron Grant struct snddev_info *d = device_get_softc(dev); 877285648f9SCameron Grant struct snddev_channel *sce; 878a67fe5c1SCameron Grant struct pcm_channel *ch; 8797c438dbeSCameron Grant 88028ef3fb0SAlexander Leidinger if (sndstat_acquire() != 0) { 88128ef3fb0SAlexander Leidinger device_printf(dev, "unregister: sndstat busy\n"); 88228ef3fb0SAlexander Leidinger return EBUSY; 88328ef3fb0SAlexander Leidinger } 88428ef3fb0SAlexander Leidinger 88549c5e6e2SCameron Grant snd_mtxlock(d->lock); 886d95502a8SCameron Grant if (d->inprog) { 8875c25132aSGeorge C A Reid device_printf(dev, "unregister: operation in progress\n"); 8885c25132aSGeorge C A Reid snd_mtxunlock(d->lock); 88928ef3fb0SAlexander Leidinger sndstat_release(); 8905c25132aSGeorge C A Reid return EBUSY; 8915c25132aSGeorge C A Reid } 8925ee30e27SMathew Kanner 893285648f9SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 894a67fe5c1SCameron Grant ch = sce->channel; 895a67fe5c1SCameron Grant if (ch->refcount > 0) { 89621ed9908SCameron Grant device_printf(dev, "unregister: channel %s busy (pid %d)\n", ch->name, ch->pid); 89749c5e6e2SCameron Grant snd_mtxunlock(d->lock); 89828ef3fb0SAlexander Leidinger sndstat_release(); 899285648f9SCameron Grant return EBUSY; 900285648f9SCameron Grant } 901c9b53085SCameron Grant } 9025ee30e27SMathew Kanner 9037233ababSAlexander Leidinger if (mixer_uninit(dev)) { 9047233ababSAlexander Leidinger device_printf(dev, "unregister: mixer busy\n"); 9057233ababSAlexander Leidinger snd_mtxunlock(d->lock); 90628ef3fb0SAlexander Leidinger sndstat_release(); 9077233ababSAlexander Leidinger return EBUSY; 9087233ababSAlexander Leidinger } 9097233ababSAlexander Leidinger 9105ee30e27SMathew Kanner SLIST_FOREACH(sce, &d->channels, link) { 9117982e7a4SAriff Abdullah if (sce->dsp_devt) { 9125ee30e27SMathew Kanner destroy_dev(sce->dsp_devt); 9137982e7a4SAriff Abdullah sce->dsp_devt = NULL; 9147982e7a4SAriff Abdullah } 9157982e7a4SAriff Abdullah if (sce->dspW_devt) { 9165ee30e27SMathew Kanner destroy_dev(sce->dspW_devt); 9177982e7a4SAriff Abdullah sce->dspW_devt = NULL; 9187982e7a4SAriff Abdullah } 9197982e7a4SAriff Abdullah if (sce->audio_devt) { 9205ee30e27SMathew Kanner destroy_dev(sce->audio_devt); 9217982e7a4SAriff Abdullah sce->audio_devt = NULL; 9227982e7a4SAriff Abdullah } 9237982e7a4SAriff Abdullah if (sce->dspr_devt) { 9245ee30e27SMathew Kanner destroy_dev(sce->dspr_devt); 9257982e7a4SAriff Abdullah sce->dspr_devt = NULL; 9267982e7a4SAriff Abdullah } 9277982e7a4SAriff Abdullah d->devcount--; 9285ee30e27SMathew Kanner } 9295ee30e27SMathew Kanner 93066ef8af5SCameron Grant #ifdef SND_DYNSYSCTL 93166ef8af5SCameron Grant d->sysctl_tree_top = NULL; 93266ef8af5SCameron Grant sysctl_ctx_free(&d->sysctl_tree); 93366ef8af5SCameron Grant #endif 934faeebea2SCameron Grant while (!SLIST_EMPTY(&d->channels)) 935285648f9SCameron Grant pcm_killchan(dev); 9367c438dbeSCameron Grant 93766ef8af5SCameron Grant chn_kill(d->fakechan); 93866ef8af5SCameron Grant fkchan_kill(d->fakechan); 93982db23e2SCameron Grant 94045550658SPoul-Henning Kamp snd_mtxunlock(d->lock); 94149c5e6e2SCameron Grant snd_mtxfree(d->lock); 94228ef3fb0SAlexander Leidinger sndstat_unregister(dev); 94328ef3fb0SAlexander Leidinger sndstat_release(); 94433dbf14aSCameron Grant return 0; 94533dbf14aSCameron Grant } 9467c438dbeSCameron Grant 94767b1dce3SCameron Grant /************************************************************************/ 94867b1dce3SCameron Grant 94967b1dce3SCameron Grant static int 95067b1dce3SCameron Grant sndstat_prepare_pcm(struct sbuf *s, device_t dev, int verbose) 95167b1dce3SCameron Grant { 95267b1dce3SCameron Grant struct snddev_info *d; 95367b1dce3SCameron Grant struct snddev_channel *sce; 95467b1dce3SCameron Grant struct pcm_channel *c; 95567b1dce3SCameron Grant struct pcm_feeder *f; 95667b1dce3SCameron Grant int pc, rc, vc; 95767b1dce3SCameron Grant 95867b1dce3SCameron Grant if (verbose < 1) 95967b1dce3SCameron Grant return 0; 96067b1dce3SCameron Grant 96167b1dce3SCameron Grant d = device_get_softc(dev); 96267b1dce3SCameron Grant if (!d) 96367b1dce3SCameron Grant return ENXIO; 96467b1dce3SCameron Grant 96567b1dce3SCameron Grant snd_mtxlock(d->lock); 96667b1dce3SCameron Grant if (!SLIST_EMPTY(&d->channels)) { 96767b1dce3SCameron Grant pc = rc = vc = 0; 96867b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 96967b1dce3SCameron Grant c = sce->channel; 97067b1dce3SCameron Grant if (c->direction == PCMDIR_PLAY) { 97167b1dce3SCameron Grant if (c->flags & CHN_F_VIRTUAL) 97267b1dce3SCameron Grant vc++; 97367b1dce3SCameron Grant else 97467b1dce3SCameron Grant pc++; 97567b1dce3SCameron Grant } else 97667b1dce3SCameron Grant rc++; 97767b1dce3SCameron Grant } 978a67fe5c1SCameron Grant sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)", d->playcount, d->reccount, d->vchancount, 97967b1dce3SCameron Grant (d->flags & SD_F_SIMPLEX)? "" : " duplex", 98067b1dce3SCameron Grant #ifdef USING_DEVFS 98167b1dce3SCameron Grant (device_get_unit(dev) == snd_unit)? " default" : "" 98267b1dce3SCameron Grant #else 98367b1dce3SCameron Grant "" 98467b1dce3SCameron Grant #endif 98567b1dce3SCameron Grant ); 986a527dbc7SCameron Grant 987a527dbc7SCameron Grant if (verbose <= 1) { 988a527dbc7SCameron Grant snd_mtxunlock(d->lock); 989a527dbc7SCameron Grant return 0; 990a527dbc7SCameron Grant } 991a527dbc7SCameron Grant 99267b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 99367b1dce3SCameron Grant c = sce->channel; 9949d978cc7SAlexander Leidinger 9959d978cc7SAlexander Leidinger KASSERT(c->bufhard != NULL && c->bufsoft != NULL, 9969d978cc7SAlexander Leidinger ("hosed pcm channel setup")); 9979d978cc7SAlexander Leidinger 998a3285889SCameron Grant sbuf_printf(s, "\n\t"); 999a3285889SCameron Grant 100045550658SPoul-Henning Kamp /* it would be better to indent child channels */ 1001a3285889SCameron Grant sbuf_printf(s, "%s[%s]: ", c->parentchannel? c->parentchannel->name : "", c->name); 10024c68642aSCameron Grant sbuf_printf(s, "spd %d", c->speed); 10034c68642aSCameron Grant if (c->speed != sndbuf_getspd(c->bufhard)) 10044c68642aSCameron Grant sbuf_printf(s, "/%d", sndbuf_getspd(c->bufhard)); 10054c68642aSCameron Grant sbuf_printf(s, ", fmt 0x%08x", c->format); 10064c68642aSCameron Grant if (c->format != sndbuf_getfmt(c->bufhard)) 10074c68642aSCameron Grant sbuf_printf(s, "/0x%08x", sndbuf_getfmt(c->bufhard)); 1008a527dbc7SCameron Grant sbuf_printf(s, ", flags 0x%08x, 0x%08x", c->flags, c->feederflags); 100967b1dce3SCameron Grant if (c->pid != -1) 101067b1dce3SCameron Grant sbuf_printf(s, ", pid %d", c->pid); 101167b1dce3SCameron Grant sbuf_printf(s, "\n\t"); 10124c68642aSCameron Grant 1013a3285889SCameron Grant sbuf_printf(s, "interrupts %d, ", c->interrupts); 1014a3285889SCameron Grant if (c->direction == PCMDIR_REC) 101597d69a96SAlexander Leidinger sbuf_printf(s, "overruns %d, hfree %d, sfree %d [b:%d/%d/%d|bs:%d/%d/%d]", 101697d69a96SAlexander Leidinger c->xruns, sndbuf_getfree(c->bufhard), sndbuf_getfree(c->bufsoft), 101797d69a96SAlexander Leidinger sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 101897d69a96SAlexander Leidinger sndbuf_getblkcnt(c->bufhard), 101997d69a96SAlexander Leidinger sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 102097d69a96SAlexander Leidinger sndbuf_getblkcnt(c->bufsoft)); 1021a3285889SCameron Grant else 102297d69a96SAlexander Leidinger sbuf_printf(s, "underruns %d, ready %d [b:%d/%d/%d|bs:%d/%d/%d]", 102397d69a96SAlexander Leidinger c->xruns, sndbuf_getready(c->bufsoft), 102497d69a96SAlexander Leidinger sndbuf_getsize(c->bufhard), sndbuf_getblksz(c->bufhard), 102597d69a96SAlexander Leidinger sndbuf_getblkcnt(c->bufhard), 102697d69a96SAlexander Leidinger sndbuf_getsize(c->bufsoft), sndbuf_getblksz(c->bufsoft), 102797d69a96SAlexander Leidinger sndbuf_getblkcnt(c->bufsoft)); 1028a3285889SCameron Grant sbuf_printf(s, "\n\t"); 10294c68642aSCameron Grant 10304c68642aSCameron Grant sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "hardware" : "userland"); 10314c68642aSCameron Grant sbuf_printf(s, " -> "); 103267b1dce3SCameron Grant f = c->feeder; 10334c68642aSCameron Grant while (f->source != NULL) 10344c68642aSCameron Grant f = f->source; 10354c68642aSCameron Grant while (f != NULL) { 103667b1dce3SCameron Grant sbuf_printf(s, "%s", f->class->name); 103767b1dce3SCameron Grant if (f->desc->type == FEEDER_FMT) 10384c68642aSCameron Grant sbuf_printf(s, "(0x%08x -> 0x%08x)", f->desc->in, f->desc->out); 103967b1dce3SCameron Grant if (f->desc->type == FEEDER_RATE) 10404c68642aSCameron Grant sbuf_printf(s, "(%d -> %d)", FEEDER_GET(f, FEEDRATE_SRC), FEEDER_GET(f, FEEDRATE_DST)); 104128ef3fb0SAlexander Leidinger if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER || 104228ef3fb0SAlexander Leidinger f->desc->type == FEEDER_VOLUME) 10434c68642aSCameron Grant sbuf_printf(s, "(0x%08x)", f->desc->out); 10444c68642aSCameron Grant sbuf_printf(s, " -> "); 10454c68642aSCameron Grant f = f->parent; 104667b1dce3SCameron Grant } 10474c68642aSCameron Grant sbuf_printf(s, "{%s}", (c->direction == PCMDIR_REC)? "userland" : "hardware"); 104867b1dce3SCameron Grant } 104967b1dce3SCameron Grant } else 105067b1dce3SCameron Grant sbuf_printf(s, " (mixer only)"); 105167b1dce3SCameron Grant snd_mtxunlock(d->lock); 105267b1dce3SCameron Grant 105367b1dce3SCameron Grant return 0; 105467b1dce3SCameron Grant } 105567b1dce3SCameron Grant 105667b1dce3SCameron Grant /************************************************************************/ 105767b1dce3SCameron Grant 105867b1dce3SCameron Grant #ifdef SND_DYNSYSCTL 105967b1dce3SCameron Grant int 106067b1dce3SCameron Grant sysctl_hw_snd_vchans(SYSCTL_HANDLER_ARGS) 106167b1dce3SCameron Grant { 106267b1dce3SCameron Grant struct snddev_info *d; 106367b1dce3SCameron Grant struct snddev_channel *sce; 106467b1dce3SCameron Grant struct pcm_channel *c; 106597d69a96SAlexander Leidinger int err, newcnt, cnt; 106667b1dce3SCameron Grant 106797d69a96SAlexander Leidinger /* 106897d69a96SAlexander Leidinger * XXX WOAH... NEED SUPER CLEANUP!!! 106997d69a96SAlexander Leidinger * Robust, yet confusing. Understanding these will 107097d69a96SAlexander Leidinger * cause your brain spinning like a Doki Doki Dynamo. 107197d69a96SAlexander Leidinger */ 107267b1dce3SCameron Grant d = oidp->oid_arg1; 107367b1dce3SCameron Grant 10743fdb3676SAriff Abdullah if (!(d->flags & SD_F_AUTOVCHAN)) 107597d69a96SAlexander Leidinger return EINVAL; 1076a527dbc7SCameron Grant 107767b1dce3SCameron Grant cnt = 0; 107867b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 107967b1dce3SCameron Grant c = sce->channel; 108012e524a2SDon Lewis CHN_LOCK(c); 1081a527dbc7SCameron Grant if ((c->direction == PCMDIR_PLAY) && (c->flags & CHN_F_VIRTUAL)) { 108267b1dce3SCameron Grant cnt++; 108397d69a96SAlexander Leidinger if (req->newptr != NULL && c->flags & CHN_F_BUSY) { 108497d69a96SAlexander Leidinger /* Better safe than sorry */ 108597d69a96SAlexander Leidinger CHN_UNLOCK(c); 108697d69a96SAlexander Leidinger return EBUSY; 108797d69a96SAlexander Leidinger } 108867b1dce3SCameron Grant } 108912e524a2SDon Lewis CHN_UNLOCK(c); 1090a527dbc7SCameron Grant } 1091a527dbc7SCameron Grant 109267b1dce3SCameron Grant newcnt = cnt; 109367b1dce3SCameron Grant 109467b1dce3SCameron Grant err = sysctl_handle_int(oidp, &newcnt, sizeof(newcnt), req); 1095a527dbc7SCameron Grant 109667b1dce3SCameron Grant if (err == 0 && req->newptr != NULL) { 1097a527dbc7SCameron Grant 10987982e7a4SAriff Abdullah if (newcnt < 0 || newcnt > (PCMMAXCHAN + 1) || 10997982e7a4SAriff Abdullah (d->playcount + d->reccount + newcnt) > (PCMMAXCHAN + 1)) 1100a527dbc7SCameron Grant return E2BIG; 110197d69a96SAlexander Leidinger 110297d69a96SAlexander Leidinger if (pcm_inprog(d, 1) != 1) { 110397d69a96SAlexander Leidinger pcm_inprog(d, -1); 110497d69a96SAlexander Leidinger return EINPROGRESS; 110567b1dce3SCameron Grant } 110667b1dce3SCameron Grant 110767b1dce3SCameron Grant if (newcnt > cnt) { 110867b1dce3SCameron Grant /* add new vchans - find a parent channel first */ 110967b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 111067b1dce3SCameron Grant c = sce->channel; 111112e524a2SDon Lewis CHN_LOCK(c); 111267b1dce3SCameron Grant /* not a candidate if not a play channel */ 111367b1dce3SCameron Grant if (c->direction != PCMDIR_PLAY) 111412e524a2SDon Lewis goto next; 111567b1dce3SCameron Grant /* not a candidate if a virtual channel */ 111667b1dce3SCameron Grant if (c->flags & CHN_F_VIRTUAL) 111712e524a2SDon Lewis goto next; 111867b1dce3SCameron Grant /* not a candidate if it's in use */ 111912e524a2SDon Lewis if (!(c->flags & CHN_F_BUSY) || 112012e524a2SDon Lewis !(SLIST_EMPTY(&c->children))) 112167b1dce3SCameron Grant /* 112212e524a2SDon Lewis * if we get here we're a nonvirtual 112312e524a2SDon Lewis * play channel, and either 112467b1dce3SCameron Grant * 1) not busy 112512e524a2SDon Lewis * 2) busy with children, not directly 112612e524a2SDon Lewis * open 112767b1dce3SCameron Grant * 112867b1dce3SCameron Grant * thus we can add children 112967b1dce3SCameron Grant */ 113067b1dce3SCameron Grant goto addok; 113112e524a2SDon Lewis next: 113212e524a2SDon Lewis CHN_UNLOCK(c); 113367b1dce3SCameron Grant } 1134a527dbc7SCameron Grant pcm_inprog(d, -1); 113567b1dce3SCameron Grant return EBUSY; 113667b1dce3SCameron Grant addok: 113767b1dce3SCameron Grant c->flags |= CHN_F_BUSY; 113867b1dce3SCameron Grant while (err == 0 && newcnt > cnt) { 11397982e7a4SAriff Abdullah if (d->devcount > PCMMAXCHAN) { 11407982e7a4SAriff Abdullah device_printf(d->dev, "%s: Maximum channel reached.\n", __func__); 11417982e7a4SAriff Abdullah break; 11427982e7a4SAriff Abdullah } 114367b1dce3SCameron Grant err = vchan_create(c); 114467b1dce3SCameron Grant if (err == 0) 114567b1dce3SCameron Grant cnt++; 11467982e7a4SAriff Abdullah if (newcnt > cnt && err == E2BIG) { 11477982e7a4SAriff Abdullah device_printf(d->dev, "%s: err=%d Maximum channel reached.\n", __func__, err); 11487982e7a4SAriff Abdullah err = 0; 11497982e7a4SAriff Abdullah break; 11507982e7a4SAriff Abdullah } 115167b1dce3SCameron Grant } 115212e524a2SDon Lewis CHN_UNLOCK(c); 115367b1dce3SCameron Grant } else if (newcnt < cnt) { 1154a527dbc7SCameron Grant snd_mtxlock(d->lock); 115567b1dce3SCameron Grant while (err == 0 && newcnt < cnt) { 11567982e7a4SAriff Abdullah c = NULL; 115767b1dce3SCameron Grant SLIST_FOREACH(sce, &d->channels, link) { 11587982e7a4SAriff Abdullah CHN_LOCK(sce->channel); 11597982e7a4SAriff Abdullah if (sce->channel->direction == PCMDIR_PLAY && 1160945510a0SAriff Abdullah (sce->channel->flags & (CHN_F_BUSY | CHN_F_VIRTUAL)) == CHN_F_VIRTUAL) 116167b1dce3SCameron Grant c = sce->channel; 11627982e7a4SAriff Abdullah CHN_UNLOCK(sce->channel); 116367b1dce3SCameron Grant } 11647982e7a4SAriff Abdullah if (c != NULL) 11657982e7a4SAriff Abdullah goto remok; 1166a527dbc7SCameron Grant snd_mtxunlock(d->lock); 1167a527dbc7SCameron Grant pcm_inprog(d, -1); 116867b1dce3SCameron Grant return EINVAL; 116967b1dce3SCameron Grant remok: 117067b1dce3SCameron Grant err = vchan_destroy(c); 117167b1dce3SCameron Grant if (err == 0) 117267b1dce3SCameron Grant cnt--; 117367b1dce3SCameron Grant } 1174a527dbc7SCameron Grant snd_mtxunlock(d->lock); 117567b1dce3SCameron Grant } 1176a527dbc7SCameron Grant pcm_inprog(d, -1); 117797d69a96SAlexander Leidinger } 117867b1dce3SCameron Grant return err; 117967b1dce3SCameron Grant } 118067b1dce3SCameron Grant #endif 118167b1dce3SCameron Grant 118267b1dce3SCameron Grant /************************************************************************/ 118367b1dce3SCameron Grant 11840739ea1dSSeigo Tanimura static int 11850739ea1dSSeigo Tanimura sound_modevent(module_t mod, int type, void *data) 11860739ea1dSSeigo Tanimura { 11877233ababSAlexander Leidinger #if 0 11880739ea1dSSeigo Tanimura return (midi_modevent(mod, type, data)); 11897233ababSAlexander Leidinger #else 11907233ababSAlexander Leidinger return 0; 11917233ababSAlexander Leidinger #endif 11920739ea1dSSeigo Tanimura } 11930739ea1dSSeigo Tanimura 11940739ea1dSSeigo Tanimura DEV_MODULE(sound, sound_modevent, NULL); 11950739ea1dSSeigo Tanimura MODULE_VERSION(sound, SOUND_MODVER); 1196