vserver 1.9.3
[linux-2.6.git] / sound / core / timer.c
index 35c5d05..cee5f47 100644 (file)
 #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/moduleparam.h>
 #include <sound/core.h>
 #include <sound/timer.h>
 #include <sound/control.h>
@@ -45,8 +47,7 @@ static int timer_limit = DEFAULT_TIMER_LIMIT;
 MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>");
 MODULE_DESCRIPTION("ALSA timer interface");
 MODULE_LICENSE("GPL");
-MODULE_CLASSES("{sound}");
-MODULE_PARM(timer_limit, "i");
+module_param(timer_limit, int, 0444);
 MODULE_PARM_DESC(timer_limit, "Maximum global timers in system.");
 
 typedef struct {
@@ -93,7 +94,7 @@ static void snd_timer_reschedule(snd_timer_t * timer, unsigned long ticks_left);
 static snd_timer_instance_t *snd_timer_instance_new(char *owner, snd_timer_t *timer)
 {
        snd_timer_instance_t *timeri;
-       timeri = snd_kcalloc(sizeof(snd_timer_instance_t), GFP_KERNEL);
+       timeri = kcalloc(1, sizeof(*timeri), GFP_KERNEL);
        if (timeri == NULL)
                return NULL;
        timeri->owner = snd_kmalloc_strdup(owner, GFP_KERNEL);
@@ -760,7 +761,7 @@ int snd_timer_new(snd_card_t *card, char *id, snd_timer_id_t *tid, snd_timer_t *
        snd_assert(tid != NULL, return -EINVAL);
        snd_assert(rtimer != NULL, return -EINVAL);
        *rtimer = NULL;
-       timer = snd_magic_kcalloc(snd_timer_t, 0, GFP_KERNEL);
+       timer = kcalloc(1, sizeof(*timer), GFP_KERNEL);
        if (timer == NULL)
                return -ENOMEM;
        timer->tmr_class = tid->dev_class;
@@ -791,19 +792,19 @@ static int snd_timer_free(snd_timer_t *timer)
        snd_assert(timer != NULL, return -ENXIO);
        if (timer->private_free)
                timer->private_free(timer);
-       snd_magic_kfree(timer);
+       kfree(timer);
        return 0;
 }
 
 int snd_timer_dev_free(snd_device_t *device)
 {
-       snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO);
+       snd_timer_t *timer = device->device_data;
        return snd_timer_free(timer);
 }
 
 int snd_timer_dev_register(snd_device_t *dev)
 {
-       snd_timer_t *timer = snd_magic_cast(snd_timer_t, dev->device_data, return -ENXIO);
+       snd_timer_t *timer = dev->device_data;
        snd_timer_t *timer1;
        struct list_head *p;
 
@@ -864,7 +865,7 @@ int snd_timer_unregister(snd_timer_t *timer)
 
 static int snd_timer_dev_unregister(snd_device_t *device)
 {
-       snd_timer_t *timer = snd_magic_cast(snd_timer_t, device->device_data, return -ENXIO);
+       snd_timer_t *timer = device->device_data;
        return snd_timer_unregister(timer);
 }
 
@@ -1017,7 +1018,7 @@ static int snd_timer_register_system(void)
                return err;
        strcpy(timer->name, "system timer");
        timer->hw = snd_timer_system;
-       priv = (struct snd_timer_system_private *) snd_kcalloc(sizeof(struct snd_timer_system_private), GFP_KERNEL);
+       priv = kcalloc(1, sizeof(*priv), GFP_KERNEL);
        if (priv == NULL) {
                snd_timer_free(timer);
                return -ENOMEM;
@@ -1085,7 +1086,7 @@ static void snd_timer_user_interrupt(snd_timer_instance_t *timeri,
                                     unsigned long resolution,
                                     unsigned long ticks)
 {
-       snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+       snd_timer_user_t *tu = timeri->callback_data;
        snd_timer_read_t *r;
        int prev;
        
@@ -1128,7 +1129,7 @@ static void snd_timer_user_ccallback(snd_timer_instance_t *timeri,
                                     struct timespec *tstamp,
                                     unsigned long resolution)
 {
-       snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+       snd_timer_user_t *tu = timeri->callback_data;
        snd_timer_tread_t r1;
 
        if (event >= SNDRV_TIMER_EVENT_START && event <= SNDRV_TIMER_EVENT_PAUSE)
@@ -1147,7 +1148,7 @@ static void snd_timer_user_tinterrupt(snd_timer_instance_t *timeri,
                                      unsigned long resolution,
                                      unsigned long ticks)
 {
-       snd_timer_user_t *tu = snd_magic_cast(snd_timer_user_t, timeri->callback_data, return);
+       snd_timer_user_t *tu = timeri->callback_data;
        snd_timer_tread_t *r, r1;
        struct timespec tstamp;
        int prev, append = 0;
@@ -1199,7 +1200,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
 {
        snd_timer_user_t *tu;
        
-       tu = snd_magic_kcalloc(snd_timer_user_t, 0, GFP_KERNEL);
+       tu = kcalloc(1, sizeof(*tu), GFP_KERNEL);
        if (tu == NULL)
                return -ENOMEM;
        spin_lock_init(&tu->qlock);
@@ -1208,7 +1209,7 @@ static int snd_timer_user_open(struct inode *inode, struct file *file)
        tu->queue_size = 128;
        tu->queue = (snd_timer_read_t *)kmalloc(tu->queue_size * sizeof(snd_timer_read_t), GFP_KERNEL);
        if (tu->queue == NULL) {
-               snd_magic_kfree(tu);
+               kfree(tu);
                return -ENOMEM;
        }
        file->private_data = tu;
@@ -1220,7 +1221,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
        snd_timer_user_t *tu;
 
        if (file->private_data) {
-               tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+               tu = file->private_data;
                file->private_data = NULL;
                fasync_helper(-1, file, 0, &tu->fasync);
                if (tu->timeri)
@@ -1229,7 +1230,7 @@ static int snd_timer_user_release(struct inode *inode, struct file *file)
                        kfree(tu->queue);
                if (tu->tqueue)
                        kfree(tu->tqueue);
-               snd_magic_kfree(tu);
+               kfree(tu);
        }
        return 0;
 }
@@ -1252,7 +1253,7 @@ 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 *_tid)
+static int snd_timer_user_next_device(snd_timer_id_t __user *_tid)
 {
        snd_timer_id_t id;
        snd_timer_t *timer;
@@ -1343,7 +1344,7 @@ static int snd_timer_user_next_device(snd_timer_id_t *_tid)
        return 0;
 } 
 
-static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo)
+static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t __user *_ginfo)
 {
        snd_timer_ginfo_t ginfo;
        snd_timer_id_t tid;
@@ -1381,7 +1382,7 @@ static int snd_timer_user_ginfo(struct file *file, snd_timer_ginfo_t *_ginfo)
        return err;
 }
 
-static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gparams)
+static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t __user *_gparams)
 {
        snd_timer_gparams_t gparams;
        snd_timer_t *t;
@@ -1407,7 +1408,7 @@ static int snd_timer_user_gparams(struct file *file, snd_timer_gparams_t *_gpara
        return err;
 }
 
-static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstatus)
+static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t __user *_gstatus)
 {
        snd_timer_gstatus_t gstatus;
        snd_timer_id_t tid;
@@ -1436,19 +1437,19 @@ static int snd_timer_user_gstatus(struct file *file, snd_timer_gstatus_t *_gstat
                err = -ENODEV;
        }
        up(&register_mutex);
-       if (err >= 0 && copy_from_user(_gstatus, &gstatus, sizeof(gstatus)))
+       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 *_tselect)
+static int snd_timer_user_tselect(struct file *file, snd_timer_select_t __user *_tselect)
 {
        snd_timer_user_t *tu;
        snd_timer_select_t tselect;
        char str[32];
        int err;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        if (tu->timeri)
                snd_timer_close(tu->timeri);
        if (copy_from_user(&tselect, _tselect, sizeof(tselect)))
@@ -1488,13 +1489,13 @@ static int snd_timer_user_tselect(struct file *file, snd_timer_select_t *_tselec
        return 0;
 }
 
-static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info)
+static int snd_timer_user_info(struct file *file, snd_timer_info_t __user *_info)
 {
        snd_timer_user_t *tu;
        snd_timer_info_t info;
        snd_timer_t *t;
 
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        t = tu->timeri->timer;
        snd_assert(t != NULL, return -ENXIO);
@@ -1510,9 +1511,8 @@ static int snd_timer_user_info(struct file *file, snd_timer_info_t *_info)
        return 0;
 }
 
