aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sound/timer.h4
-rw-r--r--sound/core/seq/seq_timer.c18
-rw-r--r--sound/core/timer.c97
3 files changed, 63 insertions, 56 deletions
diff --git a/include/sound/timer.h b/include/sound/timer.h
index 8a13c09c85f7..a53e37bcd746 100644
--- a/include/sound/timer.h
+++ b/include/sound/timer.h
@@ -118,7 +118,9 @@ int snd_timer_global_new(char *id, int device, struct snd_timer **rtimer);
int snd_timer_global_free(struct snd_timer *timer);
int snd_timer_global_register(struct snd_timer *timer);
-int snd_timer_open(struct snd_timer_instance **ti, char *owner, struct snd_timer_id *tid, unsigned int slave_id);
+struct snd_timer_instance *snd_timer_instance_new(const char *owner);
+void snd_timer_instance_free(struct snd_timer_instance *timeri);
+int snd_timer_open(struct snd_timer_instance *timeri, struct snd_timer_id *tid, unsigned int slave_id);
void snd_timer_close(struct snd_timer_instance *timeri);
unsigned long snd_timer_resolution(struct snd_timer_instance *timeri);
int snd_timer_start(struct snd_timer_instance *timeri, unsigned int ticks);
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c
index 161f3170bd7e..63dc7bdb622d 100644
--- a/sound/core/seq/seq_timer.c
+++ b/sound/core/seq/seq_timer.c
@@ -272,7 +272,13 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
return -EINVAL;
if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tmr->alsa_id.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
- err = snd_timer_open(&t, str, &tmr->alsa_id, q->queue);
+ t = snd_timer_instance_new(str);
+ if (!t)
+ return -ENOMEM;
+ t->callback = snd_seq_timer_interrupt;
+ t->callback_data = q;
+ t->flags |= SNDRV_TIMER_IFLG_AUTO;
+ err = snd_timer_open(t, &tmr->alsa_id, q->queue);
if (err < 0 && tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_SLAVE) {
if (tmr->alsa_id.dev_class != SNDRV_TIMER_CLASS_GLOBAL ||
tmr->alsa_id.device != SNDRV_TIMER_GLOBAL_SYSTEM) {
@@ -282,16 +288,14 @@ int snd_seq_timer_open(struct snd_seq_queue *q)
tid.dev_sclass = SNDRV_TIMER_SCLASS_SEQUENCER;
tid.card = -1;
tid.device = SNDRV_TIMER_GLOBAL_SYSTEM;
- err = snd_timer_open(&t, str, &tid, q->queue);
+ err = snd_timer_open(t, &tid, q->queue);
}
}
if (err < 0) {
pr_err("ALSA: seq fatal error: cannot create timer (%i)\n", err);
+ snd_timer_instance_free(t);
return err;
}
- t->callback = snd_seq_timer_interrupt;
- t->callback_data = q;
- t->flags |= SNDRV_TIMER_IFLG_AUTO;
spin_lock_irq(&tmr->lock);
tmr->timeri = t;
spin_unlock_irq(&tmr->lock);
@@ -310,8 +314,10 @@ int snd_seq_timer_close(struct snd_seq_queue *q)
t = tmr->timeri;
tmr->timeri = NULL;
spin_unlock_irq(&tmr->lock);
- if (t)
+ if (t) {
snd_timer_close(t);
+ snd_timer_instance_free(t);
+ }
return 0;
}
diff --git a/sound/core/timer.c b/sound/core/timer.c
index c0a73913ec62..9091030f4a89 100644
--- a/sound/core/timer.c
+++ b/sound/core/timer.c
@@ -88,12 +88,11 @@ static void snd_timer_reschedule(struct snd_timer * timer, unsigned long ticks_l
/*
* create a timer instance with the given owner string.
- * when timer is not NULL, increments the module counter
*/
-static struct snd_timer_instance *snd_timer_instance_new(char *owner,
- struct snd_timer *timer)
+struct snd_timer_instance *snd_timer_instance_new(const char *owner)
{
struct snd_timer_instance *timeri;
+
timeri = kzalloc(sizeof(*timeri), GFP_KERNEL);
if (timeri == NULL)
return NULL;
@@ -108,15 +107,20 @@ static struct snd_timer_instance *snd_timer_instance_new(char *owner,
INIT_LIST_HEAD(&timeri->slave_list_head);
INIT_LIST_HEAD(&timeri->slave_active_head);
- timeri->timer = timer;
- if (timer && !try_module_get(timer->module)) {
+ return timeri;
+}
+EXPORT_SYMBOL(snd_timer_instance_new);
+
+void snd_timer_instance_free(struct snd_timer_instance *timeri)
+{
+ if (timeri) {
+ if (timeri->private_free)
+ timeri->private_free(timeri);
kfree(timeri->owner);
kfree(timeri);
- return NULL;
}
-
- return timeri;
}
+EXPORT_SYMBOL(snd_timer_instance_free);
/*
* find a timer instance from the given timer id
@@ -236,12 +240,11 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
* open a timer instance
* when opening a master, the slave id must be here given.
*/
-int snd_timer_open(struct snd_timer_instance **ti,
- char *owner, struct snd_timer_id *tid,
+int snd_timer_open(struct snd_timer_instance *timeri,
+ struct snd_timer_id *tid,
unsigned int slave_id)
{
struct snd_timer *timer;
- struct snd_timer_instance *timeri = NULL;
struct device *card_dev_to_put = NULL;
int err;
@@ -259,22 +262,14 @@ int snd_timer_open(struct snd_timer_instance **ti,
err = -EBUSY;
goto unlock;
}
- timeri = snd_timer_instance_new(owner, NULL);
- if (!timeri) {
- err = -ENOMEM;
- goto unlock;
- }
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);
num_slaves++;
err = snd_timer_check_slave(timeri);
- if (err < 0) {
- snd_timer_close_locked(timeri, &card_dev_to_put);
- timeri = NULL;
- }
- goto unlock;
+ if (err < 0)
+ goto close;
}
/* open a master instance */
@@ -304,45 +299,40 @@ int snd_timer_open(struct snd_timer_instance **ti,
err = -EBUSY;
goto unlock;
}
- timeri = snd_timer_instance_new(owner, timer);
- if (!timeri) {
- err = -ENOMEM;
+ if (!try_module_get(timer->module)) {
+ err = -EBUSY;
goto unlock;
}
/* take a card refcount for safe disconnection */
- if (timer->card)
+ if (timer->card) {
get_device(&timer->card->card_dev);
- timeri->slave_class = tid->dev_sclass;
- timeri->slave_id = slave_id;
+ card_dev_to_put = &timer->card->card_dev;
+ }
if (list_empty(&timer->open_list_head) && timer->hw.open) {
err = timer->hw.open(timer);
if (err) {
- kfree(timeri->owner);
- kfree(timeri);
- timeri = NULL;
-
- if (timer->card)
- card_dev_to_put = &timer->card->card_dev;
module_put(timer->module);
goto unlock;
}
}
+ timeri->timer = timer;
+ timeri->slave_class = tid->dev_sclass;
+ timeri->slave_id = slave_id;
+
list_add_tail(&timeri->open_list, &timer->open_list_head);
timer->num_instances++;
err = snd_timer_check_master(timeri);
- if (err < 0) {
+ close:
+ if (err < 0)
snd_timer_close_locked(timeri, &card_dev_to_put);
- timeri = NULL;
- }
unlock:
mutex_unlock(&register_mutex);
/* put_device() is called after unlock for avoiding deadlock */
- if (card_dev_to_put)
+ if (err < 0 && card_dev_to_put)
put_device(card_dev_to_put);
- *ti = timeri;
return err;
}
EXPORT_SYMBOL(snd_timer_open);
@@ -363,9 +353,11 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
spin_unlock_irq(&timer->lock);
}
- list_del(&timeri->open_list);
- if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
- num_slaves--;
+ if (!list_empty(&timeri->open_list)) {
+ list_del_init(&timeri->open_list);
+ if (timeri->flags & SNDRV_TIMER_IFLG_SLAVE)
+ num_slaves--;
+ }
/* force to stop the timer */
snd_timer_stop(timeri);
@@ -384,6 +376,7 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
/* remove slave links */
spin_lock_irq(&slave_active_lock);
spin_lock(&timer->lock);
+ timeri->timer = NULL;
list_for_each_entry_safe(slave, tmp, &timeri->slave_list_head,
open_list) {
list_move_tail(&slave->open_list, &snd_timer_slave_list);
@@ -401,11 +394,6 @@ static void snd_timer_close_locked(struct snd_timer_instance *timeri,
timer = NULL;
}
- if (timeri->private_free)
- timeri->private_free(timeri);
- kfree(timeri->owner);
- kfree(timeri);
-
if (timer) {
if (list_empty(&timer->open_list_head) && timer->hw.close)
timer->hw.close(timer);
@@ -1480,8 +1468,10 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
tu = file->private_data;
file->private_data = NULL;
mutex_lock(&tu->ioctl_lock);
- if (tu->timeri)
+ if (tu->timeri) {
snd_timer_close(tu->timeri);
+ snd_timer_instance_free(tu->timeri);
+ }
mutex_unlock(&tu->ioctl_lock);
kfree(tu->queue);
kfree(tu->tqueue);
@@ -1722,6 +1712,7 @@ static int snd_timer_user_tselect(struct file *file,
tu = file->private_data;
if (tu->timeri) {
snd_timer_close(tu->timeri);
+ snd_timer_instance_free(tu->timeri);
tu->timeri = NULL;
}
if (copy_from_user(&tselect, _tselect, sizeof(tselect))) {
@@ -1731,9 +1722,11 @@ static int snd_timer_user_tselect(struct file *file,
sprintf(str, "application %i", current->pid);
if (tselect.id.dev_class != SNDRV_TIMER_CLASS_SLAVE)
tselect.id.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
- err = snd_timer_open(&tu->timeri, str, &tselect.id, current->pid);
- if (err < 0)
+ tu->timeri = snd_timer_instance_new(str);
+ if (!tu->timeri) {
+ err = -ENOMEM;
goto __err;
+ }
tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST;
tu->timeri->callback = tu->tread
@@ -1742,6 +1735,12 @@ static int snd_timer_user_tselect(struct file *file,
tu->timeri->callback_data = (void *)tu;
tu->timeri->disconnect = snd_timer_user_disconnect;
+ err = snd_timer_open(tu->timeri, &tselect.id, current->pid);
+ if (err < 0) {
+ snd_timer_instance_free(tu->timeri);
+ tu->timeri = NULL;
+ }
+
__err:
return err;
}