[media] V4L: remove V4L1 compatibility mode
[deliverable/linux.git] / drivers / media / video / v4l2-compat-ioctl32.c
CommitLineData
cf664a64
PDM
1/*
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
4 *
5 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
6 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
a2531293 8 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
cf664a64 9 * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
92f45bad 10 * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
cf664a64
PDM
11 *
12 * These routines maintain argument size conversion between 32bit and 64bit
13 * ioctls.
14 */
15
0d0fbf81 16#include <linux/compat.h>
92f45bad 17#define __OLD_VIDIOC_ /* To allow fixing old calls*/
0d0fbf81 18#include <linux/videodev.h>
cf664a64 19#include <linux/videodev2.h>
133b7354 20#include <linux/module.h>
2864462e 21#include <media/v4l2-ioctl.h>
0d0fbf81
AB
22
23#ifdef CONFIG_COMPAT
a113bc78 24
069b7479 25static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
92f45bad 26{
069b7479 27 long ret = -ENOIOCTLCMD;
92f45bad
HV
28
29 if (file->f_op->unlocked_ioctl)
30 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
92f45bad
HV
31
32 return ret;
33}
34
35
d1f81da2 36struct v4l2_clip32 {
cf664a64
PDM
37 struct v4l2_rect c;
38 compat_caddr_t next;
39};
40
d1f81da2 41struct v4l2_window32 {
cf664a64
PDM
42 struct v4l2_rect w;
43 enum v4l2_field field;
44 __u32 chromakey;
45 compat_caddr_t clips; /* actually struct v4l2_clip32 * */
46 __u32 clipcount;
47 compat_caddr_t bitmap;
48};
49
50static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
51{
a113bc78
GM
52 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
53 copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
54 get_user(kp->field, &up->field) ||
55 get_user(kp->chromakey, &up->chromakey) ||
56 get_user(kp->clipcount, &up->clipcount))
57 return -EFAULT;
cf664a64
PDM
58 if (kp->clipcount > 2048)
59 return -EINVAL;
60 if (kp->clipcount) {
5b1a43d7
AV
61 struct v4l2_clip32 __user *uclips;
62 struct v4l2_clip __user *kclips;
cf664a64 63 int n = kp->clipcount;
5b1a43d7 64 compat_caddr_t p;
cf664a64 65
5b1a43d7
AV
66 if (get_user(p, &up->clips))
67 return -EFAULT;
68 uclips = compat_ptr(p);
cf664a64
PDM
69 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
70 kp->clips = kclips;
71 while (--n >= 0) {
5b1a43d7
AV
72 if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
73 return -EFAULT;
74 if (put_user(n ? kclips + 1 : NULL, &kclips->next))
a113bc78 75 return -EFAULT;
cf664a64
PDM
76 uclips += 1;
77 kclips += 1;
78 }
79 } else
5b1a43d7 80 kp->clips = NULL;
cf664a64
PDM
81 return 0;
82}
83
84static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
85{
f2e6c6ad 86 if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
a113bc78
GM
87 put_user(kp->field, &up->field) ||
88 put_user(kp->chromakey, &up->chromakey) ||
89 put_user(kp->clipcount, &up->clipcount))
90 return -EFAULT;
cf664a64
PDM
91 return 0;
92}
93
94static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
95{
5b1a43d7
AV
96 if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
97 return -EFAULT;
a113bc78 98 return 0;
cf664a64
PDM
99}
100
101static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
102{
5b1a43d7
AV
103 if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
104 return -EFAULT;
a113bc78 105 return 0;
cf664a64
PDM
106}
107
108static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
109{
5b1a43d7
AV
110 if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
111 return -EFAULT;
a113bc78 112 return 0;
cf664a64
PDM
113}
114
115static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
116{
5b1a43d7
AV
117 if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
118 return -EFAULT;
a113bc78 119 return 0;
cf664a64
PDM
120}
121
92f45bad
HV
122static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
123{
124 if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
125 return -EFAULT;
126 return 0;
127}
128
129static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
130{
131 if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
132 return -EFAULT;
133 return 0;
134}
135
d1f81da2 136struct v4l2_format32 {
cf664a64 137 enum v4l2_buf_type type;
d1f81da2 138 union {
92f45bad
HV
139 struct v4l2_pix_format pix;
140 struct v4l2_window32 win;
141 struct v4l2_vbi_format vbi;
142 struct v4l2_sliced_vbi_format sliced;
d1f81da2 143 __u8 raw_data[200]; /* user-defined */
cf664a64
PDM
144 } fmt;
145};
146
147static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
148{
a113bc78
GM
149 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
150 get_user(kp->type, &up->type))
151 return -EFAULT;
cf664a64
PDM
152 switch (kp->type) {
153 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
92f45bad 154 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
cf664a64
PDM
155 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
156 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
92f45bad 157 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
cf664a64
PDM
158 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
159 case V4L2_BUF_TYPE_VBI_CAPTURE:
92f45bad 160 case V4L2_BUF_TYPE_VBI_OUTPUT:
cf664a64 161 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
92f45bad
HV
162 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
163 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
164 return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
165 case V4L2_BUF_TYPE_PRIVATE:
166 if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
167 return -EFAULT;
168 return 0;
169 case 0:
170 return -EINVAL;
cf664a64 171 default:
92f45bad 172 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
cf664a64 173 kp->type);
92f45bad 174 return -EINVAL;
cf664a64
PDM
175 }
176}
177
178static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
179{
d1f81da2 180 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
a113bc78 181 put_user(kp->type, &up->type))
cf664a64
PDM
182 return -EFAULT;
183 switch (kp->type) {
184 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
92f45bad 185 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
cf664a64
PDM
186 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
187 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
92f45bad 188 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
cf664a64
PDM
189 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
190 case V4L2_BUF_TYPE_VBI_CAPTURE:
92f45bad 191 case V4L2_BUF_TYPE_VBI_OUTPUT:
cf664a64 192 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
92f45bad
HV
193 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
194 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
195 return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
196 case V4L2_BUF_TYPE_PRIVATE:
197 if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
198 return -EFAULT;
199 return 0;
200 case 0:
201 return -EINVAL;
cf664a64 202 default:
92f45bad
HV
203 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
204 kp->type);
205 return -EINVAL;
cf664a64
PDM
206 }
207}
208
d1f81da2 209struct v4l2_standard32 {
cf664a64
PDM
210 __u32 index;
211 __u32 id[2]; /* __u64 would get the alignment wrong */
212 __u8 name[24];
213 struct v4l2_fract frameperiod; /* Frames, not fields */
214 __u32 framelines;
215 __u32 reserved[4];
216};
217
218static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
219{
220 /* other fields are not set by the user, nor used by the driver */
a113bc78
GM
221 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
222 get_user(kp->index, &up->index))
223 return -EFAULT;
224 return 0;
cf664a64
PDM
225}
226
227static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
228{
d1f81da2 229 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
a113bc78
GM
230 put_user(kp->index, &up->index) ||
231 copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
232 copy_to_user(up->name, kp->name, 24) ||
233 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
234 put_user(kp->framelines, &up->framelines) ||
235 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
236 return -EFAULT;
237 return 0;
238}
239
d1f81da2 240struct v4l2_buffer32 {
cf664a64
PDM
241 __u32 index;
242 enum v4l2_buf_type type;
243 __u32 bytesused;
244 __u32 flags;
245 enum v4l2_field field;
246 struct compat_timeval timestamp;
247 struct v4l2_timecode timecode;
248 __u32 sequence;
249
250 /* memory location */
251 enum v4l2_memory memory;
252 union {
253 __u32 offset;
254 compat_long_t userptr;
255 } m;
256 __u32 length;
257 __u32 input;
258 __u32 reserved;
259};
260
261static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
262{
263
a113bc78
GM
264 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
265 get_user(kp->index, &up->index) ||
266 get_user(kp->type, &up->type) ||
267 get_user(kp->flags, &up->flags) ||
268 get_user(kp->memory, &up->memory) ||
269 get_user(kp->input, &up->input))
270 return -EFAULT;
d1f81da2 271 switch (kp->memory) {
cf664a64 272 case V4L2_MEMORY_MMAP:
22c859fa
AP
273 if (get_user(kp->length, &up->length) ||
274 get_user(kp->m.offset, &up->m.offset))
275 return -EFAULT;
cf664a64
PDM
276 break;
277 case V4L2_MEMORY_USERPTR:
278 {
5b1a43d7 279 compat_long_t tmp;
cf664a64 280
5b1a43d7
AV
281 if (get_user(kp->length, &up->length) ||
282 get_user(tmp, &up->m.userptr))
283 return -EFAULT;
284
285 kp->m.userptr = (unsigned long)compat_ptr(tmp);
cf664a64
PDM
286 }
287 break;
288 case V4L2_MEMORY_OVERLAY:
d1f81da2 289 if (get_user(kp->m.offset, &up->m.offset))
a113bc78 290 return -EFAULT;
cf664a64
PDM
291 break;
292 }
293 return 0;
294}
295
296static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
297{
a113bc78
GM
298 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
299 put_user(kp->index, &up->index) ||
300 put_user(kp->type, &up->type) ||
301 put_user(kp->flags, &up->flags) ||
302 put_user(kp->memory, &up->memory) ||
303 put_user(kp->input, &up->input))
304 return -EFAULT;
d1f81da2 305 switch (kp->memory) {
cf664a64 306 case V4L2_MEMORY_MMAP:
a113bc78
GM
307 if (put_user(kp->length, &up->length) ||
308 put_user(kp->m.offset, &up->m.offset))
309 return -EFAULT;
cf664a64
PDM
310 break;
311 case V4L2_MEMORY_USERPTR:
a113bc78
GM
312 if (put_user(kp->length, &up->length) ||
313 put_user(kp->m.userptr, &up->m.userptr))
314 return -EFAULT;
cf664a64
PDM
315 break;
316 case V4L2_MEMORY_OVERLAY:
a113bc78
GM
317 if (put_user(kp->m.offset, &up->m.offset))
318 return -EFAULT;
cf664a64
PDM
319 break;
320 }
a113bc78
GM
321 if (put_user(kp->bytesused, &up->bytesused) ||
322 put_user(kp->field, &up->field) ||
323 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
324 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
325 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
326 put_user(kp->sequence, &up->sequence) ||
327 put_user(kp->reserved, &up->reserved))
328 return -EFAULT;
cf664a64
PDM
329 return 0;
330}
331
d1f81da2 332struct v4l2_framebuffer32 {
cf664a64
PDM
333 __u32 capability;
334 __u32 flags;
335 compat_caddr_t base;
336 struct v4l2_pix_format fmt;
337};
338
13d133bc
PDM
339static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
340{
341 u32 tmp;
342
a113bc78
GM
343 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
344 get_user(tmp, &up->base) ||
345 get_user(kp->capability, &up->capability) ||
346 get_user(kp->flags, &up->flags))
347 return -EFAULT;
13d133bc 348 kp->base = compat_ptr(tmp);
13d133bc
PDM
349 get_v4l2_pix_format(&kp->fmt, &up->fmt);
350 return 0;
351}
352
cf664a64
PDM
353static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
354{
355 u32 tmp = (u32)((unsigned long)kp->base);
356
d1f81da2 357 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
a113bc78
GM
358 put_user(tmp, &up->base) ||
359 put_user(kp->capability, &up->capability) ||
360 put_user(kp->flags, &up->flags))
361 return -EFAULT;
cf664a64
PDM
362 put_v4l2_pix_format(&kp->fmt, &up->fmt);
363 return 0;
364}
365
92f45bad
HV
366struct v4l2_input32 {
367 __u32 index; /* Which input */
368 __u8 name[32]; /* Label */
369 __u32 type; /* Type of input */
370 __u32 audioset; /* Associated audios (bitfield) */
371 __u32 tuner; /* Associated tuner */
372 v4l2_std_id std;
373 __u32 status;
374 __u32 reserved[4];
375} __attribute__ ((packed));
376
377/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
378 Otherwise it is identical to the 32-bit version. */
379static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
a113bc78 380{
92f45bad 381 if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
5b1a43d7 382 return -EFAULT;
a113bc78
GM
383 return 0;
384}
385
92f45bad 386static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
a113bc78 387{
92f45bad 388 if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
5b1a43d7 389 return -EFAULT;
a113bc78
GM
390 return 0;
391}
392
92f45bad
HV
393struct v4l2_ext_controls32 {
394 __u32 ctrl_class;
395 __u32 count;
396 __u32 error_idx;
397 __u32 reserved[2];
398 compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
eb4eeccc
MCC
399};
400
6b5a9492
HV
401struct v4l2_ext_control32 {
402 __u32 id;
403 __u32 size;
404 __u32 reserved2[1];
405 union {
406 __s32 value;
407 __s64 value64;
408 compat_caddr_t string; /* actually char * */
409 };
410} __attribute__ ((packed));
411
412/* The following function really belong in v4l2-common, but that causes
413 a circular dependency between modules. We need to think about this, but
414 for now this will do. */
415
416/* Return non-zero if this control is a pointer type. Currently only
fdf82dc2 417 type STRING is a pointer type. */
6b5a9492
HV
418static inline int ctrl_is_pointer(u32 id)
419{
fdf82dc2
EV
420 switch (id) {
421 case V4L2_CID_RDS_TX_PS_NAME:
422 case V4L2_CID_RDS_TX_RADIO_TEXT:
423 return 1;
424 default:
425 return 0;
426 }
6b5a9492
HV
427}
428
92f45bad 429static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
eb4eeccc 430{
6b5a9492 431 struct v4l2_ext_control32 __user *ucontrols;
92f45bad
HV
432 struct v4l2_ext_control __user *kcontrols;
433 int n;
434 compat_caddr_t p;
435
436 if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
437 get_user(kp->ctrl_class, &up->ctrl_class) ||
438 get_user(kp->count, &up->count) ||
439 get_user(kp->error_idx, &up->error_idx) ||
440 copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
441 return -EFAULT;
442 n = kp->count;
443 if (n == 0) {
444 kp->controls = NULL;
445 return 0;
446 }
447 if (get_user(p, &up->controls))
448 return -EFAULT;
449 ucontrols = compat_ptr(p);
450 if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
451 return -EFAULT;
452 kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
453 kp->controls = kcontrols;
454 while (--n >= 0) {
6b5a9492 455 if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
92f45bad 456 return -EFAULT;
6b5a9492
HV
457 if (ctrl_is_pointer(kcontrols->id)) {
458 void __user *s;
459
460 if (get_user(p, &ucontrols->string))
461 return -EFAULT;
462 s = compat_ptr(p);
463 if (put_user(s, &kcontrols->string))
464 return -EFAULT;
465 }
92f45bad
HV
466 ucontrols++;
467 kcontrols++;
468 }
eb4eeccc
MCC
469 return 0;
470}
471
92f45bad 472static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
0d0fbf81 473{
6b5a9492 474 struct v4l2_ext_control32 __user *ucontrols;
92f45bad
HV
475 struct v4l2_ext_control __user *kcontrols = kp->controls;
476 int n = kp->count;
477 compat_caddr_t p;
478
479 if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
480 put_user(kp->ctrl_class, &up->ctrl_class) ||
481 put_user(kp->count, &up->count) ||
482 put_user(kp->error_idx, &up->error_idx) ||
483 copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
484 return -EFAULT;
485 if (!kp->count)
486 return 0;
a113bc78 487
92f45bad 488 if (get_user(p, &up->controls))
0d0fbf81 489 return -EFAULT;
92f45bad
HV
490 ucontrols = compat_ptr(p);
491 if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
0d0fbf81
AB
492 return -EFAULT;
493
92f45bad 494 while (--n >= 0) {
6b5a9492
HV
495 unsigned size = sizeof(*ucontrols);
496
497 /* Do not modify the pointer when copying a pointer control.
498 The contents of the pointer was changed, not the pointer
499 itself. */
500 if (ctrl_is_pointer(kcontrols->id))
501 size -= sizeof(ucontrols->value64);
502 if (copy_in_user(ucontrols, kcontrols, size))
92f45bad
HV
503 return -EFAULT;
504 ucontrols++;
505 kcontrols++;
0d0fbf81 506 }
92f45bad 507 return 0;
0d0fbf81 508}
92f45bad
HV
509
510#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
511#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
512#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
513#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
514#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
515#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
516#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
517#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
518#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
519#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
520#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
521#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
522#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
523
524#define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
15029b39 525#ifdef __OLD_VIDIOC_
92f45bad 526#define VIDIOC_OVERLAY32_OLD _IOWR('V', 14, s32)
15029b39 527#endif
92f45bad
HV
528#define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
529#define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
530#define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
531#define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
532#define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
533#define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
0d0fbf81 534
069b7479 535static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
0d0fbf81
AB
536{
537 union {
cf664a64
PDM
538 struct v4l2_format v2f;
539 struct v4l2_buffer v2b;
540 struct v4l2_framebuffer v2fb;
a113bc78 541 struct v4l2_input v2i;
92f45bad
HV
542 struct v4l2_standard v2s;
543 struct v4l2_ext_controls v2ecs;
0d0fbf81 544 unsigned long vx;
92f45bad 545 int vi;
0d0fbf81 546 } karg;
0d0fbf81 547 void __user *up = compat_ptr(arg);
cf664a64 548 int compatible_arg = 1;
069b7479 549 long err = 0;
0d0fbf81
AB
550
551 /* First, convert the command. */
d1f81da2 552 switch (cmd) {
92f45bad
HV
553 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
554 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
555 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
556 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
557 case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
558 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
559 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
560 case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
561 case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
562 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
563 case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
564 case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
565 case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
566 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
15029b39 567#ifdef __OLD_VIDIOC_
92f45bad 568 case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
15029b39 569#endif
92f45bad
HV
570 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
571 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
572 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
573 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
574 case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
575 case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
576 }
0d0fbf81 577
d1f81da2 578 switch (cmd) {
cf664a64 579 case VIDIOC_OVERLAY:
13d133bc
PDM
580 case VIDIOC_STREAMON:
581 case VIDIOC_STREAMOFF:
92f45bad
HV
582 case VIDIOC_S_INPUT:
583 case VIDIOC_S_OUTPUT:
584 err = get_user(karg.vi, (s32 __user *)up);
585 compatible_arg = 0;
0d0fbf81 586 break;
13d133bc 587
92f45bad
HV
588 case VIDIOC_G_INPUT:
589 case VIDIOC_G_OUTPUT:
13d133bc
PDM
590 compatible_arg = 0;
591 break;
cf664a64
PDM
592
593 case VIDIOC_G_FMT:
594 case VIDIOC_S_FMT:
595 case VIDIOC_TRY_FMT:
596 err = get_v4l2_format32(&karg.v2f, up);
597 compatible_arg = 0;
598 break;
599
600 case VIDIOC_QUERYBUF:
601 case VIDIOC_QBUF:
602 case VIDIOC_DQBUF:
603 err = get_v4l2_buffer32(&karg.v2b, up);
604 compatible_arg = 0;
605 break;
606
92f45bad
HV
607 case VIDIOC_S_FBUF:
608 err = get_v4l2_framebuffer32(&karg.v2fb, up);
a113bc78
GM
609 compatible_arg = 0;
610 break;
611
92f45bad 612 case VIDIOC_G_FBUF:
cf664a64
PDM
613 compatible_arg = 0;
614 break;
615
92f45bad
HV
616 case VIDIOC_ENUMSTD:
617 err = get_v4l2_standard32(&karg.v2s, up);
a113bc78
GM
618 compatible_arg = 0;
619 break;
620
92f45bad 621 case VIDIOC_ENUMINPUT:
a113bc78
GM
622 err = get_v4l2_input32(&karg.v2i, up);
623 compatible_arg = 0;
624 break;
625
92f45bad
HV
626 case VIDIOC_G_EXT_CTRLS:
627 case VIDIOC_S_EXT_CTRLS:
628 case VIDIOC_TRY_EXT_CTRLS:
629 err = get_v4l2_ext_controls32(&karg.v2ecs, up);
a113bc78
GM
630 compatible_arg = 0;
631 break;
92f45bad 632 }
d1f81da2 633 if (err)
92f45bad 634 return err;
0d0fbf81 635
d1f81da2 636 if (compatible_arg)
92f45bad 637 err = native_ioctl(file, cmd, (unsigned long)up);
cf664a64
PDM
638 else {
639 mm_segment_t old_fs = get_fs();
0d0fbf81 640
cf664a64 641 set_fs(KERNEL_DS);
92f45bad 642 err = native_ioctl(file, cmd, (unsigned long)&karg);
cf664a64
PDM
643 set_fs(old_fs);
644 }
92f45bad
HV
645
646 /* Special case: even after an error we need to put the
647 results back for these ioctls since the error_idx will
648 contain information on which control failed. */
649 switch (cmd) {
650 case VIDIOC_G_EXT_CTRLS:
651 case VIDIOC_S_EXT_CTRLS:
652 case VIDIOC_TRY_EXT_CTRLS:
653 if (put_v4l2_ext_controls32(&karg.v2ecs, up))
654 err = -EFAULT;
655 break;
656 }
657 if (err)
658 return err;
659
660 switch (cmd) {
92f45bad
HV
661 case VIDIOC_S_INPUT:
662 case VIDIOC_S_OUTPUT:
663 case VIDIOC_G_INPUT:
664 case VIDIOC_G_OUTPUT:
665 err = put_user(((s32)karg.vi), (s32 __user *)up);
666 break;
a113bc78 667
92f45bad
HV
668 case VIDIOC_G_FBUF:
669 err = put_v4l2_framebuffer32(&karg.v2fb, up);
670 break;
671
672 case VIDIOC_G_FMT:
673 case VIDIOC_S_FMT:
674 case VIDIOC_TRY_FMT:
675 err = put_v4l2_format32(&karg.v2f, up);
676 break;
677
678 case VIDIOC_QUERYBUF:
679 case VIDIOC_QBUF:
680 case VIDIOC_DQBUF:
681 err = put_v4l2_buffer32(&karg.v2b, up);
682 break;
683
684 case VIDIOC_ENUMSTD:
685 err = put_v4l2_standard32(&karg.v2s, up);
686 break;
687
688 case VIDIOC_ENUMINPUT:
689 err = put_v4l2_input32(&karg.v2i, up);
690 break;
0d0fbf81 691 }
0d0fbf81
AB
692 return err;
693}
694
9bb7cde7 695long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
0d0fbf81 696{
069b7479 697 long ret = -ENOIOCTLCMD;
0d0fbf81 698
c6d7ba8b 699 if (!file->f_op->unlocked_ioctl)
0d0fbf81
AB
700 return ret;
701
702 switch (cmd) {
92f45bad
HV
703#ifdef __OLD_VIDIOC_
704 case VIDIOC_OVERLAY32_OLD:
705 case VIDIOC_S_PARM_OLD:
706 case VIDIOC_S_CTRL_OLD:
707 case VIDIOC_G_AUDIO_OLD:
708 case VIDIOC_G_AUDOUT_OLD:
709 case VIDIOC_CROPCAP_OLD:
5bdd6cc3 710#endif
13d133bc 711 case VIDIOC_QUERYCAP:
92f45bad 712 case VIDIOC_RESERVED:
13d133bc
PDM
713 case VIDIOC_ENUM_FMT:
714 case VIDIOC_G_FMT32:
715 case VIDIOC_S_FMT32:
716 case VIDIOC_REQBUFS:
717 case VIDIOC_QUERYBUF32:
718 case VIDIOC_G_FBUF32:
719 case VIDIOC_S_FBUF32:
720 case VIDIOC_OVERLAY32:
721 case VIDIOC_QBUF32:
722 case VIDIOC_DQBUF32:
723 case VIDIOC_STREAMON32:
724 case VIDIOC_STREAMOFF32:
725 case VIDIOC_G_PARM:
c7f09db6 726 case VIDIOC_S_PARM:
13d133bc
PDM
727 case VIDIOC_G_STD:
728 case VIDIOC_S_STD:
729 case VIDIOC_ENUMSTD32:
730 case VIDIOC_ENUMINPUT32:
731 case VIDIOC_G_CTRL:
7963fa48 732 case VIDIOC_S_CTRL:
92f45bad
HV
733 case VIDIOC_G_TUNER:
734 case VIDIOC_S_TUNER:
735 case VIDIOC_G_AUDIO:
736 case VIDIOC_S_AUDIO:
13d133bc 737 case VIDIOC_QUERYCTRL:
92f45bad 738 case VIDIOC_QUERYMENU:
13d133bc
PDM
739 case VIDIOC_G_INPUT32:
740 case VIDIOC_S_INPUT32:
92f45bad
HV
741 case VIDIOC_G_OUTPUT32:
742 case VIDIOC_S_OUTPUT32:
743 case VIDIOC_ENUMOUTPUT:
744 case VIDIOC_G_AUDOUT:
745 case VIDIOC_S_AUDOUT:
746 case VIDIOC_G_MODULATOR:
747 case VIDIOC_S_MODULATOR:
748 case VIDIOC_S_FREQUENCY:
749 case VIDIOC_G_FREQUENCY:
750 case VIDIOC_CROPCAP:
751 case VIDIOC_G_CROP:
752 case VIDIOC_S_CROP:
753 case VIDIOC_G_JPEGCOMP:
754 case VIDIOC_S_JPEGCOMP:
755 case VIDIOC_QUERYSTD:
13d133bc 756 case VIDIOC_TRY_FMT32:
92f45bad
HV
757 case VIDIOC_ENUMAUDIO:
758 case VIDIOC_ENUMAUDOUT:
759 case VIDIOC_G_PRIORITY:
760 case VIDIOC_S_PRIORITY:
761 case VIDIOC_G_SLICED_VBI_CAP:
762 case VIDIOC_LOG_STATUS:
763 case VIDIOC_G_EXT_CTRLS32:
764 case VIDIOC_S_EXT_CTRLS32:
765 case VIDIOC_TRY_EXT_CTRLS32:
c7f09db6
GJ
766 case VIDIOC_ENUM_FRAMESIZES:
767 case VIDIOC_ENUM_FRAMEINTERVALS:
92f45bad
HV
768 case VIDIOC_G_ENC_INDEX:
769 case VIDIOC_ENCODER_CMD:
770 case VIDIOC_TRY_ENCODER_CMD:
771 case VIDIOC_DBG_S_REGISTER:
772 case VIDIOC_DBG_G_REGISTER:
aecde8b5 773 case VIDIOC_DBG_G_CHIP_IDENT:
92f45bad 774 case VIDIOC_S_HW_FREQ_SEEK:
b6456c0c
MK
775 case VIDIOC_ENUM_DV_PRESETS:
776 case VIDIOC_S_DV_PRESET:
777 case VIDIOC_G_DV_PRESET:
778 case VIDIOC_QUERY_DV_PRESET:
779 case VIDIOC_S_DV_TIMINGS:
780 case VIDIOC_G_DV_TIMINGS:
fda10214
SA
781 case VIDIOC_DQEVENT:
782 case VIDIOC_SUBSCRIBE_EVENT:
783 case VIDIOC_UNSUBSCRIBE_EVENT:
0d0fbf81
AB
784 ret = do_video_ioctl(file, cmd, arg);
785 break;
786
a113bc78 787 default:
7943ecf1
HV
788 printk(KERN_WARNING "compat_ioctl32: "
789 "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
790 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
7d4f0b81 791 break;