]> err.no Git - linux-2.6/blobdiff - sound/pci/emu10k1/emufx.c
[PATCH] inotify: fix deadlock found by lockdep
[linux-2.6] / sound / pci / emu10k1 / emufx.c
index f4452c5cb4cda195ebf7b0cbb05c41e551fe24f9..dfba00230d4dac5aab2613c0f5ed0cb0add79ce6 100644 (file)
 
 #include <sound/driver.h>
 #include <linux/pci.h>
+#include <linux/capability.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/mutex.h>
+
 #include <sound/core.h>
 #include <sound/emu10k1.h>
 
@@ -872,7 +876,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
 {
        int err = 0;
 
-       down(&emu->fx8010.lock);
+       mutex_lock(&emu->fx8010.lock);
        if ((err = snd_emu10k1_verify_controls(emu, icode)) < 0)
                goto __error;
        strlcpy(emu->fx8010.name, icode->name, sizeof(emu->fx8010.name));
@@ -895,7 +899,7 @@ static int snd_emu10k1_icode_poke(struct snd_emu10k1 *emu,
        else
                snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
       __error:
-       up(&emu->fx8010.lock);
+       mutex_unlock(&emu->fx8010.lock);
        return err;
 }
 
@@ -904,7 +908,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
 {
        int err;
 
-       down(&emu->fx8010.lock);
+       mutex_lock(&emu->fx8010.lock);
        strlcpy(icode->name, emu->fx8010.name, sizeof(icode->name));
        /* ok, do the main job */
        err = snd_emu10k1_gpr_peek(emu, icode);
@@ -914,7 +918,7 @@ static int snd_emu10k1_icode_peek(struct snd_emu10k1 *emu,
                err = snd_emu10k1_code_peek(emu, icode);
        if (err >= 0)
                err = snd_emu10k1_list_controls(emu, icode);
-       up(&emu->fx8010.lock);
+       mutex_unlock(&emu->fx8010.lock);
        return err;
 }
 
@@ -930,7 +934,7 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
        if (ipcm->channels > 32)
                return -EINVAL;
        pcm = &emu->fx8010.pcm[ipcm->substream];
-       down(&emu->fx8010.lock);
+       mutex_lock(&emu->fx8010.lock);
        spin_lock_irq(&emu->reg_lock);
        if (pcm->opened) {
                err = -EBUSY;
@@ -960,7 +964,7 @@ static int snd_emu10k1_ipcm_poke(struct snd_emu10k1 *emu,
        }
       __error:
        spin_unlock_irq(&emu->reg_lock);
-       up(&emu->fx8010.lock);
+       mutex_unlock(&emu->fx8010.lock);
        return err;
 }
 
@@ -974,7 +978,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
        if (ipcm->substream >= EMU10K1_FX8010_PCM_COUNT)
                return -EINVAL;
        pcm = &emu->fx8010.pcm[ipcm->substream];
-       down(&emu->fx8010.lock);
+       mutex_lock(&emu->fx8010.lock);
        spin_lock_irq(&emu->reg_lock);
        ipcm->channels = pcm->channels;
        ipcm->tram_start = pcm->tram_start;
@@ -990,7 +994,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu,
        ipcm->res1 = ipcm->res2 = 0;
        ipcm->pad = 0;
        spin_unlock_irq(&emu->reg_lock);
-       up(&emu->fx8010.lock);
+       mutex_unlock(&emu->fx8010.lock);
        return err;
 }
 
@@ -1071,9 +1075,6 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
        u32 *gpr_map;
        mm_segment_t seg;
 
-       spin_lock_init(&emu->fx8010.irq_lock);
-       INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
-
        if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL ||
            (icode->gpr_map = (u_int32_t __user *)
             kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t),
@@ -1105,6 +1106,14 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu)
        /* stop FX processor */
        snd_emu10k1_ptr_write(emu, A_DBG, 0, (emu->fx8010.dbg = 0) | A_DBG_SINGLE_STEP);
 
