Hello All,
        I tried to fix some LOR in -current and attached you will find
some patches.
        I sent these to the -sound list but I didn't get a response.
(Maybe I should mention that I'm also part of the -sound list).  So
now I don't know what's going in with sound and -current.

        Anyway, the fixes are:
        dsp_open: rearrange to only hold one lock at a time
        dsp_close: ditto
        mixer_hwvol_init: delete locking, the only consumer seems to
         be the ess driver and it only call it a creation time, I
         think the device will be stable across the sleepable malloc
         in the dyn. sysctl allocation
        cmi interrupt routine: Release locks while caller chn_intr,
         We could either this or do what emu10k1 does which is have
         no locks at in the interrupt handler.

        Cheers,
        --Mat
-- 
        I don't even know what street Canada is on.
                        - Al Capone
--- dspold.c    Sun Sep 14 17:49:38 2003
+++ dsp.c       Tue Oct 21 14:38:44 2003
@@ -174,6 +174,8 @@
        intrmask_t s;
        u_int32_t fmt;
        int devtype;
+       int rdref;
+       int error;
 
        s = spltty();
        d = dsp_get_info(i_dev);
@@ -209,6 +211,8 @@
                panic("impossible devtype %d", devtype);
        }
 
+       rdref = 0;
+
        /* lock snddev so nobody else can monkey with it */
        pcm_lock(d);
 
@@ -251,67 +255,66 @@
                        return EBUSY;
                }
                /* got a channel, already locked for us */
-       }
-
-       if (flags & FWRITE) {
-               /* open for write */
-               wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
-               if (!wrch) {
-                       /* no channel available */
-                       if (flags & FREAD) {
-                               /* just opened a read channel, release it */
-                               pcm_chnrelease(rdch);
-                       }
-                       /* exit */
-                       pcm_unlock(d);
-                       splx(s);
-                       return EBUSY;
-               }
-               /* got a channel, already locked for us */
-       }
-
-       i_dev->si_drv1 = rdch;
-       i_dev->si_drv2 = wrch;
-
-       /* Bump refcounts, reset and unlock any channels that we just opened,
-        * and then release device lock.
-        */
-       if (flags & FREAD) {
                if (chn_reset(rdch, fmt)) {
                        pcm_chnrelease(rdch);
                        i_dev->si_drv1 = NULL;
-                       if (wrch && (flags & FWRITE)) {
-                               pcm_chnrelease(wrch);
-                               i_dev->si_drv2 = NULL;
-                       }
                        pcm_unlock(d);
                        splx(s);
                        return ENODEV;
                }
+
                if (flags & O_NONBLOCK)
                        rdch->flags |= CHN_F_NBIO;
                pcm_chnref(rdch, 1);
                CHN_UNLOCK(rdch);
+               rdref = 1;
+               /*
+                * Record channel created, ref'ed and unlocked
+                */
        }
