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