pcm_native.c 104 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
/*
 *  Digital Audio (PCM) abstract layer
3
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
Linus Torvalds's avatar
Linus Torvalds committed
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
 *
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 */

#include <linux/mm.h>
23
#include <linux/module.h>
Linus Torvalds's avatar
Linus Torvalds committed
24 25
#include <linux/file.h>
#include <linux/slab.h>
26
#include <linux/sched/signal.h>
Linus Torvalds's avatar
Linus Torvalds committed
27
#include <linux/time.h>
28
#include <linux/pm_qos.h>
29
#include <linux/io.h>
30
#include <linux/dma-mapping.h>
Linus Torvalds's avatar
Linus Torvalds committed
31 32 33 34 35 36 37
#include <sound/core.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/timer.h>
#include <sound/minors.h>
38
#include <linux/uio.h>
Linus Torvalds's avatar
Linus Torvalds committed
39

40 41
#include "pcm_local.h"

42
#ifdef CONFIG_SND_DEBUG
43 44
#define CREATE_TRACE_POINTS
#include "pcm_param_trace.h"
45 46 47 48 49 50
#else
#define trace_hw_mask_param_enabled()		0
#define trace_hw_interval_param_enabled()	0
#define trace_hw_mask_param(substream, type, index, prev, curr)
#define trace_hw_interval_param(substream, type, index, prev, curr)
#endif
51

Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55
/*
 *  Compatibility
 */

56
struct snd_pcm_hw_params_old {
Linus Torvalds's avatar
Linus Torvalds committed
57 58 59
	unsigned int flags;
	unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
			   SNDRV_PCM_HW_PARAM_ACCESS + 1];
60
	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
Linus Torvalds's avatar
Linus Torvalds committed
61 62 63 64 65 66 67
					SNDRV_PCM_HW_PARAM_SAMPLE_BITS + 1];
	unsigned int rmask;
	unsigned int cmask;
	unsigned int info;
	unsigned int msbits;
	unsigned int rate_num;
	unsigned int rate_den;
68
	snd_pcm_uframes_t fifo_size;
Linus Torvalds's avatar
Linus Torvalds committed
69 70 71
	unsigned char reserved[64];
};

72
#ifdef CONFIG_SND_SUPPORT_OLD_API
73 74
#define SNDRV_PCM_IOCTL_HW_REFINE_OLD _IOWR('A', 0x10, struct snd_pcm_hw_params_old)
#define SNDRV_PCM_IOCTL_HW_PARAMS_OLD _IOWR('A', 0x11, struct snd_pcm_hw_params_old)
Linus Torvalds's avatar
Linus Torvalds committed
75

76 77 78 79
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams);
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams);
80
#endif
81
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
Linus Torvalds's avatar
Linus Torvalds committed
82 83 84 85 86

/*
 *
 */

87 88
static DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
Linus Torvalds's avatar
Linus Torvalds committed
89

90 91 92 93 94 95 96 97 98 99 100 101
/* Writer in rwsem may block readers even during its waiting in queue,
 * and this may lead to a deadlock when the code path takes read sem
 * twice (e.g. one in snd_pcm_action_nonatomic() and another in
 * snd_pcm_stream_lock()).  As a (suboptimal) workaround, let writer to
 * spin until it gets the lock.
 */
static inline void down_write_nonblock(struct rw_semaphore *lock)
{
	while (!down_write_trylock(lock))
		cond_resched();
}

102 103 104 105 106 107 108 109
/**
 * snd_pcm_stream_lock - Lock the PCM stream
 * @substream: PCM substream
 *
 * This locks the PCM stream's spinlock or mutex depending on the nonatomic
 * flag of the given substream.  This also takes the global link rw lock
 * (or rw sem), too, for avoiding the race with linked streams.
 */
110 111 112
void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
{
	if (substream->pcm->nonatomic) {
113
		down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
114 115 116 117 118 119 120 121
		mutex_lock(&substream->self_group.mutex);
	} else {
		read_lock(&snd_pcm_link_rwlock);
		spin_lock(&substream->self_group.lock);
	}
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);

122 123 124 125 126 127
/**
 * snd_pcm_stream_lock - Unlock the PCM stream
 * @substream: PCM substream
 *
 * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock().
 */
128 129 130 131 132 133 134 135 136 137 138 139
void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
{
	if (substream->pcm->nonatomic) {
		mutex_unlock(&substream->self_group.mutex);
		up_read(&snd_pcm_link_rwsem);
	} else {
		spin_unlock(&substream->self_group.lock);
		read_unlock(&snd_pcm_link_rwlock);
	}
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);

140 141 142 143 144 145 146 147
/**
 * snd_pcm_stream_lock_irq - Lock the PCM stream
 * @substream: PCM substream
 *
 * This locks the PCM stream like snd_pcm_stream_lock() and disables the local
 * IRQ (only when nonatomic is false).  In nonatomic case, this is identical
 * as snd_pcm_stream_lock().
 */
148 149 150 151 152 153 154 155
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
{
	if (!substream->pcm->nonatomic)
		local_irq_disable();
	snd_pcm_stream_lock(substream);
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);

156 157 158 159 160 161
/**
 * snd_pcm_stream_unlock_irq - Unlock the PCM stream
 * @substream: PCM substream
 *
 * This is a counter-part of snd_pcm_stream_lock_irq().
 */
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
{
	snd_pcm_stream_unlock(substream);
	if (!substream->pcm->nonatomic)
		local_irq_enable();
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq);

unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
{
	unsigned long flags = 0;
	if (!substream->pcm->nonatomic)
		local_irq_save(flags);
	snd_pcm_stream_lock(substream);
	return flags;
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);

180 181 182 183 184 185 186
/**
 * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
 * @substream: PCM substream
 * @flags: irq flags
 *
 * This is a counter-part of snd_pcm_stream_lock_irqsave().
 */
187 188 189 190 191 192 193 194
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
				      unsigned long flags)
{
	snd_pcm_stream_unlock(substream);
	if (!substream->pcm->nonatomic)
		local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore);
Linus Torvalds's avatar
Linus Torvalds committed
195

196
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
Linus Torvalds's avatar
Linus Torvalds committed
197
{
198 199 200
	struct snd_pcm_runtime *runtime;
	struct snd_pcm *pcm = substream->pcm;
	struct snd_pcm_str *pstr = substream->pstr;
Linus Torvalds's avatar
Linus Torvalds committed
201 202 203 204 205 206 207 208 209 210 211 212 213 214

	memset(info, 0, sizeof(*info));
	info->card = pcm->card->number;
	info->device = pcm->device;
	info->stream = substream->stream;
	info->subdevice = substream->number;
	strlcpy(info->id, pcm->id, sizeof(info->id));
	strlcpy(info->name, pcm->name, sizeof(info->name));
	info->dev_class = pcm->dev_class;
	info->dev_subclass = pcm->dev_subclass;
	info->subdevices_count = pstr->substream_count;
	info->subdevices_avail = pstr->substream_count - pstr->substream_opened;
	strlcpy(info->subname, substream->name, sizeof(info->subname));
	runtime = substream->runtime;
215

Linus Torvalds's avatar
Linus Torvalds committed
216 217 218
	return 0;
}

219 220
int snd_pcm_info_user(struct snd_pcm_substream *substream,
		      struct snd_pcm_info __user * _info)
Linus Torvalds's avatar
Linus Torvalds committed
221
{
222
	struct snd_pcm_info *info;
Linus Torvalds's avatar
Linus Torvalds committed
223 224 225 226 227 228 229 230 231 232 233 234 235 236
	int err;

	info = kmalloc(sizeof(*info), GFP_KERNEL);
	if (! info)
		return -ENOMEM;
	err = snd_pcm_info(substream, info);
	if (err >= 0) {
		if (copy_to_user(_info, info, sizeof(*info)))
			err = -EFAULT;
	}
	kfree(info);
	return err;
}

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{
	if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
		return false;
	/* check architectures that return -EINVAL from dma_mmap_coherent() */
	/* FIXME: this should be some global flag */
#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\
	defined(CONFIG_PARISC) || defined(CONFIG_XTENSA)
	if (!substream->ops->mmap &&
	    substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
		return false;
#endif
	return true;
}

252 253 254 255 256 257 258 259 260 261 262 263 264 265
static int constrain_mask_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params)
{
	struct snd_pcm_hw_constraints *constrs =
					&substream->runtime->hw_constraints;
	struct snd_mask *m;
	unsigned int k;
	struct snd_mask old_mask;
	int changed;

	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
		m = hw_param_mask(params, k);
		if (snd_mask_empty(m))
			return -EINVAL;
266 267

		/* This parameter is not requested to change by a caller. */
268 269 270 271 272 273 274
		if (!(params->rmask & (1 << k)))
			continue;

		if (trace_hw_mask_param_enabled())
			old_mask = *m;

		changed = snd_mask_refine(m, constrs_mask(constrs, k));
275 276
		if (changed < 0)
			return changed;
277 278
		if (changed == 0)
			continue;
279

280
		/* Set corresponding flag so that the caller gets it. */
281 282
		trace_hw_mask_param(substream, k, 0, &old_mask, m);
		params->cmask |= 1 << k;
283 284 285 286 287
	}

	return 0;
}

288 289 290 291 292 293 294 295 296 297 298 299 300 301
static int constrain_interval_params(struct snd_pcm_substream *substream,
				     struct snd_pcm_hw_params *params)
{
	struct snd_pcm_hw_constraints *constrs =
					&substream->runtime->hw_constraints;
	struct snd_interval *i;
	unsigned int k;
	struct snd_interval old_interval;
	int changed;

	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
		i = hw_param_interval(params, k);
		if (snd_interval_empty(i))
			return -EINVAL;
302 303

		/* This parameter is not requested to change by a caller. */
304 305 306 307 308 309 310
		if (!(params->rmask & (1 << k)))
			continue;

		if (trace_hw_interval_param_enabled())
			old_interval = *i;

		changed = snd_interval_refine(i, constrs_interval(constrs, k));
311 312
		if (changed < 0)
			return changed;
313 314
		if (changed == 0)
			continue;
315

316
		/* Set corresponding flag so that the caller gets it. */
317 318
		trace_hw_interval_param(substream, k, 0, &old_interval, i);
		params->cmask |= 1 << k;
319 320 321 322 323
	}

	return 0;
}

