162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * 32bit compatibility wrappers for the input subsystem. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/export.h> 962306a36Sopenharmony_ci#include <linux/uaccess.h> 1062306a36Sopenharmony_ci#include "input-compat.h" 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#ifdef CONFIG_COMPAT 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ciint input_event_from_user(const char __user *buffer, 1562306a36Sopenharmony_ci struct input_event *event) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 1862306a36Sopenharmony_ci struct input_event_compat compat_event; 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (copy_from_user(&compat_event, buffer, 2162306a36Sopenharmony_ci sizeof(struct input_event_compat))) 2262306a36Sopenharmony_ci return -EFAULT; 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci event->input_event_sec = compat_event.sec; 2562306a36Sopenharmony_ci event->input_event_usec = compat_event.usec; 2662306a36Sopenharmony_ci event->type = compat_event.type; 2762306a36Sopenharmony_ci event->code = compat_event.code; 2862306a36Sopenharmony_ci event->value = compat_event.value; 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci } else { 3162306a36Sopenharmony_ci if (copy_from_user(event, buffer, sizeof(struct input_event))) 3262306a36Sopenharmony_ci return -EFAULT; 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return 0; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ciint input_event_to_user(char __user *buffer, 3962306a36Sopenharmony_ci const struct input_event *event) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) { 4262306a36Sopenharmony_ci struct input_event_compat compat_event; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci compat_event.sec = event->input_event_sec; 4562306a36Sopenharmony_ci compat_event.usec = event->input_event_usec; 4662306a36Sopenharmony_ci compat_event.type = event->type; 4762306a36Sopenharmony_ci compat_event.code = event->code; 4862306a36Sopenharmony_ci compat_event.value = event->value; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci if (copy_to_user(buffer, &compat_event, 5162306a36Sopenharmony_ci sizeof(struct input_event_compat))) 5262306a36Sopenharmony_ci return -EFAULT; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci } else { 5562306a36Sopenharmony_ci if (copy_to_user(buffer, event, sizeof(struct input_event))) 5662306a36Sopenharmony_ci return -EFAULT; 5762306a36Sopenharmony_ci } 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ciint input_ff_effect_from_user(const char __user *buffer, size_t size, 6362306a36Sopenharmony_ci struct ff_effect *effect) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (in_compat_syscall()) { 6662306a36Sopenharmony_ci struct ff_effect_compat *compat_effect; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (size != sizeof(struct ff_effect_compat)) 6962306a36Sopenharmony_ci return -EINVAL; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci /* 7262306a36Sopenharmony_ci * It so happens that the pointer which needs to be changed 7362306a36Sopenharmony_ci * is the last field in the structure, so we can retrieve the 7462306a36Sopenharmony_ci * whole thing and replace just the pointer. 7562306a36Sopenharmony_ci */ 7662306a36Sopenharmony_ci compat_effect = (struct ff_effect_compat *)effect; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (copy_from_user(compat_effect, buffer, 7962306a36Sopenharmony_ci sizeof(struct ff_effect_compat))) 8062306a36Sopenharmony_ci return -EFAULT; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci if (compat_effect->type == FF_PERIODIC && 8362306a36Sopenharmony_ci compat_effect->u.periodic.waveform == FF_CUSTOM) 8462306a36Sopenharmony_ci effect->u.periodic.custom_data = 8562306a36Sopenharmony_ci compat_ptr(compat_effect->u.periodic.custom_data); 8662306a36Sopenharmony_ci } else { 8762306a36Sopenharmony_ci if (size != sizeof(struct ff_effect)) 8862306a36Sopenharmony_ci return -EINVAL; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 9162306a36Sopenharmony_ci return -EFAULT; 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#else 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciint input_event_from_user(const char __user *buffer, 10062306a36Sopenharmony_ci struct input_event *event) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci if (copy_from_user(event, buffer, sizeof(struct input_event))) 10362306a36Sopenharmony_ci return -EFAULT; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci return 0; 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint input_event_to_user(char __user *buffer, 10962306a36Sopenharmony_ci const struct input_event *event) 11062306a36Sopenharmony_ci{ 11162306a36Sopenharmony_ci if (copy_to_user(buffer, event, sizeof(struct input_event))) 11262306a36Sopenharmony_ci return -EFAULT; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci return 0; 11562306a36Sopenharmony_ci} 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ciint input_ff_effect_from_user(const char __user *buffer, size_t size, 11862306a36Sopenharmony_ci struct ff_effect *effect) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci if (size != sizeof(struct ff_effect)) 12162306a36Sopenharmony_ci return -EINVAL; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (copy_from_user(effect, buffer, sizeof(struct ff_effect))) 12462306a36Sopenharmony_ci return -EFAULT; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci return 0; 12762306a36Sopenharmony_ci} 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#endif /* CONFIG_COMPAT */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(input_event_from_user); 13262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(input_event_to_user); 13362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(input_ff_effect_from_user); 134