pcm_native.c 100.9 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 *  Digital Audio (PCM) abstract layer
3
 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
L
Linus Torvalds 已提交
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>
L
Linus Torvalds 已提交
24 25
#include <linux/file.h>
#include <linux/slab.h>
26
#include <linux/sched/signal.h>
L
Linus Torvalds 已提交
27
#include <linux/time.h>
28
#include <linux/pm_qos.h>
29
#include <linux/io.h>
30
#include <linux/dma-mapping.h>
L
Linus Torvalds 已提交
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>
L
Linus Torvalds 已提交
39 40 41 42 43

/*
 *  Compatibility
 */

T
Takashi Iwai 已提交
44
struct snd_pcm_hw_params_old {
L
Linus Torvalds 已提交
45 46 47
	unsigned int flags;
	unsigned int masks[SNDRV_PCM_HW_PARAM_SUBFORMAT -
			   SNDRV_PCM_HW_PARAM_ACCESS + 1];
T
Takashi Iwai 已提交
48
	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_TICK_TIME -
L
Linus Torvalds 已提交
49 50 51 52 53 54 55
					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;
T
Takashi Iwai 已提交
56
	snd_pcm_uframes_t fifo_size;
L
Linus Torvalds 已提交
57 58 59
	unsigned char reserved[64];
};

60
#ifdef CONFIG_SND_SUPPORT_OLD_API
T
Takashi Iwai 已提交
61 62
#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)
L
Linus Torvalds 已提交
63

T
Takashi Iwai 已提交
64 65 66 67
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);
68
#endif
69
static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
L
Linus Torvalds 已提交
70 71 72 73 74

/*
 *
 */

75 76
static DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
77

78 79 80 81 82 83 84 85 86 87 88 89
/* 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();
}

T
Takashi Iwai 已提交
90 91 92 93 94 95 96 97
/**
 * 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.
 */
98 99 100
void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
{
	if (substream->pcm->nonatomic) {
101
		down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING);
102 103 104 105 106 107 108 109
		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);

T
Takashi Iwai 已提交
110 111 112 113 114 115
/**
 * 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().
 */
116 117 118 119 120 121 122 123 124 125 126 127
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);

T
Takashi Iwai 已提交
128 129 130 131 132 133 134 135
/**
 * 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().
 */
136 137 138 139 140 141 142 143
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);

T
Takashi Iwai 已提交
144 145 146 147 148 149
/**
 * snd_pcm_stream_unlock_irq - Unlock the PCM stream
 * @substream: PCM substream
 *
 * This is a counter-part of snd_pcm_stream_lock_irq().
 */
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
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);

T
Takashi Iwai 已提交
168 169 170 171 172 173 174
/**
 * 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().
 */
175 176 177 178 179 180 181 182
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);
L
Linus Torvalds 已提交
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197

static inline mm_segment_t snd_enter_user(void)
{
	mm_segment_t fs = get_fs();
	set_fs(get_ds());
	return fs;
}

static inline void snd_leave_user(mm_segment_t fs)
{
	set_fs(fs);
}



T
Takashi Iwai 已提交
198
int snd_pcm_info(struct snd_pcm_substream *substream, struct snd_pcm_info *info)
L
Linus Torvalds 已提交
199
{
T
Takashi Iwai 已提交
200 201 202
	struct snd_pcm_runtime *runtime;
	struct snd_pcm *pcm = substream->pcm;
	struct snd_pcm_str *pstr = substream->pstr;
L
Linus Torvalds 已提交
203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

	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;
	/* AB: FIXME!!! This is definitely nonsense */
	if (runtime) {
		info->sync = runtime->sync;
		substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_INFO, info);
	}
	return 0;
}

T
Takashi Iwai 已提交
225 226
int snd_pcm_info_user(struct snd_pcm_substream *substream,
		      struct snd_pcm_info __user * _info)
L
Linus Torvalds 已提交
227
{
T
Takashi Iwai 已提交
228
	struct snd_pcm_info *info;
L
Linus Torvalds 已提交
229 230 231 232 233 234 235 236 237 238 239 240 241 242
	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;
}

243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
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;
}

L
Linus Torvalds 已提交
258 259 260 261
#undef RULES_DEBUG

#ifdef RULES_DEBUG
#define HW_PARAM(v) [SNDRV_PCM_HW_PARAM_##v] = #v
262
static const char * const snd_pcm_hw_param_names[] = {
L
Linus Torvalds 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
	HW_PARAM(ACCESS),
	HW_PARAM(FORMAT),
	HW_PARAM(SUBFORMAT),
	HW_PARAM(SAMPLE_BITS),
	HW_PARAM(FRAME_BITS),
	HW_PARAM(CHANNELS),
	HW_PARAM(RATE),
	HW_PARAM(PERIOD_TIME),
	HW_PARAM(PERIOD_SIZE),
	HW_PARAM(PERIOD_BYTES),
	HW_PARAM(PERIODS),
	HW_PARAM(BUFFER_TIME),
	HW_PARAM(BUFFER_SIZE),
	HW_PARAM(BUFFER_BYTES),
	HW_PARAM(TICK_TIME),
};
#endif

T
Takashi Iwai 已提交
281 282
int snd_pcm_hw_refine(struct snd_pcm_substream *substream, 
		      struct snd_pcm_hw_params *params)
L
Linus Torvalds 已提交
283 284
{
	unsigned int k;
T
Takashi Iwai 已提交
285 286 287 288
	struct snd_pcm_hardware *hw;
	struct snd_interval *i = NULL;
	struct snd_mask *m = NULL;
	struct snd_pcm_hw_constraints *constrs = &substream->runtime->hw_constraints;
L
Linus Torvalds 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309
	unsigned int rstamps[constrs->rules_num];
	unsigned int vstamps[SNDRV_PCM_HW_PARAM_LAST_INTERVAL + 1];
	unsigned int stamp = 2;
	int changed, again;

	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;
	}

	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;
		if (!(params->rmask & (1 << k)))
			continue;
#ifdef RULES_DEBUG
310 311
		pr_debug("%s = ", snd_pcm_hw_param_names[k]);
		pr_cont("%04x%04x%04x%04x -> ", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
L
Linus Torvalds 已提交
312 313 314
#endif
		changed = snd_mask_refine(m, constrs_mask(constrs, k));
#ifdef RULES_DEBUG
315
		pr_cont("%04x%04x%04x%04x\n", m->bits[3], m->bits[2], m->bits[1], m->bits[0]);
L
Linus Torvalds 已提交
316 317 318 319 320 321 322 323 324 325 326 327 328 329
#endif
		if (changed)
			params->cmask |= 1 << k;
		if (changed < 0)
			return 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;
		if (!(params->rmask & (1 << k)))
			continue;
#ifdef RULES_DEBUG
330
		pr_debug("%s = ", snd_pcm_hw_param_names[k]);
L
Linus Torvalds 已提交
331
		if (i->empty)
332
			pr_cont("empty");
L
Linus Torvalds 已提交
333
		else
334
			pr_cont("%c%u %u%c",
L
Linus Torvalds 已提交
335 336
			       i->openmin ? '(' : '[', i->min,
			       i->max, i->openmax ? ')' : ']');
337
		pr_cont(" -> ");
L
Linus Torvalds 已提交
338 339 340 341
#endif
		changed = snd_interval_refine(i, constrs_interval(constrs, k));
#ifdef RULES_DEBUG
		if (i->empty)
342
			pr_cont("empty\n");
L
Linus Torvalds 已提交
343
		else 
344
			pr_cont("%c%u %u%c\n",
L
Linus Torvalds 已提交
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
			       i->openmin ? '(' : '[', i->min,
			       i->max, i->openmax ? ')' : ']');
#endif
		if (changed)
			params->cmask |= 1 << k;
		if (changed < 0)
			return changed;
	}

	for (k = 0; k < constrs->rules_num; k++)
		rstamps[k] = 0;
	for (k = 0; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) 
		vstamps[k] = (params->rmask & (1 << k)) ? 1 : 0;
	do {
		again = 0;
		for (k = 0; k < constrs->rules_num; k++) {
T
Takashi Iwai 已提交
361
			struct snd_pcm_hw_rule *r = &constrs->rules[k];
L
Linus Torvalds 已提交
362 363 364 365 366 367 368 369 370 371 372 373 374
			unsigned int d;
			int doit = 0;
			if (r->cond && !(r->cond & params->flags))
				continue;
			for (d = 0; r->deps[d] >= 0; d++) {
				if (vstamps[r->deps[d]] > rstamps[k]) {
					doit = 1;
					break;
				}
			}
			if (!doit)
				continue;
#ifdef RULES_DEBUG
375
			pr_debug("Rule %d [%p]: ", k, r->func);
L
Linus Torvalds 已提交
376
			if (r->var >= 0) {
377
				pr_cont("%s = ", snd_pcm_hw_param_names[r->var]);
L
Linus Torvalds 已提交
378 379
				if (hw_is_mask(r->var)) {
					m = hw_param_mask(params, r->var);
380
					pr_cont("%x", *m->bits);
L
Linus Torvalds 已提交
381 382 383
				} else {
					i = hw_param_interval(params, r->var);
					if (i->empty)
384
						pr_cont("empty");
L
Linus Torvalds 已提交
385
					else
386
						pr_cont("%c%u %u%c",
L
Linus Torvalds 已提交
387 388 389 390 391 392 393 394
						       i->openmin ? '(' : '[', i->min,
						       i->max, i->openmax ? ')' : ']');
				}
			}
#endif
			changed = r->func(params, r);
#ifdef RULES_DEBUG
			if (r->var >= 0) {
395
				pr_cont(" -> ");
L
Linus Torvalds 已提交
396
				if (hw_is_mask(r->var))
397
					pr_cont("%x", *m->bits);
L
Linus Torvalds 已提交
398 399
				else {
					if (i->empty)
400
						pr_cont("empty");
L
Linus Torvalds 已提交
401
					else
402
						pr_cont("%c%u %u%c",
L
Linus Torvalds 已提交
403 404 405 406
						       i->openmin ? '(' : '[', i->min,
						       i->max, i->openmax ? ')' : ']');
				}
			}
407
			pr_cont("\n");
L
Linus Torvalds 已提交
408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434
#endif
			rstamps[k] = stamp;
			if (changed && r->var >= 0) {
				params->cmask |= (1 << r->var);
				vstamps[r->var] = stamp;
				again = 1;
			}
			if (changed < 0)
				return changed;
			stamp++;
		}
	} while (again);
	if (!params->msbits) {
		i = hw_param_interval(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(params, SNDRV_PCM_HW_PARAM_RATE);
		if (snd_interval_single(i)) {
			params->rate_num = snd_interval_value(i);
			params->rate_den = 1;
		}
	}

	hw = &substream->runtime->hw;
435
	if (!params->info) {
436 437
		params->info = hw->info & ~(SNDRV_PCM_INFO_FIFO_IN_FRAMES |
					    SNDRV_PCM_INFO_DRAIN_TRIGGER);
438 439 440 441
		if (!hw_support_mmap(substream))
			params->info &= ~(SNDRV_PCM_INFO_MMAP |
					  SNDRV_PCM_INFO_MMAP_VALID);
	}
442
	if (!params->fifo_size) {
443 444 445 446
		m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
		i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
		if (snd_mask_min(m) == snd_mask_max(m) &&
                    snd_interval_min(i) == snd_interval_max(i)) {
447 448
			changed = substream->ops->ioctl(substream,
					SNDRV_PCM_IOCTL1_FIFO_SIZE, params);
449
			if (changed < 0)
450 451 452
				return changed;
		}
	}
L
Linus Torvalds 已提交
453 454 455 456
	params->rmask = 0;
	return 0;
}

457 458
EXPORT_SYMBOL(snd_pcm_hw_refine);

T
Takashi Iwai 已提交
459 460
static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
L
Linus Torvalds 已提交
461
{
T
Takashi Iwai 已提交
462
	struct snd_pcm_hw_params *params;
L
Linus Torvalds 已提交
463 464
	int err;

L
Li Zefan 已提交
465 466 467 468
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

L
Linus Torvalds 已提交
469 470 471 472 473
	err = snd_pcm_hw_refine(substream, params);
	if (copy_to_user(_params, params, sizeof(*params))) {
		if (!err)
			err = -EFAULT;
	}
L
Li Zefan 已提交
474

L
Linus Torvalds 已提交
475 476 477 478
	kfree(params);
	return err;
}

479 480 481 482 483 484 485 486 487 488 489 490 491 492 493
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;
}

494 495 496 497 498 499 500 501
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);
}

502 503 504 505 506 507 508 509 510 511
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
}

T
Takashi Iwai 已提交
512 513
static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_hw_params *params)
L
Linus Torvalds 已提交
514
{
T
Takashi Iwai 已提交
515
	struct snd_pcm_runtime *runtime;
516
	int err, usecs;
L
Linus Torvalds 已提交
517 518 519
	unsigned int bits;
	snd_pcm_uframes_t frames;

520 521
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
522 523 524 525 526 527 528 529 530 531 532 533
	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);
T
Takashi Iwai 已提交
534
#if IS_ENABLED(CONFIG_SND_PCM_OSS)
L
Linus Torvalds 已提交
535 536
	if (!substream->oss.oss)
#endif
537
		if (atomic_read(&substream->mmap_count))
L
Linus Torvalds 已提交
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
			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;

	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;
566 567 568
	runtime->no_period_wakeup =
			(params->info & SNDRV_PCM_INFO_NO_PERIOD_WAKEUP) &&
			(params->flags & SNDRV_PCM_HW_PARAMS_NO_PERIOD_WAKEUP);
L
Linus Torvalds 已提交
569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589

	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;
590 591 592
	runtime->boundary = runtime->buffer_size;
	while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size)
		runtime->boundary *= 2;
L
Linus Torvalds 已提交
593 594

	snd_pcm_timer_resolution_change(substream);
595
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_SETUP);
596

597 598
	if (pm_qos_request_active(&substream->latency_pm_qos_req))
		pm_qos_remove_request(&substream->latency_pm_qos_req);
599
	if ((usecs = period_to_usecs(runtime)) >= 0)
600 601
		pm_qos_add_request(&substream->latency_pm_qos_req,
				   PM_QOS_CPU_DMA_LATENCY, usecs);
L
Linus Torvalds 已提交
602 603
	return 0;
 _error:
L
Lucas De Marchi 已提交
604
	/* hardware might be unusable from this time,
L
Linus Torvalds 已提交
605 606
	   so we force application to retry to set
	   the correct hardware parameter settings */
607
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
L
Linus Torvalds 已提交
608 609 610 611 612
	if (substream->ops->hw_free != NULL)
		substream->ops->hw_free(substream);
	return err;
}

T
Takashi Iwai 已提交
613 614
static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_hw_params __user * _params)
L
Linus Torvalds 已提交
615
{
T
Takashi Iwai 已提交
616
	struct snd_pcm_hw_params *params;
L
Linus Torvalds 已提交
617 618
	int err;

L
Li Zefan 已提交
619 620 621 622
	params = memdup_user(_params, sizeof(*params));
	if (IS_ERR(params))
		return PTR_ERR(params);

L
Linus Torvalds 已提交
623 624 625 626 627
	err = snd_pcm_hw_params(substream, params);
	if (copy_to_user(_params, params, sizeof(*params))) {
		if (!err)
			err = -EFAULT;
	}
L
Li Zefan 已提交
628

L
Linus Torvalds 已提交
629 630 631 632
	kfree(params);
	return err;
}

