diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /sound/core/pcm_native.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r-- | sound/core/pcm_native.c | 3364 |
1 files changed, 3364 insertions, 0 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c new file mode 100644 index 0000000000..cad9bbde99 --- /dev/null +++ b/sound/core/pcm_native.c | |||
@@ -0,0 +1,3364 @@ | |||
1 | /* | ||
2 | * Digital Audio (PCM) abstract layer | ||
3 | * Copyright (c) by Jaroslav Kysela <perex@suse.cz> | ||
4 | * | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | * | ||
20 | */ | ||
21 | |||
22 | #include <sound/driver.h> | ||
23 | #include <linux/mm.h> | ||
24 | #include <linux/smp_lock.h> | ||
25 | #include <linux/file.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/time.h> | ||
28 | #include <linux/uio.h> | ||
29 | #include <sound/core.h> | ||
30 | #include <sound/control.h> | ||
31 | #include <sound/info.h> | ||
32 | #include <sound/pcm.h> | ||
33 | #include <sound/pcm_params.h> | ||
34 | #include <sound/timer.h> | ||
35 | #include <sound/minors.h> | ||
36 | #include <asm/io.h> | ||
37 | |||
38 | /* | ||
39 | * Compatibility | ||
40 | */ | ||
41 | |||
42 | struct sndrv_pcm_hw_params_old { | ||
43 | unsigned int flags; | ||
44 | unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT - | ||
45 | SNDRV_PCM_HW_PARAM_ACCESS + 1]; | ||
46 | struct sndrv_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME - | ||
47 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1]; | ||
48 | unsigned int rmask; | ||
49 | unsigned int cmask; | ||
50 | unsigned int info; | ||
51 | unsigned int msbits; | ||
52 | unsigned int rate_num; | ||
53 | unsigned int rate_den; | ||
54 | sndrv_pcm_uframes_t fifo_size; | ||
55 | unsigned char reserved[64]; | ||
56 | }; | ||
57 | |||
58 | #define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct sndrv_pcm_hw_params_old) | ||
59 | #define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct sndrv_pcm_hw_params_old) | ||
60 | |||
61 | static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams); | ||
62 | static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams); | ||
63 | |||
64 | /* | ||
65 | * | ||
66 | */ | ||
67 | |||
68 | DEFINE_RWLOCK(snd_pcm_link_rwlock); | ||
69 | static DECLARE_RWSEM(snd_pcm_link_rwsem); | ||
70 | |||
71 | |||
72 | static inline mm_segment_t snd_enter_user(void) | ||
73 | { | ||
74 | mm_segment_t fs = get_fs(); | ||
75 | set_fs(get_ds()); | ||
76 | return fs; | ||
77 | } | ||
78 | |||
79 | static inline void snd_leave_user(mm_segment_t fs) | ||
80 | { | ||
81 | set_fs(fs); | ||
82 | } | ||
83 | |||
84 | |||
85 | |||
86 | int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info) | ||
87 | { | ||
88 | snd_pcm_runtime_t * runtime; | ||
89 | snd_pcm_t *pcm = substream->pcm; | ||
90 | snd_pcm_str_t *pstr = substream->pstr; | ||
91 | |||
92 | snd_assert(substream != NULL, return -ENXIO); | ||
93 | memset(info, 0, sizeof(*info)); | ||
94 | info->card = pcm->card->number; | ||
95 | info->device = pcm->device; | ||
96 | info->stream = substream->stream; | ||
97 | info->subdevice = substream->number; | ||
98 | strlcpy(info->id, pcm->id, sizeof(info->id)); | ||
99 | strlcpy(info->name, pcm->name, sizeof(info->name)); | ||
100 | info->dev_class = pcm->dev_class; | ||
101 | info->dev_subclass = pcm->dev_subclass; | ||
102 | info->subdevices_count = pstr->substream_count; | ||
103 | info->subdevices_avail = pstr->substream_count - pstr->substream_opened; | ||
104 | strlcpy(info->subname, substream->name, sizeof(info->subname)); | ||
105 | runtime = substream->runtime; | ||
106 | /* AB: FIXME!!! This is definitely nonsense */ | ||
107 | if (runtime) { | ||
108 | info->sync = runtime->sync; | ||
109 | substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info); | ||
110 | } | ||
111 | return 0; | ||
112 | } | ||
113 | |||
114 | int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t __user * _info) | ||
115 | { | ||
116 | snd_pcm_info_t *info; | ||
117 | int err; | ||
118 | |||
119 | info = kmalloc(sizeof(*info), GFP_KERNEL); | ||
120 | if (! info) | ||
121 | return -ENOMEM; | ||
122 | err = snd_pcm_info(substream, info); | ||
123 | if (err >= 0) { | ||
124 | if (copy_to_user(_info, info, sizeof(*info))) | ||
125 | err = -EFAULT; | ||
126 | } | ||
127 | kfree(info); | ||
128 | return err; | ||
129 | } | ||
130 | |||
131 | #undef RULES_DEBUG | ||
132 | |||
133 | #ifdef RULES_DEBUG | ||
134 | #define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v | ||
135 | char *snd_pcm_hw_param_names[] = { | ||
136 | HW_PARAM(ACCESS), | ||
137 | HW_PARAM(FORMAT), | ||
138 | HW_PARAM(SUBFORMAT), | ||
139 | HW_PARAM(SAMPLE_BITS), | ||
140 | HW_PARAM(FRAME_BITS), | ||
141 | HW_PARAM(CHANNELS), | ||
142 | HW_PARAM(RATE), | ||
143 | HW_PARAM(PERIOD_TIME), | ||
144 | HW_PARAM(PERIOD_SIZE), | ||
145 | HW_PARAM(PERIOD_BYTES), | ||
146 | HW_PARAM(PERIODS), | ||
147 | HW_PARAM(BUFFER_TIME), | ||
148 | HW_PARAM(BUFFER_SIZE), | ||
149 | HW_PARAM(BUFFER_BYTES), | ||
150 | HW_PARAM(TICK_TIME), | ||
151 | }; | ||
152 | #endif | ||
153 | |||
154 | int snd_pcm_hw_refine(snd_pcm_substream_t *substream, | ||
155 | snd_pcm_hw_params_t *params) | ||
156 | { | ||
157 | unsigned int k; | ||
158 | snd_pcm_hardware_t *hw; | ||
159 | snd_interval_t *i = NULL; | ||
160 | snd_mask_t *m = NULL; | ||
161 | snd_pcm_hw_constraints_t *constrs = &substream->runtime->hw_constraints; | ||
162 | unsigned int rstamps[constrs->rules_num]; | ||
163 | unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1]; | ||
164 | unsigned int stamp = 2; | ||
165 | int changed, again; | ||
166 | |||
167 | params->info = 0; | ||
168 | params->fifo_size = 0; | ||
169 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS)) | ||
170 | params->msbits = 0; | ||
171 | if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) { | ||
172 | params->rate_num = 0; | ||
173 | params->rate_den = 0; | ||
174 | } | ||
175 | |||
176 | for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { | ||
177 | m = hw_param_mask(params, k); | ||
178 | if (snd_mask_empty(m)) | ||
179 | return -EINVAL; | ||
180 | if (!(params->rmask & (1 << k))) | ||
181 | continue; | ||
182 | #ifdef RULES_DEBUG | ||
183 | printk("%s = ", snd_pcm_hw_param_names[k]); | ||
184 | printk("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); | ||
185 | #endif | ||
186 | changed = snd_mask_refine(m, constrs_mask(constrs, k)); | ||
187 | #ifdef RULES_DEBUG | ||
188 | printk("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); | ||
189 | #endif | ||
190 | if (changed) | ||
191 | params->cmask |= 1 << k; | ||
192 | if (changed < 0) | ||
193 | return changed; | ||
194 | } | ||
195 | |||
196 | for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { | ||
197 | i = hw_param_interval(params, k); | ||
198 | if (snd_interval_empty(i)) | ||
199 | return -EINVAL; | ||
200 | if (!(params->rmask & (1 << k))) | ||
201 | continue; | ||
202 | #ifdef RULES_DEBUG | ||
203 | printk("%s = ", snd_pcm_hw_param_names[k]); | ||
204 | if (i->empty) | ||
205 | printk("empty"); | ||
206 | else | ||
207 | printk("%c%u %u%c", | ||
208 | i->openmin ? '(' : '[', i->min, | ||
209 | i->max, i->openmax ? ')' : ']'); | ||
210 | printk(" -> "); | ||
211 | #endif | ||
212 | changed = snd_interval_refine(i, constrs_interval(constrs, k)); | ||
213 | #ifdef RULES_DEBUG | ||
214 | if (i->empty) | ||
215 | printk("empty\n"); | ||
216 | else | ||
217 | printk("%c%u %u%c\n", | ||
218 | i->openmin ? '(' : '[', i->min, | ||
219 | i->max, i->openmax ? ')' : ']'); | ||
220 | #endif | ||
221 | if (changed) | ||
222 | params->cmask |= 1 << k; | ||
223 | if (changed < 0) | ||
224 | return changed; | ||
225 | } | ||
226 | |||
227 | for (k = 0; k < constrs->rules_num; k++) | ||
228 | rstamps[k] = 0; | ||
229 | for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) | ||
230 | vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; | ||
231 | do { | ||
232 | again = 0; | ||
233 | for (k = 0; k < constrs->rules_num; k++) { | ||
234 | snd_pcm_hw_rule_t *r = &constrs->rules[k]; | ||
235 | unsigned int d; | ||
236 | int doit = 0; | ||
237 | if (r->cond && !(r->cond & params->flags)) | ||
238 | continue; | ||
239 | for (d = 0; r->deps[d] >= 0; d++) { | ||
240 | if (vstamps[r->deps[d]] > rstamps[k]) { | ||
241 | doit = 1; | ||
242 | break; | ||
243 | } | ||
244 | } | ||
245 | if (!doit) | ||
246 | continue; | ||
247 | #ifdef RULES_DEBUG | ||
248 | printk("Rule %d [%p]: ", k, r->func); | ||
249 | if (r->var >= 0) { | ||
250 | printk("%s = ", snd_pcm_hw_param_names[r->var]); | ||
251 | if (hw_is_mask(r->var)) { | ||
252 | m = hw_param_mask(params, r->var); | ||
253 | printk("%x", *m->bits); | ||
254 | } else { | ||
255 | i = hw_param_interval(params, r->var); | ||
256 | if (i->empty) | ||
257 | printk("empty"); | ||
258 | else | ||
259 | printk("%c%u %u%c", | ||
260 | i->openmin ? '(' : '[', i->min, | ||
261 | i->max, i->openmax ? ')' : ']'); | ||
262 | } | ||
263 | } | ||
264 | #endif | ||
265 | changed = r->func(params, r); | ||
266 | #ifdef RULES_DEBUG | ||
267 | if (r->var >= 0) { | ||
268 | printk(" -> "); | ||
269 | if (hw_is_mask(r->var)) | ||
270 | printk("%x", *m->bits); | ||
271 | else { | ||
272 | if (i->empty) | ||
273 | printk("empty"); | ||
274 | else | ||
275 | printk("%c%u %u%c", | ||
276 | i->openmin ? '(' : '[', i->min, | ||
277 | i->max, i->openmax ? ')' : ']'); | ||
278 | } | ||
279 | } | ||
280 | printk("\n"); | ||
281 | #endif | ||
282 | rstamps[k] = stamp; | ||
283 | if (changed && r->var >= 0) { | ||
284 | params->cmask |= (1 << r->var); | ||
285 | vstamps[r->var] = stamp; | ||
286 | again = 1; | ||
287 | } | ||
288 | if (changed < 0) | ||
289 | return changed; | ||
290 | stamp++; | ||
291 | } | ||
292 | } while (again); | ||
293 | if (!params->msbits) { | ||
294 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); | ||
295 | if (snd_interval_single(i)) | ||
296 | params->msbits = snd_interval_value(i); | ||
297 | } | ||
298 | |||
299 | if (!params->rate_den) { | ||
300 | i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
301 | if (snd_interval_single(i)) { | ||
302 | params->rate_num = snd_interval_value(i); | ||
303 | params->rate_den = 1; | ||
304 | } | ||
305 | } | ||
306 | |||
307 | hw = &substream->runtime->hw; | ||
308 | if (!params->info) | ||
309 | params->info = hw->info; | ||
310 | if (!params->fifo_size) | ||
311 | params->fifo_size = hw->fifo_size; | ||
312 | params->rmask = 0; | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | static int snd_pcm_hw_refine_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) | ||
317 | { | ||
318 | snd_pcm_hw_params_t *params; | ||
319 | int err; | ||
320 | |||
321 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
322 | if (!params) { | ||
323 | err = -ENOMEM; | ||
324 | goto out; | ||
325 | } | ||
326 | if (copy_from_user(params, _params, sizeof(*params))) { | ||
327 | err = -EFAULT; | ||
328 | goto out; | ||
329 | } | ||
330 | err = snd_pcm_hw_refine(substream, params); | ||
331 | if (copy_to_user(_params, params, sizeof(*params))) { | ||
332 | if (!err) | ||
333 | err = -EFAULT; | ||
334 | } | ||
335 | out: | ||
336 | kfree(params); | ||
337 | return err; | ||
338 | } | ||
339 | |||
340 | int snd_pcm_hw_params(snd_pcm_substream_t *substream, | ||
341 | snd_pcm_hw_params_t *params) | ||
342 | { | ||
343 | snd_pcm_runtime_t *runtime; | ||
344 | int err; | ||
345 | unsigned int bits; | ||
346 | snd_pcm_uframes_t frames; | ||
347 | |||
348 | snd_assert(substream != NULL, return -ENXIO); | ||
349 | runtime = substream->runtime; | ||
350 | snd_assert(runtime != NULL, return -ENXIO); | ||
351 | snd_pcm_stream_lock_irq(substream); | ||
352 | switch (runtime->status->state) { | ||
353 | case SNDRV_PCM_STATE_OPEN: | ||
354 | case SNDRV_PCM_STATE_SETUP: | ||
355 | case SNDRV_PCM_STATE_PREPARED: | ||
356 | break; | ||
357 | default: | ||
358 | snd_pcm_stream_unlock_irq(substream); | ||
359 | return -EBADFD; | ||
360 | } | ||
361 | snd_pcm_stream_unlock_irq(substream); | ||
362 | #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) | ||
363 | if (!substream->oss.oss) | ||
364 | #endif | ||
365 | if (atomic_read(&runtime->mmap_count)) | ||
366 | return -EBADFD; | ||
367 | |||
368 | params->rmask = ~0U; | ||
369 | err = snd_pcm_hw_refine(substream, params); | ||
370 | if (err < 0) | ||
371 | goto _error; | ||
372 | |||
373 | err = snd_pcm_hw_params_choose(substream, params); | ||
374 | if (err < 0) | ||
375 | goto _error; | ||
376 | |||
377 | if (substream->ops->hw_params != NULL) { | ||
378 | err = substream->ops->hw_params(substream, params); | ||
379 | if (err < 0) | ||
380 | goto _error; | ||
381 | } | ||
382 | |||
383 | runtime->access = params_access(params); | ||
384 | runtime->format = params_format(params); | ||
385 | runtime->subformat = params_subformat(params); | ||
386 | runtime->channels = params_channels(params); | ||
387 | runtime->rate = params_rate(params); | ||
388 | runtime->period_size = params_period_size(params); | ||
389 | runtime->periods = params_periods(params); | ||
390 | runtime->buffer_size = params_buffer_size(params); | ||
391 | runtime->tick_time = params_tick_time(params); | ||
392 | runtime->info = params->info; | ||
393 | runtime->rate_num = params->rate_num; | ||
394 | runtime->rate_den = params->rate_den; | ||
395 | |||
396 | bits = snd_pcm_format_physical_width(runtime->format); | ||
397 | runtime->sample_bits = bits; | ||
398 | bits *= runtime->channels; | ||
399 | runtime->frame_bits = bits; | ||
400 | frames = 1; | ||
401 | while (bits % 8 != 0) { | ||
402 | bits *= 2; | ||
403 | frames *= 2; | ||
404 | } | ||
405 | runtime->byte_align = bits / 8; | ||
406 | runtime->min_align = frames; | ||
407 | |||
408 | /* Default sw params */ | ||
409 | runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE; | ||
410 | runtime->period_step = 1; | ||
411 | runtime->sleep_min = 0; | ||
412 | runtime->control->avail_min = runtime->period_size; | ||
413 | runtime->xfer_align = runtime->period_size; | ||
414 | runtime->start_threshold = 1; | ||
415 | runtime->stop_threshold = runtime->buffer_size; | ||
416 | runtime->silence_threshold = 0; | ||
417 | runtime->silence_size = 0; | ||
418 | runtime->boundary = runtime->buffer_size; | ||
419 | while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) | ||
420 | runtime->boundary *= 2; | ||
421 | |||
422 | snd_pcm_timer_resolution_change(substream); | ||
423 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | ||
424 | return 0; | ||
425 | _error: | ||
426 | /* hardware might be unuseable from this time, | ||
427 | so we force application to retry to set | ||
428 | the correct hardware parameter settings */ | ||
429 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | ||
430 | if (substream->ops->hw_free != NULL) | ||
431 | substream->ops->hw_free(substream); | ||
432 | return err; | ||
433 | } | ||
434 | |||
435 | static int snd_pcm_hw_params_user(snd_pcm_substream_t * substream, snd_pcm_hw_params_t __user * _params) | ||
436 | { | ||
437 | snd_pcm_hw_params_t *params; | ||
438 | int err; | ||
439 | |||
440 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
441 | if (!params) { | ||
442 | err = -ENOMEM; | ||
443 | goto out; | ||
444 | } | ||
445 | if (copy_from_user(params, _params, sizeof(*params))) { | ||
446 | err = -EFAULT; | ||
447 | goto out; | ||
448 | } | ||
449 | err = snd_pcm_hw_params(substream, params); | ||
450 | if (copy_to_user(_params, params, sizeof(*params))) { | ||
451 | if (!err) | ||
452 | err = -EFAULT; | ||
453 | } | ||
454 | out: | ||
455 | kfree(params); | ||
456 | return err; | ||
457 | } | ||
458 | |||
459 | static int snd_pcm_hw_free(snd_pcm_substream_t * substream) | ||
460 | { | ||
461 | snd_pcm_runtime_t *runtime; | ||
462 | int result = 0; | ||
463 | |||
464 | snd_assert(substream != NULL, return -ENXIO); | ||
465 | runtime = substream->runtime; | ||
466 | snd_assert(runtime != NULL, return -ENXIO); | ||
467 | snd_pcm_stream_lock_irq(substream); | ||
468 | switch (runtime->status->state) { | ||
469 | case SNDRV_PCM_STATE_SETUP: | ||
470 | case SNDRV_PCM_STATE_PREPARED: | ||
471 | break; | ||
472 | default: | ||
473 | snd_pcm_stream_unlock_irq(substream); | ||
474 | return -EBADFD; | ||
475 | } | ||
476 | snd_pcm_stream_unlock_irq(substream); | ||
477 | if (atomic_read(&runtime->mmap_count)) | ||
478 | return -EBADFD; | ||
479 | if (substream->ops->hw_free) | ||
480 | result = substream->ops->hw_free(substream); | ||
481 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | ||
482 | return result; | ||
483 | } | ||
484 | |||
485 | static int snd_pcm_sw_params(snd_pcm_substream_t * substream, snd_pcm_sw_params_t *params) | ||
486 | { | ||
487 | snd_pcm_runtime_t *runtime; | ||
488 | |||
489 | snd_assert(substream != NULL, return -ENXIO); | ||
490 | runtime = substream->runtime; | ||
491 | snd_assert(runtime != NULL, return -ENXIO); | ||
492 | snd_pcm_stream_lock_irq(substream); | ||
493 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
494 | snd_pcm_stream_unlock_irq(substream); | ||
495 | return -EBADFD; | ||
496 | } | ||
497 | snd_pcm_stream_unlock_irq(substream); | ||
498 | |||
499 | if (params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST) | ||
500 | return -EINVAL; | ||
501 | if (params->avail_min == 0) | ||
502 | return -EINVAL; | ||
503 | if (params->xfer_align == 0 || | ||
504 | params->xfer_align % runtime->min_align != 0) | ||
505 | return -EINVAL; | ||
506 | if (params->silence_size >= runtime->boundary) { | ||
507 | if (params->silence_threshold != 0) | ||
508 | return -EINVAL; | ||
509 | } else { | ||
510 | if (params->silence_size > params->silence_threshold) | ||
511 | return -EINVAL; | ||
512 | if (params->silence_threshold > runtime->buffer_size) | ||
513 | return -EINVAL; | ||
514 | } | ||
515 | snd_pcm_stream_lock_irq(substream); | ||
516 | runtime->tstamp_mode = params->tstamp_mode; | ||
517 | runtime->sleep_min = params->sleep_min; | ||
518 | runtime->period_step = params->period_step; | ||
519 | runtime->control->avail_min = params->avail_min; | ||
520 | runtime->start_threshold = params->start_threshold; | ||
521 | runtime->stop_threshold = params->stop_threshold; | ||
522 | runtime->silence_threshold = params->silence_threshold; | ||
523 | runtime->silence_size = params->silence_size; | ||
524 | runtime->xfer_align = params->xfer_align; | ||
525 | params->boundary = runtime->boundary; | ||
526 | if (snd_pcm_running(substream)) { | ||
527 | if (runtime->sleep_min) | ||
528 | snd_pcm_tick_prepare(substream); | ||
529 | else | ||
530 | snd_pcm_tick_set(substream, 0); | ||
531 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
532 | runtime->silence_size > 0) | ||
533 | snd_pcm_playback_silence(substream, ULONG_MAX); | ||
534 | wake_up(&runtime->sleep); | ||
535 | } | ||
536 | snd_pcm_stream_unlock_irq(substream); | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int snd_pcm_sw_params_user(snd_pcm_substream_t * substream, snd_pcm_sw_params_t __user * _params) | ||
541 | { | ||
542 | snd_pcm_sw_params_t params; | ||
543 | int err; | ||
544 | if (copy_from_user(¶ms, _params, sizeof(params))) | ||
545 | return -EFAULT; | ||
546 | err = snd_pcm_sw_params(substream, ¶ms); | ||
547 | if (copy_to_user(_params, ¶ms, sizeof(params))) | ||
548 | return -EFAULT; | ||
549 | return err; | ||
550 | } | ||
551 | |||
552 | int snd_pcm_status(snd_pcm_substream_t *substream, | ||
553 | snd_pcm_status_t *status) | ||
554 | { | ||
555 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
556 | |||
557 | snd_pcm_stream_lock_irq(substream); | ||
558 | status->state = runtime->status->state; | ||
559 | status->suspended_state = runtime->status->suspended_state; | ||
560 | if (status->state == SNDRV_PCM_STATE_OPEN) | ||
561 | goto _end; | ||
562 | status->trigger_tstamp = runtime->trigger_tstamp; | ||
563 | if (snd_pcm_running(substream)) { | ||
564 | snd_pcm_update_hw_ptr(substream); | ||
565 | if (runtime->tstamp_mode & SNDRV_PCM_TSTAMP_MMAP) | ||
566 | status->tstamp = runtime->status->tstamp; | ||
567 | else | ||
568 | snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec); | ||
569 | } else | ||
570 | snd_timestamp_now(&status->tstamp, runtime->tstamp_timespec); | ||
571 | status->appl_ptr = runtime->control->appl_ptr; | ||
572 | status->hw_ptr = runtime->status->hw_ptr; | ||
573 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
574 | status->avail = snd_pcm_playback_avail(runtime); | ||
575 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || | ||
576 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) | ||
577 | status->delay = runtime->buffer_size - status->avail; | ||
578 | else | ||
579 | status->delay = 0; | ||
580 | } else { | ||
581 | status->avail = snd_pcm_capture_avail(runtime); | ||
582 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | ||
583 | status->delay = status->avail; | ||
584 | else | ||
585 | status->delay = 0; | ||
586 | } | ||
587 | status->avail_max = runtime->avail_max; | ||
588 | status->overrange = runtime->overrange; | ||
589 | runtime->avail_max = 0; | ||
590 | runtime->overrange = 0; | ||
591 | _end: | ||
592 | snd_pcm_stream_unlock_irq(substream); | ||
593 | return 0; | ||
594 | } | ||
595 | |||
596 | static int snd_pcm_status_user(snd_pcm_substream_t * substream, snd_pcm_status_t __user * _status) | ||
597 | { | ||
598 | snd_pcm_status_t status; | ||
599 | snd_pcm_runtime_t *runtime; | ||
600 | int res; | ||
601 | |||
602 | snd_assert(substream != NULL, return -ENXIO); | ||
603 | runtime = substream->runtime; | ||
604 | memset(&status, 0, sizeof(status)); | ||
605 | res = snd_pcm_status(substream, &status); | ||
606 | if (res < 0) | ||
607 | return res; | ||
608 | if (copy_to_user(_status, &status, sizeof(status))) | ||
609 | return -EFAULT; | ||
610 | return 0; | ||
611 | } | ||
612 | |||
613 | static int snd_pcm_channel_info(snd_pcm_substream_t * substream, snd_pcm_channel_info_t * info) | ||
614 | { | ||
615 | snd_pcm_runtime_t *runtime; | ||
616 | unsigned int channel; | ||
617 | |||
618 | snd_assert(substream != NULL, return -ENXIO); | ||
619 | channel = info->channel; | ||
620 | runtime = substream->runtime; | ||
621 | snd_pcm_stream_lock_irq(substream); | ||
622 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
623 | snd_pcm_stream_unlock_irq(substream); | ||
624 | return -EBADFD; | ||
625 | } | ||
626 | snd_pcm_stream_unlock_irq(substream); | ||
627 | if (channel >= runtime->channels) | ||
628 | return -EINVAL; | ||
629 | memset(info, 0, sizeof(*info)); | ||
630 | info->channel = channel; | ||
631 | return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info); | ||
632 | } | ||
633 | |||
634 | static int snd_pcm_channel_info_user(snd_pcm_substream_t * substream, snd_pcm_channel_info_t __user * _info) | ||
635 | { | ||
636 | snd_pcm_channel_info_t info; | ||
637 | int res; | ||
638 | |||
639 | if (copy_from_user(&info, _info, sizeof(info))) | ||
640 | return -EFAULT; | ||
641 | res = snd_pcm_channel_info(substream, &info); | ||
642 | if (res < 0) | ||
643 | return res; | ||
644 | if (copy_to_user(_info, &info, sizeof(info))) | ||
645 | return -EFAULT; | ||
646 | return 0; | ||
647 | } | ||
648 | |||
649 | static void snd_pcm_trigger_tstamp(snd_pcm_substream_t *substream) | ||
650 | { | ||
651 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
652 | if (runtime->trigger_master == NULL) | ||
653 | return; | ||
654 | if (runtime->trigger_master == substream) { | ||
655 | snd_timestamp_now(&runtime->trigger_tstamp, runtime->tstamp_timespec); | ||
656 | } else { | ||
657 | snd_pcm_trigger_tstamp(runtime->trigger_master); | ||
658 | runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp; | ||
659 | } | ||
660 | runtime->trigger_master = NULL; | ||
661 | } | ||
662 | |||
663 | struct action_ops { | ||
664 | int (*pre_action)(snd_pcm_substream_t *substream, int state); | ||
665 | int (*do_action)(snd_pcm_substream_t *substream, int state); | ||
666 | void (*undo_action)(snd_pcm_substream_t *substream, int state); | ||
667 | void (*post_action)(snd_pcm_substream_t *substream, int state); | ||
668 | }; | ||
669 | |||
670 | /* | ||
671 | * this functions is core for handling of linked stream | ||
672 | * Note: the stream state might be changed also on failure | ||
673 | * Note2: call with calling stream lock + link lock | ||
674 | */ | ||
675 | static int snd_pcm_action_group(struct action_ops *ops, | ||
676 | snd_pcm_substream_t *substream, | ||
677 | int state, int do_lock) | ||
678 | { | ||
679 | struct list_head *pos; | ||
680 | snd_pcm_substream_t *s = NULL; | ||
681 | snd_pcm_substream_t *s1; | ||
682 | int res = 0; | ||
683 | |||
684 | snd_pcm_group_for_each(pos, substream) { | ||
685 | s = snd_pcm_group_substream_entry(pos); | ||
686 | if (do_lock && s != substream) | ||
687 | spin_lock(&s->self_group.lock); | ||
688 | res = ops->pre_action(s, state); | ||
689 | if (res < 0) | ||
690 | goto _unlock; | ||
691 | } | ||
692 | snd_pcm_group_for_each(pos, substream) { | ||
693 | s = snd_pcm_group_substream_entry(pos); | ||
694 | res = ops->do_action(s, state); | ||
695 | if (res < 0) { | ||
696 | if (ops->undo_action) { | ||
697 | snd_pcm_group_for_each(pos, substream) { | ||
698 | s1 = snd_pcm_group_substream_entry(pos); | ||
699 | if (s1 == s) /* failed stream */ | ||
700 | break; | ||
701 | ops->undo_action(s1, state); | ||
702 | } | ||
703 | } | ||
704 | s = NULL; /* unlock all */ | ||
705 | goto _unlock; | ||
706 | } | ||
707 | } | ||
708 | snd_pcm_group_for_each(pos, substream) { | ||
709 | s = snd_pcm_group_substream_entry(pos); | ||
710 | ops->post_action(s, state); | ||
711 | } | ||
712 | _unlock: | ||
713 | if (do_lock) { | ||
714 | /* unlock streams */ | ||
715 | snd_pcm_group_for_each(pos, substream) { | ||
716 | s1 = snd_pcm_group_substream_entry(pos); | ||
717 | if (s1 != substream) | ||
718 | spin_unlock(&s1->self_group.lock); | ||
719 | if (s1 == s) /* end */ | ||
720 | break; | ||
721 | } | ||
722 | } | ||
723 | return res; | ||
724 | } | ||
725 | |||
726 | /* | ||
727 | * Note: call with stream lock | ||
728 | */ | ||
729 | static int snd_pcm_action_single(struct action_ops *ops, | ||
730 | snd_pcm_substream_t *substream, | ||
731 | int state) | ||
732 | { | ||
733 | int res; | ||
734 | |||
735 | res = ops->pre_action(substream, state); | ||
736 | if (res < 0) | ||
737 | return res; | ||
738 | res = ops->do_action(substream, state); | ||
739 | if (res == 0) | ||
740 | ops->post_action(substream, state); | ||
741 | else if (ops->undo_action) | ||
742 | ops->undo_action(substream, state); | ||
743 | return res; | ||
744 | } | ||
745 | |||
746 | /* | ||
747 | * Note: call with stream lock | ||
748 | */ | ||
749 | static int snd_pcm_action(struct action_ops *ops, | ||
750 | snd_pcm_substream_t *substream, | ||
751 | int state) | ||
752 | { | ||
753 | int res; | ||
754 | |||
755 | if (snd_pcm_stream_linked(substream)) { | ||
756 | if (!spin_trylock(&substream->group->lock)) { | ||
757 | spin_unlock(&substream->self_group.lock); | ||
758 | spin_lock(&substream->group->lock); | ||
759 | spin_lock(&substream->self_group.lock); | ||
760 | } | ||
761 | res = snd_pcm_action_group(ops, substream, state, 1); | ||
762 | spin_unlock(&substream->group->lock); | ||
763 | } else { | ||
764 | res = snd_pcm_action_single(ops, substream, state); | ||
765 | } | ||
766 | return res; | ||
767 | } | ||
768 | |||
769 | /* | ||
770 | * Note: don't use any locks before | ||
771 | */ | ||
772 | static int snd_pcm_action_lock_irq(struct action_ops *ops, | ||
773 | snd_pcm_substream_t *substream, | ||
774 | int state) | ||
775 | { | ||
776 | int res; | ||
777 | |||
778 | read_lock_irq(&snd_pcm_link_rwlock); | ||
779 | if (snd_pcm_stream_linked(substream)) { | ||
780 | spin_lock(&substream->group->lock); | ||
781 | spin_lock(&substream->self_group.lock); | ||
782 | res = snd_pcm_action_group(ops, substream, state, 1); | ||
783 | spin_unlock(&substream->self_group.lock); | ||
784 | spin_unlock(&substream->group->lock); | ||
785 | } else { | ||
786 | spin_lock(&substream->self_group.lock); | ||
787 | res = snd_pcm_action_single(ops, substream, state); | ||
788 | spin_unlock(&substream->self_group.lock); | ||
789 | } | ||
790 | read_unlock_irq(&snd_pcm_link_rwlock); | ||
791 | return res; | ||
792 | } | ||
793 | |||
794 | /* | ||
795 | */ | ||
796 | static int snd_pcm_action_nonatomic(struct action_ops *ops, | ||
797 | snd_pcm_substream_t *substream, | ||
798 | int state) | ||
799 | { | ||
800 | int res; | ||
801 | |||
802 | down_read(&snd_pcm_link_rwsem); | ||
803 | if (snd_pcm_stream_linked(substream)) | ||
804 | res = snd_pcm_action_group(ops, substream, state, 0); | ||
805 | else | ||
806 | res = snd_pcm_action_single(ops, substream, state); | ||
807 | up_read(&snd_pcm_link_rwsem); | ||
808 | return res; | ||
809 | } | ||
810 | |||
811 | /* | ||
812 | * start callbacks | ||
813 | */ | ||
814 | static int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state) | ||
815 | { | ||
816 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
817 | if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) | ||
818 | return -EBADFD; | ||
819 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
820 | !snd_pcm_playback_data(substream)) | ||
821 | return -EPIPE; | ||
822 | runtime->trigger_master = substream; | ||
823 | return 0; | ||
824 | } | ||
825 | |||
826 | static int snd_pcm_do_start(snd_pcm_substream_t *substream, int state) | ||
827 | { | ||
828 | if (substream->runtime->trigger_master != substream) | ||
829 | return 0; | ||
830 | return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); | ||
831 | } | ||
832 | |||
833 | static void snd_pcm_undo_start(snd_pcm_substream_t *substream, int state) | ||
834 | { | ||
835 | if (substream->runtime->trigger_master == substream) | ||
836 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); | ||
837 | } | ||
838 | |||
839 | static void snd_pcm_post_start(snd_pcm_substream_t *substream, int state) | ||
840 | { | ||
841 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
842 | snd_pcm_trigger_tstamp(substream); | ||
843 | runtime->status->state = state; | ||
844 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
845 | runtime->silence_size > 0) | ||
846 | snd_pcm_playback_silence(substream, ULONG_MAX); | ||
847 | if (runtime->sleep_min) | ||
848 | snd_pcm_tick_prepare(substream); | ||
849 | if (substream->timer) | ||
850 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp); | ||
851 | } | ||
852 | |||
853 | static struct action_ops snd_pcm_action_start = { | ||
854 | .pre_action = snd_pcm_pre_start, | ||
855 | .do_action = snd_pcm_do_start, | ||
856 | .undo_action = snd_pcm_undo_start, | ||
857 | .post_action = snd_pcm_post_start | ||
858 | }; | ||
859 | |||
860 | /** | ||
861 | * snd_pcm_start | ||
862 | * | ||
863 | * Start all linked streams. | ||
864 | */ | ||
865 | int snd_pcm_start(snd_pcm_substream_t *substream) | ||
866 | { | ||
867 | return snd_pcm_action(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); | ||
868 | } | ||
869 | |||
870 | /* | ||
871 | * stop callbacks | ||
872 | */ | ||
873 | static int snd_pcm_pre_stop(snd_pcm_substream_t *substream, int state) | ||
874 | { | ||
875 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
876 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
877 | return -EBADFD; | ||
878 | runtime->trigger_master = substream; | ||
879 | return 0; | ||
880 | } | ||
881 | |||
882 | static int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state) | ||
883 | { | ||
884 | if (substream->runtime->trigger_master == substream && | ||
885 | snd_pcm_running(substream)) | ||
886 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); | ||
887 | return 0; /* unconditonally stop all substreams */ | ||
888 | } | ||
889 | |||
890 | static void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state) | ||
891 | { | ||
892 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
893 | if (runtime->status->state != state) { | ||
894 | snd_pcm_trigger_tstamp(substream); | ||
895 | if (substream->timer) | ||
896 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP, &runtime->trigger_tstamp); | ||
897 | runtime->status->state = state; | ||
898 | snd_pcm_tick_set(substream, 0); | ||
899 | } | ||
900 | wake_up(&runtime->sleep); | ||
901 | } | ||
902 | |||
903 | static struct action_ops snd_pcm_action_stop = { | ||
904 | .pre_action = snd_pcm_pre_stop, | ||
905 | .do_action = snd_pcm_do_stop, | ||
906 | .post_action = snd_pcm_post_stop | ||
907 | }; | ||
908 | |||
909 | /** | ||
910 | * snd_pcm_stop | ||
911 | * | ||
912 | * Try to stop all running streams in the substream group. | ||
913 | * The state of each stream is changed to the given value after that unconditionally. | ||
914 | */ | ||
915 | int snd_pcm_stop(snd_pcm_substream_t *substream, int state) | ||
916 | { | ||
917 | return snd_pcm_action(&snd_pcm_action_stop, substream, state); | ||
918 | } | ||
919 | |||
920 | /** | ||
921 | * snd_pcm_drain_done | ||
922 | * | ||
923 | * Stop the DMA only when the given stream is playback. | ||
924 | * The state is changed to SETUP. | ||
925 | * Unlike snd_pcm_stop(), this affects only the given stream. | ||
926 | */ | ||
927 | int snd_pcm_drain_done(snd_pcm_substream_t *substream) | ||
928 | { | ||
929 | return snd_pcm_action_single(&snd_pcm_action_stop, substream, SNDRV_PCM_STATE_SETUP); | ||
930 | } | ||
931 | |||
932 | /* | ||
933 | * pause callbacks | ||
934 | */ | ||
935 | static int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push) | ||
936 | { | ||
937 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
938 | if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) | ||
939 | return -ENOSYS; | ||
940 | if (push) { | ||
941 | if (runtime->status->state != SNDRV_PCM_STATE_RUNNING) | ||
942 | return -EBADFD; | ||
943 | } else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED) | ||
944 | return -EBADFD; | ||
945 | runtime->trigger_master = substream; | ||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | static int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push) | ||
950 | { | ||
951 | if (substream->runtime->trigger_master != substream) | ||
952 | return 0; | ||
953 | return substream->ops->trigger(substream, | ||
954 | push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : | ||
955 | SNDRV_PCM_TRIGGER_PAUSE_RELEASE); | ||
956 | } | ||
957 | |||
958 | static void snd_pcm_undo_pause(snd_pcm_substream_t *substream, int push) | ||
959 | { | ||
960 | if (substream->runtime->trigger_master == substream) | ||
961 | substream->ops->trigger(substream, | ||
962 | push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE : | ||
963 | SNDRV_PCM_TRIGGER_PAUSE_PUSH); | ||
964 | } | ||
965 | |||
966 | static void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push) | ||
967 | { | ||
968 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
969 | snd_pcm_trigger_tstamp(substream); | ||
970 | if (push) { | ||
971 | runtime->status->state = SNDRV_PCM_STATE_PAUSED; | ||
972 | if (substream->timer) | ||
973 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp); | ||
974 | snd_pcm_tick_set(substream, 0); | ||
975 | wake_up(&runtime->sleep); | ||
976 | } else { | ||
977 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; | ||
978 | if (runtime->sleep_min) | ||
979 | snd_pcm_tick_prepare(substream); | ||
980 | if (substream->timer) | ||
981 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp); | ||
982 | } | ||
983 | } | ||
984 | |||
985 | static struct action_ops snd_pcm_action_pause = { | ||
986 | .pre_action = snd_pcm_pre_pause, | ||
987 | .do_action = snd_pcm_do_pause, | ||
988 | .undo_action = snd_pcm_undo_pause, | ||
989 | .post_action = snd_pcm_post_pause | ||
990 | }; | ||
991 | |||
992 | /* | ||
993 | * Push/release the pause for all linked streams. | ||
994 | */ | ||
995 | static int snd_pcm_pause(snd_pcm_substream_t *substream, int push) | ||
996 | { | ||
997 | return snd_pcm_action(&snd_pcm_action_pause, substream, push); | ||
998 | } | ||
999 | |||
1000 | #ifdef CONFIG_PM | ||
1001 | /* suspend */ | ||
1002 | |||
1003 | static int snd_pcm_pre_suspend(snd_pcm_substream_t *substream, int state) | ||
1004 | { | ||
1005 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1006 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) | ||
1007 | return -EBUSY; | ||
1008 | runtime->trigger_master = substream; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | static int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state) | ||
1013 | { | ||
1014 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1015 | if (runtime->trigger_master != substream) | ||
1016 | return 0; | ||
1017 | if (! snd_pcm_running(substream)) | ||
1018 | return 0; | ||
1019 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); | ||
1020 | return 0; /* suspend unconditionally */ | ||
1021 | } | ||
1022 | |||
1023 | static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state) | ||
1024 | { | ||
1025 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1026 | snd_pcm_trigger_tstamp(substream); | ||
1027 | if (substream->timer) | ||
1028 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MPAUSE, &runtime->trigger_tstamp); | ||
1029 | runtime->status->suspended_state = runtime->status->state; | ||
1030 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; | ||
1031 | snd_pcm_tick_set(substream, 0); | ||
1032 | wake_up(&runtime->sleep); | ||
1033 | } | ||
1034 | |||
1035 | static struct action_ops snd_pcm_action_suspend = { | ||
1036 | .pre_action = snd_pcm_pre_suspend, | ||
1037 | .do_action = snd_pcm_do_suspend, | ||
1038 | .post_action = snd_pcm_post_suspend | ||
1039 | }; | ||
1040 | |||
1041 | /** | ||
1042 | * snd_pcm_suspend | ||
1043 | * | ||
1044 | * Trigger SUSPEND to all linked streams. | ||
1045 | * After this call, all streams are changed to SUSPENDED state. | ||
1046 | */ | ||
1047 | int snd_pcm_suspend(snd_pcm_substream_t *substream) | ||
1048 | { | ||
1049 | int err; | ||
1050 | unsigned long flags; | ||
1051 | |||
1052 | snd_pcm_stream_lock_irqsave(substream, flags); | ||
1053 | err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0); | ||
1054 | snd_pcm_stream_unlock_irqrestore(substream, flags); | ||
1055 | return err; | ||
1056 | } | ||
1057 | |||
1058 | /** | ||
1059 | * snd_pcm_suspend_all | ||
1060 | * | ||
1061 | * Trigger SUSPEND to all substreams in the given pcm. | ||
1062 | * After this call, all streams are changed to SUSPENDED state. | ||
1063 | */ | ||
1064 | int snd_pcm_suspend_all(snd_pcm_t *pcm) | ||
1065 | { | ||
1066 | snd_pcm_substream_t *substream; | ||
1067 | int stream, err = 0; | ||
1068 | |||
1069 | for (stream = 0; stream < 2; stream++) { | ||
1070 | for (substream = pcm->streams[stream].substream; substream; substream = substream->next) { | ||
1071 | /* FIXME: the open/close code should lock this as well */ | ||
1072 | if (substream->runtime == NULL) | ||
1073 | continue; | ||
1074 | err = snd_pcm_suspend(substream); | ||
1075 | if (err < 0 && err != -EBUSY) | ||
1076 | return err; | ||
1077 | } | ||
1078 | } | ||
1079 | return 0; | ||
1080 | } | ||
1081 | |||
1082 | /* resume */ | ||
1083 | |||
1084 | static int snd_pcm_pre_resume(snd_pcm_substream_t *substream, int state) | ||
1085 | { | ||
1086 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1087 | if (!(runtime->info & SNDRV_PCM_INFO_RESUME)) | ||
1088 | return -ENOSYS; | ||
1089 | runtime->trigger_master = substream; | ||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | static int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state) | ||
1094 | { | ||
1095 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1096 | if (runtime->trigger_master != substream) | ||
1097 | return 0; | ||
1098 | /* DMA not running previously? */ | ||
1099 | if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING && | ||
1100 | (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING || | ||
1101 | substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) | ||
1102 | return 0; | ||
1103 | return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); | ||
1104 | } | ||
1105 | |||
1106 | static void snd_pcm_undo_resume(snd_pcm_substream_t *substream, int state) | ||
1107 | { | ||
1108 | if (substream->runtime->trigger_master == substream && | ||
1109 | snd_pcm_running(substream)) | ||
1110 | substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); | ||
1111 | } | ||
1112 | |||
1113 | static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state) | ||
1114 | { | ||
1115 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1116 | snd_pcm_trigger_tstamp(substream); | ||
1117 | if (substream->timer) | ||
1118 | snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MCONTINUE, &runtime->trigger_tstamp); | ||
1119 | runtime->status->state = runtime->status->suspended_state; | ||
1120 | if (runtime->sleep_min) | ||
1121 | snd_pcm_tick_prepare(substream); | ||
1122 | } | ||
1123 | |||
1124 | static struct action_ops snd_pcm_action_resume = { | ||
1125 | .pre_action = snd_pcm_pre_resume, | ||
1126 | .do_action = snd_pcm_do_resume, | ||
1127 | .undo_action = snd_pcm_undo_resume, | ||
1128 | .post_action = snd_pcm_post_resume | ||
1129 | }; | ||
1130 | |||
1131 | static int snd_pcm_resume(snd_pcm_substream_t *substream) | ||
1132 | { | ||
1133 | snd_card_t *card = substream->pcm->card; | ||
1134 | int res; | ||
1135 | |||
1136 | snd_power_lock(card); | ||
1137 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) | ||
1138 | res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); | ||
1139 | snd_power_unlock(card); | ||
1140 | return res; | ||
1141 | } | ||
1142 | |||
1143 | #else | ||
1144 | |||
1145 | static int snd_pcm_resume(snd_pcm_substream_t *substream) | ||
1146 | { | ||
1147 | return -ENOSYS; | ||
1148 | } | ||
1149 | |||
1150 | #endif /* CONFIG_PM */ | ||
1151 | |||
1152 | /* | ||
1153 | * xrun ioctl | ||
1154 | * | ||
1155 | * Change the RUNNING stream(s) to XRUN state. | ||
1156 | */ | ||
1157 | static int snd_pcm_xrun(snd_pcm_substream_t *substream) | ||
1158 | { | ||
1159 | snd_card_t *card = substream->pcm->card; | ||
1160 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1161 | int result; | ||
1162 | |||
1163 | snd_power_lock(card); | ||
1164 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | ||
1165 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | ||
1166 | if (result < 0) | ||
1167 | goto _unlock; | ||
1168 | } | ||
1169 | |||
1170 | snd_pcm_stream_lock_irq(substream); | ||
1171 | switch (runtime->status->state) { | ||
1172 | case SNDRV_PCM_STATE_XRUN: | ||
1173 | result = 0; /* already there */ | ||
1174 | break; | ||
1175 | case SNDRV_PCM_STATE_RUNNING: | ||
1176 | result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | ||
1177 | break; | ||
1178 | default: | ||
1179 | result = -EBADFD; | ||
1180 | } | ||
1181 | snd_pcm_stream_unlock_irq(substream); | ||
1182 | _unlock: | ||
1183 | snd_power_unlock(card); | ||
1184 | return result; | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * reset ioctl | ||
1189 | */ | ||
1190 | static int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state) | ||
1191 | { | ||
1192 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1193 | switch (runtime->status->state) { | ||
1194 | case SNDRV_PCM_STATE_RUNNING: | ||
1195 | case SNDRV_PCM_STATE_PREPARED: | ||
1196 | case SNDRV_PCM_STATE_PAUSED: | ||
1197 | case SNDRV_PCM_STATE_SUSPENDED: | ||
1198 | return 0; | ||
1199 | default: | ||
1200 | return -EBADFD; | ||
1201 | } | ||
1202 | } | ||
1203 | |||
1204 | static int snd_pcm_do_reset(snd_pcm_substream_t * substream, int state) | ||
1205 | { | ||
1206 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1207 | int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL); | ||
1208 | if (err < 0) | ||
1209 | return err; | ||
1210 | // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, ); | ||
1211 | runtime->hw_ptr_base = 0; | ||
1212 | runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; | ||
1213 | runtime->silence_start = runtime->status->hw_ptr; | ||
1214 | runtime->silence_filled = 0; | ||
1215 | return 0; | ||
1216 | } | ||
1217 | |||
1218 | static void snd_pcm_post_reset(snd_pcm_substream_t * substream, int state) | ||
1219 | { | ||
1220 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1221 | runtime->control->appl_ptr = runtime->status->hw_ptr; | ||
1222 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
1223 | runtime->silence_size > 0) | ||
1224 | snd_pcm_playback_silence(substream, ULONG_MAX); | ||
1225 | } | ||
1226 | |||
1227 | static struct action_ops snd_pcm_action_reset = { | ||
1228 | .pre_action = snd_pcm_pre_reset, | ||
1229 | .do_action = snd_pcm_do_reset, | ||
1230 | .post_action = snd_pcm_post_reset | ||
1231 | }; | ||
1232 | |||
1233 | static int snd_pcm_reset(snd_pcm_substream_t *substream) | ||
1234 | { | ||
1235 | return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0); | ||
1236 | } | ||
1237 | |||
1238 | /* | ||
1239 | * prepare ioctl | ||
1240 | */ | ||
1241 | static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state) | ||
1242 | { | ||
1243 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1244 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
1245 | return -EBADFD; | ||
1246 | if (snd_pcm_running(substream)) | ||
1247 | return -EBUSY; | ||
1248 | return 0; | ||
1249 | } | ||
1250 | |||
1251 | static int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state) | ||
1252 | { | ||
1253 | int err; | ||
1254 | err = substream->ops->prepare(substream); | ||
1255 | if (err < 0) | ||
1256 | return err; | ||
1257 | return snd_pcm_do_reset(substream, 0); | ||
1258 | } | ||
1259 | |||
1260 | static void snd_pcm_post_prepare(snd_pcm_substream_t * substream, int state) | ||
1261 | { | ||
1262 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1263 | runtime->control->appl_ptr = runtime->status->hw_ptr; | ||
1264 | runtime->status->state = SNDRV_PCM_STATE_PREPARED; | ||
1265 | } | ||
1266 | |||
1267 | static struct action_ops snd_pcm_action_prepare = { | ||
1268 | .pre_action = snd_pcm_pre_prepare, | ||
1269 | .do_action = snd_pcm_do_prepare, | ||
1270 | .post_action = snd_pcm_post_prepare | ||
1271 | }; | ||
1272 | |||
1273 | /** | ||
1274 | * snd_pcm_prepare | ||
1275 | */ | ||
1276 | int snd_pcm_prepare(snd_pcm_substream_t *substream) | ||
1277 | { | ||
1278 | int res; | ||
1279 | snd_card_t *card = substream->pcm->card; | ||
1280 | |||
1281 | snd_power_lock(card); | ||
1282 | if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) | ||
1283 | res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, 0); | ||
1284 | snd_power_unlock(card); | ||
1285 | return res; | ||
1286 | } | ||
1287 | |||
1288 | /* | ||
1289 | * drain ioctl | ||
1290 | */ | ||
1291 | |||
1292 | static int snd_pcm_pre_drain_init(snd_pcm_substream_t * substream, int state) | ||
1293 | { | ||
1294 | if (substream->ffile->f_flags & O_NONBLOCK) | ||
1295 | return -EAGAIN; | ||
1296 | substream->runtime->trigger_master = substream; | ||
1297 | return 0; | ||
1298 | } | ||
1299 | |||
1300 | static int snd_pcm_do_drain_init(snd_pcm_substream_t * substream, int state) | ||
1301 | { | ||
1302 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1303 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1304 | switch (runtime->status->state) { | ||
1305 | case SNDRV_PCM_STATE_PREPARED: | ||
1306 | /* start playback stream if possible */ | ||
1307 | if (! snd_pcm_playback_empty(substream)) { | ||
1308 | snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING); | ||
1309 | snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING); | ||
1310 | } | ||
1311 | break; | ||
1312 | case SNDRV_PCM_STATE_RUNNING: | ||
1313 | runtime->status->state = SNDRV_PCM_STATE_DRAINING; | ||
1314 | break; | ||
1315 | default: | ||
1316 | break; | ||
1317 | } | ||
1318 | } else { | ||
1319 | /* stop running stream */ | ||
1320 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) { | ||
1321 | int state = snd_pcm_capture_avail(runtime) > 0 ? | ||
1322 | SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP; | ||
1323 | snd_pcm_do_stop(substream, state); | ||
1324 | snd_pcm_post_stop(substream, state); | ||
1325 | } | ||
1326 | } | ||
1327 | return 0; | ||
1328 | } | ||
1329 | |||
1330 | static void snd_pcm_post_drain_init(snd_pcm_substream_t * substream, int state) | ||
1331 | { | ||
1332 | } | ||
1333 | |||
1334 | static struct action_ops snd_pcm_action_drain_init = { | ||
1335 | .pre_action = snd_pcm_pre_drain_init, | ||
1336 | .do_action = snd_pcm_do_drain_init, | ||
1337 | .post_action = snd_pcm_post_drain_init | ||
1338 | }; | ||
1339 | |||
1340 | struct drain_rec { | ||
1341 | snd_pcm_substream_t *substream; | ||
1342 | wait_queue_t wait; | ||
1343 | snd_pcm_uframes_t stop_threshold; | ||
1344 | }; | ||
1345 | |||
1346 | static int snd_pcm_drop(snd_pcm_substream_t *substream); | ||
1347 | |||
1348 | /* | ||
1349 | * Drain the stream(s). | ||
1350 | * When the substream is linked, sync until the draining of all playback streams | ||
1351 | * is finished. | ||
1352 | * After this call, all streams are supposed to be either SETUP or DRAINING | ||
1353 | * (capture only) state. | ||
1354 | */ | ||
1355 | static int snd_pcm_drain(snd_pcm_substream_t *substream) | ||
1356 | { | ||
1357 | snd_card_t *card; | ||
1358 | snd_pcm_runtime_t *runtime; | ||
1359 | struct list_head *pos; | ||
1360 | int result = 0; | ||
1361 | int i, num_drecs; | ||
1362 | struct drain_rec *drec, drec_tmp, *d; | ||
1363 | |||
1364 | snd_assert(substream != NULL, return -ENXIO); | ||
1365 | card = substream->pcm->card; | ||
1366 | runtime = substream->runtime; | ||
1367 | |||
1368 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
1369 | return -EBADFD; | ||
1370 | |||
1371 | down_read(&snd_pcm_link_rwsem); | ||
1372 | snd_power_lock(card); | ||
1373 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | ||
1374 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | ||
1375 | if (result < 0) | ||
1376 | goto _unlock; | ||
1377 | } | ||
1378 | |||
1379 | /* allocate temporary record for drain sync */ | ||
1380 | if (snd_pcm_stream_linked(substream)) { | ||
1381 | drec = kmalloc(substream->group->count * sizeof(*drec), GFP_KERNEL); | ||
1382 | if (! drec) { | ||
1383 | result = -ENOMEM; | ||
1384 | goto _unlock; | ||
1385 | } | ||
1386 | } else | ||
1387 | drec = &drec_tmp; | ||
1388 | |||
1389 | snd_pcm_stream_lock_irq(substream); | ||
1390 | /* resume pause */ | ||
1391 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) | ||
1392 | snd_pcm_pause(substream, 0); | ||
1393 | |||
1394 | /* pre-start/stop - all running streams are changed to DRAINING state */ | ||
1395 | result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0); | ||
1396 | if (result < 0) | ||
1397 | goto _end; | ||
1398 | |||
1399 | /* check streams with PLAYBACK & DRAINING */ | ||
1400 | num_drecs = 0; | ||
1401 | snd_pcm_group_for_each(pos, substream) { | ||
1402 | snd_pcm_substream_t *s = snd_pcm_group_substream_entry(pos); | ||
1403 | runtime = s->runtime; | ||
1404 | if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) { | ||
1405 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | ||
1406 | continue; | ||
1407 | } | ||
1408 | if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
1409 | d = &drec[num_drecs++]; | ||
1410 | d->substream = s; | ||
1411 | init_waitqueue_entry(&d->wait, current); | ||
1412 | add_wait_queue(&runtime->sleep, &d->wait); | ||
1413 | /* stop_threshold fixup to avoid endless loop when | ||
1414 | * stop_threshold > buffer_size | ||
1415 | */ | ||
1416 | d->stop_threshold = runtime->stop_threshold; | ||
1417 | if (runtime->stop_threshold > runtime->buffer_size) | ||
1418 | runtime->stop_threshold = runtime->buffer_size; | ||
1419 | } | ||
1420 | } | ||
1421 | |||
1422 | if (! num_drecs) | ||
1423 | goto _end; | ||
1424 | |||
1425 | for (;;) { | ||
1426 | long tout; | ||
1427 | if (signal_pending(current)) { | ||
1428 | result = -ERESTARTSYS; | ||
1429 | break; | ||
1430 | } | ||
1431 | set_current_state(TASK_INTERRUPTIBLE); | ||
1432 | snd_pcm_stream_unlock_irq(substream); | ||
1433 | snd_power_unlock(card); | ||
1434 | tout = schedule_timeout(10 * HZ); | ||
1435 | snd_power_lock(card); | ||
1436 | snd_pcm_stream_lock_irq(substream); | ||
1437 | if (tout == 0) { | ||
1438 | if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) | ||
1439 | result = -ESTRPIPE; | ||
1440 | else { | ||
1441 | snd_printd("playback drain error (DMA or IRQ trouble?)\n"); | ||
1442 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | ||
1443 | result = -EIO; | ||
1444 | } | ||
1445 | break; | ||
1446 | } | ||
1447 | /* all finished? */ | ||
1448 | for (i = 0; i < num_drecs; i++) { | ||
1449 | runtime = drec[i].substream->runtime; | ||
1450 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) | ||
1451 | break; | ||
1452 | } | ||
1453 | if (i == num_drecs) | ||
1454 | break; | ||
1455 | } | ||
1456 | for (i = 0; i < num_drecs; i++) { | ||
1457 | d = &drec[i]; | ||
1458 | runtime = d->substream->runtime; | ||
1459 | remove_wait_queue(&runtime->sleep, &d->wait); | ||
1460 | runtime->stop_threshold = d->stop_threshold; | ||
1461 | } | ||
1462 | |||
1463 | _end: | ||
1464 | snd_pcm_stream_unlock_irq(substream); | ||
1465 | if (drec != &drec_tmp) | ||
1466 | kfree(drec); | ||
1467 | _unlock: | ||
1468 | snd_power_unlock(card); | ||
1469 | up_read(&snd_pcm_link_rwsem); | ||
1470 | |||
1471 | return result; | ||
1472 | } | ||
1473 | |||
1474 | /* | ||
1475 | * drop ioctl | ||
1476 | * | ||
1477 | * Immediately put all linked substreams into SETUP state. | ||
1478 | */ | ||
1479 | static int snd_pcm_drop(snd_pcm_substream_t *substream) | ||
1480 | { | ||
1481 | snd_pcm_runtime_t *runtime; | ||
1482 | snd_card_t *card; | ||
1483 | int result = 0; | ||
1484 | |||
1485 | snd_assert(substream != NULL, return -ENXIO); | ||
1486 | runtime = substream->runtime; | ||
1487 | card = substream->pcm->card; | ||
1488 | |||
1489 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
1490 | return -EBADFD; | ||
1491 | |||
1492 | snd_power_lock(card); | ||
1493 | if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { | ||
1494 | result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); | ||
1495 | if (result < 0) | ||
1496 | goto _unlock; | ||
1497 | } | ||
1498 | |||
1499 | snd_pcm_stream_lock_irq(substream); | ||
1500 | /* resume pause */ | ||
1501 | if (runtime->status->state == SNDRV_PCM_STATE_PAUSED) | ||
1502 | snd_pcm_pause(substream, 0); | ||
1503 | |||
1504 | snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); | ||
1505 | /* runtime->control->appl_ptr = runtime->status->hw_ptr; */ | ||
1506 | snd_pcm_stream_unlock_irq(substream); | ||
1507 | _unlock: | ||
1508 | snd_power_unlock(card); | ||
1509 | return result; | ||
1510 | } | ||
1511 | |||
1512 | |||
1513 | /* WARNING: Don't forget to fput back the file */ | ||
1514 | extern int snd_major; | ||
1515 | static struct file *snd_pcm_file_fd(int fd) | ||
1516 | { | ||
1517 | struct file *file; | ||
1518 | struct inode *inode; | ||
1519 | unsigned short minor; | ||
1520 | file = fget(fd); | ||
1521 | if (!file) | ||
1522 | return NULL; | ||
1523 | inode = file->f_dentry->d_inode; | ||
1524 | if (!S_ISCHR(inode->i_mode) || | ||
1525 | imajor(inode) != snd_major) { | ||
1526 | fput(file); | ||
1527 | return NULL; | ||
1528 | } | ||
1529 | minor = iminor(inode); | ||
1530 | if (minor >= 256 || | ||
1531 | minor % SNDRV_MINOR_DEVICES < SNDRV_MINOR_PCM_PLAYBACK) { | ||
1532 | fput(file); | ||
1533 | return NULL; | ||
1534 | } | ||
1535 | return file; | ||
1536 | } | ||
1537 | |||
1538 | /* | ||
1539 | * PCM link handling | ||
1540 | */ | ||
1541 | static int snd_pcm_link(snd_pcm_substream_t *substream, int fd) | ||
1542 | { | ||
1543 | int res = 0; | ||
1544 | struct file *file; | ||
1545 | snd_pcm_file_t *pcm_file; | ||
1546 | snd_pcm_substream_t *substream1; | ||
1547 | |||
1548 | file = snd_pcm_file_fd(fd); | ||
1549 | if (!file) | ||
1550 | return -EBADFD; | ||
1551 | pcm_file = file->private_data; | ||
1552 | substream1 = pcm_file->substream; | ||
1553 | down_write(&snd_pcm_link_rwsem); | ||
1554 | write_lock_irq(&snd_pcm_link_rwlock); | ||
1555 | if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN || | ||
1556 | substream->runtime->status->state != substream1->runtime->status->state) { | ||
1557 | res = -EBADFD; | ||
1558 | goto _end; | ||
1559 | } | ||
1560 | if (snd_pcm_stream_linked(substream1)) { | ||
1561 | res = -EALREADY; | ||
1562 | goto _end; | ||
1563 | } | ||
1564 | if (!snd_pcm_stream_linked(substream)) { | ||
1565 | substream->group = kmalloc(sizeof(snd_pcm_group_t), GFP_ATOMIC); | ||
1566 | if (substream->group == NULL) { | ||
1567 | res = -ENOMEM; | ||
1568 | goto _end; | ||
1569 | } | ||
1570 | spin_lock_init(&substream->group->lock); | ||
1571 | INIT_LIST_HEAD(&substream->group->substreams); | ||
1572 | list_add_tail(&substream->link_list, &substream->group->substreams); | ||
1573 | substream->group->count = 1; | ||
1574 | } | ||
1575 | list_add_tail(&substream1->link_list, &substream->group->substreams); | ||
1576 | substream->group->count++; | ||
1577 | substream1->group = substream->group; | ||
1578 | _end: | ||
1579 | write_unlock_irq(&snd_pcm_link_rwlock); | ||
1580 | up_write(&snd_pcm_link_rwsem); | ||
1581 | fput(file); | ||
1582 | return res; | ||
1583 | } | ||
1584 | |||
1585 | static void relink_to_local(snd_pcm_substream_t *substream) | ||
1586 | { | ||
1587 | substream->group = &substream->self_group; | ||
1588 | INIT_LIST_HEAD(&substream->self_group.substreams); | ||
1589 | list_add_tail(&substream->link_list, &substream->self_group.substreams); | ||
1590 | } | ||
1591 | |||
1592 | static int snd_pcm_unlink(snd_pcm_substream_t *substream) | ||
1593 | { | ||
1594 | struct list_head *pos; | ||
1595 | int res = 0; | ||
1596 | |||
1597 | down_write(&snd_pcm_link_rwsem); | ||
1598 | write_lock_irq(&snd_pcm_link_rwlock); | ||
1599 | if (!snd_pcm_stream_linked(substream)) { | ||
1600 | res = -EALREADY; | ||
1601 | goto _end; | ||
1602 | } | ||
1603 | list_del(&substream->link_list); | ||
1604 | substream->group->count--; | ||
1605 | if (substream->group->count == 1) { /* detach the last stream, too */ | ||
1606 | snd_pcm_group_for_each(pos, substream) { | ||
1607 | relink_to_local(snd_pcm_group_substream_entry(pos)); | ||
1608 | break; | ||
1609 | } | ||
1610 | kfree(substream->group); | ||
1611 | } | ||
1612 | relink_to_local(substream); | ||
1613 | _end: | ||
1614 | write_unlock_irq(&snd_pcm_link_rwlock); | ||
1615 | up_write(&snd_pcm_link_rwsem); | ||
1616 | return res; | ||
1617 | } | ||
1618 | |||
1619 | /* | ||
1620 | * hw configurator | ||
1621 | */ | ||
1622 | static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params, | ||
1623 | snd_pcm_hw_rule_t *rule) | ||
1624 | { | ||
1625 | snd_interval_t t; | ||
1626 | snd_interval_mul(hw_param_interval_c(params, rule->deps[0]), | ||
1627 | hw_param_interval_c(params, rule->deps[1]), &t); | ||
1628 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1629 | } | ||
1630 | |||
1631 | static int snd_pcm_hw_rule_div(snd_pcm_hw_params_t *params, | ||
1632 | snd_pcm_hw_rule_t *rule) | ||
1633 | { | ||
1634 | snd_interval_t t; | ||
1635 | snd_interval_div(hw_param_interval_c(params, rule->deps[0]), | ||
1636 | hw_param_interval_c(params, rule->deps[1]), &t); | ||
1637 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1638 | } | ||
1639 | |||
1640 | static int snd_pcm_hw_rule_muldivk(snd_pcm_hw_params_t *params, | ||
1641 | snd_pcm_hw_rule_t *rule) | ||
1642 | { | ||
1643 | snd_interval_t t; | ||
1644 | snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]), | ||
1645 | hw_param_interval_c(params, rule->deps[1]), | ||
1646 | (unsigned long) rule->private, &t); | ||
1647 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1648 | } | ||
1649 | |||
1650 | static int snd_pcm_hw_rule_mulkdiv(snd_pcm_hw_params_t *params, | ||
1651 | snd_pcm_hw_rule_t *rule) | ||
1652 | { | ||
1653 | snd_interval_t t; | ||
1654 | snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]), | ||
1655 | (unsigned long) rule->private, | ||
1656 | hw_param_interval_c(params, rule->deps[1]), &t); | ||
1657 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1658 | } | ||
1659 | |||
1660 | static int snd_pcm_hw_rule_format(snd_pcm_hw_params_t *params, | ||
1661 | snd_pcm_hw_rule_t *rule) | ||
1662 | { | ||
1663 | unsigned int k; | ||
1664 | snd_interval_t *i = hw_param_interval(params, rule->deps[0]); | ||
1665 | snd_mask_t m; | ||
1666 | snd_mask_t *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
1667 | snd_mask_any(&m); | ||
1668 | for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { | ||
1669 | int bits; | ||
1670 | if (! snd_mask_test(mask, k)) | ||
1671 | continue; | ||
1672 | bits = snd_pcm_format_physical_width(k); | ||
1673 | if (bits <= 0) | ||
1674 | continue; /* ignore invalid formats */ | ||
1675 | if ((unsigned)bits < i->min || (unsigned)bits > i->max) | ||
1676 | snd_mask_reset(&m, k); | ||
1677 | } | ||
1678 | return snd_mask_refine(mask, &m); | ||
1679 | } | ||
1680 | |||
1681 | static int snd_pcm_hw_rule_sample_bits(snd_pcm_hw_params_t *params, | ||
1682 | snd_pcm_hw_rule_t *rule) | ||
1683 | { | ||
1684 | snd_interval_t t; | ||
1685 | unsigned int k; | ||
1686 | t.min = UINT_MAX; | ||
1687 | t.max = 0; | ||
1688 | t.openmin = 0; | ||
1689 | t.openmax = 0; | ||
1690 | for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) { | ||
1691 | int bits; | ||
1692 | if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) | ||
1693 | continue; | ||
1694 | bits = snd_pcm_format_physical_width(k); | ||
1695 | if (bits <= 0) | ||
1696 | continue; /* ignore invalid formats */ | ||
1697 | if (t.min > (unsigned)bits) | ||
1698 | t.min = bits; | ||
1699 | if (t.max < (unsigned)bits) | ||
1700 | t.max = bits; | ||
1701 | } | ||
1702 | t.integer = 1; | ||
1703 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1704 | } | ||
1705 | |||
1706 | #if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 | ||
1707 | #error "Change this table" | ||
1708 | #endif | ||
1709 | |||
1710 | static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, | ||
1711 | 48000, 64000, 88200, 96000, 176400, 192000 }; | ||
1712 | |||
1713 | static int snd_pcm_hw_rule_rate(snd_pcm_hw_params_t *params, | ||
1714 | snd_pcm_hw_rule_t *rule) | ||
1715 | { | ||
1716 | snd_pcm_hardware_t *hw = rule->private; | ||
1717 | return snd_interval_list(hw_param_interval(params, rule->var), | ||
1718 | ARRAY_SIZE(rates), rates, hw->rates); | ||
1719 | } | ||
1720 | |||
1721 | static int snd_pcm_hw_rule_buffer_bytes_max(snd_pcm_hw_params_t *params, | ||
1722 | snd_pcm_hw_rule_t *rule) | ||
1723 | { | ||
1724 | snd_interval_t t; | ||
1725 | snd_pcm_substream_t *substream = rule->private; | ||
1726 | t.min = 0; | ||
1727 | t.max = substream->buffer_bytes_max; | ||
1728 | t.openmin = 0; | ||
1729 | t.openmax = 0; | ||
1730 | t.integer = 1; | ||
1731 | return snd_interval_refine(hw_param_interval(params, rule->var), &t); | ||
1732 | } | ||
1733 | |||
1734 | int snd_pcm_hw_constraints_init(snd_pcm_substream_t *substream) | ||
1735 | { | ||
1736 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1737 | snd_pcm_hw_constraints_t *constrs = &runtime->hw_constraints; | ||
1738 | int k, err; | ||
1739 | |||
1740 | for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { | ||
1741 | snd_mask_any(constrs_mask(constrs, k)); | ||
1742 | } | ||
1743 | |||
1744 | for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { | ||
1745 | snd_interval_any(constrs_interval(constrs, k)); | ||
1746 | } | ||
1747 | |||
1748 | snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS)); | ||
1749 | snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE)); | ||
1750 | snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)); | ||
1751 | snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS)); | ||
1752 | snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS)); | ||
1753 | |||
1754 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
1755 | snd_pcm_hw_rule_format, NULL, | ||
1756 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | ||
1757 | if (err < 0) | ||
1758 | return err; | ||
1759 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1760 | snd_pcm_hw_rule_sample_bits, NULL, | ||
1761 | SNDRV_PCM_HW_PARAM_FORMAT, | ||
1762 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | ||
1763 | if (err < 0) | ||
1764 | return err; | ||
1765 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, | ||
1766 | snd_pcm_hw_rule_div, NULL, | ||
1767 | SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
1768 | if (err < 0) | ||
1769 | return err; | ||
1770 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, | ||
1771 | snd_pcm_hw_rule_mul, NULL, | ||
1772 | SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
1773 | if (err < 0) | ||
1774 | return err; | ||
1775 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, | ||
1776 | snd_pcm_hw_rule_mulkdiv, (void*) 8, | ||
1777 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); | ||
1778 | if (err < 0) | ||
1779 | return err; | ||
1780 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, | ||
1781 | snd_pcm_hw_rule_mulkdiv, (void*) 8, | ||
1782 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); | ||
1783 | if (err < 0) | ||
1784 | return err; | ||
1785 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1786 | snd_pcm_hw_rule_div, NULL, | ||
1787 | SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1); | ||
1788 | if (err < 0) | ||
1789 | return err; | ||
1790 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
1791 | snd_pcm_hw_rule_mulkdiv, (void*) 1000000, | ||
1792 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1); | ||
1793 | if (err < 0) | ||
1794 | return err; | ||
1795 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
1796 | snd_pcm_hw_rule_mulkdiv, (void*) 1000000, | ||
1797 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1); | ||
1798 | if (err < 0) | ||
1799 | return err; | ||
1800 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, | ||
1801 | snd_pcm_hw_rule_div, NULL, | ||
1802 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); | ||
1803 | if (err < 0) | ||
1804 | return err; | ||
1805 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
1806 | snd_pcm_hw_rule_div, NULL, | ||
1807 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); | ||
1808 | if (err < 0) | ||
1809 | return err; | ||
1810 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
1811 | snd_pcm_hw_rule_mulkdiv, (void*) 8, | ||
1812 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); | ||
1813 | if (err < 0) | ||
1814 | return err; | ||
1815 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
1816 | snd_pcm_hw_rule_muldivk, (void*) 1000000, | ||
1817 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1818 | if (err < 0) | ||
1819 | return err; | ||
1820 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1821 | snd_pcm_hw_rule_mul, NULL, | ||
1822 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1); | ||
1823 | if (err < 0) | ||
1824 | return err; | ||
1825 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1826 | snd_pcm_hw_rule_mulkdiv, (void*) 8, | ||
1827 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); | ||
1828 | if (err < 0) | ||
1829 | return err; | ||
1830 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
1831 | snd_pcm_hw_rule_muldivk, (void*) 1000000, | ||
1832 | SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1833 | if (err < 0) | ||
1834 | return err; | ||
1835 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
1836 | snd_pcm_hw_rule_muldivk, (void*) 8, | ||
1837 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); | ||
1838 | if (err < 0) | ||
1839 | return err; | ||
1840 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
1841 | snd_pcm_hw_rule_muldivk, (void*) 8, | ||
1842 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1); | ||
1843 | if (err < 0) | ||
1844 | return err; | ||
1845 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
1846 | snd_pcm_hw_rule_mulkdiv, (void*) 1000000, | ||
1847 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1848 | if (err < 0) | ||
1849 | return err; | ||
1850 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, | ||
1851 | snd_pcm_hw_rule_mulkdiv, (void*) 1000000, | ||
1852 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1853 | if (err < 0) | ||
1854 | return err; | ||
1855 | return 0; | ||
1856 | } | ||
1857 | |||
1858 | int snd_pcm_hw_constraints_complete(snd_pcm_substream_t *substream) | ||
1859 | { | ||
1860 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1861 | snd_pcm_hardware_t *hw = &runtime->hw; | ||
1862 | int err; | ||
1863 | unsigned int mask = 0; | ||
1864 | |||
1865 | if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) | ||
1866 | mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED; | ||
1867 | if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) | ||
1868 | mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED; | ||
1869 | if (hw->info & SNDRV_PCM_INFO_MMAP) { | ||
1870 | if (hw->info & SNDRV_PCM_INFO_INTERLEAVED) | ||
1871 | mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED; | ||
1872 | if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED) | ||
1873 | mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED; | ||
1874 | if (hw->info & SNDRV_PCM_INFO_COMPLEX) | ||
1875 | mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX; | ||
1876 | } | ||
1877 | err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask); | ||
1878 | snd_assert(err >= 0, return -EINVAL); | ||
1879 | |||
1880 | err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats); | ||
1881 | snd_assert(err >= 0, return -EINVAL); | ||
1882 | |||
1883 | err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD); | ||
1884 | snd_assert(err >= 0, return -EINVAL); | ||
1885 | |||
1886 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1887 | hw->channels_min, hw->channels_max); | ||
1888 | snd_assert(err >= 0, return -EINVAL); | ||
1889 | |||
1890 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, | ||
1891 | hw->rate_min, hw->rate_max); | ||
1892 | snd_assert(err >= 0, return -EINVAL); | ||
1893 | |||
1894 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, | ||
1895 | hw->period_bytes_min, hw->period_bytes_max); | ||
1896 | snd_assert(err >= 0, return -EINVAL); | ||
1897 | |||
1898 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS, | ||
1899 | hw->periods_min, hw->periods_max); | ||
1900 | snd_assert(err >= 0, return -EINVAL); | ||
1901 | |||
1902 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
1903 | hw->period_bytes_min, hw->buffer_bytes_max); | ||
1904 | snd_assert(err >= 0, return -EINVAL); | ||
1905 | |||
1906 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
1907 | snd_pcm_hw_rule_buffer_bytes_max, substream, | ||
1908 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1); | ||
1909 | if (err < 0) | ||
1910 | return err; | ||
1911 | |||
1912 | /* FIXME: remove */ | ||
1913 | if (runtime->dma_bytes) { | ||
1914 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes); | ||
1915 | snd_assert(err >= 0, return -EINVAL); | ||
1916 | } | ||
1917 | |||
1918 | if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) { | ||
1919 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
1920 | snd_pcm_hw_rule_rate, hw, | ||
1921 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
1922 | if (err < 0) | ||
1923 | return err; | ||
1924 | } | ||
1925 | |||
1926 | /* FIXME: this belong to lowlevel */ | ||
1927 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_TICK_TIME, | ||
1928 | 1000000 / HZ, 1000000 / HZ); | ||
1929 | snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
1930 | |||
1931 | return 0; | ||
1932 | } | ||
1933 | |||
1934 | static void snd_pcm_add_file(snd_pcm_str_t *str, | ||
1935 | snd_pcm_file_t *pcm_file) | ||
1936 | { | ||
1937 | pcm_file->next = str->files; | ||
1938 | str->files = pcm_file; | ||
1939 | } | ||
1940 | |||
1941 | static void snd_pcm_remove_file(snd_pcm_str_t *str, | ||
1942 | snd_pcm_file_t *pcm_file) | ||
1943 | { | ||
1944 | snd_pcm_file_t * pcm_file1; | ||
1945 | if (str->files == pcm_file) { | ||
1946 | str->files = pcm_file->next; | ||
1947 | } else { | ||
1948 | pcm_file1 = str->files; | ||
1949 | while (pcm_file1 && pcm_file1->next != pcm_file) | ||
1950 | pcm_file1 = pcm_file1->next; | ||
1951 | if (pcm_file1 != NULL) | ||
1952 | pcm_file1->next = pcm_file->next; | ||
1953 | } | ||
1954 | } | ||
1955 | |||
1956 | static int snd_pcm_release_file(snd_pcm_file_t * pcm_file) | ||
1957 | { | ||
1958 | snd_pcm_substream_t *substream; | ||
1959 | snd_pcm_runtime_t *runtime; | ||
1960 | snd_pcm_str_t * str; | ||
1961 | |||
1962 | snd_assert(pcm_file != NULL, return -ENXIO); | ||
1963 | substream = pcm_file->substream; | ||
1964 | snd_assert(substream != NULL, return -ENXIO); | ||
1965 | runtime = substream->runtime; | ||
1966 | str = substream->pstr; | ||
1967 | snd_pcm_unlink(substream); | ||
1968 | if (substream->open_flag) { | ||
1969 | if (substream->ops->hw_free != NULL) | ||
1970 | substream->ops->hw_free(substream); | ||
1971 | substream->ops->close(substream); | ||
1972 | substream->open_flag = 0; | ||
1973 | } | ||
1974 | substream->ffile = NULL; | ||
1975 | snd_pcm_remove_file(str, pcm_file); | ||
1976 | snd_pcm_release_substream(substream); | ||
1977 | kfree(pcm_file); | ||
1978 | return 0; | ||
1979 | } | ||
1980 | |||
1981 | static int snd_pcm_open_file(struct file *file, | ||
1982 | snd_pcm_t *pcm, | ||
1983 | int stream, | ||
1984 | snd_pcm_file_t **rpcm_file) | ||
1985 | { | ||
1986 | int err = 0; | ||
1987 | snd_pcm_file_t *pcm_file; | ||
1988 | snd_pcm_substream_t *substream; | ||
1989 | snd_pcm_str_t *str; | ||
1990 | |||
1991 | snd_assert(rpcm_file != NULL, return -EINVAL); | ||
1992 | *rpcm_file = NULL; | ||
1993 | |||
1994 | pcm_file = kcalloc(1, sizeof(*pcm_file), GFP_KERNEL); | ||
1995 | if (pcm_file == NULL) { | ||
1996 | return -ENOMEM; | ||
1997 | } | ||
1998 | |||
1999 | if ((err = snd_pcm_open_substream(pcm, stream, &substream)) < 0) { | ||
2000 | kfree(pcm_file); | ||
2001 | return err; | ||
2002 | } | ||
2003 | |||
2004 | str = substream->pstr; | ||
2005 | substream->file = pcm_file; | ||
2006 | substream->no_mmap_ctrl = 0; | ||
2007 | |||
2008 | pcm_file->substream = substream; | ||
2009 | |||
2010 | snd_pcm_add_file(str, pcm_file); | ||
2011 | |||
2012 | err = snd_pcm_hw_constraints_init(substream); | ||
2013 | if (err < 0) { | ||
2014 | snd_printd("snd_pcm_hw_constraints_init failed\n"); | ||
2015 | snd_pcm_release_file(pcm_file); | ||
2016 | return err; | ||
2017 | } | ||
2018 | |||
2019 | if ((err = substream->ops->open(substream)) < 0) { | ||
2020 | snd_pcm_release_file(pcm_file); | ||
2021 | return err; | ||
2022 | } | ||
2023 | substream->open_flag = 1; | ||
2024 | |||
2025 | err = snd_pcm_hw_constraints_complete(substream); | ||
2026 | if (err < 0) { | ||
2027 | snd_printd("snd_pcm_hw_constraints_complete failed\n"); | ||
2028 | substream->ops->close(substream); | ||
2029 | snd_pcm_release_file(pcm_file); | ||
2030 | return err; | ||
2031 | } | ||
2032 | |||
2033 | substream->ffile = file; | ||
2034 | |||
2035 | file->private_data = pcm_file; | ||
2036 | *rpcm_file = pcm_file; | ||
2037 | return 0; | ||
2038 | } | ||
2039 | |||
2040 | static int snd_pcm_open(struct inode *inode, struct file *file) | ||
2041 | { | ||
2042 | int cardnum = SNDRV_MINOR_CARD(iminor(inode)); | ||
2043 | int device = SNDRV_MINOR_DEVICE(iminor(inode)); | ||
2044 | int err; | ||
2045 | snd_pcm_t *pcm; | ||
2046 | snd_pcm_file_t *pcm_file; | ||
2047 | wait_queue_t wait; | ||
2048 | |||
2049 | snd_runtime_check(device >= SNDRV_MINOR_PCM_PLAYBACK && device < SNDRV_MINOR_DEVICES, return -ENXIO); | ||
2050 | pcm = snd_pcm_devices[(cardnum * SNDRV_PCM_DEVICES) + (device % SNDRV_MINOR_PCMS)]; | ||
2051 | if (pcm == NULL) { | ||
2052 | err = -ENODEV; | ||
2053 | goto __error1; | ||
2054 | } | ||
2055 | err = snd_card_file_add(pcm->card, file); | ||
2056 | if (err < 0) | ||
2057 | goto __error1; | ||
2058 | if (!try_module_get(pcm->card->module)) { | ||
2059 | err = -EFAULT; | ||
2060 | goto __error2; | ||
2061 | } | ||
2062 | init_waitqueue_entry(&wait, current); | ||
2063 | add_wait_queue(&pcm->open_wait, &wait); | ||
2064 | down(&pcm->open_mutex); | ||
2065 | while (1) { | ||
2066 | err = snd_pcm_open_file(file, pcm, device >= SNDRV_MINOR_PCM_CAPTURE ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK, &pcm_file); | ||
2067 | if (err >= 0) | ||
2068 | break; | ||
2069 | if (err == -EAGAIN) { | ||
2070 | if (file->f_flags & O_NONBLOCK) { | ||
2071 | err = -EBUSY; | ||
2072 | break; | ||
2073 | } | ||
2074 | } else | ||
2075 | break; | ||
2076 | set_current_state(TASK_INTERRUPTIBLE); | ||
2077 | up(&pcm->open_mutex); | ||
2078 | schedule(); | ||
2079 | down(&pcm->open_mutex); | ||
2080 | if (signal_pending(current)) { | ||
2081 | err = -ERESTARTSYS; | ||
2082 | break; | ||
2083 | } | ||
2084 | } | ||
2085 | remove_wait_queue(&pcm->open_wait, &wait); | ||
2086 | up(&pcm->open_mutex); | ||
2087 | if (err < 0) | ||
2088 | goto __error; | ||
2089 | return err; | ||
2090 | |||
2091 | __error: | ||
2092 | module_put(pcm->card->module); | ||
2093 | __error2: | ||
2094 | snd_card_file_remove(pcm->card, file); | ||
2095 | __error1: | ||
2096 | return err; | ||
2097 | } | ||
2098 | |||
2099 | static int snd_pcm_release(struct inode *inode, struct file *file) | ||
2100 | { | ||
2101 | snd_pcm_t *pcm; | ||
2102 | snd_pcm_substream_t *substream; | ||
2103 | snd_pcm_file_t *pcm_file; | ||
2104 | |||
2105 | pcm_file = file->private_data; | ||
2106 | substream = pcm_file->substream; | ||
2107 | snd_assert(substream != NULL, return -ENXIO); | ||
2108 | snd_assert(!atomic_read(&substream->runtime->mmap_count), ); | ||
2109 | pcm = substream->pcm; | ||
2110 | snd_pcm_drop(substream); | ||
2111 | fasync_helper(-1, file, 0, &substream->runtime->fasync); | ||
2112 | down(&pcm->open_mutex); | ||
2113 | snd_pcm_release_file(pcm_file); | ||
2114 | up(&pcm->open_mutex); | ||
2115 | wake_up(&pcm->open_wait); | ||
2116 | module_put(pcm->card->module); | ||
2117 | snd_card_file_remove(pcm->card, file); | ||
2118 | return 0; | ||
2119 | } | ||
2120 | |||
2121 | static snd_pcm_sframes_t snd_pcm_playback_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames) | ||
2122 | { | ||
2123 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2124 | snd_pcm_sframes_t appl_ptr; | ||
2125 | snd_pcm_sframes_t ret; | ||
2126 | snd_pcm_sframes_t hw_avail; | ||
2127 | |||
2128 | if (frames == 0) | ||
2129 | return 0; | ||
2130 | |||
2131 | snd_pcm_stream_lock_irq(substream); | ||
2132 | switch (runtime->status->state) { | ||
2133 | case SNDRV_PCM_STATE_PREPARED: | ||
2134 | break; | ||
2135 | case SNDRV_PCM_STATE_DRAINING: | ||
2136 | case SNDRV_PCM_STATE_RUNNING: | ||
2137 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2138 | break; | ||
2139 | /* Fall through */ | ||
2140 | case SNDRV_PCM_STATE_XRUN: | ||
2141 | ret = -EPIPE; | ||
2142 | goto __end; | ||
2143 | default: | ||
2144 | ret = -EBADFD; | ||
2145 | goto __end; | ||
2146 | } | ||
2147 | |||
2148 | hw_avail = snd_pcm_playback_hw_avail(runtime); | ||
2149 | if (hw_avail <= 0) { | ||
2150 | ret = 0; | ||
2151 | goto __end; | ||
2152 | } | ||
2153 | if (frames > (snd_pcm_uframes_t)hw_avail) | ||
2154 | frames = hw_avail; | ||
2155 | else | ||
2156 | frames -= frames % runtime->xfer_align; | ||
2157 | appl_ptr = runtime->control->appl_ptr - frames; | ||
2158 | if (appl_ptr < 0) | ||
2159 | appl_ptr += runtime->boundary; | ||
2160 | runtime->control->appl_ptr = appl_ptr; | ||
2161 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2162 | runtime->sleep_min) | ||
2163 | snd_pcm_tick_prepare(substream); | ||
2164 | ret = frames; | ||
2165 | __end: | ||
2166 | snd_pcm_stream_unlock_irq(substream); | ||
2167 | return ret; | ||
2168 | } | ||
2169 | |||
2170 | static snd_pcm_sframes_t snd_pcm_capture_rewind(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames) | ||
2171 | { | ||
2172 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2173 | snd_pcm_sframes_t appl_ptr; | ||
2174 | snd_pcm_sframes_t ret; | ||
2175 | snd_pcm_sframes_t hw_avail; | ||
2176 | |||
2177 | if (frames == 0) | ||
2178 | return 0; | ||
2179 | |||
2180 | snd_pcm_stream_lock_irq(substream); | ||
2181 | switch (runtime->status->state) { | ||
2182 | case SNDRV_PCM_STATE_PREPARED: | ||
2183 | case SNDRV_PCM_STATE_DRAINING: | ||
2184 | break; | ||
2185 | case SNDRV_PCM_STATE_RUNNING: | ||
2186 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2187 | break; | ||
2188 | /* Fall through */ | ||
2189 | case SNDRV_PCM_STATE_XRUN: | ||
2190 | ret = -EPIPE; | ||
2191 | goto __end; | ||
2192 | default: | ||
2193 | ret = -EBADFD; | ||
2194 | goto __end; | ||
2195 | } | ||
2196 | |||
2197 | hw_avail = snd_pcm_capture_hw_avail(runtime); | ||
2198 | if (hw_avail <= 0) { | ||
2199 | ret = 0; | ||
2200 | goto __end; | ||
2201 | } | ||
2202 | if (frames > (snd_pcm_uframes_t)hw_avail) | ||
2203 | frames = hw_avail; | ||
2204 | else | ||
2205 | frames -= frames % runtime->xfer_align; | ||
2206 | appl_ptr = runtime->control->appl_ptr - frames; | ||
2207 | if (appl_ptr < 0) | ||
2208 | appl_ptr += runtime->boundary; | ||
2209 | runtime->control->appl_ptr = appl_ptr; | ||
2210 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2211 | runtime->sleep_min) | ||
2212 | snd_pcm_tick_prepare(substream); | ||
2213 | ret = frames; | ||
2214 | __end: | ||
2215 | snd_pcm_stream_unlock_irq(substream); | ||
2216 | return ret; | ||
2217 | } | ||
2218 | |||
2219 | static snd_pcm_sframes_t snd_pcm_playback_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames) | ||
2220 | { | ||
2221 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2222 | snd_pcm_sframes_t appl_ptr; | ||
2223 | snd_pcm_sframes_t ret; | ||
2224 | snd_pcm_sframes_t avail; | ||
2225 | |||
2226 | if (frames == 0) | ||
2227 | return 0; | ||
2228 | |||
2229 | snd_pcm_stream_lock_irq(substream); | ||
2230 | switch (runtime->status->state) { | ||
2231 | case SNDRV_PCM_STATE_PREPARED: | ||
2232 | case SNDRV_PCM_STATE_PAUSED: | ||
2233 | break; | ||
2234 | case SNDRV_PCM_STATE_DRAINING: | ||
2235 | case SNDRV_PCM_STATE_RUNNING: | ||
2236 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2237 | break; | ||
2238 | /* Fall through */ | ||
2239 | case SNDRV_PCM_STATE_XRUN: | ||
2240 | ret = -EPIPE; | ||
2241 | goto __end; | ||
2242 | default: | ||
2243 | ret = -EBADFD; | ||
2244 | goto __end; | ||
2245 | } | ||
2246 | |||
2247 | avail = snd_pcm_playback_avail(runtime); | ||
2248 | if (avail <= 0) { | ||
2249 | ret = 0; | ||
2250 | goto __end; | ||
2251 | } | ||
2252 | if (frames > (snd_pcm_uframes_t)avail) | ||
2253 | frames = avail; | ||
2254 | else | ||
2255 | frames -= frames % runtime->xfer_align; | ||
2256 | appl_ptr = runtime->control->appl_ptr + frames; | ||
2257 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | ||
2258 | appl_ptr -= runtime->boundary; | ||
2259 | runtime->control->appl_ptr = appl_ptr; | ||
2260 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2261 | runtime->sleep_min) | ||
2262 | snd_pcm_tick_prepare(substream); | ||
2263 | ret = frames; | ||
2264 | __end: | ||
2265 | snd_pcm_stream_unlock_irq(substream); | ||
2266 | return ret; | ||
2267 | } | ||
2268 | |||
2269 | static snd_pcm_sframes_t snd_pcm_capture_forward(snd_pcm_substream_t *substream, snd_pcm_uframes_t frames) | ||
2270 | { | ||
2271 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2272 | snd_pcm_sframes_t appl_ptr; | ||
2273 | snd_pcm_sframes_t ret; | ||
2274 | snd_pcm_sframes_t avail; | ||
2275 | |||
2276 | if (frames == 0) | ||
2277 | return 0; | ||
2278 | |||
2279 | snd_pcm_stream_lock_irq(substream); | ||
2280 | switch (runtime->status->state) { | ||
2281 | case SNDRV_PCM_STATE_PREPARED: | ||
2282 | case SNDRV_PCM_STATE_DRAINING: | ||
2283 | case SNDRV_PCM_STATE_PAUSED: | ||
2284 | break; | ||
2285 | case SNDRV_PCM_STATE_RUNNING: | ||
2286 | if (snd_pcm_update_hw_ptr(substream) >= 0) | ||
2287 | break; | ||
2288 | /* Fall through */ | ||
2289 | case SNDRV_PCM_STATE_XRUN: | ||
2290 | ret = -EPIPE; | ||
2291 | goto __end; | ||
2292 | default: | ||
2293 | ret = -EBADFD; | ||
2294 | goto __end; | ||
2295 | } | ||
2296 | |||
2297 | avail = snd_pcm_capture_avail(runtime); | ||
2298 | if (avail <= 0) { | ||
2299 | ret = 0; | ||
2300 | goto __end; | ||
2301 | } | ||
2302 | if (frames > (snd_pcm_uframes_t)avail) | ||
2303 | frames = avail; | ||
2304 | else | ||
2305 | frames -= frames % runtime->xfer_align; | ||
2306 | appl_ptr = runtime->control->appl_ptr + frames; | ||
2307 | if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary) | ||
2308 | appl_ptr -= runtime->boundary; | ||
2309 | runtime->control->appl_ptr = appl_ptr; | ||
2310 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING && | ||
2311 | runtime->sleep_min) | ||
2312 | snd_pcm_tick_prepare(substream); | ||
2313 | ret = frames; | ||
2314 | __end: | ||
2315 | snd_pcm_stream_unlock_irq(substream); | ||
2316 | return ret; | ||
2317 | } | ||
2318 | |||
2319 | static int snd_pcm_hwsync(snd_pcm_substream_t *substream) | ||
2320 | { | ||
2321 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2322 | int err; | ||
2323 | |||
2324 | snd_pcm_stream_lock_irq(substream); | ||
2325 | switch (runtime->status->state) { | ||
2326 | case SNDRV_PCM_STATE_DRAINING: | ||
2327 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
2328 | goto __badfd; | ||
2329 | case SNDRV_PCM_STATE_RUNNING: | ||
2330 | if ((err = snd_pcm_update_hw_ptr(substream)) < 0) | ||
2331 | break; | ||
2332 | /* Fall through */ | ||
2333 | case SNDRV_PCM_STATE_PREPARED: | ||
2334 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2335 | err = 0; | ||
2336 | break; | ||
2337 | case SNDRV_PCM_STATE_XRUN: | ||
2338 | err = -EPIPE; | ||
2339 | break; | ||
2340 | default: | ||
2341 | __badfd: | ||
2342 | err = -EBADFD; | ||
2343 | break; | ||
2344 | } | ||
2345 | snd_pcm_stream_unlock_irq(substream); | ||
2346 | return err; | ||
2347 | } | ||
2348 | |||
2349 | static int snd_pcm_delay(snd_pcm_substream_t *substream, snd_pcm_sframes_t __user *res) | ||
2350 | { | ||
2351 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2352 | int err; | ||
2353 | snd_pcm_sframes_t n = 0; | ||
2354 | |||
2355 | snd_pcm_stream_lock_irq(substream); | ||
2356 | switch (runtime->status->state) { | ||
2357 | case SNDRV_PCM_STATE_DRAINING: | ||
2358 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
2359 | goto __badfd; | ||
2360 | case SNDRV_PCM_STATE_RUNNING: | ||
2361 | if ((err = snd_pcm_update_hw_ptr(substream)) < 0) | ||
2362 | break; | ||
2363 | /* Fall through */ | ||
2364 | case SNDRV_PCM_STATE_PREPARED: | ||
2365 | case SNDRV_PCM_STATE_SUSPENDED: | ||
2366 | err = 0; | ||
2367 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
2368 | n = snd_pcm_playback_hw_avail(runtime); | ||
2369 | else | ||
2370 | n = snd_pcm_capture_avail(runtime); | ||
2371 | break; | ||
2372 | case SNDRV_PCM_STATE_XRUN: | ||
2373 | err = -EPIPE; | ||
2374 | break; | ||
2375 | default: | ||
2376 | __badfd: | ||
2377 | err = -EBADFD; | ||
2378 | break; | ||
2379 | } | ||
2380 | snd_pcm_stream_unlock_irq(substream); | ||
2381 | if (!err) | ||
2382 | if (put_user(n, res)) | ||
2383 | err = -EFAULT; | ||
2384 | return err; | ||
2385 | } | ||
2386 | |||
2387 | static int snd_pcm_sync_ptr(snd_pcm_substream_t *substream, struct sndrv_pcm_sync_ptr __user *_sync_ptr) | ||
2388 | { | ||
2389 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2390 | struct sndrv_pcm_sync_ptr sync_ptr; | ||
2391 | volatile struct sndrv_pcm_mmap_status *status; | ||
2392 | volatile struct sndrv_pcm_mmap_control *control; | ||
2393 | int err; | ||
2394 | |||
2395 | memset(&sync_ptr, 0, sizeof(sync_ptr)); | ||
2396 | if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags))) | ||
2397 | return -EFAULT; | ||
2398 | if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct sndrv_pcm_mmap_control))) | ||
2399 | return -EFAULT; | ||
2400 | status = runtime->status; | ||
2401 | control = runtime->control; | ||
2402 | if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) { | ||
2403 | err = snd_pcm_hwsync(substream); | ||
2404 | if (err < 0) | ||
2405 | return err; | ||
2406 | } | ||
2407 | snd_pcm_stream_lock_irq(substream); | ||
2408 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) | ||
2409 | control->appl_ptr = sync_ptr.c.control.appl_ptr; | ||
2410 | else | ||
2411 | sync_ptr.c.control.appl_ptr = control->appl_ptr; | ||
2412 | if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) | ||
2413 | control->avail_min = sync_ptr.c.control.avail_min; | ||
2414 | else | ||
2415 | sync_ptr.c.control.avail_min = control->avail_min; | ||
2416 | sync_ptr.s.status.state = status->state; | ||
2417 | sync_ptr.s.status.hw_ptr = status->hw_ptr; | ||
2418 | sync_ptr.s.status.tstamp = status->tstamp; | ||
2419 | sync_ptr.s.status.suspended_state = status->suspended_state; | ||
2420 | snd_pcm_stream_unlock_irq(substream); | ||
2421 | if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr))) | ||
2422 | return -EFAULT; | ||
2423 | return 0; | ||
2424 | } | ||
2425 | |||
2426 | static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, | ||
2427 | unsigned int cmd, void __user *arg); | ||
2428 | static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, | ||
2429 | unsigned int cmd, void __user *arg); | ||
2430 | |||
2431 | static int snd_pcm_common_ioctl1(snd_pcm_substream_t *substream, | ||
2432 | unsigned int cmd, void __user *arg) | ||
2433 | { | ||
2434 | snd_assert(substream != NULL, return -ENXIO); | ||
2435 | |||
2436 | switch (cmd) { | ||
2437 | case SNDRV_PCM_IOCTL_PVERSION: | ||
2438 | return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; | ||
2439 | case SNDRV_PCM_IOCTL_INFO: | ||
2440 | return snd_pcm_info_user(substream, arg); | ||
2441 | case SNDRV_PCM_IOCTL_TSTAMP: | ||
2442 | { | ||
2443 | int xarg; | ||
2444 | if (get_user(xarg, (int __user *)arg)) | ||
2445 | return -EFAULT; | ||
2446 | substream->runtime->tstamp_timespec = xarg ? 1 : 0; | ||
2447 | return 0; | ||
2448 | } | ||
2449 | case SNDRV_PCM_IOCTL_HW_REFINE: | ||
2450 | return snd_pcm_hw_refine_user(substream, arg); | ||
2451 | case SNDRV_PCM_IOCTL_HW_PARAMS: | ||
2452 | return snd_pcm_hw_params_user(substream, arg); | ||
2453 | case SNDRV_PCM_IOCTL_HW_FREE: | ||
2454 | return snd_pcm_hw_free(substream); | ||
2455 | case SNDRV_PCM_IOCTL_SW_PARAMS: | ||
2456 | return snd_pcm_sw_params_user(substream, arg); | ||
2457 | case SNDRV_PCM_IOCTL_STATUS: | ||
2458 | return snd_pcm_status_user(substream, arg); | ||
2459 | case SNDRV_PCM_IOCTL_CHANNEL_INFO: | ||
2460 | return snd_pcm_channel_info_user(substream, arg); | ||
2461 | case SNDRV_PCM_IOCTL_PREPARE: | ||
2462 | return snd_pcm_prepare(substream); | ||
2463 | case SNDRV_PCM_IOCTL_RESET: | ||
2464 | return snd_pcm_reset(substream); | ||
2465 | case SNDRV_PCM_IOCTL_START: | ||
2466 | return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); | ||
2467 | case SNDRV_PCM_IOCTL_LINK: | ||
2468 | return snd_pcm_link(substream, (int)(unsigned long) arg); | ||
2469 | case SNDRV_PCM_IOCTL_UNLINK: | ||
2470 | return snd_pcm_unlink(substream); | ||
2471 | case SNDRV_PCM_IOCTL_RESUME: | ||
2472 | return snd_pcm_resume(substream); | ||
2473 | case SNDRV_PCM_IOCTL_XRUN: | ||
2474 | return snd_pcm_xrun(substream); | ||
2475 | case SNDRV_PCM_IOCTL_HWSYNC: | ||
2476 | return snd_pcm_hwsync(substream); | ||
2477 | case SNDRV_PCM_IOCTL_DELAY: | ||
2478 | return snd_pcm_delay(substream, arg); | ||
2479 | case SNDRV_PCM_IOCTL_SYNC_PTR: | ||
2480 | return snd_pcm_sync_ptr(substream, arg); | ||
2481 | case SNDRV_PCM_IOCTL_HW_REFINE_OLD: | ||
2482 | return snd_pcm_hw_refine_old_user(substream, arg); | ||
2483 | case SNDRV_PCM_IOCTL_HW_PARAMS_OLD: | ||
2484 | return snd_pcm_hw_params_old_user(substream, arg); | ||
2485 | case SNDRV_PCM_IOCTL_DRAIN: | ||
2486 | return snd_pcm_drain(substream); | ||
2487 | case SNDRV_PCM_IOCTL_DROP: | ||
2488 | return snd_pcm_drop(substream); | ||
2489 | } | ||
2490 | snd_printd("unknown ioctl = 0x%x\n", cmd); | ||
2491 | return -ENOTTY; | ||
2492 | } | ||
2493 | |||
2494 | static int snd_pcm_playback_ioctl1(snd_pcm_substream_t *substream, | ||
2495 | unsigned int cmd, void __user *arg) | ||
2496 | { | ||
2497 | snd_assert(substream != NULL, return -ENXIO); | ||
2498 | snd_assert(substream->stream == SNDRV_PCM_STREAM_PLAYBACK, return -EINVAL); | ||
2499 | switch (cmd) { | ||
2500 | case SNDRV_PCM_IOCTL_WRITEI_FRAMES: | ||
2501 | { | ||
2502 | snd_xferi_t xferi; | ||
2503 | snd_xferi_t __user *_xferi = arg; | ||
2504 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2505 | snd_pcm_sframes_t result; | ||
2506 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2507 | return -EBADFD; | ||
2508 | if (put_user(0, &_xferi->result)) | ||
2509 | return -EFAULT; | ||
2510 | if (copy_from_user(&xferi, _xferi, sizeof(xferi))) | ||
2511 | return -EFAULT; | ||
2512 | result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames); | ||
2513 | __put_user(result, &_xferi->result); | ||
2514 | return result < 0 ? result : 0; | ||
2515 | } | ||
2516 | case SNDRV_PCM_IOCTL_WRITEN_FRAMES: | ||
2517 | { | ||
2518 | snd_xfern_t xfern; | ||
2519 | snd_xfern_t __user *_xfern = arg; | ||
2520 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2521 | void __user **bufs; | ||
2522 | snd_pcm_sframes_t result; | ||
2523 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2524 | return -EBADFD; | ||
2525 | if (runtime->channels > 128) | ||
2526 | return -EINVAL; | ||
2527 | if (put_user(0, &_xfern->result)) | ||
2528 | return -EFAULT; | ||
2529 | if (copy_from_user(&xfern, _xfern, sizeof(xfern))) | ||
2530 | return -EFAULT; | ||
2531 | bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); | ||
2532 | if (bufs == NULL) | ||
2533 | return -ENOMEM; | ||
2534 | if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { | ||
2535 | kfree(bufs); | ||
2536 | return -EFAULT; | ||
2537 | } | ||
2538 | result = snd_pcm_lib_writev(substream, bufs, xfern.frames); | ||
2539 | kfree(bufs); | ||
2540 | __put_user(result, &_xfern->result); | ||
2541 | return result < 0 ? result : 0; | ||
2542 | } | ||
2543 | case SNDRV_PCM_IOCTL_REWIND: | ||
2544 | { | ||
2545 | snd_pcm_uframes_t frames; | ||
2546 | snd_pcm_uframes_t __user *_frames = arg; | ||
2547 | snd_pcm_sframes_t result; | ||
2548 | if (get_user(frames, _frames)) | ||
2549 | return -EFAULT; | ||
2550 | if (put_user(0, _frames)) | ||
2551 | return -EFAULT; | ||
2552 | result = snd_pcm_playback_rewind(substream, frames); | ||
2553 | __put_user(result, _frames); | ||
2554 | return result < 0 ? result : 0; | ||
2555 | } | ||
2556 | case SNDRV_PCM_IOCTL_FORWARD: | ||
2557 | { | ||
2558 | snd_pcm_uframes_t frames; | ||
2559 | snd_pcm_uframes_t __user *_frames = arg; | ||
2560 | snd_pcm_sframes_t result; | ||
2561 | if (get_user(frames, _frames)) | ||
2562 | return -EFAULT; | ||
2563 | if (put_user(0, _frames)) | ||
2564 | return -EFAULT; | ||
2565 | result = snd_pcm_playback_forward(substream, frames); | ||
2566 | __put_user(result, _frames); | ||
2567 | return result < 0 ? result : 0; | ||
2568 | } | ||
2569 | case SNDRV_PCM_IOCTL_PAUSE: | ||
2570 | { | ||
2571 | int res; | ||
2572 | snd_pcm_stream_lock_irq(substream); | ||
2573 | res = snd_pcm_pause(substream, (int)(unsigned long)arg); | ||
2574 | snd_pcm_stream_unlock_irq(substream); | ||
2575 | return res; | ||
2576 | } | ||
2577 | } | ||
2578 | return snd_pcm_common_ioctl1(substream, cmd, arg); | ||
2579 | } | ||
2580 | |||
2581 | static int snd_pcm_capture_ioctl1(snd_pcm_substream_t *substream, | ||
2582 | unsigned int cmd, void __user *arg) | ||
2583 | { | ||
2584 | snd_assert(substream != NULL, return -ENXIO); | ||
2585 | snd_assert(substream->stream == SNDRV_PCM_STREAM_CAPTURE, return -EINVAL); | ||
2586 | switch (cmd) { | ||
2587 | case SNDRV_PCM_IOCTL_READI_FRAMES: | ||
2588 | { | ||
2589 | snd_xferi_t xferi; | ||
2590 | snd_xferi_t __user *_xferi = arg; | ||
2591 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2592 | snd_pcm_sframes_t result; | ||
2593 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2594 | return -EBADFD; | ||
2595 | if (put_user(0, &_xferi->result)) | ||
2596 | return -EFAULT; | ||
2597 | if (copy_from_user(&xferi, _xferi, sizeof(xferi))) | ||
2598 | return -EFAULT; | ||
2599 | result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames); | ||
2600 | __put_user(result, &_xferi->result); | ||
2601 | return result < 0 ? result : 0; | ||
2602 | } | ||
2603 | case SNDRV_PCM_IOCTL_READN_FRAMES: | ||
2604 | { | ||
2605 | snd_xfern_t xfern; | ||
2606 | snd_xfern_t __user *_xfern = arg; | ||
2607 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
2608 | void *bufs; | ||
2609 | snd_pcm_sframes_t result; | ||
2610 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2611 | return -EBADFD; | ||
2612 | if (runtime->channels > 128) | ||
2613 | return -EINVAL; | ||
2614 | if (put_user(0, &_xfern->result)) | ||
2615 | return -EFAULT; | ||
2616 | if (copy_from_user(&xfern, _xfern, sizeof(xfern))) | ||
2617 | return -EFAULT; | ||
2618 | bufs = kmalloc(sizeof(void *) * runtime->channels, GFP_KERNEL); | ||
2619 | if (bufs == NULL) | ||
2620 | return -ENOMEM; | ||
2621 | if (copy_from_user(bufs, xfern.bufs, sizeof(void *) * runtime->channels)) { | ||
2622 | kfree(bufs); | ||
2623 | return -EFAULT; | ||
2624 | } | ||
2625 | result = snd_pcm_lib_readv(substream, bufs, xfern.frames); | ||
2626 | kfree(bufs); | ||
2627 | __put_user(result, &_xfern->result); | ||
2628 | return result < 0 ? result : 0; | ||
2629 | } | ||
2630 | case SNDRV_PCM_IOCTL_REWIND: | ||
2631 | { | ||
2632 | snd_pcm_uframes_t frames; | ||
2633 | snd_pcm_uframes_t __user *_frames = arg; | ||
2634 | snd_pcm_sframes_t result; | ||
2635 | if (get_user(frames, _frames)) | ||
2636 | return -EFAULT; | ||
2637 | if (put_user(0, _frames)) | ||
2638 | return -EFAULT; | ||
2639 | result = snd_pcm_capture_rewind(substream, frames); | ||
2640 | __put_user(result, _frames); | ||
2641 | return result < 0 ? result : 0; | ||
2642 | } | ||
2643 | case SNDRV_PCM_IOCTL_FORWARD: | ||
2644 | { | ||
2645 | snd_pcm_uframes_t frames; | ||
2646 | snd_pcm_uframes_t __user *_frames = arg; | ||
2647 | snd_pcm_sframes_t result; | ||
2648 | if (get_user(frames, _frames)) | ||
2649 | return -EFAULT; | ||
2650 | if (put_user(0, _frames)) | ||
2651 | return -EFAULT; | ||
2652 | result = snd_pcm_capture_forward(substream, frames); | ||
2653 | __put_user(result, _frames); | ||
2654 | return result < 0 ? result : 0; | ||
2655 | } | ||
2656 | } | ||
2657 | return snd_pcm_common_ioctl1(substream, cmd, arg); | ||
2658 | } | ||
2659 | |||
2660 | static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
2661 | { | ||
2662 | snd_pcm_file_t *pcm_file; | ||
2663 | |||
2664 | pcm_file = file->private_data; | ||
2665 | |||
2666 | if (((cmd >> 8) & 0xff) != 'A') | ||
2667 | return -ENOTTY; | ||
2668 | |||
2669 | return snd_pcm_playback_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | ||
2670 | } | ||
2671 | |||
2672 | static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
2673 | { | ||
2674 | snd_pcm_file_t *pcm_file; | ||
2675 | |||
2676 | pcm_file = file->private_data; | ||
2677 | |||
2678 | if (((cmd >> 8) & 0xff) != 'A') | ||
2679 | return -ENOTTY; | ||
2680 | |||
2681 | return snd_pcm_capture_ioctl1(pcm_file->substream, cmd, (void __user *)arg); | ||
2682 | } | ||
2683 | |||
2684 | int snd_pcm_kernel_playback_ioctl(snd_pcm_substream_t *substream, | ||
2685 | unsigned int cmd, void *arg) | ||
2686 | { | ||
2687 | mm_segment_t fs; | ||
2688 | int result; | ||
2689 | |||
2690 | fs = snd_enter_user(); | ||
2691 | result = snd_pcm_playback_ioctl1(substream, cmd, (void __user *)arg); | ||
2692 | snd_leave_user(fs); | ||
2693 | return result; | ||
2694 | } | ||
2695 | |||
2696 | int snd_pcm_kernel_capture_ioctl(snd_pcm_substream_t *substream, | ||
2697 | unsigned int cmd, void *arg) | ||
2698 | { | ||
2699 | mm_segment_t fs; | ||
2700 | int result; | ||
2701 | |||
2702 | fs = snd_enter_user(); | ||
2703 | result = snd_pcm_capture_ioctl1(substream, cmd, (void __user *)arg); | ||
2704 | snd_leave_user(fs); | ||
2705 | return result; | ||
2706 | } | ||
2707 | |||
2708 | int snd_pcm_kernel_ioctl(snd_pcm_substream_t *substream, | ||
2709 | unsigned int cmd, void *arg) | ||
2710 | { | ||
2711 | switch (substream->stream) { | ||
2712 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
2713 | return snd_pcm_kernel_playback_ioctl(substream, cmd, arg); | ||
2714 | case SNDRV_PCM_STREAM_CAPTURE: | ||
2715 | return snd_pcm_kernel_capture_ioctl(substream, cmd, arg); | ||
2716 | default: | ||
2717 | return -EINVAL; | ||
2718 | } | ||
2719 | } | ||
2720 | |||
2721 | static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, loff_t * offset) | ||
2722 | { | ||
2723 | snd_pcm_file_t *pcm_file; | ||
2724 | snd_pcm_substream_t *substream; | ||
2725 | snd_pcm_runtime_t *runtime; | ||
2726 | snd_pcm_sframes_t result; | ||
2727 | |||
2728 | pcm_file = file->private_data; | ||
2729 | substream = pcm_file->substream; | ||
2730 | snd_assert(substream != NULL, return -ENXIO); | ||
2731 | runtime = substream->runtime; | ||
2732 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2733 | return -EBADFD; | ||
2734 | if (!frame_aligned(runtime, count)) | ||
2735 | return -EINVAL; | ||
2736 | count = bytes_to_frames(runtime, count); | ||
2737 | result = snd_pcm_lib_read(substream, buf, count); | ||
2738 | if (result > 0) | ||
2739 | result = frames_to_bytes(runtime, result); | ||
2740 | return result; | ||
2741 | } | ||
2742 | |||
2743 | static ssize_t snd_pcm_write(struct file *file, const char __user *buf, size_t count, loff_t * offset) | ||
2744 | { | ||
2745 | snd_pcm_file_t *pcm_file; | ||
2746 | snd_pcm_substream_t *substream; | ||
2747 | snd_pcm_runtime_t *runtime; | ||
2748 | snd_pcm_sframes_t result; | ||
2749 | |||
2750 | pcm_file = file->private_data; | ||
2751 | substream = pcm_file->substream; | ||
2752 | snd_assert(substream != NULL, result = -ENXIO; goto end); | ||
2753 | runtime = substream->runtime; | ||
2754 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
2755 | result = -EBADFD; | ||
2756 | goto end; | ||
2757 | } | ||
2758 | if (!frame_aligned(runtime, count)) { | ||
2759 | result = -EINVAL; | ||
2760 | goto end; | ||
2761 | } | ||
2762 | count = bytes_to_frames(runtime, count); | ||
2763 | result = snd_pcm_lib_write(substream, buf, count); | ||
2764 | if (result > 0) | ||
2765 | result = frames_to_bytes(runtime, result); | ||
2766 | end: | ||
2767 | return result; | ||
2768 | } | ||
2769 | |||
2770 | static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, | ||
2771 | unsigned long count, loff_t * offset) | ||
2772 | |||
2773 | { | ||
2774 | snd_pcm_file_t *pcm_file; | ||
2775 | snd_pcm_substream_t *substream; | ||
2776 | snd_pcm_runtime_t *runtime; | ||
2777 | snd_pcm_sframes_t result; | ||
2778 | unsigned long i; | ||
2779 | void __user **bufs; | ||
2780 | snd_pcm_uframes_t frames; | ||
2781 | |||
2782 | pcm_file = file->private_data; | ||
2783 | substream = pcm_file->substream; | ||
2784 | snd_assert(substream != NULL, return -ENXIO); | ||
2785 | runtime = substream->runtime; | ||
2786 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
2787 | return -EBADFD; | ||
2788 | if (count > 1024 || count != runtime->channels) | ||
2789 | return -EINVAL; | ||
2790 | if (!frame_aligned(runtime, _vector->iov_len)) | ||
2791 | return -EINVAL; | ||
2792 | frames = bytes_to_samples(runtime, _vector->iov_len); | ||
2793 | bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL); | ||
2794 | if (bufs == NULL) | ||
2795 | return -ENOMEM; | ||
2796 | for (i = 0; i < count; ++i) | ||
2797 | bufs[i] = _vector[i].iov_base; | ||
2798 | result = snd_pcm_lib_readv(substream, bufs, frames); | ||
2799 | if (result > 0) | ||
2800 | result = frames_to_bytes(runtime, result); | ||
2801 | kfree(bufs); | ||
2802 | return result; | ||
2803 | } | ||
2804 | |||
2805 | static ssize_t snd_pcm_writev(struct file *file, const struct iovec *_vector, | ||
2806 | unsigned long count, loff_t * offset) | ||
2807 | { | ||
2808 | snd_pcm_file_t *pcm_file; | ||
2809 | snd_pcm_substream_t *substream; | ||
2810 | snd_pcm_runtime_t *runtime; | ||
2811 | snd_pcm_sframes_t result; | ||
2812 | unsigned long i; | ||
2813 | void __user **bufs; | ||
2814 | snd_pcm_uframes_t frames; | ||
2815 | |||
2816 | pcm_file = file->private_data; | ||
2817 | substream = pcm_file->substream; | ||
2818 | snd_assert(substream != NULL, result = -ENXIO; goto end); | ||
2819 | runtime = substream->runtime; | ||
2820 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { | ||
2821 | result = -EBADFD; | ||
2822 | goto end; | ||
2823 | } | ||
2824 | if (count > 128 || count != runtime->channels || | ||
2825 | !frame_aligned(runtime, _vector->iov_len)) { | ||
2826 | result = -EINVAL; | ||
2827 | goto end; | ||
2828 | } | ||
2829 | frames = bytes_to_samples(runtime, _vector->iov_len); | ||
2830 | bufs = kmalloc(sizeof(void *) * count, GFP_KERNEL); | ||
2831 | if (bufs == NULL) | ||
2832 | return -ENOMEM; | ||
2833 | for (i = 0; i < count; ++i) | ||
2834 | bufs[i] = _vector[i].iov_base; | ||
2835 | result = snd_pcm_lib_writev(substream, bufs, frames); | ||
2836 | if (result > 0) | ||
2837 | result = frames_to_bytes(runtime, result); | ||
2838 | kfree(bufs); | ||
2839 | end: | ||
2840 | return result; | ||
2841 | } | ||
2842 | |||
2843 | static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) | ||
2844 | { | ||
2845 | snd_pcm_file_t *pcm_file; | ||
2846 | snd_pcm_substream_t *substream; | ||
2847 | snd_pcm_runtime_t *runtime; | ||
2848 | unsigned int mask; | ||
2849 | snd_pcm_uframes_t avail; | ||
2850 | |||
2851 | pcm_file = file->private_data; | ||
2852 | |||
2853 | substream = pcm_file->substream; | ||
2854 | snd_assert(substream != NULL, return -ENXIO); | ||
2855 | runtime = substream->runtime; | ||
2856 | |||
2857 | poll_wait(file, &runtime->sleep, wait); | ||
2858 | |||
2859 | snd_pcm_stream_lock_irq(substream); | ||
2860 | avail = snd_pcm_playback_avail(runtime); | ||
2861 | switch (runtime->status->state) { | ||
2862 | case SNDRV_PCM_STATE_RUNNING: | ||
2863 | case SNDRV_PCM_STATE_PREPARED: | ||
2864 | case SNDRV_PCM_STATE_PAUSED: | ||
2865 | if (avail >= runtime->control->avail_min) { | ||
2866 | mask = POLLOUT | POLLWRNORM; | ||
2867 | break; | ||
2868 | } | ||
2869 | /* Fall through */ | ||
2870 | case SNDRV_PCM_STATE_DRAINING: | ||
2871 | mask = 0; | ||
2872 | break; | ||
2873 | default: | ||
2874 | mask = POLLOUT | POLLWRNORM | POLLERR; | ||
2875 | break; | ||
2876 | } | ||
2877 | snd_pcm_stream_unlock_irq(substream); | ||
2878 | return mask; | ||
2879 | } | ||
2880 | |||
2881 | static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait) | ||
2882 | { | ||
2883 | snd_pcm_file_t *pcm_file; | ||
2884 | snd_pcm_substream_t *substream; | ||
2885 | snd_pcm_runtime_t *runtime; | ||
2886 | unsigned int mask; | ||
2887 | snd_pcm_uframes_t avail; | ||
2888 | |||
2889 | pcm_file = file->private_data; | ||
2890 | |||
2891 | substream = pcm_file->substream; | ||
2892 | snd_assert(substream != NULL, return -ENXIO); | ||
2893 | runtime = substream->runtime; | ||
2894 | |||
2895 | poll_wait(file, &runtime->sleep, wait); | ||
2896 | |||
2897 | snd_pcm_stream_lock_irq(substream); | ||
2898 | avail = snd_pcm_capture_avail(runtime); | ||
2899 | switch (runtime->status->state) { | ||
2900 | case SNDRV_PCM_STATE_RUNNING: | ||
2901 | case SNDRV_PCM_STATE_PREPARED: | ||
2902 | case SNDRV_PCM_STATE_PAUSED: | ||
2903 | if (avail >= runtime->control->avail_min) { | ||
2904 | mask = POLLIN | POLLRDNORM; | ||
2905 | break; | ||
2906 | } | ||
2907 | mask = 0; | ||
2908 | break; | ||
2909 | case SNDRV_PCM_STATE_DRAINING: | ||
2910 | if (avail > 0) { | ||
2911 | mask = POLLIN | POLLRDNORM; | ||
2912 | break; | ||
2913 | } | ||
2914 | /* Fall through */ | ||
2915 | default: | ||
2916 | mask = POLLIN | POLLRDNORM | POLLERR; | ||
2917 | break; | ||
2918 | } | ||
2919 | snd_pcm_stream_unlock_irq(substream); | ||
2920 | return mask; | ||
2921 | } | ||
2922 | |||
2923 | /* | ||
2924 | * mmap support | ||
2925 | */ | ||
2926 | |||
2927 | /* | ||
2928 | * Only on coherent architectures, we can mmap the status and the control records | ||
2929 | * for effcient data transfer. On others, we have to use HWSYNC ioctl... | ||
2930 | */ | ||
2931 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA) | ||
2932 | /* | ||
2933 | * mmap status record | ||
2934 | */ | ||
2935 | static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int *type) | ||
2936 | { | ||
2937 | snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; | ||
2938 | snd_pcm_runtime_t *runtime; | ||
2939 | struct page * page; | ||
2940 | |||
2941 | if (substream == NULL) | ||
2942 | return NOPAGE_OOM; | ||
2943 | runtime = substream->runtime; | ||
2944 | page = virt_to_page(runtime->status); | ||
2945 | if (!PageReserved(page)) | ||
2946 | get_page(page); | ||
2947 | if (type) | ||
2948 | *type = VM_FAULT_MINOR; | ||
2949 | return page; | ||
2950 | } | ||
2951 | |||
2952 | static struct vm_operations_struct snd_pcm_vm_ops_status = | ||
2953 | { | ||
2954 | .nopage = snd_pcm_mmap_status_nopage, | ||
2955 | }; | ||
2956 | |||
2957 | static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file, | ||
2958 | struct vm_area_struct *area) | ||
2959 | { | ||
2960 | snd_pcm_runtime_t *runtime; | ||
2961 | long size; | ||
2962 | if (!(area->vm_flags & VM_READ)) | ||
2963 | return -EINVAL; | ||
2964 | runtime = substream->runtime; | ||
2965 | snd_assert(runtime != NULL, return -EAGAIN); | ||
2966 | size = area->vm_end - area->vm_start; | ||
2967 | if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))) | ||
2968 | return -EINVAL; | ||
2969 | area->vm_ops = &snd_pcm_vm_ops_status; | ||
2970 | area->vm_private_data = substream; | ||
2971 | area->vm_flags |= VM_RESERVED; | ||
2972 | return 0; | ||
2973 | } | ||
2974 | |||
2975 | /* | ||
2976 | * mmap control record | ||
2977 | */ | ||
2978 | static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int *type) | ||
2979 | { | ||
2980 | snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; | ||
2981 | snd_pcm_runtime_t *runtime; | ||
2982 | struct page * page; | ||
2983 | |||
2984 | if (substream == NULL) | ||
2985 | return NOPAGE_OOM; | ||
2986 | runtime = substream->runtime; | ||
2987 | page = virt_to_page(runtime->control); | ||
2988 | if (!PageReserved(page)) | ||
2989 | get_page(page); | ||
2990 | if (type) | ||
2991 | *type = VM_FAULT_MINOR; | ||
2992 | return page; | ||
2993 | } | ||
2994 | |||
2995 | static struct vm_operations_struct snd_pcm_vm_ops_control = | ||
2996 | { | ||
2997 | .nopage = snd_pcm_mmap_control_nopage, | ||
2998 | }; | ||
2999 | |||
3000 | static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file, | ||
3001 | struct vm_area_struct *area) | ||
3002 | { | ||
3003 | snd_pcm_runtime_t *runtime; | ||
3004 | long size; | ||
3005 | if (!(area->vm_flags & VM_READ)) | ||
3006 | return -EINVAL; | ||
3007 | runtime = substream->runtime; | ||
3008 | snd_assert(runtime != NULL, return -EAGAIN); | ||
3009 | size = area->vm_end - area->vm_start; | ||
3010 | if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t))) | ||
3011 | return -EINVAL; | ||
3012 | area->vm_ops = &snd_pcm_vm_ops_control; | ||
3013 | area->vm_private_data = substream; | ||
3014 | area->vm_flags |= VM_RESERVED; | ||
3015 | return 0; | ||
3016 | } | ||
3017 | #else /* ! coherent mmap */ | ||
3018 | /* | ||
3019 | * don't support mmap for status and control records. | ||
3020 | */ | ||
3021 | static int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file, | ||
3022 | struct vm_area_struct *area) | ||
3023 | { | ||
3024 | return -ENXIO; | ||
3025 | } | ||
3026 | static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file, | ||
3027 | struct vm_area_struct *area) | ||
3028 | { | ||
3029 | return -ENXIO; | ||
3030 | } | ||
3031 | #endif /* coherent mmap */ | ||
3032 | |||
3033 | /* | ||
3034 | * nopage callback for mmapping a RAM page | ||
3035 | */ | ||
3036 | static struct page *snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int *type) | ||
3037 | { | ||
3038 | snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; | ||
3039 | snd_pcm_runtime_t *runtime; | ||
3040 | unsigned long offset; | ||
3041 | struct page * page; | ||
3042 | void *vaddr; | ||
3043 | size_t dma_bytes; | ||
3044 | |||
3045 | if (substream == NULL) | ||
3046 | return NOPAGE_OOM; | ||
3047 | runtime = substream->runtime; | ||
3048 | offset = area->vm_pgoff << PAGE_SHIFT; | ||
3049 | offset += address - area->vm_start; | ||
3050 | snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); | ||
3051 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); | ||
3052 | if (offset > dma_bytes - PAGE_SIZE) | ||
3053 | return NOPAGE_SIGBUS; | ||
3054 | if (substream->ops->page) { | ||
3055 | page = substream->ops->page(substream, offset); | ||
3056 | if (! page) | ||
3057 | return NOPAGE_OOM; | ||
3058 | } else { | ||
3059 | vaddr = runtime->dma_area + offset; | ||
3060 | page = virt_to_page(vaddr); | ||
3061 | } | ||
3062 | if (!PageReserved(page)) | ||
3063 | get_page(page); | ||
3064 | if (type) | ||
3065 | *type = VM_FAULT_MINOR; | ||
3066 | return page; | ||
3067 | } | ||
3068 | |||
3069 | static struct vm_operations_struct snd_pcm_vm_ops_data = | ||
3070 | { | ||
3071 | .open = snd_pcm_mmap_data_open, | ||
3072 | .close = snd_pcm_mmap_data_close, | ||
3073 | .nopage = snd_pcm_mmap_data_nopage, | ||
3074 | }; | ||
3075 | |||
3076 | /* | ||
3077 | * mmap the DMA buffer on RAM | ||
3078 | */ | ||
3079 | static int snd_pcm_default_mmap(snd_pcm_substream_t *substream, struct vm_area_struct *area) | ||
3080 | { | ||
3081 | area->vm_ops = &snd_pcm_vm_ops_data; | ||
3082 | area->vm_private_data = substream; | ||
3083 | area->vm_flags |= VM_RESERVED; | ||
3084 | atomic_inc(&substream->runtime->mmap_count); | ||
3085 | return 0; | ||
3086 | } | ||
3087 | |||
3088 | /* | ||
3089 | * mmap the DMA buffer on I/O memory area | ||
3090 | */ | ||
3091 | #if SNDRV_PCM_INFO_MMAP_IOMEM | ||
3092 | static struct vm_operations_struct snd_pcm_vm_ops_data_mmio = | ||
3093 | { | ||
3094 | .open = snd_pcm_mmap_data_open, | ||
3095 | .close = snd_pcm_mmap_data_close, | ||
3096 | }; | ||
3097 | |||
3098 | int snd_pcm_lib_mmap_iomem(snd_pcm_substream_t *substream, struct vm_area_struct *area) | ||
3099 | { | ||
3100 | long size; | ||
3101 | unsigned long offset; | ||
3102 | |||
3103 | #ifdef pgprot_noncached | ||
3104 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | ||
3105 | #endif | ||
3106 | area->vm_ops = &snd_pcm_vm_ops_data_mmio; | ||
3107 | area->vm_private_data = substream; | ||
3108 | area->vm_flags |= VM_IO; | ||
3109 | size = area->vm_end - area->vm_start; | ||
3110 | offset = area->vm_pgoff << PAGE_SHIFT; | ||
3111 | if (io_remap_pfn_range(area, area->vm_start, | ||
3112 | (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, | ||
3113 | size, area->vm_page_prot)) | ||
3114 | return -EAGAIN; | ||
3115 | atomic_inc(&substream->runtime->mmap_count); | ||
3116 | return 0; | ||
3117 | } | ||
3118 | #endif /* SNDRV_PCM_INFO_MMAP */ | ||
3119 | |||
3120 | /* | ||
3121 | * mmap DMA buffer | ||
3122 | */ | ||
3123 | int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file, | ||
3124 | struct vm_area_struct *area) | ||
3125 | { | ||
3126 | snd_pcm_runtime_t *runtime; | ||
3127 | long size; | ||
3128 | unsigned long offset; | ||
3129 | size_t dma_bytes; | ||
3130 | |||
3131 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | ||
3132 | if (!(area->vm_flags & (VM_WRITE|VM_READ))) | ||
3133 | return -EINVAL; | ||
3134 | } else { | ||
3135 | if (!(area->vm_flags & VM_READ)) | ||
3136 | return -EINVAL; | ||
3137 | } | ||
3138 | runtime = substream->runtime; | ||
3139 | snd_assert(runtime != NULL, return -EAGAIN); | ||
3140 | if (runtime->status->state == SNDRV_PCM_STATE_OPEN) | ||
3141 | return -EBADFD; | ||
3142 | if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) | ||
3143 | return -ENXIO; | ||
3144 | if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || | ||
3145 | runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) | ||
3146 | return -EINVAL; | ||
3147 | size = area->vm_end - area->vm_start; | ||
3148 | offset = area->vm_pgoff << PAGE_SHIFT; | ||
3149 | dma_bytes = PAGE_ALIGN(runtime->dma_bytes); | ||
3150 | if ((size_t)size > dma_bytes) | ||
3151 | return -EINVAL; | ||
3152 | if (offset > dma_bytes - size) | ||
3153 | return -EINVAL; | ||
3154 | |||
3155 | if (substream->ops->mmap) | ||
3156 | return substream->ops->mmap(substream, area); | ||
3157 | else | ||
3158 | return snd_pcm_default_mmap(substream, area); | ||
3159 | } | ||
3160 | |||
3161 | static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) | ||
3162 | { | ||
3163 | snd_pcm_file_t * pcm_file; | ||
3164 | snd_pcm_substream_t *substream; | ||
3165 | unsigned long offset; | ||
3166 | |||
3167 | pcm_file = file->private_data; | ||
3168 | substream = pcm_file->substream; | ||
3169 | snd_assert(substream != NULL, return -ENXIO); | ||
3170 | |||
3171 | offset = area->vm_pgoff << PAGE_SHIFT; | ||
3172 | switch (offset) { | ||
3173 | case SNDRV_PCM_MMAP_OFFSET_STATUS: | ||
3174 | if (substream->no_mmap_ctrl) | ||
3175 | return -ENXIO; | ||
3176 | return snd_pcm_mmap_status(substream, file, area); | ||
3177 | case SNDRV_PCM_MMAP_OFFSET_CONTROL: | ||
3178 | if (substream->no_mmap_ctrl) | ||
3179 | return -ENXIO; | ||
3180 | return snd_pcm_mmap_control(substream, file, area); | ||
3181 | default: | ||
3182 | return snd_pcm_mmap_data(substream, file, area); | ||
3183 | } | ||
3184 | return 0; | ||
3185 | } | ||
3186 | |||
3187 | static int snd_pcm_fasync(int fd, struct file * file, int on) | ||
3188 | { | ||
3189 | snd_pcm_file_t * pcm_file; | ||
3190 | snd_pcm_substream_t *substream; | ||
3191 | snd_pcm_runtime_t *runtime; | ||
3192 | int err; | ||
3193 | |||
3194 | pcm_file = file->private_data; | ||
3195 | substream = pcm_file->substream; | ||
3196 | snd_assert(substream != NULL, return -ENXIO); | ||
3197 | runtime = substream->runtime; | ||
3198 | |||
3199 | err = fasync_helper(fd, file, on, &runtime->fasync); | ||
3200 | if (err < 0) | ||
3201 | return err; | ||
3202 | return 0; | ||
3203 | } | ||
3204 | |||
3205 | /* | ||
3206 | * ioctl32 compat | ||
3207 | */ | ||
3208 | #ifdef CONFIG_COMPAT | ||
3209 | #include "pcm_compat.c" | ||
3210 | #else | ||
3211 | #define snd_pcm_ioctl_compat NULL | ||
3212 | #endif | ||
3213 | |||
3214 | /* | ||
3215 | * To be removed helpers to keep binary compatibility | ||
3216 | */ | ||
3217 | |||
3218 | #define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5)) | ||
3219 | #define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5)) | ||
3220 | |||
3221 | static void snd_pcm_hw_convert_from_old_params(snd_pcm_hw_params_t *params, struct sndrv_pcm_hw_params_old *oparams) | ||
3222 | { | ||
3223 | unsigned int i; | ||
3224 | |||
3225 | memset(params, 0, sizeof(*params)); | ||
3226 | params->flags = oparams->flags; | ||
3227 | for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) | ||
3228 | params->masks[i].bits[0] = oparams->masks[i]; | ||
3229 | memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals)); | ||
3230 | params->rmask = __OLD_TO_NEW_MASK(oparams->rmask); | ||
3231 | params->cmask = __OLD_TO_NEW_MASK(oparams->cmask); | ||
3232 | params->info = oparams->info; | ||
3233 | params->msbits = oparams->msbits; | ||
3234 | params->rate_num = oparams->rate_num; | ||
3235 | params->rate_den = oparams->rate_den; | ||
3236 | params->fifo_size = oparams->fifo_size; | ||
3237 | } | ||
3238 | |||
3239 | static void snd_pcm_hw_convert_to_old_params(struct sndrv_pcm_hw_params_old *oparams, snd_pcm_hw_params_t *params) | ||
3240 | { | ||
3241 | unsigned int i; | ||
3242 | |||
3243 | memset(oparams, 0, sizeof(*oparams)); | ||
3244 | oparams->flags = params->flags; | ||
3245 | for (i = 0; i < ARRAY_SIZE(oparams->masks); i++) | ||
3246 | oparams->masks[i] = params->masks[i].bits[0]; | ||
3247 | memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals)); | ||
3248 | oparams->rmask = __NEW_TO_OLD_MASK(params->rmask); | ||
3249 | oparams->cmask = __NEW_TO_OLD_MASK(params->cmask); | ||
3250 | oparams->info = params->info; | ||
3251 | oparams->msbits = params->msbits; | ||
3252 | oparams->rate_num = params->rate_num; | ||
3253 | oparams->rate_den = params->rate_den; | ||
3254 | oparams->fifo_size = params->fifo_size; | ||
3255 | } | ||
3256 | |||
3257 | static int snd_pcm_hw_refine_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) | ||
3258 | { | ||
3259 | snd_pcm_hw_params_t *params; | ||
3260 | struct sndrv_pcm_hw_params_old *oparams = NULL; | ||
3261 | int err; | ||
3262 | |||
3263 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
3264 | if (!params) { | ||
3265 | err = -ENOMEM; | ||
3266 | goto out; | ||
3267 | } | ||
3268 | oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); | ||
3269 | if (!oparams) { | ||
3270 | err = -ENOMEM; | ||
3271 | goto out; | ||
3272 | } | ||
3273 | |||
3274 | if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { | ||
3275 | err = -EFAULT; | ||
3276 | goto out; | ||
3277 | } | ||
3278 | snd_pcm_hw_convert_from_old_params(params, oparams); | ||
3279 | err = snd_pcm_hw_refine(substream, params); | ||
3280 | snd_pcm_hw_convert_to_old_params(oparams, params); | ||
3281 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { | ||
3282 | if (!err) | ||
3283 | err = -EFAULT; | ||
3284 | } | ||
3285 | out: | ||
3286 | kfree(params); | ||
3287 | kfree(oparams); | ||
3288 | return err; | ||
3289 | } | ||
3290 | |||
3291 | static int snd_pcm_hw_params_old_user(snd_pcm_substream_t * substream, struct sndrv_pcm_hw_params_old __user * _oparams) | ||
3292 | { | ||
3293 | snd_pcm_hw_params_t *params; | ||
3294 | struct sndrv_pcm_hw_params_old *oparams = NULL; | ||
3295 | int err; | ||
3296 | |||
3297 | params = kmalloc(sizeof(*params), GFP_KERNEL); | ||
3298 | if (!params) { | ||
3299 | err = -ENOMEM; | ||
3300 | goto out; | ||
3301 | } | ||
3302 | oparams = kmalloc(sizeof(*oparams), GFP_KERNEL); | ||
3303 | if (!oparams) { | ||
3304 | err = -ENOMEM; | ||
3305 | goto out; | ||
3306 | } | ||
3307 | if (copy_from_user(oparams, _oparams, sizeof(*oparams))) { | ||
3308 | err = -EFAULT; | ||
3309 | goto out; | ||
3310 | } | ||
3311 | snd_pcm_hw_convert_from_old_params(params, oparams); | ||
3312 | err = snd_pcm_hw_params(substream, params); | ||
3313 | snd_pcm_hw_convert_to_old_params(oparams, params); | ||
3314 | if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { | ||
3315 | if (!err) | ||
3316 | err = -EFAULT; | ||
3317 | } | ||
3318 | out: | ||
3319 | kfree(params); | ||
3320 | kfree(oparams); | ||
3321 | return err; | ||
3322 | } | ||
3323 | |||
3324 | /* | ||
3325 | * Register section | ||
3326 | */ | ||
3327 | |||
3328 | static struct file_operations snd_pcm_f_ops_playback = { | ||
3329 | .owner = THIS_MODULE, | ||
3330 | .write = snd_pcm_write, | ||
3331 | .writev = snd_pcm_writev, | ||
3332 | .open = snd_pcm_open, | ||
3333 | .release = snd_pcm_release, | ||
3334 | .poll = snd_pcm_playback_poll, | ||
3335 | .unlocked_ioctl = snd_pcm_playback_ioctl, | ||
3336 | .compat_ioctl = snd_pcm_ioctl_compat, | ||
3337 | .mmap = snd_pcm_mmap, | ||
3338 | .fasync = snd_pcm_fasync, | ||
3339 | }; | ||
3340 | |||
3341 | static struct file_operations snd_pcm_f_ops_capture = { | ||
3342 | .owner = THIS_MODULE, | ||
3343 | .read = snd_pcm_read, | ||
3344 | .readv = snd_pcm_readv, | ||
3345 | .open = snd_pcm_open, | ||
3346 | .release = snd_pcm_release, | ||
3347 | .poll = snd_pcm_capture_poll, | ||
3348 | .unlocked_ioctl = snd_pcm_capture_ioctl, | ||
3349 | .compat_ioctl = snd_pcm_ioctl_compat, | ||
3350 | .mmap = snd_pcm_mmap, | ||
3351 | .fasync = snd_pcm_fasync, | ||
3352 | }; | ||
3353 | |||
3354 | snd_minor_t snd_pcm_reg[2] = | ||
3355 | { | ||
3356 | { | ||
3357 | .comment = "digital audio playback", | ||
3358 | .f_ops = &snd_pcm_f_ops_playback, | ||
3359 | }, | ||
3360 | { | ||
3361 | .comment = "digital audio capture", | ||
3362 | .f_ops = &snd_pcm_f_ops_capture, | ||
3363 | } | ||
3364 | }; | ||