aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input/mouse/psmouse-base.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input/mouse/psmouse-base.c')
-rw-r--r--drivers/input/mouse/psmouse-base.c54
1 files changed, 44 insertions, 10 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}