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