Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
v4l2-compat-ioctl32.c
Go to the documentation of this file.
1 /*
2  * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3  * Separated from fs stuff by Arnd Bergmann <[email protected]>
4  *
5  * Copyright (C) 1997-2000 Jakub Jelinek ([email protected])
6  * Copyright (C) 1998 Eddie C. Dost ([email protected])
7  * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
8  * Copyright (C) 2003 Pavel Machek ([email protected])
9  * Copyright (C) 2005 Philippe De Muyter ([email protected])
10  * Copyright (C) 2008 Hans Verkuil <[email protected]>
11  *
12  * These routines maintain argument size conversion between 32bit and 64bit
13  * ioctls.
14  */
15 
16 #include <linux/compat.h>
17 #include <linux/module.h>
18 #include <linux/videodev2.h>
19 #include <linux/v4l2-subdev.h>
20 #include <media/v4l2-dev.h>
21 #include <media/v4l2-ioctl.h>
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;
37 };
38 
39 struct v4l2_window32 {
40  struct v4l2_rect w;
41  __u32 field; /* enum v4l2_field */
43  compat_caddr_t clips; /* actually struct v4l2_clip32 * */
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;
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 
151  __u32 type; /* enum v4l2_buf_type */
152  union {
158  __u8 raw_data[200]; /* user-defined */
159  } fmt;
160 };
161 
174  __u32 memory; /* enum v4l2_memory */
177 };
178 
179 static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
180 {
181  switch (kp->type) {
184  return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
187  return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
188  &up->fmt.pix_mp);
191  return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
194  return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
197  return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
198  default:
199  printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
200  kp->type);
201  return -EINVAL;
202  }
203 }
204 
205 static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
206 {
207  if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
208  get_user(kp->type, &up->type))
209  return -EFAULT;
210  return __get_v4l2_format32(kp, up);
211 }
212 
213 static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
214 {
215  if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
216  copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt)))
217  return -EFAULT;
218  return __get_v4l2_format32(&kp->format, &up->format);
219 }
220 
221 static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
222 {
223  switch (kp->type) {
226  return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
229  return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
230  &up->fmt.pix_mp);
233  return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
236  return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
239  return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
240  default:
241  printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
242  kp->type);
243  return -EINVAL;
244  }
245 }
246 
247 static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
248 {
249  if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
250  put_user(kp->type, &up->type))
251  return -EFAULT;
252  return __put_v4l2_format32(kp, up);
253 }
254 
255 static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
256 {
257  if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
258  copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
259  return -EFAULT;
260  return __put_v4l2_format32(&kp->format, &up->format);
261 }
262 
265  __u32 id[2]; /* __u64 would get the alignment wrong */
266  __u8 name[24];
267  struct v4l2_fract frameperiod; /* Frames, not fields */
270 };
271 
272 static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
273 {
274  /* other fields are not set by the user, nor used by the driver */
275  if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
276  get_user(kp->index, &up->index))
277  return -EFAULT;
278  return 0;
279 }
280 
281 static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
282 {
283  if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
284  put_user(kp->index, &up->index) ||
285  copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
286  copy_to_user(up->name, kp->name, 24) ||
287  copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
288  put_user(kp->framelines, &up->framelines) ||
289  copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
290  return -EFAULT;
291  return 0;
292 }
293 
294 struct v4l2_plane32 {
297  union {
300  } m;
303 };
304 
307  __u32 type; /* enum v4l2_buf_type */
310  __u32 field; /* enum v4l2_field */
314 
315  /* memory location */
316  __u32 memory; /* enum v4l2_memory */
317  union {
321  } m;
325 };
326 
327 static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
328  enum v4l2_memory memory)
329 {
330  void __user *up_pln;
332 
333  if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
334  copy_in_user(&up->data_offset, &up32->data_offset,
335  sizeof(__u32)))
336  return -EFAULT;
337 
338  if (memory == V4L2_MEMORY_USERPTR) {
339  if (get_user(p, &up32->m.userptr))
340  return -EFAULT;
341  up_pln = compat_ptr(p);
342  if (put_user((unsigned long)up_pln, &up->m.userptr))
343  return -EFAULT;
344  } else {
345  if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
346  sizeof(__u32)))
347  return -EFAULT;
348  }
349 
350  return 0;
351 }
352 
353 static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
354  enum v4l2_memory memory)
355 {
356  if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
357  copy_in_user(&up32->data_offset, &up->data_offset,
358  sizeof(__u32)))
359  return -EFAULT;
360 
361  /* For MMAP, driver might've set up the offset, so copy it back.
362  * USERPTR stays the same (was userspace-provided), so no copying. */
363  if (memory == V4L2_MEMORY_MMAP)
364  if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
365  sizeof(__u32)))
366  return -EFAULT;
367 
368  return 0;
369 }
370 
371 static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
372 {
373  struct v4l2_plane32 __user *uplane32;
374  struct v4l2_plane __user *uplane;
376  int num_planes;
377  int ret;
378 
379  if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
380  get_user(kp->index, &up->index) ||
381  get_user(kp->type, &up->type) ||
382  get_user(kp->flags, &up->flags) ||
383  get_user(kp->memory, &up->memory))
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  {
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;
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  return -EFAULT;
469 
470  if (put_user(kp->bytesused, &up->bytesused) ||
471  put_user(kp->field, &up->field) ||
472  put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
473  put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
474  copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
475  put_user(kp->sequence, &up->sequence) ||
476  put_user(kp->reserved2, &up->reserved2) ||
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 
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 */
562 } __attribute__ ((packed));
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 
585  compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
586 };
587 
592  union {
595  compat_caddr_t string; /* actually char * */
596  };
597 } __attribute__ ((packed));
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. */
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) {
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;
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;
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 {
701  union {
702  __u8 data[64];
703  } u;
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 
731 };
732 
733 static int get_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up)
734 {
735  u32 tmp;
736 
737  if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_subdev_edid32)) ||
738  get_user(kp->pad, &up->pad) ||
739  get_user(kp->start_block, &up->start_block) ||
740  get_user(kp->blocks, &up->blocks) ||
741  get_user(tmp, &up->edid) ||
742  copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
743  return -EFAULT;
744  kp->edid = compat_ptr(tmp);
745  return 0;
746 }
747 
748 static int put_v4l2_subdev_edid32(struct v4l2_subdev_edid *kp, struct v4l2_subdev_edid32 __user *up)
749 {
750  u32 tmp = (u32)((unsigned long)kp->edid);
751 
752  if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_subdev_edid32)) ||
753  put_user(kp->pad, &up->pad) ||
754  put_user(kp->start_block, &up->start_block) ||
755  put_user(kp->blocks, &up->blocks) ||
756  put_user(tmp, &up->edid) ||
757  copy_to_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
758  return -EFAULT;
759  return 0;
760 }
761 
762 
763 #define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
764 #define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
765 #define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
766 #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
767 #define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
768 #define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
769 #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
770 #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
771 #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
772 #define VIDIOC_SUBDEV_G_EDID32 _IOWR('V', 63, struct v4l2_subdev_edid32)
773 #define VIDIOC_SUBDEV_S_EDID32 _IOWR('V', 64, struct v4l2_subdev_edid32)
774 #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
775 #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
776 #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
777 #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
778 #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32)
779 #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32)
780 #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32)
781 
782 #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
783 #define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
784 #define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
785 #define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
786 #define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
787 #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
788 #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
789 
790 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
791 {
792  union {
793  struct v4l2_format v2f;
794  struct v4l2_buffer v2b;
795  struct v4l2_framebuffer v2fb;
796  struct v4l2_input v2i;
797  struct v4l2_standard v2s;
798  struct v4l2_ext_controls v2ecs;
799  struct v4l2_event v2ev;
800  struct v4l2_create_buffers v2crt;
801  struct v4l2_subdev_edid v2edid;
802  unsigned long vx;
803  int vi;
804  } karg;
805  void __user *up = compat_ptr(arg);
806  int compatible_arg = 1;
807  long err = 0;
808 
809  /* First, convert the command. */
810  switch (cmd) {
811  case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
812  case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
813  case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
814  case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
815  case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
816  case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
817  case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
818  case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
819  case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
820  case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
821  case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
822  case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
823  case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
824  case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
825  case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
826  case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
827  case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
828  case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
829  case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
830  case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
831  case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
832  case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
833  case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
834  case VIDIOC_SUBDEV_G_EDID32: cmd = VIDIOC_SUBDEV_G_EDID; break;
835  case VIDIOC_SUBDEV_S_EDID32: cmd = VIDIOC_SUBDEV_S_EDID; break;
836  }
837 
838  switch (cmd) {
839  case VIDIOC_OVERLAY:
840  case VIDIOC_STREAMON:
841  case VIDIOC_STREAMOFF:
842  case VIDIOC_S_INPUT:
843  case VIDIOC_S_OUTPUT:
844  err = get_user(karg.vi, (s32 __user *)up);
845  compatible_arg = 0;
846  break;
847 
848  case VIDIOC_G_INPUT:
849  case VIDIOC_G_OUTPUT:
850  compatible_arg = 0;
851  break;
852 
855  err = get_v4l2_subdev_edid32(&karg.v2edid, up);
856  compatible_arg = 0;
857  break;
858 
859  case VIDIOC_G_FMT:
860  case VIDIOC_S_FMT:
861  case VIDIOC_TRY_FMT:
862  err = get_v4l2_format32(&karg.v2f, up);
863  compatible_arg = 0;
864  break;
865 
866  case VIDIOC_CREATE_BUFS:
867  err = get_v4l2_create32(&karg.v2crt, up);
868  compatible_arg = 0;
869  break;
870 
871  case VIDIOC_PREPARE_BUF:
872  case VIDIOC_QUERYBUF:
873  case VIDIOC_QBUF:
874  case VIDIOC_DQBUF:
875  err = get_v4l2_buffer32(&karg.v2b, up);
876  compatible_arg = 0;
877  break;
878 
879  case VIDIOC_S_FBUF:
880  err = get_v4l2_framebuffer32(&karg.v2fb, up);
881  compatible_arg = 0;
882  break;
883 
884  case VIDIOC_G_FBUF:
885  compatible_arg = 0;
886  break;
887 
888  case VIDIOC_ENUMSTD:
889  err = get_v4l2_standard32(&karg.v2s, up);
890  compatible_arg = 0;
891  break;
892 
893  case VIDIOC_ENUMINPUT:
894  err = get_v4l2_input32(&karg.v2i, up);
895  compatible_arg = 0;
896  break;
897 
898  case VIDIOC_G_EXT_CTRLS:
899  case VIDIOC_S_EXT_CTRLS:
901  err = get_v4l2_ext_controls32(&karg.v2ecs, up);
902  compatible_arg = 0;
903  break;
904  case VIDIOC_DQEVENT:
905  compatible_arg = 0;
906  break;
907  }
908  if (err)
909  return err;
910 
911  if (compatible_arg)
912  err = native_ioctl(file, cmd, (unsigned long)up);
913  else {
914  mm_segment_t old_fs = get_fs();
915 
916  set_fs(KERNEL_DS);
917  err = native_ioctl(file, cmd, (unsigned long)&karg);
918  set_fs(old_fs);
919  }
920 
921  /* Special case: even after an error we need to put the
922  results back for these ioctls since the error_idx will
923  contain information on which control failed. */
924  switch (cmd) {
925  case VIDIOC_G_EXT_CTRLS:
926  case VIDIOC_S_EXT_CTRLS:
928  if (put_v4l2_ext_controls32(&karg.v2ecs, up))
929  err = -EFAULT;
930  break;
931  }
932  if (err)
933  return err;
934 
935  switch (cmd) {
936  case VIDIOC_S_INPUT:
937  case VIDIOC_S_OUTPUT:
938  case VIDIOC_G_INPUT:
939  case VIDIOC_G_OUTPUT:
940  err = put_user(((s32)karg.vi), (s32 __user *)up);
941  break;
942 
943  case VIDIOC_G_FBUF:
944  err = put_v4l2_framebuffer32(&karg.v2fb, up);
945  break;
946 
947  case VIDIOC_DQEVENT:
948  err = put_v4l2_event32(&karg.v2ev, up);
949  break;
950 
953  err = put_v4l2_subdev_edid32(&karg.v2edid, up);
954  break;
955 
956  case VIDIOC_G_FMT:
957  case VIDIOC_S_FMT:
958  case VIDIOC_TRY_FMT:
959  err = put_v4l2_format32(&karg.v2f, up);
960  break;
961 
962  case VIDIOC_CREATE_BUFS:
963  err = put_v4l2_create32(&karg.v2crt, up);
964  break;
965 
966  case VIDIOC_QUERYBUF:
967  case VIDIOC_QBUF:
968  case VIDIOC_DQBUF:
969  err = put_v4l2_buffer32(&karg.v2b, up);
970  break;
971 
972  case VIDIOC_ENUMSTD:
973  err = put_v4l2_standard32(&karg.v2s, up);
974  break;
975 
976  case VIDIOC_ENUMINPUT:
977  err = put_v4l2_input32(&karg.v2i, up);
978  break;
979  }
980  return err;
981 }
982 
983 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
984 {
985  struct video_device *vdev = video_devdata(file);
986  long ret = -ENOIOCTLCMD;
987 
988  if (!file->f_op->unlocked_ioctl)
989  return ret;
990 
991  switch (cmd) {
992  case VIDIOC_QUERYCAP:
993  case VIDIOC_RESERVED:
994  case VIDIOC_ENUM_FMT:
995  case VIDIOC_G_FMT32:
996  case VIDIOC_S_FMT32:
997  case VIDIOC_REQBUFS:
998  case VIDIOC_QUERYBUF32:
999  case VIDIOC_G_FBUF32:
1000  case VIDIOC_S_FBUF32:
1001  case VIDIOC_OVERLAY32:
1002  case VIDIOC_QBUF32:
1003  case VIDIOC_DQBUF32:
1004  case VIDIOC_STREAMON32:
1005  case VIDIOC_STREAMOFF32:
1006  case VIDIOC_G_PARM:
1007  case VIDIOC_S_PARM:
1008  case VIDIOC_G_STD:
1009  case VIDIOC_S_STD:
1010  case VIDIOC_ENUMSTD32:
1011  case VIDIOC_ENUMINPUT32:
1012  case VIDIOC_G_CTRL:
1013  case VIDIOC_S_CTRL:
1014  case VIDIOC_G_TUNER:
1015  case VIDIOC_S_TUNER:
1016  case VIDIOC_G_AUDIO:
1017  case VIDIOC_S_AUDIO:
1018  case VIDIOC_QUERYCTRL:
1019  case VIDIOC_QUERYMENU:
1020  case VIDIOC_G_INPUT32:
1021  case VIDIOC_S_INPUT32:
1022  case VIDIOC_G_OUTPUT32:
1023  case VIDIOC_S_OUTPUT32:
1024  case VIDIOC_ENUMOUTPUT:
1025  case VIDIOC_G_AUDOUT:
1026  case VIDIOC_S_AUDOUT:
1027  case VIDIOC_G_MODULATOR:
1028  case VIDIOC_S_MODULATOR:
1029  case VIDIOC_S_FREQUENCY:
1030  case VIDIOC_G_FREQUENCY:
1031  case VIDIOC_CROPCAP:
1032  case VIDIOC_G_CROP:
1033  case VIDIOC_S_CROP:
1034  case VIDIOC_G_SELECTION:
1035  case VIDIOC_S_SELECTION:
1036  case VIDIOC_G_JPEGCOMP:
1037  case VIDIOC_S_JPEGCOMP:
1038  case VIDIOC_QUERYSTD:
1039  case VIDIOC_TRY_FMT32:
1040  case VIDIOC_ENUMAUDIO:
1041  case VIDIOC_ENUMAUDOUT:
1042  case VIDIOC_G_PRIORITY:
1043  case VIDIOC_S_PRIORITY:
1045  case VIDIOC_LOG_STATUS:
1046  case VIDIOC_G_EXT_CTRLS32:
1047  case VIDIOC_S_EXT_CTRLS32:
1051  case VIDIOC_G_ENC_INDEX:
1052  case VIDIOC_ENCODER_CMD:
1054  case VIDIOC_DECODER_CMD:
1056  case VIDIOC_DBG_S_REGISTER:
1057  case VIDIOC_DBG_G_REGISTER:
1059  case VIDIOC_S_HW_FREQ_SEEK:
1061  case VIDIOC_S_DV_PRESET:
1062  case VIDIOC_G_DV_PRESET:
1064  case VIDIOC_S_DV_TIMINGS:
1065  case VIDIOC_G_DV_TIMINGS:
1066  case VIDIOC_DQEVENT:
1067  case VIDIOC_DQEVENT32:
1070  case VIDIOC_CREATE_BUFS32:
1071  case VIDIOC_PREPARE_BUF32:
1074  case VIDIOC_DV_TIMINGS_CAP:
1078  ret = do_video_ioctl(file, cmd, arg);
1079  break;
1080 
1081  default:
1082  if (vdev->fops->compat_ioctl32)
1083  ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1084 
1085  if (ret == -ENOIOCTLCMD)
1086  printk(KERN_WARNING "compat_ioctl32: "
1087  "unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1088  _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd),
1089  cmd);
1090  break;
1091  }
1092  return ret;
1093 }