Blame view

sound/drivers/dummy.c 31.3 KB
1a59d1b8e   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
  /*
   *  Dummy soundcard
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
4
   *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
5
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
  #include <linux/init.h>
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
7
8
  #include <linux/err.h>
  #include <linux/platform_device.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/jiffies.h>
  #include <linux/slab.h>
  #include <linux/time.h>
  #include <linux/wait.h>
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
13
14
  #include <linux/hrtimer.h>
  #include <linux/math64.h>
65a772172   Paul Gortmaker   sound: fix driver...
15
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  #include <sound/core.h>
  #include <sound/control.h>
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
18
  #include <sound/tlv.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <sound/pcm.h>
  #include <sound/rawmidi.h>
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
21
  #include <sound/info.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
  #include <sound/initval.h>
c1017a4cd   Jaroslav Kysela   [ALSA] Changed Ja...
23
  MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
26
27
28
  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...
29
  #define MAX_PCM_SUBSTREAMS	128
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
  #define MAX_MIDI_DEVICES	2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
  /* defaults */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  #define MAX_BUFFER_SIZE		(64*1024)
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
33
  #define MIN_PERIOD_SIZE		64
2ad5dd8dc   Jaroslav Kysela   [ALSA] dummy driv...
34
  #define MAX_PERIOD_SIZE		MAX_BUFFER_SIZE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  #define USE_FORMATS 		(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
  #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
39
  #define USE_CHANNELS_MIN 	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  #define USE_CHANNELS_MAX 	2
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
  #define USE_PERIODS_MIN 	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
42
  #define USE_PERIODS_MAX 	1024
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
43
44
45
  
  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...
46
  static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
47
  static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
49
50
  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...
51
  #ifdef CONFIG_HIGH_RES_TIMERS
a67ff6a54   Rusty Russell   ALSA: module_para...
52
  static bool hrtimer = 1;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
53
  #endif
a67ff6a54   Rusty Russell   ALSA: module_para...
54
  static bool fake_buffer = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
  
  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...
62
63
  module_param_array(model, charp, NULL, 0444);
  MODULE_PARM_DESC(model, "Soundcard model.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
64
65
66
  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...
67
  MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-128) for dummy driver.");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
68
69
  //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...
70
71
  module_param(fake_buffer, bool, 0444);
  MODULE_PARM_DESC(fake_buffer, "Fake buffer allocations.");
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
72
  #ifdef CONFIG_HIGH_RES_TIMERS
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
73
  module_param(hrtimer, bool, 0644);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
74
75
  MODULE_PARM_DESC(hrtimer, "Use hrtimer as the timer source.");
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
76

f7a9275d9   Clemens Ladisch   [ALSA] unregister...
77
  static struct platform_device *devices[SNDRV_CARDS];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
78
79
80
81
82
83
  #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...
84
85
86
87
88
89
90
91
  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 *);
  };
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
92
93
  #define get_dummy_ops(substream) \
  	(*(const struct dummy_timer_ops **)(substream)->runtime->private_data)
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
  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...
