[SCSI] iscsi_tcp: fix potential lockup with write commands
[safe/jmp/linux-2.6] / sound / drivers / dummy.c
index a276f7c..e008f3c 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Dummy soundcard
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *
  *   This program is free software; you can redistribute it and/or modify
  *   it under the terms of the GNU General Public License as published by
 #include <linux/moduleparam.h>
 #include <sound/core.h>
 #include <sound/control.h>
+#include <sound/tlv.h>
 #include <sound/pcm.h>
 #include <sound/rawmidi.h>
 #include <sound/initval.h>
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
 MODULE_LICENSE("GPL");
 MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
@@ -92,11 +93,27 @@ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
 #define USE_RATE_MAX           48000
 #endif
 
+#if 0 /* CA0106 */
+#define USE_FORMATS            SNDRV_PCM_FMTBIT_S16_LE
+#define USE_CHANNELS_MIN       2
+#define USE_CHANNELS_MAX       2
+#define USE_RATE               (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) 
+#define USE_RATE_MIN           48000 
+#define USE_RATE_MAX           192000
+#define MAX_BUFFER_SIZE                ((65536-64)*8)
+#define MAX_PERIOD_SIZE                (65536-64)
+#define USE_PERIODS_MIN                2
+#define USE_PERIODS_MAX                8
+#endif
+
 
 /* defaults */
 #ifndef MAX_BUFFER_SIZE
 #define MAX_BUFFER_SIZE                (64*1024)
 #endif
+#ifndef MAX_PERIOD_SIZE
+#define MAX_PERIOD_SIZE                MAX_BUFFER_SIZE
+#endif
 #ifndef USE_FORMATS
 #define USE_FORMATS            (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
 #endif
@@ -144,6 +161,8 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
 //module_param_array(midi_devs, int, NULL, 0444);
 //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
 
+static struct platform_device *devices[SNDRV_CARDS];
+
 #define MIXER_ADDR_MASTER      0
 #define MIXER_ADDR_LINE                1
 #define MIXER_ADDR_MIC         2
@@ -231,8 +250,9 @@ static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream)
 static void snd_card_dummy_pcm_timer_function(unsigned long data)
 {
        struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data;
+       unsigned long flags;
        
-       spin_lock(&dpcm->lock);
+       spin_lock_irqsave(&dpcm->lock, flags);
        dpcm->timer.expires = 1 + jiffies;
        add_timer(&dpcm->timer);
        dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
@@ -240,11 +260,10 @@ static void snd_card_dummy_pcm_timer_function(unsigned long data)
        dpcm->pcm_buf_pos %= dpcm->pcm_size;
        if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
                dpcm->pcm_irq_pos %= dpcm->pcm_count;
-               spin_unlock(&dpcm->lock);
+               spin_unlock_irqrestore(&dpcm->lock, flags);
                snd_pcm_period_elapsed(dpcm->substream);
-               spin_lock(&dpcm->lock);
-       }
-       spin_unlock(&dpcm->lock);
+       } else
+               spin_unlock_irqrestore(&dpcm->lock, flags);
 }
 
 static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream)
@@ -267,7 +286,7 @@ static struct snd_pcm_hardware snd_card_dummy_playback =
        .channels_max =         USE_CHANNELS_MAX,
        .buffer_bytes_max =     MAX_BUFFER_SIZE,
        .period_bytes_min =     64,
-       .period_bytes_max =     MAX_BUFFER_SIZE,
+       .period_bytes_max =     MAX_PERIOD_SIZE,
        .periods_min =          USE_PERIODS_MIN,
        .periods_max =          USE_PERIODS_MAX,
        .fifo_size =            0,
@@ -285,7 +304,7 @@ static struct snd_pcm_hardware snd_card_dummy_capture =
        .channels_max =         USE_CHANNELS_MAX,
        .buffer_bytes_max =     MAX_BUFFER_SIZE,
        .period_bytes_min =     64,
-       .period_bytes_max =     MAX_BUFFER_SIZE,
+       .period_bytes_max =     MAX_PERIOD_SIZE,
        .periods_min =          USE_PERIODS_MIN,
        .periods_max =          USE_PERIODS_MAX,
        .fifo_size =            0,
@@ -404,7 +423,8 @@ static struct snd_pcm_ops snd_card_dummy_capture_ops = {
        .pointer =              snd_card_dummy_pcm_pointer,
 };
 
