GNU Linux-libre 4.14.254-gnu1
[releases.git] / drivers / media / v4l2-core / 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 #include <linux/module.h>
18 #include <linux/videodev2.h>
19 #include <linux/v4l2-subdev.h>
20 #include <media/v4l2-dev.h>
21 #include <media/v4l2-fh.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-ioctl.h>
24
25 /* Use the same argument order as copy_in_user */
26 #define assign_in_user(to, from)                                        \
27 ({                                                                      \
28         typeof(*from) __assign_tmp;                                     \
29                                                                         \
30         get_user(__assign_tmp, from) || put_user(__assign_tmp, to);     \
31 })
32
33 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
34 {
35         long ret = -ENOIOCTLCMD;
36
37         if (file->f_op->unlocked_ioctl)
38                 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
39
40         return ret;
41 }
42
43
44 struct v4l2_clip32 {
45         struct v4l2_rect        c;
46         compat_caddr_t          next;
47 };
48
49 struct v4l2_window32 {
50         struct v4l2_rect        w;
51         __u32                   field;  /* enum v4l2_field */
52         __u32                   chromakey;
53         compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
54         __u32                   clipcount;
55         compat_caddr_t          bitmap;
56         __u8                    global_alpha;
57 };
58
59 static int get_v4l2_window32(struct v4l2_window __user *kp,
60                              struct v4l2_window32 __user *up,
61                              void __user *aux_buf, u32 aux_space)
62 {
63         struct v4l2_clip32 __user *uclips;
64         struct v4l2_clip __user *kclips;
65         compat_caddr_t p;
66         u32 clipcount;
67
68         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
69             copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
70             assign_in_user(&kp->field, &up->field) ||
71             assign_in_user(&kp->chromakey, &up->chromakey) ||
72             assign_in_user(&kp->global_alpha, &up->global_alpha) ||
73             get_user(clipcount, &up->clipcount) ||
74             put_user(clipcount, &kp->clipcount))
75                 return -EFAULT;
76         if (clipcount > 2048)
77                 return -EINVAL;
78         if (!clipcount)
79                 return put_user(NULL, &kp->clips);
80
81         if (get_user(p, &up->clips))
82                 return -EFAULT;
83         uclips = compat_ptr(p);
84         if (aux_space < clipcount * sizeof(*kclips))
85                 return -EFAULT;
86         kclips = aux_buf;
87         if (put_user(kclips, &kp->clips))
88                 return -EFAULT;
89
90         while (clipcount--) {
91                 if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
92                         return -EFAULT;
93                 if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
94                         return -EFAULT;
95                 uclips++;
96                 kclips++;
97         }
98         return 0;
99 }
100
101 static int put_v4l2_window32(struct v4l2_window __user *kp,
102                              struct v4l2_window32 __user *up)
103 {
104         struct v4l2_clip __user *kclips;
105         struct v4l2_clip32 __user *uclips;
106         compat_caddr_t p;
107         u32 clipcount;
108
109         if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
110             assign_in_user(&up->field, &kp->field) ||
111             assign_in_user(&up->chromakey, &kp->chromakey) ||
112             assign_in_user(&up->global_alpha, &kp->global_alpha) ||
113             get_user(clipcount, &kp->clipcount) ||
114             put_user(clipcount, &up->clipcount))
115                 return -EFAULT;
116         if (!clipcount)
117                 return 0;
118
119         if (get_user(kclips, &kp->clips))
120                 return -EFAULT;
121         if (get_user(p, &up->clips))
122                 return -EFAULT;
123         uclips = compat_ptr(p);
124         while (clipcount--) {
125                 if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
126                         return -EFAULT;
127                 uclips++;
128                 kclips++;
129         }
130         return 0;
131 }
132
133 struct v4l2_format32 {
134         __u32   type;   /* enum v4l2_buf_type */
135         union {
136                 struct v4l2_pix_format  pix;
137                 struct v4l2_pix_format_mplane   pix_mp;
138                 struct v4l2_window32    win;
139                 struct v4l2_vbi_format  vbi;
140                 struct v4l2_sliced_vbi_format   sliced;
141                 struct v4l2_sdr_format  sdr;
142                 struct v4l2_meta_format meta;
143                 __u8    raw_data[200];        /* user-defined */
144         } fmt;
145 };
146
147 /**
148  * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
149  * @index:      on return, index of the first created buffer
150  * @count:      entry: number of requested buffers,
151  *              return: number of created buffers
152  * @memory:     buffer memory type
153  * @format:     frame format, for which buffers are requested
154  * @reserved:   future extensions
155  */
156 struct v4l2_create_buffers32 {
157         __u32                   index;
158         __u32                   count;
159         __u32                   memory; /* enum v4l2_memory */
160         struct v4l2_format32    format;
161         __u32                   reserved[8];
162 };
163
164 static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
165 {
166         u32 type;
167
168         if (get_user(type, &up->type))
169                 return -EFAULT;
170
171         switch (type) {
172         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
173         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
174                 u32 clipcount;
175
176                 if (get_user(clipcount, &up->fmt.win.clipcount))
177                         return -EFAULT;
178                 if (clipcount > 2048)
179                         return -EINVAL;
180                 *size = clipcount * sizeof(struct v4l2_clip);
181                 return 0;
182         }
183         default:
184                 *size = 0;
185                 return 0;
186         }
187 }
188
189 static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
190 {
191         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
192                 return -EFAULT;
193         return __bufsize_v4l2_format(up, size);
194 }
195
196 static int __get_v4l2_format32(struct v4l2_format __user *kp,
197                                struct v4l2_format32 __user *up,
198                                void __user *aux_buf, u32 aux_space)
199 {
200         u32 type;
201
202         if (get_user(type, &up->type) || put_user(type, &kp->type))
203                 return -EFAULT;
204
205         switch (type) {
206         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
207         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
208                 return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
209                                     sizeof(kp->fmt.pix)) ? -EFAULT : 0;
210         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
211         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
212                 return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
213                                     sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
214         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
215         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
216                 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
217                                          aux_buf, aux_space);
218         case V4L2_BUF_TYPE_VBI_CAPTURE:
219         case V4L2_BUF_TYPE_VBI_OUTPUT:
220                 return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
221                                     sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
222         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
223         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
224                 return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
225                                     sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
226         case V4L2_BUF_TYPE_SDR_CAPTURE:
227         case V4L2_BUF_TYPE_SDR_OUTPUT:
228                 return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
229                                     sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
230         case V4L2_BUF_TYPE_META_CAPTURE:
231                 return copy_in_user(&kp->fmt.meta, &up->fmt.meta,
232                                     sizeof(kp->fmt.meta)) ? -EFAULT : 0;
233         default:
234                 return -EINVAL;
235         }
236 }
237
238 static int get_v4l2_format32(struct v4l2_format __user *kp,
239                              struct v4l2_format32 __user *up,
240                              void __user *aux_buf, u32 aux_space)
241 {
242         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
243                 return -EFAULT;
244         return __get_v4l2_format32(kp, up, aux_buf, aux_space);
245 }
246
247 static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
248                                u32 *size)
249 {
250         if (!access_ok(VERIFY_READ, up, sizeof(*up)))
251                 return -EFAULT;
252         return __bufsize_v4l2_format(&up->format, size);
253 }
254
255 static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
256                              struct v4l2_create_buffers32 __user *up,
257                              void __user *aux_buf, u32 aux_space)
258 {
259         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
260             copy_in_user(kp, up,
261                          offsetof(struct v4l2_create_buffers32, format)))
262                 return -EFAULT;
263         return __get_v4l2_format32(&kp->format, &up->format,
264                                    aux_buf, aux_space);
265 }
266
267 static int __put_v4l2_format32(struct v4l2_format __user *kp,
268                                struct v4l2_format32 __user *up)
269 {
270         u32 type;
271
272         if (get_user(type, &kp->type))
273                 return -EFAULT;
274
275         switch (type) {
276         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
277         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
278                 return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
279                                     sizeof(kp->fmt.pix)) ? -EFAULT : 0;
280         case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
281         case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
282                 return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
283                                     sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
284         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
285         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
286                 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
287         case V4L2_BUF_TYPE_VBI_CAPTURE:
288         case V4L2_BUF_TYPE_VBI_OUTPUT:
289                 return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
290                                     sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
291         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
292         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
293                 return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
294                                     sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
295         case V4L2_BUF_TYPE_SDR_CAPTURE:
296         case V4L2_BUF_TYPE_SDR_OUTPUT:
297                 return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
298                                     sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
299         case V4L2_BUF_TYPE_META_CAPTURE:
300                 return copy_in_user(&up->fmt.meta, &kp->fmt.meta,
301                                     sizeof(kp->fmt.meta)) ? -EFAULT : 0;
302         default:
303                 return -EINVAL;
304         }
305 }
306
307 static int put_v4l2_format32(struct v4l2_format __user *kp,
308                              struct v4l2_format32 __user *up)
309 {
310         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
311                 return -EFAULT;
312         return __put_v4l2_format32(kp, up);
313 }
314
315 static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
316                              struct v4l2_create_buffers32 __user *up)
317 {
318         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
319             copy_in_user(up, kp,
320                          offsetof(struct v4l2_create_buffers32, format)) ||
321             copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
322                 return -EFAULT;
323         return __put_v4l2_format32(&kp->format, &up->format);
324 }
325
326 struct v4l2_standard32 {
327         __u32                index;
328         compat_u64           id;
329         __u8                 name[24];
330         struct v4l2_fract    frameperiod; /* Frames, not fields */
331         __u32                framelines;
332         __u32                reserved[4];
333 };
334
335 static int get_v4l2_standard32(struct v4l2_standard __user *kp,
336                                struct v4l2_standard32 __user *up)
337 {
338         /* other fields are not set by the user, nor used by the driver */
339         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
340             assign_in_user(&kp->index, &up->index))
341                 return -EFAULT;
342         return 0;
343 }
344
345 static int put_v4l2_standard32(struct v4l2_standard __user *kp,
346                                struct v4l2_standard32 __user *up)
347 {
348         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
349             assign_in_user(&up->index, &kp->index) ||
350             assign_in_user(&up->id, &kp->id) ||
351             copy_in_user(up->name, kp->name, sizeof(up->name)) ||
352             copy_in_user(&up->frameperiod, &kp->frameperiod,
353                          sizeof(up->frameperiod)) ||
354             assign_in_user(&up->framelines, &kp->framelines) ||
355             copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
356                 return -EFAULT;
357         return 0;
358 }
359
360 struct v4l2_plane32 {
361         __u32                   bytesused;
362         __u32                   length;
363         union {
364                 __u32           mem_offset;
365                 compat_long_t   userptr;
366                 __s32           fd;
367         } m;
368         __u32                   data_offset;
369         __u32                   reserved[11];
370 };
371
372 struct v4l2_buffer32 {
373         __u32                   index;
374         __u32                   type;   /* enum v4l2_buf_type */
375         __u32                   bytesused;
376         __u32                   flags;
377         __u32                   field;  /* enum v4l2_field */
378         struct compat_timeval   timestamp;
379         struct v4l2_timecode    timecode;
380         __u32                   sequence;
381
382         /* memory location */
383         __u32                   memory; /* enum v4l2_memory */
384         union {
385                 __u32           offset;
386                 compat_long_t   userptr;
387                 compat_caddr_t  planes;
388                 __s32           fd;
389         } m;
390         __u32                   length;
391         __u32                   reserved2;
392         __u32                   reserved;
393 };
394
395 static int get_v4l2_plane32(struct v4l2_plane __user *up,
396                             struct v4l2_plane32 __user *up32,
397                             enum v4l2_memory memory)
398 {
399         compat_ulong_t p;
400
401         if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
402             copy_in_user(&up->data_offset, &up32->data_offset,
403                          sizeof(up->data_offset)))
404                 return -EFAULT;
405
406         switch (memory) {
407         case V4L2_MEMORY_MMAP:
408         case V4L2_MEMORY_OVERLAY:
409                 if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
410                                  sizeof(up32->m.mem_offset)))
411                         return -EFAULT;
412                 break;
413         case V4L2_MEMORY_USERPTR:
414                 if (get_user(p, &up32->m.userptr) ||
415                     put_user((unsigned long)compat_ptr(p), &up->m.userptr))
416                         return -EFAULT;
417                 break;
418         case V4L2_MEMORY_DMABUF:
419                 if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
420                         return -EFAULT;
421                 break;
422         }
423
424         return 0;
425 }
426
427 static int put_v4l2_plane32(struct v4l2_plane __user *up,
428                             struct v4l2_plane32 __user *up32,
429                             enum v4l2_memory memory)
430 {
431         unsigned long p;
432
433         if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
434             copy_in_user(&up32->data_offset, &up->data_offset,
435                          sizeof(up->data_offset)))
436                 return -EFAULT;
437
438         switch (memory) {
439         case V4L2_MEMORY_MMAP:
440         case V4L2_MEMORY_OVERLAY:
441                 if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
442                                  sizeof(up->m.mem_offset)))
443                         return -EFAULT;
444                 break;
445         case V4L2_MEMORY_USERPTR:
446                 if (get_user(p, &up->m.userptr) ||
447                     put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
448                              &up32->m.userptr))
449                         return -EFAULT;
450                 break;
451         case V4L2_MEMORY_DMABUF:
452                 if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
453                         return -EFAULT;
454                 break;
455         }
456
457         return 0;
458 }
459
460 static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
461 {
462         u32 type;
463         u32 length;
464
465         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
466             get_user(type, &up->type) ||
467             get_user(length, &up->length))
468                 return -EFAULT;
469
470         if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
471                 if (length > VIDEO_MAX_PLANES)
472                         return -EINVAL;
473
474                 /*
475                  * We don't really care if userspace decides to kill itself
476                  * by passing a very big length value
477                  */
478                 *size = length * sizeof(struct v4l2_plane);
479         } else {
480                 *size = 0;
481         }
482         return 0;
483 }
484
485 static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
486                              struct v4l2_buffer32 __user *up,
487                              void __user *aux_buf, u32 aux_space)
488 {
489         u32 type;
490         u32 length;
491         enum v4l2_memory memory;
492         struct v4l2_plane32 __user *uplane32;
493         struct v4l2_plane __user *uplane;
494         compat_caddr_t p;
495         int ret;
496
497         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
498             assign_in_user(&kp->index, &up->index) ||
499             get_user(type, &up->type) ||
500             put_user(type, &kp->type) ||
501             assign_in_user(&kp->flags, &up->flags) ||
502             get_user(memory, &up->memory) ||
503             put_user(memory, &kp->memory) ||
504             get_user(length, &up->length) ||
505             put_user(length, &kp->length))
506                 return -EFAULT;
507
508         if (V4L2_TYPE_IS_OUTPUT(type))
509                 if (assign_in_user(&kp->bytesused, &up->bytesused) ||
510                     assign_in_user(&kp->field, &up->field) ||
511                     assign_in_user(&kp->timestamp.tv_sec,
512                                    &up->timestamp.tv_sec) ||
513                     assign_in_user(&kp->timestamp.tv_usec,
514                                    &up->timestamp.tv_usec))
515                         return -EFAULT;
516
517         if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
518                 u32 num_planes = length;
519
520                 if (num_planes == 0) {
521                         /*
522                          * num_planes == 0 is legal, e.g. when userspace doesn't
523                          * need planes array on DQBUF
524                          */
525                         return put_user(NULL, &kp->m.planes);
526                 }
527                 if (num_planes > VIDEO_MAX_PLANES)
528                         return -EINVAL;
529
530                 if (get_user(p, &up->m.planes))
531                         return -EFAULT;
532
533                 uplane32 = compat_ptr(p);
534                 if (!access_ok(VERIFY_READ, uplane32,
535                                num_planes * sizeof(*uplane32)))
536                         return -EFAULT;
537
538                 /*
539                  * We don't really care if userspace decides to kill itself
540                  * by passing a very big num_planes value
541                  */
542                 if (aux_space < num_planes * sizeof(*uplane))
543                         return -EFAULT;
544
545                 uplane = aux_buf;
546                 if (put_user((__force struct v4l2_plane *)uplane,
547                              &kp->m.planes))
548                         return -EFAULT;
549
550                 while (num_planes--) {
551                         ret = get_v4l2_plane32(uplane, uplane32, memory);
552                         if (ret)
553                                 return ret;
554                         uplane++;
555                         uplane32++;
556                 }
557         } else {
558                 switch (memory) {
559                 case V4L2_MEMORY_MMAP:
560                 case V4L2_MEMORY_OVERLAY:
561                         if (assign_in_user(&kp->m.offset, &up->m.offset))
562                                 return -EFAULT;
563                         break;
564                 case V4L2_MEMORY_USERPTR: {
565                         compat_ulong_t userptr;
566
567                         if (get_user(userptr, &up->m.userptr) ||
568                             put_user((unsigned long)compat_ptr(userptr),
569                                      &kp->m.userptr))
570                                 return -EFAULT;
571                         break;
572                 }
573                 case V4L2_MEMORY_DMABUF:
574                         if (assign_in_user(&kp->m.fd, &up->m.fd))
575                                 return -EFAULT;
576                         break;
577                 }
578         }
579
580         return 0;
581 }
582
583 static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
584                              struct v4l2_buffer32 __user *up)
585 {
586         u32 type;
587         u32 length;
588         enum v4l2_memory memory;
589         struct v4l2_plane32 __user *uplane32;
590         struct v4l2_plane __user *uplane;
591         compat_caddr_t p;
592         int ret;
593
594         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
595             assign_in_user(&up->index, &kp->index) ||
596             get_user(type, &kp->type) ||
597             put_user(type, &up->type) ||
598             assign_in_user(&up->flags, &kp->flags) ||
599             get_user(memory, &kp->memory) ||
600             put_user(memory, &up->memory))
601                 return -EFAULT;
602
603         if (assign_in_user(&up->bytesused, &kp->bytesused) ||
604             assign_in_user(&up->field, &kp->field) ||
605             assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
606             assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
607             copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
608             assign_in_user(&up->sequence, &kp->sequence) ||
609             assign_in_user(&up->reserved2, &kp->reserved2) ||
610             assign_in_user(&up->reserved, &kp->reserved) ||
611             get_user(length, &kp->length) ||
612             put_user(length, &up->length))
613                 return -EFAULT;
614
615         if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
616                 u32 num_planes = length;
617
618                 if (num_planes == 0)
619                         return 0;
620
621                 if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
622                         return -EFAULT;
623                 if (get_user(p, &up->m.planes))
624                         return -EFAULT;
625                 uplane32 = compat_ptr(p);
626
627                 while (num_planes--) {
628                         ret = put_v4l2_plane32(uplane, uplane32, memory);
629                         if (ret)
630                                 return ret;
631                         ++uplane;
632                         ++uplane32;
633                 }
634         } else {
635                 switch (memory) {
636                 case V4L2_MEMORY_MMAP:
637                 case V4L2_MEMORY_OVERLAY:
638                         if (assign_in_user(&up->m.offset, &kp->m.offset))
639                                 return -EFAULT;
640                         break;
641                 case V4L2_MEMORY_USERPTR:
642                         if (assign_in_user(&up->m.userptr, &kp->m.userptr))
643                                 return -EFAULT;
644                         break;
645                 case V4L2_MEMORY_DMABUF:
646                         if (assign_in_user(&up->m.fd, &kp->m.fd))
647                                 return -EFAULT;
648                         break;
649                 }
650         }
651
652         return 0;
653 }
654
655 struct v4l2_framebuffer32 {
656         __u32                   capability;
657         __u32                   flags;
658         compat_caddr_t          base;
659         struct {
660                 __u32           width;
661                 __u32           height;
662                 __u32           pixelformat;
663                 __u32           field;
664                 __u32           bytesperline;
665                 __u32           sizeimage;
666                 __u32           colorspace;
667                 __u32           priv;
668         } fmt;
669 };
670
671 static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
672                                   struct v4l2_framebuffer32 __user *up)
673 {
674         compat_caddr_t tmp;
675
676         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
677             get_user(tmp, &up->base) ||
678             put_user((__force void *)compat_ptr(tmp), &kp->base) ||
679             assign_in_user(&kp->capability, &up->capability) ||
680             assign_in_user(&kp->flags, &up->flags) ||
681             copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
682                 return -EFAULT;
683         return 0;
684 }
685
686 static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
687                                   struct v4l2_framebuffer32 __user *up)
688 {
689         void *base;
690
691         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
692             get_user(base, &kp->base) ||
693             put_user(ptr_to_compat(base), &up->base) ||
694             assign_in_user(&up->capability, &kp->capability) ||
695             assign_in_user(&up->flags, &kp->flags) ||
696             copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
697                 return -EFAULT;
698         return 0;
699 }
700
701 struct v4l2_input32 {
702         __u32        index;             /*  Which input */
703         __u8         name[32];          /*  Label */
704         __u32        type;              /*  Type of input */
705         __u32        audioset;          /*  Associated audios (bitfield) */
706         __u32        tuner;             /*  Associated tuner */
707         compat_u64   std;
708         __u32        status;
709         __u32        capabilities;
710         __u32        reserved[3];
711 };
712
713 /*
714  * The 64-bit v4l2_input struct has extra padding at the end of the struct.
715  * Otherwise it is identical to the 32-bit version.
716  */
717 static inline int get_v4l2_input32(struct v4l2_input __user *kp,
718                                    struct v4l2_input32 __user *up)
719 {
720         if (copy_in_user(kp, up, sizeof(*up)))
721                 return -EFAULT;
722         return 0;
723 }
724
725 static inline int put_v4l2_input32(struct v4l2_input __user *kp,
726                                    struct v4l2_input32 __user *up)
727 {
728         if (copy_in_user(up, kp, sizeof(*up)))
729                 return -EFAULT;
730         return 0;
731 }
732
733 struct v4l2_ext_controls32 {
734         __u32 which;
735         __u32 count;
736         __u32 error_idx;
737         __u32 reserved[2];
738         compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
739 };
740
741 struct v4l2_ext_control32 {
742         __u32 id;
743         __u32 size;
744         __u32 reserved2[1];
745         union {
746                 __s32 value;
747                 __s64 value64;
748                 compat_caddr_t string; /* actually char * */
749         };
750 } __attribute__ ((packed));
751
752 /* Return true if this control is a pointer type. */
753 static inline bool ctrl_is_pointer(struct file *file, u32 id)
754 {
755         struct video_device *vdev = video_devdata(file);
756         struct v4l2_fh *fh = NULL;
757         struct v4l2_ctrl_handler *hdl = NULL;
758         struct v4l2_query_ext_ctrl qec = { id };
759         const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
760
761         if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
762                 fh = file->private_data;
763
764         if (fh && fh->ctrl_handler)
765                 hdl = fh->ctrl_handler;
766         else if (vdev->ctrl_handler)
767                 hdl = vdev->ctrl_handler;
768
769         if (hdl) {
770                 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
771
772                 return ctrl && ctrl->is_ptr;
773         }
774
775         if (!ops || !ops->vidioc_query_ext_ctrl)
776                 return false;
777
778         return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
779                 (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
780 }
781
782 static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
783                                      u32 *size)
784 {
785         u32 count;
786
787         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
788             get_user(count, &up->count))
789                 return -EFAULT;
790         if (count > V4L2_CID_MAX_CTRLS)
791                 return -EINVAL;
792         *size = count * sizeof(struct v4l2_ext_control);
793         return 0;
794 }
795
796 static int get_v4l2_ext_controls32(struct file *file,
797                                    struct v4l2_ext_controls __user *kp,
798                                    struct v4l2_ext_controls32 __user *up,
799                                    void __user *aux_buf, u32 aux_space)
800 {
801         struct v4l2_ext_control32 __user *ucontrols;
802         struct v4l2_ext_control __user *kcontrols;
803         u32 count;
804         u32 n;
805         compat_caddr_t p;
806
807         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
808             assign_in_user(&kp->which, &up->which) ||
809             get_user(count, &up->count) ||
810             put_user(count, &kp->count) ||
811             assign_in_user(&kp->error_idx, &up->error_idx) ||
812             copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
813                 return -EFAULT;
814
815         if (count == 0)
816                 return put_user(NULL, &kp->controls);
817         if (count > V4L2_CID_MAX_CTRLS)
818                 return -EINVAL;
819         if (get_user(p, &up->controls))
820                 return -EFAULT;
821         ucontrols = compat_ptr(p);
822         if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
823                 return -EFAULT;
824         if (aux_space < count * sizeof(*kcontrols))
825                 return -EFAULT;
826         kcontrols = aux_buf;
827         if (put_user((__force struct v4l2_ext_control *)kcontrols,
828                      &kp->controls))
829                 return -EFAULT;
830
831         for (n = 0; n < count; n++) {
832                 u32 id;
833
834                 if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
835                         return -EFAULT;
836
837                 if (get_user(id, &kcontrols->id))
838                         return -EFAULT;
839
840                 if (ctrl_is_pointer(file, id)) {
841                         void __user *s;
842
843                         if (get_user(p, &ucontrols->string))
844                                 return -EFAULT;
845                         s = compat_ptr(p);
846                         if (put_user(s, &kcontrols->string))
847                                 return -EFAULT;
848                 }
849                 ucontrols++;
850                 kcontrols++;
851         }
852         return 0;
853 }
854
855 static int put_v4l2_ext_controls32(struct file *file,
856                                    struct v4l2_ext_controls __user *kp,
857                                    struct v4l2_ext_controls32 __user *up)
858 {
859         struct v4l2_ext_control32 __user *ucontrols;
860         struct v4l2_ext_control __user *kcontrols;
861         u32 count;
862         u32 n;
863         compat_caddr_t p;
864
865         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
866             assign_in_user(&up->which, &kp->which) ||
867             get_user(count, &kp->count) ||
868             put_user(count, &up->count) ||
869             assign_in_user(&up->error_idx, &kp->error_idx) ||
870             copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
871             get_user(kcontrols, &kp->controls))
872                 return -EFAULT;
873
874         if (!count || count > (U32_MAX/sizeof(*ucontrols)))
875                 return 0;
876         if (get_user(p, &up->controls))
877                 return -EFAULT;
878         ucontrols = compat_ptr(p);
879         if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
880                 return -EFAULT;
881
882         for (n = 0; n < count; n++) {
883                 unsigned int size = sizeof(*ucontrols);
884                 u32 id;
885
886                 if (get_user(id, &kcontrols->id) ||
887                     put_user(id, &ucontrols->id) ||
888                     assign_in_user(&ucontrols->size, &kcontrols->size) ||
889                     copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
890                                  sizeof(ucontrols->reserved2)))
891                         return -EFAULT;
892
893                 /*
894                  * Do not modify the pointer when copying a pointer control.
895                  * The contents of the pointer was changed, not the pointer
896                  * itself.
897                  */
898                 if (ctrl_is_pointer(file, id))
899                         size -= sizeof(ucontrols->value64);
900
901                 if (copy_in_user(ucontrols, kcontrols, size))
902                         return -EFAULT;
903
904                 ucontrols++;
905                 kcontrols++;
906         }
907         return 0;
908 }
909
910 struct v4l2_event32 {
911         __u32                           type;
912         union {
913                 compat_s64              value64;
914                 __u8                    data[64];
915         } u;
916         __u32                           pending;
917         __u32                           sequence;
918         struct compat_timespec          timestamp;
919         __u32                           id;
920         __u32                           reserved[8];
921 };
922
923 static int put_v4l2_event32(struct v4l2_event __user *kp,
924                             struct v4l2_event32 __user *up)
925 {
926         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
927             assign_in_user(&up->type, &kp->type) ||
928             copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
929             assign_in_user(&up->pending, &kp->pending) ||
930             assign_in_user(&up->sequence, &kp->sequence) ||
931             assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
932             assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
933             assign_in_user(&up->id, &kp->id) ||
934             copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
935                 return -EFAULT;
936         return 0;
937 }
938
939 struct v4l2_edid32 {
940         __u32 pad;
941         __u32 start_block;
942         __u32 blocks;
943         __u32 reserved[5];
944         compat_caddr_t edid;
945 };
946
947 static int get_v4l2_edid32(struct v4l2_edid __user *kp,
948                            struct v4l2_edid32 __user *up)
949 {
950         compat_uptr_t tmp;
951
952         if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
953             assign_in_user(&kp->pad, &up->pad) ||
954             assign_in_user(&kp->start_block, &up->start_block) ||
955             assign_in_user(&kp->blocks, &up->blocks) ||
956             get_user(tmp, &up->edid) ||
957             put_user(compat_ptr(tmp), &kp->edid) ||
958             copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
959                 return -EFAULT;
960         return 0;
961 }
962
963 static int put_v4l2_edid32(struct v4l2_edid __user *kp,
964                            struct v4l2_edid32 __user *up)
965 {
966         void *edid;
967
968         if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
969             assign_in_user(&up->pad, &kp->pad) ||
970             assign_in_user(&up->start_block, &kp->start_block) ||
971             assign_in_user(&up->blocks, &kp->blocks) ||
972             get_user(edid, &kp->edid) ||
973             put_user(ptr_to_compat(edid), &up->edid) ||
974             copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
975                 return -EFAULT;
976         return 0;
977 }
978
979
980 #define VIDIOC_G_FMT32          _IOWR('V',  4, struct v4l2_format32)
981 #define VIDIOC_S_FMT32          _IOWR('V',  5, struct v4l2_format32)
982 #define VIDIOC_QUERYBUF32       _IOWR('V',  9, struct v4l2_buffer32)
983 #define VIDIOC_G_FBUF32         _IOR ('V', 10, struct v4l2_framebuffer32)
984 #define VIDIOC_S_FBUF32         _IOW ('V', 11, struct v4l2_framebuffer32)
985 #define VIDIOC_QBUF32           _IOWR('V', 15, struct v4l2_buffer32)
986 #define VIDIOC_DQBUF32          _IOWR('V', 17, struct v4l2_buffer32)
987 #define VIDIOC_ENUMSTD32        _IOWR('V', 25, struct v4l2_standard32)
988 #define VIDIOC_ENUMINPUT32      _IOWR('V', 26, struct v4l2_input32)
989 #define VIDIOC_G_EDID32         _IOWR('V', 40, struct v4l2_edid32)
990 #define VIDIOC_S_EDID32         _IOWR('V', 41, struct v4l2_edid32)
991 #define VIDIOC_TRY_FMT32        _IOWR('V', 64, struct v4l2_format32)
992 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
993 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
994 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
995 #define VIDIOC_DQEVENT32        _IOR ('V', 89, struct v4l2_event32)
996 #define VIDIOC_CREATE_BUFS32    _IOWR('V', 92, struct v4l2_create_buffers32)
997 #define VIDIOC_PREPARE_BUF32    _IOWR('V', 93, struct v4l2_buffer32)
998
999 #define VIDIOC_OVERLAY32        _IOW ('V', 14, s32)
1000 #define VIDIOC_STREAMON32       _IOW ('V', 18, s32)
1001 #define VIDIOC_STREAMOFF32      _IOW ('V', 19, s32)
1002 #define VIDIOC_G_INPUT32        _IOR ('V', 38, s32)
1003 #define VIDIOC_S_INPUT32        _IOWR('V', 39, s32)
1004 #define VIDIOC_G_OUTPUT32       _IOR ('V', 46, s32)
1005 #define VIDIOC_S_OUTPUT32       _IOWR('V', 47, s32)
1006
1007 static int alloc_userspace(unsigned int size, u32 aux_space,
1008                            void __user **up_native)
1009 {
1010         *up_native = compat_alloc_user_space(size + aux_space);
1011         if (!*up_native)
1012                 return -ENOMEM;
1013         if (clear_user(*up_native, size))
1014                 return -EFAULT;
1015         return 0;
1016 }
1017
1018 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1019 {
1020         void __user *up = compat_ptr(arg);
1021         void __user *up_native = NULL;
1022         void __user *aux_buf;
1023         u32 aux_space;
1024         int compatible_arg = 1;
1025         long err = 0;
1026
1027         /* First, convert the command. */
1028         switch (cmd) {
1029         case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
1030         case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
1031         case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
1032         case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
1033         case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
1034         case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
1035         case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
1036         case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
1037         case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
1038         case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
1039         case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
1040         case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
1041         case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
1042         case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
1043         case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
1044         case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
1045         case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
1046         case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
1047         case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
1048         case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
1049         case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
1050         case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
1051         case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
1052         case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break;
1053         case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break;
1054         }
1055
1056         switch (cmd) {
1057         case VIDIOC_OVERLAY:
1058         case VIDIOC_STREAMON:
1059         case VIDIOC_STREAMOFF:
1060         case VIDIOC_S_INPUT:
1061         case VIDIOC_S_OUTPUT:
1062                 err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1063                 if (!err && assign_in_user((unsigned int __user *)up_native,
1064                                            (compat_uint_t __user *)up))
1065                         err = -EFAULT;
1066                 compatible_arg = 0;
1067                 break;
1068
1069         case VIDIOC_G_INPUT:
1070         case VIDIOC_G_OUTPUT:
1071                 err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1072                 compatible_arg = 0;
1073                 break;
1074
1075         case VIDIOC_G_EDID:
1076         case VIDIOC_S_EDID:
1077                 err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
1078                 if (!err)
1079                         err = get_v4l2_edid32(up_native, up);
1080                 compatible_arg = 0;
1081                 break;
1082
1083         case VIDIOC_G_FMT:
1084         case VIDIOC_S_FMT:
1085         case VIDIOC_TRY_FMT:
1086                 err = bufsize_v4l2_format(up, &aux_space);
1087                 if (!err)
1088                         err = alloc_userspace(sizeof(struct v4l2_format),
1089                                               aux_space, &up_native);
1090                 if (!err) {
1091                         aux_buf = up_native + sizeof(struct v4l2_format);
1092                         err = get_v4l2_format32(up_native, up,
1093                                                 aux_buf, aux_space);
1094                 }
1095                 compatible_arg = 0;
1096                 break;
1097
1098         case VIDIOC_CREATE_BUFS:
1099                 err = bufsize_v4l2_create(up, &aux_space);
1100                 if (!err)
1101                         err = alloc_userspace(sizeof(struct v4l2_create_buffers),
1102                                               aux_space, &up_native);
1103                 if (!err) {
1104                         aux_buf = up_native + sizeof(struct v4l2_create_buffers);
1105                         err = get_v4l2_create32(up_native, up,
1106                                                 aux_buf, aux_space);
1107                 }
1108                 compatible_arg = 0;
1109                 break;
1110
1111         case VIDIOC_PREPARE_BUF:
1112         case VIDIOC_QUERYBUF:
1113         case VIDIOC_QBUF:
1114         case VIDIOC_DQBUF:
1115                 err = bufsize_v4l2_buffer(up, &aux_space);
1116                 if (!err)
1117                         err = alloc_userspace(sizeof(struct v4l2_buffer),
1118                                               aux_space, &up_native);
1119                 if (!err) {
1120                         aux_buf = up_native + sizeof(struct v4l2_buffer);
1121                         err = get_v4l2_buffer32(up_native, up,
1122                                                 aux_buf, aux_space);
1123                 }
1124                 compatible_arg = 0;
1125                 break;
1126
1127         case VIDIOC_S_FBUF:
1128                 err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1129                                       &up_native);
1130                 if (!err)
1131                         err = get_v4l2_framebuffer32(up_native, up);
1132                 compatible_arg = 0;
1133                 break;
1134
1135         case VIDIOC_G_FBUF:
1136                 err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1137                                       &up_native);
1138                 compatible_arg = 0;
1139                 break;
1140
1141         case VIDIOC_ENUMSTD:
1142                 err = alloc_userspace(sizeof(struct v4l2_standard), 0,
1143                                       &up_native);
1144                 if (!err)
1145                         err = get_v4l2_standard32(up_native, up);
1146                 compatible_arg = 0;
1147                 break;
1148
1149         case VIDIOC_ENUMINPUT:
1150                 err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
1151                 if (!err)
1152                         err = get_v4l2_input32(up_native, up);
1153                 compatible_arg = 0;
1154                 break;
1155
1156         case VIDIOC_G_EXT_CTRLS:
1157         case VIDIOC_S_EXT_CTRLS:
1158         case VIDIOC_TRY_EXT_CTRLS:
1159                 err = bufsize_v4l2_ext_controls(up, &aux_space);
1160                 if (!err)
1161                         err = alloc_userspace(sizeof(struct v4l2_ext_controls),
1162                                               aux_space, &up_native);
1163                 if (!err) {
1164                         aux_buf = up_native + sizeof(struct v4l2_ext_controls);
1165                         err = get_v4l2_ext_controls32(file, up_native, up,
1166                                                       aux_buf, aux_space);
1167                 }
1168                 compatible_arg = 0;
1169                 break;
1170         case VIDIOC_DQEVENT:
1171                 err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
1172                 compatible_arg = 0;
1173                 break;
1174         }
1175         if (err)
1176                 return err;
1177
1178         if (compatible_arg)
1179                 err = native_ioctl(file, cmd, (unsigned long)up);
1180         else
1181                 err = native_ioctl(file, cmd, (unsigned long)up_native);
1182
1183         if (err == -ENOTTY)
1184                 return err;
1185
1186         /*
1187          * Special case: even after an error we need to put the
1188          * results back for these ioctls since the error_idx will
1189          * contain information on which control failed.
1190          */
1191         switch (cmd) {
1192         case VIDIOC_G_EXT_CTRLS:
1193         case VIDIOC_S_EXT_CTRLS:
1194         case VIDIOC_TRY_EXT_CTRLS:
1195                 if (put_v4l2_ext_controls32(file, up_native, up))
1196                         err = -EFAULT;
1197                 break;
1198         case VIDIOC_S_EDID:
1199                 if (put_v4l2_edid32(up_native, up))
1200                         err = -EFAULT;
1201                 break;
1202         }
1203         if (err)
1204                 return err;
1205
1206         switch (cmd) {
1207         case VIDIOC_S_INPUT:
1208         case VIDIOC_S_OUTPUT:
1209         case VIDIOC_G_INPUT:
1210         case VIDIOC_G_OUTPUT:
1211                 if (assign_in_user((compat_uint_t __user *)up,
1212                                    ((unsigned int __user *)up_native)))
1213                         err = -EFAULT;
1214                 break;
1215
1216         case VIDIOC_G_FBUF:
1217                 err = put_v4l2_framebuffer32(up_native, up);
1218                 break;
1219
1220         case VIDIOC_DQEVENT:
1221                 err = put_v4l2_event32(up_native, up);
1222                 break;
1223
1224         case VIDIOC_G_EDID:
1225                 err = put_v4l2_edid32(up_native, up);
1226                 break;
1227
1228         case VIDIOC_G_FMT:
1229         case VIDIOC_S_FMT:
1230         case VIDIOC_TRY_FMT:
1231                 err = put_v4l2_format32(up_native, up);
1232                 break;
1233
1234         case VIDIOC_CREATE_BUFS:
1235                 err = put_v4l2_create32(up_native, up);
1236                 break;
1237
1238         case VIDIOC_PREPARE_BUF:
1239         case VIDIOC_QUERYBUF:
1240         case VIDIOC_QBUF:
1241         case VIDIOC_DQBUF:
1242                 err = put_v4l2_buffer32(up_native, up);
1243                 break;
1244
1245         case VIDIOC_ENUMSTD:
1246                 err = put_v4l2_standard32(up_native, up);
1247                 break;
1248
1249         case VIDIOC_ENUMINPUT:
1250                 err = put_v4l2_input32(up_native, up);
1251                 break;
1252         }
1253         return err;
1254 }
1255
1256 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1257 {
1258         struct video_device *vdev = video_devdata(file);
1259         long ret = -ENOIOCTLCMD;
1260
1261         if (!file->f_op->unlocked_ioctl)
1262                 return ret;
1263
1264         if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1265                 ret = do_video_ioctl(file, cmd, arg);
1266         else if (vdev->fops->compat_ioctl32)
1267                 ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1268
1269         if (ret == -ENOIOCTLCMD)
1270                 pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1271                          _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1272         return ret;
1273 }
1274 EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);