timer.c 52.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2
/*
 *  Timers 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 23 24 25
 *
 *
 *   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/delay.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/time.h>
26
#include <linux/mutex.h>
27
#include <linux/device.h>
28
#include <linux/module.h>
29
#include <linux/string.h>
L
Linus Torvalds 已提交
30 31 32 33 34 35 36 37
#include <sound/core.h>
#include <sound/timer.h>
#include <sound/control.h>
#include <sound/info.h>
#include <sound/minors.h>
#include <sound/initval.h>
#include <linux/kmod.h>

T
Takashi Iwai 已提交
38
#if IS_ENABLED(CONFIG_SND_HRTIMER)
39
#define DEFAULT_TIMER_LIMIT 4
T
Takashi Iwai 已提交
40
#elif IS_ENABLED(CONFIG_SND_RTCTIMER)
L
Linus Torvalds 已提交
41 42 43 44 45 46
#define DEFAULT_TIMER_LIMIT 2
#else
#define DEFAULT_TIMER_LIMIT 1
#endif

static int timer_limit = DEFAULT_TIMER_LIMIT;
47
static int timer_tstamp_monotonic = 1;
48
MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
L
Linus Torvalds 已提交
49 50 51 52
MODULE_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL");
module_param(timer_limit, int, 0444);
MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
53 54
module_param(timer_tstamp_monotonic, int, 0444);
MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
L
Linus Torvalds 已提交
55

56 57 58
MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER);
MODULE_ALIAS("devname:snd/timer");

59 60
struct snd_timer_user {
	struct snd_timer_instance *timeri;
C
Clemens Ladisch 已提交
61
	int tread;		/* enhanced read with timestamps and events */
L
Linus Torvalds 已提交
62 63 64 65 66 67
	unsigned long ticks;
	unsigned long overrun;
	int qhead;
	int qtail;
	int qused;
	int queue_size;
68
	bool disconnected;
69 70
	struct snd_timer_read *queue;
	struct snd_timer_tread *tqueue;
L
Linus Torvalds 已提交
71 72 73 74 75 76
	spinlock_t qlock;
	unsigned long last_resolution;
	unsigned int filter;
	struct timespec tstamp;		/* trigger tstamp */
	wait_queue_head_t qchange_sleep;
	struct fasync_struct *fasync;
77
	struct mutex ioctl_lock;
78
};
L
Linus Torvalds 已提交
79 80 81 82 83 84 85 86 87 88

/* list of timers */
static LIST_HEAD(snd_timer_list);

/* list of slave instances */
static LIST_HEAD(snd_timer_slave_list);

/* lock for slave active lists */
static DEFINE_SPINLOCK(slave_active_lock);

89
static DEFINE_MUTEX(register_mutex);
L
Linus Torvalds 已提交
90

91 92 93
static int snd_timer_free(struct snd_timer *timer);
static int snd_timer_dev_free(struct snd_device *device);
static int snd_timer_dev_register(struct snd_device *device);
94
static int snd_timer_dev_disconnect(struct snd_device *device);
L
Linus Torvalds 已提交
95

96
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left);
L
Linus Torvalds 已提交
97 98 99 100 101

/*
 * create a timer instance with the given owner string.
 * when timer is not NULL, increments the module counter
 */
102 103
static struct snd_timer_instance *snd_timer_instance_new(char *owner,
							 struct snd_timer *timer)
L
Linus Torvalds 已提交
104
{
105
	struct snd_timer_instance *timeri;
106
	timeri = kzalloc(sizeof(*timeri), GFP_KERNEL);
L
Linus Torvalds 已提交
107 108
	if (timeri == NULL)
		return NULL;
109
	timeri->owner = kstrdup(owner, GFP_KERNEL);
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119 120
	if (! timeri->owner) {
		kfree(timeri);
		return NULL;
	}
	INIT_LIST_HEAD(&timeri->open_list);
	INIT_LIST_HEAD(&timeri->active_list);
	INIT_LIST_HEAD(&timeri->ack_list);
	INIT_LIST_HEAD(&timeri->slave_list_head);
	INIT_LIST_HEAD(&timeri->slave_active_head);

	timeri->timer = timer;
121
	if (timer && !try_module_get(timer->module)) {
L
Linus Torvalds 已提交
122 123 124 125 126 127 128 129 130 131 132
		kfree(timeri->owner);
		kfree(timeri);
		return NULL;
	}

	return timeri;
}

/*
 * find a timer instance from the given timer id
 */
133
static struct snd_timer *snd_timer_find(struct snd_timer_id *tid)
L
Linus Torvalds 已提交
134
{
135
	struct snd_timer *timer = NULL;
L
Linus Torvalds 已提交
136

137
	list_for_each_entry(timer, &snd_timer_list, device_list) {
L
Linus Torvalds 已提交
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
		if (timer->tmr_class != tid->dev_class)
			continue;
		if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD ||
		     timer->tmr_class == SNDRV_TIMER_CLASS_PCM) &&
		    (timer->card == NULL ||
		     timer->card->number != tid->card))
			continue;
		if (timer->tmr_device != tid->device)
			continue;
		if (timer->tmr_subdevice != tid->subdevice)
			continue;
		return timer;
	}
	return NULL;
}

154
#ifdef CONFIG_MODULES
L
Linus Torvalds 已提交
155

156
static void snd_timer_request(struct snd_timer_id *tid)
L
Linus Torvalds 已提交
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
{
	switch (tid->dev_class) {
	case SNDRV_TIMER_CLASS_GLOBAL:
		if (tid->device < timer_limit)
			request_module("snd-timer-%i", tid->device);
		break;
	case SNDRV_TIMER_CLASS_CARD:
	case SNDRV_TIMER_CLASS_PCM:
		if (tid->card < snd_ecards_limit)
			request_module("snd-card-%i", tid->card);
		break;
	default:
		break;
	}
}

#endif

/*
 * look for a master instance matching with the slave id of the given slave.
 * when found, relink the open_link of the slave.
 *
 * call this with register_mutex down.
 */
181
static void snd_timer_check_slave(struct snd_timer_instance *slave)
L
Linus Torvalds 已提交
182
{
183 184
	struct snd_timer *timer;
	struct snd_timer_instance *master;
L
Linus Torvalds 已提交
185 186

	/* FIXME: it's really dumb to look up all entries.. */
187 188
	list_for_each_entry(timer, &snd_timer_list, device_list) {
		list_for_each_entry(master, &timer->open_list_head, open_list) {
L
Linus Torvalds 已提交
189 190
			if (slave->slave_class == master->slave_class &&
			    slave->slave_id == master->slave_id) {
191 192
				list_move_tail(&slave->open_list,
					       &master->slave_list_head);
L
Linus Torvalds 已提交
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
				spin_lock_irq(&slave_active_lock);
				slave->master = master;
				slave->timer = master->timer;
				spin_unlock_irq(&slave_active_lock);
				return;
			}
		}
	}
}

/*
 * look for slave instances matching with the slave id of the given master.
 * when found, relink the open_link of slaves.
 *
 * call this with register_mutex down.
 */
209
static void snd_timer_check_master(struct snd_timer_instance *master)
L
Linus Torvalds 已提交
210
{
211
	struct snd_timer_instance *slave, *tmp;
L
Linus Torvalds 已提交
212 213

	/* check all pending slaves */
214
	list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) {
L
Linus Torvalds 已提交
215 216
		if (slave->slave_class == master->slave_class &&
		    slave->slave_id == master->slave_id) {
217
			list_move_tail(&slave->open_list, &master->slave_list_head);
L
Linus Torvalds 已提交
218
			spin_lock_irq(&slave_active_lock);
219
			spin_lock(&master->timer->lock);
L
Linus Torvalds 已提交
220 221 222
			slave->master = master;
			slave->timer = master->timer;
			if (slave->flags & SNDRV_TIMER_IFLG_RUNNING)
C
Clemens Ladisch 已提交
223 224
				list_add_tail(&slave->active_list,
					      &master->slave_active_head);
225
			spin_unlock(&master->timer->lock);
L
Linus Torvalds 已提交
226 227 228 229 230 231 232 233 234
			spin_unlock_irq(&slave_active_lock);
		}
	}
}

/*
 * open a timer instance
 * when opening a master, the slave id must be here given.
 */
235 236
int snd_timer_open(struct snd_timer_instance **ti,
		   char *owner, struct snd_timer_id *tid,
L
Linus Torvalds 已提交
237 238
		   unsigned int slave_id)
{
239 240
	struct snd_timer *timer;
	struct snd_timer_instance *timeri = NULL;
C
Clemens Ladisch 已提交
241

L
Linus Torvalds 已提交
242 243 244 245
	if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) {
		/* open a slave instance */
		if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE ||
		    tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) {
246 247
			pr_debug("ALSA: timer: invalid slave class %i\n",
				 tid->dev_sclass);
L
Linus Torvalds 已提交
248 249
			return -EINVAL;
		}
250
		mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
251
		timeri = snd_timer_instance_new(owner, NULL);
252
		if (!timeri) {
253
			mutex_unlock(&register_mutex);
254 255
			return -ENOMEM;
		}
L
Linus Torvalds 已提交
256 257 258 259 260
		timeri->slave_class = tid->dev_sclass;
		timeri->slave_id = tid->device;
		timeri->flags |= SNDRV_TIMER_IFLG_SLAVE;
		list_add_tail(&timeri->open_list, &snd_timer_slave_list);
		snd_timer_check_slave(timeri);
261
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
262 263 264 265 266
		*ti = timeri;
		return 0;
	}

	/* open a master instance */
267
	mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
268
	timer = snd_timer_find(tid);
269 270
#ifdef CONFIG_MODULES
	if (!timer) {
271
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
272
		snd_timer_request(tid);
273
		mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
274 275 276
		timer = snd_timer_find(tid);
	}
#endif
277
	if (!timer) {
278
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
279 280
		return -ENODEV;
	}
281 282
	if (!list_empty(&timer->open_list_head)) {
		timeri = list_entry(timer->open_list_head.next,
283
				    struct snd_timer_instance, open_list);
284
		if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) {
285
			mutex_unlock(&register_mutex);
286 287 288 289 290
			return -EBUSY;
		}
	}
	timeri = snd_timer_instance_new(owner, timer);
	if (!timeri) {
291
		mutex_unlock(&register_mutex);
292 293
		return -ENOMEM;
	}
