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 <asm/uaccess.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
)
49 struct ioctl32_mapper
*m
;
51 for (m
= mappers
; m
->cmd
; m
++) {
52 err
= register_ioctl32_conversion(m
->cmd
, m
->handler
);
59 void snd_ioctl32_unregister(struct ioctl32_mapper
*mappers
)
61 struct ioctl32_mapper
*m
;
63 for (m
= mappers
; m
->cmd
; m
++) {
65 unregister_ioctl32_conversion(m
->cmd
);
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
)
79 return filp
->f_op
->ioctl(filp
->f_dentry
->d_inode
, filp
, cmd
, arg
);
87 struct sndrv_ctl_elem_list32
{
93 unsigned char reserved
[50];
94 } /* don't set packed attribute here */;
96 #define CVT_sndrv_ctl_elem_list()\
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
;
112 if (copy_from_user(&data32
, (void __user
*)arg
, sizeof(data32
)))
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
);
122 err
= file
->f_op
->ioctl(file
->f_dentry
->d_inode
, file
, native_ctl
, (unsigned long)&data
);
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
)))
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
166 unsigned char reserved
[128];
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
;
178 if (copy_from_user(&data32
, (void __user
*)arg
, sizeof(data32
)))
180 memset(&data
, 0, sizeof(data
));
182 /* we need to copy the item index.
183 * hope this doesn't break anything..
185 data
.value
.enumerated
.item
= data32
.value
.enumerated
.item
;
188 err
= file
->f_op
->ioctl(file
->f_dentry
->d_inode
, file
, native_ctl
, (unsigned long)&data
);
192 /* restore info to 32bit */
194 data32
.type
= data
.type
;
195 data32
.access
= data
.access
;
196 data32
.count
= data
.count
;
197 data32
.owner
= data
.owner
;
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
;
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
;
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
));
219 if (copy_to_user((void __user
*)arg
, &data32
, sizeof(data32
)))
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 */
243 unsigned char data
[512];
246 struct sndrv_aes_iec958 iec958
;
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
)
256 snd_kcontrol_t
*kctl
;
257 snd_ctl_elem_info_t info
;
260 ctl
= file
->private_data
;
262 down_read(&ctl
->card
->controls_rwsem
);
263 kctl
= snd_ctl_find_id(ctl
->card
, id
);
265 up_read(&ctl
->card
->controls_rwsem
);
269 err
= kctl
->info(kctl
, &info
);
270 up_read(&ctl
->card
->controls_rwsem
);
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
;
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
) {
294 if (copy_from_user(data32
, (void __user
*)arg
, sizeof(*data32
))) {
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
);
308 if (! data
->indirect
) {
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
];
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
];
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
];
323 case SNDRV_CTL_ELEM_TYPE_BYTES
:
324 memcpy(data
->value
.bytes
.data
, data32
->value
.bytes
.data
,
325 sizeof(data
->value
.bytes
.data
));
327 case SNDRV_CTL_ELEM_TYPE_IEC958
:
328 data
->value
.iec958
= data32
->value
.iec958
;
331 printk("unknown type %d\n", type
);
338 err
= file
->f_op
->ioctl(file
->f_dentry
->d_inode
, file
, native_ctl
, (unsigned long)data
);
342 /* restore info to 32bit */
343 if (! data
->indirect
) {
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
];
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
];
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
];
358 case SNDRV_CTL_ELEM_TYPE_BYTES
:
359 memcpy(data32
->value
.bytes
.data
, data
->value
.bytes
.data
,
360 sizeof(data
->value
.bytes
.data
));
362 case SNDRV_CTL_ELEM_TYPE_IEC958
:
363 data32
->value
.iec958
= data
->value
.iec958
;
370 if (copy_to_user((void __user
*)arg
, data32
, sizeof(*data32
)))
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
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
),
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
[];
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
);
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
);
453 module_init(snd_ioctl32_init
)
454 module_exit(snd_ioctl32_done
)