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