pcm_native.c 103 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
	struct snd_pcm *pcm = substream->pcm;
	struct snd_pcm_str *pstr = substream->pstr;
Linus Torvalds's avatar
Linus Torvalds committed
200 201 202 203 204 205 206 207 208 209 210 211 212

	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));
213

Linus Torvalds's avatar
Linus Torvalds committed
214 215 216
	return 0;
}

217 218
int snd_pcm_info_user(struct snd_pcm_substream *substream,
		      struct snd_pcm_info __user * _info)
Linus Torvalds's avatar
Linus Torvalds committed
219
{
220
	struct snd_pcm_info *info;
Linus Torvalds's avatar
Linus Torvalds committed
221 222 223 224 225 226 227 228 229 230 231 232 233 234
	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;
}

235 236 237 238
static bool hw_support_mmap(struct snd_pcm_substream *substream)
{
	if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
		return false;
239 240
	/* architecture supports dma_mmap_coherent()? */
#if defined(CONFIG_ARCH_NO_COHERENT_DMA_MMAP) || !defined(CONFIG_HAS_DMA)
241 242 243 244 245 246 247
	if (!substream->ops->mmap &&
	    substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
		return false;
#endif
	return true;
}

248 249
static int constrain_mask_params(struct snd_pcm_substream *substream,
				 struct snd_pcm_hw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
250
{
251 252 253
	struct snd_pcm_hw_constraints *constrs =
					&substream->runtime->hw_constraints;
	struct snd_mask *m;
Linus Torvalds's avatar
Linus Torvalds committed
254
	unsigned int k;
255 256
	struct snd_mask old_mask;
	int changed;
Linus Torvalds's avatar
Linus Torvalds committed
257 258 259 260 261

	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;
262 263

		/* This parameter is not requested to change by a caller. */
Linus Torvalds's avatar
Linus Torvalds committed
264 265
		if (!(params->rmask & (1 << k)))
			continue;
266 267 268 269

		if (trace_hw_mask_param_enabled())
			old_mask = *m;

Linus Torvalds's avatar
Linus Torvalds committed
270 271 272
		changed = snd_mask_refine(m, constrs_mask(constrs, k));
		if (changed < 0)
			return changed;
273 274
		if (changed == 0)
			continue;
275

276
		/* Set corresponding flag so that the caller gets it. */
277 278
		trace_hw_mask_param(substream, k, 0, &old_mask, m);
		params->cmask |= 1 << k;
Linus Torvalds's avatar
Linus Torvalds committed
279 280
	}

281 282 283
	return 0;
}

284 285 286 287 288 289 290 291 292 293
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;

Linus Torvalds's avatar
Linus Torvalds committed
294 295 296 297
	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;
298 299

		/* This parameter is not requested to change by a caller. */
Linus Torvalds's avatar
Linus Torvalds committed
300 301
		if (!(params->rmask & (1 << k)))
			continue;
302 303 304 305

		if (trace_hw_interval_param_enabled())
			old_interval = *i;

Linus Torvalds's avatar
Linus Torvalds committed
306 307 308
		changed = snd_interval_refine(i, constrs_interval(constrs, k));
		if (changed < 0)
			return changed;
309 310
		if (changed == 0)
			continue;
311

312
		/* Set corresponding flag so that the caller gets it. */
313 314
		trace_hw_interval_param(substream, k, 0, &old_interval, i);
		params->cmask |= 1 << k;
Linus Torvalds's avatar
Linus Torvalds committed
315 316
	}

317 318 319
	return 0;
}

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

336 337 338 339 340 341
	/*
	 * 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
342 343
	for (k = 0; k < constrs->rules_num; k++)
		rstamps[k] = 0;
344 345 346 347 348 349 350 351 352 353

	/*
	 * 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.
	 */
354
	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++)
Linus Torvalds's avatar
Linus Torvalds committed
355
		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
356 357 358

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

		/*
		 * 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.
		 */
