summaryrefslogtreecommitdiffstats
path: root/sys/dev/sound/pcm/sound.c
diff options
context:
space:
mode:
authorcg <cg@FreeBSD.org>2001-06-16 21:25:10 +0000
committercg <cg@FreeBSD.org>2001-06-16 21:25:10 +0000
commit4a0664e88e403e97d641f7ad4fd6dab71095bd0b (patch)
treeb90a72aa9539fc95aa3dfcae3c1ed22290a8bec2 /sys/dev/sound/pcm/sound.c
parentb81ba90a5fa7778120861346194bdd1912baa63b (diff)
downloadFreeBSD-src-4a0664e88e403e97d641f7ad4fd6dab71095bd0b.zip
FreeBSD-src-4a0664e88e403e97d641f7ad4fd6dab71095bd0b.tar.gz
use a global devclass for all drivers - i'm not entirely sure why this
worked before. mixer, dsp and sndstat are seperate devices - give them their own cdevsws instead of demuxing requests sent to a single cdevsw. use the si_drv1/si_drv2 fields in dev_t structures for holding information specific to an open instance of mixer/dsp. nuke /dev/{dsp,dspW,audio}[0-9]* links - this functionality is now provided using cloning. various locking fixes.
Diffstat (limited to 'sys/dev/sound/pcm/sound.c')
-rw-r--r--sys/dev/sound/pcm/sound.c602
1 files changed, 16 insertions, 586 deletions
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 3f14d89..ec8c2ed 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -30,70 +30,11 @@
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/vchan.h>
#include <sys/sysctl.h>
-#include <sys/sbuf.h>
-
-#include "feeder_if.h"
-
-#undef SNDSTAT_VERBOSE
-#define PCM_MAXCHANS 256
-
-static dev_t status_dev = 0;
-static int do_status(int action, struct uio *buf);
-
-static d_open_t sndopen;
-static d_close_t sndclose;
-static d_ioctl_t sndioctl;
-static d_read_t sndread;
-static d_write_t sndwrite;
-static d_mmap_t sndmmap;
-static d_poll_t sndpoll;
-
-#define CDEV_MAJOR 30
-static struct cdevsw snd_cdevsw = {
- /* open */ sndopen,
- /* close */ sndclose,
- /* read */ sndread,
- /* write */ sndwrite,
- /* ioctl */ sndioctl,
- /* poll */ sndpoll,
- /* mmap */ sndmmap,
- /* strategy */ nostrategy,
- /* name */ "snd",
- /* maj */ CDEV_MAJOR,
- /* dump */ nodump,
- /* psize */ nopsize,
- /* flags */ D_TRACKCLOSE,
-};
-/*
-PROPOSAL:
-each unit needs:
-status, mixer, dsp, dspW, audio, sequencer, midi-in, seq2, sndproc = 9 devices
-dspW and audio are deprecated.
-dsp needs min 64 channels, will give it 256
-
-minor = (unit << 20) + (dev << 16) + channel
-currently minor = (channel << 16) + (unit << 4) + dev
-
-nomenclature:
- /dev/pcmX/dsp.(0..255)
- /dev/pcmX/dspW
- /dev/pcmX/audio
- /dev/pcmX/status
- /dev/pcmX/mixer
- [etc.]
-*/
-
-#define PCMMINOR(x) (minor(x))
-#define PCMCHAN(x) ((PCMMINOR(x) & 0x00ff0000) >> 16)
-#define PCMUNIT(x) ((PCMMINOR(x) & 0x000000f0) >> 4)
-#define PCMDEV(x) (PCMMINOR(x) & 0x0000000f)
-#define PCMMKMINOR(u, d, c) ((((c) & 0xff) << 16) | (((u) & 0x0f) << 4) | ((d) & 0x0f))
-
-static devclass_t pcm_devclass;
+devclass_t pcm_devclass;
#ifdef USING_DEVFS
-static int snd_unit = 0;
+int snd_unit = 0;
TUNABLE_INT("hw.snd.unit", &snd_unit);
#endif
@@ -213,79 +154,6 @@ pcm_chnref(struct pcm_channel *c, int ref)
}
#ifdef USING_DEVFS
-static void
-snd_setdefaultunit(struct snddev_info *d)
-{
- static dev_t dsp = 0, dspW = 0, audio = 0, mixer = 0;
-
- 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;
- }
-
- if (d == NULL)
- return;
-
- if (d->dspdev)
- dsp = make_dev_alias(d->dspdev, "dsp");
- if (d->dspWdev)
- dspW = make_dev_alias(d->dspWdev, "dspW");
- if (d->audiodev)
- audio = make_dev_alias(d->audiodev, "audio");
- if (d->mixerdev)
- mixer = make_dev_alias(d->mixerdev, "mixer");
-}
-#endif
-
-static void
-pcm_relinkdspunit(struct snddev_info *d)
-{
-#ifdef USING_DEVFS
- int unit = device_get_unit(d->dev);
- dev_t pdev;
-
- if (d->dspdev) {
- destroy_dev(d->dspdev);
- d->dspdev = 0;
- }
- if (d->dspWdev) {
- destroy_dev(d->dspWdev);
- d->dspWdev = 0;
- }
- if (d->audiodev) {
- destroy_dev(d->audiodev);
- d->audiodev = 0;
- }
-
- if (d->defaultchan < d->chancount) {
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP, d->defaultchan));
- d->dspdev = make_dev_alias(pdev, "dsp%d", unit);
-
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_DSP16, d->defaultchan));
- d->dspWdev = make_dev_alias(pdev, "dspW%d", unit);
-
- pdev = makedev(CDEV_MAJOR, PCMMKMINOR(unit, SND_DEV_AUDIO, d->defaultchan));
- d->audiodev = make_dev_alias(pdev, "audio%d", unit);
- }
-
- if (unit == snd_unit)
- snd_setdefaultunit(d);
-#endif
-}
-
-#ifdef USING_DEVFS
static int
sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS)
{
@@ -301,7 +169,6 @@ sysctl_hw_sndunit(SYSCTL_HANDLER_ARGS)
if (d == NULL || d->chancount == 0)
return EINVAL;
snd_unit = unit;
- snd_setdefaultunit(d);
}
return (error);
}
@@ -378,36 +245,9 @@ int
pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
{
struct snddev_channel *sce;
- struct pcm_channel **aplay, **arec;
int unit = device_get_unit(d->dev);
- int cc, sz;
snd_mtxlock(d->lock);
- if (d->chancount == d->maxchans) {
- cc = d->maxchans? d->maxchans * 2 : 2;
- sz = cc * sizeof(struct pcm_channel *);
- aplay = malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
- arec = malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
- if (aplay == NULL || arec == NULL) {
- if (aplay)
- free(aplay, M_DEVBUF);
- if (arec)
- free(arec, M_DEVBUF);
- snd_mtxunlock(d->lock);
- return EINVAL;
- }
- if (d->aplay) {
- bcopy(d->aplay, aplay, d->maxchans * sizeof(struct pcm_channel *));
- free(d->aplay, M_DEVBUF);
- }
- d->aplay = aplay;
- if (d->arec) {
- bcopy(d->arec, arec, d->maxchans * sizeof(struct pcm_channel *));
- free(d->arec, M_DEVBUF);
- }
- d->arec = arec;
- d->maxchans = cc;
- }
sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO);
if (!sce) {
@@ -418,16 +258,8 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
sce->channel = ch;
SLIST_INSERT_HEAD(&d->channels, sce, link);
- 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_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? */
-
- if (d->chancount++ == 0)
- pcm_relinkdspunit(d);
+ dsp_register(unit, d->chancount);
+ d->chancount++;
snd_mtxunlock(d->lock);
@@ -439,7 +271,6 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
{
struct snddev_channel *sce;
int unit = device_get_unit(d->dev);
- dev_t pdev;
snd_mtxlock(d->lock);
SLIST_FOREACH(sce, &d->channels, link) {
@@ -453,14 +284,7 @@ gotit:
SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
free(sce, M_DEVBUF);
- if (d->chancount == 0)
- pcm_relinkdspunit(d);
- 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);
+ dsp_unregister(unit, d->chancount);
snd_mtxunlock(d->lock);
return 0;
@@ -523,13 +347,7 @@ void
pcm_setflags(device_t dev, u_int32_t val)
{
struct snddev_info *d = device_get_softc(dev);
-/*
- if ((val & SD_F_SIMPLEX) && (d->fakechan == NULL)) {
- device_printf(dev, "set simplex mode\n");
- d->fakechan = fkchan_setup(dev);
- chn_init(d->fakechan, NULL, 0);
- }
-*/
+
d->flags = val;
}
@@ -545,42 +363,20 @@ pcm_getdevinfo(device_t dev)
int
pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
{
- int unit = device_get_unit(dev);
struct snddev_info *d = device_get_softc(dev);
d->lock = snd_mtxcreate(device_get_nameunit(dev));
snd_mtxlock(d->lock);
- if (!pcm_devclass) {
- pcm_devclass = device_get_devclass(dev);
- status_dev = make_dev(&snd_cdevsw, PCMMKMINOR(0, SND_DEV_STATUS, 0),
- UID_ROOT, GID_WHEEL, 0444, "sndstat");
- }
-
- d->mixerdev = make_dev(&snd_cdevsw, PCMMKMINOR(unit, SND_DEV_CTL, 0),
- UID_ROOT, GID_WHEEL, 0666, "mixer%d", unit);
- d->dspdev = 0;
- d->dspWdev = 0;
- d->audiodev = 0;
d->dev = dev;
d->devinfo = devinfo;
d->chancount = 0;
d->defaultchan = 0;
- d->maxchans = 0;
- d->aplay = NULL;
- d->arec = NULL;
-/*
- sz = d->maxchans * sizeof(struct pcm_channel *);
+ d->inprog = 0;
- if (sz > 0) {
- d->aplay = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
- d->arec = (struct pcm_channel **)malloc(sz, M_DEVBUF, M_WAITOK | M_ZERO);
- if (!d->arec || !d->aplay) goto no;
- }
-*/
- if (((numplay == 0) || (numrec == 0)) && (numplay != numrec)) {
+ if (((numplay == 0) || (numrec == 0)) && (numplay != numrec))
d->flags |= SD_F_SIMPLEX;
- }
+
d->fakechan = fkchan_setup(dev);
chn_init(d->fakechan, NULL, 0);
@@ -594,19 +390,11 @@ pcm_register(device_t dev, void *devinfo, int numplay, int numrec)
goto no;
}
#endif
-#if 1
if (numplay > 0)
vchan_initsys(d);
-#endif
- snd_setdefaultunit(d);
snd_mtxunlock(d->lock);
return 0;
no:
-/*
- if (d->aplay) free(d->aplay, M_DEVBUF);
- if (d->arec) free(d->arec, M_DEVBUF);
-*/
- /* snd_mtxunlock(d->lock); */
snd_mtxfree(d->lock);
return ENXIO;
}
@@ -614,11 +402,15 @@ no:
int
pcm_unregister(device_t dev)
{
- int unit = device_get_unit(dev);
struct snddev_info *d = device_get_softc(dev);
struct snddev_channel *sce;
snd_mtxlock(d->lock);
+ if (d->inprog) {
+ device_printf(dev, "unregister: operation in progress");
+ snd_mtxunlock(d->lock);
+ return EBUSY;
+ }
SLIST_FOREACH(sce, &d->channels, link) {
if (sce->channel->refcount > 0) {
device_printf(dev, "unregister: channel busy");
@@ -626,7 +418,7 @@ pcm_unregister(device_t dev)
return EBUSY;
}
}
- if (mixer_isbusy(d->mixer)) {
+ if (mixer_uninit(dev)) {
device_printf(dev, "unregister: mixer busy");
snd_mtxunlock(d->lock);
return EBUSY;
@@ -636,381 +428,19 @@ pcm_unregister(device_t dev)
d->sysctl_tree_top = NULL;
sysctl_ctx_free(&d->sysctl_tree);
#endif
- if (unit == snd_unit)
- snd_setdefaultunit(NULL);
- destroy_dev(d->mixerdev);
- mixer_uninit(dev);
-
while (d->chancount > 0)
pcm_killchan(dev);
- if (d->aplay) free(d->aplay, M_DEVBUF);
- if (d->arec) free(d->arec, M_DEVBUF);
-
chn_kill(d->fakechan);
fkchan_kill(d->fakechan);
- /* snd_mtxunlock(d->lock); */
snd_mtxfree(d->lock);
return 0;
}
-/*
- * a small utility function which, given a device number, returns
- * a pointer to the associated struct snddev_info struct, and sets the unit
- * number.
- */
-static struct snddev_info *
-get_snddev_info(dev_t i_dev, int *unit, int *dev, int *chan)
-{
- struct snddev_info *sc;
- int u, d, c;
-
- u = PCMUNIT(i_dev);
- d = PCMDEV(i_dev);
- c = PCMCHAN(i_dev);
- if (u > devclass_get_maxunit(pcm_devclass)) u = -1;
- if (unit) *unit = u;
- if (dev) *dev = d;
- if (chan) *chan = c;
- if (u < 0) return NULL;
-
- sc = devclass_get_softc(pcm_devclass, u);
- if (sc == NULL) 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 sc;
-
- case SND_DEV_SEQ: /* XXX when enabled... */
- case SND_DEV_SEQ2:
- case SND_DEV_MIDIN:
- case SND_DEV_SNDPROC: /* /dev/sndproc handled by pcm */
- default:
- printf("unsupported subdevice %d\n", d);
- return NULL;
- }
-}
-
-static int
-sndopen(dev_t i_dev, int flags, int mode, struct proc *p)
-{
- int dev, unit, chan;
- struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
-
- DEB(printf("open snd%d subdev %d flags 0x%08x mode 0x%08x\n",
- unit, dev, flags, mode));
-
- switch(dev) {
- case SND_DEV_STATUS:
- return do_status(0, NULL);
-
- case SND_DEV_CTL:
- return d? mixer_busy(d->mixer, 1) : ENXIO;
-
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- case SND_DEV_NORESET:
- return d? dsp_open(d, chan, flags, dev, p->p_pid) : ENXIO;
-
- default:
- return ENXIO;
- }
-}
-
-static int
-sndclose(dev_t i_dev, int flags, int mode, struct proc *p)
-{
- int dev, unit, chan;
- struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
-
- DEB(printf("close snd%d subdev %d\n", unit, dev));
-
- switch(dev) { /* only those for which close makes sense */
- case SND_DEV_STATUS:
- return do_status(1, NULL);
-
- case SND_DEV_CTL:
- return d? mixer_busy(d->mixer, 0) : ENXIO;
-
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- return d? dsp_close(d, chan, dev) : ENXIO;
-
- default:
- return ENXIO;
- }
-}
-
-static int
-sndread(dev_t i_dev, struct uio *buf, int flag)
-{
- int dev, unit, chan;
- struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
- DEB(printf("read snd%d subdev %d flag 0x%08x\n", unit, dev, flag));
-
- switch(dev) {
- case SND_DEV_STATUS:
- return do_status(2, buf);
-
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- return d? dsp_read(d, chan, buf, flag) : EBADF;
-
- default:
- return ENXIO;
- }
-}
-
-static int
-sndwrite(dev_t i_dev, struct uio *buf, int flag)
-{
- int dev, unit, chan;
- struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
-
- DEB(printf("write snd%d subdev %d flag 0x%08x\n", unit, dev & 0xf, flag));
-
- switch(dev) { /* only writeable devices */
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- case SND_DEV_AUDIO:
- return d? dsp_write(d, chan, buf, flag) : EBADF;
-
- default:
- return EPERM; /* for non-writeable devices ; */
- }
-}
-
-static int
-sndioctl(dev_t i_dev, u_long cmd, caddr_t arg, int mode, struct proc * p)
-{
- int dev, chan;
- struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
-
- if (d == NULL) return ENXIO;
-
- switch(dev) {
- case SND_DEV_CTL:
- return mixer_ioctl(d, cmd, arg);
-
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- if (IOCGROUP(cmd) == 'M')
- return mixer_ioctl(d, cmd, arg);
- else
- return dsp_ioctl(d, chan, cmd, arg);
-
- default:
- return ENXIO;
- }
-}
-
-static int
-sndpoll(dev_t i_dev, int events, struct proc *p)
-{
- int dev, chan;
- struct snddev_info *d = get_snddev_info(i_dev, NULL, &dev, &chan);
-
- DEB(printf("sndpoll d 0x%p dev 0x%04x events 0x%08x\n", d, dev, events));
-
- if (d == NULL) return ENXIO;
-
- switch(dev) {
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- return dsp_poll(d, chan, events, p);
-
- default:
- return (events &
- (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM)) | POLLHUP;
- }
-}
-
-/*
- * The mmap interface allows access to the play and read buffer,
- * plus the device descriptor.
- * The various blocks are accessible at the following offsets:
- *
- * 0x00000000 ( 0 ) : write buffer ;
- * 0x01000000 (16 MB) : read buffer ;
- * 0x02000000 (32 MB) : device descriptor (dangerous!)
- *
- * WARNING: the mmap routines assume memory areas are aligned. This
- * is true (probably) for the dma buffers, but likely false for the
- * device descriptor. As a consequence, we do not know where it is
- * located in the requested area.
- */
-static int
-sndmmap(dev_t i_dev, vm_offset_t offset, int nprot)
-{
- int unit, dev, chan;
- struct snddev_info *d = get_snddev_info(i_dev, &unit, &dev, &chan);
-
- DEB(printf("sndmmap d 0x%p dev 0x%04x ofs 0x%08x nprot 0x%08x\n",
- d, dev, offset, nprot));
-
- if (d == NULL || nprot & PROT_EXEC) return -1; /* forbidden */
-
- switch(dev) {
- case SND_DEV_AUDIO:
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- return dsp_mmap(d, chan, offset, nprot);
-
- default:
- return -1;
- }
-}
-
-static int
-status_init(struct sbuf *s)
-{
- int i, pc, rc, vc;
- device_t dev;
- struct snddev_info *d;
- struct snddev_channel *sce;
- struct pcm_channel *c;
-#ifdef SNDSTAT_VERBOSE
- struct pcm_feeder *f;
-#endif
-
- sbuf_printf(s, "FreeBSD Audio Driver (newpcm) %s %s\nInstalled devices:\n",
- __DATE__, __TIME__);
-
- for (i = 0; i <= devclass_get_maxunit(pcm_devclass); i++) {
- d = devclass_get_softc(pcm_devclass, i);
- if (!d)
- continue;
- snd_mtxlock(d->lock);
- dev = devclass_get_device(pcm_devclass, i);
- sbuf_printf(s, "pcm%d: <%s> %s", i, device_get_desc(dev), d->status);
- if (d->chancount > 0) {
- pc = rc = vc = 0;
- SLIST_FOREACH(sce, &d->channels, link) {
- c = sce->channel;
- if (c->direction == PCMDIR_PLAY) {
- if (c->flags & CHN_F_VIRTUAL)
- vc++;
- else
- pc++;
- } else
- rc++;
- }
- sbuf_printf(s, " (%dp/%dr/%dv channels%s%s)\n", pc, rc, vc,
- (d->flags & SD_F_SIMPLEX)? "" : " duplex",
-#ifdef USING_DEVFS
- (i == snd_unit)? " default" : ""
-#else
- ""
-#endif
- );
-#ifdef SNDSTAT_VERBOSE
- SLIST_FOREACH(sce, &d->channels, link) {
- c = sce->channel;
- sbuf_printf(s, "\t%s[%s]: speed %d, format %08x, flags %08x",
- c->parentchannel? c->parentchannel->name : "",
- c->name, c->speed, c->format, c->flags);
- if (c->pid != -1)
- sbuf_printf(s, ", pid %d", c->pid);
- sbuf_printf(s, "\n\t");
- f = c->feeder;
- while (f) {
- sbuf_printf(s, "%s", f->class->name);
- if (f->desc->type == FEEDER_FMT)
- sbuf_printf(s, "(%08x <- %08x)", f->desc->out, f->desc->in);
- if (f->desc->type == FEEDER_RATE)
- sbuf_printf(s, "(%d <- %d)", FEEDER_GET(f, FEEDRATE_DST), FEEDER_GET(f, FEEDRATE_SRC));
- if (f->desc->type == FEEDER_ROOT || f->desc->type == FEEDER_MIXER)
- sbuf_printf(s, "(%08x)", f->desc->out);
- if (f->source)
- sbuf_printf(s, " <- ");
- f = f->source;
- }
- sbuf_printf(s, "\n");
- }
-#endif
- } else
- sbuf_printf(s, " (mixer only)\n");
- snd_mtxunlock(d->lock);
- }
- sbuf_finish(s);
- return sbuf_len(s);
-}
-
-static int
-do_status(int action, struct uio *buf)
-{
- static struct sbuf s;
- static int bufptr = 0;
- static int status_open = 0;
- int l, err;
-
- switch(action) {
- case 0: /* open */
- if (status_open)
- return EBUSY;
- if (sbuf_new(&s, NULL, 4096, 0) == NULL)
- return ENXIO;
- bufptr = 0;
- err = (status_init(&s) > 0)? 0 : ENOMEM;
- if (!err)
- status_open = 1;
- return err;
-
- case 1: /* close */
- if (!status_open)
- return EBADF;
- sbuf_delete(&s);
- status_open = 0;
- return 0;
-
- case 2:
- if (!status_open)
- return EBADF;
- l = min(buf->uio_resid, sbuf_len(&s) - bufptr);
- err = (l > 0)? uiomove(sbuf_data(&s) + bufptr, l, buf) : 0;
- bufptr += l;
- return err;
-
- case 3:
- return status_open;
- }
-
- return EBADF;
-}
-
-static int
-sndpcm_modevent(module_t mod, int type, void *data)
-{
-
- switch (type) {
- case MOD_LOAD:
- break;
- case MOD_UNLOAD:
- if (do_status(3, NULL))
- return EBUSY;
- 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,
NULL
};
DECLARE_MODULE(snd_pcm, sndpcm_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE);
OpenPOWER on IntegriCloud