X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=sound%2Fcore%2Ftimer.c;h=8f8b17ac074df5d8e07821c638657e55a1730fb4;hb=d0d2c38e3963f4f86a9e62d74f45a371458f2787;hp=cb011a1d4c3ea370f77c454fd5921ddcce841f81;hpb=d138b44589cc180418f5a20cb0ecfe338123d86c;p=safe%2Fjmp%2Flinux-2.6 diff --git a/sound/core/timer.c b/sound/core/timer.c index cb011a1..8f8b17a 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -1,6 +1,6 @@ /* * Timers abstract layer - * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Jaroslav Kysela * * * This program is free software; you can redistribute it and/or modify @@ -19,13 +19,13 @@ * */ -#include #include #include -#include #include #include +#include #include +#include #include #include #include @@ -33,9 +33,6 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include -#endif #if defined(CONFIG_SND_HPET) || defined(CONFIG_SND_HPET_MODULE) #define DEFAULT_TIMER_LIMIT 3 @@ -46,31 +43,34 @@ #endif static int timer_limit = DEFAULT_TIMER_LIMIT; -MODULE_AUTHOR("Jaroslav Kysela , Takashi Iwai "); +static int timer_tstamp_monotonic = 1; +MODULE_AUTHOR("Jaroslav Kysela , Takashi Iwai "); 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)."); -typedef struct { - snd_timer_instance_t *timeri; - int tread; /* enhanced read with timestamps and events */ +struct snd_timer_user { + struct snd_timer_instance *timeri; + int tread; /* enhanced read with timestamps and events */ unsigned long ticks; unsigned long overrun; int qhead; int qtail; int qused; int queue_size; - snd_timer_read_t *queue; - snd_timer_tread_t *tqueue; + struct snd_timer_read *queue; + struct snd_timer_tread *tqueue; 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; - struct semaphore tread_sem; -} snd_timer_user_t; + struct mutex tread_sem; +}; /* list of timers */ static LIST_HEAD(snd_timer_list); @@ -81,26 +81,27 @@ static LIST_HEAD(snd_timer_slave_list); /* lock for slave active lists */ static DEFINE_SPINLOCK(slave_active_lock); -static DECLARE_MUTEX(register_mutex); +static DEFINE_MUTEX(register_mutex); -static int snd_timer_free(snd_timer_t *timer); -static int snd_timer_dev_free(snd_device_t *device); -static int snd_timer_dev_register(snd_device_t *device); -static int snd_timer_dev_unregister(snd_device_t *device); +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_disconnect(struct snd_device *device); -static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left); +static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left); /* * create a timer instance with the given owner string. * when timer is not NULL, increments the module counter */ -static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer) +static struct snd_timer_instance *snd_timer_instance_new(char *owner, + struct snd_timer *timer) { - snd_timer_instance_t *timeri; - timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL); + struct snd_timer_instance *timeri; + timeri = kzalloc(sizeof(*timeri), GFP_KERNEL); if (timeri == NULL) return NULL; - timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL); + timeri->owner = kstrdup(owner, GFP_KERNEL); if (! timeri->owner) { kfree(timeri); return NULL; @@ -112,7 +113,7 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti INIT_LIST_HEAD(&timeri->slave_active_head); timeri->timer = timer; - if (timer && timer->card && !try_module_get(timer->card->module)) { + if (timer && !try_module_get(timer->module)) { kfree(timeri->owner); kfree(timeri); return NULL; @@ -124,14 +125,11 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti /* * find a timer instance from the given timer id */ -static snd_timer_t *snd_timer_find(snd_timer_id_t *tid) +static struct snd_timer *snd_timer_find(struct snd_timer_id *tid) { - snd_timer_t *timer = NULL; - struct list_head *p; - - list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + struct snd_timer *timer = NULL; + 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 || @@ -148,12 +146,10 @@ static snd_timer_t *snd_timer_find(snd_timer_id_t *tid) return NULL; } -#ifdef CONFIG_KMOD +#ifdef CONFIG_MODULES -static void snd_timer_request(snd_timer_id_t *tid) +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) @@ -177,21 +173,19 @@ static void snd_timer_request(snd_timer_id_t *tid) * * call this with register_mutex down. */ -static void snd_timer_check_slave(snd_timer_instance_t *slave) +static void snd_timer_check_slave(struct snd_timer_instance *slave) { - snd_timer_t *timer; - snd_timer_instance_t *master; - struct list_head *p, *q; + struct snd_timer *timer; + struct snd_timer_instance *master; /* FIXME: it's really dumb to look up all entries.. */ - list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); - list_for_each(q, &timer->open_list_head) { - master = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, 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_add_tail(&slave->open_list, + &master->slave_list_head); spin_lock_irq(&slave_active_lock); slave->master = master; slave->timer = master->timer; @@ -208,23 +202,21 @@ static void snd_timer_check_slave(snd_timer_instance_t *slave) * * call this with register_mutex down. */ -static void snd_timer_check_master(snd_timer_instance_t *master) +static void snd_timer_check_master(struct snd_timer_instance *master) { - snd_timer_instance_t *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 = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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; if (slave->flags & SNDRV_TIMER_IFLG_RUNNING) - list_add_tail(&slave->active_list, &master->slave_active_head); + list_add_tail(&slave->active_list, + &master->slave_active_head); spin_unlock_irq(&slave_active_lock); } } @@ -234,13 +226,13 @@ static void snd_timer_check_master(snd_timer_instance_t *master) * open a timer instance * when opening a master, the slave id must be here given. */ -int snd_timer_open(snd_timer_instance_t **ti, - char *owner, snd_timer_id_t *tid, +int snd_timer_open(struct snd_timer_instance **ti, + char *owner, struct snd_timer_id *tid, unsigned int slave_id) { - snd_timer_t *timer; - snd_timer_instance_t *timeri = NULL; - + struct snd_timer *timer; + struct snd_timer_instance *timeri = NULL; + if (tid->dev_class == SNDRV_TIMER_CLASS_SLAVE) { /* open a slave instance */ if (tid->dev_sclass <= SNDRV_TIMER_SCLASS_NONE || @@ -248,67 +240,74 @@ int snd_timer_open(snd_timer_instance_t **ti, snd_printd("invalid slave class %i\n", tid->dev_sclass); return -EINVAL; } - down(®ister_mutex); + mutex_lock(®ister_mutex); timeri = snd_timer_instance_new(owner, NULL); + if (!timeri) { + mutex_unlock(®ister_mutex); + return -ENOMEM; + } 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); - up(®ister_mutex); + mutex_unlock(®ister_mutex); *ti = timeri; return 0; } /* open a master instance */ - down(®ister_mutex); + mutex_lock(®ister_mutex); timer = snd_timer_find(tid); -#ifdef CONFIG_KMOD - if (timer == NULL) { - up(®ister_mutex); +#ifdef CONFIG_MODULES + if (!timer) { + mutex_unlock(®ister_mutex); snd_timer_request(tid); - down(®ister_mutex); + mutex_lock(®ister_mutex); timer = snd_timer_find(tid); } #endif - if (timer) { - if (!list_empty(&timer->open_list_head)) { - timeri = (snd_timer_instance_t *)list_entry(timer->open_list_head.next, snd_timer_instance_t, open_list); - if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { - up(®ister_mutex); - return -EBUSY; - } - } - timeri = snd_timer_instance_new(owner, timer); - if (timeri) { - 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); - } - } else { - up(®ister_mutex); + if (!timer) { + mutex_unlock(®ister_mutex); return -ENODEV; } - up(®ister_mutex); + if (!list_empty(&timer->open_list_head)) { + timeri = list_entry(timer->open_list_head.next, + struct snd_timer_instance, open_list); + if (timeri->flags & SNDRV_TIMER_IFLG_EXCLUSIVE) { + mutex_unlock(®ister_mutex); + return -EBUSY; + } + } + timeri = snd_timer_instance_new(owner, timer); + if (!timeri) { + mutex_unlock(®ister_mutex); + return -ENOMEM; + } + 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); + mutex_unlock(®ister_mutex); *ti = timeri; return 0; } -static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event); +static int _snd_timer_stop(struct snd_timer_instance *timeri, + int keep_flag, int event); /* * close a timer instance */ -int snd_timer_close(snd_timer_instance_t * timeri) +int snd_timer_close(struct snd_timer_instance *timeri) { - snd_timer_t *timer = NULL; - struct list_head *p, *n; - snd_timer_instance_t *slave; + 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); @@ -322,9 +321,9 @@ int snd_timer_close(snd_timer_instance_t * timeri) spin_lock_irq(&slave_active_lock); } spin_unlock_irq(&slave_active_lock); - down(®ister_mutex); + mutex_lock(®ister_mutex); list_del(&timeri->open_list); - up(®ister_mutex); + mutex_unlock(®ister_mutex); } else { timer = timeri->timer; /* wait, until the active callback is finished */ @@ -335,35 +334,35 @@ int snd_timer_close(snd_timer_instance_t * timeri) spin_lock_irq(&timer->lock); } spin_unlock_irq(&timer->lock); - down(®ister_mutex); + mutex_lock(®ister_mutex); list_del(&timeri->open_list); - if (timer && list_empty(&timer->open_list_head) && timer->hw.close) + if (timer && list_empty(&timer->open_list_head) && + timer->hw.close) timer->hw.close(timer); /* remove slave links */ - list_for_each_safe(p, n, &timeri->slave_list_head) { - slave = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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); } - up(®ister_mutex); + mutex_unlock(®ister_mutex); } if (timeri->private_free) timeri->private_free(timeri); kfree(timeri->owner); kfree(timeri); - if (timer && timer->card) - module_put(timer->card->module); + if (timer) + module_put(timer->module); return 0; } -unsigned long snd_timer_resolution(snd_timer_instance_t * timeri) +unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) { - snd_timer_t * timer; + struct snd_timer * timer; if (timeri == NULL) return 0; @@ -375,18 +374,23 @@ unsigned long snd_timer_resolution(snd_timer_instance_t * timeri) return 0; } -static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event event) +static void snd_timer_notify1(struct snd_timer_instance *ti, int event) { - snd_timer_t *timer; + struct snd_timer *timer; unsigned long flags; unsigned long resolution = 0; - snd_timer_instance_t *ts; - struct list_head *n; + struct snd_timer_instance *ts; struct timespec tstamp; - snd_timestamp_now(&tstamp, 1); - snd_assert(event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE, return); - if (event == SNDRV_TIMER_EVENT_START || event == SNDRV_TIMER_EVENT_CONTINUE) + 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); if (ti->ccallback) ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution); @@ -398,15 +402,14 @@ static void snd_timer_notify1(snd_timer_instance_t *ti, enum sndrv_timer_event e if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) return; spin_lock_irqsave(&timer->lock, flags); - list_for_each(n, &ti->slave_active_head) { - ts = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, 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(snd_timer_t *timer, snd_timer_instance_t *timeri, unsigned long sticks) +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); @@ -426,24 +429,25 @@ static int snd_timer_start1(snd_timer_t *timer, snd_timer_instance_t *timeri, un } } -static int snd_timer_start_slave(snd_timer_instance_t *timeri) +static int snd_timer_start_slave(struct snd_timer_instance *timeri) { unsigned long flags; spin_lock_irqsave(&slave_active_lock, flags); timeri->flags |= SNDRV_TIMER_IFLG_RUNNING; if (timeri->master) - list_add_tail(&timeri->active_list, &timeri->master->slave_active_head); + list_add_tail(&timeri->active_list, + &timeri->master->slave_active_head); spin_unlock_irqrestore(&slave_active_lock, flags); return 1; /* delayed start */ } /* * start the timer instance - */ -int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks) + */ +int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks) { - snd_timer_t *timer; + struct snd_timer *timer; int result = -EINVAL; unsigned long flags; @@ -466,12 +470,14 @@ int snd_timer_start(snd_timer_instance_t * timeri, unsigned int ticks) return result; } -static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sndrv_timer_event event) +static int _snd_timer_stop(struct snd_timer_instance * timeri, + int keep_flag, int event) { - snd_timer_t *timer; + 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) { @@ -500,7 +506,8 @@ static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sn } } if (!keep_flag) - timeri->flags &= ~(SNDRV_TIMER_IFLG_RUNNING|SNDRV_TIMER_IFLG_START); + timeri->flags &= + ~(SNDRV_TIMER_IFLG_RUNNING | SNDRV_TIMER_IFLG_START); spin_unlock_irqrestore(&timer->lock, flags); __end: if (event != SNDRV_TIMER_EVENT_RESOLUTION) @@ -513,9 +520,9 @@ static int _snd_timer_stop(snd_timer_instance_t * timeri, int keep_flag, enum sn * * do not call this from the timer callback! */ -int snd_timer_stop(snd_timer_instance_t * timeri) +int snd_timer_stop(struct snd_timer_instance *timeri) { - snd_timer_t *timer; + struct snd_timer *timer; unsigned long flags; int err; @@ -533,9 +540,9 @@ int snd_timer_stop(snd_timer_instance_t * timeri) /* * start again.. the tick is kept. */ -int snd_timer_continue(snd_timer_instance_t * timeri) +int snd_timer_continue(struct snd_timer_instance *timeri) { - snd_timer_t *timer; + struct snd_timer *timer; int result = -EINVAL; unsigned long flags; @@ -559,7 +566,7 @@ int snd_timer_continue(snd_timer_instance_t * timeri) /* * pause.. remember the ticks left */ -int snd_timer_pause(snd_timer_instance_t * timeri) +int snd_timer_pause(struct snd_timer_instance * timeri) { return _snd_timer_stop(timeri, 0, SNDRV_TIMER_EVENT_PAUSE); } @@ -570,14 +577,12 @@ int snd_timer_pause(snd_timer_instance_t * timeri) * start pending instances and check the scheduling ticks. * when the scheduling ticks is changed set CHANGE flag to reprogram the timer. */ -static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left) +static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_left) { - snd_timer_instance_t *ti; + struct snd_timer_instance *ti; unsigned long ticks = ~0UL; - struct list_head *p; - list_for_each(p, &timer->active_list_head) { - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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; @@ -605,20 +610,21 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left) */ static void snd_timer_tasklet(unsigned long arg) { - snd_timer_t *timer = (snd_timer_t *) arg; - snd_timer_instance_t *ti; + struct snd_timer *timer = (struct snd_timer *) 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 */ - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list); + ti = list_entry(p, struct snd_timer_instance, ack_list); /* remove from ack_list and make empty */ list_del_init(p); - + ticks = ti->pticks; ti->pticks = 0; resolution = ti->resolution; @@ -630,7 +636,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); } /* @@ -639,17 +645,18 @@ static void snd_timer_tasklet(unsigned long arg) * ticks_left is usually equal to timer->sticks. * */ -void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) +void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) { - snd_timer_instance_t *ti, *ts; + struct snd_timer_instance *ti, *ts, *tmp; unsigned long resolution, ticks; - struct list_head *p, *q, *n; + struct list_head *p, *ack_list_head; + unsigned long flags; int use_tasklet = 0; if (timer == NULL) return; - spin_lock(&timer->lock); + spin_lock_irqsave(&timer->lock, flags); /* remember the current resolution */ if (timer->hw.c_resolution) @@ -658,11 +665,12 @@ void snd_timer_interrupt(snd_timer_t * 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 processed - * instance is relinked to done_list_head before callback is called. + * 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 = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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; @@ -678,32 +686,24 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) } else { ti->flags &= ~SNDRV_TIMER_IFLG_RUNNING; if (--timer->running) - list_del(p); + list_del(&ti->active_list); } - if (list_empty(&ti->ack_list)) { - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || - (ti->flags & SNDRV_TIMER_IFLG_FAST)) { - list_add_tail(&ti->ack_list, &timer->ack_list_head); - } else { - list_add_tail(&ti->ack_list, &timer->sack_list_head); - } - } - list_for_each(q, &ti->slave_active_head) { - ts = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, active_list); + 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); + list_for_each_entry(ts, &ti->slave_active_head, active_list) { ts->pticks = ti->pticks; ts->resolution = resolution; - if (list_empty(&ts->ack_list)) { - if ((timer->hw.flags & SNDRV_TIMER_HW_TASKLET) || - (ti->flags & SNDRV_TIMER_IFLG_FAST)) { - list_add_tail(&ts->ack_list, &timer->ack_list_head); - } else { - list_add_tail(&ts->ack_list, &timer->sack_list_head); - } - } + if (list_empty(&ts->ack_list)) + list_add_tail(&ts->ack_list, ack_list_head); } } 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); @@ -722,11 +722,11 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) /* now process all fast callbacks */ while (!list_empty(&timer->ack_list_head)) { p = timer->ack_list_head.next; /* get first item */ - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, ack_list); - + ti = list_entry(p, struct snd_timer_instance, ack_list); + /* remove from ack_list and make empty */ list_del_init(p); - + ticks = ti->pticks; ti->pticks = 0; @@ -740,32 +740,36 @@ void snd_timer_interrupt(snd_timer_t * timer, unsigned long ticks_left) /* do we have any slow callbacks? */ use_tasklet = !list_empty(&timer->sack_list_head); - spin_unlock(&timer->lock); + spin_unlock_irqrestore(&timer->lock, flags); if (use_tasklet) - tasklet_hi_schedule(&timer->task_queue); + tasklet_schedule(&timer->task_queue); } /* */ -int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t ** rtimer) +int snd_timer_new(struct snd_card *card, char *id, struct snd_timer_id *tid, + struct snd_timer **rtimer) { - snd_timer_t *timer; + struct snd_timer *timer; int err; - static snd_device_ops_t ops = { + 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; - timer = kcalloc(1, sizeof(*timer), GFP_KERNEL); - if (timer == 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 -ENOMEM; + } timer->tmr_class = tid->dev_class; timer->card = card; timer->tmr_device = tid->device; @@ -778,46 +782,65 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t * INIT_LIST_HEAD(&timer->ack_list_head); INIT_LIST_HEAD(&timer->sack_list_head); spin_lock_init(&timer->lock); - tasklet_init(&timer->task_queue, snd_timer_tasklet, (unsigned long)timer); + tasklet_init(&timer->task_queue, snd_timer_tasklet, + (unsigned long)timer); if (card != NULL) { - if ((err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops)) < 0) { + timer->module = card->module; + err = snd_device_new(card, SNDRV_DEV_TIMER, timer, &ops); + if (err < 0) { snd_timer_free(timer); return err; } } - *rtimer = timer; + if (rtimer) + *rtimer = timer; return 0; } -static int snd_timer_free(snd_timer_t *timer) +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; + snd_printk(KERN_WARNING "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); return 0; } -int snd_timer_dev_free(snd_device_t *device) +static int snd_timer_dev_free(struct snd_device *device) { - snd_timer_t *timer = device->device_data; + struct snd_timer *timer = device->device_data; return snd_timer_free(timer); } -int snd_timer_dev_register(snd_device_t *dev) +static int snd_timer_dev_register(struct snd_device *dev) { - snd_timer_t *timer = dev->device_data; - snd_timer_t *timer1; - struct list_head *p; + 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; - down(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer1 = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + mutex_lock(®ister_mutex); + 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) @@ -837,65 +860,49 @@ int snd_timer_dev_register(snd_device_t *dev) if (timer1->tmr_subdevice < timer->tmr_subdevice) continue; /* conflicts.. */ - up(®ister_mutex); + mutex_unlock(®ister_mutex); return -EBUSY; } - list_add_tail(&timer->device_list, p); - up(®ister_mutex); + list_add_tail(&timer->device_list, &timer1->device_list); + mutex_unlock(®ister_mutex); return 0; } -int snd_timer_unregister(snd_timer_t *timer) +static int snd_timer_dev_disconnect(struct snd_device *device) { - struct list_head *p, *n; - snd_timer_instance_t *ti; - - snd_assert(timer != NULL, return -ENXIO); - down(®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 = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, open_list); - ti->timer = NULL; - } - } - list_del(&timer->device_list); - up(®ister_mutex); - return snd_timer_free(timer); -} - -static int snd_timer_dev_unregister(snd_device_t *device) -{ - snd_timer_t *timer = device->device_data; - return snd_timer_unregister(timer); + struct snd_timer *timer = device->device_data; + mutex_lock(®ister_mutex); + list_del_init(&timer->device_list); + mutex_unlock(®ister_mutex); + return 0; } -void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct timespec *tstamp) +void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstamp) { unsigned long flags; unsigned long resolution = 0; - snd_timer_instance_t *ti, *ts; - struct list_head *p, *n; + struct snd_timer_instance *ti, *ts; - snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return); - snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return); + if (! (timer->hw.flags & SNDRV_TIMER_HW_SLAVE)) + 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) { + if (event == SNDRV_TIMER_EVENT_MSTART || + event == SNDRV_TIMER_EVENT_MCONTINUE || + event == SNDRV_TIMER_EVENT_MRESUME) { if (timer->hw.c_resolution) resolution = timer->hw.c_resolution(timer); else resolution = timer->hw.resolution; } - list_for_each(p, &timer->active_list_head) { - ti = (snd_timer_instance_t *)list_entry(p, snd_timer_instance_t, 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 = (snd_timer_instance_t *)list_entry(n, snd_timer_instance_t, 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); } @@ -903,10 +910,10 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t /* * exported functions for global timers */ -int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer) +int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer) { - snd_timer_id_t tid; - + struct snd_timer_id tid; + tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = -1; @@ -915,53 +922,42 @@ int snd_timer_global_new(char *id, int device, snd_timer_t **rtimer) return snd_timer_new(NULL, id, &tid, rtimer); } -int snd_timer_global_free(snd_timer_t *timer) +int snd_timer_global_free(struct snd_timer *timer) { return snd_timer_free(timer); } -int snd_timer_global_register(snd_timer_t *timer) +int snd_timer_global_register(struct snd_timer *timer) { - snd_device_t dev; + struct snd_device dev; memset(&dev, 0, sizeof(dev)); dev.device_data = timer; return snd_timer_dev_register(&dev); } -int snd_timer_global_unregister(snd_timer_t *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; }; -unsigned int snd_timer_system_resolution(void) -{ - return 1000000000L / HZ; -} - static void snd_timer_s_function(unsigned long data) { - snd_timer_t *timer = (snd_timer_t *)data; + struct snd_timer *timer = (struct snd_timer *)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); } -static int snd_timer_s_start(snd_timer_t * timer) +static int snd_timer_s_start(struct snd_timer * timer) { struct snd_timer_system_private *priv; unsigned long njiff; @@ -973,14 +969,14 @@ static int snd_timer_s_start(snd_timer_t * 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); return 0; } -static int snd_timer_s_stop(snd_timer_t * timer) +static int snd_timer_s_stop(struct snd_timer * timer) { struct snd_timer_system_private *priv; unsigned long jiff; @@ -992,10 +988,11 @@ static int snd_timer_s_stop(snd_timer_t * timer) timer->sticks = priv->last_expires - jiff; else timer->sticks = 1; + priv->correction = 0; return 0; } -static struct _snd_timer_hardware snd_timer_system = +static struct snd_timer_hardware snd_timer_system = { .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_TASKLET, .resolution = 1000000000L / HZ, @@ -1004,22 +1001,23 @@ static struct _snd_timer_hardware snd_timer_system = .stop = snd_timer_s_stop }; -static void snd_timer_free_system(snd_timer_t *timer) +static void snd_timer_free_system(struct snd_timer *timer) { kfree(timer->private_data); } static int snd_timer_register_system(void) { - snd_timer_t *timer; + struct snd_timer *timer; struct snd_timer_system_private *priv; int err; - if ((err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer)) < 0) + err = snd_timer_global_new("system", SNDRV_TIMER_GLOBAL_SYSTEM, &timer); + if (err < 0) return err; strcpy(timer->name, "system timer"); timer->hw = snd_timer_system; - priv = kcalloc(1, sizeof(*priv), GFP_KERNEL); + priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (priv == NULL) { snd_timer_free(timer); return -ENOMEM; @@ -1032,65 +1030,93 @@ static int snd_timer_register_system(void) return snd_timer_global_register(timer); } +#ifdef CONFIG_PROC_FS /* * Info interface */ -static void snd_timer_proc_read(snd_info_entry_t *entry, - snd_info_buffer_t * buffer) +static void snd_timer_proc_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { - unsigned long flags; - snd_timer_t *timer; - snd_timer_instance_t *ti; - struct list_head *p, *q; + struct snd_timer *timer; + struct snd_timer_instance *ti; - down(®ister_mutex); - list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + mutex_lock(®ister_mutex); + 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); break; case SNDRV_TIMER_CLASS_CARD: - snd_iprintf(buffer, "C%i-%i: ", timer->card->number, timer->tmr_device); + snd_iprintf(buffer, "C%i-%i: ", + timer->card->number, timer->tmr_device); break; case SNDRV_TIMER_CLASS_PCM: - snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, timer->tmr_device, timer->tmr_subdevice); + snd_iprintf(buffer, "P%i-%i-%i: ", timer->card->number, + timer->tmr_device, timer->tmr_subdevice); break; default: - snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, timer->card ? timer->card->number : -1, timer->tmr_device, timer->tmr_subdevice); + snd_iprintf(buffer, "?%i-%i-%i-%i: ", timer->tmr_class, + timer->card ? timer->card->number : -1, + timer->tmr_device, timer->tmr_subdevice); } snd_iprintf(buffer, "%s :", timer->name); if (timer->hw.resolution) - snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", timer->hw.resolution / 1000, timer->hw.resolution % 1000, timer->hw.ticks); + snd_iprintf(buffer, " %lu.%03luus (%lu ticks)", + timer->hw.resolution / 1000, + timer->hw.resolution % 1000, + timer->hw.ticks); 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 = (snd_timer_instance_t *)list_entry(q, snd_timer_instance_t, open_list); - snd_iprintf(buffer, " Client %s : %s : lost interrupts %li\n", - ti->owner ? ti->owner : "unknown", - ti->flags & (SNDRV_TIMER_IFLG_START|SNDRV_TIMER_IFLG_RUNNING) ? "running" : "stopped", - ti->lost); + 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"); + } + mutex_unlock(®ister_mutex); +} + +static struct snd_info_entry *snd_timer_proc_entry; + +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; } - spin_unlock_irqrestore(&timer->lock, flags); } - up(®ister_mutex); + snd_timer_proc_entry = entry; } +static void __exit snd_timer_proc_done(void) +{ + snd_info_free_entry(snd_timer_proc_entry); +} +#else /* !CONFIG_PROC_FS */ +#define snd_timer_proc_init() +#define snd_timer_proc_done() +#endif + /* * USER SPACE interface */ -static void snd_timer_user_interrupt(snd_timer_instance_t *timeri, +static void snd_timer_user_interrupt(struct snd_timer_instance *timeri, unsigned long resolution, unsigned long ticks) { - snd_timer_user_t *tu = timeri->callback_data; - snd_timer_read_t *r; + struct snd_timer_user *tu = timeri->callback_data; + struct snd_timer_read *r; int prev; - + spin_lock(&tu->qlock); if (tu->qused > 0) { prev = tu->qtail == 0 ? tu->queue_size - 1 : tu->qtail - 1; @@ -1115,7 +1141,8 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri, wake_up(&tu->qchange_sleep); } -static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_tread_t *tread) +static void snd_timer_user_append_to_tqueue(struct snd_timer_user *tu, + struct snd_timer_tread *tread) { if (tu->qused >= tu->queue_size) { tu->overrun++; @@ -1126,15 +1153,16 @@ static void snd_timer_user_append_to_tqueue(snd_timer_user_t *tu, snd_timer_trea } } -static void snd_timer_user_ccallback(snd_timer_instance_t *timeri, - enum sndrv_timer_event event, +static void snd_timer_user_ccallback(struct snd_timer_instance *timeri, + int event, struct timespec *tstamp, unsigned long resolution) { - snd_timer_user_t *tu = timeri->callback_data; - snd_timer_tread_t r1; + struct snd_timer_user *tu = timeri->callback_data; + struct snd_timer_tread r1; - if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE) + if (event >= SNDRV_TIMER_EVENT_START && + event <= SNDRV_TIMER_EVENT_PAUSE) tu->tstamp = *tstamp; if ((tu->filter & (1 << event)) == 0 || !tu->tread) return; @@ -1148,24 +1176,30 @@ static void snd_timer_user_ccallback(snd_timer_instance_t *timeri, wake_up(&tu->qchange_sleep); } -static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri, +static void snd_timer_user_tinterrupt(struct snd_timer_instance *timeri, unsigned long resolution, unsigned long ticks) { - snd_timer_user_t *tu = timeri->callback_data; - snd_timer_tread_t *r, r1; + struct snd_timer_user *tu = timeri->callback_data; + struct snd_timer_tread *r, r1; struct timespec tstamp; int prev, append = 0; - snd_timestamp_zero(&tstamp); + memset(&tstamp, 0, sizeof(tstamp)); spin_lock(&tu->qlock); - if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION)|(1 << SNDRV_TIMER_EVENT_TICK))) == 0) { + if ((tu->filter & ((1 << SNDRV_TIMER_EVENT_RESOLUTION) | + (1 << SNDRV_TIMER_EVENT_TICK))) == 0) { spin_unlock(&tu->qlock); return; } - if (tu->last_resolution != resolution || ticks > 0) - snd_timestamp_now(&tstamp, 1); - if ((tu->filter & (1 << SNDRV_TIMER_EVENT_RESOLUTION)) && tu->last_resolution != resolution) { + 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; r1.tstamp = tstamp; r1.val = resolution; @@ -1202,17 +1236,18 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri, static int snd_timer_user_open(struct inode *inode, struct file *file) { - snd_timer_user_t *tu; - - tu = kcalloc(1, sizeof(*tu), GFP_KERNEL); + struct snd_timer_user *tu; + + tu = kzalloc(sizeof(*tu), GFP_KERNEL); if (tu == NULL) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); - init_MUTEX(&tu->tread_sem); + mutex_init(&tu->tread_sem); tu->ticks = 1; tu->queue_size = 128; - tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), + GFP_KERNEL); if (tu->queue == NULL) { kfree(tu); return -ENOMEM; @@ -1223,12 +1258,11 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) static int snd_timer_user_release(struct inode *inode, struct file *file) { - snd_timer_user_t *tu; + struct snd_timer_user *tu; 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); @@ -1238,7 +1272,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file) return 0; } -static void snd_timer_user_zero_id(snd_timer_id_t *id) +static void snd_timer_user_zero_id(struct snd_timer_id *id) { id->dev_class = SNDRV_TIMER_CLASS_NONE; id->dev_sclass = SNDRV_TIMER_SCLASS_NONE; @@ -1247,7 +1281,7 @@ static void snd_timer_user_zero_id(snd_timer_id_t *id) id->subdevice = -1; } -static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer) +static void snd_timer_user_copy_id(struct snd_timer_id *id, struct snd_timer *timer) { id->dev_class = timer->tmr_class; id->dev_sclass = SNDRV_TIMER_SCLASS_NONE; @@ -1256,20 +1290,21 @@ static void snd_timer_user_copy_id(snd_timer_id_t *id, snd_timer_t *timer) id->subdevice = timer->tmr_subdevice; } -static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) +static int snd_timer_user_next_device(struct snd_timer_id __user *_tid) { - snd_timer_id_t id; - snd_timer_t *timer; + struct snd_timer_id id; + struct snd_timer *timer; struct list_head *p; - + if (copy_from_user(&id, _tid, sizeof(id))) return -EFAULT; - down(®ister_mutex); + mutex_lock(®ister_mutex); if (id.dev_class < 0) { /* first item */ if (list_empty(&snd_timer_list)) snd_timer_user_zero_id(&id); else { - timer = (snd_timer_t *)list_entry(snd_timer_list.next, snd_timer_t, device_list); + timer = list_entry(snd_timer_list.next, + struct snd_timer, device_list); snd_timer_user_copy_id(&id, timer); } } else { @@ -1277,7 +1312,7 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) case SNDRV_TIMER_CLASS_GLOBAL: id.device = id.device < 0 ? 0 : id.device + 1; list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, struct snd_timer, device_list); if (timer->tmr_class > SNDRV_TIMER_CLASS_GLOBAL) { snd_timer_user_copy_id(&id, timer); break; @@ -1301,12 +1336,16 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) if (id.device < 0) { id.device = 0; } else { - id.subdevice = id.subdevice < 0 ? 0 : id.subdevice + 1; + if (id.subdevice < 0) { + id.subdevice = 0; + } else { + id.subdevice++; + } } } } list_for_each(p, &snd_timer_list) { - timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); + timer = list_entry(p, struct snd_timer, device_list); if (timer->tmr_class > id.dev_class) { snd_timer_user_copy_id(&id, timer); break; @@ -1341,31 +1380,29 @@ static int snd_timer_user_next_device(snd_timer_id_t __user *_tid) snd_timer_user_zero_id(&id); } } - up(®ister_mutex); + mutex_unlock(®ister_mutex); if (copy_to_user(_tid, &id, sizeof(*_tid))) return -EFAULT; return 0; -} +} -static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo) +static int snd_timer_user_ginfo(struct file *file, + struct snd_timer_ginfo __user *_ginfo) { - snd_timer_ginfo_t *ginfo; - snd_timer_id_t tid; - snd_timer_t *t; + struct snd_timer_ginfo *ginfo; + struct snd_timer_id tid; + struct snd_timer *t; 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; - down(®ister_mutex); + mutex_lock(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { ginfo->card = t->card ? t->card->number : -1; @@ -1384,44 +1421,48 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_gi } else { err = -ENODEV; } - up(®ister_mutex); + mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_ginfo, ginfo, sizeof(*ginfo))) err = -EFAULT; kfree(ginfo); return err; } -static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams) +static int snd_timer_user_gparams(struct file *file, + struct snd_timer_gparams __user *_gparams) { - snd_timer_gparams_t gparams; - snd_timer_t *t; + struct snd_timer_gparams gparams; + struct snd_timer *t; int err; if (copy_from_user(&gparams, _gparams, sizeof(gparams))) return -EFAULT; - down(®ister_mutex); + mutex_lock(®ister_mutex); t = snd_timer_find(&gparams.tid); - if (t != NULL) { - if (list_empty(&t->open_list_head)) { - if (t->hw.set_period) - err = t->hw.set_period(t, gparams.period_num, gparams.period_den); - else - err = -ENOSYS; - } else { - err = -EBUSY; - } - } else { + if (!t) { err = -ENODEV; + goto _error; } - up(®ister_mutex); + if (!list_empty(&t->open_list_head)) { + err = -EBUSY; + goto _error; + } + if (!t->hw.set_period) { + err = -ENOSYS; + goto _error; + } + err = t->hw.set_period(t, gparams.period_num, gparams.period_den); +_error: + mutex_unlock(®ister_mutex); return err; } -static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus) +static int snd_timer_user_gstatus(struct file *file, + struct snd_timer_gstatus __user *_gstatus) { - snd_timer_gstatus_t gstatus; - snd_timer_id_t tid; - snd_timer_t *t; + struct snd_timer_gstatus gstatus; + struct snd_timer_id tid; + struct snd_timer *t; int err = 0; if (copy_from_user(&gstatus, _gstatus, sizeof(gstatus))) @@ -1429,7 +1470,7 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user tid = gstatus.tid; memset(&gstatus, 0, sizeof(gstatus)); gstatus.tid = tid; - down(®ister_mutex); + mutex_lock(®ister_mutex); t = snd_timer_find(&tid); if (t != NULL) { if (t->hw.c_resolution) @@ -1437,7 +1478,8 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user else gstatus.resolution = t->hw.resolution; if (t->hw.precise_resolution) { - t->hw.precise_resolution(t, &gstatus.resolution_num, &gstatus.resolution_den); + t->hw.precise_resolution(t, &gstatus.resolution_num, + &gstatus.resolution_den); } else { gstatus.resolution_num = gstatus.resolution; gstatus.resolution_den = 1000000000uL; @@ -1445,21 +1487,22 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user } else { err = -ENODEV; } - up(®ister_mutex); + mutex_unlock(®ister_mutex); if (err >= 0 && copy_to_user(_gstatus, &gstatus, sizeof(gstatus))) err = -EFAULT; return err; } -static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect) +static int snd_timer_user_tselect(struct file *file, + struct snd_timer_select __user *_tselect) { - snd_timer_user_t *tu; - snd_timer_select_t tselect; + struct snd_timer_user *tu; + struct snd_timer_select tselect; char str[32]; int err = 0; - + tu = file->private_data; - down(&tu->tread_sem); + mutex_lock(&tu->tread_sem); if (tu->timeri) { snd_timer_close(tu->timeri); tu->timeri = NULL; @@ -1471,55 +1514,58 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * sprintf(str, "application %i", current->pid); if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE) tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION; - if ((err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid)) < 0) + err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid); + if (err < 0) goto __err; - if (tu->queue) { - kfree(tu->queue); - tu->queue = NULL; - } - if (tu->tqueue) { - kfree(tu->tqueue); - tu->tqueue = NULL; - } + kfree(tu->queue); + tu->queue = NULL; + kfree(tu->tqueue); + tu->tqueue = NULL; if (tu->tread) { - tu->tqueue = (snd_timer_tread_t *)kmalloc(tu->queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); + tu->tqueue = kmalloc(tu->queue_size * sizeof(struct snd_timer_tread), + GFP_KERNEL); if (tu->tqueue == NULL) err = -ENOMEM; } else { - tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tu->queue = kmalloc(tu->queue_size * sizeof(struct snd_timer_read), + GFP_KERNEL); if (tu->queue == NULL) err = -ENOMEM; } - + if (err < 0) { snd_timer_close(tu->timeri); tu->timeri = NULL; } else { tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - tu->timeri->callback = tu->tread ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; + tu->timeri->callback = tu->tread + ? snd_timer_user_tinterrupt : snd_timer_user_interrupt; tu->timeri->ccallback = snd_timer_user_ccallback; tu->timeri->callback_data = (void *)tu; } __err: - up(&tu->tread_sem); + mutex_unlock(&tu->tread_sem); return err; } -static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) +static int snd_timer_user_info(struct file *file, + struct snd_timer_info __user *_info) { - snd_timer_user_t *tu; - snd_timer_info_t *info; - snd_timer_t *t; + struct snd_timer_user *tu; + struct snd_timer_info *info; + struct snd_timer *t; 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 = kcalloc(1, sizeof(*info), GFP_KERNEL); + info = kzalloc(sizeof(*info), GFP_KERNEL); if (! info) return -ENOMEM; info->card = t->card ? t->card->number : -1; @@ -1534,26 +1580,30 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info return err; } -static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params) +static int snd_timer_user_params(struct file *file, + struct snd_timer_params __user *_params) { - snd_timer_user_t *tu; - snd_timer_params_t params; - snd_timer_t *t; - snd_timer_read_t *tr; - snd_timer_tread_t *ttr; + struct snd_timer_user *tu; + struct snd_timer_params params; + struct snd_timer *t; + struct snd_timer_read *tr; + struct snd_timer_tread *ttr; 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) { err = -EINVAL; goto _end; } - if (params.queue_size > 0 && (params.queue_size < 32 || params.queue_size > 1024)) { + if (params.queue_size > 0 && + (params.queue_size < 32 || params.queue_size > 1024)) { err = -EINVAL; goto _end; } @@ -1563,10 +1613,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ (1<timeri->flags |= SNDRV_TIMER_IFLG_EARLY_EVENT; spin_unlock_irq(&t->lock); - if (params.queue_size > 0 && (unsigned int)tu->queue_size != params.queue_size) { + if (params.queue_size > 0 && + (unsigned int)tu->queue_size != params.queue_size) { if (tu->tread) { - ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL); + ttr = kmalloc(params.queue_size * sizeof(*ttr), + GFP_KERNEL); if (ttr) { kfree(tu->tqueue); tu->queue_size = params.queue_size; tu->tqueue = ttr; } } else { - tr = (snd_timer_read_t *)kmalloc(params.queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); + tr = kmalloc(params.queue_size * sizeof(*tr), + GFP_KERNEL); if (tr) { kfree(tu->queue); tu->queue_size = params.queue_size; @@ -1602,20 +1659,19 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ tu->qhead = tu->qtail = tu->qused = 0; if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) { if (tu->tread) { - snd_timer_tread_t tread; + struct snd_timer_tread tread; 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 { - snd_timer_read_t *r = &tu->queue[0]; + struct snd_timer_read *r = &tu->queue[0]; r->resolution = 0; r->ticks = 0; tu->qused++; tu->qtail++; } - } tu->filter = params.filter; tu->ticks = params.ticks; @@ -1626,13 +1682,15 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_ return err; } -static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status) +static int snd_timer_user_status(struct file *file, + struct snd_timer_status __user *_status) { - snd_timer_user_t *tu; - snd_timer_status_t status; - + struct snd_timer_user *tu; + 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); @@ -1649,10 +1707,11 @@ static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_ static int snd_timer_user_start(struct file *file) { int err; - snd_timer_user_t *tu; - + 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; @@ -1662,20 +1721,22 @@ static int snd_timer_user_start(struct file *file) static int snd_timer_user_stop(struct file *file) { int err; - snd_timer_user_t *tu; - + 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; } static int snd_timer_user_continue(struct file *file) { int err; - snd_timer_user_t *tu; - + 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; } @@ -1683,10 +1744,11 @@ static int snd_timer_user_continue(struct file *file) static int snd_timer_user_pause(struct file *file) { int err; - snd_timer_user_t *tu; - + 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; } @@ -1697,12 +1759,13 @@ enum { SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), }; -static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { - snd_timer_user_t *tu; + struct snd_timer_user *tu; void __user *argp = (void __user *)arg; int __user *p = argp; - + tu = file->private_data; switch (cmd) { case SNDRV_TIMER_IOCTL_PVERSION: @@ -1712,18 +1775,18 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l case SNDRV_TIMER_IOCTL_TREAD: { int xarg; - - down(&tu->tread_sem); + + mutex_lock(&tu->tread_sem); if (tu->timeri) { /* too late */ - up(&tu->tread_sem); + mutex_unlock(&tu->tread_sem); return -EBUSY; } if (get_user(xarg, p)) { - up(&tu->tread_sem); + mutex_unlock(&tu->tread_sem); return -EFAULT; } tu->tread = xarg ? 1 : 0; - up(&tu->tread_sem); + mutex_unlock(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -1758,24 +1821,21 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l static int snd_timer_user_fasync(int fd, struct file * file, int on) { - snd_timer_user_t *tu; - int err; - + struct snd_timer_user *tu; + 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, size_t count, loff_t *offset) +static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, + size_t count, loff_t *offset) { - snd_timer_user_t *tu; + struct snd_timer_user *tu; long result = 0, unit; int err = 0; - + tu = file->private_data; - unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t); + unit = tu->tread ? sizeof(struct snd_timer_tread) : sizeof(struct snd_timer_read); spin_lock_irq(&tu->qlock); while ((long)count - result >= unit) { while (!tu->qused) { @@ -1807,12 +1867,14 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_ goto _error; if (tu->tread) { - if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], sizeof(snd_timer_tread_t))) { + if (copy_to_user(buffer, &tu->tqueue[tu->qhead++], + sizeof(struct snd_timer_tread))) { err = -EFAULT; goto _error; } } else { - if (copy_to_user(buffer, &tu->queue[tu->qhead++], sizeof(snd_timer_read_t))) { + if (copy_to_user(buffer, &tu->queue[tu->qhead++], + sizeof(struct snd_timer_read))) { err = -EFAULT; goto _error; } @@ -1834,12 +1896,12 @@ static ssize_t snd_timer_user_read(struct file *file, char __user *buffer, size_ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait) { unsigned int mask; - snd_timer_user_t *tu; + struct snd_timer_user *tu; tu = file->private_data; poll_wait(file, &tu->qchange_sleep, wait); - + mask = 0; if (tu->qused) mask |= POLLIN | POLLRDNORM; @@ -1853,7 +1915,7 @@ 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, @@ -1865,40 +1927,27 @@ static struct file_operations snd_timer_f_ops = .fasync = snd_timer_user_fasync, }; -static snd_minor_t snd_timer_reg = -{ - .comment = "timer", - .f_ops = &snd_timer_f_ops, -}; - /* * ENTRY functions */ -static snd_info_entry_t *snd_timer_proc_entry = NULL; - static int __init alsa_timer_init(void) { int err; - snd_info_entry_t *entry; #ifdef SNDRV_OSS_INFO_DEV_TIMERS - snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, "system timer"); + snd_oss_info_register(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1, + "system timer"); #endif - if ((entry = snd_info_create_module_entry(THIS_MODULE, "timers", NULL)) != 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); - entry = NULL; - } - } - snd_timer_proc_entry = entry; + if ((err = snd_timer_register_system()) < 0) - snd_printk(KERN_ERR "unable to register system timer (%i)\n", err); - if ((err = snd_register_device(SNDRV_DEVICE_TYPE_TIMER, - NULL, 0, &snd_timer_reg, "timer"))<0) - snd_printk(KERN_ERR "unable to register timer device (%i)\n", err); + snd_printk(KERN_ERR "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); + snd_timer_proc_init(); return 0; } @@ -1909,13 +1958,10 @@ static void __exit alsa_timer_exit(void) snd_unregister_device(SNDRV_DEVICE_TYPE_TIMER, NULL, 0); /* unregister the system timer */ list_for_each_safe(p, n, &snd_timer_list) { - snd_timer_t *timer = (snd_timer_t *)list_entry(p, snd_timer_t, device_list); - snd_timer_unregister(timer); - } - if (snd_timer_proc_entry) { - snd_info_unregister(snd_timer_proc_entry); - snd_timer_proc_entry = NULL; + struct snd_timer *timer = list_entry(p, struct snd_timer, device_list); + snd_timer_free(timer); } + snd_timer_proc_done(); #ifdef SNDRV_OSS_INFO_DEV_TIMERS snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_TIMERS, SNDRV_CARDS - 1); #endif @@ -1936,6 +1982,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); -EXPORT_SYMBOL(snd_timer_system_resolution);