1211 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*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 Labs9 * 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@xs4all.nl>12 *13 * These routines maintain argument size conversion between 32bit and 64bit14 * 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 that33 * came from the userspace call and a 64-bits struct, also allocated as34 * userspace, but filled internally by do_video_ioctl().35 *36 * For ioctls that have pointers inside it, the functions will also37 * receive an ancillary buffer with extra space, used to pass extra38 * 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 argument110 * @index: on return, index of the first created buffer111 * @count: entry: number of requested buffers,112 * return: number of created buffers113 * @memory: buffer memory type114 * @format: frame format, for which buffers are requested115 * @capabilities: capabilities of this buffer type.116 * @flags: additional buffer management attributes (ignored unless the117 * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and118 * configured for MMAP streaming I/O).119 * @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set120 * this field indicate the maximum possible number of buffers121 * for this queue.122 * @reserved: future extensions123 */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 timestamp282 */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_TIME310struct 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#endif333 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_TIME446static 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#endif489 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_TIME535static 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#endif578 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 = NULL;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 (test_bit(V4L2_FL_USES_V4L2_FH, &vdev->flags))681 fh = file->private_data;682 683 if (fh && fh->ctrl_handler)684 hdl = fh->ctrl_handler;685 else if (vdev->ctrl_handler)686 hdl = vdev->ctrl_handler;687 688 if (hdl) {689 struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, id);690 691 return ctrl && ctrl->is_ptr;692 }693 694 if (!ops || !ops->vidioc_query_ext_ctrl)695 return false;696 697 return !ops->vidioc_query_ext_ctrl(file, fh, &qec) &&698 (qec.flags & V4L2_CTRL_FLAG_HAS_PAYLOAD);699}700 701static int get_v4l2_ext_controls32(struct v4l2_ext_controls *p64,702 struct v4l2_ext_controls32 __user *p32)703{704 struct v4l2_ext_controls32 ec32;705 706 if (copy_from_user(&ec32, p32, sizeof(ec32)))707 return -EFAULT;708 709 *p64 = (struct v4l2_ext_controls) {710 .which = ec32.which,711 .count = ec32.count,712 .error_idx = ec32.error_idx,713 .request_fd = ec32.request_fd,714 .reserved[0] = ec32.reserved[0],715 .controls = (void __force *)compat_ptr(ec32.controls),716 };717 718 return 0;719}720 721static int put_v4l2_ext_controls32(struct v4l2_ext_controls *p64,722 struct v4l2_ext_controls32 __user *p32)723{724 struct v4l2_ext_controls32 ec32;725 726 memset(&ec32, 0, sizeof(ec32));727 ec32 = (struct v4l2_ext_controls32) {728 .which = p64->which,729 .count = p64->count,730 .error_idx = p64->error_idx,731 .request_fd = p64->request_fd,732 .reserved[0] = p64->reserved[0],733 .controls = (uintptr_t)p64->controls,734 };735 736 if (copy_to_user(p32, &ec32, sizeof(ec32)))737 return -EFAULT;738 739 return 0;740}741 742#ifdef CONFIG_X86_64743/*744 * x86 is the only compat architecture with different struct alignment745 * between 32-bit and 64-bit tasks.746 */747struct v4l2_event32 {748 __u32 type;749 union {750 compat_s64 value64;751 __u8 data[64];752 } u;753 __u32 pending;754 __u32 sequence;755 struct {756 compat_s64 tv_sec;757 compat_s64 tv_nsec;758 } timestamp;759 __u32 id;760 __u32 reserved[8];761};762 763static int put_v4l2_event32(struct v4l2_event *p64,764 struct v4l2_event32 __user *p32)765{766 if (put_user(p64->type, &p32->type) ||767 copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||768 put_user(p64->pending, &p32->pending) ||769 put_user(p64->sequence, &p32->sequence) ||770 put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||771 put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||772 put_user(p64->id, &p32->id) ||773 copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))774 return -EFAULT;775 return 0;776}777 778#endif779 780#ifdef CONFIG_COMPAT_32BIT_TIME781struct v4l2_event32_time32 {782 __u32 type;783 union {784 compat_s64 value64;785 __u8 data[64];786 } u;787 __u32 pending;788 __u32 sequence;789 struct old_timespec32 timestamp;790 __u32 id;791 __u32 reserved[8];792};793 794static int put_v4l2_event32_time32(struct v4l2_event *p64,795 struct v4l2_event32_time32 __user *p32)796{797 if (put_user(p64->type, &p32->type) ||798 copy_to_user(&p32->u, &p64->u, sizeof(p64->u)) ||799 put_user(p64->pending, &p32->pending) ||800 put_user(p64->sequence, &p32->sequence) ||801 put_user(p64->timestamp.tv_sec, &p32->timestamp.tv_sec) ||802 put_user(p64->timestamp.tv_nsec, &p32->timestamp.tv_nsec) ||803 put_user(p64->id, &p32->id) ||804 copy_to_user(p32->reserved, p64->reserved, sizeof(p32->reserved)))805 return -EFAULT;806 return 0;807}808#endif809 810struct v4l2_edid32 {811 __u32 pad;812 __u32 start_block;813 __u32 blocks;814 __u32 reserved[5];815 compat_caddr_t edid;816};817 818static int get_v4l2_edid32(struct v4l2_edid *p64,819 struct v4l2_edid32 __user *p32)820{821 compat_uptr_t edid;822 823 if (copy_from_user(p64, p32, offsetof(struct v4l2_edid32, edid)) ||824 get_user(edid, &p32->edid))825 return -EFAULT;826 827 p64->edid = (void __force *)compat_ptr(edid);828 return 0;829}830 831static int put_v4l2_edid32(struct v4l2_edid *p64,832 struct v4l2_edid32 __user *p32)833{834 if (copy_to_user(p32, p64, offsetof(struct v4l2_edid32, edid)))835 return -EFAULT;836 return 0;837}838 839/*840 * List of ioctls that require 32-bits/64-bits conversion841 *842 * The V4L2 ioctls that aren't listed there don't have pointer arguments843 * and the struct size is identical for both 32 and 64 bits versions, so844 * they don't need translations.845 */846 847#define VIDIOC_G_FMT32 _IOWR('V', 4, struct v4l2_format32)848#define VIDIOC_S_FMT32 _IOWR('V', 5, struct v4l2_format32)849#define VIDIOC_QUERYBUF32 _IOWR('V', 9, struct v4l2_buffer32)850#define VIDIOC_G_FBUF32 _IOR ('V', 10, struct v4l2_framebuffer32)851#define VIDIOC_S_FBUF32 _IOW ('V', 11, struct v4l2_framebuffer32)852#define VIDIOC_QBUF32 _IOWR('V', 15, struct v4l2_buffer32)853#define VIDIOC_DQBUF32 _IOWR('V', 17, struct v4l2_buffer32)854#define VIDIOC_ENUMSTD32 _IOWR('V', 25, struct v4l2_standard32)855#define VIDIOC_ENUMINPUT32 _IOWR('V', 26, struct v4l2_input32)856#define VIDIOC_G_EDID32 _IOWR('V', 40, struct v4l2_edid32)857#define VIDIOC_S_EDID32 _IOWR('V', 41, struct v4l2_edid32)858#define VIDIOC_TRY_FMT32 _IOWR('V', 64, struct v4l2_format32)859#define VIDIOC_G_EXT_CTRLS32 _IOWR('V', 71, struct v4l2_ext_controls32)860#define VIDIOC_S_EXT_CTRLS32 _IOWR('V', 72, struct v4l2_ext_controls32)861#define VIDIOC_TRY_EXT_CTRLS32 _IOWR('V', 73, struct v4l2_ext_controls32)862#define VIDIOC_DQEVENT32 _IOR ('V', 89, struct v4l2_event32)863#define VIDIOC_CREATE_BUFS32 _IOWR('V', 92, struct v4l2_create_buffers32)864#define VIDIOC_PREPARE_BUF32 _IOWR('V', 93, struct v4l2_buffer32)865 866#ifdef CONFIG_COMPAT_32BIT_TIME867#define VIDIOC_QUERYBUF32_TIME32 _IOWR('V', 9, struct v4l2_buffer32_time32)868#define VIDIOC_QBUF32_TIME32 _IOWR('V', 15, struct v4l2_buffer32_time32)869#define VIDIOC_DQBUF32_TIME32 _IOWR('V', 17, struct v4l2_buffer32_time32)870#define VIDIOC_DQEVENT32_TIME32 _IOR ('V', 89, struct v4l2_event32_time32)871#define VIDIOC_PREPARE_BUF32_TIME32 _IOWR('V', 93, struct v4l2_buffer32_time32)872#endif873 874unsigned int v4l2_compat_translate_cmd(unsigned int cmd)875{876 switch (cmd) {877 case VIDIOC_G_FMT32:878 return VIDIOC_G_FMT;879 case VIDIOC_S_FMT32:880 return VIDIOC_S_FMT;881 case VIDIOC_TRY_FMT32:882 return VIDIOC_TRY_FMT;883 case VIDIOC_G_FBUF32:884 return VIDIOC_G_FBUF;885 case VIDIOC_S_FBUF32:886 return VIDIOC_S_FBUF;887#ifdef CONFIG_COMPAT_32BIT_TIME888 case VIDIOC_QUERYBUF32_TIME32:889 return VIDIOC_QUERYBUF;890 case VIDIOC_QBUF32_TIME32:891 return VIDIOC_QBUF;892 case VIDIOC_DQBUF32_TIME32:893 return VIDIOC_DQBUF;894 case VIDIOC_PREPARE_BUF32_TIME32:895 return VIDIOC_PREPARE_BUF;896#endif897 case VIDIOC_QUERYBUF32:898 return VIDIOC_QUERYBUF;899 case VIDIOC_QBUF32:900 return VIDIOC_QBUF;901 case VIDIOC_DQBUF32:902 return VIDIOC_DQBUF;903 case VIDIOC_CREATE_BUFS32:904 return VIDIOC_CREATE_BUFS;905 case VIDIOC_G_EXT_CTRLS32:906 return VIDIOC_G_EXT_CTRLS;907 case VIDIOC_S_EXT_CTRLS32:908 return VIDIOC_S_EXT_CTRLS;909 case VIDIOC_TRY_EXT_CTRLS32:910 return VIDIOC_TRY_EXT_CTRLS;911 case VIDIOC_PREPARE_BUF32:912 return VIDIOC_PREPARE_BUF;913 case VIDIOC_ENUMSTD32:914 return VIDIOC_ENUMSTD;915 case VIDIOC_ENUMINPUT32:916 return VIDIOC_ENUMINPUT;917 case VIDIOC_G_EDID32:918 return VIDIOC_G_EDID;919 case VIDIOC_S_EDID32:920 return VIDIOC_S_EDID;921#ifdef CONFIG_X86_64922 case VIDIOC_DQEVENT32:923 return VIDIOC_DQEVENT;924#endif925#ifdef CONFIG_COMPAT_32BIT_TIME926 case VIDIOC_DQEVENT32_TIME32:927 return VIDIOC_DQEVENT;928#endif929 }930 return cmd;931}932 933int v4l2_compat_get_user(void __user *arg, void *parg, unsigned int cmd)934{935 switch (cmd) {936 case VIDIOC_G_FMT32:937 case VIDIOC_S_FMT32:938 case VIDIOC_TRY_FMT32:939 return get_v4l2_format32(parg, arg);940 941 case VIDIOC_S_FBUF32:942 return get_v4l2_framebuffer32(parg, arg);943#ifdef CONFIG_COMPAT_32BIT_TIME944 case VIDIOC_QUERYBUF32_TIME32:945 case VIDIOC_QBUF32_TIME32:946 case VIDIOC_DQBUF32_TIME32:947 case VIDIOC_PREPARE_BUF32_TIME32:948 return get_v4l2_buffer32_time32(parg, arg);949#endif950 case VIDIOC_QUERYBUF32:951 case VIDIOC_QBUF32:952 case VIDIOC_DQBUF32:953 case VIDIOC_PREPARE_BUF32:954 return get_v4l2_buffer32(parg, arg);955 956 case VIDIOC_G_EXT_CTRLS32:957 case VIDIOC_S_EXT_CTRLS32:958 case VIDIOC_TRY_EXT_CTRLS32:959 return get_v4l2_ext_controls32(parg, arg);960 961 case VIDIOC_CREATE_BUFS32:962 return get_v4l2_create32(parg, arg);963 964 case VIDIOC_ENUMSTD32:965 return get_v4l2_standard32(parg, arg);966 967 case VIDIOC_ENUMINPUT32:968 return get_v4l2_input32(parg, arg);969 970 case VIDIOC_G_EDID32:971 case VIDIOC_S_EDID32:972 return get_v4l2_edid32(parg, arg);973 }974 return 0;975}976 977int v4l2_compat_put_user(void __user *arg, void *parg, unsigned int cmd)978{979 switch (cmd) {980 case VIDIOC_G_FMT32:981 case VIDIOC_S_FMT32:982 case VIDIOC_TRY_FMT32:983 return put_v4l2_format32(parg, arg);984 985 case VIDIOC_G_FBUF32:986 return put_v4l2_framebuffer32(parg, arg);987#ifdef CONFIG_COMPAT_32BIT_TIME988 case VIDIOC_QUERYBUF32_TIME32:989 case VIDIOC_QBUF32_TIME32:990 case VIDIOC_DQBUF32_TIME32:991 case VIDIOC_PREPARE_BUF32_TIME32:992 return put_v4l2_buffer32_time32(parg, arg);993#endif994 case VIDIOC_QUERYBUF32:995 case VIDIOC_QBUF32:996 case VIDIOC_DQBUF32:997 case VIDIOC_PREPARE_BUF32:998 return put_v4l2_buffer32(parg, arg);999 1000 case VIDIOC_G_EXT_CTRLS32:1001 case VIDIOC_S_EXT_CTRLS32:1002 case VIDIOC_TRY_EXT_CTRLS32:1003 return put_v4l2_ext_controls32(parg, arg);1004 1005 case VIDIOC_CREATE_BUFS32:1006 return put_v4l2_create32(parg, arg);1007 1008 case VIDIOC_ENUMSTD32:1009 return put_v4l2_standard32(parg, arg);1010 1011 case VIDIOC_ENUMINPUT32:1012 return put_v4l2_input32(parg, arg);1013 1014 case VIDIOC_G_EDID32:1015 case VIDIOC_S_EDID32:1016 return put_v4l2_edid32(parg, arg);1017#ifdef CONFIG_X86_641018 case VIDIOC_DQEVENT32:1019 return put_v4l2_event32(parg, arg);1020#endif1021#ifdef CONFIG_COMPAT_32BIT_TIME1022 case VIDIOC_DQEVENT32_TIME32:1023 return put_v4l2_event32_time32(parg, arg);1024#endif1025 }1026 return 0;1027}1028 1029int v4l2_compat_get_array_args(struct file *file, void *mbuf,1030 void __user *user_ptr, size_t array_size,1031 unsigned int cmd, void *arg)1032{1033 int err = 0;1034 1035 memset(mbuf, 0, array_size);1036 1037 switch (cmd) {1038#ifdef CONFIG_COMPAT_32BIT_TIME1039 case VIDIOC_QUERYBUF32_TIME32:1040 case VIDIOC_QBUF32_TIME32:1041 case VIDIOC_DQBUF32_TIME32:1042 case VIDIOC_PREPARE_BUF32_TIME32:1043#endif1044 case VIDIOC_QUERYBUF32:1045 case VIDIOC_QBUF32:1046 case VIDIOC_DQBUF32:1047 case VIDIOC_PREPARE_BUF32: {1048 struct v4l2_buffer *b64 = arg;1049 struct v4l2_plane *p64 = mbuf;1050 struct v4l2_plane32 __user *p32 = user_ptr;1051 1052 if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {1053 u32 num_planes = b64->length;1054 1055 if (num_planes == 0)1056 return 0;1057 1058 while (num_planes--) {1059 err = get_v4l2_plane32(p64, p32, b64->memory);1060 if (err)1061 return err;1062 ++p64;1063 ++p32;1064 }1065 }1066 break;1067 }1068 case VIDIOC_G_EXT_CTRLS32:1069 case VIDIOC_S_EXT_CTRLS32:1070 case VIDIOC_TRY_EXT_CTRLS32: {1071 struct v4l2_ext_controls *ecs64 = arg;1072 struct v4l2_ext_control *ec64 = mbuf;1073 struct v4l2_ext_control32 __user *ec32 = user_ptr;1074 int n;1075 1076 for (n = 0; n < ecs64->count; n++) {1077 if (copy_from_user(ec64, ec32, sizeof(*ec32)))1078 return -EFAULT;1079 1080 if (ctrl_is_pointer(file, ec64->id)) {1081 compat_uptr_t p;1082 1083 if (get_user(p, &ec32->string))1084 return -EFAULT;1085 ec64->string = compat_ptr(p);1086 }1087 ec32++;1088 ec64++;1089 }1090 break;1091 }1092 default:1093 if (copy_from_user(mbuf, user_ptr, array_size))1094 err = -EFAULT;1095 break;1096 }1097 1098 return err;1099}1100 1101int v4l2_compat_put_array_args(struct file *file, void __user *user_ptr,1102 void *mbuf, size_t array_size,1103 unsigned int cmd, void *arg)1104{1105 int err = 0;1106 1107 switch (cmd) {1108#ifdef CONFIG_COMPAT_32BIT_TIME1109 case VIDIOC_QUERYBUF32_TIME32:1110 case VIDIOC_QBUF32_TIME32:1111 case VIDIOC_DQBUF32_TIME32:1112 case VIDIOC_PREPARE_BUF32_TIME32:1113#endif1114 case VIDIOC_QUERYBUF32:1115 case VIDIOC_QBUF32:1116 case VIDIOC_DQBUF32:1117 case VIDIOC_PREPARE_BUF32: {1118 struct v4l2_buffer *b64 = arg;1119 struct v4l2_plane *p64 = mbuf;1120 struct v4l2_plane32 __user *p32 = user_ptr;1121 1122 if (V4L2_TYPE_IS_MULTIPLANAR(b64->type)) {1123 u32 num_planes = b64->length;1124 1125 if (num_planes == 0)1126 return 0;1127 1128 while (num_planes--) {1129 err = put_v4l2_plane32(p64, p32, b64->memory);1130 if (err)1131 return err;1132 ++p64;1133 ++p32;1134 }1135 }1136 break;1137 }1138 case VIDIOC_G_EXT_CTRLS32:1139 case VIDIOC_S_EXT_CTRLS32:1140 case VIDIOC_TRY_EXT_CTRLS32: {1141 struct v4l2_ext_controls *ecs64 = arg;1142 struct v4l2_ext_control *ec64 = mbuf;1143 struct v4l2_ext_control32 __user *ec32 = user_ptr;1144 int n;1145 1146 for (n = 0; n < ecs64->count; n++) {1147 unsigned int size = sizeof(*ec32);1148 /*1149 * Do not modify the pointer when copying a pointer1150 * control. The contents of the pointer was changed,1151 * not the pointer itself.1152 * The structures are otherwise compatible.1153 */1154 if (ctrl_is_pointer(file, ec64->id))1155 size -= sizeof(ec32->value64);1156 1157 if (copy_to_user(ec32, ec64, size))1158 return -EFAULT;1159 1160 ec32++;1161 ec64++;1162 }1163 break;1164 }1165 default:1166 if (copy_to_user(user_ptr, mbuf, array_size))1167 err = -EFAULT;1168 break;1169 }1170 1171 return err;1172}1173 1174/**1175 * v4l2_compat_ioctl32() - Handles a compat32 ioctl call1176 *1177 * @file: pointer to &struct file with the file handler1178 * @cmd: ioctl to be called1179 * @arg: arguments passed from/to the ioctl handler1180 *1181 * This function is meant to be used as .compat_ioctl fops at v4l2-dev.c1182 * in order to deal with 32-bit calls on a 64-bits Kernel.1183 *1184 * This function calls do_video_ioctl() for non-private V4L2 ioctls.1185 * If the function is a private one it calls vdev->fops->compat_ioctl321186 * instead.1187 */1188long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)1189{1190 struct video_device *vdev = video_devdata(file);1191 long ret = -ENOIOCTLCMD;1192 1193 if (!file->f_op->unlocked_ioctl)1194 return ret;1195 1196 if (!video_is_registered(vdev))1197 return -ENODEV;1198 1199 if (_IOC_TYPE(cmd) == 'V' && _IOC_NR(cmd) < BASE_VIDIOC_PRIVATE)1200 ret = file->f_op->unlocked_ioctl(file, cmd,1201 (unsigned long)compat_ptr(arg));1202 else if (vdev->fops->compat_ioctl32)1203 ret = vdev->fops->compat_ioctl32(file, cmd, arg);1204 1205 if (ret == -ENOIOCTLCMD)1206 pr_debug("compat_ioctl32: unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",1207 _IOC_TYPE(cmd), _IOC_DIR(cmd), _IOC_NR(cmd), cmd);1208 return ret;1209}1210EXPORT_SYMBOL_GPL(v4l2_compat_ioctl32);1211