vserver 1.9.3
[linux-2.6.git] / sound / core / rawmidi.c
index 81be9e5..1c753cd 100644 (file)
 #include <sound/core.h>
 #include <linux/major.h>
 #include <linux/init.h>
+#include <linux/smp_lock.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/wait.h>
+#include <linux/moduleparam.h>
 #include <sound/rawmidi.h>
 #include <sound/info.h>
 #include <sound/control.h>
@@ -40,12 +42,11 @@ MODULE_LICENSE("GPL");
 #ifdef CONFIG_SND_OSSEMUL
 static int midi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 0};
 static int amidi_map[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = 1};
-MODULE_PARM(midi_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+static int boot_devs;
+module_param_array(midi_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(midi_map, "Raw MIDI device number assigned to 1st OSS device.");
-MODULE_PARM_SYNTAX(midi_map, "default:0,skill:advanced");
-MODULE_PARM(amidi_map, "1-" __MODULE_STRING(SNDRV_CARDS) "i");
+module_param_array(amidi_map, int, boot_devs, 0444);
 MODULE_PARM_DESC(amidi_map, "Raw MIDI device number assigned to 2nd OSS device.");
-MODULE_PARM_SYNTAX(amidi_map, "default:1,skill:advanced");
 #endif /* CONFIG_SND_OSSEMUL */
 
 static int snd_rawmidi_free(snd_rawmidi_t *rawmidi);
@@ -267,7 +268,7 @@ int snd_rawmidi_kernel_open(int cardnum, int device, int subdevice,
                list2 = list2->next;
        }
        if (mode & SNDRV_RAWMIDI_LFLG_INPUT) {
-               input = snd_kcalloc(sizeof(snd_rawmidi_runtime_t), GFP_KERNEL);
+               input = kcalloc(1, sizeof(*input), GFP_KERNEL);
                if (input == NULL) {
                        err = -ENOMEM;
                        goto __error;
@@ -289,7 +290,7 @@ int snd_rawmidi_kernel_open(int cardnum, int device, int subdevice,
        if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) {
                if (soutput->opened)
                        goto __skip_output;
-               output = snd_kcalloc(sizeof(snd_rawmidi_runtime_t), GFP_KERNEL);
+               output = kcalloc(1, sizeof(*output), GFP_KERNEL);
                if (output == NULL) {
                        err = -ENOMEM;
                        goto __error;
@@ -396,7 +397,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
        if ((file->f_flags & O_APPEND) || maj != CONFIG_SND_MAJOR) /* OSS emul? */
                fflags |= SNDRV_RAWMIDI_LFLG_APPEND;
        fflags |= SNDRV_RAWMIDI_LFLG_NOOPENLOCK;
-       rawmidi_file = snd_magic_kmalloc(snd_rawmidi_file_t, 0, GFP_KERNEL);
+       rawmidi_file = kmalloc(sizeof(*rawmidi_file), GFP_KERNEL);
        if (rawmidi_file == NULL) {
                snd_card_file_remove(card, file);
                return -ENOMEM;
@@ -445,7 +446,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file)
                file->private_data = rawmidi_file;
        } else {
                snd_card_file_remove(card, file);
-               snd_magic_kfree(rawmidi_file);
+               kfree(rawmidi_file);
        }
        up(&rmidi->open_mutex);
        return err;
@@ -510,11 +511,11 @@ static int snd_rawmidi_release(struct inode *inode, struct file *file)
        snd_rawmidi_t *rmidi;
        int err;
 
-       rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
+       rfile = file->private_data;
        err = snd_rawmidi_kernel_release(rfile);
        rmidi = rfile->rmidi;
        wake_up(&rmidi->open_wait);
-       snd_magic_kfree(rfile);
+       kfree(rfile);
        snd_card_file_remove(rmidi->card, file);
        return err;
 }
@@ -541,7 +542,7 @@ int snd_rawmidi_info(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t *inf
        return 0;
 }
 
-static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t * _info)
+static int snd_rawmidi_info_user(snd_rawmidi_substream_t *substream, snd_rawmidi_info_t __user * _info)
 {
        snd_rawmidi_info_t info;
        int err;
@@ -577,7 +578,7 @@ int snd_rawmidi_info_select(snd_card_t *card, snd_rawmidi_info_t *info)
 }
 
 static int snd_rawmidi_info_select_user(snd_card_t *card,
-                                       snd_rawmidi_info_t *_info)
+                                       snd_rawmidi_info_t __user *_info)
 {
        int err;
        snd_rawmidi_info_t info;
@@ -673,21 +674,22 @@ static int snd_rawmidi_input_status(snd_rawmidi_substream_t * substream,
        return 0;
 }
 
-static insnd_rawmidi_ioctl(struct inode *inode, struct file *file,
-                            unsigned int cmd, unsigned long arg)
+static inline int _snd_rawmidi_ioctl(struct inode *inode, struct file *file,
+                                    unsigned int cmd, unsigned long arg)
 {
        snd_rawmidi_file_t *rfile;
+       void __user *argp = (void __user *)arg;
 
-       rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
+       rfile = file->private_data;
        if (((cmd >> 8) & 0xff) != 'W')
                return -ENOTTY;
        switch (cmd) {
        case SNDRV_RAWMIDI_IOCTL_PVERSION:
-               return put_user(SNDRV_RAWMIDI_VERSION, (int *)arg) ? -EFAULT : 0;
+               return put_user(SNDRV_RAWMIDI_VERSION, (int __user *)argp) ? -EFAULT : 0;
        case SNDRV_RAWMIDI_IOCTL_INFO:
        {
                snd_rawmidi_stream_t stream;
-               snd_rawmidi_info_t *info = (snd_rawmidi_info_t *) arg;
+               snd_rawmidi_info_t __user *info = argp;
                if (get_user(stream, &info->stream))
                        return -EFAULT;
                switch (stream) {
@@ -702,7 +704,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
        case SNDRV_RAWMIDI_IOCTL_PARAMS:
        {
                snd_rawmidi_params_t params;
-               if (copy_from_user(&params, (snd_rawmidi_params_t *) arg, sizeof(snd_rawmidi_params_t)))
+               if (copy_from_user(&params, argp, sizeof(snd_rawmidi_params_t)))
                        return -EFAULT;
                switch (params.stream) {
                case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -721,7 +723,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
        {
                int err = 0;
                snd_rawmidi_status_t status;
-               if (copy_from_user(&status, (snd_rawmidi_status_t *) arg, sizeof(snd_rawmidi_status_t)))
+               if (copy_from_user(&status, argp, sizeof(snd_rawmidi_status_t)))
                        return -EFAULT;
                switch (status.stream) {
                case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -739,14 +741,14 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
                }
                if (err < 0)
                        return err;
-               if (copy_to_user((snd_rawmidi_status_t *) arg, &status, sizeof(snd_rawmidi_status_t)))
+               if (copy_to_user(argp, &status, sizeof(snd_rawmidi_status_t)))
                        return -EFAULT;
                return 0;
        }
        case SNDRV_RAWMIDI_IOCTL_DROP:
        {
                int val;
-               if (get_user(val, (long *) arg))
+               if (get_user(val, (long __user *) argp))
                        return -EFAULT;
                switch (val) {
                case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -760,7 +762,7 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
        case SNDRV_RAWMIDI_IOCTL_DRAIN:
        {
                int val;
-               if (get_user(val, (long *) arg))
+               if (get_user(val, (long __user *) argp))
                        return -EFAULT;
                switch (val) {
                case SNDRV_RAWMIDI_STREAM_OUTPUT:
@@ -783,9 +785,21 @@ static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
        return -ENOTTY;
 }
 
+/* FIXME: need to unlock BKL to allow preemption */
+static int snd_rawmidi_ioctl(struct inode *inode, struct file *file,
+                            unsigned int cmd, unsigned long arg)
+{
+       int err;
+       unlock_kernel();
+       err = _snd_rawmidi_ioctl(inode, file, cmd, arg);
+       lock_kernel();
+       return err;
+}
+
 int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
                              unsigned int cmd, unsigned long arg)
 {
+       void __user *argp = (void __user *)arg;
        unsigned int tmp;
 
        tmp = card->number * SNDRV_RAWMIDI_DEVICES;
@@ -794,7 +808,7 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
        {
                int device;
                
-               if (get_user(device, (int *)arg))
+               if (get_user(device, (int __user *)argp))
                        return -EFAULT;
                device = device < 0 ? 0 : device + 1;
                while (device < SNDRV_RAWMIDI_DEVICES) {
@@ -804,7 +818,7 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
                }
                if (device == SNDRV_RAWMIDI_DEVICES)
                        device = -1;
-               if (put_user(device, (int *)arg))
+               if (put_user(device, (int __user *)argp))
                        return -EFAULT;
                return 0;
        }
@@ -812,13 +826,13 @@ int snd_rawmidi_control_ioctl(snd_card_t * card, snd_ctl_file_t * control,
        {
                int val;
                
-               if (get_user(val, (int *)arg))
+               if (get_user(val, (int __user *)argp))
                        return -EFAULT;
                control->prefer_rawmidi_subdevice = val;
                return 0;
        }
        case SNDRV_CTL_IOCTL_RAWMIDI_INFO:
-               return snd_rawmidi_info_select_user(card, (snd_rawmidi_info_t *)arg);
+               return snd_rawmidi_info_select_user(card, argp);
        }
        return -ENOIOCTLCMD;
 }
@@ -932,7 +946,7 @@ long snd_rawmidi_kernel_read(snd_rawmidi_substream_t *substream, unsigned char *
        return snd_rawmidi_kernel_read1(substream, buf, count, 1);
 }
 
-static ssize_t snd_rawmidi_read(struct file *file, char *buf, size_t count, loff_t *offset)
+static ssize_t snd_rawmidi_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
        long result;
        int count1;
@@ -940,7 +954,7 @@ static ssize_t snd_rawmidi_read(struct file *file, char *buf, size_t count, loff
        snd_rawmidi_substream_t *substream;
        snd_rawmidi_runtime_t *runtime;
 
-       rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
+       rfile = file->private_data;
        substream = rfile->input;
        if (substream == NULL)
                return -EIO;
@@ -970,6 +984,8 @@ static ssize_t snd_rawmidi_read(struct file *file, char *buf, size_t count, loff
                }
                spin_unlock_irq(&runtime->lock);
                count1 = snd_rawmidi_kernel_read1(substream, buf, count, 0);
+               if (count1 < 0)
+                       return result > 0 ? result : count1;
                result += count1;
                buf += count1;
                count -= count1;
@@ -1164,7 +1180,7 @@ long snd_rawmidi_kernel_write(snd_rawmidi_substream_t * substream, const unsigne
        return snd_rawmidi_kernel_write1(substream, buf, count, 1);
 }
 
-static ssize_t snd_rawmidi_write(struct file *file, const char *buf, size_t count, loff_t *offset)
+static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
 {
        long result, timeout;
        int count1;
@@ -1172,7 +1188,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char *buf, size_t coun
        snd_rawmidi_runtime_t *runtime;
        snd_rawmidi_substream_t *substream;
 
-       rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return -ENXIO);
+       rfile = file->private_data;
        substream = rfile->output;
        runtime = substream->runtime;
        /* we cannot put an atomic message to our buffer */
@@ -1202,14 +1218,14 @@ static ssize_t snd_rawmidi_write(struct file *file, const char *buf, size_t coun
                spin_unlock_irq(&runtime->lock);
                count1 = snd_rawmidi_kernel_write1(substream, buf, count, 0);
                if (count1 < 0)
-                       continue;
+                       return result > 0 ? result : count1;
                result += count1;
                buf += count1;
                if ((size_t)count1 < count && (file->f_flags & O_NONBLOCK))
                        break;
                count -= count1;
        }
-       while (file->f_flags & O_SYNC) {
+       if (file->f_flags & O_SYNC) {
                spin_lock_irq(&runtime->lock);
                while (runtime->avail != runtime->buffer_size) {
                        wait_queue_t wait;
@@ -1237,7 +1253,7 @@ static unsigned int snd_rawmidi_poll(struct file *file, poll_table * wait)
        snd_rawmidi_runtime_t *runtime;
        unsigned int mask;
 
-       rfile = snd_magic_cast(snd_rawmidi_file_t, file->private_data, return 0);
+       rfile = file->private_data;
        if (rfile->input != NULL) {
                runtime = rfile->input->runtime;
                runtime->trigger = 1;
@@ -1272,7 +1288,7 @@ static void snd_rawmidi_proc_info_read(snd_info_entry_t *entry,
        snd_rawmidi_runtime_t *runtime;
        struct list_head *list;
 
-       rmidi = snd_magic_cast(snd_rawmidi_t, entry->private_data, return);
+       rmidi = entry->private_data;
        snd_iprintf(buffer, "%s\n\n", rmidi->name);
        down(&rmidi->open_mutex);
        if (rmidi->info_flags & SNDRV_RAWMIDI_INFO_OUTPUT) {
@@ -1349,7 +1365,7 @@ static int snd_rawmidi_alloc_substreams(snd_rawmidi_t *rmidi,
 
        INIT_LIST_HEAD(&stream->substreams);
        for (idx = 0; idx < count; idx++) {
-               substream = snd_kcalloc(sizeof(snd_rawmidi_substream_t), GFP_KERNEL);
+               substream = kcalloc(1, sizeof(*substream), GFP_KERNEL);
                if (substream == NULL)
                        return -ENOMEM;
                substream->stream = direction;
@@ -1392,7 +1408,7 @@ int snd_rawmidi_new(snd_card_t * card, char *id, int device,
        snd_assert(rrawmidi != NULL, return -EINVAL);
        *rrawmidi = NULL;
        snd_assert(card != NULL, return -ENXIO);
-       rmidi = snd_magic_kcalloc(snd_rawmidi_t, 0, GFP_KERNEL);
+       rmidi = kcalloc(1, sizeof(*rmidi), GFP_KERNEL);
        if (rmidi == NULL)
                return -ENOMEM;
        rmidi->card = card;
@@ -1435,20 +1451,20 @@ static int snd_rawmidi_free(snd_rawmidi_t *rmidi)
        snd_rawmidi_free_substreams(&rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT]);
        if (rmidi->private_free)
                rmidi->private_free(rmidi);
-       snd_magic_kfree(rmidi);
+       kfree(rmidi);
        return 0;
 }
 
 static int snd_rawmidi_dev_free(snd_device_t *device)
 {
-       snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
+       snd_rawmidi_t *rmidi = device->device_data;
        return snd_rawmidi_free(rmidi);
 }
 
 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
 static void snd_rawmidi_dev_seq_free(snd_seq_device_t *device)
 {
-       snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->private_data, return);
+       snd_rawmidi_t *rmidi = device->private_data;
        rmidi->seq_dev = NULL;
 }
 #endif
@@ -1458,7 +1474,7 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
        int idx, err;
        snd_info_entry_t *entry;
        char name[16];
-       snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
+       snd_rawmidi_t *rmidi = device->device_data;
 
        if (rmidi->device >= SNDRV_RAWMIDI_DEVICES)
                return -ENOMEM;
@@ -1535,7 +1551,7 @@ static int snd_rawmidi_dev_register(snd_device_t *device)
 
 static int snd_rawmidi_dev_disconnect(snd_device_t *device)
 {
-       snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
+       snd_rawmidi_t *rmidi = device->device_data;
        int idx;
 
        down(&register_mutex);
@@ -1548,7 +1564,7 @@ static int snd_rawmidi_dev_disconnect(snd_device_t *device)
 static int snd_rawmidi_dev_unregister(snd_device_t *device)
 {
        int idx;
-       snd_rawmidi_t *rmidi = snd_magic_cast(snd_rawmidi_t, device->device_data, return -ENXIO);
+       snd_rawmidi_t *rmidi = device->device_data;
 
        snd_assert(rmidi != NULL, return -ENXIO);
        down(&register_mutex);
@@ -1637,26 +1653,6 @@ static void __exit alsa_rawmidi_exit(void)
 module_init(alsa_rawmidi_init)
 module_exit(alsa_rawmidi_exit)
 
-#ifndef MODULE
-#ifdef CONFIG_SND_OSSEMUL
-/* format is: snd-rawmidi=midi_map,amidi_map */
-
-static int __init alsa_rawmidi_setup(char *str)
-{
-       static unsigned __initdata nr_dev = 0;
-
-       if (nr_dev >= SNDRV_CARDS)
-               return 0;
-       (void)(get_option(&str,&midi_map[nr_dev]) == 2 &&
-              get_option(&str,&amidi_map[nr_dev]) == 2);
-       nr_dev++;
-       return 1;
-}
-
-__setup("snd-rawmidi=", alsa_rawmidi_setup);
-#endif /* CONFIG_SND_OSSEMUL */
-#endif /* ifndef MODULE */
-
 EXPORT_SYMBOL(snd_rawmidi_output_params);
 EXPORT_SYMBOL(snd_rawmidi_input_params);
 EXPORT_SYMBOL(snd_rawmidi_drop_output);