diff options
Diffstat (limited to 'drivers/input/mouse/psmouse-base.c')
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 351 |
1 files changed, 297 insertions, 54 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 019034b21a0b..19785a6c5abd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include "synaptics.h" | 24 | #include "synaptics.h" |
25 | #include "logips2pp.h" | 25 | #include "logips2pp.h" |
26 | #include "alps.h" | 26 | #include "alps.h" |
27 | #include "lifebook.h" | ||
27 | 28 | ||
28 | #define DRIVER_DESC "PS/2 mouse driver" | 29 | #define DRIVER_DESC "PS/2 mouse driver" |
29 | 30 | ||
@@ -31,10 +32,9 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |||
31 | MODULE_DESCRIPTION(DRIVER_DESC); | 32 | MODULE_DESCRIPTION(DRIVER_DESC); |
32 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
33 | 34 | ||
34 | static unsigned int psmouse_max_proto = -1U; | 35 | static unsigned int psmouse_max_proto = PSMOUSE_AUTO; |
35 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp); | 36 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp); |
36 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); | 37 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); |
37 | static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, NULL }; | ||
38 | #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) | 38 | #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) |
39 | #define param_set_proto_abbrev psmouse_set_maxproto | 39 | #define param_set_proto_abbrev psmouse_set_maxproto |
40 | #define param_get_proto_abbrev psmouse_get_maxproto | 40 | #define param_get_proto_abbrev psmouse_get_maxproto |
@@ -57,6 +57,7 @@ static unsigned int psmouse_resetafter; | |||
57 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); | 57 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); |
58 | MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); | 58 | MODULE_PARM_DESC(resetafter, "Reset device after so many bad packets (0 = never)."); |
59 | 59 | ||
60 | PSMOUSE_DEFINE_ATTR(protocol); | ||
60 | PSMOUSE_DEFINE_ATTR(rate); | 61 | PSMOUSE_DEFINE_ATTR(rate); |
61 | PSMOUSE_DEFINE_ATTR(resolution); | 62 | PSMOUSE_DEFINE_ATTR(resolution); |
62 | PSMOUSE_DEFINE_ATTR(resetafter); | 63 | PSMOUSE_DEFINE_ATTR(resetafter); |
@@ -67,7 +68,23 @@ __obsolete_setup("psmouse_smartscroll="); | |||
67 | __obsolete_setup("psmouse_resetafter="); | 68 | __obsolete_setup("psmouse_resetafter="); |
68 | __obsolete_setup("psmouse_rate="); | 69 | __obsolete_setup("psmouse_rate="); |
69 | 70 | ||
70 | static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2" }; | 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 | */ | ||
78 | static DECLARE_MUTEX(psmouse_sem); | ||
79 | |||
80 | struct psmouse_protocol { | ||
81 | enum psmouse_type type; | ||
82 | char *name; | ||
83 | char *alias; | ||
84 | int maxproto; | ||
85 | int (*detect)(struct psmouse *, int); | ||
86 | int (*init)(struct psmouse *); | ||
87 | }; | ||
71 | 88 | ||
72 | /* | 89 | /* |
73 | * psmouse_process_byte() analyzes the PS/2 data stream and reports | 90 | * psmouse_process_byte() analyzes the PS/2 data stream and reports |
@@ -407,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) | |||
407 | */ | 424 | */ |
408 | static int ps2bare_detect(struct psmouse *psmouse, int set_properties) | 425 | static int ps2bare_detect(struct psmouse *psmouse, int set_properties) |
409 | { | 426 | { |
410 | if (!psmouse->vendor) psmouse->vendor = "Generic"; | 427 | if (set_properties) { |
411 | if (!psmouse->name) psmouse->name = "Mouse"; | 428 | if (!psmouse->vendor) psmouse->vendor = "Generic"; |
429 | if (!psmouse->name) psmouse->name = "Mouse"; | ||
430 | } | ||
412 | 431 | ||
413 | return 0; | 432 | return 0; |
414 | } | 433 | } |
415 | 434 | ||
435 | |||
416 | /* | 436 | /* |
417 | * psmouse_extensions() probes for any extensions to the basic PS/2 protocol | 437 | * psmouse_extensions() probes for any extensions to the basic PS/2 protocol |
418 | * the mouse may have. | 438 | * the mouse may have. |
@@ -424,6 +444,17 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
424 | int synaptics_hardware = 0; | 444 | int synaptics_hardware = 0; |
425 | 445 | ||
426 | /* | 446 | /* |
447 | * We always check for lifebook because it does not disturb mouse | ||
448 | * (it only checks DMI information). | ||
449 | */ | ||
450 | if (lifebook_detect(psmouse, set_properties) == 0) { | ||
451 | if (max_proto > PSMOUSE_IMEX) { | ||
452 | if (!set_properties || lifebook_init(psmouse) == 0) | ||
453 | return PSMOUSE_LIFEBOOK; | ||
454 | } | ||
455 | } | ||
456 | |||
457 | /* | ||
427 | * Try Kensington ThinkingMouse (we try first, because synaptics probe | 458 | * Try Kensington ThinkingMouse (we try first, because synaptics probe |
428 | * upsets the thinkingmouse). | 459 | * upsets the thinkingmouse). |
429 | */ | 460 | */ |
@@ -506,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
506 | return PSMOUSE_PS2; | 537 | return PSMOUSE_PS2; |
507 | } | 538 | } |
508 | 539 | ||
540 | static struct psmouse_protocol psmouse_protocols[] = { | ||
541 | { | ||
542 | .type = PSMOUSE_PS2, | ||
543 | .name = "PS/2", | ||
544 | .alias = "bare", | ||
545 | .maxproto = 1, | ||
546 | .detect = ps2bare_detect, | ||
547 | }, | ||
548 | { | ||
549 | .type = PSMOUSE_PS2PP, | ||
550 | .name = "PS2++", | ||
551 | .alias = "logitech", | ||
552 | .detect = ps2pp_init, | ||
553 | }, | ||
554 | { | ||
555 | .type = PSMOUSE_THINKPS, | ||
556 | .name = "ThinkPS/2", | ||
557 | .alias = "thinkps", | ||
558 | .detect = thinking_detect, | ||
559 | }, | ||
560 | { | ||
561 | .type = PSMOUSE_GENPS, | ||
562 | .name = "GenPS/2", | ||
563 | .alias = "genius", | ||
564 | .detect = genius_detect, | ||
565 | }, | ||
566 | { | ||
567 | .type = PSMOUSE_IMPS, | ||
568 | .name = "ImPS/2", | ||
569 | .alias = "imps", | ||
570 | .maxproto = 1, | ||
571 | .detect = intellimouse_detect, | ||
572 | }, | ||
573 | { | ||
574 | .type = PSMOUSE_IMEX, | ||
575 | .name = "ImExPS/2", | ||
576 | .alias = "exps", | ||
577 | .maxproto = 1, | ||
578 | .detect = im_explorer_detect, | ||
579 | }, | ||
580 | { | ||
581 | .type = PSMOUSE_SYNAPTICS, | ||
582 | .name = "SynPS/2", | ||
583 | .alias = "synaptics", | ||
584 | .detect = synaptics_detect, | ||
585 | .init = synaptics_init, | ||
586 | }, | ||
587 | { | ||
588 | .type = PSMOUSE_ALPS, | ||
589 | .name = "AlpsPS/2", | ||
590 | .alias = "alps", | ||
591 | .detect = alps_detect, | ||
592 | .init = alps_init, | ||
593 | }, | ||
594 | { | ||
595 | .type = PSMOUSE_LIFEBOOK, | ||
596 | .name = "LBPS/2", | ||
597 | .alias = "lifebook", | ||
598 | .init = lifebook_init, | ||
599 | }, | ||
600 | { | ||
601 | .type = PSMOUSE_AUTO, | ||
602 | .name = "auto", | ||
603 | .alias = "any", | ||
604 | .maxproto = 1, | ||
605 | }, | ||
606 | }; | ||
607 | |||
608 | static struct psmouse_protocol *psmouse_protocol_by_type(enum psmouse_type type) | ||
609 | { | ||
610 | int i; | ||
611 | |||
612 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) | ||
613 | if (psmouse_protocols[i].type == type) | ||
614 | return &psmouse_protocols[i]; | ||
615 | |||
616 | WARN_ON(1); | ||
617 | return &psmouse_protocols[0]; | ||
618 | } | ||
619 | |||
620 | static struct psmouse_protocol *psmouse_protocol_by_name(const char *name, size_t len) | ||
621 | { | ||
622 | struct psmouse_protocol *p; | ||
623 | int i; | ||
624 | |||
625 | for (i = 0; i < ARRAY_SIZE(psmouse_protocols); i++) { | ||
626 | p = &psmouse_protocols[i]; | ||
627 | |||
628 | if ((strlen(p->name) == len && !strncmp(p->name, name, len)) || | ||
629 | (strlen(p->alias) == len && !strncmp(p->alias, name, len))) | ||
630 | return &psmouse_protocols[i]; | ||
631 | } | ||
632 | |||
633 | return NULL; | ||
634 | } | ||
635 | |||
636 | |||
509 | /* | 637 | /* |
510 | * psmouse_probe() probes for a PS/2 mouse. | 638 | * psmouse_probe() probes for a PS/2 mouse. |
511 | */ | 639 | */ |
@@ -653,30 +781,84 @@ static void psmouse_cleanup(struct serio *serio) | |||
653 | 781 | ||
654 | static void psmouse_disconnect(struct serio *serio) | 782 | static void psmouse_disconnect(struct serio *serio) |
655 | { | 783 | { |
656 | struct psmouse *psmouse, *parent; | 784 | struct psmouse *psmouse, *parent = NULL; |
657 | 785 | ||
786 | psmouse = serio_get_drvdata(serio); | ||
787 | |||
788 | device_remove_file(&serio->dev, &psmouse_attr_protocol); | ||
658 | device_remove_file(&serio->dev, &psmouse_attr_rate); | 789 | device_remove_file(&serio->dev, &psmouse_attr_rate); |
659 | device_remove_file(&serio->dev, &psmouse_attr_resolution); | 790 | device_remove_file(&serio->dev, &psmouse_attr_resolution); |
660 | device_remove_file(&serio->dev, &psmouse_attr_resetafter); | 791 | device_remove_file(&serio->dev, &psmouse_attr_resetafter); |
661 | 792 | ||
662 | psmouse = serio_get_drvdata(serio); | 793 | down(&psmouse_sem); |
794 | |||
663 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 795 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
664 | 796 | ||
665 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | 797 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { |
666 | parent = serio_get_drvdata(serio->parent); | 798 | parent = serio_get_drvdata(serio->parent); |
667 | if (parent->pt_deactivate) | 799 | psmouse_deactivate(parent); |
668 | parent->pt_deactivate(parent); | ||
669 | } | 800 | } |
670 | 801 | ||
671 | if (psmouse->disconnect) | 802 | if (psmouse->disconnect) |
672 | psmouse->disconnect(psmouse); | 803 | psmouse->disconnect(psmouse); |
673 | 804 | ||
805 | if (parent && parent->pt_deactivate) | ||
806 | parent->pt_deactivate(parent); | ||
807 | |||
674 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | 808 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); |
675 | 809 | ||
676 | input_unregister_device(&psmouse->dev); | 810 | input_unregister_device(&psmouse->dev); |
677 | serio_close(serio); | 811 | serio_close(serio); |
678 | serio_set_drvdata(serio, NULL); | 812 | serio_set_drvdata(serio, NULL); |
679 | kfree(psmouse); | 813 | kfree(psmouse); |
814 | |||
815 | if (parent) | ||
816 | psmouse_activate(parent); | ||
817 | |||
818 | up(&psmouse_sem); | ||
819 | } | ||
820 | |||
821 | static int psmouse_switch_protocol(struct psmouse *psmouse, struct psmouse_protocol *proto) | ||
822 | { | ||
823 | memset(&psmouse->dev, 0, sizeof(struct input_dev)); | ||
824 | |||
825 | init_input_dev(&psmouse->dev); | ||
826 | |||
827 | psmouse->dev.private = psmouse; | ||
828 | psmouse->dev.dev = &psmouse->ps2dev.serio->dev; | ||
829 | |||
830 | psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | ||
831 | psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
832 | psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
833 | |||
834 | psmouse->set_rate = psmouse_set_rate; | ||
835 | psmouse->set_resolution = psmouse_set_resolution; | ||
836 | psmouse->protocol_handler = psmouse_process_byte; | ||
837 | psmouse->pktsize = 3; | ||
838 | |||
839 | if (proto && (proto->detect || proto->init)) { | ||
840 | if (proto->detect && proto->detect(psmouse, 1) < 0) | ||
841 | return -1; | ||
842 | |||
843 | if (proto->init && proto->init(psmouse) < 0) | ||
844 | return -1; | ||
845 | |||
846 | psmouse->type = proto->type; | ||
847 | } | ||
848 | else | ||
849 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); | ||
850 | |||
851 | sprintf(psmouse->devname, "%s %s %s", | ||
852 | psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); | ||
853 | |||
854 | psmouse->dev.name = psmouse->devname; | ||
855 | psmouse->dev.phys = psmouse->phys; | ||
856 | psmouse->dev.id.bustype = BUS_I8042; | ||
857 | psmouse->dev.id.vendor = 0x0002; | ||
858 | psmouse->dev.id.product = psmouse->type; | ||
859 | psmouse->dev.id.version = psmouse->model; | ||
860 | |||
861 | return 0; | ||
680 | } | 862 | } |
681 | 863 | ||
682 | /* | 864 | /* |
@@ -688,6 +870,8 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
688 | struct psmouse *psmouse, *parent = NULL; | 870 | struct psmouse *psmouse, *parent = NULL; |
689 | int retval; | 871 | int retval; |
690 | 872 | ||
873 | down(&psmouse_sem); | ||
874 | |||
691 | /* | 875 | /* |
692 | * If this is a pass-through port deactivate parent so the device | 876 | * If this is a pass-through port deactivate parent so the device |
693 | * connected to this port can be successfully identified | 877 | * connected to this port can be successfully identified |
@@ -697,20 +881,14 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
697 | psmouse_deactivate(parent); | 881 | psmouse_deactivate(parent); |
698 | } | 882 | } |
699 | 883 | ||
700 | if (!(psmouse = kmalloc(sizeof(struct psmouse), GFP_KERNEL))) { | 884 | if (!(psmouse = kcalloc(1, sizeof(struct psmouse), GFP_KERNEL))) { |
701 | retval = -ENOMEM; | 885 | retval = -ENOMEM; |
702 | goto out; | 886 | goto out; |
703 | } | 887 | } |
704 | 888 | ||
705 | memset(psmouse, 0, sizeof(struct psmouse)); | ||
706 | |||
707 | ps2_init(&psmouse->ps2dev, serio); | 889 | ps2_init(&psmouse->ps2dev, serio); |
708 | sprintf(psmouse->phys, "%s/input0", serio->phys); | 890 | sprintf(psmouse->phys, "%s/input0", serio->phys); |
709 | psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | 891 | |
710 | psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
711 | psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
712 | psmouse->dev.private = psmouse; | ||
713 | psmouse->dev.dev = &serio->dev; | ||
714 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | 892 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); |
715 | 893 | ||
716 | serio_set_drvdata(serio, psmouse); | 894 | serio_set_drvdata(serio, psmouse); |
@@ -734,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
734 | psmouse->resolution = psmouse_resolution; | 912 | psmouse->resolution = psmouse_resolution; |
735 | psmouse->resetafter = psmouse_resetafter; | 913 | psmouse->resetafter = psmouse_resetafter; |
736 | psmouse->smartscroll = psmouse_smartscroll; | 914 | psmouse->smartscroll = psmouse_smartscroll; |
737 | psmouse->set_rate = psmouse_set_rate; | ||
738 | psmouse->set_resolution = psmouse_set_resolution; | ||
739 | psmouse->protocol_handler = psmouse_process_byte; | ||
740 | psmouse->pktsize = 3; | ||
741 | 915 | ||
742 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); | 916 | psmouse_switch_protocol(psmouse, NULL); |
743 | |||
744 | sprintf(psmouse->devname, "%s %s %s", | ||
745 | psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); | ||
746 | |||
747 | psmouse->dev.name = psmouse->devname; | ||
748 | psmouse->dev.phys = psmouse->phys; | ||
749 | psmouse->dev.id.bustype = BUS_I8042; | ||
750 | psmouse->dev.id.vendor = 0x0002; | ||
751 | psmouse->dev.id.product = psmouse->type; | ||
752 | psmouse->dev.id.version = psmouse->model; | ||
753 | 917 | ||
754 | input_register_device(&psmouse->dev); | 918 | input_register_device(&psmouse->dev); |
755 | |||
756 | printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); | 919 | printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); |
757 | 920 | ||
758 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 921 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
@@ -762,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
762 | if (parent && parent->pt_activate) | 925 | if (parent && parent->pt_activate) |
763 | parent->pt_activate(parent); | 926 | parent->pt_activate(parent); |
764 | 927 | ||
928 | device_create_file(&serio->dev, &psmouse_attr_protocol); | ||
765 | device_create_file(&serio->dev, &psmouse_attr_rate); | 929 | device_create_file(&serio->dev, &psmouse_attr_rate); |
766 | device_create_file(&serio->dev, &psmouse_attr_resolution); | 930 | device_create_file(&serio->dev, &psmouse_attr_resolution); |
767 | device_create_file(&serio->dev, &psmouse_attr_resetafter); | 931 | device_create_file(&serio->dev, &psmouse_attr_resetafter); |
@@ -771,10 +935,11 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
771 | retval = 0; | 935 | retval = 0; |
772 | 936 | ||
773 | out: | 937 | out: |
774 | /* If this is a pass-through port the parent awaits to be activated */ | 938 | /* If this is a pass-through port the parent needs to be re-activated */ |
775 | if (parent) | 939 | if (parent) |
776 | psmouse_activate(parent); | 940 | psmouse_activate(parent); |
777 | 941 | ||
942 | up(&psmouse_sem); | ||
778 | return retval; | 943 | return retval; |
779 | } | 944 | } |
780 | 945 | ||
@@ -791,6 +956,8 @@ static int psmouse_reconnect(struct serio *serio) | |||
791 | return -1; | 956 | return -1; |
792 | } | 957 | } |
793 | 958 | ||
959 | down(&psmouse_sem); | ||
960 | |||
794 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | 961 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { |
795 | parent = serio_get_drvdata(serio->parent); | 962 | parent = serio_get_drvdata(serio->parent); |
796 | psmouse_deactivate(parent); | 963 | psmouse_deactivate(parent); |
@@ -823,6 +990,7 @@ out: | |||
823 | if (parent) | 990 | if (parent) |
824 | psmouse_activate(parent); | 991 | psmouse_activate(parent); |
825 | 992 | ||
993 | up(&psmouse_sem); | ||
826 | return rc; | 994 | return rc; |
827 | } | 995 | } |
828 | 996 | ||
@@ -893,26 +1061,109 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun | |||
893 | 1061 | ||
894 | if (serio->drv != &psmouse_drv) { | 1062 | if (serio->drv != &psmouse_drv) { |
895 | retval = -ENODEV; | 1063 | retval = -ENODEV; |
896 | goto out; | 1064 | goto out_unpin; |
1065 | } | ||
1066 | |||
1067 | retval = down_interruptible(&psmouse_sem); | ||
1068 | if (retval) | ||
1069 | goto out_unpin; | ||
1070 | |||
1071 | if (psmouse->state == PSMOUSE_IGNORE) { | ||
1072 | retval = -ENODEV; | ||
1073 | goto out_up; | ||
897 | } | 1074 | } |
898 | 1075 | ||
899 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | 1076 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { |
900 | parent = serio_get_drvdata(serio->parent); | 1077 | parent = serio_get_drvdata(serio->parent); |
901 | psmouse_deactivate(parent); | 1078 | psmouse_deactivate(parent); |
902 | } | 1079 | } |
1080 | |||
903 | psmouse_deactivate(psmouse); | 1081 | psmouse_deactivate(psmouse); |
904 | 1082 | ||
905 | retval = handler(psmouse, buf, count); | 1083 | retval = handler(psmouse, buf, count); |
906 | 1084 | ||
907 | psmouse_activate(psmouse); | 1085 | if (retval != -ENODEV) |
1086 | psmouse_activate(psmouse); | ||
1087 | |||
908 | if (parent) | 1088 | if (parent) |
909 | psmouse_activate(parent); | 1089 | psmouse_activate(parent); |
910 | 1090 | ||
911 | out: | 1091 | out_up: |
1092 | up(&psmouse_sem); | ||
1093 | out_unpin: | ||
912 | serio_unpin_driver(serio); | 1094 | serio_unpin_driver(serio); |
913 | return retval; | 1095 | return retval; |
914 | } | 1096 | } |
915 | 1097 | ||
1098 | static ssize_t psmouse_attr_show_protocol(struct psmouse *psmouse, char *buf) | ||
1099 | { | ||
1100 | return sprintf(buf, "%s\n", psmouse_protocol_by_type(psmouse->type)->name); | ||
1101 | } | ||
1102 | |||
1103 | static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, const char *buf, size_t count) | ||
1104 | { | ||
1105 | struct serio *serio = psmouse->ps2dev.serio; | ||
1106 | struct psmouse *parent = NULL; | ||
1107 | struct psmouse_protocol *proto; | ||
1108 | int retry = 0; | ||
1109 | |||
1110 | if (!(proto = psmouse_protocol_by_name(buf, count))) | ||
1111 | return -EINVAL; | ||
1112 | |||
1113 | if (psmouse->type == proto->type) | ||
1114 | return count; | ||
1115 | |||
1116 | while (serio->child) { | ||
1117 | if (++retry > 3) { | ||
1118 | printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); | ||
1119 | return -EIO; | ||
1120 | } | ||
1121 | |||
1122 | up(&psmouse_sem); | ||
1123 | serio_unpin_driver(serio); | ||
1124 | serio_unregister_child_port(serio); | ||
1125 | serio_pin_driver_uninterruptible(serio); | ||
1126 | down(&psmouse_sem); | ||
1127 | |||
1128 | if (serio->drv != &psmouse_drv) | ||
1129 | return -ENODEV; | ||
1130 | |||
1131 | if (psmouse->type == proto->type) | ||
1132 | return count; /* switched by other thread */ | ||
1133 | } | ||
1134 | |||
1135 | if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { | ||
1136 | parent = serio_get_drvdata(serio->parent); | ||
1137 | if (parent->pt_deactivate) | ||
1138 | parent->pt_deactivate(parent); | ||
1139 | } | ||
1140 | |||
1141 | if (psmouse->disconnect) | ||
1142 | psmouse->disconnect(psmouse); | ||
1143 | |||
1144 | psmouse_set_state(psmouse, PSMOUSE_IGNORE); | ||
1145 | input_unregister_device(&psmouse->dev); | ||
1146 | |||
1147 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | ||
1148 | |||
1149 | if (psmouse_switch_protocol(psmouse, proto) < 0) { | ||
1150 | psmouse_reset(psmouse); | ||
1151 | /* default to PSMOUSE_PS2 */ | ||
1152 | psmouse_switch_protocol(psmouse, &psmouse_protocols[0]); | ||
1153 | } | ||
1154 | |||
1155 | psmouse_initialize(psmouse); | ||
1156 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | ||
1157 | |||
1158 | input_register_device(&psmouse->dev); | ||
1159 | printk(KERN_INFO "input: %s on %s\n", psmouse->devname, serio->phys); | ||
1160 | |||
1161 | if (parent && parent->pt_activate) | ||
1162 | parent->pt_activate(parent); | ||
1163 | |||
1164 | return count; | ||
1165 | } | ||
1166 | |||
916 | static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) | 1167 | static ssize_t psmouse_attr_show_rate(struct psmouse *psmouse, char *buf) |
917 | { | 1168 | { |
918 | return sprintf(buf, "%d\n", psmouse->rate); | 1169 | return sprintf(buf, "%d\n", psmouse->rate); |
@@ -969,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char * | |||
969 | 1220 | ||
970 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) | 1221 | static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) |
971 | { | 1222 | { |
972 | int i; | 1223 | struct psmouse_protocol *proto; |
973 | 1224 | ||
974 | if (!val) | 1225 | if (!val) |
975 | return -EINVAL; | 1226 | return -EINVAL; |
976 | 1227 | ||
977 | if (!strncmp(val, "any", 3)) { | 1228 | proto = psmouse_protocol_by_name(val, strlen(val)); |
978 | *((unsigned int *)kp->arg) = -1U; | ||
979 | return 0; | ||
980 | } | ||
981 | 1229 | ||
982 | for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) { | 1230 | if (!proto || !proto->maxproto) |
983 | if (!psmouse_proto_abbrev[i]) | 1231 | return -EINVAL; |
984 | continue; | ||
985 | 1232 | ||
986 | if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) { | 1233 | *((unsigned int *)kp->arg) = proto->type; |
987 | *((unsigned int *)kp->arg) = i; | ||
988 | return 0; | ||
989 | } | ||
990 | } | ||
991 | 1234 | ||
992 | return -EINVAL; \ | 1235 | return 0; \ |
993 | } | 1236 | } |
994 | 1237 | ||
995 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) | 1238 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) |
996 | { | 1239 | { |
997 | return sprintf(buffer, "%s\n", | 1240 | int type = *((unsigned int *)kp->arg); |
998 | psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ? | 1241 | |
999 | psmouse_proto_abbrev[psmouse_max_proto] : "any"); | 1242 | return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name); |
1000 | } | 1243 | } |
1001 | 1244 | ||
1002 | static int __init psmouse_init(void) | 1245 | static int __init psmouse_init(void) |