diff mbox

Input: synaptics - add support for ForcePads

Message ID 20140909225725.GA18901@core.coreip.homeip.net (mailing list archive)
State New, archived
Headers show

Commit Message

Dmitry Torokhov Sept. 9, 2014, 10:57 p.m. UTC
On Tue, Sep 09, 2014 at 03:07:21PM -0700, Andrew Duggan wrote:
> On 09/09/2014 10:06 AM, Dmitry Torokhov wrote:
> >On Tue, Sep 09, 2014 at 09:44:17AM +0200, Hans de Goede wrote:
> >>Hi,
> >>
> >>On 09/08/2014 06:55 PM, Dmitry Torokhov wrote:
> >>>ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of
> >>>physical buttons, instead they generate primary button click when user
> >>>presses somewhat hard on the surface of the touchpad. Unfortunately they
> >>>also report primary button click whenever there are 2 or more contacts
> >>>on the pad, messing up all multi-finger gestures (2-finger scrolling,
> >>>multi-finger tapping, etc). To cope with this behavior we introduce a
> >>>delay (currently 50 msecs) in reporting primary press in case more
> >>>contacts appear.
> >>>
> >>>For now we are using DMI matching to detect ForcePads, hopefully we'll
> >>>be able to figure a better way down the road.
> >>What about using the pnp-id, in my experience with the recent lenovo
> >>laptops that tends to be more reliable.
> >Not sure. So far I only know of HP 1040 having it. FWIW:
> >
> >dtor@dtor-glaptop:~$ cat /sys/bus/pnp/drivers/i8042\ aux/00\:07/id
> >SYN300d
> >SYN0100
> >SYN0002
> >PNP0f13
> >
> >I think if we see generalities we can switch over later. I hope
> >Chris/Andrew will come with a capability bit though :)
> 
> The ForcePad capabilities bit is 1 << 15.

Awesome, thanks!

Then I guess the patch below is what we'll be needing for these devices.

Thanks.

Comments

Hans de Goede Sept. 9, 2014, 11:07 p.m. UTC | #1
Hi,

On 09/10/2014 12:57 AM, Dmitry Torokhov wrote:
> On Tue, Sep 09, 2014 at 03:07:21PM -0700, Andrew Duggan wrote:
>> On 09/09/2014 10:06 AM, Dmitry Torokhov wrote:
>>> On Tue, Sep 09, 2014 at 09:44:17AM +0200, Hans de Goede wrote:
>>>> Hi,
>>>>
>>>> On 09/08/2014 06:55 PM, Dmitry Torokhov wrote:
>>>>> ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of
>>>>> physical buttons, instead they generate primary button click when user
>>>>> presses somewhat hard on the surface of the touchpad. Unfortunately they
>>>>> also report primary button click whenever there are 2 or more contacts
>>>>> on the pad, messing up all multi-finger gestures (2-finger scrolling,
>>>>> multi-finger tapping, etc). To cope with this behavior we introduce a
>>>>> delay (currently 50 msecs) in reporting primary press in case more
>>>>> contacts appear.
>>>>>
>>>>> For now we are using DMI matching to detect ForcePads, hopefully we'll
>>>>> be able to figure a better way down the road.
>>>> What about using the pnp-id, in my experience with the recent lenovo
>>>> laptops that tends to be more reliable.
>>> Not sure. So far I only know of HP 1040 having it. FWIW:
>>>
>>> dtor@dtor-glaptop:~$ cat /sys/bus/pnp/drivers/i8042\ aux/00\:07/id
>>> SYN300d
>>> SYN0100
>>> SYN0002
>>> PNP0f13
>>>
>>> I think if we see generalities we can switch over later. I hope
>>> Chris/Andrew will come with a capability bit though :)
>>
>> The ForcePad capabilities bit is 1 << 15.
> 
> Awesome, thanks!
> 
> Then I guess the patch below is what we'll be needing for these devices.

Yep, the patch looks good to me.

Regards,

