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 sndrv_ctl_elem_list32
{
31 unsigned char reserved
[50];
32 } /* don't set packed attribute here */;
34 static int snd_ctl_elem_list_compat(snd_card_t
*card
, struct sndrv_ctl_elem_list32 __user
*data32
)
36 struct sndrv_ctl_elem_list __user
*data
;
40 data
= compat_alloc_user_space(sizeof(*data
));
42 /* offset, space, used, count */
43 if (copy_in_user(data
, data32
, 4 * sizeof(u32
)))
46 if (get_user(ptr
, &data32
->pids
) ||
47 put_user(compat_ptr(ptr
), &data
->pids
))
49 err
= snd_ctl_elem_list(card
, data
);
53 if (copy_in_user(data32
, data
, 4 * sizeof(u32
)))
59 * control element info
60 * it uses union, so the things are not easy..
63 struct sndrv_ctl_elem_info32
{
64 struct sndrv_ctl_elem_id id
; // the size of struct is same
85 unsigned char reserved
[128];
87 unsigned char reserved
[64];
88 } __attribute__((packed
));
90 static int snd_ctl_elem_info_compat(snd_ctl_file_t
*ctl
, struct sndrv_ctl_elem_info32 __user
*data32
)
92 struct sndrv_ctl_elem_info
*data
;
95 data
= kcalloc(1, sizeof(*data
), GFP_KERNEL
);
101 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
103 /* we need to copy the item index.
104 * hope this doesn't break anything..
106 if (get_user(data
->value
.enumerated
.item
, &data32
->value
.enumerated
.item
))
108 err
= snd_ctl_elem_info(ctl
, data
);
111 /* restore info to 32bit */
113 /* id, type, access, count */
114 if (copy_to_user(&data32
->id
, &data
->id
, sizeof(data
->id
)) ||
115 copy_to_user(&data32
->type
, &data
->type
, 3 * sizeof(u32
)))
117 if (put_user(data
->owner
, &data32
->owner
))
119 switch (data
->type
) {
120 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
121 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
122 if (put_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
123 put_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
124 put_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
127 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
128 if (copy_to_user(&data32
->value
.integer64
,
129 &data
->value
.integer64
,
130 sizeof(data
->value
.integer64
)))
133 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
134 if (copy_to_user(&data32
->value
.enumerated
,
135 &data
->value
.enumerated
,
136 sizeof(data
->value
.enumerated
)))
149 struct sndrv_ctl_elem_value32
{
150 struct sndrv_ctl_elem_id id
;
151 unsigned int indirect
; /* bit-field causes misalignment */
154 unsigned char data
[512];
155 #ifndef CONFIG_X86_64
159 unsigned char reserved
[128];
163 /* get the value type and count of the control */
164 static int get_ctl_type(snd_card_t
*card
, snd_ctl_elem_id_t
*id
, int *countp
)
166 snd_kcontrol_t
*kctl
;
167 snd_ctl_elem_info_t info
;
170 down_read(&card
->controls_rwsem
);
171 kctl
= snd_ctl_find_id(card
, id
);
173 up_read(&card
->controls_rwsem
);
177 err
= kctl
->info(kctl
, &info
);
178 up_read(&card
->controls_rwsem
);
181 *countp
= info
.count
;
186 static int get_elem_size(int type
, int count
)
189 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
190 return sizeof(s64
) * count
;
191 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
192 return sizeof(int) * count
;
193 case SNDRV_CTL_ELEM_TYPE_BYTES
:
195 case SNDRV_CTL_ELEM_TYPE_IEC958
:
196 return sizeof(struct sndrv_aes_iec958
);
202 static int copy_ctl_value_from_user(snd_card_t
*card
,
203 struct sndrv_ctl_elem_value
*data
,
204 struct sndrv_ctl_elem_value32 __user
*data32
,
205 int *typep
, int *countp
)
207 int i
, type
, count
, size
;
208 unsigned int indirect
;
210 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)))
212 if (get_user(indirect
, &data32
->indirect
))
216 type
= get_ctl_type(card
, &data
->id
, &count
);
220 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
221 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
222 for (i
= 0; i
< count
; i
++) {
224 if (get_user(val
, &data32
->value
.integer
[i
]))
226 data
->value
.integer
.value
[i
] = val
;
229 size
= get_elem_size(type
, count
);
231 printk(KERN_ERR
"snd_ioctl32_ctl_elem_value: unknown type %d\n", type
);
234 if (copy_from_user(data
->value
.bytes
.data
,
235 data32
->value
.data
, size
))
244 /* restore the value to 32bit */
245 static int copy_ctl_value_to_user(struct sndrv_ctl_elem_value32 __user
*data32
,
246 struct sndrv_ctl_elem_value
*data
,
251 if (type
== SNDRV_CTL_ELEM_TYPE_BOOLEAN
||
252 type
== SNDRV_CTL_ELEM_TYPE_INTEGER
) {
253 for (i
= 0; i
< count
; i
++) {
255 val
= data
->value
.integer
.value
[i
];
256 if (put_user(val
, &data32
->value
.integer
[i
]))
260 size
= get_elem_size(type
, count
);
261 if (copy_to_user(data32
->value
.data
,
262 data
->value
.bytes
.data
, size
))
268 static int snd_ctl_elem_read_user_compat(snd_card_t
*card
,
269 struct sndrv_ctl_elem_value32 __user
*data32
)
271 struct sndrv_ctl_elem_value
*data
;
272 int err
, type
, count
;
274 data
= kcalloc(1, sizeof(*data
), GFP_KERNEL
);
278 if ((err
= copy_ctl_value_from_user(card
, data
, data32
, &type
, &count
)) < 0)
280 if ((err
= snd_ctl_elem_read(card
, data
)) < 0)
282 err
= copy_ctl_value_to_user(data32
, data
, type
, count
);
288 static int snd_ctl_elem_write_user_compat(snd_ctl_file_t
*file
,
289 struct sndrv_ctl_elem_value32 __user
*data32
)
291 struct sndrv_ctl_elem_value
*data
;
292 int err
, type
, count
;
294 data
= kcalloc(1, sizeof(*data
), GFP_KERNEL
);
298 if ((err
= copy_ctl_value_from_user(file
->card
, data
, data32
, &type
, &count
)) < 0)
300 if ((err
= snd_ctl_elem_write(file
->card
, file
, data
)) < 0)
302 err
= copy_ctl_value_to_user(data32
, data
, type
, count
);
308 /* add or replace a user control */
309 static int snd_ctl_elem_add_compat(snd_ctl_file_t
*file
,
310 struct sndrv_ctl_elem_info32 __user
*data32
,
313 struct sndrv_ctl_elem_info
*data
;
316 data
= kcalloc(1, sizeof(*data
), GFP_KERNEL
);
321 /* id, type, access, count */ \
322 if (copy_from_user(&data
->id
, &data32
->id
, sizeof(data
->id
)) ||
323 copy_from_user(&data
->type
, &data32
->type
, 3 * sizeof(u32
)))
325 if (get_user(data
->owner
, &data32
->owner
) ||
326 get_user(data
->type
, &data32
->type
))
328 switch (data
->type
) {
329 case SNDRV_CTL_ELEM_TYPE_BOOLEAN
:
330 case SNDRV_CTL_ELEM_TYPE_INTEGER
:
331 if (get_user(data
->value
.integer
.min
, &data32
->value
.integer
.min
) ||
332 get_user(data
->value
.integer
.max
, &data32
->value
.integer
.max
) ||
333 get_user(data
->value
.integer
.step
, &data32
->value
.integer
.step
))
336 case SNDRV_CTL_ELEM_TYPE_INTEGER64
:
337 if (copy_from_user(&data
->value
.integer64
,
338 &data32
->value
.integer64
,
339 sizeof(data
->value
.integer64
)))
342 case SNDRV_CTL_ELEM_TYPE_ENUMERATED
:
343 if (copy_from_user(&data
->value
.enumerated
,
344 &data32
->value
.enumerated
,
345 sizeof(data
->value
.enumerated
)))
351 err
= snd_ctl_elem_add(file
, data
, replace
);
358 SNDRV_CTL_IOCTL_ELEM_LIST32
= _IOWR('U', 0x10, struct sndrv_ctl_elem_list32
),
359 SNDRV_CTL_IOCTL_ELEM_INFO32
= _IOWR('U', 0x11, struct sndrv_ctl_elem_info32
),
360 SNDRV_CTL_IOCTL_ELEM_READ32
= _IOWR('U', 0x12, struct sndrv_ctl_elem_value32
),
361 SNDRV_CTL_IOCTL_ELEM_WRITE32
= _IOWR('U', 0x13, struct sndrv_ctl_elem_value32
),
362 SNDRV_CTL_IOCTL_ELEM_ADD32
= _IOWR('U', 0x17, struct sndrv_ctl_elem_info32
),
363 SNDRV_CTL_IOCTL_ELEM_REPLACE32
= _IOWR('U', 0x18, struct sndrv_ctl_elem_info32
),
366 static inline long snd_ctl_ioctl_compat(struct file
*file
, unsigned int cmd
, unsigned long arg
)
369 struct list_head
*list
;
370 void __user
*argp
= compat_ptr(arg
);
373 ctl
= file
->private_data
;
374 snd_assert(ctl
&& ctl
->card
, return -ENXIO
);
377 case SNDRV_CTL_IOCTL_PVERSION
:
378 case SNDRV_CTL_IOCTL_CARD_INFO
:
379 case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS
:
380 case SNDRV_CTL_IOCTL_POWER
:
381 case SNDRV_CTL_IOCTL_POWER_STATE
:
382 case SNDRV_CTL_IOCTL_ELEM_LOCK
:
383 case SNDRV_CTL_IOCTL_ELEM_UNLOCK
:
384 return snd_ctl_ioctl(file
, cmd
, (unsigned long)argp
);
385 case SNDRV_CTL_IOCTL_ELEM_LIST32
:
386 return snd_ctl_elem_list_compat(ctl
->card
, argp
);
387 case SNDRV_CTL_IOCTL_ELEM_INFO32
:
388 return snd_ctl_elem_info_compat(ctl
, argp
);
389 case SNDRV_CTL_IOCTL_ELEM_READ32
:
390 return snd_ctl_elem_read_user_compat(ctl
->card
, argp
);
391 case SNDRV_CTL_IOCTL_ELEM_WRITE32
:
392 return snd_ctl_elem_write_user_compat(ctl
, argp
);
393 case SNDRV_CTL_IOCTL_ELEM_ADD32
:
394 return snd_ctl_elem_add_compat(ctl
, argp
, 0);
395 case SNDRV_CTL_IOCTL_ELEM_REPLACE32
:
396 return snd_ctl_elem_add_compat(ctl
, argp
, 1);
399 down_read(&snd_ioctl_rwsem
);
400 list_for_each(list
, &snd_control_compat_ioctls
) {
401 snd_kctl_ioctl_t
*p
= list_entry(list
, snd_kctl_ioctl_t
, list
);
403 err
= p
->fioctl(ctl
->card
, ctl
, cmd
, arg
);
404 if (err
!= -ENOIOCTLCMD
) {
405 up_read(&snd_ioctl_rwsem
);
410 up_read(&snd_ioctl_rwsem
);