294 295 296
	/* take a card refcount for safe disconnection */
	if (timer->card)
		get_device(&timer->card->card_dev);
297 298 299 300 301 302
	timeri->slave_class = tid->dev_sclass;
	timeri->slave_id = slave_id;
	if (list_empty(&timer->open_list_head) && timer->hw.open)
		timer->hw.open(timer);
	list_add_tail(&timeri->open_list, &timer->open_list_head);
	snd_timer_check_master(timeri);
303
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
304 305 306 307
	*ti = timeri;
	return 0;
}

T
Takashi Iwai 已提交
308
static int _snd_timer_stop(struct snd_timer_instance *timeri, int event);
L
Linus Torvalds 已提交
309 310 311 312

/*
 * close a timer instance
 */
313
int snd_timer_close(struct snd_timer_instance *timeri)
L
Linus Torvalds 已提交
314
{
315
	struct snd_timer *timer = NULL;
316
	struct snd_timer_instance *slave, *tmp;
L
Linus Torvalds 已提交
317

318
	if (snd_BUG_ON(!timeri))
319
		return -ENXIO;
L
Linus Torvalds 已提交
320 321 322 323 324 325 326 327 328 329 330 331 332

	/* force to stop the timer */
	snd_timer_stop(timeri);

	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
		/* wait, until the active callback is finished */
		spin_lock_irq(&slave_active_lock);
		while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
			spin_unlock_irq(&slave_active_lock);
			udelay(10);
			spin_lock_irq(&slave_active_lock);
		}
		spin_unlock_irq(&slave_active_lock);
333
		mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
334
		list_del(&timeri->open_list);
335
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
336 337
	} else {
		timer = timeri->timer;
338 339
		if (snd_BUG_ON(!timer))
			goto out;
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347
		/* wait, until the active callback is finished */
		spin_lock_irq(&timer->lock);
		while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) {
			spin_unlock_irq(&timer->lock);
			udelay(10);
			spin_lock_irq(&timer->lock);
		}
		spin_unlock_irq(&timer->lock);
348
		mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
349
		list_del(&timeri->open_list);
T
Takashi Iwai 已提交
350
		if (list_empty(&timer->open_list_head) &&
C
Clemens Ladisch 已提交
351
		    timer->hw.close)
L
Linus Torvalds 已提交
352 353
			timer->hw.close(timer);
		/* remove slave links */
354 355
		spin_lock_irq(&slave_active_lock);
		spin_lock(&timer->lock);
356 357 358
		list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
					 open_list) {
			list_move_tail(&slave->open_list, &snd_timer_slave_list);
L
Linus Torvalds 已提交
359 360
			slave->master = NULL;
			slave->timer = NULL;
361 362
			list_del_init(&slave->ack_list);
			list_del_init(&slave->active_list);
L
Linus Torvalds 已提交
363
		}
364 365
		spin_unlock(&timer->lock);
		spin_unlock_irq(&slave_active_lock);
366 367 368
		/* release a card refcount for safe disconnection */
		if (timer->card)
			put_device(&timer->card->card_dev);
369
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
370
	}
371
 out:
L
Linus Torvalds 已提交
372 373 374 375
	if (timeri->private_free)
		timeri->private_free(timeri);
	kfree(timeri->owner);
	kfree(timeri);
376 377
	if (timer)
		module_put(timer->module);
L
Linus Torvalds 已提交
378 379 380
	return 0;
}

381
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri)
L
Linus Torvalds 已提交
382
{
383
	struct snd_timer * timer;
L
Linus Torvalds 已提交
384 385 386 387 388 389 390 391 392 393 394

	if (timeri == NULL)
		return 0;
	if ((timer = timeri->timer) != NULL) {
		if (timer->hw.c_resolution)
			return timer->hw.c_resolution(timer);
		return timer->hw.resolution;
	}
	return 0;
}

395
static void snd_timer_notify1(struct snd_timer_instance *ti, int event)
L
Linus Torvalds 已提交
396
{
397
	struct snd_timer *timer;
L
Linus Torvalds 已提交
398 399
	unsigned long flags;
	unsigned long resolution = 0;
400
	struct snd_timer_instance *ts;
L
Linus Torvalds 已提交
401 402
	struct timespec tstamp;

403
	if (timer_tstamp_monotonic)
T
Thomas Gleixner 已提交
404
		ktime_get_ts(&tstamp);
405 406
	else
		getnstimeofday(&tstamp);
407 408 409
	if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
		       event > SNDRV_TIMER_EVENT_PAUSE))
		return;
C
Clemens Ladisch 已提交
410 411
	if (event == SNDRV_TIMER_EVENT_START ||
	    event == SNDRV_TIMER_EVENT_CONTINUE)
L
Linus Torvalds 已提交
412 413
		resolution = snd_timer_resolution(ti);
	if (ti->ccallback)
414
		ti->ccallback(ti, event, &tstamp, resolution);
L
Linus Torvalds 已提交
415 416 417 418 419 420 421 422
	if (ti->flags & SNDRV_TIMER_IFLG_SLAVE)
		return;
	timer = ti->timer;
	if (timer == NULL)
		return;
	if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
		return;
	spin_lock_irqsave(&timer->lock, flags);
423
	list_for_each_entry(ts, &ti->slave_active_head, active_list)
L
Linus Torvalds 已提交
424 425 426 427 428
		if (ts->ccallback)
			ts->ccallback(ti, event + 100, &tstamp, resolution);
	spin_unlock_irqrestore(&timer->lock, flags);
}

429
static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri,
C
Clemens Ladisch 已提交
430
			    unsigned long sticks)
L
Linus Torvalds 已提交
431
{
432
	list_move_tail(&timeri->active_list, &timer->active_list_head);
L
Linus Torvalds 已提交
433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448
	if (timer->running) {
		if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
			goto __start_now;
		timer->flags |= SNDRV_TIMER_FLG_RESCHED;
		timeri->flags |= SNDRV_TIMER_IFLG_START;
		return 1;	/* delayed start */
	} else {
		timer->sticks = sticks;
		timer->hw.start(timer);
	      __start_now:
		timer->running++;
		timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
		return 0;
	}
}

449
static int snd_timer_start_slave(struct snd_timer_instance *timeri)
L
Linus Torvalds 已提交
450 451 452 453 454
{
	unsigned long flags;

	spin_lock_irqsave(&slave_active_lock, flags);
	timeri->flags |= SNDRV_TIMER_IFLG_RUNNING;
455 456
	if (timeri->master && timeri->timer) {
		spin_lock(&timeri->timer->lock);
C
Clemens Ladisch 已提交
457 458
		list_add_tail(&timeri->active_list,
			      &timeri->master->slave_active_head);
459 460
		spin_unlock(&timeri->timer->lock);
	}
L
Linus Torvalds 已提交
461 462 463 464 465 466
	spin_unlock_irqrestore(&slave_active_lock, flags);
	return 1; /* delayed start */
}

/*
 *  start the timer instance
C
Clemens Ladisch 已提交
467
 */
468
int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks)
L
Linus Torvalds 已提交
469
{
470
	struct snd_timer *timer;
L
Linus Torvalds 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483
	int result = -EINVAL;
	unsigned long flags;

	if (timeri == NULL || ticks < 1)
		return -EINVAL;
	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
		result = snd_timer_start_slave(timeri);
		snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
		return result;
	}
	timer = timeri->timer;
	if (timer == NULL)
		return -EINVAL;
484 485
	if (timer->card && timer->card->shutdown)
		return -ENODEV;
L
Linus Torvalds 已提交
486 487 488 489 490 491 492 493 494
	spin_lock_irqsave(&timer->lock, flags);
	timeri->ticks = timeri->cticks = ticks;
	timeri->pticks = 0;
	result = snd_timer_start1(timer, timeri, ticks);
	spin_unlock_irqrestore(&timer->lock, flags);
	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_START);
	return result;
}

T
Takashi Iwai 已提交
495
static int _snd_timer_stop(struct snd_timer_instance *timeri, int event)
L
Linus Torvalds 已提交
496
{
497
	struct snd_timer *timer;
L
Linus Torvalds 已提交
498 499
	unsigned long flags;

500 501
	if (snd_BUG_ON(!timeri))
		return -ENXIO;
L
Linus Torvalds 已提交
502 503

	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
T
Takashi Iwai 已提交
504 505 506 507 508
		spin_lock_irqsave(&slave_active_lock, flags);
		timeri->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
		list_del_init(&timeri->ack_list);
		list_del_init(&timeri->active_list);
		spin_unlock_irqrestore(&slave_active_lock, flags);
L
Linus Torvalds 已提交
509 510 511 512 513 514 515 516
		goto __end;
	}
	timer = timeri->timer;
	if (!timer)
		return -EINVAL;
	spin_lock_irqsave(&timer->lock, flags);
	list_del_init(&timeri->ack_list);
	list_del_init(&timeri->active_list);
517 518 519 520
	if (timer->card && timer->card->shutdown) {
		spin_unlock_irqrestore(&timer->lock, flags);
		return 0;
	}
L
Linus Torvalds 已提交
521 522 523 524 525 526 527 528 529 530 531 532
	if ((timeri->flags & SNDRV_TIMER_IFLG_RUNNING) &&
	    !(--timer->running)) {
		timer->hw.stop(timer);
		if (timer->flags & SNDRV_TIMER_FLG_RESCHED) {
			timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
			snd_timer_reschedule(timer, 0);
			if (timer->flags & SNDRV_TIMER_FLG_CHANGE) {
				timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
				timer->hw.start(timer);
			}
		}
	}
T
Takashi Iwai 已提交
533
	timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START);
L
Linus Torvalds 已提交
534 535 536 537 538 539 540 541 542 543 544 545
	spin_unlock_irqrestore(&timer->lock, flags);
      __end:
	if (event != SNDRV_TIMER_EVENT_RESOLUTION)
		snd_timer_notify1(timeri, event);
	return 0;
}

/*
 * stop the timer instance.
 *
 * do not call this from the timer callback!
 */
