v4l2-compat-ioctl32.c 28.0 KB
Newer Older
1 2 3 4 5 6 7
/*
 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
 *	Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
 *
 * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
 * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
 * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
P
Pavel Machek 已提交
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 13 14 15
 *
 * These routines maintain argument size conversion between 32bit and 64bit
 * ioctls.
 */

16
#include <linux/compat.h>
17
#include <linux/videodev2.h>
18
#include <linux/module.h>
19
#include <media/v4l2-ioctl.h>
20 21

#ifdef CONFIG_COMPAT
22

23
static long native_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
24
{
25
	long ret = -ENOIOCTLCMD;
26 27 28 29 30 31 32 33

	if (file->f_op->unlocked_ioctl)
		ret = file->f_op->unlocked_ioctl(file, cmd, arg);

	return ret;
}


34
struct v4l2_clip32 {
35 36 37 38
	struct v4l2_rect        c;
	compat_caddr_t 		next;
};

39
struct v4l2_window32 {
40 41 42 43 44 45 46 47 48 49
	struct v4l2_rect        w;
	enum v4l2_field  	field;
	__u32			chromakey;
	compat_caddr_t		clips; /* actually struct v4l2_clip32 * */
	__u32			clipcount;
	compat_caddr_t		bitmap;
};

static int get_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
{
50 51 52 53 54 55
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_window32)) ||
		copy_from_user(&kp->w, &up->w, sizeof(up->w)) ||
		get_user(kp->field, &up->field) ||
		get_user(kp->chromakey, &up->chromakey) ||
		get_user(kp->clipcount, &up->clipcount))
			return -EFAULT;
56 57 58
	if (kp->clipcount > 2048)
		return -EINVAL;
	if (kp->clipcount) {
59 60
		struct v4l2_clip32 __user *uclips;
		struct v4l2_clip __user *kclips;
61
		int n = kp->clipcount;
62
		compat_caddr_t p;
63

64 65 66
		if (get_user(p, &up->clips))
			return -EFAULT;
		uclips = compat_ptr(p);
67 68 69
		kclips = compat_alloc_user_space(n * sizeof(struct v4l2_clip));
		kp->clips = kclips;
		while (--n >= 0) {
70 71 72
			if (copy_in_user(&kclips->c, &uclips->c, sizeof(uclips->c)))
				return -EFAULT;
			if (put_user(n ? kclips + 1 : NULL, &kclips->next))
73
				return -EFAULT;
74 75 76 77
			uclips += 1;
			kclips += 1;
		}
	} else
78
		kp->clips = NULL;
79 80 81 82 83
	return 0;
}

static int put_v4l2_window32(struct v4l2_window *kp, struct v4l2_window32 __user *up)
{
84
	if (copy_to_user(&up->w, &kp->w, sizeof(kp->w)) ||
85 86 87 88
		put_user(kp->field, &up->field) ||
		put_user(kp->chromakey, &up->chromakey) ||
		put_user(kp->clipcount, &up->clipcount))
			return -EFAULT;
89 90 91 92 93
	return 0;
}

static inline int get_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
94 95
	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format)))
		return -EFAULT;
96
	return 0;
97 98
}

99 100 101 102 103 104 105 106
static inline int get_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
				struct v4l2_pix_format_mplane __user *up)
{
	if (copy_from_user(kp, up, sizeof(struct v4l2_pix_format_mplane)))
		return -EFAULT;
	return 0;
}

107 108
static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
109 110
	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
		return -EFAULT;
111
	return 0;
112 113
}

114 115 116 117 118 119 120 121
static inline int put_v4l2_pix_format_mplane(struct v4l2_pix_format_mplane *kp,
				struct v4l2_pix_format_mplane __user *up)
{
	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format_mplane)))
		return -EFAULT;
	return 0;
}

122 123
static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
124 125
	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
		return -EFAULT;
126
	return 0;
127 128 129 130
}

static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
131 132
	if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
		return -EFAULT;
133
	return 0;
134 135
}

136 137 138 139 140 141 142 143 144 145 146 147 148 149
static inline int get_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
{
	if (copy_from_user(kp, up, sizeof(struct v4l2_sliced_vbi_format)))
		return -EFAULT;
	return 0;
}

static inline int put_v4l2_sliced_vbi_format(struct v4l2_sliced_vbi_format *kp, struct v4l2_sliced_vbi_format __user *up)
{
	if (copy_to_user(up, kp, sizeof(struct v4l2_sliced_vbi_format)))
		return -EFAULT;
	return 0;
}

