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>
28 #include <sound/core.h>
29 #include <sound/control.h>
30 #include <sound/minors.h>
31 #include <asm/uaccess.h>
36 * register/unregister mappers
37 * exported for other modules
40 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
41 MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
42 MODULE_LICENSE("GPL");
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);
48 int snd_ioctl32_register(struct ioctl32_mapper *mappers)
51 struct ioctl32_mapper *m;
53 for (m = mappers; m->cmd; m++) {
54 err = register_ioctl32_conversion(m->cmd, m->handler);
61 void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
63 struct ioctl32_mapper *m;
65 for (m = mappers; m->cmd; m++) {
67 unregister_ioctl32_conversion(m->cmd);
77 int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
79 if (! filp->f_op || ! filp->f_op->ioctl)
81 return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
89 struct sndrv_ctl_elem_list32 {
95 unsigned char reserved[50];
96 } /* don't set packed attribute here */;
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)
100 struct sndrv_ctl_elem_list32 __user *data32;
101 struct sndrv_ctl_elem_list __user *data;
105 data32 = compat_ptr(arg);
106 data = compat_alloc_user_space(sizeof(*data));
108 /* offset, space, used, count */
109 if (copy_in_user(data, data32, 4 * sizeof(u32)))
112 if (__get_user(ptr, &data32->pids) ||
113 __put_user(compat_ptr(ptr), &data->pids))
115 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
118 /* copy the result */
119 if (copy_in_user(data32, data, 4 * sizeof(u32)))
124 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
127 * control element info
128 * it uses union, so the things are not easy..
131 struct sndrv_ctl_elem_info32 {
132 struct sndrv_ctl_elem_id id; // the size of struct is same
153 unsigned char reserved[128];
155 unsigned char reserved[64];
156 } __attribute__((packed));
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)
160 struct sndrv_ctl_elem_info __user *data, *src;
161 struct sndrv_ctl_elem_info32 __user *data32, *dst;
165 data32 = compat_ptr(arg);
166 data = compat_alloc_user_space(sizeof(*data));
169 if (copy_in_user(&data->id, &data32->id, sizeof(data->id)))
171 /* we need to copy the item index.
172 * hope this doesn't break anything..
174 if (copy_in_user(&data->value.enumerated.item,
175 &data32->value.enumerated.item,
176 sizeof(data->value.enumerated.item)))
178 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
181 /* restore info to 32bit */
182 /* for COPY_CVT macro */
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)))
190 __get_user(type, &data->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);
198 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
199 if (copy_in_user(&data32->value.integer64,
200 &data->value.integer64,
201 sizeof(data->value.integer64)))
204 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
205 if (copy_in_user(&data32->value.enumerated,
206 &data->value.enumerated,
207 sizeof(data->value.enumerated)))
216 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
218 struct sndrv_ctl_elem_value32 {
219 struct sndrv_ctl_elem_id id;
220 unsigned int indirect; /* bit-field causes misalignment */
235 unsigned char data[512];
238 struct sndrv_aes_iec958 iec958;
240 unsigned char reserved[128];
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)
247 snd_kcontrol_t *kctl;
248 snd_ctl_elem_info_t info;
251 down_read(&card->controls_rwsem);
252 kctl = snd_ctl_find_id(card, id);
254 up_read(&card->controls_rwsem);
258 err = kctl->info(kctl, &info);
259 up_read(&card->controls_rwsem);
265 extern int snd_major;
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)
269 struct sndrv_ctl_elem_value *data;
270 struct sndrv_ctl_elem_value32 __user *data32;
276 if (imajor(file->f_dentry->d_inode) != snd_major ||
277 SNDRV_MINOR_DEVICE(iminor(file->f_dentry->d_inode)) != SNDRV_MINOR_CONTROL)
280 if ((ctl = file->private_data) == NULL)
283 data32 = compat_ptr(arg);
284 data = kmalloc(sizeof(*data), GFP_KERNEL);
288 if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) {
292 if (__get_user(data->indirect, &data32->indirect)) {
296 /* FIXME: indirect access is not supported */
297 if (data->indirect) {
301 type = get_ctl_type(ctl->card, &data->id);
308 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
309 case SNDRV_CTL_ELEM_TYPE_INTEGER:
310 for (i = 0; i < 128; i++) {
312 if (__get_user(val, &data32->value.integer.value[i])) {
316 data->value.integer.value[i] = val;
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))) {
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))) {
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))) {
343 case SNDRV_CTL_ELEM_TYPE_IEC958:
344 if (__copy_from_user(&data->value.iec958,
345 &data32->value.iec958,
346 sizeof(data32->value.iec958))) {
352 printk(KERN_ERR "snd_ioctl32_ctl_elem_value: unknown type %d\n", type);
357 if (native_ctl == SNDRV_CTL_IOCTL_ELEM_READ)
358 err = snd_ctl_elem_read(ctl->card, data);
360 err = snd_ctl_elem_write(ctl, data);
363 /* restore info to 32bit */
365 case SNDRV_CTL_ELEM_TYPE_BOOLEAN:
366 case SNDRV_CTL_ELEM_TYPE_INTEGER:
367 for (i = 0; i < 128; i++) {
369 val = data->value.integer.value[i];
370 if (__put_user(val, &data32->value.integer.value[i])) {
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))) {
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))) {
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))) {
400 case SNDRV_CTL_ELEM_TYPE_IEC958:
401 if (__copy_to_user(&data32->value.iec958,
403 sizeof(data32->value.iec958))) {
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);
422 #define AP(x) snd_ioctl32_##x
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),
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),
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[];
464 static void snd_ioctl32_done(void)
466 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
467 snd_ioctl32_unregister(seq_mappers);
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);
476 static int __init snd_ioctl32_init(void)
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);
489 module_init(snd_ioctl32_init)
490 module_exit(snd_ioctl32_done)