#include <linux/compat.h>
#include <linux/version.h>
#if KERNEL_VERSION(5, 5, 0) <= LINUX_VERSION_CODE || defined(EL8)
#else
#include <drm/drmP.h>
#endif
#include <drm/drm_edid.h>
#include "evdi_drm.h"
#include "evdi_drm_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 KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE || defined(EL8)
if (!access_ok(request, sizeof(*request))
#else
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
#endif
|| __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 KERNEL_VERSION(5, 0, 0) <= LINUX_VERSION_CODE || defined(EL8)
if (!access_ok(request, sizeof(*request))
#else
if (!access_ok(VERIFY_WRITE, request, sizeof(*request))
#endif
|| __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,
};
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;
}