aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dtor_core@ameritech.net>2005-06-01 03:39:44 -0400
committerDmitry Torokhov <dtor_core@ameritech.net>2005-06-01 03:39:44 -0400
commit04df1925fcda9a35c716423ad2b73abd70eb0913 (patch)
tree6094c0e71b5d17a62211cd56da7bb0ecb97a3df6
parent8121152c1770ef1cd029030d51802c65c489950d (diff)
Input: pmouse - introduce proper locking so state-changing
operations do not iterfere with each other. Also make sure that serio core takes serio->drv_sem not only for connect/disconnect but for reconnect too. Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r--drivers/input/mouse/psmouse-base.c54
-rw-r--r--drivers/input/serio/serio.c44
2 files changed, 80 insertions, 18 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 0ecf1297b6a8..259e6b70544b 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -68,6 +68,15 @@ __obsolete_setup("psmouse_smartscroll=");
68__obsolete_setup("psmouse_resetafter="); 68__obsolete_setup("psmouse_resetafter=");
69__obsolete_setup("psmouse_rate="); 69__obsolete_setup("psmouse_rate=");
70 70
71/*
72 * psmouse_sem protects all operations changing state of mouse
73 * (connecting, disconnecting, changing rate or resolution via
74 * sysfs). We could use a per-device semaphore but since there
75 * rarely more than one PS/2 mouse connected and since semaphore
76 * is taken in "slow" paths it is not worth it.
77 */
78static DECLARE_MUTEX(psmouse_sem);
79
71static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2", "LBPS/2" }; 80static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2", "LBPS/2" };
72 81
73/* 82/*
@@ -667,30 +676,40 @@ static void psmouse_cleanup(struct serio *serio)
667 676
668static void psmouse_disconnect(struct serio *serio) 677static void psmouse_disconnect(struct serio *serio)
669{ 678{
670 struct psmouse *psmouse, *parent; 679 struct psmouse *psmouse, *parent = NULL;
680
681 psmouse = serio_get_drvdata(serio);
671 682
672 device_remove_file(&serio->dev, &psmouse_attr_rate); 683 device_remove_file(&serio->dev, &psmouse_attr_rate);
673 device_remove_file(&serio->dev, &psmouse_attr_resolution); 684 device_remove_file(&serio->dev, &psmouse_attr_resolution);
674 device_remove_file(&serio->dev, &psmouse_attr_resetafter); 685 device_remove_file(&serio->dev, &psmouse_attr_resetafter);
675 686
676 psmouse = serio_get_drvdata(serio); 687 down(&psmouse_sem);
688
677 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); 689 psmouse_set_state(psmouse, PSMOUSE_CMD_MODE);
678 690
679 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { 691 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
680 parent = serio_get_drvdata(serio->parent); 692 parent = serio_get_drvdata(serio->parent);
681 if (parent->pt_deactivate) 693 psmouse_deactivate(parent);
682 parent->pt_deactivate(parent);
683 } 694 }
684 695
685 if (psmouse->disconnect) 696 if (psmouse->disconnect)
686 psmouse->disconnect(psmouse); 697 psmouse->disconnect(psmouse);
687 698
699 if (parent && parent->pt_deactivate)
700 parent->pt_deactivate(parent);
701
688 psmouse_set_state(psmouse, PSMOUSE_IGNORE); 702 psmouse_set_state(psmouse, PSMOUSE_IGNORE);
689 703
690 input_unregister_device(&psmouse->dev); 704 input_unregister_device(&psmouse->dev);
691 serio_close(serio); 705 serio_close(serio);
692 serio_set_drvdata(serio, NULL); 706 serio_set_drvdata(serio, NULL);
693 kfree(psmouse); 707 kfree(psmouse);
708
709 if (parent)
710 psmouse_activate(parent);
711
712 up(&psmouse_sem);
694} 713}
695 714
696/* 715/*
@@ -702,6 +721,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
702 struct psmouse *psmouse, *parent = NULL; 721 struct psmouse *psmouse, *parent = NULL;
703 int retval; 722 int retval;
704 723
724 down(&psmouse_sem);
725
705 /* 726 /*
706 * If this is a pass-through port deactivate parent so the device 727 * If this is a pass-through port deactivate parent so the device
707 * connected to this port can be successfully identified 728 * connected to this port can be successfully identified
@@ -711,13 +732,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
711 psmouse_deactivate(parent); 732 psmouse_deactivate(parent);
712 } 733 }
713 734
714 if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) { 735 if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) {
715 retval = -ENOMEM; 736 retval = -ENOMEM;
716 goto out; 737 goto out;
717 } 738 }
718 739
719 memset(psmouse, 0, sizeof(struct psmouse));
720
721 ps2_init(&psmouse->ps2dev, serio); 740 ps2_init(&psmouse->ps2dev, serio);
722 sprintf(psmouse->phys, "%s/input0", serio->phys); 741 sprintf(psmouse->phys, "%s/input0", serio->phys);
723 psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); 742 psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
@@ -785,10 +804,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
785 retval = 0; 804 retval = 0;
786 805
787out: 806out:
788 /* If this is a pass-through port the parent awaits to be activated */ 807 /* If this is a pass-through port the parent needs to be re-activated */
789 if (parent) 808 if (parent)
790 psmouse_activate(parent); 809 psmouse_activate(parent);
791 810
811 up(&psmouse_sem);
792 return retval; 812 return retval;
793} 813}
794 814
@@ -805,6 +825,8 @@ static int psmouse_reconnect(struct serio *serio)
805 return -1; 825 return -1;
806 } 826 }
807 827
828 down(&psmouse_sem);
829
808 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { 830 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
809 parent = serio_get_drvdata(serio->parent); 831 parent = serio_get_drvdata(serio->parent);
810 psmouse_deactivate(parent); 832 psmouse_deactivate(parent);
@@ -837,6 +859,7 @@ out:
837 if (parent) 859 if (parent)
838 psmouse_activate(parent); 860 psmouse_activate(parent);
839 861
862 up(&psmouse_sem);
840 return rc; 863 return rc;
841} 864}
842 865
@@ -907,7 +930,16 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
907 930
908 if (serio->drv != &psmouse_drv) { 931 if (serio->drv != &psmouse_drv) {
909 retval = -ENODEV; 932 retval = -ENODEV;
910 goto out; 933 goto out_unpin;
934 }
935
936 retval = down_interruptible(&psmouse_sem);
937 if (retval)
938 goto out_unpin;
939
940 if (psmouse->state == PSMOUSE_IGNORE) {
941 retval = -ENODEV;
942 goto out_up;
911 } 943 }
912 944
913 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { 945 if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
@@ -922,7 +954,9 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun
922 if (parent) 954 if (parent)
923 psmouse_activate(parent); 955 psmouse_activate(parent);
924 956
925out: 957 out_up:
958 up(&psmouse_sem);
959 out_unpin:
926 serio_unpin_driver(serio); 960 serio_unpin_driver(serio);
927 return retval; 961 return retval;
928} 962}
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
index 2c93ceab831a..b82815a0b65b 100644
--- a/drivers/input/serio/serio.c
+++ b/drivers/input/serio/serio.c
@@ -67,6 +67,37 @@ static void serio_destroy_port(struct serio *serio);
67static void serio_reconnect_port(struct serio *serio); 67static void serio_reconnect_port(struct serio *serio);
68static void serio_disconnect_port(struct serio *serio); 68static void serio_disconnect_port(struct serio *serio);
69 69
70static int serio_connect_driver(struct serio *serio, struct serio_driver *drv)
71{
72 int retval;
73
74 down(&serio->drv_sem);
75 retval = drv->connect(serio, drv);
76 up(&serio->drv_sem);
77
78 return retval;
79}
80
81static int serio_reconnect_driver(struct serio *serio)
82{
83 int retval = -1;
84
85 down(&serio->drv_sem);
86 if (serio->drv && serio->drv->reconnect)
87 retval = serio->drv->reconnect(serio);
88 up(&serio->drv_sem);
89
90 return retval;
91}
92
93static void serio_disconnect_driver(struct serio *serio)
94{
95 down(&serio->drv_sem);
96 if (serio->drv)
97 serio->drv->disconnect(serio);
98 up(&serio->drv_sem);
99}
100
70static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) 101static int serio_match_port(const struct serio_device_id *ids, struct serio *serio)
71{ 102{
72 while (ids->type || ids->proto) { 103 while (ids->type || ids->proto) {
@@ -90,7 +121,7 @@ static void serio_bind_driver(struct serio *serio, struct serio_driver *drv)
90 121
91 if (serio_match_port(drv->id_table, serio)) { 122 if (serio_match_port(drv->id_table, serio)) {
92 serio->dev.driver = &drv->driver; 123 serio->dev.driver = &drv->driver;
93 if (drv->connect(serio, drv)) { 124 if (serio_connect_driver(serio, drv)) {
94 serio->dev.driver = NULL; 125 serio->dev.driver = NULL;
95 goto out; 126 goto out;
96 } 127 }
@@ -550,7 +581,7 @@ static void serio_destroy_port(struct serio *serio)
550static void serio_reconnect_port(struct serio *serio) 581static void serio_reconnect_port(struct serio *serio)
551{ 582{
552 do { 583 do {
553 if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { 584 if (serio_reconnect_driver(serio)) {
554 serio_disconnect_port(serio); 585 serio_disconnect_port(serio);
555 serio_find_driver(serio); 586 serio_find_driver(serio);
556 /* Ok, old children are now gone, we are done */ 587 /* Ok, old children are now gone, we are done */
@@ -679,15 +710,14 @@ static int serio_driver_probe(struct device *dev)
679 struct serio *serio = to_serio_port(dev); 710 struct serio *serio = to_serio_port(dev);
680 struct serio_driver *drv = to_serio_driver(dev->driver); 711 struct serio_driver *drv = to_serio_driver(dev->driver);
681 712
682 return drv->connect(serio, drv); 713 return serio_connect_driver(serio, drv);
683} 714}
684 715
685static int serio_driver_remove(struct device *dev) 716static int serio_driver_remove(struct device *dev)
686{ 717{
687 struct serio *serio = to_serio_port(dev); 718 struct serio *serio = to_serio_port(dev);
688 struct serio_driver *drv = to_serio_driver(dev->driver);
689 719
690 drv->disconnect(serio); 720 serio_disconnect_driver(serio);
691 return 0; 721 return 0;
692} 722}
693 723
@@ -723,11 +753,9 @@ start_over:
723 753
724static void serio_set_drv(struct serio *serio, struct serio_driver *drv) 754static void serio_set_drv(struct serio *serio, struct serio_driver *drv)
725{ 755{
726 down(&serio->drv_sem);
727 serio_pause_rx(serio); 756 serio_pause_rx(serio);
728 serio->drv = drv; 757 serio->drv = drv;
729 serio_continue_rx(serio); 758 serio_continue_rx(serio);
730 up(&serio->drv_sem);
731} 759}
732 760
733static int serio_bus_match(struct device *dev, struct device_driver *drv) 761static int serio_bus_match(struct device *dev, struct device_driver *drv)
@@ -787,7 +815,7 @@ static int serio_resume(struct device *dev)
787{ 815{
788 struct serio *serio = to_serio_port(dev); 816 struct serio *serio = to_serio_port(dev);
789 817
790 if (!serio->drv || !serio->drv->reconnect || serio->drv->reconnect(serio)) { 818 if (serio_reconnect_driver(serio)) {
791 /* 819 /*
792 * Driver re-probing can take a while, so better let kseriod 820 * Driver re-probing can take a while, so better let kseriod
793 * deal with it. 821 * deal with it.