diff options
Diffstat (limited to 'sound/core/timer.c')
-rw-r--r-- | sound/core/timer.c | 103 |
1 files changed, 67 insertions, 36 deletions
diff --git a/sound/core/timer.c b/sound/core/timer.c index fa762ca439b..cfaccd415b3 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -26,6 +26,7 @@ #include <linux/slab.h> #include <linux/time.h> #include <linux/moduleparam.h> +#include <linux/string.h> #include <sound/core.h> #include <sound/timer.h> #include <sound/control.h> @@ -69,6 +70,7 @@ typedef struct { struct timespec tstamp; /* trigger tstamp */ wait_queue_head_t qchange_sleep; struct fasync_struct *fasync; + struct semaphore tread_sem; } snd_timer_user_t; /* list of timers */ @@ -99,7 +101,7 @@ static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *ti timeri = kcalloc(1, 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; @@ -844,7 +846,7 @@ int snd_timer_dev_register(snd_device_t *dev) return 0; } -int snd_timer_unregister(snd_timer_t *timer) +static int snd_timer_unregister(snd_timer_t *timer) { struct list_head *p, *n; snd_timer_instance_t *ti; @@ -945,11 +947,6 @@ struct snd_timer_system_private { 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; @@ -1208,6 +1205,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file) return -ENOMEM; spin_lock_init(&tu->qlock); init_waitqueue_head(&tu->qchange_sleep); + init_MUTEX(&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); @@ -1454,46 +1452,51 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user * snd_timer_user_t *tu; snd_timer_select_t tselect; char str[32]; - int err; + int err = 0; tu = file->private_data; - if (tu->timeri) + down(&tu->tread_sem); + if (tu->timeri) { snd_timer_close(tu->timeri); - if (copy_from_user(&tselect, _tselect, sizeof(tselect))) - return -EFAULT; + tu->timeri = NULL; + } + if (copy_from_user(&tselect, _tselect, sizeof(tselect))) { + err = -EFAULT; + goto __err; + } 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) - return err; + 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); - if (tu->tqueue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->tqueue == NULL) + err = -ENOMEM; } else { tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL); - if (tu->queue == NULL) { - snd_timer_close(tu->timeri); - return -ENOMEM; - } + if (tu->queue == NULL) + err = -ENOMEM; } - tu->timeri->flags |= SNDRV_TIMER_IFLG_FAST; - 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; - return 0; + 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->ccallback = snd_timer_user_ccallback; + tu->timeri->callback_data = (void *)tu; + } + + __err: + up(&tu->tread_sem); + return err; } static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info) @@ -1669,6 +1672,23 @@ static int snd_timer_user_continue(struct file *file) return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0; } +static int snd_timer_user_pause(struct file *file) +{ + int err; + snd_timer_user_t *tu; + + tu = file->private_data; + snd_assert(tu->timeri != NULL, return -ENXIO); + return (err = snd_timer_pause(tu->timeri)) < 0 ? err : 0; +} + +enum { + SNDRV_TIMER_IOCTL_START_OLD = _IO('T', 0x20), + SNDRV_TIMER_IOCTL_STOP_OLD = _IO('T', 0x21), + SNDRV_TIMER_IOCTL_CONTINUE_OLD = _IO('T', 0x22), + SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), +}; + static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { snd_timer_user_t *tu; @@ -1685,11 +1705,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l { int xarg; - if (tu->timeri) /* too late */ + down(&tu->tread_sem); + if (tu->timeri) { /* too late */ + up(&tu->tread_sem); return -EBUSY; - if (get_user(xarg, p)) + } + if (get_user(xarg, p)) { + up(&tu->tread_sem); return -EFAULT; + } tu->tread = xarg ? 1 : 0; + up(&tu->tread_sem); return 0; } case SNDRV_TIMER_IOCTL_GINFO: @@ -1707,11 +1733,17 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd, unsigned l case SNDRV_TIMER_IOCTL_STATUS: return snd_timer_user_status(file, argp); case SNDRV_TIMER_IOCTL_START: + case SNDRV_TIMER_IOCTL_START_OLD: return snd_timer_user_start(file); case SNDRV_TIMER_IOCTL_STOP: + case SNDRV_TIMER_IOCTL_STOP_OLD: return snd_timer_user_stop(file); case SNDRV_TIMER_IOCTL_CONTINUE: + case SNDRV_TIMER_IOCTL_CONTINUE_OLD: return snd_timer_user_continue(file); + case SNDRV_TIMER_IOCTL_PAUSE: + case SNDRV_TIMER_IOCTL_PAUSE_OLD: + return snd_timer_user_pause(file); } return -ENOTTY; } @@ -1898,4 +1930,3 @@ 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); |