T
Takashi Iwai 已提交
633
static int snd_pcm_hw_free(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
634
{
T
Takashi Iwai 已提交
635
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
636 637
	int result = 0;

638 639
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
640 641 642 643 644 645 646 647 648 649 650
	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);
651
	if (atomic_read(&substream->mmap_count))
L
Linus Torvalds 已提交
652 653 654
		return -EBADFD;
	if (substream->ops->hw_free)
		result = substream->ops->hw_free(substream);
655
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_OPEN);
656
	pm_qos_remove_request(&substream->latency_pm_qos_req);
L
Linus Torvalds 已提交
657 658 659
	return result;
}

T
Takashi Iwai 已提交
660 661
static int snd_pcm_sw_params(struct snd_pcm_substream *substream,
			     struct snd_pcm_sw_params *params)
L
Linus Torvalds 已提交
662
{
T
Takashi Iwai 已提交
663
	struct snd_pcm_runtime *runtime;
664
	int err;
L
Linus Torvalds 已提交
665

666 667
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
668 669 670 671 672 673 674 675
	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);

676 677
	if (params->tstamp_mode < 0 ||
	    params->tstamp_mode > SNDRV_PCM_TSTAMP_LAST)
L
Linus Torvalds 已提交
678
		return -EINVAL;
679 680
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12) &&
	    params->tstamp_type > SNDRV_PCM_TSTAMP_TYPE_LAST)
681
		return -EINVAL;
L
Linus Torvalds 已提交
682 683 684 685 686 687 688 689 690 691 692
	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;
	}
693
	err = 0;
L
Linus Torvalds 已提交
694 695
	snd_pcm_stream_lock_irq(substream);
	runtime->tstamp_mode = params->tstamp_mode;
696 697
	if (params->proto >= SNDRV_PROTOCOL_VERSION(2, 0, 12))
		runtime->tstamp_type = params->tstamp_type;
L
Linus Torvalds 已提交
698 699 700 701 702 703 704 705 706 707 708
	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);
709
		err = snd_pcm_update_state(substream, runtime);
L
Linus Torvalds 已提交
710 711
	}
	snd_pcm_stream_unlock_irq(substream);
712
	return err;
L
Linus Torvalds 已提交
713 714
}

T
Takashi Iwai 已提交
715 716
static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream,
				  struct snd_pcm_sw_params __user * _params)
L
Linus Torvalds 已提交
717
{
T
Takashi Iwai 已提交
718
	struct snd_pcm_sw_params params;
L
Linus Torvalds 已提交
719 720 721 722 723 724 725 726 727
	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;
}

T
Takashi Iwai 已提交
728 729
int snd_pcm_status(struct snd_pcm_substream *substream,
		   struct snd_pcm_status *status)
L
Linus Torvalds 已提交
730
{
T
Takashi Iwai 已提交
731
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
732 733

	snd_pcm_stream_lock_irq(substream);
734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750

	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;

L
Linus Torvalds 已提交
751 752 753 754 755
	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;
756
	if (snd_pcm_running(substream)) {
L
Linus Torvalds 已提交
757
		snd_pcm_update_hw_ptr(substream);
758 759
		if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) {
			status->tstamp = runtime->status->tstamp;
760
			status->driver_tstamp = runtime->driver_tstamp;
761 762
			status->audio_tstamp =
				runtime->status->audio_tstamp;
763 764 765 766 767 768
			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);

769 770
			goto _tstamp_end;
		}
771 772 773 774
	} 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);
775 776
	}
 _tstamp_end:
L
Linus Torvalds 已提交
777 778 779 780 781
	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 ||
782
		    runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
L
Linus Torvalds 已提交
783
			status->delay = runtime->buffer_size - status->avail;
784 785
			status->delay += runtime->delay;
		} else
L
Linus Torvalds 已提交
786 787 788 789
			status->delay = 0;
	} else {
		status->avail = snd_pcm_capture_avail(runtime);
		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING)
790
			status->delay = status->avail + runtime->delay;
L
Linus Torvalds 已提交
791 792 793 794 795 796 797 798 799 800 801 802
		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;
}

T
Takashi Iwai 已提交
803
static int snd_pcm_status_user(struct snd_pcm_substream *substream,
804 805
			       struct snd_pcm_status __user * _status,
			       bool ext)
