diff options
Diffstat (limited to 'drivers/input/mouse/psmouse-base.c')
| -rw-r--r-- | drivers/input/mouse/psmouse-base.c | 731 |
1 files changed, 478 insertions, 253 deletions
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index f5a6be1d3c4..cff065f6261 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -11,6 +11,9 @@ * the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#define psmouse_fmt(fmt) fmt + #include <linux/delay.h> #include <linux/module.h> #include <linux/slab.h> @@ -25,9 +28,13 @@ #include "synaptics.h" #include "logips2pp.h" #include "alps.h" +#include "hgpk.h" #include "lifebook.h" #include "trackpoint.h" #include "touchkit_ps2.h" +#include "elantech.h" +#include "sentelic.h" +#include "cypress_ps2.h" #define DRIVER_DESC "PS/2 mouse driver" @@ -36,11 +43,13 @@ MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); static unsigned int psmouse_max_proto = PSMOUSE_AUTO; -static int psmouse_set_maxproto(const char *val, struct kernel_param *kp); -static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp); +static int psmouse_set_maxproto(const char *val, const struct kernel_param *); +static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp); +static struct kernel_param_ops param_ops_proto_abbrev = { + .set = psmouse_set_maxproto, + .get = psmouse_get_maxproto, +}; #define param_check_proto_abbrev(name, p) __param_check(name, p, unsigned int) -#define param_set_proto_abbrev psmouse_set_maxproto -#define param_get_proto_abbrev psmouse_get_maxproto module_param_named(proto, psmouse_max_proto, proto_abbrev, 0644); MODULE_PARM_DESC(proto, "Highest protocol extension to probe (bare, imps, exps, any). Useful for KVM switches."); @@ -52,7 +61,7 @@ static unsigned int psmouse_rate = 100; module_param_named(rate, psmouse_rate, uint, 0644); MODULE_PARM_DESC(rate, "Report rate, in reports per second."); -static unsigned int psmouse_smartscroll = 1; +static bool psmouse_smartscroll = 1; module_param_named(smartscroll, psmouse_smartscroll, bool, 0644); MODULE_PARM_DESC(smartscroll, "Logitech Smartscroll autorepeat, 1 = enabled (default), 0 = disabled."); @@ -106,10 +115,11 @@ static struct workqueue_struct *kpsmoused_wq; struct psmouse_protocol { enum psmouse_type type; + bool maxproto; + bool ignore_parity; /* Protocol should ignore parity errors from KBC */ const char *name; const char *alias; - int maxproto; - int (*detect)(struct psmouse *, int); + int (*detect)(struct psmouse *, bool); int (*init)(struct psmouse *); }; @@ -118,7 +128,7 @@ struct psmouse_protocol { * relevant events to the input module once full packet has arrived. */ -static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) +psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) { struct input_dev *dev = psmouse->dev; unsigned char *packet = psmouse->packet; @@ -143,18 +153,18 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) if (psmouse->type == PSMOUSE_IMEX) { switch (packet[3] & 0xC0) { - case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); - break; - case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ - input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); - break; - case 0x00: - case 0xC0: - input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); - input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); - break; + case 0x80: /* vertical scroll on IntelliMouse Explorer 4.0 */ + input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); + break; + case 0x40: /* horizontal scroll on IntelliMouse Explorer 4.0 */ + input_report_rel(dev, REL_HWHEEL, (int) (packet[3] & 32) - (int) (packet[3] & 31)); + break; + case 0x00: + case 0xC0: + input_report_rel(dev, REL_WHEEL, (int) (packet[3] & 8) - (int) (packet[3] & 7)); + input_report_key(dev, BTN_SIDE, (packet[3] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[3] >> 5) & 1); + break; } } @@ -201,6 +211,12 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) return PSMOUSE_FULL_PACKET; } +void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work, + unsigned long delay) +{ + queue_delayed_work(kpsmoused_wq, work, delay); +} + /* * __psmouse_set_state() sets new psmouse state and resets all flags. */ @@ -208,7 +224,7 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { psmouse->state = new_state; - psmouse->pktcnt = psmouse->out_of_sync = 0; + psmouse->pktcnt = psmouse->out_of_sync_cnt = 0; psmouse->ps2dev.flags = 0; psmouse->last = jiffies; } @@ -220,7 +236,7 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta * is not a concern. */ -static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) +void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state) { serio_pause_rx(psmouse->ps2dev.serio); __psmouse_set_state(psmouse, new_state); @@ -237,31 +253,35 @@ static int psmouse_handle_byte(struct psmouse *psmouse) psmouse_ret_t rc = psmouse->protocol_handler(psmouse); switch (rc) { - case PSMOUSE_BAD_DATA: - if (psmouse->state == PSMOUSE_ACTIVATED) { - printk(KERN_WARNING "psmouse.c: %s at %s lost sync at byte %d\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); - if (++psmouse->out_of_sync == psmouse->resetafter) { - __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); - serio_reconnect(psmouse->ps2dev.serio); - return -1; - } + case PSMOUSE_BAD_DATA: + if (psmouse->state == PSMOUSE_ACTIVATED) { + psmouse_warn(psmouse, + "%s at %s lost sync at byte %d\n", + psmouse->name, psmouse->phys, + psmouse->pktcnt); + if (++psmouse->out_of_sync_cnt == psmouse->resetafter) { + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); + psmouse_notice(psmouse, + "issuing reconnect request\n"); + serio_reconnect(psmouse->ps2dev.serio); + return -1; } - psmouse->pktcnt = 0; - break; - - case PSMOUSE_FULL_PACKET: - psmouse->pktcnt = 0; - if (psmouse->out_of_sync) { - psmouse->out_of_sync = 0; - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", + } + psmouse->pktcnt = 0; + break; + + case PSMOUSE_FULL_PACKET: + psmouse->pktcnt = 0; + if (psmouse->out_of_sync_cnt) { + psmouse->out_of_sync_cnt = 0; + psmouse_notice(psmouse, + "%s at %s - driver resynced.\n", psmouse->name, psmouse->phys); - } - break; + } + break; - case PSMOUSE_GOOD_DATA: - break; + case PSMOUSE_GOOD_DATA: + break; } return 0; } @@ -279,11 +299,14 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->state == PSMOUSE_IGNORE) goto out; - if (flags & (SERIO_PARITY|SERIO_TIMEOUT)) { + if (unlikely((flags & SERIO_TIMEOUT) || + ((flags & SERIO_PARITY) && !psmouse->ignore_parity))) { + if (psmouse->state == PSMOUSE_ACTIVATED) - printk(KERN_WARNING "psmouse.c: bad data from KBC -%s%s\n", - flags & SERIO_TIMEOUT ? " timeout" : "", - flags & SERIO_PARITY ? " bad parity" : ""); + psmouse_warn(psmouse, + "bad data from KBC -%s%s\n", + flags & SERIO_TIMEOUT ? " timeout" : "", + flags & SERIO_PARITY ? " bad parity" : ""); ps2_cmd_aborted(&psmouse->ps2dev); goto out; } @@ -301,11 +324,11 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, if (psmouse->state == PSMOUSE_ACTIVATED && psmouse->pktcnt && time_after(jiffies, psmouse->last + HZ/2)) { - printk(KERN_INFO "psmouse.c: %s at %s lost synchronization, throwing %d bytes away.\n", - psmouse->name, psmouse->phys, psmouse->pktcnt); + psmouse_info(psmouse, "%s at %s lost synchronization, throwing %d bytes away.\n", + psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - queue_work(kpsmoused_wq, &psmouse->resync_work); + psmouse_queue_work(psmouse, &psmouse->resync_work, 0); goto out; } @@ -319,7 +342,9 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, goto out; } - if (psmouse->packet[1] == PSMOUSE_RET_ID) { + if (psmouse->packet[1] == PSMOUSE_RET_ID || + (psmouse->type == PSMOUSE_HGPK && + psmouse->packet[1] == PSMOUSE_RET_BAT)) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); serio_reconnect(serio); goto out; @@ -342,7 +367,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { psmouse->badbyte = psmouse->packet[0]; __psmouse_set_state(psmouse, PSMOUSE_RESYNCING); - queue_work(kpsmoused_wq, &psmouse->resync_work); + psmouse_queue_work(psmouse, &psmouse->resync_work, 0); goto out; } @@ -394,11 +419,54 @@ int psmouse_reset(struct psmouse *psmouse) return 0; } +/* + * Here we set the mouse resolution. + */ + +void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) +{ + static const unsigned char params[] = { 0, 1, 2, 2, 3 }; + unsigned char p; + + if (resolution == 0 || resolution > 200) + resolution = 200; + + p = params[resolution / 50]; + ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); + psmouse->resolution = 25 << p; +} + +/* + * Here we set the mouse report rate. + */ + +static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) +{ + static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; + unsigned char r; + int i = 0; + + while (rates[i] > rate) i++; + r = rates[i]; + ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); + psmouse->rate = r; +} + +/* + * psmouse_poll() - default poll handler. Everyone except for ALPS uses it. + */ + +static int psmouse_poll(struct psmouse *psmouse) +{ + return ps2_command(&psmouse->ps2dev, psmouse->packet, + PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); +} + /* * Genius NetMouse magic init. */ -static int genius_detect(struct psmouse *psmouse, int set_properties) +static int genius_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[4]; @@ -414,9 +482,10 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev->keybit); - set_bit(BTN_SIDE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); psmouse->vendor = "Genius"; psmouse->name = "Mouse"; @@ -429,7 +498,7 @@ static int genius_detect(struct psmouse *psmouse, int set_properties) /* * IntelliMouse magic init. */ -static int intellimouse_detect(struct psmouse *psmouse, int set_properties) +static int intellimouse_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -446,11 +515,13 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Wheel Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Wheel Mouse"; psmouse->pktsize = 4; } @@ -460,7 +531,7 @@ static int intellimouse_detect(struct psmouse *psmouse, int set_properties) /* * Try IntelliMouse/Explorer magic init. */ -static int im_explorer_detect(struct psmouse *psmouse, int set_properties) +static int im_explorer_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -487,14 +558,16 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE); if (set_properties) { - set_bit(BTN_MIDDLE, psmouse->dev->keybit); - set_bit(REL_WHEEL, psmouse->dev->relbit); - set_bit(REL_HWHEEL, psmouse->dev->relbit); - set_bit(BTN_SIDE, psmouse->dev->keybit); - set_bit(BTN_EXTRA, psmouse->dev->keybit); - - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Explorer Mouse"; + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(REL_WHEEL, psmouse->dev->relbit); + __set_bit(REL_HWHEEL, psmouse->dev->relbit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); + + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Explorer Mouse"; psmouse->pktsize = 4; } @@ -504,7 +577,7 @@ static int im_explorer_detect(struct psmouse *psmouse, int set_properties) /* * Kensington ThinkingMouse / ExpertMouse magic init. */ -static int thinking_detect(struct psmouse *psmouse, int set_properties) +static int thinking_detect(struct psmouse *psmouse, bool set_properties) { struct ps2dev *ps2dev = &psmouse->ps2dev; unsigned char param[2]; @@ -525,7 +598,8 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) return -1; if (set_properties) { - set_bit(BTN_EXTRA, psmouse->dev->keybit); + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(BTN_EXTRA, psmouse->dev->keybit); psmouse->vendor = "Kensington"; psmouse->name = "ThinkingMouse"; @@ -537,11 +611,19 @@ static int thinking_detect(struct psmouse *psmouse, int set_properties) /* * Bare PS/2 protocol "detection". Always succeeds. */ -static int ps2bare_detect(struct psmouse *psmouse, int set_properties) +static int ps2bare_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { - if (!psmouse->vendor) psmouse->vendor = "Generic"; - if (!psmouse->name) psmouse->name = "Mouse"; + if (!psmouse->vendor) + psmouse->vendor = "Generic"; + if (!psmouse->name) + psmouse->name = "Mouse"; + +/* + * We have no way of figuring true number of buttons so let's + * assume that the device has 3. + */ + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); } return 0; @@ -551,32 +633,84 @@ static int ps2bare_detect(struct psmouse *psmouse, int set_properties) * Cortron PS/2 protocol detection. There's no special way to detect it, so it * must be forced by sysfs protocol writing. */ -static int cortron_detect(struct psmouse *psmouse, int set_properties) +static int cortron_detect(struct psmouse *psmouse, bool set_properties) { if (set_properties) { psmouse->vendor = "Cortron"; psmouse->name = "PS/2 Trackball"; - set_bit(BTN_SIDE, psmouse->dev->keybit); + + __set_bit(BTN_MIDDLE, psmouse->dev->keybit); + __set_bit(BTN_SIDE, psmouse->dev->keybit); } return 0; } /* + * Apply default settings to the psmouse structure. Most of them will + * be overridden by individual protocol initialization routines. + */ + +static void psmouse_apply_defaults(struct psmouse *psmouse) +{ + struct input_dev *input_dev = psmouse->dev; + + memset(input_dev->evbit, 0, sizeof(input_dev->evbit)); + memset(input_dev->keybit, 0, sizeof(input_dev->keybit)); + memset(input_dev->relbit, 0, sizeof(input_dev->relbit)); + memset(input_dev->absbit, 0, sizeof(input_dev->absbit)); + memset(input_dev->mscbit, 0, sizeof(input_dev->mscbit)); + + __set_bit(EV_KEY, input_dev->evbit); + __set_bit(EV_REL, input_dev->evbit); + + __set_bit(BTN_LEFT, input_dev->keybit); + __set_bit(BTN_RIGHT, input_dev->keybit); + + __set_bit(REL_X, input_dev->relbit); + __set_bit(REL_Y, input_dev->relbit); + + psmouse->set_rate = psmouse_set_rate; + psmouse->set_resolution = psmouse_set_resolution; + psmouse->poll = psmouse_poll; + psmouse->protocol_handler = psmouse_process_byte; + psmouse->pktsize = 3; + psmouse->reconnect = NULL; + psmouse->disconnect = NULL; + psmouse->cleanup = NULL; + psmouse->pt_activate = NULL; + psmouse->pt_deactivate = NULL; +} + +/* + * Apply default settings to the psmouse structure and call specified + * protocol detection or initialization routine. + */ +static int psmouse_do_detect(int (*detect)(struct psmouse *psmouse, + bool set_properties), + struct psmouse *psmouse, bool set_properties) +{ + if (set_properties) + psmouse_apply_defaults(psmouse); + + return detect(psmouse, set_properties); +} + +/* * psmouse_extensions() probes for any extensions to the basic PS/2 protocol * the mouse may have. */ static int psmouse_extensions(struct psmouse *psmouse, - unsigned int max_proto, int set_properties) + unsigned int max_proto, bool set_properties) { - int synaptics_hardware = 0; + bool synaptics_hardware = false; /* * We always check for lifebook because it does not disturb mouse * (it only checks DMI information). */ - if (lifebook_detect(psmouse, set_properties) == 0) { + if (psmouse_do_detect(lifebook_detect, psmouse, set_properties) == 0) { if (max_proto > PSMOUSE_IMEX) { if (!set_properties || lifebook_init(psmouse) == 0) return PSMOUSE_LIFEBOOK; @@ -588,20 +722,30 @@ static int psmouse_extensions(struct psmouse *psmouse, * upsets the thinkingmouse). */ - if (max_proto > PSMOUSE_IMEX && thinking_detect(psmouse, set_properties) == 0) + if (max_proto > PSMOUSE_IMEX && + psmouse_do_detect(thinking_detect, psmouse, set_properties) == 0) { return PSMOUSE_THINKPS; + } /* * Try Synaptics TouchPad. Note that probing is done even if Synaptics protocol * support is disabled in config - we need to know if it is synaptics so we * can reset it properly after probing for intellimouse. */ - if (max_proto > PSMOUSE_PS2 && synaptics_detect(psmouse, set_properties) == 0) { - synaptics_hardware = 1; + if (max_proto > PSMOUSE_PS2 && + psmouse_do_detect(synaptics_detect, psmouse, set_properties) == 0) { + synaptics_hardware = true; if (max_proto > PSMOUSE_IMEX) { - if (!set_properties || synaptics_init(psmouse) == 0) +/* + * Try activating protocol, but check if support is enabled first, since + * we try detecting Synaptics even when protocol is disabled. + */ + if (synaptics_supported() && + (!set_properties || synaptics_init(psmouse) == 0)) { return PSMOUSE_SYNAPTICS; + } + /* * Some Synaptics touchpads can emulate extended protocols (like IMPS/2). * Unfortunately Logitech/Genius probes confuse some firmware versions so @@ -616,11 +760,34 @@ static int psmouse_extensions(struct psmouse *psmouse, } /* + * Try Cypress Trackpad. + * Must try it before Finger Sensing Pad because Finger Sensing Pad probe + * upsets some modules of Cypress Trackpads. + */ + if (max_proto > PSMOUSE_IMEX && + cypress_detect(psmouse, set_properties) == 0) { + if (cypress_supported()) { + if (cypress_init(psmouse) == 0) + return PSMOUSE_CYPRESS; + + /* + * Finger Sensing Pad probe upsets some modules of + * Cypress Trackpad, must avoid Finger Sensing Pad + * probe if Cypress Trackpad device detected. + */ + return PSMOUSE_PS2; + } + + max_proto = PSMOUSE_IMEX; + } + +/* * Try ALPS TouchPad */ if (max_proto > PSMOUSE_IMEX) { ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); - if (alps_detect(psmouse, set_properties) == 0) { + if (psmouse_do_detect(alps_detect, + psmouse, set_properties) == 0) { if (!set_properties || alps_init(psmouse) == 0) return PSMOUSE_ALPS; /* @@ -630,22 +797,67 @@ static int psmouse_extensions(struct psmouse *psmouse, } } - if (max_proto > PSMOUSE_IMEX) { +/* + * Try OLPC HGPK touchpad. + */ + if (max_proto > PSMOUSE_IMEX && + psmouse_do_detect(hgpk_detect, psmouse, set_properties) == 0) { + if (!set_properties || hgpk_init(psmouse) == 0) + return PSMOUSE_HGPK; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } - if (genius_detect(psmouse, set_properties) == 0) +/* + * Try Elantech touchpad. + */ + if (max_proto > PSMOUSE_IMEX && + psmouse_do_detect(elantech_detect, psmouse, set_properties) == 0) { + if (!set_properties || elantech_init(psmouse) == 0) + return PSMOUSE_ELANTECH; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } + + if (max_proto > PSMOUSE_IMEX) { + if (psmouse_do_detect(genius_detect, + psmouse, set_properties) == 0) return PSMOUSE_GENPS; - if (ps2pp_init(psmouse, set_properties) == 0) + if (psmouse_do_detect(ps2pp_init, + psmouse, set_properties) == 0) return PSMOUSE_PS2PP; - if (trackpoint_detect(psmouse, set_properties) == 0) + if (psmouse_do_detect(trackpoint_detect, + psmouse, set_properties) == 0) return PSMOUSE_TRACKPOINT; - if (touchkit_ps2_detect(psmouse, set_properties) == 0) + if (psmouse_do_detect(touchkit_ps2_detect, + psmouse, set_properties) == 0) return PSMOUSE_TOUCHKIT_PS2; } /* + * Try Finger Sensing Pad. We do it here because its probe upsets + * Trackpoint devices (causing TP_READ_ID command to time out). + */ + if (max_proto > PSMOUSE_IMEX) { + if (psmouse_do_detect(fsp_detect, + psmouse, set_properties) == 0) { + if (!set_properties || fsp_init(psmouse) == 0) + return PSMOUSE_FSP; +/* + * Init failed, try basic relative protocols + */ + max_proto = PSMOUSE_IMEX; + } + } + +/* * Reset to defaults in case the device got confused by extended * protocol probes. Note that we follow up with full reset because * some mice put themselves to sleep when they see PSMOUSE_RESET_DIS. @@ -653,17 +865,23 @@ static int psmouse_extensions(struct psmouse *psmouse, ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); psmouse_reset(psmouse); - if (max_proto >= PSMOUSE_IMEX && im_explorer_detect(psmouse, set_properties) == 0) + if (max_proto >= PSMOUSE_IMEX && + psmouse_do_detect(im_explorer_detect, + psmouse, set_properties) == 0) { return PSMOUSE_IMEX; + } - if (max_proto >= PSMOUSE_IMPS && intellimouse_detect(psmouse, set_properties) == 0) + if (max_proto >= PSMOUSE_IMPS && + psmouse_do_detect(intellimouse_detect, + psmouse, set_properties) == 0) { return PSMOUSE_IMPS; + } /* * Okay, all failed, we have a standard mouse here. The number of the buttons * is still a question, though. We assume 3. */ - ps2bare_detect(psmouse, set_properties); + psmouse_do_detect(ps2bare_detect, psmouse, set_properties); if (synaptics_hardware) { /* @@ -683,7 +901,8 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_PS2, .name = "PS/2", .alias = "bare", - .maxproto = 1, + .maxproto = true, + .ignore_parity = true, .detect = ps2bare_detect, }, #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP @@ -700,6 +919,15 @@ static const struct psmouse_protocol psmouse_protocols[] = { .alias = "thinkps", .detect = thinking_detect, }, +#ifdef CONFIG_MOUSE_PS2_CYPRESS + { + .type = PSMOUSE_CYPRESS, + .name = "CyPS/2", + .alias = "cypress", + .detect = cypress_detect, + .init = cypress_init, + }, +#endif { .type = PSMOUSE_GENPS, .name = "GenPS/2", @@ -710,14 +938,16 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_IMPS, .name = "ImPS/2", .alias = "imps", - .maxproto = 1, + .maxproto = true, + .ignore_parity = true, .detect = intellimouse_detect, }, { .type = PSMOUSE_IMEX, .name = "ImExPS/2", .alias = "exps", - .maxproto = 1, + .maxproto = true, + .ignore_parity = true, .detect = im_explorer_detect, }, #ifdef CONFIG_MOUSE_PS2_SYNAPTICS @@ -728,6 +958,13 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = synaptics_detect, .init = synaptics_init, }, + { + .type = PSMOUSE_SYNAPTICS_RELATIVE, + .name = "SynRelPS/2", + .alias = "synaptics-relative", + .detect = synaptics_detect, + .init = synaptics_init_relative, + }, #endif #ifdef CONFIG_MOUSE_PS2_ALPS { @@ -762,6 +999,32 @@ static const struct psmouse_protocol psmouse_protocols[] = { .detect = touchkit_ps2_detect, }, #endif +#ifdef CONFIG_MOUSE_PS2_OLPC + { + .type = PSMOUSE_HGPK, + .name = "OLPC HGPK", + .alias = "hgpk", + .detect = hgpk_detect, + }, +#endif +#ifdef CONFIG_MOUSE_PS2_ELANTECH + { + .type = PSMOUSE_ELANTECH, + .name = "ETPS/2", + .alias = "elantech", + .detect = elantech_detect, + .init = elantech_init, + }, +#endif +#ifdef CONFIG_MOUSE_PS2_SENTELIC + { + .type = PSMOUSE_FSP, + .name = "FSPPS/2", + .alias = "fsp", + .detect = fsp_detect, + .init = fsp_init, + }, +#endif { .type = PSMOUSE_CORTRON, .name = "CortronPS/2", @@ -772,7 +1035,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .type = PSMOUSE_AUTO, .name = "auto", .alias = "any", - .maxproto = 1, + .maxproto = true, }, }; @@ -834,45 +1097,13 @@ static int psmouse_probe(struct psmouse *psmouse) */ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_DIS)) - printk(KERN_WARNING "psmouse.c: Failed to reset mouse on %s\n", ps2dev->serio->phys); + psmouse_warn(psmouse, "Failed to reset mouse on %s\n", + ps2dev->serio->phys); return 0; } /* - * Here we set the mouse resolution. - */ - -void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution) -{ - static const unsigned char params[] = { 0, 1, 2, 2, 3 }; - unsigned char p; - - if (resolution == 0 || resolution > 200) - resolution = 200; - - p = params[resolution / 50]; - ps2_command(&psmouse->ps2dev, &p, PSMOUSE_CMD_SETRES); - psmouse->resolution = 25 << p; -} - -/* - * Here we set the mouse report rate. - */ - -static void psmouse_set_rate(struct psmouse *psmouse, unsigned int rate) -{ - static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10, 0 }; - unsigned char r; - int i = 0; - - while (rates[i] > rate) i++; - r = rates[i]; - ps2_command(&psmouse->ps2dev, &r, PSMOUSE_CMD_SETRATE); - psmouse->rate = r; -} - -/* * psmouse_initialize() initializes the mouse to a sane state. */ @@ -893,38 +1124,33 @@ static void psmouse_initialize(struct psmouse *psmouse) * psmouse_activate() enables the mouse so that we get motion reports from it. */ -static void psmouse_activate(struct psmouse *psmouse) +int psmouse_activate(struct psmouse *psmouse) { - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) - printk(KERN_WARNING "psmouse.c: Failed to enable mouse on %s\n", - psmouse->ps2dev.serio->phys); + if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { + psmouse_warn(psmouse, "Failed to enable mouse on %s\n", + psmouse->ps2dev.serio->phys); + return -1; + } psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); + return 0; } - /* * psmouse_deactivate() puts the mouse into poll mode so that we don't get motion * reports from it unless we explicitly request it. */ -static void psmouse_deactivate(struct psmouse *psmouse) +int psmouse_deactivate(struct psmouse *psmouse) { - if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) - printk(KERN_WARNING "psmouse.c: Failed to deactivate mouse on %s\n", - psmouse->ps2dev.serio->phys); + if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) { + psmouse_warn(psmouse, "Failed to deactivate mouse on %s\n", + psmouse->ps2dev.serio->phys); + return -1; + } psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); -} - -/* - * psmouse_poll() - default poll hanlder. Everyone except for ALPS uses it. - */ - -static int psmouse_poll(struct psmouse *psmouse) -{ - return ps2_command(&psmouse->ps2dev, psmouse->packet, - PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)); + return 0; } @@ -935,10 +1161,10 @@ static int psmouse_poll(struct psmouse *psmouse) static void psmouse_resync(struct work_struct *work) { struct psmouse *parent = NULL, *psmouse = - container_of(work, struct psmouse, resync_work); + container_of(work, struct psmouse, resync_work.work); struct serio *serio = psmouse->ps2dev.serio; psmouse_ret_t rc = PSMOUSE_GOOD_DATA; - int failed = 0, enabled = 0; + bool failed = false, enabled = false; int i; mutex_lock(&psmouse_mutex); @@ -965,9 +1191,9 @@ static void psmouse_resync(struct work_struct *work) if (ps2_sendbyte(&psmouse->ps2dev, PSMOUSE_CMD_DISABLE, 20)) { if (psmouse->num_resyncs < 3 || psmouse->acks_disable_command) - failed = 1; + failed = true; } else - psmouse->acks_disable_command = 1; + psmouse->acks_disable_command = true; /* * Poll the mouse. If it was reset the packet will be shorter than @@ -978,7 +1204,7 @@ static void psmouse_resync(struct work_struct *work) */ if (!failed) { if (psmouse->poll(psmouse)) - failed = 1; + failed = true; else { psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); for (i = 0; i < psmouse->pktsize; i++) { @@ -988,7 +1214,7 @@ static void psmouse_resync(struct work_struct *work) break; } if (rc != PSMOUSE_FULL_PACKET) - failed = 1; + failed = true; psmouse_set_state(psmouse, PSMOUSE_RESYNCING); } } @@ -999,21 +1225,22 @@ static void psmouse_resync(struct work_struct *work) */ for (i = 0; i < 5; i++) { if (!ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE)) { - enabled = 1; + enabled = true; break; } msleep(200); } if (!enabled) { - printk(KERN_WARNING "psmouse.c: failed to re-enable mouse on %s\n", - psmouse->ps2dev.serio->phys); - failed = 1; + psmouse_warn(psmouse, "failed to re-enable mouse on %s\n", + psmouse->ps2dev.serio->phys); + failed = true; } if (failed) { psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_INFO "psmouse.c: resync failed, issuing reconnect request\n"); + psmouse_info(psmouse, + "resync failed, issuing reconnect request\n"); serio_reconnect(serio); } else psmouse_set_state(psmouse, PSMOUSE_ACTIVATED); @@ -1040,12 +1267,22 @@ static void psmouse_cleanup(struct serio *serio) psmouse_deactivate(parent); } - psmouse_deactivate(psmouse); + psmouse_set_state(psmouse, PSMOUSE_INITIALIZING); + + /* + * Disable stream mode so cleanup routine can proceed undisturbed. + */ + if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_DISABLE)) + psmouse_warn(psmouse, "Failed to disable mouse on %s\n", + psmouse->ps2dev.serio->phys); if (psmouse->cleanup) psmouse->cleanup(psmouse); - psmouse_reset(psmouse); +/* + * Reset the mouse to defaults (bare PS/2 protocol). + */ + ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS); /* * Some boxes, such as HP nx7400, get terribly confused if mouse @@ -1108,34 +1345,32 @@ static void psmouse_disconnect(struct serio *serio) mutex_unlock(&psmouse_mutex); } -static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse_protocol *proto) +static int psmouse_switch_protocol(struct psmouse *psmouse, + const struct psmouse_protocol *proto) { + const struct psmouse_protocol *selected_proto; struct input_dev *input_dev = psmouse->dev; input_dev->dev.parent = &psmouse->ps2dev.serio->dev; - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); - input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | - BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT); - input_dev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); - - psmouse->set_rate = psmouse_set_rate; - psmouse->set_resolution = psmouse_set_resolution; - psmouse->poll = psmouse_poll; - psmouse->protocol_handler = psmouse_process_byte; - psmouse->pktsize = 3; - if (proto && (proto->detect || proto->init)) { - if (proto->detect && proto->detect(psmouse, 1) < 0) + psmouse_apply_defaults(psmouse); + + if (proto->detect && proto->detect(psmouse, true) < 0) return -1; if (proto->init && proto->init(psmouse) < 0) return -1; psmouse->type = proto->type; + selected_proto = proto; + } else { + psmouse->type = psmouse_extensions(psmouse, + psmouse_max_proto, true); + selected_proto = psmouse_protocol_by_type(psmouse->type); } - else - psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, 1); + + psmouse->ignore_parity = selected_proto->ignore_parity; /* * If mouse's packet size is 3 there is no point in polling the @@ -1155,7 +1390,7 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, const struct psmouse psmouse->resync_time = 0; snprintf(psmouse->devname, sizeof(psmouse->devname), "%s %s %s", - psmouse_protocol_by_type(psmouse->type)->name, psmouse->vendor, psmouse->name); + selected_proto->name, psmouse->vendor, psmouse->name); input_dev->name = psmouse->devname; input_dev->phys = psmouse->phys; @@ -1194,7 +1429,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) goto err_free; ps2_init(&psmouse->ps2dev, serio); - INIT_WORK(&psmouse->resync_work, psmouse_resync); + INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync); psmouse->dev = input_dev; snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); @@ -1270,10 +1505,12 @@ static int psmouse_reconnect(struct serio *serio) struct psmouse *psmouse = serio_get_drvdata(serio); struct psmouse *parent = NULL; struct serio_driver *drv = serio->drv; + unsigned char type; int rc = -1; if (!drv || !psmouse) { - printk(KERN_DEBUG "psmouse: reconnect request, but serio is disconnected, ignoring...\n"); + psmouse_dbg(psmouse, + "reconnect request, but serio is disconnected, ignoring...\n"); return -1; } @@ -1289,12 +1526,20 @@ static int psmouse_reconnect(struct serio *serio) if (psmouse->reconnect) { if (psmouse->reconnect(psmouse)) goto out; - } else if (psmouse_probe(psmouse) < 0 || - psmouse->type != psmouse_extensions(psmouse, psmouse_max_proto, 0)) - goto out; + } else { + psmouse_reset(psmouse); + + if (psmouse_probe(psmouse) < 0) + goto out; + + type = psmouse_extensions(psmouse, psmouse_max_proto, false); + if (psmouse->type != type) + goto out; + } - /* ok, the device type (and capabilities) match the old one, - * we can continue using it, complete intialization + /* + * OK, the device type (and capabilities) match the old one, + * we can continue using it, complete initialization */ psmouse_set_state(psmouse, PSMOUSE_CMD_MODE); @@ -1352,24 +1597,10 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *de struct serio *serio = to_serio_port(dev); struct psmouse_attribute *attr = to_psmouse_attr(devattr); struct psmouse *psmouse; - int retval; - - retval = serio_pin_driver(serio); - if (retval) - return retval; - - if (serio->drv != &psmouse_drv) { - retval = -ENODEV; - goto out; - } psmouse = serio_get_drvdata(serio); - retval = attr->show(psmouse, attr->data, buf); - -out: - serio_unpin_driver(serio); - return retval; + return attr->show(psmouse, attr->data, buf); } ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *devattr, @@ -1380,45 +1611,39 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev struct psmouse *psmouse, *parent = NULL; int retval; - retval = serio_pin_driver(serio); - if (retval) - return retval; - - if (serio->drv != &psmouse_drv) { - retval = -ENODEV; - goto out_unpin; - } - retval = mutex_lock_interruptible(&psmouse_mutex); if (retval) - goto out_unpin; + goto out; psmouse = serio_get_drvdata(serio); - if (psmouse->state == PSMOUSE_IGNORE) { - retval = -ENODEV; - goto out_unlock; - } + if (attr->protect) { + if (psmouse->state == PSMOUSE_IGNORE) { + retval = -ENODEV; + goto out_unlock; + } - if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { - parent = serio_get_drvdata(serio->parent); - psmouse_deactivate(parent); - } + if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { + parent = serio_get_drvdata(serio->parent); + psmouse_deactivate(parent); + } - psmouse_deactivate(psmouse); + psmouse_deactivate(psmouse); + } retval = attr->set(psmouse, attr->data, buf, count); - if (retval != -ENODEV) - psmouse_activate(psmouse); + if (attr->protect) { + if (retval != -ENODEV) + psmouse_activate(psmouse); - if (parent) - psmouse_activate(parent); + if (parent) + psmouse_activate(parent); + } out_unlock: mutex_unlock(&psmouse_mutex); - out_unpin: - serio_unpin_driver(serio); + out: return retval; } @@ -1432,15 +1657,12 @@ static ssize_t psmouse_show_int_attr(struct psmouse *psmouse, void *offset, char static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const char *buf, size_t count) { unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset); - unsigned long value; - char *rest; - - value = simple_strtoul(buf, &rest, 10); - if (*rest) - return -EINVAL; + unsigned int value; + int err; - if ((unsigned int)value != value) - return -EINVAL; + err = kstrtouint(buf, 10, &value); + if (err) + return err; *field = value; @@ -1472,17 +1694,16 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co if (!new_dev) return -ENOMEM; - while (serio->child) { + while (!list_empty(&serio->children)) { if (++retry > 3) { - printk(KERN_WARNING "psmouse: failed to destroy child port, protocol change aborted.\n"); + psmouse_warn(psmouse, + "failed to destroy children ports, protocol change aborted.\n"); input_free_device(new_dev); return -EIO; } mutex_unlock(&psmouse_mutex); - serio_unpin_driver(serio); serio_unregister_child_port(serio); - serio_pin_driver_uninterruptible(serio); mutex_lock(&psmouse_mutex); if (serio->drv != &psmouse_drv) { @@ -1548,12 +1769,12 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count) { - unsigned long value; - char *rest; + unsigned int value; + int err; - value = simple_strtoul(buf, &rest, 10); - if (*rest) - return -EINVAL; + err = kstrtouint(buf, 10, &value); + if (err) + return err; psmouse->set_rate(psmouse, value); return count; @@ -1561,19 +1782,19 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count) { - unsigned long value; - char *rest; + unsigned int value; + int err; - value = simple_strtoul(buf, &rest, 10); - if (*rest) - return -EINVAL; + err = kstrtouint(buf, 10, &value); + if (err) + return err; psmouse->set_resolution(psmouse, value); return count; } -static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) +static int psmouse_set_maxproto(const char *val, const struct kernel_param *kp) { const struct psmouse_protocol *proto; @@ -1590,20 +1811,24 @@ static int psmouse_set_maxproto(const char *val, struct kernel_param *kp) return 0; } -static int psmouse_get_maxproto(char *buffer, struct kernel_param *kp) +static int psmouse_get_maxproto(char *buffer, const struct kernel_param *kp) { int type = *((unsigned int *)kp->arg); - return sprintf(buffer, "%s\n", psmouse_protocol_by_type(type)->name); + return sprintf(buffer, "%s", psmouse_protocol_by_type(type)->name); } static int __init psmouse_init(void) { int err; + lifebook_module_init(); + synaptics_module_init(); + hgpk_module_init(); + kpsmoused_wq = create_singlethread_workqueue("kpsmoused"); if (!kpsmoused_wq) { - printk(KERN_ERR "psmouse: failed to create kpsmoused workqueue\n"); + pr_err("failed to create kpsmoused workqueue\n"); return -ENOMEM; } |