+
        if (flags & FWRITE) {
-               if (chn_reset(wrch, fmt)) {
-                       pcm_chnrelease(wrch);
-                       i_dev->si_drv2 = NULL;
-                       if (flags & FREAD) {
-                               CHN_LOCK(rdch);
-                               pcm_chnref(rdch, -1);
-                               pcm_chnrelease(rdch);
-                               i_dev->si_drv1 = NULL;
-                       }
-                       pcm_unlock(d);
-                       splx(s);
-                       return ENODEV;
+           /* open for write */
+           wrch = pcm_chnalloc(d, PCMDIR_PLAY, td->td_proc->p_pid, -1);
+           error = 0;
+
+           if (!wrch)
+               error = EBUSY; /* XXX Right return code? */
+           else if (chn_reset(wrch, fmt))
+               error = ENODEV;
+
+           if (error != 0) {
+               if (wrch) {
+                   /*
+                    * Free play channel
+                    */
+                   pcm_chnrelease(wrch);
+                   i_dev->si_drv2 = NULL;
                }
-               if (flags & O_NONBLOCK)
-                       wrch->flags |= CHN_F_NBIO;
-               pcm_chnref(wrch, 1);
-               CHN_UNLOCK(wrch);
+               if (rdref) {
+                   /*
+                    * Lock, deref and release previously created record channel
+                    */
+                   CHN_LOCK(rdch);
+                   pcm_chnref(rdch, -1);
+                   pcm_chnrelease(rdch);
+                   i_dev->si_drv1 = NULL;
+               }
+
+               pcm_unlock(d);
+               splx(s);
+               return error;
+           }
+
+           if (flags & O_NONBLOCK)
+               wrch->flags |= CHN_F_NBIO;
+           pcm_chnref(wrch, 1);
+           CHN_UNLOCK(wrch);
        }
+
+       i_dev->si_drv1 = rdch;
+       i_dev->si_drv2 = wrch;
+
        pcm_unlock(d);
        splx(s);
        return 0;
--- /home/mat/dsp.c.1.66        Fri Oct 24 18:07:23 2003
+++ /usr/src/sys/dev/sound/pcm/dsp.c    Sat Oct 25 00:24:49 2003
@@ -321,7 +321,7 @@
        struct pcm_channel *rdch, *wrch;
        struct snddev_info *d;
        intrmask_t s;
-       int exit;
+       int refs;
 
        s = spltty();
        d = dsp_get_info(i_dev);
@@ -329,53 +329,57 @@
        rdch = i_dev->si_drv1;
        wrch = i_dev->si_drv2;
 
-       exit = 0;
+       refs = 0;
 
-       /* decrement refcount for each channel, exit if nonzero */
        if (rdch) {
                CHN_LOCK(rdch);
-               if (pcm_chnref(rdch, -1) > 0) {
-                       CHN_UNLOCK(rdch);
-                       exit = 1;
-               }
+               refs += pcm_chnref(rdch, -1);
+               CHN_UNLOCK(rdch);
        }
        if (wrch) {
                CHN_LOCK(wrch);
-               if (pcm_chnref(wrch, -1) > 0) {
-                       CHN_UNLOCK(wrch);
-                       exit = 1;
-               }
-       }
-       if (exit) {
-               pcm_unlock(d);
-               splx(s);
-               return 0;
+               refs += pcm_chnref(wrch, -1);
+               CHN_UNLOCK(wrch);
        }
 
-       /* both refcounts are zero, abort and release */
+       /*
+        * If there are no more references, release the channels.
+        */
+       if ((rdch || wrch) && refs == 0) {
 
-       if (pcm_getfakechan(d))
-               pcm_getfakechan(d)->flags = 0;
+               if (pcm_getfakechan(d))
+                       pcm_getfakechan(d)->flags = 0;
 
-       i_dev->si_drv1 = NULL;
-       i_dev->si_drv2 = NULL;
+               i_dev->si_drv1 = NULL;
+               i_dev->si_drv2 = NULL;
 
-       dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
-       pcm_unlock(d);
+               dsp_set_flags(i_dev, dsp_get_flags(i_dev) & ~SD_F_TRANSIENT);
 
-       if (rdch) {
-               chn_abort(rdch); /* won't sleep */
-               rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
-               chn_reset(rdch, 0);
-               pcm_chnrelease(rdch);
-       }
-       if (wrch) {
-               chn_flush(wrch); /* may sleep */
-               wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
-               chn_reset(wrch, 0);
-               pcm_chnrelease(wrch);
-       }
+               pcm_unlock(d);
 
+               if (rdch) {
+                       CHN_LOCK(rdch);
+                       chn_abort(rdch); /* won't sleep */
+                       rdch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
+                       chn_reset(rdch, 0);
+                       pcm_chnrelease(rdch);
+               }
+               if (wrch) {
+                       CHN_LOCK(wrch);
+                       /*
+                        * XXX: Maybe the right behaviour is to abort on non_block.
+                        * It seems that mplayer flushes the audio queue by quickly
+                        * closing and re-opening.  In FBSD, there's a long pause
+                        * while the audio queue flushes that I presume isn't there in
+                        * linux.
+                        */
+                       chn_flush(wrch); /* may sleep */
+                       wrch->flags &= ~(CHN_F_RUNNING | CHN_F_MAPPED | CHN_F_DEAD);
+                       chn_reset(wrch, 0);
+                       pcm_chnrelease(wrch);
+               }
+       } else 
+               pcm_unlock(d);
        splx(s);
        return 0;
 }
