diff options
author | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-06-01 03:39:44 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor_core@ameritech.net> | 2005-06-01 03:39:44 -0400 |
commit | 04df1925fcda9a35c716423ad2b73abd70eb0913 (patch) | |
tree | 6094c0e71b5d17a62211cd56da7bb0ecb97a3df6 /drivers/input/serio | |
parent | 8121152c1770ef1cd029030d51802c65c489950d (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>
Diffstat (limited to 'drivers/input/serio')
-rw-r--r-- | drivers/input/serio/serio.c | 44 |
1 files changed, 36 insertions, 8 deletions
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); | |||
67 | static void serio_reconnect_port(struct serio *serio); | 67 | static void serio_reconnect_port(struct serio *serio); |
68 | static void serio_disconnect_port(struct serio *serio); | 68 | static void serio_disconnect_port(struct serio *serio); |
69 | 69 | ||
70 | static 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 | |||
81 | static 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 | |||
93 | static 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 | |||
70 | static int serio_match_port(const struct serio_device_id *ids, struct serio *serio) | 101 | static 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) | |||
550 | static void serio_reconnect_port(struct serio *serio) | 581 | static 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 | ||
685 | static int serio_driver_remove(struct device *dev) | 716 | static 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 | ||
724 | static void serio_set_drv(struct serio *serio, struct serio_driver *drv) | 754 | static 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 | ||
733 | static int serio_bus_match(struct device *dev, struct device_driver *drv) | 761 | static 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. |