Patchwork [1/1] UBUNTU: (pre-stable): input: Support Clickpad devices in ClickZone mode

login
register
mail settings
Submitter Chase Douglas
Date April 8, 2010, 6:01 p.m.
Message ID <1270749698-20872-2-git-send-email-chase.douglas@canonical.com>
Download mbox | patch
Permalink /patch/49743/
State Accepted
Delegated to: Andy Whitcroft
Headers show

Comments

Chase Douglas - April 8, 2010, 6:01 p.m.
From: Takashi Iwai <tiwai@xxxxxxx>

Add the experimental support of new Synatpics "Clickpad" devices.

This device reports the click as the middle-button, but it doesn't set
proper capability bits.  Thus the driver needs to check the product-id
and forces to enable the button detection.

In this patch, the device behaves as "ClickZone" mode, and gives
compatible events as other normal synaptics devices so that user-space
app works as is.  In the ClickZone mode, the buttons are emulated as
clicks in the bottom button zone.  Left and right clicks are judged by
the touch position.  Clicking the narrow middle point in the button
zone gives a middle click.

Dragging can be done by keeping the button down and touching the normal
area again.  Strangely, the sequence to click after touching the area
doesn't work with this device by unknown reason...

Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>

BugLink: http://bugs.launchpad.net/bugs/516329

Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
---

This is the second version, simply merged previous patches into one,
per request of Dmitry.

 drivers/input/mouse/synaptics.c |   48 +++++++++++++++++++++++++++++++++++++++
 drivers/input/mouse/synaptics.h |    3 ++
 2 files changed, 51 insertions(+), 0 deletions(-)