150
struct v4l2_format32 {
151
	enum v4l2_buf_type type;
152
	union {
153
		struct v4l2_pix_format	pix;
154
		struct v4l2_pix_format_mplane	pix_mp;
155 156 157
		struct v4l2_window32	win;
		struct v4l2_vbi_format	vbi;
		struct v4l2_sliced_vbi_format	sliced;
158
		__u8	raw_data[200];        /* user-defined */
159 160 161
	} fmt;
};

162 163 164 165 166 167 168 169 170
/**
 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
 * @index:	on return, index of the first created buffer
 * @count:	entry: number of requested buffers,
 *		return: number of created buffers
 * @memory:	buffer memory type
 * @format:	frame format, for which buffers are requested
 * @reserved:	future extensions
 */
171
struct v4l2_create_buffers32 {
172
	__u32			index;
173 174
	__u32			count;
	enum v4l2_memory        memory;
175
	struct v4l2_format32	format;
176 177 178 179
	__u32			reserved[8];
};

static int __get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
180 181 182
{
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
183
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
184
		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
185 186 187 188
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		return get_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
						  &up->fmt.pix_mp);
189
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
190
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
191 192
		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
	case V4L2_BUF_TYPE_VBI_CAPTURE:
193
	case V4L2_BUF_TYPE_VBI_OUTPUT:
194
		return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
195 196 197 198 199 200 201
	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
		return get_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
	case V4L2_BUF_TYPE_PRIVATE:
		if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
			return -EFAULT;
		return 0;
202
	default:
203
		printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
204
								kp->type);
205
		return -EINVAL;
206 207 208
	}
}

209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
			get_user(kp->type, &up->type))
			return -EFAULT;
	return __get_v4l2_format32(kp, up);
}

static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
{
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_create_buffers32)) ||
	    copy_from_user(kp, up, offsetof(struct v4l2_create_buffers32, format.fmt)))
			return -EFAULT;
	return __get_v4l2_format32(&kp->format, &up->format);
}

static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
226 227 228
{
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
229
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
230
		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
231 232 233 234
	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
		return put_v4l2_pix_format_mplane(&kp->fmt.pix_mp,
						  &up->fmt.pix_mp);
235
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
236
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
237 238
		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
	case V4L2_BUF_TYPE_VBI_CAPTURE:
239
	case V4L2_BUF_TYPE_VBI_OUTPUT:
240
		return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
241 242 243 244 245 246 247
	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
		return put_v4l2_sliced_vbi_format(&kp->fmt.sliced, &up->fmt.sliced);
	case V4L2_BUF_TYPE_PRIVATE:
		if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
			return -EFAULT;
		return 0;
248
	default:
249 250 251
		printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
								kp->type);
		return -EINVAL;
252 253 254
	}
}

255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
		put_user(kp->type, &up->type))
		return -EFAULT;
	return __put_v4l2_format32(kp, up);
}

static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
	    copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
			return -EFAULT;
	return __put_v4l2_format32(&kp->format, &up->format);
}

271
struct v4l2_standard32 {
272 273 274 275 276 277 278 279 280 281 282
	__u32		     index;
	__u32		     id[2]; /* __u64 would get the alignment wrong */
	__u8		     name[24];
	struct v4l2_fract    frameperiod; /* Frames, not fields */
	__u32		     framelines;
	__u32		     reserved[4];
};

static int get_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
{
	/* other fields are not set by the user, nor used by the driver */
283 284 285 286
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
		get_user(kp->index, &up->index))
		return -EFAULT;
	return 0;
287 288 289 290
}

static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
{
291
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
292 293 294 295 296 297 298 299 300 301
		put_user(kp->index, &up->index) ||
		copy_to_user(up->id, &kp->id, sizeof(__u64)) ||
		copy_to_user(up->name, kp->name, 24) ||
		copy_to_user(&up->frameperiod, &kp->frameperiod, sizeof(kp->frameperiod)) ||
		put_user(kp->framelines, &up->framelines) ||
		copy_to_user(up->reserved, kp->reserved, 4 * sizeof(__u32)))
			return -EFAULT;
	return 0;
}

302 303 304 305 306 307 308 309 310 311 312
struct v4l2_plane32 {
	__u32			bytesused;
	__u32			length;
	union {
		__u32		mem_offset;
		compat_long_t	userptr;
	} m;
	__u32			data_offset;
	__u32			reserved[11];
};

313
struct v4l2_buffer32 {
314 315 316 317 318 319 320 321 322 323 324 325 326 327
	__u32			index;
	enum v4l2_buf_type      type;
	__u32			bytesused;
	__u32			flags;
	enum v4l2_field		field;
	struct compat_timeval	timestamp;
	struct v4l2_timecode	timecode;
	__u32			sequence;