110
111
  struct snd_dummy {
  	struct snd_card *card;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
112
  	struct dummy_model *model;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
113
  	struct snd_pcm *pcm;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
114
  	struct snd_pcm_hardware pcm_hw;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
  	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...
118
119
120
  	int iobox;
  	struct snd_kcontrol *cd_volume_ctl;
  	struct snd_kcontrol *cd_switch_ctl;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
121
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122

c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
123
  /*
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
124
125
126
127
128
129
130
131
132
133
134
135
136
137
   * 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;
  }
e4c286880   Takashi Iwai   ALSA: dummy: make...
138
  static struct dummy_model model_emu10k1 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
139
140
141
142
  	.name = "emu10k1",
  	.playback_constraints = emu10k1_playback_constraints,
  	.buffer_bytes_max = 128 * 1024,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
143
  static struct dummy_model model_rme9652 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
144
145
146
147
148
149
150
151
  	.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,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
152
  static struct dummy_model model_ice1712 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
153
154
155
156
157
158
159
160
  	.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,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
161
  static struct dummy_model model_uda1341 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
162
163
164
165
166
167
168
169
  	.name = "uda1341",
  	.buffer_bytes_max = 16380,
  	.formats = SNDRV_PCM_FMTBIT_S16_LE,
  	.channels_min = 2,
  	.channels_max = 2,
  	.periods_min = 2,
  	.periods_max = 255,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
170
  static struct dummy_model model_ac97 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
171
172
173
174
175
176
177
178
  	.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,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
179
  static struct dummy_model model_ca0106 = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
180
181
182
183
184
185
186
187
188
189
190
191
  	.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,
  };
e4c286880   Takashi Iwai   ALSA: dummy: make...
192
  static struct dummy_model *dummy_models[] = {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
193
194
195
196
197
198
199
200
201
202
  	&model_emu10k1,
  	&model_rme9652,
  	&model_ice1712,
  	&model_uda1341,
  	&model_ac97,
  	&model_ca0106,
  	NULL
  };
  
  /*
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
203
204
205
206
   * system timer interface
   */
  
  struct dummy_systimer_pcm {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
207
208
  	/* ops must be the first item */
  	const struct dummy_timer_ops *timer_ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  	spinlock_t lock;
  	struct timer_list timer;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
211
212
  	unsigned long base_time;
  	unsigned int frac_pos;	/* fractional sample position (based HZ) */
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
213
  	unsigned int frac_period_rest;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
214
215
216
  	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...
217
  	int elapsed;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
218
219
  	struct snd_pcm_substream *substream;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
221
222
  static void dummy_systimer_rearm(struct dummy_systimer_pcm *dpcm)
  {
2a52b6eef   Roman Kollar   ALSA: dummy: use ...
223
224
  	mod_timer(&dpcm->timer, jiffies +
  		(dpcm->frac_period_rest + dpcm->rate - 1) / dpcm->rate);
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
225
226
227
228
229
230
231
232
233
  }
  
  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...
234
235
236
  	dpcm->base_time += delta;
  	delta *= dpcm->rate;
  	dpcm->frac_pos += delta;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
237
238
  	while (dpcm->frac_pos >= dpcm->frac_buffer_size)
  		dpcm->frac_pos -= dpcm->frac_buffer_size;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
239
240
241
242
243
  	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...
244
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
245
  static int dummy_systimer_start(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
246
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
247
248
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
  	spin_lock(&dpcm->lock);
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
249
250
  	dpcm->base_time = jiffies;
  	dummy_systimer_rearm(dpcm);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
251
252
  	spin_unlock(&dpcm->lock);
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
253
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
254
  static int dummy_systimer_stop(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
256
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
257
  	spin_lock(&dpcm->lock);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
258
  	del_timer(&dpcm->timer);
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
259
  	spin_unlock(&dpcm->lock);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
260
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
262
  static int dummy_systimer_prepare(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
263
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
264
  	struct snd_pcm_runtime *runtime = substream->runtime;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
265
  	struct dummy_systimer_pcm *dpcm = runtime->private_data;
369b240d6   Roel Kluin   [ALSA] sound/driv...
266

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
267
268
269
270
  	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...
271
272
  	dpcm->frac_period_rest = dpcm->frac_period_size;
  	dpcm->elapsed = 0;
53463a830   Ahmet Ä°nan   [ALSA] snd-dummy ...
273

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
275
  	return 0;
  }
bc47ba90b   Kees Cook   ALSA: drivers: Co...
276
  static void dummy_systimer_callback(struct timer_list *t)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
277
  {
bc47ba90b   Kees Cook   ALSA: drivers: Co...
278
  	struct dummy_systimer_pcm *dpcm = from_timer(dpcm, t, timer);
b32425ac9   Takashi Iwai   [ALSA] Fix possib...
279
  	unsigned long flags;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
280
  	int elapsed = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  	
b32425ac9   Takashi Iwai   [ALSA] Fix possib...
282
  	spin_lock_irqsave(&dpcm->lock, flags);
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
283
284
  	dummy_systimer_update(dpcm);
  	dummy_systimer_rearm(dpcm);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
285
286
  	elapsed = dpcm->elapsed;
  	dpcm->elapsed = 0;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
287
  	spin_unlock_irqrestore(&dpcm->lock, flags);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
288
289
  	if (elapsed)
  		snd_pcm_period_elapsed(dpcm->substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
290
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
291
292
  static snd_pcm_uframes_t
  dummy_systimer_pointer(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
  {
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
294
  	struct dummy_systimer_pcm *dpcm = substream->runtime->private_data;
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
295
  	snd_pcm_uframes_t pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296

b142037b4   Takashi Iwai   ALSA: dummy - Bet...
297
298
  	spin_lock(&dpcm->lock);
  	dummy_systimer_update(dpcm);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
299
  	pos = dpcm->frac_pos / HZ;
b142037b4   Takashi Iwai   ALSA: dummy - Bet...
300
  	spin_unlock(&dpcm->lock);
b5d107817   Takashi Iwai   ALSA: dummy - Fix...
301
  	return pos;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
302
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
303
  static int dummy_systimer_create(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
305
306
307
308
309
310
  	struct dummy_systimer_pcm *dpcm;
  
  	dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL);
  	if (!dpcm)
  		return -ENOMEM;
  	substream->runtime->private_data = dpcm;
bc47ba90b   Kees Cook   ALSA: drivers: Co...
311
  	timer_setup(&dpcm->timer, dummy_systimer_callback, 0);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
312
313
314
315
316
317
318
319
320
  	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);
  }
d8c5ed752   Julia Lawall   ALSA: dummy: cons...
321
  static const struct dummy_timer_ops dummy_systimer_ops = {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
322
323
324
325
326
327
  	.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
328
  };
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
329
330
331
332
333
334
  #ifdef CONFIG_HIGH_RES_TIMERS
  /*
   * hrtimer interface
   */
  
  struct dummy_hrtimer_pcm {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
335
336
  	/* ops must be the first item */
  	const struct dummy_timer_ops *timer_ops;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
337
338
339
340
  	ktime_t base_time;
  	ktime_t period_time;
  	atomic_t running;
  	struct hrtimer timer;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
341
342
  	struct snd_pcm_substream *substream;
  };
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
343
344
345
346
347
348
349
  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;
b03bbbe08   Thomas Gleixner   ALSA/dummy: Repla...
350
351
352
353
354
355
356
  	/*
  	 * In cases of XRUN and draining, this calls .trigger to stop PCM
  	 * substream.
  	 */
  	snd_pcm_period_elapsed(dpcm->substream);
  	if (!atomic_read(&dpcm->running))
  		return HRTIMER_NORESTART;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
357
358
359
360
361
362
363
364
365
  	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);
b03bbbe08   Thomas Gleixner   ALSA/dummy: Repla...
366
  	hrtimer_start(&dpcm->timer, dpcm->period_time, HRTIMER_MODE_REL_SOFT);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
367
368
369
370
371
372
373
374
375
  	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);
b03bbbe08   Thomas Gleixner   ALSA/dummy: Repla...
376
377
  	if (!hrtimer_callback_running(&dpcm->timer))
  		hrtimer_cancel(&dpcm->timer);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
378
379
380
381
382
  	return 0;
  }
  
  static inline void dummy_hrtimer_sync(struct dummy_hrtimer_pcm *dpcm)
  {
d5dbbe656   Takashi Iwai   ALSA: dummy: Fix ...
383
  	hrtimer_cancel(&dpcm->timer);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
  }
  
  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
402
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
  	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;
b03bbbe08   Thomas Gleixner   ALSA/dummy: Repla...
428
  	hrtimer_init(&dpcm->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL_SOFT);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
429
430
431
  	dpcm->timer.function = dummy_hrtimer_callback;
  	dpcm->substream = substream;
  	atomic_set(&dpcm->running, 0);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
432
433
434
435
436
437
438
439
440
  	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);
  }
d8c5ed752   Julia Lawall   ALSA: dummy: cons...
441
  static const struct dummy_timer_ops dummy_hrtimer_ops = {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
  	.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)
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
458
459
460
  	switch (cmd) {
  	case SNDRV_PCM_TRIGGER_START:
  	case SNDRV_PCM_TRIGGER_RESUME:
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
461
  		return get_dummy_ops(substream)->start(substream);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
462
463
  	case SNDRV_PCM_TRIGGER_STOP:
  	case SNDRV_PCM_TRIGGER_SUSPEND:
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
464
  		return get_dummy_ops(substream)->stop(substream);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
465
466
467
468
469
470
  	}
  	return -EINVAL;
  }
  
  static int dummy_pcm_prepare(struct snd_pcm_substream *substream)
  {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
471
  	return get_dummy_ops(substream)->prepare(substream);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
472
473
474
475
  }
  
  static snd_pcm_uframes_t dummy_pcm_pointer(struct snd_pcm_substream *substream)
  {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
476
  	return get_dummy_ops(substream)->pointer(substream);
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
477
  }
