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