--- mixer.c.old Sat Oct 25 00:29:26 2003
+++ mixer.c     Sat Oct 25 00:30:06 2003
@@ -319,7 +319,6 @@
 
        pdev = mixer_get_devt(dev);
        m = pdev->si_drv1;
-       snd_mtxlock(m->lock);
 
        m->hwvol_mixer = SOUND_MIXER_VOLUME;
        m->hwvol_step = 5;
@@ -330,7 +329,6 @@
             OID_AUTO, "hwvol_mixer", CTLTYPE_STRING | CTLFLAG_RW, m, 0,
            sysctl_hw_snd_hwvol_mixer, "A", "");
 #endif
-       snd_mtxunlock(m->lock);
        return 0;
 }
 
--- /home/mat/cmi.c.1.23        Sat Oct 25 00:22:09 2003
+++ /usr/src/sys/dev/sound/pci/cmi.c    Fri Oct 24 23:49:03 2003
@@ -51,7 +51,7 @@
 
 #include "mixer_if.h"
 
-SND_DECLARE_FILE("$FreeBSD: /repoman/r/ncvs/src/sys/dev/sound/pci/cmi.c,v 1.23 
2003/09/02 17:30:37 jhb Exp $");
+SND_DECLARE_FILE("$FreeBSD: src/sys/dev/sound/pci/cmi.c,v 1.23 2003/09/02 17:30:37 
jhb Exp $");
 
 /* Supported chip ID's */
 #define CMI8338A_PCI_ID   0x010013f6
@@ -516,41 +516,41 @@
 {
        struct sc_info *sc = data;
        u_int32_t intrstat;
+       u_int32_t toclear;
 
        snd_mtxlock(sc->lock);
        intrstat = cmi_rd(sc, CMPCI_REG_INTR_STATUS, 4);
-       if ((intrstat & CMPCI_REG_ANY_INTR) == 0) {
-               goto out;
-       }
-
-       /* Disable interrupts */
-       if (intrstat & CMPCI_REG_CH0_INTR) {
-               cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
-       }
+       if ((intrstat & CMPCI_REG_ANY_INTR) != 0) {
 
-       if (intrstat & CMPCI_REG_CH1_INTR) {
-               cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
-       }
+               toclear = 0;
+               if (intrstat & CMPCI_REG_CH0_INTR) {
+                       toclear |= CMPCI_REG_CH0_INTR_ENABLE;
+                       //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
+               }
 
-       /* Signal interrupts to channel */
-       if (intrstat & CMPCI_REG_CH0_INTR) {
-               chn_intr(sc->pch.channel);
-       }
+               if (intrstat & CMPCI_REG_CH1_INTR) {
+                       toclear |= CMPCI_REG_CH1_INTR_ENABLE;
+                       //cmi_clr4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
+               }
 
-       if (intrstat & CMPCI_REG_CH1_INTR) {
-               chn_intr(sc->rch.channel);
-       }
+               if (toclear) {
+                       cmi_clr4(sc, CMPCI_REG_INTR_CTRL, toclear);
+                       snd_mtxunlock(sc->lock);
+
+                       /* Signal interrupts to channel */
+                       if (intrstat & CMPCI_REG_CH0_INTR) {
+                               chn_intr(sc->pch.channel);
+                       }
+
+                       if (intrstat & CMPCI_REG_CH1_INTR) {
+                               chn_intr(sc->rch.channel);
+                       }
 
-       /* Enable interrupts */
-       if (intrstat & CMPCI_REG_CH0_INTR) {
-               cmi_set4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH0_INTR_ENABLE);
-       }
+                       snd_mtxlock(sc->lock);
+                       cmi_set4(sc, CMPCI_REG_INTR_CTRL, toclear);
 
-       if (intrstat & CMPCI_REG_CH1_INTR) {
-               cmi_set4(sc, CMPCI_REG_INTR_CTRL, CMPCI_REG_CH1_INTR_ENABLE);
+               }
        }
-
-out:
        snd_mtxunlock(sc->lock);
        return;
 }
_______________________________________________
[EMAIL PROTECTED] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-current
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to