b6c0b7156   Bhumika Goyal   ALSA: drivers: ma...
478
  static const struct snd_pcm_hardware dummy_pcm_hardware = {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
479
480
481
482
  	.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
483
484
485
486
487
488
489
  	.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...
490
  	.period_bytes_min =	MIN_PERIOD_SIZE,
2ad5dd8dc   Jaroslav Kysela   [ALSA] dummy driv...
491
  	.period_bytes_max =	MAX_PERIOD_SIZE,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
492
493
494
495
  	.periods_min =		USE_PERIODS_MIN,
  	.periods_max =		USE_PERIODS_MAX,
  	.fifo_size =		0,
  };
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
496
497
  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
498
  {
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
499
500
501
502
503
  	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...
504
505
  	return snd_pcm_lib_malloc_pages(substream,
  					params_buffer_bytes(hw_params));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
506
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
507
  static int dummy_pcm_hw_free(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
508
  {
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
509
510
  	if (fake_buffer)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
512
  	return snd_pcm_lib_free_pages(substream);
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
513
  static int dummy_pcm_open(struct snd_pcm_substream *substream)
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
514
  {
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
515
  	struct snd_dummy *dummy = snd_pcm_substream_chip(substream);
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
516
  	struct dummy_model *model = dummy->model;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
517
  	struct snd_pcm_runtime *runtime = substream->runtime;
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
518
  	const struct dummy_timer_ops *ops;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
519
  	int err;
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
520
  	ops = &dummy_systimer_ops;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
521
522
  #ifdef CONFIG_HIGH_RES_TIMERS
  	if (hrtimer)
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
523
  		ops = &dummy_hrtimer_ops;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
524
  #endif
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
525
  	err = ops->create(substream);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
526
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  		return err;
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
528
  	get_dummy_ops(substream) = ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529

d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
530
  	runtime->hw = dummy->pcm_hw;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
531
  	if (substream->pcm->device & 1) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
533
534
535
  		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...
536
537
  		runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP |
  				      SNDRV_PCM_INFO_MMAP_VALID);
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
538
539
540
541
542
543
544
545
546
547
  	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...
548
  	if (err < 0) {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
549
  		get_dummy_ops(substream)->free(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
  		return err;
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
551
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
552
553
  	return 0;
  }
c631d03c6   Takashi Iwai   ALSA: dummy - Sup...
554
  static int dummy_pcm_close(struct snd_pcm_substream *substream)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  {
ddce57a6f   Takashi Iwai   ALSA: dummy: Impl...
556
  	get_dummy_ops(substream)->free(substream);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
  	return 0;
  }
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
  /*
   * 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,
d53611d21   Takashi Iwai   ALSA: dummy: Conv...
594
595
596
597
598
599
600
601
602
  			  int channel, unsigned long pos,
  			  void __user *dst, unsigned long bytes)
  {
  	return 0; /* do nothing */
  }
  
  static int dummy_pcm_copy_kernel(struct snd_pcm_substream *substream,
  				 int channel, unsigned long pos,
  				 void *dst, unsigned long bytes)
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
603
604
605
606
607
  {
  	return 0; /* do nothing */
  }
  
  static int dummy_pcm_silence(struct snd_pcm_substream *substream,
d53611d21   Takashi Iwai   ALSA: dummy: Conv...
608
609
  			     int channel, unsigned long pos,
  			     unsigned long bytes)
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
610
611
612
613
614
615
616
617
618
  {
  	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...
619
620
621
622
623
624
625
626
627
  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
628
  };
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
629
630
631
632
633
634
635
636
637
  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,
d53611d21   Takashi Iwai   ALSA: dummy: Conv...
638
639
640
  	.copy_user =	dummy_pcm_copy,
  	.copy_kernel =	dummy_pcm_copy_kernel,
  	.fill_silence =	dummy_pcm_silence,
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
641
642
  	.page =		dummy_pcm_page,
  };
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
643
644
  static int snd_card_dummy_pcm(struct snd_dummy *dummy, int device,
  			      int substreams)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
646
  	struct snd_pcm *pcm;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
647
  	struct snd_pcm_ops *ops;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
648
  	int err;
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
649
650
651
  	err = snd_pcm_new(dummy->card, "Dummy PCM", device,
  			       substreams, substreams, &pcm);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
  		return err;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
653
  	dummy->pcm = pcm;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
654
655
656
657
658
659
  	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
660
661
662
  	pcm->private_data = dummy;
  	pcm->info_flags = 0;
  	strcpy(pcm->name, "Dummy PCM");
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
663
664
665
666
667
668
  	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
669
670
  	return 0;
  }
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
671
672
673
  /*
   * mixer interface
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
674
  #define DUMMY_VOLUME(xname, xindex, addr) \
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
675
676
677
  { .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
678
679
    .info = snd_dummy_volume_info, \
    .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
680
681
    .private_value = addr, \
    .tlv = { .p = db_scale_dummy } }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682

4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
683
684
  static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol,
  				 struct snd_ctl_elem_info *uinfo)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
686
687
688
689
690
691
692
  {
  	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...
693
694
  static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
695
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
696
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
  	int addr = kcontrol->private_value;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
698
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699
700
  	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 ...
701
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
  	return 0;
  }
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
704
705
  static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
707
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708
709
710
711
712
713
714
715
716
717
718
719
720
  	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 ...
721
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
722
723
724
725
  	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 ...
726
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
727
728
  	return change;
  }
0cb29ea0d   Takashi Iwai   [ALSA] Add even m...
729
  static const DECLARE_TLV_DB_SCALE(db_scale_dummy, -4500, 30, 0);
fb567a8e4   Takashi Iwai   [ALSA] Add dB sca...
730

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
734
735
  #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...
736
  #define snd_dummy_capsrc_info	snd_ctl_boolean_stereo_info
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
   
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
738
739
  static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
741
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  	int addr = kcontrol->private_value;
c8eb6ba16   Takashi Iwai   [ALSA] snd-dummy ...
743
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
  	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 ...
746
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  	return 0;
  }
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
749
  static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
751
  	struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
755
756
  	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 ...
757
  	spin_lock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
758
759
760
761
  	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 ...
762
  	spin_unlock_irq(&dummy->mixer_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763
764
  	return change;
  }
16e434670   Clemens Ladisch   ALSA: dummy: allo...
765
766
767
  static int snd_dummy_iobox_info(struct snd_kcontrol *kcontrol,
  				struct snd_ctl_elem_info *info)
  {
a4a1b7370   Colin Ian King   ALSA: drivers: ma...
768
  	static const char *const names[] = { "None", "CD Player" };
16e434670   Clemens Ladisch   ALSA: dummy: allo...
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
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
  
  	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...
815
  static struct snd_kcontrol_new snd_dummy_controls[] = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
816
817
818
  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...
819
  DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
  DUMMY_VOLUME("Line Volume", 0, MIXER_ADDR_LINE),
e05d69642   Takashi Iwai   [ALSA] Fix some t...
821
  DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
822
  DUMMY_VOLUME("Mic Volume", 0, MIXER_ADDR_MIC),
e05d69642   Takashi Iwai   [ALSA] Fix some t...
823
  DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
824
  DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD),
16e434670   Clemens Ladisch   ALSA: dummy: allo...
825
826
827
828
829
830
831
832
  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
833
  };
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
834
  static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
835
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
836
  	struct snd_card *card = dummy->card;
16e434670   Clemens Ladisch   ALSA: dummy: allo...
837
  	struct snd_kcontrol *kcontrol;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
838
839
  	unsigned int idx;
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
841
  	spin_lock_init(&dummy->mixer_lock);
  	strcpy(card->mixername, "Dummy Mixer");
16e434670   Clemens Ladisch   ALSA: dummy: allo...
842
  	dummy->iobox = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
843
844
  
  	for (idx = 0; idx < ARRAY_SIZE(snd_dummy_controls); idx++) {
16e434670   Clemens Ladisch   ALSA: dummy: allo...
845
846
  		kcontrol = snd_ctl_new1(&snd_dummy_controls[idx], dummy);
  		err = snd_ctl_add(card, kcontrol);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
847
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
848
  			return err;
16e434670   Clemens Ladisch   ALSA: dummy: allo...
849
850
851
852
  		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
853
854
855
  	}
  	return 0;
  }
129a4c9f8   Takashi Iwai   ALSA: dummy: Repl...
856
  #if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_PROC_FS)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
857
858
859
  /*
   * proc interface
   */
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
860
861
  static void print_formats(struct snd_dummy *dummy,
  			  struct snd_info_buffer *buffer)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
862
863
  {
  	int i;
39fac9515   Takashi Iwai   ALSA: dummy: Fix ...
864
  	for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; i++) {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
865
  		if (dummy->pcm_hw.formats & (1ULL << i))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
866
867
868
  			snd_iprintf(buffer, " %s", snd_pcm_format_name(i));
  	}
  }
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
869
870
  static void print_rates(struct snd_dummy *dummy,
  			struct snd_info_buffer *buffer)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