L
Linus Torvalds 已提交
806
{
T
Takashi Iwai 已提交
807
	struct snd_pcm_status status;
L
Linus Torvalds 已提交
808
	int res;
809

L
Linus Torvalds 已提交
810
	memset(&status, 0, sizeof(status));
811 812 813 814 815 816 817 818
	/*
	 * 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;
L
Linus Torvalds 已提交
819 820 821 822 823 824 825 826
	res = snd_pcm_status(substream, &status);
	if (res < 0)
		return res;
	if (copy_to_user(_status, &status, sizeof(status)))
		return -EFAULT;
	return 0;
}

T
Takashi Iwai 已提交
827 828
static int snd_pcm_channel_info(struct snd_pcm_substream *substream,
				struct snd_pcm_channel_info * info)
L
Linus Torvalds 已提交
829
{
T
Takashi Iwai 已提交
830
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847
	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);
}

T
Takashi Iwai 已提交
848 849
static int snd_pcm_channel_info_user(struct snd_pcm_substream *substream,
				     struct snd_pcm_channel_info __user * _info)
L
Linus Torvalds 已提交
850
{
T
Takashi Iwai 已提交
851
	struct snd_pcm_channel_info info;
L
Linus Torvalds 已提交
852 853 854 855 856 857 858 859 860 861 862 863
	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;
}

T
Takashi Iwai 已提交
864
static void snd_pcm_trigger_tstamp(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
865
{
T
Takashi Iwai 已提交
866
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
867 868 869
	if (runtime->trigger_master == NULL)
		return;
	if (runtime->trigger_master == substream) {
870 871
		if (!runtime->trigger_tstamp_latched)
			snd_pcm_gettime(runtime, &runtime->trigger_tstamp);
L
Linus Torvalds 已提交
872 873 874 875 876 877 878 879
	} else {
		snd_pcm_trigger_tstamp(runtime->trigger_master);
		runtime->trigger_tstamp = runtime->trigger_master->runtime->trigger_tstamp;
	}
	runtime->trigger_master = NULL;
}

struct action_ops {
T
Takashi Iwai 已提交
880 881 882 883
	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);
L
Linus Torvalds 已提交
884 885 886 887 888 889 890
};

/*
 *  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
 */
891
static int snd_pcm_action_group(const struct action_ops *ops,
T
Takashi Iwai 已提交
892
				struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
893 894
				int state, int do_lock)
{
T
Takashi Iwai 已提交
895 896
	struct snd_pcm_substream *s = NULL;
	struct snd_pcm_substream *s1;
897
	int res = 0, depth = 1;
L
Linus Torvalds 已提交
898

899
	snd_pcm_group_for_each_entry(s, substream) {
900 901
		if (do_lock && s != substream) {
			if (s->pcm->nonatomic)
902
				mutex_lock_nested(&s->self_group.mutex, depth);
903
			else
904 905
				spin_lock_nested(&s->self_group.lock, depth);
			depth++;
906
		}
L
Linus Torvalds 已提交
907 908 909 910
		res = ops->pre_action(s, state);
		if (res < 0)
			goto _unlock;
	}
911
	snd_pcm_group_for_each_entry(s, substream) {
L
Linus Torvalds 已提交
912 913 914
		res = ops->do_action(s, state);
		if (res < 0) {
			if (ops->undo_action) {
915
				snd_pcm_group_for_each_entry(s1, substream) {
L
Linus Torvalds 已提交
916 917 918 919 920 921 922 923 924
					if (s1 == s) /* failed stream */
						break;
					ops->undo_action(s1, state);
				}
			}
			s = NULL; /* unlock all */
			goto _unlock;
		}
	}
925
	snd_pcm_group_for_each_entry(s, substream) {
L
Linus Torvalds 已提交
926 927 928 929 930
		ops->post_action(s, state);
	}
 _unlock:
	if (do_lock) {
		/* unlock streams */
931
		snd_pcm_group_for_each_entry(s1, substream) {
932
			if (s1 != substream) {
933
				if (s1->pcm->nonatomic)
934 935 936 937
					mutex_unlock(&s1->self_group.mutex);
				else
					spin_unlock(&s1->self_group.lock);
			}
L
Linus Torvalds 已提交
938 939 940 941 942 943 944 945 946 947
			if (s1 == s)	/* end */
				break;
		}
	}
	return res;
}

/*
 *  Note: call with stream lock
 */
948
static int snd_pcm_action_single(const struct action_ops *ops,
T
Takashi Iwai 已提交
949
				 struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964
				 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;
}

965 966 967
/*
 *  Note: call with stream lock
 */
968
static int snd_pcm_action(const struct action_ops *ops,
969 970
			  struct snd_pcm_substream *substream,
			  int state)
971 972 973
{
	int res;

974 975 976 977
	if (!snd_pcm_stream_linked(substream))
		return snd_pcm_action_single(ops, substream, state);

	if (substream->pcm->nonatomic) {
978 979 980 981 982 983 984 985
		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 {
L
Linus Torvalds 已提交
986 987 988 989 990 991 992 993 994 995 996 997 998 999
		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
 */
1000
static int snd_pcm_action_lock_irq(const struct action_ops *ops,
T
Takashi Iwai 已提交
1001
				   struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
1002 1003 1004 1005
				   int state)
{
	int res;

1006 1007 1008
	snd_pcm_stream_lock_irq(substream);
	res = snd_pcm_action(ops, substream, state);
	snd_pcm_stream_unlock_irq(substream);
L
Linus Torvalds 已提交
1009 1010 1011 1012 1013
	return res;
}

/*
 */
1014
static int snd_pcm_action_nonatomic(const struct action_ops *ops,
T
Takashi Iwai 已提交
1015
				    struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031
				    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
 */
T
Takashi Iwai 已提交
1032
static int snd_pcm_pre_start(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1033
{
T
Takashi Iwai 已提交
1034
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1035 1036 1037 1038 1039
	if (runtime->status->state != SNDRV_PCM_STATE_PREPARED)
		return -EBADFD;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    !snd_pcm_playback_data(substream))
		return -EPIPE;
1040
	runtime->trigger_tstamp_latched = false;
L
Linus Torvalds 已提交
1041 1042 1043 1044
	runtime->trigger_master = substream;
	return 0;
}

T
Takashi Iwai 已提交
1045
static int snd_pcm_do_start(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1046 1047 1048 1049 1050 1051
{
	if (substream->runtime->trigger_master != substream)
		return 0;
	return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START);
}

T
Takashi Iwai 已提交
1052
static void snd_pcm_undo_start(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1053 1054 1055 1056 1057
{
	if (substream->runtime->trigger_master == substream)
		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
}

T
Takashi Iwai 已提交
1058
static void snd_pcm_post_start(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1059
{
T
Takashi Iwai 已提交
1060
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1061
	snd_pcm_trigger_tstamp(substream);
1062
	runtime->hw_ptr_jiffies = jiffies;
1063 1064
	runtime->hw_ptr_buffer_jiffies = (runtime->buffer_size * HZ) / 
							    runtime->rate;
L
Linus Torvalds 已提交
1065 1066 1067 1068
	runtime->status->state = state;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
		snd_pcm_playback_silence(substream, ULONG_MAX);
1069
	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTART);
L
Linus Torvalds 已提交
1070 1071
}

1072
static const struct action_ops snd_pcm_action_start = {
L
Linus Torvalds 已提交
1073 1074 1075 1076 1077 1078 1079
	.pre_action = snd_pcm_pre_start,
	.do_action = snd_pcm_do_start,
	.undo_action = snd_pcm_undo_start,
	.post_action = snd_pcm_post_start
};

/**
1080
 * snd_pcm_start - start all linked streams
T
Takashi Iwai 已提交
1081
 * @substream: the PCM substream instance
1082 1083
 *
 * Return: Zero if successful, or a negative error code.
L
Linus Torvalds 已提交
1084
 */
T
Takashi Iwai 已提交
1085
int snd_pcm_start(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1086
{
T
Takashi Iwai 已提交
1087 1088
	return snd_pcm_action(&snd_pcm_action_start, substream,
			      SNDRV_PCM_STATE_RUNNING);
L
Linus Torvalds 已提交
1089 1090 1091 1092 1093
}

/*
 * stop callbacks
 */
T
Takashi Iwai 已提交
1094
static int snd_pcm_pre_stop(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1095
{
T
Takashi Iwai 已提交
1096
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1097 1098 1099 1100 1101 1102
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	runtime->trigger_master = substream;
	return 0;
}

T
Takashi Iwai 已提交
1103
static int snd_pcm_do_stop(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1104 1105 1106 1107 1108 1109 1110
{
	if (substream->runtime->trigger_master == substream &&
	    snd_pcm_running(substream))
		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP);
	return 0; /* unconditonally stop all substreams */
}

T
Takashi Iwai 已提交
1111
static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1112
{
T
Takashi Iwai 已提交
1113
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1114 1115
	if (runtime->status->state != state) {
		snd_pcm_trigger_tstamp(substream);
1116
		runtime->status->state = state;
1117
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSTOP);
L
Linus Torvalds 已提交
1118 1119
	}
	wake_up(&runtime->sleep);
1120
	wake_up(&runtime->tsleep);
L
Linus Torvalds 已提交
1121 1122
}

1123
static const struct action_ops snd_pcm_action_stop = {
L
Linus Torvalds 已提交
1124 1125 1126 1127 1128 1129
	.pre_action = snd_pcm_pre_stop,
	.do_action = snd_pcm_do_stop,
	.post_action = snd_pcm_post_stop
};

/**
1130
 * snd_pcm_stop - try to stop all running streams in the substream group
T
Takashi Iwai 已提交
1131 1132
 * @substream: the PCM substream instance
 * @state: PCM state after stopping the stream
L
Linus Torvalds 已提交
1133
 *
1134
 * The state of each stream is then changed to the given state unconditionally.
1135
 *
1136
 * Return: Zero if successful, or a negative error code.
L
Linus Torvalds 已提交
1137
 */
C
Clemens Ladisch 已提交
1138
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t state)
L
Linus Torvalds 已提交
1139 1140 1141 1142
{
	return snd_pcm_action(&snd_pcm_action_stop, substream, state);
}

1143 1144
EXPORT_SYMBOL(snd_pcm_stop);

L
Linus Torvalds 已提交
1145
/**
1146
 * snd_pcm_drain_done - stop the DMA only when the given stream is playback
T
Takashi Iwai 已提交
1147
 * @substream: the PCM substream
L
Linus Torvalds 已提交
1148
 *
1149
 * After stopping, the state is changed to SETUP.
L
Linus Torvalds 已提交
1150
 * Unlike snd_pcm_stop(), this affects only the given stream.
1151 1152
 *
 * Return: Zero if succesful, or a negative error code.
L
Linus Torvalds 已提交
1153
 */
T
Takashi Iwai 已提交
1154
int snd_pcm_drain_done(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1155
{
T
Takashi Iwai 已提交
1156 1157
	return snd_pcm_action_single(&snd_pcm_action_stop, substream,
				     SNDRV_PCM_STATE_SETUP);
L
Linus Torvalds 已提交
1158 1159
}

1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181
/**
 * 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);

L
Linus Torvalds 已提交
1182 1183 1184
/*
 * pause callbacks
 */
T
Takashi Iwai 已提交
1185
static int snd_pcm_pre_pause(struct snd_pcm_substream *substream, int push)
L
Linus Torvalds 已提交
1186
{
T
Takashi Iwai 已提交
1187
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
	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;
}

T
Takashi Iwai 已提交
1199
static int snd_pcm_do_pause(struct snd_pcm_substream *substream, int push)
L
Linus Torvalds 已提交
1200 1201 1202
{
	if (substream->runtime->trigger_master != substream)
		return 0;
1203 1204 1205 1206
	/* some drivers might use hw_ptr to recover from the pause -
	   update the hw_ptr now */
	if (push)
		snd_pcm_update_hw_ptr(substream);
1207
	/* The jiffies check in snd_pcm_update_hw_ptr*() is done by
1208
	 * a delta between the current jiffies, this gives a large enough
1209 1210 1211
	 * delta, effectively to skip the check once.
	 */
	substream->runtime->hw_ptr_jiffies = jiffies - HZ * 1000;
L
Linus Torvalds 已提交
1212 1213 1214 1215 1216
	return substream->ops->trigger(substream,
				       push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH :
					      SNDRV_PCM_TRIGGER_PAUSE_RELEASE);
}

T
Takashi Iwai 已提交
1217
static void snd_pcm_undo_pause(struct snd_pcm_substream *substream, int push)
L
Linus Torvalds 已提交
1218 1219 1220 1221 1222 1223 1224
{
	if (substream->runtime->trigger_master == substream)
		substream->ops->trigger(substream,
					push ? SNDRV_PCM_TRIGGER_PAUSE_RELEASE :
					SNDRV_PCM_TRIGGER_PAUSE_PUSH);
}

T
Takashi Iwai 已提交
1225
static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push)
L
Linus Torvalds 已提交
1226
{
T
Takashi Iwai 已提交
1227
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1228 1229 1230
	snd_pcm_trigger_tstamp(substream);
	if (push) {
		runtime->status->state = SNDRV_PCM_STATE_PAUSED;
1231
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MPAUSE);
L
Linus Torvalds 已提交
1232
		wake_up(&runtime->sleep);
1233
		wake_up(&runtime->tsleep);
L
Linus Torvalds 已提交
1234 1235
	} else {
		runtime->status->state = SNDRV_PCM_STATE_RUNNING;
1236
		snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MCONTINUE);
L
Linus Torvalds 已提交
1237 1238 1239
	}
}

1240
static const struct action_ops snd_pcm_action_pause = {
L
Linus Torvalds 已提交
1241 1242 1243 1244 1245 1246 1247 1248 1249
	.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.
 */
T
Takashi Iwai 已提交
1250
static int snd_pcm_pause(struct snd_pcm_substream *substream, int push)
L
Linus Torvalds 已提交
1251 1252 1253 1254 1255 1256 1257
{
	return snd_pcm_action(&snd_pcm_action_pause, substream, push);
}

#ifdef CONFIG_PM
/* suspend */

T
Takashi Iwai 已提交
1258
static int snd_pcm_pre_suspend(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1259
{
T
Takashi Iwai 已提交
1260
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1261 1262 1263 1264 1265 1266
	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
		return -EBUSY;
	runtime->trigger_master = substream;
	return 0;
}

T
Takashi Iwai 已提交
1267
static int snd_pcm_do_suspend(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1268
{
T
Takashi Iwai 已提交
1269
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1270 1271 1272 1273 1274 1275 1276 1277
	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 */
}

T
Takashi Iwai 已提交
1278
static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1279
{
T
Takashi Iwai 已提交
1280
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1281
	snd_pcm_trigger_tstamp(substream);
1282 1283
	runtime->status->suspended_state = runtime->status->state;
	runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
1284
	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MSUSPEND);
L
Linus Torvalds 已提交
1285
	wake_up(&runtime->sleep);
1286
	wake_up(&runtime->tsleep);
L
Linus Torvalds 已提交
1287 1288
}

1289
static const struct action_ops snd_pcm_action_suspend = {
L
Linus Torvalds 已提交
1290 1291 1292 1293 1294 1295
	.pre_action = snd_pcm_pre_suspend,
	.do_action = snd_pcm_do_suspend,
	.post_action = snd_pcm_post_suspend
};

/**
1296
 * snd_pcm_suspend - trigger SUSPEND to all linked streams
T
Takashi Iwai 已提交
1297
 * @substream: the PCM substream
L
Linus Torvalds 已提交
1298 1299
 *
 * After this call, all streams are changed to SUSPENDED state.
1300 1301 1302
 *
 * Return: Zero if successful (or @substream is %NULL), or a negative error
 * code.
L
Linus Torvalds 已提交
1303
 */
T
Takashi Iwai 已提交
1304
int snd_pcm_suspend(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1305 1306 1307 1308
{
	int err;
	unsigned long flags;

1309 1310 1311
	if (! substream)
		return 0;

L
Linus Torvalds 已提交
1312 1313 1314 1315 1316 1317
	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;
}

1318 1319
EXPORT_SYMBOL(snd_pcm_suspend);

L
Linus Torvalds 已提交
1320
/**
1321
 * snd_pcm_suspend_all - trigger SUSPEND to all substreams in the given pcm
T
Takashi Iwai 已提交
1322
 * @pcm: the PCM instance
L
Linus Torvalds 已提交
1323 1324
 *
 * After this call, all streams are changed to SUSPENDED state.
1325 1326
 *
 * Return: Zero if successful (or @pcm is %NULL), or a negative error code.
L
Linus Torvalds 已提交
1327
 */
T
Takashi Iwai 已提交
1328
int snd_pcm_suspend_all(struct snd_pcm *pcm)
L
Linus Torvalds 已提交
1329
{
T
Takashi Iwai 已提交
1330
	struct snd_pcm_substream *substream;
L
Linus Torvalds 已提交
1331 1332
	int stream, err = 0;

1333 1334 1335
	if (! pcm)
		return 0;

L
Linus Torvalds 已提交
1336
	for (stream = 0; stream < 2; stream++) {
T
Takashi Iwai 已提交
1337 1338
		for (substream = pcm->streams[stream].substream;
		     substream; substream = substream->next) {
L
Linus Torvalds 已提交
1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349
			/* 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;
}

1350 1351
EXPORT_SYMBOL(snd_pcm_suspend_all);

L
Linus Torvalds 已提交
1352 1353
/* resume */

T
Takashi Iwai 已提交
1354
static int snd_pcm_pre_resume(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1355
{
T
Takashi Iwai 已提交
1356
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1357 1358 1359 1360 1361 1362
	if (!(runtime->info & SNDRV_PCM_INFO_RESUME))
		return -ENOSYS;
	runtime->trigger_master = substream;
	return 0;
}

T
Takashi Iwai 已提交
1363
static int snd_pcm_do_resume(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1364
{
T
Takashi Iwai 已提交
1365
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1366 1367 1368 1369 1370 1371 1372 1373 1374 1375
	if (runtime->trigger_master != substream)
		return 0;
	/* DMA not running previously? */
	if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING &&
	    (runtime->status->suspended_state != SNDRV_PCM_STATE_DRAINING ||
	     substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
		return 0;
	return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME);
}

T
Takashi Iwai 已提交
1376
static void snd_pcm_undo_resume(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1377 1378 1379 1380 1381 1382
{
	if (substream->runtime->trigger_master == substream &&
	    snd_pcm_running(substream))
		substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND);
}

T
Takashi Iwai 已提交
1383
static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1384
{
T
Takashi Iwai 已提交
1385
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1386
	snd_pcm_trigger_tstamp(substream);
1387
	runtime->status->state = runtime->status->suspended_state;
1388
	snd_pcm_timer_notify(substream, SNDRV_TIMER_EVENT_MRESUME);
L
Linus Torvalds 已提交
1389 1390
}

1391
static const struct action_ops snd_pcm_action_resume = {
L
Linus Torvalds 已提交
1392 1393 1394 1395 1396 1397
	.pre_action = snd_pcm_pre_resume,
	.do_action = snd_pcm_do_resume,
	.undo_action = snd_pcm_undo_resume,
	.post_action = snd_pcm_post_resume
};

T
Takashi Iwai 已提交
1398
static int snd_pcm_resume(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1399
{
T
Takashi Iwai 已提交
1400
	struct snd_card *card = substream->pcm->card;
L
Linus Torvalds 已提交
1401 1402 1403
	int res;

	snd_power_lock(card);
1404
	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
L
Linus Torvalds 已提交
1405 1406 1407 1408 1409 1410 1411
		res = snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0);
	snd_power_unlock(card);
	return res;
}

#else

T
Takashi Iwai 已提交
1412
static int snd_pcm_resume(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423
{
	return -ENOSYS;
}

#endif /* CONFIG_PM */

/*
 * xrun ioctl
 *
 * Change the RUNNING stream(s) to XRUN state.
 */
T
Takashi Iwai 已提交
1424
static int snd_pcm_xrun(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1425
{
T
Takashi Iwai 已提交
1426 1427
	struct snd_card *card = substream->pcm->card;
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1428 1429 1430 1431
	int result;

	snd_power_lock(card);
	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1432
		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
L
Linus Torvalds 已提交
1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
		if (result < 0)
			goto _unlock;
	}

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_XRUN:
		result = 0;	/* already there */
		break;
	case SNDRV_PCM_STATE_RUNNING:
		result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
		break;
	default:
		result = -EBADFD;
	}
	snd_pcm_stream_unlock_irq(substream);
 _unlock:
	snd_power_unlock(card);
	return result;
}

/*
 * reset ioctl
 */
T
Takashi Iwai 已提交
1457
static int snd_pcm_pre_reset(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1458
{
T
Takashi Iwai 已提交
1459
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_RUNNING:
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_PAUSED:
	case SNDRV_PCM_STATE_SUSPENDED:
		return 0;
	default:
		return -EBADFD;
	}
}

T
Takashi Iwai 已提交
1471
static int snd_pcm_do_reset(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1472
{
T
Takashi Iwai 已提交
1473
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1474 1475 1476 1477
	int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, NULL);
	if (err < 0)
		return err;
	runtime->hw_ptr_base = 0;
1478 1479
	runtime->hw_ptr_interrupt = runtime->status->hw_ptr -
		runtime->status->hw_ptr % runtime->period_size;
L
Linus Torvalds 已提交
1480 1481 1482 1483 1484
	runtime->silence_start = runtime->status->hw_ptr;
	runtime->silence_filled = 0;
	return 0;
}

T
Takashi Iwai 已提交
1485
static void snd_pcm_post_reset(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1486
{
T
Takashi Iwai 已提交
1487
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1488 1489 1490 1491 1492 1493
	runtime->control->appl_ptr = runtime->status->hw_ptr;
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
	    runtime->silence_size > 0)
		snd_pcm_playback_silence(substream, ULONG_MAX);
}

1494
static const struct action_ops snd_pcm_action_reset = {
L
Linus Torvalds 已提交
1495 1496 1497 1498 1499
	.pre_action = snd_pcm_pre_reset,
	.do_action = snd_pcm_do_reset,
	.post_action = snd_pcm_post_reset
};

T
Takashi Iwai 已提交
1500
static int snd_pcm_reset(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1501 1502 1503 1504 1505 1506 1507
{
	return snd_pcm_action_nonatomic(&snd_pcm_action_reset, substream, 0);
}

/*
 * prepare ioctl
 */
1508 1509 1510
/* we use the second argument for updating f_flags */
static int snd_pcm_pre_prepare(struct snd_pcm_substream *substream,
			       int f_flags)
L
Linus Torvalds 已提交
1511
{
T
Takashi Iwai 已提交
1512
	struct snd_pcm_runtime *runtime = substream->runtime;
1513 1514
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED)
L
Linus Torvalds 已提交
1515 1516 1517
		return -EBADFD;
	if (snd_pcm_running(substream))
		return -EBUSY;
1518
	substream->f_flags = f_flags;
L
Linus Torvalds 已提交
1519 1520 1521
	return 0;
}

T
Takashi Iwai 已提交
1522
static int snd_pcm_do_prepare(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1523 1524 1525 1526 1527 1528 1529 1530
{
	int err;
	err = substream->ops->prepare(substream);
	if (err < 0)
		return err;
	return snd_pcm_do_reset(substream, 0);
}

T
Takashi Iwai 已提交
1531
static void snd_pcm_post_prepare(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1532
{
T
Takashi Iwai 已提交
1533
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1534
	runtime->control->appl_ptr = runtime->status->hw_ptr;
1535
	snd_pcm_set_state(substream, SNDRV_PCM_STATE_PREPARED);
L
Linus Torvalds 已提交
1536 1537
}

1538
static const struct action_ops snd_pcm_action_prepare = {
L
Linus Torvalds 已提交
1539 1540 1541 1542 1543 1544
	.pre_action = snd_pcm_pre_prepare,
	.do_action = snd_pcm_do_prepare,
	.post_action = snd_pcm_post_prepare
};

/**
1545
 * snd_pcm_prepare - prepare the PCM substream to be triggerable
T
Takashi Iwai 已提交
1546
 * @substream: the PCM substream instance
1547
 * @file: file to refer f_flags
1548 1549
 *
 * Return: Zero if successful, or a negative error code.
L
Linus Torvalds 已提交
1550
 */
1551 1552
static int snd_pcm_prepare(struct snd_pcm_substream *substream,
			   struct file *file)
L
Linus Torvalds 已提交
1553 1554
{
	int res;
T
Takashi Iwai 已提交
1555
	struct snd_card *card = substream->pcm->card;
1556 1557 1558 1559 1560 1561
	int f_flags;

	if (file)
		f_flags = file->f_flags;
	else
		f_flags = substream->f_flags;
L
Linus Torvalds 已提交
1562 1563

	snd_power_lock(card);
1564
	if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0)) >= 0)
1565 1566
		res = snd_pcm_action_nonatomic(&snd_pcm_action_prepare,
					       substream, f_flags);
L
Linus Torvalds 已提交
1567 1568 1569 1570 1571 1572 1573 1574
	snd_power_unlock(card);
	return res;
}

/*
 * drain ioctl
 */

T
Takashi Iwai 已提交
1575
static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1576
{
1577 1578 1579 1580 1581 1582 1583 1584
	struct snd_pcm_runtime *runtime = substream->runtime;
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_OPEN:
	case SNDRV_PCM_STATE_DISCONNECTED:
	case SNDRV_PCM_STATE_SUSPENDED:
		return -EBADFD;
	}
	runtime->trigger_master = substream;
L
Linus Torvalds 已提交
1585 1586 1587
	return 0;
}

T
Takashi Iwai 已提交
1588
static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1589
{
T
Takashi Iwai 已提交
1590
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
1591 1592 1593 1594 1595 1596 1597
	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		switch (runtime->status->state) {
		case SNDRV_PCM_STATE_PREPARED:
			/* start playback stream if possible */
			if (! snd_pcm_playback_empty(substream)) {
				snd_pcm_do_start(substream, SNDRV_PCM_STATE_DRAINING);
				snd_pcm_post_start(substream, SNDRV_PCM_STATE_DRAINING);
1598 1599
			} else {
				runtime->status->state = SNDRV_PCM_STATE_SETUP;
L
Linus Torvalds 已提交
1600 1601 1602 1603 1604
			}
			break;
		case SNDRV_PCM_STATE_RUNNING:
			runtime->status->state = SNDRV_PCM_STATE_DRAINING;
			break;
1605 1606 1607
		case SNDRV_PCM_STATE_XRUN:
			runtime->status->state = SNDRV_PCM_STATE_SETUP;
			break;
L
Linus Torvalds 已提交
1608 1609 1610 1611 1612 1613
		default:
			break;
		}
	} else {
		/* stop running stream */
		if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) {
1614
			int new_state = snd_pcm_capture_avail(runtime) > 0 ?
L
Linus Torvalds 已提交
1615
				SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP;
1616 1617
			snd_pcm_do_stop(substream, new_state);
			snd_pcm_post_stop(substream, new_state);
L
Linus Torvalds 已提交
1618 1619
		}
	}
1620 1621 1622 1623 1624 1625 1626

	if (runtime->status->state == SNDRV_PCM_STATE_DRAINING &&
	    runtime->trigger_master == substream &&
	    (runtime->hw.info & SNDRV_PCM_INFO_DRAIN_TRIGGER))
		return substream->ops->trigger(substream,
					       SNDRV_PCM_TRIGGER_DRAIN);

L
Linus Torvalds 已提交
1627 1628 1629
	return 0;
}

T
Takashi Iwai 已提交
1630
static void snd_pcm_post_drain_init(struct snd_pcm_substream *substream, int state)
L
Linus Torvalds 已提交
1631 1632 1633
{
}

1634
static const struct action_ops snd_pcm_action_drain_init = {
L
Linus Torvalds 已提交
1635 1636 1637 1638 1639
	.pre_action = snd_pcm_pre_drain_init,
	.do_action = snd_pcm_do_drain_init,
	.post_action = snd_pcm_post_drain_init
};

T
Takashi Iwai 已提交
1640
static int snd_pcm_drop(struct snd_pcm_substream *substream);
L
Linus Torvalds 已提交
1641 1642 1643 1644 1645 1646 1647 1648

/*
 * Drain the stream(s).
 * When the substream is linked, sync until the draining of all playback streams
 * is finished.
 * After this call, all streams are supposed to be either SETUP or DRAINING
 * (capture only) state.
 */
1649 1650
static int snd_pcm_drain(struct snd_pcm_substream *substream,
			 struct file *file)
L
Linus Torvalds 已提交
1651
{
T
Takashi Iwai 已提交
1652 1653
	struct snd_card *card;
	struct snd_pcm_runtime *runtime;
1654
	struct snd_pcm_substream *s;
1655
	wait_queue_t wait;
L
Linus Torvalds 已提交
1656
	int result = 0;
1657
	int nonblock = 0;
L
Linus Torvalds 已提交
1658 1659 1660 1661 1662 1663 1664 1665 1666

	card = substream->pcm->card;
	runtime = substream->runtime;

	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;

	snd_power_lock(card);
	if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
1667
		result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
1668 1669 1670 1671
		if (result < 0) {
			snd_power_unlock(card);
			return result;
		}
L
Linus Torvalds 已提交
1672 1673
	}

1674 1675 1676 1677 1678 1679
	if (file) {
		if (file->f_flags & O_NONBLOCK)
			nonblock = 1;
	} else if (substream->f_flags & O_NONBLOCK)
		nonblock = 1;

1680 1681 1682
	down_read(&snd_pcm_link_rwsem);
	snd_pcm_stream_lock_irq(substream);
	/* resume pause */
1683
	if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
1684 1685 1686 1687
		snd_pcm_pause(substream, 0);

	/* pre-start/stop - all running streams are changed to DRAINING state */
	result = snd_pcm_action(&snd_pcm_action_drain_init, substream, 0);
1688 1689 1690 1691 1692 1693
	if (result < 0)
		goto unlock;
	/* in non-blocking, we don't wait in ioctl but let caller poll */
	if (nonblock) {
		result = -EAGAIN;
		goto unlock;
1694
	}
L
Linus Torvalds 已提交
1695 1696 1697

	for (;;) {
		long tout;
1698
		struct snd_pcm_runtime *to_check;
L
Linus Torvalds 已提交
1699 1700 1701 1702
		if (signal_pending(current)) {
			result = -ERESTARTSYS;
			break;
		}
1703 1704 1705 1706 1707 1708 1709 1710
		/* find a substream to drain */
		to_check = NULL;
		snd_pcm_group_for_each_entry(s, substream) {
			if (s->stream != SNDRV_PCM_STREAM_PLAYBACK)
				continue;
			runtime = s->runtime;
			if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) {
				to_check = runtime;
1711
				break;
1712
			}
1713
		}
1714 1715 1716 1717
		if (!to_check)
			break; /* all drained */
		init_waitqueue_entry(&wait, current);
		add_wait_queue(&to_check->sleep, &wait);
L
Linus Torvalds 已提交
1718
		snd_pcm_stream_unlock_irq(substream);
1719
		up_read(&snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
1720
		snd_power_unlock(card);
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731
		if (runtime->no_period_wakeup)
			tout = MAX_SCHEDULE_TIMEOUT;
		else {
			tout = 10;
			if (runtime->rate) {
				long t = runtime->period_size * 2 / runtime->rate;
				tout = max(t, tout);
			}
			tout = msecs_to_jiffies(tout * 1000);
		}
		tout = schedule_timeout_interruptible(tout);
L
Linus Torvalds 已提交
1732
		snd_power_lock(card);
1733
		down_read(&snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
1734
		snd_pcm_stream_lock_irq(substream);
1735
		remove_wait_queue(&to_check->sleep, &wait);
1736 1737 1738 1739
		if (card->shutdown) {
			result = -ENODEV;
			break;
		}
L
Linus Torvalds 已提交
1740 1741 1742 1743
		if (tout == 0) {
			if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
				result = -ESTRPIPE;
			else {
1744 1745
				dev_dbg(substream->pcm->card->dev,
					"playback drain error (DMA or IRQ trouble?)\n");
L
Linus Torvalds 已提交
1746 1747 1748 1749 1750 1751
				snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
				result = -EIO;
			}
			break;
		}
	}
1752

1753
 unlock:
1754
	snd_pcm_stream_unlock_irq(substream);
1755
	up_read(&snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
	snd_power_unlock(card);

	return result;
}

/*
 * drop ioctl
 *
 * Immediately put all linked substreams into SETUP state.
 */
T
Takashi Iwai 已提交
1766
static int snd_pcm_drop(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1767
{
T
Takashi Iwai 已提交
1768
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
1769 1770
	int result = 0;
	
1771 1772
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
1773 1774
	runtime = substream->runtime;

1775
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1776 1777
	    runtime->status->state == SNDRV_PCM_STATE_DISCONNECTED ||
	    runtime->status->state == SNDRV_PCM_STATE_SUSPENDED)
L
Linus Torvalds 已提交
1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
		return -EBADFD;

	snd_pcm_stream_lock_irq(substream);
	/* resume pause */
	if (runtime->status->state == SNDRV_PCM_STATE_PAUSED)
		snd_pcm_pause(substream, 0);

	snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP);
	/* runtime->control->appl_ptr = runtime->status->hw_ptr; */
	snd_pcm_stream_unlock_irq(substream);
1788

L
Linus Torvalds 已提交
1789 1790 1791 1792
	return result;
}


A
Al Viro 已提交
1793
static bool is_pcm_file(struct file *file)
L
Linus Torvalds 已提交
1794
{
A
Al Viro 已提交
1795
	struct inode *inode = file_inode(file);
1796 1797
	unsigned int minor;

A
Al Viro 已提交
1798 1799
	if (!S_ISCHR(inode->i_mode) || imajor(inode) != snd_major)
		return false;
L
Linus Torvalds 已提交
1800
	minor = iminor(inode);
A
Al Viro 已提交
1801 1802
	return snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_PLAYBACK) ||
		snd_lookup_minor_data(minor, SNDRV_DEVICE_TYPE_PCM_CAPTURE);
L
Linus Torvalds 已提交
1803 1804 1805 1806 1807
}

/*
 * PCM link handling
 */
T
Takashi Iwai 已提交
1808
static int snd_pcm_link(struct snd_pcm_substream *substream, int fd)
L
Linus Torvalds 已提交
1809 1810
{
	int res = 0;
T
Takashi Iwai 已提交
1811 1812
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream1;
1813
	struct snd_pcm_group *group;
A
Al Viro 已提交
1814
	struct fd f = fdget(fd);
L
Linus Torvalds 已提交
1815

A
Al Viro 已提交
1816
	if (!f.file)
L
Linus Torvalds 已提交
1817
		return -EBADFD;
A
Al Viro 已提交
1818 1819 1820 1821 1822
	if (!is_pcm_file(f.file)) {
		res = -EBADFD;
		goto _badf;
	}
	pcm_file = f.file->private_data;
L
Linus Torvalds 已提交
1823
	substream1 = pcm_file->substream;
1824 1825 1826 1827 1828
	group = kmalloc(sizeof(*group), GFP_KERNEL);
	if (!group) {
		res = -ENOMEM;
		goto _nolock;
	}
1829
	down_write_nonblock(&snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
1830 1831
	write_lock_irq(&snd_pcm_link_rwlock);
	if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN ||
1832 1833
	    substream->runtime->status->state != substream1->runtime->status->state ||
	    substream->pcm->nonatomic != substream1->pcm->nonatomic) {
L
Linus Torvalds 已提交
1834 1835 1836 1837 1838 1839 1840 1841
		res = -EBADFD;
		goto _end;
	}
	if (snd_pcm_stream_linked(substream1)) {
		res = -EALREADY;
		goto _end;
	}
	if (!snd_pcm_stream_linked(substream)) {
1842
		substream->group = group;
A
Al Viro 已提交
1843
		group = NULL;
L
Linus Torvalds 已提交
1844
		spin_lock_init(&substream->group->lock);
1845
		mutex_init(&substream->group->mutex);
L
Linus Torvalds 已提交
1846 1847 1848 1849 1850 1851 1852 1853 1854 1855
		INIT_LIST_HEAD(&substream->group->substreams);
		list_add_tail(&substream->link_list, &substream->group->substreams);
		substream->group->count = 1;
	}
	list_add_tail(&substream1->link_list, &substream->group->substreams);
	substream->group->count++;
	substream1->group = substream->group;
 _end:
	write_unlock_irq(&snd_pcm_link_rwlock);
	up_write(&snd_pcm_link_rwsem);
1856
 _nolock:
1857
	snd_card_unref(substream1->pcm->card);
A
Al Viro 已提交
1858
	kfree(group);
A
Al Viro 已提交
1859 1860
 _badf:
	fdput(f);
L
Linus Torvalds 已提交
1861 1862 1863
	return res;
}

T
Takashi Iwai 已提交
1864
static void relink_to_local(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1865 1866 1867 1868 1869 1870
{
	substream->group = &substream->self_group;
	INIT_LIST_HEAD(&substream->self_group.substreams);
	list_add_tail(&substream->link_list, &substream->self_group.substreams);
}

T
Takashi Iwai 已提交
1871
static int snd_pcm_unlink(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
1872
{
1873
	struct snd_pcm_substream *s;
L
Linus Torvalds 已提交
1874 1875
	int res = 0;

1876
	down_write_nonblock(&snd_pcm_link_rwsem);
L
Linus Torvalds 已提交
1877 1878 1879 1880 1881 1882 1883 1884
	write_lock_irq(&snd_pcm_link_rwlock);
	if (!snd_pcm_stream_linked(substream)) {
		res = -EALREADY;
		goto _end;
	}
	list_del(&substream->link_list);
	substream->group->count--;
	if (substream->group->count == 1) {	/* detach the last stream, too */
1885 1886
		snd_pcm_group_for_each_entry(s, substream) {
			relink_to_local(s);
L
Linus Torvalds 已提交
1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900
			break;
		}
		kfree(substream->group);
	}
	relink_to_local(substream);
       _end:
	write_unlock_irq(&snd_pcm_link_rwlock);
	up_write(&snd_pcm_link_rwsem);
	return res;
}

/*
 * hw configurator
 */
T
Takashi Iwai 已提交
1901 1902
static int snd_pcm_hw_rule_mul(struct snd_pcm_hw_params *params,
			       struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1903
{
T
Takashi Iwai 已提交
1904
	struct snd_interval t;
L
Linus Torvalds 已提交
1905 1906 1907 1908 1909
	snd_interval_mul(hw_param_interval_c(params, rule->deps[0]),
		     hw_param_interval_c(params, rule->deps[1]), &t);
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}

T
Takashi Iwai 已提交
1910 1911
static int snd_pcm_hw_rule_div(struct snd_pcm_hw_params *params,
			       struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1912
{
T
Takashi Iwai 已提交
1913
	struct snd_interval t;
L
Linus Torvalds 已提交
1914 1915 1916 1917 1918
	snd_interval_div(hw_param_interval_c(params, rule->deps[0]),
		     hw_param_interval_c(params, rule->deps[1]), &t);
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}

T
Takashi Iwai 已提交
1919 1920
static int snd_pcm_hw_rule_muldivk(struct snd_pcm_hw_params *params,
				   struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1921
{
T
Takashi Iwai 已提交
1922
	struct snd_interval t;
L
Linus Torvalds 已提交
1923 1924 1925 1926 1927 1928
	snd_interval_muldivk(hw_param_interval_c(params, rule->deps[0]),
			 hw_param_interval_c(params, rule->deps[1]),
			 (unsigned long) rule->private, &t);
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}

T
Takashi Iwai 已提交
1929 1930
static int snd_pcm_hw_rule_mulkdiv(struct snd_pcm_hw_params *params,
				   struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1931
{
T
Takashi Iwai 已提交
1932
	struct snd_interval t;
L
Linus Torvalds 已提交
1933 1934 1935 1936 1937 1938
	snd_interval_mulkdiv(hw_param_interval_c(params, rule->deps[0]),
			 (unsigned long) rule->private,
			 hw_param_interval_c(params, rule->deps[1]), &t);
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}

T
Takashi Iwai 已提交
1939 1940
static int snd_pcm_hw_rule_format(struct snd_pcm_hw_params *params,
				  struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1941 1942
{
	unsigned int k;
T
Takashi Iwai 已提交
1943 1944 1945
	struct snd_interval *i = hw_param_interval(params, rule->deps[0]);
	struct snd_mask m;
	struct snd_mask *mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
L
Linus Torvalds 已提交
1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959
	snd_mask_any(&m);
	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
		int bits;
		if (! snd_mask_test(mask, k))
			continue;
		bits = snd_pcm_format_physical_width(k);
		if (bits <= 0)
			continue; /* ignore invalid formats */
		if ((unsigned)bits < i->min || (unsigned)bits > i->max)
			snd_mask_reset(&m, k);
	}
	return snd_mask_refine(mask, &m);
}

T
Takashi Iwai 已提交
1960 1961
static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
				       struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
1962
{
T
Takashi Iwai 已提交
1963
	struct snd_interval t;
L
Linus Torvalds 已提交
1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988
	unsigned int k;
	t.min = UINT_MAX;
	t.max = 0;
	t.openmin = 0;
	t.openmax = 0;
	for (k = 0; k <= SNDRV_PCM_FORMAT_LAST; ++k) {
		int bits;
		if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k))
			continue;
		bits = snd_pcm_format_physical_width(k);
		if (bits <= 0)
			continue; /* ignore invalid formats */
		if (t.min > (unsigned)bits)
			t.min = bits;
		if (t.max < (unsigned)bits)
			t.max = bits;
	}
	t.integer = 1;
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}

#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12
#error "Change this table"
#endif

1989 1990 1991 1992
static const unsigned int rates[] = {
	5512, 8000, 11025, 16000, 22050, 32000, 44100,
	48000, 64000, 88200, 96000, 176400, 192000
};
L
Linus Torvalds 已提交
1993

1994 1995 1996 1997 1998
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
	.count = ARRAY_SIZE(rates),
	.list = rates,
};

T
Takashi Iwai 已提交
1999 2000
static int snd_pcm_hw_rule_rate(struct snd_pcm_hw_params *params,
				struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
2001
{
T
Takashi Iwai 已提交
2002
	struct snd_pcm_hardware *hw = rule->private;
L
Linus Torvalds 已提交
2003
	return snd_interval_list(hw_param_interval(params, rule->var),
2004 2005
				 snd_pcm_known_rates.count,
				 snd_pcm_known_rates.list, hw->rates);
L
Linus Torvalds 已提交
2006 2007
}		

T
Takashi Iwai 已提交
2008 2009
static int snd_pcm_hw_rule_buffer_bytes_max(struct snd_pcm_hw_params *params,
					    struct snd_pcm_hw_rule *rule)
L
Linus Torvalds 已提交
2010
{
T
Takashi Iwai 已提交
2011 2012
	struct snd_interval t;
	struct snd_pcm_substream *substream = rule->private;
L
Linus Torvalds 已提交
2013 2014 2015 2016 2017 2018 2019 2020
	t.min = 0;
	t.max = substream->buffer_bytes_max;
	t.openmin = 0;
	t.openmax = 0;
	t.integer = 1;
	return snd_interval_refine(hw_param_interval(params, rule->var), &t);
}		

T
Takashi Iwai 已提交
2021
int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
2022
{
T
Takashi Iwai 已提交
2023 2024
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
L
Linus Torvalds 已提交
2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144
	int k, err;

	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
		snd_mask_any(constrs_mask(constrs, k));
	}

	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
		snd_interval_any(constrs_interval(constrs, k));
	}

	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS));

	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
				   snd_pcm_hw_rule_format, NULL,
				   SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 
				  snd_pcm_hw_rule_sample_bits, NULL,
				  SNDRV_PCM_HW_PARAM_FORMAT, 
				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 
				  snd_pcm_hw_rule_div, NULL,
				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 
				  snd_pcm_hw_rule_mul, NULL,
				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 8,
				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 8,
				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 
				  snd_pcm_hw_rule_div, NULL,
				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_TIME, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_BUFFER_TIME, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIODS, 
				  snd_pcm_hw_rule_div, NULL,
				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 
				  snd_pcm_hw_rule_div, NULL,
				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 8,
				  SNDRV_PCM_HW_PARAM_PERIOD_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 
				  snd_pcm_hw_rule_muldivk, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_PERIOD_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 
				  snd_pcm_hw_rule_mul, NULL,
				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_PERIODS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 8,
				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 
				  snd_pcm_hw_rule_muldivk, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_BUFFER_TIME, SNDRV_PCM_HW_PARAM_RATE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 
				  snd_pcm_hw_rule_muldivk, (void*) 8,
				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 
				  snd_pcm_hw_rule_muldivk, (void*) 8,
				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_FRAME_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_PERIOD_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_TIME, 
				  snd_pcm_hw_rule_mulkdiv, (void*) 1000000,
				  SNDRV_PCM_HW_PARAM_BUFFER_SIZE, SNDRV_PCM_HW_PARAM_RATE, -1);
	if (err < 0)
		return err;
	return 0;
}

T
Takashi Iwai 已提交
2145
int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
2146
{
T
Takashi Iwai 已提交
2147 2148
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_hardware *hw = &runtime->hw;
L
Linus Torvalds 已提交
2149 2150 2151 2152 2153 2154 2155
	int err;
	unsigned int mask = 0;

        if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
		mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
        if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
		mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
2156
	if (hw_support_mmap(substream)) {
L
Linus Torvalds 已提交
2157 2158 2159 2160 2161 2162 2163 2164
		if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
		if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_NONINTERLEAVED;
		if (hw->info & SNDRV_PCM_INFO_COMPLEX)
			mask |= 1 << SNDRV_PCM_ACCESS_MMAP_COMPLEX;
	}
	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_ACCESS, mask);
2165 2166
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2167 2168

	err = snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT, hw->formats);
2169 2170
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2171 2172

	err = snd_pcm_hw_constraint_mask(runtime, SNDRV_PCM_HW_PARAM_SUBFORMAT, 1 << SNDRV_PCM_SUBFORMAT_STD);
2173 2174
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2175 2176 2177

	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_CHANNELS,
					   hw->channels_min, hw->channels_max);
2178 2179
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2180 2181 2182

	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE,
					   hw->rate_min, hw->rate_max);
2183 2184
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2185 2186 2187

	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
					   hw->period_bytes_min, hw->period_bytes_max);
2188 2189
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2190 2191 2192

	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIODS,
					   hw->periods_min, hw->periods_max);
2193 2194
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2195 2196 2197

	err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES,
					   hw->period_bytes_min, hw->buffer_bytes_max);