+#if 0
+       /* FIX: jcd test */
+       for (z = 0; z < 80; z=z+2) {
+               A_OP(icode, &ptr, iACC3, A_EXTOUT(z), A_FXBUS(FXBUS_PCM_LEFT_FRONT), A_C_00000000, A_C_00000000); /* left */
+               A_OP(icode, &ptr, iACC3, A_EXTOUT(z+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT), A_C_00000000, A_C_00000000); /* right */
+       }
+#endif /* jcd test */
+#if 1
        /* PCM front Playback Volume (independent from stereo mix) */
        A_OP(icode, &ptr, iMAC0, A_GPR(playback), A_C_00000000, A_GPR(gpr), A_FXBUS(FXBUS_PCM_LEFT_FRONT));
        A_OP(icode, &ptr, iMAC0, A_GPR(playback+1), A_C_00000000, A_GPR(gpr+1), A_FXBUS(FXBUS_PCM_RIGHT_FRONT));
@@ -1450,6 +1459,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input))
                A_OP(icode, &ptr, iACC3, A_FXBUS2(z), A_C_00000000, A_C_00000000, A_EXTIN(z));
        }
        
+#endif /* JCD test */
        /*
         * ok, set up done..
         */
@@ -1541,9 +1551,6 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
        u32 *gpr_map;
        mm_segment_t seg;
 