871
872
873
874
875
876
  {
  	static int rates[] = {
  		5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000,
  		64000, 88200, 96000, 176400, 192000,
  	};
  	int i;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
877
  	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
878
  		snd_iprintf(buffer, " continuous");
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
879
  	if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
880
881
  		snd_iprintf(buffer, " knot");
  	for (i = 0; i < ARRAY_SIZE(rates); i++)
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
882
  		if (dummy->pcm_hw.rates & (1 << i))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
883
884
  			snd_iprintf(buffer, " %d", rates[i]);
  }
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
885
886
887
888
  #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...
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
  
  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...
919
  	struct snd_dummy *dummy = entry->private_data;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
920
921
922
923
924
925
  	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...
926
  				*get_dummy_int_ptr(dummy, fields[i].offset));
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
927
928
  		else
  			snd_iprintf(buffer, fields[i].format,
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
929
  				*get_dummy_ll_ptr(dummy, fields[i].offset));
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
930
  		if (!strcmp(fields[i].name, "formats"))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
931
  			print_formats(dummy, buffer);
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
932
  		else if (!strcmp(fields[i].name, "rates"))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
933
  			print_rates(dummy, buffer);
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
934
935
936
937
938
939
940
941
  		snd_iprintf(buffer, "
  ");
  	}
  }
  
  static void dummy_proc_write(struct snd_info_entry *entry,
  			     struct snd_info_buffer *buffer)
  {
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
942
  	struct snd_dummy *dummy = entry->private_data;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
  	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...
959
  		if (kstrtoull(item, 0, &val))
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
960
961
  			continue;
  		if (fields[i].size == sizeof(int))
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
962
  			*get_dummy_int_ptr(dummy, fields[i].offset) = val;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
963
  		else
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
964
  			*get_dummy_ll_ptr(dummy, fields[i].offset) = val;
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
965
966
  	}
  }
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
967
  static void dummy_proc_init(struct snd_dummy *chip)
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
968
  {
815d808c7   Takashi Iwai   ALSA: drivers: Cl...
969
970
  	snd_card_rw_proc_new(chip->card, "dummy_pcm", chip,
  			     dummy_proc_read, dummy_proc_write);
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
971
972
973
  }
  #else
  #define dummy_proc_init(x)