Andy Whitcroft - April 9, 2010, 2:24 p.m.
On Thu, Apr 08, 2010 at 02:01:38PM -0400, Chase Douglas wrote:
> From: Takashi Iwai <tiwai@xxxxxxx>
> 
> Add the experimental support of new Synatpics "Clickpad" devices.
> 
> This device reports the click as the middle-button, but it doesn't set
> proper capability bits.  Thus the driver needs to check the product-id
> and forces to enable the button detection.
> 
> In this patch, the device behaves as "ClickZone" mode, and gives
> compatible events as other normal synaptics devices so that user-space
> app works as is.  In the ClickZone mode, the buttons are emulated as
> clicks in the bottom button zone.  Left and right clicks are judged by
> the touch position.  Clicking the narrow middle point in the button
> zone gives a middle click.
> 
> Dragging can be done by keeping the button down and touching the normal
> area again.  Strangely, the sequence to click after touching the area
> doesn't work with this device by unknown reason...
> 
> Signed-off-by: Takashi Iwai <tiwai@xxxxxxx>
> 
> BugLink: http://bugs.launchpad.net/bugs/516329
> 
> Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
> ---
> 
> This is the second version, simply merged previous patches into one,
> per request of Dmitry.
> 
>  drivers/input/mouse/synaptics.c |   48 +++++++++++++++++++++++++++++++++++++++
>  drivers/input/mouse/synaptics.h |    3 ++
>  2 files changed, 51 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
> index 05689e7..b2db417 100644
> --- a/drivers/input/mouse/synaptics.c
> +++ b/drivers/input/mouse/synaptics.c
> @@ -327,6 +327,45 @@ static void synaptics_pt_create(struct psmouse *psmouse)
>   *	Functions to interpret the absolute mode packets
>   ****************************************************************************/
>  
> +/* left and right clickpad button ranges;
> + * the gap between them is interpreted as a middle-button click
> + */
> +#define CLICKPAD_LEFT_BTN_X \
> +	((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
> +#define CLICKPAD_RIGHT_BTN_X \
> +	((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
> +
> +/* handle clickpad events */
> +static void clickpad_process_packet(struct synaptics_data *priv,
> +				    struct synaptics_hw_state *hw)
> +{
> +	/* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
> +	 * where the area Y < YMIN_NOMINAL is used as click buttons
> +	 */
> +	if (hw->y < YMIN_NOMINAL) {
> +		/* button area */
> +		hw->z = 0; /* don't move pointer */
> +		/* clickpad reports only the middle button, and we need
> +		 * to fake left/right buttons depending on the touch position
> +		 */
> +		if (hw->middle) { /* clicked? */
> +			hw->middle = 0;
> +			if (hw->x < CLICKPAD_LEFT_BTN_X)
> +				hw->left = 1;
> +			else if (hw->x > CLICKPAD_RIGHT_BTN_X)
> +				hw->right = 1;
> +			else
> +				hw->middle = 1;
> +		}
> +	} else if (hw->middle) {
> +		/* dragging */
> +		hw->left = priv->prev_hw.left;
> +		hw->right = priv->prev_hw.right;
> +		hw->middle = priv->prev_hw.middle;
> +	}
> +	priv->prev_hw = *hw;
> +}
> +
>  static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
>  {
>  	memset(hw, 0, sizeof(struct synaptics_hw_state));
> @@ -407,6 +446,9 @@ static void synaptics_process_packet(struct psmouse *psmouse)
>  
>  	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
>  
> +	if (SYN_CAP_CLICKPAD(priv->ext_cap))
> +		clickpad_process_packet(priv, &hw);
> +
>  	if (hw.scroll) {
>  		priv->scroll += hw.scroll;
>  
> @@ -701,6 +743,12 @@ int synaptics_init(struct psmouse *psmouse)
>  		SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
>  		priv->model_id, priv->capabilities, priv->ext_cap);
>  
> +	if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
> +		printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
> +		/* force to enable the middle button */
> +		priv->capabilities |= (1 << 18);
> +	}
> +
>  	set_input_params(psmouse->dev, priv);
>  
>  	/*
> diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
> index 838e7f2..76df393 100644
> --- a/drivers/input/mouse/synaptics.h
> +++ b/drivers/input/mouse/synaptics.h
> @@ -48,6 +48,8 @@
>  #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(ec)		(SYN_CAP_PRODUCT_ID(ec) == 0xe4)
>  
>  /* synaptics modes query bits */
>  #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
> @@ -103,6 +105,7 @@ struct synaptics_data {
>  	unsigned char pkt_type;			/* packet type - old, new, etc */
>  	unsigned char mode;			/* current mode byte */
>  	int scroll;
> +	struct synaptics_hw_state prev_hw;
>  };

Seems to only enable the functionality for devices with the capability
and to be nicely out of line otherwise.

Acked-by: Andy Whitcroft <apw@canonical.com>

-apw

Patch

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index 05689e7..b2db417 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -327,6 +327,45 @@  static void synaptics_pt_create(struct psmouse *psmouse)
  *	Functions to interpret the absolute mode packets
  ****************************************************************************/
 
+/* left and right clickpad button ranges;
+ * the gap between them is interpreted as a middle-button click
+ */
+#define CLICKPAD_LEFT_BTN_X \
+	((XMAX_NOMINAL - XMIN_NOMINAL) * 2 / 5 + XMIN_NOMINAL)
+#define CLICKPAD_RIGHT_BTN_X \
+	((XMAX_NOMINAL - XMIN_NOMINAL) * 3 / 5 + XMIN_NOMINAL)
+
+/* handle clickpad events */
+static void clickpad_process_packet(struct synaptics_data *priv,
+				    struct synaptics_hw_state *hw)
+{
+	/* clickpad mode reports Y range from 0 to YMAX_NOMINAL,
+	 * where the area Y < YMIN_NOMINAL is used as click buttons
+	 */
+	if (hw->y < YMIN_NOMINAL) {
+		/* button area */
+		hw->z = 0; /* don't move pointer */
+		/* clickpad reports only the middle button, and we need
+		 * to fake left/right buttons depending on the touch position
+		 */
+		if (hw->middle) { /* clicked? */
+			hw->middle = 0;
+			if (hw->x < CLICKPAD_LEFT_BTN_X)
+				hw->left = 1;
+			else if (hw->x > CLICKPAD_RIGHT_BTN_X)
+				hw->right = 1;
+			else
+				hw->middle = 1;
+		}
+	} else if (hw->middle) {
+		/* dragging */
+		hw->left = priv->prev_hw.left;
+		hw->right = priv->prev_hw.right;
+		hw->middle = priv->prev_hw.middle;
+	}
+	priv->prev_hw = *hw;
+}
+
 static void synaptics_parse_hw_state(unsigned char buf[], struct synaptics_data *priv, struct synaptics_hw_state *hw)
 {
 	memset(hw, 0, sizeof(struct synaptics_hw_state));
@@ -407,6 +446,9 @@  static void synaptics_process_packet(struct psmouse *psmouse)
 
 	synaptics_parse_hw_state(psmouse->packet, priv, &hw);
 
+	if (SYN_CAP_CLICKPAD(priv->ext_cap))
+		clickpad_process_packet(priv, &hw);
+
 	if (hw.scroll) {
 		priv->scroll += hw.scroll;
 
@@ -701,6 +743,12 @@  int synaptics_init(struct psmouse *psmouse)
 		SYN_ID_MAJOR(priv->identity), SYN_ID_MINOR(priv->identity),
 		priv->model_id, priv->capabilities, priv->ext_cap);
 
+	if (SYN_CAP_CLICKPAD(priv->ext_cap)) {
+		printk(KERN_INFO "Synaptics: Clickpad mode enabled\n");
+		/* force to enable the middle button */
+		priv->capabilities |= (1 << 18);
+	}
+
 	set_input_params(psmouse->dev, priv);
 
 	/*
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 838e7f2..76df393 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -48,6 +48,8 @@ 
 #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(ec)		(SYN_CAP_PRODUCT_ID(ec) == 0xe4)
 
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
@@ -103,6 +105,7 @@  struct synaptics_data {
 	unsigned char pkt_type;			/* packet type - old, new, etc */
 	unsigned char mode;			/* current mode byte */
 	int scroll;
+	struct synaptics_hw_state prev_hw;
 };
 
 void synaptics_module_init(void);