Ignore:
Timestamp:
Mar 24, 2008, 2:43:42 AM (17 years ago)
Author:
Paul Smedley
Message:

Update source to ALSA 1.0.16 level

File:
1 edited

Legend:

Unmodified
Added
Removed
  • GPL/branches/uniaud-2.0/alsa-kernel/drivers/dummy.c

    r135 r305  
    11/*
    22 *  Dummy soundcard
    3  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
     3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
    44 *
    55 *   This program is free software; you can redistribute it and/or modify
     
    1515 *   You should have received a copy of the GNU General Public License
    1616 *   along with this program; if not, write to the Free Software
    17  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     17 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
    1818 *
    1919 */
    2020
    21 #define SNDRV_MAIN_OBJECT_FILE
    22 #include <sound/driver.h>
     21#include <linux/init.h>
     22#include <linux/err.h>
     23#include <linux/platform_device.h>
     24#include <linux/jiffies.h>
     25#include <linux/slab.h>
     26#include <linux/time.h>
     27#include <linux/wait.h>
     28#include <linux/moduleparam.h>
     29#include <sound/core.h>
    2330#include <sound/control.h>
     31#include <sound/tlv.h>
    2432#include <sound/pcm.h>
    2533#include <sound/rawmidi.h>
    26 #define SNDRV_GET_ID
    2734#include <sound/initval.h>
    2835
    29 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
     36MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
    3037MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
    3138MODULE_LICENSE("GPL");
    32 MODULE_CLASSES("{sound}");
    33 MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
     39MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
    3440
    3541#define MAX_PCM_DEVICES         4
     
    3743#define MAX_MIDI_DEVICES        2
    3844
     45#if 0 /* emu10k1 emulation */
     46#define MAX_BUFFER_SIZE         (128 * 1024)
     47static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
     48{
     49        int err;
     50        if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
     51                return err;
     52        if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0)
     53                return err;
     54        return 0;
     55}
     56#define add_playback_constraints emu10k1_playback_constraints
     57#endif
    3958
    4059#if 0 /* RME9652 emulation */
     
    7493#endif
    7594
     95#if 0 /* CA0106 */
     96#define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
     97#define USE_CHANNELS_MIN        2
     98#define USE_CHANNELS_MAX        2
     99#define USE_RATE                (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000)
     100#define USE_RATE_MIN            48000
     101#define USE_RATE_MAX            192000
     102#define MAX_BUFFER_SIZE         ((65536-64)*8)
     103#define MAX_PERIOD_SIZE         (65536-64)
     104#define USE_PERIODS_MIN         2
     105#define USE_PERIODS_MAX         8
     106#endif
     107
    76108
    77109/* defaults */
    78110#ifndef MAX_BUFFER_SIZE
    79111#define MAX_BUFFER_SIZE         (64*1024)
     112#endif
     113#ifndef MAX_PERIOD_SIZE
     114#define MAX_PERIOD_SIZE         MAX_BUFFER_SIZE
    80115#endif
    81116#ifndef USE_FORMATS
     
    99134#define USE_PERIODS_MAX         1024
    100135#endif
     136#ifndef add_playback_constraints
     137#define add_playback_constraints(x) 0
     138#endif
     139#ifndef add_capture_constraints
     140#define add_capture_constraints(x) 0
     141#endif
    101142
    102143static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
    103144static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
    104 #if 0
    105145static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
    106146static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
    107147static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
    108 #else
    109 static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
    110 static int pcm_devs[SNDRV_CARDS] = SNDDRV_DEFAULT_PCM_DEVS;
    111 static int pcm_substreams[SNDRV_CARDS] = SNDDRV_DEFAULT_PCM_SUBSTREAMS;
    112 #endif
    113148//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
    114149
    115 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
     150module_param_array(index, int, NULL, 0444);
    116151MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
    117 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
    118 MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
     152module_param_array(id, charp, NULL, 0444);
    119153MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
    120 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
    121 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
     154module_param_array(enable, bool, NULL, 0444);
    122155MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
    123 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
    124 MODULE_PARM(pcm_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
     156module_param_array(pcm_devs, int, NULL, 0444);
    125157MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
    126 MODULE_PARM_SYNTAX(pcm_devs, SNDRV_ENABLED ",allows:{{0,4}},default:1,dialog:list");
    127 MODULE_PARM(pcm_substreams, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
     158module_param_array(pcm_substreams, int, NULL, 0444);
    128159MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
    129 MODULE_PARM_SYNTAX(pcm_substreams, SNDRV_ENABLED ",allows:{{1,16}},default:8,dialog:list");
    130 //MODULE_PARM(midi_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
     160//module_param_array(midi_devs, int, NULL, 0444);
    131161//MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
    132 //MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{0,2}},default:8,dialog:list");
     162
     163static struct platform_device *devices[SNDRV_CARDS];
     164
    133165#define MIXER_ADDR_MASTER       0
    134166#define MIXER_ADDR_LINE         1
     
    138170#define MIXER_ADDR_LAST         4
    139171
    140 typedef struct snd_card_dummy {
    141     snd_card_t *card;
    142     spinlock_t mixer_lock;
    143     int mixer_volume[MIXER_ADDR_LAST+1][2];
    144     int capture_source[MIXER_ADDR_LAST+1][2];
    145 } snd_card_dummy_t;
    146 
    147 typedef struct snd_card_dummy_pcm {
    148     snd_card_dummy_t *dummy;
    149     spinlock_t lock;
    150     struct timer_list timer;
    151     unsigned int pcm_size;
    152     unsigned int pcm_count;
    153     unsigned int pcm_bps;               /* bytes per second */
    154     unsigned int pcm_jiffie;    /* bytes per one jiffie */
    155     unsigned int pcm_irq_pos;   /* IRQ position */
    156     unsigned int pcm_buf_pos;   /* position in buffer */
    157     snd_pcm_substream_t *substream;
    158 } snd_card_dummy_pcm_t;
    159 
    160 static snd_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
    161 
    162 
    163 static int snd_card_dummy_playback_ioctl(snd_pcm_substream_t * substream,
    164                                          unsigned int cmd,
    165                                          void *arg)
    166 {
    167     return snd_pcm_lib_ioctl(substream, cmd, arg);
    168 }
    169 
    170 static int snd_card_dummy_capture_ioctl(snd_pcm_substream_t * substream,
    171                                         unsigned int cmd,
    172                                         void *arg)
    173 {
    174     return snd_pcm_lib_ioctl(substream, cmd, arg);
    175 }
    176 
    177 static void snd_card_dummy_pcm_timer_start(snd_pcm_substream_t * substream)
    178 {
    179     snd_pcm_runtime_t *runtime = substream->runtime;
    180     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    181 
    182     dpcm->timer.expires = 1 + jiffies;
    183     add_timer(&dpcm->timer);
    184 }
    185 
    186 static void snd_card_dummy_pcm_timer_stop(snd_pcm_substream_t * substream)
    187 {
    188     snd_pcm_runtime_t *runtime = substream->runtime;
    189     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    190 
    191     del_timer(&dpcm->timer);
    192 }
    193 
    194 static int snd_card_dummy_playback_trigger(snd_pcm_substream_t * substream,
    195                                            int cmd)
    196 {
    197     if (cmd == SNDRV_PCM_TRIGGER_START) {
    198         snd_card_dummy_pcm_timer_start(substream);
    199     } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
    200         snd_card_dummy_pcm_timer_stop(substream);
    201     } else {
    202         return -EINVAL;
    203     }
    204     return 0;
    205 }
    206 
    207 static int snd_card_dummy_capture_trigger(snd_pcm_substream_t * substream,
    208                                           int cmd)
    209 {
    210     if (cmd == SNDRV_PCM_TRIGGER_START) {
    211         snd_card_dummy_pcm_timer_start(substream);
    212     } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
    213         snd_card_dummy_pcm_timer_stop(substream);
    214     } else {
    215         return -EINVAL;
    216     }
    217     return 0;
    218 }
    219 
    220 static int snd_card_dummy_pcm_prepare(snd_pcm_substream_t * substream)
    221 {
    222     snd_pcm_runtime_t *runtime = substream->runtime;
    223     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    224     unsigned int bps;
    225 
    226     bps = runtime->rate * runtime->channels;
    227     bps *= snd_pcm_format_width(runtime->format);
    228     bps /= 8;
    229     if (bps == 0)
    230         return -EINVAL;
    231     dpcm->pcm_bps = bps;
    232     dpcm->pcm_jiffie = bps / HZ;
    233     dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
    234     dpcm->pcm_count = snd_pcm_lib_period_bytes(substream);
    235     dpcm->pcm_irq_pos = 0;
    236     dpcm->pcm_buf_pos = 0;
    237     return 0;
    238 }
    239 
    240 static int snd_card_dummy_playback_prepare(snd_pcm_substream_t * substream)
    241 {
    242     return snd_card_dummy_pcm_prepare(substream);
    243 }
    244 
    245 static int snd_card_dummy_capture_prepare(snd_pcm_substream_t * substream)
    246 {
    247     return snd_card_dummy_pcm_prepare(substream);
     172struct snd_dummy {
     173        struct snd_card *card;
     174        struct snd_pcm *pcm;
     175        spinlock_t mixer_lock;
     176        int mixer_volume[MIXER_ADDR_LAST+1][2];
     177        int capture_source[MIXER_ADDR_LAST+1][2];
     178};
     179
     180struct snd_dummy_pcm {
     181        struct snd_dummy *dummy;
     182        spinlock_t lock;
     183        struct timer_list timer;
     184        unsigned int pcm_size;
     185        unsigned int pcm_count;
     186        unsigned int pcm_bps;           /* bytes per second */
     187        unsigned int pcm_jiffie;        /* bytes per one jiffie */
     188        unsigned int pcm_irq_pos;       /* IRQ position */
     189        unsigned int pcm_buf_pos;       /* position in buffer */
     190        struct snd_pcm_substream *substream;
     191};
     192
     193
     194static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm)
     195{
     196        dpcm->timer.expires = 1 + jiffies;
     197        add_timer(&dpcm->timer);
     198}
     199
     200static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm)
     201{
     202        del_timer(&dpcm->timer);
     203}
     204
     205static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
     206{
     207        struct snd_pcm_runtime *runtime = substream->runtime;
     208        struct snd_dummy_pcm *dpcm = runtime->private_data;
     209        int err = 0;
     210
     211        spin_lock(&dpcm->lock);
     212        switch (cmd) {
     213        case SNDRV_PCM_TRIGGER_START:
     214        case SNDRV_PCM_TRIGGER_RESUME:
     215                snd_card_dummy_pcm_timer_start(dpcm);
     216                break;
     217        case SNDRV_PCM_TRIGGER_STOP:
     218        case SNDRV_PCM_TRIGGER_SUSPEND:
     219                snd_card_dummy_pcm_timer_stop(dpcm);
     220                break;
     221        default:
     222                err = -EINVAL;
     223                break;
     224        }
     225        spin_unlock(&dpcm->lock);
     226        return 0;
     227}
     228
     229static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream)
     230{
     231        struct snd_pcm_runtime *runtime = substream->runtime;
     232        struct snd_dummy_pcm *dpcm = runtime->private_data;
     233        unsigned int bps;
     234
     235        bps = runtime->rate * runtime->channels;
     236        bps *= snd_pcm_format_width(runtime->format);
     237        bps /= 8;
     238        if (bps <= 0)
     239                return -EINVAL;
     240        dpcm->pcm_bps = bps;
     241        dpcm->pcm_jiffie = bps / HZ;
     242        dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
     243        dpcm->pcm_count = snd_pcm_lib_period_bytes(substream);
     244        dpcm->pcm_irq_pos = 0;
     245        dpcm->pcm_buf_pos = 0;
     246        return 0;
    248247}
    249248
    250249static void snd_card_dummy_pcm_timer_function(unsigned long data)
    251250{
    252     snd_card_dummy_pcm_t *dpcm = (snd_card_dummy_pcm_t *)data;
    253 
    254     dpcm->timer.expires = 1 + jiffies;
    255     add_timer(&dpcm->timer);
    256     spin_lock_irq(&dpcm->lock);
    257     dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
    258     dpcm->pcm_buf_pos += dpcm->pcm_jiffie;
    259     dpcm->pcm_buf_pos %= dpcm->pcm_size;
    260     if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
    261         dpcm->pcm_irq_pos %= dpcm->pcm_count;
    262         snd_pcm_period_elapsed(dpcm->substream);
    263     }
    264     spin_unlock_irq(&dpcm->lock);
    265 }
    266 
    267 static snd_pcm_uframes_t snd_card_dummy_playback_pointer(snd_pcm_substream_t * substream)
    268 {
    269     snd_pcm_runtime_t *runtime = substream->runtime;
    270     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    271 
    272     return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
    273 }
    274 
    275 static snd_pcm_uframes_t snd_card_dummy_capture_pointer(snd_pcm_substream_t * substream)
    276 {
    277     snd_pcm_runtime_t *runtime = substream->runtime;
    278     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    279 
    280     return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
    281 }
    282 
    283 static snd_pcm_hardware_t snd_card_dummy_playback =
    284 {
    285     /*  info:             */   (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
    286                                 SNDRV_PCM_INFO_MMAP_VALID),
    287                                 /*      formats:          */    USE_FORMATS,
    288                                 /*      rates:            */    USE_RATE,
    289                                 /*      rate_min:         */    USE_RATE_MIN,
    290                                 /*      rate_max:         */    USE_RATE_MAX,
    291                                 /*      channels_min:     */    USE_CHANNELS_MIN,
    292                                 /*      channels_max:     */    USE_CHANNELS_MAX,
    293                                 /*      buffer_bytes_max: */    MAX_BUFFER_SIZE,
    294                                 /*      period_bytes_min: */    64,
    295                                 /*      period_bytes_max: */    MAX_BUFFER_SIZE,
    296                                 /*      periods_min:      */    USE_PERIODS_MIN,
    297                                 /*      periods_max:      */    USE_PERIODS_MAX,
    298                                 /*      fifo_size:        */    0,
     251        struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data;
     252        unsigned long flags;
     253       
     254        spin_lock_irqsave(&dpcm->lock, flags);
     255        dpcm->timer.expires = 1 + jiffies;
     256        add_timer(&dpcm->timer);
     257        dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
     258        dpcm->pcm_buf_pos += dpcm->pcm_jiffie;
     259        dpcm->pcm_buf_pos %= dpcm->pcm_size;
     260        if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
     261                dpcm->pcm_irq_pos %= dpcm->pcm_count;
     262                spin_unlock_irqrestore(&dpcm->lock, flags);
     263                snd_pcm_period_elapsed(dpcm->substream);
     264        } else
     265                spin_unlock_irqrestore(&dpcm->lock, flags);
     266}
     267
     268static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream)
     269{
     270        struct snd_pcm_runtime *runtime = substream->runtime;
     271        struct snd_dummy_pcm *dpcm = runtime->private_data;
     272
     273        return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
     274}
     275
     276static struct snd_pcm_hardware snd_card_dummy_playback =
     277{
     278        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
     279                                 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
     280        .formats =              USE_FORMATS,
     281        .rates =                USE_RATE,
     282        .rate_min =             USE_RATE_MIN,
     283        .rate_max =             USE_RATE_MAX,
     284        .channels_min =         USE_CHANNELS_MIN,
     285        .channels_max =         USE_CHANNELS_MAX,
     286        .buffer_bytes_max =     MAX_BUFFER_SIZE,
     287        .period_bytes_min =     64,
     288        .period_bytes_max =     MAX_PERIOD_SIZE,
     289        .periods_min =          USE_PERIODS_MIN,
     290        .periods_max =          USE_PERIODS_MAX,
     291        .fifo_size =            0,
    299292};
    300293
    301 static snd_pcm_hardware_t snd_card_dummy_capture =
    302 {
    303     /*  info:             */    (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
    304                                 SNDRV_PCM_INFO_MMAP_VALID),
    305                                  /*     formats:          */    USE_FORMATS,
    306                                  /*     rates:            */    USE_RATE,
    307                                  /*     rate_min:         */    USE_RATE_MIN,
    308                                  /*     rate_max:         */    USE_RATE_MAX,
    309                                  /*     channels_min:     */    USE_CHANNELS_MIN,
    310                                  /*     channels_max:     */    USE_CHANNELS_MAX,
    311                                  /*     buffer_bytes_max: */    MAX_BUFFER_SIZE,
    312                                  /*     period_bytes_min: */    64,
    313                                  /*     period_bytes_max: */    MAX_BUFFER_SIZE,
    314                                  /*     periods_min:      */    USE_PERIODS_MIN,
    315                                  /*     periods_max:      */    USE_PERIODS_MAX,
    316                                  /*     fifo_size:        */    0,
     294static struct snd_pcm_hardware snd_card_dummy_capture =
     295{
     296        .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
     297                                 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID),
     298        .formats =              USE_FORMATS,
     299        .rates =                USE_RATE,
     300        .rate_min =             USE_RATE_MIN,
     301        .rate_max =             USE_RATE_MAX,
     302        .channels_min =         USE_CHANNELS_MIN,
     303        .channels_max =         USE_CHANNELS_MAX,
     304        .buffer_bytes_max =     MAX_BUFFER_SIZE,
     305        .period_bytes_min =     64,
     306        .period_bytes_max =     MAX_PERIOD_SIZE,
     307        .periods_min =          USE_PERIODS_MIN,
     308        .periods_max =          USE_PERIODS_MAX,
     309        .fifo_size =            0,
    317310};
    318311
    319 static void snd_card_dummy_runtime_free(snd_pcm_runtime_t *runtime)
    320 {
    321     snd_card_dummy_pcm_t *dpcm = runtime->private_data;
    322     kfree(dpcm);
    323 }
    324 
    325 // 12 Jun 07 SHL fixme to be in some .h
    326 extern void * snd_malloc_pages_fallback(size_t size, unsigned int flags, size_t *res_size);
    327 
    328 static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream)
    329 {
    330     snd_pcm_runtime_t *runtime = substream->runtime;
    331     snd_card_dummy_pcm_t *dpcm;
    332 
    333     dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL);
    334     if (dpcm == NULL)
    335         return -ENOMEM;
    336     if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) {
    337         kfree(dpcm);
    338         return -ENOMEM;
    339     }
    340     init_timer(&dpcm->timer);
    341     dpcm->timer.data = (unsigned long) dpcm;
    342     dpcm->timer.function = snd_card_dummy_pcm_timer_function;
    343     spin_lock_init(&dpcm->lock);
    344     dpcm->substream = substream;
    345     runtime->private_data = dpcm;
    346     runtime->private_free = snd_card_dummy_runtime_free;
    347     runtime->hw = snd_card_dummy_playback;
    348     if (substream->pcm->device & 1) {
    349         runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
    350         runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
    351     }
    352     if (substream->pcm->device & 2)
    353         runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
    354     return 0;
    355 }
    356 
    357 static int snd_card_dummy_capture_open(snd_pcm_substream_t * substream)
    358 {
    359     snd_pcm_runtime_t *runtime = substream->runtime;
    360     snd_card_dummy_pcm_t *dpcm;
    361 
    362     dpcm = kcalloc(1, sizeof(*dpcm), GFP_KERNEL);
    363     if (dpcm == NULL)
    364         return -ENOMEM;
    365     if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) {
    366         kfree(dpcm);
    367         return -ENOMEM;
    368     }
    369     memset(runtime->dma_area, 0, runtime->dma_bytes);
    370     init_timer(&dpcm->timer);
    371     dpcm->timer.data = (unsigned long) dpcm;
    372     dpcm->timer.function = snd_card_dummy_pcm_timer_function;
    373     spin_lock_init(&dpcm->lock);
    374     dpcm->substream = substream;
    375     runtime->private_data = dpcm;
    376     runtime->private_free = snd_card_dummy_runtime_free;
    377     runtime->hw = snd_card_dummy_capture;
    378     if (substream->pcm->device == 1) {
    379         runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
    380         runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
    381     }
    382     if (substream->pcm->device & 2)
    383         runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
    384     return 0;
    385 }
    386 
    387 static int snd_card_dummy_playback_close(snd_pcm_substream_t * substream)
    388 {
    389     snd_pcm_runtime_t *runtime = substream->runtime;
    390 
    391     snd_free_pages(runtime->dma_area, runtime->dma_bytes);
    392     return 0;
    393 }
    394 
    395 static int snd_card_dummy_capture_close(snd_pcm_substream_t * substream)
    396 {
    397     snd_pcm_runtime_t *runtime = substream->runtime;
    398 
    399     snd_free_pages(runtime->dma_area, runtime->dma_bytes);
    400     return 0;
    401 }
    402 
    403 static snd_pcm_ops_t snd_card_dummy_playback_ops = {
    404     /*  open:           */      snd_card_dummy_playback_open,
    405     /*  close:          */      snd_card_dummy_playback_close,
    406     /*  ioctl:          */      snd_card_dummy_playback_ioctl,
    407     NULL, NULL,
    408     /*  prepare:        */      snd_card_dummy_playback_prepare,
    409     /*  trigger:        */      snd_card_dummy_playback_trigger,
    410     /*  pointer:        */      snd_card_dummy_playback_pointer,
    411     NULL, NULL
     312static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime)
     313{
     314        kfree(runtime->private_data);
     315}
     316
     317static int snd_card_dummy_hw_params(struct snd_pcm_substream *substream,
     318                                    struct snd_pcm_hw_params *hw_params)
     319{
     320        return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
     321}
     322
     323static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream)
     324{
     325        return snd_pcm_lib_free_pages(substream);
     326}
     327
     328static struct snd_dummy_pcm *new_pcm_stream(struct snd_pcm_substream *substream)
     329{
     330        struct snd_dummy_pcm *dpcm;
     331
     332        dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
     333        if (! dpcm)
     334                return dpcm;
     335        init_timer(&dpcm->timer);
     336        dpcm->timer.data = (unsigned long) dpcm;
     337        dpcm->timer.function = snd_card_dummy_pcm_timer_function;
     338        spin_lock_init(&dpcm->lock);
     339        dpcm->substream = substream;
     340        return dpcm;
     341}
     342
     343static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream)
     344{
     345        struct snd_pcm_runtime *runtime = substream->runtime;
     346        struct snd_dummy_pcm *dpcm;
     347        int err;
     348
     349        if ((dpcm = new_pcm_stream(substream)) == NULL)
     350                return -ENOMEM;
     351        runtime->private_data = dpcm;
     352        runtime->private_free = snd_card_dummy_runtime_free;
     353        runtime->hw = snd_card_dummy_playback;
     354        if (substream->pcm->device & 1) {
     355                runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
     356                runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
     357        }
     358        if (substream->pcm->device & 2)
     359                runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
     360        if ((err = add_playback_constraints(runtime)) < 0) {
     361                kfree(dpcm);
     362                return err;
     363        }
     364
     365        return 0;
     366}
     367
     368static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream)
     369{
     370        struct snd_pcm_runtime *runtime = substream->runtime;
     371        struct snd_dummy_pcm *dpcm;
     372        int err;
     373
     374        if ((dpcm = new_pcm_stream(substream)) == NULL)
     375                return -ENOMEM;
     376        runtime->private_data = dpcm;
     377        runtime->private_free = snd_card_dummy_runtime_free;
     378        runtime->hw = snd_card_dummy_capture;
     379        if (substream->pcm->device == 1) {
     380                runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
     381                runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
     382        }
     383        if (substream->pcm->device & 2)
     384                runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
     385        if ((err = add_capture_constraints(runtime)) < 0) {
     386                kfree(dpcm);
     387                return err;
     388        }
     389
     390        return 0;
     391}
     392
     393static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream)
     394{
     395        return 0;
     396}
     397
     398static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream)
     399{
     400        return 0;
     401}
     402
     403static struct snd_pcm_ops snd_card_dummy_playback_ops = {
     404        .open =                 snd_card_dummy_playback_open,
     405        .close =                snd_card_dummy_playback_close,
     406        .ioctl =                snd_pcm_lib_ioctl,
     407        .hw_params =            snd_card_dummy_hw_params,
     408        .hw_free =              snd_card_dummy_hw_free,
     409        .prepare =              snd_card_dummy_pcm_prepare,
     410        .trigger =              snd_card_dummy_pcm_trigger,
     411        .pointer =              snd_card_dummy_pcm_pointer,
    412412};
    413413
    414 static snd_pcm_ops_t snd_card_dummy_capture_ops = {
    415     /*  open:           */      snd_card_dummy_capture_open,
    416     /*  close:          */      snd_card_dummy_capture_close,
    417     /*  ioctl:          */      snd_card_dummy_capture_ioctl,
    418     NULL, NULL,
    419     /*  prepare:        */      snd_card_dummy_capture_prepare,
    420     /*  trigger:        */      snd_card_dummy_capture_trigger,
    421     /*  pointer:        */      snd_card_dummy_capture_pointer,
    422     NULL, NULL
     414static struct snd_pcm_ops snd_card_dummy_capture_ops = {
     415        .open =                 snd_card_dummy_capture_open,
     416        .close =                snd_card_dummy_capture_close,
     417        .ioctl =                snd_pcm_lib_ioctl,
     418        .hw_params =            snd_card_dummy_hw_params,
     419        .hw_free =              snd_card_dummy_hw_free,
     420        .prepare =              snd_card_dummy_pcm_prepare,
     421        .trigger =              snd_card_dummy_pcm_trigger,
     422        .pointer =              snd_card_dummy_pcm_pointer,
    423423};
    424424
    425 static int __init snd_card_dummy_pcm(snd_card_dummy_t *dummy, int device, int substreams)
    426 {
    427     snd_pcm_t *pcm;
    428     int err;
    429 
    430     if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, substreams, substreams, &pcm)) < 0)
    431         return err;
    432     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
    433     snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops);
    434     pcm->private_data = dummy;
    435     pcm->info_flags = 0;
    436     strcpy(pcm->name, "Dummy PCM");
    437     return 0;
    438 }
     425static int __devinit snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
     426                                        int substreams)
     427{
     428        struct snd_pcm *pcm;
     429        int err;
     430
     431        if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device,
     432                               substreams, substreams, &pcm)) < 0)
     433                return err;
     434        dummy->pcm = pcm;
     435        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
     436        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops);
     437        pcm->private_data = dummy;
     438        pcm->info_flags = 0;
     439        strcpy(pcm->name, "Dummy PCM");
     440        snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
     441                                              snd_dma_continuous_data(GFP_KERNEL),
     442                                              0, 64*1024);
     443        return 0;
     444}
     445
    439446#define DUMMY_VOLUME(xname, xindex, addr) \
    440     { SNDRV_CTL_ELEM_IFACE_MIXER, 0, 0, xname, xindex, \
    441     0, 0, snd_dummy_volume_info, \
    442     snd_dummy_volume_get, snd_dummy_volume_put, \
    443     0, \
    444     addr }
    445 
    446 static int snd_dummy_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
    447 {
    448     uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
    449     uinfo->count = 2;
    450     uinfo->value.integer.min = -50;
    451     uinfo->value.integer.max = 100;
    452     return 0;
    453 }
    454 
    455 static int snd_dummy_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
    456 {
    457     snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol);
    458     unsigned long flags;
    459     int addr = kcontrol->private_value;
    460 
    461     spin_lock_irqsave(&dummy->mixer_lock, flags);
    462     ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
    463     ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
    464     spin_unlock_irqrestore(&dummy->mixer_lock, flags);
    465     return 0;
    466 }
    467 
    468 static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
    469 {
    470     snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol);
    471     unsigned long flags;
    472     int change, addr = kcontrol->private_value;
    473     int left, right;
    474 
    475     left = ucontrol->value.integer.value[0];
    476     if (left < -50)
    477         left = -50;
    478     if (left > 100)
    479         left = 100;
    480     right = ucontrol->value.integer.value[1];
    481     if (right < -50)
    482         right = -50;
    483     if (right > 100)
    484         right = 100;
    485     spin_lock_irqsave(&dummy->mixer_lock, flags);
    486     change = dummy->mixer_volume[addr][0] != left ||
    487         dummy->mixer_volume[addr][1] != right;
    488     dummy->mixer_volume[addr][0] = left;
    489     dummy->mixer_volume[addr][1] = right;
    490     spin_unlock_irqrestore(&dummy->mixer_lock, flags);
    491     return change;
    492 }
     447{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
     448  .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
     449  .name = xname, .index = xindex, \
     450  .info = snd_dummy_volume_info, \
     451  .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
     452  .private_value = addr, \
     453  .tlv = { .p = db_scale_dummy } }
     454
     455static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
     456                                 struct snd_ctl_elem_info *uinfo)
     457{
     458        uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
     459        uinfo->count = 2;
     460        uinfo->value.integer.min = -50;
     461        uinfo->value.integer.max = 100;
     462        return 0;
     463}
     464 
     465static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,
     466                                struct snd_ctl_elem_value *ucontrol)
     467{
     468        struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
     469        int addr = kcontrol->private_value;
     470
     471        spin_lock_irq(&dummy->mixer_lock);
     472        ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
     473        ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
     474        spin_unlock_irq(&dummy->mixer_lock);
     475        return 0;
     476}
     477
     478static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
     479                                struct snd_ctl_elem_value *ucontrol)
     480{
     481        struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
     482        int change, addr = kcontrol->private_value;
     483        int left, right;
     484
     485        left = ucontrol->value.integer.value[0];
     486        if (left < -50)
     487                left = -50;
     488        if (left > 100)
     489                left = 100;
     490        right = ucontrol->value.integer.value[1];
     491        if (right < -50)
     492                right = -50;
     493        if (right > 100)
     494                right = 100;
     495        spin_lock_irq(&dummy->mixer_lock);
     496        change = dummy->mixer_volume[addr][0] != left ||
     497                 dummy->mixer_volume[addr][1] != right;
     498        dummy->mixer_volume[addr][0] = left;
     499        dummy->mixer_volume[addr][1] = right;
     500        spin_unlock_irq(&dummy->mixer_lock);
     501        return change;
     502}
     503
     504static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
    493505
    494506#define DUMMY_CAPSRC(xname, xindex, addr) \
    495     { SNDRV_CTL_ELEM_IFACE_MIXER, 0, 0, xname, xindex, \
    496     0, 0, snd_dummy_capsrc_info, \
    497     snd_dummy_capsrc_get, snd_dummy_capsrc_put, \
    498     addr }
    499 
    500 static int snd_dummy_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
    501 {
    502     uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
    503     uinfo->count = 2;
    504     uinfo->value.integer.min = 0;
    505     uinfo->value.integer.max = 1;
    506     return 0;
    507 }
    508 
    509 static int snd_dummy_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
    510 {
    511     snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol);
    512     unsigned long flags;
    513     int addr = kcontrol->private_value;
    514 
    515     spin_lock_irqsave(&dummy->mixer_lock, flags);
    516     ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
    517     ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
    518     spin_unlock_irqrestore(&dummy->mixer_lock, flags);
    519     return 0;
    520 }
    521 
    522 static int snd_dummy_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
    523 {
    524     snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol);
    525     unsigned long flags;
    526     int change, addr = kcontrol->private_value;
    527     int left, right;
    528 
    529     left = ucontrol->value.integer.value[0] & 1;
    530     right = ucontrol->value.integer.value[1] & 1;
    531     spin_lock_irqsave(&dummy->mixer_lock, flags);
    532     change = dummy->capture_source[addr][0] != left &&
    533         dummy->capture_source[addr][1] != right;
    534     dummy->capture_source[addr][0] = left;
    535     dummy->capture_source[addr][1] = right;
    536     spin_unlock_irqrestore(&dummy->mixer_lock, flags);
    537     return change;
    538 }
    539 
    540 #define DUMMY_CONTROLS (sizeof(snd_dummy_controls)/sizeof(snd_kcontrol_new_t))
    541 
    542 static snd_kcontrol_new_t snd_dummy_controls[] = {
    543     DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
    544     DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
    545     DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
    546     DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER),
    547     DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
    548     DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER),
    549     DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
    550     DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER),
    551     DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
    552     DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER)
     507{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
     508  .info = snd_dummy_capsrc_info, \
     509  .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \
     510  .private_value = addr }
     511
     512#define snd_dummy_capsrc_info   snd_ctl_boolean_stereo_info
     513 
     514static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
     515                                struct snd_ctl_elem_value *ucontrol)
     516{
     517        struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
     518        int addr = kcontrol->private_value;
     519
     520        spin_lock_irq(&dummy->mixer_lock);
     521        ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
     522        ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
     523        spin_unlock_irq(&dummy->mixer_lock);
     524        return 0;
     525}
     526
     527static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
     528{
     529        struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
     530        int change, addr = kcontrol->private_value;
     531        int left, right;
     532
     533        left = ucontrol->value.integer.value[0] & 1;
     534        right = ucontrol->value.integer.value[1] & 1;
     535        spin_lock_irq(&dummy->mixer_lock);
     536        change = dummy->capture_source[addr][0] != left &&
     537                 dummy->capture_source[addr][1] != right;
     538        dummy->capture_source[addr][0] = left;
     539        dummy->capture_source[addr][1] = right;
     540        spin_unlock_irq(&dummy->mixer_lock);
     541        return change;
     542}
     543
     544static struct snd_kcontrol_new snd_dummy_controls[] = {
     545DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
     546DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
     547DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
     548DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
     549DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
     550DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
     551DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
     552DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
     553DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
     554DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)
    553555};
    554556
    555 int __init snd_card_dummy_new_mixer(snd_card_dummy_t * dummy)
    556 {
    557     snd_card_t *card = dummy->card;
    558     unsigned int idx;
    559     int err;
    560 
    561     snd_assert(dummy != NULL, return -EINVAL);
    562     spin_lock_init(&dummy->mixer_lock);
    563     strcpy(card->mixername, "Dummy Mixer");
    564 
    565     for (idx = 0; idx < DUMMY_CONTROLS; idx++) {
    566         if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0)
    567             return err;
    568     }
    569     return 0;
    570 }
    571 
    572 static int __init snd_card_dummy_probe(int dev)
    573 {
    574     snd_card_t *card;
    575     struct snd_card_dummy *dummy;
    576     int idx, err;
    577 
    578     if (!enable[dev])
    579         return -ENODEV;
    580     card = snd_card_new(index[dev], id[dev], THIS_MODULE,
    581                         sizeof(struct snd_card_dummy));
    582     if (card == NULL)
    583         return -ENOMEM;
    584     dummy = (struct snd_card_dummy *)card->private_data;
    585     dummy->card = card;
    586     for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
    587         if (pcm_substreams[dev] < 1)
    588             pcm_substreams[dev] = 1;
    589         if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
    590             pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
    591         if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0)
    592             goto __nodev;
    593     }
    594     if ((err = snd_card_dummy_new_mixer(dummy)) < 0)
    595         goto __nodev;
    596     strcpy(card->driver, "Dummy");
    597     strcpy(card->shortname, "Dummy");
    598     sprintf(card->longname, "Dummy %i", dev + 1);
    599     if ((err = snd_card_register(card)) == 0) {
    600         snd_dummy_cards[dev] = card;
    601         return 0;
    602     }
    603 __nodev:
    604     snd_card_free(card);
    605     return err;
     557static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy)
     558{
     559        struct snd_card *card = dummy->card;
     560        unsigned int idx;
     561        int err;
     562
     563        snd_assert(dummy != NULL, return -EINVAL);
     564        spin_lock_init(&dummy->mixer_lock);
     565        strcpy(card->mixername, "Dummy Mixer");
     566
     567        for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
     568                if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0)
     569                        return err;
     570        }
     571        return 0;
     572}
     573
     574static int __devinit snd_dummy_probe(struct platform_device *devptr)
     575{
     576        struct snd_card *card;
     577        struct snd_dummy *dummy;
     578        int idx, err;
     579        int dev = devptr->id;
     580
     581        card = snd_card_new(index[dev], id[dev], THIS_MODULE,
     582                            sizeof(struct snd_dummy));
     583        if (card == NULL)
     584                return -ENOMEM;
     585        dummy = card->private_data;
     586        dummy->card = card;
     587        for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
     588                if (pcm_substreams[dev] < 1)
     589                        pcm_substreams[dev] = 1;
     590                if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
     591                        pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
     592                if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0)
     593                        goto __nodev;
     594        }
     595        if ((err = snd_card_dummy_new_mixer(dummy)) < 0)
     596                goto __nodev;
     597        strcpy(card->driver, "Dummy");
     598        strcpy(card->shortname, "Dummy");
     599        sprintf(card->longname, "Dummy %i", dev + 1);
     600
     601        snd_card_set_dev(card, &devptr->dev);
     602
     603        if ((err = snd_card_register(card)) == 0) {
     604                platform_set_drvdata(devptr, card);
     605                return 0;
     606        }
     607      __nodev:
     608        snd_card_free(card);
     609        return err;
     610}
     611
     612static int __devexit snd_dummy_remove(struct platform_device *devptr)
     613{
     614        snd_card_free(platform_get_drvdata(devptr));
     615        platform_set_drvdata(devptr, NULL);
     616        return 0;
     617}
     618
     619#ifdef CONFIG_PM
     620static int snd_dummy_suspend(struct platform_device *pdev, pm_message_t state)
     621{
     622        struct snd_card *card = platform_get_drvdata(pdev);
     623        struct snd_dummy *dummy = card->private_data;
     624
     625        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
     626        snd_pcm_suspend_all(dummy->pcm);
     627        return 0;
     628}
     629       
     630static int snd_dummy_resume(struct platform_device *pdev)
     631{
     632        struct snd_card *card = platform_get_drvdata(pdev);
     633
     634        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
     635        return 0;
     636}
     637#endif
     638
     639#define SND_DUMMY_DRIVER        "snd_dummy"
     640
     641static struct platform_driver snd_dummy_driver = {
     642        .probe          = snd_dummy_probe,
     643        .remove         = __devexit_p(snd_dummy_remove),
     644#ifdef CONFIG_PM
     645        .suspend        = snd_dummy_suspend,
     646        .resume         = snd_dummy_resume,
     647#endif
     648        .driver         = {
     649                .name   = SND_DUMMY_DRIVER
     650        },
     651};
     652
     653static void snd_dummy_unregister_all(void)
     654{
     655        int i;
     656
     657        for (i = 0; i < ARRAY_SIZE(devices); ++i)
     658                platform_device_unregister(devices[i]);
     659        platform_driver_unregister(&snd_dummy_driver);
    606660}
    607661
    608662static int __init alsa_card_dummy_init(void)
    609663{
    610     int dev, cards;
    611 
    612     for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
    613         if (snd_card_dummy_probe(dev) < 0) {
     664        int i, cards, err;
     665
     666        if ((err = platform_driver_register(&snd_dummy_driver)) < 0)
     667                return err;
     668
     669        cards = 0;
     670        for (i = 0; i < SNDRV_CARDS; i++) {
     671                struct platform_device *device;
     672                if (! enable[i])
     673                        continue;
     674                device = platform_device_register_simple(SND_DUMMY_DRIVER,
     675                                                         i, NULL, 0);
     676                if (IS_ERR(device))
     677                        continue;
     678                if (!platform_get_drvdata(device)) {
     679                        platform_device_unregister(device);
     680                        continue;
     681                }
     682                devices[i] = device;
     683                cards++;
     684        }
     685        if (!cards) {
    614686#ifdef MODULE
    615             snd_printk("Dummy soundcard #%i not found or device busy\n", dev + 1);
    616 #endif
    617             break;
    618         }
    619         cards++;
    620     }
    621     if (!cards) {
    622 #ifdef MODULE
    623         snd_printk("Dummy soundcard not found or device busy\n");
    624 #endif
    625         return -ENODEV;
    626     }
    627     return 0;
     687                printk(KERN_ERR "Dummy soundcard not found or device busy\n");
     688#endif
     689                snd_dummy_unregister_all();
     690                return -ENODEV;
     691        }
     692        return 0;
    628693}
    629694
    630695static void __exit alsa_card_dummy_exit(void)
    631696{
    632     int idx;
    633 
    634     for (idx = 0; idx < SNDRV_CARDS; idx++)
    635         snd_card_free(snd_dummy_cards[idx]);
     697        snd_dummy_unregister_all();
    636698}
    637699
    638700module_init(alsa_card_dummy_init)
    639701module_exit(alsa_card_dummy_exit)
    640 
    641 #ifndef MODULE
    642 
    643 /* format is: snd-card-dummy=snd_enable,snd_index,snd_id,
    644  snd_pcm_devs,snd_pcm_substreams */
    645 
    646 static int __init alsa_card_dummy_setup(char *str)
    647 {
    648     static unsigned __initdata nr_dev = 0;
    649 
    650     if (nr_dev >= SNDRV_CARDS)
    651         return 0;
    652     (void)(get_option(&str,&enable[nr_dev]) == 2 &&
    653            get_option(&str,&index[nr_dev]) == 2 &&
    654            get_id(&str,&id[nr_dev]) == 2 &&
    655            get_option(&str,&pcm_devs[nr_dev]) == 2 &&
    656            get_option(&str,&pcm_substreams[nr_dev]) == 2);
    657     nr_dev++;
    658     return 1;
    659 }
    660 
    661 __setup("snd-dummy=", alsa_card_dummy_setup);
    662 
    663 #endif /* ifndef MODULE */
Note: See TracChangeset for help on using the changeset viewer.