]> err.no Git - linux-2.6/blobdiff - sound/core/timer.c
Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[linux-2.6] / sound / core / timer.c
index fa762ca439be43573f9bd2bfaac8d361be4fea82..4104f6e292e959ead04756ccd52d18ee52e49326 100644 (file)
@@ -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;
@@ -797,13 +799,13 @@ static int snd_timer_free(snd_timer_t *timer)
        return 0;
 }
 
-int snd_timer_dev_free(snd_device_t *device)
+static int snd_timer_dev_free(snd_device_t *device)
 {
        snd_timer_t *timer = device->device_data;
        return snd_timer_free(timer);
 }
 
-int snd_timer_dev_register(snd_device_t *dev)
+static int snd_timer_dev_register(snd_device_t *dev)
 {
        snd_timer_t *timer = dev->device_data;
        snd_timer_t *timer1;
@@ -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;
@@ -878,9 +880,11 @@ void snd_timer_notify(snd_timer_t *timer, enum sndrv_timer_event event, struct t
        struct list_head *p, *n;
 
        snd_runtime_check(timer->hw.flags & SNDRV_TIMER_HW_SLAVE, return);      
-       snd_assert(event >= SNDRV_TIMER_EVENT_MSTART && event <= SNDRV_TIMER_EVENT_MPAUSE, return);
+       snd_assert(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
@@ -945,11 +949,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 +1207,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 +1454,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)
@@ -1552,10 +1557,14 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_
                              (1<<SNDRV_TIMER_EVENT_STOP)|
                              (1<<SNDRV_TIMER_EVENT_CONTINUE)|
                              (1<<SNDRV_TIMER_EVENT_PAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_SUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_RESUME)|
                              (1<<SNDRV_TIMER_EVENT_MSTART)|
                              (1<<SNDRV_TIMER_EVENT_MSTOP)|
                              (1<<SNDRV_TIMER_EVENT_MCONTINUE)|
-                             (1<<SNDRV_TIMER_EVENT_MPAUSE))) {
+                             (1<<SNDRV_TIMER_EVENT_MPAUSE)|
+                             (1<<SNDRV_TIMER_EVENT_MSUSPEND)|
+                             (1<<SNDRV_TIMER_EVENT_MRESUME))) {
                err = -EINVAL;
                goto _end;
        }
@@ -1669,6 +1678,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 +1711,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 +1739,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 +1936,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);