V4L/DVB (9932): v4l2-compat32: fix 32-64 compatibility module
[linux-2.6] / 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@suse.cz)
9  * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
10  * Copyright (C) 2008       Hans Verkuil <hverkuil@xs4all.nl>
11  *
12  * These routines maintain argument size conversion between 32bit and 64bit
13  * ioctls.
14  */
15
16 #include <linux/compat.h>
17 #define __OLD_VIDIOC_ /* To allow fixing old calls*/
18 #include <linux/videodev.h>
19 #include <linux/videodev2.h>
20 #include <linux/module.h>
21 #include <linux/smp_lock.h>
22 #include <media/v4l2-ioctl.h>
23
24 #ifdef CONFIG_COMPAT
25
26 #ifdef CONFIG_VIDEO_V4L1_COMPAT
27 struct video_tuner32 {
28         compat_int_t tuner;
29         char name[32];
30         compat_ulong_t rangelow, rangehigh;
31         u32 flags;      /* It is really u32 in videodev.h */
32         u16 mode, signal;
33 };
34
35 static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
36 {
37         if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
38                 get_user(kp->tuner, &up->tuner) ||
39                 copy_from_user(kp->name, up->name, 32) ||
40                 get_user(kp->rangelow, &up->rangelow) ||
41                 get_user(kp->rangehigh, &up->rangehigh) ||
42                 get_user(kp->flags, &up->flags) ||
43                 get_user(kp->mode, &up->mode) ||
44                 get_user(kp->signal, &up->signal))
45                 return -EFAULT;
46         return 0;
47 }
48
49 static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
50 {
51         if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
52                 put_user(kp->tuner, &up->tuner) ||
53                 copy_to_user(up->name, kp->name, 32) ||
54                 put_user(kp->rangelow, &up->rangelow) ||
55                 put_user(kp->rangehigh, &up->rangehigh) ||
56                 put_user(kp->flags, &up->flags) ||
57                 put_user(kp->mode, &up->mode) ||
58                 put_user(kp->signal, &up->signal))
59                         return -EFAULT;
60         return 0;
61 }
62
63 struct video_buffer32 {
64         compat_caddr_t base;
65         compat_int_t height, width, depth, bytesperline;
66 };
67
68 static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
69 {
70         u32 tmp;
71
72         if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
73                 get_user(tmp, &up->base) ||
74                 get_user(kp->height, &up->height) ||
75                 get_user(kp->width, &up->width) ||
76                 get_user(kp->depth, &up->depth) ||
77                 get_user(kp->bytesperline, &up->bytesperline))
78                         return -EFAULT;
79
80         /* This is actually a physical address stored
81          * as a void pointer.
82          */
83         kp->base = (void *)(unsigned long) tmp;
84
85         return 0;
86 }
87
88 static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
89 {
90         u32 tmp = (u32)((unsigned long)kp->base);
91
92         if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
93                 put_user(tmp, &up->base) ||
94                 put_user(kp->height, &up->height) ||
95                 put_user(kp->width, &up->width) ||
96                 put_user(kp->depth, &up->depth) ||
97                 put_user(kp->bytesperline, &up->bytesperline))
98                         return -EFAULT;
99         return 0;
100 }
101
102 struct video_clip32 {
103         s32 x, y, width, height;        /* It's really s32 in videodev.h */
104         compat_caddr_t next;
105 };
106
107 struct video_window32 {
108         u32 x, y, width, height, chromakey, flags;
109         compat_caddr_t clips;
110         compat_int_t clipcount;
111 };
112
113 static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
114 {
115         struct video_clip __user *uclips;
116         struct video_clip __user *kclips;
117         compat_caddr_t p;
118         int nclips;
119
120         if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
121                 return -EFAULT;
122
123         if (get_user(nclips, &up->clipcount))
124                 return -EFAULT;
125
126         if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)) ||
127             get_user(kp->x, &up->x) ||
128             get_user(kp->y, &up->y) ||
129             get_user(kp->width, &up->width) ||
130             get_user(kp->height, &up->height) ||
131             get_user(kp->chromakey, &up->chromakey) ||
132             get_user(kp->flags, &up->flags) ||
133             get_user(kp->clipcount, &up->clipcount))
134                 return -EFAULT;
135
136         nclips = kp->clipcount;
137         kp->clips = NULL;
138
139         if (nclips == 0)
140                 return 0;
141         if (get_user(p, &up->clips))
142                 return -EFAULT;
143         uclips = compat_ptr(p);
144
145         /* If nclips < 0, then it is a clipping bitmap of size
146            VIDEO_CLIPMAP_SIZE */
147         if (nclips < 0) {
148                 if (!access_ok(VERIFY_READ, uclips, VIDEO_CLIPMAP_SIZE))
149                         return -EFAULT;
150                 kp->clips = compat_alloc_user_space(VIDEO_CLIPMAP_SIZE);
151                 if (copy_in_user(kp->clips, uclips, VIDEO_CLIPMAP_SIZE))
152                         return -EFAULT;
153                 return 0;
154         }
155
156         /* Otherwise it is an array of video_clip structs. */
157         if (!access_ok(VERIFY_READ, uclips, nclips * sizeof(struct video_clip)))
158                 return -EFAULT;
159
160         kp->clips = compat_alloc_user_space(nclips * sizeof(struct video_clip));
161         kclips = kp->clips;
162         while (nclips--) {
163                 int err;
164
165                 err = copy_in_user(&kclips->x, &uclips->x, sizeof(kclips->x));
166                 err |= copy_in_user(&kclips->y, &uclips->y, sizeof(kclips->y));
167                 err |= copy_in_user(&kclips->width, &uclips->width, sizeof(kclips->width));
168                 err |= copy_in_user(&kclips->height, &uclips->height, sizeof(kclips->height));
169                 kclips->next = NULL;
170                 if (err)
171                         return -EFAULT;
172                 kclips++;
173                 uclips++;
174         }
175         return 0;
176 }
177
178 /* You get back everything except the clips... */
179 static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
180 {
181         if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
182                 put_user(kp->x, &up->x) ||
183                 put_user(kp->y, &up->y) ||
184                 put_user(kp->width, &up->width) ||
185                 put_user(kp->height, &up->height) ||
186                 put_user(kp->chromakey, &up->chromakey) ||
187                 put_user(kp->flags, &up->flags) ||
188                 put_user(kp->clipcount, &up->clipcount))
189                         return -EFAULT;
190         return 0;
191 }
192
193 struct video_code32 {
194         char            loadwhat[16];   /* name or tag of file being passed */
195         compat_int_t    datasize;
196         unsigned char   *data;
197 };
198
199 static int get_microcode32(struct video_code *kp, struct video_code32 __user *up)
200 {
201         if (!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
202                 copy_from_user(kp->loadwhat, up->loadwhat, sizeof(up->loadwhat)) ||
203                 get_user(kp->datasize, &up->datasize) ||
204                 copy_from_user(kp->data, up->data, up->datasize))
205                         return -EFAULT;
206         return 0;
207 }
208
209 #define VIDIOCGTUNER32          _IOWR('v', 4, struct video_tuner32)
210 #define VIDIOCSTUNER32          _IOW('v', 5, struct video_tuner32)
211 #define VIDIOCGWIN32            _IOR('v', 9, struct video_window32)
212 #define VIDIOCSWIN32            _IOW('v', 10, struct video_window32)
213 #define VIDIOCGFBUF32           _IOR('v', 11, struct video_buffer32)
214 #define VIDIOCSFBUF32           _IOW('v', 12, struct video_buffer32)
215 #define VIDIOCGFREQ32           _IOR('v', 14, u32)
216 #define VIDIOCSFREQ32           _IOW('v', 15, u32)
217 #define VIDIOCSMICROCODE32      _IOW('v', 27, struct video_code32)
218
219 #define VIDIOCCAPTURE32         _IOW('v', 8, s32)
220 #define VIDIOCSYNC32            _IOW('v', 18, s32)
221 #define VIDIOCSWRITEMODE32      _IOW('v', 25, s32)
222
223 #endif
224
225 static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
226 {
227         int ret = -ENOIOCTLCMD;
228
229         if (file->f_op->unlocked_ioctl)
230                 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
231         else if (file->f_op->ioctl) {
232                 lock_kernel();
233                 ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
234                 unlock_kernel();
235         }
236
237         return ret;
238 }
239
240
241 struct v4l2_clip32 {
242         struct v4l2_rect        c;
243         compat_caddr_t          next;
244 };
245
246 struct v4l2_window32 {
247         struct v4l2_rect        w;
248         enum v4l2_field         field;
249         __u32                   chromakey;
250         compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
251         __u32                   clipcount;
252         compat_caddr_t          bitmap;
253 };
254
255 static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
256 {
257         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
258                 copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
259                 get_user(kp->field, &up->field) ||
260                 get_user(kp->chromakey, &up->chromakey) ||
261                 get_user(kp->clipcount, &up->clipcount))
262                         return -EFAULT;
263         if (kp->clipcount > 2048)
264                 return -EINVAL;
265         if (kp->clipcount) {
266                 struct v4l2_clip32 __user *uclips;
267                 struct v4l2_clip __user *kclips;
268                 int n = kp->clipcount;
269                 compat_caddr_t p;
270
271                 if (get_user(p, &up->clips))
272                         return -EFAULT;
273                 uclips = compat_ptr(p);
274                 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
275                 kp->clips = kclips;
276                 while (--n >= 0) {
277                         if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
278                                 return -EFAULT;
279                         if (put_user(n ? kclips + 1 : NULL, &kclips->next))
280                                 return -EFAULT;
281                         uclips += 1;
282                         kclips += 1;
283                 }
284         } else
285                 kp->clips = NULL;
286         return 0;
287 }
288
289 static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
290 {
291         if (copy_to_user(&up->w, &kp->w, sizeof(up->w)) ||
292                 put_user(kp->field, &up->field) ||
293                 put_user(kp->chromakey, &up->chromakey) ||
294                 put_user(kp->clipcount, &up->clipcount))
295                         return -EFAULT;
296         return 0;
297 }
298
299 static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
300 {
301         if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
302                 return -EFAULT;
303         return 0;
304 }
305
306 static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
307 {
308         if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
309                 return -EFAULT;
310         return 0;
311 }
312
313 static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
314 {
315         if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
316                 return -EFAULT;
317         return 0;
318 }
319
320 static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
321 {
322         if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
323                 return -EFAULT;
324         return 0;
325 }
326
327 static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
328 {
329         if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
330                 return -EFAULT;
331         return 0;
332 }
333
334 static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
335 {
336         if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
337                 return -EFAULT;
338         return 0;
339 }
340
341 struct v4l2_format32 {
342         enum v4l2_buf_type type;
343         union {
344                 struct v4l2_pix_format  pix;
345                 struct v4l2_window32    win;
346                 struct v4l2_vbi_format  vbi;
347                 struct v4l2_sliced_vbi_format   sliced;
348                 __u8    raw_data[200];        /* user-defined */
349         } fmt;
350 };
351
352 static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
353 {
354         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
355                         get_user(kp->type, &up->type))
356                         return -EFAULT;
357         switch (kp->type) {
358         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
359         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
360                 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
361         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
362         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
363                 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
364         case V4L2_BUF_TYPE_VBI_CAPTURE:
365         case V4L2_BUF_TYPE_VBI_OUTPUT:
366                 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
367         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
368         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
369                 return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
370         case V4L2_BUF_TYPE_PRIVATE:
371                 if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
372                         return -EFAULT;
373                 return 0;
374         case 0:
375                 return -EINVAL;
376         default:
377                 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
378                                                                 kp->type);
379                 return -EINVAL;
380         }
381 }
382
383 static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
384 {
385         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
386                 put_user(kp->type, &up->type))
387                 return -EFAULT;
388         switch (kp->type) {
389         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
390         case V4L2_BUF_TYPE_VIDEO_OUTPUT:
391                 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
392         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
393         case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
394                 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
395         case V4L2_BUF_TYPE_VBI_CAPTURE:
396         case V4L2_BUF_TYPE_VBI_OUTPUT:
397                 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
398         case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
399         case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
400                 return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
401         case V4L2_BUF_TYPE_PRIVATE:
402                 if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
403                         return -EFAULT;
404                 return 0;
405         case 0:
406                 return -EINVAL;
407         default:
408                 printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
409                                                                 kp->type);
410                 return -EINVAL;
411         }
412 }
413
414 struct v4l2_standard32 {
415         __u32                index;
416         __u32                id[2]; /* __u64 would get the alignment wrong */
417         __u8                 name[24];
418         struct v4l2_fract    frameperiod; /* Frames, not fields */
419         __u32                framelines;
420         __u32                reserved[4];
421 };
422
423 static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
424 {
425         /* other fields are not set by the user, nor used by the driver */
426         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
427                 get_user(kp->index, &up->index))
428                 return -EFAULT;
429         return 0;
430 }
431
432 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
433 {
434         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
435                 put_user(kp->index, &up->index) ||
436                 copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
437                 copy_to_user(up->name, kp->name, 24) ||
438                 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
439                 put_user(kp->framelines, &up->framelines) ||
440                 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
441                         return -EFAULT;
442         return 0;
443 }
444
445 struct v4l2_buffer32 {
446         __u32                   index;
447         enum v4l2_buf_type      type;
448         __u32                   bytesused;
449         __u32                   flags;
450         enum v4l2_field         field;
451         struct compat_timeval   timestamp;
452         struct v4l2_timecode    timecode;
453         __u32                   sequence;
454
455         /* memory location */
456         enum v4l2_memory        memory;
457         union {
458                 __u32           offset;
459                 compat_long_t   userptr;
460         } m;
461         __u32                   length;
462         __u32                   input;
463         __u32                   reserved;
464 };
465
466 static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
467 {
468
469         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
470                 get_user(kp->index, &up->index) ||
471                 get_user(kp->type, &up->type) ||
472                 get_user(kp->flags, &up->flags) ||
473                 get_user(kp->memory, &up->memory) ||
474                 get_user(kp->input, &up->input))
475                         return -EFAULT;
476         switch (kp->memory) {
477         case V4L2_MEMORY_MMAP:
478                 break;
479         case V4L2_MEMORY_USERPTR:
480                 {
481                 compat_long_t tmp;
482
483                 if (get_user(kp->length, &up->length) ||
484                     get_user(tmp, &up->m.userptr))
485                         return -EFAULT;
486
487                 kp->m.userptr = (unsigned long)compat_ptr(tmp);
488                 }
489                 break;
490         case V4L2_MEMORY_OVERLAY:
491                 if (get_user(kp->m.offset, &up->m.offset))
492                         return -EFAULT;
493                 break;
494         }
495         return 0;
496 }
497
498 static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
499 {
500         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
501                 put_user(kp->index, &up->index) ||
502                 put_user(kp->type, &up->type) ||
503                 put_user(kp->flags, &up->flags) ||
504                 put_user(kp->memory, &up->memory) ||
505                 put_user(kp->input, &up->input))
506                         return -EFAULT;
507         switch (kp->memory) {
508         case V4L2_MEMORY_MMAP:
509                 if (put_user(kp->length, &up->length) ||
510                         put_user(kp->m.offset, &up->m.offset))
511                         return -EFAULT;
512                 break;
513         case V4L2_MEMORY_USERPTR:
514                 if (put_user(kp->length, &up->length) ||
515                         put_user(kp->m.userptr, &up->m.userptr))
516                         return -EFAULT;
517                 break;
518         case V4L2_MEMORY_OVERLAY:
519                 if (put_user(kp->m.offset, &up->m.offset))
520                         return -EFAULT;
521                 break;
522         }
523         if (put_user(kp->bytesused, &up->bytesused) ||
524                 put_user(kp->field, &up->field) ||
525                 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
526                 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
527                 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
528                 put_user(kp->sequence, &up->sequence) ||
529                 put_user(kp->reserved, &up->reserved))
530                         return -EFAULT;
531         return 0;
532 }
533
534 struct v4l2_framebuffer32 {
535         __u32                   capability;
536         __u32                   flags;
537         compat_caddr_t          base;
538         struct v4l2_pix_format  fmt;
539 };
540
541 static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
542 {
543         u32 tmp;
544
545         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
546                 get_user(tmp, &up->base) ||
547                 get_user(kp->capability, &up->capability) ||
548                 get_user(kp->flags, &up->flags))
549                         return -EFAULT;
550         kp->base = compat_ptr(tmp);
551         get_v4l2_pix_format(&kp->fmt, &up->fmt);
552         return 0;
553 }
554
555 static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
556 {
557         u32 tmp = (u32)((unsigned long)kp->base);
558
559         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
560                 put_user(tmp, &up->base) ||
561                 put_user(kp->capability, &up->capability) ||
562                 put_user(kp->flags, &up->flags))
563                         return -EFAULT;
564         put_v4l2_pix_format(&kp->fmt, &up->fmt);
565         return 0;
566 }
567
568 struct v4l2_input32 {
569         __u32        index;             /*  Which input */
570         __u8         name[32];          /*  Label */
571         __u32        type;              /*  Type of input */
572         __u32        audioset;          /*  Associated audios (bitfield) */
573         __u32        tuner;             /*  Associated tuner */
574         v4l2_std_id  std;
575         __u32        status;
576         __u32        reserved[4];
577 } __attribute__ ((packed));
578
579 /* The 64-bit v4l2_input struct has extra padding at the end of the struct.
580    Otherwise it is identical to the 32-bit version. */
581 static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
582 {
583         if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
584                 return -EFAULT;
585         return 0;
586 }
587
588 static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
589 {
590         if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
591                 return -EFAULT;
592         return 0;
593 }
594
595 struct v4l2_ext_controls32 {
596        __u32 ctrl_class;
597        __u32 count;
598        __u32 error_idx;
599        __u32 reserved[2];
600        compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
601 };
602
603 static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
604 {
605         struct v4l2_ext_control __user *ucontrols;
606         struct v4l2_ext_control __user *kcontrols;
607         int n;
608         compat_caddr_t p;
609
610         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
611                 get_user(kp->ctrl_class, &up->ctrl_class) ||
612                 get_user(kp->count, &up->count) ||
613                 get_user(kp->error_idx, &up->error_idx) ||
614                 copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
615                         return -EFAULT;
616         n = kp->count;
617         if (n == 0) {
618                 kp->controls = NULL;
619                 return 0;
620         }
621         if (get_user(p, &up->controls))
622                 return -EFAULT;
623         ucontrols = compat_ptr(p);
624         if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
625                 return -EFAULT;
626         kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
627         kp->controls = kcontrols;
628         while (--n >= 0) {
629                 if (copy_in_user(&kcontrols->id, &ucontrols->id, sizeof(__u32)))
630                         return -EFAULT;
631                 if (copy_in_user(&kcontrols->reserved2, &ucontrols->reserved2, sizeof(ucontrols->reserved2)))
632                         return -EFAULT;
633                 /* Note: if the void * part of the union ever becomes relevant
634                    then we need to know the type of the control in order to do
635                    the right thing here. Luckily, that is not yet an issue. */
636                 if (copy_in_user(&kcontrols->value, &ucontrols->value, sizeof(ucontrols->value)))
637                         return -EFAULT;
638                 ucontrols++;
639                 kcontrols++;
640         }
641         return 0;
642 }
643
644 static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
645 {
646         struct v4l2_ext_control __user *ucontrols;
647         struct v4l2_ext_control __user *kcontrols = kp->controls;
648         int n = kp->count;
649         compat_caddr_t p;
650
651         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
652                 put_user(kp->ctrl_class, &up->ctrl_class) ||
653                 put_user(kp->count, &up->count) ||
654                 put_user(kp->error_idx, &up->error_idx) ||
655                 copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
656                         return -EFAULT;
657         if (!kp->count)
658                 return 0;
659
660         if (get_user(p, &up->controls))
661                 return -EFAULT;
662         ucontrols = compat_ptr(p);
663         if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
664                 return -EFAULT;
665
666         while (--n >= 0) {
667                 if (copy_in_user(&ucontrols->id, &kcontrols->id, sizeof(__u32)))
668                         return -EFAULT;
669                 if (copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
670                                         sizeof(ucontrols->reserved2)))
671                         return -EFAULT;
672                 /* Note: if the void * part of the union ever becomes relevant
673                    then we need to know the type of the control in order to do
674                    the right thing here. Luckily, that is not yet an issue. */
675                 if (copy_in_user(&ucontrols->value, &kcontrols->value, sizeof(ucontrols->value)))
676                         return -EFAULT;
677                 ucontrols++;
678                 kcontrols++;
679         }
680         return 0;
681 }
682
683 #define VIDIOC_G_FMT32          _IOWR('V',  4, struct v4l2_format32)
684 #define VIDIOC_S_FMT32          _IOWR('V',  5, struct v4l2_format32)
685 #define VIDIOC_QUERYBUF32       _IOWR('V',  9, struct v4l2_buffer32)
686 #define VIDIOC_G_FBUF32         _IOR ('V', 10, struct v4l2_framebuffer32)
687 #define VIDIOC_S_FBUF32         _IOW ('V', 11, struct v4l2_framebuffer32)
688 #define VIDIOC_QBUF32           _IOWR('V', 15, struct v4l2_buffer32)
689 #define VIDIOC_DQBUF32          _IOWR('V', 17, struct v4l2_buffer32)
690 #define VIDIOC_ENUMSTD32        _IOWR('V', 25, struct v4l2_standard32)
691 #define VIDIOC_ENUMINPUT32      _IOWR('V', 26, struct v4l2_input32)
692 #define VIDIOC_TRY_FMT32        _IOWR('V', 64, struct v4l2_format32)
693 #define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
694 #define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
695 #define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
696
697 #define VIDIOC_OVERLAY32        _IOW ('V', 14, s32)
698 #define VIDIOC_OVERLAY32_OLD    _IOWR('V', 14, s32)
699 #define VIDIOC_STREAMON32       _IOW ('V', 18, s32)
700 #define VIDIOC_STREAMOFF32      _IOW ('V', 19, s32)
701 #define VIDIOC_G_INPUT32        _IOR ('V', 38, s32)
702 #define VIDIOC_S_INPUT32        _IOWR('V', 39, s32)
703 #define VIDIOC_G_OUTPUT32       _IOR ('V', 46, s32)
704 #define VIDIOC_S_OUTPUT32       _IOWR('V', 47, s32)
705
706 static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
707 {
708         union {
709 #ifdef CONFIG_VIDEO_V4L1_COMPAT
710                 struct video_tuner vt;
711                 struct video_buffer vb;
712                 struct video_window vw;
713                 struct video_code vc;
714                 struct video_audio va;
715 #endif
716                 struct v4l2_format v2f;
717                 struct v4l2_buffer v2b;
718                 struct v4l2_framebuffer v2fb;
719                 struct v4l2_input v2i;
720                 struct v4l2_standard v2s;
721                 struct v4l2_ext_controls v2ecs;
722                 unsigned long vx;
723                 int vi;
724         } karg;
725         void __user *up = compat_ptr(arg);
726         int compatible_arg = 1;
727         int err = 0;
728
729         /* First, convert the command. */
730         switch (cmd) {
731 #ifdef CONFIG_VIDEO_V4L1_COMPAT
732         case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break;
733         case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break;
734         case VIDIOCGWIN32: cmd = VIDIOCGWIN; break;
735         case VIDIOCSWIN32: cmd = VIDIOCSWIN; break;
736         case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break;
737         case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break;
738         case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break;
739         case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break;
740         case VIDIOCSMICROCODE32: cmd = VIDIOCSMICROCODE; break;
741 #endif
742         case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
743         case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
744         case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
745         case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
746         case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
747         case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
748         case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
749         case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
750         case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
751         case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
752         case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
753         case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
754         case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
755         case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
756         case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
757         case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
758         case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
759         case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
760         case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
761         case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
762         case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
763         }
764
765         switch (cmd) {
766 #ifdef CONFIG_VIDEO_V4L1_COMPAT
767         case VIDIOCSTUNER:
768         case VIDIOCGTUNER:
769                 err = get_video_tuner32(&karg.vt, up);
770                 compatible_arg = 0;
771                 break;
772
773         case VIDIOCSFBUF:
774                 err = get_video_buffer32(&karg.vb, up);
775                 compatible_arg = 0;
776                 break;
777
778         case VIDIOCSWIN:
779                 err = get_video_window32(&karg.vw, up);
780                 compatible_arg = 0;
781                 break;
782
783         case VIDIOCGWIN:
784         case VIDIOCGFBUF:
785         case VIDIOCGFREQ:
786                 compatible_arg = 0;
787                 break;
788
789         case VIDIOCSMICROCODE:
790                 err = get_microcode32(&karg.vc, up);
791                 compatible_arg = 0;
792                 break;
793
794         case VIDIOCSFREQ:
795                 err = get_user(karg.vx, (u32 __user *)up);
796                 compatible_arg = 0;
797                 break;
798
799         case VIDIOCCAPTURE:
800         case VIDIOCSYNC:
801         case VIDIOCSWRITEMODE:
802 #endif
803         case VIDIOC_OVERLAY:
804         case VIDIOC_STREAMON:
805         case VIDIOC_STREAMOFF:
806         case VIDIOC_S_INPUT:
807         case VIDIOC_S_OUTPUT:
808                 err = get_user(karg.vi, (s32 __user *)up);
809                 compatible_arg = 0;
810                 break;
811
812         case VIDIOC_G_INPUT:
813         case VIDIOC_G_OUTPUT:
814                 compatible_arg = 0;
815                 break;
816
817         case VIDIOC_G_FMT:
818         case VIDIOC_S_FMT:
819         case VIDIOC_TRY_FMT:
820                 err = get_v4l2_format32(&karg.v2f, up);
821                 compatible_arg = 0;
822                 break;
823
824         case VIDIOC_QUERYBUF:
825         case VIDIOC_QBUF:
826         case VIDIOC_DQBUF:
827                 err = get_v4l2_buffer32(&karg.v2b, up);
828                 compatible_arg = 0;
829                 break;
830
831         case VIDIOC_S_FBUF:
832                 err = get_v4l2_framebuffer32(&karg.v2fb, up);
833                 compatible_arg = 0;
834                 break;
835
836         case VIDIOC_G_FBUF:
837                 compatible_arg = 0;
838                 break;
839
840         case VIDIOC_ENUMSTD:
841                 err = get_v4l2_standard32(&karg.v2s, up);
842                 compatible_arg = 0;
843                 break;
844
845         case VIDIOC_ENUMINPUT:
846                 err = get_v4l2_input32(&karg.v2i, up);
847                 compatible_arg = 0;
848                 break;
849
850         case VIDIOC_G_EXT_CTRLS:
851         case VIDIOC_S_EXT_CTRLS:
852         case VIDIOC_TRY_EXT_CTRLS:
853                 err = get_v4l2_ext_controls32(&karg.v2ecs, up);
854                 compatible_arg = 0;
855                 break;
856         }
857         if (err)
858                 return err;
859
860         if (compatible_arg)
861                 err = native_ioctl(file, cmd, (unsigned long)up);
862         else {
863                 mm_segment_t old_fs = get_fs();
864
865                 set_fs(KERNEL_DS);
866                 err = native_ioctl(file, cmd, (unsigned long)&karg);
867                 set_fs(old_fs);
868         }
869
870         /* Special case: even after an error we need to put the
871            results back for these ioctls since the error_idx will
872            contain information on which control failed. */
873         switch (cmd) {
874         case VIDIOC_G_EXT_CTRLS:
875         case VIDIOC_S_EXT_CTRLS:
876         case VIDIOC_TRY_EXT_CTRLS:
877                 if (put_v4l2_ext_controls32(&karg.v2ecs, up))
878                         err = -EFAULT;
879                 break;
880         }
881         if (err)
882                 return err;
883
884         switch (cmd) {
885 #ifdef CONFIG_VIDEO_V4L1_COMPAT
886         case VIDIOCGTUNER:
887                 err = put_video_tuner32(&karg.vt, up);
888                 break;
889
890         case VIDIOCGWIN:
891                 err = put_video_window32(&karg.vw, up);
892                 break;
893
894         case VIDIOCGFBUF:
895                 err = put_video_buffer32(&karg.vb, up);
896                 break;
897
898         case VIDIOCGFREQ:
899                 err = put_user(((u32)karg.vx), (u32 __user *)up);
900                 break;
901 #endif
902         case VIDIOC_S_INPUT:
903         case VIDIOC_S_OUTPUT:
904         case VIDIOC_G_INPUT:
905         case VIDIOC_G_OUTPUT:
906                 err = put_user(((s32)karg.vi), (s32 __user *)up);
907                 break;
908
909         case VIDIOC_G_FBUF:
910                 err = put_v4l2_framebuffer32(&karg.v2fb, up);
911                 break;
912
913         case VIDIOC_G_FMT:
914         case VIDIOC_S_FMT:
915         case VIDIOC_TRY_FMT:
916                 err = put_v4l2_format32(&karg.v2f, up);
917                 break;
918
919         case VIDIOC_QUERYBUF:
920         case VIDIOC_QBUF:
921         case VIDIOC_DQBUF:
922                 err = put_v4l2_buffer32(&karg.v2b, up);
923                 break;
924
925         case VIDIOC_ENUMSTD:
926                 err = put_v4l2_standard32(&karg.v2s, up);
927                 break;
928
929         case VIDIOC_ENUMINPUT:
930                 err = put_v4l2_input32(&karg.v2i, up);
931                 break;
932         }
933         return err;
934 }
935
936 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
937 {
938         int ret = -ENOIOCTLCMD;
939
940         if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
941                 return ret;
942
943         switch (cmd) {
944 #ifdef CONFIG_VIDEO_V4L1_COMPAT
945         case VIDIOCGCAP:
946         case VIDIOCGCHAN:
947         case VIDIOCSCHAN:
948         case VIDIOCGTUNER32:
949         case VIDIOCSTUNER32:
950         case VIDIOCGPICT:
951         case VIDIOCSPICT:
952         case VIDIOCCAPTURE32:
953         case VIDIOCGWIN32:
954         case VIDIOCSWIN32:
955         case VIDIOCGFBUF32:
956         case VIDIOCSFBUF32:
957         case VIDIOCKEY:
958         case VIDIOCGFREQ32:
959         case VIDIOCSFREQ32:
960         case VIDIOCGAUDIO:
961         case VIDIOCSAUDIO:
962         case VIDIOCSYNC32:
963         case VIDIOCMCAPTURE:
964         case VIDIOCGMBUF:
965         case VIDIOCGUNIT:
966         case VIDIOCGCAPTURE:
967         case VIDIOCSCAPTURE:
968         case VIDIOCSPLAYMODE:
969         case VIDIOCSWRITEMODE32:
970         case VIDIOCGPLAYINFO:
971         case VIDIOCSMICROCODE32:
972         case VIDIOCGVBIFMT:
973         case VIDIOCSVBIFMT:
974 #endif
975 #ifdef __OLD_VIDIOC_
976         case VIDIOC_OVERLAY32_OLD:
977         case VIDIOC_S_PARM_OLD:
978         case VIDIOC_S_CTRL_OLD:
979         case VIDIOC_G_AUDIO_OLD:
980         case VIDIOC_G_AUDOUT_OLD:
981         case VIDIOC_CROPCAP_OLD:
982 #endif
983         case VIDIOC_QUERYCAP:
984         case VIDIOC_RESERVED:
985         case VIDIOC_ENUM_FMT:
986         case VIDIOC_G_FMT32:
987         case VIDIOC_S_FMT32:
988         case VIDIOC_REQBUFS:
989         case VIDIOC_QUERYBUF32:
990         case VIDIOC_G_FBUF32:
991         case VIDIOC_S_FBUF32:
992         case VIDIOC_OVERLAY32:
993         case VIDIOC_QBUF32:
994         case VIDIOC_DQBUF32:
995         case VIDIOC_STREAMON32:
996         case VIDIOC_STREAMOFF32:
997         case VIDIOC_G_PARM:
998         case VIDIOC_S_PARM:
999         case VIDIOC_G_STD:
1000         case VIDIOC_S_STD:
1001         case VIDIOC_ENUMSTD32:
1002         case VIDIOC_ENUMINPUT32:
1003         case VIDIOC_G_CTRL:
1004         case VIDIOC_S_CTRL:
1005         case VIDIOC_G_TUNER:
1006         case VIDIOC_S_TUNER:
1007         case VIDIOC_G_AUDIO:
1008         case VIDIOC_S_AUDIO:
1009         case VIDIOC_QUERYCTRL:
1010         case VIDIOC_QUERYMENU:
1011         case VIDIOC_G_INPUT32:
1012         case VIDIOC_S_INPUT32:
1013         case VIDIOC_G_OUTPUT32:
1014         case VIDIOC_S_OUTPUT32:
1015         case VIDIOC_ENUMOUTPUT:
1016         case VIDIOC_G_AUDOUT:
1017         case VIDIOC_S_AUDOUT:
1018         case VIDIOC_G_MODULATOR:
1019         case VIDIOC_S_MODULATOR:
1020         case VIDIOC_S_FREQUENCY:
1021         case VIDIOC_G_FREQUENCY:
1022         case VIDIOC_CROPCAP:
1023         case VIDIOC_G_CROP:
1024         case VIDIOC_S_CROP:
1025         case VIDIOC_G_JPEGCOMP:
1026         case VIDIOC_S_JPEGCOMP:
1027         case VIDIOC_QUERYSTD:
1028         case VIDIOC_TRY_FMT32:
1029         case VIDIOC_ENUMAUDIO:
1030         case VIDIOC_ENUMAUDOUT:
1031         case VIDIOC_G_PRIORITY:
1032         case VIDIOC_S_PRIORITY:
1033         case VIDIOC_G_SLICED_VBI_CAP:
1034         case VIDIOC_LOG_STATUS:
1035         case VIDIOC_G_EXT_CTRLS32:
1036         case VIDIOC_S_EXT_CTRLS32:
1037         case VIDIOC_TRY_EXT_CTRLS32:
1038         case VIDIOC_ENUM_FRAMESIZES:
1039         case VIDIOC_ENUM_FRAMEINTERVALS:
1040         case VIDIOC_G_ENC_INDEX:
1041         case VIDIOC_ENCODER_CMD:
1042         case VIDIOC_TRY_ENCODER_CMD:
1043         case VIDIOC_DBG_S_REGISTER:
1044         case VIDIOC_DBG_G_REGISTER:
1045         case VIDIOC_G_CHIP_IDENT:
1046         case VIDIOC_S_HW_FREQ_SEEK:
1047                 ret = do_video_ioctl(file, cmd, arg);
1048                 break;
1049
1050 #ifdef CONFIG_VIDEO_V4L1_COMPAT
1051         /* BTTV specific... */
1052         case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
1053         case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
1054         case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
1055         case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
1056         case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
1057         case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
1058         case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
1059         case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
1060                 ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
1061                 break;
1062 #endif
1063         default:
1064                 v4l_print_ioctl("compat_ioctl32", cmd);
1065                 printk(KERN_CONT "\n");
1066                 break;
1067         }
1068         return ret;
1069 }
1070 #else
1071 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1072 {
1073         return -ENOIOCTLCMD;
1074 }
1075 #endif
1076 EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
1077
1078 MODULE_LICENSE("GPL");