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>
25 struct snd_ctl_elem_list32
{
31 unsigned char reserved
[50];
32 } /* don't set packed attribute here */;
34 static int snd_ctl_elem_list_compat(struct snd_card
*card
,
35 struct snd_ctl_elem_list32 __user
*data32
)
37 struct snd_ctl_elem_list __user
*data
;
41 data
= compat_alloc_user_space(sizeof(*data
));
43 /* offset, space, used, count */
44 if (copy_in_user(data
, data32
, 4 * sizeof(u32
)))
47 if (get_user(ptr
, &data32
->pids
) ||
48 put_user(compat_ptr(ptr
), &data
->pids
))
50 err
= snd_ctl_elem_list(card
, data
);
54 if (copy_in_user(data32
, data
, 4 * sizeof(u32
)))
60 * control element info
61 * it uses union, so the things are not easy..
64 struct snd_ctl_elem_info32
{
65 struct snd_ctl_elem_id id
; // the size of struct is same
86 unsigned char reserved
[128];
88 unsigned char reserved
[64];
89 } __attribute__((packed
));
91 static int snd_ctl_elem_info_compat(struct snd_ctl_file
*ctl
,
92 struct snd_ctl_elem_info32 __user
*data32
)
94 struct snd_ctl_elem_info
*data
;
97 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
103 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
105 /* we need to copy the item index.
106 * hope this doesn't break anything..
108 if (get_user(data
->value
.enumerated
.item
, &data32
->value
.enumerated
.item
))
111 snd_power_lock(ctl
->card
);
112 err
= snd_power_wait(ctl
->card
, SNDRV_CTL_POWER_D0
);
114 err
= snd_ctl_elem_info(ctl
, data
);
115 snd_power_unlock(ctl
->card
);
119 /* restore info to 32bit */
121 /* id, type, access, count */
122 if (copy_to_user(&data32
->id
, &data
->id
, sizeof(data
->id
)) ||
123 copy_to_user(&data32
->type
, &data
->type
, 3 * sizeof(u32
)))
125 if (put_user(data
->owner
, &data32
->owner
))
127 switch (data
->type
) {
128 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
129 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
130 if (put_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
131 put_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
132 put_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
135 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
136 if (copy_to_user(&data32
->value
.integer64
,
137 &data
->value
.integer64
,
138 sizeof(data
->value
.integer64
)))
141 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
142 if (copy_to_user(&data32
->value
.enumerated
,
143 &data
->value
.enumerated
,
144 sizeof(data
->value
.enumerated
)))
157 struct snd_ctl_elem_value32
{
158 struct snd_ctl_elem_id id
;
159 unsigned int indirect
; /* bit-field causes misalignment */
162 unsigned char data
[512];
163 #ifndef CONFIG_X86_64
167 unsigned char reserved
[128];
171 /* get the value type and count of the control */
172 static int get_ctl_type(struct snd_card
*card
, struct snd_ctl_elem_id
*id
,
175 struct snd_kcontrol
*kctl
;
176 struct snd_ctl_elem_info
*info
;
179 down_read(&card
->controls_rwsem
);
180 kctl
= snd_ctl_find_id(card
, id
);
182 up_read(&card
->controls_rwsem
);
185 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
187 up_read(&card
->controls_rwsem
);
191 err
= kctl
->info(kctl
, info
);
192 up_read(&card
->controls_rwsem
);
195 *countp
= info
->count
;
201 static int get_elem_size(int type
, int count
)
204 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
205 return sizeof(s64
) * count
;
206 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
207 return sizeof(int) * count
;
208 case SNDRV_CTL_ELEM_TYPE_BYTES
:
210 case SNDRV_CTL_ELEM_TYPE_IEC958
:
211 return sizeof(struct snd_aes_iec958
);
217 static int copy_ctl_value_from_user(struct snd_card
*card
,
218 struct snd_ctl_elem_value
*data
,
219 struct snd_ctl_elem_value32 __user
*data32
,
220 int *typep
, int *countp
)
223 int uninitialized_var(count
);
224 unsigned int indirect
;
226 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
228 if (get_user(indirect
, &data32
->indirect
))
232 type
= get_ctl_type(card
, &data
->id
, &count
);
236 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
237 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
238 for (i
= 0; i
< count
; i
++) {
240 if (get_user(val
, &data32
->value
.integer
[i
]))
242 data
->value
.integer
.value
[i
] = val
;
245 size
= get_elem_size(type
, count
);
247 printk(KERN_ERR
"snd_ioctl32_ctl_elem_value: unknown type %d\n", type
);
250 if (copy_from_user(data
->value
.bytes
.data
,
251 data32
->value
.data
, size
))
260 /* restore the value to 32bit */
261 static int copy_ctl_value_to_user(struct snd_ctl_elem_value32 __user
*data32
,
262 struct snd_ctl_elem_value
*data
,
267 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
268 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
269 for (i
= 0; i
< count
; i
++) {
271 val
= data
->value
.integer
.value
[i
];
272 if (put_user(val
, &data32
->value
.integer
[i
]))
276 size
= get_elem_size(type
, count
);
277 if (copy_to_user(data32
->value
.data
,
278 data
->value
.bytes
.data
, size
))
284 static int snd_ctl_elem_read_user_compat(struct snd_card
*card
,
285 struct snd_ctl_elem_value32 __user
*data32
)
287 struct snd_ctl_elem_value
*data
;
288 int err
, type
, count
;
290 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
294 if ((err
= copy_ctl_value_from_user(card
, data
, data32
, &type
, &count
)) < 0)
297 snd_power_lock(card
);
298 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
300 err
= snd_ctl_elem_read(card
, data
);
301 snd_power_unlock(card
);
303 err
= copy_ctl_value_to_user(data32
, data
, type
, count
);
309 static int snd_ctl_elem_write_user_compat(struct snd_ctl_file
*file
,
310 struct snd_ctl_elem_value32 __user
*data32
)
312 struct snd_ctl_elem_value
*data
;
313 struct snd_card
*card
= file
->card
;
314 int err
, type
, count
;
316 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
320 if ((err
= copy_ctl_value_from_user(card
, data
, data32
, &type
, &count
)) < 0)
323 snd_power_lock(card
);
324 err
= snd_power_wait(card
, SNDRV_CTL_POWER_D0
);
326 err
= snd_ctl_elem_write(card
, file
, data
);
327 snd_power_unlock(card
);
329 err
= copy_ctl_value_to_user(data32
, data
, type
, count
);
335 /* add or replace a user control */
336 static int snd_ctl_elem_add_compat(struct snd_ctl_file
*file
,
337 struct snd_ctl_elem_info32 __user
*data32
,
340 struct snd_ctl_elem_info
*data
;
343 data
= kzalloc(sizeof(*data
), GFP_KERNEL
);
348 /* id, type, access, count */ \
349 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)) ||
350 copy_from_user(&data
->type
, &data32
->type
, 3 * sizeof(u32
)))
352 if (get_user(data
->owner
, &data32
->owner
) ||
353 get_user(data
->type
, &data32
->type
))
355 switch (data
->type
) {
356 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
357 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
358 if (get_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
359 get_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
360 get_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
363 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
364 if (copy_from_user(&data
->value
.integer64
,
365 &data32
->value
.integer64
,
366 sizeof(data
->value
.integer64
)))
369 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
370 if (copy_from_user(&data
->value
.enumerated
,
371 &data32
->value
.enumerated
,
372 sizeof(data
->value
.enumerated
)))
378 err
= snd_ctl_elem_add(file
, data
, replace
);
385 SNDRV_CTL_IOCTL_ELEM_LIST32
= _IOWR('U', 0x10, struct snd_ctl_elem_list32
),
386 SNDRV_CTL_IOCTL_ELEM_INFO32
= _IOWR('U', 0x11, struct snd_ctl_elem_info32
),
387 SNDRV_CTL_IOCTL_ELEM_READ32
= _IOWR('U', 0x12, struct snd_ctl_elem_value32
),
388 SNDRV_CTL_IOCTL_ELEM_WRITE32
= _IOWR('U', 0x13, struct snd_ctl_elem_value32
),
389 SNDRV_CTL_IOCTL_ELEM_ADD32
= _IOWR('U', 0x17, struct snd_ctl_elem_info32
),
390 SNDRV_CTL_IOCTL_ELEM_REPLACE32
= _IOWR('U', 0x18, struct snd_ctl_elem_info32
),
393 static inline long snd_ctl_ioctl_compat(struct file
*file
, unsigned int cmd
, unsigned long arg
)
395 struct snd_ctl_file
*ctl
;
396 struct snd_kctl_ioctl
*p
;
397 void __user
*argp
= compat_ptr(arg
);
400 ctl
= file
->private_data
;
401 if (snd_BUG_ON(!ctl
|| !ctl
->card
))
405 case SNDRV_CTL_IOCTL_PVERSION
:
406 case SNDRV_CTL_IOCTL_CARD_INFO
:
407 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS
:
408 case SNDRV_CTL_IOCTL_POWER
:
409 case SNDRV_CTL_IOCTL_POWER_STATE
:
410 case SNDRV_CTL_IOCTL_ELEM_LOCK
:
411 case SNDRV_CTL_IOCTL_ELEM_UNLOCK
:
412 case SNDRV_CTL_IOCTL_ELEM_REMOVE
:
413 case SNDRV_CTL_IOCTL_TLV_READ
:
414 case SNDRV_CTL_IOCTL_TLV_WRITE
:
415 case SNDRV_CTL_IOCTL_TLV_COMMAND
:
416 return snd_ctl_ioctl(file
, cmd
, (unsigned long)argp
);
417 case SNDRV_CTL_IOCTL_ELEM_LIST32
:
418 return snd_ctl_elem_list_compat(ctl
->card
, argp
);
419 case SNDRV_CTL_IOCTL_ELEM_INFO32
:
420 return snd_ctl_elem_info_compat(ctl
, argp
);
421 case SNDRV_CTL_IOCTL_ELEM_READ32
:
422 return snd_ctl_elem_read_user_compat(ctl
->card
, argp
);
423 case SNDRV_CTL_IOCTL_ELEM_WRITE32
:
424 return snd_ctl_elem_write_user_compat(ctl
, argp
);
425 case SNDRV_CTL_IOCTL_ELEM_ADD32
:
426 return snd_ctl_elem_add_compat(ctl
, argp
, 0);
427 case SNDRV_CTL_IOCTL_ELEM_REPLACE32
:
428 return snd_ctl_elem_add_compat(ctl
, argp
, 1);
431 down_read(&snd_ioctl_rwsem
);
432 list_for_each_entry(p
, &snd_control_compat_ioctls
, list
) {
434 err
= p
->fioctl(ctl
->card
, ctl
, cmd
, arg
);
435 if (err
!= -ENOIOCTLCMD
) {
436 up_read(&snd_ioctl_rwsem
);
441 up_read(&snd_ioctl_rwsem
);