aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/pcm_native.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 13:56:51 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-07-06 13:56:51 -0400
commit920f2ecdf6c3b3526f60fbd38c68597953cad3ee (patch)
tree18188922ba38a5c53ee8d17032eb5c46dffc7fa2 /sound/core/pcm_native.c
parent9ced560b82606b35adb33a27012a148d418a4c1f (diff)
parentfc18282cdcba984ab89c74d7e844c10114ae0795 (diff)
Merge tag 'sound-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai: "This development cycle resulted in a fair amount of changes in both core and driver sides. The most significant change in ALSA core is about PCM. Also the support of of-graph card and the new DAPM widget for DSP are noteworthy changes in ASoC core. And there're lots of small changes splat over the tree, as you can see in diffstat. Below are a few highlights: ALSA core: - Removal of set_fs() hackery from PCM core stuff, and the code reorganization / optimization thereafter - Improved support of PCM ack ops, and a new ABI for improved control/status mmap handling - Lots of constifications in various codes ASoC core: - The support of of-graph card, which may work as a better generic device for a replacement of simple-card - New widget types intended mainly for use with DSPs ASoC drivers: - New drivers for Allwinner V3s SoCs - Ensonic ES8316 codec support - More Intel SKL and KBL works - More device support for Intel SST Atom (mostly for cheap tablets and 2-in-1 devices) - Support for Rockchip PDM controllers - Support for STM32 I2S and S/PDIF controllers - Support for ZTE AUD96P22 codecs HD-audio: - Support of new Realtek codecs (ALC215/ALC285/ALC289), more quirks for HP and Dell machines - A few more fixes for i915 component binding" * tag 'sound-4.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (418 commits) ALSA: hda - Fix unbalance of i915 module refcount ASoC: Intel: Skylake: Remove driver debugfs exit ASoC: Intel: Skylake: explicitly add the headers sst-dsp.h ALSA: hda/realtek - Remove GPIO_MASK ALSA: hda/realtek - Fix typo of pincfg for Dell quirk ALSA: pcm: add a documentation for tracepoints ALSA: atmel: ac97c: fix error return code in atmel_ac97c_probe() ALSA: x86: fix error return code in hdmi_lpe_audio_probe() ASoC: Intel: Skylake: Add support to read firmware registers ASoC: Intel: Skylake: Add sram address to sst_addr structure ASoC: Intel: Skylake: Debugfs facility to dump module config ASoC: Intel: Skylake: Add debugfs support ASoC: fix semicolon.cocci warnings ASoC: rt5645: Add quirk override by module option ASoC: rsnd: make arrays path and cmd_case static const ASoC: audio-graph-card: add widgets and routing for external amplifier support ASoC: audio-graph-card: update bindings for amplifier support ASoC: rt5665: calibration should be done before jack detection ASoC: rsnd: constify dev_pm_ops structures. ASoC: nau8825: change crosstalk-bypass property to bool type ...
Diffstat (limited to 'sound/core/pcm_native.c')
-rw-r--r--sound/core/pcm_native.c1013
1 files changed, 559 insertions, 454 deletions
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index faa2e2be6f2e..b3d5bed75029 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -37,6 +37,18 @@
37#include <sound/minors.h> 37#include <sound/minors.h>
38#include <linux/uio.h> 38#include <linux/uio.h>
39 39
40#include "pcm_local.h"
41
42#ifdef CONFIG_SND_DEBUG
43#define CREATE_TRACE_POINTS
44#include "pcm_param_trace.h"
45#else
46#define trace_hw_mask_param_enabled() 0
47#define trace_hw_interval_param_enabled() 0
48#define trace_hw_mask_param(substream, type, index, prev, curr)
49#define trace_hw_interval_param(substream, type, index, prev, curr)
50#endif
51
40/* 52/*
41 * Compatibility 53 * Compatibility
42 */ 54 */
@@ -181,20 +193,6 @@ void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
181} 193}
182EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); 194EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
183 195
184static inline mm_segment_t snd_enter_user(void)
185{
186 mm_segment_t fs = get_fs();
187 set_fs(get_ds());
188 return fs;
189}
190
191static inline void snd_leave_user(mm_segment_t fs)
192{
193 set_fs(fs);
194}
195
196
197
198int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info) 196int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
199{ 197{
200 struct snd_pcm_runtime *runtime; 198 struct snd_pcm_runtime *runtime;
@@ -214,11 +212,7 @@ int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
214 info->subdevices_avail = pstr->substream_count - pstr->substream_opened; 212 info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
215 strlcpy(info->subname, substream->name, sizeof(info->subname)); 213 strlcpy(info->subname, substream->name, sizeof(info->subname));
216 runtime = substream->runtime; 214 runtime = substream->runtime;
217 /* AB: FIXME!!! This is definitely nonsense */ 215
218 if (runtime) {
219 info->sync = runtime->sync;
220 substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info);
221 }
222 return 0; 216 return 0;
223} 217}
224 218
@@ -255,205 +249,268 @@ static bool hw_support_mmap(struct snd_pcm_substream *substream)
255 return true; 249 return true;
256} 250}
257 251
258#undef RULES_DEBUG 252static int constrain_mask_params(struct snd_pcm_substream *substream,
259 253 struct snd_pcm_hw_params *params)
260#ifdef RULES_DEBUG
261#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
262static const char * const snd_pcm_hw_param_names[] = {
263 HW_PARAM(ACCESS),
264 HW_PARAM(FORMAT),
265 HW_PARAM(SUBFORMAT),
266 HW_PARAM(SAMPLE_BITS),
267 HW_PARAM(FRAME_BITS),
268 HW_PARAM(CHANNELS),
269 HW_PARAM(RATE),
270 HW_PARAM(PERIOD_TIME),
271 HW_PARAM(PERIOD_SIZE),
272 HW_PARAM(PERIOD_BYTES),
273 HW_PARAM(PERIODS),
274 HW_PARAM(BUFFER_TIME),
275 HW_PARAM(BUFFER_SIZE),
276 HW_PARAM(BUFFER_BYTES),
277 HW_PARAM(TICK_TIME),
278};
279#endif
280
281int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
282 struct snd_pcm_hw_params *params)
283{ 254{
255 struct snd_pcm_hw_constraints *constrs =
256 &substream->runtime->hw_constraints;
257 struct snd_mask *m;
284 unsigned int k; 258 unsigned int k;
285 struct snd_pcm_hardware *hw; 259 struct snd_mask old_mask;
286 struct snd_interval *i = NULL; 260 int changed;
287 struct snd_mask *m = NULL;
288 struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
289 unsigned int rstamps[constrs->rules_num];
290 unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
291 unsigned int stamp = 2;
292 int changed, again;
293
294 params->info = 0;
295 params->fifo_size = 0;
296 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
297 params->msbits = 0;
298 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
299 params->rate_num = 0;
300 params->rate_den = 0;
301 }
302 261
303 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) { 262 for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
304 m = hw_param_mask(params, k); 263 m = hw_param_mask(params, k);
305 if (snd_mask_empty(m)) 264 if (snd_mask_empty(m))
306 return -EINVAL; 265 return -EINVAL;
266
267 /* This parameter is not requested to change by a caller. */
307 if (!(params->rmask & (1 << k))) 268 if (!(params->rmask & (1 << k)))
308 continue; 269 continue;
309#ifdef RULES_DEBUG 270
310 pr_debug("%s = ", snd_pcm_hw_param_names[k]); 271 if (trace_hw_mask_param_enabled())
311 pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]); 272 old_mask = *m;
312#endif 273
313 changed = snd_mask_refine(m, constrs_mask(constrs, k)); 274 changed = snd_mask_refine(m, constrs_mask(constrs, k));
314#ifdef RULES_DEBUG
315 pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
316#endif
317 if (changed)
318 params->cmask |= 1 << k;
319 if (changed < 0) 275 if (changed < 0)
320 return changed; 276 return changed;
277 if (changed == 0)
278 continue;
279
280 /* Set corresponding flag so that the caller gets it. */
281 trace_hw_mask_param(substream, k, 0, &old_mask, m);
282 params->cmask |= 1 << k;
321 } 283 }
322 284
285 return 0;
286}
287
288static int constrain_interval_params(struct snd_pcm_substream *substream,
289 struct snd_pcm_hw_params *params)
290{
291 struct snd_pcm_hw_constraints *constrs =
292 &substream->runtime->hw_constraints;
293 struct snd_interval *i;
294 unsigned int k;
295 struct snd_interval old_interval;
296 int changed;
297
323 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) { 298 for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
324 i = hw_param_interval(params, k); 299 i = hw_param_interval(params, k);
325 if (snd_interval_empty(i)) 300 if (snd_interval_empty(i))
326 return -EINVAL; 301 return -EINVAL;
302
303 /* This parameter is not requested to change by a caller. */
327 if (!(params->rmask & (1 << k))) 304 if (!(params->rmask & (1 << k)))
328 continue; 305 continue;
329#ifdef RULES_DEBUG 306
330 pr_debug("%s = ", snd_pcm_hw_param_names[k]); 307 if (trace_hw_interval_param_enabled())
331 if (i->empty) 308 old_interval = *i;
332 pr_cont("empty"); 309
333 else
334 pr_cont("%c%u %u%c",
335 i->openmin ? '(' : '[', i->min,
336 i->max, i->openmax ? ')' : ']');
337 pr_cont(" -> ");
338#endif
339 changed = snd_interval_refine(i, constrs_interval(constrs, k)); 310 changed = snd_interval_refine(i, constrs_interval(constrs, k));
340#ifdef RULES_DEBUG
341 if (i->empty)
342 pr_cont("empty\n");
343 else
344 pr_cont("%c%u %u%c\n",
345 i->openmin ? '(' : '[', i->min,
346 i->max, i->openmax ? ')' : ']');
347#endif
348 if (changed)
349 params->cmask |= 1 << k;
350 if (changed < 0) 311 if (changed < 0)
351 return changed; 312 return changed;
313 if (changed == 0)
314 continue;
315
316 /* Set corresponding flag so that the caller gets it. */
317 trace_hw_interval_param(substream, k, 0, &old_interval, i);
318 params->cmask |= 1 << k;
352 } 319 }
353 320
321 return 0;
322}
323
324static int constrain_params_by_rules(struct snd_pcm_substream *substream,
325 struct snd_pcm_hw_params *params)
326{
327 struct snd_pcm_hw_constraints *constrs =
328 &substream->runtime->hw_constraints;
329 unsigned int k;
330 unsigned int rstamps[constrs->rules_num];
331 unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
332 unsigned int stamp;
333 struct snd_pcm_hw_rule *r;
334 unsigned int d;
335 struct snd_mask old_mask;
336 struct snd_interval old_interval;
337 bool again;
338 int changed;
339
340 /*
341 * Each application of rule has own sequence number.
342 *
343 * Each member of 'rstamps' array represents the sequence number of
344 * recent application of corresponding rule.
345 */
354 for (k = 0; k < constrs->rules_num; k++) 346 for (k = 0; k < constrs->rules_num; k++)
355 rstamps[k] = 0; 347 rstamps[k] = 0;
356 for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) 348
349 /*
350 * Each member of 'vstamps' array represents the sequence number of
351 * recent application of rule in which corresponding parameters were
352 * changed.
353 *
354 * In initial state, elements corresponding to parameters requested by
355 * a caller is 1. For unrequested parameters, corresponding members
356 * have 0 so that the parameters are never changed anymore.
357 */
358 for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
357 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0; 359 vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
358 do { 360
359 again = 0; 361 /* Due to the above design, actual sequence number starts at 2. */
360 for (k = 0; k < constrs->rules_num; k++) { 362 stamp = 2;
361 struct snd_pcm_hw_rule *r = &constrs->rules[k]; 363retry:
362 unsigned int d; 364 /* Apply all rules in order. */
363 int doit = 0; 365 again = false;
364 if (r->cond && !(r->cond & params->flags)) 366 for (k = 0; k < constrs->rules_num; k++) {
365 continue; 367 r = &constrs->rules[k];
366 for (d = 0; r->deps[d] >= 0; d++) { 368
367 if (vstamps[r->deps[d]] > rstamps[k]) { 369 /*
368 doit = 1; 370 * Check condition bits of this rule. When the rule has
369 break; 371 * some condition bits, parameter without the bits is
370 } 372 * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP
371 } 373 * is an example of the condition bits.
372 if (!doit) 374 */
373 continue; 375 if (r->cond && !(r->cond & params->flags))
374#ifdef RULES_DEBUG 376 continue;
375 pr_debug("Rule %d [%p]: ", k, r->func); 377
376 if (r->var >= 0) { 378 /*
377 pr_cont("%s = ", snd_pcm_hw_param_names[r->var]); 379 * The 'deps' array includes maximum three dependencies
378 if (hw_is_mask(r->var)) { 380 * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth
379 m = hw_param_mask(params, r->var); 381 * member of this array is a sentinel and should be
380 pr_cont("%x", *m->bits); 382 * negative value.
381 } else { 383 *
382 i = hw_param_interval(params, r->var); 384 * This rule should be processed in this time when dependent
383 if (i->empty) 385 * parameters were changed at former applications of the other
384 pr_cont("empty"); 386 * rules.
385 else 387 */
386 pr_cont("%c%u %u%c", 388 for (d = 0; r->deps[d] >= 0; d++) {
387 i->openmin ? '(' : '[', i->min, 389 if (vstamps[r->deps[d]] > rstamps[k])
388 i->max, i->openmax ? ')' : ']'); 390 break;
389 } 391 }
390 } 392 if (r->deps[d] < 0)
391#endif 393 continue;
392 changed = r->func(params, r); 394
393#ifdef RULES_DEBUG 395 if (trace_hw_mask_param_enabled()) {
394 if (r->var >= 0) { 396 if (hw_is_mask(r->var))
395 pr_cont(" -> "); 397 old_mask = *hw_param_mask(params, r->var);
396 if (hw_is_mask(r->var)) 398 }
397 pr_cont("%x", *m->bits); 399 if (trace_hw_interval_param_enabled()) {
398 else { 400 if (hw_is_interval(r->var))
399 if (i->empty) 401 old_interval = *hw_param_interval(params, r->var);
400 pr_cont("empty"); 402 }
401 else 403
402 pr_cont("%c%u %u%c", 404 changed = r->func(params, r);
403 i->openmin ? '(' : '[', i->min, 405 if (changed < 0)
404 i->max, i->openmax ? ')' : ']'); 406 return changed;
405 } 407
408 /*
409 * When the parameter is changed, notify it to the caller
410 * by corresponding returned bit, then preparing for next
411 * iteration.
412 */
413 if (changed && r->var >= 0) {
414 if (hw_is_mask(r->var)) {
415 trace_hw_mask_param(substream, r->var,
416 k + 1, &old_mask,
417 hw_param_mask(params, r->var));
406 } 418 }
407 pr_cont("\n"); 419 if (hw_is_interval(r->var)) {
408#endif 420 trace_hw_interval_param(substream, r->var,
409 rstamps[k] = stamp; 421 k + 1, &old_interval,
410 if (changed && r->var >= 0) { 422 hw_param_interval(params, r->var));
411 params->cmask |= (1 << r->var);
412 vstamps[r->var] = stamp;
413 again = 1;
414 } 423 }
415 if (changed < 0) 424
416 return changed; 425 params->cmask |= (1 << r->var);
417 stamp++; 426 vstamps[r->var] = stamp;
427 again = true;
418 } 428 }
419 } while (again); 429
430 rstamps[k] = stamp++;
431 }
432
433 /* Iterate to evaluate all rules till no parameters are changed. */
434 if (again)
435 goto retry;
436
437 return 0;
438}
439
440static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
441 struct snd_pcm_hw_params *params)
442{
443 const struct snd_interval *i;
444 const struct snd_mask *m;
445 int err;
446
420 if (!params->msbits) { 447 if (!params->msbits) {
421 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS); 448 i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
422 if (snd_interval_single(i)) 449 if (snd_interval_single(i))
423 params->msbits = snd_interval_value(i); 450 params->msbits = snd_interval_value(i);
424 } 451 }
425 452
426 if (!params->rate_den) { 453 if (!params->rate_den) {
427 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 454 i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
428 if (snd_interval_single(i)) { 455 if (snd_interval_single(i)) {
429 params->rate_num = snd_interval_value(i); 456 params->rate_num = snd_interval_value(i);
430 params->rate_den = 1; 457 params->rate_den = 1;
431 } 458 }
432 } 459 }
433 460
434 hw = &substream->runtime->hw; 461 if (!params->fifo_size) {
462 m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
463 i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
464 if (snd_mask_single(m) && snd_interval_single(i)) {
465 err = substream->ops->ioctl(substream,
466 SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
467 if (err < 0)
468 return err;
469 }
470 }
471
435 if (!params->info) { 472 if (!params->info) {
436 params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES | 473 params->info = substream->runtime->hw.info;
437 SNDRV_PCM_INFO_DRAIN_TRIGGER); 474 params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
475 SNDRV_PCM_INFO_DRAIN_TRIGGER);
438 if (!hw_support_mmap(substream)) 476 if (!hw_support_mmap(substream))
439 params->info &= ~(SNDRV_PCM_INFO_MMAP | 477 params->info &= ~(SNDRV_PCM_INFO_MMAP |
440 SNDRV_PCM_INFO_MMAP_VALID); 478 SNDRV_PCM_INFO_MMAP_VALID);
441 } 479 }
442 if (!params->fifo_size) { 480
443 m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 481 return 0;
444 i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 482}
445 if (snd_mask_min(m) == snd_mask_max(m) && 483
446 snd_interval_min(i) == snd_interval_max(i)) { 484int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
447 changed = substream->ops->ioctl(substream, 485 struct snd_pcm_hw_params *params)
448 SNDRV_PCM_IOCTL1_FIFO_SIZE, params); 486{
449 if (changed < 0) 487 int err;
450 return changed; 488
451 } 489 params->info = 0;
490 params->fifo_size = 0;
491 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
492 params->msbits = 0;
493 if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
494 params->rate_num = 0;
495 params->rate_den = 0;
452 } 496 }
497
498 err = constrain_mask_params(substream, params);
499 if (err < 0)
500 return err;
501
502 err = constrain_interval_params(substream, params);
503 if (err < 0)
504 return err;
505
506 err = constrain_params_by_rules(substream, params);
507 if (err < 0)
508 return err;
509
453 params->rmask = 0; 510 params->rmask = 0;
511
454 return 0; 512 return 0;
455} 513}
456
457EXPORT_SYMBOL(snd_pcm_hw_refine); 514EXPORT_SYMBOL(snd_pcm_hw_refine);
458 515
459static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream, 516static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
@@ -467,11 +524,16 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
467 return PTR_ERR(params); 524 return PTR_ERR(params);
468 525
469 err = snd_pcm_hw_refine(substream, params); 526 err = snd_pcm_hw_refine(substream, params);
470 if (copy_to_user(_params, params, sizeof(*params))) { 527 if (err < 0)
471 if (!err) 528 goto end;
472 err = -EFAULT; 529
473 } 530 err = fixup_unreferenced_params(substream, params);
531 if (err < 0)
532 goto end;
474 533
534 if (copy_to_user(_params, params, sizeof(*params)))
535 err = -EFAULT;
536end:
475 kfree(params); 537 kfree(params);
476 return err; 538 return err;
477} 539}
@@ -509,6 +571,70 @@ static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
509#endif 571#endif
510} 572}
511 573
574/**
575 * snd_pcm_hw_param_choose - choose a configuration defined by @params
576 * @pcm: PCM instance
577 * @params: the hw_params instance
578 *
579 * Choose one configuration from configuration space defined by @params.
580 * The configuration chosen is that obtained fixing in this order:
581 * first access, first format, first subformat, min channels,
582 * min rate, min period time, max buffer size, min tick time
583 *
584 * Return: Zero if successful, or a negative error code on failure.
585 */
586static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
587 struct snd_pcm_hw_params *params)
588{
589 static const int vars[] = {
590 SNDRV_PCM_HW_PARAM_ACCESS,
591 SNDRV_PCM_HW_PARAM_FORMAT,
592 SNDRV_PCM_HW_PARAM_SUBFORMAT,
593 SNDRV_PCM_HW_PARAM_CHANNELS,
594 SNDRV_PCM_HW_PARAM_RATE,
595 SNDRV_PCM_HW_PARAM_PERIOD_TIME,
596 SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
597 SNDRV_PCM_HW_PARAM_TICK_TIME,
598 -1
599 };
600 const int *v;
601 struct snd_mask old_mask;
602 struct snd_interval old_interval;
603 int changed;
604
605 for (v = vars; *v != -1; v++) {
606 /* Keep old parameter to trace. */
607 if (trace_hw_mask_param_enabled()) {
608 if (hw_is_mask(*v))
609 old_mask = *hw_param_mask(params, *v);
610 }
611 if (trace_hw_interval_param_enabled()) {
612 if (hw_is_interval(*v))
613 old_interval = *hw_param_interval(params, *v);
614 }
615 if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
616 changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
617 else
618 changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
619 if (snd_BUG_ON(changed < 0))
620 return changed;
621 if (changed == 0)
622 continue;
623
624 /* Trace the changed parameter. */
625 if (hw_is_mask(*v)) {
626 trace_hw_mask_param(pcm, *v, 0, &old_mask,
627 hw_param_mask(params, *v));
628 }
629 if (hw_is_interval(*v)) {
630 trace_hw_interval_param(pcm, *v, 0, &old_interval,
631 hw_param_interval(params, *v));
632 }
633 }
634
635 return 0;
636}
637
512static int snd_pcm_hw_params(struct snd_pcm_substream *substream, 638static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
513 struct snd_pcm_hw_params *params) 639 struct snd_pcm_hw_params *params)
514{ 640{
@@ -546,6 +672,10 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
546 if (err < 0) 672 if (err < 0)
547 goto _error; 673 goto _error;
548 674
675 err = fixup_unreferenced_params(substream, params);
676 if (err < 0)
677 goto _error;
678
549 if (substream->ops->hw_params != NULL) { 679 if (substream->ops->hw_params != NULL) {
550 err = substream->ops->hw_params(substream, params); 680 err = substream->ops->hw_params(substream, params);
551 if (err < 0) 681 if (err < 0)
@@ -621,11 +751,12 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
621 return PTR_ERR(params); 751 return PTR_ERR(params);
622 752
623 err = snd_pcm_hw_params(substream, params); 753 err = snd_pcm_hw_params(substream, params);
624 if (copy_to_user(_params, params, sizeof(*params))) { 754 if (err < 0)
625 if (!err) 755 goto end;
626 err = -EFAULT;
627 }
628 756
757 if (copy_to_user(_params, params, sizeof(*params)))
758 err = -EFAULT;
759end:
629 kfree(params); 760 kfree(params);
630 return err; 761 return err;
631} 762}
@@ -1081,6 +1212,7 @@ static const struct action_ops snd_pcm_action_start = {
1081 * @substream: the PCM substream instance 1212 * @substream: the PCM substream instance
1082 * 1213 *
1083 * Return: Zero if successful, or a negative error code. 1214 * Return: Zero if successful, or a negative error code.
1215 * The stream lock must be acquired before calling this function.
1084 */ 1216 */
1085int snd_pcm_start(struct snd_pcm_substream *substream) 1217int snd_pcm_start(struct snd_pcm_substream *substream)
1086{ 1218{
@@ -1088,6 +1220,13 @@ int snd_pcm_start(struct snd_pcm_substream *substream)
1088 SNDRV_PCM_STATE_RUNNING); 1220 SNDRV_PCM_STATE_RUNNING);
1089} 1221}
1090 1222
1223/* take the stream lock and start the streams */
1224static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
1225{
1226 return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream,
1227 SNDRV_PCM_STATE_RUNNING);
1228}
1229
1091/* 1230/*
1092 * stop callbacks 1231 * stop callbacks
1093 */ 1232 */
@@ -1139,7 +1278,6 @@ int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
1139{ 1278{
1140 return snd_pcm_action(&snd_pcm_action_stop, substream, state); 1279 return snd_pcm_action(&snd_pcm_action_stop, substream, state);
1141} 1280}
1142
1143EXPORT_SYMBOL(snd_pcm_stop); 1281EXPORT_SYMBOL(snd_pcm_stop);
1144 1282
1145/** 1283/**
@@ -1314,7 +1452,6 @@ int snd_pcm_suspend(struct snd_pcm_substream *substream)
1314 snd_pcm_stream_unlock_irqrestore(substream, flags); 1452 snd_pcm_stream_unlock_irqrestore(substream, flags);
1315 return err; 1453 return err;
1316} 1454}
1317
1318EXPORT_SYMBOL(snd_pcm_suspend); 1455EXPORT_SYMBOL(snd_pcm_suspend);
1319 1456
1320/** 1457/**
@@ -1346,7 +1483,6 @@ int snd_pcm_suspend_all(struct snd_pcm *pcm)
1346 } 1483 }
1347 return 0; 1484 return 0;
1348} 1485}
1349
1350EXPORT_SYMBOL(snd_pcm_suspend_all); 1486EXPORT_SYMBOL(snd_pcm_suspend_all);
1351 1487
1352/* resume */ 1488/* resume */
@@ -1397,14 +1533,7 @@ static const struct action_ops snd_pcm_action_resume = {
1397 1533
1398static int snd_pcm_resume(struct snd_pcm_substream *substream) 1534static int snd_pcm_resume(struct snd_pcm_substream *substream)
1399{ 1535{
1400 struct snd_card *card = substream->pcm->card; 1536 return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
1401 int res;
1402
1403 snd_power_lock(card);
1404 if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
1405 res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
1406 snd_power_unlock(card);
1407 return res;
1408} 1537}
1409 1538
1410#else 1539#else
@@ -1423,17 +1552,9 @@ static int snd_pcm_resume(struct snd_pcm_substream *substream)
1423 */ 1552 */
1424static int snd_pcm_xrun(struct snd_pcm_substream *substream) 1553static int snd_pcm_xrun(struct snd_pcm_substream *substream)
1425{ 1554{
1426 struct snd_card *card = substream->pcm->card;
1427 struct snd_pcm_runtime *runtime = substream->runtime; 1555 struct snd_pcm_runtime *runtime = substream->runtime;
1428 int result; 1556 int result;
1429 1557
1430 snd_power_lock(card);
1431 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1432 result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1433 if (result < 0)
1434 goto _unlock;
1435 }
1436
1437 snd_pcm_stream_lock_irq(substream); 1558 snd_pcm_stream_lock_irq(substream);
1438 switch (runtime->status->state) { 1559 switch (runtime->status->state) {
1439 case SNDRV_PCM_STATE_XRUN: 1560 case SNDRV_PCM_STATE_XRUN:
@@ -1446,8 +1567,6 @@ static int snd_pcm_xrun(struct snd_pcm_substream *substream)
1446 result = -EBADFD; 1567 result = -EBADFD;
1447 } 1568 }
1448 snd_pcm_stream_unlock_irq(substream); 1569 snd_pcm_stream_unlock_irq(substream);
1449 _unlock:
1450 snd_power_unlock(card);
1451 return result; 1570 return result;
1452} 1571}
1453 1572
@@ -1551,8 +1670,6 @@ static const struct action_ops snd_pcm_action_prepare = {
1551static int snd_pcm_prepare(struct snd_pcm_substream *substream, 1670static int snd_pcm_prepare(struct snd_pcm_substream *substream,
1552 struct file *file) 1671 struct file *file)
1553{ 1672{
1554 int res;
1555 struct snd_card *card = substream->pcm->card;
1556 int f_flags; 1673 int f_flags;
1557 1674
1558 if (file) 1675 if (file)
@@ -1560,12 +1677,19 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream,
1560 else 1677 else
1561 f_flags = substream->f_flags; 1678 f_flags = substream->f_flags;
1562 1679
1563 snd_power_lock(card); 1680 snd_pcm_stream_lock_irq(substream);
1564 if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0) 1681 switch (substream->runtime->status->state) {
1565 res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare, 1682 case SNDRV_PCM_STATE_PAUSED:
1566 substream, f_flags); 1683 snd_pcm_pause(substream, 0);
1567 snd_power_unlock(card); 1684 /* fallthru */
1568 return res; 1685 case SNDRV_PCM_STATE_SUSPENDED:
1686 snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
1687 break;
1688 }
1689 snd_pcm_stream_unlock_irq(substream);
1690
1691 return snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
1692 substream, f_flags);
1569} 1693}
1570 1694
1571/* 1695/*
@@ -1662,15 +1786,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1662 if (runtime->status->state == SNDRV_PCM_STATE_OPEN) 1786 if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
1663 return -EBADFD; 1787 return -EBADFD;
1664 1788
1665 snd_power_lock(card);
1666 if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1667 result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1668 if (result < 0) {
1669 snd_power_unlock(card);
1670 return result;
1671 }
1672 }
1673
1674 if (file) { 1789 if (file) {
1675 if (file->f_flags & O_NONBLOCK) 1790 if (file->f_flags & O_NONBLOCK)
1676 nonblock = 1; 1791 nonblock = 1;
@@ -1753,7 +1868,6 @@ static int snd_pcm_drain(struct snd_pcm_substream *substream,
1753 unlock: 1868 unlock:
1754 snd_pcm_stream_unlock_irq(substream); 1869 snd_pcm_stream_unlock_irq(substream);
1755 up_read(&snd_pcm_link_rwsem); 1870 up_read(&snd_pcm_link_rwsem);
1756 snd_power_unlock(card);
1757 1871
1758 return result; 1872 return result;
1759} 1873}
@@ -1773,8 +1887,7 @@ static int snd_pcm_drop(struct snd_pcm_substream *substream)
1773 runtime = substream->runtime; 1887 runtime = substream->runtime;
1774 1888
1775 if (runtime->status->state == SNDRV_PCM_STATE_OPEN || 1889 if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1776 runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED || 1890 runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
1777 runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
1778 return -EBADFD; 1891 return -EBADFD;
1779 1892
1780 snd_pcm_stream_lock_irq(substream); 1893 snd_pcm_stream_lock_irq(substream);
@@ -1940,7 +2053,8 @@ static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
1940 struct snd_pcm_hw_rule *rule) 2053 struct snd_pcm_hw_rule *rule)
1941{ 2054{
1942 unsigned int k; 2055 unsigned int k;
1943 struct snd_interval *i = hw_param_interval(params, rule->deps[0]); 2056 const struct snd_interval *i =
2057 hw_param_interval_c(params, rule->deps[0]);
1944 struct snd_mask m; 2058 struct snd_mask m;
1945 struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 2059 struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
1946 snd_mask_any(&m); 2060 snd_mask_any(&m);
@@ -1986,8 +2100,10 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
1986#error "Change this table" 2100#error "Change this table"
1987#endif 2101#endif
1988 2102
1989static unsigned int rates[] = { 5512, 8000, 11025, 16000, 22050, 32000, 44100, 2103static const unsigned int rates[] = {
1990 48000, 64000, 88200, 96000, 176400, 192000 }; 2104 5512, 8000, 11025, 16000, 22050, 32000, 44100,
2105 48000, 64000, 88200, 96000, 176400, 192000
2106};
1991 2107
1992const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { 2108const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
1993 .count = ARRAY_SIZE(rates), 2109 .count = ARRAY_SIZE(rates),
@@ -2250,7 +2366,6 @@ void snd_pcm_release_substream(struct snd_pcm_substream *substream)
2250 } 2366 }
2251 snd_pcm_detach_substream(substream); 2367 snd_pcm_detach_substream(substream);
2252} 2368}
2253
2254EXPORT_SYMBOL(snd_pcm_release_substream); 2369EXPORT_SYMBOL(snd_pcm_release_substream);
2255 2370
2256int snd_pcm_open_substream(struct snd_pcm *pcm, int stream, 2371int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
@@ -2292,7 +2407,6 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
2292 snd_pcm_release_substream(substream); 2407 snd_pcm_release_substream(substream);
2293 return err; 2408 return err;
2294} 2409}
2295
2296EXPORT_SYMBOL(snd_pcm_open_substream); 2410EXPORT_SYMBOL(snd_pcm_open_substream);
2297 2411
2298static int snd_pcm_open_file(struct file *file, 2412static int snd_pcm_open_file(struct file *file,
@@ -2428,50 +2542,84 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
2428 return 0; 2542 return 0;
2429} 2543}
2430 2544
2431static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, 2545/* check and update PCM state; return 0 or a negative error
2432 snd_pcm_uframes_t frames) 2546 * call this inside PCM lock
2547 */
2548static int do_pcm_hwsync(struct snd_pcm_substream *substream)
2433{ 2549{
2434 struct snd_pcm_runtime *runtime = substream->runtime; 2550 switch (substream->runtime->status->state) {
2435 snd_pcm_sframes_t appl_ptr;
2436 snd_pcm_sframes_t ret;
2437 snd_pcm_sframes_t hw_avail;
2438
2439 if (frames == 0)
2440 return 0;
2441
2442 snd_pcm_stream_lock_irq(substream);
2443 switch (runtime->status->state) {
2444 case SNDRV_PCM_STATE_PREPARED:
2445 break;
2446 case SNDRV_PCM_STATE_DRAINING: 2551 case SNDRV_PCM_STATE_DRAINING:
2447 case SNDRV_PCM_STATE_RUNNING: 2552 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2448 if (snd_pcm_update_hw_ptr(substream) >= 0) 2553 return -EBADFD;
2449 break;
2450 /* Fall through */ 2554 /* Fall through */
2451 case SNDRV_PCM_STATE_XRUN: 2555 case SNDRV_PCM_STATE_RUNNING:
2452 ret = -EPIPE; 2556 return snd_pcm_update_hw_ptr(substream);
2453 goto __end; 2557 case SNDRV_PCM_STATE_PREPARED:
2558 case SNDRV_PCM_STATE_PAUSED:
2559 return 0;
2454 case SNDRV_PCM_STATE_SUSPENDED: 2560 case SNDRV_PCM_STATE_SUSPENDED:
2455 ret = -ESTRPIPE; 2561 return -ESTRPIPE;
2456 goto __end; 2562 case SNDRV_PCM_STATE_XRUN:
2563 return -EPIPE;
2457 default: 2564 default:
2458 ret = -EBADFD; 2565 return -EBADFD;
2459 goto __end;
2460 } 2566 }
2567}
2461 2568
2462 hw_avail = snd_pcm_playback_hw_avail(runtime); 2569/* increase the appl_ptr; returns the processed frames or a negative error */
2463 if (hw_avail <= 0) { 2570static snd_pcm_sframes_t forward_appl_ptr(struct snd_pcm_substream *substream,
2464 ret = 0; 2571 snd_pcm_uframes_t frames,
2465 goto __end; 2572 snd_pcm_sframes_t avail)
2466 } 2573{
2467 if (frames > (snd_pcm_uframes_t)hw_avail) 2574 struct snd_pcm_runtime *runtime = substream->runtime;
2468 frames = hw_avail; 2575 snd_pcm_sframes_t appl_ptr;
2576 int ret;
2577
2578 if (avail <= 0)
2579 return 0;
2580 if (frames > (snd_pcm_uframes_t)avail)
2581 frames = avail;
2582 appl_ptr = runtime->control->appl_ptr + frames;
2583 if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
2584 appl_ptr -= runtime->boundary;
2585 ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
2586 return ret < 0 ? ret : frames;
2587}
2588
2589/* decrease the appl_ptr; returns the processed frames or a negative error */
2590static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream,
2591 snd_pcm_uframes_t frames,
2592 snd_pcm_sframes_t avail)
2593{
2594 struct snd_pcm_runtime *runtime = substream->runtime;
2595 snd_pcm_sframes_t appl_ptr;
2596 int ret;
2597
2598 if (avail <= 0)
2599 return 0;
2600 if (frames > (snd_pcm_uframes_t)avail)
2601 frames = avail;
2469 appl_ptr = runtime->control->appl_ptr - frames; 2602 appl_ptr = runtime->control->appl_ptr - frames;
2470 if (appl_ptr < 0) 2603 if (appl_ptr < 0)
2471 appl_ptr += runtime->boundary; 2604 appl_ptr += runtime->boundary;
2472 runtime->control->appl_ptr = appl_ptr; 2605 ret = pcm_lib_apply_appl_ptr(substream, appl_ptr);
2473 ret = frames; 2606 return ret < 0 ? ret : frames;
2474 __end: 2607}
2608
2609static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
2610 snd_pcm_uframes_t frames)
2611{
2612 struct snd_pcm_runtime *runtime = substream->runtime;
2613 snd_pcm_sframes_t ret;
2614
2615 if (frames == 0)
2616 return 0;
2617
2618 snd_pcm_stream_lock_irq(substream);
2619 ret = do_pcm_hwsync(substream);
2620 if (!ret)
2621 ret = rewind_appl_ptr(substream, frames,
2622 snd_pcm_playback_hw_avail(runtime));
2475 snd_pcm_stream_unlock_irq(substream); 2623 snd_pcm_stream_unlock_irq(substream);
2476 return ret; 2624 return ret;
2477} 2625}
@@ -2480,46 +2628,16 @@ static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substr
2480 snd_pcm_uframes_t frames) 2628 snd_pcm_uframes_t frames)
2481{ 2629{
2482 struct snd_pcm_runtime *runtime = substream->runtime; 2630 struct snd_pcm_runtime *runtime = substream->runtime;
2483 snd_pcm_sframes_t appl_ptr;
2484 snd_pcm_sframes_t ret; 2631 snd_pcm_sframes_t ret;
2485 snd_pcm_sframes_t hw_avail;
2486 2632
2487 if (frames == 0) 2633 if (frames == 0)
2488 return 0; 2634 return 0;
2489 2635
2490 snd_pcm_stream_lock_irq(substream); 2636 snd_pcm_stream_lock_irq(substream);
2491 switch (runtime->status->state) { 2637 ret = do_pcm_hwsync(substream);
2492 case SNDRV_PCM_STATE_PREPARED: 2638 if (!ret)
2493 case SNDRV_PCM_STATE_DRAINING: 2639 ret = rewind_appl_ptr(substream, frames,
2494 break; 2640 snd_pcm_capture_hw_avail(runtime));
2495 case SNDRV_PCM_STATE_RUNNING:
2496 if (snd_pcm_update_hw_ptr(substream) >= 0)
2497 break;
2498 /* Fall through */
2499 case SNDRV_PCM_STATE_XRUN:
2500 ret = -EPIPE;
2501 goto __end;
2502 case SNDRV_PCM_STATE_SUSPENDED:
2503 ret = -ESTRPIPE;
2504 goto __end;
2505 default:
2506 ret = -EBADFD;
2507 goto __end;
2508 }
2509
2510 hw_avail = snd_pcm_capture_hw_avail(runtime);
2511 if (hw_avail <= 0) {
2512 ret = 0;
2513 goto __end;
2514 }
2515 if (frames > (snd_pcm_uframes_t)hw_avail)
2516 frames = hw_avail;
2517 appl_ptr = runtime->control->appl_ptr - frames;
2518 if (appl_ptr < 0)
2519 appl_ptr += runtime->boundary;
2520 runtime->control->appl_ptr = appl_ptr;
2521 ret = frames;
2522 __end:
2523 snd_pcm_stream_unlock_irq(substream); 2641 snd_pcm_stream_unlock_irq(substream);
2524 return ret; 2642 return ret;
2525} 2643}
@@ -2528,47 +2646,16 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs
2528 snd_pcm_uframes_t frames) 2646 snd_pcm_uframes_t frames)
2529{ 2647{
2530 struct snd_pcm_runtime *runtime = substream->runtime; 2648 struct snd_pcm_runtime *runtime = substream->runtime;
2531 snd_pcm_sframes_t appl_ptr;
2532 snd_pcm_sframes_t ret; 2649 snd_pcm_sframes_t ret;
2533 snd_pcm_sframes_t avail;
2534 2650
2535 if (frames == 0) 2651 if (frames == 0)
2536 return 0; 2652 return 0;
2537 2653
2538 snd_pcm_stream_lock_irq(substream); 2654 snd_pcm_stream_lock_irq(substream);
2539 switch (runtime->status->state) { 2655 ret = do_pcm_hwsync(substream);
2540 case SNDRV_PCM_STATE_PREPARED: 2656 if (!ret)
2541 case SNDRV_PCM_STATE_PAUSED: 2657 ret = forward_appl_ptr(substream, frames,
2542 break; 2658 snd_pcm_playback_avail(runtime));
2543 case SNDRV_PCM_STATE_DRAINING:
2544 case SNDRV_PCM_STATE_RUNNING:
2545 if (snd_pcm_update_hw_ptr(substream) >= 0)
2546 break;
2547 /* Fall through */
2548 case SNDRV_PCM_STATE_XRUN:
2549 ret = -EPIPE;
2550 goto __end;
2551 case SNDRV_PCM_STATE_SUSPENDED:
2552 ret = -ESTRPIPE;
2553 goto __end;
2554 default:
2555 ret = -EBADFD;
2556 goto __end;
2557 }
2558
2559 avail = snd_pcm_playback_avail(runtime);
2560 if (avail <= 0) {
2561 ret = 0;
2562 goto __end;
2563 }
2564 if (frames > (snd_pcm_uframes_t)avail)
2565 frames = avail;
2566 appl_ptr = runtime->control->appl_ptr + frames;
2567 if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
2568 appl_ptr -= runtime->boundary;
2569 runtime->control->appl_ptr = appl_ptr;
2570 ret = frames;
2571 __end:
2572 snd_pcm_stream_unlock_irq(substream); 2659 snd_pcm_stream_unlock_irq(substream);
2573 return ret; 2660 return ret;
2574} 2661}
@@ -2577,123 +2664,47 @@ static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *subst
2577 snd_pcm_uframes_t frames) 2664 snd_pcm_uframes_t frames)
2578{ 2665{
2579 struct snd_pcm_runtime *runtime = substream->runtime; 2666 struct snd_pcm_runtime *runtime = substream->runtime;
2580 snd_pcm_sframes_t appl_ptr;
2581 snd_pcm_sframes_t ret; 2667 snd_pcm_sframes_t ret;
2582 snd_pcm_sframes_t avail;
2583 2668
2584 if (frames == 0) 2669 if (frames == 0)
2585 return 0; 2670 return 0;
2586 2671
2587 snd_pcm_stream_lock_irq(substream); 2672 snd_pcm_stream_lock_irq(substream);
2588 switch (runtime->status->state) { 2673 ret = do_pcm_hwsync(substream);
2589 case SNDRV_PCM_STATE_PREPARED: 2674 if (!ret)
2590 case SNDRV_PCM_STATE_DRAINING: 2675 ret = forward_appl_ptr(substream, frames,
2591 case SNDRV_PCM_STATE_PAUSED: 2676 snd_pcm_capture_avail(runtime));
2592 break;
2593 case SNDRV_PCM_STATE_RUNNING:
2594 if (snd_pcm_update_hw_ptr(substream) >= 0)
2595 break;
2596 /* Fall through */
2597 case SNDRV_PCM_STATE_XRUN:
2598 ret = -EPIPE;
2599 goto __end;
2600 case SNDRV_PCM_STATE_SUSPENDED:
2601 ret = -ESTRPIPE;
2602 goto __end;
2603 default:
2604 ret = -EBADFD;
2605 goto __end;
2606 }
2607
2608 avail = snd_pcm_capture_avail(runtime);
2609 if (avail <= 0) {
2610 ret = 0;
2611 goto __end;
2612 }
2613 if (frames > (snd_pcm_uframes_t)avail)
2614 frames = avail;
2615 appl_ptr = runtime->control->appl_ptr + frames;
2616 if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
2617 appl_ptr -= runtime->boundary;
2618 runtime->control->appl_ptr = appl_ptr;
2619 ret = frames;
2620 __end:
2621 snd_pcm_stream_unlock_irq(substream); 2677 snd_pcm_stream_unlock_irq(substream);
2622 return ret; 2678 return ret;
2623} 2679}
2624 2680
2625static int snd_pcm_hwsync(struct snd_pcm_substream *substream) 2681static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
2626{ 2682{
2627 struct snd_pcm_runtime *runtime = substream->runtime;
2628 int err; 2683 int err;
2629 2684
2630 snd_pcm_stream_lock_irq(substream); 2685 snd_pcm_stream_lock_irq(substream);
2631 switch (runtime->status->state) { 2686 err = do_pcm_hwsync(substream);
2632 case SNDRV_PCM_STATE_DRAINING:
2633 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2634 goto __badfd;
2635 /* Fall through */
2636 case SNDRV_PCM_STATE_RUNNING:
2637 if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
2638 break;
2639 /* Fall through */
2640 case SNDRV_PCM_STATE_PREPARED:
2641 err = 0;
2642 break;
2643 case SNDRV_PCM_STATE_SUSPENDED:
2644 err = -ESTRPIPE;
2645 break;
2646 case SNDRV_PCM_STATE_XRUN:
2647 err = -EPIPE;
2648 break;
2649 default:
2650 __badfd:
2651 err = -EBADFD;
2652 break;
2653 }
2654 snd_pcm_stream_unlock_irq(substream); 2687 snd_pcm_stream_unlock_irq(substream);
2655 return err; 2688 return err;
2656} 2689}
2657 2690
2658static int snd_pcm_delay(struct snd_pcm_substream *substream, 2691static snd_pcm_sframes_t snd_pcm_delay(struct snd_pcm_substream *substream)
2659 snd_pcm_sframes_t __user *res)
2660{ 2692{
2661 struct snd_pcm_runtime *runtime = substream->runtime; 2693 struct snd_pcm_runtime *runtime = substream->runtime;
2662 int err; 2694 int err;
2663 snd_pcm_sframes_t n = 0; 2695 snd_pcm_sframes_t n = 0;
2664 2696
2665 snd_pcm_stream_lock_irq(substream); 2697 snd_pcm_stream_lock_irq(substream);
2666 switch (runtime->status->state) { 2698 err = do_pcm_hwsync(substream);
2667 case SNDRV_PCM_STATE_DRAINING: 2699 if (!err) {
2668 if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
2669 goto __badfd;
2670 /* Fall through */
2671 case SNDRV_PCM_STATE_RUNNING:
2672 if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
2673 break;
2674 /* Fall through */
2675 case SNDRV_PCM_STATE_PREPARED:
2676 case SNDRV_PCM_STATE_SUSPENDED:
2677 err = 0;
2678 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) 2700 if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
2679 n = snd_pcm_playback_hw_avail(runtime); 2701 n = snd_pcm_playback_hw_avail(runtime);
2680 else 2702 else
2681 n = snd_pcm_capture_avail(runtime); 2703 n = snd_pcm_capture_avail(runtime);
2682 n += runtime->delay; 2704 n += runtime->delay;
2683 break;
2684 case SNDRV_PCM_STATE_XRUN:
2685 err = -EPIPE;
2686 break;
2687 default:
2688 __badfd:
2689 err = -EBADFD;
2690 break;
2691 } 2705 }
2692 snd_pcm_stream_unlock_irq(substream); 2706 snd_pcm_stream_unlock_irq(substream);
2693 if (!err) 2707 return err < 0 ? err : n;
2694 if (put_user(n, res))
2695 err = -EFAULT;
2696 return err;
2697} 2708}
2698 2709
2699static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream, 2710static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
@@ -2718,10 +2729,16 @@ static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
2718 return err; 2729 return err;
2719 } 2730 }
2720 snd_pcm_stream_lock_irq(substream); 2731 snd_pcm_stream_lock_irq(substream);
2721 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) 2732 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL)) {
2722 control->appl_ptr = sync_ptr.c.control.appl_ptr; 2733 err = pcm_lib_apply_appl_ptr(substream,
2723 else 2734 sync_ptr.c.control.appl_ptr);
2735 if (err < 0) {
2736 snd_pcm_stream_unlock_irq(substream);
2737 return err;
2738 }
2739 } else {
2724 sync_ptr.c.control.appl_ptr = control->appl_ptr; 2740 sync_ptr.c.control.appl_ptr = control->appl_ptr;
2741 }
2725 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN)) 2742 if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
2726 control->avail_min = sync_ptr.c.control.avail_min; 2743 control->avail_min = sync_ptr.c.control.avail_min;
2727 else 2744 else
@@ -2749,10 +2766,12 @@ static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
2749 return 0; 2766 return 0;
2750} 2767}
2751 2768
2752static int snd_pcm_common_ioctl1(struct file *file, 2769static int snd_pcm_common_ioctl(struct file *file,
2753 struct snd_pcm_substream *substream, 2770 struct snd_pcm_substream *substream,
2754 unsigned int cmd, void __user *arg) 2771 unsigned int cmd, void __user *arg)
2755{ 2772{
2773 struct snd_pcm_file *pcm_file = file->private_data;
2774
2756 switch (cmd) { 2775 switch (cmd) {
2757 case SNDRV_PCM_IOCTL_PVERSION: 2776 case SNDRV_PCM_IOCTL_PVERSION:
2758 return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0; 2777 return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
@@ -2762,6 +2781,11 @@ static int snd_pcm_common_ioctl1(struct file *file,
2762 return 0; 2781 return 0;
2763 case SNDRV_PCM_IOCTL_TTSTAMP: 2782 case SNDRV_PCM_IOCTL_TTSTAMP:
2764 return snd_pcm_tstamp(substream, arg); 2783 return snd_pcm_tstamp(substream, arg);
2784 case SNDRV_PCM_IOCTL_USER_PVERSION:
2785 if (get_user(pcm_file->user_pversion,
2786 (unsigned int __user *)arg))
2787 return -EFAULT;
2788 return 0;
2765 case SNDRV_PCM_IOCTL_HW_REFINE: 2789 case SNDRV_PCM_IOCTL_HW_REFINE:
2766 return snd_pcm_hw_refine_user(substream, arg); 2790 return snd_pcm_hw_refine_user(substream, arg);
2767 case SNDRV_PCM_IOCTL_HW_PARAMS: 2791 case SNDRV_PCM_IOCTL_HW_PARAMS:
@@ -2781,7 +2805,7 @@ static int snd_pcm_common_ioctl1(struct file *file,
2781 case SNDRV_PCM_IOCTL_RESET: 2805 case SNDRV_PCM_IOCTL_RESET:
2782 return snd_pcm_reset(substream); 2806 return snd_pcm_reset(substream);
2783 case SNDRV_PCM_IOCTL_START: 2807 case SNDRV_PCM_IOCTL_START:
2784 return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING); 2808 return snd_pcm_start_lock_irq(substream);
2785 case SNDRV_PCM_IOCTL_LINK: 2809 case SNDRV_PCM_IOCTL_LINK:
2786 return snd_pcm_link(substream, (int)(unsigned long) arg); 2810 return snd_pcm_link(substream, (int)(unsigned long) arg);
2787 case SNDRV_PCM_IOCTL_UNLINK: 2811 case SNDRV_PCM_IOCTL_UNLINK:
@@ -2793,7 +2817,16 @@ static int snd_pcm_common_ioctl1(struct file *file,
2793 case SNDRV_PCM_IOCTL_HWSYNC: 2817 case SNDRV_PCM_IOCTL_HWSYNC:
2794 return snd_pcm_hwsync(substream); 2818 return snd_pcm_hwsync(substream);
2795 case SNDRV_PCM_IOCTL_DELAY: 2819 case SNDRV_PCM_IOCTL_DELAY:
2796 return snd_pcm_delay(substream, arg); 2820 {
2821 snd_pcm_sframes_t delay = snd_pcm_delay(substream);
2822 snd_pcm_sframes_t __user *res = arg;
2823
2824 if (delay < 0)
2825 return delay;
2826 if (put_user(delay, res))
2827 return -EFAULT;
2828 return 0;
2829 }
2797 case SNDRV_PCM_IOCTL_SYNC_PTR: 2830 case SNDRV_PCM_IOCTL_SYNC_PTR:
2798 return snd_pcm_sync_ptr(substream, arg); 2831 return snd_pcm_sync_ptr(substream, arg);
2799#ifdef CONFIG_SND_SUPPORT_OLD_API 2832#ifdef CONFIG_SND_SUPPORT_OLD_API
@@ -2807,23 +2840,34 @@ static int snd_pcm_common_ioctl1(struct file *file,
2807 case SNDRV_PCM_IOCTL_DROP: 2840 case SNDRV_PCM_IOCTL_DROP:
2808 return snd_pcm_drop(substream); 2841 return snd_pcm_drop(substream);
2809 case SNDRV_PCM_IOCTL_PAUSE: 2842 case SNDRV_PCM_IOCTL_PAUSE:
2810 { 2843 return snd_pcm_action_lock_irq(&snd_pcm_action_pause,
2811 int res; 2844 substream,
2812 snd_pcm_stream_lock_irq(substream); 2845 (int)(unsigned long)arg);
2813 res = snd_pcm_pause(substream, (int)(unsigned long)arg);
2814 snd_pcm_stream_unlock_irq(substream);
2815 return res;
2816 }
2817 } 2846 }
2818 pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd); 2847 pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
2819 return -ENOTTY; 2848 return -ENOTTY;
2820} 2849}
2821 2850
2851static int snd_pcm_common_ioctl1(struct file *file,
2852 struct snd_pcm_substream *substream,
2853 unsigned int cmd, void __user *arg)
2854{
2855 struct snd_card *card = substream->pcm->card;
2856 int res;
2857
2858 snd_power_lock(card);
2859 res = snd_power_wait(card, SNDRV_CTL_POWER_D0);
2860 if (res >= 0)
2861 res = snd_pcm_common_ioctl(file, substream, cmd, arg);
2862 snd_power_unlock(card);
2863 return res;
2864}
2865
2822static int snd_pcm_playback_ioctl1(struct file *file, 2866static int snd_pcm_playback_ioctl1(struct file *file,
2823 struct snd_pcm_substream *substream, 2867 struct snd_pcm_substream *substream,
2824 unsigned int cmd, void __user *arg) 2868 unsigned int cmd, void __user *arg)
2825{ 2869{
2826 if (snd_BUG_ON(!substream)) 2870 if (PCM_RUNTIME_CHECK(substream))
2827 return -ENXIO; 2871 return -ENXIO;
2828 if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK)) 2872 if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
2829 return -EINVAL; 2873 return -EINVAL;
@@ -2903,7 +2947,7 @@ static int snd_pcm_capture_ioctl1(struct file *file,
2903 struct snd_pcm_substream *substream, 2947 struct snd_pcm_substream *substream,
2904 unsigned int cmd, void __user *arg) 2948 unsigned int cmd, void __user *arg)
2905{ 2949{
2906 if (snd_BUG_ON(!substream)) 2950 if (PCM_RUNTIME_CHECK(substream))
2907 return -ENXIO; 2951 return -ENXIO;
2908 if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE)) 2952 if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
2909 return -EINVAL; 2953 return -EINVAL;
@@ -3007,30 +3051,55 @@ static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
3007 (void __user *)arg); 3051 (void __user *)arg);
3008} 3052}
3009 3053
3054/**
3055 * snd_pcm_kernel_ioctl - Execute PCM ioctl in the kernel-space
3056 * @substream: PCM substream
3057 * @cmd: IOCTL cmd
3058 * @arg: IOCTL argument
3059 *
3060 * The function is provided primarily for OSS layer and USB gadget drivers,
3061 * and it allows only the limited set of ioctls (hw_params, sw_params,
3062 * prepare, start, drain, drop, forward).
3063 */
3010int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, 3064int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
3011 unsigned int cmd, void *arg) 3065 unsigned int cmd, void *arg)
3012{ 3066{
3013 mm_segment_t fs; 3067 snd_pcm_uframes_t *frames = arg;
3014 int result; 3068 snd_pcm_sframes_t result;
3015 3069
3016 fs = snd_enter_user(); 3070 switch (cmd) {
3017 switch (substream->stream) { 3071 case SNDRV_PCM_IOCTL_FORWARD:
3018 case SNDRV_PCM_STREAM_PLAYBACK: 3072 {
3019 result = snd_pcm_playback_ioctl1(NULL, substream, cmd, 3073 /* provided only for OSS; capture-only and no value returned */
3020 (void __user *)arg); 3074 if (substream->stream != SNDRV_PCM_STREAM_CAPTURE)
3021 break; 3075 return -EINVAL;
3022 case SNDRV_PCM_STREAM_CAPTURE: 3076 result = snd_pcm_capture_forward(substream, *frames);
3023 result = snd_pcm_capture_ioctl1(NULL, substream, cmd, 3077 return result < 0 ? result : 0;
3024 (void __user *)arg); 3078 }
3025 break; 3079 case SNDRV_PCM_IOCTL_HW_PARAMS:
3080 return snd_pcm_hw_params(substream, arg);
3081 case SNDRV_PCM_IOCTL_SW_PARAMS:
3082 return snd_pcm_sw_params(substream, arg);
3083 case SNDRV_PCM_IOCTL_PREPARE:
3084 return snd_pcm_prepare(substream, NULL);
3085 case SNDRV_PCM_IOCTL_START:
3086 return snd_pcm_start_lock_irq(substream);
3087 case SNDRV_PCM_IOCTL_DRAIN:
3088 return snd_pcm_drain(substream, NULL);
3089 case SNDRV_PCM_IOCTL_DROP:
3090 return snd_pcm_drop(substream);
3091 case SNDRV_PCM_IOCTL_DELAY:
3092 {
3093 result = snd_pcm_delay(substream);
3094 if (result < 0)
3095 return result;
3096 *frames = result;
3097 return 0;
3098 }
3026 default: 3099 default:
3027 result = -EINVAL; 3100 return -EINVAL;
3028 break;
3029 } 3101 }
3030 snd_leave_user(fs);
3031 return result;
3032} 3102}
3033
3034EXPORT_SYMBOL(snd_pcm_kernel_ioctl); 3103EXPORT_SYMBOL(snd_pcm_kernel_ioctl);
3035 3104
3036static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count, 3105static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
@@ -3314,10 +3383,41 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
3314 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP; 3383 area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
3315 return 0; 3384 return 0;
3316} 3385}
3386
3387static bool pcm_status_mmap_allowed(struct snd_pcm_file *pcm_file)
3388{
3389 if (pcm_file->no_compat_mmap)
3390 return false;
3391 /* See pcm_control_mmap_allowed() below.
3392 * Since older alsa-lib requires both status and control mmaps to be
3393 * coupled, we have to disable the status mmap for old alsa-lib, too.
3394 */
3395 if (pcm_file->user_pversion < SNDRV_PROTOCOL_VERSION(2, 0, 14) &&
3396 (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR))
3397 return false;
3398 return true;
3399}
3400
3401static bool pcm_control_mmap_allowed(struct snd_pcm_file *pcm_file)
3402{
3403 if (pcm_file->no_compat_mmap)
3404 return false;
3405 /* Disallow the control mmap when SYNC_APPLPTR flag is set;
3406 * it enforces the user-space to fall back to snd_pcm_sync_ptr(),
3407 * thus it effectively assures the manual update of appl_ptr.
3408 */
3409 if (pcm_file->substream->runtime->hw.info & SNDRV_PCM_INFO_SYNC_APPLPTR)
3410 return false;
3411 return true;
3412}
3413
3317#else /* ! coherent mmap */ 3414#else /* ! coherent mmap */
3318/* 3415/*
3319 * don't support mmap for status and control records. 3416 * don't support mmap for status and control records.
3320 */ 3417 */
3418#define pcm_status_mmap_allowed(pcm_file) false
3419#define pcm_control_mmap_allowed(pcm_file) false
3420
3321static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file, 3421static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
3322 struct vm_area_struct *area) 3422 struct vm_area_struct *area)
3323{ 3423{
@@ -3437,7 +3537,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
3437 area->vm_page_prot = pgprot_noncached(area->vm_page_prot); 3537 area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
3438 return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes); 3538 return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
3439} 3539}
3440
3441EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); 3540EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
3442#endif /* SNDRV_PCM_INFO_MMAP */ 3541#endif /* SNDRV_PCM_INFO_MMAP */
3443 3542
@@ -3486,7 +3585,6 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
3486 atomic_inc(&substream->mmap_count); 3585 atomic_inc(&substream->mmap_count);
3487 return err; 3586 return err;
3488} 3587}
3489
3490EXPORT_SYMBOL(snd_pcm_mmap_data); 3588EXPORT_SYMBOL(snd_pcm_mmap_data);
3491 3589
3492static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area) 3590static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
@@ -3503,11 +3601,11 @@ static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
3503 offset = area->vm_pgoff << PAGE_SHIFT; 3601 offset = area->vm_pgoff << PAGE_SHIFT;
3504 switch (offset) { 3602 switch (offset) {
3505 case SNDRV_PCM_MMAP_OFFSET_STATUS: 3603 case SNDRV_PCM_MMAP_OFFSET_STATUS:
3506 if (pcm_file->no_compat_mmap) 3604 if (!pcm_status_mmap_allowed(pcm_file))
3507 return -ENXIO; 3605 return -ENXIO;
3508 return snd_pcm_mmap_status(substream, file, area); 3606 return snd_pcm_mmap_status(substream, file, area);
3509 case SNDRV_PCM_MMAP_OFFSET_CONTROL: 3607 case SNDRV_PCM_MMAP_OFFSET_CONTROL:
3510 if (pcm_file->no_compat_mmap) 3608 if (!pcm_control_mmap_allowed(pcm_file))
3511 return -ENXIO; 3609 return -ENXIO;
3512 return snd_pcm_mmap_control(substream, file, area); 3610 return snd_pcm_mmap_control(substream, file, area);
3513 default: 3611 default:
@@ -3603,12 +3701,17 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
3603 } 3701 }
3604 snd_pcm_hw_convert_from_old_params(params, oparams); 3702 snd_pcm_hw_convert_from_old_params(params, oparams);
3605 err = snd_pcm_hw_refine(substream, params); 3703 err = snd_pcm_hw_refine(substream, params);
3606 snd_pcm_hw_convert_to_old_params(oparams, params); 3704 if (err < 0)
3607 if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { 3705 goto out_old;
3608 if (!err)
3609 err = -EFAULT;
3610 }
3611 3706
3707 err = fixup_unreferenced_params(substream, params);
3708 if (err < 0)
3709 goto out_old;
3710
3711 snd_pcm_hw_convert_to_old_params(oparams, params);
3712 if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
3713 err = -EFAULT;
3714out_old:
3612 kfree(oparams); 3715 kfree(oparams);
3613out: 3716out:
3614 kfree(params); 3717 kfree(params);
@@ -3631,14 +3734,16 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
3631 err = PTR_ERR(oparams); 3734 err = PTR_ERR(oparams);
3632 goto out; 3735 goto out;
3633 } 3736 }
3737
3634 snd_pcm_hw_convert_from_old_params(params, oparams); 3738 snd_pcm_hw_convert_from_old_params(params, oparams);
3635 err = snd_pcm_hw_params(substream, params); 3739 err = snd_pcm_hw_params(substream, params);
3636 snd_pcm_hw_convert_to_old_params(oparams, params); 3740 if (err < 0)
3637 if (copy_to_user(_oparams, oparams, sizeof(*oparams))) { 3741 goto out_old;
3638 if (!err)
3639 err = -EFAULT;
3640 }
3641 3742
3743 snd_pcm_hw_convert_to_old_params(oparams, params);
3744 if (copy_to_user(_oparams, oparams, sizeof(*oparams)))
3745 err = -EFAULT;
3746out_old:
3642 kfree(oparams); 3747 kfree(oparams);
3643out: 3748out:
3644 kfree(params); 3749 kfree(params);