	/* memory location */
	enum v4l2_memory        memory;
	union {
		__u32           offset;
		compat_long_t   userptr;
328
		compat_caddr_t  planes;
329 330 331 332 333 334
	} m;
	__u32			length;
	__u32			input;
	__u32			reserved;
};

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
static int get_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
				enum v4l2_memory memory)
{
	void __user *up_pln;
	compat_long_t p;

	if (copy_in_user(up, up32, 2 * sizeof(__u32)) ||
		copy_in_user(&up->data_offset, &up32->data_offset,
				sizeof(__u32)))
		return -EFAULT;

	if (memory == V4L2_MEMORY_USERPTR) {
		if (get_user(p, &up32->m.userptr))
			return -EFAULT;
		up_pln = compat_ptr(p);
		if (put_user((unsigned long)up_pln, &up->m.userptr))
			return -EFAULT;
	} else {
		if (copy_in_user(&up->m.mem_offset, &up32->m.mem_offset,
					sizeof(__u32)))
			return -EFAULT;
	}

	return 0;
}

static int put_v4l2_plane32(struct v4l2_plane *up, struct v4l2_plane32 *up32,
				enum v4l2_memory memory)
{
	if (copy_in_user(up32, up, 2 * sizeof(__u32)) ||
		copy_in_user(&up32->data_offset, &up->data_offset,
				sizeof(__u32)))
		return -EFAULT;

	/* For MMAP, driver might've set up the offset, so copy it back.
	 * USERPTR stays the same (was userspace-provided), so no copying. */
	if (memory == V4L2_MEMORY_MMAP)
		if (copy_in_user(&up32->m.mem_offset, &up->m.mem_offset,
					sizeof(__u32)))
			return -EFAULT;

	return 0;
}

379 380
static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
381 382 383 384 385
	struct v4l2_plane32 __user *uplane32;
	struct v4l2_plane __user *uplane;
	compat_caddr_t p;
	int num_planes;
	int ret;
386

387 388 389 390 391 392 393
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_buffer32)) ||
		get_user(kp->index, &up->index) ||
		get_user(kp->type, &up->type) ||
		get_user(kp->flags, &up->flags) ||
		get_user(kp->memory, &up->memory) ||
		get_user(kp->input, &up->input))
			return -EFAULT;
394 395 396 397 398 399 400

	if (V4L2_TYPE_IS_OUTPUT(kp->type))
		if (get_user(kp->bytesused, &up->bytesused) ||
			get_user(kp->field, &up->field) ||
			get_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
			get_user(kp->timestamp.tv_usec,
					&up->timestamp.tv_usec))
401
			return -EFAULT;
402

403 404
	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
		if (get_user(kp->length, &up->length))
405 406
			return -EFAULT;

407 408 409 410 411 412
		num_planes = kp->length;
		if (num_planes == 0) {
			kp->m.planes = NULL;
			/* num_planes == 0 is legal, e.g. when userspace doesn't
			 * need planes array on DQBUF*/
			return 0;
413
		}
414 415

		if (get_user(p, &up->m.planes))
416
			return -EFAULT;
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458

		uplane32 = compat_ptr(p);
		if (!access_ok(VERIFY_READ, uplane32,
				num_planes * sizeof(struct v4l2_plane32)))
			return -EFAULT;

		/* We don't really care if userspace decides to kill itself
		 * by passing a very big num_planes value */
		uplane = compat_alloc_user_space(num_planes *
						sizeof(struct v4l2_plane));
		kp->m.planes = uplane;

		while (--num_planes >= 0) {
			ret = get_v4l2_plane32(uplane, uplane32, kp->memory);
			if (ret)
				return ret;
			++uplane;
			++uplane32;
		}
	} else {
		switch (kp->memory) {
		case V4L2_MEMORY_MMAP:
			if (get_user(kp->length, &up->length) ||
				get_user(kp->m.offset, &up->m.offset))
				return -EFAULT;
			break;
		case V4L2_MEMORY_USERPTR:
			{
			compat_long_t tmp;

			if (get_user(kp->length, &up->length) ||
			    get_user(tmp, &up->m.userptr))
				return -EFAULT;

			kp->m.userptr = (unsigned long)compat_ptr(tmp);
			}
			break;
		case V4L2_MEMORY_OVERLAY:
			if (get_user(kp->m.offset, &up->m.offset))
				return -EFAULT;
			break;
		}
459
	}
460

461 462 463 464 465
	return 0;
}

static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
466 467 468 469 470 471
	struct v4l2_plane32 __user *uplane32;
	struct v4l2_plane __user *uplane;
	compat_caddr_t p;
	int num_planes;
	int ret;

