diff options
author | Dave Kleikamp <shaggy@austin.ibm.com> | 2006-01-24 15:34:47 -0500 |
---|---|---|
committer | Dave Kleikamp <shaggy@austin.ibm.com> | 2006-01-24 15:34:47 -0500 |
commit | 0a0fc0ddbe732779366ab6b1b879f62195e65967 (patch) | |
tree | 7b42490a676cf39ae0691b6859ecf7fd410f229b /sound/drivers/dummy.c | |
parent | 4d5dbd0945d9e0833dd7964a3d6ee33157f7cc7a (diff) | |
parent | 3ee68c4af3fd7228c1be63254b9f884614f9ebb2 (diff) |
Merge with /home/shaggy/git/linus-clean/
Diffstat (limited to 'sound/drivers/dummy.c')
-rw-r--r-- | sound/drivers/dummy.c | 364 |
1 files changed, 210 insertions, 154 deletions
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 64ef7f62851d..14e1a671b5cf 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -20,6 +20,8 @@ | |||
20 | 20 | ||
21 | #include <sound/driver.h> | 21 | #include <sound/driver.h> |
22 | #include <linux/init.h> | 22 | #include <linux/init.h> |
23 | #include <linux/err.h> | ||
24 | #include <linux/platform_device.h> | ||
23 | #include <linux/jiffies.h> | 25 | #include <linux/jiffies.h> |
24 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
25 | #include <linux/time.h> | 27 | #include <linux/time.h> |
@@ -42,7 +44,7 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); | |||
42 | 44 | ||
43 | #if 0 /* emu10k1 emulation */ | 45 | #if 0 /* emu10k1 emulation */ |
44 | #define MAX_BUFFER_SIZE (128 * 1024) | 46 | #define MAX_BUFFER_SIZE (128 * 1024) |
45 | static int emu10k1_playback_constraints(snd_pcm_runtime_t *runtime) | 47 | static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) |
46 | { | 48 | { |
47 | int err; | 49 | int err; |
48 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | 50 | if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) |
@@ -90,11 +92,27 @@ static int emu10k1_playback_constraints(snd_pcm_runtime_t *runtime) | |||
90 | #define USE_RATE_MAX 48000 | 92 | #define USE_RATE_MAX 48000 |
91 | #endif | 93 | #endif |
92 | 94 | ||
95 | #if 0 /* CA0106 */ | ||
96 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
97 | #define USE_CHANNELS_MIN 2 | ||
98 | #define USE_CHANNELS_MAX 2 | ||
99 | #define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) | ||
100 | #define USE_RATE_MIN 48000 | ||
101 | #define USE_RATE_MAX 192000 | ||
102 | #define MAX_BUFFER_SIZE ((65536-64)*8) | ||
103 | #define MAX_PERIOD_SIZE (65536-64) | ||
104 | #define USE_PERIODS_MIN 2 | ||
105 | #define USE_PERIODS_MAX 8 | ||
106 | #endif | ||
107 | |||
93 | 108 | ||
94 | /* defaults */ | 109 | /* defaults */ |
95 | #ifndef MAX_BUFFER_SIZE | 110 | #ifndef MAX_BUFFER_SIZE |
96 | #define MAX_BUFFER_SIZE (64*1024) | 111 | #define MAX_BUFFER_SIZE (64*1024) |
97 | #endif | 112 | #endif |
113 | #ifndef MAX_PERIOD_SIZE | ||
114 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE | ||
115 | #endif | ||
98 | #ifndef USE_FORMATS | 116 | #ifndef USE_FORMATS |
99 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) | 117 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) |
100 | #endif | 118 | #endif |
@@ -142,6 +160,8 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); | |||
142 | //module_param_array(midi_devs, int, NULL, 0444); | 160 | //module_param_array(midi_devs, int, NULL, 0444); |
143 | //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); | 161 | //MODULE_PARM_DESC(midi_devs, "MIDI devices # (0-2) for dummy driver."); |
144 | 162 | ||
163 | static struct platform_device *devices[SNDRV_CARDS]; | ||
164 | |||
145 | #define MIXER_ADDR_MASTER 0 | 165 | #define MIXER_ADDR_MASTER 0 |
146 | #define MIXER_ADDR_LINE 1 | 166 | #define MIXER_ADDR_LINE 1 |
147 | #define MIXER_ADDR_MIC 2 | 167 | #define MIXER_ADDR_MIC 2 |
@@ -149,15 +169,16 @@ MODULE_PARM_DESC(pcm_substreams, "PCM substreams # (1-16) for dummy driver."); | |||
149 | #define MIXER_ADDR_CD 4 | 169 | #define MIXER_ADDR_CD 4 |
150 | #define MIXER_ADDR_LAST 4 | 170 | #define MIXER_ADDR_LAST 4 |
151 | 171 | ||
152 | typedef struct snd_card_dummy { | 172 | struct snd_dummy { |
153 | snd_card_t *card; | 173 | struct snd_card *card; |
174 | struct snd_pcm *pcm; | ||
154 | spinlock_t mixer_lock; | 175 | spinlock_t mixer_lock; |
155 | int mixer_volume[MIXER_ADDR_LAST+1][2]; | 176 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
156 | int capture_source[MIXER_ADDR_LAST+1][2]; | 177 | int capture_source[MIXER_ADDR_LAST+1][2]; |
157 | } snd_card_dummy_t; | 178 | }; |
158 | 179 | ||
159 | typedef struct snd_card_dummy_pcm { | 180 | struct snd_dummy_pcm { |
160 | snd_card_dummy_t *dummy; | 181 | struct snd_dummy *dummy; |
161 | spinlock_t lock; | 182 | spinlock_t lock; |
162 | struct timer_list timer; | 183 | struct timer_list timer; |
163 | unsigned int pcm_size; | 184 | unsigned int pcm_size; |
@@ -166,59 +187,49 @@ typedef struct snd_card_dummy_pcm { | |||
166 | unsigned int pcm_jiffie; /* bytes per one jiffie */ | 187 | unsigned int pcm_jiffie; /* bytes per one jiffie */ |
167 | unsigned int pcm_irq_pos; /* IRQ position */ | 188 | unsigned int pcm_irq_pos; /* IRQ position */ |
168 | unsigned int pcm_buf_pos; /* position in buffer */ | 189 | unsigned int pcm_buf_pos; /* position in buffer */ |
169 | snd_pcm_substream_t *substream; | 190 | struct snd_pcm_substream *substream; |
170 | } snd_card_dummy_pcm_t; | 191 | }; |
171 | |||
172 | static snd_card_t *snd_dummy_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; | ||
173 | 192 | ||
174 | 193 | ||
175 | static void snd_card_dummy_pcm_timer_start(snd_pcm_substream_t * substream) | 194 | static inline void snd_card_dummy_pcm_timer_start(struct snd_dummy_pcm *dpcm) |
176 | { | 195 | { |
177 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
178 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | ||
179 | |||
180 | dpcm->timer.expires = 1 + jiffies; | 196 | dpcm->timer.expires = 1 + jiffies; |
181 | add_timer(&dpcm->timer); | 197 | add_timer(&dpcm->timer); |
182 | } | 198 | } |
183 | 199 | ||
184 | static void snd_card_dummy_pcm_timer_stop(snd_pcm_substream_t * substream) | 200 | static inline void snd_card_dummy_pcm_timer_stop(struct snd_dummy_pcm *dpcm) |
185 | { | 201 | { |
186 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
187 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | ||
188 | |||
189 | del_timer(&dpcm->timer); | 202 | del_timer(&dpcm->timer); |
190 | } | 203 | } |
191 | 204 | ||
192 | static int snd_card_dummy_playback_trigger(snd_pcm_substream_t * substream, | 205 | static int snd_card_dummy_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
193 | int cmd) | ||
194 | { | ||
195 | if (cmd == SNDRV_PCM_TRIGGER_START) { | ||
196 | snd_card_dummy_pcm_timer_start(substream); | ||
197 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { | ||
198 | snd_card_dummy_pcm_timer_stop(substream); | ||
199 | } else { | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | return 0; | ||
203 | } | ||
204 | |||
205 | static int snd_card_dummy_capture_trigger(snd_pcm_substream_t * substream, | ||
206 | int cmd) | ||
207 | { | 206 | { |
208 | if (cmd == SNDRV_PCM_TRIGGER_START) { | 207 | struct snd_pcm_runtime *runtime = substream->runtime; |
209 | snd_card_dummy_pcm_timer_start(substream); | 208 | struct snd_dummy_pcm *dpcm = runtime->private_data; |
210 | } else if (cmd == SNDRV_PCM_TRIGGER_STOP) { | 209 | int err = 0; |
211 | snd_card_dummy_pcm_timer_stop(substream); | 210 | |
212 | } else { | 211 | spin_lock(&dpcm->lock); |
213 | return -EINVAL; | 212 | switch (cmd) { |
213 | case SNDRV_PCM_TRIGGER_START: | ||
214 | case SNDRV_PCM_TRIGGER_RESUME: | ||
215 | snd_card_dummy_pcm_timer_start(dpcm); | ||
216 | break; | ||
217 | case SNDRV_PCM_TRIGGER_STOP: | ||
218 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
219 | snd_card_dummy_pcm_timer_stop(dpcm); | ||
220 | break; | ||
221 | default: | ||
222 | err = -EINVAL; | ||
223 | break; | ||
214 | } | 224 | } |
225 | spin_unlock(&dpcm->lock); | ||
215 | return 0; | 226 | return 0; |
216 | } | 227 | } |
217 | 228 | ||
218 | static int snd_card_dummy_pcm_prepare(snd_pcm_substream_t * substream) | 229 | static int snd_card_dummy_pcm_prepare(struct snd_pcm_substream *substream) |
219 | { | 230 | { |
220 | snd_pcm_runtime_t *runtime = substream->runtime; | 231 | struct snd_pcm_runtime *runtime = substream->runtime; |
221 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | 232 | struct snd_dummy_pcm *dpcm = runtime->private_data; |
222 | unsigned int bps; | 233 | unsigned int bps; |
223 | 234 | ||
224 | bps = runtime->rate * runtime->channels; | 235 | bps = runtime->rate * runtime->channels; |
@@ -235,53 +246,37 @@ static int snd_card_dummy_pcm_prepare(snd_pcm_substream_t * substream) | |||
235 | return 0; | 246 | return 0; |
236 | } | 247 | } |
237 | 248 | ||
238 | static int snd_card_dummy_playback_prepare(snd_pcm_substream_t * substream) | ||
239 | { | ||
240 | return snd_card_dummy_pcm_prepare(substream); | ||
241 | } | ||
242 | |||
243 | static int snd_card_dummy_capture_prepare(snd_pcm_substream_t * substream) | ||
244 | { | ||
245 | return snd_card_dummy_pcm_prepare(substream); | ||
246 | } | ||
247 | |||
248 | static void snd_card_dummy_pcm_timer_function(unsigned long data) | 249 | static void snd_card_dummy_pcm_timer_function(unsigned long data) |
249 | { | 250 | { |
250 | snd_card_dummy_pcm_t *dpcm = (snd_card_dummy_pcm_t *)data; | 251 | struct snd_dummy_pcm *dpcm = (struct snd_dummy_pcm *)data; |
252 | unsigned long flags; | ||
251 | 253 | ||
254 | spin_lock_irqsave(&dpcm->lock, flags); | ||
252 | dpcm->timer.expires = 1 + jiffies; | 255 | dpcm->timer.expires = 1 + jiffies; |
253 | add_timer(&dpcm->timer); | 256 | add_timer(&dpcm->timer); |
254 | spin_lock_irq(&dpcm->lock); | ||
255 | dpcm->pcm_irq_pos += dpcm->pcm_jiffie; | 257 | dpcm->pcm_irq_pos += dpcm->pcm_jiffie; |
256 | dpcm->pcm_buf_pos += dpcm->pcm_jiffie; | 258 | dpcm->pcm_buf_pos += dpcm->pcm_jiffie; |
257 | dpcm->pcm_buf_pos %= dpcm->pcm_size; | 259 | dpcm->pcm_buf_pos %= dpcm->pcm_size; |
258 | if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { | 260 | if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { |
259 | dpcm->pcm_irq_pos %= dpcm->pcm_count; | 261 | dpcm->pcm_irq_pos %= dpcm->pcm_count; |
262 | spin_unlock_irqrestore(&dpcm->lock, flags); | ||
260 | snd_pcm_period_elapsed(dpcm->substream); | 263 | snd_pcm_period_elapsed(dpcm->substream); |
261 | } | 264 | } else |
262 | spin_unlock_irq(&dpcm->lock); | 265 | spin_unlock_irqrestore(&dpcm->lock, flags); |
263 | } | 266 | } |
264 | 267 | ||
265 | static snd_pcm_uframes_t snd_card_dummy_playback_pointer(snd_pcm_substream_t * substream) | 268 | static snd_pcm_uframes_t snd_card_dummy_pcm_pointer(struct snd_pcm_substream *substream) |
266 | { | 269 | { |
267 | snd_pcm_runtime_t *runtime = substream->runtime; | 270 | struct snd_pcm_runtime *runtime = substream->runtime; |
268 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | 271 | struct snd_dummy_pcm *dpcm = runtime->private_data; |
269 | 272 | ||
270 | return bytes_to_frames(runtime, dpcm->pcm_buf_pos); | 273 | return bytes_to_frames(runtime, dpcm->pcm_buf_pos); |
271 | } | 274 | } |
272 | 275 | ||
273 | static snd_pcm_uframes_t snd_card_dummy_capture_pointer(snd_pcm_substream_t * substream) | 276 | static struct snd_pcm_hardware snd_card_dummy_playback = |
274 | { | ||
275 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
276 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | ||
277 | |||
278 | return bytes_to_frames(runtime, dpcm->pcm_buf_pos); | ||
279 | } | ||
280 | |||
281 | static snd_pcm_hardware_t snd_card_dummy_playback = | ||
282 | { | 277 | { |
283 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 278 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
284 | SNDRV_PCM_INFO_MMAP_VALID), | 279 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
285 | .formats = USE_FORMATS, | 280 | .formats = USE_FORMATS, |
286 | .rates = USE_RATE, | 281 | .rates = USE_RATE, |
287 | .rate_min = USE_RATE_MIN, | 282 | .rate_min = USE_RATE_MIN, |
@@ -296,10 +291,10 @@ static snd_pcm_hardware_t snd_card_dummy_playback = | |||
296 | .fifo_size = 0, | 291 | .fifo_size = 0, |
297 | }; | 292 | }; |
298 | 293 | ||
299 | static snd_pcm_hardware_t snd_card_dummy_capture = | 294 | static struct snd_pcm_hardware snd_card_dummy_capture = |
300 | { | 295 | { |
301 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 296 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
302 | SNDRV_PCM_INFO_MMAP_VALID), | 297 | SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_MMAP_VALID), |
303 | .formats = USE_FORMATS, | 298 | .formats = USE_FORMATS, |
304 | .rates = USE_RATE, | 299 | .rates = USE_RATE, |
305 | .rate_min = USE_RATE_MIN, | 300 | .rate_min = USE_RATE_MIN, |
@@ -308,43 +303,51 @@ static snd_pcm_hardware_t snd_card_dummy_capture = | |||
308 | .channels_max = USE_CHANNELS_MAX, | 303 | .channels_max = USE_CHANNELS_MAX, |
309 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 304 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
310 | .period_bytes_min = 64, | 305 | .period_bytes_min = 64, |
311 | .period_bytes_max = MAX_BUFFER_SIZE, | 306 | .period_bytes_max = MAX_PERIOD_SIZE, |
312 | .periods_min = USE_PERIODS_MIN, | 307 | .periods_min = USE_PERIODS_MIN, |
313 | .periods_max = USE_PERIODS_MAX, | 308 | .periods_max = USE_PERIODS_MAX, |
314 | .fifo_size = 0, | 309 | .fifo_size = 0, |
315 | }; | 310 | }; |
316 | 311 | ||
317 | static void snd_card_dummy_runtime_free(snd_pcm_runtime_t *runtime) | 312 | static void snd_card_dummy_runtime_free(struct snd_pcm_runtime *runtime) |
318 | { | 313 | { |
319 | snd_card_dummy_pcm_t *dpcm = runtime->private_data; | 314 | kfree(runtime->private_data); |
320 | kfree(dpcm); | ||
321 | } | 315 | } |
322 | 316 | ||
323 | static int snd_card_dummy_hw_params(snd_pcm_substream_t * substream, | 317 | static int snd_card_dummy_hw_params(struct snd_pcm_substream *substream, |
324 | snd_pcm_hw_params_t * hw_params) | 318 | struct snd_pcm_hw_params *hw_params) |
325 | { | 319 | { |
326 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | 320 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); |
327 | } | 321 | } |
328 | 322 | ||
329 | static int snd_card_dummy_hw_free(snd_pcm_substream_t * substream) | 323 | static int snd_card_dummy_hw_free(struct snd_pcm_substream *substream) |
330 | { | 324 | { |
331 | return snd_pcm_lib_free_pages(substream); | 325 | return snd_pcm_lib_free_pages(substream); |
332 | } | 326 | } |
333 | 327 | ||
334 | static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream) | 328 | static struct snd_dummy_pcm *new_pcm_stream(struct snd_pcm_substream *substream) |
335 | { | 329 | { |
336 | snd_pcm_runtime_t *runtime = substream->runtime; | 330 | struct snd_dummy_pcm *dpcm; |
337 | snd_card_dummy_pcm_t *dpcm; | ||
338 | int err; | ||
339 | 331 | ||
340 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | 332 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); |
341 | if (dpcm == NULL) | 333 | if (! dpcm) |
342 | return -ENOMEM; | 334 | return dpcm; |
343 | init_timer(&dpcm->timer); | 335 | init_timer(&dpcm->timer); |
344 | dpcm->timer.data = (unsigned long) dpcm; | 336 | dpcm->timer.data = (unsigned long) dpcm; |
345 | dpcm->timer.function = snd_card_dummy_pcm_timer_function; | 337 | dpcm->timer.function = snd_card_dummy_pcm_timer_function; |
346 | spin_lock_init(&dpcm->lock); | 338 | spin_lock_init(&dpcm->lock); |
347 | dpcm->substream = substream; | 339 | dpcm->substream = substream; |
340 | return dpcm; | ||
341 | } | ||
342 | |||
343 | static int snd_card_dummy_playback_open(struct snd_pcm_substream *substream) | ||
344 | { | ||
345 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
346 | struct snd_dummy_pcm *dpcm; | ||
347 | int err; | ||
348 | |||
349 | if ((dpcm = new_pcm_stream(substream)) == NULL) | ||
350 | return -ENOMEM; | ||
348 | runtime->private_data = dpcm; | 351 | runtime->private_data = dpcm; |
349 | runtime->private_free = snd_card_dummy_runtime_free; | 352 | runtime->private_free = snd_card_dummy_runtime_free; |
350 | runtime->hw = snd_card_dummy_playback; | 353 | runtime->hw = snd_card_dummy_playback; |
@@ -362,20 +365,14 @@ static int snd_card_dummy_playback_open(snd_pcm_substream_t * substream) | |||
362 | return 0; | 365 | return 0; |
363 | } | 366 | } |
364 | 367 | ||
365 | static int snd_card_dummy_capture_open(snd_pcm_substream_t * substream) | 368 | static int snd_card_dummy_capture_open(struct snd_pcm_substream *substream) |
366 | { | 369 | { |
367 | snd_pcm_runtime_t *runtime = substream->runtime; | 370 | struct snd_pcm_runtime *runtime = substream->runtime; |
368 | snd_card_dummy_pcm_t *dpcm; | 371 | struct snd_dummy_pcm *dpcm; |
369 | int err; | 372 | int err; |
370 | 373 | ||
371 | dpcm = kzalloc(sizeof(*dpcm), GFP_KERNEL); | 374 | if ((dpcm = new_pcm_stream(substream)) == NULL) |
372 | if (dpcm == NULL) | ||
373 | return -ENOMEM; | 375 | return -ENOMEM; |
374 | init_timer(&dpcm->timer); | ||
375 | dpcm->timer.data = (unsigned long) dpcm; | ||
376 | dpcm->timer.function = snd_card_dummy_pcm_timer_function; | ||
377 | spin_lock_init(&dpcm->lock); | ||
378 | dpcm->substream = substream; | ||
379 | runtime->private_data = dpcm; | 376 | runtime->private_data = dpcm; |
380 | runtime->private_free = snd_card_dummy_runtime_free; | 377 | runtime->private_free = snd_card_dummy_runtime_free; |
381 | runtime->hw = snd_card_dummy_capture; | 378 | runtime->hw = snd_card_dummy_capture; |
@@ -393,45 +390,47 @@ static int snd_card_dummy_capture_open(snd_pcm_substream_t * substream) | |||
393 | return 0; | 390 | return 0; |
394 | } | 391 | } |
395 | 392 | ||
396 | static int snd_card_dummy_playback_close(snd_pcm_substream_t * substream) | 393 | static int snd_card_dummy_playback_close(struct snd_pcm_substream *substream) |
397 | { | 394 | { |
398 | return 0; | 395 | return 0; |
399 | } | 396 | } |
400 | 397 | ||
401 | static int snd_card_dummy_capture_close(snd_pcm_substream_t * substream) | 398 | static int snd_card_dummy_capture_close(struct snd_pcm_substream *substream) |
402 | { | 399 | { |
403 | return 0; | 400 | return 0; |
404 | } | 401 | } |
405 | 402 | ||
406 | static snd_pcm_ops_t snd_card_dummy_playback_ops = { | 403 | static struct snd_pcm_ops snd_card_dummy_playback_ops = { |
407 | .open = snd_card_dummy_playback_open, | 404 | .open = snd_card_dummy_playback_open, |
408 | .close = snd_card_dummy_playback_close, | 405 | .close = snd_card_dummy_playback_close, |
409 | .ioctl = snd_pcm_lib_ioctl, | 406 | .ioctl = snd_pcm_lib_ioctl, |
410 | .hw_params = snd_card_dummy_hw_params, | 407 | .hw_params = snd_card_dummy_hw_params, |
411 | .hw_free = snd_card_dummy_hw_free, | 408 | .hw_free = snd_card_dummy_hw_free, |
412 | .prepare = snd_card_dummy_playback_prepare, | 409 | .prepare = snd_card_dummy_pcm_prepare, |
413 | .trigger = snd_card_dummy_playback_trigger, | 410 | .trigger = snd_card_dummy_pcm_trigger, |
414 | .pointer = snd_card_dummy_playback_pointer, | 411 | .pointer = snd_card_dummy_pcm_pointer, |
415 | }; | 412 | }; |
416 | 413 | ||
417 | static snd_pcm_ops_t snd_card_dummy_capture_ops = { | 414 | static struct snd_pcm_ops snd_card_dummy_capture_ops = { |
418 | .open = snd_card_dummy_capture_open, | 415 | .open = snd_card_dummy_capture_open, |
419 | .close = snd_card_dummy_capture_close, | 416 | .close = snd_card_dummy_capture_close, |
420 | .ioctl = snd_pcm_lib_ioctl, | 417 | .ioctl = snd_pcm_lib_ioctl, |
421 | .hw_params = snd_card_dummy_hw_params, | 418 | .hw_params = snd_card_dummy_hw_params, |
422 | .hw_free = snd_card_dummy_hw_free, | 419 | .hw_free = snd_card_dummy_hw_free, |
423 | .prepare = snd_card_dummy_capture_prepare, | 420 | .prepare = snd_card_dummy_pcm_prepare, |
424 | .trigger = snd_card_dummy_capture_trigger, | 421 | .trigger = snd_card_dummy_pcm_trigger, |
425 | .pointer = snd_card_dummy_capture_pointer, | 422 | .pointer = snd_card_dummy_pcm_pointer, |
426 | }; | 423 | }; |
427 | 424 | ||
428 | static int __init snd_card_dummy_pcm(snd_card_dummy_t *dummy, int device, int substreams) | 425 | static int __init snd_card_dummy_pcm(struct snd_dummy *dummy, int device, int substreams) |
429 | { | 426 | { |
430 | snd_pcm_t *pcm; | 427 | struct snd_pcm *pcm; |
431 | int err; | 428 | int err; |
432 | 429 | ||
433 | if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, substreams, substreams, &pcm)) < 0) | 430 | if ((err = snd_pcm_new(dummy->card, "Dummy PCM", device, |
431 | substreams, substreams, &pcm)) < 0) | ||
434 | return err; | 432 | return err; |
433 | dummy->pcm = pcm; | ||
435 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops); | 434 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_dummy_playback_ops); |
436 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); | 435 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_dummy_capture_ops); |
437 | pcm->private_data = dummy; | 436 | pcm->private_data = dummy; |
@@ -449,7 +448,8 @@ static int __init snd_card_dummy_pcm(snd_card_dummy_t *dummy, int device, int su | |||
449 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ | 448 | .get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \ |
450 | .private_value = addr } | 449 | .private_value = addr } |
451 | 450 | ||
452 | static int snd_dummy_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) | 451 | static int snd_dummy_volume_info(struct snd_kcontrol *kcontrol, |
452 | struct snd_ctl_elem_info *uinfo) | ||
453 | { | 453 | { |
454 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 454 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
455 | uinfo->count = 2; | 455 | uinfo->count = 2; |
@@ -458,23 +458,23 @@ static int snd_dummy_volume_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t | |||
458 | return 0; | 458 | return 0; |
459 | } | 459 | } |
460 | 460 | ||
461 | static int snd_dummy_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 461 | static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol, |
462 | struct snd_ctl_elem_value *ucontrol) | ||
462 | { | 463 | { |
463 | snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); | 464 | struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); |
464 | unsigned long flags; | ||
465 | int addr = kcontrol->private_value; | 465 | int addr = kcontrol->private_value; |
466 | 466 | ||
467 | spin_lock_irqsave(&dummy->mixer_lock, flags); | 467 | spin_lock_irq(&dummy->mixer_lock); |
468 | ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0]; | 468 | ucontrol->value.integer.value[0] = dummy->mixer_volume[addr][0]; |
469 | ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1]; | 469 | ucontrol->value.integer.value[1] = dummy->mixer_volume[addr][1]; |
470 | spin_unlock_irqrestore(&dummy->mixer_lock, flags); | 470 | spin_unlock_irq(&dummy->mixer_lock); |
471 | return 0; | 471 | return 0; |
472 | } | 472 | } |
473 | 473 | ||
474 | static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 474 | static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol, |
475 | struct snd_ctl_elem_value *ucontrol) | ||
475 | { | 476 | { |
476 | snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); | 477 | struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); |
477 | unsigned long flags; | ||
478 | int change, addr = kcontrol->private_value; | 478 | int change, addr = kcontrol->private_value; |
479 | int left, right; | 479 | int left, right; |
480 | 480 | ||
@@ -488,12 +488,12 @@ static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
488 | right = -50; | 488 | right = -50; |
489 | if (right > 100) | 489 | if (right > 100) |
490 | right = 100; | 490 | right = 100; |
491 | spin_lock_irqsave(&dummy->mixer_lock, flags); | 491 | spin_lock_irq(&dummy->mixer_lock); |
492 | change = dummy->mixer_volume[addr][0] != left || | 492 | change = dummy->mixer_volume[addr][0] != left || |
493 | dummy->mixer_volume[addr][1] != right; | 493 | dummy->mixer_volume[addr][1] != right; |
494 | dummy->mixer_volume[addr][0] = left; | 494 | dummy->mixer_volume[addr][0] = left; |
495 | dummy->mixer_volume[addr][1] = right; | 495 | dummy->mixer_volume[addr][1] = right; |
496 | spin_unlock_irqrestore(&dummy->mixer_lock, flags); | 496 | spin_unlock_irq(&dummy->mixer_lock); |
497 | return change; | 497 | return change; |
498 | } | 498 | } |
499 | 499 | ||
@@ -503,7 +503,8 @@ static int snd_dummy_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t | |||
503 | .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \ | 503 | .get = snd_dummy_capsrc_get, .put = snd_dummy_capsrc_put, \ |
504 | .private_value = addr } | 504 | .private_value = addr } |
505 | 505 | ||
506 | static int snd_dummy_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) | 506 | static int snd_dummy_capsrc_info(struct snd_kcontrol *kcontrol, |
507 | struct snd_ctl_elem_info *uinfo) | ||
507 | { | 508 | { |
508 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 509 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; |
509 | uinfo->count = 2; | 510 | uinfo->count = 2; |
@@ -512,38 +513,37 @@ static int snd_dummy_capsrc_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t | |||
512 | return 0; | 513 | return 0; |
513 | } | 514 | } |
514 | 515 | ||
515 | static int snd_dummy_capsrc_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 516 | static int snd_dummy_capsrc_get(struct snd_kcontrol *kcontrol, |
517 | struct snd_ctl_elem_value *ucontrol) | ||
516 | { | 518 | { |
517 | snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); | 519 | struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); |
518 | unsigned long flags; | ||
519 | int addr = kcontrol->private_value; | 520 | int addr = kcontrol->private_value; |
520 | 521 | ||
521 | spin_lock_irqsave(&dummy->mixer_lock, flags); | 522 | spin_lock_irq(&dummy->mixer_lock); |
522 | ucontrol->value.integer.value[0] = dummy->capture_source[addr][0]; | 523 | ucontrol->value.integer.value[0] = dummy->capture_source[addr][0]; |
523 | ucontrol->value.integer.value[1] = dummy->capture_source[addr][1]; | 524 | ucontrol->value.integer.value[1] = dummy->capture_source[addr][1]; |
524 | spin_unlock_irqrestore(&dummy->mixer_lock, flags); | 525 | spin_unlock_irq(&dummy->mixer_lock); |
525 | return 0; | 526 | return 0; |
526 | } | 527 | } |
527 | 528 | ||
528 | static int snd_dummy_capsrc_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) | 529 | static int snd_dummy_capsrc_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
529 | { | 530 | { |
530 | snd_card_dummy_t *dummy = snd_kcontrol_chip(kcontrol); | 531 | struct snd_dummy *dummy = snd_kcontrol_chip(kcontrol); |
531 | unsigned long flags; | ||
532 | int change, addr = kcontrol->private_value; | 532 | int change, addr = kcontrol->private_value; |
533 | int left, right; | 533 | int left, right; |
534 | 534 | ||
535 | left = ucontrol->value.integer.value[0] & 1; | 535 | left = ucontrol->value.integer.value[0] & 1; |
536 | right = ucontrol->value.integer.value[1] & 1; | 536 | right = ucontrol->value.integer.value[1] & 1; |
537 | spin_lock_irqsave(&dummy->mixer_lock, flags); | 537 | spin_lock_irq(&dummy->mixer_lock); |
538 | change = dummy->capture_source[addr][0] != left && | 538 | change = dummy->capture_source[addr][0] != left && |
539 | dummy->capture_source[addr][1] != right; | 539 | dummy->capture_source[addr][1] != right; |
540 | dummy->capture_source[addr][0] = left; | 540 | dummy->capture_source[addr][0] = left; |
541 | dummy->capture_source[addr][1] = right; | 541 | dummy->capture_source[addr][1] = right; |
542 | spin_unlock_irqrestore(&dummy->mixer_lock, flags); | 542 | spin_unlock_irq(&dummy->mixer_lock); |
543 | return change; | 543 | return change; |
544 | } | 544 | } |
545 | 545 | ||
546 | static snd_kcontrol_new_t snd_dummy_controls[] = { | 546 | static struct snd_kcontrol_new snd_dummy_controls[] = { |
547 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), | 547 | DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER), |
548 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), | 548 | DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER), |
549 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), | 549 | DUMMY_VOLUME("Synth Volume", 0, MIXER_ADDR_SYNTH), |
@@ -556,9 +556,9 @@ DUMMY_VOLUME("CD Volume", 0, MIXER_ADDR_CD), | |||
556 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER) | 556 | DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_MASTER) |
557 | }; | 557 | }; |
558 | 558 | ||
559 | static int __init snd_card_dummy_new_mixer(snd_card_dummy_t * dummy) | 559 | static int __init snd_card_dummy_new_mixer(struct snd_dummy *dummy) |
560 | { | 560 | { |
561 | snd_card_t *card = dummy->card; | 561 | struct snd_card *card = dummy->card; |
562 | unsigned int idx; | 562 | unsigned int idx; |
563 | int err; | 563 | int err; |
564 | 564 | ||
@@ -573,19 +573,18 @@ static int __init snd_card_dummy_new_mixer(snd_card_dummy_t * dummy) | |||
573 | return 0; | 573 | return 0; |
574 | } | 574 | } |
575 | 575 | ||
576 | static int __init snd_card_dummy_probe(int dev) | 576 | static int __init snd_dummy_probe(struct platform_device *devptr) |
577 | { | 577 | { |
578 | snd_card_t *card; | 578 | struct snd_card *card; |
579 | struct snd_card_dummy *dummy; | 579 | struct snd_dummy *dummy; |
580 | int idx, err; | 580 | int idx, err; |
581 | int dev = devptr->id; | ||
581 | 582 | ||
582 | if (!enable[dev]) | ||
583 | return -ENODEV; | ||
584 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, | 583 | card = snd_card_new(index[dev], id[dev], THIS_MODULE, |
585 | sizeof(struct snd_card_dummy)); | 584 | sizeof(struct snd_dummy)); |
586 | if (card == NULL) | 585 | if (card == NULL) |
587 | return -ENOMEM; | 586 | return -ENOMEM; |
588 | dummy = (struct snd_card_dummy *)card->private_data; | 587 | dummy = card->private_data; |
589 | dummy->card = card; | 588 | dummy->card = card; |
590 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { | 589 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { |
591 | if (pcm_substreams[dev] < 1) | 590 | if (pcm_substreams[dev] < 1) |
@@ -601,11 +600,10 @@ static int __init snd_card_dummy_probe(int dev) | |||
601 | strcpy(card->shortname, "Dummy"); | 600 | strcpy(card->shortname, "Dummy"); |
602 | sprintf(card->longname, "Dummy %i", dev + 1); | 601 | sprintf(card->longname, "Dummy %i", dev + 1); |
603 | 602 | ||
604 | if ((err = snd_card_set_generic_dev(card)) < 0) | 603 | snd_card_set_dev(card, &devptr->dev); |
605 | goto __nodev; | ||
606 | 604 | ||
607 | if ((err = snd_card_register(card)) == 0) { | 605 | if ((err = snd_card_register(card)) == 0) { |
608 | snd_dummy_cards[dev] = card; | 606 | platform_set_drvdata(devptr, card); |
609 | return 0; | 607 | return 0; |
610 | } | 608 | } |
611 | __nodev: | 609 | __nodev: |
@@ -613,34 +611,92 @@ static int __init snd_card_dummy_probe(int dev) | |||
613 | return err; | 611 | return err; |
614 | } | 612 | } |
615 | 613 | ||
616 | static int __init alsa_card_dummy_init(void) | 614 | static int snd_dummy_remove(struct platform_device *devptr) |
617 | { | 615 | { |
618 | int dev, cards; | 616 | snd_card_free(platform_get_drvdata(devptr)); |
617 | platform_set_drvdata(devptr, NULL); | ||
618 | return 0; | ||
619 | } | ||
619 | 620 | ||
620 | for (dev = cards = 0; dev < SNDRV_CARDS && enable[dev]; dev++) { | 621 | #ifdef CONFIG_PM |
621 | if (snd_card_dummy_probe(dev) < 0) { | 622 | static int snd_dummy_suspend(struct platform_device *pdev, pm_message_t state) |
622 | #ifdef MODULE | 623 | { |
623 | printk(KERN_ERR "Dummy soundcard #%i not found or device busy\n", dev + 1); | 624 | struct snd_card *card = platform_get_drvdata(pdev); |
625 | struct snd_dummy *dummy = card->private_data; | ||
626 | |||
627 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
628 | snd_pcm_suspend_all(dummy->pcm); | ||
629 | return 0; | ||
630 | } | ||
631 | |||
632 | static int snd_dummy_resume(struct platform_device *pdev) | ||
633 | { | ||
634 | struct snd_card *card = platform_get_drvdata(pdev); | ||
635 | |||
636 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
637 | return 0; | ||
638 | } | ||
639 | #endif | ||
640 | |||
641 | #define SND_DUMMY_DRIVER "snd_dummy" | ||
642 | |||
643 | static struct platform_driver snd_dummy_driver = { | ||
644 | .probe = snd_dummy_probe, | ||
645 | .remove = snd_dummy_remove, | ||
646 | #ifdef CONFIG_PM | ||
647 | .suspend = snd_dummy_suspend, | ||
648 | .resume = snd_dummy_resume, | ||
624 | #endif | 649 | #endif |
625 | break; | 650 | .driver = { |
651 | .name = SND_DUMMY_DRIVER | ||
652 | }, | ||
653 | }; | ||
654 | |||
655 | static void __init_or_module snd_dummy_unregister_all(void) | ||
656 | { | ||
657 | int i; | ||
658 | |||
659 | for (i = 0; i < ARRAY_SIZE(devices); ++i) | ||
660 | platform_device_unregister(devices[i]); | ||
661 | platform_driver_unregister(&snd_dummy_driver); | ||
662 | } | ||
663 | |||
664 | static int __init alsa_card_dummy_init(void) | ||
665 | { | ||
666 | int i, cards, err; | ||
667 | |||
668 | if ((err = platform_driver_register(&snd_dummy_driver)) < 0) | ||
669 | return err; | ||
670 | |||
671 | cards = 0; | ||
672 | for (i = 0; i < SNDRV_CARDS && enable[i]; i++) { | ||
673 | struct platform_device *device; | ||
674 | device = platform_device_register_simple(SND_DUMMY_DRIVER, | ||
675 | i, NULL, 0); | ||
676 | if (IS_ERR(device)) { | ||
677 | err = PTR_ERR(device); | ||
678 | goto errout; | ||
626 | } | 679 | } |
680 | devices[i] = device; | ||
627 | cards++; | 681 | cards++; |
628 | } | 682 | } |
629 | if (!cards) { | 683 | if (!cards) { |
630 | #ifdef MODULE | 684 | #ifdef MODULE |
631 | printk(KERN_ERR "Dummy soundcard not found or device busy\n"); | 685 | printk(KERN_ERR "Dummy soundcard not found or device busy\n"); |
632 | #endif | 686 | #endif |
633 | return -ENODEV; | 687 | err = -ENODEV; |
688 | goto errout; | ||
634 | } | 689 | } |
635 | return 0; | 690 | return 0; |
691 | |||
692 | errout: | ||
693 | snd_dummy_unregister_all(); | ||
694 | return err; | ||
636 | } | 695 | } |
637 | 696 | ||
638 | static void __exit alsa_card_dummy_exit(void) | 697 | static void __exit alsa_card_dummy_exit(void) |
639 | { | 698 | { |
640 | int idx; | 699 | snd_dummy_unregister_all(); |
641 | |||
642 | for (idx = 0; idx < SNDRV_CARDS; idx++) | ||
643 | snd_card_free(snd_dummy_cards[idx]); | ||
644 | } | 700 | } |
645 | 701 | ||
646 | module_init(alsa_card_dummy_init) | 702 | module_init(alsa_card_dummy_init) |