129a4c9f8   Takashi Iwai   ALSA: dummy: Repl...
974
  #endif /* CONFIG_SND_DEBUG && CONFIG_SND_PROC_FS */
9b151fec1   Takashi Iwai   ALSA: dummy - Add...
975

fbbb01a12   Bill Pemberton   ALSA: drivers: re...
976
  static int snd_dummy_probe(struct platform_device *devptr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
977
  {
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
978
979
  	struct snd_card *card;
  	struct snd_dummy *dummy;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
980
  	struct dummy_model *m = NULL, **mdl;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
981
  	int idx, err;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
982
  	int dev = devptr->id;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
983

5872f3f62   Takashi Iwai   ALSA: drivers: Co...
984
985
  	err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE,
  			   sizeof(struct snd_dummy), &card);
bd7dd77c2   Takashi Iwai   ALSA: Convert to ...
986
987
  	if (err < 0)
  		return err;
4a4d2cfd8   Takashi Iwai   [ALSA] Remove xxx...
988
  	dummy = card->private_data;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
989
  	dummy->card = card;
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
990
991
992
993
994
995
996
997
998
999
  	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
1000
1001
1002
1003
1004
  	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...
1005
1006
  		err = snd_card_dummy_pcm(dummy, idx, pcm_substreams[dev]);
  		if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1007
1008
  			goto __nodev;
  	}
