aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2007-08-30 00:22:39 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2007-08-30 00:22:39 -0400
commitb9d2d110b10f7b4788d0fdd328cf57e34b767817 (patch)
tree0be026e664e983f3c77c954a0b26cfe60b8d22e2
parentb126207ccdfe492fbc339c18d4898b1b5353fc6b (diff)
Input: tsdev - implement proper locking
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/tsdev.c388
1 files changed, 276 insertions, 112 deletions
diff --git a/drivers/input/tsdev.c b/drivers/input/tsdev.c
index d2f882e98e5e..c189f1dd569f 100644
--- a/drivers/input/tsdev.c
+++ b/drivers/input/tsdev.c
@@ -112,6 +112,8 @@ struct tsdev {
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 */
116 struct mutex mutex;
115 struct device dev; 117 struct device dev;
116 118
117 int x, y, pressure; 119 int x, y, pressure;
@@ -122,8 +124,9 @@ struct tsdev_client {
122 struct fasync_struct *fasync; 124 struct fasync_struct *fasync;
123 struct list_head node; 125 struct list_head node;
124 struct tsdev *tsdev; 126 struct tsdev *tsdev;
127 struct ts_event buffer[TSDEV_BUFFER_SIZE];
125 int head, tail; 128 int head, tail;
126 struct ts_event event[TSDEV_BUFFER_SIZE]; 129 spinlock_t buffer_lock; /* protects access to buffer, head and tail */
127 int raw; 130 int raw;
128}; 131};
129 132
@@ -137,6 +140,7 @@ struct tsdev_client {
137#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)
138 141
139static struct tsdev *tsdev_table[TSDEV_MINORS/2]; 142static struct tsdev *tsdev_table[TSDEV_MINORS/2];
143static DEFINE_MUTEX(tsdev_table_mutex);
140 144
141static int tsdev_fasync(int fd, struct file *file, int on) 145static int tsdev_fasync(int fd, struct file *file, int on)
142{ 146{
@@ -144,9 +148,91 @@ static int tsdev_fasync(int fd, struct file *file, int on)
144 int retval; 148 int retval;
145 149
146 retval = fasync_helper(fd, file, on, &client->fasync); 150 retval = fasync_helper(fd, file, on, &client->fasync);
151
147 return retval < 0 ? retval : 0; 152 return retval < 0 ? retval : 0;
148} 153}
149 154
155static void tsdev_free(struct device *dev)
156{
157 struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
158
159 kfree(tsdev);
160}
161
162static void tsdev_attach_client(struct tsdev *tsdev, struct tsdev_client *client)
163{
164 spin_lock(&tsdev->client_lock);
165 list_add_tail_rcu(&client->node, &tsdev->client_list);
166 spin_unlock(&tsdev->client_lock);
167 synchronize_sched();
168}
169
170static void tsdev_detach_client(struct tsdev *tsdev, struct tsdev_client *client)
171{
172 spin_lock(&tsdev->client_lock);
173 list_del_rcu(&client->node);
174 spin_unlock(&tsdev->client_lock);
175 synchronize_sched();
176}
177
178static int tsdev_open_device(struct tsdev *tsdev)
179{
180 int retval;
181
182 retval = mutex_lock_interruptible(&tsdev->mutex);
183 if (retval)
184 return retval;
185
186 if (!tsdev->exist)
187 retval = -ENODEV;
188 else if (!tsdev->open++)
189 retval = input_open_device(&tsdev->handle);
190
191 mutex_unlock(&tsdev->mutex);
192 return retval;
193}
194
195static void tsdev_close_device(struct tsdev *tsdev)
196{
197 mutex_lock(&tsdev->mutex);
198
199 if (tsdev->exist && !--tsdev->open)
200 input_close_device(&tsdev->handle);
201
202 mutex_unlock(&tsdev->mutex);
203}
204
205/*
206 * Wake up users waiting for IO so they can disconnect from
207 * dead device.
208 */
209static void tsdev_hangup(struct tsdev *tsdev)
210{
211 struct tsdev_client *client;
212
213 spin_lock(&tsdev->client_lock);
214 list_for_each_entry(client, &tsdev->client_list, node)
215 kill_fasync(&client->fasync, SIGIO, POLL_HUP);
216 spin_unlock(&tsdev->client_lock);
217
218 wake_up_interruptible(&tsdev->wait);
219}
220
221static int tsdev_release(struct inode *inode, struct file *file)
222{
223 struct tsdev_client *client = file->private_data;
224 struct tsdev *tsdev = client->tsdev;
225
226 tsdev_fasync(-1, file, 0);
227 tsdev_detach_client(tsdev, client);
228 kfree(client);
229
230 tsdev_close_device(tsdev);
231 put_device(&tsdev->dev);
232
233 return 0;
234}
235
150static int tsdev_open(struct inode *inode, struct file *file) 236static int tsdev_open(struct inode *inode, struct file *file)
151{ 237{
152 int i = iminor(inode) - TSDEV_MINOR_BASE; 238 int i = iminor(inode) - TSDEV_MINOR_BASE;
@@ -161,11 +247,16 @@ static int tsdev_open(struct inode *inode, struct file *file)
161 if (i >= TSDEV_MINORS) 247 if (i >= TSDEV_MINORS)
162 return -ENODEV; 248 return -ENODEV;
163 249
250 error = mutex_lock_interruptible(&tsdev_table_mutex);
251 if (error)
252 return error;
164 tsdev = tsdev_table[i & TSDEV_MINOR_MASK]; 253 tsdev = tsdev_table[i & TSDEV_MINOR_MASK];
165 if (!tsdev || !tsdev->exist) 254 if (tsdev)
166 return -ENODEV; 255 get_device(&tsdev->dev);
256 mutex_unlock(&tsdev_table_mutex);
167 257
168 get_device(&tsdev->dev); 258 if (!tsdev)
259 return -ENODEV;
169 260
170 client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL); 261 client = kzalloc(sizeof(struct tsdev_client), GFP_KERNEL);
171 if (!client) { 262 if (!client) {
@@ -173,51 +264,42 @@ static int tsdev_open(struct inode *inode, struct file *file)
173 goto err_put_tsdev; 264 goto err_put_tsdev;
174 } 265 }
175 266
267 spin_lock_init(&client->buffer_lock);
176 client->tsdev = tsdev; 268 client->tsdev = tsdev;
177 client->raw = (i >= TSDEV_MINORS / 2) ? 1 : 0; 269 client->raw = i >= TSDEV_MINORS / 2;
178 list_add_tail(&client->node, &tsdev->client_list); 270 tsdev_attach_client(tsdev, client);
179 271
180 if (!tsdev->open++ && tsdev->exist) { 272 error = tsdev_open_device(tsdev);
181 error = input_open_device(&tsdev->handle); 273 if (error)
182 if (error) 274 goto err_free_client;
183 goto err_free_client;
184 }
185 275
186 file->private_data = client; 276 file->private_data = client;
187 return 0; 277 return 0;
188 278
189 err_free_client: 279 err_free_client:
190 list_del(&client->node); 280 tsdev_detach_client(tsdev, client);
191 kfree(client); 281 kfree(client);
192 err_put_tsdev: 282 err_put_tsdev:
193 put_device(&tsdev->dev); 283 put_device(&tsdev->dev);
194 return error; 284 return error;
195} 285}
196 286
197static void tsdev_free(struct device *dev) 287static int tsdev_fetch_next_event(struct tsdev_client *client,
198{ 288 struct ts_event *event)
199 struct tsdev *tsdev = container_of(dev, struct tsdev, dev);
200
201 tsdev_table[tsdev->minor] = NULL;
202 kfree(tsdev);
203}
204
205static int tsdev_release(struct inode *inode, struct file *file)
206{ 289{
207 struct tsdev_client *client = file->private_data; 290 int have_event;
208 struct tsdev *tsdev = client->tsdev;
209 291
210 tsdev_fasync(-1, file, 0); 292 spin_lock_irq(&client->buffer_lock);
211
212 list_del(&client->node);
213 kfree(client);
214 293
215 if (!--tsdev->open && tsdev->exist) 294 have_event = client->head != client->tail;
216 input_close_device(&tsdev->handle); 295 if (have_event) {
296 *event = client->buffer[client->tail++];
297 client->tail &= TSDEV_BUFFER_SIZE - 1;
298 }
217 299
218 put_device(&tsdev->dev); 300 spin_unlock_irq(&client->buffer_lock);
219 301
220 return 0; 302 return have_event;
221} 303}
222 304
223static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count, 305static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
@@ -225,9 +307,11 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
225{ 307{
226 struct tsdev_client *client = file->private_data; 308 struct tsdev_client *client = file->private_data;
227 struct tsdev *tsdev = client->tsdev; 309 struct tsdev *tsdev = client->tsdev;
228 int retval = 0; 310 struct ts_event event;
311 int retval;
229 312
230 if (client->head == client->tail && tsdev->exist && (file->f_flags & O_NONBLOCK)) 313 if (client->head == client->tail && tsdev->exist &&
314 (file->f_flags & O_NONBLOCK))
231 return -EAGAIN; 315 return -EAGAIN;
232 316
233 retval = wait_event_interruptible(tsdev->wait, 317 retval = wait_event_interruptible(tsdev->wait,
@@ -238,13 +322,14 @@ static ssize_t tsdev_read(struct file *file, char __user *buffer, size_t count,
238 if (!tsdev->exist) 322 if (!tsdev->exist)
239 return -ENODEV; 323 return -ENODEV;
240 324
241 while (client->head != client->tail && 325 while (retval + sizeof(struct ts_event) <= count &&
242 retval + sizeof (struct ts_event) <= count) { 326 tsdev_fetch_next_event(client, &event)) {
243 if (copy_to_user (buffer + retval, client->event + client->tail, 327
244 sizeof (struct ts_event))) 328 if (copy_to_user(buffer + retval, &event,
329 sizeof(struct ts_event)))
245 return -EFAULT; 330 return -EFAULT;
246 client->tail = (client->tail + 1) & (TSDEV_BUFFER_SIZE - 1); 331
247 retval += sizeof (struct ts_event); 332 retval += sizeof(struct ts_event);
248 } 333 }
249 334
250 return retval; 335 return retval;
@@ -261,14 +346,23 @@ static unsigned int tsdev_poll(struct file *file, poll_table *wait)
261 (tsdev->exist ? 0 : (POLLHUP | POLLERR)); 346 (tsdev->exist ? 0 : (POLLHUP | POLLERR));
262} 347}
263 348
264static int tsdev_ioctl(struct inode *inode, struct file *file, 349static long tsdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
265 unsigned int cmd, unsigned long arg)
266{ 350{
267 struct tsdev_client *client = file->private_data; 351 struct tsdev_client *client = file->private_data;
268 struct tsdev *tsdev = client->tsdev; 352 struct tsdev *tsdev = client->tsdev;
269 int retval = 0; 353 int retval = 0;
270 354
355 retval = mutex_lock_interruptible(&tsdev->mutex);
356 if (retval)
357 return retval;
358
359 if (!tsdev->exist) {
360 retval = -ENODEV;
361 goto out;
362 }
363
271 switch (cmd) { 364 switch (cmd) {
365
272 case TS_GET_CAL: 366 case TS_GET_CAL:
273 if (copy_to_user((void __user *)arg, &tsdev->cal, 367 if (copy_to_user((void __user *)arg, &tsdev->cal,
274 sizeof (struct ts_calibration))) 368 sizeof (struct ts_calibration)))
@@ -277,7 +371,7 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
277 371
278 case TS_SET_CAL: 372 case TS_SET_CAL:
279 if (copy_from_user(&tsdev->cal, (void __user *)arg, 373 if (copy_from_user(&tsdev->cal, (void __user *)arg,
280 sizeof (struct ts_calibration))) 374 sizeof(struct ts_calibration)))
281 retval = -EFAULT; 375 retval = -EFAULT;
282 break; 376 break;
283 377
@@ -286,29 +380,79 @@ static int tsdev_ioctl(struct inode *inode, struct file *file,
286 break; 380 break;
287 } 381 }
288 382
383 out:
384 mutex_unlock(&tsdev->mutex);
289 return retval; 385 return retval;
290} 386}
291 387
292static const struct file_operations tsdev_fops = { 388static const struct file_operations tsdev_fops = {
293 .owner = THIS_MODULE, 389 .owner = THIS_MODULE,
294 .open = tsdev_open, 390 .open = tsdev_open,
295 .release = tsdev_release, 391 .release = tsdev_release,
296 .read = tsdev_read, 392 .read = tsdev_read,
297 .poll = tsdev_poll, 393 .poll = tsdev_poll,
298 .fasync = tsdev_fasync, 394 .fasync = tsdev_fasync,
299 .ioctl = tsdev_ioctl, 395 .unlocked_ioctl = tsdev_ioctl,
300}; 396};
301 397
398static void tsdev_pass_event(struct tsdev *tsdev, struct tsdev_client *client,
399 int x, int y, int pressure, int millisecs)
400{
401 struct ts_event *event;
402 int tmp;
403
404 /* Interrupts are already disabled, just acquire the lock */
405 spin_lock(&client->buffer_lock);
406
407 event = &client->buffer[client->head++];
408 client->head &= TSDEV_BUFFER_SIZE - 1;
409
410 /* Calibration */
411 if (!client->raw) {
412 x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans;
413 y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
414 if (tsdev->cal.xyswap) {
415 tmp = x; x = y; y = tmp;
416 }
417 }
418
419 event->millisecs = millisecs;
420 event->x = x;
421 event->y = y;
422 event->pressure = pressure;
423
424 spin_unlock(&client->buffer_lock);
425
426 kill_fasync(&client->fasync, SIGIO, POLL_IN);
427}
428
429static void tsdev_distribute_event(struct tsdev *tsdev)
430{
431 struct tsdev_client *client;
432 struct timeval time;
433 int millisecs;
434
435 do_gettimeofday(&time);
436 millisecs = time.tv_usec / 1000;
437
438 list_for_each_entry_rcu(client, &tsdev->client_list, node)
439 tsdev_pass_event(tsdev, client,
440 tsdev->x, tsdev->y,
441 tsdev->pressure, millisecs);
442}
443
302static void tsdev_event(struct input_handle *handle, unsigned int type, 444static void tsdev_event(struct input_handle *handle, unsigned int type,
303 unsigned int code, int value) 445 unsigned int code, int value)
304{ 446{
305 struct tsdev *tsdev = handle->private; 447 struct tsdev *tsdev = handle->private;
306 struct tsdev_client *client; 448 struct input_dev *dev = handle->dev;
307 struct timeval time; 449 int wake_up_readers = 0;
308 450
309 switch (type) { 451 switch (type) {
452
310 case EV_ABS: 453 case EV_ABS:
311 switch (code) { 454 switch (code) {
455
312 case ABS_X: 456 case ABS_X:
313 tsdev->x = value; 457 tsdev->x = value;
314 break; 458 break;
@@ -318,9 +462,9 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
318 break; 462 break;
319 463
320 case ABS_PRESSURE: 464 case ABS_PRESSURE:
321 if (value > handle->dev->absmax[ABS_PRESSURE]) 465 if (value > dev->absmax[ABS_PRESSURE])
322 value = handle->dev->absmax[ABS_PRESSURE]; 466 value = dev->absmax[ABS_PRESSURE];
323 value -= handle->dev->absmin[ABS_PRESSURE]; 467 value -= dev->absmin[ABS_PRESSURE];
324 if (value < 0) 468 if (value < 0)
325 value = 0; 469 value = 0;
326 tsdev->pressure = value; 470 tsdev->pressure = value;
@@ -330,6 +474,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
330 474
331 case EV_REL: 475 case EV_REL:
332 switch (code) { 476 switch (code) {
477
333 case REL_X: 478 case REL_X:
334 tsdev->x += value; 479 tsdev->x += value;
335 if (tsdev->x < 0) 480 if (tsdev->x < 0)
@@ -351,6 +496,7 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
351 case EV_KEY: 496 case EV_KEY:
352 if (code == BTN_TOUCH || code == BTN_MOUSE) { 497 if (code == BTN_TOUCH || code == BTN_MOUSE) {
353 switch (value) { 498 switch (value) {
499
354 case 0: 500 case 0:
355 tsdev->pressure = 0; 501 tsdev->pressure = 0;
356 break; 502 break;
@@ -362,49 +508,71 @@ static void tsdev_event(struct input_handle *handle, unsigned int type,
362 } 508 }
363 } 509 }
364 break; 510 break;
511
512 case EV_SYN:
513 if (code == SYN_REPORT) {
514 tsdev_distribute_event(tsdev);
515 wake_up_readers = 1;
516 }
517 break;
365 } 518 }
366 519
367 if (type != EV_SYN || code != SYN_REPORT) 520 if (wake_up_readers)
368 return; 521 wake_up_interruptible(&tsdev->wait);
522}
523
524static int tsdev_install_chrdev(struct tsdev *tsdev)
525{
526 tsdev_table[tsdev->minor] = tsdev;
527 return 0;
528}
369 529
370 list_for_each_entry(client, &tsdev->client_list, node) { 530static void tsdev_remove_chrdev(struct tsdev *tsdev)
371 int x, y, tmp; 531{
532 mutex_lock(&tsdev_table_mutex);
533 tsdev_table[tsdev->minor] = NULL;
534 mutex_unlock(&tsdev_table_mutex);
535}
372 536
373 do_gettimeofday(&time); 537/*
374 client->event[client->head].millisecs = time.tv_usec / 1000; 538 * Mark device non-existant. This disables writes, ioctls and
375 client->event[client->head].pressure = tsdev->pressure; 539 * prevents new users from opening the device. Already posted
540 * blocking reads will stay, however new ones will fail.
541 */
542static void tsdev_mark_dead(struct tsdev *tsdev)
543{
544 mutex_lock(&tsdev->mutex);
545 tsdev->exist = 0;
546 mutex_unlock(&tsdev->mutex);
547}
376 548
377 x = tsdev->x; 549static void tsdev_cleanup(struct tsdev *tsdev)
378 y = tsdev->y; 550{
551 struct input_handle *handle = &tsdev->handle;
379 552
380 /* Calibration */ 553 tsdev_mark_dead(tsdev);
381 if (!client->raw) { 554 tsdev_hangup(tsdev);
382 x = ((x * tsdev->cal.xscale) >> 8) + tsdev->cal.xtrans; 555 tsdev_remove_chrdev(tsdev);
383 y = ((y * tsdev->cal.yscale) >> 8) + tsdev->cal.ytrans;
384 if (tsdev->cal.xyswap) {
385 tmp = x; x = y; y = tmp;
386 }
387 }
388 556
389 client->event[client->head].x = x; 557 /* tsdev is marked dead so noone else accesses tsdev->open */
390 client->event[client->head].y = y; 558 if (tsdev->open)
391 client->head = (client->head + 1) & (TSDEV_BUFFER_SIZE - 1); 559 input_close_device(handle);
392 kill_fasync(&client->fasync, SIGIO, POLL_IN);
393 }
394 wake_up_interruptible(&tsdev->wait);
395} 560}
396 561
397static int tsdev_connect(struct input_handler *handler, struct input_dev *dev, 562static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
398 const struct input_device_id *id) 563 const struct input_device_id *id)
399{ 564{
400 struct tsdev *tsdev; 565 struct tsdev *tsdev;
401 int minor, delta; 566 int delta;
567 int minor;
402 int error; 568 int error;
403 569
404 for (minor = 0; minor < TSDEV_MINORS / 2 && tsdev_table[minor]; minor++); 570 for (minor = 0; minor < TSDEV_MINORS / 2; minor++)
405 if (minor >= TSDEV_MINORS / 2) { 571 if (!tsdev_table[minor])
406 printk(KERN_ERR 572 break;
407 "tsdev: You have way too many touchscreens\n"); 573
574 if (minor == TSDEV_MINORS) {
575 printk(KERN_ERR "tsdev: no more free tsdev devices\n");
408 return -ENFILE; 576 return -ENFILE;
409 } 577 }
410 578
@@ -413,15 +581,18 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
413 return -ENOMEM; 581 return -ENOMEM;
414 582
415 INIT_LIST_HEAD(&tsdev->client_list); 583 INIT_LIST_HEAD(&tsdev->client_list);
584 spin_lock_init(&tsdev->client_lock);
585 mutex_init(&tsdev->mutex);
416 init_waitqueue_head(&tsdev->wait); 586 init_waitqueue_head(&tsdev->wait);
417 587
588 snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
418 tsdev->exist = 1; 589 tsdev->exist = 1;
419 tsdev->minor = minor; 590 tsdev->minor = minor;
591
420 tsdev->handle.dev = dev; 592 tsdev->handle.dev = dev;
421 tsdev->handle.name = tsdev->name; 593 tsdev->handle.name = tsdev->name;
422 tsdev->handle.handler = handler; 594 tsdev->handle.handler = handler;
423 tsdev->handle.private = tsdev; 595 tsdev->handle.private = tsdev;
424 snprintf(tsdev->name, sizeof(tsdev->name), "ts%d", minor);
425 596
426 /* Precompute the rough calibration matrix */ 597 /* Precompute the rough calibration matrix */
427 delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1; 598 delta = dev->absmax [ABS_X] - dev->absmin [ABS_X] + 1;
@@ -436,28 +607,31 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
436 tsdev->cal.yscale = (yres << 8) / delta; 607 tsdev->cal.yscale = (yres << 8) / delta;
437 tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8); 608 tsdev->cal.ytrans = - ((dev->absmin [ABS_Y] * tsdev->cal.yscale) >> 8);
438 609
439 snprintf(tsdev->dev.bus_id, sizeof(tsdev->dev.bus_id), 610 strlcpy(tsdev->dev.bus_id, tsdev->name, sizeof(tsdev->dev.bus_id));
440 "ts%d", minor); 611 tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
441 tsdev->dev.class = &input_class; 612 tsdev->dev.class = &input_class;
442 tsdev->dev.parent = &dev->dev; 613 tsdev->dev.parent = &dev->dev;
443 tsdev->dev.devt = MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor);
444 tsdev->dev.release = tsdev_free; 614 tsdev->dev.release = tsdev_free;
445 device_initialize(&tsdev->dev); 615 device_initialize(&tsdev->dev);
446 616
447 tsdev_table[minor] = tsdev; 617 error = input_register_handle(&tsdev->handle);
448
449 error = device_add(&tsdev->dev);
450 if (error) 618 if (error)
451 goto err_free_tsdev; 619 goto err_free_tsdev;
452 620
453 error = input_register_handle(&tsdev->handle); 621 error = tsdev_install_chrdev(tsdev);
454 if (error) 622 if (error)
455 goto err_delete_tsdev; 623 goto err_unregister_handle;
624
625 error = device_add(&tsdev->dev);
626 if (error)
627 goto err_cleanup_tsdev;
456 628
457 return 0; 629 return 0;
458 630
459 err_delete_tsdev: 631 err_cleanup_tsdev:
460 device_del(&tsdev->dev); 632 tsdev_cleanup(tsdev);
633 err_unregister_handle:
634 input_unregister_handle(&tsdev->handle);
461 err_free_tsdev: 635 err_free_tsdev:
462 put_device(&tsdev->dev); 636 put_device(&tsdev->dev);
463 return error; 637 return error;
@@ -466,20 +640,10 @@ static int tsdev_connect(struct input_handler *handler, struct input_dev *dev,
466static void tsdev_disconnect(struct input_handle *handle) 640static void tsdev_disconnect(struct input_handle *handle)
467{ 641{
468 struct tsdev *tsdev = handle->private; 642 struct tsdev *tsdev = handle->private;
469 struct tsdev_client *client;
470 643
471 input_unregister_handle(handle);
472 device_del(&tsdev->dev); 644 device_del(&tsdev->dev);
473 645 tsdev_cleanup(tsdev);
474 tsdev->exist = 0; 646 input_unregister_handle(handle);
475
476 if (tsdev->open) {
477 input_close_device(handle);
478 list_for_each_entry(client, &tsdev->client_list, node)
479 kill_fasync(&client->fasync, SIGIO, POLL_HUP);
480 wake_up_interruptible(&tsdev->wait);
481 }
482
483 put_device(&tsdev->dev); 647 put_device(&tsdev->dev);
484} 648}
485 649
@@ -510,13 +674,13 @@ static const struct input_device_id tsdev_ids[] = {
510MODULE_DEVICE_TABLE(input, tsdev_ids); 674MODULE_DEVICE_TABLE(input, tsdev_ids);
511 675
512static struct input_handler tsdev_handler = { 676static struct input_handler tsdev_handler = {
513 .event = tsdev_event, 677 .event = tsdev_event,
514 .connect = tsdev_connect, 678 .connect = tsdev_connect,
515 .disconnect = tsdev_disconnect, 679 .disconnect = tsdev_disconnect,
516 .fops = &tsdev_fops, 680 .fops = &tsdev_fops,
517 .minor = TSDEV_MINOR_BASE, 681 .minor = TSDEV_MINOR_BASE,
518 .name = "tsdev", 682 .name = "tsdev",
519 .id_table = tsdev_ids, 683 .id_table = tsdev_ids,
520}; 684};
521 685
522static int __init tsdev_init(void) 686static int __init tsdev_init(void)