diff options
Diffstat (limited to 'drivers/input/joydev.c')
-rw-r--r-- | drivers/input/joydev.c | 130 |
1 files changed, 68 insertions, 62 deletions
diff --git a/drivers/input/joydev.c b/drivers/input/joydev.c index cf24a5bde539..09b8223de5ec 100644 --- a/drivers/input/joydev.c +++ b/drivers/input/joydev.c | |||
@@ -43,7 +43,7 @@ struct joydev { | |||
43 | char name[16]; | 43 | char name[16]; |
44 | struct input_handle handle; | 44 | struct input_handle handle; |
45 | wait_queue_head_t wait; | 45 | wait_queue_head_t wait; |
46 | struct list_head list; | 46 | struct list_head client_list; |
47 | struct js_corr corr[ABS_MAX + 1]; | 47 | struct js_corr corr[ABS_MAX + 1]; |
48 | struct JS_DATA_SAVE_TYPE glue; | 48 | struct JS_DATA_SAVE_TYPE glue; |
49 | int nabs; | 49 | int nabs; |
@@ -55,7 +55,7 @@ struct joydev { | |||
55 | __s16 abs[ABS_MAX + 1]; | 55 | __s16 abs[ABS_MAX + 1]; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | struct joydev_list { | 58 | struct joydev_client { |
59 | struct js_event buffer[JOYDEV_BUFFER_SIZE]; | 59 | struct js_event buffer[JOYDEV_BUFFER_SIZE]; |
60 | int head; | 60 | int head; |
61 | int tail; | 61 | int tail; |
@@ -87,7 +87,7 @@ static int joydev_correct(int value, struct js_corr *corr) | |||
87 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) | 87 | static void joydev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value) |
88 | { | 88 | { |
89 | struct joydev *joydev = handle->private; | 89 | struct joydev *joydev = handle->private; |
90 | struct joydev_list *list; | 90 | struct joydev_client *client; |
91 | struct js_event event; | 91 | struct js_event event; |
92 | 92 | ||
93 | switch (type) { | 93 | switch (type) { |
@@ -115,15 +115,15 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
115 | 115 | ||
116 | event.time = jiffies_to_msecs(jiffies); | 116 | event.time = jiffies_to_msecs(jiffies); |
117 | 117 | ||
118 | list_for_each_entry(list, &joydev->list, node) { | 118 | list_for_each_entry(client, &joydev->client_list, node) { |
119 | 119 | ||
120 | memcpy(list->buffer + list->head, &event, sizeof(struct js_event)); | 120 | memcpy(client->buffer + client->head, &event, sizeof(struct js_event)); |
121 | 121 | ||
122 | if (list->startup == joydev->nabs + joydev->nkey) | 122 | if (client->startup == joydev->nabs + joydev->nkey) |
123 | if (list->tail == (list->head = (list->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) | 123 | if (client->tail == (client->head = (client->head + 1) & (JOYDEV_BUFFER_SIZE - 1))) |
124 | list->startup = 0; | 124 | client->startup = 0; |
125 | 125 | ||
126 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 126 | kill_fasync(&client->fasync, SIGIO, POLL_IN); |
127 | } | 127 | } |
128 | 128 | ||
129 | wake_up_interruptible(&joydev->wait); | 129 | wake_up_interruptible(&joydev->wait); |
@@ -132,9 +132,9 @@ static void joydev_event(struct input_handle *handle, unsigned int type, unsigne | |||
132 | static int joydev_fasync(int fd, struct file *file, int on) | 132 | static int joydev_fasync(int fd, struct file *file, int on) |
133 | { | 133 | { |
134 | int retval; | 134 | int retval; |
135 | struct joydev_list *list = file->private_data; | 135 | struct joydev_client *client = file->private_data; |
136 | 136 | ||
137 | retval = fasync_helper(fd, file, on, &list->fasync); | 137 | retval = fasync_helper(fd, file, on, &client->fasync); |
138 | 138 | ||
139 | return retval < 0 ? retval : 0; | 139 | return retval < 0 ? retval : 0; |
140 | } | 140 | } |
@@ -145,60 +145,66 @@ static void joydev_free(struct joydev *joydev) | |||
145 | kfree(joydev); | 145 | kfree(joydev); |
146 | } | 146 | } |
147 | 147 | ||
148 | static int joydev_release(struct inode * inode, struct file * file) | 148 | static int joydev_release(struct inode *inode, struct file *file) |
149 | { | 149 | { |
150 | struct joydev_list *list = file->private_data; | 150 | struct joydev_client *client = file->private_data; |
151 | struct joydev *joydev = client->joydev; | ||
151 | 152 | ||
152 | joydev_fasync(-1, file, 0); | 153 | joydev_fasync(-1, file, 0); |
153 | 154 | ||
154 | list_del(&list->node); | 155 | list_del(&client->node); |
156 | kfree(client); | ||
155 | 157 | ||
156 | if (!--list->joydev->open) { | 158 | if (!--joydev->open) { |
157 | if (list->joydev->exist) | 159 | if (joydev->exist) |
158 | input_close_device(&list->joydev->handle); | 160 | input_close_device(&joydev->handle); |
159 | else | 161 | else |
160 | joydev_free(list->joydev); | 162 | joydev_free(joydev); |
161 | } | 163 | } |
162 | 164 | ||
163 | kfree(list); | ||
164 | return 0; | 165 | return 0; |
165 | } | 166 | } |
166 | 167 | ||
167 | static int joydev_open(struct inode *inode, struct file *file) | 168 | static int joydev_open(struct inode *inode, struct file *file) |
168 | { | 169 | { |
169 | struct joydev_list *list; | 170 | struct joydev_client *client; |
171 | struct joydev *joydev; | ||
170 | int i = iminor(inode) - JOYDEV_MINOR_BASE; | 172 | int i = iminor(inode) - JOYDEV_MINOR_BASE; |
171 | 173 | ||
172 | if (i >= JOYDEV_MINORS || !joydev_table[i]) | 174 | if (i >= JOYDEV_MINORS) |
175 | return -ENODEV; | ||
176 | |||
177 | joydev = joydev_table[i]; | ||
178 | if (!joydev || !joydev->exist) | ||
173 | return -ENODEV; | 179 | return -ENODEV; |
174 | 180 | ||
175 | if (!(list = kzalloc(sizeof(struct joydev_list), GFP_KERNEL))) | 181 | client = kzalloc(sizeof(struct joydev_client), GFP_KERNEL); |
182 | if (!client) | ||
176 | return -ENOMEM; | 183 | return -ENOMEM; |
177 | 184 | ||
178 | list->joydev = joydev_table[i]; | 185 | client->joydev = joydev; |
179 | list_add_tail(&list->node, &joydev_table[i]->list); | 186 | list_add_tail(&client->node, &joydev->client_list); |
180 | file->private_data = list; | ||
181 | 187 | ||
182 | if (!list->joydev->open++) | 188 | if (!joydev->open++ && joydev->exist) |
183 | if (list->joydev->exist) | 189 | input_open_device(&joydev->handle); |
184 | input_open_device(&list->joydev->handle); | ||
185 | 190 | ||
191 | file->private_data = client; | ||
186 | return 0; | 192 | return 0; |
187 | } | 193 | } |
188 | 194 | ||
189 | static ssize_t joydev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos) | 195 | static ssize_t joydev_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) |
190 | { | 196 | { |
191 | return -EINVAL; | 197 | return -EINVAL; |
192 | } | 198 | } |
193 | 199 | ||
194 | static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 200 | static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
195 | { | 201 | { |
196 | struct joydev_list *list = file->private_data; | 202 | struct joydev_client *client = file->private_data; |
197 | struct joydev *joydev = list->joydev; | 203 | struct joydev *joydev = client->joydev; |
198 | struct input_dev *input = joydev->handle.dev; | 204 | struct input_dev *input = joydev->handle.dev; |
199 | int retval = 0; | 205 | int retval = 0; |
200 | 206 | ||
201 | if (!list->joydev->exist) | 207 | if (!joydev->exist) |
202 | return -ENODEV; | 208 | return -ENODEV; |
203 | 209 | ||
204 | if (count < sizeof(struct js_event)) | 210 | if (count < sizeof(struct js_event)) |
@@ -217,56 +223,55 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
217 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) | 223 | if (copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE))) |
218 | return -EFAULT; | 224 | return -EFAULT; |
219 | 225 | ||
220 | list->startup = 0; | 226 | client->startup = 0; |
221 | list->tail = list->head; | 227 | client->tail = client->head; |
222 | 228 | ||
223 | return sizeof(struct JS_DATA_TYPE); | 229 | return sizeof(struct JS_DATA_TYPE); |
224 | } | 230 | } |
225 | 231 | ||
226 | if (list->startup == joydev->nabs + joydev->nkey && | 232 | if (client->startup == joydev->nabs + joydev->nkey && |
227 | list->head == list->tail && (file->f_flags & O_NONBLOCK)) | 233 | client->head == client->tail && (file->f_flags & O_NONBLOCK)) |
228 | return -EAGAIN; | 234 | return -EAGAIN; |
229 | 235 | ||
230 | retval = wait_event_interruptible(list->joydev->wait, | 236 | retval = wait_event_interruptible(joydev->wait, |
231 | !list->joydev->exist || | 237 | !joydev->exist || |
232 | list->startup < joydev->nabs + joydev->nkey || | 238 | client->startup < joydev->nabs + joydev->nkey || |
233 | list->head != list->tail); | 239 | client->head != client->tail); |
234 | |||
235 | if (retval) | 240 | if (retval) |
236 | return retval; | 241 | return retval; |
237 | 242 | ||
238 | if (!list->joydev->exist) | 243 | if (!joydev->exist) |
239 | return -ENODEV; | 244 | return -ENODEV; |
240 | 245 | ||
241 | while (list->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { | 246 | while (client->startup < joydev->nabs + joydev->nkey && retval + sizeof(struct js_event) <= count) { |
242 | 247 | ||
243 | struct js_event event; | 248 | struct js_event event; |
244 | 249 | ||
245 | event.time = jiffies_to_msecs(jiffies); | 250 | event.time = jiffies_to_msecs(jiffies); |
246 | 251 | ||
247 | if (list->startup < joydev->nkey) { | 252 | if (client->startup < joydev->nkey) { |
248 | event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; | 253 | event.type = JS_EVENT_BUTTON | JS_EVENT_INIT; |
249 | event.number = list->startup; | 254 | event.number = client->startup; |
250 | event.value = !!test_bit(joydev->keypam[event.number], input->key); | 255 | event.value = !!test_bit(joydev->keypam[event.number], input->key); |
251 | } else { | 256 | } else { |
252 | event.type = JS_EVENT_AXIS | JS_EVENT_INIT; | 257 | event.type = JS_EVENT_AXIS | JS_EVENT_INIT; |
253 | event.number = list->startup - joydev->nkey; | 258 | event.number = client->startup - joydev->nkey; |
254 | event.value = joydev->abs[event.number]; | 259 | event.value = joydev->abs[event.number]; |
255 | } | 260 | } |
256 | 261 | ||
257 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) | 262 | if (copy_to_user(buf + retval, &event, sizeof(struct js_event))) |
258 | return -EFAULT; | 263 | return -EFAULT; |
259 | 264 | ||
260 | list->startup++; | 265 | client->startup++; |
261 | retval += sizeof(struct js_event); | 266 | retval += sizeof(struct js_event); |
262 | } | 267 | } |
263 | 268 | ||
264 | while (list->head != list->tail && retval + sizeof(struct js_event) <= count) { | 269 | while (client->head != client->tail && retval + sizeof(struct js_event) <= count) { |
265 | 270 | ||
266 | if (copy_to_user(buf + retval, list->buffer + list->tail, sizeof(struct js_event))) | 271 | if (copy_to_user(buf + retval, client->buffer + client->tail, sizeof(struct js_event))) |
267 | return -EFAULT; | 272 | return -EFAULT; |
268 | 273 | ||
269 | list->tail = (list->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); | 274 | client->tail = (client->tail + 1) & (JOYDEV_BUFFER_SIZE - 1); |
270 | retval += sizeof(struct js_event); | 275 | retval += sizeof(struct js_event); |
271 | } | 276 | } |
272 | 277 | ||
@@ -276,11 +281,12 @@ static ssize_t joydev_read(struct file *file, char __user *buf, size_t count, lo | |||
276 | /* No kernel lock - fine */ | 281 | /* No kernel lock - fine */ |
277 | static unsigned int joydev_poll(struct file *file, poll_table *wait) | 282 | static unsigned int joydev_poll(struct file *file, poll_table *wait) |
278 | { | 283 | { |
279 | struct joydev_list *list = file->private_data; | 284 | struct joydev_client *client = file->private_data; |
285 | struct joydev *joydev = client->joydev; | ||
280 | 286 | ||
281 | poll_wait(file, &list->joydev->wait, wait); | 287 | poll_wait(file, &joydev->wait, wait); |
282 | return ((list->head != list->tail || list->startup < list->joydev->nabs + list->joydev->nkey) ? | 288 | return ((client->head != client->tail || client->startup < joydev->nabs + joydev->nkey) ? |
283 | (POLLIN | POLLRDNORM) : 0) | (list->joydev->exist ? 0 : (POLLHUP | POLLERR)); | 289 | (POLLIN | POLLRDNORM) : 0) | (joydev->exist ? 0 : (POLLHUP | POLLERR)); |
284 | } | 290 | } |
285 | 291 | ||
286 | static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) | 292 | static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __user *argp) |
@@ -374,8 +380,8 @@ static int joydev_ioctl_common(struct joydev *joydev, unsigned int cmd, void __u | |||
374 | #ifdef CONFIG_COMPAT | 380 | #ifdef CONFIG_COMPAT |
375 | static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 381 | static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
376 | { | 382 | { |
377 | struct joydev_list *list = file->private_data; | 383 | struct joydev_client *client = file->private_data; |
378 | struct joydev *joydev = list->joydev; | 384 | struct joydev *joydev = client->joydev; |
379 | void __user *argp = (void __user *)arg; | 385 | void __user *argp = (void __user *)arg; |
380 | s32 tmp32; | 386 | s32 tmp32; |
381 | struct JS_DATA_SAVE_TYPE_32 ds32; | 387 | struct JS_DATA_SAVE_TYPE_32 ds32; |
@@ -428,8 +434,8 @@ static long joydev_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo | |||
428 | 434 | ||
429 | static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) | 435 | static int joydev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) |
430 | { | 436 | { |
431 | struct joydev_list *list = file->private_data; | 437 | struct joydev_client *client = file->private_data; |
432 | struct joydev *joydev = list->joydev; | 438 | struct joydev *joydev = client->joydev; |
433 | void __user *argp = (void __user *)arg; | 439 | void __user *argp = (void __user *)arg; |
434 | 440 | ||
435 | if (!joydev->exist) | 441 | if (!joydev->exist) |
@@ -484,7 +490,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
484 | if (!joydev) | 490 | if (!joydev) |
485 | return -ENOMEM; | 491 | return -ENOMEM; |
486 | 492 | ||
487 | INIT_LIST_HEAD(&joydev->list); | 493 | INIT_LIST_HEAD(&joydev->client_list); |
488 | init_waitqueue_head(&joydev->wait); | 494 | init_waitqueue_head(&joydev->wait); |
489 | 495 | ||
490 | joydev->minor = minor; | 496 | joydev->minor = minor; |
@@ -572,7 +578,7 @@ static int joydev_connect(struct input_handler *handler, struct input_dev *dev, | |||
572 | static void joydev_disconnect(struct input_handle *handle) | 578 | static void joydev_disconnect(struct input_handle *handle) |
573 | { | 579 | { |
574 | struct joydev *joydev = handle->private; | 580 | struct joydev *joydev = handle->private; |
575 | struct joydev_list *list; | 581 | struct joydev_client *client; |
576 | 582 | ||
577 | input_unregister_handle(handle); | 583 | input_unregister_handle(handle); |
578 | 584 | ||
@@ -583,8 +589,8 @@ static void joydev_disconnect(struct input_handle *handle) | |||
583 | if (joydev->open) { | 589 | if (joydev->open) { |
584 | input_close_device(handle); | 590 | input_close_device(handle); |
585 | wake_up_interruptible(&joydev->wait); | 591 | wake_up_interruptible(&joydev->wait); |
586 | list_for_each_entry(list, &joydev->list, node) | 592 | list_for_each_entry(client, &joydev->client_list, node) |
587 | kill_fasync(&list->fasync, SIGIO, POLL_HUP); | 593 | kill_fasync(&client->fasync, SIGIO, POLL_HUP); |
588 | } else | 594 | } else |
589 | joydev_free(joydev); | 595 | joydev_free(joydev); |
590 | } | 596 | } |