From patchwork Fri Oct 8 16:37:22 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Takashi Iwai X-Patchwork-Id: 241621 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id o98GbPGx023633 for ; Fri, 8 Oct 2010 16:37:25 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753429Ab0JHQhY (ORCPT ); Fri, 8 Oct 2010 12:37:24 -0400 Received: from cantor2.suse.de ([195.135.220.15]:54052 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753264Ab0JHQhY convert rfc822-to-8bit (ORCPT ); Fri, 8 Oct 2010 12:37:24 -0400 Received: from relay1.suse.de (charybdis-ext.suse.de [195.135.221.2]) by mx2.suse.de (Postfix) with ESMTP id 7B17786391; Fri, 8 Oct 2010 18:37:22 +0200 (CEST) Date: Fri, 08 Oct 2010 18:37:22 +0200 Message-ID: From: Takashi Iwai To: Chase Douglas Cc: linux-input@vger.kernel.org, xorg-devel@lists.x.org, Dmitry Torokhov , Chris Bagwell , Andy Whitcroft , Henrik Rydberg , linux-kernel@vger.kernel.org, Peter Hutterer , Duncan McGreggor Subject: Re: [PATCH 0/3] Input: synaptics - multitouch and multifinger support In-Reply-To: <1286549880-32580-1-git-send-email-chase.douglas@canonical.com> References: <1286549880-32580-1-git-send-email-chase.douglas@canonical.com> User-Agent: Wanderlust/2.15.6 (Almost Unreal) SEMI/1.14.6 (Maruoka) FLIM/1.14.9 (=?UTF-8?B?R29qxY0=?=) APEL/10.7 Emacs/23.1 (x86_64-suse-linux-gnu) MULE/6.0 (HANACHIRUSATO) MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Fri, 08 Oct 2010 16:37:25 +0000 (UTC) diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index 91d3517..6dd0d29 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -76,6 +76,17 @@ config MOUSE_PS2_SYNAPTICS_LED Say Y here if you have a Synaptics device with an embedded LED. This will enable LED class driver to control the LED device. +config MOUSE_PS2_SYNAPTICS_MULTI_TOUCH + bool "Support multi-touch protocol of Synaptics devices" + depends on MOUSE_PS2_SYNAPTICS + help + Say Y here for enabling the multi-touch protocol of recent + Syanptics devices. This may result in incompatible input + events, thus make sure that you update X11 synaptics driver + beforehand with the multi-protocol touch. + + If unsure, say N. + config MOUSE_PS2_LIFEBOOK bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED default y diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c index 00799bc..79d9463 100644 --- a/drivers/input/mouse/synaptics.c +++ b/drivers/input/mouse/synaptics.c @@ -181,6 +181,12 @@ static int synaptics_capability(struct psmouse *psmouse) } } +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_MULTI_TOUCH + /* FIXME: is this the right guess? */ + if (priv->ext_cap_0c & (0x08 << 16)) + priv->can_multi_touch = 1; +#endif + return 0; } @@ -458,6 +464,32 @@ static void synaptics_free_led(struct psmouse *psmouse) #define synaptics_sync_led(ps) do {} while (0) #endif +/* change to the multi-touch mode; + * this is done by sending SYN_QUE_MODEL cmd but setting a parameter + * by SETRATE instead of querying via GETINFO. + * 0xc8 seems to be the multi-touch mode. + */ +static int synaptics_init_multi_touch(struct psmouse *psmouse) +{ + unsigned char param[1]; + + if (psmouse_sliced_command(psmouse, SYN_QUE_MODEL)) + return -1; + param[0] = 0xc8; + if (ps2_command(&psmouse->ps2dev, param, PSMOUSE_CMD_SETRATE)) + return -1; + return 0; +} + +#ifdef CONFIG_MOUSE_PS2_SYNAPTICS_MULTI_TOUCH +#define is_multi_touch(priv) (priv)->can_multi_touch +#else +#define is_multi_touch(priv) 0 +#endif +/* the multi-touch packet contains w=2 (like pen) */ +#define is_multi_touch_packet(priv, hw) \ + (is_multi_touch(priv) && (hw)->w == 2) + /***************************************************************************** * Functions to interpret the absolute mode packets ****************************************************************************/ @@ -467,17 +499,27 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data memset(hw, 0, sizeof(struct synaptics_hw_state)); if (SYN_MODEL_NEWABS(priv->model_id)) { - hw->x = (((buf[3] & 0x10) << 8) | - ((buf[1] & 0x0f) << 8) | - buf[4]); - hw->y = (((buf[3] & 0x20) << 7) | - ((buf[1] & 0xf0) << 4) | - buf[5]); - - hw->z = buf[2]; hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); + if (is_multi_touch_packet(priv, hw)) { + /* a multi-touch packet is encoded differently; + * it appears to have half-resolutions. I might + * have missed the lowest bits, but it's hard + * to recognize. + */ + hw->x = ((buf[4] & 0x0f) << 8 | buf[1]) << 1; + hw->y = ((buf[4] & 0xf0) << 4 | buf[2]) << 1; + hw->z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + } else { + hw->x = (((buf[3] & 0x10) << 8) | + ((buf[1] & 0x0f) << 8) | + buf[4]); + hw->y = (((buf[3] & 0x20) << 7) | + ((buf[1] & 0xf0) << 4) | + buf[5]); + hw->z = buf[2]; + } hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; @@ -492,7 +534,7 @@ static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data } else if (SYN_CAP_MIDDLE_BUTTON(priv->capabilities)) { hw->middle = ((buf[0] ^ buf[3]) & 0x01) ? 1 : 0; - if (hw->w == 2) + if (!is_multi_touch(priv) && hw->w == 2) hw->scroll = (signed char)(buf[1]); } @@ -550,6 +592,18 @@ static void synaptics_process_packet(struct psmouse *psmouse) synaptics_parse_hw_state(psmouse->packet, priv, &hw); + if (is_multi_touch_packet(priv, &hw)) { + /* multi-touching */ + if (hw.z > 0) { + input_report_abs(dev, ABS_MT_POSITION_X, hw.x); + input_report_abs(dev, ABS_MT_POSITION_Y, + YMAX_NOMINAL + YMIN_NOMINAL - hw.y); + } + input_report_abs(dev, ABS_MT_PRESSURE, hw.z); + input_mt_sync(dev); + return; + } + if (hw.scroll) { priv->scroll += hw.scroll; @@ -576,7 +630,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (SYN_CAP_EXTENDED(priv->capabilities)) { switch (hw.w) { case 0 ... 1: - if (SYN_CAP_MULTIFINGER(priv->capabilities)) + if (SYN_CAP_MULTIFINGER(priv->capabilities) || + is_multi_touch(priv)) num_fingers = hw.w + 2; break; case 2: @@ -602,10 +657,15 @@ static void synaptics_process_packet(struct psmouse *psmouse) if (hw.z < 25) input_report_key(dev, BTN_TOUCH, 0); if (hw.z > 0) { - input_report_abs(dev, ABS_X, hw.x); - input_report_abs(dev, ABS_Y, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); + int key; + key = is_multi_touch(priv) ? ABS_MT_POSITION_X : ABS_X; + input_report_abs(dev, key, hw.x); + key = is_multi_touch(priv) ? ABS_MT_POSITION_Y : ABS_Y; + input_report_abs(dev, key, YMAX_NOMINAL + YMIN_NOMINAL - hw.y); } - input_report_abs(dev, ABS_PRESSURE, hw.z); + input_report_abs(dev, + is_multi_touch(priv) ? ABS_MT_PRESSURE : ABS_PRESSURE, + hw.z); if (SYN_CAP_PALMDETECT(priv->capabilities)) input_report_abs(dev, ABS_TOOL_WIDTH, finger_width); @@ -614,7 +674,7 @@ static void synaptics_process_packet(struct psmouse *psmouse) input_report_key(dev, BTN_LEFT, hw.left); input_report_key(dev, BTN_RIGHT, hw.right); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(priv->capabilities) || is_multi_touch(priv)) { input_report_key(dev, BTN_TOOL_DOUBLETAP, num_fingers == 2); input_report_key(dev, BTN_TOOL_TRIPLETAP, num_fingers == 3); } @@ -630,6 +690,8 @@ static void synaptics_process_packet(struct psmouse *psmouse) for (i = 0; i < SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap); i++) input_report_key(dev, BTN_0 + i, hw.ext_buttons & (1 << i)); + if (is_multi_touch(priv)) + input_mt_sync(dev); input_sync(dev); } @@ -719,7 +781,7 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) __set_bit(BTN_LEFT, dev->keybit); __set_bit(BTN_RIGHT, dev->keybit); - if (SYN_CAP_MULTIFINGER(priv->capabilities)) { + if (SYN_CAP_MULTIFINGER(priv->capabilities) || is_multi_touch(priv)) { __set_bit(BTN_TOOL_DOUBLETAP, dev->keybit); __set_bit(BTN_TOOL_TRIPLETAP, dev->keybit); } @@ -748,6 +810,16 @@ static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) __clear_bit(BTN_RIGHT, dev->keybit); __clear_bit(BTN_MIDDLE, dev->keybit); } + + if (is_multi_touch(priv)) { + input_set_abs_params(dev, ABS_MT_POSITION_X, + XMIN_NOMINAL, XMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, + YMIN_NOMINAL, YMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0); + input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); + input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); + } } static void synaptics_disconnect(struct psmouse *psmouse) @@ -785,6 +857,8 @@ static int synaptics_reconnect(struct psmouse *psmouse) } synaptics_sync_led(psmouse); + if (is_multi_touch(priv)) + synaptics_init_multi_touch(psmouse); return 0; } @@ -863,6 +937,15 @@ int synaptics_init(struct psmouse *psmouse) if (synaptics_init_led(psmouse) < 0) goto init_fail; + if (priv->can_multi_touch) { + if (synaptics_init_multi_touch(psmouse)) { + printk(KERN_WARNING "Synaptics: " + "unable to initialize multi-touch\n"); + priv->can_multi_touch = 0; + } else + printk(KERN_INFO "Synaptics: multi-touch enabled\n"); + } + set_input_params(psmouse->dev, priv); /* diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h index e1a9033..b586087 100644 --- a/drivers/input/mouse/synaptics.h +++ b/drivers/input/mouse/synaptics.h @@ -111,6 +111,7 @@ struct synaptics_data { unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ + unsigned char can_multi_touch; /* multi-touch support */ int scroll; struct synaptics_led *led; };