[go: nahoru, domu]

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