diff options
Diffstat (limited to 'drivers/input/mouse')
-rw-r--r-- | drivers/input/mouse/Kconfig | 2 | ||||
-rw-r--r-- | drivers/input/mouse/alps.c | 1 | ||||
-rw-r--r-- | drivers/input/mouse/appletouch.c | 12 | ||||
-rw-r--r-- | drivers/input/mouse/bcm5974.c | 24 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.c | 183 | ||||
-rw-r--r-- | drivers/input/mouse/elantech.h | 5 | ||||
-rw-r--r-- | drivers/input/mouse/hgpk.c | 4 | ||||
-rw-r--r-- | drivers/input/mouse/logips2pp.c | 98 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse-base.c | 104 | ||||
-rw-r--r-- | drivers/input/mouse/psmouse.h | 1 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.c | 88 | ||||
-rw-r--r-- | drivers/input/mouse/synaptics.h | 10 |
12 files changed, 321 insertions, 211 deletions
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index c714ca2407f8..eeb58c1cac16 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -17,7 +17,7 @@ config MOUSE_PS2 default y select SERIO select SERIO_LIBPS2 - select SERIO_I8042 if X86 + select SERIO_I8042 if X86 && !X86_MRST select SERIO_GSCPS2 if GSC help Say Y here if you have a PS/2 mouse connected to your system. This diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index 0d22cb9ce42e..99d58764ef03 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -64,7 +64,6 @@ static const struct alps_model_info alps_model_data[] = { { { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */ - { { 0x73, 0x02, 0x64 }, 0xf8, 0xf8, 0 }, /* HP Pavilion dm3 */ { { 0x52, 0x01, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */ }; diff --git a/drivers/input/mouse/appletouch.c b/drivers/input/mouse/appletouch.c index 53ec7ddd1826..05edd75abca0 100644 --- a/drivers/input/mouse/appletouch.c +++ b/drivers/input/mouse/appletouch.c @@ -806,8 +806,8 @@ static int atp_probe(struct usb_interface *iface, if (!dev->urb) goto err_free_devs; - dev->data = usb_buffer_alloc(dev->udev, dev->info->datalen, GFP_KERNEL, - &dev->urb->transfer_dma); + dev->data = usb_alloc_coherent(dev->udev, dev->info->datalen, GFP_KERNEL, + &dev->urb->transfer_dma); if (!dev->data) goto err_free_urb; @@ -862,8 +862,8 @@ static int atp_probe(struct usb_interface *iface, return 0; err_free_buffer: - usb_buffer_free(dev->udev, dev->info->datalen, - dev->data, dev->urb->transfer_dma); + usb_free_coherent(dev->udev, dev->info->datalen, + dev->data, dev->urb->transfer_dma); err_free_urb: usb_free_urb(dev->urb); err_free_devs: @@ -881,8 +881,8 @@ static void atp_disconnect(struct usb_interface *iface) if (dev) { usb_kill_urb(dev->urb); input_unregister_device(dev->input); - usb_buffer_free(dev->udev, dev->info->datalen, - dev->data, dev->urb->transfer_dma); + usb_free_coherent(dev->udev, dev->info->datalen, + dev->data, dev->urb->transfer_dma); usb_free_urb(dev->urb); kfree(dev); } diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index b89879bd860f..6dedded27222 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -715,15 +715,15 @@ static int bcm5974_probe(struct usb_interface *iface, if (!dev->tp_urb) goto err_free_bt_urb; - dev->bt_data = usb_buffer_alloc(dev->udev, - dev->cfg.bt_datalen, GFP_KERNEL, - &dev->bt_urb->transfer_dma); + dev->bt_data = usb_alloc_coherent(dev->udev, + dev->cfg.bt_datalen, GFP_KERNEL, + &dev->bt_urb->transfer_dma); if (!dev->bt_data) goto err_free_urb; - dev->tp_data = usb_buffer_alloc(dev->udev, - dev->cfg.tp_datalen, GFP_KERNEL, - &dev->tp_urb->transfer_dma); + dev->tp_data = usb_alloc_coherent(dev->udev, + dev->cfg.tp_datalen, GFP_KERNEL, + &dev->tp_urb->transfer_dma); if (!dev->tp_data) goto err_free_bt_buffer; @@ -765,10 +765,10 @@ static int bcm5974_probe(struct usb_interface *iface, return 0; err_free_buffer: - usb_buffer_free(dev->udev, dev->cfg.tp_datalen, + usb_free_coherent(dev->udev, dev->cfg.tp_datalen, dev->tp_data, dev->tp_urb->transfer_dma); err_free_bt_buffer: - usb_buffer_free(dev->udev, dev->cfg.bt_datalen, + usb_free_coherent(dev->udev, dev->cfg.bt_datalen, dev->bt_data, dev->bt_urb->transfer_dma); err_free_urb: usb_free_urb(dev->tp_urb); @@ -788,10 +788,10 @@ static void bcm5974_disconnect(struct usb_interface *iface) usb_set_intfdata(iface, NULL); input_unregister_device(dev->input); - usb_buffer_free(dev->udev, dev->cfg.tp_datalen, - dev->tp_data, dev->tp_urb->transfer_dma); - usb_buffer_free(dev->udev, dev->cfg.bt_datalen, - dev->bt_data, dev->bt_urb->transfer_dma); + usb_free_coherent(dev->udev, dev->cfg.tp_datalen, + dev->tp_data, dev->tp_urb->transfer_dma); + usb_free_coherent(dev->udev, dev->cfg.bt_datalen, + dev->bt_data, dev->bt_urb->transfer_dma); usb_free_urb(dev->tp_urb); usb_free_urb(dev->bt_urb); kfree(dev); diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c index a138b5da79f9..b18862b2a70e 100644 --- a/drivers/input/mouse/elantech.c +++ b/drivers/input/mouse/elantech.c @@ -10,6 +10,8 @@ * Trademarks are the property of their respective owners. */ +#define pr_fmt(fmt) KBUILD_BASENAME ": " fmt + #include <linux/delay.h> #include <linux/slab.h> #include <linux/module.h> @@ -19,12 +21,16 @@ #include "psmouse.h" #include "elantech.h" -#define elantech_debug(format, arg...) \ - do { \ - if (etd->debug) \ - printk(KERN_DEBUG format, ##arg); \ +#define elantech_debug(fmt, ...) \ + do { \ + if (etd->debug) \ + printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \ } while (0) +static bool force_elantech; +module_param_named(force_elantech, force_elantech, bool, 0644); +MODULE_PARM_DESC(force_elantech, "Force the Elantech PS/2 protocol extension to be used, 1 = enabled, 0 = disabled (default)."); + /* * Send a Synaptics style sliced query command */ @@ -33,7 +39,7 @@ static int synaptics_send_cmd(struct psmouse *psmouse, unsigned char c, { if (psmouse_sliced_command(psmouse, c) || ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_err("elantech.c: synaptics_send_cmd query 0x%02x failed.\n", c); + pr_err("synaptics_send_cmd query 0x%02x failed.\n", c); return -1; } @@ -56,13 +62,13 @@ static int elantech_ps2_command(struct psmouse *psmouse, if (rc == 0) break; tries--; - elantech_debug("elantech.c: retrying ps2 command 0x%02x (%d).\n", - command, tries); + elantech_debug("retrying ps2 command 0x%02x (%d).\n", + command, tries); msleep(ETP_PS2_COMMAND_DELAY); } while (tries > 0); if (rc) - pr_err("elantech.c: ps2 command 0x%02x failed.\n", command); + pr_err("ps2 command 0x%02x failed.\n", command); return rc; } @@ -104,7 +110,7 @@ static int elantech_read_reg(struct psmouse *psmouse, unsigned char reg, } if (rc) - pr_err("elantech.c: failed to read register 0x%02x.\n", reg); + pr_err("failed to read register 0x%02x.\n", reg); else *val = param[0]; @@ -150,7 +156,7 @@ static int elantech_write_reg(struct psmouse *psmouse, unsigned char reg, } if (rc) - pr_err("elantech.c: failed to write register 0x%02x with value 0x%02x.\n", + pr_err("failed to write register 0x%02x with value 0x%02x.\n", reg, val); return rc; @@ -163,7 +169,7 @@ static void elantech_packet_dump(unsigned char *packet, int size) { int i; - printk(KERN_DEBUG "elantech.c: PS/2 packet ["); + printk(KERN_DEBUG pr_fmt("PS/2 packet [")); for (i = 0; i < size; i++) printk("%s0x%02x ", (i) ? ", " : " ", packet[i]); printk("]\n"); @@ -181,34 +187,40 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) int fingers; static int old_fingers; - if (etd->fw_version_maj == 0x01) { - /* byte 0: D U p1 p2 1 p3 R L - byte 1: f 0 th tw x9 x8 y9 y8 */ + if (etd->fw_version < 0x020000) { + /* + * byte 0: D U p1 p2 1 p3 R L + * byte 1: f 0 th tw x9 x8 y9 y8 + */ fingers = ((packet[1] & 0x80) >> 7) + ((packet[1] & 0x30) >> 4); } else { - /* byte 0: n1 n0 p2 p1 1 p3 R L - byte 1: 0 0 0 0 x9 x8 y9 y8 */ + /* + * byte 0: n1 n0 p2 p1 1 p3 R L + * byte 1: 0 0 0 0 x9 x8 y9 y8 + */ fingers = (packet[0] & 0xc0) >> 6; } if (etd->jumpy_cursor) { /* Discard packets that are likely to have bogus coordinates */ if (fingers > old_fingers) { - elantech_debug("elantech.c: discarding packet\n"); + elantech_debug("discarding packet\n"); goto discard_packet_v1; } } input_report_key(dev, BTN_TOUCH, fingers != 0); - /* byte 2: x7 x6 x5 x4 x3 x2 x1 x0 - byte 3: y7 y6 y5 y4 y3 y2 y1 y0 */ + /* + * byte 2: x7 x6 x5 x4 x3 x2 x1 x0 + * byte 3: y7 y6 y5 y4 y3 y2 y1 y0 + */ if (fingers) { input_report_abs(dev, ABS_X, ((packet[1] & 0x0c) << 6) | packet[2]); - input_report_abs(dev, ABS_Y, ETP_YMAX_V1 - - (((packet[1] & 0x03) << 8) | packet[3])); + input_report_abs(dev, ABS_Y, + ETP_YMAX_V1 - (((packet[1] & 0x03) << 8) | packet[3])); } input_report_key(dev, BTN_TOOL_FINGER, fingers == 1); @@ -217,7 +229,7 @@ static void elantech_report_absolute_v1(struct psmouse *psmouse) input_report_key(dev, BTN_LEFT, packet[0] & 0x01); input_report_key(dev, BTN_RIGHT, packet[0] & 0x02); - if ((etd->fw_version_maj == 0x01) && + if (etd->fw_version < 0x020000 && (etd->capabilities & ETP_CAP_HAS_ROCKER)) { /* rocker up */ input_report_key(dev, BTN_FORWARD, packet[0] & 0x40); @@ -247,34 +259,47 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) switch (fingers) { case 1: - /* byte 1: x15 x14 x13 x12 x11 x10 x9 x8 - byte 2: x7 x6 x5 x4 x4 x2 x1 x0 */ - input_report_abs(dev, ABS_X, (packet[1] << 8) | packet[2]); - /* byte 4: y15 y14 y13 y12 y11 y10 y8 y8 - byte 5: y7 y6 y5 y4 y3 y2 y1 y0 */ - input_report_abs(dev, ABS_Y, ETP_YMAX_V2 - - ((packet[4] << 8) | packet[5])); + /* + * byte 1: . . . . . x10 x9 x8 + * byte 2: x7 x6 x5 x4 x4 x2 x1 x0 + */ + input_report_abs(dev, ABS_X, + ((packet[1] & 0x07) << 8) | packet[2]); + /* + * byte 4: . . . . . . y9 y8 + * byte 5: y7 y6 y5 y4 y3 y2 y1 y0 + */ + input_report_abs(dev, ABS_Y, + ETP_YMAX_V2 - (((packet[4] & 0x03) << 8) | packet[5])); break; case 2: - /* The coordinate of each finger is reported separately with - a lower resolution for two finger touches */ - /* byte 0: . . ay8 ax8 . . . . - byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 */ + /* + * The coordinate of each finger is reported separately + * with a lower resolution for two finger touches: + * byte 0: . . ay8 ax8 . . . . + * byte 1: ax7 ax6 ax5 ax4 ax3 ax2 ax1 ax0 + */ x1 = ((packet[0] & 0x10) << 4) | packet[1]; /* byte 2: ay7 ay6 ay5 ay4 ay3 ay2 ay1 ay0 */ y1 = ETP_2FT_YMAX - (((packet[0] & 0x20) << 3) | packet[2]); - /* byte 3: . . by8 bx8 . . . . - byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 */ + /* + * byte 3: . . by8 bx8 . . . . + * byte 4: bx7 bx6 bx5 bx4 bx3 bx2 bx1 bx0 + */ x2 = ((packet[3] & 0x10) << 4) | packet[4]; /* byte 5: by7 by8 by5 by4 by3 by2 by1 by0 */ y2 = ETP_2FT_YMAX - (((packet[3] & 0x20) << 3) | packet[5]); - /* For compatibility with the X Synaptics driver scale up one - coordinate and report as ordinary mouse movent */ + /* + * For compatibility with the X Synaptics driver scale up + * one coordinate and report as ordinary mouse movent + */ input_report_abs(dev, ABS_X, x1 << 2); input_report_abs(dev, ABS_Y, y1 << 2); - /* For compatibility with the proprietary X Elantech driver - report both coordinates as hat coordinates */ + /* + * For compatibility with the proprietary X Elantech driver + * report both coordinates as hat coordinates + */ input_report_abs(dev, ABS_HAT0X, x1); input_report_abs(dev, ABS_HAT0Y, y1); input_report_abs(dev, ABS_HAT1X, x2); @@ -298,7 +323,7 @@ static int elantech_check_parity_v1(struct psmouse *psmouse) unsigned char p1, p2, p3; /* Parity bits are placed differently */ - if (etd->fw_version_maj == 0x01) { + if (etd->fw_version < 0x020000) { /* byte 0: D U p1 p2 1 p3 R L */ p1 = (packet[0] & 0x20) >> 5; p2 = (packet[0] & 0x10) >> 4; @@ -390,23 +415,21 @@ static int elantech_set_absolute_mode(struct psmouse *psmouse) if (rc == 0) break; tries--; - elantech_debug("elantech.c: retrying read (%d).\n", - tries); + elantech_debug("retrying read (%d).\n", tries); msleep(ETP_READ_BACK_DELAY); } while (tries > 0); if (rc) { - pr_err("elantech.c: failed to read back register 0x10.\n"); + pr_err("failed to read back register 0x10.\n"); } else if (etd->hw_version == 1 && !(val & ETP_R10_ABSOLUTE_MODE)) { - pr_err("elantech.c: touchpad refuses " - "to switch to absolute mode.\n"); + pr_err("touchpad refuses to switch to absolute mode.\n"); rc = -1; } } if (rc) - pr_err("elantech.c: failed to initialise registers.\n"); + pr_err("failed to initialise registers.\n"); return rc; } @@ -434,7 +457,7 @@ static void elantech_set_input_params(struct psmouse *psmouse) switch (etd->hw_version) { case 1: /* Rocker button */ - if ((etd->fw_version_maj == 0x01) && + if (etd->fw_version < 0x020000 && (etd->capabilities & ETP_CAP_HAS_ROCKER)) { __set_bit(BTN_FORWARD, dev->keybit); __set_bit(BTN_BACK, dev->keybit); @@ -552,6 +575,24 @@ static struct attribute_group elantech_attr_group = { .attrs = elantech_attrs, }; +static bool elantech_is_signature_valid(const unsigned char *param) +{ + static const unsigned char rates[] = { 200, 100, 80, 60, 40, 20, 10 }; + int i; + + if (param[0] == 0) + return false; + + if (param[1] == 0) + return true; + + for (i = 0; i < ARRAY_SIZE(rates); i++) + if (param[2] == rates[i]) + return false; + + return true; +} + /* * Use magic knock to detect Elantech touchpad */ @@ -567,7 +608,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) || ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) { - pr_debug("elantech.c: sending Elantech magic knock failed.\n"); + pr_debug("sending Elantech magic knock failed.\n"); return -1; } @@ -576,8 +617,7 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * set of magic numbers */ if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) { - pr_debug("elantech.c: " - "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", + pr_debug("unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); return -1; } @@ -588,16 +628,20 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) * to Elantech magic knock and there might be more. */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_debug("elantech.c: failed to query firmware version.\n"); + pr_debug("failed to query firmware version.\n"); return -1; } - pr_debug("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", + pr_debug("Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); - if (param[0] == 0 || param[1] != 0) { - pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n"); - return -1; + if (!elantech_is_signature_valid(param)) { + if (!force_elantech) { + pr_debug("Probably not a real Elantech touchpad. Aborting.\n"); + return -1; + } + + pr_debug("Probably not a real Elantech touchpad. Enabling anyway due to force_elantech.\n"); } if (set_properties) { @@ -628,7 +672,7 @@ static int elantech_reconnect(struct psmouse *psmouse) return -1; if (elantech_set_absolute_mode(psmouse)) { - pr_err("elantech.c: failed to put touchpad back into absolute mode.\n"); + pr_err("failed to put touchpad back into absolute mode.\n"); return -1; } @@ -656,17 +700,17 @@ int elantech_init(struct psmouse *psmouse) * Do the version query again so we can store the result */ if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) { - pr_err("elantech.c: failed to query firmware version.\n"); + pr_err("failed to query firmware version.\n"); goto init_fail; } - etd->fw_version_maj = param[0]; - etd->fw_version_min = param[2]; + + etd->fw_version = (param[0] << 16) | (param[1] << 8) | param[2]; /* * Assume every version greater than this is new EeePC style * hardware with 6 byte packets */ - if (etd->fw_version_maj >= 0x02 && etd->fw_version_min >= 0x30) { + if (etd->fw_version >= 0x020030) { etd->hw_version = 2; /* For now show extra debug information */ etd->debug = 1; @@ -676,14 +720,15 @@ int elantech_init(struct psmouse *psmouse) etd->hw_version = 1; etd->paritycheck = 1; } - pr_info("elantech.c: assuming hardware version %d, firmware version %d.%d\n", - etd->hw_version, etd->fw_version_maj, etd->fw_version_min); + + pr_info("assuming hardware version %d, firmware version %d.%d.%d\n", + etd->hw_version, param[0], param[1], param[2]); if (synaptics_send_cmd(psmouse, ETP_CAPABILITIES_QUERY, param)) { - pr_err("elantech.c: failed to query capabilities.\n"); + pr_err("failed to query capabilities.\n"); goto init_fail; } - pr_info("elantech.c: Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", + pr_info("Synaptics capabilities query result 0x%02x, 0x%02x, 0x%02x.\n", param[0], param[1], param[2]); etd->capabilities = param[0]; @@ -692,14 +737,13 @@ int elantech_init(struct psmouse *psmouse) * a touch action starts causing the mouse cursor or scrolled page * to jump. Enable a workaround. */ - if (etd->fw_version_maj == 0x02 && etd->fw_version_min == 0x22) { - pr_info("elantech.c: firmware version 2.34 detected, " - "enabling jumpy cursor workaround\n"); + if (etd->fw_version == 0x020022) { + pr_info("firmware version 2.0.34 detected, enabling jumpy cursor workaround\n"); etd->jumpy_cursor = 1; } if (elantech_set_absolute_mode(psmouse)) { - pr_err("elantech.c: failed to put touchpad into absolute mode.\n"); + pr_err("failed to put touchpad into absolute mode.\n"); goto init_fail; } @@ -708,8 +752,7 @@ int elantech_init(struct psmouse *psmouse) error = sysfs_create_group(&psmouse->ps2dev.serio->dev.kobj, &elantech_attr_group); if (error) { - pr_err("elantech.c: failed to create sysfs attributes, error: %d.\n", - error); + pr_err("failed to create sysfs attributes, error: %d.\n", error); goto init_fail; } diff --git a/drivers/input/mouse/elantech.h b/drivers/input/mouse/elantech.h index feac5f7af966..ac57bde1bb9f 100644 --- a/drivers/input/mouse/elantech.h +++ b/drivers/input/mouse/elantech.h @@ -100,11 +100,10 @@ struct elantech_data { unsigned char reg_26; unsigned char debug; unsigned char capabilities; - unsigned char fw_version_maj; - unsigned char fw_version_min; - unsigned char hw_version; unsigned char paritycheck; unsigned char jumpy_cursor; + unsigned char hw_version; + unsigned int fw_version; unsigned char parity[256]; }; diff --git a/drivers/input/mouse/hgpk.c b/drivers/input/mouse/hgpk.c index 08d66d820d2b..1d2205b24800 100644 --- a/drivers/input/mouse/hgpk.c +++ b/drivers/input/mouse/hgpk.c @@ -40,8 +40,8 @@ #include "psmouse.h" #include "hgpk.h" -static int tpdebug; -module_param(tpdebug, int, 0644); +static bool tpdebug; +module_param(tpdebug, bool, 0644); MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG."); static int recalib_delta = 100; diff --git a/drivers/input/mouse/logips2pp.c b/drivers/input/mouse/logips2pp.c index 543c240a85f2..c9983aee9082 100644 --- a/drivers/input/mouse/logips2pp.c +++ b/drivers/input/mouse/logips2pp.c @@ -56,36 +56,36 @@ static psmouse_ret_t ps2pp_process_byte(struct psmouse *psmouse) /* Logitech extended packet */ switch ((packet[1] >> 4) | (packet[0] & 0x30)) { - case 0x0d: /* Mouse extra info */ + case 0x0d: /* Mouse extra info */ - input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, - (int) (packet[2] & 8) - (int) (packet[2] & 7)); - input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); + input_report_rel(dev, packet[2] & 0x80 ? REL_HWHEEL : REL_WHEEL, + (int) (packet[2] & 8) - (int) (packet[2] & 7)); + input_report_key(dev, BTN_SIDE, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 5) & 1); - break; + break; - case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ + case 0x0e: /* buttons 4, 5, 6, 7, 8, 9, 10 info */ - input_report_key(dev, BTN_SIDE, (packet[2]) & 1); - input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); - input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); - input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); - input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); + input_report_key(dev, BTN_SIDE, (packet[2]) & 1); + input_report_key(dev, BTN_EXTRA, (packet[2] >> 1) & 1); + input_report_key(dev, BTN_BACK, (packet[2] >> 3) & 1); + input_report_key(dev, BTN_FORWARD, (packet[2] >> 4) & 1); + input_report_key(dev, BTN_TASK, (packet[2] >> 2) & 1); - break; + break; - case 0x0f: /* TouchPad extra info */ + case 0x0f: /* TouchPad extra info */ - input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, - (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); - packet[0] = packet[2] | 0x08; - break; + input_report_rel(dev, packet[2] & 0x08 ? REL_HWHEEL : REL_WHEEL, + (int) ((packet[2] >> 4) & 8) - (int) ((packet[2] >> 4) & 7)); + packet[0] = packet[2] | 0x08; + break; #ifdef DEBUG - default: - printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", - (packet[1] >> 4) | (packet[0] & 0x30)); + default: + printk(KERN_WARNING "psmouse.c: Received PS2++ packet #%x, but don't know how to handle.\n", + (packet[1] >> 4) | (packet[0] & 0x30)); #endif } } else { @@ -250,7 +250,6 @@ static const struct ps2pp_info *get_model_info(unsigned char model) if (model == ps2pp_list[i].model) return &ps2pp_list[i]; - printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); return NULL; } @@ -285,31 +284,32 @@ static void ps2pp_set_model_properties(struct psmouse *psmouse, __set_bit(REL_HWHEEL, input_dev->relbit); switch (model_info->kind) { - case PS2PP_KIND_WHEEL: - psmouse->name = "Wheel Mouse"; - break; - - case PS2PP_KIND_MX: - psmouse->name = "MX Mouse"; - break; - case PS2PP_KIND_TP3: - psmouse->name = "TouchPad 3"; - break; - - case PS2PP_KIND_TRACKMAN: - psmouse->name = "TrackMan"; - break; - - default: - /* - * Set name to "Mouse" only when using PS2++, - * otherwise let other protocols define suitable - * name - */ - if (using_ps2pp) - psmouse->name = "Mouse"; - break; + case PS2PP_KIND_WHEEL: + psmouse->name = "Wheel Mouse"; + break; + + case PS2PP_KIND_MX: + psmouse->name = "MX Mouse"; + break; + + case PS2PP_KIND_TP3: + psmouse->name = "TouchPad 3"; + break; + + case PS2PP_KIND_TRACKMAN: + psmouse->name = "TrackMan"; + break; + + default: + /* + * Set name to "Mouse" only when using PS2++, + * otherwise let other protocols define suitable + * name + */ + if (using_ps2pp) + psmouse->name = "Mouse"; + break; } } @@ -343,7 +343,8 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) if (!model || !buttons) return -1; - if ((model_info = get_model_info(model)) != NULL) { + model_info = get_model_info(model); + if (model_info) { /* * Do Logitech PS2++ / PS2T++ magic init. @@ -379,6 +380,9 @@ int ps2pp_init(struct psmouse *psmouse, bool set_properties) use_ps2pp = true; } } + + } else { + printk(KERN_WARNING "logips2pp: Detected unknown logitech mouse model %d\n", model); } if (set_properties) { diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index d8c0c8d6992c..979c50215282 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -110,6 +110,7 @@ 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 (*detect)(struct psmouse *, bool); @@ -146,18 +147,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; } } @@ -246,31 +247,31 @@ 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_cnt == psmouse->resetafter) { - __psmouse_set_state(psmouse, PSMOUSE_IGNORE); - printk(KERN_NOTICE "psmouse.c: 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_cnt) { - psmouse->out_of_sync_cnt = 0; - printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", - psmouse->name, psmouse->phys); + 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_cnt == psmouse->resetafter) { + __psmouse_set_state(psmouse, PSMOUSE_IGNORE); + printk(KERN_NOTICE "psmouse.c: issuing reconnect request\n"); + serio_reconnect(psmouse->ps2dev.serio); + return -1; } - break; + } + psmouse->pktcnt = 0; + break; + + case PSMOUSE_FULL_PACKET: + psmouse->pktcnt = 0; + if (psmouse->out_of_sync_cnt) { + psmouse->out_of_sync_cnt = 0; + printk(KERN_NOTICE "psmouse.c: %s at %s - driver resynched.\n", + psmouse->name, psmouse->phys); + } + break; - case PSMOUSE_GOOD_DATA: - break; + case PSMOUSE_GOOD_DATA: + break; } return 0; } @@ -288,7 +289,9 @@ 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" : "", @@ -759,6 +762,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "PS/2", .alias = "bare", .maxproto = true, + .ignore_parity = true, .detect = ps2bare_detect, }, #ifdef CONFIG_MOUSE_PS2_LOGIPS2PP @@ -786,6 +790,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "ImPS/2", .alias = "imps", .maxproto = true, + .ignore_parity = true, .detect = intellimouse_detect, }, { @@ -793,6 +798,7 @@ static const struct psmouse_protocol psmouse_protocols[] = { .name = "ImExPS/2", .alias = "exps", .maxproto = true, + .ignore_parity = true, .detect = im_explorer_detect, }, #ifdef CONFIG_MOUSE_PS2_SYNAPTICS @@ -1222,6 +1228,7 @@ static void psmouse_disconnect(struct serio *serio) 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; @@ -1238,16 +1245,21 @@ static int psmouse_switch_protocol(struct psmouse *psmouse, psmouse->pktsize = 3; if (proto && (proto->detect || proto->init)) { - if (proto->detect && proto->detect(psmouse, 1) < 0) + if (proto->detect && proto->detect(psmouse, true) < 0) return -1; if (proto->init && proto->init(psmouse) < 0) return -1; psmouse->type = proto->type; - } else + selected_proto = proto; + } else { psmouse->type = psmouse_extensions(psmouse, psmouse_max_proto, true); + selected_proto = psmouse_protocol_by_type(psmouse->type); + } + + psmouse->ignore_parity = selected_proto->ignore_parity; /* * If mouse's packet size is 3 there is no point in polling the @@ -1267,7 +1279,7 @@ static int psmouse_switch_protocol(struct psmouse *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; @@ -1382,6 +1394,7 @@ 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) { @@ -1401,10 +1414,15 @@ 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, false)) { - 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, diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h index e053bdd137ff..593e910bfc7a 100644 --- a/drivers/input/mouse/psmouse.h +++ b/drivers/input/mouse/psmouse.h @@ -47,6 +47,7 @@ struct psmouse { unsigned char pktcnt; unsigned char pktsize; unsigned char type; + bool ignore_parity; bool acks_disable_command; unsigned int model; unsigned long last; diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 026df6010161..40cea334ad13 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -36,6 +36,8 @@ * The x/y limits are taken from the Synaptics TouchPad interfacing Guide, * section 2.3.2, which says that they should be valid regardless of the * actual size of the sensor. + * Note that newer firmware allows querying device for maximum useable + * coordinates. */ #define XMIN_NOMINAL 1472 #define XMAX_NOMINAL 5472 @@ -137,7 +139,8 @@ static int synaptics_capability(struct psmouse *psmouse) if (synaptics_send_cmd(psmouse, SYN_QUE_CAPABILITIES, cap)) return -1; priv->capabilities = (cap[0] << 16) | (cap[1] << 8) | cap[2]; - priv->ext_cap = 0; + priv->ext_cap = priv->ext_cap_0c = 0; + if (!SYN_CAP_VALID(priv->capabilities)) return -1; @@ -150,7 +153,7 @@ static int synaptics_capability(struct psmouse *psmouse) if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 1) { if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB, cap)) { printk(KERN_ERR "Synaptics claims to have extended capabilities," - " but I'm not able to read them."); + " but I'm not able to read them.\n"); } else { priv->ext_cap = (cap[0] << 16) | (cap[1] << 8) | cap[2]; @@ -162,6 +165,16 @@ static int synaptics_capability(struct psmouse *psmouse) priv->ext_cap &= 0xff0fff; } } + + if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 4) { + if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_CAPAB_0C, cap)) { + printk(KERN_ERR "Synaptics claims to have extended capability 0x0c," + " but I'm not able to read it.\n"); + } else { + priv->ext_cap_0c = (cap[0] << 16) | (cap[1] << 8) | cap[2]; + } + } + return 0; } @@ -183,23 +196,33 @@ static int synaptics_identify(struct psmouse *psmouse) } /* - * Read touchpad resolution + * Read touchpad resolution and maximum reported coordinates * Resolution is left zero if touchpad does not support the query */ static int synaptics_resolution(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; unsigned char res[3]; + unsigned char max[3]; if (SYN_ID_MAJOR(priv->identity) < 4) - return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res)) - return 0; + if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) { + if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) { + priv->x_res = res[0]; /* x resolution in units/mm */ + priv->y_res = res[2]; /* y resolution in units/mm */ + } + } - if ((res[0] != 0) && (res[1] & 0x80) && (res[2] != 0)) { - priv->x_res = res[0]; /* x resolution in units/mm */ - priv->y_res = res[2]; /* y resolution in units/mm */ + if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && + SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { + if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) { + printk(KERN_ERR "Synaptics claims to have dimensions query," + " but I'm not able to read it.\n"); + } else { + priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1); + priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3); + } } return 0; @@ -348,7 +371,15 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; - if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { + if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + /* + * Clickpad's button is transmitted as middle button, + * however, since it is primary button, we will report + * it as BTN_LEFT. + */ + hw->left = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; + + } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; if (hw->w == 2) hw->scroll = (signed char)(buf[1]); @@ -501,19 +532,20 @@ static int synaptics_validate_byte(unsigned char packet[], int idx, unsigned cha return 0; switch (pkt_type) { - case SYN_NEWABS: - case SYN_NEWABS_RELAXED: - return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; - case SYN_NEWABS_STRICT: - return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; + case SYN_NEWABS: + case SYN_NEWABS_RELAXED: + return (packet[idx] & newabs_rel_mask[idx]) == newabs_rslt[idx]; - case SYN_OLDABS: - return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; + case SYN_NEWABS_STRICT: + return (packet[idx] & newabs_mask[idx]) == newabs_rslt[idx]; - default: - printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); - return 0; + case SYN_OLDABS: + return (packet[idx] & oldabs_mask[idx]) == oldabs_rslt[idx]; + + default: + printk(KERN_ERR "synaptics: unknown packet type %d\n", pkt_type); + return 0; } } @@ -559,8 +591,10 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) int i; __set_bit(EV_ABS, dev->evbit); - input_set_abs_params(dev, ABS_X, XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); - input_set_abs_params(dev, ABS_Y, YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_X, + XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_Y, + YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); __set_bit(ABS_TOOL_WIDTH, dev->absbit); @@ -593,6 +627,12 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) dev->absres[ABS_X] = priv->x_res; dev->absres[ABS_Y] = priv->y_res; + + if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) { + /* Clickpads report only left button */ + __clear_bit(BTN_RIGHT, dev->keybit); + __clear_bit(BTN_MIDDLE, dev->keybit); + } } static void synaptics_disconnect(struct psmouse *psmouse) @@ -697,10 +737,10 @@ int synaptics_init(struct psmouse *psmouse) priv->pkt_type = SYN_MODEL_NEWABS(priv->model_id) ? SYN_NEWABS : SYN_OLDABS; - printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx\n", + printk(KERN_INFO "Synaptics Touchpad, model: %ld, fw: %ld.%ld, id: %#lx, caps: %#lx/%#lx/%#lx\n", SYN_ID_MODEL(priv->identity), SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity), - priv->model_id, priv->capabilities, priv->ext_cap); + priv->model_id, priv->capabilities, priv->ext_cap, priv->ext_cap_0c); set_input_params(psmouse->dev, priv); diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index f0f40a331dc8..7d4d5e12c0df 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -18,6 +18,8 @@ #define SYN_QUE_SERIAL_NUMBER_SUFFIX 0x07 #define SYN_QUE_RESOLUTION 0x08 #define SYN_QUE_EXT_CAPAB 0x09 +#define SYN_QUE_EXT_CAPAB_0C 0x0c +#define SYN_QUE_EXT_DIMENSIONS 0x0d /* synatics modes */ #define SYN_BIT_ABSOLUTE_MODE (1 << 7) @@ -48,6 +50,9 @@ #define SYN_CAP_VALID(c) ((((c) & 0x00ff00) >> 8) == 0x47) #define SYN_EXT_CAP_REQUESTS(c) (((c) & 0x700000) >> 20) #define SYN_CAP_MULTI_BUTTON_NO(ec) (((ec) & 0x00f000) >> 12) +#define SYN_CAP_PRODUCT_ID(ec) (((ec) & 0xff0000) >> 16) +#define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100100) +#define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) @@ -96,9 +101,10 @@ struct synaptics_data { unsigned long int model_id; /* Model-ID */ unsigned long int capabilities; /* Capabilities */ unsigned long int ext_cap; /* Extended Capabilities */ + unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ unsigned long int identity; /* Identification */ - int x_res; /* X resolution in units/mm */ - int y_res; /* Y resolution in units/mm */ + unsigned int x_res, y_res; /* X/Y resolution in units/mm */ + unsigned int x_max, y_max; /* Max dimensions (from FW) */ unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ |