c7edada0fdf27d4c5512f24ffc9ceb93a557f9be
[linux-flexiantxendom0-3.2.10.git] / sound / drivers / dummy.c
1 /*
2  *  Dummy soundcard
3  *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  *
19  */
20
21 #include <sound/driver.h>
22 #include <linux/version.h>
23 #include <linux/init.h>
24 #include <linux/jiffies.h>
25 #include <linux/slab.h>
26 #include <linux/time.h>
27 #include <linux/wait.h>
28 #include <sound/core.h>
29 #include <sound/control.h>
30 #include <sound/pcm.h>
31 #include <sound/rawmidi.h>
32 #define SNDRV_GET_ID
33 #include <sound/initval.h>
34
35 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
36 MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
37 MODULE_LICENSE("GPL");
38 MODULE_CLASSES("{sound}");
39 MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
40
41 #define MAX_PCM_DEVICES         4
42 #define MAX_PCM_SUBSTREAMS      16
43 #define MAX_MIDI_DEVICES        2
44
45 #if 0 /* RME9652 emulation */
46 #define MAX_BUFFER_SIZE         (26 * 64 * 1024)
47 #define USE_FORMATS             SNDRV_PCM_FMTBIT_S32_LE
48 #define USE_CHANNELS_MIN        26
49 #define USE_CHANNELS_MAX        26
50 #define USE_PERIODS_MIN         2
51 #define USE_PERIODS_MAX         2
52 #endif
53
54 #if 0 /* ICE1712 emulation */
55 #define MAX_BUFFER_SIZE         (256 * 1024)
56 #define USE_FORMATS             SNDRV_PCM_FMTBIT_S32_LE
57 #define USE_CHANNELS_MIN        10
58 #define USE_CHANNELS_MAX        10
59 #define USE_PERIODS_MIN         1
60 #define USE_PERIODS_MAX         1024
61 #endif
62
63 #if 0 /* UDA1341 emulation */
64 #define MAX_BUFFER_SIZE         (16380)
65 #define USE_FORMATS             SNDRV_PCM_FMTBIT_S16_LE
66 #define USE_CHANNELS_MIN        2
67 #define USE_CHANNELS_MAX        2
68 #define USE_PERIODS_MIN         2
69 #define USE_PERIODS_MAX         255
70 #endif
71
72
73 /* defaults */
74 #ifndef MAX_BUFFER_SIZE
75 #define MAX_BUFFER_SIZE         (64*1024)
76 #endif
77 #ifndef USE_FORMATS
78 #define USE_FORMATS             (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
79 #endif
80 #ifndef USE_CHANNELS_MIN
81 #define USE_CHANNELS_MIN        1
82 #endif
83 #ifndef USE_CHANNELS_MAX
84 #define USE_CHANNELS_MAX        2
85 #endif
86 #ifndef USE_PERIODS_MIN
87 #define USE_PERIODS_MIN         1
88 #endif
89 #ifndef USE_PERIODS_MAX
90 #define USE_PERIODS_MAX         1024
91 #endif
92
93 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
94 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
95 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
96 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
97 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
98 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
99
100 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
101 MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
102 MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
103 MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
104 MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
105 MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
106 MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
107 MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
108 MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
109 MODULE_PARM(pcm_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
110 MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
111 MODULE_PARM_SYNTAX(pcm_devs, SNDRV_ENABLED ",allows:{{0,4}},default:1,dialog:list");
112 MODULE_PARM(pcm_substreams, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
113 MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
114 MODULE_PARM_SYNTAX(pcm_substreams, SNDRV_ENABLED ",allows:{{1,16}},default:8,dialog:list");
115 //MODULE_PARM(midi_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
116 //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
117 //MODULE_PARM_SYNTAX(midi_devs, SNDRV_ENABLED ",allows:{{0,2}},default:8,dialog:list");
118
119 #define MIXER_ADDR_MASTER       0
120 #define MIXER_ADDR_LINE         1
121 #define MIXER_ADDR_MIC          2
122 #define MIXER_ADDR_SYNTH        3
123 #define MIXER_ADDR_CD           4
124 #define MIXER_ADDR_LAST         4
125
126 typedef struct snd_card_dummy {
127         snd_card_t *card;
128         spinlock_t mixer_lock;
129         int mixer_volume[MIXER_ADDR_LAST+1][2];
130         int capture_source[MIXER_ADDR_LAST+1][2];
131 } snd_card_dummy_t;
132
133 typedef struct snd_card_dummy_pcm {
134         snd_card_dummy_t *dummy;
135         spinlock_t lock;
136         struct timer_list timer;
137         unsigned int pcm_size;
138         unsigned int pcm_count;
139         unsigned int pcm_bps;           /* bytes per second */
140         unsigned int pcm_jiffie;        /* bytes per one jiffie */
141         unsigned int pcm_irq_pos;       /* IRQ position */
142         unsigned int pcm_buf_pos;       /* position in buffer */
143         snd_pcm_substream_t *substream;
144 } snd_card_dummy_pcm_t;
145
146 static snd_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
147
148
149 static int snd_card_dummy_playback_ioctl(snd_pcm_substream_t * substream,
150                                          unsigned int cmd,
151                                          void *arg)
152 {
153         return snd_pcm_lib_ioctl(substream, cmd, arg);
154 }
155
156 static int snd_card_dummy_capture_ioctl(snd_pcm_substream_t * substream,
157                                         unsigned int cmd,
158                                         void *arg)
159 {
160         return snd_pcm_lib_ioctl(substream, cmd, arg);
161 }
162
163 static void snd_card_dummy_pcm_timer_start(snd_pcm_substream_t * substream)
164 {
165         snd_pcm_runtime_t *runtime = substream->runtime;
166         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return);
167
168         dpcm->timer.expires = 1 + jiffies;
169         add_timer(&dpcm->timer);
170 }
171
172 static void snd_card_dummy_pcm_timer_stop(snd_pcm_substream_t * substream)
173 {
174         snd_pcm_runtime_t *runtime = substream->runtime;
175         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return);
176
177         del_timer(&dpcm->timer);
178 }
179
180 static int snd_card_dummy_playback_trigger(snd_pcm_substream_t * substream,
181                                            int cmd)
182 {
183         if (cmd == SNDRV_PCM_TRIGGER_START) {
184                 snd_card_dummy_pcm_timer_start(substream);
185         } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
186                 snd_card_dummy_pcm_timer_stop(substream);
187         } else {
188                 return -EINVAL;
189         }
190         return 0;
191 }
192
193 static int snd_card_dummy_capture_trigger(snd_pcm_substream_t * substream,
194                                           int cmd)
195 {
196         if (cmd == SNDRV_PCM_TRIGGER_START) {
197                 snd_card_dummy_pcm_timer_start(substream);
198         } else if (cmd == SNDRV_PCM_TRIGGER_STOP) {
199                 snd_card_dummy_pcm_timer_stop(substream);
200         } else {
201                 return -EINVAL;
202         }
203         return 0;
204 }
205
206 static int snd_card_dummy_pcm_prepare(snd_pcm_substream_t * substream)
207 {
208         snd_pcm_runtime_t *runtime = substream->runtime;
209         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO);
210         unsigned int bps;
211
212         bps = runtime->rate * runtime->channels;
213         bps *= snd_pcm_format_width(runtime->format);
214         bps /= 8;
215         if (bps <= 0)
216                 return -EINVAL;
217         dpcm->pcm_bps = bps;
218         dpcm->pcm_jiffie = bps / HZ;
219         dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream);
220         dpcm->pcm_count = snd_pcm_lib_period_bytes(substream);
221         dpcm->pcm_irq_pos = 0;
222         dpcm->pcm_buf_pos = 0;
223         return 0;
224 }
225
226 static int snd_card_dummy_playback_prepare(snd_pcm_substream_t * substream)
227 {
228         return snd_card_dummy_pcm_prepare(substream);
229 }
230
231 static int snd_card_dummy_capture_prepare(snd_pcm_substream_t * substream)
232 {
233         return snd_card_dummy_pcm_prepare(substream);
234 }
235
236 static void snd_card_dummy_pcm_timer_function(unsigned long data)
237 {
238         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, (void *)data, return);
239         
240         dpcm->timer.expires = 1 + jiffies;
241         add_timer(&dpcm->timer);
242         spin_lock_irq(&dpcm->lock);
243         dpcm->pcm_irq_pos += dpcm->pcm_jiffie;
244         dpcm->pcm_buf_pos += dpcm->pcm_jiffie;
245         dpcm->pcm_buf_pos %= dpcm->pcm_size;
246         if (dpcm->pcm_irq_pos >= dpcm->pcm_count) {
247                 dpcm->pcm_irq_pos %= dpcm->pcm_count;
248                 snd_pcm_period_elapsed(dpcm->substream);
249         }
250         spin_unlock_irq(&dpcm->lock);   
251 }
252
253 static snd_pcm_uframes_t snd_card_dummy_playback_pointer(snd_pcm_substream_t * substream)
254 {
255         snd_pcm_runtime_t *runtime = substream->runtime;
256         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO);
257
258         return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
259 }
260
261 static snd_pcm_uframes_t snd_card_dummy_capture_pointer(snd_pcm_substream_t * substream)
262 {
263         snd_pcm_runtime_t *runtime = substream->runtime;
264         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return -ENXIO);
265
266         return bytes_to_frames(runtime, dpcm->pcm_buf_pos);
267 }
268
269 static snd_pcm_hardware_t snd_card_dummy_playback =
270 {
271         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
272                                  SNDRV_PCM_INFO_MMAP_VALID),
273         .formats =              USE_FORMATS,
274         .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
275         .rate_min =             5500,
276         .rate_max =             48000,
277         .channels_min =         USE_CHANNELS_MIN,
278         .channels_max =         USE_CHANNELS_MAX,
279         .buffer_bytes_max =     MAX_BUFFER_SIZE,
280         .period_bytes_min =     64,
281         .period_bytes_max =     MAX_BUFFER_SIZE,
282         .periods_min =          USE_PERIODS_MIN,
283         .periods_max =          USE_PERIODS_MAX,
284         .fifo_size =            0,
285 };
286
287 static snd_pcm_hardware_t snd_card_dummy_capture =
288 {
289         .info =                 (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |
290                                  SNDRV_PCM_INFO_MMAP_VALID),
291         .formats =              USE_FORMATS,
292         .rates =                SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000,
293         .rate_min =             5500,
294         .rate_max =             48000,
295         .channels_min =         USE_CHANNELS_MIN,
296         .channels_max =         USE_CHANNELS_MAX,
297         .buffer_bytes_max =     MAX_BUFFER_SIZE,
298         .period_bytes_min =     64,
299         .period_bytes_max =     MAX_BUFFER_SIZE,
300         .periods_min =          USE_PERIODS_MIN,
301         .periods_max =          USE_PERIODS_MAX,
302         .fifo_size =            0,
303 };
304
305 static void snd_card_dummy_runtime_free(snd_pcm_runtime_t *runtime)
306 {
307         snd_card_dummy_pcm_t *dpcm = snd_magic_cast(snd_card_dummy_pcm_t, runtime->private_data, return);
308         snd_magic_kfree(dpcm);
309 }
310
311 static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream)
312 {
313         snd_pcm_runtime_t *runtime = substream->runtime;
314         snd_card_dummy_pcm_t *dpcm;
315
316         dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL);
317         if (dpcm == NULL)
318                 return -ENOMEM;
319         if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) {
320                 snd_magic_kfree(dpcm);
321                 return -ENOMEM;
322         }
323         init_timer(&dpcm->timer);
324         dpcm->timer.data = (unsigned long) dpcm;
325         dpcm->timer.function = snd_card_dummy_pcm_timer_function;
326         spin_lock_init(&dpcm->lock);
327         dpcm->substream = substream;
328         runtime->private_data = dpcm;
329         runtime->private_free = snd_card_dummy_runtime_free;
330         runtime->hw = snd_card_dummy_playback;
331         if (substream->pcm->device & 1) {
332                 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
333                 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
334         }
335         if (substream->pcm->device & 2)
336                 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
337         return 0;
338 }
339
340 static int snd_card_dummy_capture_open(snd_pcm_substream_t * substream)
341 {
342         snd_pcm_runtime_t *runtime = substream->runtime;
343         snd_card_dummy_pcm_t *dpcm;
344
345         dpcm = snd_magic_kcalloc(snd_card_dummy_pcm_t, 0, GFP_KERNEL);
346         if (dpcm == NULL)
347                 return -ENOMEM;
348         if ((runtime->dma_area = snd_malloc_pages_fallback(MAX_BUFFER_SIZE, GFP_KERNEL, &runtime->dma_bytes)) == NULL) {
349                 snd_magic_kfree(dpcm);
350                 return -ENOMEM;
351         }
352         memset(runtime->dma_area, 0, runtime->dma_bytes);
353         init_timer(&dpcm->timer);
354         dpcm->timer.data = (unsigned long) dpcm;
355         dpcm->timer.function = snd_card_dummy_pcm_timer_function;
356         spin_lock_init(&dpcm->lock);
357         dpcm->substream = substream;
358         runtime->private_data = dpcm;
359         runtime->private_free = snd_card_dummy_runtime_free;
360         runtime->hw = snd_card_dummy_capture;
361         if (substream->pcm->device == 1) {
362                 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
363                 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
364         }
365         if (substream->pcm->device & 2)
366                 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID);
367         return 0;
368 }
369
370 static int snd_card_dummy_playback_close(snd_pcm_substream_t * substream)
371 {
372         snd_pcm_runtime_t *runtime = substream->runtime;
373
374         snd_free_pages(runtime->dma_area, runtime->dma_bytes);
375         return 0;
376 }
377
378 static int snd_card_dummy_capture_close(snd_pcm_substream_t * substream)
379 {
380         snd_pcm_runtime_t *runtime = substream->runtime;
381
382         snd_free_pages(runtime->dma_area, runtime->dma_bytes);
383         return 0;
384 }
385
386 static snd_pcm_ops_t snd_card_dummy_playback_ops = {
387         .open =                 snd_card_dummy_playback_open,
388         .close =                snd_card_dummy_playback_close,
389         .ioctl =                snd_card_dummy_playback_ioctl,
390         .prepare =              snd_card_dummy_playback_prepare,
391         .trigger =              snd_card_dummy_playback_trigger,
392         .pointer =              snd_card_dummy_playback_pointer,
393 };
394
395 static snd_pcm_ops_t snd_card_dummy_capture_ops = {
396         .open =                 snd_card_dummy_capture_open,
397         .close =                snd_card_dummy_capture_close,
398         .ioctl =                snd_card_dummy_capture_ioctl,
399         .prepare =              snd_card_dummy_capture_prepare,
400         .trigger =              snd_card_dummy_capture_trigger,
401         .pointer =              snd_card_dummy_capture_pointer,
402 };
403
404 static int __init snd_card_dummy_pcm(snd_card_dummy_t *dummy, int device, int substreams)
405 {
406         snd_pcm_t *pcm;
407         int err;
408
409         if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, substreams, substreams, &pcm)) < 0)
410                 return err;
411         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops);
412         snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops);
413         pcm->private_data = dummy;
414         pcm->info_flags = 0;
415         strcpy(pcm->name, "Dummy PCM");
416         return 0;
417 }
418
419 #define DUMMY_VOLUME(xname, xindex, addr) \
420 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
421   .info = snd_dummy_volume_info, \
422   .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
423   .private_value = addr }
424
425 static int snd_dummy_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
426 {
427         uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
428         uinfo->count = 2;
429         uinfo->value.integer.min = -50;
430         uinfo->value.integer.max = 100;
431         return 0;
432 }
433  
434 static int snd_dummy_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
435 {
436         snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol);
437         unsigned long flags;
438         int addr = kcontrol->private_value;
439
440         spin_lock_irqsave(&dummy->mixer_lock, flags);
441         ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
442         ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
443         spin_unlock_irqrestore(&dummy->mixer_lock, flags);
444         return 0;
445 }                                                                                                                                                                                                                                                                                                            
446
447 static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
448 {
449         snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol);
450         unsigned long flags;
451         int change, addr = kcontrol->private_value;
452         int left, right;
453
454         left = ucontrol->value.integer.value[0];
455         if (left < -50)
456                 left = -50;
457         if (left > 100)
458                 left = 100;
459         right = ucontrol->value.integer.value[1];
460         if (right < -50)
461                 right = -50;
462         if (right > 100)
463                 right = 100;
464         spin_lock_irqsave(&dummy->mixer_lock, flags);
465         change = dummy->mixer_volume[addr][0] != left ||
466                  dummy->mixer_volume[addr][1] != right;
467         dummy->mixer_volume[addr][0] = left;
468         dummy->mixer_volume[addr][1] = right;
469         spin_unlock_irqrestore(&dummy->mixer_lock, flags);
470         return change;
471 }                                                                                                                                                                                                                                                                                                            
472
473 #define DUMMY_CAPSRC(xname, xindex, addr) \
474 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
475   .info = snd_dummy_capsrc_info, \
476   .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \
477   .private_value = addr }
478
479 static int snd_dummy_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo)
480 {
481         uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
482         uinfo->count = 2;
483         uinfo->value.integer.min = 0;
484         uinfo->value.integer.max = 1;
485         return 0;
486 }
487  
488 static int snd_dummy_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
489 {
490         snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol);
491         unsigned long flags;
492         int addr = kcontrol->private_value;
493
494         spin_lock_irqsave(&dummy->mixer_lock, flags);
495         ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
496         ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
497         spin_unlock_irqrestore(&dummy->mixer_lock, flags);
498         return 0;
499 }
500
501 static int snd_dummy_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol)
502 {
503         snd_card_dummy_t *dummy = _snd_kcontrol_chip(kcontrol);
504         unsigned long flags;
505         int change, addr = kcontrol->private_value;
506         int left, right;
507
508         left = ucontrol->value.integer.value[0] & 1;
509         right = ucontrol->value.integer.value[1] & 1;
510         spin_lock_irqsave(&dummy->mixer_lock, flags);
511         change = dummy->capture_source[addr][0] != left &&
512                  dummy->capture_source[addr][1] != right;
513         dummy->capture_source[addr][0] = left;
514         dummy->capture_source[addr][1] = right;
515         spin_unlock_irqrestore(&dummy->mixer_lock, flags);
516         return change;
517 }                                                                                                                                                                                                                                                                                                            
518
519 #define DUMMY_CONTROLS (sizeof(snd_dummy_controls)/sizeof(snd_kcontrol_new_t))
520
521 static snd_kcontrol_new_t snd_dummy_controls[] = {
522 DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
523 DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
524 DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
525 DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_MASTER),
526 DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
527 DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_MASTER),
528 DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
529 DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MASTER),
530 DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
531 DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER)
532 };
533
534 int __init snd_card_dummy_new_mixer(snd_card_dummy_t * dummy)
535 {
536         snd_card_t *card = dummy->card;
537         unsigned int idx;
538         int err;
539
540         snd_assert(dummy != NULL, return -EINVAL);
541         spin_lock_init(&dummy->mixer_lock);
542         strcpy(card->mixername, "Dummy Mixer");
543
544         for (idx = 0; idx < DUMMY_CONTROLS; idx++) {
545                 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0)
546                         return err;
547         }
548         return 0;
549 }
550
551 static int __init snd_card_dummy_probe(int dev)
552 {
553         snd_card_t *card;
554         struct snd_card_dummy *dummy;
555         int idx, err;
556
557         if (!enable[dev])
558                 return -ENODEV;
559         card = snd_card_new(index[dev], id[dev], THIS_MODULE,
560                             sizeof(struct snd_card_dummy));
561         if (card == NULL)
562                 return -ENOMEM;
563         dummy = (struct snd_card_dummy *)card->private_data;
564         dummy->card = card;
565         for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
566                 if (pcm_substreams[dev] < 1)
567                         pcm_substreams[dev] = 1;
568                 if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
569                         pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
570                 if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0)
571                         goto __nodev;
572         }
573         if ((err = snd_card_dummy_new_mixer(dummy)) < 0)
574                 goto __nodev;
575         strcpy(card->driver, "Dummy");
576         strcpy(card->shortname, "Dummy");
577         sprintf(card->longname, "Dummy %i", dev + 1);
578         if ((err = snd_card_register(card)) == 0) {
579                 snd_dummy_cards[dev] = card;
580                 return 0;
581         }
582       __nodev:
583         snd_card_free(card);
584         return err;
585 }
586
587 static int __init alsa_card_dummy_init(void)
588 {
589         int dev, cards;
590
591         for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
592                 if (snd_card_dummy_probe(dev) < 0) {
593 #ifdef MODULE
594                         printk(KERN_ERR "Dummy soundcard #%i not found or device busy\n", dev + 1);
595 #endif
596                         break;
597                 }
598                 cards++;
599         }
600         if (!cards) {
601 #ifdef MODULE
602                 printk(KERN_ERR "Dummy soundcard not found or device busy\n");
603 #endif
604                 return -ENODEV;
605         }
606         return 0;
607 }
608
609 static void __exit alsa_card_dummy_exit(void)
610 {
611         int idx;
612
613         for (idx = 0; idx < SNDRV_CARDS; idx++)
614                 snd_card_free(snd_dummy_cards[idx]);
615 }
616
617 module_init(alsa_card_dummy_init)
618 module_exit(alsa_card_dummy_exit)
619
620 #ifndef MODULE
621
622 /* format is: snd-dummy=enable,index,id,
623                         pcm_devs,pcm_substreams */
624
625 static int __init alsa_card_dummy_setup(char *str)
626 {
627         static unsigned __initdata nr_dev = 0;
628
629         if (nr_dev >= SNDRV_CARDS)
630                 return 0;
631         (void)(get_option(&str,&enable[nr_dev]) == 2 &&
632                get_option(&str,&index[nr_dev]) == 2 &&
633                get_id(&str,&id[nr_dev]) == 2 &&
634                get_option(&str,&pcm_devs[nr_dev]) == 2 &&
635                get_option(&str,&pcm_substreams[nr_dev]) == 2);
636         nr_dev++;
637         return 1;
638 }
639
640 __setup("snd-dummy=", alsa_card_dummy_setup);
641
642 #endif /* ifndef MODULE */