1999-09-01 04:08:39 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 1999 Cameron Grant <gandalf@vilnya.demon.co.uk>
|
|
|
|
* (C) 1997 Luigi Rizzo (luigi@iet.unipi.it)
|
|
|
|
* 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.
|
|
|
|
*
|
1999-09-01 06:58:27 +00:00
|
|
|
* $FreeBSD$
|
1999-09-01 04:08:39 +00:00
|
|
|
*/
|
|
|
|
|
1999-11-20 16:50:33 +00:00
|
|
|
#include <dev/sound/pcm/sound.h>
|
2001-05-27 17:22:00 +00:00
|
|
|
#include <dev/sound/pcm/vchan.h>
|
2000-08-29 16:21:33 +00:00
|
|
|
#include <sys/sysctl.h>
|
1999-09-01 04:08:39 +00:00
|
|
|
|
2001-06-16 21:25:10 +00:00
|
|
|
devclass_t pcm_devclass;
|
2001-02-27 07:01:49 +00:00
|
|
|
|
|
|
|
#ifdef USING_DEVFS
|
2001-06-16 21:25:10 +00:00
|
|
|
int snd_unit = 0;
|
2001-06-08 05:24:21 +00:00
|
|
|
TUNABLE_INT("hw.snd.unit", &snd_unit);
|
2001-02-27 07:01:49 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
SYSCTL_NODE(_hw, OID_AUTO, snd, CTLFLAG_RD, 0, "Sound driver");
|
1999-09-01 04:08:39 +00:00
|
|
|
|
2001-02-27 07:45:09 +00:00
|
|
|
void *
|
|
|
|
snd_mtxcreate(const char *desc)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
|
|
|
struct mtx *m;
|
|
|
|
|
|
|
|
m = malloc(sizeof(*m), M_DEVBUF, M_WAITOK | M_ZERO);
|
|
|
|
if (m == NULL)
|
|
|
|
return NULL;
|
|
|
|
mtx_init(m, desc, MTX_RECURSE);
|
|
|
|
return m;
|
|
|
|
#else
|
2001-03-05 15:49:42 +00:00
|
|
|
return (void *)0xcafebabe;
|
2001-02-27 07:45:09 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
snd_mtxfree(void *m)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
|
|
|
struct mtx *mtx = m;
|
|
|
|
|
|
|
|
mtx_assert(mtx, MA_OWNED);
|
|
|
|
mtx_destroy(mtx);
|
|
|
|
free(mtx, M_DEVBUF);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
snd_mtxassert(void *m)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
2001-06-23 17:36:51 +00:00
|
|
|
#ifdef INVARIANTS
|
2001-02-27 07:45:09 +00:00
|
|
|
struct mtx *mtx = m;
|
|
|
|
|
|
|
|
mtx_assert(mtx, MA_OWNED);
|
|
|
|
#endif
|
2001-06-23 17:36:51 +00:00
|
|
|
#endif
|
2001-02-27 07:45:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
snd_mtxlock(void *m)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
|
|
|
struct mtx *mtx = m;
|
|
|
|
|
|
|
|
mtx_lock(mtx);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
snd_mtxunlock(void *m)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
|
|
|
struct mtx *mtx = m;
|
|
|
|
|
|
|
|
mtx_unlock(mtx);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
snd_setup_intr(device_t dev, struct resource *res, int flags, driver_intr_t hand, void *param, void **cookiep)
|
|
|
|
{
|
|
|
|
#ifdef USING_MUTEX
|
|
|
|
flags &= INTR_MPSAFE;
|
2001-06-16 22:59:46 +00:00
|
|
|
flags |= INTR_TYPE_AV;
|
2001-02-27 07:45:09 +00:00
|
|
|
#else
|
2001-06-16 22:59:46 +00:00
|
|
|
flags = INTR_TYPE_AV;
|
2001-02-27 07:45:09 +00:00
|
|
|
#endif
|
|
|
|
return bus_setup_intr(dev, res, flags, hand, param, cookiep);
|
|
|
|
}
|
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
/* return a locked channel */
|
2001-05-27 17:22:00 +00:00
|
|
|
struct pcm_channel *
|
2001-06-14 13:31:30 +00:00
|
|
|
pcm_chnalloc(struct snddev_info *d, int direction, pid_t pid)
|
2001-05-27 17:22:00 +00:00
|
|
|
{
|
|
|
|
struct pcm_channel *c;
|
|
|
|
struct snddev_channel *sce;
|
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
snd_mtxassert(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
SLIST_FOREACH(sce, &d->channels, link) {
|
|
|
|
c = sce->channel;
|
2001-06-07 20:06:22 +00:00
|
|
|
CHN_LOCK(c);
|
2001-05-27 17:22:00 +00:00
|
|
|
if ((c->direction == direction) && !(c->flags & CHN_F_BUSY)) {
|
|
|
|
c->flags |= CHN_F_BUSY;
|
2001-06-14 13:31:30 +00:00
|
|
|
c->pid = pid;
|
2001-05-27 17:22:00 +00:00
|
|
|
return c;
|
|
|
|
}
|
2001-06-07 20:06:22 +00:00
|
|
|
CHN_UNLOCK(c);
|
2001-05-27 17:22:00 +00:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
/* release a locked channel and unlock it */
|
2001-05-27 17:22:00 +00:00
|
|
|
int
|
2001-06-14 13:31:30 +00:00
|
|
|
pcm_chnrelease(struct pcm_channel *c)
|
2001-05-27 17:22:00 +00:00
|
|
|
{
|
2001-06-14 13:31:30 +00:00
|
|
|
CHN_LOCKASSERT(c);
|
2001-05-27 17:22:00 +00:00
|
|
|
c->flags &= ~CHN_F_BUSY;
|
2001-06-14 13:31:30 +00:00
|
|
|
c->pid = -1;
|
2001-06-07 20:06:22 +00:00
|
|
|
CHN_UNLOCK(c);
|
2001-05-27 17:22:00 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcm_chnref(struct pcm_channel *c, int ref)
|
|
|
|
{
|
2001-06-07 20:06:22 +00:00
|
|
|
int r;
|
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
CHN_LOCKASSERT(c);
|
2001-05-27 17:22:00 +00:00
|
|
|
c->refcount += ref;
|
2001-06-07 20:06:22 +00:00
|
|
|
r = c->refcount;
|
|
|
|
return r;
|
2001-05-27 17:22:00 +00:00
|
|
|
}
|
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
#ifdef USING_DEVFS
|
2000-09-01 20:09:24 +00:00
|
|
|
static int
|
|
|
|
sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS)
|
|
|
|
{
|
2001-06-14 13:31:30 +00:00
|
|
|
struct snddev_info *d;
|
2000-09-01 20:09:24 +00:00
|
|
|
int error, unit;
|
|
|
|
|
|
|
|
unit = snd_unit;
|
|
|
|
error = sysctl_handle_int(oidp, &unit, sizeof(unit), req);
|
|
|
|
if (error == 0 && req->newptr != NULL) {
|
2001-06-18 00:10:47 +00:00
|
|
|
if (unit < 0 || unit >= devclass_get_maxunit(pcm_devclass))
|
2001-06-14 13:31:30 +00:00
|
|
|
return EINVAL;
|
|
|
|
d = devclass_get_softc(pcm_devclass, unit);
|
2001-06-17 23:23:06 +00:00
|
|
|
if (d == NULL || SLIST_EMPTY(&d->channels))
|
2001-06-14 13:31:30 +00:00
|
|
|
return EINVAL;
|
2000-09-01 20:09:24 +00:00
|
|
|
snd_unit = unit;
|
|
|
|
}
|
|
|
|
return (error);
|
|
|
|
}
|
2001-01-03 01:25:26 +00:00
|
|
|
SYSCTL_PROC(_hw_snd, OID_AUTO, unit, CTLTYPE_INT | CTLFLAG_RW,
|
2000-09-01 20:09:24 +00:00
|
|
|
0, sizeof(int), sysctl_hw_sndunit, "I", "");
|
2001-02-27 07:01:49 +00:00
|
|
|
#endif
|
2000-09-01 20:09:24 +00:00
|
|
|
|
2001-05-27 17:22:00 +00:00
|
|
|
struct pcm_channel *
|
|
|
|
pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo)
|
1999-09-01 04:08:39 +00:00
|
|
|
{
|
2001-05-27 17:22:00 +00:00
|
|
|
struct pcm_channel *ch;
|
2000-09-01 20:09:24 +00:00
|
|
|
char *dirs;
|
2001-05-27 17:22:00 +00:00
|
|
|
int err;
|
1999-09-01 04:08:39 +00:00
|
|
|
|
2001-05-27 17:22:00 +00:00
|
|
|
switch(dir) {
|
|
|
|
case PCMDIR_PLAY:
|
|
|
|
dirs = "play";
|
|
|
|
break;
|
|
|
|
case PCMDIR_REC:
|
|
|
|
dirs = "record";
|
|
|
|
break;
|
|
|
|
case PCMDIR_VIRTUAL:
|
|
|
|
dirs = "virtual";
|
|
|
|
dir = PCMDIR_PLAY;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return NULL;
|
2000-06-06 22:24:53 +00:00
|
|
|
}
|
2001-05-27 17:22:00 +00:00
|
|
|
|
|
|
|
ch = malloc(sizeof(*ch), M_DEVBUF, M_WAITOK | M_ZERO);
|
|
|
|
if (!ch)
|
|
|
|
return NULL;
|
|
|
|
|
2000-12-18 01:36:41 +00:00
|
|
|
ch->methods = kobj_create(cls, M_DEVBUF, M_WAITOK);
|
2001-05-27 17:22:00 +00:00
|
|
|
if (!ch->methods) {
|
|
|
|
free(ch, M_DEVBUF);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
ch->pid = -1;
|
|
|
|
ch->parentsnddev = d;
|
|
|
|
ch->parentchannel = parent;
|
|
|
|
snprintf(ch->name, 32, "%s:%d:%s", device_get_nameunit(d->dev), d->chancount, dirs);
|
|
|
|
|
2000-12-18 01:36:41 +00:00
|
|
|
err = chn_init(ch, devinfo, dir);
|
|
|
|
if (err) {
|
2001-05-27 17:22:00 +00:00
|
|
|
device_printf(d->dev, "chn_init() for channel %d (%s) failed: err = %d\n", d->chancount, dirs, err);
|
|
|
|
kobj_delete(ch->methods, M_DEVBUF);
|
|
|
|
free(ch, M_DEVBUF);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcm_chn_destroy(struct pcm_channel *ch)
|
|
|
|
{
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = chn_kill(ch);
|
|
|
|
if (err) {
|
|
|
|
device_printf(ch->parentsnddev->dev, "chn_kill() for %s failed, err = %d\n", ch->name, err);
|
|
|
|
return err;
|
2000-01-05 20:44:41 +00:00
|
|
|
}
|
2001-05-27 17:22:00 +00:00
|
|
|
|
|
|
|
kobj_delete(ch->methods, M_DEVBUF);
|
|
|
|
free(ch, M_DEVBUF);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
|
|
|
|
{
|
|
|
|
struct snddev_channel *sce;
|
|
|
|
int unit = device_get_unit(d->dev);
|
2001-06-14 13:31:30 +00:00
|
|
|
|
|
|
|
snd_mtxlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
|
|
|
|
sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO);
|
|
|
|
if (!sce) {
|
2001-06-14 13:31:30 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
return ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
sce->channel = ch;
|
|
|
|
SLIST_INSERT_HEAD(&d->channels, sce, link);
|
|
|
|
|
2001-06-16 21:25:10 +00:00
|
|
|
dsp_register(unit, d->chancount);
|
|
|
|
d->chancount++;
|
2001-06-14 13:31:30 +00:00
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
|
2000-09-01 20:09:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-05-27 17:22:00 +00:00
|
|
|
int
|
|
|
|
pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
|
2000-09-01 20:09:24 +00:00
|
|
|
{
|
2001-05-27 17:22:00 +00:00
|
|
|
struct snddev_channel *sce;
|
|
|
|
int unit = device_get_unit(d->dev);
|
2000-09-01 20:09:24 +00:00
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
SLIST_FOREACH(sce, &d->channels, link) {
|
|
|
|
if (sce->channel == ch)
|
|
|
|
goto gotit;
|
2000-09-01 20:09:24 +00:00
|
|
|
}
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
return EINVAL;
|
|
|
|
gotit:
|
2000-09-01 20:09:24 +00:00
|
|
|
d->chancount--;
|
2001-05-27 17:22:00 +00:00
|
|
|
SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
|
|
|
|
free(sce, M_DEVBUF);
|
|
|
|
|
2001-06-16 21:25:10 +00:00
|
|
|
dsp_unregister(unit, d->chancount);
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
|
1999-09-01 04:08:39 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-05-27 17:22:00 +00:00
|
|
|
int
|
|
|
|
pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
|
|
|
|
{
|
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
|
|
|
struct pcm_channel *ch;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
ch = pcm_chn_create(d, NULL, cls, dir, devinfo);
|
|
|
|
if (!ch) {
|
|
|
|
device_printf(d->dev, "pcm_chn_create(%s, %d, %p) failed\n", cls->name, dir, devinfo);
|
|
|
|
return ENODEV;
|
|
|
|
}
|
|
|
|
err = pcm_chn_add(d, ch);
|
|
|
|
if (err) {
|
|
|
|
device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err);
|
|
|
|
pcm_chn_destroy(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
pcm_killchan(device_t dev)
|
|
|
|
{
|
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
|
|
|
struct snddev_channel *sce;
|
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
sce = SLIST_FIRST(&d->channels);
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
|
|
|
|
return pcm_chn_remove(d, sce->channel);
|
|
|
|
}
|
|
|
|
|
1999-09-01 04:08:39 +00:00
|
|
|
int
|
|
|
|
pcm_setstatus(device_t dev, char *str)
|
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
2001-06-07 20:06:22 +00:00
|
|
|
|
|
|
|
snd_mtxlock(d->lock);
|
1999-09-01 04:08:39 +00:00
|
|
|
strncpy(d->status, str, SND_STATUSLEN);
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
1999-09-01 04:08:39 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
u_int32_t
|
|
|
|
pcm_getflags(device_t dev)
|
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
2001-06-07 20:06:22 +00:00
|
|
|
|
1999-09-01 04:08:39 +00:00
|
|
|
return d->flags;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
pcm_setflags(device_t dev, u_int32_t val)
|
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
2001-06-16 21:25:10 +00:00
|
|
|
|
1999-09-01 04:08:39 +00:00
|
|
|
d->flags = val;
|
|
|
|
}
|
|
|
|
|
2000-03-20 15:30:50 +00:00
|
|
|
void *
|
|
|
|
pcm_getdevinfo(device_t dev)
|
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
2001-06-07 20:06:22 +00:00
|
|
|
|
2000-03-20 15:30:50 +00:00
|
|
|
return d->devinfo;
|
|
|
|
}
|
|
|
|
|
1999-09-01 04:08:39 +00:00
|
|
|
/* This is the generic init routine */
|
|
|
|
int
|
|
|
|
pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
|
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
1999-09-01 04:08:39 +00:00
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
d->lock = snd_mtxcreate(device_get_nameunit(dev));
|
|
|
|
snd_mtxlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
|
2000-06-20 23:27:12 +00:00
|
|
|
d->dev = dev;
|
1999-09-01 04:08:39 +00:00
|
|
|
d->devinfo = devinfo;
|
2001-05-27 17:22:00 +00:00
|
|
|
d->chancount = 0;
|
2001-06-16 21:25:10 +00:00
|
|
|
d->inprog = 0;
|
2000-01-06 04:11:36 +00:00
|
|
|
|
2001-06-16 21:25:10 +00:00
|
|
|
if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
|
2001-06-14 13:31:30 +00:00
|
|
|
d->flags |= SD_F_SIMPLEX;
|
2001-06-16 21:25:10 +00:00
|
|
|
|
2001-06-14 13:31:30 +00:00
|
|
|
d->fakechan = fkchan_setup(dev);
|
|
|
|
chn_init(d->fakechan, NULL, 0);
|
1999-09-01 04:08:39 +00:00
|
|
|
|
2001-02-27 07:01:49 +00:00
|
|
|
#ifdef SND_DYNSYSCTL
|
2001-01-05 07:07:03 +00:00
|
|
|
sysctl_ctx_init(&d->sysctl_tree);
|
|
|
|
d->sysctl_tree_top = SYSCTL_ADD_NODE(&d->sysctl_tree,
|
2001-01-11 23:22:33 +00:00
|
|
|
SYSCTL_STATIC_CHILDREN(_hw_snd), OID_AUTO,
|
2001-01-05 07:07:03 +00:00
|
|
|
device_get_nameunit(dev), CTLFLAG_RD, 0, "");
|
2001-01-11 23:22:33 +00:00
|
|
|
if (d->sysctl_tree_top == NULL) {
|
2001-01-05 07:07:03 +00:00
|
|
|
sysctl_ctx_free(&d->sysctl_tree);
|
|
|
|
goto no;
|
|
|
|
}
|
2001-02-27 07:01:49 +00:00
|
|
|
#endif
|
2001-06-14 13:31:30 +00:00
|
|
|
if (numplay > 0)
|
|
|
|
vchan_initsys(d);
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
1999-09-01 04:08:39 +00:00
|
|
|
return 0;
|
|
|
|
no:
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxfree(d->lock);
|
1999-09-01 04:08:39 +00:00
|
|
|
return ENXIO;
|
|
|
|
}
|
|
|
|
|
2000-09-01 20:09:24 +00:00
|
|
|
int
|
|
|
|
pcm_unregister(device_t dev)
|
2000-08-29 16:21:33 +00:00
|
|
|
{
|
2001-03-24 23:10:29 +00:00
|
|
|
struct snddev_info *d = device_get_softc(dev);
|
2001-05-27 17:22:00 +00:00
|
|
|
struct snddev_channel *sce;
|
2000-08-29 16:21:33 +00:00
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxlock(d->lock);
|
2001-06-16 21:25:10 +00:00
|
|
|
if (d->inprog) {
|
|
|
|
device_printf(dev, "unregister: operation in progress");
|
|
|
|
snd_mtxunlock(d->lock);
|
|
|
|
return EBUSY;
|
|
|
|
}
|
2001-05-27 17:22:00 +00:00
|
|
|
SLIST_FOREACH(sce, &d->channels, link) {
|
|
|
|
if (sce->channel->refcount > 0) {
|
|
|
|
device_printf(dev, "unregister: channel busy");
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2001-05-27 17:22:00 +00:00
|
|
|
return EBUSY;
|
|
|
|
}
|
2000-09-05 20:58:51 +00:00
|
|
|
}
|
2001-06-16 21:25:10 +00:00
|
|
|
if (mixer_uninit(dev)) {
|
2000-09-05 20:58:51 +00:00
|
|
|
device_printf(dev, "unregister: mixer busy");
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxunlock(d->lock);
|
2000-09-05 20:58:51 +00:00
|
|
|
return EBUSY;
|
|
|
|
}
|
2000-08-29 16:21:33 +00:00
|
|
|
|
2001-03-24 23:10:29 +00:00
|
|
|
#ifdef SND_DYNSYSCTL
|
|
|
|
d->sysctl_tree_top = NULL;
|
|
|
|
sysctl_ctx_free(&d->sysctl_tree);
|
|
|
|
#endif
|
2001-06-17 23:23:06 +00:00
|
|
|
while (!SLIST_EMPTY(&d->channels))
|
2001-05-27 17:22:00 +00:00
|
|
|
pcm_killchan(dev);
|
2000-08-29 16:21:33 +00:00
|
|
|
|
2001-03-24 23:10:29 +00:00
|
|
|
chn_kill(d->fakechan);
|
|
|
|
fkchan_kill(d->fakechan);
|
2001-02-27 07:01:49 +00:00
|
|
|
|
2001-06-07 20:06:22 +00:00
|
|
|
snd_mtxfree(d->lock);
|
2000-09-01 20:09:24 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2000-08-29 16:21:33 +00:00
|
|
|
|
2000-09-01 20:09:24 +00:00
|
|
|
static moduledata_t sndpcm_mod = {
|
|
|
|
"snd_pcm",
|
2001-06-16 21:25:10 +00:00
|
|
|
NULL,
|
2000-09-01 20:09:24 +00:00
|
|
|
NULL
|
|
|
|
};
|
|
|
|
DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
|
|
|
|
MODULE_VERSION(snd_pcm, PCM_MODVER);
|