-       spin_lock_init(&emu->fx8010.irq_lock);
-       INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
-
        if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL)
                return -ENOMEM;
        if ((icode->gpr_map = (u_int32_t __user *)
@@ -2102,6 +2109,8 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 
 int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu)
 {
+       spin_lock_init(&emu->fx8010.irq_lock);
+       INIT_LIST_HEAD(&emu->fx8010.gpr_ctl);
        if (emu->audigy)
                return _snd_emu10k1_audigy_init_efx(emu);
        else
@@ -2171,7 +2180,7 @@ int snd_emu10k1_fx8010_tram_setup(struct snd_emu10k1 *emu, u32 size)
                snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
                spin_lock_irq(&emu->emu_lock);
                outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
-               spin_unlock_irq(&emu->emu_lock);        
+               spin_unlock_irq(&emu->emu_lock);
        }
 
        return 0;
@@ -2301,9 +2310,9 @@ static int snd_emu10k1_fx8010_ioctl(struct snd_hwdep * hw, struct file *file, un
                        return -EPERM;
                if (get_user(addr, (unsigned int __user *)argp))
                        return -EFAULT;
-               down(&emu->fx8010.lock);
+               mutex_lock(&emu->fx8010.lock);
                res = snd_emu10k1_fx8010_tram_setup(emu, addr);
-               up(&emu->fx8010.lock);
+               mutex_unlock(&emu->fx8010.lock);
                return res;
        case SNDRV_EMU10K1_IOCTL_STOP:
                if (!capable(CAP_SYS_ADMIN))
@@ -2387,3 +2396,114 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct
                *rhwdep = hw;
        return 0;
 }
+
+#ifdef CONFIG_PM
+int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu)
+{
+       int len;
+
+       len = emu->audigy ? 0x200 : 0x100;
+       emu->saved_gpr = kmalloc(len * 4, GFP_KERNEL);
+       if (! emu->saved_gpr)
+               return -ENOMEM;
+       len = emu->audigy ? 0x100 : 0xa0;
+       emu->tram_val_saved = kmalloc(len * 4, GFP_KERNEL);
+       emu->tram_addr_saved = kmalloc(len * 4, GFP_KERNEL);
+       if (! emu->tram_val_saved || ! emu->tram_addr_saved)
+               return -ENOMEM;
+       len = emu->audigy ? 2 * 1024 : 2 * 512;
+       emu->saved_icode = vmalloc(len * 4);
+       if (! emu->saved_icode)
+               return -ENOMEM;
+       return 0;
+}
+
+void snd_emu10k1_efx_free_pm_buffer(struct snd_emu10k1 *emu)
+{
+       kfree(emu->saved_gpr);
+       kfree(emu->tram_val_saved);
+       kfree(emu->tram_addr_saved);
+       vfree(emu->saved_icode);
+}
+
+/*
+ * save/restore GPR, TRAM and codes
+ */
+void snd_emu10k1_efx_suspend(struct snd_emu10k1 *emu)
+{
+       int i, len;
+
+       len = emu->audigy ? 0x200 : 0x100;
+       for (i = 0; i < len; i++)
+               emu->saved_gpr[i] = snd_emu10k1_ptr_read(emu, emu->gpr_base + i, 0);
+
+       len = emu->audigy ? 0x100 : 0xa0;
+       for (i = 0; i < len; i++) {
+               emu->tram_val_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMDATAREGBASE + i, 0);
+               emu->tram_addr_saved[i] = snd_emu10k1_ptr_read(emu, TANKMEMADDRREGBASE + i, 0);
+               if (emu->audigy) {
+                       emu->tram_addr_saved[i] >>= 12;
+                       emu->tram_addr_saved[i] |=
+                               snd_emu10k1_ptr_read(emu, A_TANKMEMCTLREGBASE + i, 0) << 20;
+               }
+       }
+
+       len = emu->audigy ? 2 * 1024 : 2 * 512;
+       for (i = 0; i < len; i++)
+               emu->saved_icode[i] = snd_emu10k1_efx_read(emu, i);
+}
+
+void snd_emu10k1_efx_resume(struct snd_emu10k1 *emu)
+{
+       int i, len;
+
+       /* set up TRAM */
+       if (emu->fx8010.etram_pages.bytes > 0) {
+               unsigned size, size_reg = 0;
+               size = emu->fx8010.etram_pages.bytes / 2;
+               size = (size - 1) >> 13;
+               while (size) {
+                       size >>= 1;
+                       size_reg++;
+               }
+               outl(HCFG_LOCKTANKCACHE_MASK | inl(emu->port + HCFG), emu->port + HCFG);
+               snd_emu10k1_ptr_write(emu, TCB, 0, emu->fx8010.etram_pages.addr);
+               snd_emu10k1_ptr_write(emu, TCBS, 0, size_reg);
+               outl(inl(emu->port + HCFG) & ~HCFG_LOCKTANKCACHE_MASK, emu->port + HCFG);
+       }
+
+       if (emu->audigy)
+               snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg | A_DBG_SINGLE_STEP);
+       else
+               snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg | EMU10K1_DBG_SINGLE_STEP);
+
+       len = emu->audigy ? 0x200 : 0x100;
+       for (i = 0; i < len; i++)
+               snd_emu10k1_ptr_write(emu, emu->gpr_base + i, 0, emu->saved_gpr[i]);
+
+       len = emu->audigy ? 0x100 : 0xa0;
+       for (i = 0; i < len; i++) {
+               snd_emu10k1_ptr_write(emu, TANKMEMDATAREGBASE + i, 0,
+                                     emu->tram_val_saved[i]);
+               if (! emu->audigy)
+                       snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+                                             emu->tram_addr_saved[i]);
+               else {
+                       snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+                                             emu->tram_addr_saved[i] << 12);
+                       snd_emu10k1_ptr_write(emu, TANKMEMADDRREGBASE + i, 0,
+                                             emu->tram_addr_saved[i] >> 20);
+               }
+       }
+
+       len = emu->audigy ? 2 * 1024 : 2 * 512;
+       for (i = 0; i < len; i++)
+               snd_emu10k1_efx_write(emu, i, emu->saved_icode[i]);
+
+       /* start FX processor when the DSP code is updated */
+       if (emu->audigy)
+               snd_emu10k1_ptr_write(emu, A_DBG, 0, emu->fx8010.dbg);
+       else
+               snd_emu10k1_ptr_write(emu, DBG, 0, emu->fx8010.dbg);
+}
+#endif