371 372
		if (r->cond && !(r->cond & params->flags))
			continue;
373 374 375 376 377 378 379 380 381 382 383

		/*
		 * 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.
		 */
384
		for (d = 0; r->deps[d] >= 0; d++) {
385
			if (vstamps[r->deps[d]] > rstamps[k])
386 387
				break;
		}
388
		if (r->deps[d] < 0)
389
			continue;
390

391 392 393 394 395 396 397 398
		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);
		}
399

400
		changed = r->func(params, r);
401 402
		if (changed < 0)
			return changed;
403

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

421 422
			params->cmask |= (1 << r->var);
			vstamps[r->var] = stamp;
423
			again = true;
Linus Torvalds's avatar
Linus Torvalds committed
424
		}
425

426
		rstamps[k] = stamp++;
427 428
	}

429
	/* Iterate to evaluate all rules till no parameters are changed. */
430 431
	if (again)
		goto retry;
432 433 434 435

	return 0;
}

436 437 438 439 440 441 442
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;

Linus Torvalds's avatar
Linus Torvalds committed
443
	if (!params->msbits) {
444
		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS);
Linus Torvalds's avatar
Linus Torvalds committed
445 446 447 448 449
		if (snd_interval_single(i))
			params->msbits = snd_interval_value(i);
	}

	if (!params->rate_den) {
450
		i = hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
Linus Torvalds's avatar
Linus Torvalds committed
451 452 453 454 455 456
		if (snd_interval_single(i)) {
			params->rate_num = snd_interval_value(i);
			params->rate_den = 1;
		}
	}

457 458 459 460 461 462 463 464 465 466 467
	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;
		}
	}

468
	if (!params->info) {
469 470 471
		params->info = substream->runtime->hw.info;
		params->info &= ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
				  SNDRV_PCM_INFO_DRAIN_TRIGGER);
472 473 474 475
		if (!hw_support_mmap(substream))
			params->info &= ~(SNDRV_PCM_INFO_MMAP |
					  SNDRV_PCM_INFO_MMAP_VALID);
	}
476

477 478 479
	return 0;
}

480 481 482 483 484 485 486 487 488 489 490 491
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;
492
	}
493 494 495 496 497 498 499 500 501 502 503 504 505

	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
506
	params->rmask = 0;
507

Linus Torvalds's avatar
Linus Torvalds committed
508 509
	return 0;
}
510 511
EXPORT_SYMBOL(snd_pcm_hw_refine);

512 513
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
514
{
515
	struct snd_pcm_hw_params *params;
Linus Torvalds's avatar
Linus Torvalds committed
516 517
	int err;

518 519 520 521
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

Linus Torvalds's avatar
Linus Torvalds committed
522
	err = snd_pcm_hw_refine(substream, params);
523 524
	if (err < 0)
		goto end;
525

526 527 528
	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto end;
529

530 531 532
	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
Linus Torvalds's avatar
Linus Torvalds committed
533 534 535 536
	kfree(params);
	return err;
}

537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
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;
}

552 553 554 555 556 557 558 559
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);
}

560 561 562 563 564 565 566 567 568 569
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
}

570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596
/**
 * 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;
597 598
	struct snd_mask old_mask;
	struct snd_interval old_interval;
599
	int changed;
600 601

	for (v = vars; *v != -1; v++) {
602 603 604 605 606 607 608 609 610
		/* 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);
		}
611
		if (*v != SNDRV_PCM_HW_PARAM_BUFFER_SIZE)
612
			changed = snd_pcm_hw_param_first(pcm, params, *v, NULL);
613
		else
614 615 616 617 618
			changed = snd_pcm_hw_param_last(pcm, params, *v, NULL);
		if (snd_BUG_ON(changed < 0))
			return changed;
		if (changed == 0)
			continue;
619

620
		/* Trace the changed parameter. */
621 622 623 624 625 626 627 628
		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));
		}
629
	}
630

631 632 633
	return 0;
}

634 635
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
636
{
637
	struct snd_pcm_runtime *runtime;
638
	int err, usecs;
Linus Torvalds's avatar
Linus Torvalds committed
639 640 641
	unsigned int bits;
	snd_pcm_uframes_t frames;

642 643
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
644 645 646 647 648 649 650 651 652 653 654 655
	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);
656
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
Linus Torvalds's avatar
Linus Torvalds committed
657 658
	if (!substream->oss.oss)
#endif
659
		if (atomic_read(&substream->mmap_count))
Linus Torvalds's avatar
Linus Torvalds committed
660 661 662 663 664 665 666 667 668 669 670
			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;

671 672 673 674
	err = fixup_unreferenced_params(substream, params);
	if (err < 0)
		goto _error;

Linus Torvalds's avatar
Linus Torvalds committed
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
	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;
692 693 694
	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
695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715

	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;
716 717 718
	runtime->boundary = runtime->buffer_size;
	while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
		runtime->boundary *= 2;
Linus Torvalds's avatar
Linus Torvalds committed
719 720

	snd_pcm_timer_resolution_change(substream);
721
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
722

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

739 740
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
741
{
742
	struct snd_pcm_hw_params *params;
Linus Torvalds's avatar
Linus Torvalds committed
743 744
	int err;

745 746 747 748
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

Linus Torvalds's avatar
Linus Torvalds committed
749
	err = snd_pcm_hw_params(substream, params);
750 751
	if (err < 0)
		goto end;
752

753 754 755
	if (copy_to_user(_params, params, sizeof(*params)))
		err = -EFAULT;
end:
Linus Torvalds's avatar
Linus Torvalds committed
756 757 758 759
	kfree(params);
	return err;
}

760
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
Linus Torvalds's avatar
Linus Torvalds committed
761
{
762
	struct snd_pcm_runtime *runtime;
Linus Torvalds's avatar
Linus Torvalds committed
763 764
	int result = 0;

765 766
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
767 768 769 770 771 772 773 774 775 776 777
	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);
778
	if (atomic_read(&substream->mmap_count))
Linus Torvalds's avatar
Linus Torvalds committed
779 780 781
		return -EBADFD;
	if (substream->ops->hw_free)
		result = substream->ops->hw_free(substream);
782
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
783
	pm_qos_remove_request(&substream->latency_pm_qos_req);
Linus Torvalds's avatar
Linus Torvalds committed
784 785 786
	return result;
}

787 788
static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_sw_params *params)
Linus Torvalds's avatar
Linus Torvalds committed
789
{
790
	struct snd_pcm_runtime *runtime;
791
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
792

793 794
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
Linus Torvalds's avatar
Linus Torvalds committed
795 796 797 798 799 800 801 802
	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);

803 804
	if (params->tstamp_mode < 0 ||
	    params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
Linus Torvalds's avatar
Linus Torvalds committed
805
		return -EINVAL;
806 807
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
	    params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
808
		return -EINVAL;
Linus Torvalds's avatar
Linus Torvalds committed
809 810 811 812 813 814 815 816 817 818 819
	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;
	}
820
	err = 0;
Linus Torvalds's avatar
Linus Torvalds committed
821 822
	snd_pcm_stream_lock_irq(substream);
	runtime->tstamp_mode = params->tstamp_mode;
823 824
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
		runtime->tstamp_type = params->tstamp_type;
Linus Torvalds's avatar
Linus Torvalds committed
825 826 827 828 829 830 831 832 833 834 835
	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);
836
		err = snd_pcm_update_state(substream, runtime);
Linus Torvalds's avatar
Linus Torvalds committed
837 838
	}
	snd_pcm_stream_unlock_irq(substream);
839
	return err;
Linus Torvalds's avatar
Linus Torvalds committed
840 841
}

842 843
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
844
{
845
	struct snd_pcm_sw_params params;
Linus Torvalds's avatar
Linus Torvalds committed
846 847 848 849 850 851 852 853 854
	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;
}

855 856
int snd_pcm_status(struct snd_pcm_substream *substream,
		   struct snd_pcm_status *status)
Linus Torvalds's avatar
Linus Torvalds committed
857
{
858
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
859 860

	snd_pcm_stream_lock_irq(substream);
861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877

	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
878 879 880 881 882
	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;
883
	if (snd_pcm_running(substream)) {
Linus Torvalds's avatar
Linus Torvalds committed
884
		snd_pcm_update_hw_ptr(substream);
885 886
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
			status->tstamp = runtime->status->tstamp;
887
			status->driver_tstamp = runtime->driver_tstamp;
888 889
			status->audio_tstamp =
				runtime->status->audio_tstamp;
890 891 892 893 894 895
			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);

896 897
			goto _tstamp_end;
		}
898 899 900 901
	} 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);
902 903
	}
 _tstamp_end:
Linus Torvalds's avatar
Linus Torvalds committed
904 905 906 907 908
	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 ||
909
		    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
Linus Torvalds's avatar
Linus Torvalds committed
910
			status->delay = runtime->buffer_size - status->avail;
911 912
			status->delay += runtime->delay;
		} else
Linus Torvalds's avatar
Linus Torvalds committed
913 914 915 916
			status->delay = 0;
	} else {
		status->avail = snd_pcm_capture_avail(runtime);
		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
917
			status->delay = status->avail + runtime->delay;
Linus Torvalds's avatar
Linus Torvalds committed
918 919 920 921 922 923 924 925 926 927 928 929
		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;
}

930
static int snd_pcm_status_user(struct snd_pcm_substream *substream,
931 932
			       struct snd_pcm_status __user * _status,
			       bool ext)
