blob: db947414c3ca9b39f42117c7c44f0c1cc79c5050 [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
Bryan Huntsman3f2bc4d2011-08-16 17:27:22 -07009 * the Free Software Foundation; only version 2 of the License.
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 *
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
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/slab.h>
23#include <linux/time.h>
Takashi Iwai3f7440a2009-06-05 17:40:04 +020024#include <linux/math64.h>
Paul Gortmakerd81a6d72011-09-22 09:34:58 -040025#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026#include <sound/core.h>
27#include <sound/control.h>
Subhash Chandra Bose Naripeddyff1e6252012-10-18 15:44:12 -070028#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include <sound/info.h>
30#include <sound/pcm.h>
31#include <sound/pcm_params.h>
32#include <sound/timer.h>
33
Subhash Chandra Bose Naripeddy58f7b952013-04-25 19:32:52 -070034#define STRING_LENGTH_OF_INT 12
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/*
37 * fill ring buffer with silence
38 * runtime->silence_start: starting pointer to silence area
39 * runtime->silence_filled: size filled with silence
40 * runtime->silence_threshold: threshold from application
41 * runtime->silence_size: maximal size from application
42 *
43 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
44 */
Takashi Iwai877211f2005-11-17 13:59:38 +010045void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070046{
Takashi Iwai877211f2005-11-17 13:59:38 +010047 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048 snd_pcm_uframes_t frames, ofs, transfer;
49
50 if (runtime->silence_size < runtime->boundary) {
51 snd_pcm_sframes_t noise_dist, n;
52 if (runtime->silence_start != runtime->control->appl_ptr) {
53 n = runtime->control->appl_ptr - runtime->silence_start;
54 if (n < 0)
55 n += runtime->boundary;
56 if ((snd_pcm_uframes_t)n < runtime->silence_filled)
57 runtime->silence_filled -= n;
58 else
59 runtime->silence_filled = 0;
60 runtime->silence_start = runtime->control->appl_ptr;
61 }
Takashi Iwai235475c2005-12-07 15:28:07 +010062 if (runtime->silence_filled >= runtime->buffer_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
65 if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
66 return;
67 frames = runtime->silence_threshold - noise_dist;
68 if (frames > runtime->silence_size)
69 frames = runtime->silence_size;
70 } else {
71 if (new_hw_ptr == ULONG_MAX) { /* initialization */
72 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
Jaroslav Kysela9e216e82010-07-19 16:37:39 +020073 if (avail > runtime->buffer_size)
74 avail = runtime->buffer_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070075 runtime->silence_filled = avail > 0 ? avail : 0;
76 runtime->silence_start = (runtime->status->hw_ptr +
77 runtime->silence_filled) %
78 runtime->boundary;
79 } else {
80 ofs = runtime->status->hw_ptr;
81 frames = new_hw_ptr - ofs;
82 if ((snd_pcm_sframes_t)frames < 0)
83 frames += runtime->boundary;
84 runtime->silence_filled -= frames;
85 if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
86 runtime->silence_filled = 0;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020087 runtime->silence_start = new_hw_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 } else {
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020089 runtime->silence_start = ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 }
92 frames = runtime->buffer_size - runtime->silence_filled;
93 }
Takashi Iwai7eaa9432008-08-08 17:09:09 +020094 if (snd_BUG_ON(frames > runtime->buffer_size))
95 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 if (frames == 0)
97 return;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +020098 ofs = runtime->silence_start % runtime->buffer_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 while (frames > 0) {
100 transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
101 if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
102 runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED) {
103 if (substream->ops->silence) {
104 int err;
105 err = substream->ops->silence(substream, -1, ofs, transfer);
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200106 snd_BUG_ON(err < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 } else {
108 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, ofs);
109 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer * runtime->channels);
110 }
111 } else {
112 unsigned int c;
113 unsigned int channels = runtime->channels;
114 if (substream->ops->silence) {
115 for (c = 0; c < channels; ++c) {
116 int err;
117 err = substream->ops->silence(substream, c, ofs, transfer);
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200118 snd_BUG_ON(err < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 }
120 } else {
121 size_t dma_csize = runtime->dma_bytes / channels;
122 for (c = 0; c < channels; ++c) {
123 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, ofs);
124 snd_pcm_format_set_silence(runtime->format, hwbuf, transfer);
125 }
126 }
127 }
128 runtime->silence_filled += transfer;
129 frames -= transfer;
130 ofs = 0;
131 }
132}
133
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200134#ifdef CONFIG_SND_DEBUG
135void snd_pcm_debug_name(struct snd_pcm_substream *substream,
Takashi Iwaic0070112009-06-08 15:58:48 +0200136 char *name, size_t len)
137{
138 snprintf(name, len, "pcmC%dD%d%c:%d",
139 substream->pcm->card->number,
140 substream->pcm->device,
141 substream->stream ? 'c' : 'p',
142 substream->number);
143}
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200144EXPORT_SYMBOL(snd_pcm_debug_name);
145#endif
Takashi Iwaic0070112009-06-08 15:58:48 +0200146
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100147#define XRUN_DEBUG_BASIC (1<<0)
148#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
149#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
150#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
151#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
152#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
153#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
154
155#ifdef CONFIG_SND_PCM_XRUN_DEBUG
156
157#define xrun_debug(substream, mask) \
158 ((substream)->pstr->xrun_debug & (mask))
Jarkko Nikula0f170142010-03-26 16:07:25 +0200159#else
160#define xrun_debug(substream, mask) 0
161#endif
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100162
163#define dump_stack_on_xrun(substream) do { \
164 if (xrun_debug(substream, XRUN_DEBUG_STACK)) \
165 dump_stack(); \
166 } while (0)
167
Takashi Iwai877211f2005-11-17 13:59:38 +0100168static void xrun(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169{
Jaroslav Kysela13f040f2009-05-28 11:31:20 +0200170 struct snd_pcm_runtime *runtime = substream->runtime;
171
172 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
173 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
Jaroslav Kysela741b20c2009-12-17 17:34:39 +0100175 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
Takashi Iwaic0070112009-06-08 15:58:48 +0200176 char name[16];
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200177 snd_pcm_debug_name(substream, name, sizeof(name));
Takashi Iwaic0070112009-06-08 15:58:48 +0200178 snd_printd(KERN_DEBUG "XRUN: %s\n", name);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100179 dump_stack_on_xrun(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181}
182
Jarkko Nikula0f170142010-03-26 16:07:25 +0200183#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100184#define hw_ptr_error(substream, fmt, args...) \
185 do { \
186 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100187 xrun_log_show(substream); \
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100188 if (printk_ratelimit()) { \
189 snd_printd("PCM: " fmt, ##args); \
190 } \
191 dump_stack_on_xrun(substream); \
192 } \
193 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100195#define XRUN_LOG_CNT 10
196
197struct hwptr_log_entry {
Ben Gardinerec08b142011-05-18 10:03:34 -0400198 unsigned int in_interrupt;
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100199 unsigned long jiffies;
200 snd_pcm_uframes_t pos;
201 snd_pcm_uframes_t period_size;
202 snd_pcm_uframes_t buffer_size;
203 snd_pcm_uframes_t old_hw_ptr;
204 snd_pcm_uframes_t hw_ptr_base;
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100205};
206
207struct snd_pcm_hwptr_log {
208 unsigned int idx;
209 unsigned int hit: 1;
210 struct hwptr_log_entry entries[XRUN_LOG_CNT];
211};
212
213static void xrun_log(struct snd_pcm_substream *substream,
Ben Gardinerec08b142011-05-18 10:03:34 -0400214 snd_pcm_uframes_t pos, int in_interrupt)
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100215{
216 struct snd_pcm_runtime *runtime = substream->runtime;
217 struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
218 struct hwptr_log_entry *entry;
219
220 if (log == NULL) {
221 log = kzalloc(sizeof(*log), GFP_ATOMIC);
222 if (log == NULL)
223 return;
224 runtime->hwptr_log = log;
225 } else {
226 if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
227 return;
Takashi Iwai7c22f1a2005-10-10 11:46:31 +0200228 }
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100229 entry = &log->entries[log->idx];
Ben Gardinerec08b142011-05-18 10:03:34 -0400230 entry->in_interrupt = in_interrupt;
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100231 entry->jiffies = jiffies;
232 entry->pos = pos;
233 entry->period_size = runtime->period_size;
Joe Perchesc80c1d52010-11-14 19:05:02 -0800234 entry->buffer_size = runtime->buffer_size;
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100235 entry->old_hw_ptr = runtime->status->hw_ptr;
236 entry->hw_ptr_base = runtime->hw_ptr_base;
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100237 log->idx = (log->idx + 1) % XRUN_LOG_CNT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700238}
239
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100240static void xrun_log_show(struct snd_pcm_substream *substream)
241{
242 struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
243 struct hwptr_log_entry *entry;
244 char name[16];
245 unsigned int idx;
246 int cnt;
247
248 if (log == NULL)
249 return;
250 if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
251 return;
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200252 snd_pcm_debug_name(substream, name, sizeof(name));
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100253 for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
254 entry = &log->entries[idx];
255 if (entry->period_size == 0)
256 break;
Ben Gardinerec08b142011-05-18 10:03:34 -0400257 snd_printd("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100258 "hwptr=%ld/%ld\n",
Ben Gardinerec08b142011-05-18 10:03:34 -0400259 name, entry->in_interrupt ? "[Q] " : "",
260 entry->jiffies,
261 (unsigned long)entry->pos,
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100262 (unsigned long)entry->period_size,
263 (unsigned long)entry->buffer_size,
264 (unsigned long)entry->old_hw_ptr,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100265 (unsigned long)entry->hw_ptr_base);
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100266 idx++;
267 idx %= XRUN_LOG_CNT;
268 }
269 log->hit = 1;
270}
271
272#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
273
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100274#define hw_ptr_error(substream, fmt, args...) do { } while (0)
Ben Gardiner217658f2011-05-18 23:52:38 -0400275#define xrun_log(substream, pos, in_interrupt) do { } while (0)
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100276#define xrun_log_show(substream) do { } while (0)
277
278#endif
279
Jaroslav Kysela12509322010-01-07 15:36:31 +0100280int snd_pcm_update_state(struct snd_pcm_substream *substream,
281 struct snd_pcm_runtime *runtime)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282{
283 snd_pcm_uframes_t avail;
284
285 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
286 avail = snd_pcm_playback_avail(runtime);
287 else
288 avail = snd_pcm_capture_avail(runtime);
289 if (avail > runtime->avail_max)
290 runtime->avail_max = avail;
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200291 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
292 if (avail >= runtime->buffer_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700293 snd_pcm_drain_done(substream);
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200294 return -EPIPE;
295 }
296 } else {
297 if (avail >= runtime->stop_threshold) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700298 xrun(substream);
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200299 return -EPIPE;
300 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 }
David Dillow5daeba32010-06-27 00:13:20 +0200302 if (runtime->twake) {
303 if (avail >= runtime->twake)
304 wake_up(&runtime->tsleep);
305 } else if (avail >= runtime->control->avail_min)
306 wake_up(&runtime->sleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700307 return 0;
308}
309
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100310static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
311 unsigned int in_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700312{
Takashi Iwai877211f2005-11-17 13:59:38 +0100313 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700314 snd_pcm_uframes_t pos;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100315 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200316 snd_pcm_sframes_t hdelta, delta;
317 unsigned long jdelta;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200319 old_hw_ptr = runtime->status->hw_ptr;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100320 pos = substream->ops->pointer(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700321 if (pos == SNDRV_PCM_POS_XRUN) {
322 xrun(substream);
323 return -EPIPE;
324 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100325 if (pos >= runtime->buffer_size) {
326 if (printk_ratelimit()) {
327 char name[16];
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200328 snd_pcm_debug_name(substream, name, sizeof(name));
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100329 xrun_log_show(substream);
330 snd_printd(KERN_ERR "BUG: %s, pos = %ld, "
331 "buffer size = %ld, period size = %ld\n",
332 name, pos, runtime->buffer_size,
333 runtime->period_size);
334 }
335 pos = 0;
Takashi Iwaicedb8112009-07-23 11:04:13 +0200336 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100337 pos -= pos % runtime->min_align;
338 if (xrun_debug(substream, XRUN_DEBUG_LOG))
Ben Gardinerec08b142011-05-18 10:03:34 -0400339 xrun_log(substream, pos, in_interrupt);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100340 hw_base = runtime->hw_ptr_base;
341 new_hw_ptr = hw_base + pos;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100342 if (in_interrupt) {
343 /* we know that one period was processed */
344 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100345 delta = runtime->hw_ptr_interrupt + runtime->period_size;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100346 if (delta > new_hw_ptr) {
Jaroslav Kyselabd76af02010-08-18 14:16:54 +0200347 /* check for double acknowledged interrupts */
348 hdelta = jiffies - runtime->hw_ptr_jiffies;
349 if (hdelta > runtime->hw_ptr_buffer_jiffies/2) {
350 hw_base += runtime->buffer_size;
351 if (hw_base >= runtime->boundary)
352 hw_base = 0;
353 new_hw_ptr = hw_base + pos;
354 goto __delta;
355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100358 /* new_hw_ptr might be lower than old_hw_ptr in case when */
359 /* pointer crosses the end of the ring buffer */
360 if (new_hw_ptr < old_hw_ptr) {
361 hw_base += runtime->buffer_size;
362 if (hw_base >= runtime->boundary)
363 hw_base = 0;
364 new_hw_ptr = hw_base + pos;
365 }
366 __delta:
Clemens Ladischb406e612010-05-25 09:01:46 +0200367 delta = new_hw_ptr - old_hw_ptr;
368 if (delta < 0)
369 delta += runtime->boundary;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100370 if (xrun_debug(substream, in_interrupt ?
371 XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
372 char name[16];
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200373 snd_pcm_debug_name(substream, name, sizeof(name));
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100374 snd_printd("%s_update: %s: pos=%u/%u/%u, "
375 "hwptr=%ld/%ld/%ld/%ld\n",
376 in_interrupt ? "period" : "hwptr",
377 name,
378 (unsigned int)pos,
379 (unsigned int)runtime->period_size,
380 (unsigned int)runtime->buffer_size,
381 (unsigned long)delta,
382 (unsigned long)old_hw_ptr,
383 (unsigned long)new_hw_ptr,
384 (unsigned long)runtime->hw_ptr_base);
385 }
Clemens Ladischab69a492010-11-15 10:46:23 +0100386
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100387 if (runtime->no_period_wakeup) {
Kelly Anderson12ff4142011-04-01 11:58:25 +0200388 snd_pcm_sframes_t xrun_threshold;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100389 /*
390 * Without regular period interrupts, we have to check
391 * the elapsed time to detect xruns.
392 */
393 jdelta = jiffies - runtime->hw_ptr_jiffies;
Clemens Ladisch47228e42010-11-18 09:53:07 +0100394 if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
395 goto no_delta_check;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100396 hdelta = jdelta - delta * HZ / runtime->rate;
Kelly Anderson12ff4142011-04-01 11:58:25 +0200397 xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
398 while (hdelta > xrun_threshold) {
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100399 delta += runtime->buffer_size;
400 hw_base += runtime->buffer_size;
401 if (hw_base >= runtime->boundary)
402 hw_base = 0;
403 new_hw_ptr = hw_base + pos;
404 hdelta -= runtime->hw_ptr_buffer_jiffies;
405 }
Clemens Ladischab69a492010-11-15 10:46:23 +0100406 goto no_delta_check;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100407 }
Clemens Ladischab69a492010-11-15 10:46:23 +0100408
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100409 /* something must be really wrong */
Jaroslav Kysela7b3a1772010-01-08 08:43:01 +0100410 if (delta >= runtime->buffer_size + runtime->period_size) {
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100411 hw_ptr_error(substream,
412 "Unexpected hw_pointer value %s"
413 "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
414 "old_hw_ptr=%ld)\n",
415 in_interrupt ? "[Q] " : "[P]",
416 substream->stream, (long)pos,
417 (long)new_hw_ptr, (long)old_hw_ptr);
418 return 0;
419 }
Takashi Iwaic87d9732009-05-27 10:53:33 +0200420
421 /* Do jiffies check only in xrun_debug mode */
Jaroslav Kysela741b20c2009-12-17 17:34:39 +0100422 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
Takashi Iwaic87d9732009-05-27 10:53:33 +0200423 goto no_jiffies_check;
424
Takashi Iwai3e5b5012009-04-28 12:07:08 +0200425 /* Skip the jiffies check for hardwares with BATCH flag.
426 * Such hardware usually just increases the position at each IRQ,
427 * thus it can't give any strange position.
428 */
429 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
430 goto no_jiffies_check;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100431 hdelta = delta;
Jaroslav Kyselaa4444da2009-05-28 12:31:56 +0200432 if (hdelta < runtime->delay)
433 goto no_jiffies_check;
434 hdelta -= runtime->delay;
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200435 jdelta = jiffies - runtime->hw_ptr_jiffies;
436 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
437 delta = jdelta /
438 (((runtime->period_size * HZ) / runtime->rate)
439 + HZ/100);
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100440 /* move new_hw_ptr according jiffies not pos variable */
441 new_hw_ptr = old_hw_ptr;
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100442 hw_base = delta;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100443 /* use loop to avoid checks for delta overflows */
444 /* the delta value is small or zero in most cases */
445 while (delta > 0) {
446 new_hw_ptr += runtime->period_size;
447 if (new_hw_ptr >= runtime->boundary)
448 new_hw_ptr -= runtime->boundary;
449 delta--;
450 }
451 /* align hw_base to buffer_size */
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200452 hw_ptr_error(substream,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100453 "hw_ptr skipping! %s"
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200454 "(pos=%ld, delta=%ld, period=%ld, "
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100455 "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
456 in_interrupt ? "[Q] " : "",
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200457 (long)pos, (long)hdelta,
458 (long)runtime->period_size, jdelta,
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100459 ((hdelta * HZ) / runtime->rate), hw_base,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100460 (unsigned long)old_hw_ptr,
461 (unsigned long)new_hw_ptr);
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100462 /* reset values to proper state */
463 delta = 0;
464 hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200465 }
Takashi Iwai3e5b5012009-04-28 12:07:08 +0200466 no_jiffies_check:
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200467 if (delta > runtime->period_size + runtime->period_size / 2) {
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100468 hw_ptr_error(substream,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100469 "Lost interrupts? %s"
470 "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
471 "old_hw_ptr=%ld)\n",
472 in_interrupt ? "[Q] " : "",
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100473 substream->stream, (long)delta,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100474 (long)new_hw_ptr,
475 (long)old_hw_ptr);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100476 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100477
Clemens Ladischab69a492010-11-15 10:46:23 +0100478 no_delta_check:
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100479 if (runtime->status->hw_ptr == new_hw_ptr)
480 return 0;
Takashi Iwaiab1863f2009-06-07 12:09:17 +0200481
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
483 runtime->silence_size > 0)
484 snd_pcm_playback_silence(substream, new_hw_ptr);
485
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100486 if (in_interrupt) {
Clemens Ladischead40462010-05-21 09:15:59 +0200487 delta = new_hw_ptr - runtime->hw_ptr_interrupt;
488 if (delta < 0)
489 delta += runtime->boundary;
490 delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
491 runtime->hw_ptr_interrupt += delta;
492 if (runtime->hw_ptr_interrupt >= runtime->boundary)
493 runtime->hw_ptr_interrupt -= runtime->boundary;
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100494 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100495 runtime->hw_ptr_base = hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 runtime->status->hw_ptr = new_hw_ptr;
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200497 runtime->hw_ptr_jiffies = jiffies;
Jaroslav Kysela13f040f2009-05-28 11:31:20 +0200498 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
499 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500
Jaroslav Kysela12509322010-01-07 15:36:31 +0100501 return snd_pcm_update_state(substream, runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502}
503
504/* CAUTION: call it with irq disabled */
Takashi Iwai877211f2005-11-17 13:59:38 +0100505int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700506{
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100507 return snd_pcm_update_hw_ptr0(substream, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700508}
509
510/**
511 * snd_pcm_set_ops - set the PCM operators
512 * @pcm: the pcm instance
513 * @direction: stream direction, SNDRV_PCM_STREAM_XXX
514 * @ops: the operator table
515 *
516 * Sets the given PCM operators to the pcm instance.
517 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100518void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519{
Takashi Iwai877211f2005-11-17 13:59:38 +0100520 struct snd_pcm_str *stream = &pcm->streams[direction];
521 struct snd_pcm_substream *substream;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522
523 for (substream = stream->substream; substream != NULL; substream = substream->next)
524 substream->ops = ops;
525}
526
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200527EXPORT_SYMBOL(snd_pcm_set_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700528
529/**
530 * snd_pcm_sync - set the PCM sync id
531 * @substream: the pcm substream
532 *
533 * Sets the PCM sync identifier for the card.
534 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100535void snd_pcm_set_sync(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700536{
Takashi Iwai877211f2005-11-17 13:59:38 +0100537 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538
539 runtime->sync.id32[0] = substream->pcm->card->number;
540 runtime->sync.id32[1] = -1;
541 runtime->sync.id32[2] = -1;
542 runtime->sync.id32[3] = -1;
543}
544
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200545EXPORT_SYMBOL(snd_pcm_set_sync);
546
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547/*
548 * Standard ioctl routine
549 */
550
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551static inline unsigned int div32(unsigned int a, unsigned int b,
552 unsigned int *r)
553{
554 if (b == 0) {
555 *r = 0;
556 return UINT_MAX;
557 }
558 *r = a % b;
559 return a / b;
560}
561
562static inline unsigned int div_down(unsigned int a, unsigned int b)
563{
564 if (b == 0)
565 return UINT_MAX;
566 return a / b;
567}
568
569static inline unsigned int div_up(unsigned int a, unsigned int b)
570{
571 unsigned int r;
572 unsigned int q;
573 if (b == 0)
574 return UINT_MAX;
575 q = div32(a, b, &r);
576 if (r)
577 ++q;
578 return q;
579}
580
581static inline unsigned int mul(unsigned int a, unsigned int b)
582{
583 if (a == 0)
584 return 0;
585 if (div_down(UINT_MAX, a) < b)
586 return UINT_MAX;
587 return a * b;
588}
589
590static inline unsigned int muldiv32(unsigned int a, unsigned int b,
591 unsigned int c, unsigned int *r)
592{
593 u_int64_t n = (u_int64_t) a * b;
594 if (c == 0) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200595 snd_BUG_ON(!n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596 *r = 0;
597 return UINT_MAX;
598 }
Takashi Iwai3f7440a2009-06-05 17:40:04 +0200599 n = div_u64_rem(n, c, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700600 if (n >= UINT_MAX) {
601 *r = 0;
602 return UINT_MAX;
603 }
604 return n;
605}
606
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607/**
608 * snd_interval_refine - refine the interval value of configurator
609 * @i: the interval value to refine
610 * @v: the interval value to refer to
611 *
612 * Refines the interval value with the reference value.
613 * The interval is changed to the range satisfying both intervals.
614 * The interval status (min, max, integer, etc.) are evaluated.
615 *
616 * Returns non-zero if the value is changed, zero if not changed.
617 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100618int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619{
620 int changed = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200621 if (snd_BUG_ON(snd_interval_empty(i)))
622 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700623 if (i->min < v->min) {
624 i->min = v->min;
625 i->openmin = v->openmin;
626 changed = 1;
627 } else if (i->min == v->min && !i->openmin && v->openmin) {
628 i->openmin = 1;
629 changed = 1;
630 }
631 if (i->max > v->max) {
632 i->max = v->max;
633 i->openmax = v->openmax;
634 changed = 1;
635 } else if (i->max == v->max && !i->openmax && v->openmax) {
636 i->openmax = 1;
637 changed = 1;
638 }
639 if (!i->integer && v->integer) {
640 i->integer = 1;
641 changed = 1;
642 }
643 if (i->integer) {
644 if (i->openmin) {
645 i->min++;
646 i->openmin = 0;
647 }
648 if (i->openmax) {
649 i->max--;
650 i->openmax = 0;
651 }
652 } else if (!i->openmin && !i->openmax && i->min == i->max)
653 i->integer = 1;
654 if (snd_interval_checkempty(i)) {
655 snd_interval_none(i);
656 return -EINVAL;
657 }
658 return changed;
659}
660
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200661EXPORT_SYMBOL(snd_interval_refine);
662
Takashi Iwai877211f2005-11-17 13:59:38 +0100663static int snd_interval_refine_first(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200665 if (snd_BUG_ON(snd_interval_empty(i)))
666 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 if (snd_interval_single(i))
668 return 0;
669 i->max = i->min;
670 i->openmax = i->openmin;
671 if (i->openmax)
672 i->max++;
673 return 1;
674}
675
Takashi Iwai877211f2005-11-17 13:59:38 +0100676static int snd_interval_refine_last(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200678 if (snd_BUG_ON(snd_interval_empty(i)))
679 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680 if (snd_interval_single(i))
681 return 0;
682 i->min = i->max;
683 i->openmin = i->openmax;
684 if (i->openmin)
685 i->min--;
686 return 1;
687}
688
Takashi Iwai877211f2005-11-17 13:59:38 +0100689void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690{
691 if (a->empty || b->empty) {
692 snd_interval_none(c);
693 return;
694 }
695 c->empty = 0;
696 c->min = mul(a->min, b->min);
697 c->openmin = (a->openmin || b->openmin);
698 c->max = mul(a->max, b->max);
699 c->openmax = (a->openmax || b->openmax);
700 c->integer = (a->integer && b->integer);
701}
702
703/**
704 * snd_interval_div - refine the interval value with division
Takashi Iwaidf8db932005-09-07 13:38:19 +0200705 * @a: dividend
706 * @b: divisor
707 * @c: quotient
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708 *
709 * c = a / b
710 *
711 * Returns non-zero if the value is changed, zero if not changed.
712 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100713void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 unsigned int r;
716 if (a->empty || b->empty) {
717 snd_interval_none(c);
718 return;
719 }
720 c->empty = 0;
721 c->min = div32(a->min, b->max, &r);
722 c->openmin = (r || a->openmin || b->openmax);
723 if (b->min > 0) {
724 c->max = div32(a->max, b->min, &r);
725 if (r) {
726 c->max++;
727 c->openmax = 1;
728 } else
729 c->openmax = (a->openmax || b->openmin);
730 } else {
731 c->max = UINT_MAX;
732 c->openmax = 0;
733 }
734 c->integer = 0;
735}
736
737/**
738 * snd_interval_muldivk - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200739 * @a: dividend 1
740 * @b: dividend 2
741 * @k: divisor (as integer)
742 * @c: result
743 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700744 * c = a * b / k
745 *
746 * Returns non-zero if the value is changed, zero if not changed.
747 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100748void snd_interval_muldivk(const struct snd_interval *a, const struct snd_interval *b,
749 unsigned int k, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750{
751 unsigned int r;
752 if (a->empty || b->empty) {
753 snd_interval_none(c);
754 return;
755 }
756 c->empty = 0;
757 c->min = muldiv32(a->min, b->min, k, &r);
758 c->openmin = (r || a->openmin || b->openmin);
759 c->max = muldiv32(a->max, b->max, k, &r);
760 if (r) {
761 c->max++;
762 c->openmax = 1;
763 } else
764 c->openmax = (a->openmax || b->openmax);
765 c->integer = 0;
766}
767
768/**
769 * snd_interval_mulkdiv - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200770 * @a: dividend 1
771 * @k: dividend 2 (as integer)
772 * @b: divisor
773 * @c: result
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774 *
775 * c = a * k / b
776 *
777 * Returns non-zero if the value is changed, zero if not changed.
778 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100779void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
780 const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700781{
782 unsigned int r;
783 if (a->empty || b->empty) {
784 snd_interval_none(c);
785 return;
786 }
787 c->empty = 0;
788 c->min = muldiv32(a->min, k, b->max, &r);
789 c->openmin = (r || a->openmin || b->openmax);
790 if (b->min > 0) {
791 c->max = muldiv32(a->max, k, b->min, &r);
792 if (r) {
793 c->max++;
794 c->openmax = 1;
795 } else
796 c->openmax = (a->openmax || b->openmin);
797 } else {
798 c->max = UINT_MAX;
799 c->openmax = 0;
800 }
801 c->integer = 0;
802}
803
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804/* ---- */
805
806
807/**
808 * snd_interval_ratnum - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200809 * @i: interval to refine
810 * @rats_count: number of ratnum_t
811 * @rats: ratnum_t array
812 * @nump: pointer to store the resultant numerator
813 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 *
815 * Returns non-zero if the value is changed, zero if not changed.
816 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100817int snd_interval_ratnum(struct snd_interval *i,
818 unsigned int rats_count, struct snd_ratnum *rats,
819 unsigned int *nump, unsigned int *denp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820{
Krzysztof Helt8374e242009-12-21 17:07:08 +0100821 unsigned int best_num, best_den;
822 int best_diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700823 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100824 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 int err;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100826 unsigned int result_num, result_den;
827 int result_diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828
829 best_num = best_den = best_diff = 0;
830 for (k = 0; k < rats_count; ++k) {
831 unsigned int num = rats[k].num;
832 unsigned int den;
833 unsigned int q = i->min;
834 int diff;
835 if (q == 0)
836 q = 1;
Krzysztof Helt40962d72009-12-19 18:31:04 +0100837 den = div_up(num, q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838 if (den < rats[k].den_min)
839 continue;
840 if (den > rats[k].den_max)
841 den = rats[k].den_max;
842 else {
843 unsigned int r;
844 r = (den - rats[k].den_min) % rats[k].den_step;
845 if (r != 0)
846 den -= r;
847 }
848 diff = num - q * den;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100849 if (diff < 0)
850 diff = -diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 if (best_num == 0 ||
852 diff * best_den < best_diff * den) {
853 best_diff = diff;
854 best_den = den;
855 best_num = num;
856 }
857 }
858 if (best_den == 0) {
859 i->empty = 1;
860 return -EINVAL;
861 }
862 t.min = div_down(best_num, best_den);
863 t.openmin = !!(best_num % best_den);
864
Krzysztof Helt8374e242009-12-21 17:07:08 +0100865 result_num = best_num;
866 result_diff = best_diff;
867 result_den = best_den;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700868 best_num = best_den = best_diff = 0;
869 for (k = 0; k < rats_count; ++k) {
870 unsigned int num = rats[k].num;
871 unsigned int den;
872 unsigned int q = i->max;
873 int diff;
874 if (q == 0) {
875 i->empty = 1;
876 return -EINVAL;
877 }
Krzysztof Helt40962d72009-12-19 18:31:04 +0100878 den = div_down(num, q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700879 if (den > rats[k].den_max)
880 continue;
881 if (den < rats[k].den_min)
882 den = rats[k].den_min;
883 else {
884 unsigned int r;
885 r = (den - rats[k].den_min) % rats[k].den_step;
886 if (r != 0)
887 den += rats[k].den_step - r;
888 }
889 diff = q * den - num;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100890 if (diff < 0)
891 diff = -diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892 if (best_num == 0 ||
893 diff * best_den < best_diff * den) {
894 best_diff = diff;
895 best_den = den;
896 best_num = num;
897 }
898 }
899 if (best_den == 0) {
900 i->empty = 1;
901 return -EINVAL;
902 }
903 t.max = div_up(best_num, best_den);
904 t.openmax = !!(best_num % best_den);
905 t.integer = 0;
906 err = snd_interval_refine(i, &t);
907 if (err < 0)
908 return err;
909
910 if (snd_interval_single(i)) {
Krzysztof Helt8374e242009-12-21 17:07:08 +0100911 if (best_diff * result_den < result_diff * best_den) {
912 result_num = best_num;
913 result_den = best_den;
914 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 if (nump)
Krzysztof Helt8374e242009-12-21 17:07:08 +0100916 *nump = result_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 if (denp)
Krzysztof Helt8374e242009-12-21 17:07:08 +0100918 *denp = result_den;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700919 }
920 return err;
921}
922
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200923EXPORT_SYMBOL(snd_interval_ratnum);
924
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925/**
926 * snd_interval_ratden - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200927 * @i: interval to refine
Takashi Iwai877211f2005-11-17 13:59:38 +0100928 * @rats_count: number of struct ratden
929 * @rats: struct ratden array
Takashi Iwaidf8db932005-09-07 13:38:19 +0200930 * @nump: pointer to store the resultant numerator
931 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 *
933 * Returns non-zero if the value is changed, zero if not changed.
934 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100935static int snd_interval_ratden(struct snd_interval *i,
936 unsigned int rats_count, struct snd_ratden *rats,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937 unsigned int *nump, unsigned int *denp)
938{
939 unsigned int best_num, best_diff, best_den;
940 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100941 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942 int err;
943
944 best_num = best_den = best_diff = 0;
945 for (k = 0; k < rats_count; ++k) {
946 unsigned int num;
947 unsigned int den = rats[k].den;
948 unsigned int q = i->min;
949 int diff;
950 num = mul(q, den);
951 if (num > rats[k].num_max)
952 continue;
953 if (num < rats[k].num_min)
954 num = rats[k].num_max;
955 else {
956 unsigned int r;
957 r = (num - rats[k].num_min) % rats[k].num_step;
958 if (r != 0)
959 num += rats[k].num_step - r;
960 }
961 diff = num - q * den;
962 if (best_num == 0 ||
963 diff * best_den < best_diff * den) {
964 best_diff = diff;
965 best_den = den;
966 best_num = num;
967 }
968 }
969 if (best_den == 0) {
970 i->empty = 1;
971 return -EINVAL;
972 }
973 t.min = div_down(best_num, best_den);
974 t.openmin = !!(best_num % best_den);
975
976 best_num = best_den = best_diff = 0;
977 for (k = 0; k < rats_count; ++k) {
978 unsigned int num;
979 unsigned int den = rats[k].den;
980 unsigned int q = i->max;
981 int diff;
982 num = mul(q, den);
983 if (num < rats[k].num_min)
984 continue;
985 if (num > rats[k].num_max)
986 num = rats[k].num_max;
987 else {
988 unsigned int r;
989 r = (num - rats[k].num_min) % rats[k].num_step;
990 if (r != 0)
991 num -= r;
992 }
993 diff = q * den - num;
994 if (best_num == 0 ||
995 diff * best_den < best_diff * den) {
996 best_diff = diff;
997 best_den = den;
998 best_num = num;
999 }
1000 }
1001 if (best_den == 0) {
1002 i->empty = 1;
1003 return -EINVAL;
1004 }
1005 t.max = div_up(best_num, best_den);
1006 t.openmax = !!(best_num % best_den);
1007 t.integer = 0;
1008 err = snd_interval_refine(i, &t);
1009 if (err < 0)
1010 return err;
1011
1012 if (snd_interval_single(i)) {
1013 if (nump)
1014 *nump = best_num;
1015 if (denp)
1016 *denp = best_den;
1017 }
1018 return err;
1019}
1020
1021/**
1022 * snd_interval_list - refine the interval value from the list
1023 * @i: the interval value to refine
1024 * @count: the number of elements in the list
1025 * @list: the value list
1026 * @mask: the bit-mask to evaluate
1027 *
1028 * Refines the interval value from the list.
1029 * When mask is non-zero, only the elements corresponding to bit 1 are
1030 * evaluated.
1031 *
1032 * Returns non-zero if the value is changed, zero if not changed.
1033 */
Mark Brown4af87a92012-03-14 19:48:43 +00001034int snd_interval_list(struct snd_interval *i, unsigned int count,
Steve Mucklef132c6c2012-06-06 18:30:57 -07001035 unsigned int *list, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001036{
1037 unsigned int k;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001038 struct snd_interval list_range;
Takashi Iwai0981a262007-02-01 14:53:49 +01001039
1040 if (!count) {
1041 i->empty = 1;
1042 return -EINVAL;
1043 }
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001044 snd_interval_any(&list_range);
1045 list_range.min = UINT_MAX;
1046 list_range.max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001047 for (k = 0; k < count; k++) {
1048 if (mask && !(mask & (1 << k)))
1049 continue;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001050 if (!snd_interval_test(i, list[k]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 continue;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001052 list_range.min = min(list_range.min, list[k]);
1053 list_range.max = max(list_range.max, list[k]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054 }
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001055 return snd_interval_refine(i, &list_range);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056}
1057
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001058EXPORT_SYMBOL(snd_interval_list);
1059
Takashi Iwai877211f2005-11-17 13:59:38 +01001060static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001061{
1062 unsigned int n;
1063 int changed = 0;
1064 n = (i->min - min) % step;
1065 if (n != 0 || i->openmin) {
1066 i->min += step - n;
1067 changed = 1;
1068 }
1069 n = (i->max - min) % step;
1070 if (n != 0 || i->openmax) {
1071 i->max -= n;
1072 changed = 1;
1073 }
1074 if (snd_interval_checkempty(i)) {
1075 i->empty = 1;
1076 return -EINVAL;
1077 }
1078 return changed;
1079}
1080
1081/* Info constraints helpers */
1082
1083/**
1084 * snd_pcm_hw_rule_add - add the hw-constraint rule
1085 * @runtime: the pcm runtime instance
1086 * @cond: condition bits
1087 * @var: the variable to evaluate
1088 * @func: the evaluation function
1089 * @private: the private data pointer passed to function
1090 * @dep: the dependent variables
1091 *
1092 * Returns zero if successful, or a negative error code on failure.
1093 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001094int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 int var,
1096 snd_pcm_hw_rule_func_t func, void *private,
1097 int dep, ...)
1098{
Takashi Iwai877211f2005-11-17 13:59:38 +01001099 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1100 struct snd_pcm_hw_rule *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 unsigned int k;
1102 va_list args;
1103 va_start(args, dep);
1104 if (constrs->rules_num >= constrs->rules_all) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001105 struct snd_pcm_hw_rule *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001106 unsigned int new_rules = constrs->rules_all + 16;
1107 new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001108 if (!new) {
1109 va_end(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110 return -ENOMEM;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 if (constrs->rules) {
1113 memcpy(new, constrs->rules,
1114 constrs->rules_num * sizeof(*c));
1115 kfree(constrs->rules);
1116 }
1117 constrs->rules = new;
1118 constrs->rules_all = new_rules;
1119 }
1120 c = &constrs->rules[constrs->rules_num];
1121 c->cond = cond;
1122 c->func = func;
1123 c->var = var;
1124 c->private = private;
1125 k = 0;
1126 while (1) {
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001127 if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) {
1128 va_end(args);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001129 return -EINVAL;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001130 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001131 c->deps[k++] = dep;
1132 if (dep < 0)
1133 break;
1134 dep = va_arg(args, int);
1135 }
1136 constrs->rules_num++;
1137 va_end(args);
1138 return 0;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001139}
Linus Torvalds1da177e2005-04-16 15:20:36 -07001140
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001141EXPORT_SYMBOL(snd_pcm_hw_rule_add);
1142
Linus Torvalds1da177e2005-04-16 15:20:36 -07001143/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001144 * snd_pcm_hw_constraint_mask - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +02001145 * @runtime: PCM runtime instance
1146 * @var: hw_params variable to apply the mask
1147 * @mask: the bitmap mask
1148 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001149 * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001151int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 u_int32_t mask)
1153{
Takashi Iwai877211f2005-11-17 13:59:38 +01001154 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1155 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 *maskp->bits &= mask;
1157 memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
1158 if (*maskp->bits == 0)
1159 return -EINVAL;
1160 return 0;
1161}
1162
1163/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001164 * snd_pcm_hw_constraint_mask64 - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +02001165 * @runtime: PCM runtime instance
1166 * @var: hw_params variable to apply the mask
1167 * @mask: the 64bit bitmap mask
1168 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001169 * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001171int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001172 u_int64_t mask)
1173{
Takashi Iwai877211f2005-11-17 13:59:38 +01001174 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1175 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 maskp->bits[0] &= (u_int32_t)mask;
1177 maskp->bits[1] &= (u_int32_t)(mask >> 32);
1178 memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
1179 if (! maskp->bits[0] && ! maskp->bits[1])
1180 return -EINVAL;
1181 return 0;
1182}
1183
1184/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001185 * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +02001186 * @runtime: PCM runtime instance
1187 * @var: hw_params variable to apply the integer constraint
1188 *
1189 * Apply the constraint of integer to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001191int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001192{
Takashi Iwai877211f2005-11-17 13:59:38 +01001193 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001194 return snd_interval_setinteger(constrs_interval(constrs, var));
1195}
1196
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001197EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
1198
Linus Torvalds1da177e2005-04-16 15:20:36 -07001199/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001200 * snd_pcm_hw_constraint_minmax - apply a min/max range constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +02001201 * @runtime: PCM runtime instance
1202 * @var: hw_params variable to apply the range
1203 * @min: the minimal value
1204 * @max: the maximal value
1205 *
1206 * Apply the min/max range constraint to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001207 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001208int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001209 unsigned int min, unsigned int max)
1210{
Takashi Iwai877211f2005-11-17 13:59:38 +01001211 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1212 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001213 t.min = min;
1214 t.max = max;
1215 t.openmin = t.openmax = 0;
1216 t.integer = 0;
1217 return snd_interval_refine(constrs_interval(constrs, var), &t);
1218}
1219
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001220EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
1221
Takashi Iwai877211f2005-11-17 13:59:38 +01001222static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
1223 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224{
Takashi Iwai877211f2005-11-17 13:59:38 +01001225 struct snd_pcm_hw_constraint_list *list = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001226 return snd_interval_list(hw_param_interval(params, rule->var), list->count, list->list, list->mask);
1227}
1228
1229
1230/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001231 * snd_pcm_hw_constraint_list - apply a list of constraints to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001232 * @runtime: PCM runtime instance
1233 * @cond: condition bits
1234 * @var: hw_params variable to apply the list constraint
1235 * @l: list
1236 *
1237 * Apply the list of constraints to an interval parameter.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001238 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001239int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 unsigned int cond,
1241 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001242 struct snd_pcm_hw_constraint_list *l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243{
1244 return snd_pcm_hw_rule_add(runtime, cond, var,
1245 snd_pcm_hw_rule_list, l,
1246 var, -1);
1247}
1248
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001249EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
1250
Takashi Iwai877211f2005-11-17 13:59:38 +01001251static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
1252 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001253{
Takashi Iwai877211f2005-11-17 13:59:38 +01001254 struct snd_pcm_hw_constraint_ratnums *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255 unsigned int num = 0, den = 0;
1256 int err;
1257 err = snd_interval_ratnum(hw_param_interval(params, rule->var),
1258 r->nrats, r->rats, &num, &den);
1259 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1260 params->rate_num = num;
1261 params->rate_den = den;
1262 }
1263 return err;
1264}
1265
1266/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001267 * snd_pcm_hw_constraint_ratnums - apply ratnums constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001268 * @runtime: PCM runtime instance
1269 * @cond: condition bits
1270 * @var: hw_params variable to apply the ratnums constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001271 * @r: struct snd_ratnums constriants
Linus Torvalds1da177e2005-04-16 15:20:36 -07001272 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001273int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001274 unsigned int cond,
1275 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001276 struct snd_pcm_hw_constraint_ratnums *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277{
1278 return snd_pcm_hw_rule_add(runtime, cond, var,
1279 snd_pcm_hw_rule_ratnums, r,
1280 var, -1);
1281}
1282
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001283EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
1284
Takashi Iwai877211f2005-11-17 13:59:38 +01001285static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
1286 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287{
Takashi Iwai877211f2005-11-17 13:59:38 +01001288 struct snd_pcm_hw_constraint_ratdens *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001289 unsigned int num = 0, den = 0;
1290 int err = snd_interval_ratden(hw_param_interval(params, rule->var),
1291 r->nrats, r->rats, &num, &den);
1292 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1293 params->rate_num = num;
1294 params->rate_den = den;
1295 }
1296 return err;
1297}
1298
1299/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001300 * snd_pcm_hw_constraint_ratdens - apply ratdens constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001301 * @runtime: PCM runtime instance
1302 * @cond: condition bits
1303 * @var: hw_params variable to apply the ratdens constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001304 * @r: struct snd_ratdens constriants
Linus Torvalds1da177e2005-04-16 15:20:36 -07001305 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001306int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001307 unsigned int cond,
1308 snd_pcm_hw_param_t var,
Takashi Iwai877211f2005-11-17 13:59:38 +01001309 struct snd_pcm_hw_constraint_ratdens *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310{
1311 return snd_pcm_hw_rule_add(runtime, cond, var,
1312 snd_pcm_hw_rule_ratdens, r,
1313 var, -1);
1314}
1315
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001316EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
1317
Takashi Iwai877211f2005-11-17 13:59:38 +01001318static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
1319 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001320{
1321 unsigned int l = (unsigned long) rule->private;
1322 int width = l & 0xffff;
1323 unsigned int msbits = l >> 16;
Takashi Iwai877211f2005-11-17 13:59:38 +01001324 struct snd_interval *i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001325 if (snd_interval_single(i) && snd_interval_value(i) == width)
1326 params->msbits = msbits;
1327 return 0;
1328}
1329
1330/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001331 * snd_pcm_hw_constraint_msbits - add a hw constraint msbits rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001332 * @runtime: PCM runtime instance
1333 * @cond: condition bits
1334 * @width: sample bits width
1335 * @msbits: msbits width
Linus Torvalds1da177e2005-04-16 15:20:36 -07001336 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001337int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001338 unsigned int cond,
1339 unsigned int width,
1340 unsigned int msbits)
1341{
1342 unsigned long l = (msbits << 16) | width;
1343 return snd_pcm_hw_rule_add(runtime, cond, -1,
1344 snd_pcm_hw_rule_msbits,
1345 (void*) l,
1346 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1347}
1348
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001349EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
1350
Takashi Iwai877211f2005-11-17 13:59:38 +01001351static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
1352 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353{
1354 unsigned long step = (unsigned long) rule->private;
1355 return snd_interval_step(hw_param_interval(params, rule->var), 0, step);
1356}
1357
1358/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001359 * snd_pcm_hw_constraint_step - add a hw constraint step rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001360 * @runtime: PCM runtime instance
1361 * @cond: condition bits
1362 * @var: hw_params variable to apply the step constraint
1363 * @step: step size
Linus Torvalds1da177e2005-04-16 15:20:36 -07001364 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001365int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001366 unsigned int cond,
1367 snd_pcm_hw_param_t var,
1368 unsigned long step)
1369{
1370 return snd_pcm_hw_rule_add(runtime, cond, var,
1371 snd_pcm_hw_rule_step, (void *) step,
1372 var, -1);
1373}
1374
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001375EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
1376
Takashi Iwai877211f2005-11-17 13:59:38 +01001377static 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 -07001378{
Marcin Åšlusarz67c39312007-12-14 12:53:21 +01001379 static unsigned int pow2_sizes[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1381 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1382 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
1383 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
1384 };
1385 return snd_interval_list(hw_param_interval(params, rule->var),
1386 ARRAY_SIZE(pow2_sizes), pow2_sizes, 0);
1387}
1388
1389/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001390 * snd_pcm_hw_constraint_pow2 - add a hw constraint power-of-2 rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001391 * @runtime: PCM runtime instance
1392 * @cond: condition bits
1393 * @var: hw_params variable to apply the power-of-2 constraint
Linus Torvalds1da177e2005-04-16 15:20:36 -07001394 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001395int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001396 unsigned int cond,
1397 snd_pcm_hw_param_t var)
1398{
1399 return snd_pcm_hw_rule_add(runtime, cond, var,
1400 snd_pcm_hw_rule_pow2, NULL,
1401 var, -1);
1402}
1403
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001404EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
1405
Clemens Ladischd5b702a2011-09-16 23:03:02 +02001406static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
1407 struct snd_pcm_hw_rule *rule)
1408{
1409 unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
1410 struct snd_interval *rate;
1411
1412 rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1413 return snd_interval_list(rate, 1, &base_rate, 0);
1414}
1415
1416/**
1417 * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
1418 * @runtime: PCM runtime instance
1419 * @base_rate: the rate at which the hardware does not resample
1420 */
1421int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
1422 unsigned int base_rate)
1423{
1424 return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
1425 SNDRV_PCM_HW_PARAM_RATE,
1426 snd_pcm_hw_rule_noresample_func,
1427 (void *)(uintptr_t)base_rate,
1428 SNDRV_PCM_HW_PARAM_RATE, -1);
1429}
1430EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);
1431
Takashi Iwai877211f2005-11-17 13:59:38 +01001432static void _snd_pcm_hw_param_any(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001433 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434{
1435 if (hw_is_mask(var)) {
1436 snd_mask_any(hw_param_mask(params, var));
1437 params->cmask |= 1 << var;
1438 params->rmask |= 1 << var;
1439 return;
1440 }
1441 if (hw_is_interval(var)) {
1442 snd_interval_any(hw_param_interval(params, var));
1443 params->cmask |= 1 << var;
1444 params->rmask |= 1 << var;
1445 return;
1446 }
1447 snd_BUG();
1448}
1449
Takashi Iwai877211f2005-11-17 13:59:38 +01001450void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001451{
1452 unsigned int k;
1453 memset(params, 0, sizeof(*params));
1454 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
1455 _snd_pcm_hw_param_any(params, k);
1456 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
1457 _snd_pcm_hw_param_any(params, k);
1458 params->info = ~0U;
1459}
1460
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001461EXPORT_SYMBOL(_snd_pcm_hw_params_any);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462
1463/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001464 * snd_pcm_hw_param_value - return @params field @var value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001465 * @params: the hw_params instance
1466 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001467 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001468 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001469 * Return the value for field @var if it's fixed in configuration space
1470 * defined by @params. Return -%EINVAL otherwise.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001471 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001472int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
1473 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474{
1475 if (hw_is_mask(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001476 const struct snd_mask *mask = hw_param_mask_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 if (!snd_mask_single(mask))
1478 return -EINVAL;
1479 if (dir)
1480 *dir = 0;
1481 return snd_mask_value(mask);
1482 }
1483 if (hw_is_interval(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001484 const struct snd_interval *i = hw_param_interval_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001485 if (!snd_interval_single(i))
1486 return -EINVAL;
1487 if (dir)
1488 *dir = i->openmin;
1489 return snd_interval_value(i);
1490 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 return -EINVAL;
1492}
1493
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001494EXPORT_SYMBOL(snd_pcm_hw_param_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001495
Takashi Iwai877211f2005-11-17 13:59:38 +01001496void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001497 snd_pcm_hw_param_t var)
1498{
1499 if (hw_is_mask(var)) {
1500 snd_mask_none(hw_param_mask(params, var));
1501 params->cmask |= 1 << var;
1502 params->rmask |= 1 << var;
1503 } else if (hw_is_interval(var)) {
1504 snd_interval_none(hw_param_interval(params, var));
1505 params->cmask |= 1 << var;
1506 params->rmask |= 1 << var;
1507 } else {
1508 snd_BUG();
1509 }
1510}
1511
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001512EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513
Takashi Iwai877211f2005-11-17 13:59:38 +01001514static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001515 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001516{
1517 int changed;
1518 if (hw_is_mask(var))
1519 changed = snd_mask_refine_first(hw_param_mask(params, var));
1520 else if (hw_is_interval(var))
1521 changed = snd_interval_refine_first(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001522 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001523 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001524 if (changed) {
1525 params->cmask |= 1 << var;
1526 params->rmask |= 1 << var;
1527 }
1528 return changed;
1529}
1530
1531
1532/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001533 * snd_pcm_hw_param_first - refine config space and return minimum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001534 * @pcm: PCM instance
1535 * @params: the hw_params instance
1536 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001537 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001538 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001539 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001540 * values > minimum. Reduce configuration space accordingly.
1541 * Return the minimum.
1542 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001543int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
1544 struct snd_pcm_hw_params *params,
1545 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546{
1547 int changed = _snd_pcm_hw_param_first(params, var);
1548 if (changed < 0)
1549 return changed;
1550 if (params->rmask) {
1551 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001552 if (snd_BUG_ON(err < 0))
1553 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001554 }
1555 return snd_pcm_hw_param_value(params, var, dir);
1556}
1557
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001558EXPORT_SYMBOL(snd_pcm_hw_param_first);
1559
Takashi Iwai877211f2005-11-17 13:59:38 +01001560static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001561 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562{
1563 int changed;
1564 if (hw_is_mask(var))
1565 changed = snd_mask_refine_last(hw_param_mask(params, var));
1566 else if (hw_is_interval(var))
1567 changed = snd_interval_refine_last(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001568 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001569 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570 if (changed) {
1571 params->cmask |= 1 << var;
1572 params->rmask |= 1 << var;
1573 }
1574 return changed;
1575}
1576
1577
1578/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001579 * snd_pcm_hw_param_last - refine config space and return maximum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001580 * @pcm: PCM instance
1581 * @params: the hw_params instance
1582 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001583 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001584 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001585 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001586 * values < maximum. Reduce configuration space accordingly.
1587 * Return the maximum.
1588 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001589int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
1590 struct snd_pcm_hw_params *params,
1591 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592{
1593 int changed = _snd_pcm_hw_param_last(params, var);
1594 if (changed < 0)
1595 return changed;
1596 if (params->rmask) {
1597 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001598 if (snd_BUG_ON(err < 0))
1599 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001600 }
1601 return snd_pcm_hw_param_value(params, var, dir);
1602}
1603
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001604EXPORT_SYMBOL(snd_pcm_hw_param_last);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001605
1606/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001607 * snd_pcm_hw_param_choose - choose a configuration defined by @params
Takashi Iwaidf8db932005-09-07 13:38:19 +02001608 * @pcm: PCM instance
1609 * @params: the hw_params instance
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001611 * Choose one configuration from configuration space defined by @params.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001612 * The configuration chosen is that obtained fixing in this order:
1613 * first access, first format, first subformat, min channels,
1614 * min rate, min period time, max buffer size, min tick time
1615 */
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001616int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
1617 struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001618{
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001619 static int vars[] = {
1620 SNDRV_PCM_HW_PARAM_ACCESS,
1621 SNDRV_PCM_HW_PARAM_FORMAT,
1622 SNDRV_PCM_HW_PARAM_SUBFORMAT,
1623 SNDRV_PCM_HW_PARAM_CHANNELS,
1624 SNDRV_PCM_HW_PARAM_RATE,
1625 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
1626 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
1627 SNDRV_PCM_HW_PARAM_TICK_TIME,
1628 -1
1629 };
1630 int err, *v;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001631
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001632 for (v = vars; *v != -1; v++) {
1633 if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
1634 err = snd_pcm_hw_param_first(pcm, params, *v, NULL);
1635 else
1636 err = snd_pcm_hw_param_last(pcm, params, *v, NULL);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001637 if (snd_BUG_ON(err < 0))
1638 return err;
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001639 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001640 return 0;
1641}
1642
Takashi Iwai877211f2005-11-17 13:59:38 +01001643static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001644 void *arg)
1645{
Takashi Iwai877211f2005-11-17 13:59:38 +01001646 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001647 unsigned long flags;
1648 snd_pcm_stream_lock_irqsave(substream, flags);
1649 if (snd_pcm_running(substream) &&
1650 snd_pcm_update_hw_ptr(substream) >= 0)
1651 runtime->status->hw_ptr %= runtime->buffer_size;
1652 else
1653 runtime->status->hw_ptr = 0;
1654 snd_pcm_stream_unlock_irqrestore(substream, flags);
1655 return 0;
1656}
1657
Takashi Iwai877211f2005-11-17 13:59:38 +01001658static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001659 void *arg)
1660{
Takashi Iwai877211f2005-11-17 13:59:38 +01001661 struct snd_pcm_channel_info *info = arg;
1662 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 int width;
1664 if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
1665 info->offset = -1;
1666 return 0;
1667 }
1668 width = snd_pcm_format_physical_width(runtime->format);
1669 if (width < 0)
1670 return width;
1671 info->offset = 0;
1672 switch (runtime->access) {
1673 case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
1674 case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
Phani Kumar Uppalapati071823f2013-09-26 12:27:56 -07001675 if ((UINT_MAX/width) < info->channel) {
1676 snd_printd("%s: integer overflow while multiply\n",
1677 __func__);
1678 return -EINVAL;
1679 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 info->first = info->channel * width;
1681 info->step = runtime->channels * width;
1682 break;
1683 case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
1684 case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
1685 {
1686 size_t size = runtime->dma_bytes / runtime->channels;
Phani Kumar Uppalapati071823f2013-09-26 12:27:56 -07001687
1688 if ((size > 0) && ((UINT_MAX/(size * 8)) < info->channel)) {
1689 snd_printd("%s: integer overflow while multiply\n",
1690 __func__);
1691 return -EINVAL;
1692 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 info->first = info->channel * size * 8;
1694 info->step = width;
1695 break;
1696 }
1697 default:
1698 snd_BUG();
1699 break;
1700 }
1701 return 0;
1702}
1703
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001704static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
1705 void *arg)
1706{
1707 struct snd_pcm_hw_params *params = arg;
1708 snd_pcm_format_t format;
1709 int channels, width;
1710
1711 params->fifo_size = substream->runtime->hw.fifo_size;
1712 if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
1713 format = params_format(params);
1714 channels = params_channels(params);
1715 width = snd_pcm_format_physical_width(format);
1716 params->fifo_size /= width * channels;
1717 }
1718 return 0;
1719}
1720
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721/**
1722 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1723 * @substream: the pcm substream instance
1724 * @cmd: ioctl command
1725 * @arg: ioctl argument
1726 *
1727 * Processes the generic ioctl commands for PCM.
1728 * Can be passed as the ioctl callback for PCM ops.
1729 *
1730 * Returns zero if successful, or a negative error code on failure.
1731 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001732int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001733 unsigned int cmd, void *arg)
1734{
1735 switch (cmd) {
1736 case SNDRV_PCM_IOCTL1_INFO:
1737 return 0;
1738 case SNDRV_PCM_IOCTL1_RESET:
1739 return snd_pcm_lib_ioctl_reset(substream, arg);
1740 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1741 return snd_pcm_lib_ioctl_channel_info(substream, arg);
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001742 case SNDRV_PCM_IOCTL1_FIFO_SIZE:
1743 return snd_pcm_lib_ioctl_fifo_size(substream, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001744 }
1745 return -ENXIO;
1746}
1747
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001748EXPORT_SYMBOL(snd_pcm_lib_ioctl);
1749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750/**
1751 * snd_pcm_period_elapsed - update the pcm status for the next period
1752 * @substream: the pcm substream instance
1753 *
1754 * This function is called from the interrupt handler when the
1755 * PCM has processed the period size. It will update the current
Takashi Iwai31e89602008-01-08 18:09:57 +01001756 * pointer, wake up sleepers, etc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757 *
1758 * Even if more than one periods have elapsed since the last call, you
1759 * have to call this only once.
1760 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001761void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001762{
Takashi Iwai877211f2005-11-17 13:59:38 +01001763 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001764 unsigned long flags;
1765
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001766 if (PCM_RUNTIME_CHECK(substream))
1767 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001769
1770 if (runtime->transfer_ack_begin)
1771 runtime->transfer_ack_begin(substream);
1772
1773 snd_pcm_stream_lock_irqsave(substream, flags);
1774 if (!snd_pcm_running(substream) ||
Jaroslav Kyselaf2404062010-01-05 17:19:34 +01001775 snd_pcm_update_hw_ptr0(substream, 1) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 goto _end;
1777
1778 if (substream->timer_running)
1779 snd_timer_interrupt(substream->timer, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780 _end:
1781 snd_pcm_stream_unlock_irqrestore(substream, flags);
1782 if (runtime->transfer_ack_end)
1783 runtime->transfer_ack_end(substream);
1784 kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
1785}
1786
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001787EXPORT_SYMBOL(snd_pcm_period_elapsed);
1788
Takashi Iwai13075512008-01-08 18:08:14 +01001789/*
1790 * Wait until avail_min data becomes available
1791 * Returns a negative error code if any error occurs during operation.
1792 * The available space is stored on availp. When err = 0 and avail = 0
1793 * on the capture stream, it indicates the stream is in DRAINING state.
1794 */
David Dillow5daeba32010-06-27 00:13:20 +02001795static int wait_for_avail(struct snd_pcm_substream *substream,
Takashi Iwai13075512008-01-08 18:08:14 +01001796 snd_pcm_uframes_t *availp)
1797{
1798 struct snd_pcm_runtime *runtime = substream->runtime;
1799 int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
1800 wait_queue_t wait;
1801 int err = 0;
1802 snd_pcm_uframes_t avail = 0;
Takashi Iwaif2b36142011-05-26 08:09:38 +02001803 long wait_time, tout;
Takashi Iwai13075512008-01-08 18:08:14 +01001804
Arjan van de Ven763437a2011-09-15 08:49:25 +02001805 init_waitqueue_entry(&wait, current);
1806 set_current_state(TASK_INTERRUPTIBLE);
1807 add_wait_queue(&runtime->tsleep, &wait);
1808
Takashi Iwaif2b36142011-05-26 08:09:38 +02001809 if (runtime->no_period_wakeup)
1810 wait_time = MAX_SCHEDULE_TIMEOUT;
1811 else {
1812 wait_time = 10;
1813 if (runtime->rate) {
1814 long t = runtime->period_size * 2 / runtime->rate;
1815 wait_time = max(t, wait_time);
1816 }
1817 wait_time = msecs_to_jiffies(wait_time * 1000);
1818 }
Arjan van de Ven763437a2011-09-15 08:49:25 +02001819
Takashi Iwai13075512008-01-08 18:08:14 +01001820 for (;;) {
1821 if (signal_pending(current)) {
1822 err = -ERESTARTSYS;
1823 break;
1824 }
Arjan van de Ven763437a2011-09-15 08:49:25 +02001825
1826 /*
1827 * We need to check if space became available already
1828 * (and thus the wakeup happened already) first to close
1829 * the race of space already having become available.
1830 * This check must happen after been added to the waitqueue
1831 * and having current state be INTERRUPTIBLE.
1832 */
1833 if (is_playback)
1834 avail = snd_pcm_playback_avail(runtime);
1835 else
1836 avail = snd_pcm_capture_avail(runtime);
1837 if (avail >= runtime->twake)
1838 break;
Takashi Iwai13075512008-01-08 18:08:14 +01001839 snd_pcm_stream_unlock_irq(substream);
Arjan van de Ven763437a2011-09-15 08:49:25 +02001840
1841 tout = schedule_timeout(wait_time);
1842
Takashi Iwai13075512008-01-08 18:08:14 +01001843 snd_pcm_stream_lock_irq(substream);
Arjan van de Ven763437a2011-09-15 08:49:25 +02001844 set_current_state(TASK_INTERRUPTIBLE);
Takashi Iwai13075512008-01-08 18:08:14 +01001845 switch (runtime->status->state) {
1846 case SNDRV_PCM_STATE_SUSPENDED:
1847 err = -ESTRPIPE;
1848 goto _endloop;
1849 case SNDRV_PCM_STATE_XRUN:
1850 err = -EPIPE;
1851 goto _endloop;
1852 case SNDRV_PCM_STATE_DRAINING:
1853 if (is_playback)
1854 err = -EPIPE;
1855 else
1856 avail = 0; /* indicate draining */
1857 goto _endloop;
1858 case SNDRV_PCM_STATE_OPEN:
1859 case SNDRV_PCM_STATE_SETUP:
1860 case SNDRV_PCM_STATE_DISCONNECTED:
1861 err = -EBADFD;
1862 goto _endloop;
1863 }
1864 if (!tout) {
1865 snd_printd("%s write error (DMA or IRQ trouble?)\n",
1866 is_playback ? "playback" : "capture");
1867 err = -EIO;
1868 break;
1869 }
Takashi Iwai13075512008-01-08 18:08:14 +01001870 }
1871 _endloop:
Arjan van de Ven763437a2011-09-15 08:49:25 +02001872 set_current_state(TASK_RUNNING);
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01001873 remove_wait_queue(&runtime->tsleep, &wait);
Takashi Iwai13075512008-01-08 18:08:14 +01001874 *availp = avail;
1875 return err;
1876}
1877
Takashi Iwai877211f2005-11-17 13:59:38 +01001878static int snd_pcm_lib_write_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001879 unsigned int hwoff,
1880 unsigned long data, unsigned int off,
1881 snd_pcm_uframes_t frames)
1882{
Takashi Iwai877211f2005-11-17 13:59:38 +01001883 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001884 int err;
1885 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
1886 if (substream->ops->copy) {
1887 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
1888 return err;
1889 } else {
1890 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001891 if (copy_from_user(hwbuf, buf, frames_to_bytes(runtime, frames)))
1892 return -EFAULT;
1893 }
1894 return 0;
1895}
1896
Takashi Iwai877211f2005-11-17 13:59:38 +01001897typedef int (*transfer_f)(struct snd_pcm_substream *substream, unsigned int hwoff,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001898 unsigned long data, unsigned int off,
1899 snd_pcm_uframes_t size);
1900
Takashi Iwai877211f2005-11-17 13:59:38 +01001901static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001902 unsigned long data,
1903 snd_pcm_uframes_t size,
1904 int nonblock,
1905 transfer_f transfer)
1906{
Takashi Iwai877211f2005-11-17 13:59:38 +01001907 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001908 snd_pcm_uframes_t xfer = 0;
1909 snd_pcm_uframes_t offset = 0;
1910 int err = 0;
1911
1912 if (size == 0)
1913 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001914
1915 snd_pcm_stream_lock_irq(substream);
1916 switch (runtime->status->state) {
1917 case SNDRV_PCM_STATE_PREPARED:
1918 case SNDRV_PCM_STATE_RUNNING:
1919 case SNDRV_PCM_STATE_PAUSED:
1920 break;
1921 case SNDRV_PCM_STATE_XRUN:
1922 err = -EPIPE;
1923 goto _end_unlock;
1924 case SNDRV_PCM_STATE_SUSPENDED:
1925 err = -ESTRPIPE;
1926 goto _end_unlock;
1927 default:
1928 err = -EBADFD;
1929 goto _end_unlock;
1930 }
1931
David Dillow5daeba32010-06-27 00:13:20 +02001932 runtime->twake = runtime->control->avail_min ? : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001933 while (size > 0) {
1934 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
1935 snd_pcm_uframes_t avail;
1936 snd_pcm_uframes_t cont;
Takashi Iwai31e89602008-01-08 18:09:57 +01001937 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001938 snd_pcm_update_hw_ptr(substream);
1939 avail = snd_pcm_playback_avail(runtime);
Takashi Iwai13075512008-01-08 18:08:14 +01001940 if (!avail) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001941 if (nonblock) {
1942 err = -EAGAIN;
1943 goto _end_unlock;
1944 }
David Dillow5daeba32010-06-27 00:13:20 +02001945 runtime->twake = min_t(snd_pcm_uframes_t, size,
1946 runtime->control->avail_min ? : 1);
1947 err = wait_for_avail(substream, &avail);
Takashi Iwai13075512008-01-08 18:08:14 +01001948 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001949 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001950 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001951 frames = size > avail ? avail : size;
1952 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
1953 if (frames > cont)
1954 frames = cont;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001955 if (snd_BUG_ON(!frames)) {
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01001956 runtime->twake = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001957 snd_pcm_stream_unlock_irq(substream);
1958 return -EINVAL;
1959 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 appl_ptr = runtime->control->appl_ptr;
1961 appl_ofs = appl_ptr % runtime->buffer_size;
1962 snd_pcm_stream_unlock_irq(substream);
Jaroslav Kysela12509322010-01-07 15:36:31 +01001963 err = transfer(substream, appl_ofs, data, offset, frames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001964 snd_pcm_stream_lock_irq(substream);
Jaroslav Kysela12509322010-01-07 15:36:31 +01001965 if (err < 0)
1966 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001967 switch (runtime->status->state) {
1968 case SNDRV_PCM_STATE_XRUN:
1969 err = -EPIPE;
1970 goto _end_unlock;
1971 case SNDRV_PCM_STATE_SUSPENDED:
1972 err = -ESTRPIPE;
1973 goto _end_unlock;
1974 default:
1975 break;
1976 }
1977 appl_ptr += frames;
1978 if (appl_ptr >= runtime->boundary)
1979 appl_ptr -= runtime->boundary;
1980 runtime->control->appl_ptr = appl_ptr;
1981 if (substream->ops->ack)
1982 substream->ops->ack(substream);
1983
1984 offset += frames;
1985 size -= frames;
1986 xfer += frames;
1987 if (runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
1988 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
1989 err = snd_pcm_start(substream);
1990 if (err < 0)
1991 goto _end_unlock;
1992 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001993 }
1994 _end_unlock:
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01001995 runtime->twake = 0;
Jaroslav Kysela12509322010-01-07 15:36:31 +01001996 if (xfer > 0 && err >= 0)
1997 snd_pcm_update_state(substream, runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001998 snd_pcm_stream_unlock_irq(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001999 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2000}
2001
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002002/* sanity-check for read/write methods */
2003static int pcm_sanity_check(struct snd_pcm_substream *substream)
2004{
2005 struct snd_pcm_runtime *runtime;
2006 if (PCM_RUNTIME_CHECK(substream))
2007 return -ENXIO;
Liam Girdwoodad2581e2011-02-01 21:31:31 +00002008 /* TODO: consider and -EINVAL here */
2009 if (substream->hw_no_buffer)
2010 snd_printd("%s: warning this PCM is host less\n", __func__);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002011 runtime = substream->runtime;
2012 if (snd_BUG_ON(!substream->ops->copy && !runtime->dma_area))
2013 return -EINVAL;
2014 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2015 return -EBADFD;
2016 return 0;
2017}
2018
Takashi Iwai877211f2005-11-17 13:59:38 +01002019snd_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 -07002020{
Takashi Iwai877211f2005-11-17 13:59:38 +01002021 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002022 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002023 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002024
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002025 err = pcm_sanity_check(substream);
2026 if (err < 0)
2027 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002028 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02002029 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002030
2031 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
2032 runtime->channels > 1)
2033 return -EINVAL;
2034 return snd_pcm_lib_write1(substream, (unsigned long)buf, size, nonblock,
2035 snd_pcm_lib_write_transfer);
2036}
2037
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02002038EXPORT_SYMBOL(snd_pcm_lib_write);
2039
Takashi Iwai877211f2005-11-17 13:59:38 +01002040static int snd_pcm_lib_writev_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002041 unsigned int hwoff,
2042 unsigned long data, unsigned int off,
2043 snd_pcm_uframes_t frames)
2044{
Takashi Iwai877211f2005-11-17 13:59:38 +01002045 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002046 int err;
2047 void __user **bufs = (void __user **)data;
2048 int channels = runtime->channels;
2049 int c;
2050 if (substream->ops->copy) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002051 if (snd_BUG_ON(!substream->ops->silence))
2052 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002053 for (c = 0; c < channels; ++c, ++bufs) {
2054 if (*bufs == NULL) {
2055 if ((err = substream->ops->silence(substream, c, hwoff, frames)) < 0)
2056 return err;
2057 } else {
2058 char __user *buf = *bufs + samples_to_bytes(runtime, off);
2059 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
2060 return err;
2061 }
2062 }
2063 } else {
2064 /* default transfer behaviour */
2065 size_t dma_csize = runtime->dma_bytes / channels;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 for (c = 0; c < channels; ++c, ++bufs) {
2067 char *hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
2068 if (*bufs == NULL) {
2069 snd_pcm_format_set_silence(runtime->format, hwbuf, frames);
2070 } else {
2071 char __user *buf = *bufs + samples_to_bytes(runtime, off);
2072 if (copy_from_user(hwbuf, buf, samples_to_bytes(runtime, frames)))
2073 return -EFAULT;
2074 }
2075 }
2076 }
2077 return 0;
2078}
2079
Takashi Iwai877211f2005-11-17 13:59:38 +01002080snd_pcm_sframes_t snd_pcm_lib_writev(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 void __user **bufs,
2082 snd_pcm_uframes_t frames)
2083{
Takashi Iwai877211f2005-11-17 13:59:38 +01002084 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002085 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002086 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002087
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002088 err = pcm_sanity_check(substream);
2089 if (err < 0)
2090 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002091 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02002092 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002093
2094 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2095 return -EINVAL;
2096 return snd_pcm_lib_write1(substream, (unsigned long)bufs, frames,
2097 nonblock, snd_pcm_lib_writev_transfer);
2098}
2099
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02002100EXPORT_SYMBOL(snd_pcm_lib_writev);
2101
Takashi Iwai877211f2005-11-17 13:59:38 +01002102static int snd_pcm_lib_read_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002103 unsigned int hwoff,
2104 unsigned long data, unsigned int off,
2105 snd_pcm_uframes_t frames)
2106{
Takashi Iwai877211f2005-11-17 13:59:38 +01002107 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002108 int err;
2109 char __user *buf = (char __user *) data + frames_to_bytes(runtime, off);
2110 if (substream->ops->copy) {
2111 if ((err = substream->ops->copy(substream, -1, hwoff, buf, frames)) < 0)
2112 return err;
2113 } else {
2114 char *hwbuf = runtime->dma_area + frames_to_bytes(runtime, hwoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 if (copy_to_user(buf, hwbuf, frames_to_bytes(runtime, frames)))
2116 return -EFAULT;
2117 }
2118 return 0;
2119}
2120
Takashi Iwai877211f2005-11-17 13:59:38 +01002121static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002122 unsigned long data,
2123 snd_pcm_uframes_t size,
2124 int nonblock,
2125 transfer_f transfer)
2126{
Takashi Iwai877211f2005-11-17 13:59:38 +01002127 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002128 snd_pcm_uframes_t xfer = 0;
2129 snd_pcm_uframes_t offset = 0;
2130 int err = 0;
2131
2132 if (size == 0)
2133 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134
2135 snd_pcm_stream_lock_irq(substream);
2136 switch (runtime->status->state) {
2137 case SNDRV_PCM_STATE_PREPARED:
2138 if (size >= runtime->start_threshold) {
2139 err = snd_pcm_start(substream);
2140 if (err < 0)
2141 goto _end_unlock;
2142 }
2143 break;
2144 case SNDRV_PCM_STATE_DRAINING:
2145 case SNDRV_PCM_STATE_RUNNING:
2146 case SNDRV_PCM_STATE_PAUSED:
2147 break;
2148 case SNDRV_PCM_STATE_XRUN:
2149 err = -EPIPE;
2150 goto _end_unlock;
2151 case SNDRV_PCM_STATE_SUSPENDED:
2152 err = -ESTRPIPE;
2153 goto _end_unlock;
2154 default:
2155 err = -EBADFD;
2156 goto _end_unlock;
2157 }
2158
David Dillow5daeba32010-06-27 00:13:20 +02002159 runtime->twake = runtime->control->avail_min ? : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002160 while (size > 0) {
2161 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
2162 snd_pcm_uframes_t avail;
2163 snd_pcm_uframes_t cont;
Takashi Iwai31e89602008-01-08 18:09:57 +01002164 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002165 snd_pcm_update_hw_ptr(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 avail = snd_pcm_capture_avail(runtime);
Takashi Iwai13075512008-01-08 18:08:14 +01002167 if (!avail) {
2168 if (runtime->status->state ==
2169 SNDRV_PCM_STATE_DRAINING) {
2170 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 goto _end_unlock;
2172 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002173 if (nonblock) {
2174 err = -EAGAIN;
2175 goto _end_unlock;
2176 }
David Dillow5daeba32010-06-27 00:13:20 +02002177 runtime->twake = min_t(snd_pcm_uframes_t, size,
2178 runtime->control->avail_min ? : 1);
2179 err = wait_for_avail(substream, &avail);
Takashi Iwai13075512008-01-08 18:08:14 +01002180 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181 goto _end_unlock;
Takashi Iwai13075512008-01-08 18:08:14 +01002182 if (!avail)
2183 continue; /* draining */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002185 frames = size > avail ? avail : size;
2186 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
2187 if (frames > cont)
2188 frames = cont;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002189 if (snd_BUG_ON(!frames)) {
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01002190 runtime->twake = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002191 snd_pcm_stream_unlock_irq(substream);
2192 return -EINVAL;
2193 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002194 appl_ptr = runtime->control->appl_ptr;
2195 appl_ofs = appl_ptr % runtime->buffer_size;
2196 snd_pcm_stream_unlock_irq(substream);
Jaroslav Kysela12509322010-01-07 15:36:31 +01002197 err = transfer(substream, appl_ofs, data, offset, frames);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002198 snd_pcm_stream_lock_irq(substream);
Jaroslav Kysela12509322010-01-07 15:36:31 +01002199 if (err < 0)
2200 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 switch (runtime->status->state) {
2202 case SNDRV_PCM_STATE_XRUN:
2203 err = -EPIPE;
2204 goto _end_unlock;
2205 case SNDRV_PCM_STATE_SUSPENDED:
2206 err = -ESTRPIPE;
2207 goto _end_unlock;
2208 default:
2209 break;
2210 }
2211 appl_ptr += frames;
2212 if (appl_ptr >= runtime->boundary)
2213 appl_ptr -= runtime->boundary;
2214 runtime->control->appl_ptr = appl_ptr;
2215 if (substream->ops->ack)
2216 substream->ops->ack(substream);
2217
2218 offset += frames;
2219 size -= frames;
2220 xfer += frames;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002221 }
2222 _end_unlock:
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01002223 runtime->twake = 0;
Jaroslav Kysela12509322010-01-07 15:36:31 +01002224 if (xfer > 0 && err >= 0)
2225 snd_pcm_update_state(substream, runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 snd_pcm_stream_unlock_irq(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002227 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2228}
2229
Takashi Iwai877211f2005-11-17 13:59:38 +01002230snd_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 -07002231{
Takashi Iwai877211f2005-11-17 13:59:38 +01002232 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002234 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002235
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002236 err = pcm_sanity_check(substream);
2237 if (err < 0)
2238 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002239 runtime = substream->runtime;
Takashi Iwai0df63e42006-04-28 15:13:41 +02002240 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED)
2242 return -EINVAL;
2243 return snd_pcm_lib_read1(substream, (unsigned long)buf, size, nonblock, snd_pcm_lib_read_transfer);
2244}
2245
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02002246EXPORT_SYMBOL(snd_pcm_lib_read);
2247
Takashi Iwai877211f2005-11-17 13:59:38 +01002248static int snd_pcm_lib_readv_transfer(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 unsigned int hwoff,
2250 unsigned long data, unsigned int off,
2251 snd_pcm_uframes_t frames)
2252{
Takashi Iwai877211f2005-11-17 13:59:38 +01002253 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002254 int err;
2255 void __user **bufs = (void __user **)data;
2256 int channels = runtime->channels;
2257 int c;
2258 if (substream->ops->copy) {
2259 for (c = 0; c < channels; ++c, ++bufs) {
2260 char __user *buf;
2261 if (*bufs == NULL)
2262 continue;
2263 buf = *bufs + samples_to_bytes(runtime, off);
2264 if ((err = substream->ops->copy(substream, c, hwoff, buf, frames)) < 0)
2265 return err;
2266 }
2267 } else {
2268 snd_pcm_uframes_t dma_csize = runtime->dma_bytes / channels;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002269 for (c = 0; c < channels; ++c, ++bufs) {
2270 char *hwbuf;
2271 char __user *buf;
2272 if (*bufs == NULL)
2273 continue;
2274
2275 hwbuf = runtime->dma_area + (c * dma_csize) + samples_to_bytes(runtime, hwoff);
2276 buf = *bufs + samples_to_bytes(runtime, off);
2277 if (copy_to_user(buf, hwbuf, samples_to_bytes(runtime, frames)))
2278 return -EFAULT;
2279 }
2280 }
2281 return 0;
2282}
2283
Takashi Iwai877211f2005-11-17 13:59:38 +01002284snd_pcm_sframes_t snd_pcm_lib_readv(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002285 void __user **bufs,
2286 snd_pcm_uframes_t frames)
2287{
Takashi Iwai877211f2005-11-17 13:59:38 +01002288 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002289 int nonblock;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002290 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002292 err = pcm_sanity_check(substream);
2293 if (err < 0)
2294 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002295 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2297 return -EBADFD;
2298
Takashi Iwai0df63e42006-04-28 15:13:41 +02002299 nonblock = !!(substream->f_flags & O_NONBLOCK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002300 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2301 return -EINVAL;
2302 return snd_pcm_lib_read1(substream, (unsigned long)bufs, frames, nonblock, snd_pcm_lib_readv_transfer);
2303}
2304
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305EXPORT_SYMBOL(snd_pcm_lib_readv);
Subhash Chandra Bose Naripeddyff1e6252012-10-18 15:44:12 -07002306
2307/*
2308 * standard channel mapping helpers
2309 */
2310
2311/* default channel maps for multi-channel playbacks, up to 8 channels */
2312const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
2313 { .channels = 1,
2314 .map = { SNDRV_CHMAP_FC } },
2315 { .channels = 2,
2316 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
2317 { .channels = 4,
2318 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2319 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2320 { .channels = 6,
2321 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2322 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2323 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
2324 { .channels = 8,
2325 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2326 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2327 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2328 SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
2329 { }
2330};
2331EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
2332
2333/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
2334const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
2335 { .channels = 1,
2336 .map = { SNDRV_CHMAP_FC } },
2337 { .channels = 2,
2338 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
2339 { .channels = 4,
2340 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2341 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2342 { .channels = 6,
2343 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2344 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2345 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2346 { .channels = 8,
2347 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2348 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2349 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2350 SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
2351 { }
2352};
2353EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
2354
2355static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
2356{
2357 if (ch > info->max_channels)
2358 return false;
2359 return !info->channel_mask || (info->channel_mask & (1U << ch));
2360}
2361
2362static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
2363 struct snd_ctl_elem_info *uinfo)
2364{
2365 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2366
2367 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2368 uinfo->count = 0;
2369 uinfo->count = info->max_channels;
2370 uinfo->value.integer.min = 0;
2371 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
2372 return 0;
2373}
2374
2375/* get callback for channel map ctl element
2376 * stores the channel position firstly matching with the current channels
2377 */
2378static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
2379 struct snd_ctl_elem_value *ucontrol)
2380{
2381 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2382 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2383 struct snd_pcm_substream *substream;
2384 const struct snd_pcm_chmap_elem *map;
2385
2386 if (snd_BUG_ON(!info->chmap))
2387 return -EINVAL;
2388 substream = snd_pcm_chmap_substream(info, idx);
2389 if (!substream)
2390 return -ENODEV;
2391 memset(ucontrol->value.integer.value, 0,
2392 sizeof(ucontrol->value.integer.value));
2393 if (!substream->runtime)
2394 return 0; /* no channels set */
2395 for (map = info->chmap; map->channels; map++) {
2396 int i;
2397 if (map->channels == substream->runtime->channels &&
2398 valid_chmap_channels(info, map->channels)) {
2399 for (i = 0; i < map->channels; i++)
2400 ucontrol->value.integer.value[i] = map->map[i];
2401 return 0;
2402 }
2403 }
2404 return -EINVAL;
2405}
2406
2407/* tlv callback for channel map ctl element
2408 * expands the pre-defined channel maps in a form of TLV
2409 */
2410static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2411 unsigned int size, unsigned int __user *tlv)
2412{
2413 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2414 const struct snd_pcm_chmap_elem *map;
2415 unsigned int __user *dst;
2416 int c, count = 0;
2417
2418 if (snd_BUG_ON(!info->chmap))
2419 return -EINVAL;
2420 if (size < 8)
2421 return -ENOMEM;
2422 if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
2423 return -EFAULT;
2424 size -= 8;
2425 dst = tlv + 2;
2426 for (map = info->chmap; map->channels; map++) {
2427 int chs_bytes = map->channels * 4;
2428 if (!valid_chmap_channels(info, map->channels))
2429 continue;
2430 if (size < 8)
2431 return -ENOMEM;
2432 if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
2433 put_user(chs_bytes, dst + 1))
2434 return -EFAULT;
2435 dst += 2;
2436 size -= 8;
2437 count += 8;
2438 if (size < chs_bytes)
2439 return -ENOMEM;
2440 size -= chs_bytes;
2441 count += chs_bytes;
2442 for (c = 0; c < map->channels; c++) {
2443 if (put_user(map->map[c], dst))
2444 return -EFAULT;
2445 dst++;
2446 }
2447 }
2448 if (put_user(count, tlv + 1))
2449 return -EFAULT;
2450 return 0;
2451}
2452
2453static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
2454{
2455 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2456 info->pcm->streams[info->stream].chmap_kctl = NULL;
2457 kfree(info);
2458}
2459
Subhash Chandra Bose Naripeddy58f7b952013-04-25 19:32:52 -07002460static int pcm_volume_ctl_info(struct snd_kcontrol *kcontrol,
2461 struct snd_ctl_elem_info *uinfo)
2462{
2463 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2464 uinfo->count = 1;
2465 uinfo->value.integer.min = 0;
2466 uinfo->value.integer.max = 0x2000;
2467 return 0;
2468}
2469
2470static void pcm_volume_ctl_private_free(struct snd_kcontrol *kcontrol)
2471{
2472 struct snd_pcm_volume *info = snd_kcontrol_chip(kcontrol);
2473 info->pcm->streams[info->stream].vol_kctl = NULL;
2474 kfree(info);
2475}
2476
Subhash Chandra Bose Naripeddyff1e6252012-10-18 15:44:12 -07002477/**
2478 * snd_pcm_add_chmap_ctls - create channel-mapping control elements
2479 * @pcm: the assigned PCM instance
2480 * @stream: stream direction
2481 * @chmap: channel map elements (for query)
2482 * @max_channels: the max number of channels for the stream
2483 * @private_value: the value passed to each kcontrol's private_value field
2484 * @info_ret: store struct snd_pcm_chmap instance if non-NULL
2485 *
2486 * Create channel-mapping control elements assigned to the given PCM stream(s).
2487 * Returns zero if succeed, or a negative error value.
2488 */
2489int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
2490 const struct snd_pcm_chmap_elem *chmap,
2491 int max_channels,
2492 unsigned long private_value,
2493 struct snd_pcm_chmap **info_ret)
2494{
2495 struct snd_pcm_chmap *info;
2496 struct snd_kcontrol_new knew = {
2497 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
2498 .access = SNDRV_CTL_ELEM_ACCESS_READ |
Subhash Chandra Bose Naripeddyff1e6252012-10-18 15:44:12 -07002499 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2500 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
2501 .info = pcm_chmap_ctl_info,
2502 .get = pcm_chmap_ctl_get,
2503 .tlv.c = pcm_chmap_ctl_tlv,
2504 };
2505 int err;
2506
2507 info = kzalloc(sizeof(*info), GFP_KERNEL);
2508 if (!info)
2509 return -ENOMEM;
2510 info->pcm = pcm;
2511 info->stream = stream;
2512 info->chmap = chmap;
2513 info->max_channels = max_channels;
2514 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
2515 knew.name = "Playback Channel Map";
2516 else
2517 knew.name = "Capture Channel Map";
2518 knew.device = pcm->device;
2519 knew.count = pcm->streams[stream].substream_count;
2520 knew.private_value = private_value;
2521 info->kctl = snd_ctl_new1(&knew, info);
2522 if (!info->kctl) {
2523 kfree(info);
2524 return -ENOMEM;
2525 }
2526 info->kctl->private_free = pcm_chmap_ctl_private_free;
2527 err = snd_ctl_add(pcm->card, info->kctl);
2528 if (err < 0)
2529 return err;
2530 pcm->streams[stream].chmap_kctl = info->kctl;
2531 if (info_ret)
2532 *info_ret = info;
2533 return 0;
2534}
2535EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);
Subhash Chandra Bose Naripeddy58f7b952013-04-25 19:32:52 -07002536
2537/**
2538 * snd_pcm_add_volume_ctls - create volume control elements
2539 * @pcm: the assigned PCM instance
2540 * @stream: stream direction
2541 * @max_length: the max length of the volume parameter of stream
2542 * @private_value: the value passed to each kcontrol's private_value field
2543 * @info_ret: store struct snd_pcm_volume instance if non-NULL
2544 *
2545 * Create volume control elements assigned to the given PCM stream(s).
2546 * Returns zero if succeed, or a negative error value.
2547 */
2548int snd_pcm_add_volume_ctls(struct snd_pcm *pcm, int stream,
2549 const struct snd_pcm_volume_elem *volume,
2550 int max_length,
2551 unsigned long private_value,
2552 struct snd_pcm_volume **info_ret)
2553{
2554 struct snd_pcm_volume *info;
2555 struct snd_kcontrol_new knew = {
2556 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2557 .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2558 SNDRV_CTL_ELEM_ACCESS_READWRITE,
2559 .info = pcm_volume_ctl_info,
2560 };
2561 int err;
2562 int size;
2563
2564 info = kzalloc(sizeof(*info), GFP_KERNEL);
2565 if (!info)
2566 return -ENOMEM;
2567 info->pcm = pcm;
2568 info->stream = stream;
2569 info->volume = volume;
2570 info->max_length = max_length;
2571 size = sizeof("Playback ") + sizeof(" Volume") +
2572 STRING_LENGTH_OF_INT*sizeof(char) + 1;
2573 knew.name = kzalloc(size, GFP_KERNEL);
2574 if (!knew.name) {
2575 kfree(info);
2576 return -ENOMEM;
2577 }
2578 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
2579 snprintf(knew.name, size, "%s %d %s",
2580 "Playback", pcm->device, "Volume");
2581 else
2582 snprintf(knew.name, size, "%s %d %s",
2583 "Capture", pcm->device, "Volume");
2584 knew.device = pcm->device;
2585 knew.count = pcm->streams[stream].substream_count;
2586 knew.private_value = private_value;
2587 info->kctl = snd_ctl_new1(&knew, info);
2588 if (!info->kctl) {
2589 kfree(info);
2590 kfree(knew.name);
2591 return -ENOMEM;
2592 }
2593 info->kctl->private_free = pcm_volume_ctl_private_free;
2594 err = snd_ctl_add(pcm->card, info->kctl);
2595 if (err < 0) {
2596 kfree(info);
2597 kfree(knew.name);
2598 return -ENOMEM;
2599 }
2600 pcm->streams[stream].vol_kctl = info->kctl;
2601 if (info_ret)
2602 *info_ret = info;
2603 kfree(knew.name);
2604 return 0;
2605}
2606EXPORT_SYMBOL_GPL(snd_pcm_add_volume_ctls);