1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * compat ioctls for control API
5 * Copyright (c) by Takashi Iwai <tiwai@suse.de>
8 /* this file included from control.c */
10 #include <linux/compat.h>
11 #include <linux/slab.h>
13 struct snd_ctl_elem_list32
{
19 unsigned char reserved
[50];
20 } /* don't set packed attribute here */;
22 static int snd_ctl_elem_list_compat(struct snd_card
*card
,
23 struct snd_ctl_elem_list32 __user
*data32
)
25 struct snd_ctl_elem_list data
= {};
29 /* offset, space, used, count */
30 if (copy_from_user(&data
, data32
, 4 * sizeof(u32
)))
33 if (get_user(ptr
, &data32
->pids
))
35 data
.pids
= compat_ptr(ptr
);
36 err
= snd_ctl_elem_list(card
, &data
);
40 if (copy_to_user(data32
, &data
, 4 * sizeof(u32
)))
46 * control element info
47 * it uses union, so the things are not easy..
50 struct snd_ctl_elem_info32
{
51 struct snd_ctl_elem_id id
; // the size of struct is same
74 unsigned char reserved
[128];
76 unsigned char reserved
[64];
77 } __attribute__((packed
));
79 static int snd_ctl_elem_info_compat(struct snd_ctl_file
*ctl
,
80 struct snd_ctl_elem_info32 __user
*data32
)
82 struct snd_ctl_elem_info
*data
;
85 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
91 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
93 /* we need to copy the item index.
94 * hope this doesn't break anything..
96 if (get_user(data
->value
.enumerated
.item
, &data32
->value
.enumerated
.item
))
99 err
= snd_power_wait(ctl
->card
, SNDRV_CTL_POWER_D0
);
102 err
= snd_ctl_elem_info(ctl
, data
);
105 /* restore info to 32bit */
107 /* id, type, access, count */
108 if (copy_to_user(&data32
->id
, &data
->id
, sizeof(data
->id
)) ||
109 copy_to_user(&data32
->type
, &data
->type
, 3 * sizeof(u32
)))
111 if (put_user(data
->owner
, &data32
->owner
))
113 switch (data
->type
) {
114 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
115 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
116 if (put_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
117 put_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
118 put_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
121 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
122 if (copy_to_user(&data32
->value
.integer64
,
123 &data
->value
.integer64
,
124 sizeof(data
->value
.integer64
)))
127 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
128 if (copy_to_user(&data32
->value
.enumerated
,
129 &data
->value
.enumerated
,
130 sizeof(data
->value
.enumerated
)))
143 struct snd_ctl_elem_value32
{
144 struct snd_ctl_elem_id id
;
145 unsigned int indirect
; /* bit-field causes misalignment */
148 unsigned char data
[512];
149 #ifndef CONFIG_X86_64
153 unsigned char reserved
[128];
156 #ifdef CONFIG_X86_X32
157 /* x32 has a different alignment for 64bit values from ia32 */
158 struct snd_ctl_elem_value_x32
{
159 struct snd_ctl_elem_id id
;
160 unsigned int indirect
; /* bit-field causes misalignment */
163 unsigned char data
[512];
166 unsigned char reserved
[128];
168 #endif /* CONFIG_X86_X32 */
170 /* get the value type and count of the control */
171 static int get_ctl_type(struct snd_card
*card
, struct snd_ctl_elem_id
*id
,
174 struct snd_kcontrol
*kctl
;
175 struct snd_ctl_elem_info
*info
;
178 down_read(&card
->controls_rwsem
);
179 kctl
= snd_ctl_find_id(card
, id
);
181 up_read(&card
->controls_rwsem
);
184 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
186 up_read(&card
->controls_rwsem
);
190 err
= kctl
->info(kctl
, info
);
191 up_read(&card
->controls_rwsem
);
194 *countp
= info
->count
;
200 static int get_elem_size(int type
, int count
)
203 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
204 return sizeof(s64
) * count
;
205 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
206 return sizeof(int) * count
;
207 case SNDRV_CTL_ELEM_TYPE_BYTES
:
209 case SNDRV_CTL_ELEM_TYPE_IEC958
:
210 return sizeof(struct snd_aes_iec958
);
216 static int copy_ctl_value_from_user(struct snd_card
*card
,
217 struct snd_ctl_elem_value
*data
,
218 void __user
*userdata
,
220 int *typep
, int *countp
)
222 struct snd_ctl_elem_value32 __user
*data32
= userdata
;
225 unsigned int indirect
;
227 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
229 if (get_user(indirect
, &data32
->indirect
))
233 type
= get_ctl_type(card
, &data
->id
, &count
);
237 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
238 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
239 for (i
= 0; i
< count
; i
++) {
240 s32 __user
*intp
= valuep
;
242 if (get_user(val
, &intp
[i
]))
244 data
->value
.integer
.value
[i
] = val
;
247 size
= get_elem_size(type
, count
);
249 dev_err(card
->dev
, "snd_ioctl32_ctl_elem_value: unknown type %d\n", type
);
252 if (copy_from_user(data
->value
.bytes
.data
, valuep
, size
))
261 /* restore the value to 32bit */
262 static int copy_ctl_value_to_user(void __user
*userdata
,
264 struct snd_ctl_elem_value
*data
,
269 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
270 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
271 for (i
= 0; i
< count
; i
++) {
272 s32 __user
*intp
= valuep
;
274 val
= data
->value
.integer
.value
[i
];
275 if (put_user(val
, &intp
[i
]))
279 size
= get_elem_size(type
, count
);
280 if (copy_to_user(valuep
, data
->value
.bytes
.data
, size
))
286 static int ctl_elem_read_user(struct snd_card
*card
,
287 void __user
*userdata
, void __user
*valuep
)
289 struct snd_ctl_elem_value
*data
;
290 int err
, type
, count
;
292 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
296 err
= copy_ctl_value_from_user(card
, data
, userdata
, valuep
,
301 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
304 err
= snd_ctl_elem_read(card
, data
);
307 err
= copy_ctl_value_to_user(userdata
, valuep
, data
, type
, count
);
313 static int ctl_elem_write_user(struct snd_ctl_file
*file
,
314 void __user
*userdata
, void __user
*valuep
)
316 struct snd_ctl_elem_value
*data
;
317 struct snd_card
*card
= file
->card
;
318 int err
, type
, count
;
320 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
324 err
= copy_ctl_value_from_user(card
, data
, userdata
, valuep
,
329 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
332 err
= snd_ctl_elem_write(card
, file
, data
);
335 err
= copy_ctl_value_to_user(userdata
, valuep
, data
, type
, count
);
341 static int snd_ctl_elem_read_user_compat(struct snd_card
*card
,
342 struct snd_ctl_elem_value32 __user
*data32
)
344 return ctl_elem_read_user(card
, data32
, &data32
->value
);
347 static int snd_ctl_elem_write_user_compat(struct snd_ctl_file
*file
,
348 struct snd_ctl_elem_value32 __user
*data32
)
350 return ctl_elem_write_user(file
, data32
, &data32
->value
);
353 #ifdef CONFIG_X86_X32
354 static int snd_ctl_elem_read_user_x32(struct snd_card
*card
,
355 struct snd_ctl_elem_value_x32 __user
*data32
)
357 return ctl_elem_read_user(card
, data32
, &data32
->value
);
360 static int snd_ctl_elem_write_user_x32(struct snd_ctl_file
*file
,
361 struct snd_ctl_elem_value_x32 __user
*data32
)
363 return ctl_elem_write_user(file
, data32
, &data32
->value
);
365 #endif /* CONFIG_X86_X32 */
367 /* add or replace a user control */
368 static int snd_ctl_elem_add_compat(struct snd_ctl_file
*file
,
369 struct snd_ctl_elem_info32 __user
*data32
,
372 struct snd_ctl_elem_info
*data
;
375 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
380 /* id, type, access, count */ \
381 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)) ||
382 copy_from_user(&data
->type
, &data32
->type
, 3 * sizeof(u32
)))
384 if (get_user(data
->owner
, &data32
->owner
))
386 switch (data
->type
) {
387 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
388 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
389 if (get_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
390 get_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
391 get_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
394 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
395 if (copy_from_user(&data
->value
.integer64
,
396 &data32
->value
.integer64
,
397 sizeof(data
->value
.integer64
)))
400 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
401 if (copy_from_user(&data
->value
.enumerated
,
402 &data32
->value
.enumerated
,
403 sizeof(data
->value
.enumerated
)))
405 data
->value
.enumerated
.names_ptr
=
406 (uintptr_t)compat_ptr(data
->value
.enumerated
.names_ptr
);
411 err
= snd_ctl_elem_add(file
, data
, replace
);
418 SNDRV_CTL_IOCTL_ELEM_LIST32
= _IOWR('U', 0x10, struct snd_ctl_elem_list32
),
419 SNDRV_CTL_IOCTL_ELEM_INFO32
= _IOWR('U', 0x11, struct snd_ctl_elem_info32
),
420 SNDRV_CTL_IOCTL_ELEM_READ32
= _IOWR('U', 0x12, struct snd_ctl_elem_value32
),
421 SNDRV_CTL_IOCTL_ELEM_WRITE32
= _IOWR('U', 0x13, struct snd_ctl_elem_value32
),
422 SNDRV_CTL_IOCTL_ELEM_ADD32
= _IOWR('U', 0x17, struct snd_ctl_elem_info32
),
423 SNDRV_CTL_IOCTL_ELEM_REPLACE32
= _IOWR('U', 0x18, struct snd_ctl_elem_info32
),
424 #ifdef CONFIG_X86_X32
425 SNDRV_CTL_IOCTL_ELEM_READ_X32
= _IOWR('U', 0x12, struct snd_ctl_elem_value_x32
),
426 SNDRV_CTL_IOCTL_ELEM_WRITE_X32
= _IOWR('U', 0x13, struct snd_ctl_elem_value_x32
),
427 #endif /* CONFIG_X86_X32 */
430 static inline long snd_ctl_ioctl_compat(struct file
*file
, unsigned int cmd
, unsigned long arg
)
432 struct snd_ctl_file
*ctl
;
433 struct snd_kctl_ioctl
*p
;
434 void __user
*argp
= compat_ptr(arg
);
437 ctl
= file
->private_data
;
438 if (snd_BUG_ON(!ctl
|| !ctl
->card
))
442 case SNDRV_CTL_IOCTL_PVERSION
:
443 case SNDRV_CTL_IOCTL_CARD_INFO
:
444 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS
:
445 case SNDRV_CTL_IOCTL_POWER
:
446 case SNDRV_CTL_IOCTL_POWER_STATE
:
447 case SNDRV_CTL_IOCTL_ELEM_LOCK
:
448 case SNDRV_CTL_IOCTL_ELEM_UNLOCK
:
449 case SNDRV_CTL_IOCTL_ELEM_REMOVE
:
450 case SNDRV_CTL_IOCTL_TLV_READ
:
451 case SNDRV_CTL_IOCTL_TLV_WRITE
:
452 case SNDRV_CTL_IOCTL_TLV_COMMAND
:
453 return snd_ctl_ioctl(file
, cmd
, (unsigned long)argp
);
454 case SNDRV_CTL_IOCTL_ELEM_LIST32
:
455 return snd_ctl_elem_list_compat(ctl
->card
, argp
);
456 case SNDRV_CTL_IOCTL_ELEM_INFO32
:
457 return snd_ctl_elem_info_compat(ctl
, argp
);
458 case SNDRV_CTL_IOCTL_ELEM_READ32
:
459 return snd_ctl_elem_read_user_compat(ctl
->card
, argp
);
460 case SNDRV_CTL_IOCTL_ELEM_WRITE32
:
461 return snd_ctl_elem_write_user_compat(ctl
, argp
);
462 case SNDRV_CTL_IOCTL_ELEM_ADD32
:
463 return snd_ctl_elem_add_compat(ctl
, argp
, 0);
464 case SNDRV_CTL_IOCTL_ELEM_REPLACE32
:
465 return snd_ctl_elem_add_compat(ctl
, argp
, 1);
466 #ifdef CONFIG_X86_X32
467 case SNDRV_CTL_IOCTL_ELEM_READ_X32
:
468 return snd_ctl_elem_read_user_x32(ctl
->card
, argp
);
469 case SNDRV_CTL_IOCTL_ELEM_WRITE_X32
:
470 return snd_ctl_elem_write_user_x32(ctl
, argp
);
471 #endif /* CONFIG_X86_X32 */
474 down_read(&snd_ioctl_rwsem
);
475 list_for_each_entry(p
, &snd_control_compat_ioctls
, list
) {
477 err
= p
->fioctl(ctl
->card
, ctl
, cmd
, arg
);
478 if (err
!= -ENOIOCTLCMD
) {
479 up_read(&snd_ioctl_rwsem
);
484 up_read(&snd_ioctl_rwsem
);