File Index
Files and directories
Sign in
FILE

v4l2-compat-ioctl32.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/v4l2-core/v4l2-compat-ioctl32.c C
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * ioctl32.c: Conversion between 32bit and 64bit native ioctls.
   4 *	Separated from fs stuff by Arnd Bergmann <arnd@arndb.de>
   5 *
   6 * Copyright (C) 1997-2000  Jakub Jelinek  (jakub@redhat.com)
   7 * Copyright (C) 1998  Eddie C. Dost  (ecd@skynet.be)
   8 * Copyright (C) 2001,2002  Andi Kleen, SuSE Labs
   9 * Copyright (C) 2003       Pavel Machek (pavel@ucw.cz)
  10 * Copyright (C) 2005       Philippe De Muyter (phdm@macqel.be)
  11 * Copyright (C) 2008       Hans Verkuil <hverkuil@kernel.org>
  12 *
  13 * These routines maintain argument size conversion between 32bit and 64bit
  14 * ioctls.
  15 */
  16
  17#include <linux/compat.h>
  18#include <linux/module.h>
  19#include <linux/videodev2.h>
  20#include <linux/v4l2-subdev.h>
  21#include <media/v4l2-dev.h>
  22#include <media/v4l2-fh.h>
  23#include <media/v4l2-ctrls.h>
  24#include <media/v4l2-ioctl.h>
  25
  26/*
  27 * Per-ioctl data copy handlers.
  28 *
  29 * Those come in pairs, with a get_v4l2_foo() and a put_v4l2_foo() routine,
  30 * where "v4l2_foo" is the name of the V4L2 struct.
  31 *
  32 * They basically get two __user pointers, one with a 32-bits struct that
  33 * came from the userspace call and a 64-bits struct, also allocated as
  34 * userspace, but filled internally by do_video_ioctl().
  35 *
  36 * For ioctls that have pointers inside it, the functions will also
  37 * receive an ancillary buffer with extra space, used to pass extra
  38 * data to the routine.
  39 */
  40
  41struct v4l2_window32 {
  42	struct v4l2_rect        w;
  43	__u32			field;	/* enum v4l2_field */
  44	__u32			chromakey;
  45	compat_caddr_t		clips; /* always NULL */
  46	__u32			clipcount; /* always 0 */
  47	compat_caddr_t		bitmap; /* always NULL */
  48	__u8                    global_alpha;
  49};
  50
  51static int get_v4l2_window32(struct v4l2_window *p64,
  52			     struct v4l2_window32 __user *p32)
  53{
  54	struct v4l2_window32 w32;
  55
  56	if (copy_from_user(&w32, p32, sizeof(w32)))
  57		return -EFAULT;
  58
  59	*p64 = (struct v4l2_window) {
  60		.w		= w32.w,
  61		.field		= w32.field,
  62		.chromakey	= w32.chromakey,
  63		.clips		= NULL,
  64		.clipcount	= 0,
  65		.bitmap		= NULL,
  66		.global_alpha	= w32.global_alpha,
  67	};
  68
  69	return 0;
  70}
  71
  72static int put_v4l2_window32(struct v4l2_window *p64,
  73			     struct v4l2_window32 __user *p32)
  74{
  75	struct v4l2_window32 w32;
  76
  77	memset(&w32, 0, sizeof(w32));
  78	w32 = (struct v4l2_window32) {
  79		.w		= p64->w,
  80		.field		= p64->field,
  81		.chromakey	= p64->chromakey,
  82		.clips		= 0,
  83		.clipcount	= 0,
  84		.bitmap		= 0,
  85		.global_alpha	= p64->global_alpha,
  86	};
  87
  88	if (copy_to_user(p32, &w32, sizeof(w32)))
  89		return -EFAULT;
  90
  91	return 0;
  92}
  93
  94struct v4l2_format32 {
  95	__u32	type;	/* enum v4l2_buf_type */
  96	union {
  97		struct v4l2_pix_format	pix;
  98		struct v4l2_pix_format_mplane	pix_mp;
  99		struct v4l2_window32	win;
 100		struct v4l2_vbi_format	vbi;
 101		struct v4l2_sliced_vbi_format	sliced;
 102		struct v4l2_sdr_format	sdr;
 103		struct v4l2_meta_format	meta;
 104		__u8	raw_data[200];        /* user-defined */
 105	} fmt;
 106};
 107
 108/**
 109 * struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
 110 * @index:	on return, index of the first created buffer
 111 * @count:	entry: number of requested buffers,
 112 *		return: number of created buffers
 113 * @memory:	buffer memory type
 114 * @format:	frame format, for which buffers are requested
 115 * @capabilities: capabilities of this buffer type.
 116 * @flags:	additional buffer management attributes (ignored unless the
 117 *		queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
 118 *		configured for MMAP streaming I/O).
 119 * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
 120 *		this field indicate the maximum possible number of buffers
 121 *		for this queue.
 122 * @reserved:	future extensions
 123 */
 124struct v4l2_create_buffers32 {
 125	__u32			index;
 126	__u32			count;
 127	__u32			memory;	/* enum v4l2_memory */
 128	struct v4l2_format32	format;
 129	__u32			capabilities;
 130	__u32			flags;
 131	__u32			max_num_buffers;
 132	__u32			reserved[5];
 133};
 134
 135static int get_v4l2_format32(struct v4l2_format *p64,
 136			     struct v4l2_format32 __user *p32)
 137{
 138	if (get_user(p64->type, &p32->type))
 139		return -EFAULT;
 140
 141	switch (p64->type) {
 142	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 143	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 144		return copy_from_user(&p64->fmt.pix, &p32->fmt.pix,
 145				      sizeof(p64->fmt.pix)) ? -EFAULT : 0;
 146	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 147	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 148		return copy_from_user(&p64->fmt.pix_mp, &p32->fmt.pix_mp,
 149				      sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
 150	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 151	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 152		return get_v4l2_window32(&p64->fmt.win, &p32->fmt.win);
 153	case V4L2_BUF_TYPE_VBI_CAPTURE:
 154	case V4L2_BUF_TYPE_VBI_OUTPUT:
 155		return copy_from_user(&p64->fmt.vbi, &p32->fmt.vbi,
 156				      sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
 157	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 158	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 159		return copy_from_user(&p64->fmt.sliced, &p32->fmt.sliced,
 160				      sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
 161	case V4L2_BUF_TYPE_SDR_CAPTURE:
 162	case V4L2_BUF_TYPE_SDR_OUTPUT:
 163		return copy_from_user(&p64->fmt.sdr, &p32->fmt.sdr,
 164				      sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 165	case V4L2_BUF_TYPE_META_CAPTURE:
 166	case V4L2_BUF_TYPE_META_OUTPUT:
 167		return copy_from_user(&p64->fmt.meta, &p32->fmt.meta,
 168				      sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 169	default:
 170		return -EINVAL;
 171	}
 172}
 173
 174static int get_v4l2_create32(struct v4l2_create_buffers *p64,
 175			     struct v4l2_create_buffers32 __user *p32)
 176{
 177	if (copy_from_user(p64, p32,
 178			   offsetof(struct v4l2_create_buffers32, format)))
 179		return -EFAULT;
 180	if (copy_from_user(&p64->flags, &p32->flags, sizeof(p32->flags)))
 181		return -EFAULT;
 182	if (copy_from_user(&p64->max_num_buffers, &p32->max_num_buffers,
 183			   sizeof(p32->max_num_buffers)))
 184		return -EFAULT;
 185	return get_v4l2_format32(&p64->format, &p32->format);
 186}
 187
 188static int put_v4l2_format32(struct v4l2_format *p64,
 189			     struct v4l2_format32 __user *p32)
 190{
 191	switch (p64->type) {
 192	case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 193	case V4L2_BUF_TYPE_VIDEO_OUTPUT:
 194		return copy_to_user(&p32->fmt.pix, &p64->fmt.pix,
 195				    sizeof(p64->fmt.pix)) ? -EFAULT : 0;
 196	case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
 197	case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
 198		return copy_to_user(&p32->fmt.pix_mp, &p64->fmt.pix_mp,
 199				    sizeof(p64->fmt.pix_mp)) ? -EFAULT : 0;
 200	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 201	case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
 202		return put_v4l2_window32(&p64->fmt.win, &p32->fmt.win);
 203	case V4L2_BUF_TYPE_VBI_CAPTURE:
 204	case V4L2_BUF_TYPE_VBI_OUTPUT:
 205		return copy_to_user(&p32->fmt.vbi, &p64->fmt.vbi,
 206				    sizeof(p64->fmt.vbi)) ? -EFAULT : 0;
 207	case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
 208	case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
 209		return copy_to_user(&p32->fmt.sliced, &p64->fmt.sliced,
 210				    sizeof(p64->fmt.sliced)) ? -EFAULT : 0;
 211	case V4L2_BUF_TYPE_SDR_CAPTURE:
 212	case V4L2_BUF_TYPE_SDR_OUTPUT:
 213		return copy_to_user(&p32->fmt.sdr, &p64->fmt.sdr,
 214				    sizeof(p64->fmt.sdr)) ? -EFAULT : 0;
 215	case V4L2_BUF_TYPE_META_CAPTURE:
 216	case V4L2_BUF_TYPE_META_OUTPUT:
 217		return copy_to_user(&p32->fmt.meta, &p64->fmt.meta,
 218				    sizeof(p64->fmt.meta)) ? -EFAULT : 0;
 219	default:
 220		return -EINVAL;
 221	}
 222}
 223
 224static int put_v4l2_create32(struct v4l2_create_buffers *p64,
 225			     struct v4l2_create_buffers32 __user *p32)
 226{
 227	if (copy_to_user(p32, p64,
 228			 offsetof(struct v4l2_create_buffers32, format)) ||
 229	    put_user(p64->capabilities, &p32->capabilities) ||
 230	    put_user(p64->flags, &p32->flags) ||
 231	    put_user(p64->max_num_buffers, &p32->max_num_buffers) ||
 232	    copy_to_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
 233		return -EFAULT;
 234	return put_v4l2_format32(&p64->format, &p32->format);
 235}
 236
 237struct v4l2_standard32 {
 238	__u32		     index;
 239	compat_u64	     id;
 240	__u8		     name[24];
 241	struct v4l2_fract    frameperiod; /* Frames, not fields */
 242	__u32		     framelines;
 243	__u32		     reserved[4];
 244};
 245
 246static int get_v4l2_standard32(struct v4l2_standard *p64,
 247			       struct v4l2_standard32 __user *p32)
 248{
 249	/* other fields are not set by the user, nor used by the driver */
 250	return get_user(p64->index, &p32->index);
 251}
 252
 253static int put_v4l2_standard32(struct v4l2_standard *p64,
 254			       struct v4l2_standard32 __user *p32)
 255{
 256	if (put_user(p64->index, &p32->index) ||
 257	    put_user(p64->id, &p32->id) ||
 258	    copy_to_user(p32->name, p64->name, sizeof(p32->name)) ||
 259	    copy_to_user(&p32->frameperiod, &p64->frameperiod,
 260			 sizeof(p32->frameperiod)) ||
 261	    put_user(p64->framelines, &p32->framelines) ||
 262	    copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
 263		return -EFAULT;
 264	return 0;
 265}
 266
 267struct v4l2_plane32 {
 268	__u32			bytesused;
 269	__u32			length;
 270	union {
 271		__u32		mem_offset;
 272		compat_long_t	userptr;
 273		__s32		fd;
 274	} m;
 275	__u32			data_offset;
 276	__u32			reserved[11];
 277};
 278
 279/*
 280 * This is correct for all architectures including i386, but not x32,
 281 * which has different alignment requirements for timestamp
 282 */
 283struct v4l2_buffer32 {
 284	__u32			index;
 285	__u32			type;	/* enum v4l2_buf_type */
 286	__u32			bytesused;
 287	__u32			flags;
 288	__u32			field;	/* enum v4l2_field */
 289	struct {
 290		compat_s64	tv_sec;
 291		compat_s64	tv_usec;
 292	}			timestamp;
 293	struct v4l2_timecode	timecode;
 294	__u32			sequence;
 295
 296	/* memory location */
 297	__u32			memory;	/* enum v4l2_memory */
 298	union {
 299		__u32           offset;
 300		compat_long_t   userptr;
 301		compat_caddr_t  planes;
 302		__s32		fd;
 303	} m;
 304	__u32			length;
 305	__u32			reserved2;
 306	__s32			request_fd;
 307};
 308
 309#ifdef CONFIG_COMPAT_32BIT_TIME
 310struct v4l2_buffer32_time32 {
 311	__u32			index;
 312	__u32			type;	/* enum v4l2_buf_type */
 313	__u32			bytesused;
 314	__u32			flags;
 315	__u32			field;	/* enum v4l2_field */
 316	struct old_timeval32	timestamp;
 317	struct v4l2_timecode	timecode;
 318	__u32			sequence;
 319
 320	/* memory location */
 321	__u32			memory;	/* enum v4l2_memory */
 322	union {
 323		__u32           offset;
 324		compat_long_t   userptr;
 325		compat_caddr_t  planes;
 326		__s32		fd;
 327	} m;
 328	__u32			length;
 329	__u32			reserved2;
 330	__s32			request_fd;
 331};
 332#endif
 333
 334static int get_v4l2_plane32(struct v4l2_plane *p64,
 335			    struct v4l2_plane32 __user *p32,
 336			    enum v4l2_memory memory)
 337{
 338	struct v4l2_plane32 plane32;
 339	typeof(p64->m) m = {};
 340
 341	if (copy_from_user(&plane32, p32, sizeof(plane32)))
 342		return -EFAULT;
 343
 344	switch (memory) {
 345	case V4L2_MEMORY_MMAP:
 346	case V4L2_MEMORY_OVERLAY:
 347		m.mem_offset = plane32.m.mem_offset;
 348		break;
 349	case V4L2_MEMORY_USERPTR:
 350		m.userptr = (unsigned long)compat_ptr(plane32.m.userptr);
 351		break;
 352	case V4L2_MEMORY_DMABUF:
 353		m.fd = plane32.m.fd;
 354		break;
 355	}
 356
 357	memset(p64, 0, sizeof(*p64));
 358	*p64 = (struct v4l2_plane) {
 359		.bytesused	= plane32.bytesused,
 360		.length		= plane32.length,
 361		.m		= m,
 362		.data_offset	= plane32.data_offset,
 363	};
 364
 365	return 0;
 366}
 367
 368static int put_v4l2_plane32(struct v4l2_plane *p64,
 369			    struct v4l2_plane32 __user *p32,
 370			    enum v4l2_memory memory)
 371{
 372	struct v4l2_plane32 plane32;
 373
 374	memset(&plane32, 0, sizeof(plane32));
 375	plane32 = (struct v4l2_plane32) {
 376		.bytesused	= p64->bytesused,
 377		.length		= p64->length,
 378		.data_offset	= p64->data_offset,
 379	};
 380
 381	switch (memory) {
 382	case V4L2_MEMORY_MMAP:
 383	case V4L2_MEMORY_OVERLAY:
 384		plane32.m.mem_offset = p64->m.mem_offset;
 385		break;
 386	case V4L2_MEMORY_USERPTR:
 387		plane32.m.userptr = (uintptr_t)(p64->m.userptr);
 388		break;
 389	case V4L2_MEMORY_DMABUF:
 390		plane32.m.fd = p64->m.fd;
 391		break;
 392	}
 393
 394	if (copy_to_user(p32, &plane32, sizeof(plane32)))
 395		return -EFAULT;
 396
 397	return 0;
 398}
 399
 400static int get_v4l2_buffer32(struct v4l2_buffer *vb,
 401			     struct v4l2_buffer32 __user *arg)
 402{
 403	struct v4l2_buffer32 vb32;
 404
 405	if (copy_from_user(&vb32, arg, sizeof(vb32)))
 406		return -EFAULT;
 407
 408	memset(vb, 0, sizeof(*vb));
 409	*vb = (struct v4l2_buffer) {
 410		.index		= vb32.index,
 411		.type		= vb32.type,
 412		.bytesused	= vb32.bytesused,
 413		.flags		= vb32.flags,
 414		.field		= vb32.field,
 415		.timestamp.tv_sec	= vb32.timestamp.tv_sec,
 416		.timestamp.tv_usec	= vb32.timestamp.tv_usec,
 417		.timecode	= vb32.timecode,
 418		.sequence	= vb32.sequence,
 419		.memory		= vb32.memory,
 420		.m.offset	= vb32.m.offset,
 421		.length		= vb32.length,
 422		.request_fd	= vb32.request_fd,
 423	};
 424
 425	switch (vb->memory) {
 426	case V4L2_MEMORY_MMAP:
 427	case V4L2_MEMORY_OVERLAY:
 428		vb->m.offset = vb32.m.offset;
 429		break;
 430	case V4L2_MEMORY_USERPTR:
 431		vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr);
 432		break;
 433	case V4L2_MEMORY_DMABUF:
 434		vb->m.fd = vb32.m.fd;
 435		break;
 436	}
 437
 438	if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
 439		vb->m.planes = (void __force *)
 440				compat_ptr(vb32.m.planes);
 441
 442	return 0;
 443}
 444
 445#ifdef CONFIG_COMPAT_32BIT_TIME
 446static int get_v4l2_buffer32_time32(struct v4l2_buffer *vb,
 447				    struct v4l2_buffer32_time32 __user *arg)
 448{
 449	struct v4l2_buffer32_time32 vb32;
 450
 451	if (copy_from_user(&vb32, arg, sizeof(vb32)))
 452		return -EFAULT;
 453
 454	*vb = (struct v4l2_buffer) {
 455		.index		= vb32.index,
 456		.type		= vb32.type,
 457		.bytesused	= vb32.bytesused,
 458		.flags		= vb32.flags,
 459		.field		= vb32.field,
 460		.timestamp.tv_sec	= vb32.timestamp.tv_sec,
 461		.timestamp.tv_usec	= vb32.timestamp.tv_usec,
 462		.timecode	= vb32.timecode,
 463		.sequence	= vb32.sequence,
 464		.memory		= vb32.memory,
 465		.m.offset	= vb32.m.offset,
 466		.length		= vb32.length,
 467		.request_fd	= vb32.request_fd,
 468	};
 469	switch (vb->memory) {
 470	case V4L2_MEMORY_MMAP:
 471	case V4L2_MEMORY_OVERLAY:
 472		vb->m.offset = vb32.m.offset;
 473		break;
 474	case V4L2_MEMORY_USERPTR:
 475		vb->m.userptr = (unsigned long)compat_ptr(vb32.m.userptr);
 476		break;
 477	case V4L2_MEMORY_DMABUF:
 478		vb->m.fd = vb32.m.fd;
 479		break;
 480	}
 481
 482	if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
 483		vb->m.planes = (void __force *)
 484				compat_ptr(vb32.m.planes);
 485
 486	return 0;
 487}
 488#endif
 489
 490static int put_v4l2_buffer32(struct v4l2_buffer *vb,
 491			     struct v4l2_buffer32 __user *arg)
 492{
 493	struct v4l2_buffer32 vb32;
 494
 495	memset(&vb32, 0, sizeof(vb32));
 496	vb32 = (struct v4l2_buffer32) {
 497		.index		= vb->index,
 498		.type		= vb->type,
 499		.bytesused	= vb->bytesused,
 500		.flags		= vb->flags,
 501		.field		= vb->field,
 502		.timestamp.tv_sec	= vb->timestamp.tv_sec,
 503		.timestamp.tv_usec	= vb->timestamp.tv_usec,
 504		.timecode	= vb->timecode,
 505		.sequence	= vb->sequence,
 506		.memory		= vb->memory,
 507		.m.offset	= vb->m.offset,
 508		.length		= vb->length,
 509		.request_fd	= vb->request_fd,
 510	};
 511
 512	switch (vb->memory) {
 513	case V4L2_MEMORY_MMAP:
 514	case V4L2_MEMORY_OVERLAY:
 515		vb32.m.offset = vb->m.offset;
 516		break;
 517	case V4L2_MEMORY_USERPTR:
 518		vb32.m.userptr = (uintptr_t)(vb->m.userptr);
 519		break;
 520	case V4L2_MEMORY_DMABUF:
 521		vb32.m.fd = vb->m.fd;
 522		break;
 523	}
 524
 525	if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
 526		vb32.m.planes = (uintptr_t)vb->m.planes;
 527
 528	if (copy_to_user(arg, &vb32, sizeof(vb32)))
 529		return -EFAULT;
 530
 531	return 0;
 532}
 533
 534#ifdef CONFIG_COMPAT_32BIT_TIME
 535static int put_v4l2_buffer32_time32(struct v4l2_buffer *vb,
 536				    struct v4l2_buffer32_time32 __user *arg)
 537{
 538	struct v4l2_buffer32_time32 vb32;
 539
 540	memset(&vb32, 0, sizeof(vb32));
 541	vb32 = (struct v4l2_buffer32_time32) {
 542		.index		= vb->index,
 543		.type		= vb->type,
 544		.bytesused	= vb->bytesused,
 545		.flags		= vb->flags,
 546		.field		= vb->field,
 547		.timestamp.tv_sec	= vb->timestamp.tv_sec,
 548		.timestamp.tv_usec	= vb->timestamp.tv_usec,
 549		.timecode	= vb->timecode,
 550		.sequence	= vb->sequence,
 551		.memory		= vb->memory,
 552		.m.offset	= vb->m.offset,
 553		.length		= vb->length,
 554		.request_fd	= vb->request_fd,
 555	};
 556	switch (vb->memory) {
 557	case V4L2_MEMORY_MMAP:
 558	case V4L2_MEMORY_OVERLAY:
 559		vb32.m.offset = vb->m.offset;
 560		break;
 561	case V4L2_MEMORY_USERPTR:
 562		vb32.m.userptr = (uintptr_t)(vb->m.userptr);
 563		break;
 564	case V4L2_MEMORY_DMABUF:
 565		vb32.m.fd = vb->m.fd;
 566		break;
 567	}
 568
 569	if (V4L2_TYPE_IS_MULTIPLANAR(vb->type))
 570		vb32.m.planes = (uintptr_t)vb->m.planes;
 571
 572	if (copy_to_user(arg, &vb32, sizeof(vb32)))
 573		return -EFAULT;
 574
 575	return 0;
 576}
 577#endif
 578
 579struct v4l2_framebuffer32 {
 580	__u32			capability;
 581	__u32			flags;
 582	compat_caddr_t		base;
 583	struct {
 584		__u32		width;
 585		__u32		height;
 586		__u32		pixelformat;
 587		__u32		field;
 588		__u32		bytesperline;
 589		__u32		sizeimage;
 590		__u32		colorspace;
 591		__u32		priv;
 592	} fmt;
 593};
 594
 595static int get_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
 596				  struct v4l2_framebuffer32 __user *p32)
 597{
 598	if (get_user(p64->capability, &p32->capability) ||
 599	    get_user(p64->flags, &p32->flags) ||
 600	    copy_from_user(&p64->fmt, &p32->fmt, sizeof(p64->fmt)))
 601		return -EFAULT;
 602	p64->base = NULL;
 603
 604	return 0;
 605}
 606
 607static int put_v4l2_framebuffer32(struct v4l2_framebuffer *p64,
 608				  struct v4l2_framebuffer32 __user *p32)
 609{
 610	if (put_user((uintptr_t)p64->base, &p32->base) ||
 611	    put_user(p64->capability, &p32->capability) ||
 612	    put_user(p64->flags, &p32->flags) ||
 613	    copy_to_user(&p32->fmt, &p64->fmt, sizeof(p64->fmt)))
 614		return -EFAULT;
 615
 616	return 0;
 617}
 618
 619struct v4l2_input32 {
 620	__u32	     index;		/*  Which input */
 621	__u8	     name[32];		/*  Label */
 622	__u32	     type;		/*  Type of input */
 623	__u32	     audioset;		/*  Associated audios (bitfield) */
 624	__u32        tuner;             /*  Associated tuner */
 625	compat_u64   std;
 626	__u32	     status;
 627	__u32	     capabilities;
 628	__u32	     reserved[3];
 629};
 630
 631/*
 632 * The 64-bit v4l2_input struct has extra padding at the end of the struct.
 633 * Otherwise it is identical to the 32-bit version.
 634 */
 635static inline int get_v4l2_input32(struct v4l2_input *p64,
 636				   struct v4l2_input32 __user *p32)
 637{
 638	if (copy_from_user(p64, p32, sizeof(*p32)))
 639		return -EFAULT;
 640	return 0;
 641}
 642
 643static inline int put_v4l2_input32(struct v4l2_input *p64,
 644				   struct v4l2_input32 __user *p32)
 645{
 646	if (copy_to_user(p32, p64, sizeof(*p32)))
 647		return -EFAULT;
 648	return 0;
 649}
 650
 651struct v4l2_ext_controls32 {
 652	__u32 which;
 653	__u32 count;
 654	__u32 error_idx;
 655	__s32 request_fd;
 656	__u32 reserved[1];
 657	compat_caddr_t controls; /* actually struct v4l2_ext_control32 * */
 658};
 659
 660struct v4l2_ext_control32 {
 661	__u32 id;
 662	__u32 size;
 663	__u32 reserved2[1];
 664	union {
 665		__s32 value;
 666		__s64 value64;
 667		compat_caddr_t string; /* actually char * */
 668	};
 669} __attribute__ ((packed));
 670
 671/* Return true if this control is a pointer type. */
 672static inline bool ctrl_is_pointer(struct file *file, u32 id)
 673{
 674	struct video_device *vdev = video_devdata(file);
 675	struct v4l2_fh *fh = file_to_v4l2_fh(file);
 676	struct v4l2_ctrl_handler *hdl = NULL;
 677	struct v4l2_query_ext_ctrl qec = { id };
 678	const struct v4l2_ioctl_ops *ops = vdev->ioctl_ops;
 679
 680	if (fh->ctrl_handler)
 681		hdl = fh->ctrl_handler;
 682	else if (vdev->ctrl_handler)
 683		hdl = vdev->ctrl_handler;
 684
 685	if (hdl) {
 686		struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);
 687
 688		return ctrl && ctrl->is_ptr;
 689	}
 690
 691	if (!ops || !ops->vidioc_query_ext_ctrl)
 692		return false;
 693
 694	return !ops->vidioc_query_ext_ctrl(file, NULL, &qec) &&
 695		(qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);
 696}
 697
 698static int get_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
 699				   struct v4l2_ext_controls32 __user *p32)
 700{
 701	struct v4l2_ext_controls32 ec32;
 702
 703	if (copy_from_user(&ec32, p32, sizeof(ec32)))
 704		return -EFAULT;
 705
 706	*p64 = (struct v4l2_ext_controls) {
 707		.which		= ec32.which,
 708		.count		= ec32.count,
 709		.error_idx	= ec32.error_idx,
 710		.request_fd	= ec32.request_fd,
 711		.reserved[0]	= ec32.reserved[0],
 712		.controls	= (void __force *)compat_ptr(ec32.controls),
 713	};
 714
 715	return 0;
 716}
 717
 718static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64,
 719				   struct v4l2_ext_controls32 __user *p32)
 720{
 721	struct v4l2_ext_controls32 ec32;
 722
 723	memset(&ec32, 0, sizeof(ec32));
 724	ec32 = (struct v4l2_ext_controls32) {
 725		.which		= p64->which,
 726		.count		= p64->count,
 727		.error_idx	= p64->error_idx,
 728		.request_fd	= p64->request_fd,
 729		.reserved[0]	= p64->reserved[0],
 730		.controls	= (uintptr_t)p64->controls,
 731	};
 732
 733	if (copy_to_user(p32, &ec32, sizeof(ec32)))
 734		return -EFAULT;
 735
 736	return 0;
 737}
 738
 739#ifdef CONFIG_X86_64
 740/*
 741 * x86 is the only compat architecture with different struct alignment
 742 * between 32-bit and 64-bit tasks.
 743 */
 744struct v4l2_event32 {
 745	__u32				type;
 746	union {
 747		compat_s64		value64;
 748		__u8			data[64];
 749	} u;
 750	__u32				pending;
 751	__u32				sequence;
 752	struct {
 753		compat_s64		tv_sec;
 754		compat_s64		tv_nsec;
 755	} timestamp;
 756	__u32				id;
 757	__u32				reserved[8];
 758};
 759
 760static int put_v4l2_event32(struct v4l2_event *p64,
 761			    struct v4l2_event32 __user *p32)
 762{
 763	if (put_user(p64->type, &p32->type) ||
 764	    copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
 765	    put_user(p64->pending, &p32->pending) ||
 766	    put_user(p64->sequence, &p32->sequence) ||
 767	    put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
 768	    put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
 769	    put_user(p64->id, &p32->id) ||
 770	    copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
 771		return -EFAULT;
 772	return 0;
 773}
 774
 775#endif
 776
 777#ifdef CONFIG_COMPAT_32BIT_TIME
 778struct v4l2_event32_time32 {
 779	__u32				type;
 780	union {
 781		compat_s64		value64;
 782		__u8			data[64];
 783	} u;
 784	__u32				pending;
 785	__u32				sequence;
 786	struct old_timespec32		timestamp;
 787	__u32				id;
 788	__u32				reserved[8];
 789};
 790
 791static int put_v4l2_event32_time32(struct v4l2_event *p64,
 792				   struct v4l2_event32_time32 __user *p32)
 793{
 794	if (put_user(p64->type, &p32->type) ||
 795	    copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||
 796	    put_user(p64->pending, &p32->pending) ||
 797	    put_user(p64->sequence, &p32->sequence) ||
 798	    put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||
 799	    put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||
 800	    put_user(p64->id, &p32->id) ||
 801	    copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))
 802		return -EFAULT;
 803	return 0;
 804}
 805#endif
 806
 807struct v4l2_edid32 {
 808	__u32 pad;
 809	__u32 start_block;
 810	__u32 blocks;
 811	__u32 reserved[5];
 812	compat_caddr_t edid;
 813};
 814
 815static int get_v4l2_edid32(struct v4l2_edid *p64,
 816			   struct v4l2_edid32 __user *p32)
 817{
 818	compat_uptr_t edid;
 819
 820	if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) ||
 821	    get_user(edid, &p32->edid))
 822		return -EFAULT;
 823
 824	p64->edid = (void __force *)compat_ptr(edid);
 825	return 0;
 826}
 827
 828static int put_v4l2_edid32(struct v4l2_edid *p64,
 829			   struct v4l2_edid32 __user *p32)
 830{
 831	if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid)))
 832		return -EFAULT;
 833	return 0;
 834}
 835
 836/*
 837 * List of ioctls that require 32-bits/64-bits conversion
 838 *
 839 * The V4L2 ioctls that aren't listed there don't have pointer arguments
 840 * and the struct size is identical for both 32 and 64 bits versions, so
 841 * they don't need translations.
 842 */
 843
 844#define VIDIOC_G_FMT32		_IOWR('V',  4, struct v4l2_format32)
 845#define VIDIOC_S_FMT32		_IOWR('V',  5, struct v4l2_format32)
 846#define VIDIOC_QUERYBUF32	_IOWR('V',  9, struct v4l2_buffer32)
 847#define VIDIOC_G_FBUF32		_IOR ('V', 10, struct v4l2_framebuffer32)
 848#define VIDIOC_S_FBUF32		_IOW ('V', 11, struct v4l2_framebuffer32)
 849#define VIDIOC_QBUF32		_IOWR('V', 15, struct v4l2_buffer32)
 850#define VIDIOC_DQBUF32		_IOWR('V', 17, struct v4l2_buffer32)
 851#define VIDIOC_ENUMSTD32	_IOWR('V', 25, struct v4l2_standard32)
 852#define VIDIOC_ENUMINPUT32	_IOWR('V', 26, struct v4l2_input32)
 853#define VIDIOC_G_EDID32		_IOWR('V', 40, struct v4l2_edid32)
 854#define VIDIOC_S_EDID32		_IOWR('V', 41, struct v4l2_edid32)
 855#define VIDIOC_TRY_FMT32	_IOWR('V', 64, struct v4l2_format32)
 856#define VIDIOC_G_EXT_CTRLS32    _IOWR('V', 71, struct v4l2_ext_controls32)
 857#define VIDIOC_S_EXT_CTRLS32    _IOWR('V', 72, struct v4l2_ext_controls32)
 858#define VIDIOC_TRY_EXT_CTRLS32  _IOWR('V', 73, struct v4l2_ext_controls32)
 859#define	VIDIOC_DQEVENT32	_IOR ('V', 89, struct v4l2_event32)
 860#define VIDIOC_CREATE_BUFS32	_IOWR('V', 92, struct v4l2_create_buffers32)
 861#define VIDIOC_PREPARE_BUF32	_IOWR('V', 93, struct v4l2_buffer32)
 862
 863#ifdef CONFIG_COMPAT_32BIT_TIME
 864#define VIDIOC_QUERYBUF32_TIME32	_IOWR('V',  9, struct v4l2_buffer32_time32)
 865#define VIDIOC_QBUF32_TIME32		_IOWR('V', 15, struct v4l2_buffer32_time32)
 866#define VIDIOC_DQBUF32_TIME32		_IOWR('V', 17, struct v4l2_buffer32_time32)
 867#define	VIDIOC_DQEVENT32_TIME32		_IOR ('V', 89, struct v4l2_event32_time32)
 868#define VIDIOC_PREPARE_BUF32_TIME32	_IOWR('V', 93, struct v4l2_buffer32_time32)
 869#endif
 870
 871unsigned int v4l2_compat_translate_cmd(unsigned int cmd)
 872{
 873	switch (cmd) {
 874	case VIDIOC_G_FMT32:
 875		return VIDIOC_G_FMT;
 876	case VIDIOC_S_FMT32:
 877		return VIDIOC_S_FMT;
 878	case VIDIOC_TRY_FMT32:
 879		return VIDIOC_TRY_FMT;
 880	case VIDIOC_G_FBUF32:
 881		return VIDIOC_G_FBUF;
 882	case VIDIOC_S_FBUF32:
 883		return VIDIOC_S_FBUF;
 884#ifdef CONFIG_COMPAT_32BIT_TIME
 885	case VIDIOC_QUERYBUF32_TIME32:
 886		return VIDIOC_QUERYBUF;
 887	case VIDIOC_QBUF32_TIME32:
 888		return VIDIOC_QBUF;
 889	case VIDIOC_DQBUF32_TIME32:
 890		return VIDIOC_DQBUF;
 891	case VIDIOC_PREPARE_BUF32_TIME32:
 892		return VIDIOC_PREPARE_BUF;
 893#endif
 894	case VIDIOC_QUERYBUF32:
 895		return VIDIOC_QUERYBUF;
 896	case VIDIOC_QBUF32:
 897		return VIDIOC_QBUF;
 898	case VIDIOC_DQBUF32:
 899		return VIDIOC_DQBUF;
 900	case VIDIOC_CREATE_BUFS32:
 901		return VIDIOC_CREATE_BUFS;
 902	case VIDIOC_G_EXT_CTRLS32:
 903		return VIDIOC_G_EXT_CTRLS;
 904	case VIDIOC_S_EXT_CTRLS32:
 905		return VIDIOC_S_EXT_CTRLS;
 906	case VIDIOC_TRY_EXT_CTRLS32:
 907		return VIDIOC_TRY_EXT_CTRLS;
 908	case VIDIOC_PREPARE_BUF32:
 909		return VIDIOC_PREPARE_BUF;
 910	case VIDIOC_ENUMSTD32:
 911		return VIDIOC_ENUMSTD;
 912	case VIDIOC_ENUMINPUT32:
 913		return VIDIOC_ENUMINPUT;
 914	case VIDIOC_G_EDID32:
 915		return VIDIOC_G_EDID;
 916	case VIDIOC_S_EDID32:
 917		return VIDIOC_S_EDID;
 918#ifdef CONFIG_X86_64
 919	case VIDIOC_DQEVENT32:
 920		return VIDIOC_DQEVENT;
 921#endif
 922#ifdef CONFIG_COMPAT_32BIT_TIME
 923	case VIDIOC_DQEVENT32_TIME32:
 924		return VIDIOC_DQEVENT;
 925#endif
 926	}
 927	return cmd;
 928}
 929
 930int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)
 931{
 932	switch (cmd) {
 933	case VIDIOC_G_FMT32:
 934	case VIDIOC_S_FMT32:
 935	case VIDIOC_TRY_FMT32:
 936		return get_v4l2_format32(parg, arg);
 937
 938	case VIDIOC_S_FBUF32:
 939		return get_v4l2_framebuffer32(parg, arg);
 940#ifdef CONFIG_COMPAT_32BIT_TIME
 941	case VIDIOC_QUERYBUF32_TIME32:
 942	case VIDIOC_QBUF32_TIME32:
 943	case VIDIOC_DQBUF32_TIME32:
 944	case VIDIOC_PREPARE_BUF32_TIME32:
 945		return get_v4l2_buffer32_time32(parg, arg);
 946#endif
 947	case VIDIOC_QUERYBUF32:
 948	case VIDIOC_QBUF32:
 949	case VIDIOC_DQBUF32:
 950	case VIDIOC_PREPARE_BUF32:
 951		return get_v4l2_buffer32(parg, arg);
 952
 953	case VIDIOC_G_EXT_CTRLS32:
 954	case VIDIOC_S_EXT_CTRLS32:
 955	case VIDIOC_TRY_EXT_CTRLS32:
 956		return get_v4l2_ext_controls32(parg, arg);
 957
 958	case VIDIOC_CREATE_BUFS32:
 959		return get_v4l2_create32(parg, arg);
 960
 961	case VIDIOC_ENUMSTD32:
 962		return get_v4l2_standard32(parg, arg);
 963
 964	case VIDIOC_ENUMINPUT32:
 965		return get_v4l2_input32(parg, arg);
 966
 967	case VIDIOC_G_EDID32:
 968	case VIDIOC_S_EDID32:
 969		return get_v4l2_edid32(parg, arg);
 970	}
 971	return 0;
 972}
 973
 974int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)
 975{
 976	switch (cmd) {
 977	case VIDIOC_G_FMT32:
 978	case VIDIOC_S_FMT32:
 979	case VIDIOC_TRY_FMT32:
 980		return put_v4l2_format32(parg, arg);
 981
 982	case VIDIOC_G_FBUF32:
 983		return put_v4l2_framebuffer32(parg, arg);
 984#ifdef CONFIG_COMPAT_32BIT_TIME
 985	case VIDIOC_QUERYBUF32_TIME32:
 986	case VIDIOC_QBUF32_TIME32:
 987	case VIDIOC_DQBUF32_TIME32:
 988	case VIDIOC_PREPARE_BUF32_TIME32:
 989		return put_v4l2_buffer32_time32(parg, arg);
 990#endif
 991	case VIDIOC_QUERYBUF32:
 992	case VIDIOC_QBUF32:
 993	case VIDIOC_DQBUF32:
 994	case VIDIOC_PREPARE_BUF32:
 995		return put_v4l2_buffer32(parg, arg);
 996
 997	case VIDIOC_G_EXT_CTRLS32:
 998	case VIDIOC_S_EXT_CTRLS32:
 999	case VIDIOC_TRY_EXT_CTRLS32:
1000		return put_v4l2_ext_controls32(parg, arg);
1001
1002	case VIDIOC_CREATE_BUFS32:
1003		return put_v4l2_create32(parg, arg);
1004
1005	case VIDIOC_ENUMSTD32:
1006		return put_v4l2_standard32(parg, arg);
1007
1008	case VIDIOC_ENUMINPUT32:
1009		return put_v4l2_input32(parg, arg);
1010
1011	case VIDIOC_G_EDID32:
1012	case VIDIOC_S_EDID32:
1013		return put_v4l2_edid32(parg, arg);
1014#ifdef CONFIG_X86_64
1015	case VIDIOC_DQEVENT32:
1016		return put_v4l2_event32(parg, arg);
1017#endif
1018#ifdef CONFIG_COMPAT_32BIT_TIME
1019	case VIDIOC_DQEVENT32_TIME32:
1020		return put_v4l2_event32_time32(parg, arg);
1021#endif
1022	}
1023	return 0;
1024}
1025
1026int v4l2_compat_get_array_args(struct file *file, void *mbuf,
1027			       void __user *user_ptr, size_t array_size,
1028			       unsigned int cmd, void *arg)
1029{
1030	int err = 0;
1031
1032	memset(mbuf, 0, array_size);
1033
1034	switch (cmd) {
1035#ifdef CONFIG_COMPAT_32BIT_TIME
1036	case VIDIOC_QUERYBUF32_TIME32:
1037	case VIDIOC_QBUF32_TIME32:
1038	case VIDIOC_DQBUF32_TIME32:
1039	case VIDIOC_PREPARE_BUF32_TIME32:
1040#endif
1041	case VIDIOC_QUERYBUF32:
1042	case VIDIOC_QBUF32:
1043	case VIDIOC_DQBUF32:
1044	case VIDIOC_PREPARE_BUF32: {
1045		struct v4l2_buffer *b64 = arg;
1046		struct v4l2_plane *p64 = mbuf;
1047		struct v4l2_plane32 __user *p32 = user_ptr;
1048
1049		if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {
1050			u32 num_planes = b64->length;
1051
1052			if (num_planes == 0)
1053				return 0;
1054
1055			while (num_planes--) {
1056				err = get_v4l2_plane32(p64, p32, b64->memory);
1057				if (err)
1058					return err;
1059				++p64;
1060				++p32;
1061			}
1062		}
1063		break;
1064	}
1065	case VIDIOC_G_EXT_CTRLS32:
1066	case VIDIOC_S_EXT_CTRLS32:
1067	case VIDIOC_TRY_EXT_CTRLS32: {
1068		struct v4l2_ext_controls *ecs64 = arg;
1069		struct v4l2_ext_control *ec64 = mbuf;
1070		struct v4l2_ext_control32 __user *ec32 = user_ptr;
1071		int n;
1072
1073		for (n = 0; n < ecs64->count; n++) {
1074			if (copy_from_user(ec64, ec32, sizeof(*ec32)))
1075				return -EFAULT;
1076
1077			if (ctrl_is_pointer(file, ec64->id)) {
1078				compat_uptr_t p;
1079
1080				if (get_user(p, &ec32->string))
1081					return -EFAULT;
1082				ec64->string = compat_ptr(p);
1083			}
1084			ec32++;
1085			ec64++;
1086		}
1087		break;
1088	}
1089	default:
1090		if (copy_from_user(mbuf, user_ptr, array_size))
1091			err = -EFAULT;
1092		break;
1093	}
1094
1095	return err;
1096}
1097
1098int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr,
1099			       void *mbuf, size_t array_size,
1100			       unsigned int cmd, void *arg)
1101{
1102	int err = 0;
1103
1104	switch (cmd) {
1105#ifdef CONFIG_COMPAT_32BIT_TIME
1106	case VIDIOC_QUERYBUF32_TIME32:
1107	case VIDIOC_QBUF32_TIME32:
1108	case VIDIOC_DQBUF32_TIME32:
1109	case VIDIOC_PREPARE_BUF32_TIME32:
1110#endif
1111	case VIDIOC_QUERYBUF32:
1112	case VIDIOC_QBUF32:
1113	case VIDIOC_DQBUF32:
1114	case VIDIOC_PREPARE_BUF32: {
1115		struct v4l2_buffer *b64 = arg;
1116		struct v4l2_plane *p64 = mbuf;
1117		struct v4l2_plane32 __user *p32 = user_ptr;
1118
1119		if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {
1120			u32 num_planes = b64->length;
1121
1122			if (num_planes == 0)
1123				return 0;
1124
1125			while (num_planes--) {
1126				err = put_v4l2_plane32(p64, p32, b64->memory);
1127				if (err)
1128					return err;
1129				++p64;
1130				++p32;
1131			}
1132		}
1133		break;
1134	}
1135	case VIDIOC_G_EXT_CTRLS32:
1136	case VIDIOC_S_EXT_CTRLS32:
1137	case VIDIOC_TRY_EXT_CTRLS32: {
1138		struct v4l2_ext_controls *ecs64 = arg;
1139		struct v4l2_ext_control *ec64 = mbuf;
1140		struct v4l2_ext_control32 __user *ec32 = user_ptr;
1141		int n;
1142
1143		for (n = 0; n < ecs64->count; n++) {
1144			unsigned int size = sizeof(*ec32);
1145			/*
1146			 * Do not modify the pointer when copying a pointer
1147			 * control.  The contents of the pointer was changed,
1148			 * not the pointer itself.
1149			 * The structures are otherwise compatible.
1150			 */
1151			if (ctrl_is_pointer(file, ec64->id))
1152				size -= sizeof(ec32->value64);
1153
1154			if (copy_to_user(ec32, ec64, size))
1155				return -EFAULT;
1156
1157			ec32++;
1158			ec64++;
1159		}
1160		break;
1161	}
1162	default:
1163		if (copy_to_user(user_ptr, mbuf, array_size))
1164			err = -EFAULT;
1165		break;
1166	}
1167
1168	return err;
1169}
1170
1171/**
1172 * v4l2_compat_ioctl32() - Handles a compat32 ioctl call
1173 *
1174 * @file: pointer to &struct file with the file handler
1175 * @cmd: ioctl to be called
1176 * @arg: arguments passed from/to the ioctl handler
1177 *
1178 * This function is meant to be used as .compat_ioctl fops at v4l2-dev.c
1179 * in order to deal with 32-bit calls on a 64-bits Kernel.
1180 *
1181 * This function calls do_video_ioctl() for non-private V4L2 ioctls.
1182 * If the function is a private one it calls vdev->fops->compat_ioctl32
1183 * instead.
1184 */
1185long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
1186{
1187	struct video_device *vdev = video_devdata(file);
1188	long ret = -ENOIOCTLCMD;
1189
1190	if (!file->f_op->unlocked_ioctl)
1191		return ret;
1192
1193	if (!video_is_registered(vdev))
1194		return -ENODEV;
1195
1196	if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)
1197		ret = file->f_op->unlocked_ioctl(file, cmd,
1198					(unsigned long)compat_ptr(arg));
1199	else if (vdev->fops->compat_ioctl32)
1200		ret = vdev->fops->compat_ioctl32(file, cmd, arg);
1201
1202	if (ret == -ENOIOCTLCMD)
1203		pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
1204			 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);
1205	return ret;
1206}
1207EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);
~/ Read-only file preview.