blob: e8131c060c8689eb94b26e14020ddee6408a4135 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Digital Audio (PCM) abstract layer
Jaroslav Kyselac1017a42007-10-15 09:50:19 +02003 * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * Abramo Bagnara <abramo@alsa-project.org>
5 *
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include <linux/slab.h>
Ingo Molnar174cd4b2017-02-02 19:15:33 +010024#include <linux/sched/signal.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include <linux/time.h>
Takashi Iwai3f7440a2009-06-05 17:40:04 +020026#include <linux/math64.h>
Paul Gortmakerd81a6d72011-09-22 09:34:58 -040027#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070028#include <sound/core.h>
29#include <sound/control.h>
Takashi Iwai2d3391e2012-07-27 18:27:00 +020030#include <sound/tlv.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include <sound/info.h>
32#include <sound/pcm.h>
33#include <sound/pcm_params.h>
34#include <sound/timer.h>
35
Takashi Sakamoto2c4842d2017-05-26 09:30:46 +090036#include "pcm_local.h"
37
Takashi Iwaif5914902014-11-04 12:45:59 +010038#ifdef CONFIG_SND_PCM_XRUN_DEBUG
39#define CREATE_TRACE_POINTS
40#include "pcm_trace.h"
41#else
42#define trace_hwptr(substream, pos, in_interrupt)
43#define trace_xrun(substream)
44#define trace_hw_ptr_error(substream, reason)
Takashi Sakamotofccf5382017-06-12 09:41:45 +090045#define trace_applptr(substream, prev, curr)
Takashi Iwaif5914902014-11-04 12:45:59 +010046#endif
47
Takashi Iwaia9cd29e2017-05-24 18:18:15 +020048static int fill_silence_frames(struct snd_pcm_substream *substream,
49 snd_pcm_uframes_t off, snd_pcm_uframes_t frames);
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051/*
52 * fill ring buffer with silence
53 * runtime->silence_start: starting pointer to silence area
54 * runtime->silence_filled: size filled with silence
55 * runtime->silence_threshold: threshold from application
56 * runtime->silence_size: maximal size from application
57 *
58 * when runtime->silence_size >= runtime->boundary - fill processed area with silence immediately
59 */
Takashi Iwai877211f2005-11-17 13:59:38 +010060void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_uframes_t new_hw_ptr)
Linus Torvalds1da177e2005-04-16 15:20:36 -070061{
Takashi Iwai877211f2005-11-17 13:59:38 +010062 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 snd_pcm_uframes_t frames, ofs, transfer;
Takashi Iwai29d1a872017-05-10 20:02:35 +020064 int err;
Linus Torvalds1da177e2005-04-16 15:20:36 -070065
66 if (runtime->silence_size < runtime->boundary) {
67 snd_pcm_sframes_t noise_dist, n;
68 if (runtime->silence_start != runtime->control->appl_ptr) {
69 n = runtime->control->appl_ptr - runtime->silence_start;
70 if (n < 0)
71 n += runtime->boundary;
72 if ((snd_pcm_uframes_t)n < runtime->silence_filled)
73 runtime->silence_filled -= n;
74 else
75 runtime->silence_filled = 0;
76 runtime->silence_start = runtime->control->appl_ptr;
77 }
Takashi Iwai235475c2005-12-07 15:28:07 +010078 if (runtime->silence_filled >= runtime->buffer_size)
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled;
81 if (noise_dist >= (snd_pcm_sframes_t) runtime->silence_threshold)
82 return;
83 frames = runtime->silence_threshold - noise_dist;
84 if (frames > runtime->silence_size)
85 frames = runtime->silence_size;
86 } else {
87 if (new_hw_ptr == ULONG_MAX) { /* initialization */
88 snd_pcm_sframes_t avail = snd_pcm_playback_hw_avail(runtime);
Jaroslav Kysela9e216e82010-07-19 16:37:39 +020089 if (avail > runtime->buffer_size)
90 avail = runtime->buffer_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 runtime->silence_filled = avail > 0 ? avail : 0;
92 runtime->silence_start = (runtime->status->hw_ptr +
93 runtime->silence_filled) %
94 runtime->boundary;
95 } else {
96 ofs = runtime->status->hw_ptr;
97 frames = new_hw_ptr - ofs;
98 if ((snd_pcm_sframes_t)frames < 0)
99 frames += runtime->boundary;
100 runtime->silence_filled -= frames;
101 if ((snd_pcm_sframes_t)runtime->silence_filled < 0) {
102 runtime->silence_filled = 0;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +0200103 runtime->silence_start = new_hw_ptr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 } else {
Clemens Ladisch9a826dd2006-10-23 16:26:57 +0200105 runtime->silence_start = ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 }
108 frames = runtime->buffer_size - runtime->silence_filled;
109 }
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200110 if (snd_BUG_ON(frames > runtime->buffer_size))
111 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 if (frames == 0)
113 return;
Clemens Ladisch9a826dd2006-10-23 16:26:57 +0200114 ofs = runtime->silence_start % runtime->buffer_size;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700115 while (frames > 0) {
116 transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames;
Takashi Iwaia9cd29e2017-05-24 18:18:15 +0200117 err = fill_silence_frames(substream, ofs, transfer);
118 snd_BUG_ON(err < 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 runtime->silence_filled += transfer;
120 frames -= transfer;
121 ofs = 0;
122 }
123}
124
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200125#ifdef CONFIG_SND_DEBUG
126void snd_pcm_debug_name(struct snd_pcm_substream *substream,
Takashi Iwaic0070112009-06-08 15:58:48 +0200127 char *name, size_t len)
128{
129 snprintf(name, len, "pcmC%dD%d%c:%d",
130 substream->pcm->card->number,
131 substream->pcm->device,
132 substream->stream ? 'c' : 'p',
133 substream->number);
134}
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200135EXPORT_SYMBOL(snd_pcm_debug_name);
136#endif
Takashi Iwaic0070112009-06-08 15:58:48 +0200137
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100138#define XRUN_DEBUG_BASIC (1<<0)
139#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
140#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100141
142#ifdef CONFIG_SND_PCM_XRUN_DEBUG
143
144#define xrun_debug(substream, mask) \
145 ((substream)->pstr->xrun_debug & (mask))
Jarkko Nikula0f170142010-03-26 16:07:25 +0200146#else
147#define xrun_debug(substream, mask) 0
148#endif
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100149
150#define dump_stack_on_xrun(substream) do { \
151 if (xrun_debug(substream, XRUN_DEBUG_STACK)) \
152 dump_stack(); \
153 } while (0)
154
Takashi Iwai877211f2005-11-17 13:59:38 +0100155static void xrun(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156{
Jaroslav Kysela13f040f2009-05-28 11:31:20 +0200157 struct snd_pcm_runtime *runtime = substream->runtime;
158
Takashi Iwaif5914902014-11-04 12:45:59 +0100159 trace_xrun(substream);
Jaroslav Kysela13f040f2009-05-28 11:31:20 +0200160 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
161 snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
Jaroslav Kysela741b20c2009-12-17 17:34:39 +0100163 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) {
Takashi Iwaic0070112009-06-08 15:58:48 +0200164 char name[16];
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200165 snd_pcm_debug_name(substream, name, sizeof(name));
Takashi Iwai09e56df2014-02-04 18:19:48 +0100166 pcm_warn(substream->pcm, "XRUN: %s\n", name);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100167 dump_stack_on_xrun(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700169}
170
Jarkko Nikula0f170142010-03-26 16:07:25 +0200171#ifdef CONFIG_SND_PCM_XRUN_DEBUG
Takashi Iwaif5914902014-11-04 12:45:59 +0100172#define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100173 do { \
Takashi Iwaif5914902014-11-04 12:45:59 +0100174 trace_hw_ptr_error(substream, reason); \
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100175 if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
Takashi Iwaif5914902014-11-04 12:45:59 +0100176 pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \
177 (in_interrupt) ? 'Q' : 'P', ##args); \
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100178 dump_stack_on_xrun(substream); \
179 } \
180 } while (0)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100182#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
183
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100184#define hw_ptr_error(substream, fmt, args...) do { } while (0)
Jaroslav Kysela4d96eb22009-12-20 11:47:57 +0100185
186#endif
187
Jaroslav Kysela12509322010-01-07 15:36:31 +0100188int snd_pcm_update_state(struct snd_pcm_substream *substream,
189 struct snd_pcm_runtime *runtime)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190{
191 snd_pcm_uframes_t avail;
192
193 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
194 avail = snd_pcm_playback_avail(runtime);
195 else
196 avail = snd_pcm_capture_avail(runtime);
197 if (avail > runtime->avail_max)
198 runtime->avail_max = avail;
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200199 if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
200 if (avail >= runtime->buffer_size) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 snd_pcm_drain_done(substream);
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200202 return -EPIPE;
203 }
204 } else {
205 if (avail >= runtime->stop_threshold) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206 xrun(substream);
Takashi Iwai4cdc1152009-08-20 16:40:16 +0200207 return -EPIPE;
208 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209 }
David Dillow5daeba32010-06-27 00:13:20 +0200210 if (runtime->twake) {
211 if (avail >= runtime->twake)
212 wake_up(&runtime->tsleep);
213 } else if (avail >= runtime->control->avail_min)
214 wake_up(&runtime->sleep);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700215 return 0;
216}
217
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600218static void update_audio_tstamp(struct snd_pcm_substream *substream,
219 struct timespec *curr_tstamp,
220 struct timespec *audio_tstamp)
221{
222 struct snd_pcm_runtime *runtime = substream->runtime;
223 u64 audio_frames, audio_nsecs;
224 struct timespec driver_tstamp;
225
226 if (runtime->tstamp_mode != SNDRV_PCM_TSTAMP_ENABLE)
227 return;
228
229 if (!(substream->ops->get_time_info) ||
230 (runtime->audio_tstamp_report.actual_type ==
231 SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
232
233 /*
234 * provide audio timestamp derived from pointer position
235 * add delay only if requested
236 */
237
238 audio_frames = runtime->hw_ptr_wrap + runtime->status->hw_ptr;
239
240 if (runtime->audio_tstamp_config.report_delay) {
241 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
242 audio_frames -= runtime->delay;
243 else
244 audio_frames += runtime->delay;
245 }
246 audio_nsecs = div_u64(audio_frames * 1000000000LL,
247 runtime->rate);
248 *audio_tstamp = ns_to_timespec(audio_nsecs);
249 }
250 runtime->status->audio_tstamp = *audio_tstamp;
251 runtime->status->tstamp = *curr_tstamp;
252
253 /*
254 * re-take a driver timestamp to let apps detect if the reference tstamp
255 * read by low-level hardware was provided with a delay
256 */
257 snd_pcm_gettime(substream->runtime, (struct timespec *)&driver_tstamp);
258 runtime->driver_tstamp = driver_tstamp;
259}
260
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100261static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
262 unsigned int in_interrupt)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700263{
Takashi Iwai877211f2005-11-17 13:59:38 +0100264 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 snd_pcm_uframes_t pos;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100266 snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200267 snd_pcm_sframes_t hdelta, delta;
268 unsigned long jdelta;
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500269 unsigned long curr_jiffies;
270 struct timespec curr_tstamp;
Pierre-Louis Bossart4eeaaea2012-10-22 16:42:15 -0500271 struct timespec audio_tstamp;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500272 int crossed_boundary = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200274 old_hw_ptr = runtime->status->hw_ptr;
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500275
276 /*
277 * group pointer, time and jiffies reads to allow for more
278 * accurate correlations/corrections.
279 * The values are stored at the end of this routine after
280 * corrections for hw_ptr position
281 */
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100282 pos = substream->ops->pointer(substream);
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500283 curr_jiffies = jiffies;
Pierre-Louis Bossart4eeaaea2012-10-22 16:42:15 -0500284 if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600285 if ((substream->ops->get_time_info) &&
286 (runtime->audio_tstamp_config.type_requested != SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)) {
287 substream->ops->get_time_info(substream, &curr_tstamp,
288 &audio_tstamp,
289 &runtime->audio_tstamp_config,
290 &runtime->audio_tstamp_report);
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500291
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600292 /* re-test in case tstamp type is not supported in hardware and was demoted to DEFAULT */
293 if (runtime->audio_tstamp_report.actual_type == SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT)
294 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
295 } else
296 snd_pcm_gettime(runtime, (struct timespec *)&curr_tstamp);
Pierre-Louis Bossart4eeaaea2012-10-22 16:42:15 -0500297 }
298
Linus Torvalds1da177e2005-04-16 15:20:36 -0700299 if (pos == SNDRV_PCM_POS_XRUN) {
300 xrun(substream);
301 return -EPIPE;
302 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100303 if (pos >= runtime->buffer_size) {
Takashi Iwai09e56df2014-02-04 18:19:48 +0100304 if (printk_ratelimit()) {
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100305 char name[16];
Eliot Blennerhassettacb03d42011-07-23 12:36:25 +1200306 snd_pcm_debug_name(substream, name, sizeof(name));
Takashi Iwai09e56df2014-02-04 18:19:48 +0100307 pcm_err(substream->pcm,
Takashi Iwai0ab1ace2016-03-10 20:56:20 +0100308 "invalid position: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
Takashi Iwai09e56df2014-02-04 18:19:48 +0100309 name, pos, runtime->buffer_size,
310 runtime->period_size);
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100311 }
312 pos = 0;
Takashi Iwaicedb8112009-07-23 11:04:13 +0200313 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100314 pos -= pos % runtime->min_align;
Takashi Iwaif5914902014-11-04 12:45:59 +0100315 trace_hwptr(substream, pos, in_interrupt);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100316 hw_base = runtime->hw_ptr_base;
317 new_hw_ptr = hw_base + pos;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100318 if (in_interrupt) {
319 /* we know that one period was processed */
320 /* delta = "expected next hw_ptr" for in_interrupt != 0 */
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100321 delta = runtime->hw_ptr_interrupt + runtime->period_size;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100322 if (delta > new_hw_ptr) {
Jaroslav Kyselabd76af02010-08-18 14:16:54 +0200323 /* check for double acknowledged interrupts */
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500324 hdelta = curr_jiffies - runtime->hw_ptr_jiffies;
Koro Chen13a98832015-05-13 22:39:03 +0800325 if (hdelta > runtime->hw_ptr_buffer_jiffies/2 + 1) {
Jaroslav Kyselabd76af02010-08-18 14:16:54 +0200326 hw_base += runtime->buffer_size;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500327 if (hw_base >= runtime->boundary) {
Jaroslav Kyselabd76af02010-08-18 14:16:54 +0200328 hw_base = 0;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500329 crossed_boundary++;
330 }
Jaroslav Kyselabd76af02010-08-18 14:16:54 +0200331 new_hw_ptr = hw_base + pos;
332 goto __delta;
333 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700334 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700335 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100336 /* new_hw_ptr might be lower than old_hw_ptr in case when */
337 /* pointer crosses the end of the ring buffer */
338 if (new_hw_ptr < old_hw_ptr) {
339 hw_base += runtime->buffer_size;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500340 if (hw_base >= runtime->boundary) {
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100341 hw_base = 0;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500342 crossed_boundary++;
343 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100344 new_hw_ptr = hw_base + pos;
345 }
346 __delta:
Clemens Ladischb406e612010-05-25 09:01:46 +0200347 delta = new_hw_ptr - old_hw_ptr;
348 if (delta < 0)
349 delta += runtime->boundary;
Clemens Ladischab69a492010-11-15 10:46:23 +0100350
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100351 if (runtime->no_period_wakeup) {
Kelly Anderson12ff4142011-04-01 11:58:25 +0200352 snd_pcm_sframes_t xrun_threshold;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100353 /*
354 * Without regular period interrupts, we have to check
355 * the elapsed time to detect xruns.
356 */
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500357 jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
Clemens Ladisch47228e42010-11-18 09:53:07 +0100358 if (jdelta < runtime->hw_ptr_buffer_jiffies / 2)
359 goto no_delta_check;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100360 hdelta = jdelta - delta * HZ / runtime->rate;
Kelly Anderson12ff4142011-04-01 11:58:25 +0200361 xrun_threshold = runtime->hw_ptr_buffer_jiffies / 2 + 1;
362 while (hdelta > xrun_threshold) {
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100363 delta += runtime->buffer_size;
364 hw_base += runtime->buffer_size;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500365 if (hw_base >= runtime->boundary) {
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100366 hw_base = 0;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500367 crossed_boundary++;
368 }
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100369 new_hw_ptr = hw_base + pos;
370 hdelta -= runtime->hw_ptr_buffer_jiffies;
371 }
Clemens Ladischab69a492010-11-15 10:46:23 +0100372 goto no_delta_check;
Clemens Ladisch59ff8782010-11-18 09:43:52 +0100373 }
Clemens Ladischab69a492010-11-15 10:46:23 +0100374
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100375 /* something must be really wrong */
Jaroslav Kysela7b3a1772010-01-08 08:43:01 +0100376 if (delta >= runtime->buffer_size + runtime->period_size) {
Takashi Iwaif5914902014-11-04 12:45:59 +0100377 hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr",
378 "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
379 substream->stream, (long)pos,
380 (long)new_hw_ptr, (long)old_hw_ptr);
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100381 return 0;
382 }
Takashi Iwaic87d9732009-05-27 10:53:33 +0200383
384 /* Do jiffies check only in xrun_debug mode */
Jaroslav Kysela741b20c2009-12-17 17:34:39 +0100385 if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK))
Takashi Iwaic87d9732009-05-27 10:53:33 +0200386 goto no_jiffies_check;
387
Takashi Iwai3e5b5012009-04-28 12:07:08 +0200388 /* Skip the jiffies check for hardwares with BATCH flag.
389 * Such hardware usually just increases the position at each IRQ,
390 * thus it can't give any strange position.
391 */
392 if (runtime->hw.info & SNDRV_PCM_INFO_BATCH)
393 goto no_jiffies_check;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100394 hdelta = delta;
Jaroslav Kyselaa4444da2009-05-28 12:31:56 +0200395 if (hdelta < runtime->delay)
396 goto no_jiffies_check;
397 hdelta -= runtime->delay;
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500398 jdelta = curr_jiffies - runtime->hw_ptr_jiffies;
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200399 if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
400 delta = jdelta /
401 (((runtime->period_size * HZ) / runtime->rate)
402 + HZ/100);
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100403 /* move new_hw_ptr according jiffies not pos variable */
404 new_hw_ptr = old_hw_ptr;
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100405 hw_base = delta;
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100406 /* use loop to avoid checks for delta overflows */
407 /* the delta value is small or zero in most cases */
408 while (delta > 0) {
409 new_hw_ptr += runtime->period_size;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500410 if (new_hw_ptr >= runtime->boundary) {
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100411 new_hw_ptr -= runtime->boundary;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500412 crossed_boundary--;
413 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100414 delta--;
415 }
416 /* align hw_base to buffer_size */
Takashi Iwaif5914902014-11-04 12:45:59 +0100417 hw_ptr_error(substream, in_interrupt, "hw_ptr skipping",
418 "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200419 (long)pos, (long)hdelta,
420 (long)runtime->period_size, jdelta,
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100421 ((hdelta * HZ) / runtime->rate), hw_base,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100422 (unsigned long)old_hw_ptr,
423 (unsigned long)new_hw_ptr);
Jaroslav Kyselaed69c6a2010-01-13 08:12:31 +0100424 /* reset values to proper state */
425 delta = 0;
426 hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size);
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200427 }
Takashi Iwai3e5b5012009-04-28 12:07:08 +0200428 no_jiffies_check:
Jaroslav Kyselabbf6ad12009-04-10 12:28:58 +0200429 if (delta > runtime->period_size + runtime->period_size / 2) {
Takashi Iwaif5914902014-11-04 12:45:59 +0100430 hw_ptr_error(substream, in_interrupt,
431 "Lost interrupts?",
432 "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100433 substream->stream, (long)delta,
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100434 (long)new_hw_ptr,
435 (long)old_hw_ptr);
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100436 }
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100437
Clemens Ladischab69a492010-11-15 10:46:23 +0100438 no_delta_check:
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600439 if (runtime->status->hw_ptr == new_hw_ptr) {
440 update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100441 return 0;
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600442 }
Takashi Iwaiab1863f2009-06-07 12:09:17 +0200443
Linus Torvalds1da177e2005-04-16 15:20:36 -0700444 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
445 runtime->silence_size > 0)
446 snd_pcm_playback_silence(substream, new_hw_ptr);
447
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100448 if (in_interrupt) {
Clemens Ladischead40462010-05-21 09:15:59 +0200449 delta = new_hw_ptr - runtime->hw_ptr_interrupt;
450 if (delta < 0)
451 delta += runtime->boundary;
452 delta -= (snd_pcm_uframes_t)delta % runtime->period_size;
453 runtime->hw_ptr_interrupt += delta;
454 if (runtime->hw_ptr_interrupt >= runtime->boundary)
455 runtime->hw_ptr_interrupt -= runtime->boundary;
Jaroslav Kyselae7636922010-01-26 17:08:24 +0100456 }
Takashi Iwaied3da3d2009-03-03 17:00:15 +0100457 runtime->hw_ptr_base = hw_base;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 runtime->status->hw_ptr = new_hw_ptr;
Pierre-Louis Bossart3509a032012-05-22 14:54:02 -0500459 runtime->hw_ptr_jiffies = curr_jiffies;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -0500460 if (crossed_boundary) {
461 snd_BUG_ON(crossed_boundary != 1);
462 runtime->hw_ptr_wrap += runtime->boundary;
463 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464
Pierre-Louis Bossart3179f622015-02-13 15:14:06 -0600465 update_audio_tstamp(substream, &curr_tstamp, &audio_tstamp);
Pierre-Louis Bossart4eeaaea2012-10-22 16:42:15 -0500466
Jaroslav Kysela12509322010-01-07 15:36:31 +0100467 return snd_pcm_update_state(substream, runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468}
469
470/* CAUTION: call it with irq disabled */
Takashi Iwai877211f2005-11-17 13:59:38 +0100471int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700472{
Jaroslav Kyselaf2404062010-01-05 17:19:34 +0100473 return snd_pcm_update_hw_ptr0(substream, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700474}
475
476/**
477 * snd_pcm_set_ops - set the PCM operators
478 * @pcm: the pcm instance
479 * @direction: stream direction, SNDRV_PCM_STREAM_XXX
480 * @ops: the operator table
481 *
482 * Sets the given PCM operators to the pcm instance.
483 */
Lars-Peter Clausene6c2e7e2013-05-24 15:18:10 +0200484void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
485 const struct snd_pcm_ops *ops)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486{
Takashi Iwai877211f2005-11-17 13:59:38 +0100487 struct snd_pcm_str *stream = &pcm->streams[direction];
488 struct snd_pcm_substream *substream;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489
490 for (substream = stream->substream; substream != NULL; substream = substream->next)
491 substream->ops = ops;
492}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200493EXPORT_SYMBOL(snd_pcm_set_ops);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700494
495/**
496 * snd_pcm_sync - set the PCM sync id
497 * @substream: the pcm substream
498 *
499 * Sets the PCM sync identifier for the card.
500 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100501void snd_pcm_set_sync(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Takashi Iwai877211f2005-11-17 13:59:38 +0100503 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700504
505 runtime->sync.id32[0] = substream->pcm->card->number;
506 runtime->sync.id32[1] = -1;
507 runtime->sync.id32[2] = -1;
508 runtime->sync.id32[3] = -1;
509}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200510EXPORT_SYMBOL(snd_pcm_set_sync);
511
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512/*
513 * Standard ioctl routine
514 */
515
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516static inline unsigned int div32(unsigned int a, unsigned int b,
517 unsigned int *r)
518{
519 if (b == 0) {
520 *r = 0;
521 return UINT_MAX;
522 }
523 *r = a % b;
524 return a / b;
525}
526
527static inline unsigned int div_down(unsigned int a, unsigned int b)
528{
529 if (b == 0)
530 return UINT_MAX;
531 return a / b;
532}
533
534static inline unsigned int div_up(unsigned int a, unsigned int b)
535{
536 unsigned int r;
537 unsigned int q;
538 if (b == 0)
539 return UINT_MAX;
540 q = div32(a, b, &r);
541 if (r)
542 ++q;
543 return q;
544}
545
546static inline unsigned int mul(unsigned int a, unsigned int b)
547{
548 if (a == 0)
549 return 0;
550 if (div_down(UINT_MAX, a) < b)
551 return UINT_MAX;
552 return a * b;
553}
554
555static inline unsigned int muldiv32(unsigned int a, unsigned int b,
556 unsigned int c, unsigned int *r)
557{
558 u_int64_t n = (u_int64_t) a * b;
559 if (c == 0) {
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200560 snd_BUG_ON(!n);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561 *r = 0;
562 return UINT_MAX;
563 }
Takashi Iwai3f7440a2009-06-05 17:40:04 +0200564 n = div_u64_rem(n, c, r);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565 if (n >= UINT_MAX) {
566 *r = 0;
567 return UINT_MAX;
568 }
569 return n;
570}
571
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572/**
573 * snd_interval_refine - refine the interval value of configurator
574 * @i: the interval value to refine
575 * @v: the interval value to refer to
576 *
577 * Refines the interval value with the reference value.
578 * The interval is changed to the range satisfying both intervals.
579 * The interval status (min, max, integer, etc.) are evaluated.
580 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100581 * Return: Positive if the value is changed, zero if it's not changed, or a
582 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100584int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585{
586 int changed = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200587 if (snd_BUG_ON(snd_interval_empty(i)))
588 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (i->min < v->min) {
590 i->min = v->min;
591 i->openmin = v->openmin;
592 changed = 1;
593 } else if (i->min == v->min && !i->openmin && v->openmin) {
594 i->openmin = 1;
595 changed = 1;
596 }
597 if (i->max > v->max) {
598 i->max = v->max;
599 i->openmax = v->openmax;
600 changed = 1;
601 } else if (i->max == v->max && !i->openmax && v->openmax) {
602 i->openmax = 1;
603 changed = 1;
604 }
605 if (!i->integer && v->integer) {
606 i->integer = 1;
607 changed = 1;
608 }
609 if (i->integer) {
610 if (i->openmin) {
611 i->min++;
612 i->openmin = 0;
613 }
614 if (i->openmax) {
615 i->max--;
616 i->openmax = 0;
617 }
618 } else if (!i->openmin && !i->openmax && i->min == i->max)
619 i->integer = 1;
620 if (snd_interval_checkempty(i)) {
621 snd_interval_none(i);
622 return -EINVAL;
623 }
624 return changed;
625}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200626EXPORT_SYMBOL(snd_interval_refine);
627
Takashi Iwai877211f2005-11-17 13:59:38 +0100628static int snd_interval_refine_first(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700629{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200630 if (snd_BUG_ON(snd_interval_empty(i)))
631 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 if (snd_interval_single(i))
633 return 0;
634 i->max = i->min;
635 i->openmax = i->openmin;
636 if (i->openmax)
637 i->max++;
638 return 1;
639}
640
Takashi Iwai877211f2005-11-17 13:59:38 +0100641static int snd_interval_refine_last(struct snd_interval *i)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700642{
Takashi Iwai7eaa9432008-08-08 17:09:09 +0200643 if (snd_BUG_ON(snd_interval_empty(i)))
644 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 if (snd_interval_single(i))
646 return 0;
647 i->min = i->max;
648 i->openmin = i->openmax;
649 if (i->openmin)
650 i->min--;
651 return 1;
652}
653
Takashi Iwai877211f2005-11-17 13:59:38 +0100654void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655{
656 if (a->empty || b->empty) {
657 snd_interval_none(c);
658 return;
659 }
660 c->empty = 0;
661 c->min = mul(a->min, b->min);
662 c->openmin = (a->openmin || b->openmin);
663 c->max = mul(a->max, b->max);
664 c->openmax = (a->openmax || b->openmax);
665 c->integer = (a->integer && b->integer);
666}
667
668/**
669 * snd_interval_div - refine the interval value with division
Takashi Iwaidf8db932005-09-07 13:38:19 +0200670 * @a: dividend
671 * @b: divisor
672 * @c: quotient
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 *
674 * c = a / b
675 *
676 * Returns non-zero if the value is changed, zero if not changed.
677 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100678void snd_interval_div(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679{
680 unsigned int r;
681 if (a->empty || b->empty) {
682 snd_interval_none(c);
683 return;
684 }
685 c->empty = 0;
686 c->min = div32(a->min, b->max, &r);
687 c->openmin = (r || a->openmin || b->openmax);
688 if (b->min > 0) {
689 c->max = div32(a->max, b->min, &r);
690 if (r) {
691 c->max++;
692 c->openmax = 1;
693 } else
694 c->openmax = (a->openmax || b->openmin);
695 } else {
696 c->max = UINT_MAX;
697 c->openmax = 0;
698 }
699 c->integer = 0;
700}
701
702/**
703 * snd_interval_muldivk - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200704 * @a: dividend 1
705 * @b: dividend 2
706 * @k: divisor (as integer)
707 * @c: result
708 *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 * c = a * b / k
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_muldivk(const struct snd_interval *a, const struct snd_interval *b,
714 unsigned int k, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715{
716 unsigned int r;
717 if (a->empty || b->empty) {
718 snd_interval_none(c);
719 return;
720 }
721 c->empty = 0;
722 c->min = muldiv32(a->min, b->min, k, &r);
723 c->openmin = (r || a->openmin || b->openmin);
724 c->max = muldiv32(a->max, b->max, k, &r);
725 if (r) {
726 c->max++;
727 c->openmax = 1;
728 } else
729 c->openmax = (a->openmax || b->openmax);
730 c->integer = 0;
731}
732
733/**
734 * snd_interval_mulkdiv - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200735 * @a: dividend 1
736 * @k: dividend 2 (as integer)
737 * @b: divisor
738 * @c: result
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 *
740 * c = a * k / b
741 *
742 * Returns non-zero if the value is changed, zero if not changed.
743 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100744void snd_interval_mulkdiv(const struct snd_interval *a, unsigned int k,
745 const struct snd_interval *b, struct snd_interval *c)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
747 unsigned int r;
748 if (a->empty || b->empty) {
749 snd_interval_none(c);
750 return;
751 }
752 c->empty = 0;
753 c->min = muldiv32(a->min, k, b->max, &r);
754 c->openmin = (r || a->openmin || b->openmax);
755 if (b->min > 0) {
756 c->max = muldiv32(a->max, k, b->min, &r);
757 if (r) {
758 c->max++;
759 c->openmax = 1;
760 } else
761 c->openmax = (a->openmax || b->openmin);
762 } else {
763 c->max = UINT_MAX;
764 c->openmax = 0;
765 }
766 c->integer = 0;
767}
768
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769/* ---- */
770
771
772/**
773 * snd_interval_ratnum - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200774 * @i: interval to refine
775 * @rats_count: number of ratnum_t
776 * @rats: ratnum_t array
777 * @nump: pointer to store the resultant numerator
778 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100780 * Return: Positive if the value is changed, zero if it's not changed, or a
781 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100783int snd_interval_ratnum(struct snd_interval *i,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +0100784 unsigned int rats_count, const struct snd_ratnum *rats,
Takashi Iwai877211f2005-11-17 13:59:38 +0100785 unsigned int *nump, unsigned int *denp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700786{
Krzysztof Helt8374e242009-12-21 17:07:08 +0100787 unsigned int best_num, best_den;
788 int best_diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700789 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100790 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791 int err;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100792 unsigned int result_num, result_den;
793 int result_diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794
795 best_num = best_den = best_diff = 0;
796 for (k = 0; k < rats_count; ++k) {
797 unsigned int num = rats[k].num;
798 unsigned int den;
799 unsigned int q = i->min;
800 int diff;
801 if (q == 0)
802 q = 1;
Krzysztof Helt40962d72009-12-19 18:31:04 +0100803 den = div_up(num, q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if (den < rats[k].den_min)
805 continue;
806 if (den > rats[k].den_max)
807 den = rats[k].den_max;
808 else {
809 unsigned int r;
810 r = (den - rats[k].den_min) % rats[k].den_step;
811 if (r != 0)
812 den -= r;
813 }
814 diff = num - q * den;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100815 if (diff < 0)
816 diff = -diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (best_num == 0 ||
818 diff * best_den < best_diff * den) {
819 best_diff = diff;
820 best_den = den;
821 best_num = num;
822 }
823 }
824 if (best_den == 0) {
825 i->empty = 1;
826 return -EINVAL;
827 }
828 t.min = div_down(best_num, best_den);
829 t.openmin = !!(best_num % best_den);
830
Krzysztof Helt8374e242009-12-21 17:07:08 +0100831 result_num = best_num;
832 result_diff = best_diff;
833 result_den = best_den;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 best_num = best_den = best_diff = 0;
835 for (k = 0; k < rats_count; ++k) {
836 unsigned int num = rats[k].num;
837 unsigned int den;
838 unsigned int q = i->max;
839 int diff;
840 if (q == 0) {
841 i->empty = 1;
842 return -EINVAL;
843 }
Krzysztof Helt40962d72009-12-19 18:31:04 +0100844 den = div_down(num, q);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 if (den > rats[k].den_max)
846 continue;
847 if (den < rats[k].den_min)
848 den = rats[k].den_min;
849 else {
850 unsigned int r;
851 r = (den - rats[k].den_min) % rats[k].den_step;
852 if (r != 0)
853 den += rats[k].den_step - r;
854 }
855 diff = q * den - num;
Krzysztof Helt8374e242009-12-21 17:07:08 +0100856 if (diff < 0)
857 diff = -diff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858 if (best_num == 0 ||
859 diff * best_den < best_diff * den) {
860 best_diff = diff;
861 best_den = den;
862 best_num = num;
863 }
864 }
865 if (best_den == 0) {
866 i->empty = 1;
867 return -EINVAL;
868 }
869 t.max = div_up(best_num, best_den);
870 t.openmax = !!(best_num % best_den);
871 t.integer = 0;
872 err = snd_interval_refine(i, &t);
873 if (err < 0)
874 return err;
875
876 if (snd_interval_single(i)) {
Krzysztof Helt8374e242009-12-21 17:07:08 +0100877 if (best_diff * result_den < result_diff * best_den) {
878 result_num = best_num;
879 result_den = best_den;
880 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700881 if (nump)
Krzysztof Helt8374e242009-12-21 17:07:08 +0100882 *nump = result_num;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 if (denp)
Krzysztof Helt8374e242009-12-21 17:07:08 +0100884 *denp = result_den;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885 }
886 return err;
887}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +0200888EXPORT_SYMBOL(snd_interval_ratnum);
889
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890/**
891 * snd_interval_ratden - refine the interval value
Takashi Iwaidf8db932005-09-07 13:38:19 +0200892 * @i: interval to refine
Takashi Iwai877211f2005-11-17 13:59:38 +0100893 * @rats_count: number of struct ratden
894 * @rats: struct ratden array
Takashi Iwaidf8db932005-09-07 13:38:19 +0200895 * @nump: pointer to store the resultant numerator
896 * @denp: pointer to store the resultant denominator
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100898 * Return: Positive if the value is changed, zero if it's not changed, or a
899 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 */
Takashi Iwai877211f2005-11-17 13:59:38 +0100901static int snd_interval_ratden(struct snd_interval *i,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +0100902 unsigned int rats_count,
903 const struct snd_ratden *rats,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904 unsigned int *nump, unsigned int *denp)
905{
906 unsigned int best_num, best_diff, best_den;
907 unsigned int k;
Takashi Iwai877211f2005-11-17 13:59:38 +0100908 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 int err;
910
911 best_num = best_den = best_diff = 0;
912 for (k = 0; k < rats_count; ++k) {
913 unsigned int num;
914 unsigned int den = rats[k].den;
915 unsigned int q = i->min;
916 int diff;
917 num = mul(q, den);
918 if (num > rats[k].num_max)
919 continue;
920 if (num < rats[k].num_min)
921 num = rats[k].num_max;
922 else {
923 unsigned int r;
924 r = (num - rats[k].num_min) % rats[k].num_step;
925 if (r != 0)
926 num += rats[k].num_step - r;
927 }
928 diff = num - q * den;
929 if (best_num == 0 ||
930 diff * best_den < best_diff * den) {
931 best_diff = diff;
932 best_den = den;
933 best_num = num;
934 }
935 }
936 if (best_den == 0) {
937 i->empty = 1;
938 return -EINVAL;
939 }
940 t.min = div_down(best_num, best_den);
941 t.openmin = !!(best_num % best_den);
942
943 best_num = best_den = best_diff = 0;
944 for (k = 0; k < rats_count; ++k) {
945 unsigned int num;
946 unsigned int den = rats[k].den;
947 unsigned int q = i->max;
948 int diff;
949 num = mul(q, den);
950 if (num < rats[k].num_min)
951 continue;
952 if (num > rats[k].num_max)
953 num = rats[k].num_max;
954 else {
955 unsigned int r;
956 r = (num - rats[k].num_min) % rats[k].num_step;
957 if (r != 0)
958 num -= r;
959 }
960 diff = q * den - num;
961 if (best_num == 0 ||
962 diff * best_den < best_diff * den) {
963 best_diff = diff;
964 best_den = den;
965 best_num = num;
966 }
967 }
968 if (best_den == 0) {
969 i->empty = 1;
970 return -EINVAL;
971 }
972 t.max = div_up(best_num, best_den);
973 t.openmax = !!(best_num % best_den);
974 t.integer = 0;
975 err = snd_interval_refine(i, &t);
976 if (err < 0)
977 return err;
978
979 if (snd_interval_single(i)) {
980 if (nump)
981 *nump = best_num;
982 if (denp)
983 *denp = best_den;
984 }
985 return err;
986}
987
988/**
989 * snd_interval_list - refine the interval value from the list
990 * @i: the interval value to refine
991 * @count: the number of elements in the list
992 * @list: the value list
993 * @mask: the bit-mask to evaluate
994 *
995 * Refines the interval value from the list.
996 * When mask is non-zero, only the elements corresponding to bit 1 are
997 * evaluated.
998 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +0100999 * Return: Positive if the value is changed, zero if it's not changed, or a
1000 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 */
Mark Brown4af87a92012-03-14 19:48:43 +00001002int snd_interval_list(struct snd_interval *i, unsigned int count,
1003 const unsigned int *list, unsigned int mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001004{
1005 unsigned int k;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001006 struct snd_interval list_range;
Takashi Iwai0981a262007-02-01 14:53:49 +01001007
1008 if (!count) {
1009 i->empty = 1;
1010 return -EINVAL;
1011 }
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001012 snd_interval_any(&list_range);
1013 list_range.min = UINT_MAX;
1014 list_range.max = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015 for (k = 0; k < count; k++) {
1016 if (mask && !(mask & (1 << k)))
1017 continue;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001018 if (!snd_interval_test(i, list[k]))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019 continue;
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001020 list_range.min = min(list_range.min, list[k]);
1021 list_range.max = max(list_range.max, list[k]);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001022 }
Clemens Ladischb1ddaf62009-08-25 08:15:41 +02001023 return snd_interval_refine(i, &list_range);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001025EXPORT_SYMBOL(snd_interval_list);
1026
Peter Rosinf66f8982015-01-28 15:16:06 +01001027/**
1028 * snd_interval_ranges - refine the interval value from the list of ranges
1029 * @i: the interval value to refine
1030 * @count: the number of elements in the list of ranges
1031 * @ranges: the ranges list
1032 * @mask: the bit-mask to evaluate
1033 *
1034 * Refines the interval value from the list of ranges.
1035 * When mask is non-zero, only the elements corresponding to bit 1 are
1036 * evaluated.
1037 *
1038 * Return: Positive if the value is changed, zero if it's not changed, or a
1039 * negative error code.
1040 */
1041int snd_interval_ranges(struct snd_interval *i, unsigned int count,
1042 const struct snd_interval *ranges, unsigned int mask)
1043{
1044 unsigned int k;
1045 struct snd_interval range_union;
1046 struct snd_interval range;
1047
1048 if (!count) {
1049 snd_interval_none(i);
1050 return -EINVAL;
1051 }
1052 snd_interval_any(&range_union);
1053 range_union.min = UINT_MAX;
1054 range_union.max = 0;
1055 for (k = 0; k < count; k++) {
1056 if (mask && !(mask & (1 << k)))
1057 continue;
1058 snd_interval_copy(&range, &ranges[k]);
1059 if (snd_interval_refine(&range, i) < 0)
1060 continue;
1061 if (snd_interval_empty(&range))
1062 continue;
1063
1064 if (range.min < range_union.min) {
1065 range_union.min = range.min;
1066 range_union.openmin = 1;
1067 }
1068 if (range.min == range_union.min && !range.openmin)
1069 range_union.openmin = 0;
1070 if (range.max > range_union.max) {
1071 range_union.max = range.max;
1072 range_union.openmax = 1;
1073 }
1074 if (range.max == range_union.max && !range.openmax)
1075 range_union.openmax = 0;
1076 }
1077 return snd_interval_refine(i, &range_union);
1078}
1079EXPORT_SYMBOL(snd_interval_ranges);
1080
Clemens Ladisch0f519b62014-09-07 21:43:07 +02001081static int snd_interval_step(struct snd_interval *i, unsigned int step)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001082{
1083 unsigned int n;
1084 int changed = 0;
Clemens Ladisch0f519b62014-09-07 21:43:07 +02001085 n = i->min % step;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001086 if (n != 0 || i->openmin) {
1087 i->min += step - n;
Clemens Ladischdf1e4712014-09-07 21:43:41 +02001088 i->openmin = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001089 changed = 1;
1090 }
Clemens Ladisch0f519b62014-09-07 21:43:07 +02001091 n = i->max % step;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001092 if (n != 0 || i->openmax) {
1093 i->max -= n;
Clemens Ladischdf1e4712014-09-07 21:43:41 +02001094 i->openmax = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095 changed = 1;
1096 }
1097 if (snd_interval_checkempty(i)) {
1098 i->empty = 1;
1099 return -EINVAL;
1100 }
1101 return changed;
1102}
1103
1104/* Info constraints helpers */
1105
1106/**
1107 * snd_pcm_hw_rule_add - add the hw-constraint rule
1108 * @runtime: the pcm runtime instance
1109 * @cond: condition bits
1110 * @var: the variable to evaluate
1111 * @func: the evaluation function
1112 * @private: the private data pointer passed to function
1113 * @dep: the dependent variables
1114 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001115 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001116 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001117int snd_pcm_hw_rule_add(struct snd_pcm_runtime *runtime, unsigned int cond,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001118 int var,
1119 snd_pcm_hw_rule_func_t func, void *private,
1120 int dep, ...)
1121{
Takashi Iwai877211f2005-11-17 13:59:38 +01001122 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1123 struct snd_pcm_hw_rule *c;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 unsigned int k;
1125 va_list args;
1126 va_start(args, dep);
1127 if (constrs->rules_num >= constrs->rules_all) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001128 struct snd_pcm_hw_rule *new;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001129 unsigned int new_rules = constrs->rules_all + 16;
1130 new = kcalloc(new_rules, sizeof(*c), GFP_KERNEL);
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001131 if (!new) {
1132 va_end(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 return -ENOMEM;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001134 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135 if (constrs->rules) {
1136 memcpy(new, constrs->rules,
1137 constrs->rules_num * sizeof(*c));
1138 kfree(constrs->rules);
1139 }
1140 constrs->rules = new;
1141 constrs->rules_all = new_rules;
1142 }
1143 c = &constrs->rules[constrs->rules_num];
1144 c->cond = cond;
1145 c->func = func;
1146 c->var = var;
1147 c->private = private;
1148 k = 0;
1149 while (1) {
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001150 if (snd_BUG_ON(k >= ARRAY_SIZE(c->deps))) {
1151 va_end(args);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001152 return -EINVAL;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001153 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 c->deps[k++] = dep;
1155 if (dep < 0)
1156 break;
1157 dep = va_arg(args, int);
1158 }
1159 constrs->rules_num++;
1160 va_end(args);
1161 return 0;
Jesper Juhl87a1c8a2010-12-21 00:03:17 +01001162}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001163EXPORT_SYMBOL(snd_pcm_hw_rule_add);
1164
Linus Torvalds1da177e2005-04-16 15:20:36 -07001165/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001166 * snd_pcm_hw_constraint_mask - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +02001167 * @runtime: PCM runtime instance
1168 * @var: hw_params variable to apply the mask
1169 * @mask: the bitmap mask
1170 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001171 * Apply the constraint of the given bitmap mask to a 32-bit mask parameter.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001172 *
1173 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001174 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001175int snd_pcm_hw_constraint_mask(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001176 u_int32_t mask)
1177{
Takashi Iwai877211f2005-11-17 13:59:38 +01001178 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1179 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001180 *maskp->bits &= mask;
1181 memset(maskp->bits + 1, 0, (SNDRV_MASK_MAX-32) / 8); /* clear rest */
1182 if (*maskp->bits == 0)
1183 return -EINVAL;
1184 return 0;
1185}
1186
1187/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001188 * snd_pcm_hw_constraint_mask64 - apply the given bitmap mask constraint
Takashi Iwaidf8db932005-09-07 13:38:19 +02001189 * @runtime: PCM runtime instance
1190 * @var: hw_params variable to apply the mask
1191 * @mask: the 64bit bitmap mask
1192 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001193 * Apply the constraint of the given bitmap mask to a 64-bit mask parameter.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001194 *
1195 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001196 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001197int snd_pcm_hw_constraint_mask64(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001198 u_int64_t mask)
1199{
Takashi Iwai877211f2005-11-17 13:59:38 +01001200 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1201 struct snd_mask *maskp = constrs_mask(constrs, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001202 maskp->bits[0] &= (u_int32_t)mask;
1203 maskp->bits[1] &= (u_int32_t)(mask >> 32);
1204 memset(maskp->bits + 2, 0, (SNDRV_MASK_MAX-64) / 8); /* clear rest */
1205 if (! maskp->bits[0] && ! maskp->bits[1])
1206 return -EINVAL;
1207 return 0;
1208}
Mark Brown63a5d4c2014-02-20 12:13:52 +09001209EXPORT_SYMBOL(snd_pcm_hw_constraint_mask64);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001210
1211/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001212 * snd_pcm_hw_constraint_integer - apply an integer constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +02001213 * @runtime: PCM runtime instance
1214 * @var: hw_params variable to apply the integer constraint
1215 *
1216 * Apply the constraint of integer to an interval parameter.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001217 *
1218 * Return: Positive if the value is changed, zero if it's not changed, or a
1219 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001220 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001221int snd_pcm_hw_constraint_integer(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001222{
Takashi Iwai877211f2005-11-17 13:59:38 +01001223 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001224 return snd_interval_setinteger(constrs_interval(constrs, var));
1225}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001226EXPORT_SYMBOL(snd_pcm_hw_constraint_integer);
1227
Linus Torvalds1da177e2005-04-16 15:20:36 -07001228/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001229 * snd_pcm_hw_constraint_minmax - apply a min/max range constraint to an interval
Takashi Iwaidf8db932005-09-07 13:38:19 +02001230 * @runtime: PCM runtime instance
1231 * @var: hw_params variable to apply the range
1232 * @min: the minimal value
1233 * @max: the maximal value
1234 *
1235 * Apply the min/max range constraint to an interval parameter.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001236 *
1237 * Return: Positive if the value is changed, zero if it's not changed, or a
1238 * negative error code.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001239 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001240int snd_pcm_hw_constraint_minmax(struct snd_pcm_runtime *runtime, snd_pcm_hw_param_t var,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001241 unsigned int min, unsigned int max)
1242{
Takashi Iwai877211f2005-11-17 13:59:38 +01001243 struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
1244 struct snd_interval t;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245 t.min = min;
1246 t.max = max;
1247 t.openmin = t.openmax = 0;
1248 t.integer = 0;
1249 return snd_interval_refine(constrs_interval(constrs, var), &t);
1250}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001251EXPORT_SYMBOL(snd_pcm_hw_constraint_minmax);
1252
Takashi Iwai877211f2005-11-17 13:59:38 +01001253static int snd_pcm_hw_rule_list(struct snd_pcm_hw_params *params,
1254 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001255{
Takashi Iwai877211f2005-11-17 13:59:38 +01001256 struct snd_pcm_hw_constraint_list *list = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 return snd_interval_list(hw_param_interval(params, rule->var), list->count, list->list, list->mask);
1258}
1259
1260
1261/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001262 * snd_pcm_hw_constraint_list - apply a list of constraints to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001263 * @runtime: PCM runtime instance
1264 * @cond: condition bits
1265 * @var: hw_params variable to apply the list constraint
1266 * @l: list
1267 *
1268 * Apply the list of constraints to an interval parameter.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001269 *
1270 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001271 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001272int snd_pcm_hw_constraint_list(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 unsigned int cond,
1274 snd_pcm_hw_param_t var,
Mark Brown14641892012-07-05 12:15:01 +01001275 const struct snd_pcm_hw_constraint_list *l)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001276{
1277 return snd_pcm_hw_rule_add(runtime, cond, var,
Mark Brown14641892012-07-05 12:15:01 +01001278 snd_pcm_hw_rule_list, (void *)l,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001279 var, -1);
1280}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001281EXPORT_SYMBOL(snd_pcm_hw_constraint_list);
1282
Peter Rosinf66f8982015-01-28 15:16:06 +01001283static int snd_pcm_hw_rule_ranges(struct snd_pcm_hw_params *params,
1284 struct snd_pcm_hw_rule *rule)
1285{
1286 struct snd_pcm_hw_constraint_ranges *r = rule->private;
1287 return snd_interval_ranges(hw_param_interval(params, rule->var),
1288 r->count, r->ranges, r->mask);
1289}
1290
1291
1292/**
1293 * snd_pcm_hw_constraint_ranges - apply list of range constraints to a parameter
1294 * @runtime: PCM runtime instance
1295 * @cond: condition bits
1296 * @var: hw_params variable to apply the list of range constraints
1297 * @r: ranges
1298 *
1299 * Apply the list of range constraints to an interval parameter.
1300 *
1301 * Return: Zero if successful, or a negative error code on failure.
1302 */
1303int snd_pcm_hw_constraint_ranges(struct snd_pcm_runtime *runtime,
1304 unsigned int cond,
1305 snd_pcm_hw_param_t var,
1306 const struct snd_pcm_hw_constraint_ranges *r)
1307{
1308 return snd_pcm_hw_rule_add(runtime, cond, var,
1309 snd_pcm_hw_rule_ranges, (void *)r,
1310 var, -1);
1311}
1312EXPORT_SYMBOL(snd_pcm_hw_constraint_ranges);
1313
Takashi Iwai877211f2005-11-17 13:59:38 +01001314static int snd_pcm_hw_rule_ratnums(struct snd_pcm_hw_params *params,
1315 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001316{
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001317 const struct snd_pcm_hw_constraint_ratnums *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 unsigned int num = 0, den = 0;
1319 int err;
1320 err = snd_interval_ratnum(hw_param_interval(params, rule->var),
1321 r->nrats, r->rats, &num, &den);
1322 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1323 params->rate_num = num;
1324 params->rate_den = den;
1325 }
1326 return err;
1327}
1328
1329/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001330 * snd_pcm_hw_constraint_ratnums - apply ratnums constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001331 * @runtime: PCM runtime instance
1332 * @cond: condition bits
1333 * @var: hw_params variable to apply the ratnums constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001334 * @r: struct snd_ratnums constriants
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001335 *
1336 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001338int snd_pcm_hw_constraint_ratnums(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001339 unsigned int cond,
1340 snd_pcm_hw_param_t var,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001341 const struct snd_pcm_hw_constraint_ratnums *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001342{
1343 return snd_pcm_hw_rule_add(runtime, cond, var,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001344 snd_pcm_hw_rule_ratnums, (void *)r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001345 var, -1);
1346}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001347EXPORT_SYMBOL(snd_pcm_hw_constraint_ratnums);
1348
Takashi Iwai877211f2005-11-17 13:59:38 +01001349static int snd_pcm_hw_rule_ratdens(struct snd_pcm_hw_params *params,
1350 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001351{
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001352 const struct snd_pcm_hw_constraint_ratdens *r = rule->private;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001353 unsigned int num = 0, den = 0;
1354 int err = snd_interval_ratden(hw_param_interval(params, rule->var),
1355 r->nrats, r->rats, &num, &den);
1356 if (err >= 0 && den && rule->var == SNDRV_PCM_HW_PARAM_RATE) {
1357 params->rate_num = num;
1358 params->rate_den = den;
1359 }
1360 return err;
1361}
1362
1363/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001364 * snd_pcm_hw_constraint_ratdens - apply ratdens constraint to a parameter
Takashi Iwaidf8db932005-09-07 13:38:19 +02001365 * @runtime: PCM runtime instance
1366 * @cond: condition bits
1367 * @var: hw_params variable to apply the ratdens constraint
Takashi Iwai877211f2005-11-17 13:59:38 +01001368 * @r: struct snd_ratdens constriants
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001369 *
1370 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001372int snd_pcm_hw_constraint_ratdens(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001373 unsigned int cond,
1374 snd_pcm_hw_param_t var,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001375 const struct snd_pcm_hw_constraint_ratdens *r)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376{
1377 return snd_pcm_hw_rule_add(runtime, cond, var,
Lars-Peter Clausene5e113c2015-10-28 11:37:53 +01001378 snd_pcm_hw_rule_ratdens, (void *)r,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 var, -1);
1380}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001381EXPORT_SYMBOL(snd_pcm_hw_constraint_ratdens);
1382
Takashi Iwai877211f2005-11-17 13:59:38 +01001383static int snd_pcm_hw_rule_msbits(struct snd_pcm_hw_params *params,
1384 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001385{
1386 unsigned int l = (unsigned long) rule->private;
1387 int width = l & 0xffff;
1388 unsigned int msbits = l >> 16;
Takashi Sakamotob55f9fd2017-05-17 08:48:20 +09001389 const struct snd_interval *i =
1390 hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
Lars-Peter Clausen8ef9df52014-12-29 18:43:37 +01001391
1392 if (!snd_interval_single(i))
1393 return 0;
1394
1395 if ((snd_interval_value(i) == width) ||
1396 (width == 0 && snd_interval_value(i) > msbits))
Lars-Peter Clausen19f52fa2014-12-29 18:43:36 +01001397 params->msbits = min_not_zero(params->msbits, msbits);
Lars-Peter Clausen8ef9df52014-12-29 18:43:37 +01001398
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 return 0;
1400}
1401
1402/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001403 * snd_pcm_hw_constraint_msbits - add a hw constraint msbits rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001404 * @runtime: PCM runtime instance
1405 * @cond: condition bits
1406 * @width: sample bits width
1407 * @msbits: msbits width
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001408 *
Lars-Peter Clausen8ef9df52014-12-29 18:43:37 +01001409 * This constraint will set the number of most significant bits (msbits) if a
1410 * sample format with the specified width has been select. If width is set to 0
1411 * the msbits will be set for any sample format with a width larger than the
1412 * specified msbits.
1413 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001414 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001415 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001416int snd_pcm_hw_constraint_msbits(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001417 unsigned int cond,
1418 unsigned int width,
1419 unsigned int msbits)
1420{
1421 unsigned long l = (msbits << 16) | width;
1422 return snd_pcm_hw_rule_add(runtime, cond, -1,
1423 snd_pcm_hw_rule_msbits,
1424 (void*) l,
1425 SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
1426}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001427EXPORT_SYMBOL(snd_pcm_hw_constraint_msbits);
1428
Takashi Iwai877211f2005-11-17 13:59:38 +01001429static int snd_pcm_hw_rule_step(struct snd_pcm_hw_params *params,
1430 struct snd_pcm_hw_rule *rule)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431{
1432 unsigned long step = (unsigned long) rule->private;
Clemens Ladisch0f519b62014-09-07 21:43:07 +02001433 return snd_interval_step(hw_param_interval(params, rule->var), step);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434}
1435
1436/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001437 * snd_pcm_hw_constraint_step - add a hw constraint step rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001438 * @runtime: PCM runtime instance
1439 * @cond: condition bits
1440 * @var: hw_params variable to apply the step constraint
1441 * @step: step size
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001442 *
1443 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001444 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001445int snd_pcm_hw_constraint_step(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 unsigned int cond,
1447 snd_pcm_hw_param_t var,
1448 unsigned long step)
1449{
1450 return snd_pcm_hw_rule_add(runtime, cond, var,
1451 snd_pcm_hw_rule_step, (void *) step,
1452 var, -1);
1453}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001454EXPORT_SYMBOL(snd_pcm_hw_constraint_step);
1455
Takashi Iwai877211f2005-11-17 13:59:38 +01001456static 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 -07001457{
Marcin Åšlusarz67c39312007-12-14 12:53:21 +01001458 static unsigned int pow2_sizes[] = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001459 1<<0, 1<<1, 1<<2, 1<<3, 1<<4, 1<<5, 1<<6, 1<<7,
1460 1<<8, 1<<9, 1<<10, 1<<11, 1<<12, 1<<13, 1<<14, 1<<15,
1461 1<<16, 1<<17, 1<<18, 1<<19, 1<<20, 1<<21, 1<<22, 1<<23,
1462 1<<24, 1<<25, 1<<26, 1<<27, 1<<28, 1<<29, 1<<30
1463 };
1464 return snd_interval_list(hw_param_interval(params, rule->var),
1465 ARRAY_SIZE(pow2_sizes), pow2_sizes, 0);
1466}
1467
1468/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001469 * snd_pcm_hw_constraint_pow2 - add a hw constraint power-of-2 rule
Takashi Iwaidf8db932005-09-07 13:38:19 +02001470 * @runtime: PCM runtime instance
1471 * @cond: condition bits
1472 * @var: hw_params variable to apply the power-of-2 constraint
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001473 *
1474 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001476int snd_pcm_hw_constraint_pow2(struct snd_pcm_runtime *runtime,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 unsigned int cond,
1478 snd_pcm_hw_param_t var)
1479{
1480 return snd_pcm_hw_rule_add(runtime, cond, var,
1481 snd_pcm_hw_rule_pow2, NULL,
1482 var, -1);
1483}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001484EXPORT_SYMBOL(snd_pcm_hw_constraint_pow2);
1485
Clemens Ladischd5b702a2011-09-16 23:03:02 +02001486static int snd_pcm_hw_rule_noresample_func(struct snd_pcm_hw_params *params,
1487 struct snd_pcm_hw_rule *rule)
1488{
1489 unsigned int base_rate = (unsigned int)(uintptr_t)rule->private;
1490 struct snd_interval *rate;
1491
1492 rate = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
1493 return snd_interval_list(rate, 1, &base_rate, 0);
1494}
1495
1496/**
1497 * snd_pcm_hw_rule_noresample - add a rule to allow disabling hw resampling
1498 * @runtime: PCM runtime instance
1499 * @base_rate: the rate at which the hardware does not resample
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001500 *
1501 * Return: Zero if successful, or a negative error code on failure.
Clemens Ladischd5b702a2011-09-16 23:03:02 +02001502 */
1503int snd_pcm_hw_rule_noresample(struct snd_pcm_runtime *runtime,
1504 unsigned int base_rate)
1505{
1506 return snd_pcm_hw_rule_add(runtime, SNDRV_PCM_HW_PARAMS_NORESAMPLE,
1507 SNDRV_PCM_HW_PARAM_RATE,
1508 snd_pcm_hw_rule_noresample_func,
1509 (void *)(uintptr_t)base_rate,
1510 SNDRV_PCM_HW_PARAM_RATE, -1);
1511}
1512EXPORT_SYMBOL(snd_pcm_hw_rule_noresample);
1513
Takashi Iwai877211f2005-11-17 13:59:38 +01001514static void _snd_pcm_hw_param_any(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 if (hw_is_mask(var)) {
1518 snd_mask_any(hw_param_mask(params, var));
1519 params->cmask |= 1 << var;
1520 params->rmask |= 1 << var;
1521 return;
1522 }
1523 if (hw_is_interval(var)) {
1524 snd_interval_any(hw_param_interval(params, var));
1525 params->cmask |= 1 << var;
1526 params->rmask |= 1 << var;
1527 return;
1528 }
1529 snd_BUG();
1530}
1531
Takashi Iwai877211f2005-11-17 13:59:38 +01001532void _snd_pcm_hw_params_any(struct snd_pcm_hw_params *params)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001533{
1534 unsigned int k;
1535 memset(params, 0, sizeof(*params));
1536 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++)
1537 _snd_pcm_hw_param_any(params, k);
1538 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
1539 _snd_pcm_hw_param_any(params, k);
1540 params->info = ~0U;
1541}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001542EXPORT_SYMBOL(_snd_pcm_hw_params_any);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001543
1544/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001545 * snd_pcm_hw_param_value - return @params field @var value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001546 * @params: the hw_params instance
1547 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001548 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001549 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001550 * Return: The value for field @var if it's fixed in configuration space
1551 * defined by @params. -%EINVAL otherwise.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001552 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001553int snd_pcm_hw_param_value(const struct snd_pcm_hw_params *params,
1554 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001555{
1556 if (hw_is_mask(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001557 const struct snd_mask *mask = hw_param_mask_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001558 if (!snd_mask_single(mask))
1559 return -EINVAL;
1560 if (dir)
1561 *dir = 0;
1562 return snd_mask_value(mask);
1563 }
1564 if (hw_is_interval(var)) {
Takashi Iwai877211f2005-11-17 13:59:38 +01001565 const struct snd_interval *i = hw_param_interval_c(params, var);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001566 if (!snd_interval_single(i))
1567 return -EINVAL;
1568 if (dir)
1569 *dir = i->openmin;
1570 return snd_interval_value(i);
1571 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001572 return -EINVAL;
1573}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001574EXPORT_SYMBOL(snd_pcm_hw_param_value);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575
Takashi Iwai877211f2005-11-17 13:59:38 +01001576void _snd_pcm_hw_param_setempty(struct snd_pcm_hw_params *params,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001577 snd_pcm_hw_param_t var)
1578{
1579 if (hw_is_mask(var)) {
1580 snd_mask_none(hw_param_mask(params, var));
1581 params->cmask |= 1 << var;
1582 params->rmask |= 1 << var;
1583 } else if (hw_is_interval(var)) {
1584 snd_interval_none(hw_param_interval(params, var));
1585 params->cmask |= 1 << var;
1586 params->rmask |= 1 << var;
1587 } else {
1588 snd_BUG();
1589 }
1590}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001591EXPORT_SYMBOL(_snd_pcm_hw_param_setempty);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592
Takashi Iwai877211f2005-11-17 13:59:38 +01001593static int _snd_pcm_hw_param_first(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001594 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001595{
1596 int changed;
1597 if (hw_is_mask(var))
1598 changed = snd_mask_refine_first(hw_param_mask(params, var));
1599 else if (hw_is_interval(var))
1600 changed = snd_interval_refine_first(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001601 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001602 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 if (changed) {
1604 params->cmask |= 1 << var;
1605 params->rmask |= 1 << var;
1606 }
1607 return changed;
1608}
1609
1610
1611/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001612 * snd_pcm_hw_param_first - refine config space and return minimum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001613 * @pcm: PCM instance
1614 * @params: the hw_params instance
1615 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001616 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001617 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001618 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001619 * values > minimum. Reduce configuration space accordingly.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001620 *
1621 * Return: The minimum, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001622 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001623int snd_pcm_hw_param_first(struct snd_pcm_substream *pcm,
1624 struct snd_pcm_hw_params *params,
1625 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001626{
1627 int changed = _snd_pcm_hw_param_first(params, var);
1628 if (changed < 0)
1629 return changed;
1630 if (params->rmask) {
1631 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001632 if (snd_BUG_ON(err < 0))
1633 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001634 }
1635 return snd_pcm_hw_param_value(params, var, dir);
1636}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001637EXPORT_SYMBOL(snd_pcm_hw_param_first);
1638
Takashi Iwai877211f2005-11-17 13:59:38 +01001639static int _snd_pcm_hw_param_last(struct snd_pcm_hw_params *params,
Adrian Bunk123992f2005-05-18 18:02:04 +02001640 snd_pcm_hw_param_t var)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001641{
1642 int changed;
1643 if (hw_is_mask(var))
1644 changed = snd_mask_refine_last(hw_param_mask(params, var));
1645 else if (hw_is_interval(var))
1646 changed = snd_interval_refine_last(hw_param_interval(params, var));
Takashi Iwai2f4ca8e2006-04-28 15:13:40 +02001647 else
Linus Torvalds1da177e2005-04-16 15:20:36 -07001648 return -EINVAL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001649 if (changed) {
1650 params->cmask |= 1 << var;
1651 params->rmask |= 1 << var;
1652 }
1653 return changed;
1654}
1655
1656
1657/**
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001658 * snd_pcm_hw_param_last - refine config space and return maximum value
Takashi Iwaidf8db932005-09-07 13:38:19 +02001659 * @pcm: PCM instance
1660 * @params: the hw_params instance
1661 * @var: parameter to retrieve
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001662 * @dir: pointer to the direction (-1,0,1) or %NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -07001663 *
Randy Dunlap1c85cc62008-10-15 14:38:40 -07001664 * Inside configuration space defined by @params remove from @var all
Linus Torvalds1da177e2005-04-16 15:20:36 -07001665 * values < maximum. Reduce configuration space accordingly.
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001666 *
1667 * Return: The maximum, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001668 */
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001669int snd_pcm_hw_param_last(struct snd_pcm_substream *pcm,
1670 struct snd_pcm_hw_params *params,
1671 snd_pcm_hw_param_t var, int *dir)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672{
1673 int changed = _snd_pcm_hw_param_last(params, var);
1674 if (changed < 0)
1675 return changed;
1676 if (params->rmask) {
1677 int err = snd_pcm_hw_refine(pcm, params);
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001678 if (snd_BUG_ON(err < 0))
1679 return err;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001680 }
1681 return snd_pcm_hw_param_value(params, var, dir);
1682}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001683EXPORT_SYMBOL(snd_pcm_hw_param_last);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001684
Takashi Iwai877211f2005-11-17 13:59:38 +01001685static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 void *arg)
1687{
Takashi Iwai877211f2005-11-17 13:59:38 +01001688 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001689 unsigned long flags;
1690 snd_pcm_stream_lock_irqsave(substream, flags);
1691 if (snd_pcm_running(substream) &&
1692 snd_pcm_update_hw_ptr(substream) >= 0)
1693 runtime->status->hw_ptr %= runtime->buffer_size;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -05001694 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001695 runtime->status->hw_ptr = 0;
Pierre-Louis Bossart0e8014d2012-10-22 16:42:14 -05001696 runtime->hw_ptr_wrap = 0;
1697 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001698 snd_pcm_stream_unlock_irqrestore(substream, flags);
1699 return 0;
1700}
1701
Takashi Iwai877211f2005-11-17 13:59:38 +01001702static int snd_pcm_lib_ioctl_channel_info(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 void *arg)
1704{
Takashi Iwai877211f2005-11-17 13:59:38 +01001705 struct snd_pcm_channel_info *info = arg;
1706 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001707 int width;
1708 if (!(runtime->info & SNDRV_PCM_INFO_MMAP)) {
1709 info->offset = -1;
1710 return 0;
1711 }
1712 width = snd_pcm_format_physical_width(runtime->format);
1713 if (width < 0)
1714 return width;
1715 info->offset = 0;
1716 switch (runtime->access) {
1717 case SNDRV_PCM_ACCESS_MMAP_INTERLEAVED:
1718 case SNDRV_PCM_ACCESS_RW_INTERLEAVED:
1719 info->first = info->channel * width;
1720 info->step = runtime->channels * width;
1721 break;
1722 case SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED:
1723 case SNDRV_PCM_ACCESS_RW_NONINTERLEAVED:
1724 {
1725 size_t size = runtime->dma_bytes / runtime->channels;
1726 info->first = info->channel * size * 8;
1727 info->step = width;
1728 break;
1729 }
1730 default:
1731 snd_BUG();
1732 break;
1733 }
1734 return 0;
1735}
1736
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001737static int snd_pcm_lib_ioctl_fifo_size(struct snd_pcm_substream *substream,
1738 void *arg)
1739{
1740 struct snd_pcm_hw_params *params = arg;
1741 snd_pcm_format_t format;
Clemens Ladischa9960e62014-09-21 22:50:57 +02001742 int channels;
1743 ssize_t frame_size;
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001744
1745 params->fifo_size = substream->runtime->hw.fifo_size;
1746 if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_FIFO_IN_FRAMES)) {
1747 format = params_format(params);
1748 channels = params_channels(params);
Clemens Ladischa9960e62014-09-21 22:50:57 +02001749 frame_size = snd_pcm_format_size(format, channels);
1750 if (frame_size > 0)
1751 params->fifo_size /= (unsigned)frame_size;
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001752 }
1753 return 0;
1754}
1755
Linus Torvalds1da177e2005-04-16 15:20:36 -07001756/**
1757 * snd_pcm_lib_ioctl - a generic PCM ioctl callback
1758 * @substream: the pcm substream instance
1759 * @cmd: ioctl command
1760 * @arg: ioctl argument
1761 *
1762 * Processes the generic ioctl commands for PCM.
1763 * Can be passed as the ioctl callback for PCM ops.
1764 *
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01001765 * Return: Zero if successful, or a negative error code on failure.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001766 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001767int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001768 unsigned int cmd, void *arg)
1769{
1770 switch (cmd) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 case SNDRV_PCM_IOCTL1_RESET:
1772 return snd_pcm_lib_ioctl_reset(substream, arg);
1773 case SNDRV_PCM_IOCTL1_CHANNEL_INFO:
1774 return snd_pcm_lib_ioctl_channel_info(substream, arg);
Jaroslav Kysela8bea8692009-04-27 09:44:40 +02001775 case SNDRV_PCM_IOCTL1_FIFO_SIZE:
1776 return snd_pcm_lib_ioctl_fifo_size(substream, arg);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001777 }
1778 return -ENXIO;
1779}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001780EXPORT_SYMBOL(snd_pcm_lib_ioctl);
1781
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782/**
1783 * snd_pcm_period_elapsed - update the pcm status for the next period
1784 * @substream: the pcm substream instance
1785 *
1786 * This function is called from the interrupt handler when the
1787 * PCM has processed the period size. It will update the current
Takashi Iwai31e89602008-01-08 18:09:57 +01001788 * pointer, wake up sleepers, etc.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001789 *
1790 * Even if more than one periods have elapsed since the last call, you
1791 * have to call this only once.
1792 */
Takashi Iwai877211f2005-11-17 13:59:38 +01001793void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794{
Takashi Iwai877211f2005-11-17 13:59:38 +01001795 struct snd_pcm_runtime *runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001796 unsigned long flags;
1797
Takashi Iwai7eaa9432008-08-08 17:09:09 +02001798 if (PCM_RUNTIME_CHECK(substream))
1799 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001801
Linus Torvalds1da177e2005-04-16 15:20:36 -07001802 snd_pcm_stream_lock_irqsave(substream, flags);
1803 if (!snd_pcm_running(substream) ||
Jaroslav Kyselaf2404062010-01-05 17:19:34 +01001804 snd_pcm_update_hw_ptr0(substream, 1) < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001805 goto _end;
1806
Jie Yang90bbaf62015-10-16 17:57:46 +08001807#ifdef CONFIG_SND_PCM_TIMER
Linus Torvalds1da177e2005-04-16 15:20:36 -07001808 if (substream->timer_running)
1809 snd_timer_interrupt(substream->timer, 1);
Jie Yang90bbaf62015-10-16 17:57:46 +08001810#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07001811 _end:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001812 kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
Takashi Iwai3aa02cb2016-04-14 18:02:37 +02001813 snd_pcm_stream_unlock_irqrestore(substream, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001814}
Takashi Iwaie88e8ae62006-04-28 15:13:40 +02001815EXPORT_SYMBOL(snd_pcm_period_elapsed);
1816
Takashi Iwai13075512008-01-08 18:08:14 +01001817/*
1818 * Wait until avail_min data becomes available
1819 * Returns a negative error code if any error occurs during operation.
1820 * The available space is stored on availp. When err = 0 and avail = 0
1821 * on the capture stream, it indicates the stream is in DRAINING state.
1822 */
David Dillow5daeba32010-06-27 00:13:20 +02001823static int wait_for_avail(struct snd_pcm_substream *substream,
Takashi Iwai13075512008-01-08 18:08:14 +01001824 snd_pcm_uframes_t *availp)
1825{
1826 struct snd_pcm_runtime *runtime = substream->runtime;
1827 int is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
1828 wait_queue_t wait;
1829 int err = 0;
1830 snd_pcm_uframes_t avail = 0;
Takashi Iwaif2b36142011-05-26 08:09:38 +02001831 long wait_time, tout;
Takashi Iwai13075512008-01-08 18:08:14 +01001832
Arjan van de Ven763437a2011-09-15 08:49:25 +02001833 init_waitqueue_entry(&wait, current);
1834 set_current_state(TASK_INTERRUPTIBLE);
1835 add_wait_queue(&runtime->tsleep, &wait);
1836
Takashi Iwaif2b36142011-05-26 08:09:38 +02001837 if (runtime->no_period_wakeup)
1838 wait_time = MAX_SCHEDULE_TIMEOUT;
1839 else {
1840 wait_time = 10;
1841 if (runtime->rate) {
1842 long t = runtime->period_size * 2 / runtime->rate;
1843 wait_time = max(t, wait_time);
1844 }
1845 wait_time = msecs_to_jiffies(wait_time * 1000);
1846 }
Arjan van de Ven763437a2011-09-15 08:49:25 +02001847
Takashi Iwai13075512008-01-08 18:08:14 +01001848 for (;;) {
1849 if (signal_pending(current)) {
1850 err = -ERESTARTSYS;
1851 break;
1852 }
Arjan van de Ven763437a2011-09-15 08:49:25 +02001853
1854 /*
1855 * We need to check if space became available already
1856 * (and thus the wakeup happened already) first to close
1857 * the race of space already having become available.
1858 * This check must happen after been added to the waitqueue
1859 * and having current state be INTERRUPTIBLE.
1860 */
1861 if (is_playback)
1862 avail = snd_pcm_playback_avail(runtime);
1863 else
1864 avail = snd_pcm_capture_avail(runtime);
1865 if (avail >= runtime->twake)
1866 break;
Takashi Iwai13075512008-01-08 18:08:14 +01001867 snd_pcm_stream_unlock_irq(substream);
Arjan van de Ven763437a2011-09-15 08:49:25 +02001868
1869 tout = schedule_timeout(wait_time);
1870
Takashi Iwai13075512008-01-08 18:08:14 +01001871 snd_pcm_stream_lock_irq(substream);
Arjan van de Ven763437a2011-09-15 08:49:25 +02001872 set_current_state(TASK_INTERRUPTIBLE);
Takashi Iwai13075512008-01-08 18:08:14 +01001873 switch (runtime->status->state) {
1874 case SNDRV_PCM_STATE_SUSPENDED:
1875 err = -ESTRPIPE;
1876 goto _endloop;
1877 case SNDRV_PCM_STATE_XRUN:
1878 err = -EPIPE;
1879 goto _endloop;
1880 case SNDRV_PCM_STATE_DRAINING:
1881 if (is_playback)
1882 err = -EPIPE;
1883 else
1884 avail = 0; /* indicate draining */
1885 goto _endloop;
1886 case SNDRV_PCM_STATE_OPEN:
1887 case SNDRV_PCM_STATE_SETUP:
1888 case SNDRV_PCM_STATE_DISCONNECTED:
1889 err = -EBADFD;
1890 goto _endloop;
JongHo Kimed697e12013-12-17 23:02:24 +09001891 case SNDRV_PCM_STATE_PAUSED:
1892 continue;
Takashi Iwai13075512008-01-08 18:08:14 +01001893 }
1894 if (!tout) {
Takashi Iwai09e56df2014-02-04 18:19:48 +01001895 pcm_dbg(substream->pcm,
1896 "%s write error (DMA or IRQ trouble?)\n",
1897 is_playback ? "playback" : "capture");
Takashi Iwai13075512008-01-08 18:08:14 +01001898 err = -EIO;
1899 break;
1900 }
Takashi Iwai13075512008-01-08 18:08:14 +01001901 }
1902 _endloop:
Arjan van de Ven763437a2011-09-15 08:49:25 +02001903 set_current_state(TASK_RUNNING);
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01001904 remove_wait_queue(&runtime->tsleep, &wait);
Takashi Iwai13075512008-01-08 18:08:14 +01001905 *availp = avail;
1906 return err;
1907}
1908
Takashi Iwai9f600632017-05-24 18:15:26 +02001909typedef int (*pcm_transfer_f)(struct snd_pcm_substream *substream,
1910 int channel, unsigned long hwoff,
1911 void *buf, unsigned long bytes);
Takashi Iwaibdc4acf2017-05-24 17:59:17 +02001912
Takashi Iwai9f600632017-05-24 18:15:26 +02001913typedef int (*pcm_copy_f)(struct snd_pcm_substream *, snd_pcm_uframes_t, void *,
1914 snd_pcm_uframes_t, snd_pcm_uframes_t, pcm_transfer_f);
1915
1916/* calculate the target DMA-buffer position to be written/read */
1917static void *get_dma_ptr(struct snd_pcm_runtime *runtime,
1918 int channel, unsigned long hwoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001919{
Takashi Iwai9f600632017-05-24 18:15:26 +02001920 return runtime->dma_area + hwoff +
1921 channel * (runtime->dma_bytes / runtime->channels);
1922}
1923
Takashi Iwai5c7264c2017-05-24 22:36:23 +02001924/* default copy_user ops for write; used for both interleaved and non- modes */
1925static int default_write_copy(struct snd_pcm_substream *substream,
1926 int channel, unsigned long hwoff,
1927 void *buf, unsigned long bytes)
Takashi Iwai9f600632017-05-24 18:15:26 +02001928{
1929 if (copy_from_user(get_dma_ptr(substream->runtime, channel, hwoff),
Takashi Iwai5c7264c2017-05-24 22:36:23 +02001930 (void __user *)buf, bytes))
Takashi Iwai9f600632017-05-24 18:15:26 +02001931 return -EFAULT;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 return 0;
1933}
Takashi Iwai9f600632017-05-24 18:15:26 +02001934
Takashi Iwai68541212017-05-24 18:23:20 +02001935/* default copy_kernel ops for write */
1936static int default_write_copy_kernel(struct snd_pcm_substream *substream,
1937 int channel, unsigned long hwoff,
1938 void *buf, unsigned long bytes)
1939{
1940 memcpy(get_dma_ptr(substream->runtime, channel, hwoff), buf, bytes);
1941 return 0;
1942}
1943
Takashi Iwai9f600632017-05-24 18:15:26 +02001944/* fill silence instead of copy data; called as a transfer helper
1945 * from __snd_pcm_lib_write() or directly from noninterleaved_copy() when
1946 * a NULL buffer is passed
1947 */
1948static int fill_silence(struct snd_pcm_substream *substream, int channel,
1949 unsigned long hwoff, void *buf, unsigned long bytes)
Takashi Iwaibdc4acf2017-05-24 17:59:17 +02001950{
1951 struct snd_pcm_runtime *runtime = substream->runtime;
Takashi Iwaibdc4acf2017-05-24 17:59:17 +02001952
Takashi Iwai9f600632017-05-24 18:15:26 +02001953 if (substream->stream != SNDRV_PCM_STREAM_PLAYBACK)
1954 return 0;
1955 if (substream->ops->fill_silence)
1956 return substream->ops->fill_silence(substream, channel,
1957 hwoff, bytes);
1958
1959 snd_pcm_format_set_silence(runtime->format,
1960 get_dma_ptr(runtime, channel, hwoff),
1961 bytes_to_samples(runtime, bytes));
1962 return 0;
1963}
1964
Takashi Iwai5c7264c2017-05-24 22:36:23 +02001965/* default copy_user ops for read; used for both interleaved and non- modes */
1966static int default_read_copy(struct snd_pcm_substream *substream,
1967 int channel, unsigned long hwoff,
1968 void *buf, unsigned long bytes)
1969{
1970 if (copy_to_user((void __user *)buf,
1971 get_dma_ptr(substream->runtime, channel, hwoff),
1972 bytes))
1973 return -EFAULT;
1974 return 0;
1975}
1976
Takashi Iwai68541212017-05-24 18:23:20 +02001977/* default copy_kernel ops for read */
1978static int default_read_copy_kernel(struct snd_pcm_substream *substream,
1979 int channel, unsigned long hwoff,
1980 void *buf, unsigned long bytes)
1981{
1982 memcpy(buf, get_dma_ptr(substream->runtime, channel, hwoff), bytes);
1983 return 0;
1984}
1985
Takashi Iwai9f600632017-05-24 18:15:26 +02001986/* call transfer function with the converted pointers and sizes;
1987 * for interleaved mode, it's one shot for all samples
1988 */
1989static int interleaved_copy(struct snd_pcm_substream *substream,
1990 snd_pcm_uframes_t hwoff, void *data,
1991 snd_pcm_uframes_t off,
1992 snd_pcm_uframes_t frames,
1993 pcm_transfer_f transfer)
1994{
1995 struct snd_pcm_runtime *runtime = substream->runtime;
1996
1997 /* convert to bytes */
1998 hwoff = frames_to_bytes(runtime, hwoff);
1999 off = frames_to_bytes(runtime, off);
2000 frames = frames_to_bytes(runtime, frames);
2001 return transfer(substream, 0, hwoff, data + off, frames);
2002}
2003
2004/* call transfer function with the converted pointers and sizes for each
2005 * non-interleaved channel; when buffer is NULL, silencing instead of copying
2006 */
2007static int noninterleaved_copy(struct snd_pcm_substream *substream,
2008 snd_pcm_uframes_t hwoff, void *data,
2009 snd_pcm_uframes_t off,
2010 snd_pcm_uframes_t frames,
2011 pcm_transfer_f transfer)
2012{
2013 struct snd_pcm_runtime *runtime = substream->runtime;
2014 int channels = runtime->channels;
2015 void **bufs = data;
2016 int c, err;
2017
2018 /* convert to bytes; note that it's not frames_to_bytes() here.
2019 * in non-interleaved mode, we copy for each channel, thus
2020 * each copy is n_samples bytes x channels = whole frames.
2021 */
2022 off = samples_to_bytes(runtime, off);
2023 frames = samples_to_bytes(runtime, frames);
2024 hwoff = samples_to_bytes(runtime, hwoff);
2025 for (c = 0; c < channels; ++c, ++bufs) {
2026 if (!data || !*bufs)
2027 err = fill_silence(substream, c, hwoff, NULL, frames);
2028 else
2029 err = transfer(substream, c, hwoff, *bufs + off,
2030 frames);
2031 if (err < 0)
2032 return err;
Takashi Iwaibdc4acf2017-05-24 17:59:17 +02002033 }
2034 return 0;
2035}
2036
Takashi Iwaia9cd29e2017-05-24 18:18:15 +02002037/* fill silence on the given buffer position;
2038 * called from snd_pcm_playback_silence()
2039 */
2040static int fill_silence_frames(struct snd_pcm_substream *substream,
2041 snd_pcm_uframes_t off, snd_pcm_uframes_t frames)
2042{
2043 if (substream->runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
2044 substream->runtime->access == SNDRV_PCM_ACCESS_MMAP_INTERLEAVED)
2045 return interleaved_copy(substream, off, NULL, 0, frames,
2046 fill_silence);
2047 else
2048 return noninterleaved_copy(substream, off, NULL, 0, frames,
2049 fill_silence);
2050}
2051
Takashi Iwaibdc4acf2017-05-24 17:59:17 +02002052/* sanity-check for read/write methods */
2053static int pcm_sanity_check(struct snd_pcm_substream *substream)
2054{
2055 struct snd_pcm_runtime *runtime;
2056 if (PCM_RUNTIME_CHECK(substream))
2057 return -ENXIO;
2058 runtime = substream->runtime;
2059 if (snd_BUG_ON(!substream->ops->copy_user && !runtime->dma_area))
2060 return -EINVAL;
2061 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
2062 return -EBADFD;
2063 return 0;
2064}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002065
Takashi Iwai6ba63922017-05-24 17:51:30 +02002066static int pcm_accessible_state(struct snd_pcm_runtime *runtime)
2067{
2068 switch (runtime->status->state) {
2069 case SNDRV_PCM_STATE_PREPARED:
2070 case SNDRV_PCM_STATE_RUNNING:
2071 case SNDRV_PCM_STATE_PAUSED:
2072 return 0;
2073 case SNDRV_PCM_STATE_XRUN:
2074 return -EPIPE;
2075 case SNDRV_PCM_STATE_SUSPENDED:
2076 return -ESTRPIPE;
2077 default:
2078 return -EBADFD;
2079 }
2080}
2081
Takashi Sakamoto66e01a52017-06-12 09:41:44 +09002082/* update to the given appl_ptr and call ack callback if needed;
2083 * when an error is returned, take back to the original value
2084 */
2085int pcm_lib_apply_appl_ptr(struct snd_pcm_substream *substream,
2086 snd_pcm_uframes_t appl_ptr)
2087{
2088 struct snd_pcm_runtime *runtime = substream->runtime;
2089 snd_pcm_uframes_t old_appl_ptr = runtime->control->appl_ptr;
2090 int ret;
2091
Takashi Iwaif8ff2f22017-06-13 15:57:28 +02002092 if (old_appl_ptr == appl_ptr)
2093 return 0;
2094
Takashi Sakamoto66e01a52017-06-12 09:41:44 +09002095 runtime->control->appl_ptr = appl_ptr;
2096 if (substream->ops->ack) {
2097 ret = substream->ops->ack(substream);
2098 if (ret < 0) {
2099 runtime->control->appl_ptr = old_appl_ptr;
2100 return ret;
2101 }
2102 }
Takashi Sakamotofccf5382017-06-12 09:41:45 +09002103
2104 trace_applptr(substream, old_appl_ptr, appl_ptr);
2105
Takashi Sakamoto66e01a52017-06-12 09:41:44 +09002106 return 0;
2107}
2108
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002109/* the common loop for read/write data */
2110snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
2111 void *data, bool interleaved,
Takashi Iwai68541212017-05-24 18:23:20 +02002112 snd_pcm_uframes_t size, bool in_kernel)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113{
Takashi Iwai877211f2005-11-17 13:59:38 +01002114 struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002115 snd_pcm_uframes_t xfer = 0;
2116 snd_pcm_uframes_t offset = 0;
Takashi Iwai0910c212012-05-11 17:50:49 +02002117 snd_pcm_uframes_t avail;
Takashi Iwai9f600632017-05-24 18:15:26 +02002118 pcm_copy_f writer;
2119 pcm_transfer_f transfer;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002120 bool nonblock;
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002121 bool is_playback;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002122 int err;
2123
2124 err = pcm_sanity_check(substream);
2125 if (err < 0)
2126 return err;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002127
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002128 is_playback = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002129 if (interleaved) {
2130 if (runtime->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
2131 runtime->channels > 1)
2132 return -EINVAL;
Takashi Iwai9f600632017-05-24 18:15:26 +02002133 writer = interleaved_copy;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002134 } else {
2135 if (runtime->access != SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
2136 return -EINVAL;
Takashi Iwai9f600632017-05-24 18:15:26 +02002137 writer = noninterleaved_copy;
2138 }
2139
2140 if (!data) {
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002141 if (is_playback)
2142 transfer = fill_silence;
2143 else
2144 return -EINVAL;
Takashi Iwai68541212017-05-24 18:23:20 +02002145 } else if (in_kernel) {
2146 if (substream->ops->copy_kernel)
2147 transfer = substream->ops->copy_kernel;
2148 else
2149 transfer = is_playback ?
2150 default_write_copy_kernel : default_read_copy_kernel;
Takashi Iwai9f600632017-05-24 18:15:26 +02002151 } else {
2152 if (substream->ops->copy_user)
2153 transfer = (pcm_transfer_f)substream->ops->copy_user;
2154 else
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002155 transfer = is_playback ?
2156 default_write_copy : default_read_copy;
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002157 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002158
2159 if (size == 0)
2160 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002161
Takashi Iwaic48f12ee2017-05-21 09:35:21 +02002162 nonblock = !!(substream->f_flags & O_NONBLOCK);
2163
Linus Torvalds1da177e2005-04-16 15:20:36 -07002164 snd_pcm_stream_lock_irq(substream);
Takashi Iwai6ba63922017-05-24 17:51:30 +02002165 err = pcm_accessible_state(runtime);
2166 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002167 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002168
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002169 if (!is_playback &&
2170 runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
2171 size >= runtime->start_threshold) {
2172 err = snd_pcm_start(substream);
2173 if (err < 0)
2174 goto _end_unlock;
2175 }
2176
David Dillow5daeba32010-06-27 00:13:20 +02002177 runtime->twake = runtime->control->avail_min ? : 1;
Takashi Iwai0910c212012-05-11 17:50:49 +02002178 if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
2179 snd_pcm_update_hw_ptr(substream);
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002180 if (is_playback)
2181 avail = snd_pcm_playback_avail(runtime);
2182 else
2183 avail = snd_pcm_capture_avail(runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002184 while (size > 0) {
2185 snd_pcm_uframes_t frames, appl_ptr, appl_ofs;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002186 snd_pcm_uframes_t cont;
Takashi Iwai13075512008-01-08 18:08:14 +01002187 if (!avail) {
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002188 if (!is_playback &&
2189 runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
2190 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
2191 goto _end_unlock;
2192 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002193 if (nonblock) {
2194 err = -EAGAIN;
2195 goto _end_unlock;
2196 }
David Dillow5daeba32010-06-27 00:13:20 +02002197 runtime->twake = min_t(snd_pcm_uframes_t, size,
2198 runtime->control->avail_min ? : 1);
2199 err = wait_for_avail(substream, &avail);
Takashi Iwai13075512008-01-08 18:08:14 +01002200 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002201 goto _end_unlock;
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002202 if (!avail)
2203 continue; /* draining */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002205 frames = size > avail ? avail : size;
2206 cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size;
2207 if (frames > cont)
2208 frames = cont;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002209 if (snd_BUG_ON(!frames)) {
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01002210 runtime->twake = 0;
Takashi Iwai7eaa9432008-08-08 17:09:09 +02002211 snd_pcm_stream_unlock_irq(substream);
2212 return -EINVAL;
2213 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214 appl_ptr = runtime->control->appl_ptr;
2215 appl_ofs = appl_ptr % runtime->buffer_size;
2216 snd_pcm_stream_unlock_irq(substream);
Takashi Iwai9f600632017-05-24 18:15:26 +02002217 err = writer(substream, appl_ofs, data, offset, frames,
2218 transfer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219 snd_pcm_stream_lock_irq(substream);
Jaroslav Kysela12509322010-01-07 15:36:31 +01002220 if (err < 0)
2221 goto _end_unlock;
Takashi Iwai6ba63922017-05-24 17:51:30 +02002222 err = pcm_accessible_state(runtime);
2223 if (err < 0)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002225 appl_ptr += frames;
2226 if (appl_ptr >= runtime->boundary)
2227 appl_ptr -= runtime->boundary;
Takashi Sakamoto66e01a52017-06-12 09:41:44 +09002228 err = pcm_lib_apply_appl_ptr(substream, appl_ptr);
2229 if (err < 0)
2230 goto _end_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231
2232 offset += frames;
2233 size -= frames;
2234 xfer += frames;
Takashi Iwai0910c212012-05-11 17:50:49 +02002235 avail -= frames;
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002236 if (is_playback &&
2237 runtime->status->state == SNDRV_PCM_STATE_PREPARED &&
Linus Torvalds1da177e2005-04-16 15:20:36 -07002238 snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) {
2239 err = snd_pcm_start(substream);
2240 if (err < 0)
2241 goto _end_unlock;
2242 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243 }
2244 _end_unlock:
Jaroslav Kyselac91a9882010-01-21 10:32:15 +01002245 runtime->twake = 0;
Jaroslav Kysela12509322010-01-07 15:36:31 +01002246 if (xfer > 0 && err >= 0)
2247 snd_pcm_update_state(substream, runtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002248 snd_pcm_stream_unlock_irq(substream);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002249 return xfer > 0 ? (snd_pcm_sframes_t)xfer : err;
2250}
Takashi Iwai5c7264c2017-05-24 22:36:23 +02002251EXPORT_SYMBOL(__snd_pcm_lib_xfer);
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002252
2253/*
2254 * standard channel mapping helpers
2255 */
2256
2257/* default channel maps for multi-channel playbacks, up to 8 channels */
2258const struct snd_pcm_chmap_elem snd_pcm_std_chmaps[] = {
2259 { .channels = 1,
Takashi Iwai5efbc262012-09-13 14:48:46 +02002260 .map = { SNDRV_CHMAP_MONO } },
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002261 { .channels = 2,
2262 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
2263 { .channels = 4,
2264 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2265 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2266 { .channels = 6,
2267 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2268 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2269 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE } },
2270 { .channels = 8,
2271 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2272 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2273 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2274 SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
2275 { }
2276};
2277EXPORT_SYMBOL_GPL(snd_pcm_std_chmaps);
2278
2279/* alternative channel maps with CLFE <-> surround swapped for 6/8 channels */
2280const struct snd_pcm_chmap_elem snd_pcm_alt_chmaps[] = {
2281 { .channels = 1,
Takashi Iwai5efbc262012-09-13 14:48:46 +02002282 .map = { SNDRV_CHMAP_MONO } },
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002283 { .channels = 2,
2284 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } },
2285 { .channels = 4,
2286 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2287 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2288 { .channels = 6,
2289 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2290 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2291 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } },
2292 { .channels = 8,
2293 .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR,
2294 SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE,
2295 SNDRV_CHMAP_RL, SNDRV_CHMAP_RR,
2296 SNDRV_CHMAP_SL, SNDRV_CHMAP_SR } },
2297 { }
2298};
2299EXPORT_SYMBOL_GPL(snd_pcm_alt_chmaps);
2300
2301static bool valid_chmap_channels(const struct snd_pcm_chmap *info, int ch)
2302{
2303 if (ch > info->max_channels)
2304 return false;
2305 return !info->channel_mask || (info->channel_mask & (1U << ch));
2306}
2307
2308static int pcm_chmap_ctl_info(struct snd_kcontrol *kcontrol,
2309 struct snd_ctl_elem_info *uinfo)
2310{
2311 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2312
2313 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
2314 uinfo->count = 0;
2315 uinfo->count = info->max_channels;
2316 uinfo->value.integer.min = 0;
2317 uinfo->value.integer.max = SNDRV_CHMAP_LAST;
2318 return 0;
2319}
2320
2321/* get callback for channel map ctl element
2322 * stores the channel position firstly matching with the current channels
2323 */
2324static int pcm_chmap_ctl_get(struct snd_kcontrol *kcontrol,
2325 struct snd_ctl_elem_value *ucontrol)
2326{
2327 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2328 unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id);
2329 struct snd_pcm_substream *substream;
2330 const struct snd_pcm_chmap_elem *map;
2331
Takashi Iwai2deaeaf2017-06-14 16:20:32 +02002332 if (!info->chmap)
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002333 return -EINVAL;
2334 substream = snd_pcm_chmap_substream(info, idx);
2335 if (!substream)
2336 return -ENODEV;
2337 memset(ucontrol->value.integer.value, 0,
2338 sizeof(ucontrol->value.integer.value));
2339 if (!substream->runtime)
2340 return 0; /* no channels set */
2341 for (map = info->chmap; map->channels; map++) {
2342 int i;
2343 if (map->channels == substream->runtime->channels &&
2344 valid_chmap_channels(info, map->channels)) {
2345 for (i = 0; i < map->channels; i++)
2346 ucontrol->value.integer.value[i] = map->map[i];
2347 return 0;
2348 }
2349 }
2350 return -EINVAL;
2351}
2352
2353/* tlv callback for channel map ctl element
2354 * expands the pre-defined channel maps in a form of TLV
2355 */
2356static int pcm_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag,
2357 unsigned int size, unsigned int __user *tlv)
2358{
2359 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2360 const struct snd_pcm_chmap_elem *map;
2361 unsigned int __user *dst;
2362 int c, count = 0;
2363
Takashi Iwai2deaeaf2017-06-14 16:20:32 +02002364 if (!info->chmap)
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002365 return -EINVAL;
2366 if (size < 8)
2367 return -ENOMEM;
2368 if (put_user(SNDRV_CTL_TLVT_CONTAINER, tlv))
2369 return -EFAULT;
2370 size -= 8;
2371 dst = tlv + 2;
2372 for (map = info->chmap; map->channels; map++) {
2373 int chs_bytes = map->channels * 4;
2374 if (!valid_chmap_channels(info, map->channels))
2375 continue;
2376 if (size < 8)
2377 return -ENOMEM;
2378 if (put_user(SNDRV_CTL_TLVT_CHMAP_FIXED, dst) ||
2379 put_user(chs_bytes, dst + 1))
2380 return -EFAULT;
2381 dst += 2;
2382 size -= 8;
2383 count += 8;
2384 if (size < chs_bytes)
2385 return -ENOMEM;
2386 size -= chs_bytes;
2387 count += chs_bytes;
2388 for (c = 0; c < map->channels; c++) {
2389 if (put_user(map->map[c], dst))
2390 return -EFAULT;
2391 dst++;
2392 }
2393 }
2394 if (put_user(count, tlv + 1))
2395 return -EFAULT;
2396 return 0;
2397}
2398
2399static void pcm_chmap_ctl_private_free(struct snd_kcontrol *kcontrol)
2400{
2401 struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol);
2402 info->pcm->streams[info->stream].chmap_kctl = NULL;
2403 kfree(info);
2404}
2405
2406/**
2407 * snd_pcm_add_chmap_ctls - create channel-mapping control elements
2408 * @pcm: the assigned PCM instance
2409 * @stream: stream direction
2410 * @chmap: channel map elements (for query)
2411 * @max_channels: the max number of channels for the stream
2412 * @private_value: the value passed to each kcontrol's private_value field
2413 * @info_ret: store struct snd_pcm_chmap instance if non-NULL
2414 *
2415 * Create channel-mapping control elements assigned to the given PCM stream(s).
Yacine Belkadieb7c06e2013-03-11 22:05:14 +01002416 * Return: Zero if successful, or a negative error value.
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002417 */
2418int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
2419 const struct snd_pcm_chmap_elem *chmap,
2420 int max_channels,
2421 unsigned long private_value,
2422 struct snd_pcm_chmap **info_ret)
2423{
2424 struct snd_pcm_chmap *info;
2425 struct snd_kcontrol_new knew = {
2426 .iface = SNDRV_CTL_ELEM_IFACE_PCM,
2427 .access = SNDRV_CTL_ELEM_ACCESS_READ |
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002428 SNDRV_CTL_ELEM_ACCESS_TLV_READ |
2429 SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK,
2430 .info = pcm_chmap_ctl_info,
2431 .get = pcm_chmap_ctl_get,
2432 .tlv.c = pcm_chmap_ctl_tlv,
2433 };
2434 int err;
2435
Takashi Iwai8d879be2016-05-10 16:07:40 +02002436 if (WARN_ON(pcm->streams[stream].chmap_kctl))
2437 return -EBUSY;
Takashi Iwai2d3391e2012-07-27 18:27:00 +02002438 info = kzalloc(sizeof(*info), GFP_KERNEL);
2439 if (!info)
2440 return -ENOMEM;
2441 info->pcm = pcm;
2442 info->stream = stream;
2443 info->chmap = chmap;
2444 info->max_channels = max_channels;
2445 if (stream == SNDRV_PCM_STREAM_PLAYBACK)
2446 knew.name = "Playback Channel Map";
2447 else
2448 knew.name = "Capture Channel Map";
2449 knew.device = pcm->device;
2450 knew.count = pcm->streams[stream].substream_count;
2451 knew.private_value = private_value;
2452 info->kctl = snd_ctl_new1(&knew, info);
2453 if (!info->kctl) {
2454 kfree(info);
2455 return -ENOMEM;
2456 }
2457 info->kctl->private_free = pcm_chmap_ctl_private_free;
2458 err = snd_ctl_add(pcm->card, info->kctl);
2459 if (err < 0)
2460 return err;
2461 pcm->streams[stream].chmap_kctl = info->kctl;
2462 if (info_ret)
2463 *info_ret = info;
2464 return 0;
2465}
2466EXPORT_SYMBOL_GPL(snd_pcm_add_chmap_ctls);