diff options
author | matk <matk@FreeBSD.org> | 2004-01-20 03:58:57 +0000 |
---|---|---|
committer | matk <matk@FreeBSD.org> | 2004-01-20 03:58:57 +0000 |
commit | ebfd4faca3b4486d6e438fc39dacd968ecf9a8cc (patch) | |
tree | eb0f190890fc8154dc34ccf943d093f9426e4057 /sys | |
parent | 1bf3c3e6434fdf234bfa5471a146508c48e6f7f4 (diff) | |
download | FreeBSD-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.c | 135 | ||||
-rw-r--r-- | sys/dev/sound/pcm/dsp.h | 5 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.c | 144 | ||||
-rw-r--r-- | sys/dev/sound/pcm/sound.h | 21 | ||||
-rw-r--r-- | sys/dev/sound/pcm/vchan.c | 7 |
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; |