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