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 <linux/init.h>
29 #include <sound/core.h>
30 #include <sound/control.h>
31 #include <asm/uaccess.h>
35 * register/unregister mappers
36 * exported for other modules
39 MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
40 MODULE_DESCRIPTION("ioctl32 wrapper for ALSA");
41 MODULE_LICENSE("GPL");
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);
47 int snd_ioctl32_register(struct ioctl32_mapper *mappers)
50 struct ioctl32_mapper *m;
52 for (m = mappers; m->cmd; m++) {
53 err = register_ioctl32_conversion(m->cmd, m->handler);
60 void snd_ioctl32_unregister(struct ioctl32_mapper *mappers)
62 struct ioctl32_mapper *m;
64 for (m = mappers; m->cmd; m++) {
66 unregister_ioctl32_conversion(m->cmd);
76 int snd_ioctl32_compat(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *filp)
78 if (! filp->f_op || ! filp->f_op->ioctl)
80 return filp->f_op->ioctl(filp->f_dentry->d_inode, filp, cmd, arg);
88 struct sndrv_ctl_elem_list32 {
94 unsigned char reserved[50];
95 } /* don't set packed attribute here */;
97 #define CVT_sndrv_ctl_elem_list()\
106 static int _snd_ioctl32_ctl_elem_list(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
108 struct sndrv_ctl_elem_list32 data32;
109 struct sndrv_ctl_elem_list data;
113 if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
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);
123 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
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)))
138 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_list, ctl_elem_list, SNDRV_CTL_IOCTL_ELEM_LIST);
141 * control element info
142 * it uses union, so the things are not easy..
145 struct sndrv_ctl_elem_info32 {
146 struct sndrv_ctl_elem_id id; // the size of struct is same
167 unsigned char reserved[128];
169 unsigned char reserved[64];
170 } __attribute__((packed));
172 static int _snd_ioctl32_ctl_elem_info(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
174 struct sndrv_ctl_elem_info data;
175 struct sndrv_ctl_elem_info32 data32;
179 if (copy_from_user(&data32, (void*)arg, sizeof(data32)))
181 memset(&data, 0, sizeof(data));
183 /* we need to copy the item index.
184 * hope this doesn't break anything..
186 data.value.enumerated.item = data32.value.enumerated.item;
189 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)&data);
193 /* restore info to 32bit */
195 data32.type = data.type;
196 data32.access = data.access;
197 data32.count = data.count;
198 data32.owner = data.owner;
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;
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;
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));
220 if (copy_to_user((void*)arg, &data32, sizeof(data32)))
225 DEFINE_ALSA_IOCTL_ENTRY(ctl_elem_info, ctl_elem_info, SNDRV_CTL_IOCTL_ELEM_INFO);
227 struct sndrv_ctl_elem_value32 {
228 struct sndrv_ctl_elem_id id;
229 unsigned int indirect; /* bit-field causes misalignment */
244 unsigned char data[512];
247 struct sndrv_aes_iec958 iec958;
249 unsigned char reserved[128];
250 } __attribute__((packed));
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)
257 snd_kcontrol_t *kctl;
258 snd_ctl_elem_info_t info;
261 ctl = snd_magic_cast(snd_ctl_file_t, file->private_data, return -ENXIO);
263 kctl = snd_ctl_find_id(ctl->card, id);
268 err = kctl->info(kctl, &info);
275 static int _snd_ioctl32_ctl_elem_value(unsigned int fd, unsigned int cmd, unsigned long arg, struct file *file, unsigned int native_ctl)
277 struct sndrv_ctl_elem_value *data;
278 struct sndrv_ctl_elem_value32 *data32;
283 /* FIXME: check the sane ioctl.. */
285 data = kmalloc(sizeof(*data), GFP_KERNEL);
286 data32 = kmalloc(sizeof(*data32), GFP_KERNEL);
287 if (data == NULL || data32 == NULL) {
292 if (copy_from_user(data32, (void*)arg, sizeof(*data32))) {
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);
306 if (! data->indirect) {
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];
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];
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];
321 case SNDRV_CTL_ELEM_TYPE_BYTES:
322 memcpy(data->value.bytes.data, data32->value.bytes.data,
323 sizeof(data->value.bytes.data));
325 case SNDRV_CTL_ELEM_TYPE_IEC958:
326 data->value.iec958 = data32->value.iec958;
329 printk("unknown type %d\n", type);
336 err = file->f_op->ioctl(file->f_dentry->d_inode, file, native_ctl, (unsigned long)data);
340 /* restore info to 32bit */
341 if (! data->indirect) {
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];
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];
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];
356 case SNDRV_CTL_ELEM_TYPE_BYTES:
357 memcpy(data32->value.bytes.data, data->value.bytes.data,
358 sizeof(data->value.bytes.data));
360 case SNDRV_CTL_ELEM_TYPE_IEC958:
361 data32->value.iec958 = data->value.iec958;
368 if (copy_to_user((void*)arg, data32, sizeof(*data32)))
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);
384 #define AP(x) snd_ioctl32_##x
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),
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),
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[];
426 static void snd_ioctl32_done(void)
428 #if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
429 snd_ioctl32_unregister(seq_mappers);
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);
438 static int __init snd_ioctl32_init(void)
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);
451 module_init(snd_ioctl32_init)
452 module_exit(snd_ioctl32_done)