546
int snd_timer_stop(struct snd_timer_instance *timeri)
L
Linus Torvalds 已提交
547
{
548
	struct snd_timer *timer;
L
Linus Torvalds 已提交
549 550 551
	unsigned long flags;
	int err;

T
Takashi Iwai 已提交
552
	err = _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_STOP);
L
Linus Torvalds 已提交
553 554 555
	if (err < 0)
		return err;
	timer = timeri->timer;
556 557
	if (!timer)
		return -EINVAL;
L
Linus Torvalds 已提交
558 559 560 561 562 563 564 565 566 567
	spin_lock_irqsave(&timer->lock, flags);
	timeri->cticks = timeri->ticks;
	timeri->pticks = 0;
	spin_unlock_irqrestore(&timer->lock, flags);
	return 0;
}

/*
 * start again..  the tick is kept.
 */
568
int snd_timer_continue(struct snd_timer_instance *timeri)
L
Linus Torvalds 已提交
569
{
570
	struct snd_timer *timer;
L
Linus Torvalds 已提交
571 572 573 574 575 576 577 578 579 580
	int result = -EINVAL;
	unsigned long flags;

	if (timeri == NULL)
		return result;
	if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
		return snd_timer_start_slave(timeri);
	timer = timeri->timer;
	if (! timer)
		return -EINVAL;
581 582
	if (timer->card && timer->card->shutdown)
		return -ENODEV;
L
Linus Torvalds 已提交
583 584 585 586 587 588 589 590 591 592 593 594 595
	spin_lock_irqsave(&timer->lock, flags);
	if (!timeri->cticks)
		timeri->cticks = 1;
	timeri->pticks = 0;
	result = snd_timer_start1(timer, timeri, timer->sticks);
	spin_unlock_irqrestore(&timer->lock, flags);
	snd_timer_notify1(timeri, SNDRV_TIMER_EVENT_CONTINUE);
	return result;
}

/*
 * pause.. remember the ticks left
 */
596
int snd_timer_pause(struct snd_timer_instance * timeri)
L
Linus Torvalds 已提交
597
{
T
Takashi Iwai 已提交
598
	return _snd_timer_stop(timeri, SNDRV_TIMER_EVENT_PAUSE);
L
Linus Torvalds 已提交
599 600 601 602 603 604 605 606
}

/*
 * reschedule the timer
 *
 * start pending instances and check the scheduling ticks.
 * when the scheduling ticks is changed set CHANGE flag to reprogram the timer.
 */
607
static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left)
L
Linus Torvalds 已提交
608
{
609
	struct snd_timer_instance *ti;
L
Linus Torvalds 已提交
610 611
	unsigned long ticks = ~0UL;

612
	list_for_each_entry(ti, &timer->active_list_head, active_list) {
L
Linus Torvalds 已提交
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639
		if (ti->flags & SNDRV_TIMER_IFLG_START) {
			ti->flags &= ~SNDRV_TIMER_IFLG_START;
			ti->flags |= SNDRV_TIMER_IFLG_RUNNING;
			timer->running++;
		}
		if (ti->flags & SNDRV_TIMER_IFLG_RUNNING) {
			if (ticks > ti->cticks)
				ticks = ti->cticks;
		}
	}
	if (ticks == ~0UL) {
		timer->flags &= ~SNDRV_TIMER_FLG_RESCHED;
		return;
	}
	if (ticks > timer->hw.ticks)
		ticks = timer->hw.ticks;
	if (ticks_left != ticks)
		timer->flags |= SNDRV_TIMER_FLG_CHANGE;
	timer->sticks = ticks;
}

/*
 * timer tasklet
 *
 */
static void snd_timer_tasklet(unsigned long arg)
{
640 641
	struct snd_timer *timer = (struct snd_timer *) arg;
	struct snd_timer_instance *ti;
L
Linus Torvalds 已提交
642 643
	struct list_head *p;
	unsigned long resolution, ticks;
644
	unsigned long flags;
L
Linus Torvalds 已提交
645

646 647 648
	if (timer->card && timer->card->shutdown)
		return;

649
	spin_lock_irqsave(&timer->lock, flags);
L
Linus Torvalds 已提交
650 651 652
	/* now process all callbacks */
	while (!list_empty(&timer->sack_list_head)) {
		p = timer->sack_list_head.next;		/* get first item */
653
		ti = list_entry(p, struct snd_timer_instance, ack_list);
L
Linus Torvalds 已提交
654 655 656

		/* remove from ack_list and make empty */
		list_del_init(p);
C
Clemens Ladisch 已提交
657

L
Linus Torvalds 已提交
658 659 660 661 662 663 664 665 666 667 668
		ticks = ti->pticks;
		ti->pticks = 0;
		resolution = ti->resolution;

		ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
		spin_unlock(&timer->lock);
		if (ti->callback)
			ti->callback(ti, resolution, ticks);
		spin_lock(&timer->lock);
		ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
	}
669
	spin_unlock_irqrestore(&timer->lock, flags);
L
Linus Torvalds 已提交
670 671 672 673 674 675 676 677
}

/*
 * timer interrupt
 *
 * ticks_left is usually equal to timer->sticks.
 *
 */
678
void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left)
L
Linus Torvalds 已提交
679
{
680
	struct snd_timer_instance *ti, *ts, *tmp;
L
Linus Torvalds 已提交
681
	unsigned long resolution, ticks;
682
	struct list_head *p, *ack_list_head;
683
	unsigned long flags;
L
Linus Torvalds 已提交
684 685 686 687 688
	int use_tasklet = 0;

	if (timer == NULL)
		return;

689 690 691
	if (timer->card && timer->card->shutdown)
		return;

692
	spin_lock_irqsave(&timer->lock, flags);
L
Linus Torvalds 已提交
693 694 695 696 697 698 699 700

	/* remember the current resolution */
	if (timer->hw.c_resolution)
		resolution = timer->hw.c_resolution(timer);
	else
		resolution = timer->hw.resolution;

	/* loop for all active instances
701
	 * Here we cannot use list_for_each_entry because the active_list of a
C
Clemens Ladisch 已提交
702 703
	 * processed instance is relinked to done_list_head before the callback
	 * is called.
L
Linus Torvalds 已提交
704
	 */
705 706
	list_for_each_entry_safe(ti, tmp, &timer->active_list_head,
				 active_list) {
L
Linus Torvalds 已提交
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
		if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING))
			continue;
		ti->pticks += ticks_left;
		ti->resolution = resolution;
		if (ti->cticks < ticks_left)
			ti->cticks = 0;
		else
			ti->cticks -= ticks_left;
		if (ti->cticks) /* not expired */
			continue;
		if (ti->flags & SNDRV_TIMER_IFLG_AUTO) {
			ti->cticks = ti->ticks;
		} else {
			ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING;
			if (--timer->running)
722
				list_del_init(&ti->active_list);
L
Linus Torvalds 已提交
723
		}
C
Clemens Ladisch 已提交
724 725 726 727 728 729 730
		if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) ||
		    (ti->flags & SNDRV_TIMER_IFLG_FAST))
			ack_list_head = &timer->ack_list_head;
		else
			ack_list_head = &timer->sack_list_head;
		if (list_empty(&ti->ack_list))
			list_add_tail(&ti->ack_list, ack_list_head);
731
		list_for_each_entry(ts, &ti->slave_active_head, active_list) {
L
Linus Torvalds 已提交
732 733
			ts->pticks = ti->pticks;
			ts->resolution = resolution;
C
Clemens Ladisch 已提交
734 735
			if (list_empty(&ts->ack_list))
				list_add_tail(&ts->ack_list, ack_list_head);
L
Linus Torvalds 已提交
736 737 738
		}
	}
	if (timer->flags & SNDRV_TIMER_FLG_RESCHED)
739
		snd_timer_reschedule(timer, timer->sticks);
L
Linus Torvalds 已提交
740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
	if (timer->running) {
		if (timer->hw.flags & SNDRV_TIMER_HW_STOP) {
			timer->hw.stop(timer);
			timer->flags |= SNDRV_TIMER_FLG_CHANGE;
		}
		if (!(timer->hw.flags & SNDRV_TIMER_HW_AUTO) ||
		    (timer->flags & SNDRV_TIMER_FLG_CHANGE)) {
			/* restart timer */
			timer->flags &= ~SNDRV_TIMER_FLG_CHANGE;
			timer->hw.start(timer);
		}
	} else {
		timer->hw.stop(timer);
	}

	/* now process all fast callbacks */
	while (!list_empty(&timer->ack_list_head)) {
		p = timer->ack_list_head.next;		/* get first item */
758
		ti = list_entry(p, struct snd_timer_instance, ack_list);
C
Clemens Ladisch 已提交
759

L
Linus Torvalds 已提交
760 761
		/* remove from ack_list and make empty */
		list_del_init(p);
C
Clemens Ladisch 已提交
762

L
Linus Torvalds 已提交
763 764 765 766 767 768 769 770 771 772 773 774 775
		ticks = ti->pticks;
		ti->pticks = 0;

		ti->flags |= SNDRV_TIMER_IFLG_CALLBACK;
		spin_unlock(&timer->lock);
		if (ti->callback)
			ti->callback(ti, resolution, ticks);
		spin_lock(&timer->lock);
		ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK;
	}

	/* do we have any slow callbacks? */
	use_tasklet = !list_empty(&timer->sack_list_head);
776
	spin_unlock_irqrestore(&timer->lock, flags);
L
Linus Torvalds 已提交
777 778

	if (use_tasklet)
779
		tasklet_schedule(&timer->task_queue);
L
Linus Torvalds 已提交
780 781 782 783 784 785
}

/*

 */

786 787
int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid,
		  struct snd_timer **rtimer)
