vserver 1.9.3
[linux-2.6.git] / sound / core / control.c
index 7d2bdb7..9b000f7 100644 (file)
@@ -22,6 +22,7 @@
 #include <sound/driver.h>
 #include <linux/threads.h>
 #include <linux/interrupt.h>
+#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/time.h>
@@ -62,7 +63,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
                err = -EFAULT;
                goto __error2;
        }
-       ctl = snd_magic_kcalloc(snd_ctl_file_t, 0, GFP_KERNEL);
+       ctl = kcalloc(1, sizeof(*ctl), GFP_KERNEL);
        if (ctl == NULL) {
                err = -ENOMEM;
                goto __error;
@@ -108,7 +109,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
        snd_kcontrol_t *control;
        unsigned int idx;
 
-       ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+       ctl = file->private_data;
        fasync_helper(-1, file, 0, &ctl->fasync);
        file->private_data = NULL;
        card = ctl->card;
@@ -124,7 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
        }
        up_write(&card->controls_rwsem);
        snd_ctl_empty_read_queue(ctl);
-       snd_magic_kfree(ctl);
+       kfree(ctl);
        module_put(card->module);
        snd_card_file_remove(card, file);
        return 0;
@@ -155,7 +156,7 @@ void snd_ctl_notify(snd_card_t *card, unsigned int mask, snd_ctl_elem_id_t *id)
                                goto _found;
                        }
                }
-               ev = snd_kcalloc(sizeof(*ev), GFP_ATOMIC);
+               ev = kcalloc(1, sizeof(*ev), GFP_ATOMIC);
                if (ev) {
                        ev->id = *id;
                        ev->mask = mask;
@@ -188,9 +189,7 @@ snd_kcontrol_t *snd_ctl_new(snd_kcontrol_t * control, unsigned int access)
        
        snd_runtime_check(control != NULL, return NULL);
        snd_runtime_check(control->count > 0, return NULL);
-       kctl = (snd_kcontrol_t *)snd_magic_kcalloc(snd_kcontrol_t,
-                                                  sizeof(snd_kcontrol_volatile_t) * control->count,
-                                                  GFP_KERNEL);
+       kctl = kcalloc(1, sizeof(*kctl) + sizeof(snd_kcontrol_volatile_t) * control->count, GFP_KERNEL);
        if (kctl == NULL)
                return NULL;
        *kctl = *control;
@@ -249,7 +248,7 @@ void snd_ctl_free_one(snd_kcontrol_t * kcontrol)
        if (kcontrol) {
                if (kcontrol->private_free)
                        kcontrol->private_free(kcontrol);
-               snd_magic_kfree(kcontrol);
+               kfree(kcontrol);
        }
 }
 
@@ -512,7 +511,7 @@ snd_kcontrol_t *snd_ctl_find_id(snd_card_t * card, snd_ctl_elem_id_t *id)
 }
 
 static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
-                            unsigned int cmd, unsigned long arg)
+                            unsigned int cmd, void __user *arg)
 {
        snd_ctl_card_info_t info;
 
@@ -526,12 +525,12 @@ static int snd_ctl_card_info(snd_card_t * card, snd_ctl_file_t * ctl,
        strlcpy(info.mixername, card->mixername, sizeof(info.mixername));
        strlcpy(info.components, card->components, sizeof(info.components));
        up_read(&snd_ioctl_rwsem);
-       if (copy_to_user((void *) arg, &info, sizeof(snd_ctl_card_info_t)))
+       if (copy_to_user(arg, &info, sizeof(snd_ctl_card_info_t)))
                return -EFAULT;
        return 0;
 }
 
-static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t *_list)
+static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t __user *_list)
 {
        struct list_head *plist;
        snd_ctl_elem_list_t list;
@@ -593,7 +592,7 @@ static int snd_ctl_elem_list(snd_card_t *card, snd_ctl_elem_list_t *_list)
        return 0;
 }
 
-static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *_info)
+static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t __user *_info)
 {
        snd_card_t *card = ctl->card;
        snd_ctl_elem_info_t info;
@@ -636,7 +635,7 @@ static int snd_ctl_elem_info(snd_ctl_file_t *ctl, snd_ctl_elem_info_t *_info)
        return result;
 }
 
-static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control)
+static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t __user *_control)
 {
        snd_ctl_elem_value_t *control;
        snd_kcontrol_t *kctl;
@@ -676,7 +675,7 @@ static int snd_ctl_elem_read(snd_card_t *card, snd_ctl_elem_value_t *_control)
        return result;
 }
 
