linux/drivers/input/input-compat.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * 32bit compatibility wrappers for the input subsystem.
   4 *
   5 * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
   6 */
   7
   8#include <linux/export.h>
   9#include <linux/uaccess.h>
  10#include "input-compat.h"
  11
  12#ifdef CONFIG_COMPAT
  13
  14int input_event_from_user(const char __user *buffer,
  15                          struct input_event *event)
  16{
  17        if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
  18                struct input_event_compat compat_event;
  19
  20                if (copy_from_user(&compat_event, buffer,
  21                                   sizeof(struct input_event_compat)))
  22                        return -EFAULT;
  23
  24                event->input_event_sec = compat_event.sec;
  25                event->input_event_usec = compat_event.usec;
  26                event->type = compat_event.type;
  27                event->code = compat_event.code;
  28                event->value = compat_event.value;
  29
  30        } else {
  31                if (copy_from_user(event, buffer, sizeof(struct input_event)))
  32                        return -EFAULT;
  33        }
  34
  35        return 0;
  36}
  37
  38int input_event_to_user(char __user *buffer,
  39                        const struct input_event *event)
  40{
  41        if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
  42                struct input_event_compat compat_event;
  43
  44                compat_event.sec = event->input_event_sec;
  45                compat_event.usec = event->input_event_usec;
  46                compat_event.type = event->type;
  47                compat_event.code = event->code;
  48                compat_event.value = event->value;
  49
  50                if (copy_to_user(buffer, &compat_event,
  51                                 sizeof(struct input_event_compat)))
  52                        return -EFAULT;
  53
  54        } else {
  55                if (copy_to_user(buffer, event, sizeof(struct input_event)))
  56                        return -EFAULT;
  57        }
  58
  59        return 0;
  60}
  61
  62int input_ff_effect_from_user(const char __user *buffer, size_t size,
  63                              struct ff_effect *effect)
  64{
  65        if (in_compat_syscall()) {
  66                struct ff_effect_compat *compat_effect;
  67
  68                if (size != sizeof(struct ff_effect_compat))
  69                        return -EINVAL;
  70
  71                /*
  72                 * It so happens that the pointer which needs to be changed
  73                 * is the last field in the structure, so we can retrieve the
  74                 * whole thing and replace just the pointer.
  75                 */
  76                compat_effect = (struct ff_effect_compat *)effect;
  77
  78                if (copy_from_user(compat_effect, buffer,
  79                                   sizeof(struct ff_effect_compat)))
  80                        return -EFAULT;
  81
  82                if (compat_effect->type == FF_PERIODIC &&
  83                    compat_effect->u.periodic.waveform == FF_CUSTOM)
  84                        effect->u.periodic.custom_data =
  85                                compat_ptr(compat_effect->u.periodic.custom_data);
  86        } else {
  87                if (size != sizeof(struct ff_effect))
  88                        return -EINVAL;
  89
  90                if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
  91                        return -EFAULT;
  92        }
  93
  94        return 0;
  95}
  96
  97#else
  98
  99int input_event_from_user(const char __user *buffer,
 100                         struct input_event *event)
 101{
 102        if (copy_from_user(event, buffer, sizeof(struct input_event)))
 103                return -EFAULT;
 104
 105        return 0;
 106}
 107
 108int input_event_to_user(char __user *buffer,
 109                        const struct input_event *event)
 110{
 111        if (copy_to_user(buffer, event, sizeof(struct input_event)))
 112                return -EFAULT;
 113
 114        return 0;
 115}
 116
 117int input_ff_effect_from_user(const char __user *buffer, size_t size,
 118                              struct ff_effect *effect)
 119{
 120        if (size != sizeof(struct ff_effect))
 121                return -EINVAL;
 122
 123        if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
 124                return -EFAULT;
 125
 126        return 0;
 127}
 128
 129#endif /* CONFIG_COMPAT */
 130
 131EXPORT_SYMBOL_GPL(input_event_from_user);
 132EXPORT_SYMBOL_GPL(input_event_to_user);
 133EXPORT_SYMBOL_GPL(input_ff_effect_from_user);
 134