324 325
static int constrain_params_by_rules(struct snd_pcm_substream *substream,
				     struct snd_pcm_hw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
326
{
327 328
	struct snd_pcm_hw_constraints *constrs =
					&substream->runtime->hw_constraints;
Linus Torvalds's avatar
Linus Torvalds committed
329 330 331
	unsigned int k;
	unsigned int rstamps[constrs->rules_num];
	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
332
	unsigned int stamp;
333 334
	struct snd_pcm_hw_rule *r;
	unsigned int d;
335 336
	struct snd_mask old_mask;
	struct snd_interval old_interval;
337
	bool again;
338
	int changed;
Linus Torvalds's avatar
Linus Torvalds committed
339

340 341 342 343 344 345
	/*
	 * Each application of rule has own sequence number.
	 *
	 * Each member of 'rstamps' array represents the sequence number of
	 * recent application of corresponding rule.
	 */
Linus Torvalds's avatar
Linus Torvalds committed
346 347
	for (k = 0; k < constrs->rules_num; k++)
		rstamps[k] = 0;
348 349 350 351 352 353 354 355 356 357

	/*
	 * Each member of 'vstamps' array represents the sequence number of
	 * recent application of rule in which corresponding parameters were
	 * changed.
	 *
	 * In initial state, elements corresponding to parameters requested by
	 * a caller is 1. For unrequested parameters, corresponding members
	 * have 0 so that the parameters are never changed anymore.
	 */
358
	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
Linus Torvalds's avatar
Linus Torvalds committed
359
		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
360 361 362

	/* Due to the above design, actual sequence number starts at 2. */
	stamp = 2;
363
retry:
364
	/* Apply all rules in order. */
365
	again = false;
366
	for (k = 0; k < constrs->rules_num; k++) {
367
		r = &constrs->rules[k];
368 369 370 371 372 373 374

		/*
		 * Check condition bits of this rule. When the rule has
		 * some condition bits, parameter without the bits is
		 * never processed. SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP
		 * is an example of the condition bits.
		 */
375 376
		if (r->cond && !(r->cond & params->flags))
			continue;
377 378 379 380 381 382 383 384 385 386 387

		/*
		 * The 'deps' array includes maximum three dependencies
		 * to SNDRV_PCM_HW_PARAM_XXXs for this rule. The fourth
		 * member of this array is a sentinel and should be
		 * negative value.
		 *
		 * This rule should be processed in this time when dependent
		 * parameters were changed at former applications of the other
		 * rules.
		 */
388
		for (d = 0; r->deps[d] >= 0; d++) {
389
			if (vstamps[r->deps[d]] > rstamps[k])
390 391
				break;
		}
392
		if (r->deps[d] < 0)
393
			continue;
394

395 396 397 398 399 400 401 402
		if (trace_hw_mask_param_enabled()) {
			if (hw_is_mask(r->var))
				old_mask = *hw_param_mask(params, r->var);
		}
		if (trace_hw_interval_param_enabled()) {
			if (hw_is_interval(r->var))
				old_interval = *hw_param_interval(params, r->var);
		}
403

404
		changed = r->func(params, r);
405 406
		if (changed < 0)
			return changed;
407

408
		/*
409
		 * When the parameter is changed, notify it to the caller
410 411 412
		 * by corresponding returned bit, then preparing for next
		 * iteration.
		 */
413
		if (changed && r->var >= 0) {
414 415 416 417 418 419 420 421 422 423 424
			if (hw_is_mask(r->var)) {
				trace_hw_mask_param(substream, r->var,
					k + 1, &old_mask,
					hw_param_mask(params, r->var));
			}
			if (hw_is_interval(r->var)) {
				trace_hw_interval_param(substream, r->var,
					k + 1, &old_interval,
					hw_param_interval(params, r->var));
			}

425 426
			params->cmask |= (1 << r->var);
			vstamps[r->var] = stamp;
427
			again = true;
Linus Torvalds's avatar
Linus Torvalds committed
428
		}
429

430
		rstamps[k] = stamp++;
431 432
	}

433
	/* Iterate to evaluate all rules till no parameters are changed. */
434 435
	if (again)
		goto retry;
436 437 438 439

	return 0;
}

440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471
static int fixup_unreferenced_params(struct snd_pcm_substream *substream,
				     struct snd_pcm_hw_params *params)
{
	const struct snd_interval *i;
	const struct snd_mask *m;
	int err;

	if (!params->msbits) {
		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
		if (snd_interval_single(i))
			params->msbits = snd_interval_value(i);
	}

	if (!params->rate_den) {
		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
		if (snd_interval_single(i)) {
			params->rate_num = snd_interval_value(i);
			params->rate_den = 1;
		}
	}

	if (!params->fifo_size) {
		m = hw_param_mask_c(params, SNDRV_PCM_HW_PARAM_FORMAT);
		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
		if (snd_mask_single(m) && snd_interval_single(i)) {
			err = substream->ops->ioctl(substream,
					SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
			if (err < 0)
				return err;
		}
	}

472 473 474 475 476 477 478 479 480
	if (!params->info) {
		params->info = substream->runtime->hw.info;
		params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
				  SNDRV_PCM_INFO_DRAIN_TRIGGER);
		if (!hw_support_mmap(substream))
			params->info &= ~(SNDRV_PCM_INFO_MMAP |
					  SNDRV_PCM_INFO_MMAP_VALID);
	}

481 482 483
	return 0;
}

484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
		      struct snd_pcm_hw_params *params)
{
	int err;

	params->info = 0;
	params->fifo_size = 0;
	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_SAMPLE_BITS))
		params->msbits = 0;
	if (params->rmask & (1 << SNDRV_PCM_HW_PARAM_RATE)) {
		params->rate_num = 0;
		params->rate_den = 0;
	}

	err = constrain_mask_params(substream, params);
	if (err < 0)
		return err;

	err = constrain_interval_params(substream, params);
	if (err < 0)
		return err;

	err = constrain_params_by_rules(substream, params);
	if (err < 0)
		return err;

Linus Torvalds's avatar
Linus Torvalds committed
510
	params->rmask = 0;
511

Linus Torvalds's avatar
Linus Torvalds committed
512 513
	return 0;
}
514 515
EXPORT_SYMBOL(snd_pcm_hw_refine);

516 517
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
Linus Torvalds's avatar
Linus Torvalds committed
518
{
519
	struct snd_pcm_hw_params *params;
Linus Torvalds's avatar
Linus Torvalds committed
520 521
	int err;

522 523 524 525
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

Linus Torvalds's avatar
Linus Torvalds committed
526
	err = snd_pcm_hw_refine(substream, params);
527 528
	if (err < 0)
		goto end;
529

530 531 532 533 534 535 536
	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto end;

	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
Linus Torvalds's avatar
Linus Torvalds committed
537 538 539 540
	kfree(params);
	return err;
}

541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
static int period_to_usecs(struct snd_pcm_runtime *runtime)
{
	int usecs;

	if (! runtime->rate)
		return -1; /* invalid */

	/* take 75% of period time as the deadline */
	usecs = (750000 / runtime->rate) * runtime->period_size;
	usecs += ((750000 % runtime->rate) * runtime->period_size) /
		runtime->rate;

	return usecs;
}

556 557 558 559 560 561 562 563
static void snd_pcm_set_state(struct snd_pcm_substream *substream, int state)
{
	snd_pcm_stream_lock_irq(substream);
	if (substream->runtime->status->state != SNDRV_PCM_STATE_DISCONNECTED)
		substream->runtime->status->state = state;
	snd_pcm_stream_unlock_irq(substream);
}

564 565 566 567 568 569 570 571 572 573
static inline void snd_pcm_timer_notify(struct snd_pcm_substream *substream,
					int event)
{
#ifdef CONFIG_SND_PCM_TIMER
	if (substream->timer)
		snd_timer_notify(substream->timer, event,
					&substream->runtime->trigger_tstamp);
#endif
}

574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
/**
 * snd_pcm_hw_param_choose - choose a configuration defined by @params
 * @pcm: PCM instance
 * @params: the hw_params instance
 *
 * Choose one configuration from configuration space defined by @params.
 * The configuration chosen is that obtained fixing in this order:
 * first access, first format, first subformat, min channels,
 * min rate, min period time, max buffer size, min tick time
 *
 * Return: Zero if successful, or a negative error code on failure.
 */
static int snd_pcm_hw_params_choose(struct snd_pcm_substream *pcm,
				    struct snd_pcm_hw_params *params)
{
	static const int vars[] = {
		SNDRV_PCM_HW_PARAM_ACCESS,
		SNDRV_PCM_HW_PARAM_FORMAT,
		SNDRV_PCM_HW_PARAM_SUBFORMAT,
		SNDRV_PCM_HW_PARAM_CHANNELS,
		SNDRV_PCM_HW_PARAM_RATE,
		SNDRV_PCM_HW_PARAM_PERIOD_TIME,
		SNDRV_PCM_HW_PARAM_BUFFER_SIZE,
		SNDRV_PCM_HW_PARAM_TICK_TIME,
		-1
	};
	const int *v;
601 602
	struct snd_mask old_mask;
	struct snd_interval old_interval;
603
	int changed;
604 605

