Merge branch 'topic/oxygen' into to-push
[linux-2.6] / drivers / media / video / 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  *
11  * These routines maintain argument size conversion between 32bit and 64bit
12  * ioctls.
13  */
14
15 #include <linux/compat.h>
16 #include <linux/videodev.h>
17 #include <linux/videodev2.h>
18 #include <linux/module.h>
19 #include <linux/smp_lock.h>
20 #include <media/v4l2-ioctl.h>
21
22 #ifdef CONFIG_COMPAT
23
24 #ifdef CONFIG_VIDEO_V4L1_COMPAT
25 struct video_tuner32 {
26         compat_int_t tuner;
27         char name[32];
28         compat_ulong_t rangelow, rangehigh;
29         u32 flags;      /* It is really u32 in videodev.h */
30         u16 mode, signal;
31 };
32
33 static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
34 {
35         if(!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
36                 get_user(kp->tuner, &up->tuner) ||
37                 copy_from_user(kp->name, up->name, 32) ||
38                 get_user(kp->rangelow, &up->rangelow) ||
39                 get_user(kp->rangehigh, &up->rangehigh) ||
40                 get_user(kp->flags, &up->flags) ||
41                 get_user(kp->mode, &up->mode) ||
42                 get_user(kp->signal, &up->signal))
43                 return -EFAULT;
44         return 0;
45 }
46
47 static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
48 {
49         if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
50                 put_user(kp->tuner, &up->tuner) ||
51                 copy_to_user(up->name, kp->name, 32) ||
52                 put_user(kp->rangelow, &up->rangelow) ||
53                 put_user(kp->rangehigh, &up->rangehigh) ||
54                 put_user(kp->flags, &up->flags) ||
55                 put_user(kp->mode, &up->mode) ||
56                 put_user(kp->signal, &up->signal))
57                         return -EFAULT;
58         return 0;
59 }
60
61
62 struct video_buffer32 {
63         compat_caddr_t base;
64         compat_int_t height, width, depth, bytesperline;
65 };
66
67 static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
68 {
69         u32 tmp;
70
71         if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
72                 get_user(tmp, &up->base) ||
73                 get_user(kp->height, &up->height) ||
74                 get_user(kp->width, &up->width) ||
75                 get_user(kp->depth, &up->depth) ||
76                 get_user(kp->bytesperline, &up->bytesperline))
77                         return -EFAULT;
78
79         /* This is actually a physical address stored
80          * as a void pointer.
81          */
82         kp->base = (void *)(unsigned long) tmp;
83
84         return 0;
85 }
86
87 static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
88 {
89         u32 tmp = (u32)((unsigned long)kp->base);
90
91         if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
92                 put_user(tmp, &up->base) ||
93                 put_user(kp->height, &up->height) ||
94                 put_user(kp->width, &up->width) ||
95                 put_user(kp->depth, &up->depth) ||
96                 put_user(kp->bytesperline, &up->bytesperline))
97                         return -EFAULT;
98         return 0;
99 }
100
101 struct video_clip32 {
102         s32 x, y, width, height;        /* Its really s32 in videodev.h */
103         compat_caddr_t next;
104 };
105
106 struct video_window32 {
107         u32 x, y, width, height, chromakey, flags;
108         compat_caddr_t clips;
109         compat_int_t clipcount;
110 };
111 #endif
112
113 static int native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
114 {
115         int ret = -ENOIOCTLCMD;
116
117         if (file->f_op->unlocked_ioctl)
118                 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
119         else if (file->f_op->ioctl) {
120                 lock_kernel();
121                 ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
122                 unlock_kernel();
123         }
124
125         return ret;
126 }
127
128
129 #ifdef CONFIG_VIDEO_V4L1_COMPAT
130 /* You get back everything except the clips... */
131 static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
132 {
133         if(!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
134                 put_user(kp->x, &up->x) ||
135                 put_user(kp->y, &up->y) ||
136                 put_user(kp->width, &up->width) ||
137                 put_user(kp->height, &up->height) ||
138                 put_user(kp->chromakey, &up->chromakey) ||
139                 put_user(kp->flags, &up->flags) ||
140                 put_user(kp->clipcount, &up->clipcount))
141                         return -EFAULT;
142         return 0;
143 }
144 #endif
145
146 struct v4l2_clip32
147 {
148         struct v4l2_rect        c;
149         compat_caddr_t          next;
150 };
151
152 struct v4l2_window32
153 {
154         struct v4l2_rect        w;
155         enum v4l2_field         field;
156         __u32                   chromakey;
157         compat_caddr_t          clips; /* actually struct v4l2_clip32 * */
158         __u32                   clipcount;
159         compat_caddr_t          bitmap;
160 };
161
162 static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
163 {
164         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
165                 copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
166                 get_user(kp->field, &up->field) ||
167                 get_user(kp->chromakey, &up->chromakey) ||
168                 get_user(kp->clipcount, &up->clipcount))
169                         return -EFAULT;
170         if (kp->clipcount > 2048)
171                 return -EINVAL;
172         if (kp->clipcount) {
173                 struct v4l2_clip32 __user *uclips;
174                 struct v4l2_clip __user *kclips;
175                 int n = kp->clipcount;
176                 compat_caddr_t p;
177
178                 if (get_user(p, &up->clips))
179                         return -EFAULT;
180                 uclips = compat_ptr(p);
181                 kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
182                 kp->clips = kclips;
183                 while (--n >= 0) {
184                         if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
185                                 return -EFAULT;
186                         if (put_user(n ? kclips + 1 : NULL, &kclips->next))
187                                 return -EFAULT;
188                         uclips += 1;
189                         kclips += 1;
190                 }
191         } else
192                 kp->clips = NULL;
193         return 0;
194 }
195
196 static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
197 {
198         if (copy_to_user(&up->w, &kp->w, sizeof(up->w)) ||
199                 put_user(kp->field, &up->field) ||
200                 put_user(kp->chromakey, &up->chromakey) ||
201                 put_user(kp->clipcount, &up->clipcount))
202                         return -EFAULT;
203         return 0;
204 }
205
206 static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
207 {
208         if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
209                 return -EFAULT;
210         return 0;
211 }
212
213 static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
214 {
215         if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
216                 return -EFAULT;
217         return 0;
218 }
219
220 static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
221 {
222         if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
223                 return -EFAULT;
224         return 0;
225 }
226
227 static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
228 {
229         if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
230                 return -EFAULT;
231         return 0;
232 }
233
234 struct v4l2_format32
235 {
236         enum v4l2_buf_type type;
237         union
238         {
239                 struct v4l2_pix_format  pix;  // V4L2_BUF_TYPE_VIDEO_CAPTURE
240                 struct v4l2_window32    win;  // V4L2_BUF_TYPE_VIDEO_OVERLAY
241                 struct v4l2_vbi_format  vbi;  // V4L2_BUF_TYPE_VBI_CAPTURE
242                 __u8    raw_data[200];        // user-defined
243         } fmt;
244 };
245
246 static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
247 {
248         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
249                         get_user(kp->type, &up->type))
250                         return -EFAULT;
251         switch (kp->type) {
252         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
253                 return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
254         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
255                 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
256         case V4L2_BUF_TYPE_VBI_CAPTURE:
257                 return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
258         default:
259                 printk("compat_ioctl : unexpected VIDIOC_FMT type %d\n",
260                                                                 kp->type);
261                 return -ENXIO;
262         }
263 }
264
265 static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
266 {
267         if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
268                 put_user(kp->type, &up->type))
269                 return -EFAULT;
270         switch (kp->type) {
271         case V4L2_BUF_TYPE_VIDEO_CAPTURE:
272                 return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
273         case V4L2_BUF_TYPE_VIDEO_OVERLAY:
274                 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
275         case V4L2_BUF_TYPE_VBI_CAPTURE:
276                 return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
277         default:
278                 return -ENXIO;
279         }
280 }
281
282 static inline int get_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
283 {
284         if (copy_from_user(kp, up, sizeof(struct v4l2_standard)))
285                 return -EFAULT;
286         return 0;
287
288 }
289
290 static inline int put_v4l2_standard(struct v4l2_standard *kp, struct v4l2_standard __user *up)
291 {
292         if (copy_to_user(up, kp, sizeof(struct v4l2_standard)))
293                 return -EFAULT;
294         return 0;
295 }
296
297 struct v4l2_standard32
298 {
299         __u32                index;
300         __u32                id[2]; /* __u64 would get the alignment wrong */
301         __u8                 name[24];
302         struct v4l2_fract    frameperiod; /* Frames, not fields */
303         __u32                framelines;
304         __u32                reserved[4];
305 };
306
307 static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
308 {
309         /* other fields are not set by the user, nor used by the driver */
310         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
311                 get_user(kp->index, &up->index))
312                 return -EFAULT;
313         return 0;
314 }
315
316 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
317 {
318         if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
319                 put_user(kp->index, &up->index) ||
320                 copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
321                 copy_to_user(up->name, kp->name, 24) ||
322                 copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
323                 put_user(kp->framelines, &up->framelines) ||
324                 copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
325                         return -EFAULT;
326         return 0;
327 }
328
329 static inline int get_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
330 {
331         if (copy_from_user(kp, up, sizeof(struct v4l2_tuner)))
332                 return -EFAULT;
333         return 0;
334
335 }
336
337 static inline int put_v4l2_tuner(struct v4l2_tuner *kp, struct v4l2_tuner __user *up)
338 {
339         if (copy_to_user(up, kp, sizeof(struct v4l2_tuner)))
340                 return -EFAULT;
341         return 0;
342 }
343
344 struct v4l2_buffer32
345 {
346         __u32                   index;
347         enum v4l2_buf_type      type;
348         __u32                   bytesused;
349         __u32                   flags;
350         enum v4l2_field         field;
351         struct compat_timeval   timestamp;
352         struct v4l2_timecode    timecode;
353         __u32                   sequence;
354
355         /* memory location */
356         enum v4l2_memory        memory;
357         union {
358                 __u32           offset;
359                 compat_long_t   userptr;
360         } m;
361         __u32                   length;
362         __u32                   input;
363         __u32                   reserved;
364 };
365
366 static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
367 {
368
369         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
370                 get_user(kp->index, &up->index) ||
371                 get_user(kp->type, &up->type) ||
372                 get_user(kp->flags, &up->flags) ||
373                 get_user(kp->memory, &up->memory) ||
374                 get_user(kp->input, &up->input))
375                         return -EFAULT;
376         switch(kp->memory) {
377         case V4L2_MEMORY_MMAP:
378                 break;
379         case V4L2_MEMORY_USERPTR:
380                 {
381                 compat_long_t tmp;
382
383                 if (get_user(kp->length, &up->length) ||
384                     get_user(tmp, &up->m.userptr))
385                         return -EFAULT;
386
387                 kp->m.userptr = (unsigned long)compat_ptr(tmp);
388                 }
389                 break;
390         case V4L2_MEMORY_OVERLAY:
391                 if(get_user(kp->m.offset, &up->m.offset))
392                         return -EFAULT;
393                 break;
394         }
395         return 0;
396 }
397
398 static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
399 {
400         if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
401                 put_user(kp->index, &up->index) ||
402                 put_user(kp->type, &up->type) ||
403                 put_user(kp->flags, &up->flags) ||
404                 put_user(kp->memory, &up->memory) ||
405                 put_user(kp->input, &up->input))
406                         return -EFAULT;
407         switch(kp->memory) {
408         case V4L2_MEMORY_MMAP:
409                 if (put_user(kp->length, &up->length) ||
410                         put_user(kp->m.offset, &up->m.offset))
411                         return -EFAULT;
412                 break;
413         case V4L2_MEMORY_USERPTR:
414                 if (put_user(kp->length, &up->length) ||
415                         put_user(kp->m.userptr, &up->m.userptr))
416                         return -EFAULT;
417                 break;
418         case V4L2_MEMORY_OVERLAY:
419                 if (put_user(kp->m.offset, &up->m.offset))
420                         return -EFAULT;
421                 break;
422         }
423         if (put_user(kp->bytesused, &up->bytesused) ||
424                 put_user(kp->field, &up->field) ||
425                 put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
426                 put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
427                 copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
428                 put_user(kp->sequence, &up->sequence) ||
429                 put_user(kp->reserved, &up->reserved))
430                         return -EFAULT;
431         return 0;
432 }
433
434 struct v4l2_framebuffer32
435 {
436         __u32                   capability;
437         __u32                   flags;
438         compat_caddr_t          base;
439         struct v4l2_pix_format  fmt;
440 };
441
442 static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
443 {
444         u32 tmp;
445
446         if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
447                 get_user(tmp, &up->base) ||
448                 get_user(kp->capability, &up->capability) ||
449                 get_user(kp->flags, &up->flags))
450                         return -EFAULT;
451         kp->base = compat_ptr(tmp);
452         get_v4l2_pix_format(&kp->fmt, &up->fmt);
453         return 0;
454 }
455
456 static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
457 {
458         u32 tmp = (u32)((unsigned long)kp->base);
459
460         if(!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
461                 put_user(tmp, &up->base) ||
462                 put_user(kp->capability, &up->capability) ||
463                 put_user(kp->flags, &up->flags))
464                         return -EFAULT;
465         put_v4l2_pix_format(&kp->fmt, &up->fmt);
466         return 0;
467 }
468
469 static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
470 {
471         if (copy_from_user(kp, up, sizeof(struct v4l2_input) - 4))
472                 return -EFAULT;
473         return 0;
474 }
475
476 static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input __user *up)
477 {
478         if (copy_to_user(up, kp, sizeof(struct v4l2_input) - 4))
479                 return -EFAULT;
480         return 0;
481 }
482
483 static inline int get_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
484 {
485         if (copy_from_user(kp, up, sizeof(struct v4l2_input)))
486                 return -EFAULT;
487         return 0;
488 }
489
490 static inline int put_v4l2_input(struct v4l2_input *kp, struct v4l2_input __user *up)
491 {
492         if (copy_to_user(up, kp, sizeof(struct v4l2_input)))
493                 return -EFAULT;
494         return 0;
495 }
496
497 #ifdef CONFIG_VIDEO_V4L1_COMPAT
498 struct video_code32
499 {
500         char            loadwhat[16];   /* name or tag of file being passed */
501         compat_int_t    datasize;
502         unsigned char   *data;
503 };
504
505 static inline int microcode32(struct video_code *kp, struct video_code32 __user *up)
506 {
507         if(!access_ok(VERIFY_READ, up, sizeof(struct video_code32)) ||
508                 copy_from_user(kp->loadwhat, up->loadwhat, sizeof (up->loadwhat)) ||
509                 get_user(kp->datasize, &up->datasize) ||
510                 copy_from_user(kp->data, up->data, up->datasize))
511                         return -EFAULT;
512         return 0;
513 }
514
515 #define VIDIOCGTUNER32          _IOWR('v',4, struct video_tuner32)
516 #define VIDIOCSTUNER32          _IOW('v',5, struct video_tuner32)
517 #define VIDIOCGWIN32            _IOR('v',9, struct video_window32)
518 #define VIDIOCSWIN32            _IOW('v',10, struct video_window32)
519 #define VIDIOCGFBUF32           _IOR('v',11, struct video_buffer32)
520 #define VIDIOCSFBUF32           _IOW('v',12, struct video_buffer32)
521 #define VIDIOCGFREQ32           _IOR('v',14, u32)
522 #define VIDIOCSFREQ32           _IOW('v',15, u32)
523 #define VIDIOCSMICROCODE32      _IOW('v',27, struct video_code32)
524
525 #endif
526
527 /* VIDIOC_ENUMINPUT32 is VIDIOC_ENUMINPUT minus 4 bytes of padding alignement */
528 #define VIDIOC_ENUMINPUT32      VIDIOC_ENUMINPUT - _IOC(0, 0, 0, 4)
529 #define VIDIOC_G_FMT32          _IOWR ('V',  4, struct v4l2_format32)
530 #define VIDIOC_S_FMT32          _IOWR ('V',  5, struct v4l2_format32)
531 #define VIDIOC_QUERYBUF32       _IOWR ('V',  9, struct v4l2_buffer32)
532 #define VIDIOC_G_FBUF32         _IOR  ('V', 10, struct v4l2_framebuffer32)
533 #define VIDIOC_S_FBUF32         _IOW  ('V', 11, struct v4l2_framebuffer32)
534 /* VIDIOC_OVERLAY is now _IOW, but was _IOWR */
535 #define VIDIOC_OVERLAY32        _IOWR ('V', 14, compat_int_t)
536 #define VIDIOC_QBUF32           _IOWR ('V', 15, struct v4l2_buffer32)
537 #define VIDIOC_DQBUF32          _IOWR ('V', 17, struct v4l2_buffer32)
538 #define VIDIOC_STREAMON32       _IOW  ('V', 18, compat_int_t)
539 #define VIDIOC_STREAMOFF32      _IOW  ('V', 19, compat_int_t)
540 #define VIDIOC_ENUMSTD32        _IOWR ('V', 25, struct v4l2_standard32)
541 /* VIDIOC_S_CTRL is now _IOWR, but was _IOW */
542 #define VIDIOC_S_CTRL32         _IOW  ('V', 28, struct v4l2_control)
543 #define VIDIOC_G_INPUT32        _IOR  ('V', 38, compat_int_t)
544 #define VIDIOC_S_INPUT32        _IOWR ('V', 39, compat_int_t)
545 #define VIDIOC_TRY_FMT32        _IOWR ('V', 64, struct v4l2_format32)
546
547 #ifdef CONFIG_VIDEO_V4L1_COMPAT
548 enum {
549         MaxClips = (~0U-sizeof(struct video_window))/sizeof(struct video_clip)
550 };
551
552 static int do_set_window(struct file *file, unsigned int cmd, unsigned long arg)
553 {
554         struct video_window32 __user *up = compat_ptr(arg);
555         struct video_window __user *vw;
556         struct video_clip __user *p;
557         int nclips;
558         u32 n;
559
560         if (!access_ok(VERIFY_READ, up, sizeof(struct video_window32)))
561                 return -EFAULT;
562
563         if (get_user(nclips, &up->clipcount))
564                 return -EFAULT;
565
566         /* Peculiar interface... */
567         if (nclips < 0)
568                 nclips = VIDEO_CLIPMAP_SIZE;
569
570         if (nclips > MaxClips)
571                 return -ENOMEM;
572
573         vw = compat_alloc_user_space(sizeof(struct video_window) +
574                                     nclips * sizeof(struct video_clip));
575
576         p = nclips ? (struct video_clip __user *)(vw + 1) : NULL;
577
578         if (get_user(n, &up->x) || put_user(n, &vw->x) ||
579             get_user(n, &up->y) || put_user(n, &vw->y) ||
580             get_user(n, &up->width) || put_user(n, &vw->width) ||
581             get_user(n, &up->height) || put_user(n, &vw->height) ||
582             get_user(n, &up->chromakey) || put_user(n, &vw->chromakey) ||
583             get_user(n, &up->flags) || put_user(n, &vw->flags) ||
584             get_user(n, &up->clipcount) || put_user(n, &vw->clipcount) ||
585             get_user(n, &up->clips) || put_user(p, &vw->clips))
586                 return -EFAULT;
587
588         if (nclips) {
589                 struct video_clip32 __user *u = compat_ptr(n);
590                 int i;
591                 if (!u)
592                         return -EINVAL;
593                 for (i = 0; i < nclips; i++, u++, p++) {
594                         s32 v;
595                         if (!access_ok(VERIFY_READ, u, sizeof(struct video_clip32)) ||
596                             !access_ok(VERIFY_WRITE, p, sizeof(struct video_clip32)) ||
597                             get_user(v, &u->x) ||
598                             put_user(v, &p->x) ||
599                             get_user(v, &u->y) ||
600                             put_user(v, &p->y) ||
601                             get_user(v, &u->width) ||
602                             put_user(v, &p->width) ||
603                             get_user(v, &u->height) ||
604                             put_user(v, &p->height) ||
605                             put_user(NULL, &p->next))
606                                 return -EFAULT;
607                 }
608         }
609
610         return native_ioctl(file, VIDIOCSWIN, (unsigned long)vw);
611 }
612 #endif
613
614 static int do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
615 {
616         union {
617 #ifdef CONFIG_VIDEO_V4L1_COMPAT
618                 struct video_tuner vt;
619                 struct video_buffer vb;
620                 struct video_window vw;
621                 struct video_code vc;
622                 struct video_audio va;
623 #endif
624                 struct v4l2_format v2f;
625                 struct v4l2_buffer v2b;
626                 struct v4l2_framebuffer v2fb;
627                 struct v4l2_standard v2s;
628                 struct v4l2_input v2i;
629                 struct v4l2_tuner v2t;
630                 unsigned long vx;
631         } karg;
632         void __user *up = compat_ptr(arg);
633         int compatible_arg = 1;
634         int err = 0;
635         int realcmd = cmd;
636
637         /* First, convert the command. */
638         switch(cmd) {
639 #ifdef CONFIG_VIDEO_V4L1_COMPAT
640         case VIDIOCGTUNER32: realcmd = cmd = VIDIOCGTUNER; break;
641         case VIDIOCSTUNER32: realcmd = cmd = VIDIOCSTUNER; break;
642         case VIDIOCGWIN32: realcmd = cmd = VIDIOCGWIN; break;
643         case VIDIOCGFBUF32: realcmd = cmd = VIDIOCGFBUF; break;
644         case VIDIOCSFBUF32: realcmd = cmd = VIDIOCSFBUF; break;
645         case VIDIOCGFREQ32: realcmd = cmd = VIDIOCGFREQ; break;
646         case VIDIOCSFREQ32: realcmd = cmd = VIDIOCSFREQ; break;
647         case VIDIOCSMICROCODE32: realcmd = cmd = VIDIOCSMICROCODE; break;
648 #endif
649         case VIDIOC_G_FMT32: realcmd = cmd = VIDIOC_G_FMT; break;
650         case VIDIOC_S_FMT32: realcmd = cmd = VIDIOC_S_FMT; break;
651         case VIDIOC_QUERYBUF32: realcmd = cmd = VIDIOC_QUERYBUF; break;
652         case VIDIOC_QBUF32: realcmd = cmd = VIDIOC_QBUF; break;
653         case VIDIOC_DQBUF32: realcmd = cmd = VIDIOC_DQBUF; break;
654         case VIDIOC_STREAMON32: realcmd = cmd = VIDIOC_STREAMON; break;
655         case VIDIOC_STREAMOFF32: realcmd = cmd = VIDIOC_STREAMOFF; break;
656         case VIDIOC_G_FBUF32: realcmd = cmd = VIDIOC_G_FBUF; break;
657         case VIDIOC_S_FBUF32: realcmd = cmd = VIDIOC_S_FBUF; break;
658         case VIDIOC_OVERLAY32: realcmd = cmd = VIDIOC_OVERLAY; break;
659         case VIDIOC_ENUMSTD32: realcmd = VIDIOC_ENUMSTD; break;
660         case VIDIOC_ENUMINPUT32: realcmd = VIDIOC_ENUMINPUT; break;
661         case VIDIOC_S_CTRL32: realcmd = cmd = VIDIOC_S_CTRL; break;
662         case VIDIOC_G_INPUT32: realcmd = cmd = VIDIOC_G_INPUT; break;
663         case VIDIOC_S_INPUT32: realcmd = cmd = VIDIOC_S_INPUT; break;
664         case VIDIOC_TRY_FMT32: realcmd = cmd = VIDIOC_TRY_FMT; break;
665         };
666
667         switch(cmd) {
668 #ifdef CONFIG_VIDEO_V4L1_COMPAT
669         case VIDIOCSTUNER:
670         case VIDIOCGTUNER:
671                 err = get_video_tuner32(&karg.vt, up);
672                 compatible_arg = 0;
673
674                 break;
675
676         case VIDIOCSFBUF:
677                 err = get_video_buffer32(&karg.vb, up);
678                 compatible_arg = 0;
679                 break;
680
681
682         case VIDIOCSFREQ:
683 #endif
684         case VIDIOC_S_INPUT:
685         case VIDIOC_OVERLAY:
686         case VIDIOC_STREAMON:
687         case VIDIOC_STREAMOFF:
688                 err = get_user(karg.vx, (u32 __user *)up);
689                 compatible_arg = 1;
690                 break;
691
692         case VIDIOC_S_FBUF:
693                 err = get_v4l2_framebuffer32(&karg.v2fb, up);
694                 compatible_arg = 0;
695                 break;
696
697         case VIDIOC_G_FMT:
698         case VIDIOC_S_FMT:
699         case VIDIOC_TRY_FMT:
700                 err = get_v4l2_format32(&karg.v2f, up);
701                 compatible_arg = 0;
702                 break;
703
704         case VIDIOC_QUERYBUF:
705         case VIDIOC_QBUF:
706         case VIDIOC_DQBUF:
707                 err = get_v4l2_buffer32(&karg.v2b, up);
708                 compatible_arg = 0;
709                 break;
710
711         case VIDIOC_ENUMSTD:
712                 err = get_v4l2_standard(&karg.v2s, up);
713                 compatible_arg = 0;
714                 break;
715
716         case VIDIOC_ENUMSTD32:
717                 err = get_v4l2_standard32(&karg.v2s, up);
718                 compatible_arg = 0;
719                 break;
720
721         case VIDIOC_ENUMINPUT:
722                 err = get_v4l2_input(&karg.v2i, up);
723                 compatible_arg = 0;
724                 break;
725
726         case VIDIOC_ENUMINPUT32:
727                 err = get_v4l2_input32(&karg.v2i, up);
728                 compatible_arg = 0;
729                 break;
730
731         case VIDIOC_G_TUNER:
732         case VIDIOC_S_TUNER:
733                 err = get_v4l2_tuner(&karg.v2t, up);
734                 compatible_arg = 0;
735                 break;
736
737 #ifdef CONFIG_VIDEO_V4L1_COMPAT
738         case VIDIOCGWIN:
739         case VIDIOCGFBUF:
740         case VIDIOCGFREQ:
741 #endif
742         case VIDIOC_G_FBUF:
743         case VIDIOC_G_INPUT:
744                 compatible_arg = 0;
745                 break;
746 #ifdef CONFIG_VIDEO_V4L1_COMPAT
747         case VIDIOCSMICROCODE:
748                 err = microcode32(&karg.vc, up);
749                 compatible_arg = 0;
750                 break;
751 #endif
752         };
753         if(err)
754                 goto out;
755
756         if(compatible_arg)
757                 err = native_ioctl(file, realcmd, (unsigned long)up);
758         else {
759                 mm_segment_t old_fs = get_fs();
760
761                 set_fs(KERNEL_DS);
762                 err = native_ioctl(file, realcmd, (unsigned long) &karg);
763                 set_fs(old_fs);
764         }
765         if(err == 0) {
766                 switch(cmd) {
767 #ifdef CONFIG_VIDEO_V4L1_COMPAT
768                 case VIDIOCGTUNER:
769                         err = put_video_tuner32(&karg.vt, up);
770                         break;
771
772                 case VIDIOCGWIN:
773                         err = put_video_window32(&karg.vw, up);
774                         break;
775
776                 case VIDIOCGFBUF:
777                         err = put_video_buffer32(&karg.vb, up);
778                         break;
779
780 #endif
781                 case VIDIOC_G_FBUF:
782                         err = put_v4l2_framebuffer32(&karg.v2fb, up);
783                         break;
784
785                 case VIDIOC_G_FMT:
786                 case VIDIOC_S_FMT:
787                 case VIDIOC_TRY_FMT:
788                         err = put_v4l2_format32(&karg.v2f, up);
789                         break;
790
791                 case VIDIOC_QUERYBUF:
792                 case VIDIOC_QBUF:
793                 case VIDIOC_DQBUF:
794                         err = put_v4l2_buffer32(&karg.v2b, up);
795                         break;
796
797                 case VIDIOC_ENUMSTD:
798                         err = put_v4l2_standard(&karg.v2s, up);
799                         break;
800
801                 case VIDIOC_ENUMSTD32:
802                         err = put_v4l2_standard32(&karg.v2s, up);
803                         break;
804
805                 case VIDIOC_G_TUNER:
806                 case VIDIOC_S_TUNER:
807                         err = put_v4l2_tuner(&karg.v2t, up);
808                         break;
809
810                 case VIDIOC_ENUMINPUT:
811                         err = put_v4l2_input(&karg.v2i, up);
812                         break;
813
814                 case VIDIOC_ENUMINPUT32:
815                         err = put_v4l2_input32(&karg.v2i, up);
816                         break;
817
818 #ifdef CONFIG_VIDEO_V4L1_COMPAT
819                 case VIDIOCGFREQ:
820 #endif
821                 case VIDIOC_G_INPUT:
822                         err = put_user(((u32)karg.vx), (u32 __user *)up);
823                         break;
824                 };
825         }
826 out:
827         return err;
828 }
829
830 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
831 {
832         int ret = -ENOIOCTLCMD;
833
834         if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
835                 return ret;
836
837         switch (cmd) {
838 #ifdef CONFIG_VIDEO_V4L1_COMPAT
839         case VIDIOCSWIN32:
840                 ret = do_set_window(file, cmd, arg);
841                 break;
842         case VIDIOCGTUNER32:
843         case VIDIOCSTUNER32:
844         case VIDIOCGWIN32:
845         case VIDIOCGFBUF32:
846         case VIDIOCSFBUF32:
847         case VIDIOCGFREQ32:
848         case VIDIOCSFREQ32:
849         case VIDIOCGAUDIO:
850         case VIDIOCSAUDIO:
851         case VIDIOCGVBIFMT:
852         case VIDIOCSVBIFMT:
853 #endif
854         case VIDIOC_QUERYCAP:
855         case VIDIOC_ENUM_FMT:
856         case VIDIOC_G_FMT32:
857         case VIDIOC_CROPCAP:
858         case VIDIOC_S_CROP:
859         case VIDIOC_S_FMT32:
860         case VIDIOC_REQBUFS:
861         case VIDIOC_QUERYBUF32:
862         case VIDIOC_G_FBUF32:
863         case VIDIOC_S_FBUF32:
864         case VIDIOC_OVERLAY32:
865         case VIDIOC_QBUF32:
866         case VIDIOC_DQBUF32:
867         case VIDIOC_STREAMON32:
868         case VIDIOC_STREAMOFF32:
869         case VIDIOC_G_PARM:
870         case VIDIOC_S_PARM:
871         case VIDIOC_G_STD:
872         case VIDIOC_S_STD:
873         case VIDIOC_G_TUNER:
874         case VIDIOC_S_TUNER:
875         case VIDIOC_ENUMSTD:
876         case VIDIOC_ENUMSTD32:
877         case VIDIOC_ENUMINPUT:
878         case VIDIOC_ENUMINPUT32:
879         case VIDIOC_G_CTRL:
880         case VIDIOC_S_CTRL:
881         case VIDIOC_S_CTRL32:
882         case VIDIOC_S_FREQUENCY:
883         case VIDIOC_G_FREQUENCY:
884         case VIDIOC_QUERYCTRL:
885         case VIDIOC_G_INPUT32:
886         case VIDIOC_S_INPUT32:
887         case VIDIOC_TRY_FMT32:
888         case VIDIOC_S_HW_FREQ_SEEK:
889         case VIDIOC_ENUM_FRAMESIZES:
890         case VIDIOC_ENUM_FRAMEINTERVALS:
891                 ret = do_video_ioctl(file, cmd, arg);
892                 break;
893
894 #ifdef CONFIG_VIDEO_V4L1_COMPAT
895         /* Little v, the video4linux ioctls (conflict?) */
896         case VIDIOCGCAP:
897         case VIDIOCGCHAN:
898         case VIDIOCSCHAN:
899         case VIDIOCGPICT:
900         case VIDIOCSPICT:
901         case VIDIOCCAPTURE:
902         case VIDIOCKEY:
903         case VIDIOCSYNC:
904         case VIDIOCMCAPTURE:
905         case VIDIOCGMBUF:
906         case VIDIOCGUNIT:
907         case VIDIOCGCAPTURE:
908         case VIDIOCSCAPTURE:
909
910         /* BTTV specific... */
911         case _IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]):
912         case _IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]):
913         case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
914         case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
915         case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
916         case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
917         case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
918         case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
919                 ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
920                 break;
921 #endif
922         default:
923                 v4l_print_ioctl("compat_ioctl32", cmd);
924         }
925         return ret;
926 }
927 #else
928 long v4l_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
929 {
930         return -ENOIOCTLCMD;
931 }
932 #endif
933 EXPORT_SYMBOL_GPL(v4l_compat_ioctl32);
934
935 MODULE_LICENSE("GPL");