Blame view

sound/drivers/dummy.c 32 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
  /*
   *  Dummy soundcard
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
3
   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   *   This program is free software; you can redistribute it and/or modify
   *   it under the terms of the GNU General Public License as published by
   *   the Free Software Foundation; either version 2 of the License, or
   *   (at your option) any later version.
   *
   *   This program is distributed in the hope that it will be useful,
   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   *   GNU General Public License for more details.
   *
   *   You should have received a copy of the GNU General Public License
   *   along with this program; if not, write to the Free Software
   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/init.h>
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
21
22
  #include <linux/err.h>
  #include <linux/platform_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
25
26
  #include <linux/jiffies.h>
  #include <linux/slab.h>
  #include <linux/time.h>
  #include <linux/wait.h>
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
27
28
  #include <linux/hrtimer.h>
  #include <linux/math64.h>
65a772172   Paul Gortmaker   sound: fix driver...
29
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
  #include <sound/core.h>
  #include <sound/control.h>
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
32
  #include <sound/tlv.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33
34
  #include <sound/pcm.h>
  #include <sound/rawmidi.h>
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
35
  #include <sound/info.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include <sound/initval.h>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
37
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
39
40
41
42
  MODULE_DESCRIPTION("Dummy soundcard (/dev/null)");
  MODULE_LICENSE("GPL");
  MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}");
  
  #define MAX_PCM_DEVICES		4
b888d1ce8   Takashi Iwai   ALSA: dummy - Inc...
43
  #define MAX_PCM_SUBSTREAMS	128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
  #define MAX_MIDI_DEVICES	2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  /* defaults */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  #define MAX_BUFFER_SIZE		(64*1024)
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
47
  #define MIN_PERIOD_SIZE		64
2ad5dd8dc   Jaroslav Kysela   [ALSA] dummy driv...
48
  #define MAX_PERIOD_SIZE		MAX_BUFFER_SIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
  #define USE_FORMATS 		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
  #define USE_RATE		SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000
  #define USE_RATE_MIN		5500
  #define USE_RATE_MAX		48000
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
53
  #define USE_CHANNELS_MIN 	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  #define USE_CHANNELS_MAX 	2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
  #define USE_PERIODS_MIN 	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  #define USE_PERIODS_MAX 	1024
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57
58
59
  
  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */
  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */
a67ff6a54   Rusty Russell   ALSA: module_para...
60
  static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
61
  static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
  static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1};
  static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};
  //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2};
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
65
  #ifdef CONFIG_HIGH_RES_TIMERS
a67ff6a54   Rusty Russell   ALSA: module_para...
66
  static bool hrtimer = 1;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
67
  #endif
