blob: 302654769faf00723ed35c54aac6c2e6e0533077 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Digital Audio (PCM) abstract layer
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02003 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/slab.h>
24#include <linux/time.h>
25#include <sound/core.h>
26#include <sound/control.h>
27#include <sound/info.h>
28#include <sound/pcm.h>
29#include <sound/pcm_params.h>
30#include <sound/timer.h>
31
32/*
33 * fill ring buffer with silence
34 * runtime->silence_start: starting pointer to silence area
35 * runtime->silence_filled: size filled with silence
36 * runtime->silence_threshold: threshold from application
37 * runtime->silence_size: maximal size from application
38 *
39 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
40 */
Takashi Iwai877211f2005-11-17 13:59:38 +010041void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070042{
Takashi Iwai877211f2005-11-17 13:59:38 +010043 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 snd_pcm_uframes_t frames, ofs, transfer;
45
46 if (runtime->silence_size < runtime->boundary) {
47 snd_pcm_sframes_t noise_dist, n;
48 if (runtime->silence_start != runtime->control->appl_ptr) {
49 n = runtime->control->appl_ptr - runtime->silence_start;
50 if (n < 0)
51 n += runtime->boundary;
52 if ((snd_pcm_uframes_t)n < runtime->silence_filled)
53 runtime->silence_filled -= n;
54 else
55 runtime->silence_filled = 0;
56 runtime->silence_start = runtime->control->appl_ptr;
57 }
Takashi Iwai235475c2005-12-07 15:28:07 +010058 if (runtime->silence_filled >= runtime->buffer_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
61 if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
62 return;
63 frames = runtime->silence_threshold - noise_dist;
64 if (frames > runtime->silence_size)
65 frames = runtime->silence_size;
66 } else {
67 if (new_hw_ptr == ULONG_MAX) { /* initialization */
68 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
69 runtime->silence_filled = avail > 0 ? avail : 0;
70 runtime->silence_start = (runtime->status->hw_ptr +
71 runtime->silence_filled) %
72 runtime->boundary;
73 } else {
74 ofs = runtime->status->hw_ptr;
75 frames = new_hw_ptr - ofs;
76 if ((snd_pcm_sframes_t)frames < 0)
77 frames += runtime->boundary;
78 runtime->silence_filled -= frames;
79 if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
80 runtime->silence_filled = 0;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020081 runtime->silence_start = new_hw_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070082 } else {
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020083 runtime->silence_start = ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 }
86 frames = runtime->buffer_size - runtime->silence_filled;
87 }
Takashi Iwai7eaa9432008-08-08 17:09:09 +020088 if (snd_BUG_ON(frames > runtime->buffer_size))
89 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 if (frames == 0)
91 return;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020092 ofs = runtime->silence_start % runtime->buffer_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 while (frames > 0) {
94 transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
95 if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
96 runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
97 if (substream->ops->silence) {
98 int err;
99 err = substream->ops->silence(substream, -1, ofs, transfer);
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200100 snd_BUG_ON(err < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 } else {
102 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
103 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
104 }
105 } else {
106 unsigned int c;
107 unsigned int channels = runtime->channels;
108 if (substream->ops->silence) {
109 for (c = 0; c < channels; ++c) {
110 int err;
111 err = substream->ops->silence(substream, c, ofs, transfer);
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200112 snd_BUG_ON(err < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 }
114 } else {
115 size_t dma_csize = runtime->dma_bytes / channels;
116 for (c = 0; c < channels; ++c) {
117 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
118 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
119 }
120 }
121 }
122 runtime->silence_filled += transfer;
123 frames -= transfer;
124 ofs = 0;
125 }
126}
127
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100128#ifdef CONFIG_SND_PCM_XRUN_DEBUG
129#define xrun_debug(substream) ((substream)->pstr->xrun_debug)
130#else
131#define xrun_debug(substream) 0
132#endif
133
134#define dump_stack_on_xrun(substream) do { \
135 if (xrun_debug(substream) > 1) \
136 dump_stack(); \
137 } while (0)
138
Takashi Iwai877211f2005-11-17 13:59:38 +0100139static void xrun(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140{
141 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100142 if (xrun_debug(substream)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 snd_printd(KERN_DEBUG "XRUN: pcmC%dD%d%c\n",
144 substream->pcm->card->number,
145 substream->pcm->device,
146 substream->stream ? 'c' : 'p');
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100147 dump_stack_on_xrun(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149}
150
Takashi Iwai98204642009-03-19 09:59:21 +0100151static snd_pcm_uframes_t
152snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream,
153 struct snd_pcm_runtime *runtime)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154{
155 snd_pcm_uframes_t pos;
156
Jaroslav Kysela8c121582008-01-11 08:45:08 +0100157 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
158 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 pos = substream->ops->pointer(substream);
160 if (pos == SNDRV_PCM_POS_XRUN)
161 return pos; /* XRUN */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162#ifdef CONFIG_SND_DEBUG
163 if (pos >= runtime->buffer_size) {
164 snd_printk(KERN_ERR "BUG: stream = %i, pos = 0x%lx, buffer size = 0x%lx, period size = 0x%lx\n", substream->stream, pos, runtime->buffer_size, runtime->period_size);
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200165 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700167 pos -= pos % runtime->min_align;
168 return pos;
169}
170
Takashi Iwai98204642009-03-19 09:59:21 +0100171static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream,
172 struct snd_pcm_runtime *runtime)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173{
174 snd_pcm_uframes_t avail;
175
176 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
177 avail = snd_pcm_playback_avail(runtime);
178 else
179 avail = snd_pcm_capture_avail(runtime);
180 if (avail > runtime->avail_max)
181 runtime->avail_max = avail;
182 if (avail >= runtime->stop_threshold) {
183 if (substream->runtime->status->state == SNDRV_PCM_STATE_DRAINING)
184 snd_pcm_drain_done(substream);
185 else
186 xrun(substream);
187 return -EPIPE;
188 }
189 if (avail >= runtime->control->avail_min)
190 wake_up(&runtime->sleep);
191 return 0;
192}
193
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100194#define hw_ptr_error(substream, fmt, args...) \
195 do { \
196 if (xrun_debug(substream)) { \
197 if (printk_ratelimit()) { \
Takashi Iwaicad377a2009-03-19 09:55:15 +0100198 snd_printd("PCM: " fmt, ##args); \
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100199 } \
200 dump_stack_on_xrun(substream); \
201 } \
202 } while (0)
203
Takashi Iwai98204642009-03-19 09:59:21 +0100204static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700205{
Takashi Iwai877211f2005-11-17 13:59:38 +0100206 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207 snd_pcm_uframes_t pos;
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100208 snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 snd_pcm_sframes_t delta;
210
211 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
212 if (pos == SNDRV_PCM_POS_XRUN) {
213 xrun(substream);
214 return -EPIPE;
215 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100216 hw_base = runtime->hw_ptr_base;
217 new_hw_ptr = hw_base + pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size;
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100219 delta = new_hw_ptr - hw_ptr_interrupt;
220 if (hw_ptr_interrupt == runtime->boundary)
221 hw_ptr_interrupt = 0;
222 if (delta < 0) {
223 delta += runtime->buffer_size;
224 if (delta < 0) {
225 hw_ptr_error(substream,
226 "Unexpected hw_pointer value "
227 "(stream=%i, pos=%ld, intr_ptr=%ld)\n",
228 substream->stream, (long)pos,
229 (long)hw_ptr_interrupt);
230 /* rebase to interrupt position */
231 hw_base = new_hw_ptr = hw_ptr_interrupt;
232 delta = 0;
233 } else {
234 hw_base += runtime->buffer_size;
235 if (hw_base == runtime->boundary)
236 hw_base = 0;
237 new_hw_ptr = hw_base + pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100240 if (delta > runtime->period_size) {
241 hw_ptr_error(substream,
242 "Lost interrupts? "
243 "(stream=%i, delta=%ld, intr_ptr=%ld)\n",
244 substream->stream, (long)delta,
245 (long)hw_ptr_interrupt);
246 /* rebase hw_ptr_interrupt */
247 hw_ptr_interrupt =
248 new_hw_ptr - new_hw_ptr % runtime->period_size;
249 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700250 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
251 runtime->silence_size > 0)
252 snd_pcm_playback_silence(substream, new_hw_ptr);
253
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100254 runtime->hw_ptr_base = hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700255 runtime->status->hw_ptr = new_hw_ptr;
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100256 runtime->hw_ptr_interrupt = hw_ptr_interrupt;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700257
258 return snd_pcm_update_hw_ptr_post(substream, runtime);
259}
260
261/* CAUTION: call it with irq disabled */
Takashi Iwai877211f2005-11-17 13:59:38 +0100262int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
Takashi Iwai877211f2005-11-17 13:59:38 +0100264 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 snd_pcm_uframes_t pos;
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100266 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700267 snd_pcm_sframes_t delta;
268
269 old_hw_ptr = runtime->status->hw_ptr;
270 pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
271 if (pos == SNDRV_PCM_POS_XRUN) {
272 xrun(substream);
273 return -EPIPE;
274 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100275 hw_base = runtime->hw_ptr_base;
276 new_hw_ptr = hw_base + pos;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100278 delta = new_hw_ptr - old_hw_ptr;
279 if (delta < 0) {
280 delta += runtime->buffer_size;
281 if (delta < 0) {
282 hw_ptr_error(substream,
283 "Unexpected hw_pointer value [2] "
284 "(stream=%i, pos=%ld, old_ptr=%ld)\n",
285 substream->stream, (long)pos,
286 (long)old_hw_ptr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700287 return 0;
288 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100289 hw_base += runtime->buffer_size;
290 if (hw_base == runtime->boundary)
291 hw_base = 0;
292 new_hw_ptr = hw_base + pos;
293 }
294 if (delta > runtime->period_size && runtime->periods > 1) {
295 hw_ptr_error(substream,
296 "hw_ptr skipping! "
297 "(pos=%ld, delta=%ld, period=%ld)\n",
298 (long)pos, (long)delta,
299 (long)runtime->period_size);
300 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
302 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
303 runtime->silence_size > 0)
304 snd_pcm_playback_silence(substream, new_hw_ptr);
305
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100306 runtime->hw_ptr_base = hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 runtime->status->hw_ptr = new_hw_ptr;
308
309 return snd_pcm_update_hw_ptr_post(substream, runtime);
310}
311
312/**
313 * snd_pcm_set_ops - set the PCM operators
314 * @pcm: the pcm instance
315 * @direction: stream direction, SNDRV_PCM_STREAM_XXX
316 * @ops: the operator table
317 *
318 * Sets the given PCM operators to the pcm instance.
319 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100320void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321{
Takashi Iwai877211f2005-11-17 13:59:38 +0100322 struct snd_pcm_str *stream = &pcm->streams[direction];
323 struct snd_pcm_substream *substream;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324
325 for (substream = stream->substream; substream != NULL; substream = substream->next)
326 substream->ops = ops;
327}
328
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200329EXPORT_SYMBOL(snd_pcm_set_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331/**
332 * snd_pcm_sync - set the PCM sync id
333 * @substream: the pcm substream
334 *
335 * Sets the PCM sync identifier for the card.
336 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100337void snd_pcm_set_sync(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700338{
Takashi Iwai877211f2005-11-17 13:59:38 +0100339 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340
341 runtime->sync.id32[0] = substream->pcm->card->number;
342 runtime->sync.id32[1] = -1;
343 runtime->sync.id32[2] = -1;
344 runtime->sync.id32[3] = -1;
345}
346
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200347EXPORT_SYMBOL(snd_pcm_set_sync);
348
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349/*
350 * Standard ioctl routine
351 */
352
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353static inline unsigned int div32(unsigned int a, unsigned int b,
354 unsigned int *r)
355{
356 if (b == 0) {
357 *r = 0;
358 return UINT_MAX;
359 }
360 *r = a % b;
361 return a / b;
362}
363
364static inline unsigned int div_down(unsigned int a, unsigned int b)
365{
366 if (b == 0)
367 return UINT_MAX;
368 return a / b;
369}
370
371static inline unsigned int div_up(unsigned int a, unsigned int b)
372{
373 unsigned int r;
374 unsigned int q;
375 if (b == 0)
376 return UINT_MAX;
377 q = div32(a, b, &r);
378 if (r)
379 ++q;
380 return q;
381}
382
383static inline unsigned int mul(unsigned int a, unsigned int b)
384{
385 if (a == 0)
386 return 0;
387 if (div_down(UINT_MAX, a) < b)
388 return UINT_MAX;
389 return a * b;
390}
391
392static inline unsigned int muldiv32(unsigned int a, unsigned int b,
393 unsigned int c, unsigned int *r)
394{
395 u_int64_t n = (u_int64_t) a * b;
396 if (c == 0) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200397 snd_BUG_ON(!n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700398 *r = 0;
399 return UINT_MAX;
400 }
401 div64_32(&n, c, r);
402 if (n >= UINT_MAX) {
403 *r = 0;
404 return UINT_MAX;
405 }
406 return n;
407}
408
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409/**
410 * snd_interval_refine - refine the interval value of configurator
411 * @i: the interval value to refine
412 * @v: the interval value to refer to
413 *
414 * Refines the interval value with the reference value.
415 * The interval is changed to the range satisfying both intervals.
416 * The interval status (min, max, integer, etc.) are evaluated.
417 *
418 * Returns non-zero if the value is changed, zero if not changed.
419 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100420int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700421{
422 int changed = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200423 if (snd_BUG_ON(snd_interval_empty(i)))
424 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 if (i->min < v->min) {
426 i->min = v->min;
427 i->openmin = v->openmin;
428 changed = 1;
429 } else if (i->min == v->min && !i->openmin && v->openmin) {
430 i->openmin = 1;
431 changed = 1;
432 }
433 if (i->max > v->max) {
434 i->max = v->max;
435 i->openmax = v->openmax;
436 changed = 1;
437 } else if (i->max == v->max && !i->openmax && v->openmax) {
438 i->openmax = 1;
439 changed = 1;
440 }
441 if (!i->integer && v->integer) {
442 i->integer = 1;
443 changed = 1;
444 }
445 if (i->integer) {
446 if (i->openmin) {
447 i->min++;
448 i->openmin = 0;
449 }
450 if (i->openmax) {
451 i->max--;
452 i->openmax = 0;
453 }
454 } else if (!i->openmin && !i->openmax && i->min == i->max)
455 i->integer = 1;
456 if (snd_interval_checkempty(i)) {
457 snd_interval_none(i);
458 return -EINVAL;
459 }
460 return changed;
461}
462
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200463EXPORT_SYMBOL(snd_interval_refine);
464
Takashi Iwai877211f2005-11-17 13:59:38 +0100465static int snd_interval_refine_first(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700466{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200467 if (snd_BUG_ON(snd_interval_empty(i)))
468 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 if (snd_interval_single(i))
470 return 0;
471 i->max = i->min;
472 i->openmax = i->openmin;
473 if (i->openmax)
474 i->max++;
475 return 1;
476}
477
Takashi Iwai877211f2005-11-17 13:59:38 +0100478static int snd_interval_refine_last(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700479{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200480 if (snd_BUG_ON(snd_interval_empty(i)))
481 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (snd_interval_single(i))
483 return 0;
484 i->min = i->max;
485 i->openmin = i->openmax;
486 if (i->openmin)
487 i->min--;
488 return 1;
489}
490
Takashi Iwai877211f2005-11-17 13:59:38 +0100491void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700492{
493 if (a->empty || b->empty) {
494 snd_interval_none(c);
495 return;
496 }
497 c->empty = 0;
498 c->min = mul(a->min, b->min);
499 c->openmin = (a->openmin || b->openmin);
500 c->max = mul(a->max, b->max);
501 c->openmax = (a->openmax || b->openmax);
502 c->integer = (a->integer && b->integer);
503}
504
505/**
506 * snd_interval_div - refine the interval value with division
Takashi Iwaidf8db932005-09-07 13:38:19 +0200507 * @a: dividend
508 * @b: divisor
509 * @c: quotient
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510 *
511 * c = a / b
512 *
513 * Returns non-zero if the value is changed, zero if not changed.
514 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100515void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516{
517 unsigned int r;
518 if (a->empty || b->empty) {
519 snd_interval_none(c);
520 return;
521 }
522 c->empty = 0;
523 c->min = div32(a->min, b->max, &r);
524 c->openmin = (r || a->openmin || b->openmax);
525 if (b->min > 0) {
526 c->max = div32(a->max, b->min, &r);
527 if (r) {
528 c->max++;
529 c->openmax = 1;
530 } else
531 c->openmax = (a->openmax || b->openmin);
532 } else {
533 c->max = UINT_MAX;
534 c->openmax = 0;
535 }
536 c->integer = 0;
537}
538
539/**
540 * snd_interval_muldivk - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200541 * @a: dividend 1
542 * @b: dividend 2
543 * @k: divisor (as integer)
544 * @c: result
545 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700546 * c = a * b / k
547 *
548 * Returns non-zero if the value is changed, zero if not changed.
549 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100550void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b,
551 unsigned int k, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552{
553 unsigned int r;
554 if (a->empty || b->empty) {
555 snd_interval_none(c);
556 return;
557 }
558 c->empty = 0;
559 c->min = muldiv32(a->min, b->min, k, &r);
560 c->openmin = (r || a->openmin || b->openmin);
561 c->max = muldiv32(a->max, b->max, k, &r);
562 if (r) {
563 c->max++;
564 c->openmax = 1;
565 } else
566 c->openmax = (a->openmax || b->openmax);
567 c->integer = 0;
568}
569
570/**
571 * snd_interval_mulkdiv - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200572 * @a: dividend 1
573 * @k: dividend 2 (as integer)
574 * @b: divisor
575 * @c: result
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576 *
577 * c = a * k / b
578 *
579 * Returns non-zero if the value is changed, zero if not changed.
580 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100581void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
582 const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583{
584 unsigned int r;
585 if (a->empty || b->empty) {
586 snd_interval_none(c);
587 return;
588 }
589 c->empty = 0;
590 c->min = muldiv32(a->min, k, b->max, &r);
591 c->openmin = (r || a->openmin || b->openmax);
592 if (b->min > 0) {
593 c->max = muldiv32(a->max, k, b->min, &r);
594 if (r) {
595 c->max++;
596 c->openmax = 1;
597 } else
598 c->openmax = (a->openmax || b->openmin);
599 } else {
600 c->max = UINT_MAX;
601 c->openmax = 0;
602 }
603 c->integer = 0;
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606/* ---- */
607
608
609/**
610 * snd_interval_ratnum - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200611 * @i: interval to refine
612 * @rats_count: number of ratnum_t
613 * @rats: ratnum_t array
614 * @nump: pointer to store the resultant numerator
615 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700616 *
617 * Returns non-zero if the value is changed, zero if not changed.
618 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100619int snd_interval_ratnum(struct snd_interval *i,
620 unsigned int rats_count, struct snd_ratnum *rats,
621 unsigned int *nump, unsigned int *denp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700622{
623 unsigned int best_num, best_diff, best_den;
624 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100625 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 int err;
627
628 best_num = best_den = best_diff = 0;
629 for (k = 0; k < rats_count; ++k) {
630 unsigned int num = rats[k].num;
631 unsigned int den;
632 unsigned int q = i->min;
633 int diff;
634 if (q == 0)
635 q = 1;
636 den = div_down(num, q);
637 if (den < rats[k].den_min)
638 continue;
639 if (den > rats[k].den_max)
640 den = rats[k].den_max;
641 else {
642 unsigned int r;
643 r = (den - rats[k].den_min) % rats[k].den_step;
644 if (r != 0)
645 den -= r;
646 }
647 diff = num - q * den;
648 if (best_num == 0 ||
649 diff * best_den < best_diff * den) {
650 best_diff = diff;
651 best_den = den;
652 best_num = num;
653 }
654 }
655 if (best_den == 0) {
656 i->empty = 1;
657 return -EINVAL;
658 }
659 t.min = div_down(best_num, best_den);
660 t.openmin = !!(best_num % best_den);
661
662 best_num = best_den = best_diff = 0;
663 for (k = 0; k < rats_count; ++k) {
664 unsigned int num = rats[k].num;
665 unsigned int den;
666 unsigned int q = i->max;
667 int diff;
668 if (q == 0) {
669 i->empty = 1;
670 return -EINVAL;
671 }
672 den = div_up(num, q);
673 if (den > rats[k].den_max)
674 continue;
675 if (den < rats[k].den_min)
676 den = rats[k].den_min;
677 else {
678 unsigned int r;
679 r = (den - rats[k].den_min) % rats[k].den_step;
680 if (r != 0)
681 den += rats[k].den_step - r;
682 }
683 diff = q * den - num;
684 if (best_num == 0 ||
685 diff * best_den < best_diff * den) {
686 best_diff = diff;
687 best_den = den;
688 best_num = num;
689 }
690 }
691 if (best_den == 0) {
692 i->empty = 1;
693 return -EINVAL;
694 }
695 t.max = div_up(best_num, best_den);
696 t.openmax = !!(best_num % best_den);
697 t.integer = 0;
698 err = snd_interval_refine(i, &t);
699 if (err < 0)
700 return err;
701
702 if (snd_interval_single(i)) {
703 if (nump)
704 *nump = best_num;
705 if (denp)
706 *denp = best_den;
707 }
708 return err;
709}
710
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200711EXPORT_SYMBOL(snd_interval_ratnum);
712
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713/**
714 * snd_interval_ratden - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200715 * @i: interval to refine
Takashi Iwai877211f2005-11-17 13:59:38 +0100716 * @rats_count: number of struct ratden
717 * @rats: struct ratden array
Takashi Iwaidf8db932005-09-07 13:38:19 +0200718 * @nump: pointer to store the resultant numerator
719 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720 *
721 * Returns non-zero if the value is changed, zero if not changed.
722 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100723static int snd_interval_ratden(struct snd_interval *i,
724 unsigned int rats_count, struct snd_ratden *rats,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725 unsigned int *nump, unsigned int *denp)
726{
727 unsigned int best_num, best_diff, best_den;
728 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100729 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 int err;
731
732 best_num = best_den = best_diff = 0;
733 for (k = 0; k < rats_count; ++k) {
734 unsigned int num;
735 unsigned int den = rats[k].den;
736 unsigned int q = i->min;
737 int diff;
738 num = mul(q, den);
739 if (num > rats[k].num_max)
740 continue;
741 if (num < rats[k].num_min)
742 num = rats[k].num_max;
743 else {
744 unsigned int r;
745 r = (num - rats[k].num_min) % rats[k].num_step;
746 if (r != 0)
747 num += rats[k].num_step - r;
748 }
749 diff = num - q * den;
750 if (best_num == 0 ||
751 diff * best_den < best_diff * den) {
752 best_diff = diff;
753 best_den = den;
754 best_num = num;
755 }
756 }
757 if (best_den == 0) {
758 i->empty = 1;
759 return -EINVAL;
760 }
761 t.min = div_down(best_num, best_den);
762 t.openmin = !!(best_num % best_den);
763
764 best_num = best_den = best_diff = 0;
765 for (k = 0; k < rats_count; ++k) {
766 unsigned int num;
767 unsigned int den = rats[k].den;
768 unsigned int q = i->max;
769 int diff;
770 num = mul(q, den);
771 if (num < rats[k].num_min)
772 continue;
773 if (num > rats[k].num_max)
774 num = rats[k].num_max;
775 else {
776 unsigned int r;
777 r = (num - rats[k].num_min) % rats[k].num_step;
778 if (r != 0)
779 num -= r;
780 }
781 diff = q * den - num;
782 if (best_num == 0 ||
783 diff * best_den < best_diff * den) {
784 best_diff = diff;
785 best_den = den;
786 best_num = num;
787 }
788 }
789 if (best_den == 0) {
790 i->empty = 1;
791 return -EINVAL;
792 }
793 t.max = div_up(best_num, best_den);
794 t.openmax = !!(best_num % best_den);
795 t.integer = 0;
796 err = snd_interval_refine(i, &t);
797 if (err < 0)
798 return err;
799
800 if (snd_interval_single(i)) {
801 if (nump)
802 *nump = best_num;
803 if (denp)
804 *denp = best_den;
805 }
806 return err;
807}
808
809/**
810 * snd_interval_list - refine the interval value from the list
811 * @i: the interval value to refine
812 * @count: the number of elements in the list
813 * @list: the value list
814 * @mask: the bit-mask to evaluate
815 *
816 * Refines the interval value from the list.
817 * When mask is non-zero, only the elements corresponding to bit 1 are
818 * evaluated.
819 *
820 * Returns non-zero if the value is changed, zero if not changed.
821 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100822int snd_interval_list(struct snd_interval *i, unsigned int count, unsigned int *list, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823{
824 unsigned int k;
825 int changed = 0;
Takashi Iwai0981a262007-02-01 14:53:49 +0100826
827 if (!count) {
828 i->empty = 1;
829 return -EINVAL;
830 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 for (k = 0; k < count; k++) {
832 if (mask && !(mask & (1 << k)))
833 continue;
834 if (i->min == list[k] && !i->openmin)
835 goto _l1;
836 if (i->min < list[k]) {
837 i->min = list[k];
838 i->openmin = 0;
839 changed = 1;
840 goto _l1;
841 }
842 }
843 i->empty = 1;
844 return -EINVAL;
845 _l1:
846 for (k = count; k-- > 0;) {
847 if (mask && !(mask & (1 << k)))
848 continue;
849 if (i->max == list[k] && !i->openmax)
850 goto _l2;
851 if (i->max > list[k]) {
852 i->max = list[k];
853 i->openmax = 0;
854 changed = 1;
855 goto _l2;
856 }
857 }
858 i->empty = 1;
859 return -EINVAL;
860 _l2:
861 if (snd_interval_checkempty(i)) {
862 i->empty = 1;
863 return -EINVAL;
864 }
865 return changed;
866}
867
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200868EXPORT_SYMBOL(snd_interval_list);
869
Takashi Iwai877211f2005-11-17 13:59:38 +0100870static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700871{
872 unsigned int n;
873 int changed = 0;
874 n = (i->min - min) % step;
875 if (n != 0 || i->openmin) {
876 i->min += step - n;
877 changed = 1;
878 }
879 n = (i->max - min) % step;
880 if (n != 0 || i->openmax) {
881 i->max -= n;
882 changed = 1;
883 }
884 if (snd_interval_checkempty(i)) {
885 i->empty = 1;
886 return -EINVAL;
887 }
888 return changed;
889}
890
891/* Info constraints helpers */
892
893/**
894 * snd_pcm_hw_rule_add - add the hw-constraint rule
895 * @runtime: the pcm runtime instance
896 * @cond: condition bits
897 * @var: the variable to evaluate
898 * @func: the evaluation function
899 * @private: the private data pointer passed to function
900 * @dep: the dependent variables
901 *
902 * Returns zero if successful, or a negative error code on failure.
903 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100904int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905 int var,
906 snd_pcm_hw_rule_func_t func, void *private,
907 int dep, ...)
908{
Takashi Iwai877211f2005-11-17 13:59:38 +0100909 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
910 struct snd_pcm_hw_rule *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 unsigned int k;
912 va_list args;
913 va_start(args, dep);
914 if (constrs->rules_num >= constrs->rules_all) {
Takashi Iwai877211f2005-11-17 13:59:38 +0100915 struct snd_pcm_hw_rule *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916 unsigned int new_rules = constrs->rules_all + 16;
917 new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
918 if (!new)
919 return -ENOMEM;
920 if (constrs->rules) {
921 memcpy(new, constrs->rules,
922 constrs->rules_num * sizeof(*c));
923 kfree(constrs->rules);
924 }
925 constrs->rules = new;
926 constrs->rules_all = new_rules;
927 }
928 c = &constrs->rules[constrs->rules_num];
929 c->cond = cond;
930 c->func = func;
931 c->var = var;
932 c->private = private;
933 k = 0;
934 while (1) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200935 if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps)))
936 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 c->deps[k++] = dep;
938 if (dep < 0)
939 break;
940 dep = va_arg(args, int);
941 }
942 constrs->rules_num++;
943 va_end(args);
944 return 0;
945}
946
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200947EXPORT_SYMBOL(snd_pcm_hw_rule_add);
948
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -0700950 * snd_pcm_hw_constraint_mask - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +0200951 * @runtime: PCM runtime instance
952 * @var: hw_params variable to apply the mask
953 * @mask: the bitmap mask
954 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -0700955 * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100957int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 u_int32_t mask)
959{
Takashi Iwai877211f2005-11-17 13:59:38 +0100960 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
961 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 *maskp->bits &= mask;
963 memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
964 if (*maskp->bits == 0)
965 return -EINVAL;
966 return 0;
967}
968
969/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -0700970 * snd_pcm_hw_constraint_mask64 - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +0200971 * @runtime: PCM runtime instance
972 * @var: hw_params variable to apply the mask
973 * @mask: the 64bit bitmap mask
974 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -0700975 * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100977int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 u_int64_t mask)
979{
Takashi Iwai877211f2005-11-17 13:59:38 +0100980 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
981 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 maskp->bits[0] &= (u_int32_t)mask;
983 maskp->bits[1] &= (u_int32_t)(mask >> 32);
984 memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
985 if (! maskp->bits[0] && ! maskp->bits[1])
986 return -EINVAL;
987 return 0;
988}
989
990/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -0700991 * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +0200992 * @runtime: PCM runtime instance
993 * @var: hw_params variable to apply the integer constraint
994 *
995 * Apply the constraint of integer to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700996 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100997int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700998{
Takashi Iwai877211f2005-11-17 13:59:38 +0100999 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000 return snd_interval_setinteger(constrs_interval(constrs, var));
1001}
1002
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001003EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
1004
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001006 * snd_pcm_hw_constraint_minmax - apply a min/max range constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +02001007 * @runtime: PCM runtime instance
1008 * @var: hw_params variable to apply the range
1009 * @min: the minimal value
1010 * @max: the maximal value
1011 *
1012 * Apply the min/max range constraint to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001014int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 unsigned int min, unsigned int max)
1016{
Takashi Iwai877211f2005-11-17 13:59:38 +01001017 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1018 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 t.min = min;
1020 t.max = max;
1021 t.openmin = t.openmax = 0;
1022 t.integer = 0;
1023 return snd_interval_refine(constrs_interval(constrs, var), &t);
1024}
1025
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001026EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
1027
Takashi Iwai877211f2005-11-17 13:59:38 +01001028static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
1029 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001030{
Takashi Iwai877211f2005-11-17 13:59:38 +01001031 struct snd_pcm_hw_constraint_list *list = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001032 return snd_interval_list(hw_param_interval(params, rule->var), list->count, list->list, list->mask);
1033}
1034
1035
1036/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001037 * snd_pcm_hw_constraint_list - apply a list of constraints to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001038 * @runtime: PCM runtime instance
1039 * @cond: condition bits
1040 * @var: hw_params variable to apply the list constraint
1041 * @l: list
1042 *
1043 * Apply the list of constraints to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001044 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001045int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046 unsigned int cond,
1047 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001048 struct snd_pcm_hw_constraint_list *l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001049{
1050 return snd_pcm_hw_rule_add(runtime, cond, var,
1051 snd_pcm_hw_rule_list, l,
1052 var, -1);
1053}
1054
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001055EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
1056
Takashi Iwai877211f2005-11-17 13:59:38 +01001057static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
1058 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059{
Takashi Iwai877211f2005-11-17 13:59:38 +01001060 struct snd_pcm_hw_constraint_ratnums *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061 unsigned int num = 0, den = 0;
1062 int err;
1063 err = snd_interval_ratnum(hw_param_interval(params, rule->var),
1064 r->nrats, r->rats, &num, &den);
1065 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1066 params->rate_num = num;
1067 params->rate_den = den;
1068 }
1069 return err;
1070}
1071
1072/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001073 * snd_pcm_hw_constraint_ratnums - apply ratnums constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001074 * @runtime: PCM runtime instance
1075 * @cond: condition bits
1076 * @var: hw_params variable to apply the ratnums constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001077 * @r: struct snd_ratnums constriants
Linus Torvalds1da177e2005-04-16 15:20:36 -07001078 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001079int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001080 unsigned int cond,
1081 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001082 struct snd_pcm_hw_constraint_ratnums *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001083{
1084 return snd_pcm_hw_rule_add(runtime, cond, var,
1085 snd_pcm_hw_rule_ratnums, r,
1086 var, -1);
1087}
1088
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001089EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
1090
Takashi Iwai877211f2005-11-17 13:59:38 +01001091static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
1092 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001093{
Takashi Iwai877211f2005-11-17 13:59:38 +01001094 struct snd_pcm_hw_constraint_ratdens *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 unsigned int num = 0, den = 0;
1096 int err = snd_interval_ratden(hw_param_interval(params, rule->var),
1097 r->nrats, r->rats, &num, &den);
1098 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1099 params->rate_num = num;
1100 params->rate_den = den;
1101 }
1102 return err;
1103}
1104
1105/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001106 * snd_pcm_hw_constraint_ratdens - apply ratdens constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001107 * @runtime: PCM runtime instance
1108 * @cond: condition bits
1109 * @var: hw_params variable to apply the ratdens constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001110 * @r: struct snd_ratdens constriants
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001112int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001113 unsigned int cond,
1114 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001115 struct snd_pcm_hw_constraint_ratdens *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116{
1117 return snd_pcm_hw_rule_add(runtime, cond, var,
1118 snd_pcm_hw_rule_ratdens, r,
1119 var, -1);
1120}
1121
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001122EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
1123
Takashi Iwai877211f2005-11-17 13:59:38 +01001124static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
1125 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001126{
1127 unsigned int l = (unsigned long) rule->private;
1128 int width = l & 0xffff;
1129 unsigned int msbits = l >> 16;
Takashi Iwai877211f2005-11-17 13:59:38 +01001130 struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 if (snd_interval_single(i) && snd_interval_value(i) == width)
1132 params->msbits = msbits;
1133 return 0;
1134}
1135
1136/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001137 * snd_pcm_hw_constraint_msbits - add a hw constraint msbits rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001138 * @runtime: PCM runtime instance
1139 * @cond: condition bits
1140 * @width: sample bits width
1141 * @msbits: msbits width
Linus Torvalds1da177e2005-04-16 15:20:36 -07001142 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001143int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144 unsigned int cond,
1145 unsigned int width,
1146 unsigned int msbits)
1147{
1148 unsigned long l = (msbits << 16) | width;
1149 return snd_pcm_hw_rule_add(runtime, cond, -1,
1150 snd_pcm_hw_rule_msbits,
1151 (void*) l,
1152 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1153}
1154
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001155EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
1156
Takashi Iwai877211f2005-11-17 13:59:38 +01001157static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
1158 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159{
1160 unsigned long step = (unsigned long) rule->private;
1161 return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
1162}
1163
1164/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001165 * snd_pcm_hw_constraint_step - add a hw constraint step rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001166 * @runtime: PCM runtime instance
1167 * @cond: condition bits
1168 * @var: hw_params variable to apply the step constraint
1169 * @step: step size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001171int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 unsigned int cond,
1173 snd_pcm_hw_param_t var,
1174 unsigned long step)
1175{
1176 return snd_pcm_hw_rule_add(runtime, cond, var,
1177 snd_pcm_hw_rule_step, (void *) step,
1178 var, -1);
1179}
1180
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001181EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
1182
Takashi Iwai877211f2005-11-17 13:59:38 +01001183static int snd_pcm_hw_rule_pow2(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001184{
Marcin Åšlusarz67c39312007-12-14 12:53:21 +01001185 static unsigned int pow2_sizes[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001186 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1187 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1188 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
1189 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
1190 };
1191 return snd_interval_list(hw_param_interval(params, rule->var),
1192 ARRAY_SIZE(pow2_sizes), pow2_sizes, 0);
1193}
1194
1195/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001196 * snd_pcm_hw_constraint_pow2 - add a hw constraint power-of-2 rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001197 * @runtime: PCM runtime instance
1198 * @cond: condition bits
1199 * @var: hw_params variable to apply the power-of-2 constraint
Linus Torvalds1da177e2005-04-16 15:20:36 -07001200 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001201int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 unsigned int cond,
1203 snd_pcm_hw_param_t var)
1204{
1205 return snd_pcm_hw_rule_add(runtime, cond, var,
1206 snd_pcm_hw_rule_pow2, NULL,
1207 var, -1);
1208}
1209
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001210EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
1211
Takashi Iwai877211f2005-11-17 13:59:38 +01001212static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001213 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001214{
1215 if (hw_is_mask(var)) {
1216 snd_mask_any(hw_param_mask(params, var));
1217 params->cmask |= 1 << var;
1218 params->rmask |= 1 << var;
1219 return;
1220 }
1221 if (hw_is_interval(var)) {
1222 snd_interval_any(hw_param_interval(params, var));
1223 params->cmask |= 1 << var;
1224 params->rmask |= 1 << var;
1225 return;
1226 }
1227 snd_BUG();
1228}
1229
Takashi Iwai877211f2005-11-17 13:59:38 +01001230void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001231{
1232 unsigned int k;
1233 memset(params, 0, sizeof(*params));
1234 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
1235 _snd_pcm_hw_param_any(params, k);
1236 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
1237 _snd_pcm_hw_param_any(params, k);
1238 params->info = ~0U;
1239}
1240
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001241EXPORT_SYMBOL(_snd_pcm_hw_params_any);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001242
1243/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001244 * snd_pcm_hw_param_value - return @params field @var value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001245 * @params: the hw_params instance
1246 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001247 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001249 * Return the value for field @var if it's fixed in configuration space
1250 * defined by @params. Return -%EINVAL otherwise.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001252int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
1253 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001254{
1255 if (hw_is_mask(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001256 const struct snd_mask *mask = hw_param_mask_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 if (!snd_mask_single(mask))
1258 return -EINVAL;
1259 if (dir)
1260 *dir = 0;
1261 return snd_mask_value(mask);
1262 }
1263 if (hw_is_interval(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001264 const struct snd_interval *i = hw_param_interval_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 if (!snd_interval_single(i))
1266 return -EINVAL;
1267 if (dir)
1268 *dir = i->openmin;
1269 return snd_interval_value(i);
1270 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 return -EINVAL;
1272}
1273
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001274EXPORT_SYMBOL(snd_pcm_hw_param_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275
Takashi Iwai877211f2005-11-17 13:59:38 +01001276void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 snd_pcm_hw_param_t var)
1278{
1279 if (hw_is_mask(var)) {
1280 snd_mask_none(hw_param_mask(params, var));
1281 params->cmask |= 1 << var;
1282 params->rmask |= 1 << var;
1283 } else if (hw_is_interval(var)) {
1284 snd_interval_none(hw_param_interval(params, var));
1285 params->cmask |= 1 << var;
1286 params->rmask |= 1 << var;
1287 } else {
1288 snd_BUG();
1289 }
1290}
1291
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001292EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001293
Takashi Iwai877211f2005-11-17 13:59:38 +01001294static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001295 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296{
1297 int changed;
1298 if (hw_is_mask(var))
1299 changed = snd_mask_refine_first(hw_param_mask(params, var));
1300 else if (hw_is_interval(var))
1301 changed = snd_interval_refine_first(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001302 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 if (changed) {
1305 params->cmask |= 1 << var;
1306 params->rmask |= 1 << var;
1307 }
1308 return changed;
1309}
1310
1311
1312/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001313 * snd_pcm_hw_param_first - refine config space and return minimum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001314 * @pcm: PCM instance
1315 * @params: the hw_params instance
1316 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001317 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001319 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320 * values > minimum. Reduce configuration space accordingly.
1321 * Return the minimum.
1322 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001323int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
1324 struct snd_pcm_hw_params *params,
1325 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001326{
1327 int changed = _snd_pcm_hw_param_first(params, var);
1328 if (changed < 0)
1329 return changed;
1330 if (params->rmask) {
1331 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001332 if (snd_BUG_ON(err < 0))
1333 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334 }
1335 return snd_pcm_hw_param_value(params, var, dir);
1336}
1337
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001338EXPORT_SYMBOL(snd_pcm_hw_param_first);
1339
Takashi Iwai877211f2005-11-17 13:59:38 +01001340static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001341 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
1343 int changed;
1344 if (hw_is_mask(var))
1345 changed = snd_mask_refine_last(hw_param_mask(params, var));
1346 else if (hw_is_interval(var))
1347 changed = snd_interval_refine_last(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001348 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001349 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 if (changed) {
1351 params->cmask |= 1 << var;
1352 params->rmask |= 1 << var;
1353 }
1354 return changed;
1355}
1356
1357
1358/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001359 * snd_pcm_hw_param_last - refine config space and return maximum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001360 * @pcm: PCM instance
1361 * @params: the hw_params instance
1362 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001363 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001365 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 * values < maximum. Reduce configuration space accordingly.
1367 * Return the maximum.
1368 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001369int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
1370 struct snd_pcm_hw_params *params,
1371 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001372{
1373 int changed = _snd_pcm_hw_param_last(params, var);
1374 if (changed < 0)
1375 return changed;
1376 if (params->rmask) {
1377 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001378 if (snd_BUG_ON(err < 0))
1379 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 }
1381 return snd_pcm_hw_param_value(params, var, dir);
1382}
1383
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001384EXPORT_SYMBOL(snd_pcm_hw_param_last);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385
1386/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001387 * snd_pcm_hw_param_choose - choose a configuration defined by @params
Takashi Iwaidf8db932005-09-07 13:38:19 +02001388 * @pcm: PCM instance
1389 * @params: the hw_params instance
Linus Torvalds1da177e2005-04-16 15:20:36 -07001390 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001391 * Choose one configuration from configuration space defined by @params.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001392 * The configuration chosen is that obtained fixing in this order:
1393 * first access, first format, first subformat, min channels,
1394 * min rate, min period time, max buffer size, min tick time
1395 */
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001396int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
1397 struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001398{
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001399 static int vars[] = {
1400 SNDRV_PCM_HW_PARAM_ACCESS,
1401 SNDRV_PCM_HW_PARAM_FORMAT,
1402 SNDRV_PCM_HW_PARAM_SUBFORMAT,
1403 SNDRV_PCM_HW_PARAM_CHANNELS,
1404 SNDRV_PCM_HW_PARAM_RATE,
1405 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
1406 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1407 SNDRV_PCM_HW_PARAM_TICK_TIME,
1408 -1
1409 };
1410 int err, *v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001412 for (v = vars; *v != -1; v++) {
1413 if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
1414 err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
1415 else
1416 err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001417 if (snd_BUG_ON(err < 0))
1418 return err;
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001419 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 return 0;
1421}
1422
Takashi Iwai877211f2005-11-17 13:59:38 +01001423static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 void *arg)
1425{
Takashi Iwai877211f2005-11-17 13:59:38 +01001426 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427 unsigned long flags;
1428 snd_pcm_stream_lock_irqsave(substream, flags);
1429 if (snd_pcm_running(substream) &&
1430 snd_pcm_update_hw_ptr(substream) >= 0)
1431 runtime->status->hw_ptr %= runtime->buffer_size;
1432 else
1433 runtime->status->hw_ptr = 0;
1434 snd_pcm_stream_unlock_irqrestore(substream, flags);
1435 return 0;
1436}
1437
Takashi Iwai877211f2005-11-17 13:59:38 +01001438static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001439 void *arg)
1440{
Takashi Iwai877211f2005-11-17 13:59:38 +01001441 struct snd_pcm_channel_info *info = arg;
1442 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001443 int width;
1444 if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
1445 info->offset = -1;
1446 return 0;
1447 }
1448 width = snd_pcm_format_physical_width(runtime->format);
1449 if (width < 0)
1450 return width;
1451 info->offset = 0;
1452 switch (runtime->access) {
1453 case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
1454 case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
1455 info->first = info->channel * width;
1456 info->step = runtime->channels * width;
1457 break;
1458 case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
1459 case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
1460 {
1461 size_t size = runtime->dma_bytes / runtime->channels;
1462 info->first = info->channel * size * 8;
1463 info->step = width;
1464 break;
1465 }
1466 default:
1467 snd_BUG();
1468 break;
1469 }
1470 return 0;
1471}
1472
1473/**
1474 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1475 * @substream: the pcm substream instance
1476 * @cmd: ioctl command
1477 * @arg: ioctl argument
1478 *
1479 * Processes the generic ioctl commands for PCM.
1480 * Can be passed as the ioctl callback for PCM ops.
1481 *
1482 * Returns zero if successful, or a negative error code on failure.
1483 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001484int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 unsigned int cmd, void *arg)
1486{
1487 switch (cmd) {
1488 case SNDRV_PCM_IOCTL1_INFO:
1489 return 0;
1490 case SNDRV_PCM_IOCTL1_RESET:
1491 return snd_pcm_lib_ioctl_reset(substream, arg);
1492 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1493 return snd_pcm_lib_ioctl_channel_info(substream, arg);
1494 }
1495 return -ENXIO;
1496}
1497
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001498EXPORT_SYMBOL(snd_pcm_lib_ioctl);
1499
Linus Torvalds1da177e2005-04-16 15:20:36 -07001500/**
1501 * snd_pcm_period_elapsed - update the pcm status for the next period
1502 * @substream: the pcm substream instance
1503 *
1504 * This function is called from the interrupt handler when the
1505 * PCM has processed the period size. It will update the current
Takashi Iwai31e89602008-01-08 18:09:57 +01001506 * pointer, wake up sleepers, etc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001507 *
1508 * Even if more than one periods have elapsed since the last call, you
1509 * have to call this only once.
1510 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001511void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512{
Takashi Iwai877211f2005-11-17 13:59:38 +01001513 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001514 unsigned long flags;
1515
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001516 if (PCM_RUNTIME_CHECK(substream))
1517 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001518 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001519
1520 if (runtime->transfer_ack_begin)
1521 runtime->transfer_ack_begin(substream);
1522
1523 snd_pcm_stream_lock_irqsave(substream, flags);
1524 if (!snd_pcm_running(substream) ||
1525 snd_pcm_update_hw_ptr_interrupt(substream) < 0)
1526 goto _end;
1527
1528 if (substream->timer_running)
1529 snd_timer_interrupt(substream->timer, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 _end:
1531 snd_pcm_stream_unlock_irqrestore(substream, flags);
1532 if (runtime->transfer_ack_end)
1533 runtime->transfer_ack_end(substream);
1534 kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
1535}
1536
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001537EXPORT_SYMBOL(snd_pcm_period_elapsed);
1538
Takashi Iwai13075512008-01-08 18:08:14 +01001539/*
1540 * Wait until avail_min data becomes available
1541 * Returns a negative error code if any error occurs during operation.
1542 * The available space is stored on availp. When err = 0 and avail = 0
1543 * on the capture stream, it indicates the stream is in DRAINING state.
1544 */
1545static int wait_for_avail_min(struct snd_pcm_substream *substream,
1546 snd_pcm_uframes_t *availp)
1547{
1548 struct snd_pcm_runtime *runtime = substream->runtime;
1549 int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
1550 wait_queue_t wait;
1551 int err = 0;
1552 snd_pcm_uframes_t avail = 0;
1553 long tout;
1554
1555 init_waitqueue_entry(&wait, current);
1556 add_wait_queue(&runtime->sleep, &wait);
1557 for (;;) {
1558 if (signal_pending(current)) {
1559 err = -ERESTARTSYS;
1560 break;
1561 }
1562 set_current_state(TASK_INTERRUPTIBLE);
1563 snd_pcm_stream_unlock_irq(substream);
1564 tout = schedule_timeout(msecs_to_jiffies(10000));
1565 snd_pcm_stream_lock_irq(substream);
1566 switch (runtime->status->state) {
1567 case SNDRV_PCM_STATE_SUSPENDED:
1568 err = -ESTRPIPE;
1569 goto _endloop;
1570 case SNDRV_PCM_STATE_XRUN:
1571 err = -EPIPE;
1572 goto _endloop;
1573 case SNDRV_PCM_STATE_DRAINING:
1574 if (is_playback)
1575 err = -EPIPE;
1576 else
1577 avail = 0; /* indicate draining */
1578 goto _endloop;
1579 case SNDRV_PCM_STATE_OPEN:
1580 case SNDRV_PCM_STATE_SETUP:
1581 case SNDRV_PCM_STATE_DISCONNECTED:
1582 err = -EBADFD;
1583 goto _endloop;
1584 }
1585 if (!tout) {
1586 snd_printd("%s write error (DMA or IRQ trouble?)\n",
1587 is_playback ? "playback" : "capture");
1588 err = -EIO;
1589 break;
1590 }
1591 if (is_playback)
1592 avail = snd_pcm_playback_avail(runtime);
1593 else
1594 avail = snd_pcm_capture_avail(runtime);
1595 if (avail >= runtime->control->avail_min)
1596 break;
1597 }
1598 _endloop:
1599 remove_wait_queue(&runtime->sleep, &wait);
1600 *availp = avail;
1601 return err;
1602}
1603
Takashi Iwai877211f2005-11-17 13:59:38 +01001604static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605 unsigned int hwoff,
1606 unsigned long data, unsigned int off,
1607 snd_pcm_uframes_t frames)
1608{
Takashi Iwai877211f2005-11-17 13:59:38 +01001609 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 int err;
1611 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
1612 if (substream->ops->copy) {
1613 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
1614 return err;
1615 } else {
1616 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
1618 return -EFAULT;
1619 }
1620 return 0;
1621}
1622
Takashi Iwai877211f2005-11-17 13:59:38 +01001623typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001624 unsigned long data, unsigned int off,
1625 snd_pcm_uframes_t size);
1626
Takashi Iwai877211f2005-11-17 13:59:38 +01001627static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001628 unsigned long data,
1629 snd_pcm_uframes_t size,
1630 int nonblock,
1631 transfer_f transfer)
1632{
Takashi Iwai877211f2005-11-17 13:59:38 +01001633 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 snd_pcm_uframes_t xfer = 0;
1635 snd_pcm_uframes_t offset = 0;
1636 int err = 0;
1637
1638 if (size == 0)
1639 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640
1641 snd_pcm_stream_lock_irq(substream);
1642 switch (runtime->status->state) {
1643 case SNDRV_PCM_STATE_PREPARED:
1644 case SNDRV_PCM_STATE_RUNNING:
1645 case SNDRV_PCM_STATE_PAUSED:
1646 break;
1647 case SNDRV_PCM_STATE_XRUN:
1648 err = -EPIPE;
1649 goto _end_unlock;
1650 case SNDRV_PCM_STATE_SUSPENDED:
1651 err = -ESTRPIPE;
1652 goto _end_unlock;
1653 default:
1654 err = -EBADFD;
1655 goto _end_unlock;
1656 }
1657
1658 while (size > 0) {
1659 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1660 snd_pcm_uframes_t avail;
1661 snd_pcm_uframes_t cont;
Takashi Iwai31e89602008-01-08 18:09:57 +01001662 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 snd_pcm_update_hw_ptr(substream);
1664 avail = snd_pcm_playback_avail(runtime);
Takashi Iwai13075512008-01-08 18:08:14 +01001665 if (!avail) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001666 if (nonblock) {
1667 err = -EAGAIN;
1668 goto _end_unlock;
1669 }
Takashi Iwai13075512008-01-08 18:08:14 +01001670 err = wait_for_avail_min(substream, &avail);
1671 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674 frames = size > avail ? avail : size;
1675 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
1676 if (frames > cont)
1677 frames = cont;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001678 if (snd_BUG_ON(!frames)) {
1679 snd_pcm_stream_unlock_irq(substream);
1680 return -EINVAL;
1681 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001682 appl_ptr = runtime->control->appl_ptr;
1683 appl_ofs = appl_ptr % runtime->buffer_size;
1684 snd_pcm_stream_unlock_irq(substream);
1685 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
1686 goto _end;
1687 snd_pcm_stream_lock_irq(substream);
1688 switch (runtime->status->state) {
1689 case SNDRV_PCM_STATE_XRUN:
1690 err = -EPIPE;
1691 goto _end_unlock;
1692 case SNDRV_PCM_STATE_SUSPENDED:
1693 err = -ESTRPIPE;
1694 goto _end_unlock;
1695 default:
1696 break;
1697 }
1698 appl_ptr += frames;
1699 if (appl_ptr >= runtime->boundary)
1700 appl_ptr -= runtime->boundary;
1701 runtime->control->appl_ptr = appl_ptr;
1702 if (substream->ops->ack)
1703 substream->ops->ack(substream);
1704
1705 offset += frames;
1706 size -= frames;
1707 xfer += frames;
1708 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
1709 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
1710 err = snd_pcm_start(substream);
1711 if (err < 0)
1712 goto _end_unlock;
1713 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714 }
1715 _end_unlock:
1716 snd_pcm_stream_unlock_irq(substream);
1717 _end:
1718 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
1719}
1720
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001721/* sanity-check for read/write methods */
1722static int pcm_sanity_check(struct snd_pcm_substream *substream)
1723{
1724 struct snd_pcm_runtime *runtime;
1725 if (PCM_RUNTIME_CHECK(substream))
1726 return -ENXIO;
1727 runtime = substream->runtime;
1728 if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
1729 return -EINVAL;
1730 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1731 return -EBADFD;
1732 return 0;
1733}
1734
Takashi Iwai877211f2005-11-17 13:59:38 +01001735snd_pcm_sframes_t snd_pcm_lib_write(struct snd_pcm_substream *substream, const void __user *buf, snd_pcm_uframes_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001736{
Takashi Iwai877211f2005-11-17 13:59:38 +01001737 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001738 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001739 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001740
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001741 err = pcm_sanity_check(substream);
1742 if (err < 0)
1743 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02001745 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001746
1747 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
1748 runtime->channels > 1)
1749 return -EINVAL;
1750 return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
1751 snd_pcm_lib_write_transfer);
1752}
1753
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001754EXPORT_SYMBOL(snd_pcm_lib_write);
1755
Takashi Iwai877211f2005-11-17 13:59:38 +01001756static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 unsigned int hwoff,
1758 unsigned long data, unsigned int off,
1759 snd_pcm_uframes_t frames)
1760{
Takashi Iwai877211f2005-11-17 13:59:38 +01001761 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762 int err;
1763 void __user **bufs = (void __user **)data;
1764 int channels = runtime->channels;
1765 int c;
1766 if (substream->ops->copy) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001767 if (snd_BUG_ON(!substream->ops->silence))
1768 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769 for (c = 0; c < channels; ++c, ++bufs) {
1770 if (*bufs == NULL) {
1771 if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
1772 return err;
1773 } else {
1774 char __user *buf = *bufs + samples_to_bytes(runtime, off);
1775 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
1776 return err;
1777 }
1778 }
1779 } else {
1780 /* default transfer behaviour */
1781 size_t dma_csize = runtime->dma_bytes / channels;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782 for (c = 0; c < channels; ++c, ++bufs) {
1783 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
1784 if (*bufs == NULL) {
1785 snd_pcm_format_set_silence(runtime->format, hwbuf, frames);
1786 } else {
1787 char __user *buf = *bufs + samples_to_bytes(runtime, off);
1788 if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames)))
1789 return -EFAULT;
1790 }
1791 }
1792 }
1793 return 0;
1794}
1795
Takashi Iwai877211f2005-11-17 13:59:38 +01001796snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 void __user **bufs,
1798 snd_pcm_uframes_t frames)
1799{
Takashi Iwai877211f2005-11-17 13:59:38 +01001800 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001802 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001804 err = pcm_sanity_check(substream);
1805 if (err < 0)
1806 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001807 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02001808 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001809
1810 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
1811 return -EINVAL;
1812 return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames,
1813 nonblock, snd_pcm_lib_writev_transfer);
1814}
1815
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001816EXPORT_SYMBOL(snd_pcm_lib_writev);
1817
Takashi Iwai877211f2005-11-17 13:59:38 +01001818static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819 unsigned int hwoff,
1820 unsigned long data, unsigned int off,
1821 snd_pcm_uframes_t frames)
1822{
Takashi Iwai877211f2005-11-17 13:59:38 +01001823 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001824 int err;
1825 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
1826 if (substream->ops->copy) {
1827 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
1828 return err;
1829 } else {
1830 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001831 if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
1832 return -EFAULT;
1833 }
1834 return 0;
1835}
1836
Takashi Iwai877211f2005-11-17 13:59:38 +01001837static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001838 unsigned long data,
1839 snd_pcm_uframes_t size,
1840 int nonblock,
1841 transfer_f transfer)
1842{
Takashi Iwai877211f2005-11-17 13:59:38 +01001843 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 snd_pcm_uframes_t xfer = 0;
1845 snd_pcm_uframes_t offset = 0;
1846 int err = 0;
1847
1848 if (size == 0)
1849 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001850
1851 snd_pcm_stream_lock_irq(substream);
1852 switch (runtime->status->state) {
1853 case SNDRV_PCM_STATE_PREPARED:
1854 if (size >= runtime->start_threshold) {
1855 err = snd_pcm_start(substream);
1856 if (err < 0)
1857 goto _end_unlock;
1858 }
1859 break;
1860 case SNDRV_PCM_STATE_DRAINING:
1861 case SNDRV_PCM_STATE_RUNNING:
1862 case SNDRV_PCM_STATE_PAUSED:
1863 break;
1864 case SNDRV_PCM_STATE_XRUN:
1865 err = -EPIPE;
1866 goto _end_unlock;
1867 case SNDRV_PCM_STATE_SUSPENDED:
1868 err = -ESTRPIPE;
1869 goto _end_unlock;
1870 default:
1871 err = -EBADFD;
1872 goto _end_unlock;
1873 }
1874
1875 while (size > 0) {
1876 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1877 snd_pcm_uframes_t avail;
1878 snd_pcm_uframes_t cont;
Takashi Iwai31e89602008-01-08 18:09:57 +01001879 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001880 snd_pcm_update_hw_ptr(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 avail = snd_pcm_capture_avail(runtime);
Takashi Iwai13075512008-01-08 18:08:14 +01001882 if (!avail) {
1883 if (runtime->status->state ==
1884 SNDRV_PCM_STATE_DRAINING) {
1885 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001886 goto _end_unlock;
1887 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001888 if (nonblock) {
1889 err = -EAGAIN;
1890 goto _end_unlock;
1891 }
Takashi Iwai13075512008-01-08 18:08:14 +01001892 err = wait_for_avail_min(substream, &avail);
1893 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001894 goto _end_unlock;
Takashi Iwai13075512008-01-08 18:08:14 +01001895 if (!avail)
1896 continue; /* draining */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 frames = size > avail ? avail : size;
1899 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
1900 if (frames > cont)
1901 frames = cont;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001902 if (snd_BUG_ON(!frames)) {
1903 snd_pcm_stream_unlock_irq(substream);
1904 return -EINVAL;
1905 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001906 appl_ptr = runtime->control->appl_ptr;
1907 appl_ofs = appl_ptr % runtime->buffer_size;
1908 snd_pcm_stream_unlock_irq(substream);
1909 if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0)
1910 goto _end;
1911 snd_pcm_stream_lock_irq(substream);
1912 switch (runtime->status->state) {
1913 case SNDRV_PCM_STATE_XRUN:
1914 err = -EPIPE;
1915 goto _end_unlock;
1916 case SNDRV_PCM_STATE_SUSPENDED:
1917 err = -ESTRPIPE;
1918 goto _end_unlock;
1919 default:
1920 break;
1921 }
1922 appl_ptr += frames;
1923 if (appl_ptr >= runtime->boundary)
1924 appl_ptr -= runtime->boundary;
1925 runtime->control->appl_ptr = appl_ptr;
1926 if (substream->ops->ack)
1927 substream->ops->ack(substream);
1928
1929 offset += frames;
1930 size -= frames;
1931 xfer += frames;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 }
1933 _end_unlock:
1934 snd_pcm_stream_unlock_irq(substream);
1935 _end:
1936 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
1937}
1938
Takashi Iwai877211f2005-11-17 13:59:38 +01001939snd_pcm_sframes_t snd_pcm_lib_read(struct snd_pcm_substream *substream, void __user *buf, snd_pcm_uframes_t size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001940{
Takashi Iwai877211f2005-11-17 13:59:38 +01001941 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001943 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001945 err = pcm_sanity_check(substream);
1946 if (err < 0)
1947 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001948 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02001949 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
1951 return -EINVAL;
1952 return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
1953}
1954
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001955EXPORT_SYMBOL(snd_pcm_lib_read);
1956
Takashi Iwai877211f2005-11-17 13:59:38 +01001957static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001958 unsigned int hwoff,
1959 unsigned long data, unsigned int off,
1960 snd_pcm_uframes_t frames)
1961{
Takashi Iwai877211f2005-11-17 13:59:38 +01001962 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001963 int err;
1964 void __user **bufs = (void __user **)data;
1965 int channels = runtime->channels;
1966 int c;
1967 if (substream->ops->copy) {
1968 for (c = 0; c < channels; ++c, ++bufs) {
1969 char __user *buf;
1970 if (*bufs == NULL)
1971 continue;
1972 buf = *bufs + samples_to_bytes(runtime, off);
1973 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
1974 return err;
1975 }
1976 } else {
1977 snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001978 for (c = 0; c < channels; ++c, ++bufs) {
1979 char *hwbuf;
1980 char __user *buf;
1981 if (*bufs == NULL)
1982 continue;
1983
1984 hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
1985 buf = *bufs + samples_to_bytes(runtime, off);
1986 if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames)))
1987 return -EFAULT;
1988 }
1989 }
1990 return 0;
1991}
1992
Takashi Iwai877211f2005-11-17 13:59:38 +01001993snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994 void __user **bufs,
1995 snd_pcm_uframes_t frames)
1996{
Takashi Iwai877211f2005-11-17 13:59:38 +01001997 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001999 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002000
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002001 err = pcm_sanity_check(substream);
2002 if (err < 0)
2003 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002004 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2006 return -EBADFD;
2007
Takashi Iwai0df63e42006-04-28 15:13:41 +02002008 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002009 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2010 return -EINVAL;
2011 return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
2012}
2013
Linus Torvalds1da177e2005-04-16 15:20:36 -07002014EXPORT_SYMBOL(snd_pcm_lib_readv);