2198 2199
	if (err < 0)
		return err;
L
Linus Torvalds 已提交
2200 2201 2202 2203 2204 2205 2206 2207 2208 2209

	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 
				  snd_pcm_hw_rule_buffer_bytes_max, substream,
				  SNDRV_PCM_HW_PARAM_BUFFER_BYTES, -1);
	if (err < 0)
		return err;

	/* FIXME: remove */
	if (runtime->dma_bytes) {
		err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 0, runtime->dma_bytes);
2210
		if (err < 0)
2211
			return err;
L
Linus Torvalds 已提交
2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227
	}

	if (!(hw->rates & (SNDRV_PCM_RATE_KNOT | SNDRV_PCM_RATE_CONTINUOUS))) {
		err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 
					  snd_pcm_hw_rule_rate, hw,
					  SNDRV_PCM_HW_PARAM_RATE, -1);
		if (err < 0)
			return err;
	}

	/* FIXME: this belong to lowlevel */
	snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE);

	return 0;
}

2228
static void pcm_release_private(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
2229 2230
{
	snd_pcm_unlink(substream);
2231 2232 2233 2234
}

void snd_pcm_release_substream(struct snd_pcm_substream *substream)
{
2235 2236 2237 2238
	substream->ref_count--;
	if (substream->ref_count > 0)
		return;

2239 2240
	snd_pcm_drop(substream);
	if (substream->hw_opened) {
2241 2242
		if (substream->ops->hw_free &&
		    substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
L
Linus Torvalds 已提交
2243 2244
			substream->ops->hw_free(substream);
		substream->ops->close(substream);
2245
		substream->hw_opened = 0;
L
Linus Torvalds 已提交
2246
	}
2247 2248
	if (pm_qos_request_active(&substream->latency_pm_qos_req))
		pm_qos_remove_request(&substream->latency_pm_qos_req);
2249 2250 2251 2252
	if (substream->pcm_release) {
		substream->pcm_release(substream);
		substream->pcm_release = NULL;
	}
2253 2254 2255
	snd_pcm_detach_substream(substream);
}

2256 2257
EXPORT_SYMBOL(snd_pcm_release_substream);

2258 2259 2260 2261 2262 2263 2264 2265 2266 2267
int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
			   struct file *file,
			   struct snd_pcm_substream **rsubstream)
{
	struct snd_pcm_substream *substream;
	int err;

	err = snd_pcm_attach_substream(pcm, stream, file, &substream);
	if (err < 0)
		return err;
2268 2269 2270 2271 2272
	if (substream->ref_count > 1) {
		*rsubstream = substream;
		return 0;
	}

2273 2274
	err = snd_pcm_hw_constraints_init(substream);
	if (err < 0) {
2275
		pcm_dbg(pcm, "snd_pcm_hw_constraints_init failed\n");
2276 2277 2278 2279 2280 2281 2282 2283 2284 2285
		goto error;
	}

	if ((err = substream->ops->open(substream)) < 0)
		goto error;

	substream->hw_opened = 1;

	err = snd_pcm_hw_constraints_complete(substream);
	if (err < 0) {
2286
		pcm_dbg(pcm, "snd_pcm_hw_constraints_complete failed\n");
2287 2288 2289 2290
		goto error;
	}

	*rsubstream = substream;
L
Linus Torvalds 已提交
2291
	return 0;
2292 2293 2294 2295

 error:
	snd_pcm_release_substream(substream);
	return err;
L
Linus Torvalds 已提交
2296 2297
}

2298 2299
EXPORT_SYMBOL(snd_pcm_open_substream);

L
Linus Torvalds 已提交
2300
static int snd_pcm_open_file(struct file *file,
T
Takashi Iwai 已提交
2301
			     struct snd_pcm *pcm,
2302
			     int stream)
L
Linus Torvalds 已提交
2303
{
T
Takashi Iwai 已提交
2304 2305
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
2306
	int err;
L
Linus Torvalds 已提交
2307

2308 2309 2310 2311
	err = snd_pcm_open_substream(pcm, stream, file, &substream);
	if (err < 0)
		return err;

2312 2313 2314 2315 2316 2317 2318
	pcm_file = kzalloc(sizeof(*pcm_file), GFP_KERNEL);
	if (pcm_file == NULL) {
		snd_pcm_release_substream(substream);
		return -ENOMEM;
	}
	pcm_file->substream = substream;
	if (substream->ref_count == 1) {
2319 2320
		substream->file = pcm_file;
		substream->pcm_release = pcm_release_private;
L
Linus Torvalds 已提交
2321 2322
	}
	file->private_data = pcm_file;
2323

L
Linus Torvalds 已提交
2324 2325 2326
	return 0;
}

2327 2328 2329
static int snd_pcm_playback_open(struct inode *inode, struct file *file)
{
	struct snd_pcm *pcm;
T
Takashi Iwai 已提交
2330 2331 2332
	int err = nonseekable_open(inode, file);
	if (err < 0)
		return err;
2333 2334
	pcm = snd_lookup_minor_data(iminor(inode),
				    SNDRV_DEVICE_TYPE_PCM_PLAYBACK);
2335
	err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_PLAYBACK);
T
Takashi Iwai 已提交
2336 2337
	if (pcm)
		snd_card_unref(pcm->card);
2338
	return err;
2339 2340 2341
}