L
Linus Torvalds 已提交
788
{
789
	struct snd_timer *timer;
L
Linus Torvalds 已提交
790
	int err;
791
	static struct snd_device_ops ops = {
L
Linus Torvalds 已提交
792 793
		.dev_free = snd_timer_dev_free,
		.dev_register = snd_timer_dev_register,
794
		.dev_disconnect = snd_timer_dev_disconnect,
L
Linus Torvalds 已提交
795 796
	};

797 798 799 800
	if (snd_BUG_ON(!tid))
		return -EINVAL;
	if (rtimer)
		*rtimer = NULL;
801
	timer = kzalloc(sizeof(*timer), GFP_KERNEL);
802
	if (!timer)
L
Linus Torvalds 已提交
803 804 805 806 807 808 809 810 811 812 813 814 815
		return -ENOMEM;
	timer->tmr_class = tid->dev_class;
	timer->card = card;
	timer->tmr_device = tid->device;
	timer->tmr_subdevice = tid->subdevice;
	if (id)
		strlcpy(timer->id, id, sizeof(timer->id));
	INIT_LIST_HEAD(&timer->device_list);
	INIT_LIST_HEAD(&timer->open_list_head);
	INIT_LIST_HEAD(&timer->active_list_head);
	INIT_LIST_HEAD(&timer->ack_list_head);
	INIT_LIST_HEAD(&timer->sack_list_head);
	spin_lock_init(&timer->lock);
C
Clemens Ladisch 已提交
816 817
	tasklet_init(&timer->task_queue, snd_timer_tasklet,
		     (unsigned long)timer);
L
Linus Torvalds 已提交
818
	if (card != NULL) {
819
		timer->module = card->module;
C
Clemens Ladisch 已提交
820 821
		err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops);
		if (err < 0) {
L
Linus Torvalds 已提交
822 823 824 825
			snd_timer_free(timer);
			return err;
		}
	}
826 827
	if (rtimer)
		*rtimer = timer;
L
Linus Torvalds 已提交
828 829 830
	return 0;
}

831
static int snd_timer_free(struct snd_timer *timer)
L
Linus Torvalds 已提交
832
{
833 834
	if (!timer)
		return 0;
835 836 837 838 839

	mutex_lock(&register_mutex);
	if (! list_empty(&timer->open_list_head)) {
		struct list_head *p, *n;
		struct snd_timer_instance *ti;
840
		pr_warn("ALSA: timer %p is busy?\n", timer);
841 842 843 844 845 846 847 848 849
		list_for_each_safe(p, n, &timer->open_list_head) {
			list_del_init(p);
			ti = list_entry(p, struct snd_timer_instance, open_list);
			ti->timer = NULL;
		}
	}
	list_del(&timer->device_list);
	mutex_unlock(&register_mutex);

L
Linus Torvalds 已提交
850 851 852 853 854 855
	if (timer->private_free)
		timer->private_free(timer);
	kfree(timer);
	return 0;
}

856
static int snd_timer_dev_free(struct snd_device *device)
L
Linus Torvalds 已提交
857
{
858
	struct snd_timer *timer = device->device_data;
L
Linus Torvalds 已提交
859 860 861
	return snd_timer_free(timer);
}

862
static int snd_timer_dev_register(struct snd_device *dev)
L
Linus Torvalds 已提交
863
{
864 865
	struct snd_timer *timer = dev->device_data;
	struct snd_timer *timer1;
L
Linus Torvalds 已提交
866

867 868
	if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
		return -ENXIO;
L
Linus Torvalds 已提交
869 870 871 872
	if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
	    !timer->hw.resolution && timer->hw.c_resolution == NULL)
	    	return -EINVAL;

873
	mutex_lock(&register_mutex);
874
	list_for_each_entry(timer1, &snd_timer_list, device_list) {
L
Linus Torvalds 已提交
875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893
		if (timer1->tmr_class > timer->tmr_class)
			break;
		if (timer1->tmr_class < timer->tmr_class)
			continue;
		if (timer1->card && timer->card) {
			if (timer1->card->number > timer->card->number)
				break;
			if (timer1->card->number < timer->card->number)
				continue;
		}
		if (timer1->tmr_device > timer->tmr_device)
			break;
		if (timer1->tmr_device < timer->tmr_device)
			continue;
		if (timer1->tmr_subdevice > timer->tmr_subdevice)
			break;
		if (timer1->tmr_subdevice < timer->tmr_subdevice)
			continue;
		/* conflicts.. */
894
		mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
895 896
		return -EBUSY;
	}
897
	list_add_tail(&timer->device_list, &timer1->device_list);
898
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
899 900 901
	return 0;
}

902 903 904 905 906
/* just for reference in snd_timer_dev_disconnect() below */
static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
				     int event, struct timespec *tstamp,
				     unsigned long resolution);

907
static int snd_timer_dev_disconnect(struct snd_device *device)
L
Linus Torvalds 已提交
908
{
909
	struct snd_timer *timer = device->device_data;
910 911
	struct snd_timer_instance *ti;

912
	mutex_lock(&register_mutex);
913
	list_del_init(&timer->device_list);
914 915 916 917 918 919 920 921 922 923
	/* wake up pending sleepers */
	list_for_each_entry(ti, &timer->open_list_head, open_list) {
		/* FIXME: better to have a ti.disconnect() op */
		if (ti->ccallback == snd_timer_user_ccallback) {
			struct snd_timer_user *tu = ti->callback_data;

			tu->disconnected = true;
			wake_up(&tu->qchange_sleep);
		}
	}
924
	mutex_unlock(&register_mutex);
925
	return 0;
L
Linus Torvalds 已提交
926 927
}

928
void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp)
L
Linus Torvalds 已提交
929 930 931
{
	unsigned long flags;
	unsigned long resolution = 0;
932
	struct snd_timer_instance *ti, *ts;
L
Linus Torvalds 已提交
933

934 935
	if (timer->card && timer->card->shutdown)
		return;
936 937
	if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
		return;
938 939 940
	if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
		       event > SNDRV_TIMER_EVENT_MRESUME))
		return;
L
Linus Torvalds 已提交
941
	spin_lock_irqsave(&timer->lock, flags);
942 943 944
	if (event == SNDRV_TIMER_EVENT_MSTART ||
	    event == SNDRV_TIMER_EVENT_MCONTINUE ||
	    event == SNDRV_TIMER_EVENT_MRESUME) {
L
Linus Torvalds 已提交
945 946 947 948 949
		if (timer->hw.c_resolution)
			resolution = timer->hw.c_resolution(timer);
		else
			resolution = timer->hw.resolution;
	}
950
	list_for_each_entry(ti, &timer->active_list_head, active_list) {
L
Linus Torvalds 已提交
951 952
		if (ti->ccallback)
			ti->ccallback(ti, event, tstamp, resolution);
953
		list_for_each_entry(ts, &ti->slave_active_head, active_list)
L
Linus Torvalds 已提交
954 955 956 957 958 959 960 961 962
			if (ts->ccallback)
				ts->ccallback(ts, event, tstamp, resolution);
	}
	spin_unlock_irqrestore(&timer->lock, flags);
}

/*
 * exported functions for global timers
 */
963
int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer)
L
Linus Torvalds 已提交
964
{
965
	struct snd_timer_id tid;
C
Clemens Ladisch 已提交
966

L
Linus Torvalds 已提交
967 968 969 970 971 972 973 974
	tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
	tid.card = -1;
	tid.device = device;
	tid.subdevice = 0;
	return snd_timer_new(NULL, id, &tid, rtimer);
}

975
int snd_timer_global_free(struct snd_timer *timer)
L
Linus Torvalds 已提交
976 977 978 979
{
	return snd_timer_free(timer);
}

980
int snd_timer_global_register(struct snd_timer *timer)
L
Linus Torvalds 已提交
981
{
982
	struct snd_device dev;
L
Linus Torvalds 已提交
983 984 985 986 987 988

	memset(&dev, 0, sizeof(dev));
	dev.device_data = timer;
	return snd_timer_dev_register(&dev);
}

C
Clemens Ladisch 已提交
989
/*
L
Linus Torvalds 已提交
990 991 992 993 994 995 996 997 998 999 1000 1001
 *  System timer
 */

struct snd_timer_system_private {
	struct timer_list tlist;
	unsigned long last_expires;
	unsigned long last_jiffies;
	unsigned long correction;
};

static void snd_timer_s_function(unsigned long data)
{
1002
	struct snd_timer *timer = (struct snd_timer *)data;
L
Linus Torvalds 已提交
1003 1004 1005
	struct snd_timer_system_private *priv = timer->private_data;
	unsigned long jiff = jiffies;
	if (time_after(jiff, priv->last_expires))
1006
		priv->correction += (long)jiff - (long)priv->last_expires;
L
Linus Torvalds 已提交
1007 1008 1009
	snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies);
}

1010
static int snd_timer_s_start(struct snd_timer * timer)
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021
{
	struct snd_timer_system_private *priv;
	unsigned long njiff;

	priv = (struct snd_timer_system_private *) timer->private_data;
	njiff = (priv->last_jiffies = jiffies);
	if (priv->correction > timer->sticks - 1) {
		priv->correction -= timer->sticks - 1;
		njiff++;
	} else {
		njiff += timer->sticks - priv->correction;
1022
		priv->correction = 0;
L
Linus Torvalds 已提交
1023 1024 1025 1026 1027 1028
	}
	priv->last_expires = priv->tlist.expires = njiff;
	add_timer(&priv->tlist);
	return 0;
}

1029
static int snd_timer_s_stop(struct snd_timer * timer)
L
Linus Torvalds 已提交
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
{
	struct snd_timer_system_private *priv;
	unsigned long jiff;

	priv = (struct snd_timer_system_private *) timer->private_data;
	del_timer(&priv->tlist);
	jiff = jiffies;
	if (time_before(jiff, priv->last_expires))
		timer->sticks = priv->last_expires - jiff;
	else
		timer->sticks = 1;
1041
	priv->correction = 0;
L
Linus Torvalds 已提交
1042 1043 1044
	return 0;
}

1045
static struct snd_timer_hardware snd_timer_system =
L
Linus Torvalds 已提交
1046 1047 1048 1049 1050 1051 1052 1053
{
	.flags =	SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET,
	.resolution =	1000000000L / HZ,
	.ticks =	10000000L,
	.start =	snd_timer_s_start,
	.stop =		snd_timer_s_stop
};

1054
static void snd_timer_free_system(struct snd_timer *timer)
L
Linus Torvalds 已提交
1055 1056 1057 1058 1059 1060
{
	kfree(timer->private_data);
}

