v4l2-compat-ioctl32.c 21.6 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
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
18
#include <linux/videodev.h>
19
#include <linux/videodev2.h>
20
#include <linux/module.h>
21
#include <media/v4l2-ioctl.h>
22 23

#ifdef CONFIG_COMPAT
24

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

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

	return ret;
}


36
struct v4l2_clip32 {
37 38 39 40
	struct v4l2_rect        c;
	compat_caddr_t 		next;
};

41
struct v4l2_window32 {
42 43 44 45 46 47 48 49 50 51
	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)
{
52 53 54 55 56 57
	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;
58 59 60
	if (kp->clipcount > 2048)
		return -EINVAL;
	if (kp->clipcount) {
61 62
		struct v4l2_clip32 __user *uclips;
		struct v4l2_clip __user *kclips;
63
		int n = kp->clipcount;
64
		compat_caddr_t p;
65

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

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

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

static inline int put_v4l2_pix_format(struct v4l2_pix_format *kp, struct v4l2_pix_format __user *up)
{
103 104
	if (copy_to_user(up, kp, sizeof(struct v4l2_pix_format)))
		return -EFAULT;
105
	return 0;
106 107 108 109
}

static inline int get_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
110 111
	if (copy_from_user(kp, up, sizeof(struct v4l2_vbi_format)))
		return -EFAULT;
112
	return 0;
113 114 115 116
}

static inline int put_v4l2_vbi_format(struct v4l2_vbi_format *kp, struct v4l2_vbi_format __user *up)
{
117 118
	if (copy_to_user(up, kp, sizeof(struct v4l2_vbi_format)))
		return -EFAULT;
119
	return 0;
120 121
}

122 123 124 125 126 127 128 129 130 131 132 133 134 135
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;
}

136
struct v4l2_format32 {
137
	enum v4l2_buf_type type;
138
	union {
139 140 141 142
		struct v4l2_pix_format	pix;
		struct v4l2_window32	win;
		struct v4l2_vbi_format	vbi;
		struct v4l2_sliced_vbi_format	sliced;
143
		__u8	raw_data[200];        /* user-defined */
144 145 146 147 148
	} fmt;
};

static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
149 150 151
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_format32)) ||
			get_user(kp->type, &up->type))
			return -EFAULT;
152 153
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
154
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
155 156
		return get_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
157
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
158 159
		return get_v4l2_window32(&kp->fmt.win, &up->fmt.win);
	case V4L2_BUF_TYPE_VBI_CAPTURE:
160
	case V4L2_BUF_TYPE_VBI_OUTPUT:
161
		return get_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
162 163 164 165 166 167 168 169 170
	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;
	case 0:
		return -EINVAL;
171
	default:
172
		printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
173
								kp->type);
174
		return -EINVAL;
175 176 177 178 179
	}
}

static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
180
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
181
		put_user(kp->type, &up->type))
182 183 184
		return -EFAULT;
	switch (kp->type) {
	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
185
	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
186 187
		return put_v4l2_pix_format(&kp->fmt.pix, &up->fmt.pix);
	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
188
	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
189 190
		return put_v4l2_window32(&kp->fmt.win, &up->fmt.win);
	case V4L2_BUF_TYPE_VBI_CAPTURE:
191
	case V4L2_BUF_TYPE_VBI_OUTPUT:
192
		return put_v4l2_vbi_format(&kp->fmt.vbi, &up->fmt.vbi);
193 194 195 196 197 198 199 200 201
	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;
	case 0:
		return -EINVAL;
202
	default:
203 204 205
		printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
								kp->type);
		return -EINVAL;
206 207 208
	}
}

209
struct v4l2_standard32 {
210 211 212 213 214 215 216 217 218 219 220
	__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 */
221 222 223 224
	if (!access_ok(VERIFY_READ, up, sizeof(struct v4l2_standard32)) ||
		get_user(kp->index, &up->index))
		return -EFAULT;
	return 0;
225 226 227 228
}