static int snd_pcm_capture_open(struct inode *inode, struct file *file)
L
Linus Torvalds 已提交
2342
{
T
Takashi Iwai 已提交
2343
	struct snd_pcm *pcm;
T
Takashi Iwai 已提交
2344 2345 2346
	int err = nonseekable_open(inode, file);
	if (err < 0)
		return err;
2347 2348
	pcm = snd_lookup_minor_data(iminor(inode),
				    SNDRV_DEVICE_TYPE_PCM_CAPTURE);
2349
	err = snd_pcm_open(file, pcm, SNDRV_PCM_STREAM_CAPTURE);
T
Takashi Iwai 已提交
2350 2351
	if (pcm)
		snd_card_unref(pcm->card);
2352
	return err;
2353 2354 2355 2356 2357
}

static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream)
{
	int err;
L
Linus Torvalds 已提交
2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372
	wait_queue_t wait;

	if (pcm == NULL) {
		err = -ENODEV;
		goto __error1;
	}
	err = snd_card_file_add(pcm->card, file);
	if (err < 0)
		goto __error1;
	if (!try_module_get(pcm->card->module)) {
		err = -EFAULT;
		goto __error2;
	}
	init_waitqueue_entry(&wait, current);
	add_wait_queue(&pcm->open_wait, &wait);
2373
	mutex_lock(&pcm->open_mutex);
L
Linus Torvalds 已提交
2374
	while (1) {
2375
		err = snd_pcm_open_file(file, pcm, stream);
L
Linus Torvalds 已提交
2376 2377 2378 2379 2380 2381 2382 2383 2384 2385
		if (err >= 0)
			break;
		if (err == -EAGAIN) {
			if (file->f_flags & O_NONBLOCK) {
				err = -EBUSY;
				break;
			}
		} else
			break;
		set_current_state(TASK_INTERRUPTIBLE);
2386
		mutex_unlock(&pcm->open_mutex);
L
Linus Torvalds 已提交
2387
		schedule();
2388
		mutex_lock(&pcm->open_mutex);
2389 2390 2391 2392
		if (pcm->card->shutdown) {
			err = -ENODEV;
			break;
		}
L
Linus Torvalds 已提交
2393 2394 2395 2396 2397 2398
		if (signal_pending(current)) {
			err = -ERESTARTSYS;
			break;
		}
	}
	remove_wait_queue(&pcm->open_wait, &wait);
2399
	mutex_unlock(&pcm->open_mutex);
L
Linus Torvalds 已提交
2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413
	if (err < 0)
		goto __error;
	return err;

      __error:
	module_put(pcm->card->module);
      __error2:
      	snd_card_file_remove(pcm->card, file);
      __error1:
      	return err;
}

static int snd_pcm_release(struct inode *inode, struct file *file)
{
T
Takashi Iwai 已提交
2414 2415 2416
	struct snd_pcm *pcm;
	struct snd_pcm_substream *substream;
	struct snd_pcm_file *pcm_file;
L
Linus Torvalds 已提交
2417 2418 2419

	pcm_file = file->private_data;
	substream = pcm_file->substream;
2420 2421
	if (snd_BUG_ON(!substream))
		return -ENXIO;
L
Linus Torvalds 已提交
2422
	pcm = substream->pcm;
2423
	mutex_lock(&pcm->open_mutex);
2424
	snd_pcm_release_substream(substream);
2425
	kfree(pcm_file);
2426
	mutex_unlock(&pcm->open_mutex);
L
Linus Torvalds 已提交
2427 2428 2429 2430 2431 2432
	wake_up(&pcm->open_wait);
	module_put(pcm->card->module);
	snd_card_file_remove(pcm->card, file);
	return 0;
}

T
Takashi Iwai 已提交
2433 2434
static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream,
						 snd_pcm_uframes_t frames)
L
Linus Torvalds 已提交
2435
{
T
Takashi Iwai 已提交
2436
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455
	snd_pcm_sframes_t appl_ptr;
	snd_pcm_sframes_t ret;
	snd_pcm_sframes_t hw_avail;

	if (frames == 0)
		return 0;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_PREPARED:
		break;
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_RUNNING:
		if (snd_pcm_update_hw_ptr(substream) >= 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_XRUN:
		ret = -EPIPE;
		goto __end;
2456 2457 2458
	case SNDRV_PCM_STATE_SUSPENDED:
		ret = -ESTRPIPE;
		goto __end;
L
Linus Torvalds 已提交
2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480
	default:
		ret = -EBADFD;
		goto __end;
	}

	hw_avail = snd_pcm_playback_hw_avail(runtime);
	if (hw_avail <= 0) {
		ret = 0;
		goto __end;
	}
	if (frames > (snd_pcm_uframes_t)hw_avail)
		frames = hw_avail;
	appl_ptr = runtime->control->appl_ptr - frames;
	if (appl_ptr < 0)
		appl_ptr += runtime->boundary;
	runtime->control->appl_ptr = appl_ptr;
	ret = frames;
 __end:
	snd_pcm_stream_unlock_irq(substream);
	return ret;
}

T
Takashi Iwai 已提交
2481 2482
static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream,
						snd_pcm_uframes_t frames)
L
Linus Torvalds 已提交
2483
{
T
Takashi Iwai 已提交
2484
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503
	snd_pcm_sframes_t appl_ptr;
	snd_pcm_sframes_t ret;
	snd_pcm_sframes_t hw_avail;

	if (frames == 0)
		return 0;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_DRAINING:
		break;
	case SNDRV_PCM_STATE_RUNNING:
		if (snd_pcm_update_hw_ptr(substream) >= 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_XRUN:
		ret = -EPIPE;
		goto __end;
2504 2505 2506
	case SNDRV_PCM_STATE_SUSPENDED:
		ret = -ESTRPIPE;
		goto __end;
L
Linus Torvalds 已提交
2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528
	default:
		ret = -EBADFD;
		goto __end;
	}

	hw_avail = snd_pcm_capture_hw_avail(runtime);
	if (hw_avail <= 0) {
		ret = 0;
		goto __end;
	}
	if (frames > (snd_pcm_uframes_t)hw_avail)
		frames = hw_avail;
	appl_ptr = runtime->control->appl_ptr - frames;
	if (appl_ptr < 0)
		appl_ptr += runtime->boundary;
	runtime->control->appl_ptr = appl_ptr;
	ret = frames;
 __end:
	snd_pcm_stream_unlock_irq(substream);
	return ret;
}

T
Takashi Iwai 已提交
2529 2530
static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream,
						  snd_pcm_uframes_t frames)