472 473 474 475 476 477 478
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_buffer32)) ||
		put_user(kp->index, &up->index) ||
		put_user(kp->type, &up->type) ||
		put_user(kp->flags, &up->flags) ||
		put_user(kp->memory, &up->memory) ||
		put_user(kp->input, &up->input))
			return -EFAULT;
479

480 481 482 483 484 485 486 487
	if (put_user(kp->bytesused, &up->bytesused) ||
		put_user(kp->field, &up->field) ||
		put_user(kp->timestamp.tv_sec, &up->timestamp.tv_sec) ||
		put_user(kp->timestamp.tv_usec, &up->timestamp.tv_usec) ||
		copy_to_user(&up->timecode, &kp->timecode, sizeof(struct v4l2_timecode)) ||
		put_user(kp->sequence, &up->sequence) ||
		put_user(kp->reserved, &up->reserved))
			return -EFAULT;
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

	if (V4L2_TYPE_IS_MULTIPLANAR(kp->type)) {
		num_planes = kp->length;
		if (num_planes == 0)
			return 0;

		uplane = kp->m.planes;
		if (get_user(p, &up->m.planes))
			return -EFAULT;
		uplane32 = compat_ptr(p);

		while (--num_planes >= 0) {
			ret = put_v4l2_plane32(uplane, uplane32, kp->memory);
			if (ret)
				return ret;
			++uplane;
			++uplane32;
		}
	} else {
		switch (kp->memory) {
		case V4L2_MEMORY_MMAP:
			if (put_user(kp->length, &up->length) ||
				put_user(kp->m.offset, &up->m.offset))
				return -EFAULT;
			break;
		case V4L2_MEMORY_USERPTR:
			if (put_user(kp->length, &up->length) ||
				put_user(kp->m.userptr, &up->m.userptr))
				return -EFAULT;
			break;
		case V4L2_MEMORY_OVERLAY:
			if (put_user(kp->m.offset, &up->m.offset))
				return -EFAULT;
			break;
		}
	}

525 526 527
	return 0;
}

528
struct v4l2_framebuffer32 {
529 530 531 532 533 534
	__u32			capability;
	__u32			flags;
	compat_caddr_t 		base;
	struct v4l2_pix_format	fmt;
};

535 536 537 538
static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
	u32 tmp;

539 540 541 542 543
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_framebuffer32)) ||
		get_user(tmp, &up->base) ||
		get_user(kp->capability, &up->capability) ||
		get_user(kp->flags, &up->flags))
			return -EFAULT;
544 545 546 547 548
	kp->base = compat_ptr(tmp);
	get_v4l2_pix_format(&kp->fmt, &up->fmt);
	return 0;
}

549 550 551 552
static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
	u32 tmp = (u32)((unsigned long)kp->base);

553
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
554 555 556 557
		put_user(tmp, &up->base) ||
		put_user(kp->capability, &up->capability) ||
		put_user(kp->flags, &up->flags))
			return -EFAULT;
558 559 560 561
	put_v4l2_pix_format(&kp->fmt, &up->fmt);
	return 0;
}

562 563 564 565 566 567 568 569 570 571 572 573 574 575
struct v4l2_input32 {
	__u32	     index;		/*  Which input */
	__u8	     name[32];		/*  Label */
	__u32	     type;		/*  Type of input */
	__u32	     audioset;		/*  Associated audios (bitfield) */
	__u32        tuner;             /*  Associated tuner */
	v4l2_std_id  std;
	__u32	     status;
	__u32	     reserved[4];
} __attribute__ ((packed));

/* The 64-bit v4l2_input struct has extra padding at the end of the struct.
   Otherwise it is identical to the 32-bit version. */
static inline int get_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
576
{
577
	if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
578
		return -EFAULT;
579 580 581
	return 0;
}

582
static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
583
{
584
	if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
585
		return -EFAULT;
586 587 588
	return 0;
}

589 590 591 592 593 594
struct v4l2_ext_controls32 {
       __u32 ctrl_class;
       __u32 count;
       __u32 error_idx;
       __u32 reserved[2];
       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
595 596
};

597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
struct v4l2_ext_control32 {
	__u32 id;
	__u32 size;
	__u32 reserved2[1];
	union {
		__s32 value;
		__s64 value64;
		compat_caddr_t string; /* actually char * */
	};
} __attribute__ ((packed));

/* The following function really belong in v4l2-common, but that causes
   a circular dependency between modules. We need to think about this, but
   for now this will do. */

/* Return non-zero if this control is a pointer type. Currently only
613
   type STRING is a pointer type. */
614 615
static inline int ctrl_is_pointer(u32 id)
{
616 617 618 619 620 621 622
	switch (id) {
	case V4L2_CID_RDS_TX_PS_NAME:
	case V4L2_CID_RDS_TX_RADIO_TEXT:
		return 1;
	default:
		return 0;
	}
623 624
}

