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