summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/sound/pcm')
-rw-r--r--sys/dev/sound/pcm/ac97.c21
-rw-r--r--sys/dev/sound/pcm/ac97.h1
-rw-r--r--sys/dev/sound/pcm/channel.c26
-rw-r--r--sys/dev/sound/pcm/channel.h2
-rw-r--r--sys/dev/sound/pcm/datatypes.h16
-rw-r--r--sys/dev/sound/pcm/mixer.c41
-rw-r--r--sys/dev/sound/pcm/mixer.h11
-rw-r--r--sys/dev/sound/pcm/sound.c245
-rw-r--r--sys/dev/sound/pcm/sound.h1
9 files changed, 276 insertions, 88 deletions
diff --git a/sys/dev/sound/pcm/ac97.c b/sys/dev/sound/pcm/ac97.c
index 8432769..296e800 100644
--- a/sys/dev/sound/pcm/ac97.c
+++ b/sys/dev/sound/pcm/ac97.c
@@ -386,6 +386,12 @@ ac97_create(device_t dev, void *devinfo, ac97_init *init, ac97_read *rd, ac97_wr
return codec;
}
+void
+ac97_destroy(struct ac97_info *codec)
+{
+ free(codec, M_DEVBUF);
+}
+
static int
ac97mix_init(snd_mixer *m)
{
@@ -400,6 +406,20 @@ ac97mix_init(snd_mixer *m)
}
static int
+ac97mix_uninit(snd_mixer *m)
+{
+ struct ac97_info *codec = mix_getdevinfo(m);
+ if (codec == NULL)
+ return -1;
+ /*
+ if (ac97_uninitmixer(codec))
+ return -1;
+ */
+ ac97_destroy(codec);
+ return 0;
+}
+
+static int
ac97mix_set(snd_mixer *m, unsigned dev, unsigned left, unsigned right)
{
struct ac97_info *codec = mix_getdevinfo(m);
@@ -424,6 +444,7 @@ ac97mix_setrecsrc(snd_mixer *m, u_int32_t src)
snd_mixer ac97_mixer = {
"AC97 mixer",
ac97mix_init,
+ ac97mix_uninit,
ac97mix_set,
ac97mix_setrecsrc,
};
diff --git a/sys/dev/sound/pcm/ac97.h b/sys/dev/sound/pcm/ac97.h
index 11ff139..0697cea 100644
--- a/sys/dev/sound/pcm/ac97.h
+++ b/sys/dev/sound/pcm/ac97.h
@@ -72,6 +72,7 @@ struct ac97_info;
struct ac97_info *ac97_create(device_t dev, void *devinfo, ac97_init *init,
ac97_read *rd, ac97_write *wr);
+void ac97_destroy(struct ac97_info *codec);
int ac97_setrate(struct ac97_info *codec, int which, int rate);
int ac97_setextmode(struct ac97_info *codec, u_int16_t mode);
diff --git a/sys/dev/sound/pcm/channel.c b/sys/dev/sound/pcm/channel.c
index 2e292b7..af338628 100644
--- a/sys/dev/sound/pcm/channel.c
+++ b/sys/dev/sound/pcm/channel.c
@@ -850,13 +850,20 @@ chn_dma_setmap(void *arg, bus_dma_segment_t *segs, int nseg, int error)
int
chn_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat)
{
- if (bus_dmamem_alloc(parent_dmat, (void **)&b->buf,
+ b->parent_dmat = parent_dmat;
+ if (bus_dmamem_alloc(b->parent_dmat, (void **)&b->buf,
BUS_DMA_NOWAIT, &b->dmamap)) return -1;
- if (bus_dmamap_load(parent_dmat, b->dmamap, b->buf,
+ if (bus_dmamap_load(b->parent_dmat, b->dmamap, b->buf,
b->bufsize, chn_dma_setmap, b, 0)) return -1;
return 0;
}
+void
+chn_freebuf(snd_dbuf *b)
+{
+ bus_dmamem_free(b->parent_dmat, b->buf, b->dmamap);
+}
+
static void
buf_clear(snd_dbuf *b, u_int32_t fmt, int length)
{
@@ -1152,6 +1159,21 @@ chn_init(pcm_channel *c, void *devinfo, int dir)
}
int
+chn_kill(pcm_channel *c)
+{
+ chn_trigger(c, PCMTRIG_ABORT);
+ while (chn_removefeeder(c) == 0);
+ free(c->feeder->desc, M_DEVBUF);
+ free(c->feeder, M_DEVBUF);
+ if (c->free)
+ c->free(c->devinfo);
+ else
+ chn_freebuf(&c->buffer);
+ c->flags |= CHN_F_DEAD;
+ return 0;
+}
+
+int
chn_setdir(pcm_channel *c, int dir)
{
int r;
diff --git a/sys/dev/sound/pcm/channel.h b/sys/dev/sound/pcm/channel.h
index 3f6a359..26857a6 100644
--- a/sys/dev/sound/pcm/channel.h
+++ b/sys/dev/sound/pcm/channel.h
@@ -34,6 +34,7 @@ int chn_flush(pcm_channel *c);
int chn_poll(pcm_channel *c, int ev, struct proc *p);
int chn_init(pcm_channel *c, void *devinfo, int dir);
+int chn_kill(pcm_channel *c);
int chn_setdir(pcm_channel *c, int dir);
int chn_reset(pcm_channel *c, u_int32_t fmt);
int chn_setvolume(pcm_channel *c, int left, int right);
@@ -46,6 +47,7 @@ pcmchan_caps *chn_getcaps(pcm_channel *c);
u_int32_t chn_getformats(pcm_channel *c);
int chn_allocbuf(snd_dbuf *b, bus_dma_tag_t parent_dmat);
+void chn_freebuf(snd_dbuf *b);
void chn_resetbuf(pcm_channel *c);
void chn_intr(pcm_channel *c);
void chn_checkunderflow(pcm_channel *c);
diff --git a/sys/dev/sound/pcm/datatypes.h b/sys/dev/sound/pcm/datatypes.h
index 6f831e5..c6343a5 100644
--- a/sys/dev/sound/pcm/datatypes.h
+++ b/sys/dev/sound/pcm/datatypes.h
@@ -36,14 +36,17 @@ typedef struct _pcm_channel pcm_channel;
typedef int (mix_set_t)(snd_mixer *m, unsigned dev, unsigned left, unsigned right);
typedef int (mix_recsrc_t)(snd_mixer *m, u_int32_t src);
typedef int (mix_init_t)(snd_mixer *m);
+typedef int (mix_uninit_t)(snd_mixer *m);
struct _snd_mixer {
char name[64];
mix_init_t *init;
+ mix_uninit_t *uninit;
mix_set_t *set;
mix_recsrc_t *setrecsrc;
void *devinfo;
+ int busy;
u_int32_t devs;
u_int32_t recdevs;
u_int32_t recsrc;
@@ -70,6 +73,7 @@ struct _snd_dbuf {
int fmt, blksz, blkcnt;
int underflow, overrun;
bus_dmamap_t dmamap;
+ bus_dma_tag_t parent_dmat;
struct selinfo sel;
};
@@ -116,6 +120,7 @@ typedef int (pcmchan_setspeed_t)(void *data, u_int32_t speed);
typedef int (pcmchan_setblocksize_t)(void *data, u_int32_t blocksize);
typedef int (pcmchan_trigger_t)(void *data, int go);
typedef int (pcmchan_getptr_t)(void *data);
+typedef int (pcmchan_free_t)(void *data);
typedef pcmchan_caps *(pcmchan_getcaps_t)(void *data);
struct _pcm_channel {
@@ -127,6 +132,15 @@ struct _pcm_channel {
pcmchan_trigger_t *trigger;
pcmchan_getptr_t *getptr;
pcmchan_getcaps_t *getcaps;
+ pcmchan_free_t *free;
+ void *nop1;
+ void *nop2;
+ void *nop3;
+ void *nop4;
+ void *nop5;
+ void *nop6;
+ void *nop7;
+
pcm_feeder *feeder;
struct pcm_feederdesc *feederdesc;
u_int32_t align;
@@ -149,7 +163,7 @@ typedef void (pcm_swap_t)(void *data, int dir);
struct _snddev_info {
pcm_channel *play, *rec, **aplay, **arec, fakechan;
int *ref;
- unsigned playcount, reccount, chancount;
+ unsigned playcount, reccount, chancount, maxchans;
snd_mixer mixer;
u_long magic;
unsigned flags;
diff --git a/sys/dev/sound/pcm/mixer.c b/sys/dev/sound/pcm/mixer.c
index 68e45d9..77d3e66 100644
--- a/sys/dev/sound/pcm/mixer.c
+++ b/sys/dev/sound/pcm/mixer.c
@@ -45,8 +45,9 @@ static u_int16_t snd_mixerdefaults[SOUND_MIXER_NRDEVICES] = {
};
int
-mixer_init(snddev_info *d, snd_mixer *m, void *devinfo)
+mixer_init(device_t dev, snd_mixer *m, void *devinfo)
{
+ snddev_info *d = device_get_softc(dev);
if (d == NULL) return -1;
d->mixer = *m;
d->mixer.devinfo = devinfo;
@@ -63,9 +64,23 @@ mixer_init(snddev_info *d, snd_mixer *m, void *devinfo)
}
int
-mixer_reinit(snddev_info *d)
+mixer_uninit(device_t dev)
{
int i;
+ snddev_info *d = device_get_softc(dev);
+ if (d == NULL) return -1;
+ for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
+ mixer_set(d, i, 0);
+ mixer_setrecsrc(d, SOUND_MASK_MIC);
+ if (d->mixer.uninit != NULL) d->mixer.uninit(&d->mixer);
+ return 0;
+}
+
+int
+mixer_reinit(device_t dev)
+{
+ int i;
+ snddev_info *d = device_get_softc(dev);
if (d == NULL) return -1;
if (d->mixer.init != NULL && d->mixer.init(&d->mixer) == 0) {
for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
@@ -75,7 +90,7 @@ mixer_reinit(snddev_info *d)
} else return -1;
}
-int
+static int
mixer_set(snddev_info *d, unsigned dev, unsigned lev)
{
if (d == NULL || d->mixer.set == NULL) return -1;
@@ -88,7 +103,7 @@ mixer_set(snddev_info *d, unsigned dev, unsigned lev)
} else return -1;
}
-int
+static int
mixer_get(snddev_info *d, int dev)
{
if (d == NULL) return -1;
@@ -97,7 +112,7 @@ mixer_get(snddev_info *d, int dev)
else return -1;
}
-int
+static int
mixer_setrecsrc(snddev_info *d, u_int32_t src)
{
if (d == NULL || d->mixer.setrecsrc == NULL) return -1;
@@ -107,7 +122,7 @@ mixer_setrecsrc(snddev_info *d, u_int32_t src)
return 0;
}
-int
+static int
mixer_getrecsrc(snddev_info *d)
{
if (d == NULL) return -1;
@@ -154,6 +169,20 @@ mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg)
return ENXIO;
}
+int
+mixer_busy(snddev_info *d, int busy)
+{
+ if (d == NULL) return -1;
+ d->mixer.busy = busy;
+}
+
+int
+mixer_isbusy(snddev_info *d)
+{
+ if (d == NULL) return -1;
+ return d->mixer.busy;
+}
+
void
mix_setdevs(snd_mixer *m, u_int32_t v)
{
diff --git a/sys/dev/sound/pcm/mixer.h b/sys/dev/sound/pcm/mixer.h
index a0487d5..eb1946b 100644
--- a/sys/dev/sound/pcm/mixer.h
+++ b/sys/dev/sound/pcm/mixer.h
@@ -26,13 +26,12 @@
* $FreeBSD$
*/
-extern int mixer_init(snddev_info *d, snd_mixer *m, void *devinfo);
-extern int mixer_reinit(snddev_info *d);
-extern int mixer_set(snddev_info *d, unsigned dev, unsigned lev);
-extern int mixer_get(snddev_info *d, int dev);
-extern int mixer_setrecsrc(snddev_info *d, u_int32_t src);
-extern int mixer_getrecsrc(snddev_info *d);
+extern int mixer_init(device_t dev, snd_mixer *m, void *devinfo);
+extern int mixer_uninit(device_t dev);
+extern int mixer_reinit(device_t dev);
extern int mixer_ioctl(snddev_info *d, u_long cmd, caddr_t arg);
+extern int mixer_busy(snddev_info *d, int busy);
+extern int mixer_isbusy(snddev_info *d);
extern void change_bits(mixer_tab *t, u_char *regval, int dev, int chn, int newval);
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index b27e2d0..bd9434a 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -31,12 +31,11 @@
#include <sys/sysctl.h>
#include "opt_devfs.h"
+static dev_t status_dev = 0;
static int status_isopen = 0;
static int status_init(char *buf, int size);
static int status_read(struct uio *buf);
-MODULE_VERSION(snd_pcm, PCM_MODVER);
-
static d_open_t sndopen;
static d_close_t sndclose;
static d_ioctl_t sndioctl;
@@ -94,42 +93,133 @@ int snd_unit;
TUNABLE_INT_DECL("hw.sndunit", 0, snd_unit);
#endif
-static snddev_info *
-gsd(int unit)
+#ifdef DEVFS
+static void
+pcm_makelinks(void *dummy)
{
- return devclass_get_softc(pcm_devclass, unit);
+ int unit;
+ dev_t pdev;
+ static dev_t dsp = 0, dspW = 0, audio = 0, mixer = 0;
+
+ if (pcm_devclass == NULL)
+ return;
+ if (dsp) {
+ destroy_dev(dsp);
+ dsp = 0;
+ }
+ if (dspW) {
+ destroy_dev(dspW);
+ dspW = 0;
+ }
+ if (audio) {
+ destroy_dev(audio);
+ audio = 0;
+ }
+ if (mixer) {
+ destroy_dev(mixer);
+ mixer = 0;
+ }
+
+ unit = snd_unit;
+ if (unit < 0 || unit > devclass_get_maxunit(pcm_devclass))
+ return;
+ if (devclass_get_softc(pcm_devclass, unit) == NULL)
+ return;
+
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, 0));
+ dsp = make_dev_alias(pdev, "dsp");
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, 0));
+ dspW = make_dev_alias(pdev, "dspW");
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, 0));
+ audio = make_dev_alias(pdev, "audio");
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0));
+ mixer = make_dev_alias(pdev, "mixer");
}
+static int
+sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS)
+{
+ int error, unit;
+
+ unit = snd_unit;
+ error = sysctl_handle_int(oidp, &unit, sizeof(unit), req);
+ if (error == 0 && req->newptr != NULL) {
+ snd_unit = unit;
+ pcm_makelinks(NULL);
+ }
+ return (error);
+}
+SYSCTL_PROC(_hw, OID_AUTO, sndunit, CTLTYPE_INT | CTLFLAG_RW,
+ 0, sizeof(int), sysctl_hw_sndunit, "I", "");
+#endif
+
int
pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo)
{
- int unit = device_get_unit(dev);
+ int unit = device_get_unit(dev), idx;
snddev_info *d = device_get_softc(dev);
- pcm_channel *ch;
+ pcm_channel *chns, *ch;
+ char *dirs;
+
+ dirs = ((dir == PCMDIR_PLAY)? "play" : "record");
+ chns = ((dir == PCMDIR_PLAY)? d->play : d->rec);
+ idx = ((dir == PCMDIR_PLAY)? d->playcount++ : d->reccount++);
- if (((dir == PCMDIR_PLAY)? d->play : d->rec) == NULL) {
- device_printf(dev, "bad channel add (%s)\n",
- (dir == PCMDIR_PLAY)? "play" : "record");
+ if (chns == NULL) {
+ device_printf(dev, "bad channel add (%s:%d)\n", dirs, idx);
return 1;
}
- ch = (dir == PCMDIR_PLAY)? &d->play[d->playcount] : &d->rec[d->reccount];
+ ch = &chns[idx];
*ch = *templ;
ch->parent = d;
if (chn_init(ch, devinfo, dir)) {
- device_printf(dev, "chn_init() for %s:%d failed\n",
- (dir == PCMDIR_PLAY)? "play" : "record",
- (dir == PCMDIR_PLAY)? d->playcount : d->reccount);
+ device_printf(dev, "chn_init() for (%s:%d) failed\n", dirs, idx);
return 1;
}
- if (dir == PCMDIR_PLAY) d->playcount++; else d->reccount++;
make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount),
UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, d->chancount);
- make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount),
- UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, d->chancount);
make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount),
UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, d->chancount);
+ make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount),
+ UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, d->chancount);
/* XXX SND_DEV_NORESET? */
d->chancount++;
+#ifdef DEVFS
+ if (d->chancount == d->maxchans)
+ pcm_makelinks(NULL);
+#endif
+ return 0;
+}
+
+static int
+pcm_killchan(device_t dev, int dir)
+{
+ int unit = device_get_unit(dev), idx;
+ snddev_info *d = device_get_softc(dev);
+ pcm_channel *chns, *ch;
+ char *dirs;
+ dev_t pdev;
+
+ dirs = ((dir == PCMDIR_PLAY)? "play" : "record");
+ chns = ((dir == PCMDIR_PLAY)? d->play : d->rec);
+ idx = ((dir == PCMDIR_PLAY)? --d->playcount : --d->reccount);
+
+ if (chns == NULL || idx < 0) {
+ device_printf(dev, "bad channel kill (%s:%d)\n", dirs, idx);
+ return 1;
+ }
+ ch = &chns[idx];
+ if (chn_kill(ch)) {
+ device_printf(dev, "chn_kill() for (%s:%d) failed\n", dirs, idx);
+ return 1;
+ }
+ d->chancount--;
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, d->chancount));
+ destroy_dev(pdev);
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, d->chancount));
+ destroy_dev(pdev);
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, d->chancount));
+ destroy_dev(pdev);
return 0;
}
@@ -168,6 +258,7 @@ pcm_setswap(device_t dev, pcm_swap_t *swap)
snddev_info *d = device_get_softc(dev);
d->swap = swap;
}
+
/* This is the generic init routine */
int
pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
@@ -177,7 +268,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
if (!pcm_devclass) {
pcm_devclass = device_get_devclass(dev);
- make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0),
+ status_dev = make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0),
UID_ROOT, GID_WHEEL, 0444, "sndstat");
}
make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
@@ -185,6 +276,7 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
d->dev = dev;
d->devinfo = devinfo;
d->chancount = d->playcount = d->reccount = 0;
+ d->maxchans = numplay + numrec;
sz = (numplay + numrec) * sizeof(pcm_channel *);
if (sz > 0) {
@@ -232,67 +324,44 @@ no:
if (d->play) free(d->play, M_DEVBUF);
if (d->arec) free(d->arec, M_DEVBUF);
if (d->rec) free(d->rec, M_DEVBUF);
+ if (d->ref) free(d->ref, M_DEVBUF);
return ENXIO;
}
-#ifdef DEVFS
-static void
-pcm_makelinks(void *dummy)
+int
+pcm_unregister(device_t dev)
{
- int unit;
+ int r, i, unit = device_get_unit(dev);
+ snddev_info *d = device_get_softc(dev);
dev_t pdev;
- static dev_t dsp = 0, dspW = 0, audio = 0, mixer = 0;
- unit = snd_unit;
- if (unit > devclass_get_maxunit(pcm_devclass))
- unit = -1;
+ r = 0;
+ for (i = 0; i < d->chancount; i++)
+ if (d->ref[i]) r = EBUSY;
+ if (r) return r;
+ if (mixer_isbusy(d) || status_isopen) return EBUSY;
- if (dsp) {
- destroy_dev(dsp);
- dsp = 0;
- }
- if (dspW) {
- destroy_dev(dspW);
- dspW = 0;
- }
- if (audio) {
- destroy_dev(audio);
- audio = 0;
- }
- if (mixer) {
- destroy_dev(mixer);
- mixer = 0;
- }
+ pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0));
+ destroy_dev(pdev);
+ mixer_uninit(dev);
- if (unit >= 0) {
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, 0));
- dsp = make_dev_alias(pdev, "dsp");
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, 0));
- dspW = make_dev_alias(pdev, "dspW");
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, 0));
- audio = make_dev_alias(pdev, "audio");
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_CTL, 0));
- mixer = make_dev_alias(pdev, "mixer");
- }
-}
-SYSINIT(pcm_makelinks, SI_SUB_MOUNT_ROOT, SI_ORDER_ANY, pcm_makelinks, NULL);
+ while (d->playcount > 0)
+ pcm_killchan(dev, PCMDIR_PLAY);
+ while (d->reccount > 0)
+ pcm_killchan(dev, PCMDIR_REC);
+ d->magic = 0;
-static int
-sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS)
-{
- int error, unit;
+ if (d->aplay) free(d->aplay, M_DEVBUF);
+ if (d->play) free(d->play, M_DEVBUF);
+ if (d->arec) free(d->arec, M_DEVBUF);
+ if (d->rec) free(d->rec, M_DEVBUF);
+ if (d->ref) free(d->ref, M_DEVBUF);
- unit = snd_unit;
- error = sysctl_handle_int(oidp, &unit, sizeof(unit), req);
- if (error == 0 && req->newptr != NULL) {
- snd_unit = unit;
- pcm_makelinks(NULL);
- }
- return (error);
-}
-SYSCTL_PROC(_hw, OID_AUTO, sndunit, CTLTYPE_INT | CTLFLAG_RW,
- 0, sizeof(int), sysctl_hw_sndunit, "I", "");
+#ifdef DEVFS
+ pcm_makelinks(NULL);
#endif
+ return 0;
+}
/*
* a small utility function which, given a device number, returns
@@ -302,6 +371,7 @@ SYSCTL_PROC(_hw, OID_AUTO, sndunit, CTLTYPE_INT | CTLFLAG_RW,
static snddev_info *
get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
{
+ snddev_info *sc;
int u, d, c;
u = PCMUNIT(i_dev);
@@ -313,13 +383,16 @@ get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
if (chan) *chan = c;
if (u < 0) return NULL;
- switch(d) {
+ sc = devclass_get_softc(pcm_devclass, u);
+ if (sc == NULL || sc->magic == 0) return NULL;
+
+ switch(d) {
case SND_DEV_CTL: /* /dev/mixer handled by pcm */
case SND_DEV_STATUS: /* /dev/sndstat handled by pcm */
case SND_DEV_DSP:
case SND_DEV_DSP16:
case SND_DEV_AUDIO:
- return gsd(u);
+ return sc;
case SND_DEV_SEQ: /* XXX when enabled... */
case SND_DEV_SEQ2:
@@ -347,7 +420,7 @@ sndopen(dev_t i_dev, int flags, int mode, struct proc *p)
return 0;
case SND_DEV_CTL:
- return d? 0 : ENXIO;
+ return d? mixer_busy(d, 1) : ENXIO;
case SND_DEV_AUDIO:
case SND_DEV_DSP:
@@ -375,7 +448,7 @@ sndclose(dev_t i_dev, int flags, int mode, struct proc *p)
return 0;
case SND_DEV_CTL:
- return d? 0 : ENXIO;
+ return d? mixer_busy(d, 0) : ENXIO;
case SND_DEV_AUDIO:
case SND_DEV_DSP:
@@ -521,7 +594,7 @@ status_init(char *buf, int size)
"Installed devices:\n", __DATE__, __TIME__);
for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) {
- d = gsd(i);
+ d = devclass_get_softc(pcm_devclass, i);
if (!d) continue;
dev = devclass_get_device(pcm_devclass, i);
if (1) {
@@ -558,3 +631,29 @@ status_read(struct uio *buf)
bufptr += l;
return (l > 0)? uiomove(status_buf + bufptr - l, l, buf) : 0;
}
+
+static int
+sndpcm_modevent(module_t mod, int type, void *data)
+{
+
+ switch (type) {
+ case MOD_LOAD:
+ break;
+ case MOD_UNLOAD:
+ if (status_dev)
+ destroy_dev(status_dev);
+ status_dev = 0;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static moduledata_t sndpcm_mod = {
+ "snd_pcm",
+ sndpcm_modevent,
+ NULL
+};
+DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
+MODULE_VERSION(snd_pcm, PCM_MODVER);
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index 0e50926..4bc388e 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -165,6 +165,7 @@ int fkchan_setup(pcm_channel *c);
int pcm_addchan(device_t dev, int dir, pcm_channel *templ, void *devinfo);
int pcm_register(device_t dev, void *devinfo, int numplay, int numrec);
+int pcm_unregister(device_t dev);
int pcm_setstatus(device_t dev, char *str);
u_int32_t pcm_getflags(device_t dev);
void pcm_setflags(device_t dev, u_int32_t val);
OpenPOWER on IntegriCloud