d5e1ca05f   Jaroslav Kysela   ALSA: dummy drive...
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
  
  	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...
1035
1036
  	err = snd_card_dummy_new_mixer(dummy);
  	if (err < 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1037
1038
1039
1040
  		goto __nodev;
  	strcpy(card->driver, "Dummy");
  	strcpy(card->shortname, "Dummy");
  	sprintf(card->longname, "Dummy %i", dev + 1);
16dab54b8   Takashi Iwai   [ALSA] Add snd_ca...
1041

9b151fec1   Takashi Iwai   ALSA: dummy - Add...
1042
  	dummy_proc_init(dummy);
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1043
1044
  	err = snd_card_register(card);
  	if (err == 0) {
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1045
  		platform_set_drvdata(devptr, card);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1046
1047
1048
1049
1050
1051
  		return 0;
  	}
        __nodev:
  	snd_card_free(card);
  	return err;
  }
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
1052
  static int snd_dummy_remove(struct platform_device *devptr)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1053
1054
  {
  	snd_card_free(platform_get_drvdata(devptr));
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1055
1056
  	return 0;
  }
d34e4e00a   Takashi Iwai   ALSA: platform: C...
1057
  #ifdef CONFIG_PM_SLEEP
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1058
  static int snd_dummy_suspend(struct device *pdev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1059
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1060
  	struct snd_card *card = dev_get_drvdata(pdev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1061

6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1062
  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1063
1064
1065
  	return 0;
  }
  	
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1066
  static int snd_dummy_resume(struct device *pdev)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1067
  {
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1068
  	struct snd_card *card = dev_get_drvdata(pdev);
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1069
1070
1071
1072
  
  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);
  	return 0;
  }
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1073
1074
1075
1076
1077
  
  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...
