commented early_printk patch because of rejects.
[linux-flexiantxendom0-3.2.10.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 <linux/init.h>
29 #include <sound/core.h>
30 #include <sound/control.h>
31 #include <asm/uaccess.h>
32 #include "ioctl32.h"
33
34 /*
35  * register/unregister mappers
36  * exported for other modules
37  */
38
39 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
40 MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
41 MODULE_LICENSE("GPL");
42
43 int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *));
44 int unregister_ioctl32_conversion(unsigned int cmd);
45
46
47 int snd_ioctl32_register(struct ioctl32_mapper *mappers)
48 {
49         int err;
50         struct ioctl32_mapper *m;
51
52         for (m = mappers; m->cmd; m++) {
53                 err = register_ioctl32_conversion(m->cmd, m->handler);
54                 if (err >= 0)
55                         m->registered++;
56         }
57         return 0;
58 }
59
60 void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
61 {
62         struct ioctl32_mapper *m;
63
64         for (m = mappers; m->cmd; m++) {
65                 if (m->registered) {
66                         unregister_ioctl32_conversion(m->cmd);
67                         m->registered = 0;
68                 }
69         }
70 }
71
72
73 /*
74  * compatible wrapper
75  */
76 int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
77 {
78         if (! filp->f_op || ! filp->f_op->ioctl)
79                 return -ENOTTY;
80         return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
81 }
82
83
84 /*
85  * Controls
86  */
87
88 struct sndrv_ctl_elem_list32 {
89         u32 offset;
90         u32 space;
91         u32 used;
92         u32 count;
93         u32 pids;
94         unsigned char reserved[50];
95 } /* don't set packed attribute here */;
96
97 #define CVT_sndrv_ctl_elem_list()\
98 {\
99         COPY(offset);\
100         COPY(space);\
101         COPY(used);\
102         COPY(count);\
103         CPTR(pids);\
104 }
105
106 static int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
107 {
108         struct sndrv_ctl_elem_list32 data32;
109         struct sndrv_ctl_elem_list data;
110         mm_segment_t oldseg;
111         int err;
112
113         if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
114                 return -EFAULT;
115         memset(&data, 0, sizeof(data));
116         data.offset = data32.offset;
117         data.space = data32.space;
118         data.used = data32.used;
119         data.count = data32.count;
120         data.pids = A(data32.pids);
121         oldseg = get_fs();
122         set_fs(KERNEL_DS);
123         err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
124         set_fs(oldseg);
125         if (err < 0)
126                 return err;
127         /* copy the result */
128         data32.offset = data.offset;
129         data32.space = data.space;
130         data32.used = data.used;
131         data32.count = data.count;
132         //data.pids = data.pids;
133         if (copy_to_user((void*)arg, &data32, sizeof(data32)))
134                 return -EFAULT;
135         return 0;
136 }
137
138 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
139
140 /*
141  * control element info
142  * it uses union, so the things are not easy..
143  */
144
145 struct sndrv_ctl_elem_info32 {
146         struct sndrv_ctl_elem_id id; // the size of struct is same
147         s32 type;
148         u32 access;
149         u32 count;
150         s32 owner;
151         union {
152                 struct {
153                         s32 min;
154                         s32 max;
155                         s32 step;
156                 } integer;
157                 struct {
158                         u64 min;
159                         u64 max;
160                         u64 step;
161                 } integer64;
162                 struct {
163                         u32 items;
164                         u32 item;
165                         char name[64];
166                 } enumerated;
167                 unsigned char reserved[128];
168         } value;
169         unsigned char reserved[64];
170 } __attribute__((packed));
171
172 static int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
173 {
174         struct sndrv_ctl_elem_info data;
175         struct sndrv_ctl_elem_info32 data32;
176         int err;
177         mm_segment_t oldseg;
178
179         if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
180                 return -EFAULT;
181         memset(&data, 0, sizeof(data));
182         data.id = data32.id;
183         /* we need to copy the item index.
184          * hope this doesn't break anything..
185          */
186         data.value.enumerated.item = data32.value.enumerated.item;
187         oldseg = get_fs();
188         set_fs(KERNEL_DS);
189         err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
190         set_fs(oldseg);
191         if (err < 0)
192                 return err;
193         /* restore info to 32bit */
194         data32.id = data.id;
195         data32.type = data.type;
196         data32.access = data.access;
197         data32.count = data.count;
198         data32.owner = data.owner;
199         switch (data.type) {
200         case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
201         case SNDRV_CTL_ELEM_TYPE_INTEGER:
202                 data32.value.integer.min = data.value.integer.min;
203                 data32.value.integer.max = data.value.integer.max;
204                 data32.value.integer.step = data.value.integer.step;
205                 break;
206         case SNDRV_CTL_ELEM_TYPE_INTEGER64:
207                 data32.value.integer64.min = data.value.integer64.min;
208                 data32.value.integer64.max = data.value.integer64.max;
209                 data32.value.integer64.step = data.value.integer64.step;
210                 break;
211         case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
212                 data32.value.enumerated.items = data.value.enumerated.items;
213                 data32.value.enumerated.item = data.value.enumerated.item;
214                 memcpy(data32.value.enumerated.name, data.value.enumerated.name,
215                        sizeof(data.value.enumerated.name));
216                 break;
217         default:
218                 break;
219         }
220         if (copy_to_user((void*)arg, &data32, sizeof(data32)))
221                 return -EFAULT;
222         return 0;
223 }
224
225 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
226
227 struct sndrv_ctl_elem_value32 {
228         struct sndrv_ctl_elem_id id;
229         unsigned int indirect;  /* bit-field causes misalignment */
230         union {
231                 union {
232                         s32 value[128];
233                         u32 value_ptr;
234                 } integer;
235                 union {
236                         s64 value[64];
237                         u32 value_ptr;
238                 } integer64;
239                 union {
240                         u32 item[128];
241                         u32 item_ptr;
242                 } enumerated;
243                 union {
244                         unsigned char data[512];
245                         u32 data_ptr;
246                 } bytes;
247                 struct sndrv_aes_iec958 iec958;
248         } value;
249         unsigned char reserved[128];
250 } __attribute__((packed));
251
252
253 /* hmm, it's so hard to retrieve the value type from the control id.. */
254 static int get_ctl_type(struct file *file, snd_ctl_elem_id_t *id)
255 {
256         snd_ctl_file_t *ctl;
257         snd_kcontrol_t *kctl;
258         snd_ctl_elem_info_t info;
259         int err;
260
261         ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
262
263         kctl = snd_ctl_find_id(ctl->card, id);
264         if (! kctl) {
265                 return -ENXIO;
266         }
267         info.id = *id;
268         err = kctl->info(kctl, &info);
269         if (err >= 0)
270                 err = info.type;
271         return err;
272 }
273
274
275 static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
276 {
277         struct sndrv_ctl_elem_value *data;
278         struct sndrv_ctl_elem_value32 *data32;
279         int err, i;
280         int type;
281         mm_segment_t oldseg;
282
283         /* FIXME: check the sane ioctl.. */
284
285         data = kmalloc(sizeof(*data), GFP_KERNEL);
286         data32 = kmalloc(sizeof(*data32), GFP_KERNEL);
287         if (data == NULL || data32 == NULL) {
288                 err = -ENOMEM;
289                 goto __end;
290         }
291
292         if (copy_from_user(data32, (void*)arg, sizeof(*data32))) {
293                 err = -EFAULT;
294                 goto __end;
295         }
296         memset(data, 0, sizeof(*data));
297         data->id = data32->id;
298         data->indirect = data32->indirect;
299         if (data->indirect) /* FIXME: this is not correct for long arrays */
300                 data->value.integer.value_ptr = (void*)TO_PTR(data32->value.integer.value_ptr);
301         type = get_ctl_type(file, &data->id);
302         if (type < 0) {
303                 err = type;
304                 goto __end;
305         }
306         if (! data->indirect) {
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                                 data->value.integer.value[i] = data32->value.integer.value[i];
312                         break;
313                 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
314                         for (i = 0; i < 64; i++)
315                                 data->value.integer64.value[i] = data32->value.integer64.value[i];
316                         break;
317                 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
318                         for (i = 0; i < 128; i++)
319                                 data->value.enumerated.item[i] = data32->value.enumerated.item[i];
320                         break;
321                 case SNDRV_CTL_ELEM_TYPE_BYTES:
322                         memcpy(data->value.bytes.data, data32->value.bytes.data,
323                                sizeof(data->value.bytes.data));
324                         break;
325                 case SNDRV_CTL_ELEM_TYPE_IEC958:
326                         data->value.iec958 = data32->value.iec958;
327                         break;
328                 default:
329                         printk("unknown type %d\n", type);
330                         break;
331                 }
332         }
333
334         oldseg = get_fs();
335         set_fs(KERNEL_DS);
336         err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
337         set_fs(oldseg);
338         if (err < 0)
339                 goto __end;
340         /* restore info to 32bit */
341         if (! data->indirect) {
342                 switch (type) {
343                 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
344                 case SNDRV_CTL_ELEM_TYPE_INTEGER:
345                         for (i = 0; i < 128; i++)
346                                 data32->value.integer.value[i] = data->value.integer.value[i];
347                         break;
348                 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
349                         for (i = 0; i < 64; i++)
350                                 data32->value.integer64.value[i] = data->value.integer64.value[i];
351                         break;
352                 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
353                         for (i = 0; i < 128; i++)
354                                 data32->value.enumerated.item[i] = data->value.enumerated.item[i];
355                         break;
356                 case SNDRV_CTL_ELEM_TYPE_BYTES:
357                         memcpy(data32->value.bytes.data, data->value.bytes.data,
358                                sizeof(data->value.bytes.data));
359                         break;
360                 case SNDRV_CTL_ELEM_TYPE_IEC958:
361                         data32->value.iec958 = data->value.iec958;
362                         break;
363                 default:
364                         break;
365                 }
366         }
367         err = 0;
368         if (copy_to_user((void*)arg, data32, sizeof(*data32)))
369                 err = -EFAULT;
370       __end:
371         if (data32)
372                 kfree(data32);
373         if (data)
374                 kfree(data);
375         return err;
376 }
377
378 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_read, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_READ);
379 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_write, ctl_elem_value, SNDRV_CTL_IOCTL_ELEM_WRITE);
380
381 /*
382  */
383
384 #define AP(x) snd_ioctl32_##x
385
386 enum {
387         SNDRV_CTL_IOCTL_ELEM_LIST32 = _IOWR('U', 0x10, struct sndrv_ctl_elem_list32),
388         SNDRV_CTL_IOCTL_ELEM_INFO32 = _IOWR('U', 0x11, struct sndrv_ctl_elem_info32),
389         SNDRV_CTL_IOCTL_ELEM_READ32 = _IOWR('U', 0x12, struct sndrv_ctl_elem_value32),
390         SNDRV_CTL_IOCTL_ELEM_WRITE32 = _IOWR('U', 0x13, struct sndrv_ctl_elem_value32),
391 };
392
393 static struct ioctl32_mapper control_mappers[] = {
394         /* controls (without rawmidi, hwdep, timer releated ones) */
395         MAP_COMPAT(SNDRV_CTL_IOCTL_PVERSION),
396         MAP_COMPAT(SNDRV_CTL_IOCTL_CARD_INFO),
397         { SNDRV_CTL_IOCTL_ELEM_LIST32, AP(ctl_elem_list) },
398         { SNDRV_CTL_IOCTL_ELEM_INFO32, AP(ctl_elem_info) },
399         { SNDRV_CTL_IOCTL_ELEM_READ32, AP(ctl_elem_read) },
400         { SNDRV_CTL_IOCTL_ELEM_WRITE32, AP(ctl_elem_write) },
401         MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_LOCK),
402         MAP_COMPAT(SNDRV_CTL_IOCTL_ELEM_UNLOCK),
403         MAP_COMPAT(SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS),
404         MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_INFO),
405         MAP_COMPAT(SNDRV_CTL_IOCTL_HWDEP_NEXT_DEVICE),
406         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_NEXT_DEVICE),
407         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_INFO),
408         MAP_COMPAT(SNDRV_CTL_IOCTL_PCM_PREFER_SUBDEVICE),
409         MAP_COMPAT(SNDRV_CTL_IOCTL_POWER),
410         MAP_COMPAT(SNDRV_CTL_IOCTL_POWER_STATE),
411         { 0 }
412 };
413
414
415 /*
416  */
417
418 extern struct ioctl32_mapper pcm_mappers[];
419 extern struct ioctl32_mapper rawmidi_mappers[];
420 extern struct ioctl32_mapper timer_mappers[];
421 extern struct ioctl32_mapper hwdep_mappers[];
422 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
423 extern struct ioctl32_mapper seq_mappers[];
424 #endif
425
426 static void snd_ioctl32_done(void)
427 {
428 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
429         snd_ioctl32_unregister(seq_mappers);
430 #endif
431         snd_ioctl32_unregister(hwdep_mappers);
432         snd_ioctl32_unregister(timer_mappers);
433         snd_ioctl32_unregister(rawmidi_mappers);
434         snd_ioctl32_unregister(pcm_mappers);
435         snd_ioctl32_unregister(control_mappers);
436 }
437
438 static int __init snd_ioctl32_init(void)
439 {
440         snd_ioctl32_register(control_mappers);
441         snd_ioctl32_register(pcm_mappers);
442         snd_ioctl32_register(rawmidi_mappers);
443         snd_ioctl32_register(timer_mappers);
444         snd_ioctl32_register(hwdep_mappers);
445 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
446         snd_ioctl32_register(seq_mappers);
447 #endif
448         return 0;
449 }
450
451 module_init(snd_ioctl32_init)
452 module_exit(snd_ioctl32_done)