projects/linux·blob master · refs

165 lines · 3.8 KiB

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/sprintf.h>
10#include <linux/uaccess.h>
11#include "input-compat.h"
12
13#ifdef CONFIG_COMPAT
14
15int input_event_from_user(const char __user *buffer,
16 struct input_event *event)
17{
18 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
19 struct input_event_compat compat_event;
20
21 if (copy_from_user(&compat_event, buffer,
22 sizeof(struct input_event_compat)))
23 return -EFAULT;
24
25 event->input_event_sec = compat_event.sec;
26 event->input_event_usec = compat_event.usec;
27 event->type = compat_event.type;
28 event->code = compat_event.code;
29 event->value = compat_event.value;
30
31 } else {
32 if (copy_from_user(event, buffer, sizeof(struct input_event)))
33 return -EFAULT;
34 }
35
36 return 0;
37}
38
39int input_event_to_user(char __user *buffer,
40 const struct input_event *event)
41{
42 if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
43 struct input_event_compat compat_event;
44
45 compat_event.sec = event->input_event_sec;
46 compat_event.usec = event->input_event_usec;
47 compat_event.type = event->type;
48 compat_event.code = event->code;
49 compat_event.value = event->value;
50
51 if (copy_to_user(buffer, &compat_event,
52 sizeof(struct input_event_compat)))
53 return -EFAULT;
54
55 } else {
56 if (copy_to_user(buffer, event, sizeof(struct input_event)))
57 return -EFAULT;
58 }
59
60 return 0;
61}
62
63int input_ff_effect_from_user(const char __user *buffer, size_t size,
64 struct ff_effect *effect)
65{
66 if (in_compat_syscall()) {
67 struct ff_effect_compat *compat_effect;
68
69 if (size != sizeof(struct ff_effect_compat))
70 return -EINVAL;
71
72 /*
73 * It so happens that the pointer which needs to be changed
74 * is the last field in the structure, so we can retrieve the
75 * whole thing and replace just the pointer.
76 */
77 compat_effect = (struct ff_effect_compat *)effect;
78
79 memset(effect, 0, sizeof(*effect));
80
81 if (copy_from_user(compat_effect, buffer,
82 sizeof(struct ff_effect_compat)))
83 return -EFAULT;
84
85 if (compat_effect->type == FF_PERIODIC &&
86 compat_effect->u.periodic.waveform == FF_CUSTOM)
87 effect->u.periodic.custom_data =
88 compat_ptr(compat_effect->u.periodic.custom_data);
89 } else {
90 if (size != sizeof(struct ff_effect))
91 return -EINVAL;
92
93 if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
94 return -EFAULT;
95 }
96
97 return 0;
98}
99
100int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
101 bool skip_empty)
102{
103 int len = 0;
104
105 if (in_compat_syscall()) {
106 u32 dword = bits >> 32;
107 if (dword || !skip_empty)
108 len += snprintf(buf, buf_size, "%x ", dword);
109
110 dword = bits & 0xffffffffUL;
111 if (dword || !skip_empty || len)
112 len += snprintf(buf + len, max(buf_size - len, 0),
113 "%x", dword);
114 } else {
115 if (bits || !skip_empty)
116 len += snprintf(buf, buf_size, "%lx", bits);
117 }
118
119 return len;
120}
121
122#else
123
124int input_event_from_user(const char __user *buffer,
125 struct input_event *event)
126{
127 if (copy_from_user(event, buffer, sizeof(struct input_event)))
128 return -EFAULT;
129
130 return 0;
131}
132
133int input_event_to_user(char __user *buffer,
134 const struct input_event *event)
135{
136 if (copy_to_user(buffer, event, sizeof(struct input_event)))
137 return -EFAULT;
138
139 return 0;
140}
141
142int input_ff_effect_from_user(const char __user *buffer, size_t size,
143 struct ff_effect *effect)
144{
145 if (size != sizeof(struct ff_effect))
146 return -EINVAL;
147
148 if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
149 return -EFAULT;
150
151 return 0;
152}
153
154int input_bits_to_string(char *buf, int buf_size, unsigned long bits,
155 bool skip_empty)
156{
157 return bits || !skip_empty ?
158 snprintf(buf, buf_size, "%lx", bits) : 0;
159}
160
161#endif /* CONFIG_COMPAT */
162
163EXPORT_SYMBOL_GPL(input_event_from_user);
164EXPORT_SYMBOL_GPL(input_event_to_user);
165EXPORT_SYMBOL_GPL(input_ff_effect_from_user);