/*
* Timers abstract layer
- * Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ * Copyright (c) by Jaroslav Kysela <perex@perex.cz>
*
*
* This program is free software; you can redistribute it and/or modify
*
*/
-#include <sound/driver.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <linux/time.h>
#include <linux/mutex.h>
#include <sound/minors.h>
#include <sound/initval.h>
#include <linux/kmod.h>
-#ifdef CONFIG_KERNELD
-#include <linux/kerneld.h>
-#endif
#if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE)
#define DEFAULT_TIMER_LIMIT 3
#endif
static int timer_limit = DEFAULT_TIMER_LIMIT;
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
+static int timer_tstamp_monotonic = 1;
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>, Takashi Iwai <tiwai@suse.de>");
MODULE_DESCRIPTION("ALSA timer interface");
MODULE_LICENSE("GPL");
module_param(timer_limit, int, 0444);
MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
+module_param(timer_tstamp_monotonic, int, 0444);
+MODULE_PARM_DESC(timer_tstamp_monotonic, "Use posix monotonic clock source for timestamps (default).");
struct snd_timer_user {
struct snd_timer_instance *timeri;
return NULL;
}
-#ifdef CONFIG_KMOD
+#ifdef CONFIG_MODULES
static void snd_timer_request(struct snd_timer_id *tid)
{
- if (! current->fs->root)
- return;
switch (tid->dev_class) {
case SNDRV_TIMER_CLASS_GLOBAL:
if (tid->device < timer_limit)
/* open a master instance */
mutex_lock(®ister_mutex);
timer = snd_timer_find(tid);
-#ifdef CONFIG_KMOD
- if (timer == NULL) {
+#ifdef CONFIG_MODULES
+ if (!timer) {
mutex_unlock(®ister_mutex);
snd_timer_request(tid);
mutex_lock(®ister_mutex);
struct snd_timer *timer = NULL;
struct snd_timer_instance *slave, *tmp;
- snd_assert(timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timeri))
+ return -ENXIO;
/* force to stop the timer */
snd_timer_stop(timeri);
struct snd_timer_instance *ts;
struct timespec tstamp;
- getnstimeofday(&tstamp);
- snd_assert(event >= SNDRV_TIMER_EVENT_START &&
- event <= SNDRV_TIMER_EVENT_PAUSE, return);
+ if (timer_tstamp_monotonic)
+ do_posix_clock_monotonic_gettime(&tstamp);
+ else
+ getnstimeofday(&tstamp);
+ if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START ||
+ event > SNDRV_TIMER_EVENT_PAUSE))
+ return;
if (event == SNDRV_TIMER_EVENT_START ||
event == SNDRV_TIMER_EVENT_CONTINUE)
resolution = snd_timer_resolution(ti);
struct snd_timer *timer;
unsigned long flags;
- snd_assert(timeri != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timeri))
+ return -ENXIO;
if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE) {
if (!keep_flag) {
spin_unlock_irqrestore(&timer->lock, flags);
if (use_tasklet)
- tasklet_hi_schedule(&timer->task_queue);
+ tasklet_schedule(&timer->task_queue);
}
/*
.dev_disconnect = snd_timer_dev_disconnect,
};
- snd_assert(tid != NULL, return -EINVAL);
- snd_assert(rtimer != NULL, return -EINVAL);
- *rtimer = NULL;
+ if (snd_BUG_ON(!tid))
+ return -EINVAL;
+ if (rtimer)
+ *rtimer = NULL;
timer = kzalloc(sizeof(*timer), GFP_KERNEL);
if (timer == NULL) {
snd_printk(KERN_ERR "timer: cannot allocate\n");
return err;
}
}
- *rtimer = timer;
+ if (rtimer)
+ *rtimer = timer;
return 0;
}
static int snd_timer_free(struct snd_timer *timer)
{
- snd_assert(timer != NULL, return -ENXIO);
+ if (!timer)
+ return 0;
mutex_lock(®ister_mutex);
if (! list_empty(&timer->open_list_head)) {
struct snd_timer *timer = dev->device_data;
struct snd_timer *timer1;
- snd_assert(timer != NULL && timer->hw.start != NULL &&
- timer->hw.stop != NULL, return -ENXIO);
+ if (snd_BUG_ON(!timer || !timer->hw.start || !timer->hw.stop))
+ return -ENXIO;
if (!(timer->hw.flags & SNDRV_TIMER_HW_SLAVE) &&
!timer->hw.resolution && timer->hw.c_resolution == NULL)
return -EINVAL;
if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE))
return;
- snd_assert(event >= SNDRV_TIMER_EVENT_MSTART &&
- event <= SNDRV_TIMER_EVENT_MRESUME, return);
+ if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_MSTART ||
+ event > SNDRV_TIMER_EVENT_MRESUME))
+ return;
spin_lock_irqsave(&timer->lock, flags);
if (event == SNDRV_TIMER_EVENT_MSTART ||
event == SNDRV_TIMER_EVENT_MCONTINUE ||
spin_unlock(&tu->qlock);
return;
}
- if (tu->last_resolution != resolution || ticks > 0)
- getnstimeofday(&tstamp);
+ if (tu->last_resolution != resolution || ticks > 0) {
+ if (timer_tstamp_monotonic)
+ do_posix_clock_monotonic_gettime(&tstamp);
+ else
+ getnstimeofday(&tstamp);
+ }
if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) &&
tu->last_resolution != resolution) {
r1.event = SNDRV_TIMER_EVENT_RESOLUTION;
if (file->private_data) {
tu = file->private_data;
file->private_data = NULL;
- fasync_helper(-1, file, 0, &tu->fasync);
if (tu->timeri)
snd_timer_close(tu->timeri);
kfree(tu->queue);
struct list_head *p;
int err = 0;
- ginfo = kmalloc(sizeof(*ginfo), GFP_KERNEL);
- if (! ginfo)
- return -ENOMEM;
- if (copy_from_user(ginfo, _ginfo, sizeof(*ginfo))) {
- kfree(ginfo);
- return -EFAULT;
- }
+ ginfo = memdup_user(_ginfo, sizeof(*ginfo));
+ if (IS_ERR(ginfo))
+ return PTR_ERR(ginfo);
+
tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo));
ginfo->tid = tid;
int err = 0;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
info = kzalloc(sizeof(*info), GFP_KERNEL);
if (! info)
int err;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
t = tu->timeri->timer;
- snd_assert(t != NULL, return -ENXIO);
+ if (!t)
+ return -EBADFD;
if (copy_from_user(¶ms, _params, sizeof(params)))
return -EFAULT;
if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE) && params.ticks < 1) {
struct snd_timer_status status;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
memset(&status, 0, sizeof(status));
status.tstamp = tu->tstamp;
status.resolution = snd_timer_resolution(tu->timeri);
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
snd_timer_stop(tu->timeri);
tu->timeri->lost = 0;
tu->last_resolution = 0;
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
}
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
tu->timeri->lost = 0;
return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
}
struct snd_timer_user *tu;
tu = file->private_data;
- snd_assert(tu->timeri != NULL, return -ENXIO);
+ if (!tu->timeri)
+ return -EBADFD;
return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0;
}
static int snd_timer_user_fasync(int fd, struct file * file, int on)
{
struct snd_timer_user *tu;
- int err;
tu = file->private_data;
- err = fasync_helper(fd, file, on, &tu->fasync);
- if (err < 0)
- return err;
- return 0;
+ return fasync_helper(fd, file, on, &tu->fasync);
}
static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
#define snd_timer_user_ioctl_compat NULL
#endif
-static struct file_operations snd_timer_f_ops =
+static const struct file_operations snd_timer_f_ops =
{
.owner = THIS_MODULE,
.read = snd_timer_user_read,