625
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
626
{
627
	struct v4l2_ext_control32 __user *ucontrols;
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645
	struct v4l2_ext_control __user *kcontrols;
	int n;
	compat_caddr_t p;

	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_ext_controls32)) ||
		get_user(kp->ctrl_class, &up->ctrl_class) ||
		get_user(kp->count, &up->count) ||
		get_user(kp->error_idx, &up->error_idx) ||
		copy_from_user(kp->reserved, up->reserved, sizeof(kp->reserved)))
			return -EFAULT;
	n = kp->count;
	if (n == 0) {
		kp->controls = NULL;
		return 0;
	}
	if (get_user(p, &up->controls))
		return -EFAULT;
	ucontrols = compat_ptr(p);
646 647
	if (!access_ok(VERIFY_READ, ucontrols,
			n * sizeof(struct v4l2_ext_control32)))
648 649 650 651
		return -EFAULT;
	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
	kp->controls = kcontrols;
	while (--n >= 0) {
652
		if (copy_in_user(kcontrols, ucontrols, sizeof(*ucontrols)))
653
			return -EFAULT;
654 655 656 657 658 659 660 661 662
		if (ctrl_is_pointer(kcontrols->id)) {
			void __user *s;

			if (get_user(p, &ucontrols->string))
				return -EFAULT;
			s = compat_ptr(p);
			if (put_user(s, &kcontrols->string))
				return -EFAULT;
		}
663 664 665
		ucontrols++;
		kcontrols++;
	}
666 667 668
	return 0;
}

669
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
670
{
671
	struct v4l2_ext_control32 __user *ucontrols;
672 673 674 675 676 677 678 679 680 681 682 683
	struct v4l2_ext_control __user *kcontrols = kp->controls;
	int n = kp->count;
	compat_caddr_t p;

	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_ext_controls32)) ||
		put_user(kp->ctrl_class, &up->ctrl_class) ||
		put_user(kp->count, &up->count) ||
		put_user(kp->error_idx, &up->error_idx) ||
		copy_to_user(up->reserved, kp->reserved, sizeof(up->reserved)))
			return -EFAULT;
	if (!kp->count)
		return 0;
684

685
	if (get_user(p, &up->controls))
686
		return -EFAULT;
687
	ucontrols = compat_ptr(p);
688 689
	if (!access_ok(VERIFY_WRITE, ucontrols,
			n * sizeof(struct v4l2_ext_control32)))
690 691
		return -EFAULT;

692
	while (--n >= 0) {
693 694 695 696 697 698 699 700
		unsigned size = sizeof(*ucontrols);

		/* Do not modify the pointer when copying a pointer control.
		   The contents of the pointer was changed, not the pointer
		   itself. */
		if (ctrl_is_pointer(kcontrols->id))
			size -= sizeof(ucontrols->value64);
		if (copy_in_user(ucontrols, kcontrols, size))
701 702 703
			return -EFAULT;
		ucontrols++;
		kcontrols++;
704
	}
705
	return 0;
706
}
707

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
struct v4l2_event32 {
	__u32				type;
	union {
		__u8			data[64];
	} u;
	__u32				pending;
	__u32				sequence;
	struct compat_timespec		timestamp;
	__u32				id;
	__u32				reserved[8];
};

static int put_v4l2_event32(struct v4l2_event *kp, struct v4l2_event32 __user *up)
{
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_event32)) ||
		put_user(kp->type, &up->type) ||
		copy_to_user(&up->u, &kp->u, sizeof(kp->u)) ||
		put_user(kp->pending, &up->pending) ||
		put_user(kp->sequence, &up->sequence) ||
		put_compat_timespec(&kp->timestamp, &up->timestamp) ||
		put_user(kp->id, &up->id) ||
		copy_to_user(up->reserved, kp->reserved, 8 * sizeof(__u32)))
			return -EFAULT;
	return 0;
}

734 735 736 737 738 739 740 741 742 743 744 745 746
#define VIDIOC_G_FMT32		_IOWR('V',  4, struct v4l2_format32)
#define VIDIOC_S_FMT32		_IOWR('V',  5, struct v4l2_format32)
#define VIDIOC_QUERYBUF32	_IOWR('V',  9, struct v4l2_buffer32)
#define VIDIOC_G_FBUF32		_IOR ('V', 10, struct v4l2_framebuffer32)
#define VIDIOC_S_FBUF32		_IOW ('V', 11, struct v4l2_framebuffer32)
#define VIDIOC_QBUF32		_IOWR('V', 15, struct v4l2_buffer32)
#define VIDIOC_DQBUF32		_IOWR('V', 17, struct v4l2_buffer32)
#define VIDIOC_ENUMSTD32	_IOWR('V', 25, struct v4l2_standard32)
#define VIDIOC_ENUMINPUT32	_IOWR('V', 26, struct v4l2_input32)
#define VIDIOC_TRY_FMT32      	_IOWR('V', 64, struct v4l2_format32)
#define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
747
#define	VIDIOC_DQEVENT32	_IOR ('V', 89, struct v4l2_event32)
748 749
#define VIDIOC_CREATE_BUFS32	_IOWR('V', 92, struct v4l2_create_buffers32)
#define VIDIOC_PREPARE_BUF32	_IOWR('V', 93, struct v4l2_buffer32)
750 751 752 753 754 755 756 757