-static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
+static int snd_timer_user_params(struct file *file, snd_timer_params_t __user *_params)
 {
-       unsigned long flags;
        snd_timer_user_t *tu;
        snd_timer_params_t params;
        snd_timer_t *t;
@@ -1520,7 +1520,7 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
        snd_timer_tread_t *ttr;
        int err;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        t = tu->timeri->timer;
        snd_assert(t != NULL, return -ENXIO);
@@ -1548,18 +1548,17 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
                goto _end;
        }
        snd_timer_stop(tu->timeri);
-       spin_lock_irqsave(&t->lock, flags);
-       if (params.flags & SNDRV_TIMER_PSFLG_AUTO) {
+       spin_lock_irq(&t->lock);
+       tu->timeri->flags &= ~(SNDRV_TIMER_IFLG_AUTO|
+                              SNDRV_TIMER_IFLG_EXCLUSIVE|
+                              SNDRV_TIMER_IFLG_EARLY_EVENT);
+       if (params.flags & SNDRV_TIMER_PSFLG_AUTO)
                tu->timeri->flags |= SNDRV_TIMER_IFLG_AUTO;
-       } else {
-               tu->timeri->flags &= ~SNDRV_TIMER_IFLG_AUTO;
-       }
-       if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE) {
+       if (params.flags & SNDRV_TIMER_PSFLG_EXCLUSIVE)
                tu->timeri->flags |= SNDRV_TIMER_IFLG_EXCLUSIVE;
-       } else {
-               tu->timeri->flags &= ~SNDRV_TIMER_IFLG_EXCLUSIVE;
-       }
-       spin_unlock_irqrestore(&t->lock, flags);
+       if (params.flags & SNDRV_TIMER_PSFLG_EARLY_EVENT)
+               tu->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 (tu->tread) {
                        ttr = (snd_timer_tread_t *)kmalloc(params.queue_size * sizeof(snd_timer_tread_t), GFP_KERNEL);
@@ -1577,6 +1576,24 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
                        }
                }
        }