static int snd_timer_register_system(void)
{
1061
	struct snd_timer *timer;
L
Linus Torvalds 已提交
1062 1063 1064
	struct snd_timer_system_private *priv;
	int err;

C
Clemens Ladisch 已提交
1065 1066
	err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer);
	if (err < 0)
L
Linus Torvalds 已提交
1067 1068 1069
		return err;
	strcpy(timer->name, "system timer");
	timer->hw = snd_timer_system;
1070
	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
L
Linus Torvalds 已提交
1071 1072 1073 1074
	if (priv == NULL) {
		snd_timer_free(timer);
		return -ENOMEM;
	}
1075
	setup_timer(&priv->tlist, snd_timer_s_function, (unsigned long) timer);
L
Linus Torvalds 已提交
1076 1077 1078 1079 1080
	timer->private_data = priv;
	timer->private_free = snd_timer_free_system;
	return snd_timer_global_register(timer);
}

1081
#ifdef CONFIG_SND_PROC_FS
L
Linus Torvalds 已提交
1082 1083 1084 1085
/*
 *  Info interface
 */

1086 1087
static void snd_timer_proc_read(struct snd_info_entry *entry,
				struct snd_info_buffer *buffer)
L
Linus Torvalds 已提交
1088
{
1089 1090
	struct snd_timer *timer;
	struct snd_timer_instance *ti;
L
Linus Torvalds 已提交
1091

1092
	mutex_lock(&register_mutex);
1093
	list_for_each_entry(timer, &snd_timer_list, device_list) {
1094 1095
		if (timer->card && timer->card->shutdown)
			continue;
L
Linus Torvalds 已提交
1096 1097 1098 1099 1100
		switch (timer->tmr_class) {
		case SNDRV_TIMER_CLASS_GLOBAL:
			snd_iprintf(buffer, "G%i: ", timer->tmr_device);
			break;
		case SNDRV_TIMER_CLASS_CARD:
C
Clemens Ladisch 已提交
1101 1102
			snd_iprintf(buffer, "C%i-%i: ",
				    timer->card->number, timer->tmr_device);
L
Linus Torvalds 已提交
1103 1104
			break;
		case SNDRV_TIMER_CLASS_PCM:
C
Clemens Ladisch 已提交
1105 1106
			snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number,
				    timer->tmr_device, timer->tmr_subdevice);
L
Linus Torvalds 已提交
1107 1108
			break;
		default:
C
Clemens Ladisch 已提交
1109 1110 1111
			snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class,
				    timer->card ? timer->card->number : -1,
				    timer->tmr_device, timer->tmr_subdevice);
L
Linus Torvalds 已提交
1112 1113 1114
		}
		snd_iprintf(buffer, "%s :", timer->name);
		if (timer->hw.resolution)
C
Clemens Ladisch 已提交
1115 1116 1117 1118
			snd_iprintf(buffer, " %lu.%03luus (%lu ticks)",
				    timer->hw.resolution / 1000,
				    timer->hw.resolution % 1000,
				    timer->hw.ticks);
L
Linus Torvalds 已提交
1119 1120 1121
		if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)
			snd_iprintf(buffer, " SLAVE");
		snd_iprintf(buffer, "\n");
1122
		list_for_each_entry(ti, &timer->open_list_head, open_list)
C
Clemens Ladisch 已提交
1123 1124 1125 1126 1127
			snd_iprintf(buffer, "  Client %s : %s\n",
				    ti->owner ? ti->owner : "unknown",
				    ti->flags & (SNDRV_TIMER_IFLG_START |
						 SNDRV_TIMER_IFLG_RUNNING)
				    ? "running" : "stopped");
L
Linus Torvalds 已提交
1128
	}
1129
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
1130 1131
}

1132
static struct snd_info_entry *snd_timer_proc_entry;
1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150

static void __init snd_timer_proc_init(void)
{
	struct snd_info_entry *entry;

	entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL);
	if (entry != NULL) {
		entry->c.text.read = snd_timer_proc_read;
		if (snd_info_register(entry) < 0) {
			snd_info_free_entry(entry);
			entry = NULL;
		}
	}
	snd_timer_proc_entry = entry;
}

static void __exit snd_timer_proc_done(void)
{
1151
	snd_info_free_entry(snd_timer_proc_entry);
1152
}
1153
#else /* !CONFIG_SND_PROC_FS */
1154 1155 1156 1157
#define snd_timer_proc_init()
#define snd_timer_proc_done()
#endif

L
Linus Torvalds 已提交
1158 1159 1160 1161
/*
 *  USER SPACE interface
 */

1162
static void snd_timer_user_interrupt(struct snd_timer_instance *timeri,
L
Linus Torvalds 已提交
1163 1164 1165
				     unsigned long resolution,
				     unsigned long ticks)
{
1166 1167
	struct snd_timer_user *tu = timeri->callback_data;
	struct snd_timer_read *r;
L
Linus Torvalds 已提交
1168
	int prev;
C
Clemens Ladisch 已提交
1169

L
Linus Torvalds 已提交
1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
	spin_lock(&tu->qlock);
	if (tu->qused > 0) {
		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
		r = &tu->queue[prev];
		if (r->resolution == resolution) {
			r->ticks += ticks;
			goto __wake;
		}
	}
	if (tu->qused >= tu->queue_size) {
		tu->overrun++;
	} else {
		r = &tu->queue[tu->qtail++];
		tu->qtail %= tu->queue_size;
		r->resolution = resolution;
		r->ticks = ticks;
		tu->qused++;
	}
      __wake:
	spin_unlock(&tu->qlock);
	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
	wake_up(&tu->qchange_sleep);
}

1194 1195
static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu,
					    struct snd_timer_tread *tread)
L
Linus Torvalds 已提交
1196 1197 1198 1199 1200 1201 1202 1203 1204 1205
{
	if (tu->qused >= tu->queue_size) {
		tu->overrun++;
	} else {
		memcpy(&tu->tqueue[tu->qtail++], tread, sizeof(*tread));
		tu->qtail %= tu->queue_size;
		tu->qused++;
	}
}

1206 1207
static void snd_timer_user_ccallback(struct snd_timer_instance *timeri,
				     int event,
L
Linus Torvalds 已提交
1208 1209 1210
				     struct timespec *tstamp,
				     unsigned long resolution)
{
1211 1212
	struct snd_timer_user *tu = timeri->callback_data;
	struct snd_timer_tread r1;
1213
	unsigned long flags;
L
Linus Torvalds 已提交
1214

C
Clemens Ladisch 已提交
1215 1216
	if (event >= SNDRV_TIMER_EVENT_START &&
	    event <= SNDRV_TIMER_EVENT_PAUSE)
L
Linus Torvalds 已提交
1217 1218 1219 1220 1221 1222
		tu->tstamp = *tstamp;
	if ((tu->filter & (1 << event)) == 0 || !tu->tread)
		return;
	r1.event = event;
	r1.tstamp = *tstamp;
	r1.val = resolution;
1223
	spin_lock_irqsave(&tu->qlock, flags);
L
Linus Torvalds 已提交
1224
	snd_timer_user_append_to_tqueue(tu, &r1);
1225
	spin_unlock_irqrestore(&tu->qlock, flags);
L
Linus Torvalds 已提交
1226 1227 1228 1229
	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
	wake_up(&tu->qchange_sleep);
}

1230
static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri,
L
Linus Torvalds 已提交
1231 1232 1233
				      unsigned long resolution,
				      unsigned long ticks)
{
1234 1235
	struct snd_timer_user *tu = timeri->callback_data;
	struct snd_timer_tread *r, r1;
L
Linus Torvalds 已提交
1236 1237 1238
	struct timespec tstamp;
	int prev, append = 0;

T
Takashi Iwai 已提交
1239
	memset(&tstamp, 0, sizeof(tstamp));
L
Linus Torvalds 已提交
1240
	spin_lock(&tu->qlock);
C
Clemens Ladisch 已提交
1241 1242
	if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) |
			   (1 << SNDRV_TIMER_EVENT_TICK))) == 0) {
L
Linus Torvalds 已提交
1243 1244 1245
		spin_unlock(&tu->qlock);
		return;
	}
1246 1247
	if (tu->last_resolution != resolution || ticks > 0) {
		if (timer_tstamp_monotonic)
T
Thomas Gleixner 已提交
1248
			ktime_get_ts(&tstamp);
1249 1250 1251
		else
			getnstimeofday(&tstamp);
	}
C
Clemens Ladisch 已提交
1252 1253
	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
	    tu->last_resolution != resolution) {
L
Linus Torvalds 已提交
1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
		r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
		r1.tstamp = tstamp;
		r1.val = resolution;
		snd_timer_user_append_to_tqueue(tu, &r1);
		tu->last_resolution = resolution;
		append++;
	}
	if ((tu->filter & (1 << SNDRV_TIMER_EVENT_TICK)) == 0)
		goto __wake;
	if (ticks == 0)
		goto __wake;
	if (tu->qused > 0) {
		prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1;
		r = &tu->tqueue[prev];
		if (r->event == SNDRV_TIMER_EVENT_TICK) {
			r->tstamp = tstamp;
			r->val += ticks;
			append++;
			goto __wake;
		}
	}
	r1.event = SNDRV_TIMER_EVENT_TICK;
	r1.tstamp = tstamp;
	r1.val = ticks;
	snd_timer_user_append_to_tqueue(tu, &r1);
	append++;
      __wake:
	spin_unlock(&tu->qlock);
	if (append == 0)
		return;
	kill_fasync(&tu->fasync, SIGIO, POLL_IN);
	wake_up(&tu->qchange_sleep);
}

static int snd_timer_user_open(struct inode *inode, struct file *file)
{
1290
	struct snd_timer_user *tu;
T
Takashi Iwai 已提交
1291 1292 1293 1294 1295
	int err;

	err = nonseekable_open(inode, file);
	if (err < 0)
		return err;
C
Clemens Ladisch 已提交
1296

1297
	tu = kzalloc(sizeof(*tu), GFP_KERNEL);
L
Linus Torvalds 已提交
1298 1299 1300 1301
	if (tu == NULL)
		return -ENOMEM;
	spin_lock_init(&tu->qlock);
	init_waitqueue_head(&tu->qchange_sleep);
1302
	mutex_init(&tu->ioctl_lock);
L
Linus Torvalds 已提交
1303 1304
	tu->ticks = 1;
	tu->queue_size = 128;
1305
	tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
C
Clemens Ladisch 已提交
1306
			    GFP_KERNEL);