	for (v = vars; *v != -1; v++) {
606 607 608 609 610 611 612 613 614
		/* Keep old parameter to trace. */
		if (trace_hw_mask_param_enabled()) {
			if (hw_is_mask(*v))
				old_mask = *hw_param_mask(params, *v);
		}
		if (trace_hw_interval_param_enabled()) {
			if (hw_is_interval(*v))
				old_interval = *hw_param_interval(params, *v);
		}
615
		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
616
			changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
617
		else
618 619 620 621 622
			changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
		if (snd_BUG_ON(changed < 0))
			return changed;
		if (changed == 0)
			continue;
623

624
		/* Trace the changed parameter. */
625 626 627 628 629 630 631 632
		if (hw_is_mask(*v)) {
			trace_hw_mask_param(pcm, *v, 0, &old_mask,
					    hw_param_mask(params, *v));
		}
		if (hw_is_interval(*v)) {
			trace_hw_interval_param(pcm, *v, 0, &old_interval,
						hw_param_interval(params, *v));
		}
633
	}
634

635 636 637
	return 0;
}

638 639
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
640
{
641
	struct snd_pcm_runtime *runtime;
642
	int err, usecs;
Linus Torvalds's avatar
Linus Torvalds committed
643 644 645
	unsigned int bits;
	snd_pcm_uframes_t frames;

646 647
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
648 649 650 651 652 653 654 655 656 657 658 659
	runtime = substream->runtime;
	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_OPEN:
	case SNDRV_PCM_STATE_SETUP:
	case SNDRV_PCM_STATE_PREPARED:
		break;
	default:
		snd_pcm_stream_unlock_irq(substream);
		return -EBADFD;
	}
	snd_pcm_stream_unlock_irq(substream);
660
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Linus Torvalds's avatar
Linus Torvalds committed
661 662
	if (!substream->oss.oss)
#endif
663
		if (atomic_read(&substream->mmap_count))
Linus Torvalds's avatar
Linus Torvalds committed
664 665 666 667 668 669 670 671 672 673 674
			return -EBADFD;

	params->rmask = ~0U;
	err = snd_pcm_hw_refine(substream, params);
	if (err < 0)
		goto _error;

	err = snd_pcm_hw_params_choose(substream, params);
	if (err < 0)
		goto _error;

675 676 677 678
	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto _error;

Linus Torvalds's avatar
Linus Torvalds committed
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695
	if (substream->ops->hw_params != NULL) {
		err = substream->ops->hw_params(substream, params);
		if (err < 0)
			goto _error;
	}

	runtime->access = params_access(params);
	runtime->format = params_format(params);
	runtime->subformat = params_subformat(params);
	runtime->channels = params_channels(params);
	runtime->rate = params_rate(params);
	runtime->period_size = params_period_size(params);
	runtime->periods = params_periods(params);
	runtime->buffer_size = params_buffer_size(params);
	runtime->info = params->info;
	runtime->rate_num = params->rate_num;
	runtime->rate_den = params->rate_den;
696 697 698
	runtime->no_period_wakeup =
			(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
			(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
Linus Torvalds's avatar
Linus Torvalds committed
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719

	bits = snd_pcm_format_physical_width(runtime->format);
	runtime->sample_bits = bits;
	bits *= runtime->channels;
	runtime->frame_bits = bits;
	frames = 1;
	while (bits % 8 != 0) {
		bits *= 2;
		frames *= 2;
	}
	runtime->byte_align = bits / 8;
	runtime->min_align = frames;

	/* Default sw params */
	runtime->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
	runtime->period_step = 1;
	runtime->control->avail_min = runtime->period_size;
	runtime->start_threshold = 1;
	runtime->stop_threshold = runtime->buffer_size;
	runtime->silence_threshold = 0;
	runtime->silence_size = 0;
720 721 722
	runtime->boundary = runtime->buffer_size;
	while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
		runtime->boundary *= 2;
Linus Torvalds's avatar
Linus Torvalds committed
723 724

	snd_pcm_timer_resolution_change(substream);
725
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
726

727 728
	if (pm_qos_request_active(&substream->latency_pm_qos_req))
		pm_qos_remove_request(&substream->latency_pm_qos_req);
729
	if ((usecs = period_to_usecs(runtime)) >= 0)
730 731
		pm_qos_add_request(&substream->latency_pm_qos_req,
				   PM_QOS_CPU_DMA_LATENCY, usecs);
Linus Torvalds's avatar
Linus Torvalds committed
732 733
	return 0;
 _error:
734
	/* hardware might be unusable from this time,
Linus Torvalds's avatar
Linus Torvalds committed
735 736
	   so we force application to retry to set
	   the correct hardware parameter settings */
737
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
Linus Torvalds's avatar
Linus Torvalds committed
738 739 740 741 742
	if (substream->ops->hw_free != NULL)
		substream->ops->hw_free(substream);
	return err;
}

743 744
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
Linus Torvalds's avatar
Linus Torvalds committed
745
{
746
	struct snd_pcm_hw_params *params;
Linus Torvalds's avatar
Linus Torvalds committed
747 748
	int err;

749 750 751 752
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

Linus Torvalds's avatar
Linus Torvalds committed
753
	err = snd_pcm_hw_params(substream, params);
754 755
	if (err < 0)
		goto end;
756

757 758 759
	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
Linus Torvalds's avatar
Linus Torvalds committed
760 761 762 763
	kfree(params);
	return err;
}

764
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
765
{
766
	struct snd_pcm_runtime *runtime;
Linus Torvalds's avatar
Linus Torvalds committed
767 768
	int result = 0;

769 770
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
771 772 773 774 775 776 777 778 779 780 781
	runtime = substream->runtime;
	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_SETUP:
	case SNDRV_PCM_STATE_PREPARED:
		break;
	default:
		snd_pcm_stream_unlock_irq(substream);
		return -EBADFD;
	}
	snd_pcm_stream_unlock_irq(substream);
782
	if (atomic_read(&substream->mmap_count))
Linus Torvalds's avatar
Linus Torvalds committed
783 784 785
		return -EBADFD;
	if (substream->ops->hw_free)
		result = substream->ops->hw_free(substream);
786
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
787
	pm_qos_remove_request(&substream->latency_pm_qos_req);
Linus Torvalds's avatar
Linus Torvalds committed
788 789 790
	return result;
}

