summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormatk <matk@FreeBSD.org>2004-01-20 03:58:57 +0000
committermatk <matk@FreeBSD.org>2004-01-20 03:58:57 +0000
commitebfd4faca3b4486d6e438fc39dacd968ecf9a8cc (patch)
treeeb0f190890fc8154dc34ccf943d093f9426e4057 /sys
parent1bf3c3e6434fdf234bfa5471a146508c48e6f7f4 (diff)
downloadFreeBSD-src-ebfd4faca3b4486d6e438fc39dacd968ecf9a8cc.zip
FreeBSD-src-ebfd4faca3b4486d6e438fc39dacd968ecf9a8cc.tar.gz
Fix a panic when kldloading a sound driver. Do this by replacing the
link-list of dev_t's with named variables. Remove used code. Approved by: tanimura (mentor)
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/sound/pcm/dsp.c135
-rw-r--r--sys/dev/sound/pcm/dsp.h5
-rw-r--r--sys/dev/sound/pcm/sound.c144
-rw-r--r--sys/dev/sound/pcm/sound.h21
-rw-r--r--sys/dev/sound/pcm/vchan.c7
5 files changed, 95 insertions, 217 deletions
diff --git a/sys/dev/sound/pcm/dsp.c b/sys/dev/sound/pcm/dsp.c
index c6ab830..546041b 100644
--- a/sys/dev/sound/pcm/dsp.c
+++ b/sys/dev/sound/pcm/dsp.c
@@ -41,7 +41,7 @@ static d_ioctl_t dsp_ioctl;
static d_poll_t dsp_poll;
static d_mmap_t dsp_mmap;
-static struct cdevsw dsp_cdevsw = {
+struct cdevsw dsp_cdevsw = {
.d_open = dsp_open,
.d_close = dsp_close,
.d_read = dsp_read,
@@ -1044,101 +1044,23 @@ dsp_mmap(dev_t i_dev, vm_offset_t offset, vm_paddr_t *paddr, int nprot)
return 0;
}
-int
-dsp_register(int unit, int channel)
-{
- dev_t dt;
- int r;
-
- dt = make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP, channel),
- UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d", unit, channel);
- r = pcm_regdevt(dt, unit, SND_DEV_DSP, channel);
- if (r)
- return r;
-
- dt = make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSP16, channel),
- UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d", unit, channel);
- r = pcm_regdevt(dt, unit, SND_DEV_DSP16, channel);
- if (r)
- return r;
-
- dt = make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_AUDIO, channel),
- UID_ROOT, GID_WHEEL, 0666, "audio%d.%d", unit, channel);
- r = pcm_regdevt(dt, unit, SND_DEV_AUDIO, channel);
- if (r)
- return r;
-
- return 0;
-}
-
-int
-dsp_registerrec(int unit, int channel)
-{
- dev_t dt;
- int r;
-
- dt = make_dev(&dsp_cdevsw, PCMMKMINOR(unit, SND_DEV_DSPREC, channel),
- UID_ROOT, GID_WHEEL, 0666, "dspr%d.%d", unit, channel);
-
- r = pcm_regdevt(dt, unit, SND_DEV_DSPREC, channel);
-
- return r;
-}
-
-int
-dsp_unregister(int unit, int channel)
-{
- dev_t pdev;
- int r;
-
- pdev = pcm_getdevt(unit, SND_DEV_DSP, channel);
- if (pdev == NULL)
- return ENOENT;
- destroy_dev(pdev);
- r = pcm_unregdevt(unit, SND_DEV_DSP, channel);
- if (r)
- return r;
-
- pdev = pcm_getdevt(unit, SND_DEV_DSP16, channel);
- if (pdev == NULL)
- return ENOENT;
- destroy_dev(pdev);
- r = pcm_unregdevt(unit, SND_DEV_DSP16, channel);
- if (r)
- return r;
-
- pdev = pcm_getdevt(unit, SND_DEV_AUDIO, channel);
- if (pdev == NULL)
- return ENOENT;
- destroy_dev(pdev);
- r = pcm_unregdevt(unit, SND_DEV_AUDIO, channel);
- if (r)
- return r;
-
- return 0;
-}
-
-int
-dsp_unregisterrec(int unit, int channel)
-{
- dev_t pdev;
- int r;
-
- pdev = pcm_getdevt(unit, SND_DEV_DSPREC, channel);
- if (pdev == NULL)
- return ENOENT;
- destroy_dev(pdev);
- r = pcm_unregdevt(unit, SND_DEV_DSPREC, channel);
-
- return r;
-}
-
#ifdef USING_DEVFS
+
+/*
+ * Clone logic is this:
+ * x E X = {dsp, dspW, audio}
+ * x -> x${sysctl("hw.snd.unit")}
+ * xN->
+ * for i N = 1 to channels of device N
+ * if xN.i isn't busy, return its dev_t
+ */
static void
dsp_clone(void *arg, char *name, int namelen, dev_t *dev)
{
dev_t pdev;
- int i, cont, unit, devtype;
+ struct snddev_info *pcm_dev;
+ struct snddev_channel *pcm_chan;
+ int i, unit, devtype;
int devtypes[3] = {SND_DEV_DSP, SND_DEV_DSP16, SND_DEV_AUDIO};
char *devnames[3] = {"dsp", "dspW", "audio"};
@@ -1161,16 +1083,27 @@ dsp_clone(void *arg, char *name, int namelen, dev_t *dev)
if (unit == -1 || unit >= devclass_get_maxunit(pcm_devclass))
return;
- cont = 1;
- for (i = 0; cont; i++) {
- pdev = pcm_getdevt(unit, devtype, i);
- if (pdev->si_flags & SI_NAMED) {
- if ((pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
- *dev = pdev;
- return;
- }
- } else {
- cont = 0;
+ pcm_dev = devclass_get_softc(pcm_devclass, unit);
+
+ SLIST_FOREACH(pcm_chan, &pcm_dev->channels, link) {
+
+ switch(devtype) {
+ case SND_DEV_DSP:
+ pdev = pcm_chan->dsp_devt;
+ break;
+ case SND_DEV_DSP16:
+ pdev = pcm_chan->dspW_devt;
+ break;
+ case SND_DEV_AUDIO:
+ pdev = pcm_chan->audio_devt;
+ break;
+ default:
+ panic("Unknown devtype %d", devtype);
+ }
+
+ if ((pdev->si_drv1 == NULL) && (pdev->si_drv2 == NULL)) {
+ *dev = pdev;
+ return;
}
}
}
diff --git a/sys/dev/sound/pcm/dsp.h b/sys/dev/sound/pcm/dsp.h
index 5e92d20..0a42e74 100644
--- a/sys/dev/sound/pcm/dsp.h
+++ b/sys/dev/sound/pcm/dsp.h
@@ -26,7 +26,4 @@
* $FreeBSD$
*/
-int dsp_register(int unit, int channel);
-int dsp_registerrec(int unit, int channel);
-int dsp_unregister(int unit, int channel);
-int dsp_unregisterrec(int unit, int channel);
+extern struct cdevsw dsp_cdevsw;
diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c
index 652fb7a..3ba4636 100644
--- a/sys/dev/sound/pcm/sound.c
+++ b/sys/dev/sound/pcm/sound.c
@@ -27,6 +27,7 @@
#include <dev/sound/pcm/sound.h>
#include <dev/sound/pcm/vchan.h>
+#include <dev/sound/pcm/dsp.h>
#include <sys/sysctl.h>
#include "feeder_if.h"
@@ -413,11 +414,20 @@ pcm_chn_destroy(struct pcm_channel *ch)
}
int
-pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev)
+pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch)
{
struct snddev_channel *sce, *tmp, *after;
- int unit = device_get_unit(d->dev);
- int x = -1;
+ int device = device_get_unit(d->dev);
+
+ /*
+ * Note it's confusing nomenclature.
+ * dev_t
+ * device -> pcm_device
+ * unit -> pcm_channel
+ * channel -> snddev_channel
+ * device_t
+ * unit -> pcm_device
+ */
sce = malloc(sizeof(*sce), M_DEVBUF, M_WAITOK | M_ZERO);
if (!sce) {
@@ -426,6 +436,7 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev)
snd_mtxlock(d->lock);
sce->channel = ch;
+ sce->chan_num= d->devcount++;
if (SLIST_EMPTY(&d->channels)) {
SLIST_INSERT_HEAD(&d->channels, sce, link);
} else {
@@ -435,24 +446,35 @@ pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev)
}
SLIST_INSERT_AFTER(after, sce, link);
}
- if (mkdev)
- x = d->devcount++;
snd_mtxunlock(d->lock);
-
- if (mkdev) {
- dsp_register(unit, x);
- if (ch->direction == PCMDIR_REC)
- dsp_registerrec(unit, ch->num);
- }
+ sce->dsp_devt= make_dev(&dsp_cdevsw,
+ PCMMKMINOR(device, SND_DEV_DSP, sce->chan_num),
+ UID_ROOT, GID_WHEEL, 0666, "dsp%d.%d",
+ device, sce->chan_num);
+
+ sce->dspW_devt= make_dev(&dsp_cdevsw,
+ PCMMKMINOR(device, SND_DEV_DSP16, sce->chan_num),
+ UID_ROOT, GID_WHEEL, 0666, "dspW%d.%d",
+ device, sce->chan_num);
+
+ sce->audio_devt= make_dev(&dsp_cdevsw,
+ PCMMKMINOR(device, SND_DEV_AUDIO, sce->chan_num),
+ UID_ROOT, GID_WHEEL, 0666, "audio%d.%d",
+ device, sce->chan_num);
+
+ if (ch->direction == PCMDIR_REC)
+ sce->dspr_devt = make_dev(&dsp_cdevsw,
+ PCMMKMINOR(device, SND_DEV_DSPREC,
+ sce->chan_num), UID_ROOT, GID_WHEEL,
+ 0666, "dspr%d.%d", device, sce->chan_num);
return 0;
}
int
-pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev)
+pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch)
{
struct snddev_channel *sce;
- int unit = device_get_unit(d->dev);
#if 0
int ourlock;
@@ -474,11 +496,6 @@ pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev)
return EINVAL;
gotit:
SLIST_REMOVE(&d->channels, sce, snddev_channel, link);
- if (rmdev) {
- dsp_unregister(unit, --d->devcount);
- if (ch->direction == PCMDIR_REC)
- dsp_unregisterrec(unit, ch->num);
- }
if (ch->direction == PCMDIR_REC)
d->reccount--;
@@ -509,7 +526,7 @@ pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo)
return ENODEV;
}
- err = pcm_chn_add(d, ch, 1);
+ err = pcm_chn_add(d, ch);
if (err) {
device_printf(d->dev, "pcm_chn_add(%s) failed, err=%d\n", ch->name, err);
snd_mtxunlock(d->lock);
@@ -541,7 +558,7 @@ pcm_killchan(device_t dev)
sce = SLIST_FIRST(&d->channels);
ch = sce->channel;
- error = pcm_chn_remove(d, sce->channel, SLIST_EMPTY(&ch->children));
+ error = pcm_chn_remove(d, sce->channel);
if (error)
return (error);
return (pcm_chn_destroy(ch));
@@ -685,6 +702,8 @@ pcm_unregister(device_t dev)
snd_mtxunlock(d->lock);
return EBUSY;
}
+
+
SLIST_FOREACH(sce, &d->channels, link) {
ch = sce->channel;
if (ch->refcount > 0) {
@@ -693,6 +712,15 @@ pcm_unregister(device_t dev)
return EBUSY;
}
}
+
+ SLIST_FOREACH(sce, &d->channels, link) {
+ destroy_dev(sce->dsp_devt);
+ destroy_dev(sce->dspW_devt);
+ destroy_dev(sce->audio_devt);
+ if (sce->dspr_devt)
+ destroy_dev(sce->dspr_devt);
+ }
+
if (mixer_uninit(dev)) {
device_printf(dev, "unregister: mixer busy\n");
snd_mtxunlock(d->lock);
@@ -715,82 +743,6 @@ pcm_unregister(device_t dev)
return 0;
}
-int
-pcm_regdevt(dev_t dev, unsigned unit, unsigned type, unsigned channel)
-{
- struct snddev_info *d;
- struct snddev_devt *dt;
-
- d = devclass_get_softc(pcm_devclass, unit);
- KASSERT((d != NULL), ("bad d"));
- KASSERT((dev != NULL), ("bad dev"));
-
- dt = malloc(sizeof(*dt), M_DEVBUF, M_ZERO | M_WAITOK);
- if (dt == NULL)
- return ENOMEM;
- dt->dev = dev;
- dt->type = type;
- dt->channel = channel;
-
- snd_mtxlock(d->lock);
- SLIST_INSERT_HEAD(&d->devs, dt, link);
- snd_mtxunlock(d->lock);
-
- return 0;
-}
-
-dev_t
-pcm_getdevt(unsigned unit, unsigned type, unsigned channel)
-{
- struct snddev_info *d;
- struct snddev_devt *dt;
-
- d = devclass_get_softc(pcm_devclass, unit);
- KASSERT((d != NULL), ("bad d"));
-
-#if 0
- snd_mtxlock(d->lock);
-#endif
- SLIST_FOREACH(dt, &d->devs, link) {
- if ((dt->type == type) && (dt->channel == channel))
- return dt->dev;
- }
-#if 0
- snd_mtxunlock(d->lock);
-#endif
-
- return NULL;
-}
-
-int
-pcm_unregdevt(unsigned unit, unsigned type, unsigned channel)
-{
- struct snddev_info *d;
- struct snddev_devt *dt;
-
- d = devclass_get_softc(pcm_devclass, unit);
- KASSERT((d != NULL), ("bad d"));
-
-#if 0
- snd_mtxlock(d->lock);
-#endif
- SLIST_FOREACH(dt, &d->devs, link) {
- if ((dt->type == type) && (dt->channel == channel)) {
- SLIST_REMOVE(&d->devs, dt, snddev_devt, link);
- free(dt, M_DEVBUF);
-#if 0
- snd_mtxunlock(d->lock);
-#endif
- return 0;
- }
- }
-#if 0
- snd_mtxunlock(d->lock);
-#endif
-
- return ENOENT;
-}
-
/************************************************************************/
static int
diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h
index f89f1bf..29ddd44 100644
--- a/sys/dev/sound/pcm/sound.h
+++ b/sys/dev/sound/pcm/sound.h
@@ -98,7 +98,6 @@ struct snd_mixer;
#include <dev/sound/pcm/channel.h>
#include <dev/sound/pcm/feeder.h>
#include <dev/sound/pcm/mixer.h>
-#include <dev/sound/pcm/dsp.h>
#define PCM_SOFTC_SIZE 512
@@ -222,8 +221,8 @@ int pcm_inprog(struct snddev_info *d, int delta);
struct pcm_channel *pcm_chn_create(struct snddev_info *d, struct pcm_channel *parent, kobj_class_t cls, int dir, void *devinfo);
int pcm_chn_destroy(struct pcm_channel *ch);
-int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch, int mkdev);
-int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch, int rmdev);
+int pcm_chn_add(struct snddev_info *d, struct pcm_channel *ch);
+int pcm_chn_remove(struct snddev_info *d, struct pcm_channel *ch);
int pcm_addchan(device_t dev, int dir, kobj_class_t cls, void *devinfo);
unsigned int pcm_getbuffersize(device_t dev, unsigned int min, unsigned int deflt, unsigned int max);
@@ -234,9 +233,6 @@ u_int32_t pcm_getflags(device_t dev);
void pcm_setflags(device_t dev, u_int32_t val);
void *pcm_getdevinfo(device_t dev);
-int pcm_regdevt(dev_t dev, unsigned unit, unsigned type, unsigned channel);
-dev_t pcm_getdevt(unsigned unit, unsigned type, unsigned channel);
-int pcm_unregdevt(unsigned unit, unsigned type, unsigned channel);
int snd_setup_intr(device_t dev, struct resource *res, int flags,
driver_intr_t hand, void *param, void **cookiep);
@@ -286,18 +282,15 @@ int sndstat_busy(void);
struct snddev_channel {
SLIST_ENTRY(snddev_channel) link;
struct pcm_channel *channel;
-};
-
-struct snddev_devt {
- SLIST_ENTRY(snddev_devt) link;
- dev_t dev;
- unsigned channel;
- unsigned type;
+ int chan_num;
+ dev_t dsp_devt;
+ dev_t dspW_devt;
+ dev_t audio_devt;
+ dev_t dspr_devt;
};
struct snddev_info {
SLIST_HEAD(, snddev_channel) channels;
- SLIST_HEAD(, snddev_devt) devs;
struct pcm_channel *fakechan;
unsigned devcount, playcount, reccount, vchancount;
unsigned flags;
diff --git a/sys/dev/sound/pcm/vchan.c b/sys/dev/sound/pcm/vchan.c
index 4a70a82..0c5867b 100644
--- a/sys/dev/sound/pcm/vchan.c
+++ b/sys/dev/sound/pcm/vchan.c
@@ -260,7 +260,10 @@ vchan_create(struct pcm_channel *parent)
CHN_UNLOCK(parent);
/* add us to our grandparent's channel list */
- err = pcm_chn_add(d, child, !first);
+ /*
+ * XXX maybe we shouldn't always add the dev_t
+ */
+ err = pcm_chn_add(d, child);
if (err) {
pcm_chn_destroy(child);
free(pce, M_DEVBUF);
@@ -313,7 +316,7 @@ gotch:
parent->flags &= ~CHN_F_BUSY;
/* remove us from our grandparent's channel list */
- err = pcm_chn_remove(d, c, !last);
+ err = pcm_chn_remove(d, c);
if (err)
return err;
OpenPOWER on IntegriCloud