aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/input/mouse/psmouse-base.c4
-rw-r--r--drivers/input/serio/serio.c124
-rw-r--r--include/linux/serio.h4
3 files changed, 86 insertions, 46 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 73a7af2542a8..cd9d0c97e429 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -1584,10 +1584,10 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
1584 if (!new_dev) 1584 if (!new_dev)
1585 return -ENOMEM; 1585 return -ENOMEM;
1586 1586
1587 while (serio->child) { 1587 while (!list_empty(&serio->children)) {
1588 if (++retry > 3) { 1588 if (++retry > 3) {
1589 printk(KERN_WARNING 1589 printk(KERN_WARNING
1590 "psmouse: failed to destroy child port, " 1590 "psmouse: failed to destroy children ports, "
1591 "protocol change aborted.\n"); 1591 "protocol change aborted.\n");
1592 input_free_device(new_dev); 1592 input_free_device(new_dev);
1593 return -EIO; 1593 return -EIO;
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 8a426375fcb3..405bf214527c 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -55,7 +55,7 @@ static struct bus_type serio_bus;
55static void serio_add_port(struct serio *serio); 55static void serio_add_port(struct serio *serio);
56static int serio_reconnect_port(struct serio *serio); 56static int serio_reconnect_port(struct serio *serio);
57static void serio_disconnect_port(struct serio *serio); 57static void serio_disconnect_port(struct serio *serio);
58static void serio_reconnect_chain(struct serio *serio); 58static void serio_reconnect_subtree(struct serio *serio);
59static void serio_attach_driver(struct serio_driver *drv); 59static void serio_attach_driver(struct serio_driver *drv);
60 60
61static int serio_connect_driver(struct serio *serio, struct serio_driver *drv) 61static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
@@ -151,7 +151,7 @@ static void serio_find_driver(struct serio *serio)
151enum serio_event_type { 151enum serio_event_type {
152 SERIO_RESCAN_PORT, 152 SERIO_RESCAN_PORT,
153 SERIO_RECONNECT_PORT, 153 SERIO_RECONNECT_PORT,
154 SERIO_RECONNECT_CHAIN, 154 SERIO_RECONNECT_SUBTREE,
155 SERIO_REGISTER_PORT, 155 SERIO_REGISTER_PORT,
156 SERIO_ATTACH_DRIVER, 156 SERIO_ATTACH_DRIVER,
157}; 157};
@@ -291,8 +291,8 @@ static void serio_handle_event(void)
291 serio_find_driver(event->object); 291 serio_find_driver(event->object);
292 break; 292 break;
293 293
294 case SERIO_RECONNECT_CHAIN: 294 case SERIO_RECONNECT_SUBTREE:
295 serio_reconnect_chain(event->object); 295 serio_reconnect_subtree(event->object);
296 break; 296 break;
297 297
298 case SERIO_ATTACH_DRIVER: 298 case SERIO_ATTACH_DRIVER:
@@ -329,12 +329,10 @@ static void serio_remove_pending_events(void *object)
329} 329}
330 330
331/* 331/*
332 * Destroy child serio port (if any) that has not been fully registered yet. 332 * Locate child serio port (if any) that has not been fully registered yet.
333 * 333 *
334 * Note that we rely on the fact that port can have only one child and therefore 334 * Children are registered by driver's connect() handler so there can't be a
335 * only one child registration request can be pending. Additionally, children 335 * grandchild pending registration together with a child.
336 * are registered by driver's connect() handler so there can't be a grandchild
337 * pending registration together with a child.
338 */ 336 */
339static struct serio *serio_get_pending_child(struct serio *parent) 337static struct serio *serio_get_pending_child(struct serio *parent)
340{ 338{
@@ -448,7 +446,7 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
448 if (!strncmp(buf, "none", count)) { 446 if (!strncmp(buf, "none", count)) {
449 serio_disconnect_port(serio); 447 serio_disconnect_port(serio);
450 } else if (!strncmp(buf, "reconnect", count)) { 448 } else if (!strncmp(buf, "reconnect", count)) {
451 serio_reconnect_chain(serio); 449 serio_reconnect_subtree(serio);
452 } else if (!strncmp(buf, "rescan", count)) { 450 } else if (!strncmp(buf, "rescan", count)) {
453 serio_disconnect_port(serio); 451 serio_disconnect_port(serio);
454 serio_find_driver(serio); 452 serio_find_driver(serio);
@@ -515,6 +513,8 @@ static void serio_init_port(struct serio *serio)
515 __module_get(THIS_MODULE); 513 __module_get(THIS_MODULE);
516 514
517 INIT_LIST_HEAD(&serio->node); 515 INIT_LIST_HEAD(&serio->node);
516 INIT_LIST_HEAD(&serio->child_node);
517 INIT_LIST_HEAD(&serio->children);
518 spin_lock_init(&serio->lock); 518 spin_lock_init(&serio->lock);
519 mutex_init(&serio->drv_mutex); 519 mutex_init(&serio->drv_mutex);
520 device_initialize(&serio->dev); 520 device_initialize(&serio->dev);
@@ -537,12 +537,13 @@ static void serio_init_port(struct serio *serio)
537 */ 537 */
538static void serio_add_port(struct serio *serio) 538static void serio_add_port(struct serio *serio)
539{ 539{
540 struct serio *parent = serio->parent;
540 int error; 541 int error;
541 542
542 if (serio->parent) { 543 if (parent) {
543 serio_pause_rx(serio->parent); 544 serio_pause_rx(parent);
544 serio->parent->child = serio; 545 list_add_tail(&serio->child_node, &parent->children);
545 serio_continue_rx(serio->parent); 546 serio_continue_rx(parent);
546 } 547 }
547 548
548 list_add_tail(&serio->node, &serio_list); 549 list_add_tail(&serio->node, &serio_list);
@@ -558,15 +559,14 @@ static void serio_add_port(struct serio *serio)
558} 559}
559 560
560/* 561/*
561 * serio_destroy_port() completes deregistration process and removes 562 * serio_destroy_port() completes unregistration process and removes
562 * port from the system 563 * port from the system
563 */ 564 */
564static void serio_destroy_port(struct serio *serio) 565static void serio_destroy_port(struct serio *serio)
565{ 566{
566 struct serio *child; 567 struct serio *child;
567 568
568 child = serio_get_pending_child(serio); 569 while ((child = serio_get_pending_child(serio)) != NULL) {
569 if (child) {
570 serio_remove_pending_events(child); 570 serio_remove_pending_events(child);
571 put_device(&child->dev); 571 put_device(&child->dev);
572 } 572 }
@@ -576,7 +576,7 @@ static void serio_destroy_port(struct serio *serio)
576 576
577 if (serio->parent) { 577 if (serio->parent) {
578 serio_pause_rx(serio->parent); 578 serio_pause_rx(serio->parent);
579 serio->parent->child = NULL; 579 list_del_init(&serio->child_node);
580 serio_continue_rx(serio->parent); 580 serio_continue_rx(serio->parent);
581 serio->parent = NULL; 581 serio->parent = NULL;
582 } 582 }
@@ -608,46 +608,82 @@ static int serio_reconnect_port(struct serio *serio)
608} 608}
609 609
610/* 610/*
611 * Reconnect serio port and all its children (re-initialize attached devices) 611 * Reconnect serio port and all its children (re-initialize attached
612 * devices).
612 */ 613 */
613static void serio_reconnect_chain(struct serio *serio) 614static void serio_reconnect_subtree(struct serio *root)
614{ 615{
616 struct serio *s = root;
617 int error;
618
615 do { 619 do {
616 if (serio_reconnect_port(serio)) { 620 error = serio_reconnect_port(s);
617 /* Ok, old children are now gone, we are done */ 621 if (!error) {
618 break; 622 /*
623 * Reconnect was successful, move on to do the
624 * first child.
625 */
626 if (!list_empty(&s->children)) {
627 s = list_first_entry(&s->children,
628 struct serio, child_node);
629 continue;
630 }
619 } 631 }
620 serio = serio->child; 632
621 } while (serio); 633 /*
634 * Either it was a leaf node or reconnect failed and it
635 * became a leaf node. Continue reconnecting starting with
636 * the next sibling of the parent node.
637 */
638 while (s != root) {
639 struct serio *parent = s->parent;
640
641 if (!list_is_last(&s->child_node, &parent->children)) {
642 s = list_entry(s->child_node.next,
643 struct serio, child_node);
644 break;
645 }
646
647 s = parent;
648 }
649 } while (s != root);
622} 650}
623 651
624/* 652/*
625 * serio_disconnect_port() unbinds a port from its driver. As a side effect 653 * serio_disconnect_port() unbinds a port from its driver. As a side effect
626 * all child ports are unbound and destroyed. 654 * all children ports are unbound and destroyed.
627 */ 655 */
628static void serio_disconnect_port(struct serio *serio) 656static void serio_disconnect_port(struct serio *serio)
629{ 657{
630 struct serio *s, *parent; 658 struct serio *s = serio;
659
660 /*
661 * Children ports should be disconnected and destroyed
662 * first; we travel the tree in depth-first order.
663 */
664 while (!list_empty(&serio->children)) {
665
666 /* Locate a leaf */
667 while (!list_empty(&s->children))
668 s = list_first_entry(&s->children,
669 struct serio, child_node);
631 670
632 if (serio->child) {
633 /* 671 /*
634 * Children ports should be disconnected and destroyed 672 * Prune this leaf node unless it is the one we
635 * first, staring with the leaf one, since we don't want 673 * started with.
636 * to do recursion
637 */ 674 */
638 for (s = serio; s->child; s = s->child) 675 if (s != serio) {
639 /* empty */; 676 struct serio *parent = s->parent;
640
641 do {
642 parent = s->parent;
643 677
644 device_release_driver(&s->dev); 678 device_release_driver(&s->dev);
645 serio_destroy_port(s); 679 serio_destroy_port(s);
646 } while ((s = parent) != serio); 680
681 s = parent;
682 }
647 } 683 }
648 684
649 /* 685 /*
650 * Ok, no children left, now disconnect this port 686 * OK, no children left, now disconnect this port.
651 */ 687 */
652 device_release_driver(&serio->dev); 688 device_release_driver(&serio->dev);
653} 689}
@@ -660,7 +696,7 @@ EXPORT_SYMBOL(serio_rescan);
660 696
661void serio_reconnect(struct serio *serio) 697void serio_reconnect(struct serio *serio)
662{ 698{
663 serio_queue_event(serio, NULL, SERIO_RECONNECT_CHAIN); 699 serio_queue_event(serio, NULL, SERIO_RECONNECT_SUBTREE);
664} 700}
665EXPORT_SYMBOL(serio_reconnect); 701EXPORT_SYMBOL(serio_reconnect);
666 702
@@ -688,14 +724,16 @@ void serio_unregister_port(struct serio *serio)
688EXPORT_SYMBOL(serio_unregister_port); 724EXPORT_SYMBOL(serio_unregister_port);
689 725
690/* 726/*
691 * Safely unregisters child port if one is present. 727 * Safely unregisters children ports if they are present.
692 */ 728 */
693void serio_unregister_child_port(struct serio *serio) 729void serio_unregister_child_port(struct serio *serio)
694{ 730{
731 struct serio *s, *next;
732
695 mutex_lock(&serio_mutex); 733 mutex_lock(&serio_mutex);
696 if (serio->child) { 734 list_for_each_entry_safe(s, next, &serio->children, child_node) {
697 serio_disconnect_port(serio->child); 735 serio_disconnect_port(s);
698 serio_destroy_port(serio->child); 736 serio_destroy_port(s);
699 } 737 }
700 mutex_unlock(&serio_mutex); 738 mutex_unlock(&serio_mutex);
701} 739}
diff --git a/include/linux/serio.h b/include/linux/serio.h
index 111ad501b054..109b237603b6 100644
--- a/include/linux/serio.h
+++ b/include/linux/serio.h
@@ -41,7 +41,9 @@ struct serio {
41 int (*start)(struct serio *); 41 int (*start)(struct serio *);
42 void (*stop)(struct serio *); 42 void (*stop)(struct serio *);
43 43
44 struct serio *parent, *child; 44 struct serio *parent;
45 struct list_head child_node; /* Entry in parent->children list */
46 struct list_head children;
45 unsigned int depth; /* level of nesting in serio hierarchy */ 47 unsigned int depth; /* level of nesting in serio hierarchy */
46 48
47 struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */ 49 struct serio_driver *drv; /* accessed from interrupt, must be protected by serio->lock and serio->sem */