-static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *_control)
+static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t __user *_control)
 {
        snd_card_t *card = file->card;
        snd_ctl_elem_value_t *control;
@@ -726,7 +725,7 @@ static int snd_ctl_elem_write(snd_ctl_file_t *file, snd_ctl_elem_value_t *_contr
        return result;
 }
 
-static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
 {
        snd_card_t *card = file->card;
        snd_ctl_elem_id_t id;
@@ -754,7 +753,7 @@ static int snd_ctl_elem_lock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
        return result;
 }
 
-static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_unlock(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
 {
        snd_card_t *card = file->card;
        snd_ctl_elem_id_t id;
@@ -840,7 +839,7 @@ static void snd_ctl_elem_user_free(snd_kcontrol_t * kcontrol)
        kfree(kcontrol->private_data);
 }
 
-static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, int replace)
+static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t __user *_info, int replace)
 {
        snd_card_t *card = file->card;
        snd_ctl_elem_info_t info;
@@ -927,7 +926,7 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, in
        if (!(info.access & SNDRV_CTL_ELEM_ACCESS_DINDIRECT))
                for (idx = 0; idx < 4 && info.dimen.d[idx]; idx++)
                        dimen_size += sizeof(unsigned short);
-       ue = snd_kcalloc(sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL);
+       ue = kcalloc(1, sizeof(struct user_element) + dimen_size + private_size + extra_size, GFP_KERNEL);
        if (ue == NULL)
                return -ENOMEM;
        ue->type = info.type;
@@ -965,7 +964,7 @@ static int snd_ctl_elem_add(snd_ctl_file_t *file, snd_ctl_elem_info_t *_info, in
        return 0;
 }
 
-static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
+static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t __user *_id)
 {
        snd_ctl_elem_id_t id;
 
@@ -974,7 +973,7 @@ static int snd_ctl_elem_remove(snd_ctl_file_t *file, snd_ctl_elem_id_t *_id)
        return snd_ctl_remove_unlocked_id(file, &id);
 }
 
-static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr)
+static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int __user *ptr)
 {
        int subscribe;
        if (get_user(subscribe, ptr))
@@ -995,52 +994,81 @@ static int snd_ctl_subscribe_events(snd_ctl_file_t *file, int *ptr)
        return 0;
 }
 
