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