static int put_v4l2_standard32(struct v4l2_standard *kp, struct v4l2_standard32 __user *up)
{
229
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_standard32)) ||
230 231 232 233 234 235 236 237 238 239
		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;
}

240
struct v4l2_buffer32 {
241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
	__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;
	} m;
	__u32			length;
	__u32			input;
	__u32			reserved;
};

static int get_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{

264 265 266 267 268 269 270
	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;
271
	switch (kp->memory) {
272
	case V4L2_MEMORY_MMAP:
273 274 275
		if (get_user(kp->length, &up->length) ||
			get_user(kp->m.offset, &up->m.offset))
			return -EFAULT;
276 277 278
		break;
	case V4L2_MEMORY_USERPTR:
		{
279
		compat_long_t tmp;
280

281 282 283 284 285
		if (get_user(kp->length, &up->length) ||
		    get_user(tmp, &up->m.userptr))
			return -EFAULT;

		kp->m.userptr = (unsigned long)compat_ptr(tmp);
286 287 288
		}
		break;
	case V4L2_MEMORY_OVERLAY:
289
		if (get_user(kp->m.offset, &up->m.offset))
290
			return -EFAULT;
291 292 293 294 295 296 297
		break;
	}
	return 0;
}

static int put_v4l2_buffer32(struct v4l2_buffer *kp, struct v4l2_buffer32 __user *up)
{
298 299 300 301 302 303 304
	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;
305
	switch (kp->memory) {
306
	case V4L2_MEMORY_MMAP:
307 308 309
		if (put_user(kp->length, &up->length) ||
			put_user(kp->m.offset, &up->m.offset))
			return -EFAULT;
310 311
		break;
	case V4L2_MEMORY_USERPTR:
312 313 314
		if (put_user(kp->length, &up->length) ||
			put_user(kp->m.userptr, &up->m.userptr))
			return -EFAULT;
315 316
		break;
	case V4L2_MEMORY_OVERLAY:
317 318
		if (put_user(kp->m.offset, &up->m.offset))
			return -EFAULT;
319 320
		break;
	}
321 322 323 324 325 326 327 328
	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;
329 330 331
	return 0;
}

332
struct v4l2_framebuffer32 {
333 334 335 336 337 338
	__u32			capability;
	__u32			flags;
	compat_caddr_t 		base;
	struct v4l2_pix_format	fmt;
};

339 340 341 342
static int get_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
	u32 tmp;

343 344 345 346 347
	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;
348 349 350 351 352
	kp->base = compat_ptr(tmp);
	get_v4l2_pix_format(&kp->fmt, &up->fmt);
	return 0;
}

353 354 355 356
static int put_v4l2_framebuffer32(struct v4l2_framebuffer *kp, struct v4l2_framebuffer32 __user *up)
{
	u32 tmp = (u32)((unsigned long)kp->base);

357
	if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_framebuffer32)) ||
358 359 360 361
		put_user(tmp, &up->base) ||
		put_user(kp->capability, &up->capability) ||
		put_user(kp->flags, &up->flags))
			return -EFAULT;
362 363 364 365
	put_v4l2_pix_format(&kp->fmt, &up->fmt);
	return 0;
}

366 367 368 369 370 371 372 373 374 375 376 377 378 379
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)
380
{
381
	if (copy_from_user(kp, up, sizeof(struct v4l2_input32)))
382
		return -EFAULT;
383 384 385
	return 0;
}

386
static inline int put_v4l2_input32(struct v4l2_input *kp, struct v4l2_input32 __user *up)
387
{
388
	if (copy_to_user(up, kp, sizeof(struct v4l2_input32)))
389
		return -EFAULT;
390 391 392
	return 0;
}

393 394 395 396 397 398
struct v4l2_ext_controls32 {
       __u32 ctrl_class;
       __u32 count;
       __u32 error_idx;
       __u32 reserved[2];
       compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
399 400
};

401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416
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
417
   type STRING is a pointer type. */
418 419
static inline int ctrl_is_pointer(u32 id)
{
420 421 422 423 424 425 426
	switch (id) {
	case V4L2_CID_RDS_TX_PS_NAME:
	case V4L2_CID_RDS_TX_RADIO_TEXT:
		return 1;
	default:
		return 0;
	}
427 428
}