+       tu->qhead = tu->qtail = tu->qused = 0;
+       if (tu->timeri->flags & SNDRV_TIMER_IFLG_EARLY_EVENT) {
+               if (tu->tread) {
+                       snd_timer_tread_t 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];
+                       r->resolution = 0;
+                       r->ticks = 0;
+                       tu->qused++;
+                       tu->qtail++;
+               }
+               
+       }
        tu->filter = params.filter;
        tu->ticks = params.ticks;
        err = 0;
@@ -1586,22 +1603,21 @@ static int snd_timer_user_params(struct file *file, snd_timer_params_t *_params)
        return err;
 }
 
-static int snd_timer_user_status(struct file *file, snd_timer_status_t *_status)
+static int snd_timer_user_status(struct file *file, snd_timer_status_t __user *_status)
 {
-       unsigned long flags;
        snd_timer_user_t *tu;
        snd_timer_status_t status;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        memset(&status, 0, sizeof(status));
        status.tstamp = tu->tstamp;
        status.resolution = snd_timer_resolution(tu->timeri);
        status.lost = tu->timeri->lost;
        status.overrun = tu->overrun;
-       spin_lock_irqsave(&tu->qlock, flags);
+       spin_lock_irq(&tu->qlock);
        status.queue = tu->qused;
-       spin_unlock_irqrestore(&tu->qlock, flags);
+       spin_unlock_irq(&tu->qlock);
        if (copy_to_user(_status, &status, sizeof(status)))
                return -EFAULT;
        return 0;
@@ -1612,7 +1628,7 @@ static int snd_timer_user_start(struct file *file)
        int err;
        snd_timer_user_t *tu;
                
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        snd_timer_stop(tu->timeri);
        tu->timeri->lost = 0;
@@ -1625,7 +1641,7 @@ static int snd_timer_user_stop(struct file *file)
        int err;
        snd_timer_user_t *tu;
                
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        return (err = snd_timer_stop(tu->timeri)) < 0 ? err : 0;
 }
@@ -1635,48 +1651,50 @@ static int snd_timer_user_continue(struct file *file)
        int err;
        snd_timer_user_t *tu;
                
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        snd_assert(tu->timeri != NULL, return -ENXIO);
        tu->timeri->lost = 0;
        return (err = snd_timer_continue(tu->timeri)) < 0 ? err : 0;
 }
 
