| // SPDX-License-Identifier: GPL-2.0-only |
| /** |
| * evdi_ioc32.c |
| * |
| * Copyright (c) 2016 The Chromium OS Authors |
| * Copyright (c) 2018 DisplayLink (UK) Ltd. |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by the |
| * Free Software Foundation; either version 2 of the License, or (at your |
| * option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include <linux/compat.h> |
| |
| #include <drm/drmP.h> |
| #include <drm/drm_edid.h> |
| #include <uapi/drm/evdi_drm.h> |
| |
| #include "evdi_drv.h" |
| |
| struct drm_evdi_connect32 { |
| int32_t connected; |
| int32_t dev_index; |
| uint32_t edid_ptr32; |
| uint32_t edid_length; |
| uint32_t sku_area_limit; |
| }; |
| |
| struct drm_evdi_grabpix32 { |
| uint32_t mode; |
| int32_t buf_width; |
| int32_t buf_height; |
| int32_t buf_byte_stride; |
| uint32_t buffer_ptr32; |
| int32_t num_rects; |
| uint32_t rects_ptr32; |
| }; |
| |
| static int compat_evdi_connect(struct file *file, |
| unsigned int __always_unused cmd, |
| unsigned long arg) |
| { |
| struct drm_evdi_connect32 req32; |
| struct drm_evdi_connect __user *request; |
| |
| if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) |
| return -EFAULT; |
| |
| request = compat_alloc_user_space(sizeof(*request)); |
| if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) |
| || __put_user(req32.connected, &request->connected) |
| || __put_user(req32.dev_index, &request->dev_index) |
| || __put_user((void __user *)(unsigned long)req32.edid_ptr32, |
| &request->edid) |
| || __put_user(req32.edid_length, &request->edid_length) |
| || __put_user(req32.sku_area_limit, &request->sku_area_limit)) |
| return -EFAULT; |
| |
| return drm_ioctl(file, DRM_IOCTL_EVDI_CONNECT, |
| (unsigned long)request); |
| } |
| |
| static int compat_evdi_grabpix(struct file *file, |
| unsigned int __always_unused cmd, |
| unsigned long arg) |
| { |
| struct drm_evdi_grabpix32 req32; |
| struct drm_evdi_grabpix __user *request; |
| |
| if (copy_from_user(&req32, (void __user *)arg, sizeof(req32))) |
| return -EFAULT; |
| |
| request = compat_alloc_user_space(sizeof(*request)); |
| if (!access_ok(VERIFY_WRITE, request, sizeof(*request)) |
| || __put_user(req32.mode, &request->mode) |
| || __put_user(req32.buf_width, &request->buf_width) |
| || __put_user(req32.buf_height, &request->buf_height) |
| || __put_user(req32.buf_byte_stride, &request->buf_byte_stride) |
| || __put_user((void __user *)(unsigned long)req32.buffer_ptr32, |
| &request->buffer) |
| || __put_user(req32.num_rects, &request->num_rects) |
| || __put_user((void __user *)(unsigned long)req32.rects_ptr32, |
| &request->rects)) |
| return -EFAULT; |
| |
| return drm_ioctl(file, DRM_IOCTL_EVDI_GRABPIX, |
| (unsigned long)request); |
| } |
| |
| static drm_ioctl_compat_t *evdi_compat_ioctls[] = { |
| [DRM_EVDI_CONNECT] = compat_evdi_connect, |
| [DRM_EVDI_GRABPIX] = compat_evdi_grabpix, |
| }; |
| |
| /** |
| * Called whenever a 32-bit process running under a 64-bit kernel |
| * performs an ioctl on /dev/dri/card<n>. |
| * |
| * \param filp file pointer. |
| * \param cmd command. |
| * \param arg user argument. |
| * \return zero on success or negative number on failure. |
| */ |
| long evdi_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
| { |
| unsigned int nr = DRM_IOCTL_NR(cmd); |
| drm_ioctl_compat_t *fn = NULL; |
| int ret; |
| |
| if (nr < DRM_COMMAND_BASE || nr >= DRM_COMMAND_END) |
| return drm_compat_ioctl(filp, cmd, arg); |
| |
| if (nr < DRM_COMMAND_BASE + ARRAY_SIZE(evdi_compat_ioctls)) |
| fn = evdi_compat_ioctls[nr - DRM_COMMAND_BASE]; |
| |
| if (fn != NULL) |
| ret = (*fn) (filp, cmd, arg); |
| else |
| ret = drm_ioctl(filp, cmd, arg); |
| |
| return ret; |
| } |