L
Linus Torvalds 已提交
2531
{
T
Takashi Iwai 已提交
2532
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
	snd_pcm_sframes_t appl_ptr;
	snd_pcm_sframes_t ret;
	snd_pcm_sframes_t avail;

	if (frames == 0)
		return 0;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_PAUSED:
		break;
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_RUNNING:
		if (snd_pcm_update_hw_ptr(substream) >= 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_XRUN:
		ret = -EPIPE;
		goto __end;
2553 2554 2555
	case SNDRV_PCM_STATE_SUSPENDED:
		ret = -ESTRPIPE;
		goto __end;
L
Linus Torvalds 已提交
2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577
	default:
		ret = -EBADFD;
		goto __end;
	}

	avail = snd_pcm_playback_avail(runtime);
	if (avail <= 0) {
		ret = 0;
		goto __end;
	}
	if (frames > (snd_pcm_uframes_t)avail)
		frames = avail;
	appl_ptr = runtime->control->appl_ptr + frames;
	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
		appl_ptr -= runtime->boundary;
	runtime->control->appl_ptr = appl_ptr;
	ret = frames;
 __end:
	snd_pcm_stream_unlock_irq(substream);
	return ret;
}

T
Takashi Iwai 已提交
2578 2579
static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream,
						 snd_pcm_uframes_t frames)
L
Linus Torvalds 已提交
2580
{
T
Takashi Iwai 已提交
2581
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601
	snd_pcm_sframes_t appl_ptr;
	snd_pcm_sframes_t ret;
	snd_pcm_sframes_t avail;

	if (frames == 0)
		return 0;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_DRAINING:
	case SNDRV_PCM_STATE_PAUSED:
		break;
	case SNDRV_PCM_STATE_RUNNING:
		if (snd_pcm_update_hw_ptr(substream) >= 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_XRUN:
		ret = -EPIPE;
		goto __end;
2602 2603 2604
	case SNDRV_PCM_STATE_SUSPENDED:
		ret = -ESTRPIPE;
		goto __end;
L
Linus Torvalds 已提交
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626
	default:
		ret = -EBADFD;
		goto __end;
	}

	avail = snd_pcm_capture_avail(runtime);
	if (avail <= 0) {
		ret = 0;
		goto __end;
	}
	if (frames > (snd_pcm_uframes_t)avail)
		frames = avail;
	appl_ptr = runtime->control->appl_ptr + frames;
	if (appl_ptr >= (snd_pcm_sframes_t)runtime->boundary)
		appl_ptr -= runtime->boundary;
	runtime->control->appl_ptr = appl_ptr;
	ret = frames;
 __end:
	snd_pcm_stream_unlock_irq(substream);
	return ret;
}

T
Takashi Iwai 已提交
2627
static int snd_pcm_hwsync(struct snd_pcm_substream *substream)
L
Linus Torvalds 已提交
2628
{
T
Takashi Iwai 已提交
2629
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2630 2631 2632 2633 2634 2635 2636
	int err;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_DRAINING:
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
			goto __badfd;
T
Takashi Iwai 已提交
2637
		/* Fall through */
L
Linus Torvalds 已提交
2638 2639 2640 2641 2642 2643 2644
	case SNDRV_PCM_STATE_RUNNING:
		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_PREPARED:
		err = 0;
		break;
2645 2646 2647
	case SNDRV_PCM_STATE_SUSPENDED:
		err = -ESTRPIPE;
		break;
L
Linus Torvalds 已提交
2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659
	case SNDRV_PCM_STATE_XRUN:
		err = -EPIPE;
		break;
	default:
	      __badfd:
		err = -EBADFD;
		break;
	}
	snd_pcm_stream_unlock_irq(substream);
	return err;
}
		
T
Takashi Iwai 已提交
2660 2661
static int snd_pcm_delay(struct snd_pcm_substream *substream,
			 snd_pcm_sframes_t __user *res)
L
Linus Torvalds 已提交
2662
{
T
Takashi Iwai 已提交
2663
	struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2664 2665 2666 2667 2668 2669 2670 2671
	int err;
	snd_pcm_sframes_t n = 0;

	snd_pcm_stream_lock_irq(substream);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_DRAINING:
		if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
			goto __badfd;
T
Takashi Iwai 已提交
2672
		/* Fall through */
L
Linus Torvalds 已提交
2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683
	case SNDRV_PCM_STATE_RUNNING:
		if ((err = snd_pcm_update_hw_ptr(substream)) < 0)
			break;
		/* Fall through */
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_SUSPENDED:
		err = 0;
		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
			n = snd_pcm_playback_hw_avail(runtime);
		else
			n = snd_pcm_capture_avail(runtime);
2684
		n += runtime->delay;
L
Linus Torvalds 已提交
2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700
		break;
	case SNDRV_PCM_STATE_XRUN:
		err = -EPIPE;
		break;
	default:
	      __badfd:
		err = -EBADFD;
		break;
	}
	snd_pcm_stream_unlock_irq(substream);
	if (!err)
		if (put_user(n, res))
			err = -EFAULT;
	return err;
}
		
T
Takashi Iwai 已提交
2701 2702
static int snd_pcm_sync_ptr(struct snd_pcm_substream *substream,
			    struct snd_pcm_sync_ptr __user *_sync_ptr)
L
Linus Torvalds 已提交
2703
{
T
Takashi Iwai 已提交
2704 2705 2706 2707
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_sync_ptr sync_ptr;
	volatile struct snd_pcm_mmap_status *status;
	volatile struct snd_pcm_mmap_control *control;
L
Linus Torvalds 已提交
2708 2709 2710 2711 2712
	int err;

	memset(&sync_ptr, 0, sizeof(sync_ptr));
	if (get_user(sync_ptr.flags, (unsigned __user *)&(_sync_ptr->flags)))
		return -EFAULT;
T
Takashi Iwai 已提交
2713
	if (copy_from_user(&sync_ptr.c.control, &(_sync_ptr->c.control), sizeof(struct snd_pcm_mmap_control)))
L
Linus Torvalds 已提交
2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739
		return -EFAULT;	
	status = runtime->status;
	control = runtime->control;
	if (sync_ptr.flags & SNDRV_PCM_SYNC_PTR_HWSYNC) {
		err = snd_pcm_hwsync(substream);
		if (err < 0)
			return err;
	}
	snd_pcm_stream_lock_irq(substream);
	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_APPL))
		control->appl_ptr = sync_ptr.c.control.appl_ptr;
	else
		sync_ptr.c.control.appl_ptr = control->appl_ptr;
	if (!(sync_ptr.flags & SNDRV_PCM_SYNC_PTR_AVAIL_MIN))
		control->avail_min = sync_ptr.c.control.avail_min;
	else
		sync_ptr.c.control.avail_min = control->avail_min;
	sync_ptr.s.status.state = status->state;
	sync_ptr.s.status.hw_ptr = status->hw_ptr;
	sync_ptr.s.status.tstamp = status->tstamp;
	sync_ptr.s.status.suspended_state = status->suspended_state;
	snd_pcm_stream_unlock_irq(substream);
	if (copy_to_user(_sync_ptr, &sync_ptr, sizeof(sync_ptr)))
		return -EFAULT;
	return 0;
}
2740 2741 2742 2743 2744 2745 2746 2747 2748 2749

static int snd_pcm_tstamp(struct snd_pcm_substream *substream, int __user *_arg)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	int arg;
	
	if (get_user(arg, _arg))
		return -EFAULT;
	if (arg < 0 || arg > SNDRV_PCM_TSTAMP_TYPE_LAST)
		return -EINVAL;
2750
	runtime->tstamp_type = arg;
2751 2752
	return 0;
}
L
Linus Torvalds 已提交
2753
		
2754 2755
static int snd_pcm_common_ioctl1(struct file *file,
				 struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
2756 2757 2758 2759 2760 2761 2762
				 unsigned int cmd, void __user *arg)
{
	switch (cmd) {
	case SNDRV_PCM_IOCTL_PVERSION:
		return put_user(SNDRV_PCM_VERSION, (int __user *)arg) ? -EFAULT : 0;
	case SNDRV_PCM_IOCTL_INFO:
		return snd_pcm_info_user(substream, arg);
2763 2764
	case SNDRV_PCM_IOCTL_TSTAMP:	/* just for compatibility */
		return 0;
2765 2766
	case SNDRV_PCM_IOCTL_TTSTAMP:
		return snd_pcm_tstamp(substream, arg);
L
Linus Torvalds 已提交
2767 2768 2769 2770 2771 2772 2773 2774 2775
	case SNDRV_PCM_IOCTL_HW_REFINE:
		return snd_pcm_hw_refine_user(substream, arg);
	case SNDRV_PCM_IOCTL_HW_PARAMS:
		return snd_pcm_hw_params_user(substream, arg);
	case SNDRV_PCM_IOCTL_HW_FREE:
		return snd_pcm_hw_free(substream);
	case SNDRV_PCM_IOCTL_SW_PARAMS:
		return snd_pcm_sw_params_user(substream, arg);
	case SNDRV_PCM_IOCTL_STATUS:
2776 2777 2778
		return snd_pcm_status_user(substream, arg, false);
	case SNDRV_PCM_IOCTL_STATUS_EXT:
		return snd_pcm_status_user(substream, arg, true);
L
Linus Torvalds 已提交
2779 2780 2781
	case SNDRV_PCM_IOCTL_CHANNEL_INFO:
		return snd_pcm_channel_info_user(substream, arg);
	case SNDRV_PCM_IOCTL_PREPARE:
2782
		return snd_pcm_prepare(substream, file);
L
Linus Torvalds 已提交
2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800
	case SNDRV_PCM_IOCTL_RESET:
		return snd_pcm_reset(substream);
	case SNDRV_PCM_IOCTL_START:
		return snd_pcm_action_lock_irq(&snd_pcm_action_start, substream, SNDRV_PCM_STATE_RUNNING);
	case SNDRV_PCM_IOCTL_LINK:
		return snd_pcm_link(substream, (int)(unsigned long) arg);
	case SNDRV_PCM_IOCTL_UNLINK:
		return snd_pcm_unlink(substream);
	case SNDRV_PCM_IOCTL_RESUME:
		return snd_pcm_resume(substream);
	case SNDRV_PCM_IOCTL_XRUN:
		return snd_pcm_xrun(substream);
	case SNDRV_PCM_IOCTL_HWSYNC:
		return snd_pcm_hwsync(substream);
	case SNDRV_PCM_IOCTL_DELAY:
		return snd_pcm_delay(substream, arg);
	case SNDRV_PCM_IOCTL_SYNC_PTR:
		return snd_pcm_sync_ptr(substream, arg);
2801
#ifdef CONFIG_SND_SUPPORT_OLD_API
L
Linus Torvalds 已提交
2802 2803 2804 2805
	case SNDRV_PCM_IOCTL_HW_REFINE_OLD:
		return snd_pcm_hw_refine_old_user(substream, arg);
	case SNDRV_PCM_IOCTL_HW_PARAMS_OLD:
		return snd_pcm_hw_params_old_user(substream, arg);
2806
#endif
L
Linus Torvalds 已提交
2807
	case SNDRV_PCM_IOCTL_DRAIN:
2808
		return snd_pcm_drain(substream, file);
L
Linus Torvalds 已提交
2809 2810
	case SNDRV_PCM_IOCTL_DROP:
		return snd_pcm_drop(substream);
2811 2812 2813 2814 2815 2816 2817 2818
	case SNDRV_PCM_IOCTL_PAUSE:
	{
		int res;
		snd_pcm_stream_lock_irq(substream);
		res = snd_pcm_pause(substream, (int)(unsigned long)arg);
		snd_pcm_stream_unlock_irq(substream);
		return res;
	}
L
Linus Torvalds 已提交
2819
	}
2820
	pcm_dbg(substream->pcm, "unknown ioctl = 0x%x\n", cmd);
L
Linus Torvalds 已提交
2821 2822 2823
	return -ENOTTY;
}

2824 2825
static int snd_pcm_playback_ioctl1(struct file *file,
				   struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
2826 2827
				   unsigned int cmd, void __user *arg)
{
2828 2829 2830 2831
	if (snd_BUG_ON(!substream))
		return -ENXIO;
	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_PLAYBACK))
		return -EINVAL;
