// SPDX-License-Identifier: GPL-2.0-only
/*
* 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
* Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
* Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
*
* These routines maintain argument size conversion between 32bit and 64bit
* ioctls.
*/
#include <linux/compat.h>
#include <linux/module.h>
#include <linux/videodev2.h>
#include <linux/v4l2-subdev.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-ioctl.h>
/*
* Per-ioctl data copy handlers.
*
* Those come in pairs, with a get_v4l2_foo() and a put_v4l2_foo() routine,
* where "v4l2_foo" is the name of the V4L2 struct.
*
* They basically get two __user pointers, one with a 32-bits struct that
* came from the userspace call and a 64-bits struct, also allocated as
* userspace, but filled internally by do_video_ioctl().
*
* For ioctls that have pointers inside it, the functions will also
* receive an ancillary buffer with extra space, used to pass extra
* data to the routine.
*/
struct v4l2_window32 {
struct v4l2_rect w;
__u32 field; /* enum v4l2_field */
__u32 chromakey;
compat_caddr_t clips; /* always NULL */
__u32 clipcount; /* always 0 */
compat_caddr_t bitmap; /* always NULL */
__u8 global_alpha;
};
static int get_v4l2_window32(struct v4l2_window *p64,
struct v4l2_window32 __user *p32)
{
struct v4l2_window32 w32;
if (copy_from_user(&w32, p32, sizeof(w32)))
return -EFAULT;
*p64 = (struct v4l2_window) {
.w = w32.w,
.field = w32.field,
.chromakey = w32.chromakey,
.clips = NULL,
.clipcount = 0,
.bitmap = NULL,
.global_alpha = w32.global_alpha,
};
return 0;
}
static int put_v4l2_window32(struct v4l2_window *p64,
struct v4l2_window32 __user *p32)
{
struct v4l2_window32 w32;
memset(&w32, 0, sizeof(w32));
w32 = (struct v4l2_window32) {
.w = p64->w,
.field = p64->field,
.chromakey = p64->chromakey,
.clips = 0,
.clipcount = 0,
.bitmap = 0,
.global_alpha = p64->global_alpha,
};
if (copy_to_user(p32, &w32, sizeof(w32)))
return -EFAULT;
return 0;
}
struct v4l2_format32 {
__u32 type; /* enum v4l2_buf_type */
union {
struct v4l2_pix_format pix;
struct v4l2_pix_format_mplane pix_mp;
struct v4l2_window32 win;
struct v4l2_vbi_format vbi;
struct v4l2_sliced_vbi_format sliced;
struct v4l2_sdr_format sdr;
struct v4l2_meta_format meta;
__u8 raw_data[200]; /* user-defined */
} fmt;
};
/**
* struct v4l2_create_buffers32 - VIDIOC_CREATE_BUFS32 argument
* @index: on return, index of the first created buffer
* @count: entry: number of requested buffers,
* return: number of created buffers
* @memory: buffer memory type
* @format: frame format, for which buffers are requested
* @capabilities: capabilities of this buffer type.
* @flags: additional buffer management attributes (ignored unless the
* queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
* configured for MMAP streaming I/O).
* @max_num_buffers: if V4L2_BUF_CAP_SUPPORTS_MAX_NUM_BUFFERS capability flag is set
* this field indicate the maximum possible number of buffers
* for this queue.
* @reserved: future extensions
*/
struct v4l2_create_buffers32 {
__u32 index;
__u32 count;
__u32 memory; /* enum v4l2_memory */
struct v4l2_format32 format;
__u32 capabilities;
__u32 flags;
__u32 max_num_buffers;
__u32 reserved[5];
};
static int get_v4l2_format32(struct v4l2_format *p64,
struct v4l2_format32 __user *p32)
{
if (get_user(p64->type, &p32->type))
return -EFAULT;
switch (p64->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
return copy_from_user(&p64->fmt.pix, &p32->fmt.pix,
sizeof(p64->fmt.pix)) ? -EFAULT : 0;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
return copy_from_user(&p64->fmt.pix_mp, &p32->fmt