Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v2.6.20 709 lines 20 kB view raw
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/init.h> 23#include <linux/err.h> 24#include <linux/platform_device.h> 25#include <linux/jiffies.h> 26#include <linux/slab.h> 27#include <linux/time.h> 28#include <linux/wait.h> 29#include <linux/moduleparam.h> 30#include <sound/core.h> 31#include <sound/control.h> 32#include <sound/tlv.h> 33#include <sound/pcm.h> 34#include <sound/rawmidi.h> 35#include <sound/initval.h> 36 37MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); 38MODULE_DESCRIPTION("Dummy soundcard (/dev/null)"); 39MODULE_LICENSE("GPL"); 40MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); 41 42#define MAX_PCM_DEVICES 4 43#define MAX_PCM_SUBSTREAMS 16 44#define MAX_MIDI_DEVICES 2 45 46#if 0 /* emu10k1 emulation */ 47#define MAX_BUFFER_SIZE (128 * 1024) 48static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) 49{ 50 int err; 51 if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) 52 return err; 53 if ((err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX)) < 0) 54 return err; 55 return 0; 56} 57#define add_playback_constraints emu10k1_playback_constraints 58#endif 59 60#if 0 /* RME9652 emulation */ 61#define MAX_BUFFER_SIZE (26 * 64 * 1024) 62#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE 63#define USE_CHANNELS_MIN 26 64#define USE_CHANNELS_MAX 26 65#define USE_PERIODS_MIN 2 66#define USE_PERIODS_MAX 2 67#endif 68 69#if 0 /* ICE1712 emulation */ 70#define MAX_BUFFER_SIZE (256 * 1024) 71#define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE 72#define USE_CHANNELS_MIN 10 73#define USE_CHANNELS_MAX 10 74#define USE_PERIODS_MIN 1 75#define USE_PERIODS_MAX 1024 76#endif 77 78#if 0 /* UDA1341 emulation */ 79#define MAX_BUFFER_SIZE (16380) 80#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE 81#define USE_CHANNELS_MIN 2 82#define USE_CHANNELS_MAX 2 83#define USE_PERIODS_MIN 2 84#define USE_PERIODS_MAX 255 85#endif 86 87#if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ 88#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE 89#define USE_CHANNELS_MIN 2 90#define USE_CHANNELS_MAX 2 91#define USE_RATE SNDRV_PCM_RATE_48000 92#define USE_RATE_MIN 48000 93#define USE_RATE_MAX 48000 94#endif 95 96#if 0 /* CA0106 */ 97#define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE 98#define USE_CHANNELS_MIN 2 99#define USE_CHANNELS_MAX 2 100#define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) 101#define USE_RATE_MIN 48000 102#define USE_RATE_MAX 192000 103#define MAX_BUFFER_SIZE ((65536-64)*8) 104#define MAX_PERIOD_SIZE (65536-64) 105#define USE_PERIODS_MIN 2 106#define USE_PERIODS_MAX 8 107#endif 108 109 110/* defaults */ 111#ifndef MAX_BUFFER_SIZE 112#define MAX_BUFFER_SIZE (64*1024) 113#endif 114#ifndef MAX_PERIOD_SIZE 115#define MAX_PERIOD_SIZE MAX_BUFFER_SIZE 116#endif 117#ifndef USE_FORMATS 118#define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) 119#endif 120#ifndef USE_RATE 121#define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 122#define USE_RATE_MIN 5500 123#define USE_RATE_MAX 48000 124#endif 125#ifndef USE_CHANNELS_MIN 126#define USE_CHANNELS_MIN 1 127#endif 128#ifndef USE_CHANNELS_MAX 129#define USE_CHANNELS_MAX 2 130#endif 131#ifndef USE_PERIODS_MIN 132#define USE_PERIODS_MIN 1 133#endif 134#ifndef USE_PERIODS_MAX 135#define USE_PERIODS_MAX 1024 136#endif 137#ifndef add_playback_constraints 138#define add_playback_constraints(x) 0 139#endif 140#ifndef add_capture_constraints 141#define add_capture_constraints(x) 0 142#endif 143 144static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 145static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 146static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 147static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; 148static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; 149//static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; 150 151module_param_array(index, int, NULL, 0444); 152MODULE_PARM_DESC(index, "Index value for dummy soundcard."); 153module_param_array(id, charp, NULL, 0444); 154MODULE_PARM_DESC(id, "ID string for dummy soundcard."); 155module_param_array(enable, bool, NULL, 0444); 156MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); 157module_param_array(pcm_devs, int, NULL, 0444); 158MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); 159module_param_array(pcm_substreams, int, NULL, 0444); 160MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); 161//module_param_array(midi_devs, int, NULL, 0444); 162//MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); 163 164static struct platform_device *devices[SNDRV_CARDS]; 165 166#define MIXER_ADDR_MASTER 0 167#define MIXER_ADDR_LINE 1 168#define MIXER_ADDR_MIC 2 169#define MIXER_ADDR_SYNTH 3 170#define MIXER_ADDR_CD 4 171#define MIXER_ADDR_LAST 4 172 173struct snd_dummy { 174 struct snd_card *card; 175 struct snd_pcm *pcm; 176 spinlock_t mixer_lock; 177 int mixer_volume[MIXER_ADDR_LAST+1][2]; 178 int capture_source[MIXER_ADDR_LAST+1][2]; 179}; 180 181struct snd_dummy_pcm { 182 struct snd_dummy *dummy; 183 spinlock_t lock; 184 struct timer_list timer; 185 unsigned int pcm_size; 186 unsigned int pcm_count; 187 unsigned int pcm_bps; /* bytes per second */ 188 unsigned int pcm_jiffie; /* bytes per one jiffie */ 189 unsigned int pcm_irq_pos; /* IRQ position */ 190 unsigned int pcm_buf_pos; /* position in buffer */ 191 struct snd_pcm_substream *substream; 192}; 193 194 195static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm) 196{ 197 dpcm->timer.expires = 1 + jiffies; 198 add_timer(&dpcm->timer); 199} 200 201static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm) 202{ 203 del_timer(&dpcm->timer); 204} 205 206static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) 207{ 208 struct snd_pcm_runtime *runtime = substream->runtime; 209 struct snd_dummy_pcm *dpcm = runtime->private_data; 210 int err = 0; 211 212 spin_lock(&dpcm->lock); 213 switch (cmd) { 214 case SNDRV_PCM_TRIGGER_START: 215 case SNDRV_PCM_TRIGGER_RESUME: 216 snd_card_dummy_pcm_timer_start(dpcm); 217 break; 218 case SNDRV_PCM_TRIGGER_STOP: 219 case SNDRV_PCM_TRIGGER_SUSPEND: 220 snd_card_dummy_pcm_timer_stop(dpcm); 221 break; 222 default: 223 err = -EINVAL; 224 break; 225 } 226 spin_unlock(&dpcm->lock); 227 return 0; 228} 229 230static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) 231{ 232 struct snd_pcm_runtime *runtime = substream->runtime; 233 struct snd_dummy_pcm *dpcm = runtime->private_data; 234 unsigned int bps; 235 236 bps = runtime->rate * runtime->channels; 237 bps *= snd_pcm_format_width(runtime->format); 238 bps /= 8; 239 if (bps <= 0) 240 return -EINVAL; 241 dpcm->pcm_bps = bps; 242 dpcm->pcm_jiffie = bps / HZ; 243 dpcm->pcm_size = snd_pcm_lib_buffer_bytes(substream); 244 dpcm->pcm_count = snd_pcm_lib_period_bytes(substream); 245 dpcm->pcm_irq_pos = 0; 246 dpcm->pcm_buf_pos = 0; 247 return 0; 248} 249 250static void snd_card_dummy_pcm_timer_function(unsigned long data) 251{ 252 struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data; 253 unsigned long flags; 254 255 spin_lock_irqsave(&dpcm->lock, flags); 256 dpcm->timer.expires = 1 + jiffies; 257 add_timer(&dpcm->timer); 258 dpcm->pcm_irq_pos += dpcm->pcm_jiffie; 259 dpcm->pcm_buf_pos += dpcm->pcm_jiffie; 260 dpcm->pcm_buf_pos %= dpcm->pcm_size; 261 if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { 262 dpcm->pcm_irq_pos %= dpcm->pcm_count; 263 spin_unlock_irqrestore(&dpcm->lock, flags); 264 snd_pcm_period_elapsed(dpcm->substream); 265 } else 266 spin_unlock_irqrestore(&dpcm->lock, flags); 267} 268 269static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream) 270{ 271 struct snd_pcm_runtime *runtime = substream->runtime; 272 struct snd_dummy_pcm *dpcm = runtime->private_data; 273 274 return bytes_to_frames(runtime, dpcm->pcm_buf_pos); 275} 276 277static struct snd_pcm_hardware snd_card_dummy_playback = 278{ 279 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 280 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), 281 .formats = USE_FORMATS, 282 .rates = USE_RATE, 283 .rate_min = USE_RATE_MIN, 284 .rate_max = USE_RATE_MAX, 285 .channels_min = USE_CHANNELS_MIN, 286 .channels_max = USE_CHANNELS_MAX, 287 .buffer_bytes_max = MAX_BUFFER_SIZE, 288 .period_bytes_min = 64, 289 .period_bytes_max = MAX_PERIOD_SIZE, 290 .periods_min = USE_PERIODS_MIN, 291 .periods_max = USE_PERIODS_MAX, 292 .fifo_size = 0, 293}; 294 295static struct snd_pcm_hardware snd_card_dummy_capture = 296{ 297 .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | 298 SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), 299 .formats = USE_FORMATS, 300 .rates = USE_RATE, 301 .rate_min = USE_RATE_MIN, 302 .rate_max = USE_RATE_MAX, 303 .channels_min = USE_CHANNELS_MIN, 304 .channels_max = USE_CHANNELS_MAX, 305 .buffer_bytes_max = MAX_BUFFER_SIZE, 306 .period_bytes_min = 64, 307 .period_bytes_max = MAX_PERIOD_SIZE, 308 .periods_min = USE_PERIODS_MIN, 309 .periods_max = USE_PERIODS_MAX, 310 .fifo_size = 0, 311}; 312 313static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime) 314{ 315 kfree(runtime->private_data); 316} 317 318static int snd_card_dummy_hw_params(struct snd_pcm_substream *substream, 319 struct snd_pcm_hw_params *hw_params) 320{ 321 return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); 322} 323 324static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream) 325{ 326 return snd_pcm_lib_free_pages(substream); 327} 328 329static struct snd_dummy_pcm *new_pcm_stream(struct snd_pcm_substream *substream) 330{ 331 struct snd_dummy_pcm *dpcm; 332 333 dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); 334 if (! dpcm) 335 return dpcm; 336 init_timer(&dpcm->timer); 337 dpcm->timer.data = (unsigned long) dpcm; 338 dpcm->timer.function = snd_card_dummy_pcm_timer_function; 339 spin_lock_init(&dpcm->lock); 340 dpcm->substream = substream; 341 return dpcm; 342} 343 344static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream) 345{ 346 struct snd_pcm_runtime *runtime = substream->runtime; 347 struct snd_dummy_pcm *dpcm; 348 int err; 349 350 if ((dpcm = new_pcm_stream(substream)) == NULL) 351 return -ENOMEM; 352 runtime->private_data = dpcm; 353 runtime->private_free = snd_card_dummy_runtime_free; 354 runtime->hw = snd_card_dummy_playback; 355 if (substream->pcm->device & 1) { 356 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; 357 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; 358 } 359 if (substream->pcm->device & 2) 360 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); 361 if ((err = add_playback_constraints(runtime)) < 0) { 362 kfree(dpcm); 363 return err; 364 } 365 366 return 0; 367} 368 369static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream) 370{ 371 struct snd_pcm_runtime *runtime = substream->runtime; 372 struct snd_dummy_pcm *dpcm; 373 int err; 374 375 if ((dpcm = new_pcm_stream(substream)) == NULL) 376 return -ENOMEM; 377 runtime->private_data = dpcm; 378 runtime->private_free = snd_card_dummy_runtime_free; 379 runtime->hw = snd_card_dummy_capture; 380 if (substream->pcm->device == 1) { 381 runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; 382 runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; 383 } 384 if (substream->pcm->device & 2) 385 runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP|SNDRV_PCM_INFO_MMAP_VALID); 386 if ((err = add_capture_constraints(runtime)) < 0) { 387 kfree(dpcm); 388 return err; 389 } 390 391 return 0; 392} 393 394static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream) 395{ 396 return 0; 397} 398 399static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream) 400{ 401 return 0; 402} 403 404static struct snd_pcm_ops snd_card_dummy_playback_ops = { 405 .open = snd_card_dummy_playback_open, 406 .close = snd_card_dummy_playback_close, 407 .ioctl = snd_pcm_lib_ioctl, 408 .hw_params = snd_card_dummy_hw_params, 409 .hw_free = snd_card_dummy_hw_free, 410 .prepare = snd_card_dummy_pcm_prepare, 411 .trigger = snd_card_dummy_pcm_trigger, 412 .pointer = snd_card_dummy_pcm_pointer, 413}; 414 415static struct snd_pcm_ops snd_card_dummy_capture_ops = { 416 .open = snd_card_dummy_capture_open, 417 .close = snd_card_dummy_capture_close, 418 .ioctl = snd_pcm_lib_ioctl, 419 .hw_params = snd_card_dummy_hw_params, 420 .hw_free = snd_card_dummy_hw_free, 421 .prepare = snd_card_dummy_pcm_prepare, 422 .trigger = snd_card_dummy_pcm_trigger, 423 .pointer = snd_card_dummy_pcm_pointer, 424}; 425 426static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, 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 446#define DUMMY_VOLUME(xname, xindex, addr) \ 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 DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); 505 506#define DUMMY_CAPSRC(xname, xindex, addr) \ 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 512static int snd_dummy_capsrc_info(struct snd_kcontrol *kcontrol, 513 struct snd_ctl_elem_info *uinfo) 514{ 515 uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; 516 uinfo->count = 2; 517 uinfo->value.integer.min = 0; 518 uinfo->value.integer.max = 1; 519 return 0; 520} 521 522static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, 523 struct snd_ctl_elem_value *ucontrol) 524{ 525 struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); 526 int addr = kcontrol->private_value; 527 528 spin_lock_irq(&dummy->mixer_lock); 529 ucontrol->value.integer.value[0] = dummy->capture_source[addr][0]; 530 ucontrol->value.integer.value[1] = dummy->capture_source[addr][1]; 531 spin_unlock_irq(&dummy->mixer_lock); 532 return 0; 533} 534 535static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) 536{ 537 struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); 538 int change, addr = kcontrol->private_value; 539 int left, right; 540 541 left = ucontrol->value.integer.value[0] & 1; 542 right = ucontrol->value.integer.value[1] & 1; 543 spin_lock_irq(&dummy->mixer_lock); 544 change = dummy->capture_source[addr][0] != left && 545 dummy->capture_source[addr][1] != right; 546 dummy->capture_source[addr][0] = left; 547 dummy->capture_source[addr][1] = right; 548 spin_unlock_irq(&dummy->mixer_lock); 549 return change; 550} 551 552static struct snd_kcontrol_new snd_dummy_controls[] = { 553DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), 554DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), 555DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), 556DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH), 557DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), 558DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), 559DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), 560DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), 561DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), 562DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) 563}; 564 565static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) 566{ 567 struct snd_card *card = dummy->card; 568 unsigned int idx; 569 int err; 570 571 snd_assert(dummy != NULL, return -EINVAL); 572 spin_lock_init(&dummy->mixer_lock); 573 strcpy(card->mixername, "Dummy Mixer"); 574 575 for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) { 576 if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))) < 0) 577 return err; 578 } 579 return 0; 580} 581 582static int __init snd_dummy_probe(struct platform_device *devptr) 583{ 584 struct snd_card *card; 585 struct snd_dummy *dummy; 586 int idx, err; 587 int dev = devptr->id; 588 589 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 590 sizeof(struct snd_dummy)); 591 if (card == NULL) 592 return -ENOMEM; 593 dummy = card->private_data; 594 dummy->card = card; 595 for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { 596 if (pcm_substreams[dev] < 1) 597 pcm_substreams[dev] = 1; 598 if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS) 599 pcm_substreams[dev] = MAX_PCM_SUBSTREAMS; 600 if ((err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev])) < 0) 601 goto __nodev; 602 } 603 if ((err = snd_card_dummy_new_mixer(dummy)) < 0) 604 goto __nodev; 605 strcpy(card->driver, "Dummy"); 606 strcpy(card->shortname, "Dummy"); 607 sprintf(card->longname, "Dummy %i", dev + 1); 608 609 snd_card_set_dev(card, &devptr->dev); 610 611 if ((err = snd_card_register(card)) == 0) { 612 platform_set_drvdata(devptr, card); 613 return 0; 614 } 615 __nodev: 616 snd_card_free(card); 617 return err; 618} 619 620static int snd_dummy_remove(struct platform_device *devptr) 621{ 622 snd_card_free(platform_get_drvdata(devptr)); 623 platform_set_drvdata(devptr, NULL); 624 return 0; 625} 626 627#ifdef CONFIG_PM 628static int snd_dummy_suspend(struct platform_device *pdev, pm_message_t state) 629{ 630 struct snd_card *card = platform_get_drvdata(pdev); 631 struct snd_dummy *dummy = card->private_data; 632 633 snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); 634 snd_pcm_suspend_all(dummy->pcm); 635 return 0; 636} 637 638static int snd_dummy_resume(struct platform_device *pdev) 639{ 640 struct snd_card *card = platform_get_drvdata(pdev); 641 642 snd_power_change_state(card, SNDRV_CTL_POWER_D0); 643 return 0; 644} 645#endif 646 647#define SND_DUMMY_DRIVER "snd_dummy" 648 649static struct platform_driver snd_dummy_driver = { 650 .probe = snd_dummy_probe, 651 .remove = snd_dummy_remove, 652#ifdef CONFIG_PM 653 .suspend = snd_dummy_suspend, 654 .resume = snd_dummy_resume, 655#endif 656 .driver = { 657 .name = SND_DUMMY_DRIVER 658 }, 659}; 660 661static void __init_or_module snd_dummy_unregister_all(void) 662{ 663 int i; 664 665 for (i = 0; i < ARRAY_SIZE(devices); ++i) 666 platform_device_unregister(devices[i]); 667 platform_driver_unregister(&snd_dummy_driver); 668} 669 670static int __init alsa_card_dummy_init(void) 671{ 672 int i, cards, err; 673 674 if ((err = platform_driver_register(&snd_dummy_driver)) < 0) 675 return err; 676 677 cards = 0; 678 for (i = 0; i < SNDRV_CARDS; i++) { 679 struct platform_device *device; 680 if (! enable[i]) 681 continue; 682 device = platform_device_register_simple(SND_DUMMY_DRIVER, 683 i, NULL, 0); 684 if (IS_ERR(device)) 685 continue; 686 if (!platform_get_drvdata(device)) { 687 platform_device_unregister(device); 688 continue; 689 } 690 devices[i] = device; 691 cards++; 692 } 693 if (!cards) { 694#ifdef MODULE 695 printk(KERN_ERR "Dummy soundcard not found or device busy\n"); 696#endif 697 snd_dummy_unregister_all(); 698 return -ENODEV; 699 } 700 return 0; 701} 702 703static void __exit alsa_card_dummy_exit(void) 704{ 705 snd_dummy_unregister_all(); 706} 707 708module_init(alsa_card_dummy_init) 709module_exit(alsa_card_dummy_exit)