#define VIDIOC_OVERLAY32	_IOW ('V', 14, s32)
#define VIDIOC_STREAMON32	_IOW ('V', 18, s32)
#define VIDIOC_STREAMOFF32	_IOW ('V', 19, s32)
#define VIDIOC_G_INPUT32	_IOR ('V', 38, s32)
#define VIDIOC_S_INPUT32	_IOWR('V', 39, s32)
#define VIDIOC_G_OUTPUT32	_IOR ('V', 46, s32)
#define VIDIOC_S_OUTPUT32	_IOWR('V', 47, s32)
758

759
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
760 761
{
	union {
762 763 764
		struct v4l2_format v2f;
		struct v4l2_buffer v2b;
		struct v4l2_framebuffer v2fb;
765
		struct v4l2_input v2i;
766 767
		struct v4l2_standard v2s;
		struct v4l2_ext_controls v2ecs;
768
		struct v4l2_event v2ev;
769
		struct v4l2_create_buffers v2crt;
770
		unsigned long vx;
771
		int vi;
772 773
	} karg;
	void __user *up = compat_ptr(arg);
774
	int compatible_arg = 1;
775
	long err = 0;
776 777

	/* First, convert the command. */
778
	switch (cmd) {
779 780 781 782 783 784 785 786 787 788 789 790 791
	case VIDIOC_G_FMT32: cmd = VIDIOC_G_FMT; break;
	case VIDIOC_S_FMT32: cmd = VIDIOC_S_FMT; break;
	case VIDIOC_QUERYBUF32: cmd = VIDIOC_QUERYBUF; break;
	case VIDIOC_G_FBUF32: cmd = VIDIOC_G_FBUF; break;
	case VIDIOC_S_FBUF32: cmd = VIDIOC_S_FBUF; break;
	case VIDIOC_QBUF32: cmd = VIDIOC_QBUF; break;
	case VIDIOC_DQBUF32: cmd = VIDIOC_DQBUF; break;
	case VIDIOC_ENUMSTD32: cmd = VIDIOC_ENUMSTD; break;
	case VIDIOC_ENUMINPUT32: cmd = VIDIOC_ENUMINPUT; break;
	case VIDIOC_TRY_FMT32: cmd = VIDIOC_TRY_FMT; break;
	case VIDIOC_G_EXT_CTRLS32: cmd = VIDIOC_G_EXT_CTRLS; break;
	case VIDIOC_S_EXT_CTRLS32: cmd = VIDIOC_S_EXT_CTRLS; break;
	case VIDIOC_TRY_EXT_CTRLS32: cmd = VIDIOC_TRY_EXT_CTRLS; break;
792
	case VIDIOC_DQEVENT32: cmd = VIDIOC_DQEVENT; break;
793 794 795 796 797 798 799
	case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
	case VIDIOC_STREAMON32: cmd = VIDIOC_STREAMON; break;
	case VIDIOC_STREAMOFF32: cmd = VIDIOC_STREAMOFF; break;
	case VIDIOC_G_INPUT32: cmd = VIDIOC_G_INPUT; break;
	case VIDIOC_S_INPUT32: cmd = VIDIOC_S_INPUT; break;
	case VIDIOC_G_OUTPUT32: cmd = VIDIOC_G_OUTPUT; break;
	case VIDIOC_S_OUTPUT32: cmd = VIDIOC_S_OUTPUT; break;
800 801
	case VIDIOC_CREATE_BUFS32: cmd = VIDIOC_CREATE_BUFS; break;
	case VIDIOC_PREPARE_BUF32: cmd = VIDIOC_PREPARE_BUF; break;
802
	}
803

804
	switch (cmd) {
805
	case VIDIOC_OVERLAY:
806 807
	case VIDIOC_STREAMON:
	case VIDIOC_STREAMOFF:
808 809 810 811
	case VIDIOC_S_INPUT:
	case VIDIOC_S_OUTPUT:
		err = get_user(karg.vi, (s32 __user *)up);
		compatible_arg = 0;
812
		break;
813

814 815
	case VIDIOC_G_INPUT:
	case VIDIOC_G_OUTPUT:
816 817
		compatible_arg = 0;
		break;
818 819 820 821 822 823 824 825

	case VIDIOC_G_FMT:
	case VIDIOC_S_FMT:
	case VIDIOC_TRY_FMT:
		err = get_v4l2_format32(&karg.v2f, up);
		compatible_arg = 0;
		break;

826 827 828 829 830 831
	case VIDIOC_CREATE_BUFS:
		err = get_v4l2_create32(&karg.v2crt, up);
		compatible_arg = 0;
		break;

	case VIDIOC_PREPARE_BUF:
832 833 834 835 836 837 838
	case VIDIOC_QUERYBUF:
	case VIDIOC_QBUF:
	case VIDIOC_DQBUF:
		err = get_v4l2_buffer32(&karg.v2b, up);
		compatible_arg = 0;
		break;

839 840
	case VIDIOC_S_FBUF:
		err = get_v4l2_framebuffer32(&karg.v2fb, up);
841 842 843
		compatible_arg = 0;
		break;

844
	case VIDIOC_G_FBUF:
845 846 847
		compatible_arg = 0;
		break;

848 849
	case VIDIOC_ENUMSTD:
		err = get_v4l2_standard32(&karg.v2s, up);
850 851 852
		compatible_arg = 0;
		break;

853
	case VIDIOC_ENUMINPUT:
854 855 856 857
		err = get_v4l2_input32(&karg.v2i, up);
		compatible_arg = 0;
		break;

858 859 860 861
	case VIDIOC_G_EXT_CTRLS:
	case VIDIOC_S_EXT_CTRLS:
	case VIDIOC_TRY_EXT_CTRLS:
		err = get_v4l2_ext_controls32(&karg.v2ecs, up);
862 863
		compatible_arg = 0;
		break;
864 865 866
	case VIDIOC_DQEVENT:
		compatible_arg = 0;
		break;
867
	}
868
	if (err)
869
		return err;
870

871
	if (compatible_arg)
872
		err = native_ioctl(file, cmd, (unsigned long)up);
873 874
	else {
		mm_segment_t old_fs = get_fs();
875

876
		set_fs(KERNEL_DS);
877
		err = native_ioctl(file, cmd, (unsigned long)&karg);
878 879
		set_fs(old_fs);
	}
880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901

	/* Special case: even after an error we need to put the
	   results back for these ioctls since the error_idx will
	   contain information on which control failed. */
	switch (cmd) {
	case VIDIOC_G_EXT_CTRLS:
	case VIDIOC_S_EXT_CTRLS:
	case VIDIOC_TRY_EXT_CTRLS:
		if (put_v4l2_ext_controls32(&karg.v2ecs, up))
			err = -EFAULT;
		break;
	}
	if (err)
		return err;

	switch (cmd) {
	case VIDIOC_S_INPUT:
	case VIDIOC_S_OUTPUT:
	case VIDIOC_G_INPUT:
	case VIDIOC_G_OUTPUT:
		err = put_user(((s32)karg.vi), (s32 __user *)up);
		break;
902

903 904 905 906
	case VIDIOC_G_FBUF:
		err = put_v4l2_framebuffer32(&karg.v2fb, up);
		break;

907 908 909 910
	case VIDIOC_DQEVENT:
		err = put_v4l2_event32(&karg.v2ev, up);
		break;

911 912 913 914 915 916
	case VIDIOC_G_FMT:
	case VIDIOC_S_FMT:
	case VIDIOC_TRY_FMT:
		err = put_v4l2_format32(&karg.v2f, up);
		break;

917 918 919 920
	case VIDIOC_CREATE_BUFS:
		err = put_v4l2_create32(&karg.v2crt, up);
		break;

921 922 923 924 925 926 927 928 929 930 931 932 933
	case VIDIOC_QUERYBUF:
	case VIDIOC_QBUF:
	case VIDIOC_DQBUF:
		err = put_v4l2_buffer32(&karg.v2b, up);
		break;

	case VIDIOC_ENUMSTD:
		err = put_v4l2_standard32(&karg.v2s, up);
		break;

	case VIDIOC_ENUMINPUT:
		err = put_v4l2_input32(&karg.v2i, up);
		break;
934 935 936 937
	}
	return err;
}

