2.6.12 planetlab config file
[linux-2.6.git] / sound / core / ioctl32 / ioctl32.c
1 /*
2  *   32bit -> 64bit ioctl wrapper for control API
3  *   Copyright (c) by Takashi Iwai <tiwai@suse.de>
4  *
5  *   This program is free software; you can redistribute it and/or modify
6  *   it under the terms of the GNU General Public License as published by
7  *   the Free Software Foundation; either version 2 of the License, or
8  *   (at your option) any later version.
9  *
10  *   This program is distributed in the hope that it will be useful,
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *   GNU General Public License for more details.
14  *
15  *   You should have received a copy of the GNU General Public License
16  *   along with this program; if not, write to the Free Software
17  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
18  *
19  */
20
21 #include <sound/driver.h>
22 #include <linux/sched.h>
23 #include <linux/smp_lock.h>
24 #include <linux/init.h>
25 #include <linux/time.h>
26 #include <linux/slab.h>
27 #include <linux/fs.h>
28 #include <sound/core.h>
29 #include <sound/control.h>
30 #include <sound/minors.h>
31 #include <asm/uaccess.h>
32 #include "ioctl32.h"
33
34
35 /*
36  * register/unregister mappers
37  * exported for other modules
38  */
39
40 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
41 MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
42 MODULE_LICENSE("GPL");
43
44 int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
45 int unregister_ioctl32_conversion(unsigned int cmd);
46
47
48 int snd_ioctl32_register(struct ioctl32_mapper *mappers)
49 {
50         int err;
51         struct ioctl32_mapper *m;
52
53         for (m = mappers; m->cmd; m++) {
54                 err = register_ioctl32_conversion(m->cmd, m->handler);
55                 if (err >= 0)
56                         m->registered++;
57         }
58         return 0;
59 }
60
61 void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
62 {
63         struct ioctl32_mapper *m;
64
65         for (m = mappers; m->cmd; m++) {
66                 if (m->registered) {
67                         unregister_ioctl32_conversion(m->cmd);
68                         m->registered = 0;
69                 }
70         }
71 }
72
73
74 /*
75  * compatible wrapper
76  */
77 int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
78 {
79         if (! filp->f_op || ! filp->f_op->ioctl)
80                 return -ENOTTY;
81         return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
82 }
83
84
85 /*
86  * Controls
87  */
88
89 struct sndrv_ctl_elem_list32 {
90         u32 offset;
91         u32 space;
92         u32 used;
93         u32 count;
94         u32 pids;
95         unsigned char reserved[50];
96 } /* don't set packed attribute here */;
97
98 static inline int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
99 {
100         struct sndrv_ctl_elem_list32 __user *data32;
101         struct sndrv_ctl_elem_list __user *data;
102         compat_caddr_t ptr;
103         int err;
104
105         data32 = compat_ptr(arg);
106         data = compat_alloc_user_space(sizeof(*data));
107
108         /* offset, space, used, count */
109         if (copy_in_user(data, data32, 4 * sizeof(u32)))
110                 return -EFAULT;
111         /* pids */
112         if (__get_user(ptr, &data32->pids) ||
113             __put_user(compat_ptr(ptr), &data->pids))
114                 return -EFAULT;
115         err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
116         if (err < 0)
117                 return err;
118         /* copy the result */
119         if (copy_in_user(data32, data, 4 * sizeof(u32)))
120                 return -EFAULT;
121         return 0;
122 }
123
124 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
125
126 /*
127  * control element info
128  * it uses union, so the things are not easy..
129  */
130
131 struct sndrv_ctl_elem_info32 {
132         struct sndrv_ctl_elem_id id; // the size of struct is same
133         s32 type;
134         u32 access;
135         u32 count;
136         s32 owner;
137         union {
138                 struct {
139                         s32 min;
140                         s32 max;
141                         s32 step;
142                 } integer;
143                 struct {
144                         u64 min;
145                         u64 max;
146                         u64 step;
147                 } integer64;
148                 struct {
149                         u32 items;
150                         u32 item;
151                         char name[64];
152                 } enumerated;
153                 unsigned char reserved[128];
154         } value;
155         unsigned char reserved[64];
156 } __attribute__((packed));
157
158 static inline int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
159 {
160         struct sndrv_ctl_elem_info __user *data, *src;
161         struct sndrv_ctl_elem_info32 __user *data32, *dst;
162         unsigned int type;
163         int err;
164
165         data32 = compat_ptr(arg);
166         data = compat_alloc_user_space(sizeof(*data));
167
168         /* copy id */
169         if (copy_in_user(&data->id, &data32->id, sizeof(data->id)))
170                 return -EFAULT;
171         /* we need to copy the item index.
172          * hope this doesn't break anything..
173          */
174         if (copy_in_user(&data->value.enumerated.item,
175                          &data32->value.enumerated.item,
176                          sizeof(data->value.enumerated.item)))
177                 return -EFAULT;
178         err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
179         if (err < 0)
180                 return err;
181         /* restore info to 32bit */
182         /* for COPY_CVT macro */
183         src = data;
184         dst = data32;
185         /* id, type, access, count */
186         if (copy_in_user(&data32->id, &data->id, sizeof(data->id)) ||
187             copy_in_user(&data32->type, &data->type, 3 * sizeof(u32)))
188                 return -EFAULT;
189         COPY_CVT(owner);
190         __get_user(type, &data->type);
191         switch (type) {
192         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
193         case SNDRV_CTL_ELEM_TYPE_INTEGER:
194                 COPY_CVT(value.integer.min);
195                 COPY_CVT(value.integer.max);
196                 COPY_CVT(value.integer.step);
197                 break;
198         case SNDRV_CTL_ELEM_TYPE_INTEGER64:
199                 if (copy_in_user(&data32->value.integer64,
200                                  &data->value.integer64,
201                                  sizeof(data->value.integer64)))
202                         return -EFAULT;
203                 break;
204         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
205                 if (copy_in_user(&data32->value.enumerated,
206                                  &data->value.enumerated,
207                                  sizeof(data->value.enumerated)))
208                         return -EFAULT;
209                 break;
210         default:
211                 break;
212         }
213         return 0;
214 }
215
216 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
217
218 struct sndrv_ctl_elem_value32 {
219         struct sndrv_ctl_elem_id id;
220         unsigned int indirect;  /* bit-field causes misalignment */
221         union {
222                 union {
223                         s32 value[128];
224                         u32 value_ptr;
225                 } integer;
226                 union {
227                         s64 value[64];
228                         u32 value_ptr;
229                 } integer64;
230                 union {
231                         u32 item[128];
232                         u32 item_ptr;
233                 } enumerated;
234                 union {
235                         unsigned char data[512];
236                         u32 data_ptr;
237                 } bytes;
238                 struct sndrv_aes_iec958 iec958;
239         } value;
240         unsigned char reserved[128];
241 };
242
243
244 /* hmm, it's so hard to retrieve the value type from the control id.. */
245 static int get_ctl_type(snd_card_t *card, snd_ctl_elem_id_t *id)
246 {
247         snd_kcontrol_t *kctl;
248         snd_ctl_elem_info_t info;
249         int err;
250
251         down_read(&card->controls_rwsem);
252         kctl = snd_ctl_find_id(card, id);
253         if (! kctl) {
254                 up_read(&card->controls_rwsem);
255                 return -ENXIO;
256         }
257         info.id = *id;
258         err = kctl->info(kctl, &info);
259         up_read(&card->controls_rwsem);
260         if (err >= 0)
261                 err = info.type;
262         return err;
263 }
264
265 extern int snd_major;
266
267 static inline int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
268 {
269         struct sndrv_ctl_elem_value *data;
270         struct sndrv_ctl_elem_value32 __user *data32;
271         snd_ctl_file_t *ctl;
272         int err, i;
273         int type;
274
275         /* sanity check */
276         if (imajor(file->f_dentry->d_inode) != snd_major ||
277             SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL)
278                 return -ENOTTY;
279
280         if ((ctl = file->private_data) == NULL)
281                 return -ENOTTY;
282
283         data32 = compat_ptr(arg);
284         data = kmalloc(sizeof(*data), GFP_KERNEL);
285         if (data == NULL)
286                 return -ENOMEM;
287
288         if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) {
289                 err = -EFAULT;
290                 goto __end;
291         }
292         if (__get_user(data->indirect, &data32->indirect)) {
293                 err = -EFAULT;
294                 goto __end;
295         }
296         /* FIXME: indirect access is not supported */
297         if (data->indirect) {
298                 err = -EINVAL;
299                 goto __end;
300         }
301         type = get_ctl_type(ctl->card, &data->id);
302         if (type < 0) {
303                 err = type;
304                 goto __end;
305         }
306
307         switch (type) {
308         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
309         case SNDRV_CTL_ELEM_TYPE_INTEGER:
310                 for (i = 0; i < 128; i++) {
311                         int val;
312                         if (__get_user(val, &data32->value.integer.value[i])) {
313                                 err = -EFAULT;
314                                 goto __end;
315                         }
316                         data->value.integer.value[i] = val;
317                 }
318                 break;
319         case SNDRV_CTL_ELEM_TYPE_INTEGER64:
320                 if (__copy_from_user(data->value.integer64.value,
321                                      data32->value.integer64.value,
322                                      sizeof(data->value.integer64.value))) {
323                         err = -EFAULT;
324                         goto __end;
325                 }
326                 break;
327         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
328                 if (__copy_from_user(data->value.enumerated.item,
329                                      data32->value.enumerated.item,
330                                      sizeof(data32->value.enumerated.item))) {
331                         err = -EFAULT;
332                         goto __end;
333                 }
334                 break;
335         case SNDRV_CTL_ELEM_TYPE_BYTES:
336                 if (__copy_from_user(data->value.bytes.data,
337                                      data32->value.bytes.data,
338                                      sizeof(data32->value.bytes.data))) {
339                         err = -EFAULT;
340                         goto __end;
341                 }
342                 break;
343         case SNDRV_CTL_ELEM_TYPE_IEC958:
344                 if (__copy_from_user(&data->value.iec958,
345                                      &data32->value.iec958,
346                                      sizeof(data32->value.iec958))) {
347                         err = -EFAULT;
348                         goto __end;
349                 }
350                 break;
351         default:
352                 printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
353                 err = -EINVAL;
354                 goto __end;
355         }
356
357         if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ)
358                 err = snd_ctl_elem_read(ctl->card, data);
359         else
360                 err = snd_ctl_elem_write(ctl, data);
361         if (err < 0)
362                 goto __end;
363         /* restore info to 32bit */
364         switch (type) {
365         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
366         case SNDRV_CTL_ELEM_TYPE_INTEGER:
367                 for (i = 0; i < 128; i++) {
368                         int val;
369                         val = data->value.integer.value[i];
370                         if (__put_user(val, &data32->value.integer.value[i])) {
371                                 err = -EFAULT;
372                                 goto __end;
373                         }
374                 }
375                 break;
376         case SNDRV_CTL_ELEM_TYPE_INTEGER64:
377                 if (__copy_to_user(data32->value.integer64.value,
378                                    data->value.integer64.value,
379                                    sizeof(data32->value.integer64.value))) {
380                         err = -EFAULT;
381                         goto __end;
382                 }
383                 break;
384         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
385                 if (__copy_to_user(data32->value.enumerated.item,
386                                    data->value.enumerated.item,
387                                    sizeof(data32->value.enumerated.item))) {
388                         err = -EFAULT;
389                         goto __end;
390                 }
391                 break;
392         case SNDRV_CTL_ELEM_TYPE_BYTES:
393                 if (__copy_to_user(data32->value.bytes.data,
394                                    data->value.bytes.data,
395                                    sizeof(data32->value.bytes.data))) {
396                         err = -EFAULT;
397                         goto __end;
398                 }
399                 break;
400         case SNDRV_CTL_ELEM_TYPE_IEC958:
401                 if (__copy_to_user(&data32->value.iec958,
402                                    &data->value.iec958,
403                                    sizeof(data32->value.iec958))) {
404                         err = -EFAULT;
405                         goto __end;
406                 }
407                 break;
408         }
409         err = 0;
410       __end:
411         if (data)
412                 kfree(data);
413         return err;
414 }
415
416 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
417 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);
418
419 /*
420  */
421
422 #define AP(x) snd_ioctl32_##x
423
424 enum {
425         SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
426         SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
427         SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
428         SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
429 };
430
431 static struct ioctl32_mapper control_mappers[] = {
432         /* controls (without rawmidi, hwdep, timer releated ones) */
433         MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION),
434         MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO),
435         { SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },
436         { SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },
437         { SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },
438         { SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },
439         MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK),
440         MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK),
441         MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS),
442         MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO),
443         MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE),
444         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE),
445         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO),
446         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE),
447         MAP_COMPAT(SNDRV_CTL_IOCTL_POWER),
448         MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE),
449         { 0 }
450 };
451
452
453 /*
454  */
455
456 extern struct ioctl32_mapper pcm_mappers[];
457 extern struct ioctl32_mapper rawmidi_mappers[];
458 extern struct ioctl32_mapper timer_mappers[];
459 extern struct ioctl32_mapper hwdep_mappers[];
460 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
461 extern struct ioctl32_mapper seq_mappers[];
462 #endif
463
464 static void snd_ioctl32_done(void)
465 {
466 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
467         snd_ioctl32_unregister(seq_mappers);
468 #endif
469         snd_ioctl32_unregister(hwdep_mappers);
470         snd_ioctl32_unregister(timer_mappers);
471         snd_ioctl32_unregister(rawmidi_mappers);
472         snd_ioctl32_unregister(pcm_mappers);
473         snd_ioctl32_unregister(control_mappers);
474 }
475
476 static int __init snd_ioctl32_init(void)
477 {
478         snd_ioctl32_register(control_mappers);
479         snd_ioctl32_register(pcm_mappers);
480         snd_ioctl32_register(rawmidi_mappers);
481         snd_ioctl32_register(timer_mappers);
482         snd_ioctl32_register(hwdep_mappers);
483 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
484         snd_ioctl32_register(seq_mappers);
485 #endif
486         return 0;
487 }
488
489 module_init(snd_ioctl32_init)
490 module_exit(snd_ioctl32_done)