xref: /linux/drivers/input/input-compat.c (revision 905e46acd3272d04566fec49afbd7ad9e2ed9ae3)
1 /*
2  * 32bit compatibility wrappers for the input subsystem.
3  *
4  * Very heavily based on evdev.c - Copyright (c) 1999-2002 Vojtech Pavlik
5  *
6  * This program is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License version 2 as published by
8  * the Free Software Foundation.
9  */
10 
11 #include <linux/export.h>
12 #include <linux/uaccess.h>
13 #include "input-compat.h"
14 
15 #ifdef CONFIG_COMPAT
16 
17 int input_event_from_user(const char __user *buffer,
18 			  struct input_event *event)
19 {
20 	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
21 		struct input_event_compat compat_event;
22 
23 		if (copy_from_user(&compat_event, buffer,
24 				   sizeof(struct input_event_compat)))
25 			return -EFAULT;
26 
27 		event->time.tv_sec = compat_event.time.tv_sec;
28 		event->time.tv_usec = compat_event.time.tv_usec;
29 		event->type = compat_event.type;
30 		event->code = compat_event.code;
31 		event->value = compat_event.value;
32 
33 	} else {
34 		if (copy_from_user(event, buffer, sizeof(struct input_event)))
35 			return -EFAULT;
36 	}
37 
38 	return 0;
39 }
40 
41 int input_event_to_user(char __user *buffer,
42 			const struct input_event *event)
43 {
44 	if (in_compat_syscall() && !COMPAT_USE_64BIT_TIME) {
45 		struct input_event_compat compat_event;
46 
47 		compat_event.time.tv_sec = event->time.tv_sec;
48 		compat_event.time.tv_usec = event->time.tv_usec;
49 		compat_event.type = event->type;
50 		compat_event.code = event->code;
51 		compat_event.value = event->value;
52 
53 		if (copy_to_user(buffer, &compat_event,
54 				 sizeof(struct input_event_compat)))
55 			return -EFAULT;
56 
57 	} else {
58 		if (copy_to_user(buffer, event, sizeof(struct input_event)))
59 			return -EFAULT;
60 	}
61 
62 	return 0;
63 }
64 
65 int input_ff_effect_from_user(const char __user *buffer, size_t size,
66 			      struct ff_effect *effect)
67 {
68 	if (in_compat_syscall()) {
69 		struct ff_effect_compat *compat_effect;
70 
71 		if (size != sizeof(struct ff_effect_compat))
72 			return -EINVAL;
73 
74 		/*
75 		 * It so happens that the pointer which needs to be changed
76 		 * is the last field in the structure, so we can retrieve the
77 		 * whole thing and replace just the pointer.
78 		 */
79 		compat_effect = (struct ff_effect_compat *)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 
100 #else
101 
102 int input_event_from_user(const char __user *buffer,
103 			 struct input_event *event)
104 {
105 	if (copy_from_user(event, buffer, sizeof(struct input_event)))
106 		return -EFAULT;
107 
108 	return 0;
109 }
110 
111 int input_event_to_user(char __user *buffer,
112 			const struct input_event *event)
113 {
114 	if (copy_to_user(buffer, event, sizeof(struct input_event)))
115 		return -EFAULT;
116 
117 	return 0;
118 }
119 
120 int input_ff_effect_from_user(const char __user *buffer, size_t size,
121 			      struct ff_effect *effect)
122 {
123 	if (size != sizeof(struct ff_effect))
124 		return -EINVAL;
125 
126 	if (copy_from_user(effect, buffer, sizeof(struct ff_effect)))
127 		return -EFAULT;
128 
129 	return 0;
130 }
131 
132 #endif /* CONFIG_COMPAT */
133 
134 EXPORT_SYMBOL_GPL(input_event_from_user);
135 EXPORT_SYMBOL_GPL(input_event_to_user);
136 EXPORT_SYMBOL_GPL(input_ff_effect_from_user);
137