Hans
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov Sept. 9, 2014, 11:15 p.m. UTC | #2
On Wed, Sep 10, 2014 at 01:07:02AM +0200, Hans de Goede wrote:
> Hi,
> 
> On 09/10/2014 12:57 AM, Dmitry Torokhov wrote:
> > On Tue, Sep 09, 2014 at 03:07:21PM -0700, Andrew Duggan wrote:
> >> On 09/09/2014 10:06 AM, Dmitry Torokhov wrote:
> >>> On Tue, Sep 09, 2014 at 09:44:17AM +0200, Hans de Goede wrote:
> >>>> Hi,
> >>>>
> >>>> On 09/08/2014 06:55 PM, Dmitry Torokhov wrote:
> >>>>> ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of
> >>>>> physical buttons, instead they generate primary button click when user
> >>>>> presses somewhat hard on the surface of the touchpad. Unfortunately they
> >>>>> also report primary button click whenever there are 2 or more contacts
> >>>>> on the pad, messing up all multi-finger gestures (2-finger scrolling,
> >>>>> multi-finger tapping, etc). To cope with this behavior we introduce a
> >>>>> delay (currently 50 msecs) in reporting primary press in case more
> >>>>> contacts appear.
> >>>>>
> >>>>> For now we are using DMI matching to detect ForcePads, hopefully we'll
> >>>>> be able to figure a better way down the road.
> >>>> What about using the pnp-id, in my experience with the recent lenovo
> >>>> laptops that tends to be more reliable.
> >>> Not sure. So far I only know of HP 1040 having it. FWIW:
> >>>
> >>> dtor@dtor-glaptop:~$ cat /sys/bus/pnp/drivers/i8042\ aux/00\:07/id
> >>> SYN300d
> >>> SYN0100
> >>> SYN0002
> >>> PNP0f13
> >>>
> >>> I think if we see generalities we can switch over later. I hope
> >>> Chris/Andrew will come with a capability bit though :)
> >>
> >> The ForcePad capabilities bit is 1 << 15.
> > 
> > Awesome, thanks!
> > 
> > Then I guess the patch below is what we'll be needing for these devices.
> 
> Yep, the patch looks good to me.

Thanks, I'll put you down as reviewed-by then.
Peter Hutterer Oct. 30, 2014, 12:38 a.m. UTC | #3
On Tue, Sep 09, 2014 at 03:57:25PM -0700, Dmitry Torokhov wrote:
> From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> 
> ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of
> physical buttons, instead they generate primary button click when user
> presses somewhat hard on the surface of the touchpad. Unfortunately they
> also report primary button click whenever there are 2 or more contacts
> on the pad, messing up all multi-finger gestures (2-finger scrolling,
> multi-finger tapping, etc). To cope with this behavior we introduce a
> delay (currently 50 msecs) in reporting primary press in case more
> contacts appear.

can we assign INPUT_PROP_FORCEPAD to this? or PRESSUREPAD or something if
we're worried about trademarks. This is something I'd like to know in
userspace, we can then ignore clicks completely and do the rest ourselves. 

Cheers,
   Peter

> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
>  drivers/input/mouse/synaptics.c |   68 ++++++++++++++++++++++++++++++---------
>  drivers/input/mouse/synaptics.h |   11 ++++++
>  2 files changed, 63 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
> index e8573c6..fd23181 100644
> --- a/drivers/input/mouse/synaptics.c
> +++ b/drivers/input/mouse/synaptics.c
> @@ -629,10 +629,61 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
>  			 ((buf[0] & 0x04) >> 1) |
>  			 ((buf[3] & 0x04) >> 2));
>  
> +		if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
> +			SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
> +		    hw->w == 2) {
> +			synaptics_parse_agm(buf, priv, hw);
> +			return 1;
> +		}
> +
> +		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;
>  
> -		if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
> +		if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) {
> +			/*
> +			 * ForcePads, like Clickpads, use middle button
> +			 * bits to report primary button clicks.
> +			 * Unfortunately they report primary button not
> +			 * only when user presses on the pad above certain
> +			 * threshold, but also when there are more than one
> +			 * finger on the touchpad, which interferes with
> +			 * out multi-finger gestures.
> +			 */
> +			if (hw->z == 0) {
> +				/* No contacts */
> +				priv->press = priv->report_press = false;
> +			} else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
> +				/*
> +				 * Single-finger touch with pressure above
> +				 * the threshold. If pressure stays long
> +				 * enough, we'll start reporting primary
> +				 * button. We rely on the device continuing
> +				 * sending data even if finger does not
> +				 * move.
> +				 */
> +				if  (!priv->press) {
> +					priv->press_start = jiffies;
> +					priv->press = true;
> +				} else if (time_after(jiffies,
> +						priv->press_start +
> +							msecs_to_jiffies(50))) {
> +					priv->report_press = true;
> +				}
> +			} else {
> +				priv->press = false;
> +			}
> +
> +			hw->left = priv->report_press;
> +
> +		} else 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
> @@ -651,21 +702,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[],
>  			hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
>  		}
>  
> -		if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
> -			SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
> -		    hw->w == 2) {
> -			synaptics_parse_agm(buf, priv, hw);
> -			return 1;
> -		}
> -
> -		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];
> -
>  		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
>  		    ((buf[0] ^ buf[3]) & 0x02)) {
>  			switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
> diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
> index e594af0..fb2e076 100644
> --- a/drivers/input/mouse/synaptics.h
> +++ b/drivers/input/mouse/synaptics.h
> @@ -78,6 +78,11 @@
>   * 2	0x08	image sensor		image sensor tracks 5 fingers, but only
>   *					reports 2.
>   * 2	0x20	report min		query 0x0f gives min coord reported
> + * 2	0x80	forcepad		forcepad is a variant of clickpad that
> + *					does not have physical buttons but rather
> + *					uses pressure above certain threshold to
> + *					report primary clicks. Forcepads also have
> + *					clickpad bit set.
>   */
>  #define SYN_CAP_CLICKPAD(ex0c)		((ex0c) & 0x100000) /* 1-button ClickPad */
>  #define SYN_CAP_CLICKPAD2BTN(ex0c)	((ex0c) & 0x000100) /* 2-button ClickPad */
> @@ -86,6 +91,7 @@
>  #define SYN_CAP_ADV_GESTURE(ex0c)	((ex0c) & 0x080000)
>  #define SYN_CAP_REDUCED_FILTERING(ex0c)	((ex0c) & 0x000400)
>  #define SYN_CAP_IMAGE_SENSOR(ex0c)	((ex0c) & 0x000800)
> +#define SYN_CAP_FORCEPAD(ex0c)		((ex0c) & 0x008000)
>  
>  /* synaptics modes query bits */
>  #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
> @@ -177,6 +183,11 @@ struct synaptics_data {
>  	 */
>  	struct synaptics_hw_state agm;
>  	bool agm_pending;			/* new AGM packet received */
> +
> +	/* ForcePad handling */
> +	unsigned long				press_start;
> +	bool					press;
> +	bool					report_press;
>  };
>  
>  void synaptics_module_init(void);
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Dmitry Torokhov Oct. 30, 2014, 5:35 p.m. UTC | #4
On Thu, Oct 30, 2014 at 10:38:55AM +1000, Peter Hutterer wrote:
> On Tue, Sep 09, 2014 at 03:57:25PM -0700, Dmitry Torokhov wrote:
> > From: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> > 
> > ForcePads are found on HP EliteBook 1040 laptops. They lack any kind of
> > physical buttons, instead they generate primary button click when user
> > presses somewhat hard on the surface of the touchpad. Unfortunately they
> > also report primary button click whenever there are 2 or more contacts
> > on the pad, messing up all multi-finger gestures (2-finger scrolling,
> > multi-finger tapping, etc). To cope with this behavior we introduce a
> > delay (currently 50 msecs) in reporting primary press in case more
> > contacts appear.
> 
> can we assign INPUT_PROP_FORCEPAD to this? or PRESSUREPAD or something if
> we're worried about trademarks. This is something I'd like to know in
> userspace, we can then ignore clicks completely and do the rest ourselves. 

Hmm, I think we can, but I'd like to wait to see if there are more
models with such touchpads (I sure hope there isn't; lack of tactile
feedback on presses is not the best user experience so I hope this
initiative dies a quick death).

Thanks.
diff mbox

Patch

diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index e8573c6..fd23181 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -629,10 +629,61 @@  static int synaptics_parse_hw_state(const unsigned char buf[],
 			 ((buf[0] & 0x04) >> 1) |
 			 ((buf[3] & 0x04) >> 2));
 
+		if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
+			SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
+		    hw->w == 2) {
+			synaptics_parse_agm(buf, priv, hw);
+			return 1;
+		}
+
+		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;
 