938
long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
939
{
940
	long ret = -ENOIOCTLCMD;
941

942
	if (!file->f_op->unlocked_ioctl)
943 944 945
		return ret;

	switch (cmd) {
946
	case VIDIOC_QUERYCAP:
947
	case VIDIOC_RESERVED:
948 949 950 951 952 953 954 955 956 957 958 959 960
	case VIDIOC_ENUM_FMT:
	case VIDIOC_G_FMT32:
	case VIDIOC_S_FMT32:
	case VIDIOC_REQBUFS:
	case VIDIOC_QUERYBUF32:
	case VIDIOC_G_FBUF32:
	case VIDIOC_S_FBUF32:
	case VIDIOC_OVERLAY32:
	case VIDIOC_QBUF32:
	case VIDIOC_DQBUF32:
	case VIDIOC_STREAMON32:
	case VIDIOC_STREAMOFF32:
	case VIDIOC_G_PARM:
961
	case VIDIOC_S_PARM:
962 963 964 965 966
	case VIDIOC_G_STD:
	case VIDIOC_S_STD:
	case VIDIOC_ENUMSTD32:
	case VIDIOC_ENUMINPUT32:
	case VIDIOC_G_CTRL:
967
	case VIDIOC_S_CTRL:
968 969 970 971
	case VIDIOC_G_TUNER:
	case VIDIOC_S_TUNER:
	case VIDIOC_G_AUDIO:
	case VIDIOC_S_AUDIO:
972
	case VIDIOC_QUERYCTRL:
973
	case VIDIOC_QUERYMENU:
974 975
	case VIDIOC_G_INPUT32:
	case VIDIOC_S_INPUT32:
976 977 978 979 980 981 982 983 984 985 986 987
	case VIDIOC_G_OUTPUT32:
	case VIDIOC_S_OUTPUT32:
	case VIDIOC_ENUMOUTPUT:
	case VIDIOC_G_AUDOUT:
	case VIDIOC_S_AUDOUT:
	case VIDIOC_G_MODULATOR:
	case VIDIOC_S_MODULATOR:
	case VIDIOC_S_FREQUENCY:
	case VIDIOC_G_FREQUENCY:
	case VIDIOC_CROPCAP:
	case VIDIOC_G_CROP:
	case VIDIOC_S_CROP:
988 989
	case VIDIOC_G_SELECTION:
	case VIDIOC_S_SELECTION:
990 991 992
	case VIDIOC_G_JPEGCOMP:
	case VIDIOC_S_JPEGCOMP:
	case VIDIOC_QUERYSTD:
993
	case VIDIOC_TRY_FMT32:
994 995 996 997 998 999 1000 1001 1002
	case VIDIOC_ENUMAUDIO:
	case VIDIOC_ENUMAUDOUT:
	case VIDIOC_G_PRIORITY:
	case VIDIOC_S_PRIORITY:
	case VIDIOC_G_SLICED_VBI_CAP:
	case VIDIOC_LOG_STATUS:
	case VIDIOC_G_EXT_CTRLS32:
	case VIDIOC_S_EXT_CTRLS32:
	case VIDIOC_TRY_EXT_CTRLS32:
1003 1004
	case VIDIOC_ENUM_FRAMESIZES:
	case VIDIOC_ENUM_FRAMEINTERVALS:
1005 1006 1007
	case VIDIOC_G_ENC_INDEX:
	case VIDIOC_ENCODER_CMD:
	case VIDIOC_TRY_ENCODER_CMD:
1008 1009
	case VIDIOC_DECODER_CMD:
	case VIDIOC_TRY_DECODER_CMD:
1010 1011
	case VIDIOC_DBG_S_REGISTER:
	case VIDIOC_DBG_G_REGISTER:
1012
	case VIDIOC_DBG_G_CHIP_IDENT:
1013
	case VIDIOC_S_HW_FREQ_SEEK:
1014 1015 1016 1017 1018 1019
	case VIDIOC_ENUM_DV_PRESETS:
	case VIDIOC_S_DV_PRESET:
	case VIDIOC_G_DV_PRESET:
	case VIDIOC_QUERY_DV_PRESET:
	case VIDIOC_S_DV_TIMINGS:
	case VIDIOC_G_DV_TIMINGS:
1020
	case VIDIOC_DQEVENT:
1021
	case VIDIOC_DQEVENT32:
1022 1023
	case VIDIOC_SUBSCRIBE_EVENT:
	case VIDIOC_UNSUBSCRIBE_EVENT:
1024 1025
	case VIDIOC_CREATE_BUFS32:
	case VIDIOC_PREPARE_BUF32:
1026 1027 1028
		ret = do_video_ioctl(file, cmd, arg);
		break;

1029
	default:
1030 1031 1032
		printk(KERN_WARNING "compat_ioctl32: "
			"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
			_IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1033
		break;
1034
	}
1035
	return ret;
1036
}
1037
EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
1038
#endif
1039 1040

MODULE_LICENSE("GPL");