791 792
static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_sw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
793
{
794
	struct snd_pcm_runtime *runtime;
795
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
796

797 798
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
799 800 801 802 803 804 805 806
	runtime = substream->runtime;
	snd_pcm_stream_lock_irq(substream);
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
		snd_pcm_stream_unlock_irq(substream);
		return -EBADFD;
	}
	snd_pcm_stream_unlock_irq(substream);

807 808
	if (params->tstamp_mode < 0 ||
	    params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
Linus Torvalds's avatar
Linus Torvalds committed
809
		return -EINVAL;
810 811
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
	    params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
812
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
813 814 815 816 817 818 819 820 821 822 823
	if (params->avail_min == 0)
		return -EINVAL;
	if (params->silence_size >= runtime->boundary) {
		if (params->silence_threshold != 0)
			return -EINVAL;
	} else {
		if (params->silence_size > params->silence_threshold)
			return -EINVAL;
		if (params->silence_threshold > runtime->buffer_size)
			return -EINVAL;
	}
824
	err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
825 826
	snd_pcm_stream_lock_irq(substream);
	runtime->tstamp_mode = params->tstamp_mode;
827 828
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
		runtime->tstamp_type = params->tstamp_type;
Linus Torvalds's avatar
Linus Torvalds committed
829 830 831 832 833 834 835 836 837 838 839
	runtime->period_step = params->period_step;
	runtime->control->avail_min = params->avail_min;
	runtime->start_threshold = params->start_threshold;
	runtime->stop_threshold = params->stop_threshold;
	runtime->silence_threshold = params->silence_threshold;
	runtime->silence_size = params->silence_size;
        params->boundary = runtime->boundary;
	if (snd_pcm_running(substream)) {
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
		    runtime->silence_size > 0)
			snd_pcm_playback_silence(substream, ULONG_MAX);
840
		err = snd_pcm_update_state(substream, runtime);
Linus Torvalds's avatar
Linus Torvalds committed
841 842
	}
	snd_pcm_stream_unlock_irq(substream);
843
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
844 845
}

846 847
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_sw_params __user * _params)
Linus Torvalds's avatar
Linus Torvalds committed
848
{
849
	struct snd_pcm_sw_params params;
Linus Torvalds's avatar
Linus Torvalds committed
850 851 852 853 854 855 856 857 858
	int err;
	if (copy_from_user(&params, _params, sizeof(params)))
		return -EFAULT;
	err = snd_pcm_sw_params(substream, &params);
	if (copy_to_user(_params, &params, sizeof(params)))
		return -EFAULT;
	return err;
}

859 860
int snd_pcm_status(struct snd_pcm_substream *substream,
		   struct snd_pcm_status *status)
Linus Torvalds's avatar
Linus Torvalds committed
861
{
862
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
863 864

	snd_pcm_stream_lock_irq(substream);
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881

	snd_pcm_unpack_audio_tstamp_config(status->audio_tstamp_data,
					&runtime->audio_tstamp_config);

	/* backwards compatible behavior */
	if (runtime->audio_tstamp_config.type_requested ==
		SNDRV_PCM_AUDIO_TSTAMP_TYPE_COMPAT) {
		if (runtime->hw.info & SNDRV_PCM_INFO_HAS_WALL_CLOCK)
			runtime->audio_tstamp_config.type_requested =
				SNDRV_PCM_AUDIO_TSTAMP_TYPE_LINK;
		else
			runtime->audio_tstamp_config.type_requested =
				SNDRV_PCM_AUDIO_TSTAMP_TYPE_DEFAULT;
		runtime->audio_tstamp_report.valid = 0;
	} else
		runtime->audio_tstamp_report.valid = 1;

Linus Torvalds's avatar
Linus Torvalds committed
882 883 884 885 886
	status->state = runtime->status->state;
	status->suspended_state = runtime->status->suspended_state;
	if (status->state == SNDRV_PCM_STATE_OPEN)
		goto _end;
	status->trigger_tstamp = runtime->trigger_tstamp;
887
	if (snd_pcm_running(substream)) {
Linus Torvalds's avatar
Linus Torvalds committed
888
		snd_pcm_update_hw_ptr(substream);
889 890
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
			status->tstamp = runtime->status->tstamp;
891
			status->driver_tstamp = runtime->driver_tstamp;
892 893
			status->audio_tstamp =
				runtime->status->audio_tstamp;
894 895 896 897 898 899
			if (runtime->audio_tstamp_report.valid == 1)
				/* backwards compatibility, no report provided in COMPAT mode */
				snd_pcm_pack_audio_tstamp_report(&status->audio_tstamp_data,
								&status->audio_tstamp_accuracy,
								&runtime->audio_tstamp_report);

900 901
			goto _tstamp_end;
		}
902 903 904 905
	} else {
		/* get tstamp only in fallback mode and only if enabled */
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
			snd_pcm_gettime(runtime, &status->tstamp);
906 907
	}
 _tstamp_end:
Linus Torvalds's avatar
Linus Torvalds committed
908 909 910 911 912
	status->appl_ptr = runtime->control->appl_ptr;
	status->hw_ptr = runtime->status->hw_ptr;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		status->avail = snd_pcm_playback_avail(runtime);
		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
913
		    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
Linus Torvalds's avatar
Linus Torvalds committed
914
			status->delay = runtime->buffer_size - status->avail;
915 916
			status->delay += runtime->delay;
		} else
Linus Torvalds's avatar
Linus Torvalds committed
917 918 919 920
			status->delay = 0;
	} else {
		status->avail = snd_pcm_capture_avail(runtime);
		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
921
			status->delay = status->avail + runtime->delay;
Linus Torvalds's avatar
Linus Torvalds committed
922 923 924 925 926 927 928 929 930 931 932 933
		else
			status->delay = 0;
	}
	status->avail_max = runtime->avail_max;
	status->overrange = runtime->overrange;
	runtime->avail_max = 0;
	runtime->overrange = 0;
 _end:
 	snd_pcm_stream_unlock_irq(substream);
	return 0;
}

934
static int snd_pcm_status_user(struct snd_pcm_substream *substream,
935 936
			       struct snd_pcm_status __user * _status,
			       bool ext)
Linus Torvalds's avatar
Linus Torvalds committed
937
{
938
	struct snd_pcm_status status;
Linus Torvalds's avatar
Linus Torvalds committed
939
	int res;
940

Linus Torvalds's avatar
Linus Torvalds committed
941
	memset(&status, 0, sizeof(status));
942 943 944 945 946 947 948 949
	/*
	 * with extension, parameters are read/write,
	 * get audio_tstamp_data from user,
	 * ignore rest of status structure
	 */
	if (ext && get_user(status.audio_tstamp_data,
				(u32 __user *)(&_status->audio_tstamp_data)))
		return -EFAULT;
Linus Torvalds's avatar
Linus Torvalds committed
950 951 952 953 954 955 956 957
	res = snd_pcm_status(substream, &status);
	if (res < 0)
		return res;
	if (copy_to_user(_status, &status, sizeof(status)))
		return -EFAULT;
	return 0;
}