-		if (SYN_CAP_CLICKPAD(priv->ext_cap_0c)) {
+		if (SYN_CAP_FORCEPAD(priv->ext_cap_0c)) {
+			/*
+			 * ForcePads, like Clickpads, use middle button
+			 * bits to report primary button clicks.
+			 * Unfortunately they report primary button not
+			 * only when user presses on the pad above certain
+			 * threshold, but also when there are more than one
+			 * finger on the touchpad, which interferes with
+			 * out multi-finger gestures.
+			 */
+			if (hw->z == 0) {
+				/* No contacts */
+				priv->press = priv->report_press = false;
+			} else if (hw->w >= 4 && ((buf[0] ^ buf[3]) & 0x01)) {
+				/*
+				 * Single-finger touch with pressure above
+				 * the threshold. If pressure stays long
+				 * enough, we'll start reporting primary
+				 * button. We rely on the device continuing
+				 * sending data even if finger does not
+				 * move.
+				 */
+				if  (!priv->press) {
+					priv->press_start = jiffies;
+					priv->press = true;
+				} else if (time_after(jiffies,
+						priv->press_start +
+							msecs_to_jiffies(50))) {
+					priv->report_press = true;
+				}
+			} else {
+				priv->press = false;
+			}
+
+			hw->left = priv->report_press;
+
+		} else 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
@@ -651,21 +702,6 @@  static int synaptics_parse_hw_state(const unsigned char buf[],
 			hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0;
 		}
 
-		if ((SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) ||
-			SYN_CAP_IMAGE_SENSOR(priv->ext_cap_0c)) &&
-		    hw->w == 2) {
-			synaptics_parse_agm(buf, priv, hw);
-			return 1;
-		}
-
-		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];
-
 		if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) &&
 		    ((buf[0] ^ buf[3]) & 0x02)) {
 			switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) {
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index e594af0..fb2e076 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -78,6 +78,11 @@ 
  * 2	0x08	image sensor		image sensor tracks 5 fingers, but only
  *					reports 2.
  * 2	0x20	report min		query 0x0f gives min coord reported
+ * 2	0x80	forcepad		forcepad is a variant of clickpad that
+ *					does not have physical buttons but rather
+ *					uses pressure above certain threshold to
+ *					report primary clicks. Forcepads also have
+ *					clickpad bit set.
  */
 #define SYN_CAP_CLICKPAD(ex0c)		((ex0c) & 0x100000) /* 1-button ClickPad */
 #define SYN_CAP_CLICKPAD2BTN(ex0c)	((ex0c) & 0x000100) /* 2-button ClickPad */
@@ -86,6 +91,7 @@ 
 #define SYN_CAP_ADV_GESTURE(ex0c)	((ex0c) & 0x080000)
 #define SYN_CAP_REDUCED_FILTERING(ex0c)	((ex0c) & 0x000400)
 #define SYN_CAP_IMAGE_SENSOR(ex0c)	((ex0c) & 0x000800)
+#define SYN_CAP_FORCEPAD(ex0c)		((ex0c) & 0x008000)
 
 /* synaptics modes query bits */
 #define SYN_MODE_ABSOLUTE(m)		((m) & (1 << 7))
@@ -177,6 +183,11 @@  struct synaptics_data {
 	 */
 	struct synaptics_hw_state agm;
 	bool agm_pending;			/* new AGM packet received */
+
+	/* ForcePad handling */
+	unsigned long				press_start;
+	bool					press;
+	bool					report_press;
 };
 
 void synaptics_module_init(void);