2 * compat ioctls for control API
4 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 /* this file included from control.c */
23 #include <linux/compat.h>
24 #include <linux/slab.h>
26 struct snd_ctl_elem_list32
{
32 unsigned char reserved
[50];
33 } /* don't set packed attribute here */;
35 static int snd_ctl_elem_list_compat(struct snd_card
*card
,
36 struct snd_ctl_elem_list32 __user
*data32
)
38 struct snd_ctl_elem_list __user
*data
;
42 data
= compat_alloc_user_space(sizeof(*data
));
44 /* offset, space, used, count */
45 if (copy_in_user(data
, data32
, 4 * sizeof(u32
)))
48 if (get_user(ptr
, &data32
->pids
) ||
49 put_user(compat_ptr(ptr
), &data
->pids
))
51 err
= snd_ctl_elem_list(card
, data
);
55 if (copy_in_user(data32
, data
, 4 * sizeof(u32
)))
61 * control element info
62 * it uses union, so the things are not easy..
65 struct snd_ctl_elem_info32
{
66 struct snd_ctl_elem_id id
; // the size of struct is same
89 unsigned char reserved
[128];
91 unsigned char reserved
[64];
92 } __attribute__((packed
));
94 static int snd_ctl_elem_info_compat(struct snd_ctl_file
*ctl
,
95 struct snd_ctl_elem_info32 __user
*data32
)
97 struct snd_ctl_elem_info
*data
;
100 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
106 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
108 /* we need to copy the item index.
109 * hope this doesn't break anything..
111 if (get_user(data
->value
.enumerated
.item
, &data32
->value
.enumerated
.item
))
114 snd_power_lock(ctl
->card
);
115 err
= snd_power_wait(ctl
->card
, SNDRV_CTL_POWER_D0
);
117 err
= snd_ctl_elem_info(ctl
, data
);
118 snd_power_unlock(ctl
->card
);
122 /* restore info to 32bit */
124 /* id, type, access, count */
125 if (copy_to_user(&data32
->id
, &data
->id
, sizeof(data
->id
)) ||
126 copy_to_user(&data32
->type
, &data
->type
, 3 * sizeof(u32
)))
128 if (put_user(data
->owner
, &data32
->owner
))
130 switch (data
->type
) {
131 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
132 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
133 if (put_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
134 put_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
135 put_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
138 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
139 if (copy_to_user(&data32
->value
.integer64
,
140 &data
->value
.integer64
,
141 sizeof(data
->value
.integer64
)))
144 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
145 if (copy_to_user(&data32
->value
.enumerated
,
146 &data
->value
.enumerated
,
147 sizeof(data
->value
.enumerated
)))
160 struct snd_ctl_elem_value32
{
161 struct snd_ctl_elem_id id
;
162 unsigned int indirect
; /* bit-field causes misalignment */
165 unsigned char data
[512];
166 #ifndef CONFIG_X86_64
170 unsigned char reserved
[128];
173 #ifdef CONFIG_X86_X32
174 /* x32 has a different alignment for 64bit values from ia32 */
175 struct snd_ctl_elem_value_x32
{
176 struct snd_ctl_elem_id id
;
177 unsigned int indirect
; /* bit-field causes misalignment */
180 unsigned char data
[512];
183 unsigned char reserved
[128];
185 #endif /* CONFIG_X86_X32 */
187 /* get the value type and count of the control */
188 static int get_ctl_type(struct snd_card
*card
, struct snd_ctl_elem_id
*id
,
191 struct snd_kcontrol
*kctl
;
192 struct snd_ctl_elem_info
*info
;
195 down_read(&card
->controls_rwsem
);
196 kctl
= snd_ctl_find_id(card
, id
);
198 up_read(&card
->controls_rwsem
);
201 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
203 up_read(&card
->controls_rwsem
);
207 err
= kctl
->info(kctl
, info
);
208 up_read(&card
->controls_rwsem
);
211 *countp
= info
->count
;
217 static int get_elem_size(int type
, int count
)
220 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
221 return sizeof(s64
) * count
;
222 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
223 return sizeof(int) * count
;
224 case SNDRV_CTL_ELEM_TYPE_BYTES
:
226 case SNDRV_CTL_ELEM_TYPE_IEC958
:
227 return sizeof(struct snd_aes_iec958
);
233 static int copy_ctl_value_from_user(struct snd_card
*card
,
234 struct snd_ctl_elem_value
*data
,
235 void __user
*userdata
,
237 int *typep
, int *countp
)
239 struct snd_ctl_elem_value32 __user
*data32
= userdata
;
241 int uninitialized_var(count
);
242 unsigned int indirect
;
244 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
246 if (get_user(indirect
, &data32
->indirect
))
250 type
= get_ctl_type(card
, &data
->id
, &count
);
254 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
255 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
256 for (i
= 0; i
< count
; i
++) {
257 s32 __user
*intp
= valuep
;
259 if (get_user(val
, &intp
[i
]))
261 data
->value
.integer
.value
[i
] = val
;
264 size
= get_elem_size(type
, count
);
266 dev_err(card
->dev
, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type
);
269 if (copy_from_user(data
->value
.bytes
.data
, valuep
, size
))
278 /* restore the value to 32bit */
279 static int copy_ctl_value_to_user(void __user
*userdata
,
281 struct snd_ctl_elem_value
*data
,
286 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
287 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
288 for (i
= 0; i
< count
; i
++) {
289 s32 __user
*intp
= valuep
;
291 val
= data
->value
.integer
.value
[i
];
292 if (put_user(val
, &intp
[i
]))
296 size
= get_elem_size(type
, count
);
297 if (copy_to_user(valuep
, data
->value
.bytes
.data
, size
))
303 static int ctl_elem_read_user(struct snd_card
*card
,
304 void __user
*userdata
, void __user
*valuep
)
306 struct snd_ctl_elem_value
*data
;
307 int err
, type
, count
;
309 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
313 err
= copy_ctl_value_from_user(card
, data
, userdata
, valuep
,
318 snd_power_lock(card
);
319 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
321 err
= snd_ctl_elem_read(card
, data
);
322 snd_power_unlock(card
);
324 err
= copy_ctl_value_to_user(userdata
, valuep
, data
,
331 static int ctl_elem_write_user(struct snd_ctl_file
*file
,
332 void __user
*userdata
, void __user
*valuep
)
334 struct snd_ctl_elem_value
*data
;
335 struct snd_card
*card
= file
->card
;
336 int err
, type
, count
;
338 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
342 err
= copy_ctl_value_from_user(card
, data
, userdata
, valuep
,
347 snd_power_lock(card
);
348 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
350 err
= snd_ctl_elem_write(card
, file
, data
);
351 snd_power_unlock(card
);
353 err
= copy_ctl_value_to_user(userdata
, valuep
, data
,
360 static int snd_ctl_elem_read_user_compat(struct snd_card
*card
,
361 struct snd_ctl_elem_value32 __user
*data32
)
363 return ctl_elem_read_user(card
, data32
, &data32
->value
);
366 static int snd_ctl_elem_write_user_compat(struct snd_ctl_file
*file
,
367 struct snd_ctl_elem_value32 __user
*data32
)
369 return ctl_elem_write_user(file
, data32
, &data32
->value
);
372 #ifdef CONFIG_X86_X32
373 static int snd_ctl_elem_read_user_x32(struct snd_card
*card
,
374 struct snd_ctl_elem_value_x32 __user
*data32
)
376 return ctl_elem_read_user(card
, data32
, &data32
->value
);
379 static int snd_ctl_elem_write_user_x32(struct snd_ctl_file
*file
,
380 struct snd_ctl_elem_value_x32 __user
*data32
)
382 return ctl_elem_write_user(file
, data32
, &data32
->value
);
384 #endif /* CONFIG_X86_X32 */
386 /* add or replace a user control */
387 static int snd_ctl_elem_add_compat(struct snd_ctl_file
*file
,
388 struct snd_ctl_elem_info32 __user
*data32
,
391 struct snd_ctl_elem_info
*data
;
394 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
399 /* id, type, access, count */ \
400 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)) ||
401 copy_from_user(&data
->type
, &data32
->type
, 3 * sizeof(u32
)))
403 if (get_user(data
->owner
, &data32
->owner
) ||
404 get_user(data
->type
, &data32
->type
))
406 switch (data
->type
) {
407 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
408 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
409 if (get_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
410 get_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
411 get_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
414 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
415 if (copy_from_user(&data
->value
.integer64
,
416 &data32
->value
.integer64
,
417 sizeof(data
->value
.integer64
)))
420 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
421 if (copy_from_user(&data
->value
.enumerated
,
422 &data32
->value
.enumerated
,
423 sizeof(data
->value
.enumerated
)))
425 data
->value
.enumerated
.names_ptr
=
426 (uintptr_t)compat_ptr(data
->value
.enumerated
.names_ptr
);
431 err
= snd_ctl_elem_add(file
, data
, replace
);
438 SNDRV_CTL_IOCTL_ELEM_LIST32
= _IOWR('U', 0x10, struct snd_ctl_elem_list32
),
439 SNDRV_CTL_IOCTL_ELEM_INFO32
= _IOWR('U', 0x11, struct snd_ctl_elem_info32
),
440 SNDRV_CTL_IOCTL_ELEM_READ32
= _IOWR('U', 0x12, struct snd_ctl_elem_value32
),
441 SNDRV_CTL_IOCTL_ELEM_WRITE32
= _IOWR('U', 0x13, struct snd_ctl_elem_value32
),
442 SNDRV_CTL_IOCTL_ELEM_ADD32
= _IOWR('U', 0x17, struct snd_ctl_elem_info32
),
443 SNDRV_CTL_IOCTL_ELEM_REPLACE32
= _IOWR('U', 0x18, struct snd_ctl_elem_info32
),
444 #ifdef CONFIG_X86_X32
445 SNDRV_CTL_IOCTL_ELEM_READ_X32
= _IOWR('U', 0x12, struct snd_ctl_elem_value_x32
),
446 SNDRV_CTL_IOCTL_ELEM_WRITE_X32
= _IOWR('U', 0x13, struct snd_ctl_elem_value_x32
),
447 #endif /* CONFIG_X86_X32 */
450 static inline long snd_ctl_ioctl_compat(struct file
*file
, unsigned int cmd
, unsigned long arg
)
452 struct snd_ctl_file
*ctl
;
453 struct snd_kctl_ioctl
*p
;
454 void __user
*argp
= compat_ptr(arg
);
457 ctl
= file
->private_data
;
458 if (snd_BUG_ON(!ctl
|| !ctl
->card
))
462 case SNDRV_CTL_IOCTL_PVERSION
:
463 case SNDRV_CTL_IOCTL_CARD_INFO
:
464 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS
:
465 case SNDRV_CTL_IOCTL_POWER
:
466 case SNDRV_CTL_IOCTL_POWER_STATE
:
467 case SNDRV_CTL_IOCTL_ELEM_LOCK
:
468 case SNDRV_CTL_IOCTL_ELEM_UNLOCK
:
469 case SNDRV_CTL_IOCTL_ELEM_REMOVE
:
470 case SNDRV_CTL_IOCTL_TLV_READ
:
471 case SNDRV_CTL_IOCTL_TLV_WRITE
:
472 case SNDRV_CTL_IOCTL_TLV_COMMAND
:
473 return snd_ctl_ioctl(file
, cmd
, (unsigned long)argp
);
474 case SNDRV_CTL_IOCTL_ELEM_LIST32
:
475 return snd_ctl_elem_list_compat(ctl
->card
, argp
);
476 case SNDRV_CTL_IOCTL_ELEM_INFO32
:
477 return snd_ctl_elem_info_compat(ctl
, argp
);
478 case SNDRV_CTL_IOCTL_ELEM_READ32
:
479 return snd_ctl_elem_read_user_compat(ctl
->card
, argp
);
480 case SNDRV_CTL_IOCTL_ELEM_WRITE32
:
481 return snd_ctl_elem_write_user_compat(ctl
, argp
);
482 case SNDRV_CTL_IOCTL_ELEM_ADD32
:
483 return snd_ctl_elem_add_compat(ctl
, argp
, 0);
484 case SNDRV_CTL_IOCTL_ELEM_REPLACE32
:
485 return snd_ctl_elem_add_compat(ctl
, argp
, 1);
486 #ifdef CONFIG_X86_X32
487 case SNDRV_CTL_IOCTL_ELEM_READ_X32
:
488 return snd_ctl_elem_read_user_x32(ctl
->card
, argp
);
489 case SNDRV_CTL_IOCTL_ELEM_WRITE_X32
:
490 return snd_ctl_elem_write_user_x32(ctl
, argp
);
491 #endif /* CONFIG_X86_X32 */
494 down_read(&snd_ioctl_rwsem
);
495 list_for_each_entry(p
, &snd_control_compat_ioctls
, list
) {
497 err
= p
->fioctl(ctl
->card
, ctl
, cmd
, arg
);
498 if (err
!= -ENOIOCTLCMD
) {
499 up_read(&snd_ioctl_rwsem
);
504 up_read(&snd_ioctl_rwsem
);