diff options
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 291 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 1 | ||||
-rw-r--r-- | drivers/input/serio/serio.c | 18 | ||||
-rw-r--r-- | include/linux/serio.h | 6 |
4 files changed, 266 insertions, 50 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 259e6b70544b..19785a6c5abd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c | |||
@@ -32,15 +32,14 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |||
32 | MODULE_DESCRIPTION(DRIVER_DESC); | 32 | MODULE_DESCRIPTION(DRIVER_DESC); |
33 | MODULE_LICENSE("GPL"); | 33 | MODULE_LICENSE("GPL"); |
34 | 34 | ||
35 | static unsigned int psmouse_max_proto = -1U; | 35 | static unsigned int psmouse_max_proto = PSMOUSE_AUTO; |
36 | 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); |
37 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); | 37 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); |
38 | static char *psmouse_proto_abbrev[] = { NULL, "bare", NULL, NULL, NULL, "imps", "exps", NULL, NULL, "lifebook" }; | ||
39 | #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) |
40 | #define param_set_proto_abbrev psmouse_set_maxproto | 39 | #define param_set_proto_abbrev psmouse_set_maxproto |
41 | #define param_get_proto_abbrev psmouse_get_maxproto | 40 | #define param_get_proto_abbrev psmouse_get_maxproto |
42 | module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644); | 41 | module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644); |
43 | MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, lifebook, any). Useful for KVM switches."); | 42 | MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches."); |
44 | 43 | ||
45 | static unsigned int psmouse_resolution = 200; | 44 | static unsigned int psmouse_resolution = 200; |
46 | module_param_named(resolution, psmouse_resolution, uint, 0644); | 45 | module_param_named(resolution, psmouse_resolution, uint, 0644); |
@@ -58,6 +57,7 @@ static unsigned int psmouse_resetafter; | |||
58 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); | 57 | module_param_named(resetafter, psmouse_resetafter, uint, 0644); |
59 | 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)."); |
60 | 59 | ||
60 | PSMOUSE_DEFINE_ATTR(protocol); | ||
61 | PSMOUSE_DEFINE_ATTR(rate); | 61 | PSMOUSE_DEFINE_ATTR(rate); |
62 | PSMOUSE_DEFINE_ATTR(resolution); | 62 | PSMOUSE_DEFINE_ATTR(resolution); |
63 | PSMOUSE_DEFINE_ATTR(resetafter); | 63 | PSMOUSE_DEFINE_ATTR(resetafter); |
@@ -77,7 +77,14 @@ __obsolete_setup("psmouse_rate="); | |||
77 | */ | 77 | */ |
78 | static DECLARE_MUTEX(psmouse_sem); | 78 | static DECLARE_MUTEX(psmouse_sem); |
79 | 79 | ||
80 | static char *psmouse_protocols[] = { "None", "PS/2", "PS2++", "ThinkPS/2", "GenPS/2", "ImPS/2", "ImExPS/2", "SynPS/2", "AlpsPS/2", "LBPS/2" }; | 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 | }; | ||
81 | 88 | ||
82 | /* | 89 | /* |
83 | * psmouse_process_byte() analyzes the PS/2 data stream and reports | 90 | * psmouse_process_byte() analyzes the PS/2 data stream and reports |
@@ -417,12 +424,15 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) | |||
417 | */ | 424 | */ |
418 | static int ps2bare_detect(struct psmouse *psmouse, int set_properties) | 425 | static int ps2bare_detect(struct psmouse *psmouse, int set_properties) |
419 | { | 426 | { |
420 | if (!psmouse->vendor) psmouse->vendor = "Generic"; | 427 | if (set_properties) { |
421 | if (!psmouse->name) psmouse->name = "Mouse"; | 428 | if (!psmouse->vendor) psmouse->vendor = "Generic"; |
429 | if (!psmouse->name) psmouse->name = "Mouse"; | ||
430 | } | ||
422 | 431 | ||
423 | return 0; | 432 | return 0; |
424 | } | 433 | } |
425 | 434 | ||
435 | |||
426 | /* | 436 | /* |
427 | * 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 |
428 | * the mouse may have. | 438 | * the mouse may have. |
@@ -437,9 +447,7 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
437 | * We always check for lifebook because it does not disturb mouse | 447 | * We always check for lifebook because it does not disturb mouse |
438 | * (it only checks DMI information). | 448 | * (it only checks DMI information). |
439 | */ | 449 | */ |
440 | if (lifebook_detect(psmouse, set_properties) == 0 || | 450 | if (lifebook_detect(psmouse, set_properties) == 0) { |
441 | max_proto == PSMOUSE_LIFEBOOK) { | ||
442 | |||
443 | if (max_proto > PSMOUSE_IMEX) { | 451 | if (max_proto > PSMOUSE_IMEX) { |
444 | if (!set_properties || lifebook_init(psmouse) == 0) | 452 | if (!set_properties || lifebook_init(psmouse) == 0) |
445 | return PSMOUSE_LIFEBOOK; | 453 | return PSMOUSE_LIFEBOOK; |
@@ -529,6 +537,103 @@ static int psmouse_extensions(struct psmouse *psmouse, | |||
529 | return PSMOUSE_PS2; | 537 | return PSMOUSE_PS2; |
530 | } | 538 | } |
531 | 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 | |||
532 | /* | 637 | /* |
533 | * psmouse_probe() probes for a PS/2 mouse. | 638 | * psmouse_probe() probes for a PS/2 mouse. |
534 | */ | 639 | */ |
@@ -680,6 +785,7 @@ static void psmouse_disconnect(struct serio *serio) | |||
680 | 785 | ||
681 | psmouse = serio_get_drvdata(serio); | 786 | psmouse = serio_get_drvdata(serio); |
682 | 787 | ||
788 | device_remove_file(&serio->dev, &psmouse_attr_protocol); | ||
683 | device_remove_file(&serio->dev, &psmouse_attr_rate); | 789 | device_remove_file(&serio->dev, &psmouse_attr_rate); |
684 | device_remove_file(&serio->dev, &psmouse_attr_resolution); | 790 | device_remove_file(&serio->dev, &psmouse_attr_resolution); |
685 | device_remove_file(&serio->dev, &psmouse_attr_resetafter); | 791 | device_remove_file(&serio->dev, &psmouse_attr_resetafter); |
@@ -712,6 +818,49 @@ static void psmouse_disconnect(struct serio *serio) | |||
712 | up(&psmouse_sem); | 818 | up(&psmouse_sem); |
713 | } | 819 | } |
714 | 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; | ||
862 | } | ||
863 | |||
715 | /* | 864 | /* |
716 | * psmouse_connect() is a callback from the serio module when | 865 | * psmouse_connect() is a callback from the serio module when |
717 | * an unhandled serio port is found. | 866 | * an unhandled serio port is found. |
@@ -739,11 +888,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
739 | 888 | ||
740 | ps2_init(&psmouse->ps2dev, serio); | 889 | ps2_init(&psmouse->ps2dev, serio); |
741 | sprintf(psmouse->phys, "%s/input0", serio->phys); | 890 | sprintf(psmouse->phys, "%s/input0", serio->phys); |
742 | psmouse->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL); | 891 | |
743 | psmouse->dev.keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT); | ||
744 | psmouse->dev.relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
745 | psmouse->dev.private = psmouse; | ||
746 | psmouse->dev.dev = &serio->dev; | ||
747 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); | 892 | psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); |
748 | 893 | ||
749 | serio_set_drvdata(serio, psmouse); | 894 | serio_set_drvdata(serio, psmouse); |
@@ -767,25 +912,10 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
767 | psmouse->resolution = psmouse_resolution; | 912 | psmouse->resolution = psmouse_resolution; |
768 | psmouse->resetafter = psmouse_resetafter; | 913 | psmouse->resetafter = psmouse_resetafter; |
769 | psmouse->smartscroll = psmouse_smartscroll; | 914 | psmouse->smartscroll = psmouse_smartscroll; |
770 | psmouse->set_rate = psmouse_set_rate; | ||
771 | psmouse->set_resolution = psmouse_set_resolution; | ||
772 | psmouse->protocol_handler = psmouse_process_byte; | ||
773 | psmouse->pktsize = 3; | ||
774 | |||
775 | psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); | ||
776 | |||
777 | sprintf(psmouse->devname, "%s %s %s", | ||
778 | psmouse_protocols[psmouse->type], psmouse->vendor, psmouse->name); | ||
779 | 915 | ||
780 | psmouse->dev.name = psmouse->devname; | 916 | psmouse_switch_protocol(psmouse, NULL); |
781 | psmouse->dev.phys = psmouse->phys; | ||
782 | psmouse->dev.id.bustype = BUS_I8042; | ||
783 | psmouse->dev.id.vendor = 0x0002; | ||
784 | psmouse->dev.id.product = psmouse->type; | ||
785 | psmouse->dev.id.version = psmouse->model; | ||
786 | 917 | ||
787 | input_register_device(&psmouse->dev); | 918 | input_register_device(&psmouse->dev); |
788 | |||
789 | 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); |
790 | 920 | ||
791 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); | 921 | psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); |
@@ -795,6 +925,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) | |||
795 | if (parent && parent->pt_activate) | 925 | if (parent && parent->pt_activate) |
796 | parent->pt_activate(parent); | 926 | parent->pt_activate(parent); |
797 | 927 | ||
928 | device_create_file(&serio->dev, &psmouse_attr_protocol); | ||
798 | device_create_file(&serio->dev, &psmouse_attr_rate); | 929 | device_create_file(&serio->dev, &psmouse_attr_rate); |
799 | device_create_file(&serio->dev, &psmouse_attr_resolution); | 930 | device_create_file(&serio->dev, &psmouse_attr_resolution); |
800 | device_create_file(&serio->dev, &psmouse_attr_resetafter); | 931 | device_create_file(&serio->dev, &psmouse_attr_resetafter); |
@@ -946,11 +1077,14 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun | |||
946 | parent = serio_get_drvdata(serio->parent); | 1077 | parent = serio_get_drvdata(serio->parent); |
947 | psmouse_deactivate(parent); | 1078 | psmouse_deactivate(parent); |
948 | } | 1079 | } |
1080 | |||
949 | psmouse_deactivate(psmouse); | 1081 | psmouse_deactivate(psmouse); |
950 | 1082 | ||
951 | retval = handler(psmouse, buf, count); | 1083 | retval = handler(psmouse, buf, count); |
952 | 1084 | ||
953 | psmouse_activate(psmouse); | 1085 | if (retval != -ENODEV) |
1086 | psmouse_activate(psmouse); | ||
1087 | |||
954 | if (parent) | 1088 | if (parent) |
955 | psmouse_activate(parent); | 1089 | psmouse_activate(parent); |
956 | 1090 | ||
@@ -961,6 +1095,75 @@ ssize_t psmouse_attr_set_helper(struct device *dev, const char *buf, size_t coun | |||
961 | return retval; | 1095 | return retval; |
962 | } | 1096 | } |
963 | 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 | |||
964 | 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) |
965 | { | 1168 | { |
966 | return sprintf(buf, "%d\n", psmouse->rate); | 1169 | return sprintf(buf, "%d\n", psmouse->rate); |
@@ -1017,34 +1220,26 @@ static ssize_t psmouse_attr_set_resetafter(struct psmouse *psmouse, const char * | |||
1017 | 1220 | ||
1018 | 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) |
1019 | { | 1222 | { |
1020 | int i; | 1223 | struct psmouse_protocol *proto; |
1021 | 1224 | ||
1022 | if (!val) | 1225 | if (!val) |
1023 | return -EINVAL; | 1226 | return -EINVAL; |
1024 | 1227 | ||
1025 | if (!strncmp(val, "any", 3)) { | 1228 | proto = psmouse_protocol_by_name(val, strlen(val)); |
1026 | *((unsigned int *)kp->arg) = -1U; | ||
1027 | return 0; | ||
1028 | } | ||
1029 | 1229 | ||
1030 | for (i = 0; i < ARRAY_SIZE(psmouse_proto_abbrev); i++) { | 1230 | if (!proto || !proto->maxproto) |
1031 | if (!psmouse_proto_abbrev[i]) | 1231 | return -EINVAL; |
1032 | continue; | ||
1033 | 1232 | ||
1034 | if (!strncmp(val, psmouse_proto_abbrev[i], strlen(psmouse_proto_abbrev[i]))) { | 1233 | *((unsigned int *)kp->arg) = proto->type; |
1035 | *((unsigned int *)kp->arg) = i; | ||
1036 | return 0; | ||
1037 | } | ||
1038 | } | ||
1039 | 1234 | ||
1040 | return -EINVAL; \ | 1235 | return 0; \ |
1041 | } | 1236 | } |
1042 | 1237 | ||
1043 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) | 1238 | static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) |
1044 | { | 1239 | { |
1045 | return sprintf(buffer, "%s\n", | 1240 | int type = *((unsigned int *)kp->arg); |
1046 | psmouse_max_proto < ARRAY_SIZE(psmouse_proto_abbrev) ? | 1241 | |
1047 | psmouse_proto_abbrev[psmouse_max_proto] : "any"); | 1242 | return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name); |
1048 | } | 1243 | } |
1049 | 1244 | ||
1050 | static int __init psmouse_init(void) | 1245 | static int __init psmouse_init(void) |
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index 4848be627a6f..dc8e9ae07f32 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h | |||
@@ -78,6 +78,7 @@ enum psmouse_type { | |||
78 | PSMOUSE_SYNAPTICS, | 78 | PSMOUSE_SYNAPTICS, |
79 | PSMOUSE_ALPS, | 79 | PSMOUSE_ALPS, |
80 | PSMOUSE_LIFEBOOK, | 80 | PSMOUSE_LIFEBOOK, |
81 | PSMOUSE_AUTO /* This one should always be last */ | ||
81 | }; | 82 | }; |
82 | 83 | ||
83 | int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); | 84 | int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command); |
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c index b82815a0b65b..615bf62ad468 100644 --- a/drivers/input/serio/serio.c +++ b/drivers/input/serio/serio.c | |||
@@ -42,6 +42,7 @@ MODULE_LICENSE("GPL"); | |||
42 | EXPORT_SYMBOL(serio_interrupt); | 42 | EXPORT_SYMBOL(serio_interrupt); |
43 | EXPORT_SYMBOL(__serio_register_port); | 43 | EXPORT_SYMBOL(__serio_register_port); |
44 | EXPORT_SYMBOL(serio_unregister_port); | 44 | EXPORT_SYMBOL(serio_unregister_port); |
45 | EXPORT_SYMBOL(serio_unregister_child_port); | ||
45 | EXPORT_SYMBOL(__serio_unregister_port_delayed); | 46 | EXPORT_SYMBOL(__serio_unregister_port_delayed); |
46 | EXPORT_SYMBOL(__serio_register_driver); | 47 | EXPORT_SYMBOL(__serio_register_driver); |
47 | EXPORT_SYMBOL(serio_unregister_driver); | 48 | EXPORT_SYMBOL(serio_unregister_driver); |
@@ -179,12 +180,12 @@ static void serio_queue_event(void *object, struct module *owner, | |||
179 | spin_lock_irqsave(&serio_event_lock, flags); | 180 | spin_lock_irqsave(&serio_event_lock, flags); |
180 | 181 | ||
181 | /* | 182 | /* |
182 | * Scan event list for the other events for the same serio port, | 183 | * Scan event list for the other events for the same serio port, |
183 | * starting with the most recent one. If event is the same we | 184 | * starting with the most recent one. If event is the same we |
184 | * do not need add new one. If event is of different type we | 185 | * do not need add new one. If event is of different type we |
185 | * need to add this event and should not look further because | 186 | * need to add this event and should not look further because |
186 | * we need to preseve sequence of distinct events. | 187 | * we need to preseve sequence of distinct events. |
187 | */ | 188 | */ |
188 | list_for_each_entry_reverse(event, &serio_event_list, node) { | 189 | list_for_each_entry_reverse(event, &serio_event_list, node) { |
189 | if (event->object == object) { | 190 | if (event->object == object) { |
190 | if (event->type == event_type) | 191 | if (event->type == event_type) |
@@ -654,6 +655,19 @@ void serio_unregister_port(struct serio *serio) | |||
654 | } | 655 | } |
655 | 656 | ||
656 | /* | 657 | /* |
658 | * Safely unregisters child port if one is present. | ||
659 | */ | ||
660 | void serio_unregister_child_port(struct serio *serio) | ||
661 | { | ||
662 | down(&serio_sem); | ||
663 | if (serio->child) { | ||
664 | serio_disconnect_port(serio->child); | ||
665 | serio_destroy_port(serio->child); | ||
666 | } | ||
667 | up(&serio_sem); | ||
668 | } | ||
669 | |||
670 | /* | ||
657 | * Submits register request to kseriod for subsequent execution. | 671 | * Submits register request to kseriod for subsequent execution. |
658 | * Can be used when it is not obvious whether the serio_sem is | 672 | * Can be used when it is not obvious whether the serio_sem is |
659 | * taken or not and when delayed execution is feasible. | 673 | * taken or not and when delayed execution is feasible. |
diff --git a/include/linux/serio.h b/include/linux/serio.h index a2d3b9ae06f4..aa4d6493a034 100644 --- a/include/linux/serio.h +++ b/include/linux/serio.h | |||
@@ -83,6 +83,7 @@ static inline void serio_register_port(struct serio *serio) | |||
83 | } | 83 | } |
84 | 84 | ||
85 | void serio_unregister_port(struct serio *serio); | 85 | void serio_unregister_port(struct serio *serio); |
86 | void serio_unregister_child_port(struct serio *serio); | ||
86 | void __serio_unregister_port_delayed(struct serio *serio, struct module *owner); | 87 | void __serio_unregister_port_delayed(struct serio *serio, struct module *owner); |
87 | static inline void serio_unregister_port_delayed(struct serio *serio) | 88 | static inline void serio_unregister_port_delayed(struct serio *serio) |
88 | { | 89 | { |
@@ -153,6 +154,11 @@ static inline int serio_pin_driver(struct serio *serio) | |||
153 | return down_interruptible(&serio->drv_sem); | 154 | return down_interruptible(&serio->drv_sem); |
154 | } | 155 | } |
155 | 156 | ||
157 | static inline void serio_pin_driver_uninterruptible(struct serio *serio) | ||
158 | { | ||
159 | down(&serio->drv_sem); | ||
160 | } | ||
161 | |||
156 | static inline void serio_unpin_driver(struct serio *serio) | 162 | static inline void serio_unpin_driver(struct serio *serio) |
157 | { | 163 | { |
158 | up(&serio->drv_sem); | 164 | up(&serio->drv_sem); |