958 959
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
				struct snd_pcm_channel_info * info)
Linus Torvalds's avatar
Linus Torvalds committed
960
{
961
	struct snd_pcm_runtime *runtime;
Linus Torvalds's avatar
Linus Torvalds committed
962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
	unsigned int channel;
	
	channel = info->channel;
	runtime = substream->runtime;
	snd_pcm_stream_lock_irq(substream);
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN) {
		snd_pcm_stream_unlock_irq(substream);
		return -EBADFD;
	}
	snd_pcm_stream_unlock_irq(substream);
	if (channel >= runtime->channels)
		return -EINVAL;
	memset(info, 0, sizeof(*info));
	info->channel = channel;
	return substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_CHANNEL_INFO, info);
}

979 980
static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
				     struct snd_pcm_channel_info __user * _info)
Linus Torvalds's avatar
Linus Torvalds committed
981
{
982
	struct snd_pcm_channel_info info;
Linus Torvalds's avatar
Linus Torvalds committed
983 984 985 986 987 988 989 990 991 992 993 994
	int res;
	
	if (copy_from_user(&info, _info, sizeof(info)))
		return -EFAULT;
	res = snd_pcm_channel_info(substream, &info);
	if (res < 0)
		return res;
	if (copy_to_user(_info, &info, sizeof(info)))
		return -EFAULT;
	return 0;
}

995
static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
996
{
997
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
998 999 1000
	if (runtime->trigger_master == NULL)
		return;
	if (runtime->trigger_master == substream) {
1001 1002
		if (!runtime->trigger_tstamp_latched)
			snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
Linus Torvalds's avatar
Linus Torvalds committed
1003 1004 1005 1006 1007 1008 1009 1010
	} else {
		snd_pcm_trigger_tstamp(runtime->trigger_master);
		runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
	}
	runtime->trigger_master = NULL;
}

struct action_ops {
1011 1012 1013 1014
	int (*pre_action)(struct snd_pcm_substream *substream, int state);
	int (*do_action)(struct snd_pcm_substream *substream, int state);
	void (*undo_action)(struct snd_pcm_substream *substream, int state);
	void (*post_action)(struct snd_pcm_substream *substream, int state);
Linus Torvalds's avatar
Linus Torvalds committed
1015 1016 1017 1018 1019 1020 1021
};

/*
 *  this functions is core for handling of linked stream
 *  Note: the stream state might be changed also on failure
 *  Note2: call with calling stream lock + link lock
 */
1022
static int snd_pcm_action_group(const struct action_ops *ops,
1023
				struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1024 1025
				int state, int do_lock)
{
1026 1027
	struct snd_pcm_substream *s = NULL;
	struct snd_pcm_substream *s1;
1028
	int res = 0, depth = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1029

1030
	snd_pcm_group_for_each_entry(s, substream) {
1031 1032
		if (do_lock && s != substream) {
			if (s->pcm->nonatomic)
1033
				mutex_lock_nested(&s->self_group.mutex, depth);
1034
			else
1035 1036
				spin_lock_nested(&s->self_group.lock, depth);
			depth++;
1037
		}
Linus Torvalds's avatar
Linus Torvalds committed
1038 1039 1040 1041
		res = ops->pre_action(s, state);
		if (res < 0)
			goto _unlock;
	}
1042
	snd_pcm_group_for_each_entry(s, substream) {
Linus Torvalds's avatar
Linus Torvalds committed
1043 1044 1045
		res = ops->do_action(s, state);
		if (res < 0) {
			if (ops->undo_action) {
1046
				snd_pcm_group_for_each_entry(s1, substream) {
Linus Torvalds's avatar
Linus Torvalds committed
1047 1048 1049 1050 1051 1052 1053 1054 1055
					if (s1 == s) /* failed stream */
						break;
					ops->undo_action(s1, state);
				}
			}
			s = NULL; /* unlock all */
			goto _unlock;
		}
	}
1056
	snd_pcm_group_for_each_entry(s, substream) {
Linus Torvalds's avatar
Linus Torvalds committed
1057 1058 1059 1060 1061
		ops->post_action(s, state);
	}
 _unlock:
	if (do_lock) {
		/* unlock streams */
1062
		snd_pcm_group_for_each_entry(s1, substream) {
1063
			if (s1 != substream) {
1064
				if (s1->pcm->nonatomic)
1065 1066 1067 1068
					mutex_unlock(&s1->self_group.mutex);
				else
					spin_unlock(&s1->self_group.lock);
			}
Linus Torvalds's avatar
Linus Torvalds committed
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078
			if (s1 == s)	/* end */
				break;
		}
	}
	return res;
}

/*
 *  Note: call with stream lock
 */
1079
static int snd_pcm_action_single(const struct action_ops *ops,
1080
				 struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095
				 int state)
{
	int res;
	
	res = ops->pre_action(substream, state);
	if (res < 0)
		return res;
	res = ops->do_action(substream, state);
	if (res == 0)
		ops->post_action(substream, state);
	else if (ops->undo_action)
		ops->undo_action(substream, state);
	return res;
}

1096 1097 1098
/*
 *  Note: call with stream lock
 */
1099
static int snd_pcm_action(const struct action_ops *ops,
1100 1101
			  struct snd_pcm_substream *substream,
			  int state)
1102 1103 1104
{
	int res;

1105 1106 1107 1108
	if (!snd_pcm_stream_linked(substream))
		return snd_pcm_action_single(ops, substream, state);

	if (substream->pcm->nonatomic) {
1109 1110 1111 1112 1113 1114 1115 1116
		if (!mutex_trylock(&substream->group->mutex)) {
			mutex_unlock(&substream->self_group.mutex);
			mutex_lock(&substream->group->mutex);
			mutex_lock(&substream->self_group.mutex);
		}
		res = snd_pcm_action_group(ops, substream, state, 1);
		mutex_unlock(&substream->group->mutex);
	} else {
Linus Torvalds's avatar
Linus Torvalds committed
1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130
		if (!spin_trylock(&substream->group->lock)) {
			spin_unlock(&substream->self_group.lock);
			spin_lock(&substream->group->lock);
			spin_lock(&substream->self_group.lock);
		}
		res = snd_pcm_action_group(ops, substream, state, 1);
		spin_unlock(&substream->group->lock);
	}
	return res;
}