-static insnd_timer_user_ioctl(struct inode *inode, struct file *file,
-                               unsigned int cmd, unsigned long arg)
+static inline int _snd_timer_user_ioctl(struct inode *inode, struct file *file,
+                                       unsigned int cmd, unsigned long arg)
 {
        snd_timer_user_t *tu;
+       void __user *argp = (void __user *)arg;
+       int __user *p = argp;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        switch (cmd) {
        case SNDRV_TIMER_IOCTL_PVERSION:
-               return put_user(SNDRV_TIMER_VERSION, (int *)arg) ? -EFAULT : 0;
+               return put_user(SNDRV_TIMER_VERSION, p) ? -EFAULT : 0;
        case SNDRV_TIMER_IOCTL_NEXT_DEVICE:
-               return snd_timer_user_next_device((snd_timer_id_t *)arg);
+               return snd_timer_user_next_device(argp);
        case SNDRV_TIMER_IOCTL_TREAD:
        {
                int xarg;
                
                if (tu->timeri)         /* too late */
                        return -EBUSY;
-               if (get_user(xarg, (int *) arg))
+               if (get_user(xarg, p))
                        return -EFAULT;
                tu->tread = xarg ? 1 : 0;
                return 0;
        }
        case SNDRV_TIMER_IOCTL_GINFO:
-               return snd_timer_user_ginfo(file, (snd_timer_ginfo_t *)arg);
+               return snd_timer_user_ginfo(file, argp);
        case SNDRV_TIMER_IOCTL_GPARAMS:
-               return snd_timer_user_gparams(file, (snd_timer_gparams_t *)arg);
+               return snd_timer_user_gparams(file, argp);
        case SNDRV_TIMER_IOCTL_GSTATUS:
-               return snd_timer_user_gstatus(file, (snd_timer_gstatus_t *)arg);
+               return snd_timer_user_gstatus(file, argp);
        case SNDRV_TIMER_IOCTL_SELECT:
-               return snd_timer_user_tselect(file, (snd_timer_select_t *)arg);
+               return snd_timer_user_tselect(file, argp);
        case SNDRV_TIMER_IOCTL_INFO:
-               return snd_timer_user_info(file, (snd_timer_info_t *)arg);
+               return snd_timer_user_info(file, argp);
        case SNDRV_TIMER_IOCTL_PARAMS:
-               return snd_timer_user_params(file, (snd_timer_params_t *)arg);
+               return snd_timer_user_params(file, argp);
        case SNDRV_TIMER_IOCTL_STATUS:
-               return snd_timer_user_status(file, (snd_timer_status_t *)arg);
+               return snd_timer_user_status(file, argp);
        case SNDRV_TIMER_IOCTL_START:
                return snd_timer_user_start(file);
        case SNDRV_TIMER_IOCTL_STOP:
@@ -1687,25 +1705,36 @@ static int snd_timer_user_ioctl(struct inode *inode, struct file *file,
        return -ENOTTY;
 }
 
+/* FIXME: need to unlock BKL to allow preemption */
+static int snd_timer_user_ioctl(struct inode *inode, struct file * file,
+                               unsigned int cmd, unsigned long arg)
+{
+       int err;
+       unlock_kernel();
+       err = _snd_timer_user_ioctl(inode, file, cmd, arg);
+       lock_kernel();
+       return err;
+}
+
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 {
        snd_timer_user_t *tu;
        int err;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        err = fasync_helper(fd, file, on, &tu->fasync);
         if (err < 0)
                return err;
        return 0;
 }
 
-static ssize_t snd_timer_user_read(struct file *file, char *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;
        long result = 0, unit;
        int err = 0;
        
-       tu = snd_magic_cast(snd_timer_user_t, file->private_data, return -ENXIO);
+       tu = file->private_data;
        unit = tu->tread ? sizeof(snd_timer_tread_t) : sizeof(snd_timer_read_t);
        spin_lock_irq(&tu->qlock);
        while ((long)count - result >= unit) {
@@ -1767,7 +1796,7 @@ static unsigned int snd_timer_user_poll(struct file *file, poll_table * wait)
         unsigned int mask;
         snd_timer_user_t *tu;
 
-        tu = snd_magic_cast(snd_timer_user_t, file->private_data, return 0);
+        tu = file->private_data;
 
         poll_wait(file, &tu->qchange_sleep, wait);
        
@@ -1848,18 +1877,6 @@ static void __exit alsa_timer_exit(void)
 module_init(alsa_timer_init)
 module_exit(alsa_timer_exit)
 
-#ifndef MODULE
-/* format is: snd-timer=timer_limit */
-
-static int __init alsa_timer_setup(char *str)
-{
-       (void)(get_option(&str,&timer_limit) == 2);
-       return 1;
-}
-
-__setup("snd-timer=", alsa_timer_setup);
-#endif /* ifndef MODULE */
-
 EXPORT_SYMBOL(snd_timer_open);
 EXPORT_SYMBOL(snd_timer_close);
 EXPORT_SYMBOL(snd_timer_resolution);