a67ff6a54   Rusty Russell   ALSA: module_para...
68
  static bool fake_buffer = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
  
  module_param_array(index, int, NULL, 0444);
  MODULE_PARM_DESC(index, "Index value for dummy soundcard.");
  module_param_array(id, charp, NULL, 0444);
  MODULE_PARM_DESC(id, "ID string for dummy soundcard.");
  module_param_array(enable, bool, NULL, 0444);
  MODULE_PARM_DESC(enable, "Enable this dummy soundcard.");
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
76
77
  module_param_array(model, charp, NULL, 0444);
  MODULE_PARM_DESC(model, "Soundcard model.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
  module_param_array(pcm_devs, int, NULL, 0444);
  MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver.");
  module_param_array(pcm_substreams, int, NULL, 0444);
23aebca48   Takashi Iwai   ALSA: dummy - Fix...
81
  MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
82
83
  //module_param_array(midi_devs, int, NULL, 0444);
  //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver.");
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
84
85
  module_param(fake_buffer, bool, 0444);
  MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
86
87
88
89
  #ifdef CONFIG_HIGH_RES_TIMERS
  module_param(hrtimer, bool, 0644);
  MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90

f7a9275d9   Clemens Ladisch   [ALSA] unregister...
91
  static struct platform_device *devices[SNDRV_CARDS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
92
93
94
95
96
97
  #define MIXER_ADDR_MASTER	0
  #define MIXER_ADDR_LINE		1
  #define MIXER_ADDR_MIC		2
  #define MIXER_ADDR_SYNTH	3
  #define MIXER_ADDR_CD		4
  #define MIXER_ADDR_LAST		4
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
98
99
100
101
102
103
104
105
  struct dummy_timer_ops {
  	int (*create)(struct snd_pcm_substream *);
  	void (*free)(struct snd_pcm_substream *);
  	int (*prepare)(struct snd_pcm_substream *);
  	int (*start)(struct snd_pcm_substream *);
  	int (*stop)(struct snd_pcm_substream *);
  	snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *);
  };
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  struct dummy_model {
  	const char *name;
  	int (*playback_constraints)(struct snd_pcm_runtime *runtime);
  	int (*capture_constraints)(struct snd_pcm_runtime *runtime);
  	u64 formats;
  	size_t buffer_bytes_max;
  	size_t period_bytes_min;
  	size_t period_bytes_max;
  	unsigned int periods_min;
  	unsigned int periods_max;
  	unsigned int rates;
  	unsigned int rate_min;
  	unsigned int rate_max;
  	unsigned int channels_min;
  	unsigned int channels_max;
  };
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
122
123
  struct snd_dummy {
  	struct snd_card *card;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
124
  	struct dummy_model *model;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
125
  	struct snd_pcm *pcm;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
126
  	struct snd_pcm_hardware pcm_hw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
  	spinlock_t mixer_lock;
  	int mixer_volume[MIXER_ADDR_LAST+1][2];
  	int capture_source[MIXER_ADDR_LAST+1][2];
16e434670   Clemens Ladisch   ALSA: dummy: allo...
130
131
132
  	int iobox;
  	struct snd_kcontrol *cd_volume_ctl;
  	struct snd_kcontrol *cd_switch_ctl;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
133
  	const struct dummy_timer_ops *timer_ops;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
134
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
135

c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
136
  /*
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
   * card models
   */
  
  static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
  {
  	int err;
  	err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
  	if (err < 0)
  		return err;
  	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX);
  	if (err < 0)
  		return err;
  	return 0;
  }
  
  struct dummy_model model_emu10k1 = {
  	.name = "emu10k1",
  	.playback_constraints = emu10k1_playback_constraints,
  	.buffer_bytes_max = 128 * 1024,
  };
  
  struct dummy_model model_rme9652 = {
  	.name = "rme9652",
  	.buffer_bytes_max = 26 * 64 * 1024,
  	.formats = SNDRV_PCM_FMTBIT_S32_LE,
  	.channels_min = 26,
  	.channels_max = 26,
  	.periods_min = 2,
  	.periods_max = 2,
  };
  
  struct dummy_model model_ice1712 = {
  	.name = "ice1712",
  	.buffer_bytes_max = 256 * 1024,
  	.formats = SNDRV_PCM_FMTBIT_S32_LE,
  	.channels_min = 10,
  	.channels_max = 10,
  	.periods_min = 1,
  	.periods_max = 1024,
  };
  
  struct dummy_model model_uda1341 = {
  	.name = "uda1341",
  	.buffer_bytes_max = 16380,
  	.formats = SNDRV_PCM_FMTBIT_S16_LE,
  	.channels_min = 2,
  	.channels_max = 2,
  	.periods_min = 2,
  	.periods_max = 255,
  };
  
  struct dummy_model model_ac97 = {
  	.name = "ac97",
  	.formats = SNDRV_PCM_FMTBIT_S16_LE,
  	.channels_min = 2,
  	.channels_max = 2,
  	.rates = SNDRV_PCM_RATE_48000,
  	.rate_min = 48000,
  	.rate_max = 48000,
  };
  
  struct dummy_model model_ca0106 = {
  	.name = "ca0106",
  	.formats = SNDRV_PCM_FMTBIT_S16_LE,
  	.buffer_bytes_max = ((65536-64)*8),
  	.period_bytes_max = (65536-64),
  	.periods_min = 2,
  	.periods_max = 8,
  	.channels_min = 2,
  	.channels_max = 2,
  	.rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000,
  	.rate_min = 48000,
  	.rate_max = 192000,
  };
  
  struct dummy_model *dummy_models[] = {
  	&model_emu10k1,
  	&model_rme9652,
  	&model_ice1712,
  	&model_uda1341,
  	&model_ac97,
  	&model_ca0106,
  	NULL
  };
  
  /*
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
223
224
225
226
   * system timer interface
   */
  
  struct dummy_systimer_pcm {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
227
228
  	spinlock_t lock;
  	struct timer_list timer;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
229
230
  	unsigned long base_time;
  	unsigned int frac_pos;	/* fractional sample position (based HZ) */
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
231
  	unsigned int frac_period_rest;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
232
233
234
  	unsigned int frac_buffer_size;	/* buffer_size * HZ */
  	unsigned int frac_period_size;	/* period_size * HZ */
  	unsigned int rate;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
235
  	int elapsed;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
236
237
  	struct snd_pcm_substream *substream;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
238

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
239
240
  static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
  {
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
241
  	dpcm->timer.expires = jiffies +
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
242
  		(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
243
244
245
246
247
248
249
250
251
252
  	add_timer(&dpcm->timer);
  }
  
  static void dummy_systimer_update(struct dummy_systimer_pcm *dpcm)
  {
  	unsigned long delta;
  
  	delta = jiffies - dpcm->base_time;
  	if (!delta)
  		return;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
253
254
255
  	dpcm->base_time += delta;
  	delta *= dpcm->rate;
  	dpcm->frac_pos += delta;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
256
257
  	while (dpcm->frac_pos >= dpcm->frac_buffer_size)
  		dpcm->frac_pos -= dpcm->frac_buffer_size;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
258
259
260
261
262
  	while (dpcm->frac_period_rest <= delta) {
  		dpcm->elapsed++;
  		dpcm->frac_period_rest += dpcm->frac_period_size;
  	}
  	dpcm->frac_period_rest -= delta;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
263
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
264
  static int dummy_systimer_start(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
266
267
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
  	spin_lock(&dpcm->lock);
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
268
269
  	dpcm->base_time = jiffies;
  	dummy_systimer_rearm(dpcm);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
270
271
  	spin_unlock(&dpcm->lock);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
272
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
273
  static int dummy_systimer_stop(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
275
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
276
  	spin_lock(&dpcm->lock);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
277
  	del_timer(&dpcm->timer);
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
278
  	spin_unlock(&dpcm->lock);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
279
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
281
  static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
282
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
283
  	struct snd_pcm_runtime *runtime = substream->runtime;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
284
  	struct dummy_systimer_pcm *dpcm = runtime->private_data;
369b240d6   Roel Kluin   [ALSA] sound/driv...
285

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
286
287
288
289
  	dpcm->frac_pos = 0;
  	dpcm->rate = runtime->rate;
  	dpcm->frac_buffer_size = runtime->buffer_size * HZ;
  	dpcm->frac_period_size = runtime->period_size * HZ;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
290
291
  	dpcm->frac_period_rest = dpcm->frac_period_size;
  	dpcm->elapsed = 0;
53463a830   Ahmet Ä°nan   [ALSA] snd-dummy ...
292

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  	return 0;
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
295
  static void dummy_systimer_callback(unsigned long data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
297
  	struct dummy_systimer_pcm *dpcm = (struct dummy_systimer_pcm *)data;
b32425ac9   Takashi Iwai   [ALSA] Fix possib...
298
  	unsigned long flags;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
299
  	int elapsed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
  	
b32425ac9   Takashi Iwai   [ALSA] Fix possib...
301
  	spin_lock_irqsave(&dpcm->lock, flags);
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
302
303
  	dummy_systimer_update(dpcm);
  	dummy_systimer_rearm(dpcm);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
304
305
  	elapsed = dpcm->elapsed;
  	dpcm->elapsed = 0;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
306
  	spin_unlock_irqrestore(&dpcm->lock, flags);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
307
308
  	if (elapsed)
  		snd_pcm_period_elapsed(dpcm->substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
309
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
310
311
  static snd_pcm_uframes_t
  dummy_systimer_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
312
  {
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
313
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
314
  	snd_pcm_uframes_t pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
316
317
  	spin_lock(&dpcm->lock);
  	dummy_systimer_update(dpcm);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
318
  	pos = dpcm->frac_pos / HZ;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
319
  	spin_unlock(&dpcm->lock);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
320
  	return pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
321
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
322
  static int dummy_systimer_create(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  	struct dummy_systimer_pcm *dpcm;
  
  	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
  	if (!dpcm)
  		return -ENOMEM;
  	substream->runtime->private_data = dpcm;
  	init_timer(&dpcm->timer);
  	dpcm->timer.data = (unsigned long) dpcm;
  	dpcm->timer.function = dummy_systimer_callback;
  	spin_lock_init(&dpcm->lock);
  	dpcm->substream = substream;
  	return 0;
  }
  
  static void dummy_systimer_free(struct snd_pcm_substream *substream)
  {
  	kfree(substream->runtime->private_data);
  }
  
  static struct dummy_timer_ops dummy_systimer_ops = {
  	.create =	dummy_systimer_create,
  	.free =		dummy_systimer_free,
  	.prepare =	dummy_systimer_prepare,
  	.start =	dummy_systimer_start,
  	.stop =		dummy_systimer_stop,
  	.pointer =	dummy_systimer_pointer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
  };
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  #ifdef CONFIG_HIGH_RES_TIMERS
  /*
   * hrtimer interface
   */
  
  struct dummy_hrtimer_pcm {
  	ktime_t base_time;
  	ktime_t period_time;
  	atomic_t running;
  	struct hrtimer timer;
  	struct tasklet_struct tasklet;
  	struct snd_pcm_substream *substream;
  };
  
  static void dummy_hrtimer_pcm_elapsed(unsigned long priv)
  {
  	struct dummy_hrtimer_pcm *dpcm = (struct dummy_hrtimer_pcm *)priv;
  	if (atomic_read(&dpcm->running))
  		snd_pcm_period_elapsed(dpcm->substream);
  }
  
  static enum hrtimer_restart dummy_hrtimer_callback(struct hrtimer *timer)
  {
  	struct dummy_hrtimer_pcm *dpcm;
  
  	dpcm = container_of(timer, struct dummy_hrtimer_pcm, timer);
  	if (!atomic_read(&dpcm->running))
  		return HRTIMER_NORESTART;
  	tasklet_schedule(&dpcm->tasklet);
  	hrtimer_forward_now(timer, dpcm->period_time);
  	return HRTIMER_RESTART;
  }
  
  static int dummy_hrtimer_start(struct snd_pcm_substream *substream)
  {
  	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  
  	dpcm->base_time = hrtimer_cb_get_time(&dpcm->timer);
  	hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL);
  	atomic_set(&dpcm->running, 1);
  	return 0;
  }
  
  static int dummy_hrtimer_stop(struct snd_pcm_substream *substream)
  {
  	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  
  	atomic_set(&dpcm->running, 0);
  	hrtimer_cancel(&dpcm->timer);
  	return 0;
  }
  
  static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
  {
  	tasklet_kill(&dpcm->tasklet);
  }
  
  static snd_pcm_uframes_t
  dummy_hrtimer_pointer(struct snd_pcm_substream *substream)
  {
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
  	u64 delta;
  	u32 pos;
  
  	delta = ktime_us_delta(hrtimer_cb_get_time(&dpcm->timer),
  			       dpcm->base_time);
  	delta = div_u64(delta * runtime->rate + 999999, 1000000);
  	div_u64_rem(delta, runtime->buffer_size, &pos);
  	return pos;
  }
  
  static int dummy_hrtimer_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
  	struct snd_pcm_runtime *runtime = substream->runtime;
  	struct dummy_hrtimer_pcm *dpcm = runtime->private_data;
  	unsigned int period, rate;
  	long sec;
  	unsigned long nsecs;
  
  	dummy_hrtimer_sync(dpcm);
  	period = runtime->period_size;
  	rate = runtime->rate;
  	sec = period / rate;
  	period %= rate;
  	nsecs = div_u64((u64)period * 1000000000UL + rate - 1, rate);
  	dpcm->period_time = ktime_set(sec, nsecs);
  
  	return 0;
  }
  
  static int dummy_hrtimer_create(struct snd_pcm_substream *substream)
  {
  	struct dummy_hrtimer_pcm *dpcm;
  
  	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
  	if (!dpcm)
  		return -ENOMEM;
  	substream->runtime->private_data = dpcm;
  	hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
  	dpcm->timer.function = dummy_hrtimer_callback;
  	dpcm->substream = substream;
  	atomic_set(&dpcm->running, 0);
  	tasklet_init(&dpcm->tasklet, dummy_hrtimer_pcm_elapsed,
  		     (unsigned long)dpcm);
  	return 0;
  }
  
  static void dummy_hrtimer_free(struct snd_pcm_substream *substream)
  {
  	struct dummy_hrtimer_pcm *dpcm = substream->runtime->private_data;
  	dummy_hrtimer_sync(dpcm);
  	kfree(dpcm);
  }
  
  static struct dummy_timer_ops dummy_hrtimer_ops = {
  	.create =	dummy_hrtimer_create,
  	.free =		dummy_hrtimer_free,
  	.prepare =	dummy_hrtimer_prepare,
  	.start =	dummy_hrtimer_start,
  	.stop =		dummy_hrtimer_stop,
  	.pointer =	dummy_hrtimer_pointer,
  };
  
  #endif /* CONFIG_HIGH_RES_TIMERS */
  
  /*
   * PCM interface
   */
  
  static int dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
  {
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
  		return dummy->timer_ops->start(substream);
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
  		return dummy->timer_ops->stop(substream);
  	}
  	return -EINVAL;
  }
  
  static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
498
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
  	return dummy->timer_ops->prepare(substream);
  }
  
  static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
  {
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  
  	return dummy->timer_ops->pointer(substream);
  }
  
  static struct snd_pcm_hardware dummy_pcm_hardware = {
  	.info =			(SNDRV_PCM_INFO_MMAP |
  				 SNDRV_PCM_INFO_INTERLEAVED |
  				 SNDRV_PCM_INFO_RESUME |
  				 SNDRV_PCM_INFO_MMAP_VALID),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
514
515
516
517
518
519
520
  	.formats =		USE_FORMATS,
  	.rates =		USE_RATE,
  	.rate_min =		USE_RATE_MIN,
  	.rate_max =		USE_RATE_MAX,
  	.channels_min =		USE_CHANNELS_MIN,
  	.channels_max =		USE_CHANNELS_MAX,
  	.buffer_bytes_max =	MAX_BUFFER_SIZE,
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
521
  	.period_bytes_min =	MIN_PERIOD_SIZE,
2ad5dd8dc   Jaroslav Kysela   [ALSA] dummy driv...
522
  	.period_bytes_max =	MAX_PERIOD_SIZE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
  	.periods_min =		USE_PERIODS_MIN,
  	.periods_max =		USE_PERIODS_MAX,
  	.fifo_size =		0,
  };
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
527
528
  static int dummy_pcm_hw_params(struct snd_pcm_substream *substream,
  			       struct snd_pcm_hw_params *hw_params)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  {
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
530
531
532
533
534
  	if (fake_buffer) {
  		/* runtime->dma_bytes has to be set manually to allow mmap */
  		substream->runtime->dma_bytes = params_buffer_bytes(hw_params);
  		return 0;
  	}
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
535
536
  	return snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
538
  static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
  {
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
540
541
  	if (fake_buffer)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  	return snd_pcm_lib_free_pages(substream);
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
544
  static int dummy_pcm_open(struct snd_pcm_substream *substream)
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
545
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
546
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
547
  	struct dummy_model *model = dummy->model;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
548
  	struct snd_pcm_runtime *runtime = substream->runtime;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
549
  	int err;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
550
551
552
553
554
555
556
  	dummy->timer_ops = &dummy_systimer_ops;
  #ifdef CONFIG_HIGH_RES_TIMERS
  	if (hrtimer)
  		dummy->timer_ops = &dummy_hrtimer_ops;
  #endif
  
  	err = dummy->timer_ops->create(substream);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
557
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559

d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
560
  	runtime->hw = dummy->pcm_hw;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
561
  	if (substream->pcm->device & 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
562
563
564
565
  		runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED;
  		runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED;
  	}
  	if (substream->pcm->device & 2)
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
566
567
  		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
  				      SNDRV_PCM_INFO_MMAP_VALID);
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
568
569
570
571
572
573
574
575
576
577
  	if (model == NULL)
  		return 0;
  
  	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
  		if (model->playback_constraints)
  			err = model->playback_constraints(substream->runtime);
  	} else {
  		if (model->capture_constraints)
  			err = model->capture_constraints(substream->runtime);
  	}
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
578
579
  	if (err < 0) {
  		dummy->timer_ops->free(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
580
  		return err;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
581
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
  	return 0;
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
584
  static int dummy_pcm_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
586
587
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
  	dummy->timer_ops->free(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
  	return 0;
  }
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
  /*
   * dummy buffer handling
   */
  
  static void *dummy_page[2];
  
  static void free_fake_buffer(void)
  {
  	if (fake_buffer) {
  		int i;
  		for (i = 0; i < 2; i++)
  			if (dummy_page[i]) {
  				free_page((unsigned long)dummy_page[i]);
  				dummy_page[i] = NULL;
  			}
  	}
  }
  
  static int alloc_fake_buffer(void)
  {
  	int i;
  
  	if (!fake_buffer)
  		return 0;
  	for (i = 0; i < 2; i++) {
  		dummy_page[i] = (void *)get_zeroed_page(GFP_KERNEL);
  		if (!dummy_page[i]) {
  			free_fake_buffer();
  			return -ENOMEM;
  		}
  	}
  	return 0;
  }
  
  static int dummy_pcm_copy(struct snd_pcm_substream *substream,
  			  int channel, snd_pcm_uframes_t pos,
  			  void __user *dst, snd_pcm_uframes_t count)
  {
  	return 0; /* do nothing */
  }
  
  static int dummy_pcm_silence(struct snd_pcm_substream *substream,
  			     int channel, snd_pcm_uframes_t pos,
  			     snd_pcm_uframes_t count)
  {
  	return 0; /* do nothing */
  }
  
  static struct page *dummy_pcm_page(struct snd_pcm_substream *substream,
  				   unsigned long offset)
  {
  	return virt_to_page(dummy_page[substream->stream]); /* the same page */
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
643
644
645
646
647
648
649
650
651
  static struct snd_pcm_ops dummy_pcm_ops = {
  	.open =		dummy_pcm_open,
  	.close =	dummy_pcm_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	dummy_pcm_hw_params,
  	.hw_free =	dummy_pcm_hw_free,
  	.prepare =	dummy_pcm_prepare,
  	.trigger =	dummy_pcm_trigger,
  	.pointer =	dummy_pcm_pointer,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  };
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
653
654
655
656
657
658
659
660
661
662
663
664
665
  static struct snd_pcm_ops dummy_pcm_ops_no_buf = {
  	.open =		dummy_pcm_open,
  	.close =	dummy_pcm_close,
  	.ioctl =	snd_pcm_lib_ioctl,
  	.hw_params =	dummy_pcm_hw_params,
  	.hw_free =	dummy_pcm_hw_free,
  	.prepare =	dummy_pcm_prepare,
  	.trigger =	dummy_pcm_trigger,
  	.pointer =	dummy_pcm_pointer,
  	.copy =		dummy_pcm_copy,
  	.silence =	dummy_pcm_silence,
  	.page =		dummy_pcm_page,
  };
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
666
667
  static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
  			      int substreams)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
669
  	struct snd_pcm *pcm;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
670
  	struct snd_pcm_ops *ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	int err;
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
672
673
674
  	err = snd_pcm_new(dummy->card, "Dummy PCM", device,
  			       substreams, substreams, &pcm);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
675
  		return err;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
676
  	dummy->pcm = pcm;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
677
678
679
680
681
682
  	if (fake_buffer)
  		ops = &dummy_pcm_ops_no_buf;
  	else
  		ops = &dummy_pcm_ops;
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, ops);
  	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
  	pcm->private_data = dummy;
  	pcm->info_flags = 0;
  	strcpy(pcm->name, "Dummy PCM");
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
686
687
688
689
690
691
  	if (!fake_buffer) {
  		snd_pcm_lib_preallocate_pages_for_all(pcm,
  			SNDRV_DMA_TYPE_CONTINUOUS,
  			snd_dma_continuous_data(GFP_KERNEL),
  			0, 64*1024);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  	return 0;
  }
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
694
695
696
  /*
   * mixer interface
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  #define DUMMY_VOLUME(xname, xindex, addr) \
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
698
699
700
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
    .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
    .name = xname, .index = xindex, \
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
    .info = snd_dummy_volume_info, \
    .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
703
704
    .private_value = addr, \
    .tlv = { .p = db_scale_dummy } }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
705

4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
706
707
  static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 2;
  	uinfo->value.integer.min = -50;
  	uinfo->value.integer.max = 100;
  	return 0;
  }
   
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
716
717
  static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
719
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
720
  	int addr = kcontrol->private_value;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
721
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
  	ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0];
  	ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1];
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
724
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
  	return 0;
  }
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
727
728
  static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
729
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
730
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
736
737
738
739
740
741
742
743
  	int change, addr = kcontrol->private_value;
  	int left, right;
  
  	left = ucontrol->value.integer.value[0];
  	if (left < -50)
  		left = -50;
  	if (left > 100)
  		left = 100;
  	right = ucontrol->value.integer.value[1];
  	if (right < -50)
  		right = -50;
  	if (right > 100)
  		right = 100;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
744
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
747
748
  	change = dummy->mixer_volume[addr][0] != left ||
  	         dummy->mixer_volume[addr][1] != right;
  	dummy->mixer_volume[addr][0] = left;
  	dummy->mixer_volume[addr][1] = right;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
749
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
  	return change;
  }
0cb29ea0d   Takashi Iwai   [ALSA] Add even m...
752
  static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
753

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
758
  #define DUMMY_CAPSRC(xname, xindex, addr) \
  { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
    .info = snd_dummy_capsrc_info, \
    .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \
    .private_value = addr }
a5ce88909   Takashi Iwai   [ALSA] Clean up w...
759
  #define snd_dummy_capsrc_info	snd_ctl_boolean_stereo_info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
760
   
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
761
762
  static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
764
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
765
  	int addr = kcontrol->private_value;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
766
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
  	ucontrol->value.integer.value[0] = dummy->capture_source[addr][0];
  	ucontrol->value.integer.value[1] = dummy->capture_source[addr][1];
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
769
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
770
771
  	return 0;
  }
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
772
  static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
773
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
774
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
775
776
777
778
779
  	int change, addr = kcontrol->private_value;
  	int left, right;
  
  	left = ucontrol->value.integer.value[0] & 1;
  	right = ucontrol->value.integer.value[1] & 1;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
780
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781
782
783
784
  	change = dummy->capture_source[addr][0] != left &&
  	         dummy->capture_source[addr][1] != right;
  	dummy->capture_source[addr][0] = left;
  	dummy->capture_source[addr][1] = right;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
785
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
786
787
  	return change;
  }
16e434670   Clemens Ladisch   ALSA: dummy: allo...
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
  static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_info *info)
  {
  	const char *const names[] = { "None", "CD Player" };
  
  	return snd_ctl_enum_info(info, 1, 2, names);
  }
  
  static int snd_dummy_iobox_get(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *value)
  {
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
  
  	value->value.enumerated.item[0] = dummy->iobox;
  	return 0;
  }
  
  static int snd_dummy_iobox_put(struct snd_kcontrol *kcontrol,
  			       struct snd_ctl_elem_value *value)
  {
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
  	int changed;
  
  	if (value->value.enumerated.item[0] > 1)
  		return -EINVAL;
  
  	changed = value->value.enumerated.item[0] != dummy->iobox;
  	if (changed) {
  		dummy->iobox = value->value.enumerated.item[0];
  
  		if (dummy->iobox) {
  			dummy->cd_volume_ctl->vd[0].access &=
  				~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  			dummy->cd_switch_ctl->vd[0].access &=
  				~SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  		} else {
  			dummy->cd_volume_ctl->vd[0].access |=
  				SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  			dummy->cd_switch_ctl->vd[0].access |=
  				SNDRV_CTL_ELEM_ACCESS_INACTIVE;
  		}
  
  		snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,
  			       &dummy->cd_volume_ctl->id);
  		snd_ctl_notify(dummy->card, SNDRV_CTL_EVENT_MASK_INFO,
  			       &dummy->cd_switch_ctl->id);
  	}
  
  	return changed;
  }
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
838
  static struct snd_kcontrol_new snd_dummy_controls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
839
840
841
  DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),
  DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),
  DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH),
e05d69642   Takashi Iwai   [ALSA] Fix some t...
842
  DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
  DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
e05d69642   Takashi Iwai   [ALSA] Fix some t...
844
  DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
  DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
e05d69642   Takashi Iwai   [ALSA] Fix some t...
846
  DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
847
  DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
16e434670   Clemens Ladisch   ALSA: dummy: allo...
848
849
850
851
852
853
854
855
  DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD),
  {
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name  = "External I/O Box",
  	.info  = snd_dummy_iobox_info,
  	.get   = snd_dummy_iobox_get,
  	.put   = snd_dummy_iobox_put,
  },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
856
  };
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
857
  static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
858
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
859
  	struct snd_card *card = dummy->card;
16e434670   Clemens Ladisch   ALSA: dummy: allo...
860
  	struct snd_kcontrol *kcontrol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
861
862
  	unsigned int idx;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
863
864
  	spin_lock_init(&dummy->mixer_lock);
  	strcpy(card->mixername, "Dummy Mixer");
16e434670   Clemens Ladisch   ALSA: dummy: allo...
865
  	dummy->iobox = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
866
867
  
  	for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
16e434670   Clemens Ladisch   ALSA: dummy: allo...
868
869
  		kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy);
  		err = snd_ctl_add(card, kcontrol);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
870
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
871
  			return err;
16e434670   Clemens Ladisch   ALSA: dummy: allo...
872
873
874
875
  		if (!strcmp(kcontrol->id.name, "CD Volume"))
  			dummy->cd_volume_ctl = kcontrol;
  		else if (!strcmp(kcontrol->id.name, "CD Capture Switch"))
  			dummy->cd_switch_ctl = kcontrol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
876
877
878
  	}
  	return 0;
  }
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
879
880
881
882
  #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_PROC_FS)
  /*
   * proc interface
   */
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
883
884
  static void print_formats(struct snd_dummy *dummy,
  			  struct snd_info_buffer *buffer)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
885
886
887
888
  {
  	int i;
  
  	for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
889
  		if (dummy->pcm_hw.formats & (1ULL << i))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
890
891
892
  			snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
  	}
  }
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
893
894
  static void print_rates(struct snd_dummy *dummy,
  			struct snd_info_buffer *buffer)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
895
896
897
898
899
900
  {
  	static int rates[] = {
  		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
  		64000, 88200, 96000, 176400, 192000,
  	};
  	int i;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
901
  	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
902
  		snd_iprintf(buffer, " continuous");
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
903
  	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
904
905
  		snd_iprintf(buffer, " knot");
  	for (i = 0; i < ARRAY_SIZE(rates); i++)
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
906
  		if (dummy->pcm_hw.rates & (1 << i))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
907
908
  			snd_iprintf(buffer, " %d", rates[i]);
  }
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
909
910
911
912
  #define get_dummy_int_ptr(dummy, ofs) \
  	(unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs))
  #define get_dummy_ll_ptr(dummy, ofs) \
  	(unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
  
  struct dummy_hw_field {
  	const char *name;
  	const char *format;
  	unsigned int offset;
  	unsigned int size;
  };
  #define FIELD_ENTRY(item, fmt) {		   \
  	.name = #item,				   \
  	.format = fmt,				   \
  	.offset = offsetof(struct snd_pcm_hardware, item), \
  	.size = sizeof(dummy_pcm_hardware.item) }
  
  static struct dummy_hw_field fields[] = {
  	FIELD_ENTRY(formats, "%#llx"),
  	FIELD_ENTRY(rates, "%#x"),
  	FIELD_ENTRY(rate_min, "%d"),
  	FIELD_ENTRY(rate_max, "%d"),
  	FIELD_ENTRY(channels_min, "%d"),
  	FIELD_ENTRY(channels_max, "%d"),
  	FIELD_ENTRY(buffer_bytes_max, "%ld"),
  	FIELD_ENTRY(period_bytes_min, "%ld"),
  	FIELD_ENTRY(period_bytes_max, "%ld"),
  	FIELD_ENTRY(periods_min, "%d"),
  	FIELD_ENTRY(periods_max, "%d"),
  };
  
  static void dummy_proc_read(struct snd_info_entry *entry,
  			    struct snd_info_buffer *buffer)
  {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
943
  	struct snd_dummy *dummy = entry->private_data;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
944
945
946
947
948
949
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(fields); i++) {
  		snd_iprintf(buffer, "%s ", fields[i].name);
  		if (fields[i].size == sizeof(int))
  			snd_iprintf(buffer, fields[i].format,
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
950
  				*get_dummy_int_ptr(dummy, fields[i].offset));
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
951
952
  		else
  			snd_iprintf(buffer, fields[i].format,
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
953
  				*get_dummy_ll_ptr(dummy, fields[i].offset));
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
954
  		if (!strcmp(fields[i].name, "formats"))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
955
  			print_formats(dummy, buffer);
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
956
  		else if (!strcmp(fields[i].name, "rates"))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
957
  			print_rates(dummy, buffer);
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
958
959
960
961
962
963
964
965
  		snd_iprintf(buffer, "
  ");
  	}
  }
  
  static void dummy_proc_write(struct snd_info_entry *entry,
  			     struct snd_info_buffer *buffer)
  {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
966
  	struct snd_dummy *dummy = entry->private_data;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
  	char line[64];
  
  	while (!snd_info_get_line(buffer, line, sizeof(line))) {
  		char item[20];
  		const char *ptr;
  		unsigned long long val;
  		int i;
  
  		ptr = snd_info_get_str(item, line, sizeof(item));
  		for (i = 0; i < ARRAY_SIZE(fields); i++) {
  			if (!strcmp(item, fields[i].name))
  				break;
  		}
  		if (i >= ARRAY_SIZE(fields))
  			continue;
  		snd_info_get_str(item, ptr, sizeof(item));
b785a492c   Jingoo Han   ALSA: replace str...
983
  		if (kstrtoull(item, 0, &val))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
984
985
  			continue;
  		if (fields[i].size == sizeof(int))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
986
  			*get_dummy_int_ptr(dummy, fields[i].offset) = val;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
987
  		else
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
988
  			*get_dummy_ll_ptr(dummy, fields[i].offset) = val;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
989
990
  	}
  }
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
991
  static void dummy_proc_init(struct snd_dummy *chip)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
992
993
994
995
996
997
998
  {
  	struct snd_info_entry *entry;
  
  	if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) {
  		snd_info_set_text_ops(entry, chip, dummy_proc_read);
  		entry->c.text.write = dummy_proc_write;
  		entry->mode |= S_IWUSR;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
999
  		entry->private_data = chip;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
1000
1001
1002
1003
1004
  	}
  }
  #else
  #define dummy_proc_init(x)
  #endif /* CONFIG_SND_DEBUG && CONFIG_PROC_FS */
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
1005
  static int snd_dummy_probe(struct platform_device *devptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1006
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
1007
1008
  	struct snd_card *card;
  	struct snd_dummy *dummy;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
1009
  	struct dummy_model *m = NULL, **mdl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  	int idx, err;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1011
  	int dev = devptr->id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012

5872f3f62   Takashi Iwai   ALSA: drivers: Co...
1013
1014
  	err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
  			   sizeof(struct snd_dummy), &card);
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
1015
1016
  	if (err < 0)
  		return err;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
1017
  	dummy = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1018
  	dummy->card = card;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  	for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
  		if (strcmp(model[dev], (*mdl)->name) == 0) {
  			printk(KERN_INFO
  				"snd-dummy: Using model '%s' for card %i
  ",
  				(*mdl)->name, card->number);
  			m = dummy->model = *mdl;
  			break;
  		}
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1029
1030
1031
1032
1033
  	for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) {
  		if (pcm_substreams[dev] < 1)
  			pcm_substreams[dev] = 1;
  		if (pcm_substreams[dev] > MAX_PCM_SUBSTREAMS)
  			pcm_substreams[dev] = MAX_PCM_SUBSTREAMS;
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1034
1035
  		err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1036
1037
  			goto __nodev;
  	}
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
  
  	dummy->pcm_hw = dummy_pcm_hardware;
  	if (m) {
  		if (m->formats)
  			dummy->pcm_hw.formats = m->formats;
  		if (m->buffer_bytes_max)
  			dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max;
  		if (m->period_bytes_min)
  			dummy->pcm_hw.period_bytes_min = m->period_bytes_min;
  		if (m->period_bytes_max)
  			dummy->pcm_hw.period_bytes_max = m->period_bytes_max;
  		if (m->periods_min)
  			dummy->pcm_hw.periods_min = m->periods_min;
  		if (m->periods_max)
  			dummy->pcm_hw.periods_max = m->periods_max;
  		if (m->rates)
  			dummy->pcm_hw.rates = m->rates;
  		if (m->rate_min)
  			dummy->pcm_hw.rate_min = m->rate_min;
  		if (m->rate_max)
  			dummy->pcm_hw.rate_max = m->rate_max;
  		if (m->channels_min)
  			dummy->pcm_hw.channels_min = m->channels_min;
  		if (m->channels_max)
  			dummy->pcm_hw.channels_max = m->channels_max;
  	}
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1064
1065
  	err = snd_card_dummy_new_mixer(dummy);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1066
1067
1068
1069
  		goto __nodev;
  	strcpy(card->driver, "Dummy");
  	strcpy(card->shortname, "Dummy");
  	sprintf(card->longname, "Dummy %i", dev + 1);
16dab54b8   Takashi Iwai   [ALSA] Add snd_ca...
1070

9b151fec1   Takashi Iwai   ALSA: dummy - Add...
1071
  	dummy_proc_init(dummy);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1072
1073
  	err = snd_card_register(card);
  	if (err == 0) {
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1074
  		platform_set_drvdata(devptr, card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1075
1076
1077
1078
1079
1080
  		return 0;
  	}
        __nodev:
  	snd_card_free(card);
  	return err;
  }
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
1081
  static int snd_dummy_remove(struct platform_device *devptr)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1082
1083
  {
  	snd_card_free(platform_get_drvdata(devptr));
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1084
1085
  	return 0;
  }
d34e4e00a   Takashi Iwai   ALSA: platform: C...
1086
  #ifdef CONFIG_PM_SLEEP
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1087
  static int snd_dummy_suspend(struct device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1088
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1089
  	struct snd_card *card = dev_get_drvdata(pdev);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1090
  	struct snd_dummy *dummy = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1091

6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1092
1093
1094
1095
1096
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
  	snd_pcm_suspend_all(dummy->pcm);
  	return 0;
  }
  	
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1097
  static int snd_dummy_resume(struct device *pdev)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1098
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1099
  	struct snd_card *card = dev_get_drvdata(pdev);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1100
1101
1102
1103
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return 0;
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1104
1105
1106
1107
1108
  
  static SIMPLE_DEV_PM_OPS(snd_dummy_pm, snd_dummy_suspend, snd_dummy_resume);
  #define SND_DUMMY_PM_OPS	&snd_dummy_pm
  #else
  #define SND_DUMMY_PM_OPS	NULL
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1109
1110
1111
1112
1113
1114
  #endif
  
  #define SND_DUMMY_DRIVER	"snd_dummy"
  
  static struct platform_driver snd_dummy_driver = {
  	.probe		= snd_dummy_probe,
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
1115
  	.remove		= snd_dummy_remove,
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1116
  	.driver		= {
8bf01d8ab   Takashi Iwai   ALSA: Add missing...
1117
1118
  		.name	= SND_DUMMY_DRIVER,
  		.owner	= THIS_MODULE,
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1119
  		.pm	= SND_DUMMY_PM_OPS,
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1120
1121
  	},
  };
c12aad6ef   Randy Dunlap   [ALSA] more secti...
1122
  static void snd_dummy_unregister_all(void)
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1123
1124
1125
1126
1127
1128
  {
  	int i;
  
  	for (i = 0; i < ARRAY_SIZE(devices); ++i)
  		platform_device_unregister(devices[i]);
  	platform_driver_unregister(&snd_dummy_driver);
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
1129
  	free_fake_buffer();
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1130
  }
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1131
1132
1133
  static int __init alsa_card_dummy_init(void)
  {
  	int i, cards, err;
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1134
1135
  	err = platform_driver_register(&snd_dummy_driver);
  	if (err < 0)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1136
  		return err;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
1137
1138
1139
1140
1141
  	err = alloc_fake_buffer();
  	if (err < 0) {
  		platform_driver_unregister(&snd_dummy_driver);
  		return err;
  	}
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1142
  	cards = 0;
8278ca8fe   Takashi Iwai   [ALSA] Fix check ...
1143
  	for (i = 0; i < SNDRV_CARDS; i++) {
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1144
  		struct platform_device *device;
8278ca8fe   Takashi Iwai   [ALSA] Fix check ...
1145
1146
  		if (! enable[i])
  			continue;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1147
1148
  		device = platform_device_register_simple(SND_DUMMY_DRIVER,
  							 i, NULL, 0);
a182ee987   Rene Herman   [ALSA] continue o...
1149
1150
  		if (IS_ERR(device))
  			continue;
7152447df   Rene Herman   [ALSA] unregister...
1151
1152
1153
1154
  		if (!platform_get_drvdata(device)) {
  			platform_device_unregister(device);
  			continue;
  		}
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1155
  		devices[i] = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1156
1157
1158
1159
1160
1161
1162
  		cards++;
  	}
  	if (!cards) {
  #ifdef MODULE
  		printk(KERN_ERR "Dummy soundcard not found or device busy
  ");
  #endif
a182ee987   Rene Herman   [ALSA] continue o...
1163
1164
  		snd_dummy_unregister_all();
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1165
1166
1167
1168
1169
1170
  	}
  	return 0;
  }
  
  static void __exit alsa_card_dummy_exit(void)
  {
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1171
  	snd_dummy_unregister_all();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1172
1173
1174
1175
  }
  
  module_init(alsa_card_dummy_init)
  module_exit(alsa_card_dummy_exit)