/*
 *  Note: don't use any locks before
 */
1131
static int snd_pcm_action_lock_irq(const struct action_ops *ops,
1132
				   struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1133 1134 1135 1136
				   int state)
{
	int res;

1137 1138 1139
	snd_pcm_stream_lock_irq(substream);
	res = snd_pcm_action(ops, substream, state);
	snd_pcm_stream_unlock_irq(substream);
Linus Torvalds's avatar
Linus Torvalds committed
1140 1141 1142 1143 1144
	return res;
}

/*
 */
1145
static int snd_pcm_action_nonatomic(const struct action_ops *ops,
1146
				    struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
				    int state)
{
	int res;

	down_read(&snd_pcm_link_rwsem);
	if (snd_pcm_stream_linked(substream))
		res = snd_pcm_action_group(ops, substream, state, 0);
	else
		res = snd_pcm_action_single(ops, substream, state);
	up_read(&snd_pcm_link_rwsem);
	return res;
}

/*
 * start callbacks
 */
1163
static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1164
{
1165
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1166 1167 1168 1169 1170
	if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
		return -EBADFD;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    !snd_pcm_playback_data(substream))
		return -EPIPE;
1171
	runtime->trigger_tstamp_latched = false;
Linus Torvalds's avatar
Linus Torvalds committed
1172 1173 1174 1175
	runtime->trigger_master = substream;
	return 0;
}

1176
static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1177 1178 1179 1180 1181 1182
{
	if (substream->runtime->trigger_master != substream)
		return 0;
	return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
}

1183
static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1184 1185 1186 1187 1188
{
	if (substream->runtime->trigger_master == substream)
		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
}

1189
static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1190
{
1191
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1192
	snd_pcm_trigger_tstamp(substream);
1193
	runtime->hw_ptr_jiffies = jiffies;
1194 1195
	runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
							    runtime->rate;
Linus Torvalds's avatar
Linus Torvalds committed
1196 1197 1198 1199
	runtime->status->state = state;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
		snd_pcm_playback_silence(substream, ULONG_MAX);
1200
	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
Linus Torvalds's avatar
Linus Torvalds committed
1201 1202
}

1203
static const struct action_ops snd_pcm_action_start = {
Linus Torvalds's avatar
Linus Torvalds committed
1204 1205 1206 1207 1208 1209 1210
	.pre_action = snd_pcm_pre_start,
	.do_action = snd_pcm_do_start,
	.undo_action = snd_pcm_undo_start,
	.post_action = snd_pcm_post_start
};

/**
1211
 * snd_pcm_start - start all linked streams
1212
 * @substream: the PCM substream instance
1213 1214
 *
 * Return: Zero if successful, or a negative error code.
1215
 * The stream lock must be acquired before calling this function.
Linus Torvalds's avatar
Linus Torvalds committed
1216
 */
1217
int snd_pcm_start(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
1218
{
1219 1220
	return snd_pcm_action(&snd_pcm_action_start, substream,
			      SNDRV_PCM_STATE_RUNNING);
Linus Torvalds's avatar
Linus Torvalds committed
1221 1222
}

1223 1224 1225 1226 1227 1228 1229
/* take the stream lock and start the streams */
static int snd_pcm_start_lock_irq(struct snd_pcm_substream *substream)
{
	return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream,
				       SNDRV_PCM_STATE_RUNNING);
}

Linus Torvalds's avatar
Linus Torvalds committed
1230 1231 1232
/*
 * stop callbacks
 */
1233
static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1234
{
1235
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1236 1237 1238 1239 1240 1241
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	runtime->trigger_master = substream;
	return 0;
}

1242
static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1243 1244 1245 1246 1247 1248 1249
{
	if (substream->runtime->trigger_master == substream &&
	    snd_pcm_running(substream))
		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
	return 0; /* unconditonally stop all substreams */
}

1250
static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1251
{
1252
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1253 1254
	if (runtime->status->state != state) {
		snd_pcm_trigger_tstamp(substream);
1255
		runtime->status->state = state;
1256
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
Linus Torvalds's avatar
Linus Torvalds committed
1257 1258
	}
	wake_up(&runtime->sleep);
1259
	wake_up(&runtime->tsleep);
Linus Torvalds's avatar
Linus Torvalds committed
1260 1261
}

1262
static const struct action_ops snd_pcm_action_stop = {
Linus Torvalds's avatar
Linus Torvalds committed
1263 1264 1265 1266 1267 1268
	.pre_action = snd_pcm_pre_stop,
	.do_action = snd_pcm_do_stop,
	.post_action = snd_pcm_post_stop
};

/**
1269
 * snd_pcm_stop - try to stop all running streams in the substream group
1270 1271
 * @substream: the PCM substream instance
 * @state: PCM state after stopping the stream
Linus Torvalds's avatar
Linus Torvalds committed
1272
 *
1273
 * The state of each stream is then changed to the given state unconditionally.
1274
 *
1275
 * Return: Zero if successful, or a negative error code.
Linus Torvalds's avatar
Linus Torvalds committed
1276
 */
1277
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
Linus Torvalds's avatar
Linus Torvalds committed
1278 1279 1280 1281
{
	return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}

1282 1283
EXPORT_SYMBOL(snd_pcm_stop);

Linus Torvalds's avatar
Linus Torvalds committed
1284
/**
1285
 * snd_pcm_drain_done - stop the DMA only when the given stream is playback
1286
 * @substream: the PCM substream
Linus Torvalds's avatar
Linus Torvalds committed
1287
 *
1288
 * After stopping, the state is changed to SETUP.
Linus Torvalds's avatar
Linus Torvalds committed
1289
 * Unlike snd_pcm_stop(), this affects only the given stream.
1290 1291
 *
 * Return: Zero if succesful, or a negative error code.
Linus Torvalds's avatar
Linus Torvalds committed
1292
 */
1293
int snd_pcm_drain_done(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
1294
{
1295 1296
	return snd_pcm_action_single(&snd_pcm_action_stop, substream,
				     SNDRV_PCM_STATE_SETUP);
Linus Torvalds's avatar
Linus Torvalds committed
1297 1298
}

1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320
/**
 * snd_pcm_stop_xrun - stop the running streams as XRUN
 * @substream: the PCM substream instance
 *
 * This stops the given running substream (and all linked substreams) as XRUN.
 * Unlike snd_pcm_stop(), this function takes the substream lock by itself.
 *
 * Return: Zero if successful, or a negative error code.
 */
int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
{
	unsigned long flags;
	int ret = 0;

	snd_pcm_stream_lock_irqsave(substream, flags);
	if (snd_pcm_running(substream))
		ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
	snd_pcm_stream_unlock_irqrestore(substream, flags);
	return ret;
}
EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);

