Merge branch 'x86-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[cris-mirror.git] / drivers / media / v4l2-core / v4l2-compat-ioctl32.c
blob5198c9eeb3480387b021eaccf9cb941a2166fa37
1 /*
2 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
3 * Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
5 * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
6 * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
7 * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
8 * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
9 * Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
10 * Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
12 * These routines maintain argument size conversion between 32bit and 64bit
13 * ioctls.
16 #include <linux/compat.h>
17 #include <linux/module.h>
18 #include <linux/videodev2.h>
19 #include <linux/v4l2-subdev.h>
20 #include <media/v4l2-dev.h>
21 #include <media/v4l2-fh.h>
22 #include <media/v4l2-ctrls.h>
23 #include <media/v4l2-ioctl.h>
25 /* Use the same argument order as copy_in_user */
26 #define assign_in_user(to, from) \
27 ({ \
28 typeof(*from) __assign_tmp; \
30 get_user(__assign_tmp, from) || put_user(__assign_tmp, to); \
33 static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
35 long ret = -ENOIOCTLCMD;
37 if (file->f_op->unlocked_ioctl)
38 ret = file->f_op->unlocked_ioctl(file, cmd, arg);
40 return ret;
44 struct v4l2_clip32 {
45 struct v4l2_rect c;
46 compat_caddr_t next;
49 struct v4l2_window32 {
50 struct v4l2_rect w;
51 __u32 field; /* enum v4l2_field */
52 __u32 chromakey;
53 compat_caddr_t clips; /* actually struct v4l2_clip32 * */
54 __u32 clipcount;
55 compat_caddr_t bitmap;
56 __u8 global_alpha;
59 static int get_v4l2_window32(struct v4l2_window __user *kp,
60 struct v4l2_window32 __user *up,
61 void __user *aux_buf, u32 aux_space)
63 struct v4l2_clip32 __user *uclips;
64 struct v4l2_clip __user *kclips;
65 compat_caddr_t p;
66 u32 clipcount;
68 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
69 copy_in_user(&kp->w, &up->w, sizeof(up->w)) ||
70 assign_in_user(&kp->field, &up->field) ||
71 assign_in_user(&kp->chromakey, &up->chromakey) ||
72 assign_in_user(&kp->global_alpha, &up->global_alpha) ||
73 get_user(clipcount, &up->clipcount) ||
74 put_user(clipcount, &kp->clipcount))
75 return -EFAULT;
76 if (clipcount > 2048)
77 return -EINVAL;
78 if (!clipcount)
79 return put_user(NULL, &kp->clips);
81 if (get_user(p, &up->clips))
82 return -EFAULT;
83 uclips = compat_ptr(p);
84 if (aux_space < clipcount * sizeof(*kclips))
85 return -EFAULT;
86 kclips = aux_buf;
87 if (put_user(kclips, &kp->clips))
88 return -EFAULT;
90 while (clipcount--) {
91 if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
92 return -EFAULT;
93 if (put_user(clipcount ? kclips + 1 : NULL, &kclips->next))
94 return -EFAULT;
95 uclips++;
96 kclips++;
98 return 0;
101 static int put_v4l2_window32(struct v4l2_window __user *kp,
102 struct v4l2_window32 __user *up)
104 struct v4l2_clip __user *kclips = kp->clips;
105 struct v4l2_clip32 __user *uclips;
106 compat_caddr_t p;
107 u32 clipcount;
109 if (copy_in_user(&up->w, &kp->w, sizeof(kp->w)) ||
110 assign_in_user(&up->field, &kp->field) ||
111 assign_in_user(&up->chromakey, &kp->chromakey) ||
112 assign_in_user(&up->global_alpha, &kp->global_alpha) ||
113 get_user(clipcount, &kp->clipcount) ||
114 put_user(clipcount, &up->clipcount))
115 return -EFAULT;
116 if (!clipcount)
117 return 0;
119 if (get_user(p, &up->clips))
120 return -EFAULT;
121 uclips = compat_ptr(p);
122 while (clipcount--) {
123 if (copy_in_user(&uclips->c, &kclips->c, sizeof(uclips->c)))
124 return -EFAULT;
125 uclips++;
126 kclips++;
128 return 0;
131 struct v4l2_format32 {
132 __u32 type; /* enum v4l2_buf_type */
133 union {
134 struct v4l2_pix_format pix;
135 struct v4l2_pix_format_mplane pix_mp;
136 struct v4l2_window32 win;
137 struct v4l2_vbi_format vbi;
138 struct v4l2_sliced_vbi_format sliced;
139 struct v4l2_sdr_format sdr;
140 struct v4l2_meta_format meta;
141 __u8 raw_data[200]; /* user-defined */
142 } fmt;
146 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
147 * @index: on return, index of the first created buffer
148 * @count: entry: number of requested buffers,
149 * return: number of created buffers
150 * @memory: buffer memory type
151 * @format: frame format, for which buffers are requested
152 * @reserved: future extensions
154 struct v4l2_create_buffers32 {
155 __u32 index;
156 __u32 count;
157 __u32 memory; /* enum v4l2_memory */
158 struct v4l2_format32 format;
159 __u32 reserved[8];
162 static int __bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
164 u32 type;
166 if (get_user(type, &up->type))
167 return -EFAULT;
169 switch (type) {
170 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
171 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY: {
172 u32 clipcount;
174 if (get_user(clipcount, &up->fmt.win.clipcount))
175 return -EFAULT;
176 if (clipcount > 2048)
177 return -EINVAL;
178 *size = clipcount * sizeof(struct v4l2_clip);
179 return 0;
181 default:
182 *size = 0;
183 return 0;
187 static int bufsize_v4l2_format(struct v4l2_format32 __user *up, u32 *size)
189 if (!access_ok(VERIFY_READ, up, sizeof(*up)))
190 return -EFAULT;
191 return __bufsize_v4l2_format(up, size);
194 static int __get_v4l2_format32(struct v4l2_format __user *kp,
195 struct v4l2_format32 __user *up,
196 void __user *aux_buf, u32 aux_space)
198 u32 type;
200 if (get_user(type, &up->type) || put_user(type, &kp->type))
201 return -EFAULT;
203 switch (type) {
204 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
205 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
206 return copy_in_user(&kp->fmt.pix, &up->fmt.pix,
207 sizeof(kp->fmt.pix)) ? -EFAULT : 0;
208 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
209 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
210 return copy_in_user(&kp->fmt.pix_mp, &up->fmt.pix_mp,
211 sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
212 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
213 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
214 return get_v4l2_window32(&kp->fmt.win, &up->fmt.win,
215 aux_buf, aux_space);
216 case V4L2_BUF_TYPE_VBI_CAPTURE:
217 case V4L2_BUF_TYPE_VBI_OUTPUT:
218 return copy_in_user(&kp->fmt.vbi, &up->fmt.vbi,
219 sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
220 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
221 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
222 return copy_in_user(&kp->fmt.sliced, &up->fmt.sliced,
223 sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
224 case V4L2_BUF_TYPE_SDR_CAPTURE:
225 case V4L2_BUF_TYPE_SDR_OUTPUT:
226 return copy_in_user(&kp->fmt.sdr, &up->fmt.sdr,
227 sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
228 case V4L2_BUF_TYPE_META_CAPTURE:
229 return copy_in_user(&kp->fmt.meta, &up->fmt.meta,
230 sizeof(kp->fmt.meta)) ? -EFAULT : 0;
231 default:
232 return -EINVAL;
236 static int get_v4l2_format32(struct v4l2_format __user *kp,
237 struct v4l2_format32 __user *up,
238 void __user *aux_buf, u32 aux_space)
240 if (!access_ok(VERIFY_READ, up, sizeof(*up)))
241 return -EFAULT;
242 return __get_v4l2_format32(kp, up, aux_buf, aux_space);
245 static int bufsize_v4l2_create(struct v4l2_create_buffers32 __user *up,
246 u32 *size)
248 if (!access_ok(VERIFY_READ, up, sizeof(*up)))
249 return -EFAULT;
250 return __bufsize_v4l2_format(&up->format, size);
253 static int get_v4l2_create32(struct v4l2_create_buffers __user *kp,
254 struct v4l2_create_buffers32 __user *up,
255 void __user *aux_buf, u32 aux_space)
257 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
258 copy_in_user(kp, up,
259 offsetof(struct v4l2_create_buffers32, format)))
260 return -EFAULT;
261 return __get_v4l2_format32(&kp->format, &up->format,
262 aux_buf, aux_space);
265 static int __put_v4l2_format32(struct v4l2_format __user *kp,
266 struct v4l2_format32 __user *up)
268 u32 type;
270 if (get_user(type, &kp->type))
271 return -EFAULT;
273 switch (type) {
274 case V4L2_BUF_TYPE_VIDEO_CAPTURE:
275 case V4L2_BUF_TYPE_VIDEO_OUTPUT:
276 return copy_in_user(&up->fmt.pix, &kp->fmt.pix,
277 sizeof(kp->fmt.pix)) ? -EFAULT : 0;
278 case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
279 case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
280 return copy_in_user(&up->fmt.pix_mp, &kp->fmt.pix_mp,
281 sizeof(kp->fmt.pix_mp)) ? -EFAULT : 0;
282 case V4L2_BUF_TYPE_VIDEO_OVERLAY:
283 case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
284 return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
285 case V4L2_BUF_TYPE_VBI_CAPTURE:
286 case V4L2_BUF_TYPE_VBI_OUTPUT:
287 return copy_in_user(&up->fmt.vbi, &kp->fmt.vbi,
288 sizeof(kp->fmt.vbi)) ? -EFAULT : 0;
289 case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
290 case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
291 return copy_in_user(&up->fmt.sliced, &kp->fmt.sliced,
292 sizeof(kp->fmt.sliced)) ? -EFAULT : 0;
293 case V4L2_BUF_TYPE_SDR_CAPTURE:
294 case V4L2_BUF_TYPE_SDR_OUTPUT:
295 return copy_in_user(&up->fmt.sdr, &kp->fmt.sdr,
296 sizeof(kp->fmt.sdr)) ? -EFAULT : 0;
297 case V4L2_BUF_TYPE_META_CAPTURE:
298 return copy_in_user(&up->fmt.meta, &kp->fmt.meta,
299 sizeof(kp->fmt.meta)) ? -EFAULT : 0;
300 default:
301 return -EINVAL;
305 static int put_v4l2_format32(struct v4l2_format __user *kp,
306 struct v4l2_format32 __user *up)
308 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
309 return -EFAULT;
310 return __put_v4l2_format32(kp, up);
313 static int put_v4l2_create32(struct v4l2_create_buffers __user *kp,
314 struct v4l2_create_buffers32 __user *up)
316 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
317 copy_in_user(up, kp,
318 offsetof(struct v4l2_create_buffers32, format)) ||
319 copy_in_user(up->reserved, kp->reserved, sizeof(kp->reserved)))
320 return -EFAULT;
321 return __put_v4l2_format32(&kp->format, &up->format);
324 struct v4l2_standard32 {
325 __u32 index;
326 compat_u64 id;
327 __u8 name[24];
328 struct v4l2_fract frameperiod; /* Frames, not fields */
329 __u32 framelines;
330 __u32 reserved[4];
333 static int get_v4l2_standard32(struct v4l2_standard __user *kp,
334 struct v4l2_standard32 __user *up)
336 /* other fields are not set by the user, nor used by the driver */
337 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
338 assign_in_user(&kp->index, &up->index))
339 return -EFAULT;
340 return 0;
343 static int put_v4l2_standard32(struct v4l2_standard __user *kp,
344 struct v4l2_standard32 __user *up)
346 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
347 assign_in_user(&up->index, &kp->index) ||
348 assign_in_user(&up->id, &kp->id) ||
349 copy_in_user(up->name, kp->name, sizeof(up->name)) ||
350 copy_in_user(&up->frameperiod, &kp->frameperiod,
351 sizeof(up->frameperiod)) ||
352 assign_in_user(&up->framelines, &kp->framelines) ||
353 copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
354 return -EFAULT;
355 return 0;
358 struct v4l2_plane32 {
359 __u32 bytesused;
360 __u32 length;
361 union {
362 __u32 mem_offset;
363 compat_long_t userptr;
364 __s32 fd;
365 } m;
366 __u32 data_offset;
367 __u32 reserved[11];
370 struct v4l2_buffer32 {
371 __u32 index;
372 __u32 type; /* enum v4l2_buf_type */
373 __u32 bytesused;
374 __u32 flags;
375 __u32 field; /* enum v4l2_field */
376 struct compat_timeval timestamp;
377 struct v4l2_timecode timecode;
378 __u32 sequence;
380 /* memory location */
381 __u32 memory; /* enum v4l2_memory */
382 union {
383 __u32 offset;
384 compat_long_t userptr;
385 compat_caddr_t planes;
386 __s32 fd;
387 } m;
388 __u32 length;
389 __u32 reserved2;
390 __u32 reserved;
393 static int get_v4l2_plane32(struct v4l2_plane __user *up,
394 struct v4l2_plane32 __user *up32,
395 enum v4l2_memory memory)
397 compat_ulong_t p;
399 if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
400 copy_in_user(&up->data_offset, &up32->data_offset,
401 sizeof(up->data_offset)))
402 return -EFAULT;
404 switch (memory) {
405 case V4L2_MEMORY_MMAP:
406 case V4L2_MEMORY_OVERLAY:
407 if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
408 sizeof(up32->m.mem_offset)))
409 return -EFAULT;
410 break;
411 case V4L2_MEMORY_USERPTR:
412 if (get_user(p, &up32->m.userptr) ||
413 put_user((unsigned long)compat_ptr(p), &up->m.userptr))
414 return -EFAULT;
415 break;
416 case V4L2_MEMORY_DMABUF:
417 if (copy_in_user(&up->m.fd, &up32->m.fd, sizeof(up32->m.fd)))
418 return -EFAULT;
419 break;
422 return 0;
425 static int put_v4l2_plane32(struct v4l2_plane __user *up,
426 struct v4l2_plane32 __user *up32,
427 enum v4l2_memory memory)
429 unsigned long p;
431 if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
432 copy_in_user(&up32->data_offset, &up->data_offset,
433 sizeof(up->data_offset)))
434 return -EFAULT;
436 switch (memory) {
437 case V4L2_MEMORY_MMAP:
438 case V4L2_MEMORY_OVERLAY:
439 if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
440 sizeof(up->m.mem_offset)))
441 return -EFAULT;
442 break;
443 case V4L2_MEMORY_USERPTR:
444 if (get_user(p, &up->m.userptr) ||
445 put_user((compat_ulong_t)ptr_to_compat((__force void *)p),
446 &up32->m.userptr))
447 return -EFAULT;
448 break;
449 case V4L2_MEMORY_DMABUF:
450 if (copy_in_user(&up32->m.fd, &up->m.fd, sizeof(up->m.fd)))
451 return -EFAULT;
452 break;
455 return 0;
458 static int bufsize_v4l2_buffer(struct v4l2_buffer32 __user *up, u32 *size)
460 u32 type;
461 u32 length;
463 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
464 get_user(type, &up->type) ||
465 get_user(length, &up->length))
466 return -EFAULT;
468 if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
469 if (length > VIDEO_MAX_PLANES)
470 return -EINVAL;
473 * We don't really care if userspace decides to kill itself
474 * by passing a very big length value
476 *size = length * sizeof(struct v4l2_plane);
477 } else {
478 *size = 0;
480 return 0;
483 static int get_v4l2_buffer32(struct v4l2_buffer __user *kp,
484 struct v4l2_buffer32 __user *up,
485 void __user *aux_buf, u32 aux_space)
487 u32 type;
488 u32 length;
489 enum v4l2_memory memory;
490 struct v4l2_plane32 __user *uplane32;
491 struct v4l2_plane __user *uplane;
492 compat_caddr_t p;
493 int ret;
495 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
496 assign_in_user(&kp->index, &up->index) ||
497 get_user(type, &up->type) ||
498 put_user(type, &kp->type) ||
499 assign_in_user(&kp->flags, &up->flags) ||
500 get_user(memory, &up->memory) ||
501 put_user(memory, &kp->memory) ||
502 get_user(length, &up->length) ||
503 put_user(length, &kp->length))
504 return -EFAULT;
506 if (V4L2_TYPE_IS_OUTPUT(type))
507 if (assign_in_user(&kp->bytesused, &up->bytesused) ||
508 assign_in_user(&kp->field, &up->field) ||
509 assign_in_user(&kp->timestamp.tv_sec,
510 &up->timestamp.tv_sec) ||
511 assign_in_user(&kp->timestamp.tv_usec,
512 &up->timestamp.tv_usec))
513 return -EFAULT;
515 if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
516 u32 num_planes = length;
518 if (num_planes == 0) {
520 * num_planes == 0 is legal, e.g. when userspace doesn't
521 * need planes array on DQBUF
523 return put_user(NULL, &kp->m.planes);
525 if (num_planes > VIDEO_MAX_PLANES)
526 return -EINVAL;
528 if (get_user(p, &up->m.planes))
529 return -EFAULT;
531 uplane32 = compat_ptr(p);
532 if (!access_ok(VERIFY_READ, uplane32,
533 num_planes * sizeof(*uplane32)))
534 return -EFAULT;
537 * We don't really care if userspace decides to kill itself
538 * by passing a very big num_planes value
540 if (aux_space < num_planes * sizeof(*uplane))
541 return -EFAULT;
543 uplane = aux_buf;
544 if (put_user((__force struct v4l2_plane *)uplane,
545 &kp->m.planes))
546 return -EFAULT;
548 while (num_planes--) {
549 ret = get_v4l2_plane32(uplane, uplane32, memory);
550 if (ret)
551 return ret;
552 uplane++;
553 uplane32++;
555 } else {
556 switch (memory) {
557 case V4L2_MEMORY_MMAP:
558 case V4L2_MEMORY_OVERLAY:
559 if (assign_in_user(&kp->m.offset, &up->m.offset))
560 return -EFAULT;
561 break;
562 case V4L2_MEMORY_USERPTR: {
563 compat_ulong_t userptr;
565 if (get_user(userptr, &up->m.userptr) ||
566 put_user((unsigned long)compat_ptr(userptr),
567 &kp->m.userptr))
568 return -EFAULT;
569 break;
571 case V4L2_MEMORY_DMABUF:
572 if (assign_in_user(&kp->m.fd, &up->m.fd))
573 return -EFAULT;
574 break;
578 return 0;
581 static int put_v4l2_buffer32(struct v4l2_buffer __user *kp,
582 struct v4l2_buffer32 __user *up)
584 u32 type;
585 u32 length;
586 enum v4l2_memory memory;
587 struct v4l2_plane32 __user *uplane32;
588 struct v4l2_plane __user *uplane;
589 compat_caddr_t p;
590 int ret;
592 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
593 assign_in_user(&up->index, &kp->index) ||
594 get_user(type, &kp->type) ||
595 put_user(type, &up->type) ||
596 assign_in_user(&up->flags, &kp->flags) ||
597 get_user(memory, &kp->memory) ||
598 put_user(memory, &up->memory))
599 return -EFAULT;
601 if (assign_in_user(&up->bytesused, &kp->bytesused) ||
602 assign_in_user(&up->field, &kp->field) ||
603 assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
604 assign_in_user(&up->timestamp.tv_usec, &kp->timestamp.tv_usec) ||
605 copy_in_user(&up->timecode, &kp->timecode, sizeof(kp->timecode)) ||
606 assign_in_user(&up->sequence, &kp->sequence) ||
607 assign_in_user(&up->reserved2, &kp->reserved2) ||
608 assign_in_user(&up->reserved, &kp->reserved) ||
609 get_user(length, &kp->length) ||
610 put_user(length, &up->length))
611 return -EFAULT;
613 if (V4L2_TYPE_IS_MULTIPLANAR(type)) {
614 u32 num_planes = length;
616 if (num_planes == 0)
617 return 0;
619 if (get_user(uplane, ((__force struct v4l2_plane __user **)&kp->m.planes)))
620 return -EFAULT;
621 if (get_user(p, &up->m.planes))
622 return -EFAULT;
623 uplane32 = compat_ptr(p);
625 while (num_planes--) {
626 ret = put_v4l2_plane32(uplane, uplane32, memory);
627 if (ret)
628 return ret;
629 ++uplane;
630 ++uplane32;
632 } else {
633 switch (memory) {
634 case V4L2_MEMORY_MMAP:
635 case V4L2_MEMORY_OVERLAY:
636 if (assign_in_user(&up->m.offset, &kp->m.offset))
637 return -EFAULT;
638 break;
639 case V4L2_MEMORY_USERPTR:
640 if (assign_in_user(&up->m.userptr, &kp->m.userptr))
641 return -EFAULT;
642 break;
643 case V4L2_MEMORY_DMABUF:
644 if (assign_in_user(&up->m.fd, &kp->m.fd))
645 return -EFAULT;
646 break;
650 return 0;
653 struct v4l2_framebuffer32 {
654 __u32 capability;
655 __u32 flags;
656 compat_caddr_t base;
657 struct {
658 __u32 width;
659 __u32 height;
660 __u32 pixelformat;
661 __u32 field;
662 __u32 bytesperline;
663 __u32 sizeimage;
664 __u32 colorspace;
665 __u32 priv;
666 } fmt;
669 static int get_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
670 struct v4l2_framebuffer32 __user *up)
672 compat_caddr_t tmp;
674 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
675 get_user(tmp, &up->base) ||
676 put_user((__force void *)compat_ptr(tmp), &kp->base) ||
677 assign_in_user(&kp->capability, &up->capability) ||
678 assign_in_user(&kp->flags, &up->flags) ||
679 copy_in_user(&kp->fmt, &up->fmt, sizeof(kp->fmt)))
680 return -EFAULT;
681 return 0;
684 static int put_v4l2_framebuffer32(struct v4l2_framebuffer __user *kp,
685 struct v4l2_framebuffer32 __user *up)
687 void *base;
689 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
690 get_user(base, &kp->base) ||
691 put_user(ptr_to_compat(base), &up->base) ||
692 assign_in_user(&up->capability, &kp->capability) ||
693 assign_in_user(&up->flags, &kp->flags) ||
694 copy_in_user(&up->fmt, &kp->fmt, sizeof(kp->fmt)))
695 return -EFAULT;
696 return 0;
699 struct v4l2_input32 {
700 __u32 index; /* Which input */
701 __u8 name[32]; /* Label */
702 __u32 type; /* Type of input */
703 __u32 audioset; /* Associated audios (bitfield) */
704 __u32 tuner; /* Associated tuner */
705 compat_u64 std;
706 __u32 status;
707 __u32 capabilities;
708 __u32 reserved[3];
712 * The 64-bit v4l2_input struct has extra padding at the end of the struct.
713 * Otherwise it is identical to the 32-bit version.
715 static inline int get_v4l2_input32(struct v4l2_input __user *kp,
716 struct v4l2_input32 __user *up)
718 if (copy_in_user(kp, up, sizeof(*up)))
719 return -EFAULT;
720 return 0;
723 static inline int put_v4l2_input32(struct v4l2_input __user *kp,
724 struct v4l2_input32 __user *up)
726 if (copy_in_user(up, kp, sizeof(*up)))
727 return -EFAULT;
728 return 0;
731 struct v4l2_ext_controls32 {
732 __u32 which;
733 __u32 count;
734 __u32 error_idx;
735 __u32 reserved[2];
736 compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
739 struct v4l2_ext_control32 {
740 __u32 id;
741 __u32 size;
742 __u32 reserved2[1];
743 union {
744 __s32 value;
745 __s64 value64;
746 compat_caddr_t string; /* actually char * */
748 } __attribute__ ((packed));
750 /* Return true if this control is a pointer type. */
751 static inline bool ctrl_is_pointer(struct file *file, u32 id)
753 struct video_device *vdev = video_devdata(file);
754 struct v4l2_fh *fh = NULL;
755 struct v4l2_ctrl_handler *hdl = NULL;
756 struct v4l2_query_ext_ctrl qec = { id };
757 const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
759 if (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))
760 fh = file->private_data;
762 if (fh && fh->ctrl_handler)
763 hdl = fh->ctrl_handler;
764 else if (vdev->ctrl_handler)
765 hdl = vdev->ctrl_handler;
767 if (hdl) {
768 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
770 return ctrl && ctrl->is_ptr;
773 if (!ops || !ops->vidioc_query_ext_ctrl)
774 return false;
776 return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&
777 (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
780 static int bufsize_v4l2_ext_controls(struct v4l2_ext_controls32 __user *up,
781 u32 *size)
783 u32 count;
785 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
786 get_user(count, &up->count))
787 return -EFAULT;
788 if (count > V4L2_CID_MAX_CTRLS)
789 return -EINVAL;
790 *size = count * sizeof(struct v4l2_ext_control);
791 return 0;
794 static int get_v4l2_ext_controls32(struct file *file,
795 struct v4l2_ext_controls __user *kp,
796 struct v4l2_ext_controls32 __user *up,
797 void __user *aux_buf, u32 aux_space)
799 struct v4l2_ext_control32 __user *ucontrols;
800 struct v4l2_ext_control __user *kcontrols;
801 u32 count;
802 u32 n;
803 compat_caddr_t p;
805 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
806 assign_in_user(&kp->which, &up->which) ||
807 get_user(count, &up->count) ||
808 put_user(count, &kp->count) ||
809 assign_in_user(&kp->error_idx, &up->error_idx) ||
810 copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
811 return -EFAULT;
813 if (count == 0)
814 return put_user(NULL, &kp->controls);
815 if (count > V4L2_CID_MAX_CTRLS)
816 return -EINVAL;
817 if (get_user(p, &up->controls))
818 return -EFAULT;
819 ucontrols = compat_ptr(p);
820 if (!access_ok(VERIFY_READ, ucontrols, count * sizeof(*ucontrols)))
821 return -EFAULT;
822 if (aux_space < count * sizeof(*kcontrols))
823 return -EFAULT;
824 kcontrols = aux_buf;
825 if (put_user((__force struct v4l2_ext_control *)kcontrols,
826 &kp->controls))
827 return -EFAULT;
829 for (n = 0; n < count; n++) {
830 u32 id;
832 if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
833 return -EFAULT;
835 if (get_user(id, &kcontrols->id))
836 return -EFAULT;
838 if (ctrl_is_pointer(file, id)) {
839 void __user *s;
841 if (get_user(p, &ucontrols->string))
842 return -EFAULT;
843 s = compat_ptr(p);
844 if (put_user(s, &kcontrols->string))
845 return -EFAULT;
847 ucontrols++;
848 kcontrols++;
850 return 0;
853 static int put_v4l2_ext_controls32(struct file *file,
854 struct v4l2_ext_controls __user *kp,
855 struct v4l2_ext_controls32 __user *up)
857 struct v4l2_ext_control32 __user *ucontrols;
858 struct v4l2_ext_control __user *kcontrols;
859 u32 count;
860 u32 n;
861 compat_caddr_t p;
863 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
864 assign_in_user(&up->which, &kp->which) ||
865 get_user(count, &kp->count) ||
866 put_user(count, &up->count) ||
867 assign_in_user(&up->error_idx, &kp->error_idx) ||
868 copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)) ||
869 get_user(kcontrols, &kp->controls))
870 return -EFAULT;
872 if (!count)
873 return 0;
874 if (get_user(p, &up->controls))
875 return -EFAULT;
876 ucontrols = compat_ptr(p);
877 if (!access_ok(VERIFY_WRITE, ucontrols, count * sizeof(*ucontrols)))
878 return -EFAULT;
880 for (n = 0; n < count; n++) {
881 unsigned int size = sizeof(*ucontrols);
882 u32 id;
884 if (get_user(id, &kcontrols->id) ||
885 put_user(id, &ucontrols->id) ||
886 assign_in_user(&ucontrols->size, &kcontrols->size) ||
887 copy_in_user(&ucontrols->reserved2, &kcontrols->reserved2,
888 sizeof(ucontrols->reserved2)))
889 return -EFAULT;
892 * Do not modify the pointer when copying a pointer control.
893 * The contents of the pointer was changed, not the pointer
894 * itself.
896 if (ctrl_is_pointer(file, id))
897 size -= sizeof(ucontrols->value64);
899 if (copy_in_user(ucontrols, kcontrols, size))
900 return -EFAULT;
902 ucontrols++;
903 kcontrols++;
905 return 0;
908 struct v4l2_event32 {
909 __u32 type;
910 union {
911 compat_s64 value64;
912 __u8 data[64];
913 } u;
914 __u32 pending;
915 __u32 sequence;
916 struct compat_timespec timestamp;
917 __u32 id;
918 __u32 reserved[8];
921 static int put_v4l2_event32(struct v4l2_event __user *kp,
922 struct v4l2_event32 __user *up)
924 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
925 assign_in_user(&up->type, &kp->type) ||
926 copy_in_user(&up->u, &kp->u, sizeof(kp->u)) ||
927 assign_in_user(&up->pending, &kp->pending) ||
928 assign_in_user(&up->sequence, &kp->sequence) ||
929 assign_in_user(&up->timestamp.tv_sec, &kp->timestamp.tv_sec) ||
930 assign_in_user(&up->timestamp.tv_nsec, &kp->timestamp.tv_nsec) ||
931 assign_in_user(&up->id, &kp->id) ||
932 copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
933 return -EFAULT;
934 return 0;
937 struct v4l2_edid32 {
938 __u32 pad;
939 __u32 start_block;
940 __u32 blocks;
941 __u32 reserved[5];
942 compat_caddr_t edid;
945 static int get_v4l2_edid32(struct v4l2_edid __user *kp,
946 struct v4l2_edid32 __user *up)
948 compat_uptr_t tmp;
950 if (!access_ok(VERIFY_READ, up, sizeof(*up)) ||
951 assign_in_user(&kp->pad, &up->pad) ||
952 assign_in_user(&kp->start_block, &up->start_block) ||
953 assign_in_user(&kp->blocks, &up->blocks) ||
954 get_user(tmp, &up->edid) ||
955 put_user(compat_ptr(tmp), &kp->edid) ||
956 copy_in_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
957 return -EFAULT;
958 return 0;
961 static int put_v4l2_edid32(struct v4l2_edid __user *kp,
962 struct v4l2_edid32 __user *up)
964 void *edid;
966 if (!access_ok(VERIFY_WRITE, up, sizeof(*up)) ||
967 assign_in_user(&up->pad, &kp->pad) ||
968 assign_in_user(&up->start_block, &kp->start_block) ||
969 assign_in_user(&up->blocks, &kp->blocks) ||
970 get_user(edid, &kp->edid) ||
971 put_user(ptr_to_compat(edid), &up->edid) ||
972 copy_in_user(up->reserved, kp->reserved, sizeof(up->reserved)))
973 return -EFAULT;
974 return 0;
978 #define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)
979 #define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)
980 #define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)
981 #define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)
982 #define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)
983 #define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)
984 #define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)
985 #define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)
986 #define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)
987 #define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)
988 #define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)
989 #define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)
990 #define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)
991 #define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)
992 #define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)
993 #define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32)
994 #define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32)
995 #define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32)
997 #define VIDIOC_OVERLAY32 _IOW ('V', 14, s32)
998 #define VIDIOC_STREAMON32 _IOW ('V', 18, s32)
999 #define VIDIOC_STREAMOFF32 _IOW ('V', 19, s32)
1000 #define VIDIOC_G_INPUT32 _IOR ('V', 38, s32)
1001 #define VIDIOC_S_INPUT32 _IOWR('V', 39, s32)
1002 #define VIDIOC_G_OUTPUT32 _IOR ('V', 46, s32)
1003 #define VIDIOC_S_OUTPUT32 _IOWR('V', 47, s32)
1005 static int alloc_userspace(unsigned int size, u32 aux_space,
1006 void __user **up_native)
1008 *up_native = compat_alloc_user_space(size + aux_space);
1009 if (!*up_native)
1010 return -ENOMEM;
1011 if (clear_user(*up_native, size))
1012 return -EFAULT;
1013 return 0;
1016 static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
1018 void __user *up = compat_ptr(arg);
1019 void __user *up_native = NULL;
1020 void __user *aux_buf;
1021 u32 aux_space;
1022 int compatible_arg = 1;
1023 long err = 0;
1025 /* First, convert the command. */
1026 switch (cmd) {
1027 case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
1028 case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
1029 case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
1030 case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
1031 case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
1032 case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
1033 case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
1034 case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
1035 case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
1036 case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
1037 case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
1038 case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
1039 case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
1040 case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
1041 case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
1042 case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
1043 case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
1044 case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
1045 case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
1046 case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
1047 case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
1048 case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
1049 case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
1050 case VIDIOC_G_EDID32: cmd = VIDIOC_G_EDID; break;
1051 case VIDIOC_S_EDID32: cmd = VIDIOC_S_EDID; break;
1054 switch (cmd) {
1055 case VIDIOC_OVERLAY:
1056 case VIDIOC_STREAMON:
1057 case VIDIOC_STREAMOFF:
1058 case VIDIOC_S_INPUT:
1059 case VIDIOC_S_OUTPUT:
1060 err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1061 if (!err && assign_in_user((unsigned int __user *)up_native,
1062 (compat_uint_t __user *)up))
1063 err = -EFAULT;
1064 compatible_arg = 0;
1065 break;
1067 case VIDIOC_G_INPUT:
1068 case VIDIOC_G_OUTPUT:
1069 err = alloc_userspace(sizeof(unsigned int), 0, &up_native);
1070 compatible_arg = 0;
1071 break;
1073 case VIDIOC_G_EDID:
1074 case VIDIOC_S_EDID:
1075 err = alloc_userspace(sizeof(struct v4l2_edid), 0, &up_native);
1076 if (!err)
1077 err = get_v4l2_edid32(up_native, up);
1078 compatible_arg = 0;
1079 break;
1081 case VIDIOC_G_FMT:
1082 case VIDIOC_S_FMT:
1083 case VIDIOC_TRY_FMT:
1084 err = bufsize_v4l2_format(up, &aux_space);
1085 if (!err)
1086 err = alloc_userspace(sizeof(struct v4l2_format),
1087 aux_space, &up_native);
1088 if (!err) {
1089 aux_buf = up_native + sizeof(struct v4l2_format);
1090 err = get_v4l2_format32(up_native, up,
1091 aux_buf, aux_space);
1093 compatible_arg = 0;
1094 break;
1096 case VIDIOC_CREATE_BUFS:
1097 err = bufsize_v4l2_create(up, &aux_space);
1098 if (!err)
1099 err = alloc_userspace(sizeof(struct v4l2_create_buffers),
1100 aux_space, &up_native);
1101 if (!err) {
1102 aux_buf = up_native + sizeof(struct v4l2_create_buffers);
1103 err = get_v4l2_create32(up_native, up,
1104 aux_buf, aux_space);
1106 compatible_arg = 0;
1107 break;
1109 case VIDIOC_PREPARE_BUF:
1110 case VIDIOC_QUERYBUF:
1111 case VIDIOC_QBUF:
1112 case VIDIOC_DQBUF:
1113 err = bufsize_v4l2_buffer(up, &aux_space);
1114 if (!err)
1115 err = alloc_userspace(sizeof(struct v4l2_buffer),
1116 aux_space, &up_native);
1117 if (!err) {
1118 aux_buf = up_native + sizeof(struct v4l2_buffer);
1119 err = get_v4l2_buffer32(up_native, up,
1120 aux_buf, aux_space);
1122 compatible_arg = 0;
1123 break;
1125 case VIDIOC_S_FBUF:
1126 err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1127 &up_native);
1128 if (!err)
1129 err = get_v4l2_framebuffer32(up_native, up);
1130 compatible_arg = 0;
1131 break;
1133 case VIDIOC_G_FBUF:
1134 err = alloc_userspace(sizeof(struct v4l2_framebuffer), 0,
1135 &up_native);
1136 compatible_arg = 0;
1137 break;
1139 case VIDIOC_ENUMSTD:
1140 err = alloc_userspace(sizeof(struct v4l2_standard), 0,
1141 &up_native);
1142 if (!err)
1143 err = get_v4l2_standard32(up_native, up);
1144 compatible_arg = 0;
1145 break;
1147 case VIDIOC_ENUMINPUT:
1148 err = alloc_userspace(sizeof(struct v4l2_input), 0, &up_native);
1149 if (!err)
1150 err = get_v4l2_input32(up_native, up);
1151 compatible_arg = 0;
1152 break;
1154 case VIDIOC_G_EXT_CTRLS:
1155 case VIDIOC_S_EXT_CTRLS:
1156 case VIDIOC_TRY_EXT_CTRLS:
1157 err = bufsize_v4l2_ext_controls(up, &aux_space);
1158 if (!err)
1159 err = alloc_userspace(sizeof(struct v4l2_ext_controls),
1160 aux_space, &up_native);
1161 if (!err) {
1162 aux_buf = up_native + sizeof(struct v4l2_ext_controls);
1163 err = get_v4l2_ext_controls32(file, up_native, up,
1164 aux_buf, aux_space);
1166 compatible_arg = 0;
1167 break;
1168 case VIDIOC_DQEVENT:
1169 err = alloc_userspace(sizeof(struct v4l2_event), 0, &up_native);
1170 compatible_arg = 0;
1171 break;
1173 if (err)
1174 return err;
1176 if (compatible_arg)
1177 err = native_ioctl(file, cmd, (unsigned long)up);
1178 else
1179 err = native_ioctl(file, cmd, (unsigned long)up_native);
1181 if (err == -ENOTTY)
1182 return err;
1185 * Special case: even after an error we need to put the
1186 * results back for these ioctls since the error_idx will
1187 * contain information on which control failed.
1189 switch (cmd) {
1190 case VIDIOC_G_EXT_CTRLS:
1191 case VIDIOC_S_EXT_CTRLS:
1192 case VIDIOC_TRY_EXT_CTRLS:
1193 if (put_v4l2_ext_controls32(file, up_native, up))
1194 err = -EFAULT;
1195 break;
1196 case VIDIOC_S_EDID:
1197 if (put_v4l2_edid32(up_native, up))
1198 err = -EFAULT;
1199 break;
1201 if (err)
1202 return err;
1204 switch (cmd) {
1205 case VIDIOC_S_INPUT:
1206 case VIDIOC_S_OUTPUT:
1207 case VIDIOC_G_INPUT:
1208 case VIDIOC_G_OUTPUT:
1209 if (assign_in_user((compat_uint_t __user *)up,
1210 ((unsigned int __user *)up_native)))
1211 err = -EFAULT;
1212 break;
1214 case VIDIOC_G_FBUF:
1215 err = put_v4l2_framebuffer32(up_native, up);
1216 break;
1218 case VIDIOC_DQEVENT:
1219 err = put_v4l2_event32(up_native, up);
1220 break;
1222 case VIDIOC_G_EDID:
1223 err = put_v4l2_edid32(up_native, up);
1224 break;
1226 case VIDIOC_G_FMT:
1227 case VIDIOC_S_FMT:
1228 case VIDIOC_TRY_FMT:
1229 err = put_v4l2_format32(up_native, up);
1230 break;
1232 case VIDIOC_CREATE_BUFS:
1233 err = put_v4l2_create32(up_native, up);
1234 break;
1236 case VIDIOC_PREPARE_BUF:
1237 case VIDIOC_QUERYBUF:
1238 case VIDIOC_QBUF:
1239 case VIDIOC_DQBUF:
1240 err = put_v4l2_buffer32(up_native, up);
1241 break;
1243 case VIDIOC_ENUMSTD:
1244 err = put_v4l2_standard32(up_native, up);
1245 break;
1247 case VIDIOC_ENUMINPUT:
1248 err = put_v4l2_input32(up_native, up);
1249 break;
1251 return err;
1254 long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1256 struct video_device *vdev = video_devdata(file);
1257 long ret = -ENOIOCTLCMD;
1259 if (!file->f_op->unlocked_ioctl)
1260 return ret;
1262 if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1263 ret = do_video_ioctl(file, cmd, arg);
1264 else if (vdev->fops->compat_ioctl32)
1265 ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1267 if (ret == -ENOIOCTLCMD)
1268 pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1269 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1270 return ret;
1272 EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);