L
Linus Torvalds 已提交
2832 2833 2834
	switch (cmd) {
	case SNDRV_PCM_IOCTL_WRITEI_FRAMES:
	{
T
Takashi Iwai 已提交
2835 2836 2837
		struct snd_xferi xferi;
		struct snd_xferi __user *_xferi = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (put_user(0, &_xferi->result))
			return -EFAULT;
		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
			return -EFAULT;
		result = snd_pcm_lib_write(substream, xferi.buf, xferi.frames);
		__put_user(result, &_xferi->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_WRITEN_FRAMES:
	{
T
Takashi Iwai 已提交
2851 2852 2853
		struct snd_xfern xfern;
		struct snd_xfern __user *_xfern = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2854 2855 2856 2857 2858 2859 2860 2861 2862 2863
		void __user **bufs;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (runtime->channels > 128)
			return -EINVAL;
		if (put_user(0, &_xfern->result))
			return -EFAULT;
		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
			return -EFAULT;
L
Li Zefan 已提交
2864 2865 2866 2867 2868

		bufs = memdup_user(xfern.bufs,
				   sizeof(void *) * runtime->channels);
		if (IS_ERR(bufs))
			return PTR_ERR(bufs);
L
Linus Torvalds 已提交
2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900
		result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
		kfree(bufs);
		__put_user(result, &_xfern->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_REWIND:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_playback_rewind(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_FORWARD:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_playback_forward(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	}
2901
	return snd_pcm_common_ioctl1(file, substream, cmd, arg);
L
Linus Torvalds 已提交
2902 2903
}

2904 2905
static int snd_pcm_capture_ioctl1(struct file *file,
				  struct snd_pcm_substream *substream,
L
Linus Torvalds 已提交
2906 2907
				  unsigned int cmd, void __user *arg)
{
2908 2909 2910 2911
	if (snd_BUG_ON(!substream))
		return -ENXIO;
	if (snd_BUG_ON(substream->stream != SNDRV_PCM_STREAM_CAPTURE))
		return -EINVAL;
L
Linus Torvalds 已提交
2912 2913 2914
	switch (cmd) {
	case SNDRV_PCM_IOCTL_READI_FRAMES:
	{
T
Takashi Iwai 已提交
2915 2916 2917
		struct snd_xferi xferi;
		struct snd_xferi __user *_xferi = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (put_user(0, &_xferi->result))
			return -EFAULT;
		if (copy_from_user(&xferi, _xferi, sizeof(xferi)))
			return -EFAULT;
		result = snd_pcm_lib_read(substream, xferi.buf, xferi.frames);
		__put_user(result, &_xferi->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_READN_FRAMES:
	{
T
Takashi Iwai 已提交
2931 2932 2933
		struct snd_xfern xfern;
		struct snd_xfern __user *_xfern = arg;
		struct snd_pcm_runtime *runtime = substream->runtime;
L
Linus Torvalds 已提交
2934 2935 2936 2937 2938 2939 2940 2941 2942 2943
		void *bufs;
		snd_pcm_sframes_t result;
		if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
			return -EBADFD;
		if (runtime->channels > 128)
			return -EINVAL;
		if (put_user(0, &_xfern->result))
			return -EFAULT;
		if (copy_from_user(&xfern, _xfern, sizeof(xfern)))
			return -EFAULT;
L
Li Zefan 已提交
2944 2945 2946 2947 2948

		bufs = memdup_user(xfern.bufs,
				   sizeof(void *) * runtime->channels);
		if (IS_ERR(bufs))
			return PTR_ERR(bufs);
L
Linus Torvalds 已提交
2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980
		result = snd_pcm_lib_readv(substream, bufs, xfern.frames);
		kfree(bufs);
		__put_user(result, &_xfern->result);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_REWIND:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_capture_rewind(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	case SNDRV_PCM_IOCTL_FORWARD:
	{
		snd_pcm_uframes_t frames;
		snd_pcm_uframes_t __user *_frames = arg;
		snd_pcm_sframes_t result;
		if (get_user(frames, _frames))
			return -EFAULT;
		if (put_user(0, _frames))
			return -EFAULT;
		result = snd_pcm_capture_forward(substream, frames);
		__put_user(result, _frames);
		return result < 0 ? result : 0;
	}
	}
2981
	return snd_pcm_common_ioctl1(file, substream, cmd, arg);
L
Linus Torvalds 已提交
2982 2983
}

T
Takashi Iwai 已提交
2984 2985
static long snd_pcm_playback_ioctl(struct file *file, unsigned int cmd,
				   unsigned long arg)
L
Linus Torvalds 已提交
2986
{
T
Takashi Iwai 已提交
2987
	struct snd_pcm_file *pcm_file;
L
Linus Torvalds 已提交
2988 2989 2990 2991 2992 2993

	pcm_file = file->private_data;

	if (((cmd >> 8) & 0xff) != 'A')
		return -ENOTTY;

2994 2995
	return snd_pcm_playback_ioctl1(file, pcm_file->substream, cmd,
				       (void __user *)arg);
L
Linus Torvalds 已提交
2996 2997
}

T
Takashi Iwai 已提交
2998 2999
static long snd_pcm_capture_ioctl(struct file *file, unsigned int cmd,
				  unsigned long arg)
L
Linus Torvalds 已提交
3000
{
T
Takashi Iwai 已提交
3001
	struct snd_pcm_file *pcm_file;
L
Linus Torvalds 已提交
3002 3003 3004 3005 3006 3007

	pcm_file = file->private_data;

	if (((cmd >> 8) & 0xff) != 'A')
		return -ENOTTY;

3008 3009
	return snd_pcm_capture_ioctl1(file, pcm_file->substream, cmd,
				      (void __user *)arg);
L
Linus Torvalds 已提交
3010 3011
}

T
Takashi Iwai 已提交
3012 3013
int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream,
			 unsigned int cmd, void *arg)
L
Linus Torvalds 已提交
3014 3015 3016 3017 3018 3019 3020
{
	mm_segment_t fs;
	int result;
	
	fs = snd_enter_user();
	switch (substream->stream) {
	case SNDRV_PCM_STREAM_PLAYBACK:
3021 3022
		result = snd_pcm_playback_ioctl1(NULL, substream, cmd,
						 (void __user *)arg);
T
Takashi Iwai 已提交
3023
		break;
L
Linus Torvalds 已提交
3024
	case SNDRV_PCM_STREAM_CAPTURE:
3025 3026
		result = snd_pcm_capture_ioctl1(NULL, substream, cmd,
						(void __user *)arg);
T
Takashi Iwai 已提交
3027
		break;
L
Linus Torvalds 已提交
3028
	default:
T
Takashi Iwai 已提交
3029 3030
		result = -EINVAL;
		break;
L
Linus Torvalds 已提交
3031
	}
T
Takashi Iwai 已提交
3032 3033
	snd_leave_user(fs);
	return result;
L
Linus Torvalds 已提交
3034 3035
}

3036 3037
EXPORT_SYMBOL(snd_pcm_kernel_ioctl);

T
Takashi Iwai 已提交
3038 3039
static ssize_t snd_pcm_read(struct file *file, char __user *buf, size_t count,
			    loff_t * offset)
L
Linus Torvalds 已提交
3040
{
T
Takashi Iwai 已提交
3041 3042 3043
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3044 3045 3046 3047
	snd_pcm_sframes_t result;

	pcm_file = file->private_data;
	substream = pcm_file->substream;
3048 3049
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 3060 3061
	runtime = substream->runtime;
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (!frame_aligned(runtime, count))
		return -EINVAL;
	count = bytes_to_frames(runtime, count);
	result = snd_pcm_lib_read(substream, buf, count);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	return result;
}

T
Takashi Iwai 已提交
3062 3063
static ssize_t snd_pcm_write(struct file *file, const char __user *buf,
			     size_t count, loff_t * offset)
L
Linus Torvalds 已提交
3064
{
T
Takashi Iwai 已提交
3065 3066 3067
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3068 3069 3070 3071
	snd_pcm_sframes_t result;

	pcm_file = file->private_data;
	substream = pcm_file->substream;
3072 3073
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
3074
	runtime = substream->runtime;
3075 3076 3077 3078
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (!frame_aligned(runtime, count))
		return -EINVAL;
L
Linus Torvalds 已提交
3079 3080 3081 3082 3083 3084 3085
	count = bytes_to_frames(runtime, count);
	result = snd_pcm_lib_write(substream, buf, count);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	return result;
}

A
Al Viro 已提交
3086
static ssize_t snd_pcm_readv(struct kiocb *iocb, struct iov_iter *to)
L
Linus Torvalds 已提交
3087
{
T
Takashi Iwai 已提交
3088 3089 3090
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3091 3092 3093 3094 3095
	snd_pcm_sframes_t result;
	unsigned long i;
	void __user **bufs;
	snd_pcm_uframes_t frames;

3096
	pcm_file = iocb->ki_filp->private_data;
L
Linus Torvalds 已提交
3097
	substream = pcm_file->substream;
3098 3099
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
3100 3101 3102
	runtime = substream->runtime;
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
A
Al Viro 已提交
3103 3104 3105
	if (!iter_is_iovec(to))
		return -EINVAL;
	if (to->nr_segs > 1024 || to->nr_segs != runtime->channels)
L
Linus Torvalds 已提交
3106
		return -EINVAL;
A
Al Viro 已提交
3107
	if (!frame_aligned(runtime, to->iov->iov_len))
L
Linus Torvalds 已提交
3108
		return -EINVAL;
A
Al Viro 已提交
3109 3110
	frames = bytes_to_samples(runtime, to->iov->iov_len);
	bufs = kmalloc(sizeof(void *) * to->nr_segs, GFP_KERNEL);
L
Linus Torvalds 已提交
3111 3112
	if (bufs == NULL)
		return -ENOMEM;
A
Al Viro 已提交
3113 3114
	for (i = 0; i < to->nr_segs; ++i)
		bufs[i] = to->iov[i].iov_base;
L
Linus Torvalds 已提交
3115 3116 3117 3118 3119 3120 3121
	result = snd_pcm_lib_readv(substream, bufs, frames);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	kfree(bufs);
	return result;
}

A
Al Viro 已提交
3122
static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from)
L
Linus Torvalds 已提交
3123
{
T
Takashi Iwai 已提交
3124 3125 3126
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3127 3128 3129 3130 3131
	snd_pcm_sframes_t result;
	unsigned long i;
	void __user **bufs;
	snd_pcm_uframes_t frames;

3132
	pcm_file = iocb->ki_filp->private_data;
L
Linus Torvalds 已提交
3133
	substream = pcm_file->substream;
3134 3135
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
3136
	runtime = substream->runtime;
3137 3138
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
A
Al Viro 已提交
3139 3140 3141 3142
	if (!iter_is_iovec(from))
		return -EINVAL;
	if (from->nr_segs > 128 || from->nr_segs != runtime->channels ||
	    !frame_aligned(runtime, from->iov->iov_len))
3143
		return -EINVAL;
A
Al Viro 已提交
3144 3145
	frames = bytes_to_samples(runtime, from->iov->iov_len);
	bufs = kmalloc(sizeof(void *) * from->nr_segs, GFP_KERNEL);
L
Linus Torvalds 已提交
3146 3147
	if (bufs == NULL)
		return -ENOMEM;
A
Al Viro 已提交
3148 3149
	for (i = 0; i < from->nr_segs; ++i)
		bufs[i] = from->iov[i].iov_base;
L
Linus Torvalds 已提交
3150 3151 3152 3153 3154 3155 3156 3157 3158
	result = snd_pcm_lib_writev(substream, bufs, frames);
	if (result > 0)
		result = frames_to_bytes(runtime, result);
	kfree(bufs);
	return result;
}

static unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait)
{
T
Takashi Iwai 已提交
3159 3160 3161
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3162 3163 3164 3165 3166 3167
        unsigned int mask;
	snd_pcm_uframes_t avail;

	pcm_file = file->private_data;

	substream = pcm_file->substream;
3168
	if (PCM_RUNTIME_CHECK(substream))
3169
		return POLLOUT | POLLWRNORM | POLLERR;
L
Linus Torvalds 已提交
3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197
	runtime = substream->runtime;

	poll_wait(file, &runtime->sleep, wait);

	snd_pcm_stream_lock_irq(substream);
	avail = snd_pcm_playback_avail(runtime);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_RUNNING:
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_PAUSED:
		if (avail >= runtime->control->avail_min) {
			mask = POLLOUT | POLLWRNORM;
			break;
		}
		/* Fall through */
	case SNDRV_PCM_STATE_DRAINING:
		mask = 0;
		break;
	default:
		mask = POLLOUT | POLLWRNORM | POLLERR;
		break;
	}
	snd_pcm_stream_unlock_irq(substream);
	return mask;
}

static unsigned int snd_pcm_capture_poll(struct file *file, poll_table * wait)
{
T
Takashi Iwai 已提交
3198 3199 3200
	struct snd_pcm_file *pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3201 3202 3203 3204 3205 3206
        unsigned int mask;
	snd_pcm_uframes_t avail;

	pcm_file = file->private_data;

	substream = pcm_file->substream;
3207
	if (PCM_RUNTIME_CHECK(substream))
3208
		return POLLIN | POLLRDNORM | POLLERR;
L
Linus Torvalds 已提交
3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250
	runtime = substream->runtime;

	poll_wait(file, &runtime->sleep, wait);

	snd_pcm_stream_lock_irq(substream);
	avail = snd_pcm_capture_avail(runtime);
	switch (runtime->status->state) {
	case SNDRV_PCM_STATE_RUNNING:
	case SNDRV_PCM_STATE_PREPARED:
	case SNDRV_PCM_STATE_PAUSED:
		if (avail >= runtime->control->avail_min) {
			mask = POLLIN | POLLRDNORM;
			break;
		}
		mask = 0;
		break;
	case SNDRV_PCM_STATE_DRAINING:
		if (avail > 0) {
			mask = POLLIN | POLLRDNORM;
			break;
		}
		/* Fall through */
	default:
		mask = POLLIN | POLLRDNORM | POLLERR;
		break;
	}
	snd_pcm_stream_unlock_irq(substream);
	return mask;
}

/*
 * mmap support
 */

/*
 * Only on coherent architectures, we can mmap the status and the control records
 * for effcient data transfer.  On others, we have to use HWSYNC ioctl...
 */
#if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_ALPHA)
/*
 * mmap status record
 */
3251
static int snd_pcm_mmap_status_fault(struct vm_fault *vmf)
L
Linus Torvalds 已提交
3252
{
3253
	struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
T
Takashi Iwai 已提交
3254
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3255 3256
	
	if (substream == NULL)
N
Nick Piggin 已提交
3257
		return VM_FAULT_SIGBUS;
L
Linus Torvalds 已提交
3258
	runtime = substream->runtime;
N
Nick Piggin 已提交
3259 3260 3261
	vmf->page = virt_to_page(runtime->status);
	get_page(vmf->page);
	return 0;
L
Linus Torvalds 已提交
3262 3263
}

3264
static const struct vm_operations_struct snd_pcm_vm_ops_status =
L
Linus Torvalds 已提交
3265
{
N
Nick Piggin 已提交
3266
	.fault =	snd_pcm_mmap_status_fault,
L
Linus Torvalds 已提交
3267 3268
};

T
Takashi Iwai 已提交
3269
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
L
Linus Torvalds 已提交
3270 3271 3272 3273 3274 3275
			       struct vm_area_struct *area)
{
	long size;
	if (!(area->vm_flags & VM_READ))
		return -EINVAL;
	size = area->vm_end - area->vm_start;
T
Takashi Iwai 已提交
3276
	if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_status)))
L
Linus Torvalds 已提交
3277 3278 3279
		return -EINVAL;
	area->vm_ops = &snd_pcm_vm_ops_status;
	area->vm_private_data = substream;
3280
	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
L
Linus Torvalds 已提交
3281 3282 3283 3284 3285 3286
	return 0;
}

/*
 * mmap control record
 */
3287
static int snd_pcm_mmap_control_fault(struct vm_fault *vmf)
L
Linus Torvalds 已提交
3288
{
3289
	struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
T
Takashi Iwai 已提交
3290
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3291 3292
	
	if (substream == NULL)
N
Nick Piggin 已提交
3293
		return VM_FAULT_SIGBUS;
L
Linus Torvalds 已提交
3294
	runtime = substream->runtime;
N
Nick Piggin 已提交
3295 3296 3297
	vmf->page = virt_to_page(runtime->control);
	get_page(vmf->page);
	return 0;
L
Linus Torvalds 已提交
3298 3299
}

3300
static const struct vm_operations_struct snd_pcm_vm_ops_control =
L
Linus Torvalds 已提交
3301
{
N
Nick Piggin 已提交
3302
	.fault =	snd_pcm_mmap_control_fault,
L
Linus Torvalds 已提交
3303 3304
};

T
Takashi Iwai 已提交
3305
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
L
Linus Torvalds 已提交
3306 3307 3308 3309 3310 3311
				struct vm_area_struct *area)
{
	long size;
	if (!(area->vm_flags & VM_READ))
		return -EINVAL;
	size = area->vm_end - area->vm_start;
T
Takashi Iwai 已提交
3312
	if (size != PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control)))
L
Linus Torvalds 已提交
3313 3314 3315
		return -EINVAL;
	area->vm_ops = &snd_pcm_vm_ops_control;
	area->vm_private_data = substream;
3316
	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
L
Linus Torvalds 已提交
3317 3318 3319 3320 3321 3322
	return 0;
}
#else /* ! coherent mmap */
/*
 * don't support mmap for status and control records.
 */
T
Takashi Iwai 已提交
3323
static int snd_pcm_mmap_status(struct snd_pcm_substream *substream, struct file *file,
L
Linus Torvalds 已提交
3324 3325 3326 3327
			       struct vm_area_struct *area)
{
	return -ENXIO;
}
T
Takashi Iwai 已提交
3328
static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file *file,
L
Linus Torvalds 已提交
3329 3330 3331 3332 3333 3334
				struct vm_area_struct *area)
{
	return -ENXIO;
}
#endif /* coherent mmap */

3335 3336 3337 3338 3339 3340 3341
static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
	void *vaddr = substream->runtime->dma_area + ofs;
	return virt_to_page(vaddr);
}

L
Linus Torvalds 已提交
3342
/*
N
Nick Piggin 已提交
3343
 * fault callback for mmapping a RAM page
L
Linus Torvalds 已提交
3344
 */
3345
static int snd_pcm_mmap_data_fault(struct vm_fault *vmf)
L
Linus Torvalds 已提交
3346
{
3347
	struct snd_pcm_substream *substream = vmf->vma->vm_private_data;
T
Takashi Iwai 已提交
3348
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3349 3350 3351 3352 3353
	unsigned long offset;
	struct page * page;
	size_t dma_bytes;
	
	if (substream == NULL)
N
Nick Piggin 已提交
3354
		return VM_FAULT_SIGBUS;
L
Linus Torvalds 已提交
3355
	runtime = substream->runtime;
N
Nick Piggin 已提交
3356
	offset = vmf->pgoff << PAGE_SHIFT;
L
Linus Torvalds 已提交
3357 3358
	dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
	if (offset > dma_bytes - PAGE_SIZE)
N
Nick Piggin 已提交
3359
		return VM_FAULT_SIGBUS;
3360
	if (substream->ops->page)
L
Linus Torvalds 已提交
3361
		page = substream->ops->page(substream, offset);
3362 3363 3364 3365
	else
		page = snd_pcm_default_page_ops(substream, offset);
	if (!page)
		return VM_FAULT_SIGBUS;
N
Nick Piggin 已提交
3366
	get_page(page);
N
Nick Piggin 已提交
3367 3368
	vmf->page = page;
	return 0;
L
Linus Torvalds 已提交
3369 3370
}

