source: GPL/trunk/alsa-kernel/drivers/dummy.c@ 135

Last change on this file since 135 was 135, checked in by stevenhl, 18 years ago

Get rid of spurious warnings

File size: 22.3 KB
Line 
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., 675 Mass Ave, Cambridge, MA 02139, USA.
18 *
19 */
20
21#define SNDRV_MAIN_OBJECT_FILE
22#include <sound/driver.h>
23#include <sound/control.h>
24#include <sound/pcm.h>
25#include <sound/rawmidi.h>
26#define SNDRV_GET_ID
27#include <sound/initval.h>
28
29MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
30MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
31MODULE_LICENSE("GPL");
32MODULE_CLASSES("{sound}");
33MODULE_DEVICES("{{ALSA,Dummy soundcard}}");
34
35#define MAX_PCM_DEVICES 4
36#define MAX_PCM_SUBSTREAMS 16
37#define MAX_MIDI_DEVICES 2
38
39
40#if 0 /* RME9652 emulation */
41#define MAX_BUFFER_SIZE (26 * 64 * 1024)
42#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
43#define USE_CHANNELS_MIN 26
44#define USE_CHANNELS_MAX 26
45#define USE_PERIODS_MIN 2
46#define USE_PERIODS_MAX 2
47#endif
48
49#if 0 /* ICE1712 emulation */
50#define MAX_BUFFER_SIZE (256 * 1024)
51#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE
52#define USE_CHANNELS_MIN 10
53#define USE_CHANNELS_MAX 10
54#define USE_PERIODS_MIN 1
55#define USE_PERIODS_MAX 1024
56#endif
57
58#if 0 /* UDA1341 emulation */
59#define MAX_BUFFER_SIZE (16380)
60#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
61#define USE_CHANNELS_MIN 2
62#define USE_CHANNELS_MAX 2
63#define USE_PERIODS_MIN 2
64#define USE_PERIODS_MAX 255
65#endif
66
67#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */
68#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE
69#define USE_CHANNELS_MIN 2
70#define USE_CHANNELS_MAX 2
71#define USE_RATE SNDRV_PCM_RATE_48000
72#define USE_RATE_MIN 48000
73#define USE_RATE_MAX 48000
74#endif
75
76
77/* defaults */
78#ifndef MAX_BUFFER_SIZE
79#define MAX_BUFFER_SIZE (64*1024)
80#endif
81#ifndef USE_FORMATS
82#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
83#endif
84#ifndef USE_RATE
85#define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
86#define USE_RATE_MIN 5500
87#define USE_RATE_MAX 48000
88#endif
89#ifndef USE_CHANNELS_MIN
90#define USE_CHANNELS_MIN 1
91#endif
92#ifndef USE_CHANNELS_MAX
93#define USE_CHANNELS_MAX 2
94#endif
95#ifndef USE_PERIODS_MIN
96#define USE_PERIODS_MIN 1
97#endif
98#ifndef USE_PERIODS_MAX
99#define USE_PERIODS_MAX 1024
100#endif
101
102static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
103static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
104#if 0
105static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
106static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
107static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
108#else
109static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
110static int pcm_devs[SNDRV_CARDS] = SNDDRV_DEFAULT_PCM_DEVS;
111static int pcm_substreams[SNDRV_CARDS] = SNDDRV_DEFAULT_PCM_SUBSTREAMS;
112#endif
113//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
114
115MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
116MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
117MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC);
118MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s");
119MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
120MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC);
121MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
122MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
123MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC);
124MODULE_PARM(pcm_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
125MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
126MODULE_PARM_SYNTAX(pcm_devs, SNDRV_ENABLED ",allows:{{0,4}},default:1,dialog:list");
127MODULE_PARM(pcm_substreams, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
128MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver.");
129MODULE_PARM_SYNTAX(pcm_substreams, SNDRV_ENABLED ",allows:{{1,16}},default:8,dialog:list");
130//MODULE_PARM(midi_devs, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
131//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");
133#define MIXER_ADDR_MASTER 0
134#define MIXER_ADDR_LINE 1
135#define MIXER_ADDR_MIC 2
136#define MIXER_ADDR_SYNTH 3
137#define MIXER_ADDR_CD 4
138#define MIXER_ADDR_LAST 4
139
140typedef 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
147typedef 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
160static snd_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR;
161
162
163static 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
170static 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
177static 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
186static 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
194static 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
207static 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
220static 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
240static int snd_card_dummy_playback_prepare(snd_pcm_substream_t * substream)
241{
242 return snd_card_dummy_pcm_prepare(substream);
243}
244
245static int snd_card_dummy_capture_prepare(snd_pcm_substream_t * substream)
246{
247 return snd_card_dummy_pcm_prepare(substream);
248}
249
250static void snd_card_dummy_pcm_timer_function(unsigned long data)
251{
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
267static 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
275static 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
283static 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,
299};
300
301static 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,
317};
318
319static 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
326extern void * snd_malloc_pages_fallback(size_t size, unsigned int flags, size_t *res_size);
327
328static 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
357static 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
387static 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
395static 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
403static 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
412};
413
414static 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
423};
424
425static 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}
439#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
446static 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
455static 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
468static 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}
493
494#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
500static 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
509static 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
522static 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
542static 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)
553};
554
555int __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
572static 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;
606}
607
608static int __init alsa_card_dummy_init(void)
609{
610 int dev, cards;
611
612 for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) {
613 if (snd_card_dummy_probe(dev) < 0) {
614#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;
628}
629
630static void __exit alsa_card_dummy_exit(void)
631{
632 int idx;
633
634 for (idx = 0; idx < SNDRV_CARDS; idx++)
635 snd_card_free(snd_dummy_cards[idx]);
636}
637
638module_init(alsa_card_dummy_init)
639module_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
646static 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 TracBrowser for help on using the repository browser.