Linus Torvalds's avatar
Linus Torvalds committed
1321 1322 1323
/*
 * pause callbacks
 */
1324
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1325
{
1326
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
	if (!(runtime->info & SNDRV_PCM_INFO_PAUSE))
		return -ENOSYS;
	if (push) {
		if (runtime->status->state != SNDRV_PCM_STATE_RUNNING)
			return -EBADFD;
	} else if (runtime->status->state != SNDRV_PCM_STATE_PAUSED)
		return -EBADFD;
	runtime->trigger_master = substream;
	return 0;
}

1338
static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1339 1340 1341
{
	if (substream->runtime->trigger_master != substream)
		return 0;
1342 1343 1344 1345
	/* some drivers might use hw_ptr to recover from the pause -
	   update the hw_ptr now */
	if (push)
		snd_pcm_update_hw_ptr(substream);
1346
	/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
1347
	 * a delta between the current jiffies, this gives a large enough
1348 1349 1350
	 * delta, effectively to skip the check once.
	 */
	substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
Linus Torvalds's avatar
Linus Torvalds committed
1351 1352 1353 1354 1355
	return substream->ops->trigger(substream,
				       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
					      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
}

1356
static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1357 1358 1359 1360 1361 1362 1363
{
	if (substream->runtime->trigger_master == substream)
		substream->ops->trigger(substream,
					push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
					SNDRV_PCM_TRIGGER_PAUSE_PUSH);
}

1364
static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1365
{
1366
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1367 1368 1369
	snd_pcm_trigger_tstamp(substream);
	if (push) {
		runtime->status->state = SNDRV_PCM_STATE_PAUSED;
1370
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE);
Linus Torvalds's avatar
Linus Torvalds committed
1371
		wake_up(&runtime->sleep);
1372
		wake_up(&runtime->tsleep);
Linus Torvalds's avatar
Linus Torvalds committed
1373 1374
	} else {
		runtime->status->state = SNDRV_PCM_STATE_RUNNING;
1375
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE);
Linus Torvalds's avatar
Linus Torvalds committed
1376 1377 1378
	}
}

1379
static const struct action_ops snd_pcm_action_pause = {
Linus Torvalds's avatar
Linus Torvalds committed
1380 1381 1382 1383 1384 1385 1386 1387 1388
	.pre_action = snd_pcm_pre_pause,
	.do_action = snd_pcm_do_pause,
	.undo_action = snd_pcm_undo_pause,
	.post_action = snd_pcm_post_pause
};

/*
 * Push/release the pause for all linked streams.
 */
1389
static int snd_pcm_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1390 1391 1392 1393 1394 1395 1396
{
	return snd_pcm_action(&snd_pcm_action_pause, substream, push);
}

#ifdef CONFIG_PM
/* suspend */

1397
static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1398
{
1399
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1400 1401 1402 1403 1404 1405
	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
		return -EBUSY;
	runtime->trigger_master = substream;
	return 0;
}

1406
static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1407
{
1408
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1409 1410 1411 1412 1413 1414 1415 1416
	if (runtime->trigger_master != substream)
		return 0;
	if (! snd_pcm_running(substream))
		return 0;
	substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
	return 0; /* suspend unconditionally */
}

1417
static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1418
{
1419
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1420
	snd_pcm_trigger_tstamp(substream);
1421 1422
	runtime->status->suspended_state = runtime->status->state;
	runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
1423
	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND);
Linus Torvalds's avatar
Linus Torvalds committed
1424
	wake_up(&runtime->sleep);
1425
	wake_up(&runtime->tsleep);
Linus Torvalds's avatar
Linus Torvalds committed
1426 1427
}

1428
static const struct action_ops snd_pcm_action_suspend = {
Linus Torvalds's avatar
Linus Torvalds committed
1429 1430 1431 1432 1433 1434
	.pre_action = snd_pcm_pre_suspend,
	.do_action = snd_pcm_do_suspend,
	.post_action = snd_pcm_post_suspend
};

/**
1435
 * snd_pcm_suspend - trigger SUSPEND to all linked streams
1436
 * @substream: the PCM substream
Linus Torvalds's avatar
Linus Torvalds committed
1437 1438
 *
 * After this call, all streams are changed to SUSPENDED state.
1439 1440 1441
 *
 * Return: Zero if successful (or @substream is %NULL), or a negative error
 * code.
Linus Torvalds's avatar
Linus Torvalds committed
1442
 */
1443
int snd_pcm_suspend(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
1444 1445 1446 1447
{
	int err;
	unsigned long flags;

1448 1449 1450
	if (! substream)
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
1451 1452 1453 1454 1455 1456
	snd_pcm_stream_lock_irqsave(substream, flags);
	err = snd_pcm_action(&snd_pcm_action_suspend, substream, 0);
	snd_pcm_stream_unlock_irqrestore(substream, flags);
	return err;
}

1457 1458
EXPORT_SYMBOL(snd_pcm_suspend);

Linus Torvalds's avatar
Linus Torvalds committed
1459
/**
1460
 * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm
1461
 * @pcm: the PCM instance
Linus Torvalds's avatar
Linus Torvalds committed
1462 1463
 *
 * After this call, all streams are changed to SUSPENDED state.
1464 1465
 *
 * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
Linus Torvalds's avatar
Linus Torvalds committed
1466
 */
1467
int snd_pcm_suspend_all(struct snd_pcm *pcm)
Linus Torvalds's avatar
Linus Torvalds committed
1468
{
1469
	struct snd_pcm_substream *substream;
Linus Torvalds's avatar
Linus Torvalds committed
1470 1471
	int stream, err = 0;

1472 1473 1474
	if (! pcm)
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
1475
	for (stream = 0; stream < 2; stream++) {
1476 1477
		for (substream = pcm->streams[stream].substream;
		     substream; substream = substream->next) {
Linus Torvalds's avatar
Linus Torvalds committed
1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488
			/* FIXME: the open/close code should lock this as well */
			if (substream->runtime == NULL)
				continue;
			err = snd_pcm_suspend(substream);
			if (err < 0 && err != -EBUSY)
				return err;
		}
	}
	return 0;
}

Takashi Iwai's avatar