3371 3372 3373 3374 3375 3376
static const struct vm_operations_struct snd_pcm_vm_ops_data = {
	.open =		snd_pcm_mmap_data_open,
	.close =	snd_pcm_mmap_data_close,
};

static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
L
Linus Torvalds 已提交
3377 3378
	.open =		snd_pcm_mmap_data_open,
	.close =	snd_pcm_mmap_data_close,
N
Nick Piggin 已提交
3379
	.fault =	snd_pcm_mmap_data_fault,
L
Linus Torvalds 已提交
3380 3381 3382 3383 3384
};

/*
 * mmap the DMA buffer on RAM
 */
T
Takashi Iwai 已提交
3385 3386 3387 3388 3389 3390 3391 3392 3393

/**
 * snd_pcm_lib_default_mmap - Default PCM data mmap function
 * @substream: PCM substream
 * @area: VMA
 *
 * This is the default mmap handler for PCM data.  When mmap pcm_ops is NULL,
 * this function is invoked implicitly.
 */
3394 3395
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
			     struct vm_area_struct *area)
L
Linus Torvalds 已提交
3396
{
3397
	area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
3398
#ifdef CONFIG_GENERIC_ALLOCATOR
3399 3400 3401 3402 3403 3404
	if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
		area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
		return remap_pfn_range(area, area->vm_start,
				substream->dma_buffer.addr >> PAGE_SHIFT,
				area->vm_end - area->vm_start, area->vm_page_prot);
	}
3405
#endif /* CONFIG_GENERIC_ALLOCATOR */
3406
#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
3407 3408 3409 3410 3411 3412 3413
	if (!substream->ops->page &&
	    substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
		return dma_mmap_coherent(substream->dma_buffer.dev.dev,
					 area,
					 substream->runtime->dma_area,
					 substream->runtime->dma_addr,
					 area->vm_end - area->vm_start);
3414
#endif /* CONFIG_X86 */
3415 3416
	/* mmap with fault handler */
	area->vm_ops = &snd_pcm_vm_ops_data_fault;
L
Linus Torvalds 已提交
3417 3418
	return 0;
}
3419
EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
L
Linus Torvalds 已提交
3420 3421 3422 3423 3424

/*
 * mmap the DMA buffer on I/O memory area
 */
#if SNDRV_PCM_INFO_MMAP_IOMEM
T
Takashi Iwai 已提交
3425 3426 3427 3428 3429 3430 3431 3432 3433
/**
 * snd_pcm_lib_mmap_iomem - Default PCM data mmap function for I/O mem
 * @substream: PCM substream
 * @area: VMA
 *
 * When your hardware uses the iomapped pages as the hardware buffer and
 * wants to mmap it, pass this function as mmap pcm_ops.  Note that this
 * is supposed to work only on limited architectures.
 */
T
Takashi Iwai 已提交
3434 3435
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
			   struct vm_area_struct *area)
L
Linus Torvalds 已提交
3436
{
3437
	struct snd_pcm_runtime *runtime = substream->runtime;;
L
Linus Torvalds 已提交
3438 3439

	area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
3440
	return vm_iomap_memory(area, runtime->dma_addr, runtime->dma_bytes);
L
Linus Torvalds 已提交
3441
}
3442 3443

EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem);
L
Linus Torvalds 已提交
3444 3445 3446 3447 3448
#endif /* SNDRV_PCM_INFO_MMAP */

/*
 * mmap DMA buffer
 */
T
Takashi Iwai 已提交
3449
int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file,
L
Linus Torvalds 已提交
3450 3451
		      struct vm_area_struct *area)
{
T
Takashi Iwai 已提交
3452
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3453 3454 3455
	long size;
	unsigned long offset;
	size_t dma_bytes;
3456
	int err;
L
Linus Torvalds 已提交
3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480

	if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
		if (!(area->vm_flags & (VM_WRITE|VM_READ)))
			return -EINVAL;
	} else {
		if (!(area->vm_flags & VM_READ))
			return -EINVAL;
	}
	runtime = substream->runtime;
	if (runtime->status->state == SNDRV_PCM_STATE_OPEN)
		return -EBADFD;
	if (!(runtime->info & SNDRV_PCM_INFO_MMAP))
		return -ENXIO;
	if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED ||
	    runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED)
		return -EINVAL;
	size = area->vm_end - area->vm_start;
	offset = area->vm_pgoff << PAGE_SHIFT;
	dma_bytes = PAGE_ALIGN(runtime->dma_bytes);
	if ((size_t)size > dma_bytes)
		return -EINVAL;
	if (offset > dma_bytes - size)
		return -EINVAL;

3481 3482
	area->vm_ops = &snd_pcm_vm_ops_data;
	area->vm_private_data = substream;
L
Linus Torvalds 已提交
3483
	if (substream->ops->mmap)
3484
		err = substream->ops->mmap(substream, area);
L
Linus Torvalds 已提交
3485
	else
3486
		err = snd_pcm_lib_default_mmap(substream, area);
3487 3488 3489
	if (!err)
		atomic_inc(&substream->mmap_count);
	return err;
L
Linus Torvalds 已提交
3490 3491
}

3492 3493
EXPORT_SYMBOL(snd_pcm_mmap_data);

L
Linus Torvalds 已提交
3494 3495
static int snd_pcm_mmap(struct file *file, struct vm_area_struct *area)
{
T
Takashi Iwai 已提交
3496 3497
	struct snd_pcm_file * pcm_file;
	struct snd_pcm_substream *substream;	
L
Linus Torvalds 已提交
3498 3499 3500 3501
	unsigned long offset;
	
	pcm_file = file->private_data;
	substream = pcm_file->substream;
3502 3503
	if (PCM_RUNTIME_CHECK(substream))
		return -ENXIO;
L
Linus Torvalds 已提交
3504 3505 3506 3507

	offset = area->vm_pgoff << PAGE_SHIFT;
	switch (offset) {
	case SNDRV_PCM_MMAP_OFFSET_STATUS:
3508
		if (pcm_file->no_compat_mmap)
L
Linus Torvalds 已提交
3509 3510 3511
			return -ENXIO;
		return snd_pcm_mmap_status(substream, file, area);
	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
3512
		if (pcm_file->no_compat_mmap)
L
Linus Torvalds 已提交
3513 3514 3515 3516 3517 3518 3519 3520 3521 3522
			return -ENXIO;
		return snd_pcm_mmap_control(substream, file, area);
	default:
		return snd_pcm_mmap_data(substream, file, area);
	}
	return 0;
}

static int snd_pcm_fasync(int fd, struct file * file, int on)
{
T
Takashi Iwai 已提交
3523 3524 3525
	struct snd_pcm_file * pcm_file;
	struct snd_pcm_substream *substream;
	struct snd_pcm_runtime *runtime;
L
Linus Torvalds 已提交
3526 3527 3528

	pcm_file = file->private_data;
	substream = pcm_file->substream;
3529
	if (PCM_RUNTIME_CHECK(substream))
3530
		return -ENXIO;
L
Linus Torvalds 已提交
3531
	runtime = substream->runtime;
3532
	return fasync_helper(fd, file, on, &runtime->fasync);
L
Linus Torvalds 已提交
3533 3534 3535 3536 3537 3538 3539 3540 3541 3542 3543 3544 3545 3546 3547
}

/*
 * ioctl32 compat
 */
#ifdef CONFIG_COMPAT
#include "pcm_compat.c"
#else
#define snd_pcm_ioctl_compat	NULL
#endif

/*
 *  To be removed helpers to keep binary compatibility
 */

3548
#ifdef CONFIG_SND_SUPPORT_OLD_API
L
Linus Torvalds 已提交
3549 3550 3551
#define __OLD_TO_NEW_MASK(x) ((x&7)|((x&0x07fffff8)<<5))
#define __NEW_TO_OLD_MASK(x) ((x&7)|((x&0xffffff00)>>5))

T
Takashi Iwai 已提交
3552 3553
static void snd_pcm_hw_convert_from_old_params(struct snd_pcm_hw_params *params,
					       struct snd_pcm_hw_params_old *oparams)
L
Linus Torvalds 已提交
3554 3555 3556 3557 3558 3559 3560 3561 3562 3563 3564 3565 3566 3567 3568 3569 3570
{
	unsigned int i;

	memset(params, 0, sizeof(*params));
	params->flags = oparams->flags;
	for (i = 0; i < ARRAY_SIZE(oparams->masks); i++)
		params->masks[i].bits[0] = oparams->masks[i];
	memcpy(params->intervals, oparams->intervals, sizeof(oparams->intervals));
	params->rmask = __OLD_TO_NEW_MASK(oparams->rmask);
	params->cmask = __OLD_TO_NEW_MASK(oparams->cmask);
	params->info = oparams->info;
	params->msbits = oparams->msbits;
	params->rate_num = oparams->rate_num;
	params->rate_den = oparams->rate_den;
	params->fifo_size = oparams->fifo_size;
}

T
Takashi Iwai 已提交
3571 3572
static void snd_pcm_hw_convert_to_old_params(struct snd_pcm_hw_params_old *oparams,
					     struct snd_pcm_hw_params *params)
L
Linus Torvalds 已提交
3573 3574 3575 3576 3577 3578 3579 3580 3581 3582 3583 3584 3585 3586 3587 3588 3589
{
	unsigned int i;

	memset(oparams, 0, sizeof(*oparams));
	oparams->flags = params->flags;
	for (i = 0; i < ARRAY_SIZE(oparams->masks); i++)
		oparams->masks[i] = params->masks[i].bits[0];
	memcpy(oparams->intervals, params->intervals, sizeof(oparams->intervals));
	oparams->rmask = __NEW_TO_OLD_MASK(params->rmask);
	oparams->cmask = __NEW_TO_OLD_MASK(params->cmask);
	oparams->info = params->info;
	oparams->msbits = params->msbits;
	oparams->rate_num = params->rate_num;
	oparams->rate_den = params->rate_den;
	oparams->fifo_size = params->fifo_size;
}

T
Takashi Iwai 已提交
3590 3591
static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams)
L
Linus Torvalds 已提交
3592
{
T
Takashi Iwai 已提交
3593 3594
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params_old *oparams = NULL;
L
Linus Torvalds 已提交
3595 3596 3597
	int err;

	params = kmalloc(sizeof(*params), GFP_KERNEL);
L
Li Zefan 已提交
3598 3599
	if (!params)
		return -ENOMEM;
L
Linus Torvalds 已提交
3600

L
Li Zefan 已提交
3601 3602 3603
	oparams = memdup_user(_oparams, sizeof(*oparams));
	if (IS_ERR(oparams)) {
		err = PTR_ERR(oparams);
L
Linus Torvalds 已提交
3604 3605 3606 3607 3608 3609 3610 3611 3612
		goto out;
	}
	snd_pcm_hw_convert_from_old_params(params, oparams);
	err = snd_pcm_hw_refine(substream, params);
	snd_pcm_hw_convert_to_old_params(oparams, params);
	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
		if (!err)
			err = -EFAULT;
	}
L
Li Zefan 已提交
3613 3614

	kfree(oparams);
L
Linus Torvalds 已提交
3615 3616 3617 3618 3619
out:
	kfree(params);
	return err;
}

T
Takashi Iwai 已提交
3620 3621
static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
				      struct snd_pcm_hw_params_old __user * _oparams)
L
Linus Torvalds 已提交
3622
{
T
Takashi Iwai 已提交
3623 3624
	struct snd_pcm_hw_params *params;
	struct snd_pcm_hw_params_old *oparams = NULL;
L
Linus Torvalds 已提交
3625 3626 3627
	int err;

	params = kmalloc(sizeof(*params), GFP_KERNEL);
L
Li Zefan 已提交
3628 3629 3630 3631 3632 3633
	if (!params)
		return -ENOMEM;

	oparams = memdup_user(_oparams, sizeof(*oparams));
	if (IS_ERR(oparams)) {
		err = PTR_ERR(oparams);
L
Linus Torvalds 已提交
3634 3635 3636 3637 3638 3639 3640 3641 3642
		goto out;
	}
	snd_pcm_hw_convert_from_old_params(params, oparams);
	err = snd_pcm_hw_params(substream, params);
	snd_pcm_hw_convert_to_old_params(oparams, params);
	if (copy_to_user(_oparams, oparams, sizeof(*oparams))) {
		if (!err)
			err = -EFAULT;
	}
L
Li Zefan 已提交
3643 3644

	kfree(oparams);
L
Linus Torvalds 已提交
3645 3646 3647 3648
out:
	kfree(params);
	return err;
}
3649
#endif /* CONFIG_SND_SUPPORT_OLD_API */
L
Linus Torvalds 已提交
3650

3651
#ifndef CONFIG_MMU
3652 3653 3654 3655 3656 3657 3658 3659 3660 3661 3662 3663 3664 3665 3666 3667 3668 3669 3670
static unsigned long snd_pcm_get_unmapped_area(struct file *file,
					       unsigned long addr,
					       unsigned long len,
					       unsigned long pgoff,
					       unsigned long flags)
{
	struct snd_pcm_file *pcm_file = file->private_data;
	struct snd_pcm_substream *substream = pcm_file->substream;
	struct snd_pcm_runtime *runtime = substream->runtime;
	unsigned long offset = pgoff << PAGE_SHIFT;

	switch (offset) {
	case SNDRV_PCM_MMAP_OFFSET_STATUS:
		return (unsigned long)runtime->status;
	case SNDRV_PCM_MMAP_OFFSET_CONTROL:
		return (unsigned long)runtime->control;
	default:
		return (unsigned long)runtime->dma_area + offset;
	}
3671 3672
}
#else
3673
# define snd_pcm_get_unmapped_area NULL
3674 3675
#endif

L
Linus Torvalds 已提交
3676 3677 3678 3679
/*
 *  Register section
 */

3680
const struct file_operations snd_pcm_f_ops[2] = {
L
Linus Torvalds 已提交
3681
	{
3682 3683
		.owner =		THIS_MODULE,
		.write =		snd_pcm_write,
A
Al Viro 已提交
3684
		.write_iter =		snd_pcm_writev,
3685
		.open =			snd_pcm_playback_open,
3686
		.release =		snd_pcm_release,
T
Takashi Iwai 已提交
3687
		.llseek =		no_llseek,
3688 3689 3690 3691 3692
		.poll =			snd_pcm_playback_poll,
		.unlocked_ioctl =	snd_pcm_playback_ioctl,
		.compat_ioctl = 	snd_pcm_ioctl_compat,
		.mmap =			snd_pcm_mmap,
		.fasync =		snd_pcm_fasync,
3693
		.get_unmapped_area =	snd_pcm_get_unmapped_area,
L
Linus Torvalds 已提交
3694 3695
	},
	{
3696 3697
		.owner =		THIS_MODULE,
		.read =			snd_pcm_read,
A
Al Viro 已提交
3698
		.read_iter =		snd_pcm_readv,
3699
		.open =			snd_pcm_capture_open,
3700
		.release =		snd_pcm_release,
T
Takashi Iwai 已提交
3701
		.llseek =		no_llseek,
3702 3703 3704 3705 3706
		.poll =			snd_pcm_capture_poll,
		.unlocked_ioctl =	snd_pcm_capture_ioctl,
		.compat_ioctl = 	snd_pcm_ioctl_compat,
		.mmap =			snd_pcm_mmap,
		.fasync =		snd_pcm_fasync,
3707
		.get_unmapped_area =	snd_pcm_get_unmapped_area,
L
Linus Torvalds 已提交
3708 3709
	}
};