L
Linus Torvalds 已提交
1307 1308 1309 1310 1311 1312 1313 1314 1315 1316
	if (tu->queue == NULL) {
		kfree(tu);
		return -ENOMEM;
	}
	file->private_data = tu;
	return 0;
}

static int snd_timer_user_release(struct inode *inode, struct file *file)
{
1317
	struct snd_timer_user *tu;
L
Linus Torvalds 已提交
1318 1319 1320 1321

	if (file->private_data) {
		tu = file->private_data;
		file->private_data = NULL;
1322
		mutex_lock(&tu->ioctl_lock);
L
Linus Torvalds 已提交
1323 1324
		if (tu->timeri)
			snd_timer_close(tu->timeri);
1325
		mutex_unlock(&tu->ioctl_lock);
L
Linus Torvalds 已提交
1326 1327 1328 1329 1330 1331 1332
		kfree(tu->queue);
		kfree(tu->tqueue);
		kfree(tu);
	}
	return 0;
}

1333
static void snd_timer_user_zero_id(struct snd_timer_id *id)
L
Linus Torvalds 已提交
1334 1335 1336 1337 1338 1339 1340 1341
{
	id->dev_class = SNDRV_TIMER_CLASS_NONE;
	id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
	id->card = -1;
	id->device = -1;
	id->subdevice = -1;
}

1342
static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer)
L
Linus Torvalds 已提交
1343 1344 1345 1346 1347 1348 1349 1350
{
	id->dev_class = timer->tmr_class;
	id->dev_sclass = SNDRV_TIMER_SCLASS_NONE;
	id->card = timer->card ? timer->card->number : -1;
	id->device = timer->tmr_device;
	id->subdevice = timer->tmr_subdevice;
}

1351
static int snd_timer_user_next_device(struct snd_timer_id __user *_tid)
L
Linus Torvalds 已提交
1352
{
1353 1354
	struct snd_timer_id id;
	struct snd_timer *timer;
L
Linus Torvalds 已提交
1355
	struct list_head *p;
C
Clemens Ladisch 已提交
1356

L
Linus Torvalds 已提交
1357 1358
	if (copy_from_user(&id, _tid, sizeof(id)))
		return -EFAULT;
1359
	mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
1360 1361 1362 1363
	if (id.dev_class < 0) {		/* first item */
		if (list_empty(&snd_timer_list))
			snd_timer_user_zero_id(&id);
		else {
1364
			timer = list_entry(snd_timer_list.next,
1365
					   struct snd_timer, device_list);
L
Linus Torvalds 已提交
1366 1367 1368 1369 1370 1371 1372
			snd_timer_user_copy_id(&id, timer);
		}
	} else {
		switch (id.dev_class) {
		case SNDRV_TIMER_CLASS_GLOBAL:
			id.device = id.device < 0 ? 0 : id.device + 1;
			list_for_each(p, &snd_timer_list) {
1373
				timer = list_entry(p, struct snd_timer, device_list);
L
Linus Torvalds 已提交
1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396
				if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
				if (timer->tmr_device >= id.device) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
			}
			if (p == &snd_timer_list)
				snd_timer_user_zero_id(&id);
			break;
		case SNDRV_TIMER_CLASS_CARD:
		case SNDRV_TIMER_CLASS_PCM:
			if (id.card < 0) {
				id.card = 0;
			} else {
				if (id.card < 0) {
					id.card = 0;
				} else {
					if (id.device < 0) {
						id.device = 0;
					} else {
C
Clemens Ladisch 已提交
1397 1398 1399 1400 1401
						if (id.subdevice < 0) {
							id.subdevice = 0;
						} else {
							id.subdevice++;
						}
L
Linus Torvalds 已提交
1402 1403 1404 1405
					}
				}
			}
			list_for_each(p, &snd_timer_list) {
1406
				timer = list_entry(p, struct snd_timer, device_list);
L
Linus Torvalds 已提交
1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440
				if (timer->tmr_class > id.dev_class) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
				if (timer->tmr_class < id.dev_class)
					continue;
				if (timer->card->number > id.card) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
				if (timer->card->number < id.card)
					continue;
				if (timer->tmr_device > id.device) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
				if (timer->tmr_device < id.device)
					continue;
				if (timer->tmr_subdevice > id.subdevice) {
					snd_timer_user_copy_id(&id, timer);
					break;
				}
				if (timer->tmr_subdevice < id.subdevice)
					continue;
				snd_timer_user_copy_id(&id, timer);
				break;
			}
			if (p == &snd_timer_list)
				snd_timer_user_zero_id(&id);
			break;
		default:
			snd_timer_user_zero_id(&id);
		}
	}
1441
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
1442 1443 1444
	if (copy_to_user(_tid, &id, sizeof(*_tid)))
		return -EFAULT;
	return 0;
C
Clemens Ladisch 已提交
1445
}
L
Linus Torvalds 已提交
1446

C
Clemens Ladisch 已提交
1447
static int snd_timer_user_ginfo(struct file *file,
1448
				struct snd_timer_ginfo __user *_ginfo)
L
Linus Torvalds 已提交
1449
{
1450 1451 1452
	struct snd_timer_ginfo *ginfo;
	struct snd_timer_id tid;
	struct snd_timer *t;
L
Linus Torvalds 已提交
1453 1454 1455
	struct list_head *p;
	int err = 0;

L
Li Zefan 已提交
1456 1457 1458 1459
	ginfo = memdup_user(_ginfo, sizeof(*ginfo));
	if (IS_ERR(ginfo))
		return PTR_ERR(ginfo);

L
Linus Torvalds 已提交
1460 1461 1462
	tid = ginfo->tid;
	memset(ginfo, 0, sizeof(*ginfo));
	ginfo->tid = tid;
1463
	mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
	t = snd_timer_find(&tid);
	if (t != NULL) {
		ginfo->card = t->card ? t->card->number : -1;
		if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
			ginfo->flags |= SNDRV_TIMER_FLG_SLAVE;
		strlcpy(ginfo->id, t->id, sizeof(ginfo->id));
		strlcpy(ginfo->name, t->name, sizeof(ginfo->name));
		ginfo->resolution = t->hw.resolution;
		if (t->hw.resolution_min > 0) {
			ginfo->resolution_min = t->hw.resolution_min;
			ginfo->resolution_max = t->hw.resolution_max;
		}
		list_for_each(p, &t->open_list_head) {
			ginfo->clients++;
		}
	} else {
		err = -ENODEV;
	}
1482
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
1483 1484 1485 1486 1487 1488
	if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo)))
		err = -EFAULT;
	kfree(ginfo);
	return err;
}

C
Clemens Ladisch 已提交
1489
static int snd_timer_user_gparams(struct file *file,
1490
				  struct snd_timer_gparams __user *_gparams)
L
Linus Torvalds 已提交
1491
{
1492 1493
	struct snd_timer_gparams gparams;
	struct snd_timer *t;
L
Linus Torvalds 已提交
1494 1495 1496 1497
	int err;

	if (copy_from_user(&gparams, _gparams, sizeof(gparams)))
		return -EFAULT;
1498
	mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
1499
	t = snd_timer_find(&gparams.tid);
C
Clemens Ladisch 已提交
1500
	if (!t) {
L
Linus Torvalds 已提交
1501
		err = -ENODEV;
C
Clemens Ladisch 已提交
1502 1503 1504 1505 1506 1507 1508 1509 1510
		goto _error;
	}
	if (!list_empty(&t->open_list_head)) {
		err = -EBUSY;
		goto _error;
	}
	if (!t->hw.set_period) {
		err = -ENOSYS;
		goto _error;
L
Linus Torvalds 已提交
1511
	}
C
Clemens Ladisch 已提交
1512 1513
	err = t->hw.set_period(t, gparams.period_num, gparams.period_den);
_error:
1514
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
1515 1516 1517
	return err;
}

C
Clemens Ladisch 已提交
1518
static int snd_timer_user_gstatus(struct file *file,
1519
				  struct snd_timer_gstatus __user *_gstatus)
L
Linus Torvalds 已提交
1520
{
1521 1522 1523
	struct snd_timer_gstatus gstatus;
	struct snd_timer_id tid;
	struct snd_timer *t;
L
Linus Torvalds 已提交
1524 1525 1526 1527 1528 1529 1530
	int err = 0;

	if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus)))
		return -EFAULT;
	tid = gstatus.tid;
	memset(&gstatus, 0, sizeof(gstatus));
	gstatus.tid = tid;
1531
	mutex_lock(&register_mutex);
L
Linus Torvalds 已提交
1532 1533 1534 1535 1536 1537 1538
	t = snd_timer_find(&tid);
	if (t != NULL) {
		if (t->hw.c_resolution)
			gstatus.resolution = t->hw.c_resolution(t);
		else
			gstatus.resolution = t->hw.resolution;
		if (t->hw.precise_resolution) {
C
Clemens Ladisch 已提交
1539 1540
			t->hw.precise_resolution(t, &gstatus.resolution_num,
						 &gstatus.resolution_den);
L
Linus Torvalds 已提交
1541 1542 1543 1544 1545 1546 1547
		} else {
			gstatus.resolution_num = gstatus.resolution;
			gstatus.resolution_den = 1000000000uL;
		}
	} else {
		err = -ENODEV;
	}
1548
	mutex_unlock(&register_mutex);
L
Linus Torvalds 已提交
1549 1550 1551 1552 1553
	if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus)))
		err = -EFAULT;
	return err;
}

C
Clemens Ladisch 已提交
1554
static int snd_timer_user_tselect(struct file *file,
1555
				  struct snd_timer_select __user *_tselect)
L
Linus Torvalds 已提交
1556
{
1557 1558
	struct snd_timer_user *tu;
	struct snd_timer_select tselect;
L
Linus Torvalds 已提交
1559
	char str[32];
1560
	int err = 0;
C
Clemens Ladisch 已提交
1561

L
Linus Torvalds 已提交
1562
	tu = file->private_data;
1563
	if (tu->timeri) {
L
Linus Torvalds 已提交
1564
		snd_timer_close(tu->timeri);
1565 1566 1567 1568 1569 1570
		tu->timeri = NULL;
	}
	if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
		err = -EFAULT;
		goto __err;
	}
