Commit 064450140f1eab959bd0eca0245f449993216074
Committed by
Dmitry Torokhov
1 parent
1ea3abf7fb
Exists in
master
and in
7 other branches
Input: fix open count handling in input interfaces
If input_open_device() fails we should not leave interfaces marked as opened. Signed-off-by: Oliver Neukum <oneukum@suse.de> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 4 changed files with 16 additions and 4 deletions Inline Diff
drivers/input/evdev.c
1 | /* | 1 | /* |
2 | * Event char devices, giving access to raw input device events. | 2 | * Event char devices, giving access to raw input device events. |
3 | * | 3 | * |
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | 4 | * Copyright (c) 1999-2002 Vojtech Pavlik |
5 | * | 5 | * |
6 | * This program is free software; you can redistribute it and/or modify it | 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 | 7 | * under the terms of the GNU General Public License version 2 as published by |
8 | * the Free Software Foundation. | 8 | * the Free Software Foundation. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | #define EVDEV_MINOR_BASE 64 | 11 | #define EVDEV_MINOR_BASE 64 |
12 | #define EVDEV_MINORS 32 | 12 | #define EVDEV_MINORS 32 |
13 | #define EVDEV_BUFFER_SIZE 64 | 13 | #define EVDEV_BUFFER_SIZE 64 |
14 | 14 | ||
15 | #include <linux/poll.h> | 15 | #include <linux/poll.h> |
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/init.h> | 18 | #include <linux/init.h> |
19 | #include <linux/input.h> | 19 | #include <linux/input.h> |
20 | #include <linux/major.h> | 20 | #include <linux/major.h> |
21 | #include <linux/device.h> | 21 | #include <linux/device.h> |
22 | #include <linux/compat.h> | 22 | #include <linux/compat.h> |
23 | 23 | ||
24 | struct evdev { | 24 | struct evdev { |
25 | int exist; | 25 | int exist; |
26 | int open; | 26 | int open; |
27 | int minor; | 27 | int minor; |
28 | char name[16]; | 28 | char name[16]; |
29 | struct input_handle handle; | 29 | struct input_handle handle; |
30 | wait_queue_head_t wait; | 30 | wait_queue_head_t wait; |
31 | struct evdev_client *grab; | 31 | struct evdev_client *grab; |
32 | struct list_head client_list; | 32 | struct list_head client_list; |
33 | spinlock_t client_lock; /* protects client_list */ | 33 | spinlock_t client_lock; /* protects client_list */ |
34 | struct mutex mutex; | 34 | struct mutex mutex; |
35 | struct device dev; | 35 | struct device dev; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | struct evdev_client { | 38 | struct evdev_client { |
39 | struct input_event buffer[EVDEV_BUFFER_SIZE]; | 39 | struct input_event buffer[EVDEV_BUFFER_SIZE]; |
40 | int head; | 40 | int head; |
41 | int tail; | 41 | int tail; |
42 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | 42 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
43 | struct fasync_struct *fasync; | 43 | struct fasync_struct *fasync; |
44 | struct evdev *evdev; | 44 | struct evdev *evdev; |
45 | struct list_head node; | 45 | struct list_head node; |
46 | }; | 46 | }; |
47 | 47 | ||
48 | static struct evdev *evdev_table[EVDEV_MINORS]; | 48 | static struct evdev *evdev_table[EVDEV_MINORS]; |
49 | static DEFINE_MUTEX(evdev_table_mutex); | 49 | static DEFINE_MUTEX(evdev_table_mutex); |
50 | 50 | ||
51 | static void evdev_pass_event(struct evdev_client *client, | 51 | static void evdev_pass_event(struct evdev_client *client, |
52 | struct input_event *event) | 52 | struct input_event *event) |
53 | { | 53 | { |
54 | /* | 54 | /* |
55 | * Interrupts are disabled, just acquire the lock | 55 | * Interrupts are disabled, just acquire the lock |
56 | */ | 56 | */ |
57 | spin_lock(&client->buffer_lock); | 57 | spin_lock(&client->buffer_lock); |
58 | client->buffer[client->head++] = *event; | 58 | client->buffer[client->head++] = *event; |
59 | client->head &= EVDEV_BUFFER_SIZE - 1; | 59 | client->head &= EVDEV_BUFFER_SIZE - 1; |
60 | spin_unlock(&client->buffer_lock); | 60 | spin_unlock(&client->buffer_lock); |
61 | 61 | ||
62 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 62 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
63 | } | 63 | } |
64 | 64 | ||
65 | /* | 65 | /* |
66 | * Pass incoming event to all connected clients. Note that we are | 66 | * Pass incoming event to all connected clients. Note that we are |
67 | * caleld under a spinlock with interrupts off so we don't need | 67 | * caleld under a spinlock with interrupts off so we don't need |
68 | * to use rcu_read_lock() here. Writers will be using syncronize_sched() | 68 | * to use rcu_read_lock() here. Writers will be using syncronize_sched() |
69 | * instead of synchrnoize_rcu(). | 69 | * instead of synchrnoize_rcu(). |
70 | */ | 70 | */ |
71 | static void evdev_event(struct input_handle *handle, | 71 | static void evdev_event(struct input_handle *handle, |
72 | unsigned int type, unsigned int code, int value) | 72 | unsigned int type, unsigned int code, int value) |
73 | { | 73 | { |
74 | struct evdev *evdev = handle->private; | 74 | struct evdev *evdev = handle->private; |
75 | struct evdev_client *client; | 75 | struct evdev_client *client; |
76 | struct input_event event; | 76 | struct input_event event; |
77 | 77 | ||
78 | do_gettimeofday(&event.time); | 78 | do_gettimeofday(&event.time); |
79 | event.type = type; | 79 | event.type = type; |
80 | event.code = code; | 80 | event.code = code; |
81 | event.value = value; | 81 | event.value = value; |
82 | 82 | ||
83 | client = rcu_dereference(evdev->grab); | 83 | client = rcu_dereference(evdev->grab); |
84 | if (client) | 84 | if (client) |
85 | evdev_pass_event(client, &event); | 85 | evdev_pass_event(client, &event); |
86 | else | 86 | else |
87 | list_for_each_entry_rcu(client, &evdev->client_list, node) | 87 | list_for_each_entry_rcu(client, &evdev->client_list, node) |
88 | evdev_pass_event(client, &event); | 88 | evdev_pass_event(client, &event); |
89 | 89 | ||
90 | wake_up_interruptible(&evdev->wait); | 90 | wake_up_interruptible(&evdev->wait); |
91 | } | 91 | } |
92 | 92 | ||
93 | static int evdev_fasync(int fd, struct file *file, int on) | 93 | static int evdev_fasync(int fd, struct file *file, int on) |
94 | { | 94 | { |
95 | struct evdev_client *client = file->private_data; | 95 | struct evdev_client *client = file->private_data; |
96 | int retval; | 96 | int retval; |
97 | 97 | ||
98 | retval = fasync_helper(fd, file, on, &client->fasync); | 98 | retval = fasync_helper(fd, file, on, &client->fasync); |
99 | 99 | ||
100 | return retval < 0 ? retval : 0; | 100 | return retval < 0 ? retval : 0; |
101 | } | 101 | } |
102 | 102 | ||
103 | static int evdev_flush(struct file *file, fl_owner_t id) | 103 | static int evdev_flush(struct file *file, fl_owner_t id) |
104 | { | 104 | { |
105 | struct evdev_client *client = file->private_data; | 105 | struct evdev_client *client = file->private_data; |
106 | struct evdev *evdev = client->evdev; | 106 | struct evdev *evdev = client->evdev; |
107 | int retval; | 107 | int retval; |
108 | 108 | ||
109 | retval = mutex_lock_interruptible(&evdev->mutex); | 109 | retval = mutex_lock_interruptible(&evdev->mutex); |
110 | if (retval) | 110 | if (retval) |
111 | return retval; | 111 | return retval; |
112 | 112 | ||
113 | if (!evdev->exist) | 113 | if (!evdev->exist) |
114 | retval = -ENODEV; | 114 | retval = -ENODEV; |
115 | else | 115 | else |
116 | retval = input_flush_device(&evdev->handle, file); | 116 | retval = input_flush_device(&evdev->handle, file); |
117 | 117 | ||
118 | mutex_unlock(&evdev->mutex); | 118 | mutex_unlock(&evdev->mutex); |
119 | return retval; | 119 | return retval; |
120 | } | 120 | } |
121 | 121 | ||
122 | static void evdev_free(struct device *dev) | 122 | static void evdev_free(struct device *dev) |
123 | { | 123 | { |
124 | struct evdev *evdev = container_of(dev, struct evdev, dev); | 124 | struct evdev *evdev = container_of(dev, struct evdev, dev); |
125 | 125 | ||
126 | kfree(evdev); | 126 | kfree(evdev); |
127 | } | 127 | } |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * Grabs an event device (along with underlying input device). | 130 | * Grabs an event device (along with underlying input device). |
131 | * This function is called with evdev->mutex taken. | 131 | * This function is called with evdev->mutex taken. |
132 | */ | 132 | */ |
133 | static int evdev_grab(struct evdev *evdev, struct evdev_client *client) | 133 | static int evdev_grab(struct evdev *evdev, struct evdev_client *client) |
134 | { | 134 | { |
135 | int error; | 135 | int error; |
136 | 136 | ||
137 | if (evdev->grab) | 137 | if (evdev->grab) |
138 | return -EBUSY; | 138 | return -EBUSY; |
139 | 139 | ||
140 | error = input_grab_device(&evdev->handle); | 140 | error = input_grab_device(&evdev->handle); |
141 | if (error) | 141 | if (error) |
142 | return error; | 142 | return error; |
143 | 143 | ||
144 | rcu_assign_pointer(evdev->grab, client); | 144 | rcu_assign_pointer(evdev->grab, client); |
145 | /* | 145 | /* |
146 | * We don't use synchronize_rcu() here because read-side | 146 | * We don't use synchronize_rcu() here because read-side |
147 | * critical section is protected by a spinlock instead | 147 | * critical section is protected by a spinlock instead |
148 | * of rcu_read_lock(). | 148 | * of rcu_read_lock(). |
149 | */ | 149 | */ |
150 | synchronize_sched(); | 150 | synchronize_sched(); |
151 | 151 | ||
152 | return 0; | 152 | return 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) | 155 | static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client) |
156 | { | 156 | { |
157 | if (evdev->grab != client) | 157 | if (evdev->grab != client) |
158 | return -EINVAL; | 158 | return -EINVAL; |
159 | 159 | ||
160 | rcu_assign_pointer(evdev->grab, NULL); | 160 | rcu_assign_pointer(evdev->grab, NULL); |
161 | synchronize_sched(); | 161 | synchronize_sched(); |
162 | input_release_device(&evdev->handle); | 162 | input_release_device(&evdev->handle); |
163 | 163 | ||
164 | return 0; | 164 | return 0; |
165 | } | 165 | } |
166 | 166 | ||
167 | static void evdev_attach_client(struct evdev *evdev, | 167 | static void evdev_attach_client(struct evdev *evdev, |
168 | struct evdev_client *client) | 168 | struct evdev_client *client) |
169 | { | 169 | { |
170 | spin_lock(&evdev->client_lock); | 170 | spin_lock(&evdev->client_lock); |
171 | list_add_tail_rcu(&client->node, &evdev->client_list); | 171 | list_add_tail_rcu(&client->node, &evdev->client_list); |
172 | spin_unlock(&evdev->client_lock); | 172 | spin_unlock(&evdev->client_lock); |
173 | synchronize_sched(); | 173 | synchronize_sched(); |
174 | } | 174 | } |
175 | 175 | ||
176 | static void evdev_detach_client(struct evdev *evdev, | 176 | static void evdev_detach_client(struct evdev *evdev, |
177 | struct evdev_client *client) | 177 | struct evdev_client *client) |
178 | { | 178 | { |
179 | spin_lock(&evdev->client_lock); | 179 | spin_lock(&evdev->client_lock); |
180 | list_del_rcu(&client->node); | 180 | list_del_rcu(&client->node); |
181 | spin_unlock(&evdev->client_lock); | 181 | spin_unlock(&evdev->client_lock); |
182 | synchronize_sched(); | 182 | synchronize_sched(); |
183 | } | 183 | } |
184 | 184 | ||
185 | static int evdev_open_device(struct evdev *evdev) | 185 | static int evdev_open_device(struct evdev *evdev) |
186 | { | 186 | { |
187 | int retval; | 187 | int retval; |
188 | 188 | ||
189 | retval = mutex_lock_interruptible(&evdev->mutex); | 189 | retval = mutex_lock_interruptible(&evdev->mutex); |
190 | if (retval) | 190 | if (retval) |
191 | return retval; | 191 | return retval; |
192 | 192 | ||
193 | if (!evdev->exist) | 193 | if (!evdev->exist) |
194 | retval = -ENODEV; | 194 | retval = -ENODEV; |
195 | else if (!evdev->open++) | 195 | else if (!evdev->open++) { |
196 | retval = input_open_device(&evdev->handle); | 196 | retval = input_open_device(&evdev->handle); |
197 | if (retval) | ||
198 | evdev->open--; | ||
199 | } | ||
197 | 200 | ||
198 | mutex_unlock(&evdev->mutex); | 201 | mutex_unlock(&evdev->mutex); |
199 | return retval; | 202 | return retval; |
200 | } | 203 | } |
201 | 204 | ||
202 | static void evdev_close_device(struct evdev *evdev) | 205 | static void evdev_close_device(struct evdev *evdev) |
203 | { | 206 | { |
204 | mutex_lock(&evdev->mutex); | 207 | mutex_lock(&evdev->mutex); |
205 | 208 | ||
206 | if (evdev->exist && !--evdev->open) | 209 | if (evdev->exist && !--evdev->open) |
207 | input_close_device(&evdev->handle); | 210 | input_close_device(&evdev->handle); |
208 | 211 | ||
209 | mutex_unlock(&evdev->mutex); | 212 | mutex_unlock(&evdev->mutex); |
210 | } | 213 | } |
211 | 214 | ||
212 | /* | 215 | /* |
213 | * Wake up users waiting for IO so they can disconnect from | 216 | * Wake up users waiting for IO so they can disconnect from |
214 | * dead device. | 217 | * dead device. |
215 | */ | 218 | */ |
216 | static void evdev_hangup(struct evdev *evdev) | 219 | static void evdev_hangup(struct evdev *evdev) |
217 | { | 220 | { |
218 | struct evdev_client *client; | 221 | struct evdev_client *client; |
219 | 222 | ||
220 | spin_lock(&evdev->client_lock); | 223 | spin_lock(&evdev->client_lock); |
221 | list_for_each_entry(client, &evdev->client_list, node) | 224 | list_for_each_entry(client, &evdev->client_list, node) |
222 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 225 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
223 | spin_unlock(&evdev->client_lock); | 226 | spin_unlock(&evdev->client_lock); |
224 | 227 | ||
225 | wake_up_interruptible(&evdev->wait); | 228 | wake_up_interruptible(&evdev->wait); |
226 | } | 229 | } |
227 | 230 | ||
228 | static int evdev_release(struct inode *inode, struct file *file) | 231 | static int evdev_release(struct inode *inode, struct file *file) |
229 | { | 232 | { |
230 | struct evdev_client *client = file->private_data; | 233 | struct evdev_client *client = file->private_data; |
231 | struct evdev *evdev = client->evdev; | 234 | struct evdev *evdev = client->evdev; |
232 | 235 | ||
233 | mutex_lock(&evdev->mutex); | 236 | mutex_lock(&evdev->mutex); |
234 | if (evdev->grab == client) | 237 | if (evdev->grab == client) |
235 | evdev_ungrab(evdev, client); | 238 | evdev_ungrab(evdev, client); |
236 | mutex_unlock(&evdev->mutex); | 239 | mutex_unlock(&evdev->mutex); |
237 | 240 | ||
238 | evdev_fasync(-1, file, 0); | 241 | evdev_fasync(-1, file, 0); |
239 | evdev_detach_client(evdev, client); | 242 | evdev_detach_client(evdev, client); |
240 | kfree(client); | 243 | kfree(client); |
241 | 244 | ||
242 | evdev_close_device(evdev); | 245 | evdev_close_device(evdev); |
243 | put_device(&evdev->dev); | 246 | put_device(&evdev->dev); |
244 | 247 | ||
245 | return 0; | 248 | return 0; |
246 | } | 249 | } |
247 | 250 | ||
248 | static int evdev_open(struct inode *inode, struct file *file) | 251 | static int evdev_open(struct inode *inode, struct file *file) |
249 | { | 252 | { |
250 | struct evdev *evdev; | 253 | struct evdev *evdev; |
251 | struct evdev_client *client; | 254 | struct evdev_client *client; |
252 | int i = iminor(inode) - EVDEV_MINOR_BASE; | 255 | int i = iminor(inode) - EVDEV_MINOR_BASE; |
253 | int error; | 256 | int error; |
254 | 257 | ||
255 | if (i >= EVDEV_MINORS) | 258 | if (i >= EVDEV_MINORS) |
256 | return -ENODEV; | 259 | return -ENODEV; |
257 | 260 | ||
258 | error = mutex_lock_interruptible(&evdev_table_mutex); | 261 | error = mutex_lock_interruptible(&evdev_table_mutex); |
259 | if (error) | 262 | if (error) |
260 | return error; | 263 | return error; |
261 | evdev = evdev_table[i]; | 264 | evdev = evdev_table[i]; |
262 | if (evdev) | 265 | if (evdev) |
263 | get_device(&evdev->dev); | 266 | get_device(&evdev->dev); |
264 | mutex_unlock(&evdev_table_mutex); | 267 | mutex_unlock(&evdev_table_mutex); |
265 | 268 | ||
266 | if (!evdev) | 269 | if (!evdev) |
267 | return -ENODEV; | 270 | return -ENODEV; |
268 | 271 | ||
269 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); | 272 | client = kzalloc(sizeof(struct evdev_client), GFP_KERNEL); |
270 | if (!client) { | 273 | if (!client) { |
271 | error = -ENOMEM; | 274 | error = -ENOMEM; |
272 | goto err_put_evdev; | 275 | goto err_put_evdev; |
273 | } | 276 | } |
274 | 277 | ||
275 | spin_lock_init(&client->buffer_lock); | 278 | spin_lock_init(&client->buffer_lock); |
276 | client->evdev = evdev; | 279 | client->evdev = evdev; |
277 | evdev_attach_client(evdev, client); | 280 | evdev_attach_client(evdev, client); |
278 | 281 | ||
279 | error = evdev_open_device(evdev); | 282 | error = evdev_open_device(evdev); |
280 | if (error) | 283 | if (error) |
281 | goto err_free_client; | 284 | goto err_free_client; |
282 | 285 | ||
283 | file->private_data = client; | 286 | file->private_data = client; |
284 | return 0; | 287 | return 0; |
285 | 288 | ||
286 | err_free_client: | 289 | err_free_client: |
287 | evdev_detach_client(evdev, client); | 290 | evdev_detach_client(evdev, client); |
288 | kfree(client); | 291 | kfree(client); |
289 | err_put_evdev: | 292 | err_put_evdev: |
290 | put_device(&evdev->dev); | 293 | put_device(&evdev->dev); |
291 | return error; | 294 | return error; |
292 | } | 295 | } |
293 | 296 | ||
294 | #ifdef CONFIG_COMPAT | 297 | #ifdef CONFIG_COMPAT |
295 | 298 | ||
296 | struct input_event_compat { | 299 | struct input_event_compat { |
297 | struct compat_timeval time; | 300 | struct compat_timeval time; |
298 | __u16 type; | 301 | __u16 type; |
299 | __u16 code; | 302 | __u16 code; |
300 | __s32 value; | 303 | __s32 value; |
301 | }; | 304 | }; |
302 | 305 | ||
303 | /* Note to the author of this code: did it ever occur to | 306 | /* Note to the author of this code: did it ever occur to |
304 | you why the ifdefs are needed? Think about it again. -AK */ | 307 | you why the ifdefs are needed? Think about it again. -AK */ |
305 | #ifdef CONFIG_X86_64 | 308 | #ifdef CONFIG_X86_64 |
306 | # define COMPAT_TEST is_compat_task() | 309 | # define COMPAT_TEST is_compat_task() |
307 | #elif defined(CONFIG_IA64) | 310 | #elif defined(CONFIG_IA64) |
308 | # define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) | 311 | # define COMPAT_TEST IS_IA32_PROCESS(task_pt_regs(current)) |
309 | #elif defined(CONFIG_S390) | 312 | #elif defined(CONFIG_S390) |
310 | # define COMPAT_TEST test_thread_flag(TIF_31BIT) | 313 | # define COMPAT_TEST test_thread_flag(TIF_31BIT) |
311 | #elif defined(CONFIG_MIPS) | 314 | #elif defined(CONFIG_MIPS) |
312 | # define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR) | 315 | # define COMPAT_TEST (current->thread.mflags & MF_32BIT_ADDR) |
313 | #else | 316 | #else |
314 | # define COMPAT_TEST test_thread_flag(TIF_32BIT) | 317 | # define COMPAT_TEST test_thread_flag(TIF_32BIT) |
315 | #endif | 318 | #endif |
316 | 319 | ||
317 | static inline size_t evdev_event_size(void) | 320 | static inline size_t evdev_event_size(void) |
318 | { | 321 | { |
319 | return COMPAT_TEST ? | 322 | return COMPAT_TEST ? |
320 | sizeof(struct input_event_compat) : sizeof(struct input_event); | 323 | sizeof(struct input_event_compat) : sizeof(struct input_event); |
321 | } | 324 | } |
322 | 325 | ||
323 | static int evdev_event_from_user(const char __user *buffer, | 326 | static int evdev_event_from_user(const char __user *buffer, |
324 | struct input_event *event) | 327 | struct input_event *event) |
325 | { | 328 | { |
326 | if (COMPAT_TEST) { | 329 | if (COMPAT_TEST) { |
327 | struct input_event_compat compat_event; | 330 | struct input_event_compat compat_event; |
328 | 331 | ||
329 | if (copy_from_user(&compat_event, buffer, | 332 | if (copy_from_user(&compat_event, buffer, |
330 | sizeof(struct input_event_compat))) | 333 | sizeof(struct input_event_compat))) |
331 | return -EFAULT; | 334 | return -EFAULT; |
332 | 335 | ||
333 | event->time.tv_sec = compat_event.time.tv_sec; | 336 | event->time.tv_sec = compat_event.time.tv_sec; |
334 | event->time.tv_usec = compat_event.time.tv_usec; | 337 | event->time.tv_usec = compat_event.time.tv_usec; |
335 | event->type = compat_event.type; | 338 | event->type = compat_event.type; |
336 | event->code = compat_event.code; | 339 | event->code = compat_event.code; |
337 | event->value = compat_event.value; | 340 | event->value = compat_event.value; |
338 | 341 | ||
339 | } else { | 342 | } else { |
340 | if (copy_from_user(event, buffer, sizeof(struct input_event))) | 343 | if (copy_from_user(event, buffer, sizeof(struct input_event))) |
341 | return -EFAULT; | 344 | return -EFAULT; |
342 | } | 345 | } |
343 | 346 | ||
344 | return 0; | 347 | return 0; |
345 | } | 348 | } |
346 | 349 | ||
347 | static int evdev_event_to_user(char __user *buffer, | 350 | static int evdev_event_to_user(char __user *buffer, |
348 | const struct input_event *event) | 351 | const struct input_event *event) |
349 | { | 352 | { |
350 | if (COMPAT_TEST) { | 353 | if (COMPAT_TEST) { |
351 | struct input_event_compat compat_event; | 354 | struct input_event_compat compat_event; |
352 | 355 | ||
353 | compat_event.time.tv_sec = event->time.tv_sec; | 356 | compat_event.time.tv_sec = event->time.tv_sec; |
354 | compat_event.time.tv_usec = event->time.tv_usec; | 357 | compat_event.time.tv_usec = event->time.tv_usec; |
355 | compat_event.type = event->type; | 358 | compat_event.type = event->type; |
356 | compat_event.code = event->code; | 359 | compat_event.code = event->code; |
357 | compat_event.value = event->value; | 360 | compat_event.value = event->value; |
358 | 361 | ||
359 | if (copy_to_user(buffer, &compat_event, | 362 | if (copy_to_user(buffer, &compat_event, |
360 | sizeof(struct input_event_compat))) | 363 | sizeof(struct input_event_compat))) |
361 | return -EFAULT; | 364 | return -EFAULT; |
362 | 365 | ||
363 | } else { | 366 | } else { |
364 | if (copy_to_user(buffer, event, sizeof(struct input_event))) | 367 | if (copy_to_user(buffer, event, sizeof(struct input_event))) |
365 | return -EFAULT; | 368 | return -EFAULT; |
366 | } | 369 | } |
367 | 370 | ||
368 | return 0; | 371 | return 0; |
369 | } | 372 | } |
370 | 373 | ||
371 | #else | 374 | #else |
372 | 375 | ||
373 | static inline size_t evdev_event_size(void) | 376 | static inline size_t evdev_event_size(void) |
374 | { | 377 | { |
375 | return sizeof(struct input_event); | 378 | return sizeof(struct input_event); |
376 | } | 379 | } |
377 | 380 | ||
378 | static int evdev_event_from_user(const char __user *buffer, | 381 | static int evdev_event_from_user(const char __user *buffer, |
379 | struct input_event *event) | 382 | struct input_event *event) |
380 | { | 383 | { |
381 | if (copy_from_user(event, buffer, sizeof(struct input_event))) | 384 | if (copy_from_user(event, buffer, sizeof(struct input_event))) |
382 | return -EFAULT; | 385 | return -EFAULT; |
383 | 386 | ||
384 | return 0; | 387 | return 0; |
385 | } | 388 | } |
386 | 389 | ||
387 | static int evdev_event_to_user(char __user *buffer, | 390 | static int evdev_event_to_user(char __user *buffer, |
388 | const struct input_event *event) | 391 | const struct input_event *event) |
389 | { | 392 | { |
390 | if (copy_to_user(buffer, event, sizeof(struct input_event))) | 393 | if (copy_to_user(buffer, event, sizeof(struct input_event))) |
391 | return -EFAULT; | 394 | return -EFAULT; |
392 | 395 | ||
393 | return 0; | 396 | return 0; |
394 | } | 397 | } |
395 | 398 | ||
396 | #endif /* CONFIG_COMPAT */ | 399 | #endif /* CONFIG_COMPAT */ |
397 | 400 | ||
398 | static ssize_t evdev_write(struct file *file, const char __user *buffer, | 401 | static ssize_t evdev_write(struct file *file, const char __user *buffer, |
399 | size_t count, loff_t *ppos) | 402 | size_t count, loff_t *ppos) |
400 | { | 403 | { |
401 | struct evdev_client *client = file->private_data; | 404 | struct evdev_client *client = file->private_data; |
402 | struct evdev *evdev = client->evdev; | 405 | struct evdev *evdev = client->evdev; |
403 | struct input_event event; | 406 | struct input_event event; |
404 | int retval; | 407 | int retval; |
405 | 408 | ||
406 | retval = mutex_lock_interruptible(&evdev->mutex); | 409 | retval = mutex_lock_interruptible(&evdev->mutex); |
407 | if (retval) | 410 | if (retval) |
408 | return retval; | 411 | return retval; |
409 | 412 | ||
410 | if (!evdev->exist) { | 413 | if (!evdev->exist) { |
411 | retval = -ENODEV; | 414 | retval = -ENODEV; |
412 | goto out; | 415 | goto out; |
413 | } | 416 | } |
414 | 417 | ||
415 | while (retval < count) { | 418 | while (retval < count) { |
416 | 419 | ||
417 | if (evdev_event_from_user(buffer + retval, &event)) { | 420 | if (evdev_event_from_user(buffer + retval, &event)) { |
418 | retval = -EFAULT; | 421 | retval = -EFAULT; |
419 | goto out; | 422 | goto out; |
420 | } | 423 | } |
421 | 424 | ||
422 | input_inject_event(&evdev->handle, | 425 | input_inject_event(&evdev->handle, |
423 | event.type, event.code, event.value); | 426 | event.type, event.code, event.value); |
424 | retval += evdev_event_size(); | 427 | retval += evdev_event_size(); |
425 | } | 428 | } |
426 | 429 | ||
427 | out: | 430 | out: |
428 | mutex_unlock(&evdev->mutex); | 431 | mutex_unlock(&evdev->mutex); |
429 | return retval; | 432 | return retval; |
430 | } | 433 | } |
431 | 434 | ||
432 | static int evdev_fetch_next_event(struct evdev_client *client, | 435 | static int evdev_fetch_next_event(struct evdev_client *client, |
433 | struct input_event *event) | 436 | struct input_event *event) |
434 | { | 437 | { |
435 | int have_event; | 438 | int have_event; |
436 | 439 | ||
437 | spin_lock_irq(&client->buffer_lock); | 440 | spin_lock_irq(&client->buffer_lock); |
438 | 441 | ||
439 | have_event = client->head != client->tail; | 442 | have_event = client->head != client->tail; |
440 | if (have_event) { | 443 | if (have_event) { |
441 | *event = client->buffer[client->tail++]; | 444 | *event = client->buffer[client->tail++]; |
442 | client->tail &= EVDEV_BUFFER_SIZE - 1; | 445 | client->tail &= EVDEV_BUFFER_SIZE - 1; |
443 | } | 446 | } |
444 | 447 | ||
445 | spin_unlock_irq(&client->buffer_lock); | 448 | spin_unlock_irq(&client->buffer_lock); |
446 | 449 | ||
447 | return have_event; | 450 | return have_event; |
448 | } | 451 | } |
449 | 452 | ||
450 | static ssize_t evdev_read(struct file *file, char __user *buffer, | 453 | static ssize_t evdev_read(struct file *file, char __user *buffer, |
451 | size_t count, loff_t *ppos) | 454 | size_t count, loff_t *ppos) |
452 | { | 455 | { |
453 | struct evdev_client *client = file->private_data; | 456 | struct evdev_client *client = file->private_data; |
454 | struct evdev *evdev = client->evdev; | 457 | struct evdev *evdev = client->evdev; |
455 | struct input_event event; | 458 | struct input_event event; |
456 | int retval; | 459 | int retval; |
457 | 460 | ||
458 | if (count < evdev_event_size()) | 461 | if (count < evdev_event_size()) |
459 | return -EINVAL; | 462 | return -EINVAL; |
460 | 463 | ||
461 | if (client->head == client->tail && evdev->exist && | 464 | if (client->head == client->tail && evdev->exist && |
462 | (file->f_flags & O_NONBLOCK)) | 465 | (file->f_flags & O_NONBLOCK)) |
463 | return -EAGAIN; | 466 | return -EAGAIN; |
464 | 467 | ||
465 | retval = wait_event_interruptible(evdev->wait, | 468 | retval = wait_event_interruptible(evdev->wait, |
466 | client->head != client->tail || !evdev->exist); | 469 | client->head != client->tail || !evdev->exist); |
467 | if (retval) | 470 | if (retval) |
468 | return retval; | 471 | return retval; |
469 | 472 | ||
470 | if (!evdev->exist) | 473 | if (!evdev->exist) |
471 | return -ENODEV; | 474 | return -ENODEV; |
472 | 475 | ||
473 | while (retval + evdev_event_size() <= count && | 476 | while (retval + evdev_event_size() <= count && |
474 | evdev_fetch_next_event(client, &event)) { | 477 | evdev_fetch_next_event(client, &event)) { |
475 | 478 | ||
476 | if (evdev_event_to_user(buffer + retval, &event)) | 479 | if (evdev_event_to_user(buffer + retval, &event)) |
477 | return -EFAULT; | 480 | return -EFAULT; |
478 | 481 | ||
479 | retval += evdev_event_size(); | 482 | retval += evdev_event_size(); |
480 | } | 483 | } |
481 | 484 | ||
482 | return retval; | 485 | return retval; |
483 | } | 486 | } |
484 | 487 | ||
485 | /* No kernel lock - fine */ | 488 | /* No kernel lock - fine */ |
486 | static unsigned int evdev_poll(struct file *file, poll_table *wait) | 489 | static unsigned int evdev_poll(struct file *file, poll_table *wait) |
487 | { | 490 | { |
488 | struct evdev_client *client = file->private_data; | 491 | struct evdev_client *client = file->private_data; |
489 | struct evdev *evdev = client->evdev; | 492 | struct evdev *evdev = client->evdev; |
490 | 493 | ||
491 | poll_wait(file, &evdev->wait, wait); | 494 | poll_wait(file, &evdev->wait, wait); |
492 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 495 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | |
493 | (evdev->exist ? 0 : (POLLHUP | POLLERR)); | 496 | (evdev->exist ? 0 : (POLLHUP | POLLERR)); |
494 | } | 497 | } |
495 | 498 | ||
496 | #ifdef CONFIG_COMPAT | 499 | #ifdef CONFIG_COMPAT |
497 | 500 | ||
498 | #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) | 501 | #define BITS_PER_LONG_COMPAT (sizeof(compat_long_t) * 8) |
499 | #define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) | 502 | #define NBITS_COMPAT(x) ((((x) - 1) / BITS_PER_LONG_COMPAT) + 1) |
500 | 503 | ||
501 | #ifdef __BIG_ENDIAN | 504 | #ifdef __BIG_ENDIAN |
502 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, | 505 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, |
503 | unsigned int maxlen, void __user *p, int compat) | 506 | unsigned int maxlen, void __user *p, int compat) |
504 | { | 507 | { |
505 | int len, i; | 508 | int len, i; |
506 | 509 | ||
507 | if (compat) { | 510 | if (compat) { |
508 | len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); | 511 | len = NBITS_COMPAT(maxbit) * sizeof(compat_long_t); |
509 | if (len > maxlen) | 512 | if (len > maxlen) |
510 | len = maxlen; | 513 | len = maxlen; |
511 | 514 | ||
512 | for (i = 0; i < len / sizeof(compat_long_t); i++) | 515 | for (i = 0; i < len / sizeof(compat_long_t); i++) |
513 | if (copy_to_user((compat_long_t __user *) p + i, | 516 | if (copy_to_user((compat_long_t __user *) p + i, |
514 | (compat_long_t *) bits + | 517 | (compat_long_t *) bits + |
515 | i + 1 - ((i % 2) << 1), | 518 | i + 1 - ((i % 2) << 1), |
516 | sizeof(compat_long_t))) | 519 | sizeof(compat_long_t))) |
517 | return -EFAULT; | 520 | return -EFAULT; |
518 | } else { | 521 | } else { |
519 | len = NBITS(maxbit) * sizeof(long); | 522 | len = NBITS(maxbit) * sizeof(long); |
520 | if (len > maxlen) | 523 | if (len > maxlen) |
521 | len = maxlen; | 524 | len = maxlen; |
522 | 525 | ||
523 | if (copy_to_user(p, bits, len)) | 526 | if (copy_to_user(p, bits, len)) |
524 | return -EFAULT; | 527 | return -EFAULT; |
525 | } | 528 | } |
526 | 529 | ||
527 | return len; | 530 | return len; |
528 | } | 531 | } |
529 | #else | 532 | #else |
530 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, | 533 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, |
531 | unsigned int maxlen, void __user *p, int compat) | 534 | unsigned int maxlen, void __user *p, int compat) |
532 | { | 535 | { |
533 | int len = compat ? | 536 | int len = compat ? |
534 | NBITS_COMPAT(maxbit) * sizeof(compat_long_t) : | 537 | NBITS_COMPAT(maxbit) * sizeof(compat_long_t) : |
535 | NBITS(maxbit) * sizeof(long); | 538 | NBITS(maxbit) * sizeof(long); |
536 | 539 | ||
537 | if (len > maxlen) | 540 | if (len > maxlen) |
538 | len = maxlen; | 541 | len = maxlen; |
539 | 542 | ||
540 | return copy_to_user(p, bits, len) ? -EFAULT : len; | 543 | return copy_to_user(p, bits, len) ? -EFAULT : len; |
541 | } | 544 | } |
542 | #endif /* __BIG_ENDIAN */ | 545 | #endif /* __BIG_ENDIAN */ |
543 | 546 | ||
544 | #else | 547 | #else |
545 | 548 | ||
546 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, | 549 | static int bits_to_user(unsigned long *bits, unsigned int maxbit, |
547 | unsigned int maxlen, void __user *p, int compat) | 550 | unsigned int maxlen, void __user *p, int compat) |
548 | { | 551 | { |
549 | int len = NBITS(maxbit) * sizeof(long); | 552 | int len = NBITS(maxbit) * sizeof(long); |
550 | 553 | ||
551 | if (len > maxlen) | 554 | if (len > maxlen) |
552 | len = maxlen; | 555 | len = maxlen; |
553 | 556 | ||
554 | return copy_to_user(p, bits, len) ? -EFAULT : len; | 557 | return copy_to_user(p, bits, len) ? -EFAULT : len; |
555 | } | 558 | } |
556 | 559 | ||
557 | #endif /* CONFIG_COMPAT */ | 560 | #endif /* CONFIG_COMPAT */ |
558 | 561 | ||
559 | static int str_to_user(const char *str, unsigned int maxlen, void __user *p) | 562 | static int str_to_user(const char *str, unsigned int maxlen, void __user *p) |
560 | { | 563 | { |
561 | int len; | 564 | int len; |
562 | 565 | ||
563 | if (!str) | 566 | if (!str) |
564 | return -ENOENT; | 567 | return -ENOENT; |
565 | 568 | ||
566 | len = strlen(str) + 1; | 569 | len = strlen(str) + 1; |
567 | if (len > maxlen) | 570 | if (len > maxlen) |
568 | len = maxlen; | 571 | len = maxlen; |
569 | 572 | ||
570 | return copy_to_user(p, str, len) ? -EFAULT : len; | 573 | return copy_to_user(p, str, len) ? -EFAULT : len; |
571 | } | 574 | } |
572 | 575 | ||
573 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, | 576 | static long evdev_do_ioctl(struct file *file, unsigned int cmd, |
574 | void __user *p, int compat_mode) | 577 | void __user *p, int compat_mode) |
575 | { | 578 | { |
576 | struct evdev_client *client = file->private_data; | 579 | struct evdev_client *client = file->private_data; |
577 | struct evdev *evdev = client->evdev; | 580 | struct evdev *evdev = client->evdev; |
578 | struct input_dev *dev = evdev->handle.dev; | 581 | struct input_dev *dev = evdev->handle.dev; |
579 | struct input_absinfo abs; | 582 | struct input_absinfo abs; |
580 | struct ff_effect effect; | 583 | struct ff_effect effect; |
581 | int __user *ip = (int __user *)p; | 584 | int __user *ip = (int __user *)p; |
582 | int i, t, u, v; | 585 | int i, t, u, v; |
583 | int error; | 586 | int error; |
584 | 587 | ||
585 | switch (cmd) { | 588 | switch (cmd) { |
586 | 589 | ||
587 | case EVIOCGVERSION: | 590 | case EVIOCGVERSION: |
588 | return put_user(EV_VERSION, ip); | 591 | return put_user(EV_VERSION, ip); |
589 | 592 | ||
590 | case EVIOCGID: | 593 | case EVIOCGID: |
591 | if (copy_to_user(p, &dev->id, sizeof(struct input_id))) | 594 | if (copy_to_user(p, &dev->id, sizeof(struct input_id))) |
592 | return -EFAULT; | 595 | return -EFAULT; |
593 | return 0; | 596 | return 0; |
594 | 597 | ||
595 | case EVIOCGREP: | 598 | case EVIOCGREP: |
596 | if (!test_bit(EV_REP, dev->evbit)) | 599 | if (!test_bit(EV_REP, dev->evbit)) |
597 | return -ENOSYS; | 600 | return -ENOSYS; |
598 | if (put_user(dev->rep[REP_DELAY], ip)) | 601 | if (put_user(dev->rep[REP_DELAY], ip)) |
599 | return -EFAULT; | 602 | return -EFAULT; |
600 | if (put_user(dev->rep[REP_PERIOD], ip + 1)) | 603 | if (put_user(dev->rep[REP_PERIOD], ip + 1)) |
601 | return -EFAULT; | 604 | return -EFAULT; |
602 | return 0; | 605 | return 0; |
603 | 606 | ||
604 | case EVIOCSREP: | 607 | case EVIOCSREP: |
605 | if (!test_bit(EV_REP, dev->evbit)) | 608 | if (!test_bit(EV_REP, dev->evbit)) |
606 | return -ENOSYS; | 609 | return -ENOSYS; |
607 | if (get_user(u, ip)) | 610 | if (get_user(u, ip)) |
608 | return -EFAULT; | 611 | return -EFAULT; |
609 | if (get_user(v, ip + 1)) | 612 | if (get_user(v, ip + 1)) |
610 | return -EFAULT; | 613 | return -EFAULT; |
611 | 614 | ||
612 | input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); | 615 | input_inject_event(&evdev->handle, EV_REP, REP_DELAY, u); |
613 | input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); | 616 | input_inject_event(&evdev->handle, EV_REP, REP_PERIOD, v); |
614 | 617 | ||
615 | return 0; | 618 | return 0; |
616 | 619 | ||
617 | case EVIOCGKEYCODE: | 620 | case EVIOCGKEYCODE: |
618 | if (get_user(t, ip)) | 621 | if (get_user(t, ip)) |
619 | return -EFAULT; | 622 | return -EFAULT; |
620 | 623 | ||
621 | error = dev->getkeycode(dev, t, &v); | 624 | error = dev->getkeycode(dev, t, &v); |
622 | if (error) | 625 | if (error) |
623 | return error; | 626 | return error; |
624 | 627 | ||
625 | if (put_user(v, ip + 1)) | 628 | if (put_user(v, ip + 1)) |
626 | return -EFAULT; | 629 | return -EFAULT; |
627 | 630 | ||
628 | return 0; | 631 | return 0; |
629 | 632 | ||
630 | case EVIOCSKEYCODE: | 633 | case EVIOCSKEYCODE: |
631 | if (get_user(t, ip) || get_user(v, ip + 1)) | 634 | if (get_user(t, ip) || get_user(v, ip + 1)) |
632 | return -EFAULT; | 635 | return -EFAULT; |
633 | 636 | ||
634 | return dev->setkeycode(dev, t, v); | 637 | return dev->setkeycode(dev, t, v); |
635 | 638 | ||
636 | case EVIOCSFF: | 639 | case EVIOCSFF: |
637 | if (copy_from_user(&effect, p, sizeof(effect))) | 640 | if (copy_from_user(&effect, p, sizeof(effect))) |
638 | return -EFAULT; | 641 | return -EFAULT; |
639 | 642 | ||
640 | error = input_ff_upload(dev, &effect, file); | 643 | error = input_ff_upload(dev, &effect, file); |
641 | 644 | ||
642 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) | 645 | if (put_user(effect.id, &(((struct ff_effect __user *)p)->id))) |
643 | return -EFAULT; | 646 | return -EFAULT; |
644 | 647 | ||
645 | return error; | 648 | return error; |
646 | 649 | ||
647 | case EVIOCRMFF: | 650 | case EVIOCRMFF: |
648 | return input_ff_erase(dev, (int)(unsigned long) p, file); | 651 | return input_ff_erase(dev, (int)(unsigned long) p, file); |
649 | 652 | ||
650 | case EVIOCGEFFECTS: | 653 | case EVIOCGEFFECTS: |
651 | i = test_bit(EV_FF, dev->evbit) ? | 654 | i = test_bit(EV_FF, dev->evbit) ? |
652 | dev->ff->max_effects : 0; | 655 | dev->ff->max_effects : 0; |
653 | if (put_user(i, ip)) | 656 | if (put_user(i, ip)) |
654 | return -EFAULT; | 657 | return -EFAULT; |
655 | return 0; | 658 | return 0; |
656 | 659 | ||
657 | case EVIOCGRAB: | 660 | case EVIOCGRAB: |
658 | if (p) | 661 | if (p) |
659 | return evdev_grab(evdev, client); | 662 | return evdev_grab(evdev, client); |
660 | else | 663 | else |
661 | return evdev_ungrab(evdev, client); | 664 | return evdev_ungrab(evdev, client); |
662 | 665 | ||
663 | default: | 666 | default: |
664 | 667 | ||
665 | if (_IOC_TYPE(cmd) != 'E') | 668 | if (_IOC_TYPE(cmd) != 'E') |
666 | return -EINVAL; | 669 | return -EINVAL; |
667 | 670 | ||
668 | if (_IOC_DIR(cmd) == _IOC_READ) { | 671 | if (_IOC_DIR(cmd) == _IOC_READ) { |
669 | 672 | ||
670 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { | 673 | if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { |
671 | 674 | ||
672 | unsigned long *bits; | 675 | unsigned long *bits; |
673 | int len; | 676 | int len; |
674 | 677 | ||
675 | switch (_IOC_NR(cmd) & EV_MAX) { | 678 | switch (_IOC_NR(cmd) & EV_MAX) { |
676 | 679 | ||
677 | case 0: bits = dev->evbit; len = EV_MAX; break; | 680 | case 0: bits = dev->evbit; len = EV_MAX; break; |
678 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; | 681 | case EV_KEY: bits = dev->keybit; len = KEY_MAX; break; |
679 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; | 682 | case EV_REL: bits = dev->relbit; len = REL_MAX; break; |
680 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; | 683 | case EV_ABS: bits = dev->absbit; len = ABS_MAX; break; |
681 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; | 684 | case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break; |
682 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; | 685 | case EV_LED: bits = dev->ledbit; len = LED_MAX; break; |
683 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; | 686 | case EV_SND: bits = dev->sndbit; len = SND_MAX; break; |
684 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; | 687 | case EV_FF: bits = dev->ffbit; len = FF_MAX; break; |
685 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; | 688 | case EV_SW: bits = dev->swbit; len = SW_MAX; break; |
686 | default: return -EINVAL; | 689 | default: return -EINVAL; |
687 | } | 690 | } |
688 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); | 691 | return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode); |
689 | } | 692 | } |
690 | 693 | ||
691 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) | 694 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) |
692 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), | 695 | return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), |
693 | p, compat_mode); | 696 | p, compat_mode); |
694 | 697 | ||
695 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) | 698 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) |
696 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), | 699 | return bits_to_user(dev->led, LED_MAX, _IOC_SIZE(cmd), |
697 | p, compat_mode); | 700 | p, compat_mode); |
698 | 701 | ||
699 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) | 702 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) |
700 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), | 703 | return bits_to_user(dev->snd, SND_MAX, _IOC_SIZE(cmd), |
701 | p, compat_mode); | 704 | p, compat_mode); |
702 | 705 | ||
703 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) | 706 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSW(0))) |
704 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), | 707 | return bits_to_user(dev->sw, SW_MAX, _IOC_SIZE(cmd), |
705 | p, compat_mode); | 708 | p, compat_mode); |
706 | 709 | ||
707 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) | 710 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) |
708 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); | 711 | return str_to_user(dev->name, _IOC_SIZE(cmd), p); |
709 | 712 | ||
710 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) | 713 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) |
711 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); | 714 | return str_to_user(dev->phys, _IOC_SIZE(cmd), p); |
712 | 715 | ||
713 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) | 716 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) |
714 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); | 717 | return str_to_user(dev->uniq, _IOC_SIZE(cmd), p); |
715 | 718 | ||
716 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | 719 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { |
717 | 720 | ||
718 | t = _IOC_NR(cmd) & ABS_MAX; | 721 | t = _IOC_NR(cmd) & ABS_MAX; |
719 | 722 | ||
720 | abs.value = dev->abs[t]; | 723 | abs.value = dev->abs[t]; |
721 | abs.minimum = dev->absmin[t]; | 724 | abs.minimum = dev->absmin[t]; |
722 | abs.maximum = dev->absmax[t]; | 725 | abs.maximum = dev->absmax[t]; |
723 | abs.fuzz = dev->absfuzz[t]; | 726 | abs.fuzz = dev->absfuzz[t]; |
724 | abs.flat = dev->absflat[t]; | 727 | abs.flat = dev->absflat[t]; |
725 | 728 | ||
726 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) | 729 | if (copy_to_user(p, &abs, sizeof(struct input_absinfo))) |
727 | return -EFAULT; | 730 | return -EFAULT; |
728 | 731 | ||
729 | return 0; | 732 | return 0; |
730 | } | 733 | } |
731 | 734 | ||
732 | } | 735 | } |
733 | 736 | ||
734 | if (_IOC_DIR(cmd) == _IOC_WRITE) { | 737 | if (_IOC_DIR(cmd) == _IOC_WRITE) { |
735 | 738 | ||
736 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { | 739 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCSABS(0))) { |
737 | 740 | ||
738 | t = _IOC_NR(cmd) & ABS_MAX; | 741 | t = _IOC_NR(cmd) & ABS_MAX; |
739 | 742 | ||
740 | if (copy_from_user(&abs, p, | 743 | if (copy_from_user(&abs, p, |
741 | sizeof(struct input_absinfo))) | 744 | sizeof(struct input_absinfo))) |
742 | return -EFAULT; | 745 | return -EFAULT; |
743 | 746 | ||
744 | /* | 747 | /* |
745 | * Take event lock to ensure that we are not | 748 | * Take event lock to ensure that we are not |
746 | * changing device parameters in the middle | 749 | * changing device parameters in the middle |
747 | * of event. | 750 | * of event. |
748 | */ | 751 | */ |
749 | spin_lock_irq(&dev->event_lock); | 752 | spin_lock_irq(&dev->event_lock); |
750 | 753 | ||
751 | dev->abs[t] = abs.value; | 754 | dev->abs[t] = abs.value; |
752 | dev->absmin[t] = abs.minimum; | 755 | dev->absmin[t] = abs.minimum; |
753 | dev->absmax[t] = abs.maximum; | 756 | dev->absmax[t] = abs.maximum; |
754 | dev->absfuzz[t] = abs.fuzz; | 757 | dev->absfuzz[t] = abs.fuzz; |
755 | dev->absflat[t] = abs.flat; | 758 | dev->absflat[t] = abs.flat; |
756 | 759 | ||
757 | spin_unlock_irq(&dev->event_lock); | 760 | spin_unlock_irq(&dev->event_lock); |
758 | 761 | ||
759 | return 0; | 762 | return 0; |
760 | } | 763 | } |
761 | } | 764 | } |
762 | } | 765 | } |
763 | return -EINVAL; | 766 | return -EINVAL; |
764 | } | 767 | } |
765 | 768 | ||
766 | static long evdev_ioctl_handler(struct file *file, unsigned int cmd, | 769 | static long evdev_ioctl_handler(struct file *file, unsigned int cmd, |
767 | void __user *p, int compat_mode) | 770 | void __user *p, int compat_mode) |
768 | { | 771 | { |
769 | struct evdev_client *client = file->private_data; | 772 | struct evdev_client *client = file->private_data; |
770 | struct evdev *evdev = client->evdev; | 773 | struct evdev *evdev = client->evdev; |
771 | int retval; | 774 | int retval; |
772 | 775 | ||
773 | retval = mutex_lock_interruptible(&evdev->mutex); | 776 | retval = mutex_lock_interruptible(&evdev->mutex); |
774 | if (retval) | 777 | if (retval) |
775 | return retval; | 778 | return retval; |
776 | 779 | ||
777 | if (!evdev->exist) { | 780 | if (!evdev->exist) { |
778 | retval = -ENODEV; | 781 | retval = -ENODEV; |
779 | goto out; | 782 | goto out; |
780 | } | 783 | } |
781 | 784 | ||
782 | retval = evdev_do_ioctl(file, cmd, p, compat_mode); | 785 | retval = evdev_do_ioctl(file, cmd, p, compat_mode); |
783 | 786 | ||
784 | out: | 787 | out: |
785 | mutex_unlock(&evdev->mutex); | 788 | mutex_unlock(&evdev->mutex); |
786 | return retval; | 789 | return retval; |
787 | } | 790 | } |
788 | 791 | ||
789 | static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 792 | static long evdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
790 | { | 793 | { |
791 | return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); | 794 | return evdev_ioctl_handler(file, cmd, (void __user *)arg, 0); |
792 | } | 795 | } |
793 | 796 | ||
794 | #ifdef CONFIG_COMPAT | 797 | #ifdef CONFIG_COMPAT |
795 | static long evdev_ioctl_compat(struct file *file, | 798 | static long evdev_ioctl_compat(struct file *file, |
796 | unsigned int cmd, unsigned long arg) | 799 | unsigned int cmd, unsigned long arg) |
797 | { | 800 | { |
798 | return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); | 801 | return evdev_ioctl_handler(file, cmd, compat_ptr(arg), 1); |
799 | } | 802 | } |
800 | #endif | 803 | #endif |
801 | 804 | ||
802 | static const struct file_operations evdev_fops = { | 805 | static const struct file_operations evdev_fops = { |
803 | .owner = THIS_MODULE, | 806 | .owner = THIS_MODULE, |
804 | .read = evdev_read, | 807 | .read = evdev_read, |
805 | .write = evdev_write, | 808 | .write = evdev_write, |
806 | .poll = evdev_poll, | 809 | .poll = evdev_poll, |
807 | .open = evdev_open, | 810 | .open = evdev_open, |
808 | .release = evdev_release, | 811 | .release = evdev_release, |
809 | .unlocked_ioctl = evdev_ioctl, | 812 | .unlocked_ioctl = evdev_ioctl, |
810 | #ifdef CONFIG_COMPAT | 813 | #ifdef CONFIG_COMPAT |
811 | .compat_ioctl = evdev_ioctl_compat, | 814 | .compat_ioctl = evdev_ioctl_compat, |
812 | #endif | 815 | #endif |
813 | .fasync = evdev_fasync, | 816 | .fasync = evdev_fasync, |
814 | .flush = evdev_flush | 817 | .flush = evdev_flush |
815 | }; | 818 | }; |
816 | 819 | ||
817 | static int evdev_install_chrdev(struct evdev *evdev) | 820 | static int evdev_install_chrdev(struct evdev *evdev) |
818 | { | 821 | { |
819 | /* | 822 | /* |
820 | * No need to do any locking here as calls to connect and | 823 | * No need to do any locking here as calls to connect and |
821 | * disconnect are serialized by the input core | 824 | * disconnect are serialized by the input core |
822 | */ | 825 | */ |
823 | evdev_table[evdev->minor] = evdev; | 826 | evdev_table[evdev->minor] = evdev; |
824 | return 0; | 827 | return 0; |
825 | } | 828 | } |
826 | 829 | ||
827 | static void evdev_remove_chrdev(struct evdev *evdev) | 830 | static void evdev_remove_chrdev(struct evdev *evdev) |
828 | { | 831 | { |
829 | /* | 832 | /* |
830 | * Lock evdev table to prevent race with evdev_open() | 833 | * Lock evdev table to prevent race with evdev_open() |
831 | */ | 834 | */ |
832 | mutex_lock(&evdev_table_mutex); | 835 | mutex_lock(&evdev_table_mutex); |
833 | evdev_table[evdev->minor] = NULL; | 836 | evdev_table[evdev->minor] = NULL; |
834 | mutex_unlock(&evdev_table_mutex); | 837 | mutex_unlock(&evdev_table_mutex); |
835 | } | 838 | } |
836 | 839 | ||
837 | /* | 840 | /* |
838 | * Mark device non-existent. This disables writes, ioctls and | 841 | * Mark device non-existent. This disables writes, ioctls and |
839 | * prevents new users from opening the device. Already posted | 842 | * prevents new users from opening the device. Already posted |
840 | * blocking reads will stay, however new ones will fail. | 843 | * blocking reads will stay, however new ones will fail. |
841 | */ | 844 | */ |
842 | static void evdev_mark_dead(struct evdev *evdev) | 845 | static void evdev_mark_dead(struct evdev *evdev) |
843 | { | 846 | { |
844 | mutex_lock(&evdev->mutex); | 847 | mutex_lock(&evdev->mutex); |
845 | evdev->exist = 0; | 848 | evdev->exist = 0; |
846 | mutex_unlock(&evdev->mutex); | 849 | mutex_unlock(&evdev->mutex); |
847 | } | 850 | } |
848 | 851 | ||
849 | static void evdev_cleanup(struct evdev *evdev) | 852 | static void evdev_cleanup(struct evdev *evdev) |
850 | { | 853 | { |
851 | struct input_handle *handle = &evdev->handle; | 854 | struct input_handle *handle = &evdev->handle; |
852 | 855 | ||
853 | evdev_mark_dead(evdev); | 856 | evdev_mark_dead(evdev); |
854 | evdev_hangup(evdev); | 857 | evdev_hangup(evdev); |
855 | evdev_remove_chrdev(evdev); | 858 | evdev_remove_chrdev(evdev); |
856 | 859 | ||
857 | /* evdev is marked dead so no one else accesses evdev->open */ | 860 | /* evdev is marked dead so no one else accesses evdev->open */ |
858 | if (evdev->open) { | 861 | if (evdev->open) { |
859 | input_flush_device(handle, NULL); | 862 | input_flush_device(handle, NULL); |
860 | input_close_device(handle); | 863 | input_close_device(handle); |
861 | } | 864 | } |
862 | } | 865 | } |
863 | 866 | ||
864 | /* | 867 | /* |
865 | * Create new evdev device. Note that input core serializes calls | 868 | * Create new evdev device. Note that input core serializes calls |
866 | * to connect and disconnect so we don't need to lock evdev_table here. | 869 | * to connect and disconnect so we don't need to lock evdev_table here. |
867 | */ | 870 | */ |
868 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, | 871 | static int evdev_connect(struct input_handler *handler, struct input_dev *dev, |
869 | const struct input_device_id *id) | 872 | const struct input_device_id *id) |
870 | { | 873 | { |
871 | struct evdev *evdev; | 874 | struct evdev *evdev; |
872 | int minor; | 875 | int minor; |
873 | int error; | 876 | int error; |
874 | 877 | ||
875 | for (minor = 0; minor < EVDEV_MINORS; minor++) | 878 | for (minor = 0; minor < EVDEV_MINORS; minor++) |
876 | if (!evdev_table[minor]) | 879 | if (!evdev_table[minor]) |
877 | break; | 880 | break; |
878 | 881 | ||
879 | if (minor == EVDEV_MINORS) { | 882 | if (minor == EVDEV_MINORS) { |
880 | printk(KERN_ERR "evdev: no more free evdev devices\n"); | 883 | printk(KERN_ERR "evdev: no more free evdev devices\n"); |
881 | return -ENFILE; | 884 | return -ENFILE; |
882 | } | 885 | } |
883 | 886 | ||
884 | evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); | 887 | evdev = kzalloc(sizeof(struct evdev), GFP_KERNEL); |
885 | if (!evdev) | 888 | if (!evdev) |
886 | return -ENOMEM; | 889 | return -ENOMEM; |
887 | 890 | ||
888 | INIT_LIST_HEAD(&evdev->client_list); | 891 | INIT_LIST_HEAD(&evdev->client_list); |
889 | spin_lock_init(&evdev->client_lock); | 892 | spin_lock_init(&evdev->client_lock); |
890 | mutex_init(&evdev->mutex); | 893 | mutex_init(&evdev->mutex); |
891 | init_waitqueue_head(&evdev->wait); | 894 | init_waitqueue_head(&evdev->wait); |
892 | 895 | ||
893 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); | 896 | snprintf(evdev->name, sizeof(evdev->name), "event%d", minor); |
894 | evdev->exist = 1; | 897 | evdev->exist = 1; |
895 | evdev->minor = minor; | 898 | evdev->minor = minor; |
896 | 899 | ||
897 | evdev->handle.dev = dev; | 900 | evdev->handle.dev = dev; |
898 | evdev->handle.name = evdev->name; | 901 | evdev->handle.name = evdev->name; |
899 | evdev->handle.handler = handler; | 902 | evdev->handle.handler = handler; |
900 | evdev->handle.private = evdev; | 903 | evdev->handle.private = evdev; |
901 | 904 | ||
902 | strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); | 905 | strlcpy(evdev->dev.bus_id, evdev->name, sizeof(evdev->dev.bus_id)); |
903 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); | 906 | evdev->dev.devt = MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor); |
904 | evdev->dev.class = &input_class; | 907 | evdev->dev.class = &input_class; |
905 | evdev->dev.parent = &dev->dev; | 908 | evdev->dev.parent = &dev->dev; |
906 | evdev->dev.release = evdev_free; | 909 | evdev->dev.release = evdev_free; |
907 | device_initialize(&evdev->dev); | 910 | device_initialize(&evdev->dev); |
908 | 911 | ||
909 | error = input_register_handle(&evdev->handle); | 912 | error = input_register_handle(&evdev->handle); |
910 | if (error) | 913 | if (error) |
911 | goto err_free_evdev; | 914 | goto err_free_evdev; |
912 | 915 | ||
913 | error = evdev_install_chrdev(evdev); | 916 | error = evdev_install_chrdev(evdev); |
914 | if (error) | 917 | if (error) |
915 | goto err_unregister_handle; | 918 | goto err_unregister_handle; |
916 | 919 | ||
917 | error = device_add(&evdev->dev); | 920 | error = device_add(&evdev->dev); |
918 | if (error) | 921 | if (error) |
919 | goto err_cleanup_evdev; | 922 | goto err_cleanup_evdev; |
920 | 923 | ||
921 | return 0; | 924 | return 0; |
922 | 925 | ||
923 | err_cleanup_evdev: | 926 | err_cleanup_evdev: |
924 | evdev_cleanup(evdev); | 927 | evdev_cleanup(evdev); |
925 | err_unregister_handle: | 928 | err_unregister_handle: |
926 | input_unregister_handle(&evdev->handle); | 929 | input_unregister_handle(&evdev->handle); |
927 | err_free_evdev: | 930 | err_free_evdev: |
928 | put_device(&evdev->dev); | 931 | put_device(&evdev->dev); |
929 | return error; | 932 | return error; |
930 | } | 933 | } |
931 | 934 | ||
932 | static void evdev_disconnect(struct input_handle *handle) | 935 | static void evdev_disconnect(struct input_handle *handle) |
933 | { | 936 | { |
934 | struct evdev *evdev = handle->private; | 937 | struct evdev *evdev = handle->private; |
935 | 938 | ||
936 | device_del(&evdev->dev); | 939 | device_del(&evdev->dev); |
937 | evdev_cleanup(evdev); | 940 | evdev_cleanup(evdev); |
938 | input_unregister_handle(handle); | 941 | input_unregister_handle(handle); |
939 | put_device(&evdev->dev); | 942 | put_device(&evdev->dev); |
940 | } | 943 | } |
941 | 944 | ||
942 | static const struct input_device_id evdev_ids[] = { | 945 | static const struct input_device_id evdev_ids[] = { |
943 | { .driver_info = 1 }, /* Matches all devices */ | 946 | { .driver_info = 1 }, /* Matches all devices */ |
944 | { }, /* Terminating zero entry */ | 947 | { }, /* Terminating zero entry */ |
945 | }; | 948 | }; |
946 | 949 | ||
947 | MODULE_DEVICE_TABLE(input, evdev_ids); | 950 | MODULE_DEVICE_TABLE(input, evdev_ids); |
948 | 951 | ||
949 | static struct input_handler evdev_handler = { | 952 | static struct input_handler evdev_handler = { |
950 | .event = evdev_event, | 953 | .event = evdev_event, |
951 | .connect = evdev_connect, | 954 | .connect = evdev_connect, |
952 | .disconnect = evdev_disconnect, | 955 | .disconnect = evdev_disconnect, |
953 | .fops = &evdev_fops, | 956 | .fops = &evdev_fops, |
954 | .minor = EVDEV_MINOR_BASE, | 957 | .minor = EVDEV_MINOR_BASE, |
955 | .name = "evdev", | 958 | .name = "evdev", |
956 | .id_table = evdev_ids, | 959 | .id_table = evdev_ids, |
957 | }; | 960 | }; |
958 | 961 | ||
959 | static int __init evdev_init(void) | 962 | static int __init evdev_init(void) |
960 | { | 963 | { |
961 | return input_register_handler(&evdev_handler); | 964 | return input_register_handler(&evdev_handler); |
962 | } | 965 | } |
963 | 966 | ||
964 | static void __exit evdev_exit(void) | 967 | static void __exit evdev_exit(void) |
965 | { | 968 | { |
966 | input_unregister_handler(&evdev_handler); | 969 | input_unregister_handler(&evdev_handler); |
967 | } | 970 | } |
968 | 971 | ||
969 | module_init(evdev_init); | 972 | module_init(evdev_init); |
970 | module_exit(evdev_exit); | 973 | module_exit(evdev_exit); |
971 | 974 | ||
972 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 975 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
973 | MODULE_DESCRIPTION("Input driver event char devices"); | 976 | MODULE_DESCRIPTION("Input driver event char devices"); |
974 | MODULE_LICENSE("GPL"); | 977 | MODULE_LICENSE("GPL"); |
975 | 978 |
drivers/input/joydev.c
1 | /* | 1 | /* |
2 | * Joystick device driver for the input driver suite. | 2 | * Joystick device driver for the input driver suite. |
3 | * | 3 | * |
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | 4 | * Copyright (c) 1999-2002 Vojtech Pavlik |
5 | * Copyright (c) 1999 Colin Van Dyke | 5 | * Copyright (c) 1999 Colin Van Dyke |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or | 9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. | 10 | * (at your option) any later version. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <asm/io.h> | 13 | #include <asm/io.h> |
14 | #include <asm/system.h> | 14 | #include <asm/system.h> |
15 | #include <linux/delay.h> | 15 | #include <linux/delay.h> |
16 | #include <linux/errno.h> | 16 | #include <linux/errno.h> |
17 | #include <linux/joystick.h> | 17 | #include <linux/joystick.h> |
18 | #include <linux/input.h> | 18 | #include <linux/input.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/major.h> | 20 | #include <linux/major.h> |
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <linux/mm.h> | 22 | #include <linux/mm.h> |
23 | #include <linux/miscdevice.h> | 23 | #include <linux/miscdevice.h> |
24 | #include <linux/module.h> | 24 | #include <linux/module.h> |
25 | #include <linux/poll.h> | 25 | #include <linux/poll.h> |
26 | #include <linux/init.h> | 26 | #include <linux/init.h> |
27 | #include <linux/device.h> | 27 | #include <linux/device.h> |
28 | 28 | ||
29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
30 | MODULE_DESCRIPTION("Joystick device interfaces"); | 30 | MODULE_DESCRIPTION("Joystick device interfaces"); |
31 | MODULE_SUPPORTED_DEVICE("input/js"); | 31 | MODULE_SUPPORTED_DEVICE("input/js"); |
32 | MODULE_LICENSE("GPL"); | 32 | MODULE_LICENSE("GPL"); |
33 | 33 | ||
34 | #define JOYDEV_MINOR_BASE 0 | 34 | #define JOYDEV_MINOR_BASE 0 |
35 | #define JOYDEV_MINORS 16 | 35 | #define JOYDEV_MINORS 16 |
36 | #define JOYDEV_BUFFER_SIZE 64 | 36 | #define JOYDEV_BUFFER_SIZE 64 |
37 | 37 | ||
38 | struct joydev { | 38 | struct joydev { |
39 | int exist; | 39 | int exist; |
40 | int open; | 40 | int open; |
41 | int minor; | 41 | int minor; |
42 | char name[16]; | 42 | char name[16]; |
43 | struct input_handle handle; | 43 | struct input_handle handle; |
44 | wait_queue_head_t wait; | 44 | wait_queue_head_t wait; |
45 | struct list_head client_list; | 45 | struct list_head client_list; |
46 | spinlock_t client_lock; /* protects client_list */ | 46 | spinlock_t client_lock; /* protects client_list */ |
47 | struct mutex mutex; | 47 | struct mutex mutex; |
48 | struct device dev; | 48 | struct device dev; |
49 | 49 | ||
50 | struct js_corr corr[ABS_MAX + 1]; | 50 | struct js_corr corr[ABS_MAX + 1]; |
51 | struct JS_DATA_SAVE_TYPE glue; | 51 | struct JS_DATA_SAVE_TYPE glue; |
52 | int nabs; | 52 | int nabs; |
53 | int nkey; | 53 | int nkey; |
54 | __u16 keymap[KEY_MAX - BTN_MISC + 1]; | 54 | __u16 keymap[KEY_MAX - BTN_MISC + 1]; |
55 | __u16 keypam[KEY_MAX - BTN_MISC + 1]; | 55 | __u16 keypam[KEY_MAX - BTN_MISC + 1]; |
56 | __u8 absmap[ABS_MAX + 1]; | 56 | __u8 absmap[ABS_MAX + 1]; |
57 | __u8 abspam[ABS_MAX + 1]; | 57 | __u8 abspam[ABS_MAX + 1]; |
58 | __s16 abs[ABS_MAX + 1]; | 58 | __s16 abs[ABS_MAX + 1]; |
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct joydev_client { | 61 | struct joydev_client { |
62 | struct js_event buffer[JOYDEV_BUFFER_SIZE]; | 62 | struct js_event buffer[JOYDEV_BUFFER_SIZE]; |
63 | int head; | 63 | int head; |
64 | int tail; | 64 | int tail; |
65 | int startup; | 65 | int startup; |
66 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | 66 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
67 | struct fasync_struct *fasync; | 67 | struct fasync_struct *fasync; |
68 | struct joydev *joydev; | 68 | struct joydev *joydev; |
69 | struct list_head node; | 69 | struct list_head node; |
70 | }; | 70 | }; |
71 | 71 | ||
72 | static struct joydev *joydev_table[JOYDEV_MINORS]; | 72 | static struct joydev *joydev_table[JOYDEV_MINORS]; |
73 | static DEFINE_MUTEX(joydev_table_mutex); | 73 | static DEFINE_MUTEX(joydev_table_mutex); |
74 | 74 | ||
75 | static int joydev_correct(int value, struct js_corr *corr) | 75 | static int joydev_correct(int value, struct js_corr *corr) |
76 | { | 76 | { |
77 | switch (corr->type) { | 77 | switch (corr->type) { |
78 | 78 | ||
79 | case JS_CORR_NONE: | 79 | case JS_CORR_NONE: |
80 | break; | 80 | break; |
81 | 81 | ||
82 | case JS_CORR_BROKEN: | 82 | case JS_CORR_BROKEN: |
83 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : | 83 | value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 : |
84 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : | 84 | ((corr->coef[3] * (value - corr->coef[1])) >> 14)) : |
85 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); | 85 | ((corr->coef[2] * (value - corr->coef[0])) >> 14); |
86 | break; | 86 | break; |
87 | 87 | ||
88 | default: | 88 | default: |
89 | return 0; | 89 | return 0; |
90 | } | 90 | } |
91 | 91 | ||
92 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); | 92 | return value < -32767 ? -32767 : (value > 32767 ? 32767 : value); |
93 | } | 93 | } |
94 | 94 | ||
95 | static void joydev_pass_event(struct joydev_client *client, | 95 | static void joydev_pass_event(struct joydev_client *client, |
96 | struct js_event *event) | 96 | struct js_event *event) |
97 | { | 97 | { |
98 | struct joydev *joydev = client->joydev; | 98 | struct joydev *joydev = client->joydev; |
99 | 99 | ||
100 | /* | 100 | /* |
101 | * IRQs already disabled, just acquire the lock | 101 | * IRQs already disabled, just acquire the lock |
102 | */ | 102 | */ |
103 | spin_lock(&client->buffer_lock); | 103 | spin_lock(&client->buffer_lock); |
104 | 104 | ||
105 | client->buffer[client->head] = *event; | 105 | client->buffer[client->head] = *event; |
106 | 106 | ||
107 | if (client->startup == joydev->nabs + joydev->nkey) { | 107 | if (client->startup == joydev->nabs + joydev->nkey) { |
108 | client->head++; | 108 | client->head++; |
109 | client->head &= JOYDEV_BUFFER_SIZE - 1; | 109 | client->head &= JOYDEV_BUFFER_SIZE - 1; |
110 | if (client->tail == client->head) | 110 | if (client->tail == client->head) |
111 | client->startup = 0; | 111 | client->startup = 0; |
112 | } | 112 | } |
113 | 113 | ||
114 | spin_unlock(&client->buffer_lock); | 114 | spin_unlock(&client->buffer_lock); |
115 | 115 | ||
116 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 116 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
117 | } | 117 | } |
118 | 118 | ||
119 | static void joydev_event(struct input_handle *handle, | 119 | static void joydev_event(struct input_handle *handle, |
120 | unsigned int type, unsigned int code, int value) | 120 | unsigned int type, unsigned int code, int value) |
121 | { | 121 | { |
122 | struct joydev *joydev = handle->private; | 122 | struct joydev *joydev = handle->private; |
123 | struct joydev_client *client; | 123 | struct joydev_client *client; |
124 | struct js_event event; | 124 | struct js_event event; |
125 | 125 | ||
126 | switch (type) { | 126 | switch (type) { |
127 | 127 | ||
128 | case EV_KEY: | 128 | case EV_KEY: |
129 | if (code < BTN_MISC || value == 2) | 129 | if (code < BTN_MISC || value == 2) |
130 | return; | 130 | return; |
131 | event.type = JS_EVENT_BUTTON; | 131 | event.type = JS_EVENT_BUTTON; |
132 | event.number = joydev->keymap[code - BTN_MISC]; | 132 | event.number = joydev->keymap[code - BTN_MISC]; |
133 | event.value = value; | 133 | event.value = value; |
134 | break; | 134 | break; |
135 | 135 | ||
136 | case EV_ABS: | 136 | case EV_ABS: |
137 | event.type = JS_EVENT_AXIS; | 137 | event.type = JS_EVENT_AXIS; |
138 | event.number = joydev->absmap[code]; | 138 | event.number = joydev->absmap[code]; |
139 | event.value = joydev_correct(value, | 139 | event.value = joydev_correct(value, |
140 | &joydev->corr[event.number]); | 140 | &joydev->corr[event.number]); |
141 | if (event.value == joydev->abs[event.number]) | 141 | if (event.value == joydev->abs[event.number]) |
142 | return; | 142 | return; |
143 | joydev->abs[event.number] = event.value; | 143 | joydev->abs[event.number] = event.value; |
144 | break; | 144 | break; |
145 | 145 | ||
146 | default: | 146 | default: |
147 | return; | 147 | return; |
148 | } | 148 | } |
149 | 149 | ||
150 | event.time = jiffies_to_msecs(jiffies); | 150 | event.time = jiffies_to_msecs(jiffies); |
151 | 151 | ||
152 | list_for_each_entry_rcu(client, &joydev->client_list, node) | 152 | list_for_each_entry_rcu(client, &joydev->client_list, node) |
153 | joydev_pass_event(client, &event); | 153 | joydev_pass_event(client, &event); |
154 | 154 | ||
155 | wake_up_interruptible(&joydev->wait); | 155 | wake_up_interruptible(&joydev->wait); |
156 | } | 156 | } |
157 | 157 | ||
158 | static int joydev_fasync(int fd, struct file *file, int on) | 158 | static int joydev_fasync(int fd, struct file *file, int on) |
159 | { | 159 | { |
160 | int retval; | 160 | int retval; |
161 | struct joydev_client *client = file->private_data; | 161 | struct joydev_client *client = file->private_data; |
162 | 162 | ||
163 | retval = fasync_helper(fd, file, on, &client->fasync); | 163 | retval = fasync_helper(fd, file, on, &client->fasync); |
164 | 164 | ||
165 | return retval < 0 ? retval : 0; | 165 | return retval < 0 ? retval : 0; |
166 | } | 166 | } |
167 | 167 | ||
168 | static void joydev_free(struct device *dev) | 168 | static void joydev_free(struct device *dev) |
169 | { | 169 | { |
170 | struct joydev *joydev = container_of(dev, struct joydev, dev); | 170 | struct joydev *joydev = container_of(dev, struct joydev, dev); |
171 | 171 | ||
172 | kfree(joydev); | 172 | kfree(joydev); |
173 | } | 173 | } |
174 | 174 | ||
175 | static void joydev_attach_client(struct joydev *joydev, | 175 | static void joydev_attach_client(struct joydev *joydev, |
176 | struct joydev_client *client) | 176 | struct joydev_client *client) |
177 | { | 177 | { |
178 | spin_lock(&joydev->client_lock); | 178 | spin_lock(&joydev->client_lock); |
179 | list_add_tail_rcu(&client->node, &joydev->client_list); | 179 | list_add_tail_rcu(&client->node, &joydev->client_list); |
180 | spin_unlock(&joydev->client_lock); | 180 | spin_unlock(&joydev->client_lock); |
181 | /* | 181 | /* |
182 | * We don't use synchronize_rcu() here because read-side | 182 | * We don't use synchronize_rcu() here because read-side |
183 | * critical section is protected by a spinlock (dev->event_lock) | 183 | * critical section is protected by a spinlock (dev->event_lock) |
184 | * instead of rcu_read_lock(). | 184 | * instead of rcu_read_lock(). |
185 | */ | 185 | */ |
186 | synchronize_sched(); | 186 | synchronize_sched(); |
187 | } | 187 | } |
188 | 188 | ||
189 | static void joydev_detach_client(struct joydev *joydev, | 189 | static void joydev_detach_client(struct joydev *joydev, |
190 | struct joydev_client *client) | 190 | struct joydev_client *client) |
191 | { | 191 | { |
192 | spin_lock(&joydev->client_lock); | 192 | spin_lock(&joydev->client_lock); |
193 | list_del_rcu(&client->node); | 193 | list_del_rcu(&client->node); |
194 | spin_unlock(&joydev->client_lock); | 194 | spin_unlock(&joydev->client_lock); |
195 | synchronize_sched(); | 195 | synchronize_sched(); |
196 | } | 196 | } |
197 | 197 | ||
198 | static int joydev_open_device(struct joydev *joydev) | 198 | static int joydev_open_device(struct joydev *joydev) |
199 | { | 199 | { |
200 | int retval; | 200 | int retval; |
201 | 201 | ||
202 | retval = mutex_lock_interruptible(&joydev->mutex); | 202 | retval = mutex_lock_interruptible(&joydev->mutex); |
203 | if (retval) | 203 | if (retval) |
204 | return retval; | 204 | return retval; |
205 | 205 | ||
206 | if (!joydev->exist) | 206 | if (!joydev->exist) |
207 | retval = -ENODEV; | 207 | retval = -ENODEV; |
208 | else if (!joydev->open++) | 208 | else if (!joydev->open++) { |
209 | retval = input_open_device(&joydev->handle); | 209 | retval = input_open_device(&joydev->handle); |
210 | if (retval) | ||
211 | joydev->open--; | ||
212 | } | ||
210 | 213 | ||
211 | mutex_unlock(&joydev->mutex); | 214 | mutex_unlock(&joydev->mutex); |
212 | return retval; | 215 | return retval; |
213 | } | 216 | } |
214 | 217 | ||
215 | static void joydev_close_device(struct joydev *joydev) | 218 | static void joydev_close_device(struct joydev *joydev) |
216 | { | 219 | { |
217 | mutex_lock(&joydev->mutex); | 220 | mutex_lock(&joydev->mutex); |
218 | 221 | ||
219 | if (joydev->exist && !--joydev->open) | 222 | if (joydev->exist && !--joydev->open) |
220 | input_close_device(&joydev->handle); | 223 | input_close_device(&joydev->handle); |
221 | 224 | ||
222 | mutex_unlock(&joydev->mutex); | 225 | mutex_unlock(&joydev->mutex); |
223 | } | 226 | } |
224 | 227 | ||
225 | /* | 228 | /* |
226 | * Wake up users waiting for IO so they can disconnect from | 229 | * Wake up users waiting for IO so they can disconnect from |
227 | * dead device. | 230 | * dead device. |
228 | */ | 231 | */ |
229 | static void joydev_hangup(struct joydev *joydev) | 232 | static void joydev_hangup(struct joydev *joydev) |
230 | { | 233 | { |
231 | struct joydev_client *client; | 234 | struct joydev_client *client; |
232 | 235 | ||
233 | spin_lock(&joydev->client_lock); | 236 | spin_lock(&joydev->client_lock); |
234 | list_for_each_entry(client, &joydev->client_list, node) | 237 | list_for_each_entry(client, &joydev->client_list, node) |
235 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 238 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
236 | spin_unlock(&joydev->client_lock); | 239 | spin_unlock(&joydev->client_lock); |
237 | 240 | ||
238 | wake_up_interruptible(&joydev->wait); | 241 | wake_up_interruptible(&joydev->wait); |
239 | } | 242 | } |
240 | 243 | ||
241 | static int joydev_release(struct inode *inode, struct file *file) | 244 | static int joydev_release(struct inode *inode, struct file *file) |
242 | { | 245 | { |
243 | struct joydev_client *client = file->private_data; | 246 | struct joydev_client *client = file->private_data; |
244 | struct joydev *joydev = client->joydev; | 247 | struct joydev *joydev = client->joydev; |
245 | 248 | ||
246 | joydev_fasync(-1, file, 0); | 249 | joydev_fasync(-1, file, 0); |
247 | joydev_detach_client(joydev, client); | 250 | joydev_detach_client(joydev, client); |
248 | kfree(client); | 251 | kfree(client); |
249 | 252 | ||
250 | joydev_close_device(joydev); | 253 | joydev_close_device(joydev); |
251 | put_device(&joydev->dev); | 254 | put_device(&joydev->dev); |
252 | 255 | ||
253 | return 0; | 256 | return 0; |
254 | } | 257 | } |
255 | 258 | ||
256 | static int joydev_open(struct inode *inode, struct file *file) | 259 | static int joydev_open(struct inode *inode, struct file *file) |
257 | { | 260 | { |
258 | struct joydev_client *client; | 261 | struct joydev_client *client; |
259 | struct joydev *joydev; | 262 | struct joydev *joydev; |
260 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | 263 | int i = iminor(inode) - JOYDEV_MINOR_BASE; |
261 | int error; | 264 | int error; |
262 | 265 | ||
263 | if (i >= JOYDEV_MINORS) | 266 | if (i >= JOYDEV_MINORS) |
264 | return -ENODEV; | 267 | return -ENODEV; |
265 | 268 | ||
266 | error = mutex_lock_interruptible(&joydev_table_mutex); | 269 | error = mutex_lock_interruptible(&joydev_table_mutex); |
267 | if (error) | 270 | if (error) |
268 | return error; | 271 | return error; |
269 | joydev = joydev_table[i]; | 272 | joydev = joydev_table[i]; |
270 | if (joydev) | 273 | if (joydev) |
271 | get_device(&joydev->dev); | 274 | get_device(&joydev->dev); |
272 | mutex_unlock(&joydev_table_mutex); | 275 | mutex_unlock(&joydev_table_mutex); |
273 | 276 | ||
274 | if (!joydev) | 277 | if (!joydev) |
275 | return -ENODEV; | 278 | return -ENODEV; |
276 | 279 | ||
277 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); | 280 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
278 | if (!client) { | 281 | if (!client) { |
279 | error = -ENOMEM; | 282 | error = -ENOMEM; |
280 | goto err_put_joydev; | 283 | goto err_put_joydev; |
281 | } | 284 | } |
282 | 285 | ||
283 | spin_lock_init(&client->buffer_lock); | 286 | spin_lock_init(&client->buffer_lock); |
284 | client->joydev = joydev; | 287 | client->joydev = joydev; |
285 | joydev_attach_client(joydev, client); | 288 | joydev_attach_client(joydev, client); |
286 | 289 | ||
287 | error = joydev_open_device(joydev); | 290 | error = joydev_open_device(joydev); |
288 | if (error) | 291 | if (error) |
289 | goto err_free_client; | 292 | goto err_free_client; |
290 | 293 | ||
291 | file->private_data = client; | 294 | file->private_data = client; |
292 | return 0; | 295 | return 0; |
293 | 296 | ||
294 | err_free_client: | 297 | err_free_client: |
295 | joydev_detach_client(joydev, client); | 298 | joydev_detach_client(joydev, client); |
296 | kfree(client); | 299 | kfree(client); |
297 | err_put_joydev: | 300 | err_put_joydev: |
298 | put_device(&joydev->dev); | 301 | put_device(&joydev->dev); |
299 | return error; | 302 | return error; |
300 | } | 303 | } |
301 | 304 | ||
302 | static int joydev_generate_startup_event(struct joydev_client *client, | 305 | static int joydev_generate_startup_event(struct joydev_client *client, |
303 | struct input_dev *input, | 306 | struct input_dev *input, |
304 | struct js_event *event) | 307 | struct js_event *event) |
305 | { | 308 | { |
306 | struct joydev *joydev = client->joydev; | 309 | struct joydev *joydev = client->joydev; |
307 | int have_event; | 310 | int have_event; |
308 | 311 | ||
309 | spin_lock_irq(&client->buffer_lock); | 312 | spin_lock_irq(&client->buffer_lock); |
310 | 313 | ||
311 | have_event = client->startup < joydev->nabs + joydev->nkey; | 314 | have_event = client->startup < joydev->nabs + joydev->nkey; |
312 | 315 | ||
313 | if (have_event) { | 316 | if (have_event) { |
314 | 317 | ||
315 | event->time = jiffies_to_msecs(jiffies); | 318 | event->time = jiffies_to_msecs(jiffies); |
316 | if (client->startup < joydev->nkey) { | 319 | if (client->startup < joydev->nkey) { |
317 | event->type = JS_EVENT_BUTTON | JS_EVENT_INIT; | 320 | event->type = JS_EVENT_BUTTON | JS_EVENT_INIT; |
318 | event->number = client->startup; | 321 | event->number = client->startup; |
319 | event->value = !!test_bit(joydev->keypam[event->number], | 322 | event->value = !!test_bit(joydev->keypam[event->number], |
320 | input->key); | 323 | input->key); |
321 | } else { | 324 | } else { |
322 | event->type = JS_EVENT_AXIS | JS_EVENT_INIT; | 325 | event->type = JS_EVENT_AXIS | JS_EVENT_INIT; |
323 | event->number = client->startup - joydev->nkey; | 326 | event->number = client->startup - joydev->nkey; |
324 | event->value = joydev->abs[event->number]; | 327 | event->value = joydev->abs[event->number]; |
325 | } | 328 | } |
326 | client->startup++; | 329 | client->startup++; |
327 | } | 330 | } |
328 | 331 | ||
329 | spin_unlock_irq(&client->buffer_lock); | 332 | spin_unlock_irq(&client->buffer_lock); |
330 | 333 | ||
331 | return have_event; | 334 | return have_event; |
332 | } | 335 | } |
333 | 336 | ||
334 | static int joydev_fetch_next_event(struct joydev_client *client, | 337 | static int joydev_fetch_next_event(struct joydev_client *client, |
335 | struct js_event *event) | 338 | struct js_event *event) |
336 | { | 339 | { |
337 | int have_event; | 340 | int have_event; |
338 | 341 | ||
339 | spin_lock_irq(&client->buffer_lock); | 342 | spin_lock_irq(&client->buffer_lock); |
340 | 343 | ||
341 | have_event = client->head != client->tail; | 344 | have_event = client->head != client->tail; |
342 | if (have_event) { | 345 | if (have_event) { |
343 | *event = client->buffer[client->tail++]; | 346 | *event = client->buffer[client->tail++]; |
344 | client->tail &= JOYDEV_BUFFER_SIZE - 1; | 347 | client->tail &= JOYDEV_BUFFER_SIZE - 1; |
345 | } | 348 | } |
346 | 349 | ||
347 | spin_unlock_irq(&client->buffer_lock); | 350 | spin_unlock_irq(&client->buffer_lock); |
348 | 351 | ||
349 | return have_event; | 352 | return have_event; |
350 | } | 353 | } |
351 | 354 | ||
352 | /* | 355 | /* |
353 | * Old joystick interface | 356 | * Old joystick interface |
354 | */ | 357 | */ |
355 | static ssize_t joydev_0x_read(struct joydev_client *client, | 358 | static ssize_t joydev_0x_read(struct joydev_client *client, |
356 | struct input_dev *input, | 359 | struct input_dev *input, |
357 | char __user *buf) | 360 | char __user *buf) |
358 | { | 361 | { |
359 | struct joydev *joydev = client->joydev; | 362 | struct joydev *joydev = client->joydev; |
360 | struct JS_DATA_TYPE data; | 363 | struct JS_DATA_TYPE data; |
361 | int i; | 364 | int i; |
362 | 365 | ||
363 | spin_lock_irq(&input->event_lock); | 366 | spin_lock_irq(&input->event_lock); |
364 | 367 | ||
365 | /* | 368 | /* |
366 | * Get device state | 369 | * Get device state |
367 | */ | 370 | */ |
368 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) | 371 | for (data.buttons = i = 0; i < 32 && i < joydev->nkey; i++) |
369 | data.buttons |= | 372 | data.buttons |= |
370 | test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; | 373 | test_bit(joydev->keypam[i], input->key) ? (1 << i) : 0; |
371 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; | 374 | data.x = (joydev->abs[0] / 256 + 128) >> joydev->glue.JS_CORR.x; |
372 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; | 375 | data.y = (joydev->abs[1] / 256 + 128) >> joydev->glue.JS_CORR.y; |
373 | 376 | ||
374 | /* | 377 | /* |
375 | * Reset reader's event queue | 378 | * Reset reader's event queue |
376 | */ | 379 | */ |
377 | spin_lock(&client->buffer_lock); | 380 | spin_lock(&client->buffer_lock); |
378 | client->startup = 0; | 381 | client->startup = 0; |
379 | client->tail = client->head; | 382 | client->tail = client->head; |
380 | spin_unlock(&client->buffer_lock); | 383 | spin_unlock(&client->buffer_lock); |
381 | 384 | ||
382 | spin_unlock_irq(&input->event_lock); | 385 | spin_unlock_irq(&input->event_lock); |
383 | 386 | ||
384 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | 387 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) |
385 | return -EFAULT; | 388 | return -EFAULT; |
386 | 389 | ||
387 | return sizeof(struct JS_DATA_TYPE); | 390 | return sizeof(struct JS_DATA_TYPE); |
388 | } | 391 | } |
389 | 392 | ||
390 | static inline int joydev_data_pending(struct joydev_client *client) | 393 | static inline int joydev_data_pending(struct joydev_client *client) |
391 | { | 394 | { |
392 | struct joydev *joydev = client->joydev; | 395 | struct joydev *joydev = client->joydev; |
393 | 396 | ||
394 | return client->startup < joydev->nabs + joydev->nkey || | 397 | return client->startup < joydev->nabs + joydev->nkey || |
395 | client->head != client->tail; | 398 | client->head != client->tail; |
396 | } | 399 | } |
397 | 400 | ||
398 | static ssize_t joydev_read(struct file *file, char __user *buf, | 401 | static ssize_t joydev_read(struct file *file, char __user *buf, |
399 | size_t count, loff_t *ppos) | 402 | size_t count, loff_t *ppos) |
400 | { | 403 | { |
401 | struct joydev_client *client = file->private_data; | 404 | struct joydev_client *client = file->private_data; |
402 | struct joydev *joydev = client->joydev; | 405 | struct joydev *joydev = client->joydev; |
403 | struct input_dev *input = joydev->handle.dev; | 406 | struct input_dev *input = joydev->handle.dev; |
404 | struct js_event event; | 407 | struct js_event event; |
405 | int retval; | 408 | int retval; |
406 | 409 | ||
407 | if (!joydev->exist) | 410 | if (!joydev->exist) |
408 | return -ENODEV; | 411 | return -ENODEV; |
409 | 412 | ||
410 | if (count < sizeof(struct js_event)) | 413 | if (count < sizeof(struct js_event)) |
411 | return -EINVAL; | 414 | return -EINVAL; |
412 | 415 | ||
413 | if (count == sizeof(struct JS_DATA_TYPE)) | 416 | if (count == sizeof(struct JS_DATA_TYPE)) |
414 | return joydev_0x_read(client, input, buf); | 417 | return joydev_0x_read(client, input, buf); |
415 | 418 | ||
416 | if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK)) | 419 | if (!joydev_data_pending(client) && (file->f_flags & O_NONBLOCK)) |
417 | return -EAGAIN; | 420 | return -EAGAIN; |
418 | 421 | ||
419 | retval = wait_event_interruptible(joydev->wait, | 422 | retval = wait_event_interruptible(joydev->wait, |
420 | !joydev->exist || joydev_data_pending(client)); | 423 | !joydev->exist || joydev_data_pending(client)); |
421 | if (retval) | 424 | if (retval) |
422 | return retval; | 425 | return retval; |
423 | 426 | ||
424 | if (!joydev->exist) | 427 | if (!joydev->exist) |
425 | return -ENODEV; | 428 | return -ENODEV; |
426 | 429 | ||
427 | while (retval + sizeof(struct js_event) <= count && | 430 | while (retval + sizeof(struct js_event) <= count && |
428 | joydev_generate_startup_event(client, input, &event)) { | 431 | joydev_generate_startup_event(client, input, &event)) { |
429 | 432 | ||
430 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | 433 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
431 | return -EFAULT; | 434 | return -EFAULT; |
432 | 435 | ||
433 | retval += sizeof(struct js_event); | 436 | retval += sizeof(struct js_event); |
434 | } | 437 | } |
435 | 438 | ||
436 | while (retval + sizeof(struct js_event) <= count && | 439 | while (retval + sizeof(struct js_event) <= count && |
437 | joydev_fetch_next_event(client, &event)) { | 440 | joydev_fetch_next_event(client, &event)) { |
438 | 441 | ||
439 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | 442 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
440 | return -EFAULT; | 443 | return -EFAULT; |
441 | 444 | ||
442 | retval += sizeof(struct js_event); | 445 | retval += sizeof(struct js_event); |
443 | } | 446 | } |
444 | 447 | ||
445 | return retval; | 448 | return retval; |
446 | } | 449 | } |
447 | 450 | ||
448 | /* No kernel lock - fine */ | 451 | /* No kernel lock - fine */ |
449 | static unsigned int joydev_poll(struct file *file, poll_table *wait) | 452 | static unsigned int joydev_poll(struct file *file, poll_table *wait) |
450 | { | 453 | { |
451 | struct joydev_client *client = file->private_data; | 454 | struct joydev_client *client = file->private_data; |
452 | struct joydev *joydev = client->joydev; | 455 | struct joydev *joydev = client->joydev; |
453 | 456 | ||
454 | poll_wait(file, &joydev->wait, wait); | 457 | poll_wait(file, &joydev->wait, wait); |
455 | return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) | | 458 | return (joydev_data_pending(client) ? (POLLIN | POLLRDNORM) : 0) | |
456 | (joydev->exist ? 0 : (POLLHUP | POLLERR)); | 459 | (joydev->exist ? 0 : (POLLHUP | POLLERR)); |
457 | } | 460 | } |
458 | 461 | ||
459 | static int joydev_ioctl_common(struct joydev *joydev, | 462 | static int joydev_ioctl_common(struct joydev *joydev, |
460 | unsigned int cmd, void __user *argp) | 463 | unsigned int cmd, void __user *argp) |
461 | { | 464 | { |
462 | struct input_dev *dev = joydev->handle.dev; | 465 | struct input_dev *dev = joydev->handle.dev; |
463 | int i, j; | 466 | int i, j; |
464 | 467 | ||
465 | switch (cmd) { | 468 | switch (cmd) { |
466 | 469 | ||
467 | case JS_SET_CAL: | 470 | case JS_SET_CAL: |
468 | return copy_from_user(&joydev->glue.JS_CORR, argp, | 471 | return copy_from_user(&joydev->glue.JS_CORR, argp, |
469 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 472 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
470 | 473 | ||
471 | case JS_GET_CAL: | 474 | case JS_GET_CAL: |
472 | return copy_to_user(argp, &joydev->glue.JS_CORR, | 475 | return copy_to_user(argp, &joydev->glue.JS_CORR, |
473 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; | 476 | sizeof(joydev->glue.JS_CORR)) ? -EFAULT : 0; |
474 | 477 | ||
475 | case JS_SET_TIMEOUT: | 478 | case JS_SET_TIMEOUT: |
476 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 479 | return get_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
477 | 480 | ||
478 | case JS_GET_TIMEOUT: | 481 | case JS_GET_TIMEOUT: |
479 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); | 482 | return put_user(joydev->glue.JS_TIMEOUT, (s32 __user *) argp); |
480 | 483 | ||
481 | case JSIOCGVERSION: | 484 | case JSIOCGVERSION: |
482 | return put_user(JS_VERSION, (__u32 __user *) argp); | 485 | return put_user(JS_VERSION, (__u32 __user *) argp); |
483 | 486 | ||
484 | case JSIOCGAXES: | 487 | case JSIOCGAXES: |
485 | return put_user(joydev->nabs, (__u8 __user *) argp); | 488 | return put_user(joydev->nabs, (__u8 __user *) argp); |
486 | 489 | ||
487 | case JSIOCGBUTTONS: | 490 | case JSIOCGBUTTONS: |
488 | return put_user(joydev->nkey, (__u8 __user *) argp); | 491 | return put_user(joydev->nkey, (__u8 __user *) argp); |
489 | 492 | ||
490 | case JSIOCSCORR: | 493 | case JSIOCSCORR: |
491 | if (copy_from_user(joydev->corr, argp, | 494 | if (copy_from_user(joydev->corr, argp, |
492 | sizeof(joydev->corr[0]) * joydev->nabs)) | 495 | sizeof(joydev->corr[0]) * joydev->nabs)) |
493 | return -EFAULT; | 496 | return -EFAULT; |
494 | 497 | ||
495 | for (i = 0; i < joydev->nabs; i++) { | 498 | for (i = 0; i < joydev->nabs; i++) { |
496 | j = joydev->abspam[i]; | 499 | j = joydev->abspam[i]; |
497 | joydev->abs[i] = joydev_correct(dev->abs[j], | 500 | joydev->abs[i] = joydev_correct(dev->abs[j], |
498 | &joydev->corr[i]); | 501 | &joydev->corr[i]); |
499 | } | 502 | } |
500 | return 0; | 503 | return 0; |
501 | 504 | ||
502 | case JSIOCGCORR: | 505 | case JSIOCGCORR: |
503 | return copy_to_user(argp, joydev->corr, | 506 | return copy_to_user(argp, joydev->corr, |
504 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; | 507 | sizeof(joydev->corr[0]) * joydev->nabs) ? -EFAULT : 0; |
505 | 508 | ||
506 | case JSIOCSAXMAP: | 509 | case JSIOCSAXMAP: |
507 | if (copy_from_user(joydev->abspam, argp, | 510 | if (copy_from_user(joydev->abspam, argp, |
508 | sizeof(__u8) * (ABS_MAX + 1))) | 511 | sizeof(__u8) * (ABS_MAX + 1))) |
509 | return -EFAULT; | 512 | return -EFAULT; |
510 | 513 | ||
511 | for (i = 0; i < joydev->nabs; i++) { | 514 | for (i = 0; i < joydev->nabs; i++) { |
512 | if (joydev->abspam[i] > ABS_MAX) | 515 | if (joydev->abspam[i] > ABS_MAX) |
513 | return -EINVAL; | 516 | return -EINVAL; |
514 | joydev->absmap[joydev->abspam[i]] = i; | 517 | joydev->absmap[joydev->abspam[i]] = i; |
515 | } | 518 | } |
516 | return 0; | 519 | return 0; |
517 | 520 | ||
518 | case JSIOCGAXMAP: | 521 | case JSIOCGAXMAP: |
519 | return copy_to_user(argp, joydev->abspam, | 522 | return copy_to_user(argp, joydev->abspam, |
520 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; | 523 | sizeof(__u8) * (ABS_MAX + 1)) ? -EFAULT : 0; |
521 | 524 | ||
522 | case JSIOCSBTNMAP: | 525 | case JSIOCSBTNMAP: |
523 | if (copy_from_user(joydev->keypam, argp, | 526 | if (copy_from_user(joydev->keypam, argp, |
524 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) | 527 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1))) |
525 | return -EFAULT; | 528 | return -EFAULT; |
526 | 529 | ||
527 | for (i = 0; i < joydev->nkey; i++) { | 530 | for (i = 0; i < joydev->nkey; i++) { |
528 | if (joydev->keypam[i] > KEY_MAX || | 531 | if (joydev->keypam[i] > KEY_MAX || |
529 | joydev->keypam[i] < BTN_MISC) | 532 | joydev->keypam[i] < BTN_MISC) |
530 | return -EINVAL; | 533 | return -EINVAL; |
531 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; | 534 | joydev->keymap[joydev->keypam[i] - BTN_MISC] = i; |
532 | } | 535 | } |
533 | 536 | ||
534 | return 0; | 537 | return 0; |
535 | 538 | ||
536 | case JSIOCGBTNMAP: | 539 | case JSIOCGBTNMAP: |
537 | return copy_to_user(argp, joydev->keypam, | 540 | return copy_to_user(argp, joydev->keypam, |
538 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; | 541 | sizeof(__u16) * (KEY_MAX - BTN_MISC + 1)) ? -EFAULT : 0; |
539 | 542 | ||
540 | default: | 543 | default: |
541 | if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { | 544 | if ((cmd & ~IOCSIZE_MASK) == JSIOCGNAME(0)) { |
542 | int len; | 545 | int len; |
543 | if (!dev->name) | 546 | if (!dev->name) |
544 | return 0; | 547 | return 0; |
545 | len = strlen(dev->name) + 1; | 548 | len = strlen(dev->name) + 1; |
546 | if (len > _IOC_SIZE(cmd)) | 549 | if (len > _IOC_SIZE(cmd)) |
547 | len = _IOC_SIZE(cmd); | 550 | len = _IOC_SIZE(cmd); |
548 | if (copy_to_user(argp, dev->name, len)) | 551 | if (copy_to_user(argp, dev->name, len)) |
549 | return -EFAULT; | 552 | return -EFAULT; |
550 | return len; | 553 | return len; |
551 | } | 554 | } |
552 | } | 555 | } |
553 | return -EINVAL; | 556 | return -EINVAL; |
554 | } | 557 | } |
555 | 558 | ||
556 | #ifdef CONFIG_COMPAT | 559 | #ifdef CONFIG_COMPAT |
557 | static long joydev_compat_ioctl(struct file *file, | 560 | static long joydev_compat_ioctl(struct file *file, |
558 | unsigned int cmd, unsigned long arg) | 561 | unsigned int cmd, unsigned long arg) |
559 | { | 562 | { |
560 | struct joydev_client *client = file->private_data; | 563 | struct joydev_client *client = file->private_data; |
561 | struct joydev *joydev = client->joydev; | 564 | struct joydev *joydev = client->joydev; |
562 | void __user *argp = (void __user *)arg; | 565 | void __user *argp = (void __user *)arg; |
563 | s32 tmp32; | 566 | s32 tmp32; |
564 | struct JS_DATA_SAVE_TYPE_32 ds32; | 567 | struct JS_DATA_SAVE_TYPE_32 ds32; |
565 | int retval; | 568 | int retval; |
566 | 569 | ||
567 | retval = mutex_lock_interruptible(&joydev->mutex); | 570 | retval = mutex_lock_interruptible(&joydev->mutex); |
568 | if (retval) | 571 | if (retval) |
569 | return retval; | 572 | return retval; |
570 | 573 | ||
571 | if (!joydev->exist) { | 574 | if (!joydev->exist) { |
572 | retval = -ENODEV; | 575 | retval = -ENODEV; |
573 | goto out; | 576 | goto out; |
574 | } | 577 | } |
575 | 578 | ||
576 | switch (cmd) { | 579 | switch (cmd) { |
577 | 580 | ||
578 | case JS_SET_TIMELIMIT: | 581 | case JS_SET_TIMELIMIT: |
579 | retval = get_user(tmp32, (s32 __user *) arg); | 582 | retval = get_user(tmp32, (s32 __user *) arg); |
580 | if (retval == 0) | 583 | if (retval == 0) |
581 | joydev->glue.JS_TIMELIMIT = tmp32; | 584 | joydev->glue.JS_TIMELIMIT = tmp32; |
582 | break; | 585 | break; |
583 | 586 | ||
584 | case JS_GET_TIMELIMIT: | 587 | case JS_GET_TIMELIMIT: |
585 | tmp32 = joydev->glue.JS_TIMELIMIT; | 588 | tmp32 = joydev->glue.JS_TIMELIMIT; |
586 | retval = put_user(tmp32, (s32 __user *) arg); | 589 | retval = put_user(tmp32, (s32 __user *) arg); |
587 | break; | 590 | break; |
588 | 591 | ||
589 | case JS_SET_ALL: | 592 | case JS_SET_ALL: |
590 | retval = copy_from_user(&ds32, argp, | 593 | retval = copy_from_user(&ds32, argp, |
591 | sizeof(ds32)) ? -EFAULT : 0; | 594 | sizeof(ds32)) ? -EFAULT : 0; |
592 | if (retval == 0) { | 595 | if (retval == 0) { |
593 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; | 596 | joydev->glue.JS_TIMEOUT = ds32.JS_TIMEOUT; |
594 | joydev->glue.BUSY = ds32.BUSY; | 597 | joydev->glue.BUSY = ds32.BUSY; |
595 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; | 598 | joydev->glue.JS_EXPIRETIME = ds32.JS_EXPIRETIME; |
596 | joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT; | 599 | joydev->glue.JS_TIMELIMIT = ds32.JS_TIMELIMIT; |
597 | joydev->glue.JS_SAVE = ds32.JS_SAVE; | 600 | joydev->glue.JS_SAVE = ds32.JS_SAVE; |
598 | joydev->glue.JS_CORR = ds32.JS_CORR; | 601 | joydev->glue.JS_CORR = ds32.JS_CORR; |
599 | } | 602 | } |
600 | break; | 603 | break; |
601 | 604 | ||
602 | case JS_GET_ALL: | 605 | case JS_GET_ALL: |
603 | ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT; | 606 | ds32.JS_TIMEOUT = joydev->glue.JS_TIMEOUT; |
604 | ds32.BUSY = joydev->glue.BUSY; | 607 | ds32.BUSY = joydev->glue.BUSY; |
605 | ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME; | 608 | ds32.JS_EXPIRETIME = joydev->glue.JS_EXPIRETIME; |
606 | ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT; | 609 | ds32.JS_TIMELIMIT = joydev->glue.JS_TIMELIMIT; |
607 | ds32.JS_SAVE = joydev->glue.JS_SAVE; | 610 | ds32.JS_SAVE = joydev->glue.JS_SAVE; |
608 | ds32.JS_CORR = joydev->glue.JS_CORR; | 611 | ds32.JS_CORR = joydev->glue.JS_CORR; |
609 | 612 | ||
610 | retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; | 613 | retval = copy_to_user(argp, &ds32, sizeof(ds32)) ? -EFAULT : 0; |
611 | break; | 614 | break; |
612 | 615 | ||
613 | default: | 616 | default: |
614 | retval = joydev_ioctl_common(joydev, cmd, argp); | 617 | retval = joydev_ioctl_common(joydev, cmd, argp); |
615 | break; | 618 | break; |
616 | } | 619 | } |
617 | 620 | ||
618 | out: | 621 | out: |
619 | mutex_unlock(&joydev->mutex); | 622 | mutex_unlock(&joydev->mutex); |
620 | return retval; | 623 | return retval; |
621 | } | 624 | } |
622 | #endif /* CONFIG_COMPAT */ | 625 | #endif /* CONFIG_COMPAT */ |
623 | 626 | ||
624 | static long joydev_ioctl(struct file *file, | 627 | static long joydev_ioctl(struct file *file, |
625 | unsigned int cmd, unsigned long arg) | 628 | unsigned int cmd, unsigned long arg) |
626 | { | 629 | { |
627 | struct joydev_client *client = file->private_data; | 630 | struct joydev_client *client = file->private_data; |
628 | struct joydev *joydev = client->joydev; | 631 | struct joydev *joydev = client->joydev; |
629 | void __user *argp = (void __user *)arg; | 632 | void __user *argp = (void __user *)arg; |
630 | int retval; | 633 | int retval; |
631 | 634 | ||
632 | retval = mutex_lock_interruptible(&joydev->mutex); | 635 | retval = mutex_lock_interruptible(&joydev->mutex); |
633 | if (retval) | 636 | if (retval) |
634 | return retval; | 637 | return retval; |
635 | 638 | ||
636 | if (!joydev->exist) { | 639 | if (!joydev->exist) { |
637 | retval = -ENODEV; | 640 | retval = -ENODEV; |
638 | goto out; | 641 | goto out; |
639 | } | 642 | } |
640 | 643 | ||
641 | switch (cmd) { | 644 | switch (cmd) { |
642 | 645 | ||
643 | case JS_SET_TIMELIMIT: | 646 | case JS_SET_TIMELIMIT: |
644 | retval = get_user(joydev->glue.JS_TIMELIMIT, | 647 | retval = get_user(joydev->glue.JS_TIMELIMIT, |
645 | (long __user *) arg); | 648 | (long __user *) arg); |
646 | break; | 649 | break; |
647 | 650 | ||
648 | case JS_GET_TIMELIMIT: | 651 | case JS_GET_TIMELIMIT: |
649 | retval = put_user(joydev->glue.JS_TIMELIMIT, | 652 | retval = put_user(joydev->glue.JS_TIMELIMIT, |
650 | (long __user *) arg); | 653 | (long __user *) arg); |
651 | break; | 654 | break; |
652 | 655 | ||
653 | case JS_SET_ALL: | 656 | case JS_SET_ALL: |
654 | retval = copy_from_user(&joydev->glue, argp, | 657 | retval = copy_from_user(&joydev->glue, argp, |
655 | sizeof(joydev->glue)) ? -EFAULT: 0; | 658 | sizeof(joydev->glue)) ? -EFAULT: 0; |
656 | break; | 659 | break; |
657 | 660 | ||
658 | case JS_GET_ALL: | 661 | case JS_GET_ALL: |
659 | retval = copy_to_user(argp, &joydev->glue, | 662 | retval = copy_to_user(argp, &joydev->glue, |
660 | sizeof(joydev->glue)) ? -EFAULT : 0; | 663 | sizeof(joydev->glue)) ? -EFAULT : 0; |
661 | break; | 664 | break; |
662 | 665 | ||
663 | default: | 666 | default: |
664 | retval = joydev_ioctl_common(joydev, cmd, argp); | 667 | retval = joydev_ioctl_common(joydev, cmd, argp); |
665 | break; | 668 | break; |
666 | } | 669 | } |
667 | out: | 670 | out: |
668 | mutex_unlock(&joydev->mutex); | 671 | mutex_unlock(&joydev->mutex); |
669 | return retval; | 672 | return retval; |
670 | } | 673 | } |
671 | 674 | ||
672 | static const struct file_operations joydev_fops = { | 675 | static const struct file_operations joydev_fops = { |
673 | .owner = THIS_MODULE, | 676 | .owner = THIS_MODULE, |
674 | .read = joydev_read, | 677 | .read = joydev_read, |
675 | .poll = joydev_poll, | 678 | .poll = joydev_poll, |
676 | .open = joydev_open, | 679 | .open = joydev_open, |
677 | .release = joydev_release, | 680 | .release = joydev_release, |
678 | .unlocked_ioctl = joydev_ioctl, | 681 | .unlocked_ioctl = joydev_ioctl, |
679 | #ifdef CONFIG_COMPAT | 682 | #ifdef CONFIG_COMPAT |
680 | .compat_ioctl = joydev_compat_ioctl, | 683 | .compat_ioctl = joydev_compat_ioctl, |
681 | #endif | 684 | #endif |
682 | .fasync = joydev_fasync, | 685 | .fasync = joydev_fasync, |
683 | }; | 686 | }; |
684 | 687 | ||
685 | static int joydev_install_chrdev(struct joydev *joydev) | 688 | static int joydev_install_chrdev(struct joydev *joydev) |
686 | { | 689 | { |
687 | joydev_table[joydev->minor] = joydev; | 690 | joydev_table[joydev->minor] = joydev; |
688 | return 0; | 691 | return 0; |
689 | } | 692 | } |
690 | 693 | ||
691 | static void joydev_remove_chrdev(struct joydev *joydev) | 694 | static void joydev_remove_chrdev(struct joydev *joydev) |
692 | { | 695 | { |
693 | mutex_lock(&joydev_table_mutex); | 696 | mutex_lock(&joydev_table_mutex); |
694 | joydev_table[joydev->minor] = NULL; | 697 | joydev_table[joydev->minor] = NULL; |
695 | mutex_unlock(&joydev_table_mutex); | 698 | mutex_unlock(&joydev_table_mutex); |
696 | } | 699 | } |
697 | 700 | ||
698 | /* | 701 | /* |
699 | * Mark device non-existant. This disables writes, ioctls and | 702 | * Mark device non-existant. This disables writes, ioctls and |
700 | * prevents new users from opening the device. Already posted | 703 | * prevents new users from opening the device. Already posted |
701 | * blocking reads will stay, however new ones will fail. | 704 | * blocking reads will stay, however new ones will fail. |
702 | */ | 705 | */ |
703 | static void joydev_mark_dead(struct joydev *joydev) | 706 | static void joydev_mark_dead(struct joydev *joydev) |
704 | { | 707 | { |
705 | mutex_lock(&joydev->mutex); | 708 | mutex_lock(&joydev->mutex); |
706 | joydev->exist = 0; | 709 | joydev->exist = 0; |
707 | mutex_unlock(&joydev->mutex); | 710 | mutex_unlock(&joydev->mutex); |
708 | } | 711 | } |
709 | 712 | ||
710 | static void joydev_cleanup(struct joydev *joydev) | 713 | static void joydev_cleanup(struct joydev *joydev) |
711 | { | 714 | { |
712 | struct input_handle *handle = &joydev->handle; | 715 | struct input_handle *handle = &joydev->handle; |
713 | 716 | ||
714 | joydev_mark_dead(joydev); | 717 | joydev_mark_dead(joydev); |
715 | joydev_hangup(joydev); | 718 | joydev_hangup(joydev); |
716 | joydev_remove_chrdev(joydev); | 719 | joydev_remove_chrdev(joydev); |
717 | 720 | ||
718 | /* joydev is marked dead so noone else accesses joydev->open */ | 721 | /* joydev is marked dead so noone else accesses joydev->open */ |
719 | if (joydev->open) | 722 | if (joydev->open) |
720 | input_close_device(handle); | 723 | input_close_device(handle); |
721 | } | 724 | } |
722 | 725 | ||
723 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | 726 | static int joydev_connect(struct input_handler *handler, struct input_dev *dev, |
724 | const struct input_device_id *id) | 727 | const struct input_device_id *id) |
725 | { | 728 | { |
726 | struct joydev *joydev; | 729 | struct joydev *joydev; |
727 | int i, j, t, minor; | 730 | int i, j, t, minor; |
728 | int error; | 731 | int error; |
729 | 732 | ||
730 | for (minor = 0; minor < JOYDEV_MINORS; minor++) | 733 | for (minor = 0; minor < JOYDEV_MINORS; minor++) |
731 | if (!joydev_table[minor]) | 734 | if (!joydev_table[minor]) |
732 | break; | 735 | break; |
733 | 736 | ||
734 | if (minor == JOYDEV_MINORS) { | 737 | if (minor == JOYDEV_MINORS) { |
735 | printk(KERN_ERR "joydev: no more free joydev devices\n"); | 738 | printk(KERN_ERR "joydev: no more free joydev devices\n"); |
736 | return -ENFILE; | 739 | return -ENFILE; |
737 | } | 740 | } |
738 | 741 | ||
739 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); | 742 | joydev = kzalloc(sizeof(struct joydev), GFP_KERNEL); |
740 | if (!joydev) | 743 | if (!joydev) |
741 | return -ENOMEM; | 744 | return -ENOMEM; |
742 | 745 | ||
743 | INIT_LIST_HEAD(&joydev->client_list); | 746 | INIT_LIST_HEAD(&joydev->client_list); |
744 | spin_lock_init(&joydev->client_lock); | 747 | spin_lock_init(&joydev->client_lock); |
745 | mutex_init(&joydev->mutex); | 748 | mutex_init(&joydev->mutex); |
746 | init_waitqueue_head(&joydev->wait); | 749 | init_waitqueue_head(&joydev->wait); |
747 | 750 | ||
748 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); | 751 | snprintf(joydev->name, sizeof(joydev->name), "js%d", minor); |
749 | joydev->exist = 1; | 752 | joydev->exist = 1; |
750 | joydev->minor = minor; | 753 | joydev->minor = minor; |
751 | 754 | ||
752 | joydev->exist = 1; | 755 | joydev->exist = 1; |
753 | joydev->handle.dev = dev; | 756 | joydev->handle.dev = dev; |
754 | joydev->handle.name = joydev->name; | 757 | joydev->handle.name = joydev->name; |
755 | joydev->handle.handler = handler; | 758 | joydev->handle.handler = handler; |
756 | joydev->handle.private = joydev; | 759 | joydev->handle.private = joydev; |
757 | 760 | ||
758 | for (i = 0; i < ABS_MAX + 1; i++) | 761 | for (i = 0; i < ABS_MAX + 1; i++) |
759 | if (test_bit(i, dev->absbit)) { | 762 | if (test_bit(i, dev->absbit)) { |
760 | joydev->absmap[i] = joydev->nabs; | 763 | joydev->absmap[i] = joydev->nabs; |
761 | joydev->abspam[joydev->nabs] = i; | 764 | joydev->abspam[joydev->nabs] = i; |
762 | joydev->nabs++; | 765 | joydev->nabs++; |
763 | } | 766 | } |
764 | 767 | ||
765 | for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) | 768 | for (i = BTN_JOYSTICK - BTN_MISC; i < KEY_MAX - BTN_MISC + 1; i++) |
766 | if (test_bit(i + BTN_MISC, dev->keybit)) { | 769 | if (test_bit(i + BTN_MISC, dev->keybit)) { |
767 | joydev->keymap[i] = joydev->nkey; | 770 | joydev->keymap[i] = joydev->nkey; |
768 | joydev->keypam[joydev->nkey] = i + BTN_MISC; | 771 | joydev->keypam[joydev->nkey] = i + BTN_MISC; |
769 | joydev->nkey++; | 772 | joydev->nkey++; |
770 | } | 773 | } |
771 | 774 | ||
772 | for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) | 775 | for (i = 0; i < BTN_JOYSTICK - BTN_MISC; i++) |
773 | if (test_bit(i + BTN_MISC, dev->keybit)) { | 776 | if (test_bit(i + BTN_MISC, dev->keybit)) { |
774 | joydev->keymap[i] = joydev->nkey; | 777 | joydev->keymap[i] = joydev->nkey; |
775 | joydev->keypam[joydev->nkey] = i + BTN_MISC; | 778 | joydev->keypam[joydev->nkey] = i + BTN_MISC; |
776 | joydev->nkey++; | 779 | joydev->nkey++; |
777 | } | 780 | } |
778 | 781 | ||
779 | for (i = 0; i < joydev->nabs; i++) { | 782 | for (i = 0; i < joydev->nabs; i++) { |
780 | j = joydev->abspam[i]; | 783 | j = joydev->abspam[i]; |
781 | if (dev->absmax[j] == dev->absmin[j]) { | 784 | if (dev->absmax[j] == dev->absmin[j]) { |
782 | joydev->corr[i].type = JS_CORR_NONE; | 785 | joydev->corr[i].type = JS_CORR_NONE; |
783 | joydev->abs[i] = dev->abs[j]; | 786 | joydev->abs[i] = dev->abs[j]; |
784 | continue; | 787 | continue; |
785 | } | 788 | } |
786 | joydev->corr[i].type = JS_CORR_BROKEN; | 789 | joydev->corr[i].type = JS_CORR_BROKEN; |
787 | joydev->corr[i].prec = dev->absfuzz[j]; | 790 | joydev->corr[i].prec = dev->absfuzz[j]; |
788 | joydev->corr[i].coef[0] = | 791 | joydev->corr[i].coef[0] = |
789 | (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; | 792 | (dev->absmax[j] + dev->absmin[j]) / 2 - dev->absflat[j]; |
790 | joydev->corr[i].coef[1] = | 793 | joydev->corr[i].coef[1] = |
791 | (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; | 794 | (dev->absmax[j] + dev->absmin[j]) / 2 + dev->absflat[j]; |
792 | 795 | ||
793 | t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; | 796 | t = (dev->absmax[j] - dev->absmin[j]) / 2 - 2 * dev->absflat[j]; |
794 | if (t) { | 797 | if (t) { |
795 | joydev->corr[i].coef[2] = (1 << 29) / t; | 798 | joydev->corr[i].coef[2] = (1 << 29) / t; |
796 | joydev->corr[i].coef[3] = (1 << 29) / t; | 799 | joydev->corr[i].coef[3] = (1 << 29) / t; |
797 | 800 | ||
798 | joydev->abs[i] = joydev_correct(dev->abs[j], | 801 | joydev->abs[i] = joydev_correct(dev->abs[j], |
799 | joydev->corr + i); | 802 | joydev->corr + i); |
800 | } | 803 | } |
801 | } | 804 | } |
802 | 805 | ||
803 | strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); | 806 | strlcpy(joydev->dev.bus_id, joydev->name, sizeof(joydev->dev.bus_id)); |
804 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); | 807 | joydev->dev.devt = MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor); |
805 | joydev->dev.class = &input_class; | 808 | joydev->dev.class = &input_class; |
806 | joydev->dev.parent = &dev->dev; | 809 | joydev->dev.parent = &dev->dev; |
807 | joydev->dev.release = joydev_free; | 810 | joydev->dev.release = joydev_free; |
808 | device_initialize(&joydev->dev); | 811 | device_initialize(&joydev->dev); |
809 | 812 | ||
810 | error = input_register_handle(&joydev->handle); | 813 | error = input_register_handle(&joydev->handle); |
811 | if (error) | 814 | if (error) |
812 | goto err_free_joydev; | 815 | goto err_free_joydev; |
813 | 816 | ||
814 | error = joydev_install_chrdev(joydev); | 817 | error = joydev_install_chrdev(joydev); |
815 | if (error) | 818 | if (error) |
816 | goto err_unregister_handle; | 819 | goto err_unregister_handle; |
817 | 820 | ||
818 | error = device_add(&joydev->dev); | 821 | error = device_add(&joydev->dev); |
819 | if (error) | 822 | if (error) |
820 | goto err_cleanup_joydev; | 823 | goto err_cleanup_joydev; |
821 | 824 | ||
822 | return 0; | 825 | return 0; |
823 | 826 | ||
824 | err_cleanup_joydev: | 827 | err_cleanup_joydev: |
825 | joydev_cleanup(joydev); | 828 | joydev_cleanup(joydev); |
826 | err_unregister_handle: | 829 | err_unregister_handle: |
827 | input_unregister_handle(&joydev->handle); | 830 | input_unregister_handle(&joydev->handle); |
828 | err_free_joydev: | 831 | err_free_joydev: |
829 | put_device(&joydev->dev); | 832 | put_device(&joydev->dev); |
830 | return error; | 833 | return error; |
831 | } | 834 | } |
832 | 835 | ||
833 | static void joydev_disconnect(struct input_handle *handle) | 836 | static void joydev_disconnect(struct input_handle *handle) |
834 | { | 837 | { |
835 | struct joydev *joydev = handle->private; | 838 | struct joydev *joydev = handle->private; |
836 | 839 | ||
837 | device_del(&joydev->dev); | 840 | device_del(&joydev->dev); |
838 | joydev_cleanup(joydev); | 841 | joydev_cleanup(joydev); |
839 | input_unregister_handle(handle); | 842 | input_unregister_handle(handle); |
840 | put_device(&joydev->dev); | 843 | put_device(&joydev->dev); |
841 | } | 844 | } |
842 | 845 | ||
843 | static const struct input_device_id joydev_blacklist[] = { | 846 | static const struct input_device_id joydev_blacklist[] = { |
844 | { | 847 | { |
845 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 848 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
846 | INPUT_DEVICE_ID_MATCH_KEYBIT, | 849 | INPUT_DEVICE_ID_MATCH_KEYBIT, |
847 | .evbit = { BIT(EV_KEY) }, | 850 | .evbit = { BIT(EV_KEY) }, |
848 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 851 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
849 | }, /* Avoid itouchpads, touchscreens and tablets */ | 852 | }, /* Avoid itouchpads, touchscreens and tablets */ |
850 | { } /* Terminating entry */ | 853 | { } /* Terminating entry */ |
851 | }; | 854 | }; |
852 | 855 | ||
853 | static const struct input_device_id joydev_ids[] = { | 856 | static const struct input_device_id joydev_ids[] = { |
854 | { | 857 | { |
855 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 858 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
856 | INPUT_DEVICE_ID_MATCH_ABSBIT, | 859 | INPUT_DEVICE_ID_MATCH_ABSBIT, |
857 | .evbit = { BIT(EV_ABS) }, | 860 | .evbit = { BIT(EV_ABS) }, |
858 | .absbit = { BIT(ABS_X) }, | 861 | .absbit = { BIT(ABS_X) }, |
859 | }, | 862 | }, |
860 | { | 863 | { |
861 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 864 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
862 | INPUT_DEVICE_ID_MATCH_ABSBIT, | 865 | INPUT_DEVICE_ID_MATCH_ABSBIT, |
863 | .evbit = { BIT(EV_ABS) }, | 866 | .evbit = { BIT(EV_ABS) }, |
864 | .absbit = { BIT(ABS_WHEEL) }, | 867 | .absbit = { BIT(ABS_WHEEL) }, |
865 | }, | 868 | }, |
866 | { | 869 | { |
867 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 870 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
868 | INPUT_DEVICE_ID_MATCH_ABSBIT, | 871 | INPUT_DEVICE_ID_MATCH_ABSBIT, |
869 | .evbit = { BIT(EV_ABS) }, | 872 | .evbit = { BIT(EV_ABS) }, |
870 | .absbit = { BIT(ABS_THROTTLE) }, | 873 | .absbit = { BIT(ABS_THROTTLE) }, |
871 | }, | 874 | }, |
872 | { } /* Terminating entry */ | 875 | { } /* Terminating entry */ |
873 | }; | 876 | }; |
874 | 877 | ||
875 | MODULE_DEVICE_TABLE(input, joydev_ids); | 878 | MODULE_DEVICE_TABLE(input, joydev_ids); |
876 | 879 | ||
877 | static struct input_handler joydev_handler = { | 880 | static struct input_handler joydev_handler = { |
878 | .event = joydev_event, | 881 | .event = joydev_event, |
879 | .connect = joydev_connect, | 882 | .connect = joydev_connect, |
880 | .disconnect = joydev_disconnect, | 883 | .disconnect = joydev_disconnect, |
881 | .fops = &joydev_fops, | 884 | .fops = &joydev_fops, |
882 | .minor = JOYDEV_MINOR_BASE, | 885 | .minor = JOYDEV_MINOR_BASE, |
883 | .name = "joydev", | 886 | .name = "joydev", |
884 | .id_table = joydev_ids, | 887 | .id_table = joydev_ids, |
885 | .blacklist = joydev_blacklist, | 888 | .blacklist = joydev_blacklist, |
886 | }; | 889 | }; |
887 | 890 | ||
888 | static int __init joydev_init(void) | 891 | static int __init joydev_init(void) |
889 | { | 892 | { |
890 | return input_register_handler(&joydev_handler); | 893 | return input_register_handler(&joydev_handler); |
891 | } | 894 | } |
892 | 895 | ||
893 | static void __exit joydev_exit(void) | 896 | static void __exit joydev_exit(void) |
894 | { | 897 | { |
895 | input_unregister_handler(&joydev_handler); | 898 | input_unregister_handler(&joydev_handler); |
896 | } | 899 | } |
897 | 900 | ||
898 | module_init(joydev_init); | 901 | module_init(joydev_init); |
899 | module_exit(joydev_exit); | 902 | module_exit(joydev_exit); |
900 | 903 |
drivers/input/mousedev.c
1 | /* | 1 | /* |
2 | * Input driver to ExplorerPS/2 device driver module. | 2 | * Input driver to ExplorerPS/2 device driver module. |
3 | * | 3 | * |
4 | * Copyright (c) 1999-2002 Vojtech Pavlik | 4 | * Copyright (c) 1999-2002 Vojtech Pavlik |
5 | * Copyright (c) 2004 Dmitry Torokhov | 5 | * Copyright (c) 2004 Dmitry Torokhov |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 as published by | 8 | * it under the terms of the GNU General Public License version 2 as published by |
9 | * the Free Software Foundation. | 9 | * the Free Software Foundation. |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #define MOUSEDEV_MINOR_BASE 32 | 12 | #define MOUSEDEV_MINOR_BASE 32 |
13 | #define MOUSEDEV_MINORS 32 | 13 | #define MOUSEDEV_MINORS 32 |
14 | #define MOUSEDEV_MIX 31 | 14 | #define MOUSEDEV_MIX 31 |
15 | 15 | ||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/poll.h> | 17 | #include <linux/poll.h> |
18 | #include <linux/module.h> | 18 | #include <linux/module.h> |
19 | #include <linux/moduleparam.h> | 19 | #include <linux/moduleparam.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/input.h> | 21 | #include <linux/input.h> |
22 | #include <linux/random.h> | 22 | #include <linux/random.h> |
23 | #include <linux/major.h> | 23 | #include <linux/major.h> |
24 | #include <linux/device.h> | 24 | #include <linux/device.h> |
25 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 25 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
26 | #include <linux/miscdevice.h> | 26 | #include <linux/miscdevice.h> |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 29 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
30 | MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); | 30 | MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); |
31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
32 | 32 | ||
33 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X | 33 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X |
34 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 | 34 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 |
35 | #endif | 35 | #endif |
36 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y | 36 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_Y |
37 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 | 37 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768 |
38 | #endif | 38 | #endif |
39 | 39 | ||
40 | static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; | 40 | static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X; |
41 | module_param(xres, uint, 0644); | 41 | module_param(xres, uint, 0644); |
42 | MODULE_PARM_DESC(xres, "Horizontal screen resolution"); | 42 | MODULE_PARM_DESC(xres, "Horizontal screen resolution"); |
43 | 43 | ||
44 | static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; | 44 | static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y; |
45 | module_param(yres, uint, 0644); | 45 | module_param(yres, uint, 0644); |
46 | MODULE_PARM_DESC(yres, "Vertical screen resolution"); | 46 | MODULE_PARM_DESC(yres, "Vertical screen resolution"); |
47 | 47 | ||
48 | static unsigned tap_time = 200; | 48 | static unsigned tap_time = 200; |
49 | module_param(tap_time, uint, 0644); | 49 | module_param(tap_time, uint, 0644); |
50 | MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); | 50 | MODULE_PARM_DESC(tap_time, "Tap time for touchpads in absolute mode (msecs)"); |
51 | 51 | ||
52 | struct mousedev_hw_data { | 52 | struct mousedev_hw_data { |
53 | int dx, dy, dz; | 53 | int dx, dy, dz; |
54 | int x, y; | 54 | int x, y; |
55 | int abs_event; | 55 | int abs_event; |
56 | unsigned long buttons; | 56 | unsigned long buttons; |
57 | }; | 57 | }; |
58 | 58 | ||
59 | struct mousedev { | 59 | struct mousedev { |
60 | int exist; | 60 | int exist; |
61 | int open; | 61 | int open; |
62 | int minor; | 62 | int minor; |
63 | char name[16]; | 63 | char name[16]; |
64 | struct input_handle handle; | 64 | struct input_handle handle; |
65 | wait_queue_head_t wait; | 65 | wait_queue_head_t wait; |
66 | struct list_head client_list; | 66 | struct list_head client_list; |
67 | spinlock_t client_lock; /* protects client_list */ | 67 | spinlock_t client_lock; /* protects client_list */ |
68 | struct mutex mutex; | 68 | struct mutex mutex; |
69 | struct device dev; | 69 | struct device dev; |
70 | 70 | ||
71 | struct list_head mixdev_node; | 71 | struct list_head mixdev_node; |
72 | int mixdev_open; | 72 | int mixdev_open; |
73 | 73 | ||
74 | struct mousedev_hw_data packet; | 74 | struct mousedev_hw_data packet; |
75 | unsigned int pkt_count; | 75 | unsigned int pkt_count; |
76 | int old_x[4], old_y[4]; | 76 | int old_x[4], old_y[4]; |
77 | int frac_dx, frac_dy; | 77 | int frac_dx, frac_dy; |
78 | unsigned long touch; | 78 | unsigned long touch; |
79 | }; | 79 | }; |
80 | 80 | ||
81 | enum mousedev_emul { | 81 | enum mousedev_emul { |
82 | MOUSEDEV_EMUL_PS2, | 82 | MOUSEDEV_EMUL_PS2, |
83 | MOUSEDEV_EMUL_IMPS, | 83 | MOUSEDEV_EMUL_IMPS, |
84 | MOUSEDEV_EMUL_EXPS | 84 | MOUSEDEV_EMUL_EXPS |
85 | }; | 85 | }; |
86 | 86 | ||
87 | struct mousedev_motion { | 87 | struct mousedev_motion { |
88 | int dx, dy, dz; | 88 | int dx, dy, dz; |
89 | unsigned long buttons; | 89 | unsigned long buttons; |
90 | }; | 90 | }; |
91 | 91 | ||
92 | #define PACKET_QUEUE_LEN 16 | 92 | #define PACKET_QUEUE_LEN 16 |
93 | struct mousedev_client { | 93 | struct mousedev_client { |
94 | struct fasync_struct *fasync; | 94 | struct fasync_struct *fasync; |
95 | struct mousedev *mousedev; | 95 | struct mousedev *mousedev; |
96 | struct list_head node; | 96 | struct list_head node; |
97 | 97 | ||
98 | struct mousedev_motion packets[PACKET_QUEUE_LEN]; | 98 | struct mousedev_motion packets[PACKET_QUEUE_LEN]; |
99 | unsigned int head, tail; | 99 | unsigned int head, tail; |
100 | spinlock_t packet_lock; | 100 | spinlock_t packet_lock; |
101 | int pos_x, pos_y; | 101 | int pos_x, pos_y; |
102 | 102 | ||
103 | signed char ps2[6]; | 103 | signed char ps2[6]; |
104 | unsigned char ready, buffer, bufsiz; | 104 | unsigned char ready, buffer, bufsiz; |
105 | unsigned char imexseq, impsseq; | 105 | unsigned char imexseq, impsseq; |
106 | enum mousedev_emul mode; | 106 | enum mousedev_emul mode; |
107 | unsigned long last_buttons; | 107 | unsigned long last_buttons; |
108 | }; | 108 | }; |
109 | 109 | ||
110 | #define MOUSEDEV_SEQ_LEN 6 | 110 | #define MOUSEDEV_SEQ_LEN 6 |
111 | 111 | ||
112 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; | 112 | static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 }; |
113 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; | 113 | static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 }; |
114 | 114 | ||
115 | static struct input_handler mousedev_handler; | 115 | static struct input_handler mousedev_handler; |
116 | 116 | ||
117 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; | 117 | static struct mousedev *mousedev_table[MOUSEDEV_MINORS]; |
118 | static DEFINE_MUTEX(mousedev_table_mutex); | 118 | static DEFINE_MUTEX(mousedev_table_mutex); |
119 | static struct mousedev *mousedev_mix; | 119 | static struct mousedev *mousedev_mix; |
120 | static LIST_HEAD(mousedev_mix_list); | 120 | static LIST_HEAD(mousedev_mix_list); |
121 | 121 | ||
122 | static void mixdev_open_devices(void); | 122 | static void mixdev_open_devices(void); |
123 | static void mixdev_close_devices(void); | 123 | static void mixdev_close_devices(void); |
124 | 124 | ||
125 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) | 125 | #define fx(i) (mousedev->old_x[(mousedev->pkt_count - (i)) & 03]) |
126 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) | 126 | #define fy(i) (mousedev->old_y[(mousedev->pkt_count - (i)) & 03]) |
127 | 127 | ||
128 | static void mousedev_touchpad_event(struct input_dev *dev, | 128 | static void mousedev_touchpad_event(struct input_dev *dev, |
129 | struct mousedev *mousedev, | 129 | struct mousedev *mousedev, |
130 | unsigned int code, int value) | 130 | unsigned int code, int value) |
131 | { | 131 | { |
132 | int size, tmp; | 132 | int size, tmp; |
133 | enum { FRACTION_DENOM = 128 }; | 133 | enum { FRACTION_DENOM = 128 }; |
134 | 134 | ||
135 | switch (code) { | 135 | switch (code) { |
136 | 136 | ||
137 | case ABS_X: | 137 | case ABS_X: |
138 | fx(0) = value; | 138 | fx(0) = value; |
139 | if (mousedev->touch && mousedev->pkt_count >= 2) { | 139 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
140 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 140 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
141 | if (size == 0) | 141 | if (size == 0) |
142 | size = 256 * 2; | 142 | size = 256 * 2; |
143 | tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; | 143 | tmp = ((value - fx(2)) * 256 * FRACTION_DENOM) / size; |
144 | tmp += mousedev->frac_dx; | 144 | tmp += mousedev->frac_dx; |
145 | mousedev->packet.dx = tmp / FRACTION_DENOM; | 145 | mousedev->packet.dx = tmp / FRACTION_DENOM; |
146 | mousedev->frac_dx = | 146 | mousedev->frac_dx = |
147 | tmp - mousedev->packet.dx * FRACTION_DENOM; | 147 | tmp - mousedev->packet.dx * FRACTION_DENOM; |
148 | } | 148 | } |
149 | break; | 149 | break; |
150 | 150 | ||
151 | case ABS_Y: | 151 | case ABS_Y: |
152 | fy(0) = value; | 152 | fy(0) = value; |
153 | if (mousedev->touch && mousedev->pkt_count >= 2) { | 153 | if (mousedev->touch && mousedev->pkt_count >= 2) { |
154 | /* use X size to keep the same scale */ | 154 | /* use X size to keep the same scale */ |
155 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 155 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
156 | if (size == 0) | 156 | if (size == 0) |
157 | size = 256 * 2; | 157 | size = 256 * 2; |
158 | tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; | 158 | tmp = -((value - fy(2)) * 256 * FRACTION_DENOM) / size; |
159 | tmp += mousedev->frac_dy; | 159 | tmp += mousedev->frac_dy; |
160 | mousedev->packet.dy = tmp / FRACTION_DENOM; | 160 | mousedev->packet.dy = tmp / FRACTION_DENOM; |
161 | mousedev->frac_dy = tmp - | 161 | mousedev->frac_dy = tmp - |
162 | mousedev->packet.dy * FRACTION_DENOM; | 162 | mousedev->packet.dy * FRACTION_DENOM; |
163 | } | 163 | } |
164 | break; | 164 | break; |
165 | } | 165 | } |
166 | } | 166 | } |
167 | 167 | ||
168 | static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, | 168 | static void mousedev_abs_event(struct input_dev *dev, struct mousedev *mousedev, |
169 | unsigned int code, int value) | 169 | unsigned int code, int value) |
170 | { | 170 | { |
171 | int size; | 171 | int size; |
172 | 172 | ||
173 | switch (code) { | 173 | switch (code) { |
174 | 174 | ||
175 | case ABS_X: | 175 | case ABS_X: |
176 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; | 176 | size = dev->absmax[ABS_X] - dev->absmin[ABS_X]; |
177 | if (size == 0) | 177 | if (size == 0) |
178 | size = xres ? : 1; | 178 | size = xres ? : 1; |
179 | if (value > dev->absmax[ABS_X]) | 179 | if (value > dev->absmax[ABS_X]) |
180 | value = dev->absmax[ABS_X]; | 180 | value = dev->absmax[ABS_X]; |
181 | if (value < dev->absmin[ABS_X]) | 181 | if (value < dev->absmin[ABS_X]) |
182 | value = dev->absmin[ABS_X]; | 182 | value = dev->absmin[ABS_X]; |
183 | mousedev->packet.x = | 183 | mousedev->packet.x = |
184 | ((value - dev->absmin[ABS_X]) * xres) / size; | 184 | ((value - dev->absmin[ABS_X]) * xres) / size; |
185 | mousedev->packet.abs_event = 1; | 185 | mousedev->packet.abs_event = 1; |
186 | break; | 186 | break; |
187 | 187 | ||
188 | case ABS_Y: | 188 | case ABS_Y: |
189 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; | 189 | size = dev->absmax[ABS_Y] - dev->absmin[ABS_Y]; |
190 | if (size == 0) | 190 | if (size == 0) |
191 | size = yres ? : 1; | 191 | size = yres ? : 1; |
192 | if (value > dev->absmax[ABS_Y]) | 192 | if (value > dev->absmax[ABS_Y]) |
193 | value = dev->absmax[ABS_Y]; | 193 | value = dev->absmax[ABS_Y]; |
194 | if (value < dev->absmin[ABS_Y]) | 194 | if (value < dev->absmin[ABS_Y]) |
195 | value = dev->absmin[ABS_Y]; | 195 | value = dev->absmin[ABS_Y]; |
196 | mousedev->packet.y = yres - | 196 | mousedev->packet.y = yres - |
197 | ((value - dev->absmin[ABS_Y]) * yres) / size; | 197 | ((value - dev->absmin[ABS_Y]) * yres) / size; |
198 | mousedev->packet.abs_event = 1; | 198 | mousedev->packet.abs_event = 1; |
199 | break; | 199 | break; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | static void mousedev_rel_event(struct mousedev *mousedev, | 203 | static void mousedev_rel_event(struct mousedev *mousedev, |
204 | unsigned int code, int value) | 204 | unsigned int code, int value) |
205 | { | 205 | { |
206 | switch (code) { | 206 | switch (code) { |
207 | case REL_X: | 207 | case REL_X: |
208 | mousedev->packet.dx += value; | 208 | mousedev->packet.dx += value; |
209 | break; | 209 | break; |
210 | 210 | ||
211 | case REL_Y: | 211 | case REL_Y: |
212 | mousedev->packet.dy -= value; | 212 | mousedev->packet.dy -= value; |
213 | break; | 213 | break; |
214 | 214 | ||
215 | case REL_WHEEL: | 215 | case REL_WHEEL: |
216 | mousedev->packet.dz -= value; | 216 | mousedev->packet.dz -= value; |
217 | break; | 217 | break; |
218 | } | 218 | } |
219 | } | 219 | } |
220 | 220 | ||
221 | static void mousedev_key_event(struct mousedev *mousedev, | 221 | static void mousedev_key_event(struct mousedev *mousedev, |
222 | unsigned int code, int value) | 222 | unsigned int code, int value) |
223 | { | 223 | { |
224 | int index; | 224 | int index; |
225 | 225 | ||
226 | switch (code) { | 226 | switch (code) { |
227 | 227 | ||
228 | case BTN_TOUCH: | 228 | case BTN_TOUCH: |
229 | case BTN_0: | 229 | case BTN_0: |
230 | case BTN_LEFT: index = 0; break; | 230 | case BTN_LEFT: index = 0; break; |
231 | 231 | ||
232 | case BTN_STYLUS: | 232 | case BTN_STYLUS: |
233 | case BTN_1: | 233 | case BTN_1: |
234 | case BTN_RIGHT: index = 1; break; | 234 | case BTN_RIGHT: index = 1; break; |
235 | 235 | ||
236 | case BTN_2: | 236 | case BTN_2: |
237 | case BTN_FORWARD: | 237 | case BTN_FORWARD: |
238 | case BTN_STYLUS2: | 238 | case BTN_STYLUS2: |
239 | case BTN_MIDDLE: index = 2; break; | 239 | case BTN_MIDDLE: index = 2; break; |
240 | 240 | ||
241 | case BTN_3: | 241 | case BTN_3: |
242 | case BTN_BACK: | 242 | case BTN_BACK: |
243 | case BTN_SIDE: index = 3; break; | 243 | case BTN_SIDE: index = 3; break; |
244 | 244 | ||
245 | case BTN_4: | 245 | case BTN_4: |
246 | case BTN_EXTRA: index = 4; break; | 246 | case BTN_EXTRA: index = 4; break; |
247 | 247 | ||
248 | default: return; | 248 | default: return; |
249 | } | 249 | } |
250 | 250 | ||
251 | if (value) { | 251 | if (value) { |
252 | set_bit(index, &mousedev->packet.buttons); | 252 | set_bit(index, &mousedev->packet.buttons); |
253 | set_bit(index, &mousedev_mix->packet.buttons); | 253 | set_bit(index, &mousedev_mix->packet.buttons); |
254 | } else { | 254 | } else { |
255 | clear_bit(index, &mousedev->packet.buttons); | 255 | clear_bit(index, &mousedev->packet.buttons); |
256 | clear_bit(index, &mousedev_mix->packet.buttons); | 256 | clear_bit(index, &mousedev_mix->packet.buttons); |
257 | } | 257 | } |
258 | } | 258 | } |
259 | 259 | ||
260 | static void mousedev_notify_readers(struct mousedev *mousedev, | 260 | static void mousedev_notify_readers(struct mousedev *mousedev, |
261 | struct mousedev_hw_data *packet) | 261 | struct mousedev_hw_data *packet) |
262 | { | 262 | { |
263 | struct mousedev_client *client; | 263 | struct mousedev_client *client; |
264 | struct mousedev_motion *p; | 264 | struct mousedev_motion *p; |
265 | unsigned int new_head; | 265 | unsigned int new_head; |
266 | int wake_readers = 0; | 266 | int wake_readers = 0; |
267 | 267 | ||
268 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { | 268 | list_for_each_entry_rcu(client, &mousedev->client_list, node) { |
269 | 269 | ||
270 | /* Just acquire the lock, interrupts already disabled */ | 270 | /* Just acquire the lock, interrupts already disabled */ |
271 | spin_lock(&client->packet_lock); | 271 | spin_lock(&client->packet_lock); |
272 | 272 | ||
273 | p = &client->packets[client->head]; | 273 | p = &client->packets[client->head]; |
274 | if (client->ready && p->buttons != mousedev->packet.buttons) { | 274 | if (client->ready && p->buttons != mousedev->packet.buttons) { |
275 | new_head = (client->head + 1) % PACKET_QUEUE_LEN; | 275 | new_head = (client->head + 1) % PACKET_QUEUE_LEN; |
276 | if (new_head != client->tail) { | 276 | if (new_head != client->tail) { |
277 | p = &client->packets[client->head = new_head]; | 277 | p = &client->packets[client->head = new_head]; |
278 | memset(p, 0, sizeof(struct mousedev_motion)); | 278 | memset(p, 0, sizeof(struct mousedev_motion)); |
279 | } | 279 | } |
280 | } | 280 | } |
281 | 281 | ||
282 | if (packet->abs_event) { | 282 | if (packet->abs_event) { |
283 | p->dx += packet->x - client->pos_x; | 283 | p->dx += packet->x - client->pos_x; |
284 | p->dy += packet->y - client->pos_y; | 284 | p->dy += packet->y - client->pos_y; |
285 | client->pos_x = packet->x; | 285 | client->pos_x = packet->x; |
286 | client->pos_y = packet->y; | 286 | client->pos_y = packet->y; |
287 | } | 287 | } |
288 | 288 | ||
289 | client->pos_x += packet->dx; | 289 | client->pos_x += packet->dx; |
290 | client->pos_x = client->pos_x < 0 ? | 290 | client->pos_x = client->pos_x < 0 ? |
291 | 0 : (client->pos_x >= xres ? xres : client->pos_x); | 291 | 0 : (client->pos_x >= xres ? xres : client->pos_x); |
292 | client->pos_y += packet->dy; | 292 | client->pos_y += packet->dy; |
293 | client->pos_y = client->pos_y < 0 ? | 293 | client->pos_y = client->pos_y < 0 ? |
294 | 0 : (client->pos_y >= yres ? yres : client->pos_y); | 294 | 0 : (client->pos_y >= yres ? yres : client->pos_y); |
295 | 295 | ||
296 | p->dx += packet->dx; | 296 | p->dx += packet->dx; |
297 | p->dy += packet->dy; | 297 | p->dy += packet->dy; |
298 | p->dz += packet->dz; | 298 | p->dz += packet->dz; |
299 | p->buttons = mousedev->packet.buttons; | 299 | p->buttons = mousedev->packet.buttons; |
300 | 300 | ||
301 | if (p->dx || p->dy || p->dz || | 301 | if (p->dx || p->dy || p->dz || |
302 | p->buttons != client->last_buttons) | 302 | p->buttons != client->last_buttons) |
303 | client->ready = 1; | 303 | client->ready = 1; |
304 | 304 | ||
305 | spin_unlock(&client->packet_lock); | 305 | spin_unlock(&client->packet_lock); |
306 | 306 | ||
307 | if (client->ready) { | 307 | if (client->ready) { |
308 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 308 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
309 | wake_readers = 1; | 309 | wake_readers = 1; |
310 | } | 310 | } |
311 | } | 311 | } |
312 | 312 | ||
313 | if (wake_readers) | 313 | if (wake_readers) |
314 | wake_up_interruptible(&mousedev->wait); | 314 | wake_up_interruptible(&mousedev->wait); |
315 | } | 315 | } |
316 | 316 | ||
317 | static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) | 317 | static void mousedev_touchpad_touch(struct mousedev *mousedev, int value) |
318 | { | 318 | { |
319 | if (!value) { | 319 | if (!value) { |
320 | if (mousedev->touch && | 320 | if (mousedev->touch && |
321 | time_before(jiffies, | 321 | time_before(jiffies, |
322 | mousedev->touch + msecs_to_jiffies(tap_time))) { | 322 | mousedev->touch + msecs_to_jiffies(tap_time))) { |
323 | /* | 323 | /* |
324 | * Toggle left button to emulate tap. | 324 | * Toggle left button to emulate tap. |
325 | * We rely on the fact that mousedev_mix always has 0 | 325 | * We rely on the fact that mousedev_mix always has 0 |
326 | * motion packet so we won't mess current position. | 326 | * motion packet so we won't mess current position. |
327 | */ | 327 | */ |
328 | set_bit(0, &mousedev->packet.buttons); | 328 | set_bit(0, &mousedev->packet.buttons); |
329 | set_bit(0, &mousedev_mix->packet.buttons); | 329 | set_bit(0, &mousedev_mix->packet.buttons); |
330 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); | 330 | mousedev_notify_readers(mousedev, &mousedev_mix->packet); |
331 | mousedev_notify_readers(mousedev_mix, | 331 | mousedev_notify_readers(mousedev_mix, |
332 | &mousedev_mix->packet); | 332 | &mousedev_mix->packet); |
333 | clear_bit(0, &mousedev->packet.buttons); | 333 | clear_bit(0, &mousedev->packet.buttons); |
334 | clear_bit(0, &mousedev_mix->packet.buttons); | 334 | clear_bit(0, &mousedev_mix->packet.buttons); |
335 | } | 335 | } |
336 | mousedev->touch = mousedev->pkt_count = 0; | 336 | mousedev->touch = mousedev->pkt_count = 0; |
337 | mousedev->frac_dx = 0; | 337 | mousedev->frac_dx = 0; |
338 | mousedev->frac_dy = 0; | 338 | mousedev->frac_dy = 0; |
339 | 339 | ||
340 | } else if (!mousedev->touch) | 340 | } else if (!mousedev->touch) |
341 | mousedev->touch = jiffies; | 341 | mousedev->touch = jiffies; |
342 | } | 342 | } |
343 | 343 | ||
344 | static void mousedev_event(struct input_handle *handle, | 344 | static void mousedev_event(struct input_handle *handle, |
345 | unsigned int type, unsigned int code, int value) | 345 | unsigned int type, unsigned int code, int value) |
346 | { | 346 | { |
347 | struct mousedev *mousedev = handle->private; | 347 | struct mousedev *mousedev = handle->private; |
348 | 348 | ||
349 | switch (type) { | 349 | switch (type) { |
350 | 350 | ||
351 | case EV_ABS: | 351 | case EV_ABS: |
352 | /* Ignore joysticks */ | 352 | /* Ignore joysticks */ |
353 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) | 353 | if (test_bit(BTN_TRIGGER, handle->dev->keybit)) |
354 | return; | 354 | return; |
355 | 355 | ||
356 | if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | 356 | if (test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) |
357 | mousedev_touchpad_event(handle->dev, | 357 | mousedev_touchpad_event(handle->dev, |
358 | mousedev, code, value); | 358 | mousedev, code, value); |
359 | else | 359 | else |
360 | mousedev_abs_event(handle->dev, mousedev, code, value); | 360 | mousedev_abs_event(handle->dev, mousedev, code, value); |
361 | 361 | ||
362 | break; | 362 | break; |
363 | 363 | ||
364 | case EV_REL: | 364 | case EV_REL: |
365 | mousedev_rel_event(mousedev, code, value); | 365 | mousedev_rel_event(mousedev, code, value); |
366 | break; | 366 | break; |
367 | 367 | ||
368 | case EV_KEY: | 368 | case EV_KEY: |
369 | if (value != 2) { | 369 | if (value != 2) { |
370 | if (code == BTN_TOUCH && | 370 | if (code == BTN_TOUCH && |
371 | test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) | 371 | test_bit(BTN_TOOL_FINGER, handle->dev->keybit)) |
372 | mousedev_touchpad_touch(mousedev, value); | 372 | mousedev_touchpad_touch(mousedev, value); |
373 | else | 373 | else |
374 | mousedev_key_event(mousedev, code, value); | 374 | mousedev_key_event(mousedev, code, value); |
375 | } | 375 | } |
376 | break; | 376 | break; |
377 | 377 | ||
378 | case EV_SYN: | 378 | case EV_SYN: |
379 | if (code == SYN_REPORT) { | 379 | if (code == SYN_REPORT) { |
380 | if (mousedev->touch) { | 380 | if (mousedev->touch) { |
381 | mousedev->pkt_count++; | 381 | mousedev->pkt_count++; |
382 | /* | 382 | /* |
383 | * Input system eats duplicate events, | 383 | * Input system eats duplicate events, |
384 | * but we need all of them to do correct | 384 | * but we need all of them to do correct |
385 | * averaging so apply present one forward | 385 | * averaging so apply present one forward |
386 | */ | 386 | */ |
387 | fx(0) = fx(1); | 387 | fx(0) = fx(1); |
388 | fy(0) = fy(1); | 388 | fy(0) = fy(1); |
389 | } | 389 | } |
390 | 390 | ||
391 | mousedev_notify_readers(mousedev, &mousedev->packet); | 391 | mousedev_notify_readers(mousedev, &mousedev->packet); |
392 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); | 392 | mousedev_notify_readers(mousedev_mix, &mousedev->packet); |
393 | 393 | ||
394 | mousedev->packet.dx = mousedev->packet.dy = | 394 | mousedev->packet.dx = mousedev->packet.dy = |
395 | mousedev->packet.dz = 0; | 395 | mousedev->packet.dz = 0; |
396 | mousedev->packet.abs_event = 0; | 396 | mousedev->packet.abs_event = 0; |
397 | } | 397 | } |
398 | break; | 398 | break; |
399 | } | 399 | } |
400 | } | 400 | } |
401 | 401 | ||
402 | static int mousedev_fasync(int fd, struct file *file, int on) | 402 | static int mousedev_fasync(int fd, struct file *file, int on) |
403 | { | 403 | { |
404 | int retval; | 404 | int retval; |
405 | struct mousedev_client *client = file->private_data; | 405 | struct mousedev_client *client = file->private_data; |
406 | 406 | ||
407 | retval = fasync_helper(fd, file, on, &client->fasync); | 407 | retval = fasync_helper(fd, file, on, &client->fasync); |
408 | 408 | ||
409 | return retval < 0 ? retval : 0; | 409 | return retval < 0 ? retval : 0; |
410 | } | 410 | } |
411 | 411 | ||
412 | static void mousedev_free(struct device *dev) | 412 | static void mousedev_free(struct device *dev) |
413 | { | 413 | { |
414 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); | 414 | struct mousedev *mousedev = container_of(dev, struct mousedev, dev); |
415 | 415 | ||
416 | kfree(mousedev); | 416 | kfree(mousedev); |
417 | } | 417 | } |
418 | 418 | ||
419 | static int mousedev_open_device(struct mousedev *mousedev) | 419 | static int mousedev_open_device(struct mousedev *mousedev) |
420 | { | 420 | { |
421 | int retval; | 421 | int retval; |
422 | 422 | ||
423 | retval = mutex_lock_interruptible(&mousedev->mutex); | 423 | retval = mutex_lock_interruptible(&mousedev->mutex); |
424 | if (retval) | 424 | if (retval) |
425 | return retval; | 425 | return retval; |
426 | 426 | ||
427 | if (mousedev->minor == MOUSEDEV_MIX) | 427 | if (mousedev->minor == MOUSEDEV_MIX) |
428 | mixdev_open_devices(); | 428 | mixdev_open_devices(); |
429 | else if (!mousedev->exist) | 429 | else if (!mousedev->exist) |
430 | retval = -ENODEV; | 430 | retval = -ENODEV; |
431 | else if (!mousedev->open++) | 431 | else if (!mousedev->open++) { |
432 | retval = input_open_device(&mousedev->handle); | 432 | retval = input_open_device(&mousedev->handle); |
433 | if (retval) | ||
434 | mousedev->open--; | ||
435 | } | ||
433 | 436 | ||
434 | mutex_unlock(&mousedev->mutex); | 437 | mutex_unlock(&mousedev->mutex); |
435 | return retval; | 438 | return retval; |
436 | } | 439 | } |
437 | 440 | ||
438 | static void mousedev_close_device(struct mousedev *mousedev) | 441 | static void mousedev_close_device(struct mousedev *mousedev) |
439 | { | 442 | { |
440 | mutex_lock(&mousedev->mutex); | 443 | mutex_lock(&mousedev->mutex); |
441 | 444 | ||
442 | if (mousedev->minor == MOUSEDEV_MIX) | 445 | if (mousedev->minor == MOUSEDEV_MIX) |
443 | mixdev_close_devices(); | 446 | mixdev_close_devices(); |
444 | else if (mousedev->exist && !--mousedev->open) | 447 | else if (mousedev->exist && !--mousedev->open) |
445 | input_close_device(&mousedev->handle); | 448 | input_close_device(&mousedev->handle); |
446 | 449 | ||
447 | mutex_unlock(&mousedev->mutex); | 450 | mutex_unlock(&mousedev->mutex); |
448 | } | 451 | } |
449 | 452 | ||
450 | /* | 453 | /* |
451 | * Open all available devices so they can all be multiplexed in one. | 454 | * Open all available devices so they can all be multiplexed in one. |
452 | * stream. Note that this function is called with mousedev_mix->mutex | 455 | * stream. Note that this function is called with mousedev_mix->mutex |
453 | * held. | 456 | * held. |
454 | */ | 457 | */ |
455 | static void mixdev_open_devices(void) | 458 | static void mixdev_open_devices(void) |
456 | { | 459 | { |
457 | struct mousedev *mousedev; | 460 | struct mousedev *mousedev; |
458 | 461 | ||
459 | if (mousedev_mix->open++) | 462 | if (mousedev_mix->open++) |
460 | return; | 463 | return; |
461 | 464 | ||
462 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 465 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
463 | if (!mousedev->mixdev_open) { | 466 | if (!mousedev->mixdev_open) { |
464 | if (mousedev_open_device(mousedev)) | 467 | if (mousedev_open_device(mousedev)) |
465 | continue; | 468 | continue; |
466 | 469 | ||
467 | mousedev->mixdev_open = 1; | 470 | mousedev->mixdev_open = 1; |
468 | } | 471 | } |
469 | } | 472 | } |
470 | } | 473 | } |
471 | 474 | ||
472 | /* | 475 | /* |
473 | * Close all devices that were opened as part of multiplexed | 476 | * Close all devices that were opened as part of multiplexed |
474 | * device. Note that this function is called with mousedev_mix->mutex | 477 | * device. Note that this function is called with mousedev_mix->mutex |
475 | * held. | 478 | * held. |
476 | */ | 479 | */ |
477 | static void mixdev_close_devices(void) | 480 | static void mixdev_close_devices(void) |
478 | { | 481 | { |
479 | struct mousedev *mousedev; | 482 | struct mousedev *mousedev; |
480 | 483 | ||
481 | if (--mousedev_mix->open) | 484 | if (--mousedev_mix->open) |
482 | return; | 485 | return; |
483 | 486 | ||
484 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { | 487 | list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) { |
485 | if (mousedev->mixdev_open) { | 488 | if (mousedev->mixdev_open) { |
486 | mousedev->mixdev_open = 0; | 489 | mousedev->mixdev_open = 0; |
487 | mousedev_close_device(mousedev); | 490 | mousedev_close_device(mousedev); |
488 | } | 491 | } |
489 | } | 492 | } |
490 | } | 493 | } |
491 | 494 | ||
492 | 495 | ||
493 | static void mousedev_attach_client(struct mousedev *mousedev, | 496 | static void mousedev_attach_client(struct mousedev *mousedev, |
494 | struct mousedev_client *client) | 497 | struct mousedev_client *client) |
495 | { | 498 | { |
496 | spin_lock(&mousedev->client_lock); | 499 | spin_lock(&mousedev->client_lock); |
497 | list_add_tail_rcu(&client->node, &mousedev->client_list); | 500 | list_add_tail_rcu(&client->node, &mousedev->client_list); |
498 | spin_unlock(&mousedev->client_lock); | 501 | spin_unlock(&mousedev->client_lock); |
499 | /* | 502 | /* |
500 | * We don't use synchronize_rcu() here because read-side | 503 | * We don't use synchronize_rcu() here because read-side |
501 | * critical section is protected by a spinlock (dev->event_lock) | 504 | * critical section is protected by a spinlock (dev->event_lock) |
502 | * instead of rcu_read_lock(). | 505 | * instead of rcu_read_lock(). |
503 | */ | 506 | */ |
504 | synchronize_sched(); | 507 | synchronize_sched(); |
505 | } | 508 | } |
506 | 509 | ||
507 | static void mousedev_detach_client(struct mousedev *mousedev, | 510 | static void mousedev_detach_client(struct mousedev *mousedev, |
508 | struct mousedev_client *client) | 511 | struct mousedev_client *client) |
509 | { | 512 | { |
510 | spin_lock(&mousedev->client_lock); | 513 | spin_lock(&mousedev->client_lock); |
511 | list_del_rcu(&client->node); | 514 | list_del_rcu(&client->node); |
512 | spin_unlock(&mousedev->client_lock); | 515 | spin_unlock(&mousedev->client_lock); |
513 | synchronize_sched(); | 516 | synchronize_sched(); |
514 | } | 517 | } |
515 | 518 | ||
516 | static int mousedev_release(struct inode *inode, struct file *file) | 519 | static int mousedev_release(struct inode *inode, struct file *file) |
517 | { | 520 | { |
518 | struct mousedev_client *client = file->private_data; | 521 | struct mousedev_client *client = file->private_data; |
519 | struct mousedev *mousedev = client->mousedev; | 522 | struct mousedev *mousedev = client->mousedev; |
520 | 523 | ||
521 | mousedev_fasync(-1, file, 0); | 524 | mousedev_fasync(-1, file, 0); |
522 | mousedev_detach_client(mousedev, client); | 525 | mousedev_detach_client(mousedev, client); |
523 | kfree(client); | 526 | kfree(client); |
524 | 527 | ||
525 | mousedev_close_device(mousedev); | 528 | mousedev_close_device(mousedev); |
526 | put_device(&mousedev->dev); | 529 | put_device(&mousedev->dev); |
527 | 530 | ||
528 | return 0; | 531 | return 0; |
529 | } | 532 | } |
530 | 533 | ||
531 | static int mousedev_open(struct inode *inode, struct file *file) | 534 | static int mousedev_open(struct inode *inode, struct file *file) |
532 | { | 535 | { |
533 | struct mousedev_client *client; | 536 | struct mousedev_client *client; |
534 | struct mousedev *mousedev; | 537 | struct mousedev *mousedev; |
535 | int error; | 538 | int error; |
536 | int i; | 539 | int i; |
537 | 540 | ||
538 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 541 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
539 | if (imajor(inode) == MISC_MAJOR) | 542 | if (imajor(inode) == MISC_MAJOR) |
540 | i = MOUSEDEV_MIX; | 543 | i = MOUSEDEV_MIX; |
541 | else | 544 | else |
542 | #endif | 545 | #endif |
543 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; | 546 | i = iminor(inode) - MOUSEDEV_MINOR_BASE; |
544 | 547 | ||
545 | if (i >= MOUSEDEV_MINORS) | 548 | if (i >= MOUSEDEV_MINORS) |
546 | return -ENODEV; | 549 | return -ENODEV; |
547 | 550 | ||
548 | error = mutex_lock_interruptible(&mousedev_table_mutex); | 551 | error = mutex_lock_interruptible(&mousedev_table_mutex); |
549 | if (error) | 552 | if (error) |
550 | return error; | 553 | return error; |
551 | mousedev = mousedev_table[i]; | 554 | mousedev = mousedev_table[i]; |
552 | if (mousedev) | 555 | if (mousedev) |
553 | get_device(&mousedev->dev); | 556 | get_device(&mousedev->dev); |
554 | mutex_unlock(&mousedev_table_mutex); | 557 | mutex_unlock(&mousedev_table_mutex); |
555 | 558 | ||
556 | if (!mousedev) | 559 | if (!mousedev) |
557 | return -ENODEV; | 560 | return -ENODEV; |
558 | 561 | ||
559 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); | 562 | client = kzalloc(sizeof(struct mousedev_client), GFP_KERNEL); |
560 | if (!client) { | 563 | if (!client) { |
561 | error = -ENOMEM; | 564 | error = -ENOMEM; |
562 | goto err_put_mousedev; | 565 | goto err_put_mousedev; |
563 | } | 566 | } |
564 | 567 | ||
565 | spin_lock_init(&client->packet_lock); | 568 | spin_lock_init(&client->packet_lock); |
566 | client->pos_x = xres / 2; | 569 | client->pos_x = xres / 2; |
567 | client->pos_y = yres / 2; | 570 | client->pos_y = yres / 2; |
568 | client->mousedev = mousedev; | 571 | client->mousedev = mousedev; |
569 | mousedev_attach_client(mousedev, client); | 572 | mousedev_attach_client(mousedev, client); |
570 | 573 | ||
571 | error = mousedev_open_device(mousedev); | 574 | error = mousedev_open_device(mousedev); |
572 | if (error) | 575 | if (error) |
573 | goto err_free_client; | 576 | goto err_free_client; |
574 | 577 | ||
575 | file->private_data = client; | 578 | file->private_data = client; |
576 | return 0; | 579 | return 0; |
577 | 580 | ||
578 | err_free_client: | 581 | err_free_client: |
579 | mousedev_detach_client(mousedev, client); | 582 | mousedev_detach_client(mousedev, client); |
580 | kfree(client); | 583 | kfree(client); |
581 | err_put_mousedev: | 584 | err_put_mousedev: |
582 | put_device(&mousedev->dev); | 585 | put_device(&mousedev->dev); |
583 | return error; | 586 | return error; |
584 | } | 587 | } |
585 | 588 | ||
586 | static inline int mousedev_limit_delta(int delta, int limit) | 589 | static inline int mousedev_limit_delta(int delta, int limit) |
587 | { | 590 | { |
588 | return delta > limit ? limit : (delta < -limit ? -limit : delta); | 591 | return delta > limit ? limit : (delta < -limit ? -limit : delta); |
589 | } | 592 | } |
590 | 593 | ||
591 | static void mousedev_packet(struct mousedev_client *client, | 594 | static void mousedev_packet(struct mousedev_client *client, |
592 | signed char *ps2_data) | 595 | signed char *ps2_data) |
593 | { | 596 | { |
594 | struct mousedev_motion *p = &client->packets[client->tail]; | 597 | struct mousedev_motion *p = &client->packets[client->tail]; |
595 | 598 | ||
596 | ps2_data[0] = 0x08 | | 599 | ps2_data[0] = 0x08 | |
597 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); | 600 | ((p->dx < 0) << 4) | ((p->dy < 0) << 5) | (p->buttons & 0x07); |
598 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); | 601 | ps2_data[1] = mousedev_limit_delta(p->dx, 127); |
599 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); | 602 | ps2_data[2] = mousedev_limit_delta(p->dy, 127); |
600 | p->dx -= ps2_data[1]; | 603 | p->dx -= ps2_data[1]; |
601 | p->dy -= ps2_data[2]; | 604 | p->dy -= ps2_data[2]; |
602 | 605 | ||
603 | switch (client->mode) { | 606 | switch (client->mode) { |
604 | case MOUSEDEV_EMUL_EXPS: | 607 | case MOUSEDEV_EMUL_EXPS: |
605 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); | 608 | ps2_data[3] = mousedev_limit_delta(p->dz, 7); |
606 | p->dz -= ps2_data[3]; | 609 | p->dz -= ps2_data[3]; |
607 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); | 610 | ps2_data[3] = (ps2_data[3] & 0x0f) | ((p->buttons & 0x18) << 1); |
608 | client->bufsiz = 4; | 611 | client->bufsiz = 4; |
609 | break; | 612 | break; |
610 | 613 | ||
611 | case MOUSEDEV_EMUL_IMPS: | 614 | case MOUSEDEV_EMUL_IMPS: |
612 | ps2_data[0] |= | 615 | ps2_data[0] |= |
613 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 616 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
614 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); | 617 | ps2_data[3] = mousedev_limit_delta(p->dz, 127); |
615 | p->dz -= ps2_data[3]; | 618 | p->dz -= ps2_data[3]; |
616 | client->bufsiz = 4; | 619 | client->bufsiz = 4; |
617 | break; | 620 | break; |
618 | 621 | ||
619 | case MOUSEDEV_EMUL_PS2: | 622 | case MOUSEDEV_EMUL_PS2: |
620 | default: | 623 | default: |
621 | ps2_data[0] |= | 624 | ps2_data[0] |= |
622 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); | 625 | ((p->buttons & 0x10) >> 3) | ((p->buttons & 0x08) >> 1); |
623 | p->dz = 0; | 626 | p->dz = 0; |
624 | client->bufsiz = 3; | 627 | client->bufsiz = 3; |
625 | break; | 628 | break; |
626 | } | 629 | } |
627 | 630 | ||
628 | if (!p->dx && !p->dy && !p->dz) { | 631 | if (!p->dx && !p->dy && !p->dz) { |
629 | if (client->tail == client->head) { | 632 | if (client->tail == client->head) { |
630 | client->ready = 0; | 633 | client->ready = 0; |
631 | client->last_buttons = p->buttons; | 634 | client->last_buttons = p->buttons; |
632 | } else | 635 | } else |
633 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; | 636 | client->tail = (client->tail + 1) % PACKET_QUEUE_LEN; |
634 | } | 637 | } |
635 | } | 638 | } |
636 | 639 | ||
637 | static void mousedev_generate_response(struct mousedev_client *client, | 640 | static void mousedev_generate_response(struct mousedev_client *client, |
638 | int command) | 641 | int command) |
639 | { | 642 | { |
640 | client->ps2[0] = 0xfa; /* ACK */ | 643 | client->ps2[0] = 0xfa; /* ACK */ |
641 | 644 | ||
642 | switch (command) { | 645 | switch (command) { |
643 | 646 | ||
644 | case 0xeb: /* Poll */ | 647 | case 0xeb: /* Poll */ |
645 | mousedev_packet(client, &client->ps2[1]); | 648 | mousedev_packet(client, &client->ps2[1]); |
646 | client->bufsiz++; /* account for leading ACK */ | 649 | client->bufsiz++; /* account for leading ACK */ |
647 | break; | 650 | break; |
648 | 651 | ||
649 | case 0xf2: /* Get ID */ | 652 | case 0xf2: /* Get ID */ |
650 | switch (client->mode) { | 653 | switch (client->mode) { |
651 | case MOUSEDEV_EMUL_PS2: | 654 | case MOUSEDEV_EMUL_PS2: |
652 | client->ps2[1] = 0; | 655 | client->ps2[1] = 0; |
653 | break; | 656 | break; |
654 | case MOUSEDEV_EMUL_IMPS: | 657 | case MOUSEDEV_EMUL_IMPS: |
655 | client->ps2[1] = 3; | 658 | client->ps2[1] = 3; |
656 | break; | 659 | break; |
657 | case MOUSEDEV_EMUL_EXPS: | 660 | case MOUSEDEV_EMUL_EXPS: |
658 | client->ps2[1] = 4; | 661 | client->ps2[1] = 4; |
659 | break; | 662 | break; |
660 | } | 663 | } |
661 | client->bufsiz = 2; | 664 | client->bufsiz = 2; |
662 | break; | 665 | break; |
663 | 666 | ||
664 | case 0xe9: /* Get info */ | 667 | case 0xe9: /* Get info */ |
665 | client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; | 668 | client->ps2[1] = 0x60; client->ps2[2] = 3; client->ps2[3] = 200; |
666 | client->bufsiz = 4; | 669 | client->bufsiz = 4; |
667 | break; | 670 | break; |
668 | 671 | ||
669 | case 0xff: /* Reset */ | 672 | case 0xff: /* Reset */ |
670 | client->impsseq = client->imexseq = 0; | 673 | client->impsseq = client->imexseq = 0; |
671 | client->mode = MOUSEDEV_EMUL_PS2; | 674 | client->mode = MOUSEDEV_EMUL_PS2; |
672 | client->ps2[1] = 0xaa; client->ps2[2] = 0x00; | 675 | client->ps2[1] = 0xaa; client->ps2[2] = 0x00; |
673 | client->bufsiz = 3; | 676 | client->bufsiz = 3; |
674 | break; | 677 | break; |
675 | 678 | ||
676 | default: | 679 | default: |
677 | client->bufsiz = 1; | 680 | client->bufsiz = 1; |
678 | break; | 681 | break; |
679 | } | 682 | } |
680 | client->buffer = client->bufsiz; | 683 | client->buffer = client->bufsiz; |
681 | } | 684 | } |
682 | 685 | ||
683 | static ssize_t mousedev_write(struct file *file, const char __user *buffer, | 686 | static ssize_t mousedev_write(struct file *file, const char __user *buffer, |
684 | size_t count, loff_t *ppos) | 687 | size_t count, loff_t *ppos) |
685 | { | 688 | { |
686 | struct mousedev_client *client = file->private_data; | 689 | struct mousedev_client *client = file->private_data; |
687 | unsigned char c; | 690 | unsigned char c; |
688 | unsigned int i; | 691 | unsigned int i; |
689 | 692 | ||
690 | for (i = 0; i < count; i++) { | 693 | for (i = 0; i < count; i++) { |
691 | 694 | ||
692 | if (get_user(c, buffer + i)) | 695 | if (get_user(c, buffer + i)) |
693 | return -EFAULT; | 696 | return -EFAULT; |
694 | 697 | ||
695 | spin_lock_irq(&client->packet_lock); | 698 | spin_lock_irq(&client->packet_lock); |
696 | 699 | ||
697 | if (c == mousedev_imex_seq[client->imexseq]) { | 700 | if (c == mousedev_imex_seq[client->imexseq]) { |
698 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { | 701 | if (++client->imexseq == MOUSEDEV_SEQ_LEN) { |
699 | client->imexseq = 0; | 702 | client->imexseq = 0; |
700 | client->mode = MOUSEDEV_EMUL_EXPS; | 703 | client->mode = MOUSEDEV_EMUL_EXPS; |
701 | } | 704 | } |
702 | } else | 705 | } else |
703 | client->imexseq = 0; | 706 | client->imexseq = 0; |
704 | 707 | ||
705 | if (c == mousedev_imps_seq[client->impsseq]) { | 708 | if (c == mousedev_imps_seq[client->impsseq]) { |
706 | if (++client->impsseq == MOUSEDEV_SEQ_LEN) { | 709 | if (++client->impsseq == MOUSEDEV_SEQ_LEN) { |
707 | client->impsseq = 0; | 710 | client->impsseq = 0; |
708 | client->mode = MOUSEDEV_EMUL_IMPS; | 711 | client->mode = MOUSEDEV_EMUL_IMPS; |
709 | } | 712 | } |
710 | } else | 713 | } else |
711 | client->impsseq = 0; | 714 | client->impsseq = 0; |
712 | 715 | ||
713 | mousedev_generate_response(client, c); | 716 | mousedev_generate_response(client, c); |
714 | 717 | ||
715 | spin_unlock_irq(&client->packet_lock); | 718 | spin_unlock_irq(&client->packet_lock); |
716 | } | 719 | } |
717 | 720 | ||
718 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 721 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
719 | wake_up_interruptible(&client->mousedev->wait); | 722 | wake_up_interruptible(&client->mousedev->wait); |
720 | 723 | ||
721 | return count; | 724 | return count; |
722 | } | 725 | } |
723 | 726 | ||
724 | static ssize_t mousedev_read(struct file *file, char __user *buffer, | 727 | static ssize_t mousedev_read(struct file *file, char __user *buffer, |
725 | size_t count, loff_t *ppos) | 728 | size_t count, loff_t *ppos) |
726 | { | 729 | { |
727 | struct mousedev_client *client = file->private_data; | 730 | struct mousedev_client *client = file->private_data; |
728 | struct mousedev *mousedev = client->mousedev; | 731 | struct mousedev *mousedev = client->mousedev; |
729 | signed char data[sizeof(client->ps2)]; | 732 | signed char data[sizeof(client->ps2)]; |
730 | int retval = 0; | 733 | int retval = 0; |
731 | 734 | ||
732 | if (!client->ready && !client->buffer && mousedev->exist && | 735 | if (!client->ready && !client->buffer && mousedev->exist && |
733 | (file->f_flags & O_NONBLOCK)) | 736 | (file->f_flags & O_NONBLOCK)) |
734 | return -EAGAIN; | 737 | return -EAGAIN; |
735 | 738 | ||
736 | retval = wait_event_interruptible(mousedev->wait, | 739 | retval = wait_event_interruptible(mousedev->wait, |
737 | !mousedev->exist || client->ready || client->buffer); | 740 | !mousedev->exist || client->ready || client->buffer); |
738 | if (retval) | 741 | if (retval) |
739 | return retval; | 742 | return retval; |
740 | 743 | ||
741 | if (!mousedev->exist) | 744 | if (!mousedev->exist) |
742 | return -ENODEV; | 745 | return -ENODEV; |
743 | 746 | ||
744 | spin_lock_irq(&client->packet_lock); | 747 | spin_lock_irq(&client->packet_lock); |
745 | 748 | ||
746 | if (!client->buffer && client->ready) { | 749 | if (!client->buffer && client->ready) { |
747 | mousedev_packet(client, client->ps2); | 750 | mousedev_packet(client, client->ps2); |
748 | client->buffer = client->bufsiz; | 751 | client->buffer = client->bufsiz; |
749 | } | 752 | } |
750 | 753 | ||
751 | if (count > client->buffer) | 754 | if (count > client->buffer) |
752 | count = client->buffer; | 755 | count = client->buffer; |
753 | 756 | ||
754 | memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); | 757 | memcpy(data, client->ps2 + client->bufsiz - client->buffer, count); |
755 | client->buffer -= count; | 758 | client->buffer -= count; |
756 | 759 | ||
757 | spin_unlock_irq(&client->packet_lock); | 760 | spin_unlock_irq(&client->packet_lock); |
758 | 761 | ||
759 | if (copy_to_user(buffer, data, count)) | 762 | if (copy_to_user(buffer, data, count)) |
760 | return -EFAULT; | 763 | return -EFAULT; |
761 | 764 | ||
762 | return count; | 765 | return count; |
763 | } | 766 | } |
764 | 767 | ||
765 | /* No kernel lock - fine */ | 768 | /* No kernel lock - fine */ |
766 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) | 769 | static unsigned int mousedev_poll(struct file *file, poll_table *wait) |
767 | { | 770 | { |
768 | struct mousedev_client *client = file->private_data; | 771 | struct mousedev_client *client = file->private_data; |
769 | struct mousedev *mousedev = client->mousedev; | 772 | struct mousedev *mousedev = client->mousedev; |
770 | 773 | ||
771 | poll_wait(file, &mousedev->wait, wait); | 774 | poll_wait(file, &mousedev->wait, wait); |
772 | return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) | | 775 | return ((client->ready || client->buffer) ? (POLLIN | POLLRDNORM) : 0) | |
773 | (mousedev->exist ? 0 : (POLLHUP | POLLERR)); | 776 | (mousedev->exist ? 0 : (POLLHUP | POLLERR)); |
774 | } | 777 | } |
775 | 778 | ||
776 | static const struct file_operations mousedev_fops = { | 779 | static const struct file_operations mousedev_fops = { |
777 | .owner = THIS_MODULE, | 780 | .owner = THIS_MODULE, |
778 | .read = mousedev_read, | 781 | .read = mousedev_read, |
779 | .write = mousedev_write, | 782 | .write = mousedev_write, |
780 | .poll = mousedev_poll, | 783 | .poll = mousedev_poll, |
781 | .open = mousedev_open, | 784 | .open = mousedev_open, |
782 | .release = mousedev_release, | 785 | .release = mousedev_release, |
783 | .fasync = mousedev_fasync, | 786 | .fasync = mousedev_fasync, |
784 | }; | 787 | }; |
785 | 788 | ||
786 | static int mousedev_install_chrdev(struct mousedev *mousedev) | 789 | static int mousedev_install_chrdev(struct mousedev *mousedev) |
787 | { | 790 | { |
788 | mousedev_table[mousedev->minor] = mousedev; | 791 | mousedev_table[mousedev->minor] = mousedev; |
789 | return 0; | 792 | return 0; |
790 | } | 793 | } |
791 | 794 | ||
792 | static void mousedev_remove_chrdev(struct mousedev *mousedev) | 795 | static void mousedev_remove_chrdev(struct mousedev *mousedev) |
793 | { | 796 | { |
794 | mutex_lock(&mousedev_table_mutex); | 797 | mutex_lock(&mousedev_table_mutex); |
795 | mousedev_table[mousedev->minor] = NULL; | 798 | mousedev_table[mousedev->minor] = NULL; |
796 | mutex_unlock(&mousedev_table_mutex); | 799 | mutex_unlock(&mousedev_table_mutex); |
797 | } | 800 | } |
798 | 801 | ||
799 | /* | 802 | /* |
800 | * Mark device non-existent. This disables writes, ioctls and | 803 | * Mark device non-existent. This disables writes, ioctls and |
801 | * prevents new users from opening the device. Already posted | 804 | * prevents new users from opening the device. Already posted |
802 | * blocking reads will stay, however new ones will fail. | 805 | * blocking reads will stay, however new ones will fail. |
803 | */ | 806 | */ |
804 | static void mousedev_mark_dead(struct mousedev *mousedev) | 807 | static void mousedev_mark_dead(struct mousedev *mousedev) |
805 | { | 808 | { |
806 | mutex_lock(&mousedev->mutex); | 809 | mutex_lock(&mousedev->mutex); |
807 | mousedev->exist = 0; | 810 | mousedev->exist = 0; |
808 | mutex_unlock(&mousedev->mutex); | 811 | mutex_unlock(&mousedev->mutex); |
809 | } | 812 | } |
810 | 813 | ||
811 | /* | 814 | /* |
812 | * Wake up users waiting for IO so they can disconnect from | 815 | * Wake up users waiting for IO so they can disconnect from |
813 | * dead device. | 816 | * dead device. |
814 | */ | 817 | */ |
815 | static void mousedev_hangup(struct mousedev *mousedev) | 818 | static void mousedev_hangup(struct mousedev *mousedev) |
816 | { | 819 | { |
817 | struct mousedev_client *client; | 820 | struct mousedev_client *client; |
818 | 821 | ||
819 | spin_lock(&mousedev->client_lock); | 822 | spin_lock(&mousedev->client_lock); |
820 | list_for_each_entry(client, &mousedev->client_list, node) | 823 | list_for_each_entry(client, &mousedev->client_list, node) |
821 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 824 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
822 | spin_unlock(&mousedev->client_lock); | 825 | spin_unlock(&mousedev->client_lock); |
823 | 826 | ||
824 | wake_up_interruptible(&mousedev->wait); | 827 | wake_up_interruptible(&mousedev->wait); |
825 | } | 828 | } |
826 | 829 | ||
827 | static void mousedev_cleanup(struct mousedev *mousedev) | 830 | static void mousedev_cleanup(struct mousedev *mousedev) |
828 | { | 831 | { |
829 | struct input_handle *handle = &mousedev->handle; | 832 | struct input_handle *handle = &mousedev->handle; |
830 | 833 | ||
831 | mousedev_mark_dead(mousedev); | 834 | mousedev_mark_dead(mousedev); |
832 | mousedev_hangup(mousedev); | 835 | mousedev_hangup(mousedev); |
833 | mousedev_remove_chrdev(mousedev); | 836 | mousedev_remove_chrdev(mousedev); |
834 | 837 | ||
835 | /* mousedev is marked dead so no one else accesses mousedev->open */ | 838 | /* mousedev is marked dead so no one else accesses mousedev->open */ |
836 | if (mousedev->open) | 839 | if (mousedev->open) |
837 | input_close_device(handle); | 840 | input_close_device(handle); |
838 | } | 841 | } |
839 | 842 | ||
840 | static struct mousedev *mousedev_create(struct input_dev *dev, | 843 | static struct mousedev *mousedev_create(struct input_dev *dev, |
841 | struct input_handler *handler, | 844 | struct input_handler *handler, |
842 | int minor) | 845 | int minor) |
843 | { | 846 | { |
844 | struct mousedev *mousedev; | 847 | struct mousedev *mousedev; |
845 | int error; | 848 | int error; |
846 | 849 | ||
847 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); | 850 | mousedev = kzalloc(sizeof(struct mousedev), GFP_KERNEL); |
848 | if (!mousedev) { | 851 | if (!mousedev) { |
849 | error = -ENOMEM; | 852 | error = -ENOMEM; |
850 | goto err_out; | 853 | goto err_out; |
851 | } | 854 | } |
852 | 855 | ||
853 | INIT_LIST_HEAD(&mousedev->client_list); | 856 | INIT_LIST_HEAD(&mousedev->client_list); |
854 | INIT_LIST_HEAD(&mousedev->mixdev_node); | 857 | INIT_LIST_HEAD(&mousedev->mixdev_node); |
855 | spin_lock_init(&mousedev->client_lock); | 858 | spin_lock_init(&mousedev->client_lock); |
856 | mutex_init(&mousedev->mutex); | 859 | mutex_init(&mousedev->mutex); |
857 | lockdep_set_subclass(&mousedev->mutex, | 860 | lockdep_set_subclass(&mousedev->mutex, |
858 | minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); | 861 | minor == MOUSEDEV_MIX ? MOUSEDEV_MIX : 0); |
859 | init_waitqueue_head(&mousedev->wait); | 862 | init_waitqueue_head(&mousedev->wait); |
860 | 863 | ||
861 | if (minor == MOUSEDEV_MIX) | 864 | if (minor == MOUSEDEV_MIX) |
862 | strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); | 865 | strlcpy(mousedev->name, "mice", sizeof(mousedev->name)); |
863 | else | 866 | else |
864 | snprintf(mousedev->name, sizeof(mousedev->name), | 867 | snprintf(mousedev->name, sizeof(mousedev->name), |
865 | "mouse%d", minor); | 868 | "mouse%d", minor); |
866 | 869 | ||
867 | mousedev->minor = minor; | 870 | mousedev->minor = minor; |
868 | mousedev->exist = 1; | 871 | mousedev->exist = 1; |
869 | mousedev->handle.dev = dev; | 872 | mousedev->handle.dev = dev; |
870 | mousedev->handle.name = mousedev->name; | 873 | mousedev->handle.name = mousedev->name; |
871 | mousedev->handle.handler = handler; | 874 | mousedev->handle.handler = handler; |
872 | mousedev->handle.private = mousedev; | 875 | mousedev->handle.private = mousedev; |
873 | 876 | ||
874 | strlcpy(mousedev->dev.bus_id, mousedev->name, | 877 | strlcpy(mousedev->dev.bus_id, mousedev->name, |
875 | sizeof(mousedev->dev.bus_id)); | 878 | sizeof(mousedev->dev.bus_id)); |
876 | mousedev->dev.class = &input_class; | 879 | mousedev->dev.class = &input_class; |
877 | if (dev) | 880 | if (dev) |
878 | mousedev->dev.parent = &dev->dev; | 881 | mousedev->dev.parent = &dev->dev; |
879 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); | 882 | mousedev->dev.devt = MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor); |
880 | mousedev->dev.release = mousedev_free; | 883 | mousedev->dev.release = mousedev_free; |
881 | device_initialize(&mousedev->dev); | 884 | device_initialize(&mousedev->dev); |
882 | 885 | ||
883 | if (minor != MOUSEDEV_MIX) { | 886 | if (minor != MOUSEDEV_MIX) { |
884 | error = input_register_handle(&mousedev->handle); | 887 | error = input_register_handle(&mousedev->handle); |
885 | if (error) | 888 | if (error) |
886 | goto err_free_mousedev; | 889 | goto err_free_mousedev; |
887 | } | 890 | } |
888 | 891 | ||
889 | error = mousedev_install_chrdev(mousedev); | 892 | error = mousedev_install_chrdev(mousedev); |
890 | if (error) | 893 | if (error) |
891 | goto err_unregister_handle; | 894 | goto err_unregister_handle; |
892 | 895 | ||
893 | error = device_add(&mousedev->dev); | 896 | error = device_add(&mousedev->dev); |
894 | if (error) | 897 | if (error) |
895 | goto err_cleanup_mousedev; | 898 | goto err_cleanup_mousedev; |
896 | 899 | ||
897 | return mousedev; | 900 | return mousedev; |
898 | 901 | ||
899 | err_cleanup_mousedev: | 902 | err_cleanup_mousedev: |
900 | mousedev_cleanup(mousedev); | 903 | mousedev_cleanup(mousedev); |
901 | err_unregister_handle: | 904 | err_unregister_handle: |
902 | if (minor != MOUSEDEV_MIX) | 905 | if (minor != MOUSEDEV_MIX) |
903 | input_unregister_handle(&mousedev->handle); | 906 | input_unregister_handle(&mousedev->handle); |
904 | err_free_mousedev: | 907 | err_free_mousedev: |
905 | put_device(&mousedev->dev); | 908 | put_device(&mousedev->dev); |
906 | err_out: | 909 | err_out: |
907 | return ERR_PTR(error); | 910 | return ERR_PTR(error); |
908 | } | 911 | } |
909 | 912 | ||
910 | static void mousedev_destroy(struct mousedev *mousedev) | 913 | static void mousedev_destroy(struct mousedev *mousedev) |
911 | { | 914 | { |
912 | device_del(&mousedev->dev); | 915 | device_del(&mousedev->dev); |
913 | mousedev_cleanup(mousedev); | 916 | mousedev_cleanup(mousedev); |
914 | if (mousedev->minor != MOUSEDEV_MIX) | 917 | if (mousedev->minor != MOUSEDEV_MIX) |
915 | input_unregister_handle(&mousedev->handle); | 918 | input_unregister_handle(&mousedev->handle); |
916 | put_device(&mousedev->dev); | 919 | put_device(&mousedev->dev); |
917 | } | 920 | } |
918 | 921 | ||
919 | static int mixdev_add_device(struct mousedev *mousedev) | 922 | static int mixdev_add_device(struct mousedev *mousedev) |
920 | { | 923 | { |
921 | int retval; | 924 | int retval; |
922 | 925 | ||
923 | retval = mutex_lock_interruptible(&mousedev_mix->mutex); | 926 | retval = mutex_lock_interruptible(&mousedev_mix->mutex); |
924 | if (retval) | 927 | if (retval) |
925 | return retval; | 928 | return retval; |
926 | 929 | ||
927 | if (mousedev_mix->open) { | 930 | if (mousedev_mix->open) { |
928 | retval = mousedev_open_device(mousedev); | 931 | retval = mousedev_open_device(mousedev); |
929 | if (retval) | 932 | if (retval) |
930 | goto out; | 933 | goto out; |
931 | 934 | ||
932 | mousedev->mixdev_open = 1; | 935 | mousedev->mixdev_open = 1; |
933 | } | 936 | } |
934 | 937 | ||
935 | get_device(&mousedev->dev); | 938 | get_device(&mousedev->dev); |
936 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); | 939 | list_add_tail(&mousedev->mixdev_node, &mousedev_mix_list); |
937 | 940 | ||
938 | out: | 941 | out: |
939 | mutex_unlock(&mousedev_mix->mutex); | 942 | mutex_unlock(&mousedev_mix->mutex); |
940 | return retval; | 943 | return retval; |
941 | } | 944 | } |
942 | 945 | ||
943 | static void mixdev_remove_device(struct mousedev *mousedev) | 946 | static void mixdev_remove_device(struct mousedev *mousedev) |
944 | { | 947 | { |
945 | mutex_lock(&mousedev_mix->mutex); | 948 | mutex_lock(&mousedev_mix->mutex); |
946 | 949 | ||
947 | if (mousedev->mixdev_open) { | 950 | if (mousedev->mixdev_open) { |
948 | mousedev->mixdev_open = 0; | 951 | mousedev->mixdev_open = 0; |
949 | mousedev_close_device(mousedev); | 952 | mousedev_close_device(mousedev); |
950 | } | 953 | } |
951 | 954 | ||
952 | list_del_init(&mousedev->mixdev_node); | 955 | list_del_init(&mousedev->mixdev_node); |
953 | mutex_unlock(&mousedev_mix->mutex); | 956 | mutex_unlock(&mousedev_mix->mutex); |
954 | 957 | ||
955 | put_device(&mousedev->dev); | 958 | put_device(&mousedev->dev); |
956 | } | 959 | } |
957 | 960 | ||
958 | static int mousedev_connect(struct input_handler *handler, | 961 | static int mousedev_connect(struct input_handler *handler, |
959 | struct input_dev *dev, | 962 | struct input_dev *dev, |
960 | const struct input_device_id *id) | 963 | const struct input_device_id *id) |
961 | { | 964 | { |
962 | struct mousedev *mousedev; | 965 | struct mousedev *mousedev; |
963 | int minor; | 966 | int minor; |
964 | int error; | 967 | int error; |
965 | 968 | ||
966 | for (minor = 0; minor < MOUSEDEV_MINORS; minor++) | 969 | for (minor = 0; minor < MOUSEDEV_MINORS; minor++) |
967 | if (!mousedev_table[minor]) | 970 | if (!mousedev_table[minor]) |
968 | break; | 971 | break; |
969 | 972 | ||
970 | if (minor == MOUSEDEV_MINORS) { | 973 | if (minor == MOUSEDEV_MINORS) { |
971 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | 974 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); |
972 | return -ENFILE; | 975 | return -ENFILE; |
973 | } | 976 | } |
974 | 977 | ||
975 | mousedev = mousedev_create(dev, handler, minor); | 978 | mousedev = mousedev_create(dev, handler, minor); |
976 | if (IS_ERR(mousedev)) | 979 | if (IS_ERR(mousedev)) |
977 | return PTR_ERR(mousedev); | 980 | return PTR_ERR(mousedev); |
978 | 981 | ||
979 | error = mixdev_add_device(mousedev); | 982 | error = mixdev_add_device(mousedev); |
980 | if (error) { | 983 | if (error) { |
981 | mousedev_destroy(mousedev); | 984 | mousedev_destroy(mousedev); |
982 | return error; | 985 | return error; |
983 | } | 986 | } |
984 | 987 | ||
985 | return 0; | 988 | return 0; |
986 | } | 989 | } |
987 | 990 | ||
988 | static void mousedev_disconnect(struct input_handle *handle) | 991 | static void mousedev_disconnect(struct input_handle *handle) |
989 | { | 992 | { |
990 | struct mousedev *mousedev = handle->private; | 993 | struct mousedev *mousedev = handle->private; |
991 | 994 | ||
992 | mixdev_remove_device(mousedev); | 995 | mixdev_remove_device(mousedev); |
993 | mousedev_destroy(mousedev); | 996 | mousedev_destroy(mousedev); |
994 | } | 997 | } |
995 | 998 | ||
996 | static const struct input_device_id mousedev_ids[] = { | 999 | static const struct input_device_id mousedev_ids[] = { |
997 | { | 1000 | { |
998 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 1001 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
999 | INPUT_DEVICE_ID_MATCH_KEYBIT | | 1002 | INPUT_DEVICE_ID_MATCH_KEYBIT | |
1000 | INPUT_DEVICE_ID_MATCH_RELBIT, | 1003 | INPUT_DEVICE_ID_MATCH_RELBIT, |
1001 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1004 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
1002 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | 1005 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
1003 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | 1006 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, |
1004 | }, /* A mouse like device, at least one button, | 1007 | }, /* A mouse like device, at least one button, |
1005 | two relative axes */ | 1008 | two relative axes */ |
1006 | { | 1009 | { |
1007 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 1010 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
1008 | INPUT_DEVICE_ID_MATCH_RELBIT, | 1011 | INPUT_DEVICE_ID_MATCH_RELBIT, |
1009 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 1012 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
1010 | .relbit = { BIT(REL_WHEEL) }, | 1013 | .relbit = { BIT(REL_WHEEL) }, |
1011 | }, /* A separate scrollwheel */ | 1014 | }, /* A separate scrollwheel */ |
1012 | { | 1015 | { |
1013 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 1016 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
1014 | INPUT_DEVICE_ID_MATCH_KEYBIT | | 1017 | INPUT_DEVICE_ID_MATCH_KEYBIT | |
1015 | INPUT_DEVICE_ID_MATCH_ABSBIT, | 1018 | INPUT_DEVICE_ID_MATCH_ABSBIT, |
1016 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1019 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
1017 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 1020 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
1018 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | 1021 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, |
1019 | }, /* A tablet like device, at least touch detection, | 1022 | }, /* A tablet like device, at least touch detection, |
1020 | two absolute axes */ | 1023 | two absolute axes */ |
1021 | { | 1024 | { |
1022 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | | 1025 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | |
1023 | INPUT_DEVICE_ID_MATCH_KEYBIT | | 1026 | INPUT_DEVICE_ID_MATCH_KEYBIT | |
1024 | INPUT_DEVICE_ID_MATCH_ABSBIT, | 1027 | INPUT_DEVICE_ID_MATCH_ABSBIT, |
1025 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 1028 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
1026 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, | 1029 | .keybit = { [LONG(BTN_TOOL_FINGER)] = BIT(BTN_TOOL_FINGER) }, |
1027 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | | 1030 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | |
1028 | BIT(ABS_TOOL_WIDTH) }, | 1031 | BIT(ABS_TOOL_WIDTH) }, |
1029 | }, /* A touchpad */ | 1032 | }, /* A touchpad */ |
1030 | 1033 | ||
1031 | { }, /* Terminating entry */ | 1034 | { }, /* Terminating entry */ |
1032 | }; | 1035 | }; |
1033 | 1036 | ||
1034 | MODULE_DEVICE_TABLE(input, mousedev_ids); | 1037 | MODULE_DEVICE_TABLE(input, mousedev_ids); |
1035 | 1038 | ||
1036 | static struct input_handler mousedev_handler = { | 1039 | static struct input_handler mousedev_handler = { |
1037 | .event = mousedev_event, | 1040 | .event = mousedev_event, |
1038 | .connect = mousedev_connect, | 1041 | .connect = mousedev_connect, |
1039 | .disconnect = mousedev_disconnect, | 1042 | .disconnect = mousedev_disconnect, |
1040 | .fops = &mousedev_fops, | 1043 | .fops = &mousedev_fops, |
1041 | .minor = MOUSEDEV_MINOR_BASE, | 1044 | .minor = MOUSEDEV_MINOR_BASE, |
1042 | .name = "mousedev", | 1045 | .name = "mousedev", |
1043 | .id_table = mousedev_ids, | 1046 | .id_table = mousedev_ids, |
1044 | }; | 1047 | }; |
1045 | 1048 | ||
1046 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 1049 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
1047 | static struct miscdevice psaux_mouse = { | 1050 | static struct miscdevice psaux_mouse = { |
1048 | PSMOUSE_MINOR, "psaux", &mousedev_fops | 1051 | PSMOUSE_MINOR, "psaux", &mousedev_fops |
1049 | }; | 1052 | }; |
1050 | static int psaux_registered; | 1053 | static int psaux_registered; |
1051 | #endif | 1054 | #endif |
1052 | 1055 | ||
1053 | static int __init mousedev_init(void) | 1056 | static int __init mousedev_init(void) |
1054 | { | 1057 | { |
1055 | int error; | 1058 | int error; |
1056 | 1059 | ||
1057 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); | 1060 | mousedev_mix = mousedev_create(NULL, &mousedev_handler, MOUSEDEV_MIX); |
1058 | if (IS_ERR(mousedev_mix)) | 1061 | if (IS_ERR(mousedev_mix)) |
1059 | return PTR_ERR(mousedev_mix); | 1062 | return PTR_ERR(mousedev_mix); |
1060 | 1063 | ||
1061 | error = input_register_handler(&mousedev_handler); | 1064 | error = input_register_handler(&mousedev_handler); |
1062 | if (error) { | 1065 | if (error) { |
1063 | mousedev_destroy(mousedev_mix); | 1066 | mousedev_destroy(mousedev_mix); |
1064 | return error; | 1067 | return error; |
1065 | } | 1068 | } |
1066 | 1069 | ||
1067 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 1070 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
1068 | error = misc_register(&psaux_mouse); | 1071 | error = misc_register(&psaux_mouse); |
1069 | if (error) | 1072 | if (error) |
1070 | printk(KERN_WARNING "mice: could not register psaux device, " | 1073 | printk(KERN_WARNING "mice: could not register psaux device, " |
1071 | "error: %d\n", error); | 1074 | "error: %d\n", error); |
1072 | else | 1075 | else |
1073 | psaux_registered = 1; | 1076 | psaux_registered = 1; |
1074 | #endif | 1077 | #endif |
1075 | 1078 | ||
1076 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); | 1079 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); |
1077 | 1080 | ||
1078 | return 0; | 1081 | return 0; |
1079 | } | 1082 | } |
1080 | 1083 | ||
1081 | static void __exit mousedev_exit(void) | 1084 | static void __exit mousedev_exit(void) |
1082 | { | 1085 | { |
1083 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | 1086 | #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX |
1084 | if (psaux_registered) | 1087 | if (psaux_registered) |
1085 | misc_deregister(&psaux_mouse); | 1088 | misc_deregister(&psaux_mouse); |
1086 | #endif | 1089 | #endif |
1087 | input_unregister_handler(&mousedev_handler); | 1090 | input_unregister_handler(&mousedev_handler); |
1088 | mousedev_destroy(mousedev_mix); | 1091 | mousedev_destroy(mousedev_mix); |
1089 | } | 1092 | } |
1090 | 1093 | ||
1091 | module_init(mousedev_init); | 1094 | module_init(mousedev_init); |
1092 | module_exit(mousedev_exit); | 1095 | module_exit(mousedev_exit); |
1093 | 1096 |
drivers/input/tsdev.c
1 | /* | 1 | /* |
2 | * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ | 2 | * $Id: tsdev.c,v 1.15 2002/04/10 16:50:19 jsimmons Exp $ |
3 | * | 3 | * |
4 | * Copyright (c) 2001 "Crazy" james Simmons | 4 | * Copyright (c) 2001 "Crazy" james Simmons |
5 | * | 5 | * |
6 | * Compaq touchscreen protocol driver. The protocol emulated by this driver | 6 | * Compaq touchscreen protocol driver. The protocol emulated by this driver |
7 | * is obsolete; for new programs use the tslib library which can read directly | 7 | * is obsolete; for new programs use the tslib library which can read directly |
8 | * from evdev and perform dejittering, variance filtering and calibration - | 8 | * from evdev and perform dejittering, variance filtering and calibration - |
9 | * all in user space, not at kernel level. The meaning of this driver is | 9 | * all in user space, not at kernel level. The meaning of this driver is |
10 | * to allow usage of newer input drivers with old applications that use the | 10 | * to allow usage of newer input drivers with old applications that use the |
11 | * old /dev/h3600_ts and /dev/h3600_tsraw devices. | 11 | * old /dev/h3600_ts and /dev/h3600_tsraw devices. |
12 | * | 12 | * |
13 | * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru> | 13 | * 09-Apr-2004: Andrew Zabolotny <zap@homelink.ru> |
14 | * Fixed to actually work, not just output random numbers. | 14 | * Fixed to actually work, not just output random numbers. |
15 | * Added support for both h3600_ts and h3600_tsraw protocol | 15 | * Added support for both h3600_ts and h3600_tsraw protocol |
16 | * emulation. | 16 | * emulation. |
17 | */ | 17 | */ |
18 | 18 | ||
19 | /* | 19 | /* |
20 | * This program is free software; you can redistribute it and/or modify | 20 | * This program is free software; you can redistribute it and/or modify |
21 | * it under the terms of the GNU General Public License as published by | 21 | * it under the terms of the GNU General Public License as published by |
22 | * the Free Software Foundation; either version 2 of the License, or | 22 | * the Free Software Foundation; either version 2 of the License, or |
23 | * (at your option) any later version. | 23 | * (at your option) any later version. |
24 | * | 24 | * |
25 | * This program is distributed in the hope that it will be useful, | 25 | * This program is distributed in the hope that it will be useful, |
26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 26 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 27 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
28 | * GNU General Public License for more details. | 28 | * GNU General Public License for more details. |
29 | * | 29 | * |
30 | * You should have received a copy of the GNU General Public License | 30 | * You should have received a copy of the GNU General Public License |
31 | * along with this program; if not, write to the Free Software | 31 | * along with this program; if not, write to the Free Software |
32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 32 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
33 | * | 33 | * |
34 | * Should you need to contact me, the author, you can do so either by | 34 | * Should you need to contact me, the author, you can do so either by |
35 | * e-mail - mail your message to <jsimmons@infradead.org>. | 35 | * e-mail - mail your message to <jsimmons@infradead.org>. |
36 | */ | 36 | */ |
37 | 37 | ||
38 | #define TSDEV_MINOR_BASE 128 | 38 | #define TSDEV_MINOR_BASE 128 |
39 | #define TSDEV_MINORS 32 | 39 | #define TSDEV_MINORS 32 |
40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ | 40 | /* First 16 devices are h3600_ts compatible; second 16 are h3600_tsraw */ |
41 | #define TSDEV_MINOR_MASK 15 | 41 | #define TSDEV_MINOR_MASK 15 |
42 | #define TSDEV_BUFFER_SIZE 64 | 42 | #define TSDEV_BUFFER_SIZE 64 |
43 | 43 | ||
44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
45 | #include <linux/poll.h> | 45 | #include <linux/poll.h> |
46 | #include <linux/module.h> | 46 | #include <linux/module.h> |
47 | #include <linux/moduleparam.h> | 47 | #include <linux/moduleparam.h> |
48 | #include <linux/init.h> | 48 | #include <linux/init.h> |
49 | #include <linux/input.h> | 49 | #include <linux/input.h> |
50 | #include <linux/major.h> | 50 | #include <linux/major.h> |
51 | #include <linux/random.h> | 51 | #include <linux/random.h> |
52 | #include <linux/time.h> | 52 | #include <linux/time.h> |
53 | #include <linux/device.h> | 53 | #include <linux/device.h> |
54 | 54 | ||
55 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_X | 55 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_X |
56 | #define CONFIG_INPUT_TSDEV_SCREEN_X 240 | 56 | #define CONFIG_INPUT_TSDEV_SCREEN_X 240 |
57 | #endif | 57 | #endif |
58 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y | 58 | #ifndef CONFIG_INPUT_TSDEV_SCREEN_Y |
59 | #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 | 59 | #define CONFIG_INPUT_TSDEV_SCREEN_Y 320 |
60 | #endif | 60 | #endif |
61 | 61 | ||
62 | /* This driver emulates both protocols of the old h3600_ts and h3600_tsraw | 62 | /* This driver emulates both protocols of the old h3600_ts and h3600_tsraw |
63 | * devices. The first one must output X/Y data in 'cooked' format, e.g. | 63 | * devices. The first one must output X/Y data in 'cooked' format, e.g. |
64 | * filtered, dejittered and calibrated. Second device just outputs raw | 64 | * filtered, dejittered and calibrated. Second device just outputs raw |
65 | * data received from the hardware. | 65 | * data received from the hardware. |
66 | * | 66 | * |
67 | * This driver doesn't support filtering and dejittering; it supports only | 67 | * This driver doesn't support filtering and dejittering; it supports only |
68 | * calibration. Filtering and dejittering must be done in the low-level | 68 | * calibration. Filtering and dejittering must be done in the low-level |
69 | * driver, if needed, because it may gain additional benefits from knowing | 69 | * driver, if needed, because it may gain additional benefits from knowing |
70 | * the low-level details, the nature of noise and so on. | 70 | * the low-level details, the nature of noise and so on. |
71 | * | 71 | * |
72 | * The driver precomputes a calibration matrix given the initial xres and | 72 | * The driver precomputes a calibration matrix given the initial xres and |
73 | * yres values (quite innacurate for most touchscreens) that will result | 73 | * yres values (quite innacurate for most touchscreens) that will result |
74 | * in a more or less expected range of output values. The driver supports | 74 | * in a more or less expected range of output values. The driver supports |
75 | * the TS_SET_CAL ioctl, which will replace the calibration matrix with a | 75 | * the TS_SET_CAL ioctl, which will replace the calibration matrix with a |
76 | * new one, supposedly generated from the values taken from the raw device. | 76 | * new one, supposedly generated from the values taken from the raw device. |
77 | */ | 77 | */ |
78 | 78 | ||
79 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); | 79 | MODULE_AUTHOR("James Simmons <jsimmons@transvirtual.com>"); |
80 | MODULE_DESCRIPTION("Input driver to touchscreen converter"); | 80 | MODULE_DESCRIPTION("Input driver to touchscreen converter"); |
81 | MODULE_LICENSE("GPL"); | 81 | MODULE_LICENSE("GPL"); |
82 | 82 | ||
83 | static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; | 83 | static int xres = CONFIG_INPUT_TSDEV_SCREEN_X; |
84 | module_param(xres, uint, 0); | 84 | module_param(xres, uint, 0); |
85 | MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); | 85 | MODULE_PARM_DESC(xres, "Horizontal screen resolution (can be negative for X-mirror)"); |
86 | 86 | ||
87 | static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; | 87 | static int yres = CONFIG_INPUT_TSDEV_SCREEN_Y; |
88 | module_param(yres, uint, 0); | 88 | module_param(yres, uint, 0); |
89 | MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); | 89 | MODULE_PARM_DESC(yres, "Vertical screen resolution (can be negative for Y-mirror)"); |
90 | 90 | ||
91 | /* From Compaq's Touch Screen Specification version 0.2 (draft) */ | 91 | /* From Compaq's Touch Screen Specification version 0.2 (draft) */ |
92 | struct ts_event { | 92 | struct ts_event { |
93 | short pressure; | 93 | short pressure; |
94 | short x; | 94 | short x; |
95 | short y; | 95 | short y; |
96 | short millisecs; | 96 | short millisecs; |
97 | }; | 97 | }; |
98 | 98 | ||
99 | struct ts_calibration { | 99 | struct ts_calibration { |
100 | int xscale; | 100 | int xscale; |
101 | int xtrans; | 101 | int xtrans; |
102 | int yscale; | 102 | int yscale; |
103 | int ytrans; | 103 | int ytrans; |
104 | int xyswap; | 104 | int xyswap; |
105 | }; | 105 | }; |
106 | 106 | ||
107 | struct tsdev { | 107 | struct tsdev { |
108 | int exist; | 108 | int exist; |
109 | int open; | 109 | int open; |
110 | int minor; | 110 | int minor; |
111 | char name[8]; | 111 | char name[8]; |
112 | struct input_handle handle; | 112 | struct input_handle handle; |
113 | wait_queue_head_t wait; | 113 | wait_queue_head_t wait; |
114 | struct list_head client_list; | 114 | struct list_head client_list; |
115 | spinlock_t client_lock; /* protects client_list */ | 115 | spinlock_t client_lock; /* protects client_list */ |
116 | struct mutex mutex; | 116 | struct mutex mutex; |
117 | struct device dev; | 117 | struct device dev; |
118 | 118 | ||
119 | int x, y, pressure; | 119 | int x, y, pressure; |
120 | struct ts_calibration cal; | 120 | struct ts_calibration cal; |
121 | }; | 121 | }; |
122 | 122 | ||
123 | struct tsdev_client { | 123 | struct tsdev_client { |
124 | struct fasync_struct *fasync; | 124 | struct fasync_struct *fasync; |
125 | struct list_head node; | 125 | struct list_head node; |
126 | struct tsdev *tsdev; | 126 | struct tsdev *tsdev; |
127 | struct ts_event buffer[TSDEV_BUFFER_SIZE]; | 127 | struct ts_event buffer[TSDEV_BUFFER_SIZE]; |
128 | int head, tail; | 128 | int head, tail; |
129 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ | 129 | spinlock_t buffer_lock; /* protects access to buffer, head and tail */ |
130 | int raw; | 130 | int raw; |
131 | }; | 131 | }; |
132 | 132 | ||
133 | /* The following ioctl codes are defined ONLY for backward compatibility. | 133 | /* The following ioctl codes are defined ONLY for backward compatibility. |
134 | * Don't use tsdev for new developement; use the tslib library instead. | 134 | * Don't use tsdev for new developement; use the tslib library instead. |
135 | * Touchscreen calibration is a fully userspace task. | 135 | * Touchscreen calibration is a fully userspace task. |
136 | */ | 136 | */ |
137 | /* Use 'f' as magic number */ | 137 | /* Use 'f' as magic number */ |
138 | #define IOC_H3600_TS_MAGIC 'f' | 138 | #define IOC_H3600_TS_MAGIC 'f' |
139 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) | 139 | #define TS_GET_CAL _IOR(IOC_H3600_TS_MAGIC, 10, struct ts_calibration) |
140 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) | 140 | #define TS_SET_CAL _IOW(IOC_H3600_TS_MAGIC, 11, struct ts_calibration) |
141 | 141 | ||
142 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; | 142 | static struct tsdev *tsdev_table[TSDEV_MINORS/2]; |
143 | static DEFINE_MUTEX(tsdev_table_mutex); | 143 | static DEFINE_MUTEX(tsdev_table_mutex); |
144 | 144 | ||
145 | static int tsdev_fasync(int fd, struct file *file, int on) | 145 | static int tsdev_fasync(int fd, struct file *file, int on) |
146 | { | 146 | { |
147 | struct tsdev_client *client = file->private_data; | 147 | struct tsdev_client *client = file->private_data; |
148 | int retval; | 148 | int retval; |
149 | 149 | ||
150 | retval = fasync_helper(fd, file, on, &client->fasync); | 150 | retval = fasync_helper(fd, file, on, &client->fasync); |
151 | 151 | ||
152 | return retval < 0 ? retval : 0; | 152 | return retval < 0 ? retval : 0; |
153 | } | 153 | } |
154 | 154 | ||
155 | static void tsdev_free(struct device *dev) | 155 | static void tsdev_free(struct device *dev) |
156 | { | 156 | { |
157 | struct tsdev *tsdev = container_of(dev, struct tsdev, dev); | 157 | struct tsdev *tsdev = container_of(dev, struct tsdev, dev); |
158 | 158 | ||
159 | kfree(tsdev); | 159 | kfree(tsdev); |
160 | } | 160 | } |
161 | 161 | ||
162 | static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client) | 162 | static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client) |
163 | { | 163 | { |
164 | spin_lock(&tsdev->client_lock); | 164 | spin_lock(&tsdev->client_lock); |
165 | list_add_tail_rcu(&client->node, &tsdev->client_list); | 165 | list_add_tail_rcu(&client->node, &tsdev->client_list); |
166 | spin_unlock(&tsdev->client_lock); | 166 | spin_unlock(&tsdev->client_lock); |
167 | synchronize_sched(); | 167 | synchronize_sched(); |
168 | } | 168 | } |
169 | 169 | ||
170 | static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client) | 170 | static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client) |
171 | { | 171 | { |
172 | spin_lock(&tsdev->client_lock); | 172 | spin_lock(&tsdev->client_lock); |
173 | list_del_rcu(&client->node); | 173 | list_del_rcu(&client->node); |
174 | spin_unlock(&tsdev->client_lock); | 174 | spin_unlock(&tsdev->client_lock); |
175 | synchronize_sched(); | 175 | synchronize_sched(); |
176 | } | 176 | } |
177 | 177 | ||
178 | static int tsdev_open_device(struct tsdev *tsdev) | 178 | static int tsdev_open_device(struct tsdev *tsdev) |
179 | { | 179 | { |
180 | int retval; | 180 | int retval; |
181 | 181 | ||
182 | retval = mutex_lock_interruptible(&tsdev->mutex); | 182 | retval = mutex_lock_interruptible(&tsdev->mutex); |
183 | if (retval) | 183 | if (retval) |
184 | return retval; | 184 | return retval; |
185 | 185 | ||
186 | if (!tsdev->exist) | 186 | if (!tsdev->exist) |
187 | retval = -ENODEV; | 187 | retval = -ENODEV; |
188 | else if (!tsdev->open++) | 188 | else if (!tsdev->open++) { |
189 | retval = input_open_device(&tsdev->handle); | 189 | retval = input_open_device(&tsdev->handle); |
190 | if (retval) | ||
191 | tsdev->open--; | ||
192 | } | ||
190 | 193 | ||
191 | mutex_unlock(&tsdev->mutex); | 194 | mutex_unlock(&tsdev->mutex); |
192 | return retval; | 195 | return retval; |
193 | } | 196 | } |
194 | 197 | ||
195 | static void tsdev_close_device(struct tsdev *tsdev) | 198 | static void tsdev_close_device(struct tsdev *tsdev) |
196 | { | 199 | { |
197 | mutex_lock(&tsdev->mutex); | 200 | mutex_lock(&tsdev->mutex); |
198 | 201 | ||
199 | if (tsdev->exist && !--tsdev->open) | 202 | if (tsdev->exist && !--tsdev->open) |
200 | input_close_device(&tsdev->handle); | 203 | input_close_device(&tsdev->handle); |
201 | 204 | ||
202 | mutex_unlock(&tsdev->mutex); | 205 | mutex_unlock(&tsdev->mutex); |
203 | } | 206 | } |
204 | 207 | ||
205 | /* | 208 | /* |
206 | * Wake up users waiting for IO so they can disconnect from | 209 | * Wake up users waiting for IO so they can disconnect from |
207 | * dead device. | 210 | * dead device. |
208 | */ | 211 | */ |
209 | static void tsdev_hangup(struct tsdev *tsdev) | 212 | static void tsdev_hangup(struct tsdev *tsdev) |
210 | { | 213 | { |
211 | struct tsdev_client *client; | 214 | struct tsdev_client *client; |
212 | 215 | ||
213 | spin_lock(&tsdev->client_lock); | 216 | spin_lock(&tsdev->client_lock); |
214 | list_for_each_entry(client, &tsdev->client_list, node) | 217 | list_for_each_entry(client, &tsdev->client_list, node) |
215 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); | 218 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
216 | spin_unlock(&tsdev->client_lock); | 219 | spin_unlock(&tsdev->client_lock); |
217 | 220 | ||
218 | wake_up_interruptible(&tsdev->wait); | 221 | wake_up_interruptible(&tsdev->wait); |
219 | } | 222 | } |
220 | 223 | ||
221 | static int tsdev_release(struct inode *inode, struct file *file) | 224 | static int tsdev_release(struct inode *inode, struct file *file) |
222 | { | 225 | { |
223 | struct tsdev_client *client = file->private_data; | 226 | struct tsdev_client *client = file->private_data; |
224 | struct tsdev *tsdev = client->tsdev; | 227 | struct tsdev *tsdev = client->tsdev; |
225 | 228 | ||
226 | tsdev_fasync(-1, file, 0); | 229 | tsdev_fasync(-1, file, 0); |
227 | tsdev_detach_client(tsdev, client); | 230 | tsdev_detach_client(tsdev, client); |
228 | kfree(client); | 231 | kfree(client); |
229 | 232 | ||
230 | tsdev_close_device(tsdev); | 233 | tsdev_close_device(tsdev); |
231 | put_device(&tsdev->dev); | 234 | put_device(&tsdev->dev); |
232 | 235 | ||
233 | return 0; | 236 | return 0; |
234 | } | 237 | } |
235 | 238 | ||
236 | static int tsdev_open(struct inode *inode, struct file *file) | 239 | static int tsdev_open(struct inode *inode, struct file *file) |
237 | { | 240 | { |
238 | int i = iminor(inode) - TSDEV_MINOR_BASE; | 241 | int i = iminor(inode) - TSDEV_MINOR_BASE; |
239 | struct tsdev_client *client; | 242 | struct tsdev_client *client; |
240 | struct tsdev *tsdev; | 243 | struct tsdev *tsdev; |
241 | int error; | 244 | int error; |
242 | 245 | ||
243 | printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " | 246 | printk(KERN_WARNING "tsdev (compaq touchscreen emulation) is scheduled " |
244 | "for removal.\nSee Documentation/feature-removal-schedule.txt " | 247 | "for removal.\nSee Documentation/feature-removal-schedule.txt " |
245 | "for details.\n"); | 248 | "for details.\n"); |
246 | 249 | ||
247 | if (i >= TSDEV_MINORS) | 250 | if (i >= TSDEV_MINORS) |
248 | return -ENODEV; | 251 | return -ENODEV; |
249 | 252 | ||
250 | error = mutex_lock_interruptible(&tsdev_table_mutex); | 253 | error = mutex_lock_interruptible(&tsdev_table_mutex); |
251 | if (error) | 254 | if (error) |
252 | return error; | 255 | return error; |
253 | tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; | 256 | tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; |
254 | if (tsdev) | 257 | if (tsdev) |
255 | get_device(&tsdev->dev); | 258 | get_device(&tsdev->dev); |
256 | mutex_unlock(&tsdev_table_mutex); | 259 | mutex_unlock(&tsdev_table_mutex); |
257 | 260 | ||
258 | if (!tsdev) | 261 | if (!tsdev) |
259 | return -ENODEV; | 262 | return -ENODEV; |
260 | 263 | ||
261 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); | 264 | client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); |
262 | if (!client) { | 265 | if (!client) { |
263 | error = -ENOMEM; | 266 | error = -ENOMEM; |
264 | goto err_put_tsdev; | 267 | goto err_put_tsdev; |
265 | } | 268 | } |
266 | 269 | ||
267 | spin_lock_init(&client->buffer_lock); | 270 | spin_lock_init(&client->buffer_lock); |
268 | client->tsdev = tsdev; | 271 | client->tsdev = tsdev; |
269 | client->raw = i >= TSDEV_MINORS / 2; | 272 | client->raw = i >= TSDEV_MINORS / 2; |
270 | tsdev_attach_client(tsdev, client); | 273 | tsdev_attach_client(tsdev, client); |
271 | 274 | ||
272 | error = tsdev_open_device(tsdev); | 275 | error = tsdev_open_device(tsdev); |
273 | if (error) | 276 | if (error) |
274 | goto err_free_client; | 277 | goto err_free_client; |
275 | 278 | ||
276 | file->private_data = client; | 279 | file->private_data = client; |
277 | return 0; | 280 | return 0; |
278 | 281 | ||
279 | err_free_client: | 282 | err_free_client: |
280 | tsdev_detach_client(tsdev, client); | 283 | tsdev_detach_client(tsdev, client); |
281 | kfree(client); | 284 | kfree(client); |
282 | err_put_tsdev: | 285 | err_put_tsdev: |
283 | put_device(&tsdev->dev); | 286 | put_device(&tsdev->dev); |
284 | return error; | 287 | return error; |
285 | } | 288 | } |
286 | 289 | ||
287 | static int tsdev_fetch_next_event(struct tsdev_client *client, | 290 | static int tsdev_fetch_next_event(struct tsdev_client *client, |
288 | struct ts_event *event) | 291 | struct ts_event *event) |
289 | { | 292 | { |
290 | int have_event; | 293 | int have_event; |
291 | 294 | ||
292 | spin_lock_irq(&client->buffer_lock); | 295 | spin_lock_irq(&client->buffer_lock); |
293 | 296 | ||
294 | have_event = client->head != client->tail; | 297 | have_event = client->head != client->tail; |
295 | if (have_event) { | 298 | if (have_event) { |
296 | *event = client->buffer[client->tail++]; | 299 | *event = client->buffer[client->tail++]; |
297 | client->tail &= TSDEV_BUFFER_SIZE - 1; | 300 | client->tail &= TSDEV_BUFFER_SIZE - 1; |
298 | } | 301 | } |
299 | 302 | ||
300 | spin_unlock_irq(&client->buffer_lock); | 303 | spin_unlock_irq(&client->buffer_lock); |
301 | 304 | ||
302 | return have_event; | 305 | return have_event; |
303 | } | 306 | } |
304 | 307 | ||
305 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, | 308 | static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, |
306 | loff_t *ppos) | 309 | loff_t *ppos) |
307 | { | 310 | { |
308 | struct tsdev_client *client = file->private_data; | 311 | struct tsdev_client *client = file->private_data; |
309 | struct tsdev *tsdev = client->tsdev; | 312 | struct tsdev *tsdev = client->tsdev; |
310 | struct ts_event event; | 313 | struct ts_event event; |
311 | int retval; | 314 | int retval; |
312 | 315 | ||
313 | if (client->head == client->tail && tsdev->exist && | 316 | if (client->head == client->tail && tsdev->exist && |
314 | (file->f_flags & O_NONBLOCK)) | 317 | (file->f_flags & O_NONBLOCK)) |
315 | return -EAGAIN; | 318 | return -EAGAIN; |
316 | 319 | ||
317 | retval = wait_event_interruptible(tsdev->wait, | 320 | retval = wait_event_interruptible(tsdev->wait, |
318 | client->head != client->tail || !tsdev->exist); | 321 | client->head != client->tail || !tsdev->exist); |
319 | if (retval) | 322 | if (retval) |
320 | return retval; | 323 | return retval; |
321 | 324 | ||
322 | if (!tsdev->exist) | 325 | if (!tsdev->exist) |
323 | return -ENODEV; | 326 | return -ENODEV; |
324 | 327 | ||
325 | while (retval + sizeof(struct ts_event) <= count && | 328 | while (retval + sizeof(struct ts_event) <= count && |
326 | tsdev_fetch_next_event(client, &event)) { | 329 | tsdev_fetch_next_event(client, &event)) { |
327 | 330 | ||
328 | if (copy_to_user(buffer + retval, &event, | 331 | if (copy_to_user(buffer + retval, &event, |
329 | sizeof(struct ts_event))) | 332 | sizeof(struct ts_event))) |
330 | return -EFAULT; | 333 | return -EFAULT; |
331 | 334 | ||
332 | retval += sizeof(struct ts_event); | 335 | retval += sizeof(struct ts_event); |
333 | } | 336 | } |
334 | 337 | ||
335 | return retval; | 338 | return retval; |
336 | } | 339 | } |
337 | 340 | ||
338 | /* No kernel lock - fine */ | 341 | /* No kernel lock - fine */ |
339 | static unsigned int tsdev_poll(struct file *file, poll_table *wait) | 342 | static unsigned int tsdev_poll(struct file *file, poll_table *wait) |
340 | { | 343 | { |
341 | struct tsdev_client *client = file->private_data; | 344 | struct tsdev_client *client = file->private_data; |
342 | struct tsdev *tsdev = client->tsdev; | 345 | struct tsdev *tsdev = client->tsdev; |
343 | 346 | ||
344 | poll_wait(file, &tsdev->wait, wait); | 347 | poll_wait(file, &tsdev->wait, wait); |
345 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | | 348 | return ((client->head == client->tail) ? 0 : (POLLIN | POLLRDNORM)) | |
346 | (tsdev->exist ? 0 : (POLLHUP | POLLERR)); | 349 | (tsdev->exist ? 0 : (POLLHUP | POLLERR)); |
347 | } | 350 | } |
348 | 351 | ||
349 | static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 352 | static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
350 | { | 353 | { |
351 | struct tsdev_client *client = file->private_data; | 354 | struct tsdev_client *client = file->private_data; |
352 | struct tsdev *tsdev = client->tsdev; | 355 | struct tsdev *tsdev = client->tsdev; |
353 | int retval = 0; | 356 | int retval = 0; |
354 | 357 | ||
355 | retval = mutex_lock_interruptible(&tsdev->mutex); | 358 | retval = mutex_lock_interruptible(&tsdev->mutex); |
356 | if (retval) | 359 | if (retval) |
357 | return retval; | 360 | return retval; |
358 | 361 | ||
359 | if (!tsdev->exist) { | 362 | if (!tsdev->exist) { |
360 | retval = -ENODEV; | 363 | retval = -ENODEV; |
361 | goto out; | 364 | goto out; |
362 | } | 365 | } |
363 | 366 | ||
364 | switch (cmd) { | 367 | switch (cmd) { |
365 | 368 | ||
366 | case TS_GET_CAL: | 369 | case TS_GET_CAL: |
367 | if (copy_to_user((void __user *)arg, &tsdev->cal, | 370 | if (copy_to_user((void __user *)arg, &tsdev->cal, |
368 | sizeof (struct ts_calibration))) | 371 | sizeof (struct ts_calibration))) |
369 | retval = -EFAULT; | 372 | retval = -EFAULT; |
370 | break; | 373 | break; |
371 | 374 | ||
372 | case TS_SET_CAL: | 375 | case TS_SET_CAL: |
373 | if (copy_from_user(&tsdev->cal, (void __user *)arg, | 376 | if (copy_from_user(&tsdev->cal, (void __user *)arg, |
374 | sizeof(struct ts_calibration))) | 377 | sizeof(struct ts_calibration))) |
375 | retval = -EFAULT; | 378 | retval = -EFAULT; |
376 | break; | 379 | break; |
377 | 380 | ||
378 | default: | 381 | default: |
379 | retval = -EINVAL; | 382 | retval = -EINVAL; |
380 | break; | 383 | break; |
381 | } | 384 | } |
382 | 385 | ||
383 | out: | 386 | out: |
384 | mutex_unlock(&tsdev->mutex); | 387 | mutex_unlock(&tsdev->mutex); |
385 | return retval; | 388 | return retval; |
386 | } | 389 | } |
387 | 390 | ||
388 | static const struct file_operations tsdev_fops = { | 391 | static const struct file_operations tsdev_fops = { |
389 | .owner = THIS_MODULE, | 392 | .owner = THIS_MODULE, |
390 | .open = tsdev_open, | 393 | .open = tsdev_open, |
391 | .release = tsdev_release, | 394 | .release = tsdev_release, |
392 | .read = tsdev_read, | 395 | .read = tsdev_read, |
393 | .poll = tsdev_poll, | 396 | .poll = tsdev_poll, |
394 | .fasync = tsdev_fasync, | 397 | .fasync = tsdev_fasync, |
395 | .unlocked_ioctl = tsdev_ioctl, | 398 | .unlocked_ioctl = tsdev_ioctl, |
396 | }; | 399 | }; |
397 | 400 | ||
398 | static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client, | 401 | static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client, |
399 | int x, int y, int pressure, int millisecs) | 402 | int x, int y, int pressure, int millisecs) |
400 | { | 403 | { |
401 | struct ts_event *event; | 404 | struct ts_event *event; |
402 | int tmp; | 405 | int tmp; |
403 | 406 | ||
404 | /* Interrupts are already disabled, just acquire the lock */ | 407 | /* Interrupts are already disabled, just acquire the lock */ |
405 | spin_lock(&client->buffer_lock); | 408 | spin_lock(&client->buffer_lock); |
406 | 409 | ||
407 | event = &client->buffer[client->head++]; | 410 | event = &client->buffer[client->head++]; |
408 | client->head &= TSDEV_BUFFER_SIZE - 1; | 411 | client->head &= TSDEV_BUFFER_SIZE - 1; |
409 | 412 | ||
410 | /* Calibration */ | 413 | /* Calibration */ |
411 | if (!client->raw) { | 414 | if (!client->raw) { |
412 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; | 415 | x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; |
413 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; | 416 | y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans; |
414 | if (tsdev->cal.xyswap) { | 417 | if (tsdev->cal.xyswap) { |
415 | tmp = x; x = y; y = tmp; | 418 | tmp = x; x = y; y = tmp; |
416 | } | 419 | } |
417 | } | 420 | } |
418 | 421 | ||
419 | event->millisecs = millisecs; | 422 | event->millisecs = millisecs; |
420 | event->x = x; | 423 | event->x = x; |
421 | event->y = y; | 424 | event->y = y; |
422 | event->pressure = pressure; | 425 | event->pressure = pressure; |
423 | 426 | ||
424 | spin_unlock(&client->buffer_lock); | 427 | spin_unlock(&client->buffer_lock); |
425 | 428 | ||
426 | kill_fasync(&client->fasync, SIGIO, POLL_IN); | 429 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
427 | } | 430 | } |
428 | 431 | ||
429 | static void tsdev_distribute_event(struct tsdev *tsdev) | 432 | static void tsdev_distribute_event(struct tsdev *tsdev) |
430 | { | 433 | { |
431 | struct tsdev_client *client; | 434 | struct tsdev_client *client; |
432 | struct timeval time; | 435 | struct timeval time; |
433 | int millisecs; | 436 | int millisecs; |
434 | 437 | ||
435 | do_gettimeofday(&time); | 438 | do_gettimeofday(&time); |
436 | millisecs = time.tv_usec / 1000; | 439 | millisecs = time.tv_usec / 1000; |
437 | 440 | ||
438 | list_for_each_entry_rcu(client, &tsdev->client_list, node) | 441 | list_for_each_entry_rcu(client, &tsdev->client_list, node) |
439 | tsdev_pass_event(tsdev, client, | 442 | tsdev_pass_event(tsdev, client, |
440 | tsdev->x, tsdev->y, | 443 | tsdev->x, tsdev->y, |
441 | tsdev->pressure, millisecs); | 444 | tsdev->pressure, millisecs); |
442 | } | 445 | } |
443 | 446 | ||
444 | static void tsdev_event(struct input_handle *handle, unsigned int type, | 447 | static void tsdev_event(struct input_handle *handle, unsigned int type, |
445 | unsigned int code, int value) | 448 | unsigned int code, int value) |
446 | { | 449 | { |
447 | struct tsdev *tsdev = handle->private; | 450 | struct tsdev *tsdev = handle->private; |
448 | struct input_dev *dev = handle->dev; | 451 | struct input_dev *dev = handle->dev; |
449 | int wake_up_readers = 0; | 452 | int wake_up_readers = 0; |
450 | 453 | ||
451 | switch (type) { | 454 | switch (type) { |
452 | 455 | ||
453 | case EV_ABS: | 456 | case EV_ABS: |
454 | switch (code) { | 457 | switch (code) { |
455 | 458 | ||
456 | case ABS_X: | 459 | case ABS_X: |
457 | tsdev->x = value; | 460 | tsdev->x = value; |
458 | break; | 461 | break; |
459 | 462 | ||
460 | case ABS_Y: | 463 | case ABS_Y: |
461 | tsdev->y = value; | 464 | tsdev->y = value; |
462 | break; | 465 | break; |
463 | 466 | ||
464 | case ABS_PRESSURE: | 467 | case ABS_PRESSURE: |
465 | if (value > dev->absmax[ABS_PRESSURE]) | 468 | if (value > dev->absmax[ABS_PRESSURE]) |
466 | value = dev->absmax[ABS_PRESSURE]; | 469 | value = dev->absmax[ABS_PRESSURE]; |
467 | value -= dev->absmin[ABS_PRESSURE]; | 470 | value -= dev->absmin[ABS_PRESSURE]; |
468 | if (value < 0) | 471 | if (value < 0) |
469 | value = 0; | 472 | value = 0; |
470 | tsdev->pressure = value; | 473 | tsdev->pressure = value; |
471 | break; | 474 | break; |
472 | } | 475 | } |
473 | break; | 476 | break; |
474 | 477 | ||
475 | case EV_REL: | 478 | case EV_REL: |
476 | switch (code) { | 479 | switch (code) { |
477 | 480 | ||
478 | case REL_X: | 481 | case REL_X: |
479 | tsdev->x += value; | 482 | tsdev->x += value; |
480 | if (tsdev->x < 0) | 483 | if (tsdev->x < 0) |
481 | tsdev->x = 0; | 484 | tsdev->x = 0; |
482 | else if (tsdev->x > xres) | 485 | else if (tsdev->x > xres) |
483 | tsdev->x = xres; | 486 | tsdev->x = xres; |
484 | break; | 487 | break; |
485 | 488 | ||
486 | case REL_Y: | 489 | case REL_Y: |
487 | tsdev->y += value; | 490 | tsdev->y += value; |
488 | if (tsdev->y < 0) | 491 | if (tsdev->y < 0) |
489 | tsdev->y = 0; | 492 | tsdev->y = 0; |
490 | else if (tsdev->y > yres) | 493 | else if (tsdev->y > yres) |
491 | tsdev->y = yres; | 494 | tsdev->y = yres; |
492 | break; | 495 | break; |
493 | } | 496 | } |
494 | break; | 497 | break; |
495 | 498 | ||
496 | case EV_KEY: | 499 | case EV_KEY: |
497 | if (code == BTN_TOUCH || code == BTN_MOUSE) { | 500 | if (code == BTN_TOUCH || code == BTN_MOUSE) { |
498 | switch (value) { | 501 | switch (value) { |
499 | 502 | ||
500 | case 0: | 503 | case 0: |
501 | tsdev->pressure = 0; | 504 | tsdev->pressure = 0; |
502 | break; | 505 | break; |
503 | 506 | ||
504 | case 1: | 507 | case 1: |
505 | if (!tsdev->pressure) | 508 | if (!tsdev->pressure) |
506 | tsdev->pressure = 1; | 509 | tsdev->pressure = 1; |
507 | break; | 510 | break; |
508 | } | 511 | } |
509 | } | 512 | } |
510 | break; | 513 | break; |
511 | 514 | ||
512 | case EV_SYN: | 515 | case EV_SYN: |
513 | if (code == SYN_REPORT) { | 516 | if (code == SYN_REPORT) { |
514 | tsdev_distribute_event(tsdev); | 517 | tsdev_distribute_event(tsdev); |
515 | wake_up_readers = 1; | 518 | wake_up_readers = 1; |
516 | } | 519 | } |
517 | break; | 520 | break; |
518 | } | 521 | } |
519 | 522 | ||
520 | if (wake_up_readers) | 523 | if (wake_up_readers) |
521 | wake_up_interruptible(&tsdev->wait); | 524 | wake_up_interruptible(&tsdev->wait); |
522 | } | 525 | } |
523 | 526 | ||
524 | static int tsdev_install_chrdev(struct tsdev *tsdev) | 527 | static int tsdev_install_chrdev(struct tsdev *tsdev) |
525 | { | 528 | { |
526 | tsdev_table[tsdev->minor] = tsdev; | 529 | tsdev_table[tsdev->minor] = tsdev; |
527 | return 0; | 530 | return 0; |
528 | } | 531 | } |
529 | 532 | ||
530 | static void tsdev_remove_chrdev(struct tsdev *tsdev) | 533 | static void tsdev_remove_chrdev(struct tsdev *tsdev) |
531 | { | 534 | { |
532 | mutex_lock(&tsdev_table_mutex); | 535 | mutex_lock(&tsdev_table_mutex); |
533 | tsdev_table[tsdev->minor] = NULL; | 536 | tsdev_table[tsdev->minor] = NULL; |
534 | mutex_unlock(&tsdev_table_mutex); | 537 | mutex_unlock(&tsdev_table_mutex); |
535 | } | 538 | } |
536 | 539 | ||
537 | /* | 540 | /* |
538 | * Mark device non-existant. This disables writes, ioctls and | 541 | * Mark device non-existant. This disables writes, ioctls and |
539 | * prevents new users from opening the device. Already posted | 542 | * prevents new users from opening the device. Already posted |
540 | * blocking reads will stay, however new ones will fail. | 543 | * blocking reads will stay, however new ones will fail. |
541 | */ | 544 | */ |
542 | static void tsdev_mark_dead(struct tsdev *tsdev) | 545 | static void tsdev_mark_dead(struct tsdev *tsdev) |
543 | { | 546 | { |
544 | mutex_lock(&tsdev->mutex); | 547 | mutex_lock(&tsdev->mutex); |
545 | tsdev->exist = 0; | 548 | tsdev->exist = 0; |
546 | mutex_unlock(&tsdev->mutex); | 549 | mutex_unlock(&tsdev->mutex); |
547 | } | 550 | } |
548 | 551 | ||
549 | static void tsdev_cleanup(struct tsdev *tsdev) | 552 | static void tsdev_cleanup(struct tsdev *tsdev) |
550 | { | 553 | { |
551 | struct input_handle *handle = &tsdev->handle; | 554 | struct input_handle *handle = &tsdev->handle; |
552 | 555 | ||
553 | tsdev_mark_dead(tsdev); | 556 | tsdev_mark_dead(tsdev); |
554 | tsdev_hangup(tsdev); | 557 | tsdev_hangup(tsdev); |
555 | tsdev_remove_chrdev(tsdev); | 558 | tsdev_remove_chrdev(tsdev); |
556 | 559 | ||
557 | /* tsdev is marked dead so noone else accesses tsdev->open */ | 560 | /* tsdev is marked dead so noone else accesses tsdev->open */ |
558 | if (tsdev->open) | 561 | if (tsdev->open) |
559 | input_close_device(handle); | 562 | input_close_device(handle); |
560 | } | 563 | } |
561 | 564 | ||
562 | static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, | 565 | static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, |
563 | const struct input_device_id *id) | 566 | const struct input_device_id *id) |
564 | { | 567 | { |
565 | struct tsdev *tsdev; | 568 | struct tsdev *tsdev; |
566 | int delta; | 569 | int delta; |
567 | int minor; | 570 | int minor; |
568 | int error; | 571 | int error; |
569 | 572 | ||
570 | for (minor = 0; minor < TSDEV_MINORS / 2; minor++) | 573 | for (minor = 0; minor < TSDEV_MINORS / 2; minor++) |
571 | if (!tsdev_table[minor]) | 574 | if (!tsdev_table[minor]) |
572 | break; | 575 | break; |
573 | 576 | ||
574 | if (minor == TSDEV_MINORS) { | 577 | if (minor == TSDEV_MINORS) { |
575 | printk(KERN_ERR "tsdev: no more free tsdev devices\n"); | 578 | printk(KERN_ERR "tsdev: no more free tsdev devices\n"); |
576 | return -ENFILE; | 579 | return -ENFILE; |
577 | } | 580 | } |
578 | 581 | ||
579 | tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); | 582 | tsdev = kzalloc(sizeof(struct tsdev), GFP_KERNEL); |
580 | if (!tsdev) | 583 | if (!tsdev) |
581 | return -ENOMEM; | 584 | return -ENOMEM; |
582 | 585 | ||
583 | INIT_LIST_HEAD(&tsdev->client_list); | 586 | INIT_LIST_HEAD(&tsdev->client_list); |
584 | spin_lock_init(&tsdev->client_lock); | 587 | spin_lock_init(&tsdev->client_lock); |
585 | mutex_init(&tsdev->mutex); | 588 | mutex_init(&tsdev->mutex); |
586 | init_waitqueue_head(&tsdev->wait); | 589 | init_waitqueue_head(&tsdev->wait); |
587 | 590 | ||
588 | snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); | 591 | snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor); |
589 | tsdev->exist = 1; | 592 | tsdev->exist = 1; |
590 | tsdev->minor = minor; | 593 | tsdev->minor = minor; |
591 | 594 | ||
592 | tsdev->handle.dev = dev; | 595 | tsdev->handle.dev = dev; |
593 | tsdev->handle.name = tsdev->name; | 596 | tsdev->handle.name = tsdev->name; |
594 | tsdev->handle.handler = handler; | 597 | tsdev->handle.handler = handler; |
595 | tsdev->handle.private = tsdev; | 598 | tsdev->handle.private = tsdev; |
596 | 599 | ||
597 | /* Precompute the rough calibration matrix */ | 600 | /* Precompute the rough calibration matrix */ |
598 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; | 601 | delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; |
599 | if (delta == 0) | 602 | if (delta == 0) |
600 | delta = 1; | 603 | delta = 1; |
601 | tsdev->cal.xscale = (xres << 8) / delta; | 604 | tsdev->cal.xscale = (xres << 8) / delta; |
602 | tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); | 605 | tsdev->cal.xtrans = - ((dev->absmin [ABS_X] * tsdev->cal.xscale) >> 8); |
603 | 606 | ||
604 | delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; | 607 | delta = dev->absmax [ABS_Y] - dev->absmin [ABS_Y] + 1; |
605 | if (delta == 0) | 608 | if (delta == 0) |
606 | delta = 1; | 609 | delta = 1; |
607 | tsdev->cal.yscale = (yres << 8) / delta; | 610 | tsdev->cal.yscale = (yres << 8) / delta; |
608 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); | 611 | tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); |
609 | 612 | ||
610 | strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id)); | 613 | strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id)); |
611 | tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor); | 614 | tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor); |
612 | tsdev->dev.class = &input_class; | 615 | tsdev->dev.class = &input_class; |
613 | tsdev->dev.parent = &dev->dev; | 616 | tsdev->dev.parent = &dev->dev; |
614 | tsdev->dev.release = tsdev_free; | 617 | tsdev->dev.release = tsdev_free; |
615 | device_initialize(&tsdev->dev); | 618 | device_initialize(&tsdev->dev); |
616 | 619 | ||
617 | error = input_register_handle(&tsdev->handle); | 620 | error = input_register_handle(&tsdev->handle); |
618 | if (error) | 621 | if (error) |
619 | goto err_free_tsdev; | 622 | goto err_free_tsdev; |
620 | 623 | ||
621 | error = tsdev_install_chrdev(tsdev); | 624 | error = tsdev_install_chrdev(tsdev); |
622 | if (error) | 625 | if (error) |
623 | goto err_unregister_handle; | 626 | goto err_unregister_handle; |
624 | 627 | ||
625 | error = device_add(&tsdev->dev); | 628 | error = device_add(&tsdev->dev); |
626 | if (error) | 629 | if (error) |
627 | goto err_cleanup_tsdev; | 630 | goto err_cleanup_tsdev; |
628 | 631 | ||
629 | return 0; | 632 | return 0; |
630 | 633 | ||
631 | err_cleanup_tsdev: | 634 | err_cleanup_tsdev: |
632 | tsdev_cleanup(tsdev); | 635 | tsdev_cleanup(tsdev); |
633 | err_unregister_handle: | 636 | err_unregister_handle: |
634 | input_unregister_handle(&tsdev->handle); | 637 | input_unregister_handle(&tsdev->handle); |
635 | err_free_tsdev: | 638 | err_free_tsdev: |
636 | put_device(&tsdev->dev); | 639 | put_device(&tsdev->dev); |
637 | return error; | 640 | return error; |
638 | } | 641 | } |
639 | 642 | ||
640 | static void tsdev_disconnect(struct input_handle *handle) | 643 | static void tsdev_disconnect(struct input_handle *handle) |
641 | { | 644 | { |
642 | struct tsdev *tsdev = handle->private; | 645 | struct tsdev *tsdev = handle->private; |
643 | 646 | ||
644 | device_del(&tsdev->dev); | 647 | device_del(&tsdev->dev); |
645 | tsdev_cleanup(tsdev); | 648 | tsdev_cleanup(tsdev); |
646 | input_unregister_handle(handle); | 649 | input_unregister_handle(handle); |
647 | put_device(&tsdev->dev); | 650 | put_device(&tsdev->dev); |
648 | } | 651 | } |
649 | 652 | ||
650 | static const struct input_device_id tsdev_ids[] = { | 653 | static const struct input_device_id tsdev_ids[] = { |
651 | { | 654 | { |
652 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | 655 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, |
653 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, | 656 | .evbit = { BIT(EV_KEY) | BIT(EV_REL) }, |
654 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | 657 | .keybit = { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, |
655 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, | 658 | .relbit = { BIT(REL_X) | BIT(REL_Y) }, |
656 | }, /* A mouse like device, at least one button, two relative axes */ | 659 | }, /* A mouse like device, at least one button, two relative axes */ |
657 | 660 | ||
658 | { | 661 | { |
659 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 662 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
660 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, | 663 | .evbit = { BIT(EV_KEY) | BIT(EV_ABS) }, |
661 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | 664 | .keybit = { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, |
662 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, | 665 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) }, |
663 | }, /* A tablet like device, at least touch detection, two absolute axes */ | 666 | }, /* A tablet like device, at least touch detection, two absolute axes */ |
664 | 667 | ||
665 | { | 668 | { |
666 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | 669 | .flags = INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, |
667 | .evbit = { BIT(EV_ABS) }, | 670 | .evbit = { BIT(EV_ABS) }, |
668 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, | 671 | .absbit = { BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) }, |
669 | }, /* A tablet like device with several gradations of pressure */ | 672 | }, /* A tablet like device with several gradations of pressure */ |
670 | 673 | ||
671 | {} /* Terminating entry */ | 674 | {} /* Terminating entry */ |
672 | }; | 675 | }; |
673 | 676 | ||
674 | MODULE_DEVICE_TABLE(input, tsdev_ids); | 677 | MODULE_DEVICE_TABLE(input, tsdev_ids); |
675 | 678 | ||
676 | static struct input_handler tsdev_handler = { | 679 | static struct input_handler tsdev_handler = { |
677 | .event = tsdev_event, | 680 | .event = tsdev_event, |
678 | .connect = tsdev_connect, | 681 | .connect = tsdev_connect, |
679 | .disconnect = tsdev_disconnect, | 682 | .disconnect = tsdev_disconnect, |
680 | .fops = &tsdev_fops, | 683 | .fops = &tsdev_fops, |
681 | .minor = TSDEV_MINOR_BASE, | 684 | .minor = TSDEV_MINOR_BASE, |
682 | .name = "tsdev", | 685 | .name = "tsdev", |
683 | .id_table = tsdev_ids, | 686 | .id_table = tsdev_ids, |
684 | }; | 687 | }; |
685 | 688 | ||
686 | static int __init tsdev_init(void) | 689 | static int __init tsdev_init(void) |
687 | { | 690 | { |
688 | return input_register_handler(&tsdev_handler); | 691 | return input_register_handler(&tsdev_handler); |
689 | } | 692 | } |
690 | 693 | ||
691 | static void __exit tsdev_exit(void) | 694 | static void __exit tsdev_exit(void) |
692 | { | 695 | { |
693 | input_unregister_handler(&tsdev_handler); | 696 | input_unregister_handler(&tsdev_handler); |
694 | } | 697 | } |
695 | 698 | ||
696 | module_init(tsdev_init); | 699 | module_init(tsdev_init); |
697 | module_exit(tsdev_exit); | 700 | module_exit(tsdev_exit); |
698 | 701 |