429
static int get_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
430
{
431
	struct v4l2_ext_control32 __user *ucontrols;
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
	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);
	if (!access_ok(VERIFY_READ, ucontrols, n * sizeof(struct v4l2_ext_control)))
		return -EFAULT;
	kcontrols = compat_alloc_user_space(n * sizeof(struct v4l2_ext_control));
	kp->controls = kcontrols;
	while (--n >= 0) {
455
		if (copy_in_user(kcontrols, ucontrols, sizeof(*kcontrols)))
456
			return -EFAULT;
457 458 459 460 461 462 463 464 465
		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;
		}
466 467 468
		ucontrols++;
		kcontrols++;
	}
469 470 471
	return 0;
}

472
static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext_controls32 __user *up)
473
{
474
	struct v4l2_ext_control32 __user *ucontrols;
475 476 477 478 479 480 481 482 483 484 485 486
	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;
487

488
	if (get_user(p, &up->controls))
489
		return -EFAULT;
490 491
	ucontrols = compat_ptr(p);
	if (!access_ok(VERIFY_WRITE, ucontrols, n * sizeof(struct v4l2_ext_control)))
492 493
		return -EFAULT;

494
	while (--n >= 0) {
495 496 497 498 499 500 501 502
		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))
503 504 505
			return -EFAULT;
		ucontrols++;
		kcontrols++;
506
	}
507
	return 0;
508
}
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524

#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)

#define VIDIOC_OVERLAY32	_IOW ('V', 14, s32)
525
#ifdef __OLD_VIDIOC_
526
#define VIDIOC_OVERLAY32_OLD	_IOWR('V', 14, s32)
527
#endif
528 529 530 531 532 533
#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)
534