1078
1079
1080
1081
1082
1083
  #endif
  
  #define SND_DUMMY_DRIVER	"snd_dummy"
  
  static struct platform_driver snd_dummy_driver = {
  	.probe		= snd_dummy_probe,
fbbb01a12   Bill Pemberton   ALSA: drivers: re...
1084
  	.remove		= snd_dummy_remove,
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1085
  	.driver		= {
8bf01d8ab   Takashi Iwai   ALSA: Add missing...
1086
  		.name	= SND_DUMMY_DRIVER,
284e7ca75   Takashi Iwai   ALSA: convert PM ...
1087
  		.pm	= SND_DUMMY_PM_OPS,
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1088
1089
  	},
  };
c12aad6ef   Randy Dunlap   [ALSA] more secti...
1090
  static void snd_dummy_unregister_all(void)
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1091
1092
1093
1094
1095
1096
  {
  	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...
1097
  	free_fake_buffer();
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1098
  }
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1099
1100
1101
  static int __init alsa_card_dummy_init(void)
  {
  	int i, cards, err;
1a11cb642   Jaroslav Kysela   ALSA: dummy drive...
1102
1103
  	err = platform_driver_register(&snd_dummy_driver);
  	if (err < 0)
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1104
  		return err;
a68c4d113   Takashi Iwai   ALSA: dummy - Fak...
1105
1106
1107
1108
1109
  	err = alloc_fake_buffer();
  	if (err < 0) {
  		platform_driver_unregister(&snd_dummy_driver);
  		return err;
  	}
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1110
  	cards = 0;
8278ca8fe   Takashi Iwai   [ALSA] Fix check ...
1111
  	for (i = 0; i < SNDRV_CARDS; i++) {
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1112
  		struct platform_device *device;
8278ca8fe   Takashi Iwai   [ALSA] Fix check ...
1113
1114
  		if (! enable[i])
  			continue;
6e65c1cc4   Takashi Iwai   [ALSA] dummy - Us...
1115
1116
  		device = platform_device_register_simple(SND_DUMMY_DRIVER,
  							 i, NULL, 0);
a182ee987   Rene Herman   [ALSA] continue o...
1117
1118
  		if (IS_ERR(device))
  			continue;
7152447df   Rene Herman   [ALSA] unregister...
1119
1120
1121
1122
  		if (!platform_get_drvdata(device)) {
  			platform_device_unregister(device);
  			continue;
  		}
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1123
  		devices[i] = device;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1124
1125
1126
1127
1128
1129
1130
  		cards++;
  	}
  	if (!cards) {
  #ifdef MODULE
  		printk(KERN_ERR "Dummy soundcard not found or device busy
  ");
  #endif
a182ee987   Rene Herman   [ALSA] continue o...
1131
1132
  		snd_dummy_unregister_all();
  		return -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1133
1134
1135
1136
1137
1138
  	}
  	return 0;
  }
  
  static void __exit alsa_card_dummy_exit(void)
  {
f7a9275d9   Clemens Ladisch   [ALSA] unregister...
1139
  	snd_dummy_unregister_all();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1140
1141
1142
1143
  }
  
  module_init(alsa_card_dummy_init)
  module_exit(alsa_card_dummy_exit)