L
Linus Torvalds 已提交
1571 1572 1573
	sprintf(str, "application %i", current->pid);
	if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
		tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
C
Clemens Ladisch 已提交
1574 1575
	err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid);
	if (err < 0)
1576
		goto __err;
L
Linus Torvalds 已提交
1577

1578 1579 1580 1581
	kfree(tu->queue);
	tu->queue = NULL;
	kfree(tu->tqueue);
	tu->tqueue = NULL;
L
Linus Torvalds 已提交
1582
	if (tu->tread) {
1583
		tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread),
C
Clemens Ladisch 已提交
1584
				     GFP_KERNEL);
1585 1586
		if (tu->tqueue == NULL)
			err = -ENOMEM;
L
Linus Torvalds 已提交
1587
	} else {
1588
		tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read),
C
Clemens Ladisch 已提交
1589
				    GFP_KERNEL);
1590 1591
		if (tu->queue == NULL)
			err = -ENOMEM;
L
Linus Torvalds 已提交
1592
	}
C
Clemens Ladisch 已提交
1593

1594 1595 1596 1597 1598
      	if (err < 0) {
		snd_timer_close(tu->timeri);
      		tu->timeri = NULL;
      	} else {
		tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
C
Clemens Ladisch 已提交
1599 1600
		tu->timeri->callback = tu->tread
			? snd_timer_user_tinterrupt : snd_timer_user_interrupt;
1601 1602 1603 1604 1605 1606
		tu->timeri->ccallback = snd_timer_user_ccallback;
		tu->timeri->callback_data = (void *)tu;
	}

      __err:
	return err;
L
Linus Torvalds 已提交
1607 1608
}

C
Clemens Ladisch 已提交
1609
static int snd_timer_user_info(struct file *file,
1610
			       struct snd_timer_info __user *_info)
L
Linus Torvalds 已提交
1611
{
1612 1613 1614
	struct snd_timer_user *tu;
	struct snd_timer_info *info;
	struct snd_timer *t;
L
Linus Torvalds 已提交
1615 1616 1617
	int err = 0;

	tu = file->private_data;
1618 1619
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1620
	t = tu->timeri->timer;
1621 1622
	if (!t)
		return -EBADFD;
L
Linus Torvalds 已提交
1623

1624
	info = kzalloc(sizeof(*info), GFP_KERNEL);
L
Linus Torvalds 已提交
1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638
	if (! info)
		return -ENOMEM;
	info->card = t->card ? t->card->number : -1;
	if (t->hw.flags & SNDRV_TIMER_HW_SLAVE)
		info->flags |= SNDRV_TIMER_FLG_SLAVE;
	strlcpy(info->id, t->id, sizeof(info->id));
	strlcpy(info->name, t->name, sizeof(info->name));
	info->resolution = t->hw.resolution;
	if (copy_to_user(_info, info, sizeof(*_info)))
		err = -EFAULT;
	kfree(info);
	return err;
}

C
Clemens Ladisch 已提交
1639
static int snd_timer_user_params(struct file *file,
1640
				 struct snd_timer_params __user *_params)
L
Linus Torvalds 已提交
1641
{
1642 1643 1644 1645 1646
	struct snd_timer_user *tu;
	struct snd_timer_params params;
	struct snd_timer *t;
	struct snd_timer_read *tr;
	struct snd_timer_tread *ttr;
L
Linus Torvalds 已提交
1647
	int err;
C
Clemens Ladisch 已提交
1648

L
Linus Torvalds 已提交
1649
	tu = file->private_data;
1650 1651
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1652
	t = tu->timeri->timer;
1653 1654
	if (!t)
		return -EBADFD;
L
Linus Torvalds 已提交
1655 1656 1657 1658 1659 1660
	if (copy_from_user(&params, _params, sizeof(params)))
		return -EFAULT;
	if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
		err = -EINVAL;
		goto _end;
	}
C
Clemens Ladisch 已提交
1661 1662
	if (params.queue_size > 0 &&
	    (params.queue_size < 32 || params.queue_size > 1024)) {
L
Linus Torvalds 已提交
1663 1664 1665 1666 1667 1668 1669 1670 1671
		err = -EINVAL;
		goto _end;
	}
	if (params.filter & ~((1<<SNDRV_TIMER_EVENT_RESOLUTION)|
			      (1<<SNDRV_TIMER_EVENT_TICK)|
			      (1<<SNDRV_TIMER_EVENT_START)|
			      (1<<SNDRV_TIMER_EVENT_STOP)|
			      (1<<SNDRV_TIMER_EVENT_CONTINUE)|
			      (1<<SNDRV_TIMER_EVENT_PAUSE)|
1672 1673
			      (1<<SNDRV_TIMER_EVENT_SUSPEND)|
			      (1<<SNDRV_TIMER_EVENT_RESUME)|
L
Linus Torvalds 已提交
1674 1675 1676
			      (1<<SNDRV_TIMER_EVENT_MSTART)|
			      (1<<SNDRV_TIMER_EVENT_MSTOP)|
			      (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
1677 1678
			      (1<<SNDRV_TIMER_EVENT_MPAUSE)|
			      (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
1679
			      (1<<SNDRV_TIMER_EVENT_MRESUME))) {
L
Linus Torvalds 已提交
1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694
		err = -EINVAL;
		goto _end;
	}
	snd_timer_stop(tu->timeri);
	spin_lock_irq(&t->lock);
	tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
			       SNDRV_TIMER_IFLG_EXCLUSIVE|
			       SNDRV_TIMER_IFLG_EARLY_EVENT);
	if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
		tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
	if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
		tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
	if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
		tu->timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT;
	spin_unlock_irq(&t->lock);
C
Clemens Ladisch 已提交
1695 1696
	if (params.queue_size > 0 &&
	    (unsigned int)tu->queue_size != params.queue_size) {
L
Linus Torvalds 已提交
1697
		if (tu->tread) {
C
Clemens Ladisch 已提交
1698 1699
			ttr = kmalloc(params.queue_size * sizeof(*ttr),
				      GFP_KERNEL);
L
Linus Torvalds 已提交
1700 1701 1702 1703 1704 1705
			if (ttr) {
				kfree(tu->tqueue);
				tu->queue_size = params.queue_size;
				tu->tqueue = ttr;
			}
		} else {
C
Clemens Ladisch 已提交
1706 1707
			tr = kmalloc(params.queue_size * sizeof(*tr),
				     GFP_KERNEL);
L
Linus Torvalds 已提交
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
			if (tr) {
				kfree(tu->queue);
				tu->queue_size = params.queue_size;
				tu->queue = tr;
			}
		}
	}
	tu->qhead = tu->qtail = tu->qused = 0;
	if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
		if (tu->tread) {
1718
			struct snd_timer_tread tread;
L
Linus Torvalds 已提交
1719 1720 1721 1722 1723 1724
			tread.event = SNDRV_TIMER_EVENT_EARLY;
			tread.tstamp.tv_sec = 0;
			tread.tstamp.tv_nsec = 0;
			tread.val = 0;
			snd_timer_user_append_to_tqueue(tu, &tread);
		} else {
1725
			struct snd_timer_read *r = &tu->queue[0];
L
Linus Torvalds 已提交
1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740
			r->resolution = 0;
			r->ticks = 0;
			tu->qused++;
			tu->qtail++;
		}
	}
	tu->filter = params.filter;
	tu->ticks = params.ticks;
	err = 0;
 _end:
	if (copy_to_user(_params, &params, sizeof(params)))
		return -EFAULT;
	return err;
}

C
Clemens Ladisch 已提交
1741
static int snd_timer_user_status(struct file *file,
1742
				 struct snd_timer_status __user *_status)
L
Linus Torvalds 已提交
1743
{
1744 1745
	struct snd_timer_user *tu;
	struct snd_timer_status status;
C
Clemens Ladisch 已提交
1746

L
Linus Torvalds 已提交
1747
	tu = file->private_data;
1748 1749
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765
	memset(&status, 0, sizeof(status));
	status.tstamp = tu->tstamp;
	status.resolution = snd_timer_resolution(tu->timeri);
	status.lost = tu->timeri->lost;
	status.overrun = tu->overrun;
	spin_lock_irq(&tu->qlock);
	status.queue = tu->qused;
	spin_unlock_irq(&tu->qlock);
	if (copy_to_user(_status, &status, sizeof(status)))
		return -EFAULT;
	return 0;
}

static int snd_timer_user_start(struct file *file)
{
	int err;
1766
	struct snd_timer_user *tu;
C
Clemens Ladisch 已提交
1767

L
Linus Torvalds 已提交
1768
	tu = file->private_data;
1769 1770
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1771 1772 1773 1774 1775 1776 1777 1778 1779
	snd_timer_stop(tu->timeri);
	tu->timeri->lost = 0;
	tu->last_resolution = 0;
	return (err = snd_timer_start(tu->timeri, tu->ticks)) < 0 ? err : 0;
}

static int snd_timer_user_stop(struct file *file)
{
	int err;
1780
	struct snd_timer_user *tu;
C
Clemens Ladisch 已提交
1781

L
Linus Torvalds 已提交
1782
	tu = file->private_data;
1783 1784
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1785 1786 1787 1788 1789 1790
	return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
}

static int snd_timer_user_continue(struct file *file)
{
	int err;
1791
	struct snd_timer_user *tu;
C
Clemens Ladisch 已提交
1792

L
Linus Torvalds 已提交
1793
	tu = file->private_data;
1794 1795
	if (!tu->timeri)
		return -EBADFD;
L
Linus Torvalds 已提交
1796 1797 1798 1799
	tu->timeri->lost = 0;
	return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}

T
Takashi Iwai 已提交
1800 1801 1802
static int snd_timer_user_pause(struct file *file)
{
	int err;
1803
	struct snd_timer_user *tu;
C
Clemens Ladisch 已提交
1804

T
Takashi Iwai 已提交
1805
	tu = file->private_data;
1806 1807
	if (!tu->timeri)
		return -EBADFD;
1808
	return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
T
Takashi Iwai 已提交
1809 1810
}

