diff options
Diffstat (limited to 'sound/core/timer.c')
| -rw-r--r-- | sound/core/timer.c | 314 |
1 files changed, 150 insertions, 164 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c index cdeeb639b67..777a45e08e5 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1,6 +1,6 @@ /* * 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 @@ -19,14 +19,13 @@ * */ -#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 <linux/moduleparam.h> +#include <linux/device.h> +#include <linux/module.h> #include <linux/string.h> #include <sound/core.h> #include <sound/timer.h> @@ -35,24 +34,27 @@ #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 -#elif defined(CONFIG_SND_RTCTIMER) || defined(CONFIG_SND_RTCTIMER_MODULE) +#if IS_ENABLED(CONFIG_SND_HRTIMER) +#define DEFAULT_TIMER_LIMIT 4 +#elif IS_ENABLED(CONFIG_SND_RTCTIMER) #define DEFAULT_TIMER_LIMIT 2 #else #define DEFAULT_TIMER_LIMIT 1 #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)."); + +MODULE_ALIAS_CHARDEV(CONFIG_SND_MAJOR, SNDRV_MINOR_TIMER); +MODULE_ALIAS("devname:snd/timer"); struct snd_timer_user { struct snd_timer_instance *timeri; @@ -88,7 +90,7 @@ static DEFINE_MUTEX(register_mutex); 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); -static int snd_timer_dev_unregister(struct snd_device *device); +static int snd_timer_dev_disconnect(struct snd_device *device); static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); @@ -130,11 +132,8 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner, static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) { struct snd_timer *timer = NULL; - struct list_head *p; - - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { if (timer->tmr_class != tid->dev_class) continue; if ((timer->tmr_class == SNDRV_TIMER_CLASS_CARD || @@ -151,12 +150,10 @@ static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) 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) @@ -184,18 +181,14 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) { struct snd_timer *timer; struct snd_timer_instance *master; - struct list_head *p, *q; /* FIXME: it's really dumb to look up all entries.. */ - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); - list_for_each(q, &timer->open_list_head) { - master = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { + list_for_each_entry(master, &timer->open_list_head, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { - list_del(&slave->open_list); - list_add_tail(&slave->open_list, - &master->slave_list_head); + list_move_tail(&slave->open_list, + &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -214,16 +207,13 @@ static void snd_timer_check_slave(struct snd_timer_instance *slave) */ static void snd_timer_check_master(struct snd_timer_instance *master) { - struct snd_timer_instance *slave; - struct list_head *p, *n; + struct snd_timer_instance *slave, *tmp; /* check all pending slaves */ - list_for_each_safe(p, n, &snd_timer_slave_list) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &snd_timer_slave_list, open_list) { if (slave->slave_class == master->slave_class && slave->slave_id == master->slave_id) { - list_del(p); - list_add_tail(p, &master->slave_list_head); + list_move_tail(&slave->open_list, &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -250,7 +240,8 @@ int snd_timer_open(struct snd_timer_instance **ti, /* open a slave instance */ if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || tid->dev_sclass > SNDRV_TIMER_SCLASS_OSS_SEQUENCER) { - snd_printd("invalid slave class %i\n", tid->dev_sclass); + pr_debug("ALSA: timer: invalid slave class %i\n", + tid->dev_sclass); return -EINVAL; } mutex_lock(®ister_mutex); @@ -272,8 +263,8 @@ int snd_timer_open(struct snd_timer_instance **ti, /* 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); @@ -317,10 +308,10 @@ static int _snd_timer_stop(struct snd_timer_instance *timeri, int snd_timer_close(struct snd_timer_instance *timeri) { struct snd_timer *timer = NULL; - struct list_head *p, *n; - struct snd_timer_instance *slave; + 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); @@ -339,6 +330,8 @@ int snd_timer_close(struct snd_timer_instance *timeri) mutex_unlock(®ister_mutex); } else { timer = timeri->timer; + if (snd_BUG_ON(!timer)) + goto out; /* wait, until the active callback is finished */ spin_lock_irq(&timer->lock); while (timeri->flags & SNDRV_TIMER_IFLG_CALLBACK) { @@ -353,18 +346,18 @@ int snd_timer_close(struct snd_timer_instance *timeri) timer->hw.close) timer->hw.close(timer); /* remove slave links */ - list_for_each_safe(p, n, &timeri->slave_list_head) { - slave = list_entry(p, struct snd_timer_instance, open_list); + list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head, + open_list) { spin_lock_irq(&slave_active_lock); _snd_timer_stop(slave, 1, SNDRV_TIMER_EVENT_RESOLUTION); - list_del(p); - list_add_tail(p, &snd_timer_slave_list); + list_move_tail(&slave->open_list, &snd_timer_slave_list); slave->master = NULL; slave->timer = NULL; spin_unlock_irq(&slave_active_lock); } mutex_unlock(®ister_mutex); } + out: if (timeri->private_free) timeri->private_free(timeri); kfree(timeri->owner); @@ -394,17 +387,20 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ts; - struct list_head *n; struct timespec tstamp; - getnstimeofday(&tstamp); - snd_assert(event >= SNDRV_TIMER_EVENT_START && - event <= SNDRV_TIMER_EVENT_PAUSE, return); + if (timer_tstamp_monotonic) + ktime_get_ts(&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); if (ti->ccallback) - ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution); + ti->ccallback(ti, event, &tstamp, resolution); if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) return; timer = ti->timer; @@ -413,19 +409,16 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) return; spin_lock_irqsave(&timer->lock, flags); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ti, event + 100, &tstamp, resolution); - } spin_unlock_irqrestore(&timer->lock, flags); } static int snd_timer_start1(struct snd_timer *timer, struct snd_timer_instance *timeri, unsigned long sticks) { - list_del(&timeri->active_list); - list_add_tail(&timeri->active_list, &timer->active_list_head); + list_move_tail(&timeri->active_list, &timer->active_list_head); if (timer->running) { if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) goto __start_now; @@ -489,7 +482,8 @@ static int _snd_timer_stop(struct snd_timer_instance * timeri, 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) { @@ -542,6 +536,8 @@ int snd_timer_stop(struct snd_timer_instance *timeri) if (err < 0) return err; timer = timeri->timer; + if (!timer) + return -EINVAL; spin_lock_irqsave(&timer->lock, flags); timeri->cticks = timeri->ticks; timeri->pticks = 0; @@ -593,10 +589,8 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l { struct snd_timer_instance *ti; unsigned long ticks = ~0UL; - struct list_head *p; - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->flags & SNDRV_TIMER_IFLG_START) { ti->flags &= ~SNDRV_TIMER_IFLG_START; ti->flags |= SNDRV_TIMER_IFLG_RUNNING; @@ -628,8 +622,9 @@ static void snd_timer_tasklet(unsigned long arg) struct snd_timer_instance *ti; struct list_head *p; unsigned long resolution, ticks; + unsigned long flags; - spin_lock(&timer->lock); + spin_lock_irqsave(&timer->lock, flags); /* now process all callbacks */ while (!list_empty(&timer->sack_list_head)) { p = timer->sack_list_head.next; /* get first item */ @@ -649,7 +644,7 @@ static void snd_timer_tasklet(unsigned long arg) spin_lock(&timer->lock); ti->flags &= ~SNDRV_TIMER_IFLG_CALLBACK; } - spin_unlock(&timer->lock); + spin_unlock_irqrestore(&timer->lock, flags); } /* @@ -660,9 +655,9 @@ static void snd_timer_tasklet(unsigned long arg) */ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) { - struct snd_timer_instance *ti, *ts; + struct snd_timer_instance *ti, *ts, *tmp; unsigned long resolution, ticks; - struct list_head *p, *q, *n, *ack_list_head; + struct list_head *p, *ack_list_head; unsigned long flags; int use_tasklet = 0; @@ -678,12 +673,12 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) resolution = timer->hw.resolution; /* loop for all active instances - * Here we cannot use list_for_each because the active_list of a + * Here we cannot use list_for_each_entry because the active_list of a * processed instance is relinked to done_list_head before the callback * is called. */ - list_for_each_safe(p, n, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry_safe(ti, tmp, &timer->active_list_head, + active_list) { if (!(ti->flags & SNDRV_TIMER_IFLG_RUNNING)) continue; ti->pticks += ticks_left; @@ -699,7 +694,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(p); + list_del(&ti->active_list); } if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || (ti->flags & SNDRV_TIMER_IFLG_FAST)) @@ -708,8 +703,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) ack_list_head = &timer->sack_list_head; if (list_empty(&ti->ack_list)) list_add_tail(&ti->ack_list, ack_list_head); - list_for_each(q, &ti->slave_active_head) { - ts = list_entry(q, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; if (list_empty(&ts->ack_list)) @@ -717,7 +711,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) } } if (timer->flags & SNDRV_TIMER_FLG_RESCHED) - snd_timer_reschedule(timer, ticks_left); + snd_timer_reschedule(timer, timer->sticks); if (timer->running) { if (timer->hw.flags & SNDRV_TIMER_HW_STOP) { timer->hw.stop(timer); @@ -757,7 +751,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) spin_unlock_irqrestore(&timer->lock, flags); if (use_tasklet) - tasklet_hi_schedule(&timer->task_queue); + tasklet_schedule(&timer->task_queue); } /* @@ -772,15 +766,16 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, static struct snd_device_ops ops = { .dev_free = snd_timer_dev_free, .dev_register = snd_timer_dev_register, - .dev_unregister = snd_timer_dev_unregister + .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"); + pr_err("ALSA: timer: cannot allocate\n"); return -ENOMEM; } timer->tmr_class = tid->dev_class; @@ -805,13 +800,30 @@ int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, 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 list_head *p, *n; + struct snd_timer_instance *ti; + pr_warn("ALSA: timer %p is busy?\n", timer); + 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(®ister_mutex); + if (timer->private_free) timer->private_free(timer); kfree(timer); @@ -828,17 +840,15 @@ static int snd_timer_dev_register(struct snd_device *dev) { struct snd_timer *timer = dev->device_data; struct snd_timer *timer1; - struct list_head *p; - 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; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer1 = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer1, &snd_timer_list, device_list) { if (timer1->tmr_class > timer->tmr_class) break; if (timer1->tmr_class < timer->tmr_class) @@ -861,35 +871,18 @@ static int snd_timer_dev_register(struct snd_device *dev) mutex_unlock(®ister_mutex); return -EBUSY; } - list_add_tail(&timer->device_list, p); + list_add_tail(&timer->device_list, &timer1->device_list); mutex_unlock(®ister_mutex); return 0; } -static int snd_timer_unregister(struct snd_timer *timer) +static int snd_timer_dev_disconnect(struct snd_device *device) { - struct list_head *p, *n; - struct snd_timer_instance *ti; - - snd_assert(timer != NULL, return -ENXIO); + struct snd_timer *timer = device->device_data; mutex_lock(®ister_mutex); - if (! list_empty(&timer->open_list_head)) { - snd_printk(KERN_WARNING "timer 0x%lx is busy?\n", (long)timer); - 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); + list_del_init(&timer->device_list); mutex_unlock(®ister_mutex); - return snd_timer_free(timer); -} - -static int snd_timer_dev_unregister(struct snd_device *device) -{ - struct snd_timer *timer = device->device_data; - return snd_timer_unregister(timer); + return 0; } void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) @@ -897,12 +890,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam unsigned long flags; unsigned long resolution = 0; struct snd_timer_instance *ti, *ts; - struct list_head *p, *n; 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 || @@ -912,15 +905,12 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam else resolution = timer->hw.resolution; } - list_for_each(p, &timer->active_list_head) { - ti = list_entry(p, struct snd_timer_instance, active_list); + list_for_each_entry(ti, &timer->active_list_head, active_list) { if (ti->ccallback) ti->ccallback(ti, event, tstamp, resolution); - list_for_each(n, &ti->slave_active_head) { - ts = list_entry(n, struct snd_timer_instance, active_list); + list_for_each_entry(ts, &ti->slave_active_head, active_list) if (ts->ccallback) ts->ccallback(ts, event, tstamp, resolution); - } } spin_unlock_irqrestore(&timer->lock, flags); } @@ -954,18 +944,12 @@ int snd_timer_global_register(struct snd_timer *timer) return snd_timer_dev_register(&dev); } -int snd_timer_global_unregister(struct snd_timer *timer) -{ - return snd_timer_unregister(timer); -} - /* * System timer */ struct snd_timer_system_private { struct timer_list tlist; - struct timer * timer; unsigned long last_expires; unsigned long last_jiffies; unsigned long correction; @@ -977,7 +961,7 @@ static void snd_timer_s_function(unsigned long data) struct snd_timer_system_private *priv = timer->private_data; unsigned long jiff = jiffies; if (time_after(jiff, priv->last_expires)) - priv->correction = (long)jiff - (long)priv->last_expires; + priv->correction += (long)jiff - (long)priv->last_expires; snd_timer_interrupt(timer, (long)jiff - (long)priv->last_jiffies); } @@ -993,7 +977,7 @@ static int snd_timer_s_start(struct snd_timer * timer) njiff++; } else { njiff += timer->sticks - priv->correction; - priv->correction -= timer->sticks; + priv->correction = 0; } priv->last_expires = priv->tlist.expires = njiff; add_timer(&priv->tlist); @@ -1012,6 +996,7 @@ static int snd_timer_s_stop(struct snd_timer * timer) timer->sticks = priv->last_expires - jiff; else timer->sticks = 1; + priv->correction = 0; return 0; } @@ -1061,14 +1046,11 @@ static int snd_timer_register_system(void) static void snd_timer_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { - unsigned long flags; struct snd_timer *timer; struct snd_timer_instance *ti; - struct list_head *p, *q; mutex_lock(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer = list_entry(p, struct snd_timer, device_list); + list_for_each_entry(timer, &snd_timer_list, device_list) { switch (timer->tmr_class) { case SNDRV_TIMER_CLASS_GLOBAL: snd_iprintf(buffer, "G%i: ", timer->tmr_device); @@ -1095,21 +1077,17 @@ static void snd_timer_proc_read(struct snd_info_entry *entry, if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) snd_iprintf(buffer, " SLAVE"); snd_iprintf(buffer, "\n"); - spin_lock_irqsave(&timer->lock, flags); - list_for_each(q, &timer->open_list_head) { - ti = list_entry(q, struct snd_timer_instance, open_list); + list_for_each_entry(ti, &timer->open_list_head, open_list) snd_iprintf(buffer, " Client %s : %s\n", ti->owner ? ti->owner : "unknown", ti->flags & (SNDRV_TIMER_IFLG_START | SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped"); - } - spin_unlock_irqrestore(&timer->lock, flags); } mutex_unlock(®ister_mutex); } -static struct snd_info_entry *snd_timer_proc_entry = NULL; +static struct snd_info_entry *snd_timer_proc_entry; static void __init snd_timer_proc_init(void) { @@ -1117,7 +1095,6 @@ static void __init snd_timer_proc_init(void) entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL); if (entry != NULL) { - entry->c.text.read_size = SNDRV_TIMER_DEVICES * 128; entry->c.text.read = snd_timer_proc_read; if (snd_info_register(entry) < 0) { snd_info_free_entry(entry); @@ -1129,7 +1106,7 @@ static void __init snd_timer_proc_init(void) static void __exit snd_timer_proc_done(void) { - snd_info_unregister(snd_timer_proc_entry); + snd_info_free_entry(snd_timer_proc_entry); } #else /* !CONFIG_PROC_FS */ #define snd_timer_proc_init() @@ -1191,6 +1168,7 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, { struct snd_timer_user *tu = timeri->callback_data; struct snd_timer_tread r1; + unsigned long flags; if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) @@ -1200,9 +1178,9 @@ static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, r1.event = event; r1.tstamp = *tstamp; r1.val = resolution; - spin_lock(&tu->qlock); + spin_lock_irqsave(&tu->qlock, flags); snd_timer_user_append_to_tqueue(tu, &r1); - spin_unlock(&tu->qlock); + spin_unlock_irqrestore(&tu->qlock, flags); kill_fasync(&tu->fasync, SIGIO, POLL_IN); wake_up(&tu->qchange_sleep); } @@ -1223,8 +1201,12 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, 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) + ktime_get_ts(&tstamp); + else + getnstimeofday(&tstamp); + } if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { r1.event = SNDRV_TIMER_EVENT_RESOLUTION; @@ -1264,6 +1246,11 @@ static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, static int snd_timer_user_open(struct inode *inode, struct file *file) { struct snd_timer_user *tu; + int err; + + err = nonseekable_open(inode, file); + if (err < 0) + return err; tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) @@ -1290,7 +1277,6 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) 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); @@ -1423,13 +1409,10 @@ static int snd_timer_user_ginfo(struct file *file, 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; @@ -1590,9 +1573,11 @@ static int snd_timer_user_info(struct file *file, 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) @@ -1620,9 +1605,11 @@ static int snd_timer_user_params(struct file *file, 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) { @@ -1716,7 +1703,8 @@ static int snd_timer_user_status(struct file *file, 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); @@ -1736,7 +1724,8 @@ static int snd_timer_user_start(struct file *file) 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; @@ -1749,7 +1738,8 @@ static int snd_timer_user_stop(struct file *file) 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; } @@ -1759,7 +1749,8 @@ static int snd_timer_user_continue(struct file *file) 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; } @@ -1770,7 +1761,8 @@ static int snd_timer_user_pause(struct file *file) 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; } @@ -1844,13 +1836,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, 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, @@ -1941,12 +1929,13 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) #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, .open = snd_timer_user_open, .release = snd_timer_user_release, + .llseek = no_llseek, .poll = snd_timer_user_poll, .unlocked_ioctl = snd_timer_user_ioctl, .compat_ioctl = snd_timer_user_ioctl_compat, @@ -1967,12 +1956,10 @@ static int __init alsa_timer_init(void) #endif if ((err = snd_timer_register_system()) < 0) - snd_printk(KERN_ERR "unable to register system timer (%i)\n", - err); + pr_err("ALSA: unable to register system timer (%i)\n", err); if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0, &snd_timer_f_ops, NULL, "timer")) < 0) - snd_printk(KERN_ERR "unable to register timer device (%i)\n", - err); + pr_err("ALSA: unable to register timer device (%i)\n", err); snd_timer_proc_init(); return 0; } @@ -1985,7 +1972,7 @@ static void __exit alsa_timer_exit(void) /* unregister the system timer */ list_for_each_safe(p, n, &snd_timer_list) { struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); - snd_timer_unregister(timer); + snd_timer_free(timer); } snd_timer_proc_done(); #ifdef SNDRV_OSS_INFO_DEV_TIMERS @@ -2008,5 +1995,4 @@ 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_global_unregister); EXPORT_SYMBOL(snd_timer_interrupt); |
