Changeset 305 for GPL/branches/uniaud-2.0/alsa-kernel/drivers/dummy.c
- Timestamp:
- Mar 24, 2008, 2:43:42 AM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GPL/branches/uniaud-2.0/alsa-kernel/drivers/dummy.c
r135 r305 1 1 /* 2 2 * Dummy soundcard 3 * Copyright (c) by Jaroslav Kysela <perex@ suse.cz>3 * Copyright (c) by Jaroslav Kysela <perex@perex.cz> 4 4 * 5 5 * This program is free software; you can redistribute it and/or modify … … 15 15 * You should have received a copy of the GNU General Public License 16 16 * 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 18 18 * 19 19 */ 20 20 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> 23 30 #include <sound/control.h> 31 #include <sound/tlv.h> 24 32 #include <sound/pcm.h> 25 33 #include <sound/rawmidi.h> 26 #define SNDRV_GET_ID27 34 #include <sound/initval.h> 28 35 29 MODULE_AUTHOR("Jaroslav Kysela <perex@ suse.cz>");36 MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); 30 37 MODULE_DESCRIPTION("Dummy soundcard (/dev/null)"); 31 38 MODULE_LICENSE("GPL"); 32 MODULE_CLASSES("{sound}"); 33 MODULE_DEVICES("{{ALSA,Dummy soundcard}}"); 39 MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); 34 40 35 41 #define MAX_PCM_DEVICES 4 … … 37 43 #define MAX_MIDI_DEVICES 2 38 44 45 #if 0 /* emu10k1 emulation */ 46 #define MAX_BUFFER_SIZE (128 * 1024) 47 static 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 39 58 40 59 #if 0 /* RME9652 emulation */ … … 74 93 #endif 75 94 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 76 108 77 109 /* defaults */ 78 110 #ifndef MAX_BUFFER_SIZE 79 111 #define MAX_BUFFER_SIZE (64*1024) 112 #endif 113 #ifndef MAX_PERIOD_SIZE 114 #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE 80 115 #endif 81 116 #ifndef USE_FORMATS … … 99 134 #define USE_PERIODS_MAX 1024 100 135 #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 101 142 102 143 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 103 144 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 104 #if 0105 145 static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; 106 146 static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; 107 147 static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; 108 #else109 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 #endif113 148 //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; 114 149 115 MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i");150 module_param_array(index, int, NULL, 0444); 116 151 MODULE_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"); 152 module_param_array(id, charp, NULL, 0444); 119 153 MODULE_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"); 154 module_param_array(enable, bool, NULL, 0444); 122 155 MODULE_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"); 156 module_param_array(pcm_devs, int, NULL, 0444); 125 157 MODULE_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"); 158 module_param_array(pcm_substreams, int, NULL, 0444); 128 159 MODULE_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); 131 161 //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 163 static struct platform_device *devices[SNDRV_CARDS]; 164 133 165 #define MIXER_ADDR_MASTER 0 134 166 #define MIXER_ADDR_LINE 1 … … 138 170 #define MIXER_ADDR_LAST 4 139 171 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); 172 struct 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 180 struct 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 194 static 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 200 static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm) 201 { 202 del_timer(&dpcm->timer); 203 } 204 205 static 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 229 static 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; 248 247 } 249 248 250 249 static void snd_card_dummy_pcm_timer_function(unsigned long data) 251 250 { 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 268 static 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 276 static 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, 299 292 }; 300 293 301 static s nd_pcm_hardware_tsnd_card_dummy_capture =302 { 303 /* info: */(SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED |304 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,294 static 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, 317 310 }; 318 311 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 312 static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime) 313 { 314 kfree(runtime->private_data); 315 } 316 317 static 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 323 static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream) 324 { 325 return snd_pcm_lib_free_pages(substream); 326 } 327 328 static 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 343 static 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 368 static 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 393 static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream) 394 { 395 return 0; 396 } 397 398 static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream) 399 { 400 return 0; 401 } 402 403 static 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, 412 412 }; 413 413 414 static s nd_pcm_ops_tsnd_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 414 static 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, 423 423 }; 424 424 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 } 425 static 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 439 446 #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 455 static 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 465 static 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 478 static 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 504 static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0); 493 505 494 506 #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 514 static 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 527 static 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 544 static struct snd_kcontrol_new snd_dummy_controls[] = { 545 DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), 546 DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), 547 DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), 548 DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH), 549 DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE), 550 DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE), 551 DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC), 552 DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC), 553 DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), 554 DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD) 553 555 }; 554 556 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; 557 static 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 574 static 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 612 static 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 620 static 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 630 static 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 641 static 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 653 static 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); 606 660 } 607 661 608 662 static int __init alsa_card_dummy_init(void) 609 663 { 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) { 614 686 #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; 628 693 } 629 694 630 695 static void __exit alsa_card_dummy_exit(void) 631 696 { 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(); 636 698 } 637 699 638 700 module_init(alsa_card_dummy_init) 639 701 module_exit(alsa_card_dummy_exit) 640 641 #ifndef MODULE642 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.