1811 1812 1813 1814 1815 1816 1817
enum {
	SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20),
	SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21),
	SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22),
	SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
};

1818
static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
C
Clemens Ladisch 已提交
1819
				 unsigned long arg)
L
Linus Torvalds 已提交
1820
{
1821
	struct snd_timer_user *tu;
L
Linus Torvalds 已提交
1822 1823
	void __user *argp = (void __user *)arg;
	int __user *p = argp;
C
Clemens Ladisch 已提交
1824

L
Linus Torvalds 已提交
1825 1826 1827 1828 1829 1830 1831 1832 1833
	tu = file->private_data;
	switch (cmd) {
	case SNDRV_TIMER_IOCTL_PVERSION:
		return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
	case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
		return snd_timer_user_next_device(argp);
	case SNDRV_TIMER_IOCTL_TREAD:
	{
		int xarg;
C
Clemens Ladisch 已提交
1834

1835
		if (tu->timeri)	/* too late */
L
Linus Torvalds 已提交
1836
			return -EBUSY;
1837
		if (get_user(xarg, p))
L
Linus Torvalds 已提交
1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
			return -EFAULT;
		tu->tread = xarg ? 1 : 0;
		return 0;
	}
	case SNDRV_TIMER_IOCTL_GINFO:
		return snd_timer_user_ginfo(file, argp);
	case SNDRV_TIMER_IOCTL_GPARAMS:
		return snd_timer_user_gparams(file, argp);
	case SNDRV_TIMER_IOCTL_GSTATUS:
		return snd_timer_user_gstatus(file, argp);
	case SNDRV_TIMER_IOCTL_SELECT:
		return snd_timer_user_tselect(file, argp);
	case SNDRV_TIMER_IOCTL_INFO:
		return snd_timer_user_info(file, argp);
	case SNDRV_TIMER_IOCTL_PARAMS:
		return snd_timer_user_params(file, argp);
	case SNDRV_TIMER_IOCTL_STATUS:
		return snd_timer_user_status(file, argp);
	case SNDRV_TIMER_IOCTL_START:
1857
	case SNDRV_TIMER_IOCTL_START_OLD:
L
Linus Torvalds 已提交
1858 1859
		return snd_timer_user_start(file);
	case SNDRV_TIMER_IOCTL_STOP:
1860
	case SNDRV_TIMER_IOCTL_STOP_OLD:
L
Linus Torvalds 已提交
1861 1862
		return snd_timer_user_stop(file);
	case SNDRV_TIMER_IOCTL_CONTINUE:
1863
	case SNDRV_TIMER_IOCTL_CONTINUE_OLD:
L
Linus Torvalds 已提交
1864
		return snd_timer_user_continue(file);
T
Takashi Iwai 已提交
1865
	case SNDRV_TIMER_IOCTL_PAUSE:
1866
	case SNDRV_TIMER_IOCTL_PAUSE_OLD:
T
Takashi Iwai 已提交
1867
		return snd_timer_user_pause(file);
L
Linus Torvalds 已提交
1868 1869 1870 1871
	}
	return -ENOTTY;
}

1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883
static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
				 unsigned long arg)
{
	struct snd_timer_user *tu = file->private_data;
	long ret;

	mutex_lock(&tu->ioctl_lock);
	ret = __snd_timer_user_ioctl(file, cmd, arg);
	mutex_unlock(&tu->ioctl_lock);
	return ret;
}

L
Linus Torvalds 已提交
1884 1885
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
1886
	struct snd_timer_user *tu;
C
Clemens Ladisch 已提交
1887

L
Linus Torvalds 已提交
1888
	tu = file->private_data;
1889
	return fasync_helper(fd, file, on, &tu->fasync);
L
Linus Torvalds 已提交
1890 1891
}

C
Clemens Ladisch 已提交
1892 1893
static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
				   size_t count, loff_t *offset)
L
Linus Torvalds 已提交
1894
{
1895
	struct snd_timer_user *tu;
L
Linus Torvalds 已提交
1896 1897
	long result = 0, unit;
	int err = 0;
C
Clemens Ladisch 已提交
1898

L
Linus Torvalds 已提交
1899
	tu = file->private_data;
1900
	unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read);
L
Linus Torvalds 已提交
1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920
	spin_lock_irq(&tu->qlock);
	while ((long)count - result >= unit) {
		while (!tu->qused) {
			wait_queue_t wait;

			if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
				err = -EAGAIN;
				break;
			}

			set_current_state(TASK_INTERRUPTIBLE);
			init_waitqueue_entry(&wait, current);
			add_wait_queue(&tu->qchange_sleep, &wait);

			spin_unlock_irq(&tu->qlock);
			schedule();
			spin_lock_irq(&tu->qlock);

			remove_wait_queue(&tu->qchange_sleep, &wait);

1921 1922 1923 1924
			if (tu->disconnected) {
				err = -ENODEV;
				break;
			}
L
Linus Torvalds 已提交
1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935
			if (signal_pending(current)) {
				err = -ERESTARTSYS;
				break;
			}
		}

		spin_unlock_irq(&tu->qlock);
		if (err < 0)
			goto _error;

		if (tu->tread) {
C
Clemens Ladisch 已提交
1936
			if (copy_to_user(buffer, &tu->tqueue[tu->qhead++],
1937
					 sizeof(struct snd_timer_tread))) {
L
Linus Torvalds 已提交
1938 1939 1940 1941
				err = -EFAULT;
				goto _error;
			}
		} else {
C
Clemens Ladisch 已提交
1942
			if (copy_to_user(buffer, &tu->queue[tu->qhead++],
1943
					 sizeof(struct snd_timer_read))) {
L
Linus Torvalds 已提交
1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964
				err = -EFAULT;
				goto _error;
			}
		}

		tu->qhead %= tu->queue_size;

		result += unit;
		buffer += unit;

		spin_lock_irq(&tu->qlock);
		tu->qused--;
	}
	spin_unlock_irq(&tu->qlock);
 _error:
	return result > 0 ? result : err;
}

static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
{
        unsigned int mask;
1965
        struct snd_timer_user *tu;
L
Linus Torvalds 已提交
1966 1967 1968 1969

        tu = file->private_data;

        poll_wait(file, &tu->qchange_sleep, wait);
C
Clemens Ladisch 已提交
1970

L
Linus Torvalds 已提交
1971 1972 1973
	mask = 0;
	if (tu->qused)
		mask |= POLLIN | POLLRDNORM;
1974 1975
	if (tu->disconnected)
		mask |= POLLERR;
L
Linus Torvalds 已提交
1976 1977 1978 1979 1980 1981 1982 1983 1984 1985

	return mask;
}

#ifdef CONFIG_COMPAT
#include "timer_compat.c"
#else
#define snd_timer_user_ioctl_compat	NULL
#endif

1986
static const struct file_operations snd_timer_f_ops =
L
Linus Torvalds 已提交
1987 1988 1989 1990 1991
{
	.owner =	THIS_MODULE,
	.read =		snd_timer_user_read,
	.open =		snd_timer_user_open,
	.release =	snd_timer_user_release,
T
Takashi Iwai 已提交
1992
	.llseek =	no_llseek,
L
Linus Torvalds 已提交
1993 1994 1995 1996 1997 1998
	.poll =		snd_timer_user_poll,
	.unlocked_ioctl =	snd_timer_user_ioctl,
	.compat_ioctl =	snd_timer_user_ioctl_compat,
	.fasync = 	snd_timer_user_fasync,
};

1999 2000 2001 2002 2003 2004 2005 2006 2007
/* unregister the system timer */
static void snd_timer_free_all(void)
{
	struct snd_timer *timer, *n;

	list_for_each_entry_safe(timer, n, &snd_timer_list, device_list)
		snd_timer_free(timer);
}

2008 2009
static struct device timer_dev;

L
Linus Torvalds 已提交
2010 2011 2012 2013 2014 2015 2016 2017
/*
 *  ENTRY functions
 */

static int __init alsa_timer_init(void)
{
	int err;

2018 2019 2020
	snd_device_initialize(&timer_dev, NULL);
	dev_set_name(&timer_dev, "timer");

L
Linus Torvalds 已提交
2021
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
C
Clemens Ladisch 已提交
2022 2023
	snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1,
			      "system timer");
L
Linus Torvalds 已提交
2024
#endif
2025

2026 2027
	err = snd_timer_register_system();
	if (err < 0) {
2028
		pr_err("ALSA: unable to register system timer (%i)\n", err);
2029
		put_device(&timer_dev);
2030 2031 2032
		return err;
	}

2033 2034
	err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0,
				  &snd_timer_f_ops, NULL, &timer_dev);
2035
	if (err < 0) {
2036
		pr_err("ALSA: unable to register timer device (%i)\n", err);
2037
		snd_timer_free_all();
2038
		put_device(&timer_dev);
2039 2040 2041
		return err;
	}

2042
	snd_timer_proc_init();
L
Linus Torvalds 已提交
2043 2044 2045 2046 2047
	return 0;
}

static void __exit alsa_timer_exit(void)
{
2048
	snd_unregister_device(&timer_dev);
2049
	snd_timer_free_all();
2050
	put_device(&timer_dev);
2051
	snd_timer_proc_done();
L
Linus Torvalds 已提交
2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072
#ifdef SNDRV_OSS_INFO_DEV_TIMERS
	snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1);
#endif
}

module_init(alsa_timer_init)
module_exit(alsa_timer_exit)

EXPORT_SYMBOL(snd_timer_open);
EXPORT_SYMBOL(snd_timer_close);
EXPORT_SYMBOL(snd_timer_resolution);
EXPORT_SYMBOL(snd_timer_start);
EXPORT_SYMBOL(snd_timer_stop);
EXPORT_SYMBOL(snd_timer_continue);
EXPORT_SYMBOL(snd_timer_pause);
EXPORT_SYMBOL(snd_timer_new);
EXPORT_SYMBOL(snd_timer_notify);
EXPORT_SYMBOL(snd_timer_global_new);
EXPORT_SYMBOL(snd_timer_global_free);
EXPORT_SYMBOL(snd_timer_global_register);
EXPORT_SYMBOL(snd_timer_interrupt);