diff options
author | Philip Langdale <philipl@overt.org> | 2008-10-16 22:31:42 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2008-10-27 22:03:42 -0400 |
commit | 2d56f3a32c0e62f99c043d2579840f9731fe5855 (patch) | |
tree | 3bf1539bbed43e5309dcfd634f202bb9ad0f11b2 /drivers/input/input-compat.c | |
parent | 49fdf6785fd660e18a1eb4588928f47e9fa29a9a (diff) |
Input: refactor evdev 32bit compat to be shareable with uinput
Currently, evdev has working 32bit compatibility and uinput does not. uinput
needs the input_event code that evdev uses, so let's refactor it so it can
be shared.
[dtor@mail.ru: add fix for force feedback compat issues]
Signed-off-by: Philip Langdale <philipl@overt.org>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/input-compat.c')
-rw-r--r-- | drivers/input/input-compat.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/drivers/input/input-compat.c b/drivers/input/input-compat.c new file mode 100644 index 000000000000..1accb89ae66f --- /dev/null +++ b/drivers/input/input-compat.c | |||
@@ -0,0 +1,135 @@ | |||
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); | ||