Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/pci-2.6
[sfrench/cifs-2.6.git] / sound / sh / aica.c
index 739786529ca5e8b834425d809773629c296a3a13..d49417bf78c693dc115390cd14d6c54d84fd8c7f 100644 (file)
@@ -35,7 +35,6 @@
 #include <linux/timer.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
-#include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
@@ -106,11 +105,14 @@ static void spu_write_wait(void)
 static void spu_memset(u32 toi, u32 what, int length)
 {
        int i;
+       unsigned long flags;
        snd_assert(length % 4 == 0, return);
        for (i = 0; i < length; i++) {
                if (!(i % 8))
                        spu_write_wait();
+               local_irq_save(flags);
                writel(what, toi + SPU_MEMORY_BASE);
+               local_irq_restore(flags);
                toi++;
        }
 }
@@ -118,6 +120,7 @@ static void spu_memset(u32 toi, u32 what, int length)
 /* spu_memload - write to SPU address space */
 static void spu_memload(u32 toi, void *from, int length)
 {
+       unsigned long flags;
        u32 *froml = from;
        u32 __iomem *to = (u32 __iomem *) (SPU_MEMORY_BASE + toi);
        int i;
@@ -128,7 +131,9 @@ static void spu_memload(u32 toi, void *from, int length)
                if (!(i % 8))
                        spu_write_wait();
                val = *froml;
+               local_irq_save(flags);
                writel(val, to);
+               local_irq_restore(flags);
                froml++;
                to++;
        }
@@ -138,28 +143,36 @@ static void spu_memload(u32 toi, void *from, int length)
 static void spu_disable(void)
 {
        int i;
+       unsigned long flags;
        u32 regval;
        spu_write_wait();
        regval = readl(ARM_RESET_REGISTER);
        regval |= 1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
        for (i = 0; i < 64; i++) {
                spu_write_wait();
                regval = readl(SPU_REGISTER_BASE + (i * 0x80));
                regval = (regval & ~0x4000) | 0x8000;
                spu_write_wait();
+               local_irq_save(flags);
                writel(regval, SPU_REGISTER_BASE + (i * 0x80));
+               local_irq_restore(flags);
        }
 }
 
 /* spu_enable - set spu registers to enable sound output */
 static void spu_enable(void)
 {
+       unsigned long flags;
        u32 regval = readl(ARM_RESET_REGISTER);
        regval &= ~1;
        spu_write_wait();
+       local_irq_save(flags);
        writel(regval, ARM_RESET_REGISTER);
+       local_irq_restore(flags);
 }
 
 /* 
@@ -168,25 +181,34 @@ static void spu_enable(void)
 */
 static void spu_reset(void)
 {
+       unsigned long flags;
        spu_disable();
        spu_memset(0, 0, 0x200000 / 4);
        /* Put ARM7 in endless loop */
+       local_irq_save(flags);
        ctrl_outl(0xea000002, SPU_MEMORY_BASE);
+       local_irq_restore(flags);
        spu_enable();
 }
 
 /* aica_chn_start - write to spu to start playback */
 static void aica_chn_start(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_START, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* aica_chn_halt - write to spu to halt playback */
 static void aica_chn_halt(void)
 {
+       unsigned long flags;
        spu_write_wait();
+       local_irq_save(flags);
        writel(AICA_CMD_KICK | AICA_CMD_STOP, (u32 *) AICA_CONTROL_POINT);
+       local_irq_restore(flags);
 }
 
 /* ALSA code below */
@@ -213,12 +235,14 @@ static int aica_dma_transfer(int channels, int buffer_size,
        int q, err, period_offset;
        struct snd_card_aica *dreamcastcard;
        struct snd_pcm_runtime *runtime;
+       unsigned long flags;
        err = 0;
        dreamcastcard = substream->pcm->private_data;
        period_offset = dreamcastcard->clicks;
        period_offset %= (AICA_PERIOD_NUMBER / channels);
        runtime = substream->runtime;
        for (q = 0; q < channels; q++) {
+               local_irq_save(flags);
                err = dma_xfer(AICA_DMA_CHANNEL,
                               (unsigned long) (runtime->dma_area +
                                                (AICA_BUFFER_SIZE * q) /
@@ -228,9 +252,12 @@ static int aica_dma_transfer(int channels, int buffer_size,
                               AICA_CHANNEL0_OFFSET + q * CHANNEL_OFFSET +
                               AICA_PERIOD_SIZE * period_offset,
                               buffer_size / channels, AICA_DMA_MODE);
-               if (unlikely(err < 0))
+               if (unlikely(err < 0)) {
+                       local_irq_restore(flags);
                        break;
+               }
                dma_wait_for_completion(AICA_DMA_CHANNEL);
+               local_irq_restore(flags);
        }
        return err;
 }
@@ -451,15 +478,7 @@ static int __init snd_aicapcmchip(struct snd_card_aica
 }
 
 /* Mixer controls */
-static int aica_pcmswitch_info(struct snd_kcontrol *kcontrol,
-                              struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
+#define aica_pcmswitch_info            snd_ctl_boolean_mono_info
 
 static int aica_pcmswitch_get(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
@@ -503,11 +522,14 @@ static int aica_pcmvolume_put(struct snd_kcontrol *kcontrol,
                              struct snd_ctl_elem_value *ucontrol)
 {
        struct snd_card_aica *dreamcastcard;
+       unsigned int vol;
        dreamcastcard = kcontrol->private_data;
        if (unlikely(!dreamcastcard->channel))
                return -ETXTBSY;
-       if (unlikely(dreamcastcard->channel->vol ==
-                    ucontrol->value.integer.value[0]))
+       vol = ucontrol->value.integer.value[0];
+       if (vol > 0xff)
+               return -EINVAL;
+       if (unlikely(dreamcastcard->channel->vol == vol))
                return 0;
        dreamcastcard->channel->vol = ucontrol->value.integer.value[0];
        dreamcastcard->master_volume = ucontrol->value.integer.value[0];