-static int snd_ctl_ioctl(struct inode *inode, struct file *file,
-                        unsigned int cmd, unsigned long arg)
+#ifdef CONFIG_PM
+/*
+ * change the power state
+ */
+static int snd_ctl_set_power_state(snd_card_t *card, unsigned int power_state)
+{
+       switch (power_state) {
+       case SNDRV_CTL_POWER_D0:
+       case SNDRV_CTL_POWER_D1:
+       case SNDRV_CTL_POWER_D2:
+               if (card->power_state != power_state)
+                       /* FIXME: pass the correct state value */
+                       card->pm_resume(card, 0);
+               break;
+       case SNDRV_CTL_POWER_D3hot:
+       case SNDRV_CTL_POWER_D3cold:
+               if (card->power_state != power_state)
+                       /* FIXME: pass the correct state value */
+                       card->pm_suspend(card, 0);
+               break;
+       default:
+               return -EINVAL;
+       }
+       return 0;
+}
+#endif
+
+static inline int _snd_ctl_ioctl(struct inode *inode, struct file *file,
+                                unsigned int cmd, unsigned long arg)
 {
        snd_ctl_file_t *ctl;
        snd_card_t *card;
        struct list_head *list;
        snd_kctl_ioctl_t *p;
+       void __user *argp = (void __user *)arg;
+       int __user *ip = argp;
        int err;
 
-       ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+       ctl = file->private_data;
        card = ctl->card;
        snd_assert(card != NULL, return -ENXIO);
        switch (cmd) {
        case SNDRV_CTL_IOCTL_PVERSION:
-               return put_user(SNDRV_CTL_VERSION, (int *)arg) ? -EFAULT : 0;
+               return put_user(SNDRV_CTL_VERSION, ip) ? -EFAULT : 0;
        case SNDRV_CTL_IOCTL_CARD_INFO:
-               return snd_ctl_card_info(card, ctl, cmd, arg);
+               return snd_ctl_card_info(card, ctl, cmd, argp);
        case SNDRV_CTL_IOCTL_ELEM_LIST:
-               return snd_ctl_elem_list(ctl->card, (snd_ctl_elem_list_t *) arg);
+               return snd_ctl_elem_list(ctl->card, argp);
        case SNDRV_CTL_IOCTL_ELEM_INFO:
-               return snd_ctl_elem_info(ctl, (snd_ctl_elem_info_t *) arg);
+               return snd_ctl_elem_info(ctl, argp);
        case SNDRV_CTL_IOCTL_ELEM_READ:
-               return snd_ctl_elem_read(ctl->card, (snd_ctl_elem_value_t *) arg);
+               return snd_ctl_elem_read(ctl->card, argp);
        case SNDRV_CTL_IOCTL_ELEM_WRITE:
-               return snd_ctl_elem_write(ctl, (snd_ctl_elem_value_t *) arg);
+               return snd_ctl_elem_write(ctl, argp);
        case SNDRV_CTL_IOCTL_ELEM_LOCK:
-               return snd_ctl_elem_lock(ctl, (snd_ctl_elem_id_t *) arg);
+               return snd_ctl_elem_lock(ctl, argp);
        case SNDRV_CTL_IOCTL_ELEM_UNLOCK:
-               return snd_ctl_elem_unlock(ctl, (snd_ctl_elem_id_t *) arg);
+               return snd_ctl_elem_unlock(ctl, argp);
        case SNDRV_CTL_IOCTL_ELEM_ADD:
-               return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 0);
+               return snd_ctl_elem_add(ctl, argp, 0);
        case SNDRV_CTL_IOCTL_ELEM_REPLACE:
-               return snd_ctl_elem_add(ctl, (snd_ctl_elem_info_t *) arg, 1);
+               return snd_ctl_elem_add(ctl, argp, 1);
        case SNDRV_CTL_IOCTL_ELEM_REMOVE:
-               return snd_ctl_elem_remove(ctl, (snd_ctl_elem_id_t *) arg);
+               return snd_ctl_elem_remove(ctl, argp);
        case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
-               return snd_ctl_subscribe_events(ctl, (int *) arg);
+               return snd_ctl_subscribe_events(ctl, ip);
        case SNDRV_CTL_IOCTL_POWER:
-               if (get_user(err, (int *)arg))
+               if (get_user(err, ip))
                        return -EFAULT;
                if (!capable(CAP_SYS_ADMIN))
                        return -EPERM;
 #ifdef CONFIG_PM
-               if (card->set_power_state) {
+               if (card->pm_suspend && card->pm_resume) {
                        snd_power_lock(card);
-                       err = card->set_power_state(card, err);
+                       err = snd_ctl_set_power_state(card, err);
                        snd_power_unlock(card);
                } else
 #endif
@@ -1048,9 +1076,9 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file,
                return err;
        case SNDRV_CTL_IOCTL_POWER_STATE:
 #ifdef CONFIG_PM
-               return put_user(card->power_state, (int *)arg) ? -EFAULT : 0;
+               return put_user(card->power_state, ip) ? -EFAULT : 0;
 #else
-               return put_user(SNDRV_CTL_POWER_D0, (int *)arg) ? -EFAULT : 0;
+               return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
 #endif
        }
        down_read(&snd_ioctl_rwsem);
@@ -1067,13 +1095,24 @@ static int snd_ctl_ioctl(struct inode *inode, struct file *file,
        return -ENOTTY;
 }
 
-static ssize_t snd_ctl_read(struct file *file, char *buffer, size_t count, loff_t * offset)
+/* FIXME: need to unlock BKL to allow preemption */
+static int snd_ctl_ioctl(struct inode *inode, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       int err;
+       unlock_kernel();
+       err = _snd_ctl_ioctl(inode, file, cmd, arg);
+       lock_kernel();
+       return err;
+}
+
+static ssize_t snd_ctl_read(struct file *file, char __user *buffer, size_t count, loff_t * offset)
 {
        snd_ctl_file_t *ctl;
        int err = 0;
        ssize_t result = 0;
 
-       ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+       ctl = file->private_data;
        snd_assert(ctl != NULL && ctl->card != NULL, return -ENXIO);
        if (!ctl->subscribed)
                return -EBADFD;
@@ -1087,7 +1126,7 @@ static ssize_t snd_ctl_read(struct file *file, char *buffer, size_t count, loff_
                        wait_queue_t wait;
                        if ((file->f_flags & O_NONBLOCK) != 0 || result > 0) {
                                err = -EAGAIN;
-                               goto __end;
+                               goto __end_lock;
                        }
                        init_waitqueue_entry(&wait, current);
                        add_wait_queue(&ctl->change_sleep, &wait);
@@ -1115,8 +1154,9 @@ static ssize_t snd_ctl_read(struct file *file, char *buffer, size_t count, loff_
                count -= sizeof(snd_ctl_event_t);
                result += sizeof(snd_ctl_event_t);
        }
-      __end:
+      __end_lock:
        spin_unlock_irq(&ctl->read_lock);
+      __end:
        return result > 0 ? result : err;
 }
 
@@ -1125,7 +1165,7 @@ static unsigned int snd_ctl_poll(struct file *file, poll_table * wait)
        unsigned int mask;
        snd_ctl_file_t *ctl;
 
-       ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return 0);
+       ctl = file->private_data;
        if (!ctl->subscribed)
                return 0;
        poll_wait(file, &ctl->change_sleep, wait);
@@ -1145,8 +1185,7 @@ int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
 {
        snd_kctl_ioctl_t *pn;
 
-       pn = (snd_kctl_ioctl_t *)
-               snd_kcalloc(sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
+       pn = kcalloc(1, sizeof(snd_kctl_ioctl_t), GFP_KERNEL);
        if (pn == NULL)
                return -ENOMEM;
        pn->fioctl = fcn;
@@ -1184,7 +1223,7 @@ static int snd_ctl_fasync(int fd, struct file * file, int on)
 {
        snd_ctl_file_t *ctl;
        int err;
-       ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
+       ctl = file->private_data;
        err = fasync_helper(fd, file, on, &ctl->fasync);
        if (err < 0)
                return err;