535
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
536 537
{
	union {
538 539 540
		struct v4l2_format v2f;
		struct v4l2_buffer v2b;
		struct v4l2_framebuffer v2fb;
541
		struct v4l2_input v2i;
542 543
		struct v4l2_standard v2s;
		struct v4l2_ext_controls v2ecs;
544
		unsigned long vx;
545
		int vi;
546 547
	} karg;
	void __user *up = compat_ptr(arg);
548
	int compatible_arg = 1;
549
	long err = 0;
550 551

	/* First, convert the command. */
552
	switch (cmd) {
553 554 555 556 557 558 559 560 561 562 563 564 565 566
	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;
	case VIDIOC_OVERLAY32: cmd = VIDIOC_OVERLAY; break;
567
#ifdef __OLD_VIDIOC_
568
	case VIDIOC_OVERLAY32_OLD: cmd = VIDIOC_OVERLAY; break;
569
#endif
570 571 572 573 574 575 576
	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;
	}
577

578
	switch (cmd) {
579
	case VIDIOC_OVERLAY:
580 581
	case VIDIOC_STREAMON:
	case VIDIOC_STREAMOFF:
582 583 584 585
	case VIDIOC_S_INPUT:
	case VIDIOC_S_OUTPUT:
		err = get_user(karg.vi, (s32 __user *)up);
		compatible_arg = 0;
586
		break;
587

588 589
	case VIDIOC_G_INPUT:
	case VIDIOC_G_OUTPUT:
590 591
		compatible_arg = 0;
		break;
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606

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

	case VIDIOC_QUERYBUF:
	case VIDIOC_QBUF:
	case VIDIOC_DQBUF:
		err = get_v4l2_buffer32(&karg.v2b, up);
		compatible_arg = 0;
		break;

607 608
	case VIDIOC_S_FBUF:
		err = get_v4l2_framebuffer32(&karg.v2fb, up);
609 610 611
		compatible_arg = 0;
		break;

612
	case VIDIOC_G_FBUF:
613 614 615
		compatible_arg = 0;
		break;

616 617
	case VIDIOC_ENUMSTD:
		err = get_v4l2_standard32(&karg.v2s, up);
618 619 620
		compatible_arg = 0;
		break;

621
	case VIDIOC_ENUMINPUT:
622 623 624 625
		err = get_v4l2_input32(&karg.v2i, up);
		compatible_arg = 0;
		break;

626 627 628 629
	case VIDIOC_G_EXT_CTRLS:
	case VIDIOC_S_EXT_CTRLS:
	case VIDIOC_TRY_EXT_CTRLS:
		err = get_v4l2_ext_controls32(&karg.v2ecs, up);
630 631
		compatible_arg = 0;
		break;
632
	}
633
	if (err)
634
		return err;
635

636
	if (compatible_arg)
637
		err = native_ioctl(file, cmd, (unsigned long)up);
638 639
	else {
		mm_segment_t old_fs = get_fs();
640

641
		set_fs(KERNEL_DS);
642
		err = native_ioctl(file, cmd, (unsigned long)&karg);
643 644
		set_fs(old_fs);
	}
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666

	/* 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;
667

668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
	case VIDIOC_G_FBUF:
		err = put_v4l2_framebuffer32(&karg.v2fb, up);
		break;

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

	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;
691 692 693 694
	}
	return err;
}

695
long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
696
{
697
	long ret = -ENOIOCTLCMD;
698

699
	if (!file->f_op->unlocked_ioctl)
700 701 702
		return ret;

	switch (cmd) {
703 704 705 706 707 708 709
#ifdef __OLD_VIDIOC_
	case VIDIOC_OVERLAY32_OLD:
	case VIDIOC_S_PARM_OLD:
	case VIDIOC_S_CTRL_OLD:
	case VIDIOC_G_AUDIO_OLD:
	case VIDIOC_G_AUDOUT_OLD:
	case VIDIOC_CROPCAP_OLD:
710
#endif
711
	case VIDIOC_QUERYCAP:
712
	case VIDIOC_RESERVED:
713 714 715 716 717 718 719 720 721 722 723 724 725
	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:
726
	case VIDIOC_S_PARM:
727 728 729 730 731
	case VIDIOC_G_STD:
	case VIDIOC_S_STD:
	case VIDIOC_ENUMSTD32:
	case VIDIOC_ENUMINPUT32:
	case VIDIOC_G_CTRL:
732
	case VIDIOC_S_CTRL:
733 734 735 736
	case VIDIOC_G_TUNER:
	case VIDIOC_S_TUNER:
	case VIDIOC_G_AUDIO:
	case VIDIOC_S_AUDIO:
737
	case VIDIOC_QUERYCTRL:
738
	case VIDIOC_QUERYMENU:
739 740
	case VIDIOC_G_INPUT32:
	case VIDIOC_S_INPUT32:
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
	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:
	case VIDIOC_G_JPEGCOMP:
	case VIDIOC_S_JPEGCOMP:
	case VIDIOC_QUERYSTD:
756
	case VIDIOC_TRY_FMT32:
757 758 759 760 761 762 763 764 765
	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:
766 767
	case VIDIOC_ENUM_FRAMESIZES:
	case VIDIOC_ENUM_FRAMEINTERVALS:
768 769 770 771 772
	case VIDIOC_G_ENC_INDEX:
	case VIDIOC_ENCODER_CMD:
	case VIDIOC_TRY_ENCODER_CMD:
	case VIDIOC_DBG_S_REGISTER:
	case VIDIOC_DBG_G_REGISTER:
773
	case VIDIOC_DBG_G_CHIP_IDENT:
774
	case VIDIOC_S_HW_FREQ_SEEK:
775 776 777 778 779 780
	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:
781 782 783
	case VIDIOC_DQEVENT:
	case VIDIOC_SUBSCRIBE_EVENT:
	case VIDIOC_UNSUBSCRIBE_EVENT:
784 785 786
		ret = do_video_ioctl(file, cmd, arg);
		break;

787
	default:
788 789 790
		printk(KERN_WARNING "compat_ioctl32: "
			"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
			_IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
791
		break;
792
	}
793
	return ret;
794
}
795
EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
796
#endif
797 798

MODULE_LICENSE("GPL");