Linus Torvalds's avatar
Linus Torvalds committed
933
{
934
	struct snd_pcm_status status;
Linus Torvalds's avatar
Linus Torvalds committed
935
	int res;
936

Linus Torvalds's avatar
Linus Torvalds committed
937
	memset(&status, 0, sizeof(status));
938 939 940 941 942 943 944 945
	/*
	 * 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
946 947 948 949 950 951 952 953
	res = snd_pcm_status(substream, &status);
	if (res < 0)
		return res;
	if (copy_to_user(_status, &status, sizeof(status)))
		return -EFAULT;
	return 0;
}

954 955
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
				struct snd_pcm_channel_info * info)
Linus Torvalds's avatar
Linus Torvalds committed
956
{
957
	struct snd_pcm_runtime *runtime;
Linus Torvalds's avatar
Linus Torvalds committed
958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974
	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);
}

975 976
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
977
{
978
	struct snd_pcm_channel_info info;
Linus Torvalds's avatar
Linus Torvalds committed
979 980 981 982 983 984 985 986 987 988 989 990
	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;
}

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

struct action_ops {
1007 1008 1009 1010
	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
1011 1012 1013 1014 1015 1016 1017
};

/*
 *  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
 */
1018
static int snd_pcm_action_group(const struct action_ops *ops,
1019
				struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1020 1021
				int state, int do_lock)
{
1022 1023
	struct snd_pcm_substream *s = NULL;
	struct snd_pcm_substream *s1;
1024
	int res = 0, depth = 1;
Linus Torvalds's avatar
Linus Torvalds committed
1025

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

/*
 *  Note: call with stream lock
 */
1075
static int snd_pcm_action_single(const struct action_ops *ops,
1076
				 struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091
				 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;
}

1092 1093 1094
/*
 *  Note: call with stream lock
 */
1095
static int snd_pcm_action(const struct action_ops *ops,
1096 1097
			  struct snd_pcm_substream *substream,
			  int state)
1098 1099 1100
{
	int res;

1101 1102 1103 1104
	if (!snd_pcm_stream_linked(substream))
		return snd_pcm_action_single(ops, substream, state);

	if (substream->pcm->nonatomic) {
1105 1106 1107 1108 1109 1110 1111 1112
		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
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126
		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
 */
1127
static int snd_pcm_action_lock_irq(const struct action_ops *ops,
1128
				   struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1129 1130 1131 1132
				   int state)
{
	int res;

1133 1134 1135
	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
1136 1137 1138 1139 1140
	return res;
}

/*
 */
1141
static int snd_pcm_action_nonatomic(const struct action_ops *ops,
1142
				    struct snd_pcm_substream *substream,
Linus Torvalds's avatar
Linus Torvalds committed
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
				    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
 */
1159
static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1160
{
1161
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1162 1163 1164 1165 1166
	if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
		return -EBADFD;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    !snd_pcm_playback_data(substream))
		return -EPIPE;
1167
	runtime->trigger_tstamp_latched = false;
Linus Torvalds's avatar
Linus Torvalds committed
1168 1169 1170 1171
	runtime->trigger_master = substream;
	return 0;
}

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

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

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

1199
static const struct action_ops snd_pcm_action_start = {
Linus Torvalds's avatar
Linus Torvalds committed
1200 1201 1202 1203 1204 1205 1206
	.pre_action = snd_pcm_pre_start,
	.do_action = snd_pcm_do_start,
	.undo_action = snd_pcm_undo_start,
	.post_action = snd_pcm_post_start
};

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

1219 1220 1221 1222 1223 1224 1225
/* 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
1226 1227 1228
/*
 * stop callbacks
 */
1229
static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1230
{
1231
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1232 1233 1234 1235 1236 1237
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	runtime->trigger_master = substream;
	return 0;
}

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

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

1258
static const struct action_ops snd_pcm_action_stop = {
Linus Torvalds's avatar
Linus Torvalds committed
1259 1260 1261 1262 1263 1264
	.pre_action = snd_pcm_pre_stop,
	.do_action = snd_pcm_do_stop,
	.post_action = snd_pcm_post_stop
};

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

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

1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315
/**
 * 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
1316 1317 1318
/*
 * pause callbacks
 */
1319
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1320
{
1321
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332
	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;
}

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

1351
static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1352 1353 1354 1355 1356 1357 1358
{
	if (substream->runtime->trigger_master == substream)
		substream->ops->trigger(substream,
					push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
					SNDRV_PCM_TRIGGER_PAUSE_PUSH);
}

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

1374
static const struct action_ops snd_pcm_action_pause = {
Linus Torvalds's avatar
Linus Torvalds committed
1375 1376 1377 1378 1379 1380 1381 1382 1383
	.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.
 */
1384
static int snd_pcm_pause(struct snd_pcm_substream *substream, int push)
Linus Torvalds's avatar
Linus Torvalds committed
1385 1386 1387 1388 1389 1390 1391
{
	return snd_pcm_action(&snd_pcm_action_pause, substream, push);
}

#ifdef CONFIG_PM
/* suspend */

1392
static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1393
{
1394
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1395 1396 1397 1398 1399 1400
	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
		return -EBUSY;
	runtime->trigger_master = substream;
	return 0;
}

1401
static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state)
Linus Torvalds's avatar
Linus Torvalds committed
1402
{
1403
	struct snd_pcm_runtime *runtime = substream->runtime;
Linus Torvalds's avatar
Linus Torvalds committed
1404 1405 1406 1407 1408 1409 1410 1411
	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 */
}

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

1423
static const struct action_ops snd_pcm_action_suspend = {
Linus Torvalds's avatar
Linus Torvalds committed
1424 1425 1426 1427 1428 1429
	.pre_action = snd_pcm_pre_suspend,
	.do_action = snd_pcm_do_suspend,
	.post_action = snd_pcm_post_suspend
};

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

1443 1444 1445
	if (! substream)
		return 0;

Linus Torvalds's avatar
Linus Torvalds committed
1446 1447