-static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int substreams)
+static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
+                                       int substreams)
 {
        struct snd_pcm *pcm;
        int err;
@@ -425,10 +445,13 @@ static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int su
 }
 
 #define DUMMY_VOLUME(xname, xindex, addr) \
-{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+  .name = xname, .index = xindex, \
   .info = snd_dummy_volume_info, \
   .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
-  .private_value = addr }
+  .private_value = addr, \
+  .tlv = { .p = db_scale_dummy } }
 
 static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
                                 struct snd_ctl_elem_info *uinfo)
@@ -479,21 +502,15 @@ static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
+static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
+
 #define DUMMY_CAPSRC(xname, xindex, addr) \
 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
   .info = snd_dummy_capsrc_info, \
   .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \
   .private_value = addr }
 
-static int snd_dummy_capsrc_info(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 1;
-       return 0;
-}
+#define snd_dummy_capsrc_info  snd_ctl_boolean_stereo_info
  
 static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_value *ucontrol)
@@ -529,16 +546,16 @@ static struct snd_kcontrol_new snd_dummy_controls[] = {
 DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
 DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
 DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
-DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER),
+DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
 DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
-DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER),
+DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
 DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
-DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER),
+DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
 DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
-DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER)
+DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)
 };
 
-static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy)
+static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
 {
        struct snd_card *card = dummy->card;
        unsigned int idx;
@@ -555,7 +572,7 @@ static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy)
        return 0;
 }
 
-static int __init snd_dummy_probe(struct platform_device *devptr)
+static int __devinit snd_dummy_probe(struct platform_device *devptr)
 {
        struct snd_card *card;
        struct snd_dummy *dummy;
@@ -593,7 +610,7 @@ static int __init snd_dummy_probe(struct platform_device *devptr)
        return err;
 }
 
-static int snd_dummy_remove(struct platform_device *devptr)
+static int __devexit snd_dummy_remove(struct platform_device *devptr)
 {
        snd_card_free(platform_get_drvdata(devptr));
        platform_set_drvdata(devptr, NULL);
@@ -624,7 +641,7 @@ static int snd_dummy_resume(struct platform_device *pdev)
 
 static struct platform_driver snd_dummy_driver = {
        .probe          = snd_dummy_probe,
-       .remove         = snd_dummy_remove,
+       .remove         = __devexit_p(snd_dummy_remove),
 #ifdef CONFIG_PM
        .suspend        = snd_dummy_suspend,
        .resume         = snd_dummy_resume,
@@ -634,6 +651,15 @@ static struct platform_driver snd_dummy_driver = {
        },
 };
 
+static void snd_dummy_unregister_all(void)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(devices); ++i)
+               platform_device_unregister(devices[i]);
+       platform_driver_unregister(&snd_dummy_driver);
+}
+
 static int __init alsa_card_dummy_init(void)
 {
        int i, cards, err;
@@ -642,33 +668,34 @@ static int __init alsa_card_dummy_init(void)
                return err;
 
        cards = 0;
-       for (i = 0; i < SNDRV_CARDS && enable[i]; i++) {
+       for (i = 0; i < SNDRV_CARDS; i++) {
                struct platform_device *device;
+               if (! enable[i])
+                       continue;
                device = platform_device_register_simple(SND_DUMMY_DRIVER,
                                                         i, NULL, 0);
-               if (IS_ERR(device)) {
-                       err = PTR_ERR(device);
-                       goto errout;
+               if (IS_ERR(device))
+                       continue;
+               if (!platform_get_drvdata(device)) {
+                       platform_device_unregister(device);
+                       continue;
                }
+               devices[i] = device;
                cards++;
        }
        if (!cards) {
 #ifdef MODULE
                printk(KERN_ERR "Dummy soundcard not found or device busy\n");
 #endif
-               err = -ENODEV;
-               goto errout;
+               snd_dummy_unregister_all();
+               return -ENODEV;
        }
        return 0;
-
- errout:
-       platform_driver_unregister(&snd_dummy_driver);
-       return err;
 }
 
 static void __exit alsa_card_dummy_exit(void)
 {
-       platform_driver_unregister(&snd_dummy_driver);
+       snd_dummy_unregister_all();
 }
 
 module_init(alsa_card_dummy_init)