Linux Input/HID development
 help / color / mirror / Atom feed
* Regression: mouse pointer stuck in KDE with kernel 3.13 and above
From: Dâniel Fraga @ 2014-03-25  2:28 UTC (permalink / raw)
  To: linux-input

	I'd like some help to debug this regression. After upgrading
from kernel 3.12 to 3.13, my mouse gets stuck after entering in KDE (at
console with gpm everything is fine).

	Bisect is worthless in this case, because this bug doesn't
trigger everytime. USB is not the problem, since usbmon trace shows
activity even with the mouse pointer stuck.

	What can I do do debug this? Any hints?

	Thanks.

-- 
Linux 3.12.14: Shuffling Zombie Juror
http://www.youtube.com/DanielFragaBR
http://mcxnow.com?r=danielfragabr
Bitcoin: 12H6661yoLDUZaYPdah6urZS5WiXwTAUgL



^ permalink raw reply

* Re: Elan touchscreen report (HP Pavilion 10-e010nr)
From: 劉嘉駿 @ 2014-03-25  2:36 UTC (permalink / raw)
  To: Robert Kraus, linux-input
In-Reply-To: <CAMsr0sLqRj+pi20GrncOYjNSxaMLwPZbi10HX8ATa97SNtn0Ww@mail.gmail.com>

thanks Robert and I think that we're no longer need manual configuration 
after Kernel > v3.4.

Scott

於 2014/3/22 上午 11:53, Robert Kraus 提到:
> Hello,
>
> I'm sending this to you as per the directions at
> https://wiki.archlinux.org/index.php/Multitouch_Displays
>
> Hardware: HP Pavilion 10-e010nr touchscreen laptop
> OS: xubuntu 12.04 LTS, kernel 3.2.0-60-generic
> Module: hid-multitouch, vendor class
> MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 (decimal 265)
> lsusb output: (note, the device # kept incrementing due to mtp-probe
> thinking it's an MTP device)
> Bus 003 Device 119: ID 04f3:0268 Elan Microelectronics Corp.
>
> It may already be known to you guys as the touchscreen worked without
> configuration in Steam OS, in which case feel free to trash this
> message.
>
> Regards,
> -Bob
> --
> 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

^ permalink raw reply

* Re: Re: [PATCH v2 2/8] mfd: AXP20x: Add bindings documentation
From: Maxime Ripard @ 2014-03-25 10:11 UTC (permalink / raw)
  To: Carlo Caione
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
	wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <20140322141157.GA20668-bi+AKbBUZKZeIdyRz4JgOMwOAu8XWILU@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 952 bytes --]

On Sat, Mar 22, 2014 at 03:11:57PM +0100, Carlo Caione wrote:
> > > +
> > > +Example:
> > > +
> > > +axp: axp20x@34 {
> > > +	reg = <0x34>;
> > > +	interrupt-parent = <&nmi_intc>;
> > > +	interrupts = <0 8>;
> > > +
> > > +	compatible = "x-powers,axp209";
> > > +	interrupt-controller;
> > > +	#interrupt-cells = <1>;
> > > +
> > > +	regulators {
> > 
> > Do we really need that subnode ? it looks useless, and we already know
> > that we are defining regulators here.
> 
> What do you mean? We are defining the MFD and regulators are just one of
> the subsystem here.

I mean that it's useless.

> Moveover I'm using the "regulators" node in the
> regulators driver (using of_find_node_by_name()) to get the regulators
> configuration.

Can't you just use the of_node field of whatever struct device you
get?

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* Re: Re: [PATCH v2 6/8] ARM: sunxi: dt: Add x-powers-axp209.dtsi file
From: Maxime Ripard @ 2014-03-25 10:11 UTC (permalink / raw)
  To: Carlo Caione
  Cc: linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
	linux-sunxi-/JYPxA39Uh5TLH3MbocFFw,
	hdegoede-H+wXaHxf7aLQT0dZR+AlfA, emilio-0Z03zUJReD5OxF6Tv1QG9Q,
	wens-jdAy2FN1RRM, sameo-VuQAYsv1563Yd54FQh9/CA,
	lee.jones-QSEj5FYQhm4dnm+yROfE0A,
	devicetree-u79uwXL29TY76Z2rM5mHXA,
	dmitry.torokhov-Re5JQEeQqe8AvxtiuMwx3w,
	linux-input-u79uwXL29TY76Z2rM5mHXA,
	linux-doc-u79uwXL29TY76Z2rM5mHXA,
	lgirdwood-Re5JQEeQqe8AvxtiuMwx3w, broonie-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <20140322143157.GB20668-bi+AKbBUZKZeIdyRz4JgOMwOAu8XWILU@public.gmane.org>

[-- Attachment #1: Type: text/plain, Size: 599 bytes --]

On Sat, Mar 22, 2014 at 03:31:57PM +0100, Carlo Caione wrote:
> > > +	compatible = "x-powers,axp209";
> > > +	interrupt-controller;
> > > +	#interrupt-cells = <1>;
> > 
> > However, I'd move this out of it, and in the board file, so that we
> > actually get an idea by looking at the board DTS of what device we are
> > actually registering at this given address, and what it's capable of.
> 
> Do you mean the whole dtsi or just those three lines?

Just those three lines.

-- 
Maxime Ripard, Free Electrons
Embedded Linux, Kernel and Android engineering
http://free-electrons.com

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 836 bytes --]

^ permalink raw reply

* [PATCH] Add VID/PID for HID-type Multi-Touch Module of AFO CO., LTD.
From: YongHwan Ki @ 2014-03-25 10:12 UTC (permalink / raw)
  To: jkosina, rydberg, linux-input, linux-kernel


There is no way to support the hid-type AFO multi touch modules.

Add the VID/PID of AFO to the hid-related lists.

Kernel Version : linux-3.14.rc7

Signed-off-by: Yonghwan Ki <kyhw@afoi.co.kr>

diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-core.c ../linux-3.14-rc7/drivers/hid/hid-core.c
--- ./drivers/hid/hid-core.c	2014-03-21 17:41:51.846939444 +0900
+++ ../linux-3.14-rc7/drivers/hid/hid-core.c	2014-03-17 10:51:24.000000000 +0900
@@ -1881,8 +1881,6 @@ static const struct hid_device_id hid_ha
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_TCM) },
-	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_THM) },
 
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-ids.h ../linux-3.14-rc7/drivers/hid/hid-ids.h
--- ./drivers/hid/hid-ids.h	2014-03-21 17:30:34.478959555 +0900
+++ ../linux-3.14-rc7/drivers/hid/hid-ids.h	2014-03-17 10:51:24.000000000 +0900
@@ -960,9 +960,5 @@
 #define USB_VENDOR_ID_PRIMAX	0x0461
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05
 
-#define USB_VENDOR_ID_AFO		0x2576
-#define USB_DEVICE_ID_AFO_TCM		0x0003
-#define USB_DEVICE_ID_AFO_BL		0x0005
-#define USB_DEVICE_ID_AFO_THM		0x0011
 
 #endif
diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-multitouch.c ../linux-3.14-rc7/drivers/hid/hid-multitouch.c
--- ./drivers/hid/hid-multitouch.c	2014-03-21 17:45:25.946933088 +0900
+++ ../linux-3.14-rc7/drivers/hid/hid-multitouch.c	2014-03-17 10:51:24.000000000 +0900
@@ -1395,15 +1395,6 @@ static const struct hid_device_id mt_dev
 	{  .driver_data = MT_CLS_WIN_8,
 		HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
 			HID_ANY_ID, HID_ANY_ID) },
-
-	/* AFO MultiTouch device */
-	{  .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
-			USB_DEVICE_ID_AFO_TCM) },
-	{  .driver_data = MT_CLS_SERIAL,
-		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
-			USB_DEVICE_ID_AFO_THM) },
-
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, mt_devices);
Binary files ./kernel/x509_certificate_list and ../linux-3.14-rc7/kernel/x509_certificate_list differ
diff -uprN -X Documentation/dontdiff ./lib/oid_registry_data.c ../linux-3.14-rc7/lib/oid_registry_data.c
--- ./lib/oid_registry_data.c	2014-03-24 21:43:59.826812763 +0900
+++ ../linux-3.14-rc7/lib/oid_registry_data.c	2014-03-21 18:45:37.598825862 +0900
@@ -1,5 +1,5 @@
 /*
- * Automatically generated by /usr/src/linux-3.14-rc7m/lib/build_OID_registry.  Do not edit
+ * Automatically generated by /usr/src/linux-3.14-rc7/lib/build_OID_registry.  Do not edit
  */
 
 static const unsigned short oid_index[OID__NR + 1] = {
diff -uprN -X Documentation/dontdiff ./signing_key.priv ../linux-3.14-rc7/signing_key.priv
--- ./signing_key.priv	2014-03-24 20:22:01.946958769 +0900
+++ ../linux-3.14-rc7/signing_key.priv	2014-03-21 17:24:11.874970914 +0900
@@ -1,52 +1,52 @@
 -----BEGIN PRIVATE KEY-----
-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
-NQEgswM/gxjKwcqSioy0WoCqby9/ng==
+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
+gUBtt5vx/OQqJtWSut69esv2u9KYjmM=
 -----END PRIVATE KEY-----
Binary files ./signing_key.x509 and ../linux-3.14-rc7/signing_key.x509 differ


^ permalink raw reply

* Re: [PATCH] Add VID/PID for HID-type Multi-Touch Module of AFO CO., LTD.
From: Jiri Kosina @ 2014-03-25 10:59 UTC (permalink / raw)
  To: YongHwan Ki; +Cc: rydberg, linux-input, linux-kernel
In-Reply-To: <006101cf4812$c3ac1680$4b044380$@afoi.co.kr>

On Tue, 25 Mar 2014, YongHwan Ki wrote:

> There is no way to support the hid-type AFO multi touch modules.

Could you please elaborate? What tree is this patch against? I don't have 
AFO-related defines in my tree.

> Add the VID/PID of AFO to the hid-related lists.
> 
> Kernel Version : linux-3.14.rc7
> 
> Signed-off-by: Yonghwan Ki <kyhw@afoi.co.kr>
> 
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-core.c ../linux-3.14-rc7/drivers/hid/hid-core.c
> --- ./drivers/hid/hid-core.c	2014-03-21 17:41:51.846939444 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-core.c	2014-03-17 10:51:24.000000000 +0900
> @@ -1881,8 +1881,6 @@ static const struct hid_device_id hid_ha
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_TCM) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_THM) },
>  
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-ids.h ../linux-3.14-rc7/drivers/hid/hid-ids.h
> --- ./drivers/hid/hid-ids.h	2014-03-21 17:30:34.478959555 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-ids.h	2014-03-17 10:51:24.000000000 +0900
> @@ -960,9 +960,5 @@
>  #define USB_VENDOR_ID_PRIMAX	0x0461
>  #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05
>  
> -#define USB_VENDOR_ID_AFO		0x2576
> -#define USB_DEVICE_ID_AFO_TCM		0x0003
> -#define USB_DEVICE_ID_AFO_BL		0x0005
> -#define USB_DEVICE_ID_AFO_THM		0x0011
>  
>  #endif
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-multitouch.c ../linux-3.14-rc7/drivers/hid/hid-multitouch.c
> --- ./drivers/hid/hid-multitouch.c	2014-03-21 17:45:25.946933088 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-multitouch.c	2014-03-17 10:51:24.000000000 +0900
> @@ -1395,15 +1395,6 @@ static const struct hid_device_id mt_dev
>  	{  .driver_data = MT_CLS_WIN_8,
>  		HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
>  			HID_ANY_ID, HID_ANY_ID) },
> -
> -	/* AFO MultiTouch device */
> -	{  .driver_data = MT_CLS_SERIAL,
> -		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
> -			USB_DEVICE_ID_AFO_TCM) },
> -	{  .driver_data = MT_CLS_SERIAL,
> -		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
> -			USB_DEVICE_ID_AFO_THM) },
> -
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(hid, mt_devices);
> Binary files ./kernel/x509_certificate_list and ../linux-3.14-rc7/kernel/x509_certificate_list differ
> diff -uprN -X Documentation/dontdiff ./lib/oid_registry_data.c ../linux-3.14-rc7/lib/oid_registry_data.c
> --- ./lib/oid_registry_data.c	2014-03-24 21:43:59.826812763 +0900
> +++ ../linux-3.14-rc7/lib/oid_registry_data.c	2014-03-21 18:45:37.598825862 +0900
> @@ -1,5 +1,5 @@
>  /*
> - * Automatically generated by /usr/src/linux-3.14-rc7m/lib/build_OID_registry.  Do not edit
> + * Automatically generated by /usr/src/linux-3.14-rc7/lib/build_OID_registry.  Do not edit
>   */
>  
>  static const unsigned short oid_index[OID__NR + 1] = {
> diff -uprN -X Documentation/dontdiff ./signing_key.priv ../linux-3.14-rc7/signing_key.priv
> --- ./signing_key.priv	2014-03-24 20:22:01.946958769 +0900
> +++ ../linux-3.14-rc7/signing_key.priv	2014-03-21 17:24:11.874970914 +0900
> @@ -1,52 +1,52 @@
>  -----BEGIN PRIVATE KEY-----

I doubt this was intended.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH] HID: hid-sensor-hub: fix sleeping function called from invalid context
From: Jiri Kosina @ 2014-03-25 12:11 UTC (permalink / raw)
  To: Srinivas Pandruvada; +Cc: linux-input
In-Reply-To: <1395703504-3945-1-git-send-email-srinivas.pandruvada@linux.intel.com>

On Mon, 24 Mar 2014, Srinivas Pandruvada wrote:

> Fix issue with the sleeping calling hid_hw_request under spinlock.
> When i2c is used as HID transport, this is calling kmalloc, which
> can sleep. So remove call to this function while under spinlock.
>  [ 1067.021961] Call Trace:
>  [ 1067.021970]  [<ffffffff8192f5f2>] dump_stack+0x4d/0x6f
>  [ 1067.021976]  [<ffffffff811109f2>] __might_sleep+0xd2/0xf0
>  [ 1067.021981]  [<ffffffff811ea15b>] __kmalloc+0xeb/0x200
>  [ 1067.021989]  [<ffffffff816e0cb3>] ? hid_alloc_report_buf+0x23/0x30
>  [ 1067.021993]  [<ffffffff816e0cb3>] hid_alloc_report_buf+0x23/0x30
>  [ 1067.021997]  [<ffffffff816f4cb7>] i2c_hid_request+0x57/0x110
>  [ 1067.022006]  [<ffffffffa02bc61c>] sensor_hub_input_attr_get_raw_value+0xbc/0x100 [hid_sensor_hub]

Applied, thanks.

-- 
Jiri Kosina
SUSE Labs

^ permalink raw reply

* Re: [PATCH 2/3] Input: synaptics-rmi4 - ability disable abs or rel reporting
From: Andrew Duggan @ 2014-03-25 20:45 UTC (permalink / raw)
  To: Benjamin Tissoires, Christopher Heiny, Dmitry Torokhov
  Cc: Linux Input, Vincent Huang, Vivian Ly, Daniel Rosenberg,
	Linus Walleij, David Herrmann, Jiri Kosina
In-Reply-To: <5329B17C.8080202@redhat.com>

Hi Benjamin,

Thanks for reviewing our patches. We are putting together a v2 set based 
on your comments. Everything looks straight forward, I just have one 
comment in line.

On 03/19/2014 08:02 AM, Benjamin Tissoires wrote:
>
>
> On 03/18/2014 09:03 PM, Christopher Heiny wrote:
>> Even if the RMI4 touchscreen/touchpad provides reporting both
>> relative and absolute coordinates, reporting both to userspace
>> could be confusing. Allow the platform data to disable either
>> absolute or relative coordinates.
>
> General comments on the patch:
> Is there really a need to export the rel axis when there is already an 
> abs collection?
> I mean, with the RMI4 over HID over I2C found on the XPS Haswell 
> series, RMI4 will be bound automatically, and the sensor may (will) 
> pretend that it can do both abs and rel. However, we are not using a 
> platform_data for them (I think we should not), and we will get the 
> two collections.
>
> I would personally be in favor of having a priority mechanism: if abs 
> is here, skip rel, otherwise use rel. But I have no clue if you will 
> ship devices which will require both. So you make the call.
>
>>
>> Signed-off-by: Andrew Duggan <aduggan@synaptics.com>
>> Acked-by: Christopher Heiny <cheiny@synaptics.com>
>> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>
>> Cc: Benjamin Tissoires <benjamin.tissoires@redhat.com>
>> Cc: Linux Walleij <linus.walleij@linaro.org>
>> Cc: David Herrmann <dh.herrmann@gmail.com>
>> Cc: Jiri Kosina <jkosina@suse.cz>
>>
>> ---
>>   drivers/input/rmi4/rmi_f11.c | 78 
>> +++++++++++++++++++++++++++++++++++++-------
>>   include/linux/rmi.h          |  6 ++++
>>   2 files changed, 73 insertions(+), 11 deletions(-)
>>
>> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
>> index 07044d79..c87c6cc3 100644
>> --- a/drivers/input/rmi4/rmi_f11.c
>> +++ b/drivers/input/rmi4/rmi_f11.c
>> @@ -520,6 +520,8 @@ struct f11_2d_sensor {
>>       struct rmi_function *fn;
>>       char input_phys[NAME_BUFFER_SIZE];
>>       char input_phys_mouse[NAME_BUFFER_SIZE];
>> +    u8 report_abs;
>> +    u8 report_rel;
>>   };
>>
>>   /** Data pertaining to F11 in general.  For per-sensor data, see 
>> struct
>> @@ -544,6 +546,10 @@ struct f11_data {
>>       struct mutex dev_controls_mutex;
>>       u16 rezero_wait_ms;
>>       struct f11_2d_sensor sensor;
>> +    unsigned long *abs_mask;
>> +    unsigned long *rel_mask;
>> +    unsigned long *result_bits;
>> +    unsigned long mask_memory[];
>>   };
>>
>>   enum finger_state_values {
>> @@ -591,10 +597,14 @@ static void rmi_f11_rel_pos_report(struct 
>> f11_2d_sensor *sensor, u8 n_finger)
>>       if (x || y) {
>>           input_report_rel(sensor->input, REL_X, x);
>>           input_report_rel(sensor->input, REL_Y, y);
>> -        input_report_rel(sensor->mouse_input, REL_X, x);
>> -        input_report_rel(sensor->mouse_input, REL_Y, y);
>> +
>> +        if (sensor->mouse_input) {
>> +            input_report_rel(sensor->mouse_input, REL_X, x);
>> +            input_report_rel(sensor->mouse_input, REL_Y, y);
>> +        }
>>       }
>> -    input_sync(sensor->mouse_input);
>> +    if (sensor->mouse_input)
>> +        input_sync(sensor->mouse_input);
>>   }
>>
>>   static void rmi_f11_abs_pos_report(struct f11_data *f11,
>> @@ -694,13 +704,17 @@ static void rmi_f11_abs_pos_report(struct 
>> f11_data *f11,
>>   }
>>
>>   static void rmi_f11_finger_handler(struct f11_data *f11,
>> -                   struct f11_2d_sensor *sensor)
>> +                   struct f11_2d_sensor *sensor,
>> +                   unsigned long *irq_bits, int num_irq_regs)
>>   {
>>       const u8 *f_state = sensor->data.f_state;
>>       u8 finger_state;
>>       u8 finger_pressed_count;
>>       u8 i;
>>
>> +    int rel_bits;
>> +    int abs_bits;
>> +
>>       for (i = 0, finger_pressed_count = 0; i < sensor->nbr_fingers; 
>> i++) {
>>           /* Possible of having 4 fingers per f_statet register */
>>           finger_state = (f_state[i / 4] >> (2 * (i % 4))) &
>> @@ -714,13 +728,19 @@ static void rmi_f11_finger_handler(struct 
>> f11_data *f11,
>>               finger_pressed_count++;
>>           }
>>
>> -        if (sensor->data.abs_pos)
>> +        abs_bits = bitmap_and(f11->result_bits, irq_bits, 
>> f11->abs_mask,
>> +                num_irq_regs);
>> +        if (abs_bits)
>>               rmi_f11_abs_pos_report(f11, sensor, finger_state, i);
>
> rmi_driver.c uses bitmap_and this way:
> bitmap_and(data->fn_irq_bits, data->irq_status, fn->irq_mask, 
> data->irq_count);
> if (!bitmap_empty(data->fn_irq_bits, data->irq_count))
>     fh->attention(fn, data->fn_irq_bits);
>
> Not sure which way is the best.
Looks like based on commit f4b0373b26567cafd421d91101852ed7a34e9e94 the 
call to bitmap_empty is redundant so I am going to leave it the way it 
is. We should clean up rmi_driver.c in a future patch.
>
>>
>> -        if (sensor->data.rel_pos)
>> +        rel_bits = bitmap_and(f11->result_bits, irq_bits, 
>> f11->rel_mask,
>> +                num_irq_regs);
>> +        if (rel_bits)
>>               rmi_f11_rel_pos_report(sensor, i);
>>       }
>> +
>>       input_report_key(sensor->input, BTN_TOUCH, finger_pressed_count);
>> +
>
> those two blank lines are unrelated to the commit.
>
>>       input_sync(sensor->input);
>>   }
>>
>> @@ -1180,21 +1200,33 @@ static int rmi_f11_initialize(struct 
>> rmi_function *fn)
>>       u16 max_x_pos, max_y_pos, temp;
>>       int rc;
>>       const struct rmi_device_platform_data *pdata = 
>> rmi_get_platform_data(rmi_dev);
>> +    struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
>>       struct f11_2d_sensor *sensor;
>>       u8 buf;
>> +    int mask_size;
>>
>>       dev_dbg(&fn->dev, "Initializing F11 values for %s.\n",
>>            pdata->sensor_name);
>>
>> +    mask_size = BITS_TO_LONGS(drvdata->irq_count) * sizeof(unsigned 
>> long);
>> +
>>       /*
>>       ** init instance data, fill in values and create any sysfs files
>>       */
>> -    f11 = devm_kzalloc(&fn->dev, sizeof(struct f11_data), GFP_KERNEL);
>> +    f11 = devm_kzalloc(&fn->dev, sizeof(struct f11_data) + mask_size 
>> * 3,
>> +            GFP_KERNEL);
>>       if (!f11)
>>           return -ENOMEM;
>>
>>       f11->rezero_wait_ms = pdata->f11_rezero_wait;
>>
>> +    f11->abs_mask = f11->mask_memory + mask_size * 0;
>
> I personally don't like the " + mask_size * 0"
>
> Can't you just also remove the mask_memory field and use sizeof(struct 
> f11_data)?
>
>> +    f11->rel_mask = f11->mask_memory + mask_size * 1;
>> +    f11->result_bits = f11->mask_memory + mask_size * 2;
>> +
>> +    set_bit(fn->irq_pos, f11->abs_mask);
>> +    set_bit(fn->irq_pos + 1, f11->rel_mask);
>> +
>>       query_base_addr = fn->fd.query_base_addr;
>>       control_base_addr = fn->fd.control_base_addr;
>>
>> @@ -1226,12 +1258,25 @@ static int rmi_f11_initialize(struct 
>> rmi_function *fn)
>>           return rc;
>>       }
>>
>> +    sensor->report_rel = sensor->sens_query.has_rel;
>> +    sensor->report_abs = sensor->sens_query.has_abs;
>> +
>>       if (pdata->f11_sensor_data) {
>>           sensor->axis_align =
>>               pdata->f11_sensor_data->axis_align;
>>           sensor->type_a = pdata->f11_sensor_data->type_a;
>>           sensor->sensor_type =
>>                   pdata->f11_sensor_data->sensor_type;
>> +
>> +        if (sensor->sens_query.has_abs)
>> +            sensor->report_abs = sensor->report_abs
>> +                && !(pdata->f11_sensor_data->disable_report_mask
>> +                    & RMI_F11_DISABLE_ABS_REPORT);
>
> sensor->report_abs already contains sensor->sens_query.has_abs (set 
> few lines above)...
>
> so you can just skip the if test here.
>
>
>> +
>> +        if (sensor->sens_query.has_rel)
>> +            sensor->report_rel = sensor->report_rel
>> +                && !(pdata->f11_sensor_data->disable_report_mask
>> +                    & RMI_F11_DISABLE_REL_REPORT);
>
> same here.
>
>>       }
>>
>>       rc = rmi_read_block(rmi_dev,
>> @@ -1324,9 +1369,10 @@ static int rmi_f11_register_devices(struct 
>> rmi_function *fn)
>>       set_bit(EV_ABS, input_dev->evbit);
>>       input_set_capability(input_dev, EV_KEY, BTN_TOUCH);
>>
>> -    f11_set_abs_params(fn, f11);
>> +    if (sensor->report_abs)
>> +        f11_set_abs_params(fn, f11);
>>
>> -    if (sensor->sens_query.has_rel) {
>> +    if (sensor->report_rel) {
>>           set_bit(EV_REL, input_dev->evbit);
>>           set_bit(REL_X, input_dev->relbit);
>>           set_bit(REL_Y, input_dev->relbit);
>> @@ -1338,7 +1384,7 @@ static int rmi_f11_register_devices(struct 
>> rmi_function *fn)
>>           goto error_unregister;
>>       }
>>
>> -    if (sensor->sens_query.has_rel) {
>> +    if (sensor->report_rel) {
>>           /*create input device for mouse events  */
>>           input_dev_mouse = input_allocate_device();
>>           if (!input_dev_mouse) {
>> @@ -1407,8 +1453,16 @@ error_unregister:
>>   static int rmi_f11_config(struct rmi_function *fn)
>>   {
>>       struct f11_data *f11 = dev_get_drvdata(&fn->dev);
>> +    struct rmi_driver *drv = fn->rmi_dev->driver;
>> +    struct f11_2d_sensor *sensor = &f11->sensor;
>>       int rc;
>>
>> +    if (!sensor->report_abs)
>> +        drv->clear_irq_bits(fn->rmi_dev, f11->abs_mask);
>> +
>> +    if (!sensor->report_rel)
>> +        drv->clear_irq_bits(fn->rmi_dev, f11->rel_mask);
>> +
>>       rc = f11_write_control_regs(fn, &f11->sensor.sens_query,
>>                  &f11->dev_controls, fn->fd.query_base_addr);
>>       if (rc < 0)
>> @@ -1420,6 +1474,7 @@ static int rmi_f11_config(struct rmi_function *fn)
>>   static int rmi_f11_attention(struct rmi_function *fn, unsigned long 
>> *irq_bits)
>>   {
>>       struct rmi_device *rmi_dev = fn->rmi_dev;
>> +    struct rmi_driver_data *drvdata = dev_get_drvdata(&rmi_dev->dev);
>>       struct f11_data *f11 = dev_get_drvdata(&fn->dev);
>>       u16 data_base_addr = fn->fd.data_base_addr;
>>       u16 data_base_addr_offset = 0;
>> @@ -1432,7 +1487,8 @@ static int rmi_f11_attention(struct 
>> rmi_function *fn, unsigned long *irq_bits)
>>       if (error)
>>           return error;
>>
>> -    rmi_f11_finger_handler(f11, &f11->sensor);
>> +    rmi_f11_finger_handler(f11, &f11->sensor, irq_bits,
>> +                drvdata->num_of_irq_regs);
>>       data_base_addr_offset += f11->sensor.pkt_size;
>>
>>       return 0;
>> diff --git a/include/linux/rmi.h b/include/linux/rmi.h
>> index 735e978..a0d0187 100644
>> --- a/include/linux/rmi.h
>> +++ b/include/linux/rmi.h
>> @@ -76,6 +76,9 @@ enum rmi_f11_sensor_type {
>>       rmi_f11_sensor_touchpad
>>   };
>>
>> +#define RMI_F11_DISABLE_ABS_REPORT      (1 << 0)
>> +#define RMI_F11_DISABLE_REL_REPORT      (1 << 1)
>
> We have BIT() macro in the kernel for this (I know, I do not use it 
> that much either... :-P )
>
> Cheers,
> Benjamin
>
>> +
>>   /**
>>    * struct rmi_f11_sensor_data - overrides defaults for a single F11 
>> 2D sensor.
>>    * @axis_align - provides axis alignment overrides (see above).
>> @@ -86,11 +89,14 @@ enum rmi_f11_sensor_type {
>>    * pointing device (touchpad) rather than a direct pointing device
>>    * (touchscreen).  This is useful when F11_2D_QUERY14 register is not
>>    * available.
>> + * @disable_report_mask - Force data to not be reported even if it 
>> is supported
>> + * by the firware.
>>    */
>>   struct rmi_f11_sensor_data {
>>       struct rmi_f11_2d_axis_alignment axis_align;
>>       bool type_a;
>>       enum rmi_f11_sensor_type sensor_type;
>> +    int disable_report_mask;
>>   };
>>
>>   /**
>>
Andrew

^ permalink raw reply

* [PATCH] hid: Add custom driver for Lenovo ThinkPad Compact Bluetooth Keyboard
From: Jamie Lentin @ 2014-03-25 22:26 UTC (permalink / raw)
  To: Jiri Kosina; +Cc: linux-input, linux-kernel, Jamie Lentin

This keyboard requires some custom mappings for all keys to be
available, and the Fn-lock toggle needs to be controlled in software.

Signed-off-by: Jamie Lentin <jm@lentin.co.uk>
---
I assume that Linux users want Fn-Lock enabled by default, so they can
get at the function keys. If this is an incorrect assumption then can
change it---so long as there's some way of me leaving it enabled :)

Tested with and applies cleanly to 3.13.6.

 drivers/hid/Kconfig                   |  10 ++
 drivers/hid/Makefile                  |   1 +
 drivers/hid/hid-core.c                |   3 +
 drivers/hid/hid-ids.h                 |   1 +
 drivers/hid/hid-lenovo-tpcompactkbd.c | 191 ++++++++++++++++++++++++++++++++++
 5 files changed, 206 insertions(+)
 create mode 100644 drivers/hid/hid-lenovo-tpcompactkbd.c

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 34e2d39..8e45413 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -335,6 +335,16 @@ config HID_LENOVO_TPKBD
 	sensitivity of the trackpoint, using the microphone mute button or
 	controlling the mute and microphone mute LEDs.
 
+config HID_LENOVO_CBTKBD
+	tristate "Lenovo ThinkPad Compact Bluetooth Keyboard with TrackPoint"
+	depends on HID
+	---help---
+	Support for the Lenovo ThinkPad Compact Bluetooth Keyboard with TrackPoint.
+
+	Say Y here if you have a Lenovo ThinkPad Compact Bluetooth Keyboard with
+	TrackPoint and would like to use the function keys as function keys, as
+	well as letting linux recognise the special functions such as brightness.
+
 config HID_LOGITECH
 	tristate "Logitech devices" if EXPERT
 	depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index 30e4431..c0a2f89 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -59,6 +59,7 @@ obj-$(CONFIG_HID_KEYTOUCH)	+= hid-keytouch.o
 obj-$(CONFIG_HID_KYE)		+= hid-kye.o
 obj-$(CONFIG_HID_LCPOWER)       += hid-lcpower.o
 obj-$(CONFIG_HID_LENOVO_TPKBD)	+= hid-lenovo-tpkbd.o
+obj-$(CONFIG_HID_LENOVO_CBTKBD)	+= hid-lenovo-tpcompactkbd.o
 obj-$(CONFIG_HID_LOGITECH)	+= hid-logitech.o
 obj-$(CONFIG_HID_LOGITECH_DJ)	+= hid-logitech-dj.o
 obj-$(CONFIG_HID_MAGICMOUSE)    += hid-magicmouse.o
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 253fe23..77bce8f 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1734,6 +1734,9 @@ static const struct hid_device_id hid_have_special_driver[] = {
 #if IS_ENABLED(CONFIG_HID_LENOVO_TPKBD)
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
 #endif
+#if IS_ENABLED(CONFIG_HID_LENOVO_CBTKBD)
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
+#endif
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index f9304cb..6802166 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -539,6 +539,7 @@
 
 #define USB_VENDOR_ID_LENOVO		0x17ef
 #define USB_DEVICE_ID_LENOVO_TPKBD	0x6009
+#define USB_DEVICE_ID_LENOVO_CBTKBD	0x6048
 
 #define USB_VENDOR_ID_LG		0x1fd2
 #define USB_DEVICE_ID_LG_MULTITOUCH	0x0064
diff --git a/drivers/hid/hid-lenovo-tpcompactkbd.c b/drivers/hid/hid-lenovo-tpcompactkbd.c
new file mode 100644
index 0000000..0fd085b
--- /dev/null
+++ b/drivers/hid/hid-lenovo-tpcompactkbd.c
@@ -0,0 +1,191 @@
+/*
+ *  ThinkPad Compact (Bluetooth|USB) Keyboard with TrackPoint
+ *
+ *  Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
+ *
+ */
+
+/*
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static unsigned int fnmode;
+module_param(fnmode, uint, 0644);
+MODULE_PARM_DESC(fnmode, "Fn lock mode ([0] = normal (Fn Lock toggles), 1 = Permanently on, 2 = Permanently off)");
+
+struct tpcompactkbd_sc {
+	unsigned int fn_lock;
+};
+
+/* Send a config command to the keyboard */
+static int tpcompactkbd_send_cmd(struct hid_device *hdev,
+			unsigned char byte2, unsigned char byte3)
+{
+	unsigned char buf[] = {0x18, byte2, byte3};
+
+	return hdev->hid_output_raw_report(hdev, buf, sizeof(buf),
+						HID_OUTPUT_REPORT);
+}
+
+/* Toggle fnlock on or off, if fnmode allows */
+static void tpcompactkbd_toggle_fnlock(struct hid_device *hdev)
+{
+	struct tpcompactkbd_sc *tpcsc = hid_get_drvdata(hdev);
+
+	tpcsc->fn_lock = fnmode == 2 ? 0 : fnmode == 1 ? 1 : !tpcsc->fn_lock;
+	if (tpcompactkbd_send_cmd(hdev, 0x05, tpcsc->fn_lock ? 0x01 : 0x00))
+		hid_err(hdev, "Fn-lock toggle failed\n");
+}
+
+/*
+ * Keyboard sends non-standard reports for most "hotkey" Fn functions.
+ * Map these back to regular keys.
+ *
+ * Esc:	KEY_FN_ESC		FnLock
+ * (F1--F3 are regular keys)
+ * F4:	KEY_MICMUTE		Mic Mute
+ * F5:	KEY_BRIGHTNESSDOWN	Brightness down
+ * F6:	KEY_BRIGHTNESSUP	Brightness up
+ * F7:	KEY_SWITCHVIDEOMODE	External display (projector)
+ * F8:	KEY_FN_F8		Wireless
+ * F9:	KEY_CONFIG		Control panel / settings
+ * F10:	KEY_SEARCH		Search
+ * F11:	KEY_FN_F11		View open applications (3 boxes)
+ * F12:	KEY_FN_F12		Open My computer (6 boxes)
+ */
+
+#define tpckbd_map_key_clear(c)	hid_map_usage_clear(hi, usage, bit, max, \
+					EV_KEY, (c))
+static int tpcompactkbd_input_mapping(struct hid_device *hdev,
+		struct hid_input *hi, struct hid_field *field,
+		struct hid_usage *usage, unsigned long **bit, int *max)
+{
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
+		set_bit(EV_REP, hi->input->evbit);
+		switch (usage->hid & HID_USAGE) {
+		case 0x03f1:
+			tpckbd_map_key_clear(KEY_FN_F8);
+			return 1;
+		case 0x0221:
+			tpckbd_map_key_clear(KEY_SEARCH);
+			return 1;
+		case 0x03f2:
+			tpckbd_map_key_clear(KEY_FN_F12);
+			return 1;
+		}
+	}
+
+	if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
+		set_bit(EV_REP, hi->input->evbit);
+		switch (usage->hid & HID_USAGE) {
+		case 0x00f0:
+			tpckbd_map_key_clear(KEY_FN_ESC);
+			return 1;
+		case 0x00f1:
+			tpckbd_map_key_clear(KEY_MICMUTE);
+			return 1;
+		case 0x00f2:
+			tpckbd_map_key_clear(KEY_BRIGHTNESSDOWN);
+			return 1;
+		case 0x00f3:
+			tpckbd_map_key_clear(KEY_BRIGHTNESSUP);
+			return 1;
+		case 0x00f4:
+			tpckbd_map_key_clear(KEY_SWITCHVIDEOMODE);
+			return 1;
+		case 0x00f5:
+			tpckbd_map_key_clear(KEY_FN_F8);
+			return 1;
+		case 0x00f6:
+			tpckbd_map_key_clear(KEY_CONFIG);
+			return 1;
+		case 0x00f8:
+			tpckbd_map_key_clear(KEY_FN_F11);
+			return 1;
+		case 0x00fa:
+			tpckbd_map_key_clear(KEY_FN_ESC);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static int tpcompactkbd_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	/* Switch fn-lock on fn-esc */
+	if (unlikely(usage->code == KEY_FN_ESC && value))
+		tpcompactkbd_toggle_fnlock(hdev);
+
+	return 0;
+}
+
+static int tpcompactkbd_probe(struct hid_device *hdev,
+			const struct hid_device_id *id)
+{
+	int ret;
+	struct tpcompactkbd_sc *tpcsc;
+
+	tpcsc = devm_kzalloc(&hdev->dev, sizeof(*tpcsc), GFP_KERNEL);
+	if (tpcsc == NULL) {
+		hid_err(hdev, "can't alloc keyboard descriptor\n");
+		return -ENOMEM;
+	}
+	hid_set_drvdata(hdev, tpcsc);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "hid_parse failed\n");
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hid_hw_start failed\n");
+		return ret;
+	}
+
+	/*
+	 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
+	 * regular keys
+	 */
+	ret = tpcompactkbd_send_cmd(hdev, 0x01, 0x03);
+	if (ret)
+		hid_warn(hdev, "Failed to switch F7/9/11 into regular keys\n");
+
+	/* Toggle once to init the state of fn-lock */
+	tpcsc->fn_lock = 0;
+	tpcompactkbd_toggle_fnlock(hdev);
+
+	return 0;
+}
+
+static const struct hid_device_id tpcompactkbd_devices[] = {
+	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
+
+	{ }
+};
+MODULE_DEVICE_TABLE(hid, tpcompactkbd_devices);
+
+static struct hid_driver tpcompactkbd_driver = {
+	.name = "lenovo_tpcompactkbd",
+	.id_table = tpcompactkbd_devices,
+	.input_mapping = tpcompactkbd_input_mapping,
+	.probe = tpcompactkbd_probe,
+	.event = tpcompactkbd_event,
+};
+module_hid_driver(tpcompactkbd_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jamie Lentin <jm@lentin.co.uk>");
+MODULE_DESCRIPTION("ThinkPad Compact Keyboard with TrackPoint input driver");
-- 
1.8.5.2


^ permalink raw reply related

* RE: [PATCH] Add VID/PID for HID-type Multi-Touch Module of AFO CO.,  LTD.
From: YongHwan Ki @ 2014-03-26  0:45 UTC (permalink / raw)
  To: 'Jiri Kosina'; +Cc: rydberg, linux-input, linux-kernel
In-Reply-To: <alpine.LNX.2.00.1403251156260.17500@pobox.suse.cz>

Sorry, I woud like to add the AFO defines in the Linux Kernel.
No afo defines exists in the current kernel tree.
I correctly changed the log for adding the afo defines.

Kernel Version : linux-3.14.rc7
Signed-off-by: Yonghwan Ki <kyhw@afoi.co.kr>

diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-core.c ../linux-3.14-rc7m/drivers/hid/hid-core.c
--- ./drivers/hid/hid-core.c	2014-03-17 10:51:24.000000000 +0900
+++ ../linux-3.14-rc7m/drivers/hid/hid-core.c	2014-03-21 17:41:51.846939444 +0900
@@ -1881,6 +1881,8 @@ static const struct hid_device_id hid_ha
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_TCM) },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_THM) },
 
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-ids.h ../linux-3.14-rc7m/drivers/hid/hid-ids.h
--- ./drivers/hid/hid-ids.h	2014-03-17 10:51:24.000000000 +0900
+++ ../linux-3.14-rc7m/drivers/hid/hid-ids.h	2014-03-21 17:30:34.478959555 +0900
@@ -960,5 +960,9 @@
 #define USB_VENDOR_ID_PRIMAX	0x0461
 #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05
 
+#define USB_VENDOR_ID_AFO		0x2576
+#define USB_DEVICE_ID_AFO_TCM		0x0003
+#define USB_DEVICE_ID_AFO_BL		0x0005
+#define USB_DEVICE_ID_AFO_THM		0x0011
 
 #endif
diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-multitouch.c ../linux-3.14-rc7m/drivers/hid/hid-multitouch.c
--- ./drivers/hid/hid-multitouch.c	2014-03-17 10:51:24.000000000 +0900
+++ ../linux-3.14-rc7m/drivers/hid/hid-multitouch.c	2014-03-21 17:45:25.946933088 +0900
@@ -1395,6 +1395,15 @@ static const struct hid_device_id mt_dev
 	{  .driver_data = MT_CLS_WIN_8,
 		HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
 			HID_ANY_ID, HID_ANY_ID) },
+
+	/* AFO MultiTouch device */
+	{  .driver_data = MT_CLS_SERIAL,
+		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
+			USB_DEVICE_ID_AFO_TCM) },
+	{  .driver_data = MT_CLS_SERIAL,
+		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
+			USB_DEVICE_ID_AFO_THM) },
+
 	{ }
 };
 MODULE_DEVICE_TABLE(hid, mt_devices);
Binary files ./kernel/x509_certificate_list and ../linux-3.14-rc7m/kernel/x509_certificate_list differ
diff -uprN -X Documentation/dontdiff ./lib/oid_registry_data.c ../linux-3.14-rc7m/lib/oid_registry_data.c
--- ./lib/oid_registry_data.c	2014-03-21 18:45:37.598825862 +0900
+++ ../linux-3.14-rc7m/lib/oid_registry_data.c	2014-03-24 21:43:59.826812763 +0900
@@ -1,5 +1,5 @@
 /*
- * Automatically generated by /usr/src/linux-3.14-rc7/lib/build_OID_registry.  Do not edit
+ * Automatically generated by /usr/src/linux-3.14-rc7m/lib/build_OID_registry.  Do not edit
  */
 
 static const unsigned short oid_index[OID__NR + 1] = {
diff -uprN -X Documentation/dontdiff ./signing_key.priv ../linux-3.14-rc7m/signing_key.priv
--- ./signing_key.priv	2014-03-21 17:24:11.874970914 +0900
+++ ../linux-3.14-rc7m/signing_key.priv	2014-03-24 20:22:01.946958769 +0900
@@ -1,52 +1,52 @@
 -----BEGIN PRIVATE KEY-----
-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
-gUBtt5vx/OQqJtWSut69esv2u9KYjmM=
+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
+NQEgswM/gxjKwcqSioy0WoCqby9/ng==
 -----END PRIVATE KEY-----
Binary files ./signing_key.x509 and ../linux-3.14-rc7m/signing_key.x509 differ

-----Original Message-----
From: linux-kernel-owner@vger.kernel.org [mailto:linux-kernel-owner@vger.kernel.org] On Behalf Of Jiri Kosina
Sent: Tuesday, March 25, 2014 8:00 PM
To: YongHwan Ki
Cc: rydberg@euromail.se; linux-input@vger.kernel.org; linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Add VID/PID for HID-type Multi-Touch Module of AFO CO., LTD.

On Tue, 25 Mar 2014, YongHwan Ki wrote:

> There is no way to support the hid-type AFO multi touch modules.

Could you please elaborate? What tree is this patch against? I don't have 
AFO-related defines in my tree.

> Add the VID/PID of AFO to the hid-related lists.
> 
> Kernel Version : linux-3.14.rc7
> 
> Signed-off-by: Yonghwan Ki <kyhw@afoi.co.kr>
> 
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-core.c ../linux-3.14-rc7/drivers/hid/hid-core.c
> --- ./drivers/hid/hid-core.c	2014-03-21 17:41:51.846939444 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-core.c	2014-03-17 10:51:24.000000000 +0900
> @@ -1881,8 +1881,6 @@ static const struct hid_device_id hid_ha
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
>  	{ HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_TCM) },
> -	{ HID_USB_DEVICE(USB_VENDOR_ID_AFO, USB_DEVICE_ID_AFO_THM) },
>  
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
>  	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-ids.h ../linux-3.14-rc7/drivers/hid/hid-ids.h
> --- ./drivers/hid/hid-ids.h	2014-03-21 17:30:34.478959555 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-ids.h	2014-03-17 10:51:24.000000000 +0900
> @@ -960,9 +960,5 @@
>  #define USB_VENDOR_ID_PRIMAX	0x0461
>  #define USB_DEVICE_ID_PRIMAX_KEYBOARD	0x4e05
>  
> -#define USB_VENDOR_ID_AFO		0x2576
> -#define USB_DEVICE_ID_AFO_TCM		0x0003
> -#define USB_DEVICE_ID_AFO_BL		0x0005
> -#define USB_DEVICE_ID_AFO_THM		0x0011
>  
>  #endif
> diff -uprN -X Documentation/dontdiff ./drivers/hid/hid-multitouch.c ../linux-3.14-rc7/drivers/hid/hid-multitouch.c
> --- ./drivers/hid/hid-multitouch.c	2014-03-21 17:45:25.946933088 +0900
> +++ ../linux-3.14-rc7/drivers/hid/hid-multitouch.c	2014-03-17 10:51:24.000000000 +0900
> @@ -1395,15 +1395,6 @@ static const struct hid_device_id mt_dev
>  	{  .driver_data = MT_CLS_WIN_8,
>  		HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH_WIN_8,
>  			HID_ANY_ID, HID_ANY_ID) },
> -
> -	/* AFO MultiTouch device */
> -	{  .driver_data = MT_CLS_SERIAL,
> -		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
> -			USB_DEVICE_ID_AFO_TCM) },
> -	{  .driver_data = MT_CLS_SERIAL,
> -		HID_USB_DEVICE(USB_VENDOR_ID_AFO,
> -			USB_DEVICE_ID_AFO_THM) },
> -
>  	{ }
>  };
>  MODULE_DEVICE_TABLE(hid, mt_devices);
> Binary files ./kernel/x509_certificate_list and ../linux-3.14-rc7/kernel/x509_certificate_list differ
> diff -uprN -X Documentation/dontdiff ./lib/oid_registry_data.c ../linux-3.14-rc7/lib/oid_registry_data.c
> --- ./lib/oid_registry_data.c	2014-03-24 21:43:59.826812763 +0900
> +++ ../linux-3.14-rc7/lib/oid_registry_data.c	2014-03-21 18:45:37.598825862 +0900
> @@ -1,5 +1,5 @@
>  /*
> - * Automatically generated by /usr/src/linux-3.14-rc7m/lib/build_OID_registry.  Do not edit
> + * Automatically generated by /usr/src/linux-3.14-rc7/lib/build_OID_registry.  Do not edit
>   */
>  
>  static const unsigned short oid_index[OID__NR + 1] = {
> diff -uprN -X Documentation/dontdiff ./signing_key.priv ../linux-3.14-rc7/signing_key.priv
> --- ./signing_key.priv	2014-03-24 20:22:01.946958769 +0900
> +++ ../linux-3.14-rc7/signing_key.priv	2014-03-21 17:24:11.874970914 +0900
> @@ -1,52 +1,52 @@
>  -----BEGIN PRIVATE KEY-----

I doubt this was intended.

-- 
Jiri Kosina
SUSE Labs
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/



^ permalink raw reply

* [PATCH] input: misc: Add driver for Intel Bay Trail GPIO buttons
From: Zhu, Lejun @ 2014-03-26  5:01 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: linux-kernel, linux-input, lejun.zhu
In-Reply-To: <533259F7.3050908@linux.intel.com>

This patch adds support for the GPIO buttons on some Intel Bay Trail
tablets originally running Windows 8. The ACPI description of these
buttons follows "Windows ACPI Design Guide for SoC Platforms".

Signed-off-by: Lejun Zhu <lejun.zhu@linux.intel.com>
---
 drivers/input/misc/Kconfig           |  10 ++
 drivers/input/misc/Makefile          |   1 +
 drivers/input/misc/baytrail_button.c | 198
+++++++++++++++++++++++++++++++++++
 3 files changed, 209 insertions(+)
 create mode 100644 drivers/input/misc/baytrail_button.c

diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 7904ab0..bb6fe2e 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -666,4 +666,14 @@ config INPUT_IDEAPAD_SLIDEBAR
 	  To compile this driver as a module, choose M here: the
 	  module will be called ideapad_slidebar.

+config INPUT_BAYTRAIL_BUTTON
+	tristate "Intel Baytrail Buttons"
+	depends on KEYBOARD_GPIO
+	help
+	  Say Y here if you have a Baytrail tablet that is compatible
+	  with Windows ACPI Design Guide.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called baytrail_button.
+
 endif
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index cda71fc..c3d6a68 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -63,3 +63,4 @@ obj-$(CONFIG_INPUT_WM831X_ON)		+= wm831x-on.o
 obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND)	+= xen-kbdfront.o
 obj-$(CONFIG_INPUT_YEALINK)		+= yealink.o
 obj-$(CONFIG_INPUT_IDEAPAD_SLIDEBAR)	+= ideapad_slidebar.o
+obj-$(CONFIG_INPUT_BAYTRAIL_BUTTON)	+= baytrail_button.o
diff --git a/drivers/input/misc/baytrail_button.c
b/drivers/input/misc/baytrail_button.c
new file mode 100644
index 0000000..e4829e1
--- /dev/null
+++ b/drivers/input/misc/baytrail_button.c
@@ -0,0 +1,198 @@
+/*
+ * baytrail_button.c: supports the GPIO buttons on some Baytrail
+ * tablets.
+ *
+ * (C) Copyright 2014 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/gpio_keys.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/pnp.h>
+
+static void byt_button_device_release(struct device *);
+
+/*
+ * Definition of buttons on the tablet. The ACPI index of each button
+ * is defined in "Windows ACPI Design Guide for SoC Platforms"
+ */
+#define	MAX_NBUTTONS	5
+
+struct byt_button_info {
+	const char *name;
+	int acpi_index;
+	unsigned int event_code;
+	int repeat;
+	int wakeup;
+	int gpio;
+};
+
+static struct byt_button_info byt_button_tbl[] = {
+	{"power", 0, KEY_POWER, 0, 1, -1},
+	{"home", 1, KEY_HOME, 0, 1, -1},
+	{"volume_up", 2, KEY_VOLUMEUP, 1, 0, -1},
+	{"volume_down", 3, KEY_VOLUMEDOWN, 1, 0, -1},
+	{"rotation_lock", 4, KEY_RO, 0, 0, -1},
+};
+
+/*
+ * Some of the buttons like volume up/down are auto repeat, while others
+ * are not. To support both, we register two gpio-keys device, and put
+ * buttons into them based on whether the key should be auto repeat.
+ */
+#define	BUTTON_TYPES	2
+
+static struct gpio_keys_button byt_buttons[BUTTON_TYPES][MAX_NBUTTONS];
+
+static struct gpio_keys_platform_data byt_button_data[BUTTON_TYPES] = {
+	{
+		.buttons	= byt_buttons[0],
+		.nbuttons	= 0,
+		.rep		= 0
+	},
+	{
+		.buttons	= byt_buttons[1],
+		.nbuttons	= 0,
+		.rep		= 1
+	}
+};
+
+static struct platform_device byt_button_device[BUTTON_TYPES] = {
+	{
+		.name	= "gpio-keys",
+		.id	= PLATFORM_DEVID_AUTO,
+		.dev	= {
+			.release	= byt_button_device_release,
+			.platform_data	= &byt_button_data[0],
+		}
+	},
+	{
+		.name	= "gpio-keys",
+		.id	= PLATFORM_DEVID_AUTO,
+		.dev	= {
+			.release	= byt_button_device_release,
+			.platform_data	= &byt_button_data[1],
+		}
+	}
+};
+
+/*
+ * Get the Nth GPIO number from the ACPI object.
+ */
+static int byt_button_lookup_gpio(struct device *dev, int acpi_index)
+{
+	struct gpio_desc *desc;
+	int ret;
+
+	desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
+
+	if (IS_ERR(desc))
+		return -1;
+
+	ret = desc_to_gpio(desc);
+
+	gpiod_put(desc);
+
+	return ret;
+}
+
+static int byt_button_pnp_probe(struct pnp_dev *pdev,
+	const struct pnp_device_id *id)
+{
+	int i, j, r, ret;
+	int sz_tbl = sizeof(byt_button_tbl) / sizeof(byt_button_tbl[0]);
+	struct gpio_keys_button *gk;
+
+	/* Find GPIO number of all the buttons */
+	for (i = 0; i < sz_tbl; i++) {
+		byt_button_tbl[i].gpio = byt_button_lookup_gpio(&pdev->dev,
+						byt_button_tbl[i].acpi_index);
+	}
+
+	for (r = 0; r < BUTTON_TYPES; r++) {
+		gk = byt_buttons[r];
+		j = 0;
+
+		/* Register buttons in the correct device */
+		for (i = 0; i < sz_tbl; i++) {
+			if (byt_button_tbl[i].repeat == r &&
+			    byt_button_tbl[i].gpio > 0) {
+				gk[j].code = byt_button_tbl[i].event_code;
+				gk[j].gpio = byt_button_tbl[i].gpio;
+				gk[j].active_low = 1;
+				gk[j].desc = byt_button_tbl[i].name;
+				gk[j].type = EV_KEY;
+				gk[j].wakeup = byt_button_tbl[i].wakeup;
+				j++;
+			}
+		}
+
+		byt_button_data[r].nbuttons = j;
+
+		if (j == 0)
+			continue;
+
+		ret = platform_device_register(&byt_button_device[r]);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to register %d\n", r);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static void byt_button_device_release(struct device *dev)
+{
+	/* Nothing to do */
+}
+
+static void byt_button_remove(struct pnp_dev *pdev)
+{
+	int r;
+
+	for (r = 0; r < BUTTON_TYPES; r++) {
+		if (byt_button_data[r].nbuttons)
+			platform_device_unregister(&byt_button_device[r]);
+	}
+}
+
+static const struct pnp_device_id byt_button_pnp_match[] = {
+	{.id = "INTCFD9", .driver_data = 0},
+	{.id = ""}
+};
+
+MODULE_DEVICE_TABLE(pnp, byt_button_pnp_match);
+
+static struct pnp_driver byt_button_pnp_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= byt_button_pnp_match,
+	.probe          = byt_button_pnp_probe,
+	.remove		= byt_button_remove,
+};
+
+static int __init byt_button_init(void)
+{
+	return pnp_register_driver(&byt_button_pnp_driver);
+}
+
+static void __exit byt_button_exit(void)
+{
+	pnp_unregister_driver(&byt_button_pnp_driver);
+}
+
+module_init(byt_button_init);
+module_exit(byt_button_exit);
+
+MODULE_LICENSE("GPL");
-- 
1.8.3.2






^ permalink raw reply related

* Re: [PATCH] input: add support for ALPS v7 protocol device
From: Václav Krpec @ 2014-03-26 12:20 UTC (permalink / raw)
  To: Qiting Chen
  Cc: dmitry.torokhov, cernekee, dturvene, linux-input, ndevos, jclift,
	Qiting Chen, justin
In-Reply-To: <1395219353-27683-1-git-send-email-qiting.chen@cn.alps.com>

[-- Attachment #1: Type: text/plain, Size: 32531 bytes --]

Hello Qiting,

I've applied your patch and tested the driver on my Toshiba Portege
Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22).

The TP driver works nicely, however, I've observed a few things to note:

1/
There's no support for trackstick; my device has one.
Justin has suggested that it may be a Toshiba mod of the device...
Nevertheless, since I was in process of RA of the device myself before
you've committed the patch, I merged the TS driver to your patch;
see alps_process_trackstick_packet_v7 function + tiny bit of
refactoring of the packet ID resolving mechanism in the patch attached.
I hope it shouldn't break the driver functionality for devices w/o
the trackstick, but testing should definitely be done.

2/
I've noticed that your patch wasn't cleanly applicable to current 3.14
kernel; could you be more specific on what branch should it be applied?
The patch attached is valid for 3.14-rc8 tree.

3/
I also took the liberty of fixing indentation of your code a bit to put
it (hopefully) more in line with the conventions of the alps.[ch]

So, could you (or anyone else) test the patch attached?
Comments, recommendations etc welcome.

Thanks,

Best regards

vencik



On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote:
> Here is a patch of supporting ALPS v7 protocol device.
> ALPS v7 protocol device is a clickpad that is currently used on
> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1,
> as well as other machines with ALPS Touchpad of following infomation:
> 	Device ID = 0x73, 0x03, 0x0a
> 	Firmware ID = 0x88, 0xb*, 0x**
> 
> A v7 protocol support patch is first relesed 2 months ago:
> http://www.spinics.net/lists/linux-input/msg29084.html
> After that some feedbacks were received from end user. Now this patch fixed the bugs
> reported by them:
> 1) Fix cursor jump when doing a right click drag
> 2) Fix cursor jitter when button clicking
> 
> Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> ---
>  drivers/input/mouse/alps.c | 560 ++++++++++++++++++++++++++++++++++++++++++---
>  drivers/input/mouse/alps.h | 132 +++++++++--
>  2 files changed, 641 insertions(+), 51 deletions(-)
> 
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index fb15c64..383281f 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -32,6 +32,13 @@
>  #define ALPS_REG_BASE_RUSHMORE	0xc2c0
>  #define ALPS_REG_BASE_PINNACLE	0x0000
>  
> +#define LEFT_BUTTON_BIT			0x01
> +#define RIGHT_BUTTON_BIT		0x02
> +
> +#define V7_LARGE_MOVEMENT		130
> +#define V7_DEAD_ZONE_OFFSET_X	72
> +#define V7_DEAD_ZONE_OFFSET_Y	72
> +
>  static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>  	{ PSMOUSE_CMD_SETPOLL,		0x00 }, /* 0 */
>  	{ PSMOUSE_CMD_RESET_DIS,	0x00 }, /* 1 */
> @@ -99,6 +106,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
>  #define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
>  #define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
>  					   6-byte ALPS packet */
> +#define ALPS_BTNLESS			0x100	/* ALPS ClickPad flag */
>  
>  static const struct alps_model_info alps_model_data[] = {
>  	{ { 0x32, 0x02, 0x14 },	0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },	/* Toshiba Salellite Pro M10 */
> @@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>   * isn't valid per PS/2 spec.
>   */
>  
> +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> +				    struct alps_abs_data *pt1)
> +{
> +	int vect_x, vect_y;
> +
> +	if (!pt0 || !pt1)
> +		return 0;
> +
> +	vect_x = pt0->x - pt1->x;
> +	vect_y = pt0->y - pt1->y;
> +
> +	return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> +}
> +
>  /* Packet formats are described in Documentation/input/alps.txt */
>  
>  static bool alps_is_valid_first_byte(struct alps_data *priv,
> @@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
>  		end_bit = y_msb - 1;
>  		box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>  				(2 * (priv->y_bits - 1));
> -		*x1 = fields->x;
> -		*y1 = fields->y;
> +		*x1 = fields->pt.x;
> +		*y1 = fields->pt.y;
>  		*x2 = 2 * box_middle_x - *x1;
>  		*y2 = 2 * box_middle_y - *y1;
>  	}
> @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
>  	alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>  }
>  
> +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> +				      struct alps_fields *f)
> +{
> +	struct input_dev *dev;
> +
> +	if (!psmouse || !f)
> +		return;
> +
> +	dev = psmouse->dev;
> +
> +	if (f->fingers) {
> +		input_report_key(dev, BTN_TOUCH, 1);
> +		alps_report_semi_mt_data(dev, f->fingers,
> +			f->pt_img[0].x, f->pt_img[0].y,
> +			f->pt_img[1].x, f->pt_img[1].y);
> +		input_mt_report_finger_count(dev, f->fingers);
> +
> +		input_report_abs(dev, ABS_X, f->pt_img[0].x);
> +		input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> +		input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> +	} else {
> +		input_report_key(dev, BTN_TOUCH, 0);
> +		input_mt_report_finger_count(dev, 0);
> +		input_report_abs(dev, ABS_PRESSURE, 0);
> +	}
> +
> +	input_report_key(dev, BTN_LEFT, f->btn.left);
> +	input_report_key(dev, BTN_RIGHT, f->btn.right);
> +
> +	input_sync(dev);
> +}
> +
>  static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>  {
>  	struct alps_data *priv = psmouse->private;
> @@ -523,13 +577,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>  
>  static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
>  {
> -	f->left = !!(p[3] & 0x01);
> -	f->right = !!(p[3] & 0x02);
> -	f->middle = !!(p[3] & 0x04);
> +	f->btn.left = !!(p[3] & 0x01);
> +	f->btn.right = !!(p[3] & 0x02);
> +	f->btn.middle = !!(p[3] & 0x04);
>  
> -	f->ts_left = !!(p[3] & 0x10);
> -	f->ts_right = !!(p[3] & 0x20);
> -	f->ts_middle = !!(p[3] & 0x40);
> +	f->btn.ts_left = !!(p[3] & 0x10);
> +	f->btn.ts_right = !!(p[3] & 0x20);
> +	f->btn.ts_middle = !!(p[3] & 0x40);
>  }
>  
>  static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
>  		   ((p[2] & 0x7f) << 1) |
>  		   (p[4] & 0x01);
>  
> -	f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> +	f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>  	       ((p[0] & 0x30) >> 4);
> -	f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> -	f->z = p[5] & 0x7f;
> +	f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> +	f->pt.z = p[5] & 0x7f;
>  
>  	alps_decode_buttons_v3(f, p);
>  }
> @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
>  	f->is_mp = !!(p[0] & 0x20);
>  
>  	if (!f->is_mp) {
> -		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> -		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> -		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> +		f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> +		f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> +		f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>  		alps_decode_buttons_v3(f, p);
>  	} else {
>  		f->fingers = ((p[0] & 0x6) >> 1 |
> @@ -687,7 +741,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>  	 * with x, y, and z all zero, so these seem to be flukes.
>  	 * Ignore them.
>  	 */
> -	if (f.x && f.y && !f.z)
> +	if (f.pt.x && f.pt.y && !f.pt.z)
>  		return;
>  
>  	/*
> @@ -695,12 +749,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>  	 * to rely on ST data.
>  	 */
>  	if (!fingers) {
> -		x1 = f.x;
> -		y1 = f.y;
> -		fingers = f.z > 0 ? 1 : 0;
> +		x1 = f.pt.x;
> +		y1 = f.pt.y;
> +		fingers = f.pt.z > 0 ? 1 : 0;
>  	}
>  
> -	if (f.z >= 64)
> +	if (f.pt.z >= 64)
>  		input_report_key(dev, BTN_TOUCH, 1);
>  	else
>  		input_report_key(dev, BTN_TOUCH, 0);
> @@ -709,22 +763,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>  
>  	input_mt_report_finger_count(dev, fingers);
>  
> -	input_report_key(dev, BTN_LEFT, f.left);
> -	input_report_key(dev, BTN_RIGHT, f.right);
> -	input_report_key(dev, BTN_MIDDLE, f.middle);
> +	input_report_key(dev, BTN_LEFT, f.btn.left);
> +	input_report_key(dev, BTN_RIGHT, f.btn.right);
> +	input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>  
> -	if (f.z > 0) {
> -		input_report_abs(dev, ABS_X, f.x);
> -		input_report_abs(dev, ABS_Y, f.y);
> +	if (f.pt.z > 0) {
> +		input_report_abs(dev, ABS_X, f.pt.x);
> +		input_report_abs(dev, ABS_Y, f.pt.y);
>  	}
> -	input_report_abs(dev, ABS_PRESSURE, f.z);
> +	input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>  
>  	input_sync(dev);
>  
>  	if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> -		input_report_key(dev2, BTN_LEFT, f.ts_left);
> -		input_report_key(dev2, BTN_RIGHT, f.ts_right);
> -		input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> +		input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> +		input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> +		input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>  		input_sync(dev2);
>  	}
>  }
> @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
>  	input_sync(dev);
>  }
>  
> +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> +{
> +	if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> +		return false;
> +	if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> +		return false;
> +	if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> +		return false;
> +	return true;
> +}
> +
> +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	int drop = 1;
> +
> +	if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> +	    priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> +	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> +	    priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> +		drop = 0;
> +
> +	return drop;
> +}
> +
> +static unsigned char alps_get_packet_id_v7(char *byte)
> +{
> +	unsigned char packet_id;
> +
> +	if (byte[4] & 0x40)
> +		packet_id = V7_PACKET_ID_TWO;
> +	else if (byte[4] & 0x01)
> +		packet_id = V7_PACKET_ID_MULTI;
> +	else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> +		packet_id = V7_PACKET_ID_NEW;
> +	else
> +		packet_id = V7_PACKET_ID_IDLE;
> +
> +	return packet_id;
> +}
> +
> +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> +					  unsigned char *pkt,
> +					  unsigned char pkt_id)
> +{
> +	if ((pkt_id == V7_PACKET_ID_TWO) ||
> +	   (pkt_id == V7_PACKET_ID_MULTI) ||
> +	   (pkt_id == V7_PACKET_ID_NEW)) {
> +		pt[0].x = ((pkt[2] & 0x80) << 4);
> +		pt[0].x |= ((pkt[2] & 0x3F) << 5);
> +		pt[0].x |= ((pkt[3] & 0x30) >> 1);
> +		pt[0].x |= (pkt[3] & 0x07);
> +		pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> +
> +		pt[1].x = ((pkt[3] & 0x80) << 4);
> +		pt[1].x |= ((pkt[4] & 0x80) << 3);
> +		pt[1].x |= ((pkt[4] & 0x3F) << 4);
> +		pt[1].y = ((pkt[5] & 0x80) << 3);
> +		pt[1].y |= ((pkt[5] & 0x3F) << 4);
> +
> +		if (pkt_id == V7_PACKET_ID_TWO) {
> +			pt[1].x &= ~0x000F;
> +			pt[1].y |= 0x000F;
> +		} else if (pkt_id == V7_PACKET_ID_MULTI) {
> +			pt[1].x &= ~0x003F;
> +			pt[1].y &= ~0x0020;
> +			pt[1].y |= ((pkt[4] & 0x02) << 4);
> +			pt[1].y |= 0x001F;
> +		} else if (pkt_id == V7_PACKET_ID_NEW) {
> +			pt[1].x &= ~0x003F;
> +			pt[1].x |= (pkt[0] & 0x20);
> +			pt[1].y |= 0x000F;
> +		}
> +
> +		pt[0].y = 0x7FF - pt[0].y;
> +		pt[1].y = 0x7FF - pt[1].y;
> +
> +		pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> +		pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> +	}
> +}
> +
> +static void alps_decode_packet_v7(struct alps_fields *f,
> +				  unsigned char *p,
> +				  struct psmouse *psmouse)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	static struct v7_raw prev_r;
> +
> +	priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> +
> +	alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> +
> +	priv->r.v7.rest_left = 0;
> +	priv->r.v7.rest_right = 0;
> +	priv->r.v7.additional_fingers = 0;
> +	priv->phy_btn = 0;
> +
> +	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> +	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> +		priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> +		priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> +	}
> +
> +	if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> +		priv->r.v7.additional_fingers = p[5] & 0x03;
> +
> +	priv->phy_btn = (p[0] & 0x80) >> 7;
> +
> +	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
> +		if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
> +			priv->r.v7.raw_fn = 2;
> +		else
> +			priv->r.v7.raw_fn = 1;
> +	} else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> +		priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
> +	else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> +		priv->r.v7.raw_fn = 0;
> +	else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
> +		priv->r.v7.raw_fn = prev_r.raw_fn;
> +
> +	/* It is a trick to bypass firmware bug of older version
> +	that 'New' Packet is missed when finger number changed.
> +	We fake a 'New' Packet in such cases.*/
> +	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> +		priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> +		priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) {
> +		if (priv->r.v7.raw_fn != prev_r.raw_fn)
> +			priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
> +	}
> +
> +	memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
> +}
> +
> +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> +				     struct alps_abs_data *pt,
> +				     struct alps_bl_pt_attr *pt_attr)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	unsigned int dist;
> +
> +	if (!pt_attr->is_init_pt_got && pt->z != 0) {
> +		pt_attr->is_init_pt_got = 1;
> +		pt_attr->is_counted = 0;
> +		memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> +	}
> +
> +	if (pt->z != 0) {
> +		if (pt->y < priv->resting_zone_y_min) {
> +			/* A finger is recognized as a non-resting finger
> +			if it's position is outside the resting finger zone.*/
> +			pt_attr->zone = ZONE_NORMAL;
> +			pt_attr->is_counted = 1;
> +		} else {
> +			/* A finger is recognized as a resting finger if it's
> +			position is inside the resting finger zone and there's
> +			no large movement from it's touch down position.*/
> +			pt_attr->zone = ZONE_RESTING;
> +
> +			if (pt->x > priv->x_max / 2)
> +				pt_attr->zone |= ZONE_RIGHT_BTN;
> +			else
> +				pt_attr->zone |= ZONE_LEFT_BTN;
> +
> +			/* A resting finger will turn to be a non-resting
> +			finger if it has made large movement from it's touch
> +			down position. A non-resting finger will never turn
> +			to a resting finger before it leaves the touchpad
> +			surface.*/
> +			if (pt_attr->is_init_pt_got) {
> +				dist = alps_pt_distance(pt, &pt_attr->init_pt);
> +
> +				if (dist > V7_LARGE_MOVEMENT)
> +					pt_attr->is_counted = 1;
> +			}
> +		}
> +	}
> +}
> +
> +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> +				       struct alps_fields *f)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	int i;
> +
> +	switch (priv->r.v7.pkt_id) {
> +	case  V7_PACKET_ID_TWO:
> +	case  V7_PACKET_ID_MULTI:
> +		for (i = 0; i < V7_IMG_PT_NUM; i++) {
> +			alps_set_each_pt_attr_v7(psmouse,
> +						 &f->pt_img[i],
> +						 &priv->pt_attr[i]);
> +		}
> +		break;
> +	default:
> +		/*All finger attributes are cleared when packet ID is
> +		'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> +		indicates that there's no finger and no button activity.
> +		A 'NEW' packet indicates the finger position in packet
> +		is not continues from previous packet. Such as the
> +		condition there's finger placed or lifted. In these cases,
> +		finger attributes will be reset.*/
> +		memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> +		break;
> +	}
> +}
> +
> +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> +					struct alps_fields *f)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	unsigned int fn = 0;
> +	int i;
> +
> +	switch (priv->r.v7.pkt_id) {
> +	case V7_PACKET_ID_IDLE:
> +	case V7_PACKET_ID_NEW:
> +		/*No finger is reported when packet ID is 'IDLE' or 'New'.
> +		An 'IDLE' packet indicates that there's no finger on touchpad.
> +		A 'NEW' packet indicates there's finger placed or lifted.
> +		Finger position of 'New' packet is not continues from the
> +		previous packet.*/
> +		fn = 0;
> +		break;
> +	case V7_PACKET_ID_TWO:
> +		if (f->pt_img[0].z == 0) {
> +			/*The first finger slot is zero when a non-resting
> +			finger lifted and remaining only one resting finger
> +			on touchpad. Hardware report the remaining resting
> +			finger in second slot. This resting is ignored*/
> +			fn = 0;
> +		} else if (f->pt_img[1].z == 0) {
> +			/* The second finger slot is zero if there's
> +			only one finger*/
> +			fn = 1;
> +		} else {
> +			/*All non-resting fingers will be counted to report*/
> +			fn = 0;
> +			for (i = 0; i < V7_IMG_PT_NUM; i++) {
> +				if (priv->pt_attr[i].is_counted)
> +					fn++;
> +			}
> +
> +			/*In the case that both fingers are
> +			resting fingers, report the first one*/
> +			if (!priv->pt_attr[0].is_counted &&
> +			    !priv->pt_attr[1].is_counted) {
> +				fn = 1;
> +			}
> +		}
> +		break;
> +	case V7_PACKET_ID_MULTI:
> +		/*A packet ID 'MULTI' indicats that at least 3 non-resting
> +		finger exist.*/
> +		fn = 3 + priv->r.v7.additional_fingers;
> +		break;
> +	}
> +
> +	f->fingers = fn;
> +}
> +
> +static void alps_button_dead_zone_filter(struct psmouse *psmouse,
> +				   struct alps_fields *f,
> +				   struct alps_fields *prev_f)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	int dx, dy;
> +
> +	if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
> +		memcpy(&priv->pt_attr[0].init_dead_pt,
> +				&f->pt_img[0],
> +				sizeof(struct alps_abs_data));
> +	}
> +
> +	if (priv->pt_attr[0].init_dead_pt.x != 0 &&
> +		priv->pt_attr[0].init_dead_pt.x != 0) {
> +			dx = f->pt_img[0].x - priv->pt_attr[0].init_dead_pt.x;
> +			dy = f->pt_img[0].y - priv->pt_attr[0].init_dead_pt.y;
> +		if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
> +			(abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) {
> +				memset(&priv->pt_attr[0].init_dead_pt, 0,
> +						sizeof(struct alps_abs_data));
> +				priv->btn_delay_cnt = 0;
> +		} else {
> +			memcpy(&f->pt_img[0],
> +					&prev_f->pt_img[0],
> +					sizeof(struct alps_abs_data));
> +			if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
> +				priv->btn_delay_cnt = 2;
> +		}
> +	}
> +
> +	if (priv->btn_delay_cnt > 0) {
> +		f->btn.left = 0;
> +		f->btn.right = 0;
> +		priv->btn_delay_cnt--;
> +	}
> +}
> +
> +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> +				   struct alps_fields *f,
> +				   struct alps_fields *prev_f)
> +{
> +	struct alps_data *priv = psmouse->private;
> +
> +	if (priv->phy_btn) {
> +		if (!priv->prev_phy_btn) {
> +			/* Report a right click as long as there's finger on
> +			right button zone. Othrewise, report a left click.*/
> +			if (priv->r.v7.rest_right ||
> +			    priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> +			    priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> +				f->btn.right = 1;
> +				priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> +			} else {
> +				f->btn.left = 1;
> +				priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> +			}
> +		} else {
> +			if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> +				f->btn.right = 1;
> +			if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> +				f->btn.left = 1;
> +		}
> +	} else {
> +		priv->pressed_btn_bits = 0;
> +		f->btn.right = 0;
> +		f->btn.left = 0;
> +	}
> +
> +	alps_button_dead_zone_filter(psmouse, f, prev_f);
> +
> +	priv->prev_phy_btn = priv->phy_btn;
> +}
> +
> +static void alps_process_packet_v7(struct psmouse *psmouse)
> +{
> +	struct alps_data *priv = psmouse->private;
> +	struct alps_fields f = {0};
> +	static struct alps_fields prev_f;
> +	unsigned char *packet = psmouse->packet;
> +
> +	priv->decode_fields(&f, packet, psmouse);
> +
> +	if (alps_drop_unsupported_packet_v7(psmouse))
> +		return;
> +
> +	alps_set_pt_attr_v7(psmouse, &f);
> +
> +	alps_cal_output_finger_num_v7(psmouse, &f);
> +
> +	alps_assign_buttons_v7(psmouse, &f, &prev_f);
> +
> +	alps_report_coord_and_btn(psmouse, &f);
> +
> +	memcpy(&prev_f, &f, sizeof(struct alps_fields));
> +}
> +
>  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>  					unsigned char packet[],
>  					bool report_buttons)
> @@ -1080,6 +1492,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
>  		return PSMOUSE_BAD_DATA;
>  	}
>  
> +	if ((priv->proto_version == ALPS_PROTO_V7 &&
> +	    !alps_is_valid_package_v7(psmouse))) {
> +		psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> +			    psmouse->pktcnt - 1,
> +			    psmouse->packet[psmouse->pktcnt - 1]);
> +		return PSMOUSE_BAD_DATA;
> +	}
> +
>  	if (psmouse->pktcnt == psmouse->pktsize) {
>  		priv->process_packet(psmouse);
>  		return PSMOUSE_FULL_PACKET;
> @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
>  	return 0;
>  }
>  
> +static int alps_check_valid_firmware_id(unsigned char id[])
> +{
> +	int valid = 1;
> +
> +	if (id[0] == 0x73)
> +		valid = 1;
> +	else if (id[0] == 0x88) {
> +		if ((id[1] == 0x07) ||
> +		    (id[1] == 0x08) ||
> +		    ((id[1] & 0xf0) == 0xB0))
> +			valid = 1;
> +	}
> +
> +	return valid;
> +}
> +
>  static int alps_enter_command_mode(struct psmouse *psmouse)
>  {
>  	unsigned char param[4];
> @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
>  		return -1;
>  	}
>  
> -	if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> -	    param[0] != 0x73) {
> +	if (!alps_check_valid_firmware_id(param)) {
>  		psmouse_dbg(psmouse,
>  			    "unknown response while entering command mode\n");
>  		return -1;
> @@ -1704,6 +2139,36 @@ error:
>  	return ret;
>  }
>  
> +static int alps_hw_init_v7(struct psmouse *psmouse)
> +{
> +	struct ps2dev *ps2dev = &psmouse->ps2dev;
> +	int reg_val, ret = -1;
> +
> +	if (alps_enter_command_mode(psmouse))
> +		goto error;
> +
> +	reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
> +	if (reg_val == -1)
> +		goto error;
> +
> +	if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
> +		goto error;
> +
> +	reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
> +	if (reg_val == -1)
> +		goto error;
> +
> +	if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
> +		goto error;
> +
> +	alps_exit_command_mode(psmouse);
> +	return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
> +
> +error:
> +	alps_exit_command_mode(psmouse);
> +	return ret;
> +}
> +
>  /* Must be in command mode when calling this function */
>  static int alps_absolute_mode_v4(struct psmouse *psmouse)
>  {
> @@ -1875,6 +2340,7 @@ static void alps_set_defaults(struct alps_data *priv)
>  		priv->set_abs_params = alps_set_abs_params_st;
>  		priv->x_max = 1023;
>  		priv->y_max = 767;
> +		priv->slot_number = 1;
>  		break;
>  	case ALPS_PROTO_V3:
>  		priv->hw_init = alps_hw_init_v3;
> @@ -1883,6 +2349,7 @@ static void alps_set_defaults(struct alps_data *priv)
>  		priv->decode_fields = alps_decode_pinnacle;
>  		priv->nibble_commands = alps_v3_nibble_commands;
>  		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> +		priv->slot_number = 2;
>  		break;
>  	case ALPS_PROTO_V4:
>  		priv->hw_init = alps_hw_init_v4;
> @@ -1890,6 +2357,7 @@ static void alps_set_defaults(struct alps_data *priv)
>  		priv->set_abs_params = alps_set_abs_params_mt;
>  		priv->nibble_commands = alps_v4_nibble_commands;
>  		priv->addr_command = PSMOUSE_CMD_DISABLE;
> +		priv->slot_number = 2;
>  		break;
>  	case ALPS_PROTO_V5:
>  		priv->hw_init = alps_hw_init_dolphin_v1;
> @@ -1905,6 +2373,7 @@ static void alps_set_defaults(struct alps_data *priv)
>  		priv->y_max = 660;
>  		priv->x_bits = 23;
>  		priv->y_bits = 12;
> +		priv->slot_number = 2;
>  		break;
>  	case ALPS_PROTO_V6:
>  		priv->hw_init = alps_hw_init_v6;
> @@ -1913,6 +2382,28 @@ static void alps_set_defaults(struct alps_data *priv)
>  		priv->nibble_commands = alps_v6_nibble_commands;
>  		priv->x_max = 2047;
>  		priv->y_max = 1535;
> +		priv->slot_number = 2;
> +		break;
> +	case ALPS_PROTO_V7:
> +		priv->hw_init = alps_hw_init_v7;
> +		priv->process_packet = alps_process_packet_v7;
> +		priv->decode_fields = alps_decode_packet_v7;
> +		priv->set_abs_params = alps_set_abs_params_mt;
> +		priv->nibble_commands = alps_v3_nibble_commands;
> +		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> +		priv->x_max = 0xfff;
> +		priv->y_max = 0x7ff;
> +		priv->resting_zone_y_min = 0x654;
> +		priv->byte0 = 0x48;
> +		priv->mask0 = 0x48;
> +		priv->flags = 0;
> +		priv->slot_number = 2;
> +
> +		priv->phy_btn = 0;
> +		priv->prev_phy_btn = 0;
> +		priv->btn_delay_cnt = 0;
> +		priv->pressed_btn_bits = 0;
> +		memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>  		break;
>  	}
>  }
> @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
>  			return -EIO;
>  		else
>  			return 0;
> +	} else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> +		priv->proto_version = ALPS_PROTO_V7;
> +		alps_set_defaults(priv);
> +
> +		return 0;
>  	} else if (ec[0] == 0x88 && ec[1] == 0x08) {
>  		priv->proto_version = ALPS_PROTO_V3;
>  		alps_set_defaults(priv);
> @@ -2045,7 +2541,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>  				   struct input_dev *dev1)
>  {
>  	set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> -	input_mt_init_slots(dev1, 2, 0);
> +	input_mt_init_slots(dev1, priv->slot_number, 0);
>  	input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
>  	input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
>  
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index 03f88b6..dedbd27 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,11 +18,36 @@
>  #define ALPS_PROTO_V4	4
>  #define ALPS_PROTO_V5	5
>  #define ALPS_PROTO_V6	6
> +#define ALPS_PROTO_V7	7
> +
> +#define MAX_IMG_PT_NUM		5
> +#define V7_IMG_PT_NUM		2
> +
> +#define ZONE_NORMAL				0x01
> +#define ZONE_RESTING			0x02
> +#define ZONE_LEFT_BTN			0x04
> +#define ZONE_RIGHT_BTN			0x08
>  
>  #define DOLPHIN_COUNT_PER_ELECTRODE	64
>  #define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
>  #define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */
>  
> +/*
> + * enum V7_PACKET_ID - defines the packet type for V7
> + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> + *  or there's button activities.
> + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> + *  previous packet.
> +*/
> +enum V7_PACKET_ID {
> +	 V7_PACKET_ID_IDLE,
> +	 V7_PACKET_ID_TWO,
> +	 V7_PACKET_ID_MULTI,
> +	 V7_PACKET_ID_NEW,
> +};
> +
>  /**
>   * struct alps_model_info - touchpad ID table
>   * @signature: E7 response string to match.
> @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>  };
>  
>  /**
> - * struct alps_fields - decoded version of the report packet
> - * @x_map: Bitmap of active X positions for MT.
> - * @y_map: Bitmap of active Y positions for MT.
> - * @fingers: Number of fingers for MT.
> - * @x: X position for ST.
> - * @y: Y position for ST.
> - * @z: Z position for ST.
> - * @first_mp: Packet is the first of a multi-packet report.
> - * @is_mp: Packet is part of a multi-packet report.
> + * struct alps_btn - decoded version of the button status
>   * @left: Left touchpad button is active.
>   * @right: Right touchpad button is active.
>   * @middle: Middle touchpad button is active.
> @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>   * @ts_right: Right trackstick button is active.
>   * @ts_middle: Middle trackstick button is active.
>   */
> -struct alps_fields {
> -	unsigned int x_map;
> -	unsigned int y_map;
> -	unsigned int fingers;
> -	unsigned int x;
> -	unsigned int y;
> -	unsigned int z;
> -	unsigned int first_mp:1;
> -	unsigned int is_mp:1;
> -
> +struct alps_btn {
>  	unsigned int left:1;
>  	unsigned int right:1;
>  	unsigned int middle:1;
> @@ -102,6 +110,73 @@ struct alps_fields {
>  };
>  
>  /**
> + * struct alps_btn - decoded version of the X Y Z postion for ST.
> + * @x: X position for ST.
> + * @y: Y position for ST.
> + * @z: Z position for ST.
> + */
> +struct alps_abs_data {
> +	unsigned int x;
> +	unsigned int y;
> +	unsigned int z;
> +};
> +
> +/**
> + * struct alps_fields - decoded version of the report packet
> + * @fingers: Number of fingers for MT.
> + * @pt: X Y Z postion for ST.
> + * @pt: X Y Z postion for image MT.
> + * @x_map: Bitmap of active X positions for MT.
> + * @y_map: Bitmap of active Y positions for MT.
> + * @first_mp: Packet is the first of a multi-packet report.
> + * @is_mp: Packet is part of a multi-packet report.
> + * @btn: Button activity status
> + */
> +struct alps_fields {
> +	unsigned int fingers;
> +	struct alps_abs_data pt;
> +	struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> +	unsigned int x_map;
> +	unsigned int y_map;
> +	unsigned int first_mp:1;
> +	unsigned int is_mp:1;
> +	struct alps_btn btn;
> +};
> +
> +/**
> + * struct v7_raw - data decoded from raw packet for V7.
> + * @pkt_id: An id that specifies the type of packet.
> + * @additional_fingers: Number of additional finger that is neighter included
> + *  in pt slot nor reflected in rest_left and rest_right flag of data packet.
> + * @rest_left: There are fingers on left resting zone.
> + * @rest_right: There are fingers on right resting zone.
> + * @raw_fn: The number of finger on touchpad.
> + */
> +struct v7_raw {
> +	unsigned char pkt_id;
> +	unsigned int additional_fingers;
> +	unsigned char rest_left;
> +	unsigned char rest_right;
> +	unsigned char raw_fn;
> +};
> +
> +/**
> + * struct alps_bl_pt_attr - generic attributes of touch points for buttonless device
> + * @zone: The part of touchpad that the touch point locates
> + * @is_counted: The touch point is not a resting finger.
> + * @is_init_pt_got: The touch down point is got.
> + * @init_pt: The X Y Z position of the touch down point.
> + * @init_dead_pt: The touch down point of a finger used by dead zone process.
> + */
> +struct alps_bl_pt_attr {
> +	unsigned char zone;
> +	unsigned char is_counted;
> +	unsigned char is_init_pt_got;
> +	struct alps_abs_data init_pt;
> +	struct alps_abs_data init_dead_pt;
> +};
> +
> +/**
>   * struct alps_data - private data structure for the ALPS driver
>   * @dev2: "Relative" device used to report trackstick or mouse activity.
>   * @phys: Physical path for the relative device.
> @@ -116,8 +191,10 @@ struct alps_fields {
>   * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
>   * @x_max: Largest possible X position value.
>   * @y_max: Largest possible Y position value.
> + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
>   * @x_bits: Number of X bits in the MT bitmap.
>   * @y_bits: Number of Y bits in the MT bitmap.
> + * @img_fingers: Number of image fingers.
>   * @hw_init: Protocol-specific hardware init function.
>   * @process_packet: Protocol-specific function to process a report packet.
>   * @decode_fields: Protocol-specific function to read packet bitfields.
> @@ -132,6 +209,11 @@ struct alps_fields {
>   * @fingers: Number of fingers from last MT report.
>   * @quirks: Bitmap of ALPS_QUIRK_*.
>   * @timer: Timer for flushing out the final report packet in the stream.
> + * @v7: Data decoded from raw packet for V7
> + * @phy_btn: Physical button is active.
> + * @prev_phy_btn: Physical button of previous packet is active.
> + * @pressed_btn_bits: Pressed positon of button zone
> + * @pt_attr: Generic attributes of touch points for buttonless device.
>   */
>  struct alps_data {
>  	struct input_dev *dev2;
> @@ -145,8 +227,10 @@ struct alps_data {
>  	unsigned char flags;
>  	int x_max;
>  	int y_max;
> +	int resting_zone_y_min;
>  	int x_bits;
>  	int y_bits;
> +	unsigned char slot_number;
>  
>  	int (*hw_init)(struct psmouse *psmouse);
>  	void (*process_packet)(struct psmouse *psmouse);
> @@ -161,6 +245,16 @@ struct alps_data {
>  	int fingers;
>  	u8 quirks;
>  	struct timer_list timer;
> +
> +	/* these are used for buttonless touchpad*/
> +	union {
> +		struct v7_raw v7;
> +	} r;
> +	unsigned char phy_btn;
> +	unsigned char prev_phy_btn;
> +	unsigned char btn_delay_cnt;
> +	unsigned char pressed_btn_bits;
> +	struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>  };
>  
>  #define ALPS_QUIRK_TRACKSTICK_BUTTONS	1 /* trakcstick buttons in trackstick packet */


[-- Attachment #2: linux-patch-3.14-rc8.alps.patch --]
[-- Type: text/x-patch, Size: 30345 bytes --]

diff -upr a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
--- a/drivers/input/mouse/alps.c	2014-03-26 11:31:28.215133549 +0100
+++ b/drivers/input/mouse/alps.c	2014-03-26 11:39:51.713370675 +0100
@@ -32,6 +32,13 @@
 #define ALPS_REG_BASE_RUSHMORE	0xc2c0
 #define ALPS_REG_BASE_PINNACLE	0x0000
 
+#define LEFT_BUTTON_BIT  0x01
+#define RIGHT_BUTTON_BIT 0x02
+
+#define V7_LARGE_MOVEMENT      130
+#define V7_DEAD_ZONE_OFFSET_X  72
+#define V7_DEAD_ZONE_OFFSET_Y  72
+
 static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
 	{ PSMOUSE_CMD_SETPOLL,		0x00 }, /* 0 */
 	{ PSMOUSE_CMD_RESET_DIS,	0x00 }, /* 1 */
@@ -98,7 +105,8 @@ static const struct alps_nibble_commands
 #define ALPS_FW_BK_2		0x20	/* front & back buttons present */
 #define ALPS_FOUR_BUTTONS	0x40	/* 4 direction button present */
 #define ALPS_PS2_INTERLEAVED	0x80	/* 3-byte PS/2 packet interleaved with
-					   6-byte ALPS packet */
+										   6-byte ALPS packet */
+#define ALPS_BTNLESS		0x100	/* ALPS ClickPad flag */
 
 static const struct alps_model_info alps_model_data[] = {
 	{ { 0x32, 0x02, 0x14 },	0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },	/* Toshiba Salellite Pro M10 */
@@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struc
  * isn't valid per PS/2 spec.
  */
 
+static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
+                                   struct alps_abs_data *pt1)
+{
+       int vect_x, vect_y;
+
+       if (!pt0 || !pt1)
+               return 0;
+
+       vect_x = pt0->x - pt1->x;
+       vect_y = pt0->y - pt1->y;
+
+       return int_sqrt(vect_x * vect_x + vect_y * vect_y);
+}
+
 /* Packet formats are described in Documentation/input/alps.txt */
 
 static bool alps_is_valid_first_byte(struct alps_data *priv,
@@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(
 		end_bit = y_msb - 1;
 		box_middle_y = (priv->y_max * (start_bit + end_bit)) /
 				(2 * (priv->y_bits - 1));
-		*x1 = fields->x;
-		*y1 = fields->y;
+		*x1 = fields->pt.x;
+		*y1 = fields->pt.y;
 		*x2 = 2 * box_middle_x - *x1;
 		*y2 = 2 * box_middle_y - *y1;
 	}
@@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(str
 	alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
 }
 
+static void alps_report_coord_and_btn(struct psmouse *psmouse,
+									  struct alps_fields *f)
+{
+	struct input_dev *dev;
+
+	if (!psmouse || !f)
+		return;
+
+	dev = psmouse->dev;
+
+	if (f->fingers) {
+		input_report_key(dev, BTN_TOUCH, 1);
+		alps_report_semi_mt_data(dev, f->fingers,
+								 f->pt_img[0].x, f->pt_img[0].y,
+								 f->pt_img[1].x, f->pt_img[1].y);
+		input_mt_report_finger_count(dev, f->fingers);
+
+		input_report_abs(dev, ABS_X, f->pt_img[0].x);
+		input_report_abs(dev, ABS_Y, f->pt_img[0].y);
+		input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
+	} else {
+		input_report_key(dev, BTN_TOUCH, 0);
+		input_mt_report_finger_count(dev, 0);
+		input_report_abs(dev, ABS_PRESSURE, 0);
+	}
+
+	input_report_key(dev, BTN_LEFT, f->btn.left);
+	input_report_key(dev, BTN_RIGHT, f->btn.right);
+
+	input_sync(dev);
+}
+
 static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
 {
 	struct alps_data *priv = psmouse->private;
@@ -523,13 +577,13 @@ static void alps_process_trackstick_pack
 
 static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
 {
-	f->left = !!(p[3] & 0x01);
-	f->right = !!(p[3] & 0x02);
-	f->middle = !!(p[3] & 0x04);
-
-	f->ts_left = !!(p[3] & 0x10);
-	f->ts_right = !!(p[3] & 0x20);
-	f->ts_middle = !!(p[3] & 0x40);
+	f->btn.left = !!(p[3] & 0x01);
+	f->btn.right = !!(p[3] & 0x02);
+	f->btn.middle = !!(p[3] & 0x04);
+
+	f->btn.ts_left = !!(p[3] & 0x10);
+	f->btn.ts_right = !!(p[3] & 0x20);
+	f->btn.ts_middle = !!(p[3] & 0x40);
 }
 
 static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
@@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct
 		   ((p[2] & 0x7f) << 1) |
 		   (p[4] & 0x01);
 
-	f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
+	f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
 	       ((p[0] & 0x30) >> 4);
-	f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
-	f->z = p[5] & 0x7f;
+	f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
+	f->pt.z = p[5] & 0x7f;
 
 	alps_decode_buttons_v3(f, p);
 }
@@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct a
 	f->is_mp = !!(p[0] & 0x20);
 
 	if (!f->is_mp) {
-		f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
-		f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
-		f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
+		f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+		f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+		f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
 		alps_decode_buttons_v3(f, p);
 	} else {
 		f->fingers = ((p[0] & 0x6) >> 1 |
@@ -687,7 +741,7 @@ static void alps_process_touchpad_packet
 	 * with x, y, and z all zero, so these seem to be flukes.
 	 * Ignore them.
 	 */
-	if (f.x && f.y && !f.z)
+	if (f.pt.x && f.pt.y && !f.pt.z)
 		return;
 
 	/*
@@ -695,12 +749,12 @@ static void alps_process_touchpad_packet
 	 * to rely on ST data.
 	 */
 	if (!fingers) {
-		x1 = f.x;
-		y1 = f.y;
-		fingers = f.z > 0 ? 1 : 0;
+		x1 = f.pt.x;
+		y1 = f.pt.y;
+		fingers = f.pt.z > 0 ? 1 : 0;
 	}
 
-	if (f.z >= 64)
+	if (f.pt.z >= 64)
 		input_report_key(dev, BTN_TOUCH, 1);
 	else
 		input_report_key(dev, BTN_TOUCH, 0);
@@ -709,22 +763,22 @@ static void alps_process_touchpad_packet
 
 	input_mt_report_finger_count(dev, fingers);
 
-	input_report_key(dev, BTN_LEFT, f.left);
-	input_report_key(dev, BTN_RIGHT, f.right);
-	input_report_key(dev, BTN_MIDDLE, f.middle);
-
-	if (f.z > 0) {
-		input_report_abs(dev, ABS_X, f.x);
-		input_report_abs(dev, ABS_Y, f.y);
+	input_report_key(dev, BTN_LEFT, f.btn.left);
+	input_report_key(dev, BTN_RIGHT, f.btn.right);
+	input_report_key(dev, BTN_MIDDLE, f.btn.middle);
+
+	if (f.pt.z > 0) {
+		input_report_abs(dev, ABS_X, f.pt.x);
+		input_report_abs(dev, ABS_Y, f.pt.y);
 	}
-	input_report_abs(dev, ABS_PRESSURE, f.z);
+	input_report_abs(dev, ABS_PRESSURE, f.pt.z);
 
 	input_sync(dev);
 
 	if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
-		input_report_key(dev2, BTN_LEFT, f.ts_left);
-		input_report_key(dev2, BTN_RIGHT, f.ts_right);
-		input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
+		input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
+		input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
+		input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
 		input_sync(dev2);
 	}
 }
@@ -916,6 +970,445 @@ static void alps_process_packet_v4(struc
 	input_sync(dev);
 }
 
+static bool alps_is_valid_package_v7(struct psmouse *psmouse)
+{
+	if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
+		return false;
+	if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
+		return false;
+	if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
+		return false;
+
+	return true;
+}
+
+static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	int drop = 1;
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
+		drop = 0;
+
+	return drop;
+}
+
+static unsigned char alps_get_packet_id_v7(char *byte)
+{
+	unsigned char packet_id;
+
+	if (byte[4] & 0x40)
+		packet_id = V7_PACKET_ID_TWO;
+	else if (byte[4] & 0x01)
+		packet_id = V7_PACKET_ID_MULTI;
+	else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
+		packet_id = V7_PACKET_ID_NEW;
+	else if (byte[1] & 0x08)
+		packet_id = V7_PACKET_ID_TRACKSTICK;
+	else
+		packet_id = V7_PACKET_ID_IDLE;
+
+	return packet_id;
+}
+
+static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
+										  unsigned char *pkt,
+										  unsigned char pkt_id)
+{
+	if ((pkt_id == V7_PACKET_ID_TWO) ||
+	   (pkt_id == V7_PACKET_ID_MULTI) ||
+	   (pkt_id == V7_PACKET_ID_NEW))
+	{
+		pt[0].x  = ((pkt[2] & 0x80) << 4);
+		pt[0].x |= ((pkt[2] & 0x3F) << 5);
+		pt[0].x |= ((pkt[3] & 0x30) >> 1);
+		pt[0].x |= (pkt[3] & 0x07);
+
+		pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
+
+		pt[1].x  = ((pkt[3] & 0x80) << 4);
+		pt[1].x |= ((pkt[4] & 0x80) << 3);
+		pt[1].x |= ((pkt[4] & 0x3F) << 4);
+
+		pt[1].y  = ((pkt[5] & 0x80) << 3);
+		pt[1].y |= ((pkt[5] & 0x3F) << 4);
+
+		if (pkt_id == V7_PACKET_ID_TWO) {
+			pt[1].x &= ~0x000F;
+			pt[1].y |= 0x000F;
+		} else if (pkt_id == V7_PACKET_ID_MULTI) {
+			pt[1].x &= ~0x003F;
+			pt[1].y &= ~0x0020;
+			pt[1].y |= ((pkt[4] & 0x02) << 4);
+			pt[1].y |= 0x001F;
+		} else if (pkt_id == V7_PACKET_ID_NEW) {
+			pt[1].x &= ~0x003F;
+			pt[1].x |= (pkt[0] & 0x20);
+			pt[1].y |= 0x000F;
+		}
+
+		pt[0].y = 0x7FF - pt[0].y;
+		pt[1].y = 0x7FF - pt[1].y;
+
+		pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
+		pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
+	}
+}
+
+static void alps_decode_packet_v7(struct alps_fields *f,
+								  unsigned char *p,
+								  struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	static struct v7_raw prev_r;
+
+	alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
+
+	priv->r.v7.rest_left = 0;
+	priv->r.v7.rest_right = 0;
+	priv->r.v7.additional_fingers = 0;
+	priv->phy_btn = 0;
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+		priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
+	{
+		priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
+		priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
+	}
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
+		priv->r.v7.additional_fingers = p[5] & 0x03;
+
+	priv->phy_btn = (p[0] & 0x80) >> 7;
+
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
+		if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
+			priv->r.v7.raw_fn = 2;
+		else
+			priv->r.v7.raw_fn = 1;
+	} else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
+		priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
+	else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
+		priv->r.v7.raw_fn = 0;
+	else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
+		priv->r.v7.raw_fn = prev_r.raw_fn;
+
+	/*
+	 * It is a trick to bypass firmware bug of older version
+	 * that 'New' Packet is missed when finger number changed.
+	 * We fake a 'New' Packet in such cases.
+	 */
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
+	    priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
+	{
+		if (priv->r.v7.raw_fn != prev_r.raw_fn)
+			priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
+	}
+
+	memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
+}
+
+static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
+									 struct alps_abs_data *pt,
+									 struct alps_bl_pt_attr *pt_attr)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned int dist;
+
+	if (!pt_attr->is_init_pt_got && pt->z != 0) {
+		pt_attr->is_init_pt_got = 1;
+		pt_attr->is_counted = 0;
+		memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
+	}
+
+	if (pt->z != 0) {
+		if (pt->y < priv->resting_zone_y_min) {
+			/*
+			 * A finger is recognized as a non-resting finger
+			 * if it's position is outside the resting finger zone.
+			 */
+			pt_attr->zone = ZONE_NORMAL;
+			pt_attr->is_counted = 1;
+		} else {
+			/*
+			 * A finger is recognized as a resting finger if it's
+			 * position is inside the resting finger zone and there's
+			 * no large movement from it's touch down position.
+			 */
+			pt_attr->zone = ZONE_RESTING;
+
+			if (pt->x > priv->x_max / 2)
+				pt_attr->zone |= ZONE_RIGHT_BTN;
+			else
+				pt_attr->zone |= ZONE_LEFT_BTN;
+
+			/*
+			 * A resting finger will turn to be a non-resting
+			 * finger if it has made large movement from it's touch
+			 * down position. A non-resting finger will never turn
+			 * to a resting finger before it leaves the touchpad
+			 * surface.
+			 */
+			if (pt_attr->is_init_pt_got) {
+				dist = alps_pt_distance(pt, &pt_attr->init_pt);
+
+				if (dist > V7_LARGE_MOVEMENT)
+					pt_attr->is_counted = 1;
+			}
+		}
+	}
+}
+
+static void alps_set_pt_attr_v7(struct psmouse *psmouse,
+							    struct alps_fields *f)
+{
+	struct alps_data *priv = psmouse->private;
+	int i;
+
+	switch (priv->r.v7.pkt_id) {
+		case  V7_PACKET_ID_TWO:
+		case  V7_PACKET_ID_MULTI:
+			for (i = 0; i < V7_IMG_PT_NUM; i++) {
+				alps_set_each_pt_attr_v7(psmouse,
+										 &f->pt_img[i],
+										 &priv->pt_attr[i]);
+			}
+			break;
+
+		default:
+			/*
+			 * All finger attributes are cleared when packet ID is
+			 * 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
+			 * indicates that there's no finger and no button activity.
+			 * A 'NEW' packet indicates the finger position in packet
+			 * is not continues from previous packet. Such as the
+			 * condition there's finger placed or lifted. In these cases,
+			 * finger attributes will be reset.
+			 */
+			memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
+			break;
+	}
+}
+
+static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
+										  struct alps_fields *f)
+{
+	struct alps_data *priv = psmouse->private;
+	unsigned int fn = 0;
+	int i;
+
+	switch (priv->r.v7.pkt_id) {
+		case V7_PACKET_ID_IDLE:
+		case V7_PACKET_ID_NEW:
+			/*
+			 * No finger is reported when packet ID is 'IDLE' or 'New'.
+			 * An 'IDLE' packet indicates that there's no finger on touchpad.
+			 * A 'NEW' packet indicates there's finger placed or lifted.
+			 * Finger position of 'New' packet is not continues from the
+			 * previous packet.
+			 */
+			fn = 0;
+			break;
+		case V7_PACKET_ID_TWO:
+			if (f->pt_img[0].z == 0) {
+				/*
+				 * The first finger slot is zero when a non-resting
+				 * finger lifted and remaining only one resting finger
+				 * on touchpad. Hardware report the remaining resting
+				 * finger in second slot. This resting is ignored
+				 */
+				fn = 0;
+			} else if (f->pt_img[1].z == 0) {
+				/*
+				 * The second finger slot is zero if there's
+				 * only one finger
+				 */
+				fn = 1;
+			} else {
+				/* All non-resting fingers will be counted to report */
+				fn = 0;
+				for (i = 0; i < V7_IMG_PT_NUM; i++) {
+					if (priv->pt_attr[i].is_counted)
+						fn++;
+				}
+
+				/*
+				 * In the case that both fingers are
+				 * resting fingers, report the first one
+				 */
+				if (!priv->pt_attr[0].is_counted &&
+				    !priv->pt_attr[1].is_counted)
+				{
+					fn = 1;
+				}
+			}
+			break;
+		case V7_PACKET_ID_MULTI:
+			/*
+			 * A packet ID 'MULTI' indicats that at least 3 non-resting
+			 * finger exist.
+			 */
+			fn = 3 + priv->r.v7.additional_fingers;
+			break;
+	}
+
+	f->fingers = fn;
+}
+
+static void alps_button_dead_zone_filter(struct psmouse *psmouse,
+										 struct alps_fields *f,
+										 struct alps_fields *prev_f)
+{
+	struct alps_data *priv = psmouse->private;
+	int dx, dy;
+
+	if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
+		memcpy(&priv->pt_attr[0].init_dead_pt,
+			   &f->pt_img[0],
+			   sizeof(struct alps_abs_data));
+	}
+
+	if (priv->pt_attr[0].init_dead_pt.x != 0 &&
+	    priv->pt_attr[0].init_dead_pt.x != 0)
+	{
+		dx = f->pt_img[0].x - priv->pt_attr[0].init_dead_pt.x;
+		dy = f->pt_img[0].y - priv->pt_attr[0].init_dead_pt.y;
+		if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
+		    (abs(dy) > V7_DEAD_ZONE_OFFSET_Y))
+		{
+			memset(&priv->pt_attr[0].init_dead_pt, 0,
+				   sizeof(struct alps_abs_data));
+			priv->btn_delay_cnt = 0;
+		} else {
+			memcpy(&f->pt_img[0],
+				   &prev_f->pt_img[0],
+				   sizeof(struct alps_abs_data));
+			if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
+				priv->btn_delay_cnt = 2;
+		}
+	}
+
+	if (priv->btn_delay_cnt > 0) {
+		f->btn.left = 0;
+		f->btn.right = 0;
+		priv->btn_delay_cnt--;
+	}
+}
+
+static void alps_assign_buttons_v7(struct psmouse *psmouse,
+								   struct alps_fields *f,
+								   struct alps_fields *prev_f)
+{
+	struct alps_data *priv = psmouse->private;
+
+	if (priv->phy_btn) {
+		if (!priv->prev_phy_btn) {
+			/*
+			 * Report a right click as long as there's finger on
+			 * right button zone. Othrewise, report a left click.
+			 */
+			if (priv->r.v7.rest_right ||
+			    priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
+			    priv->pt_attr[1].zone & ZONE_RIGHT_BTN)
+			{
+				f->btn.right = 1;
+				priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
+			} else {
+				f->btn.left = 1;
+				priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
+			}
+		} else {
+			if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
+				f->btn.right = 1;
+			if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
+				f->btn.left = 1;
+		}
+	} else {
+		priv->pressed_btn_bits = 0;
+		f->btn.right = 0;
+		f->btn.left = 0;
+	}
+
+	alps_button_dead_zone_filter(psmouse, f, prev_f);
+
+	priv->prev_phy_btn = priv->phy_btn;
+}
+
+static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
+{
+	unsigned char    *packet = psmouse->packet;
+	struct alps_data *priv   = psmouse->private;
+	struct input_dev *dev    = priv->dev2;
+
+	int x, y;  /* trackstick vector */
+
+	/* Buttons status is reported for any packet */
+	input_report_key(dev, BTN_LEFT,  !!(0x01 & packet[1]));
+	input_report_key(dev, BTN_RIGHT, !!(0x02 & packet[1]));
+
+	/*
+	 * AlpsPS/2 v7 trackstick produces 2D relative coorinates
+	 * as signed integers (normal binary complement +1 encoding)
+	 */
+
+	x  = (0x3f & packet[2]);       /* low 6 bits */
+	x |= (0x10 & packet[3]) << 2;  /* bit 7      */
+	x |= (0x80 & packet[2]);       /* bit 8      */
+
+	/* x sign */
+	if (0x10 & packet[1])
+		x |= -1 << 8;
+
+	y  = (0x07 & packet[3]);       /* low 3 bits */
+	y |= (0x20 & packet[3]) >> 2;  /* bit 4      */
+	y |= (0x38 & packet[4]) << 1;  /* bits 5 - 7 */
+	y |= (0x80 & packet[4]);       /* bit 8      */
+
+	/* y sign */
+	if (0x20 & packet[1])
+		y |= -1 << 8;
+
+	/* Report trackstick vector */
+	input_report_rel(dev, REL_X,  x / 6);
+	input_report_rel(dev, REL_Y, -y / 8);
+
+	input_sync(dev);
+}
+
+static void alps_process_packet_v7(struct psmouse *psmouse)
+{
+	struct alps_data *priv = psmouse->private;
+	struct alps_fields f = {0};
+	static struct alps_fields prev_f;
+	unsigned char *packet = psmouse->packet;
+
+	/* Resolve packet ID */
+	priv->r.v7.pkt_id = alps_get_packet_id_v7(packet);
+
+	/* Process trackstick packet separately */
+	if (priv->r.v7.pkt_id == V7_PACKET_ID_TRACKSTICK)
+		return alps_process_trackstick_packet_v7(psmouse);
+
+	priv->decode_fields(&f, packet, psmouse);
+
+	if (alps_drop_unsupported_packet_v7(psmouse))
+		return;
+
+	alps_set_pt_attr_v7(psmouse, &f);
+
+	alps_cal_output_finger_num_v7(psmouse, &f);
+
+	alps_assign_buttons_v7(psmouse, &f, &prev_f);
+
+	alps_report_coord_and_btn(psmouse, &f);
+
+	memcpy(&prev_f, &f, sizeof(struct alps_fields));
+}
+
 static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
 					unsigned char packet[],
 					bool report_buttons)
@@ -1080,6 +1573,14 @@ static psmouse_ret_t alps_process_byte(s
 		return PSMOUSE_BAD_DATA;
 	}
 
+	if ((priv->proto_version == ALPS_PROTO_V7 &&
+	     !alps_is_valid_package_v7(psmouse))) {
+		psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
+		            psmouse->pktcnt - 1,
+		            psmouse->packet[psmouse->pktcnt - 1]);
+		return PSMOUSE_BAD_DATA;
+	}
+
 	if (psmouse->pktcnt == psmouse->pktsize) {
 		priv->process_packet(psmouse);
 		return PSMOUSE_FULL_PACKET;
@@ -1192,6 +1693,22 @@ static int alps_rpt_cmd(struct psmouse *
 	return 0;
 }
 
+static int alps_check_valid_firmware_id(unsigned char id[])
+{
+       int valid = 1;
+
+       if (id[0] == 0x73)
+               valid = 1;
+       else if (id[0] == 0x88) {
+               if ((id[1] == 0x07) ||
+                   (id[1] == 0x08) ||
+                   ((id[1] & 0xf0) == 0xB0))
+                       valid = 1;
+       }
+
+       return valid;
+}
+
 static int alps_enter_command_mode(struct psmouse *psmouse)
 {
 	unsigned char param[4];
@@ -1201,8 +1718,7 @@ static int alps_enter_command_mode(struc
 		return -1;
 	}
 
-	if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
-	    param[0] != 0x73) {
+	if (!alps_check_valid_firmware_id(param)) {
 		psmouse_dbg(psmouse,
 			    "unknown response while entering command mode\n");
 		return -1;
@@ -1704,6 +2220,36 @@ error:
 	return ret;
 }
 
+static int alps_hw_init_v7(struct psmouse *psmouse)
+{
+       struct ps2dev *ps2dev = &psmouse->ps2dev;
+       int reg_val, ret = -1;
+
+       if (alps_enter_command_mode(psmouse))
+               goto error;
+
+       reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
+       if (reg_val == -1)
+               goto error;
+
+       if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
+               goto error;
+
+       reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
+       if (reg_val == -1)
+               goto error;
+
+       if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
+               goto error;
+
+       alps_exit_command_mode(psmouse);
+       return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
+
+error:
+       alps_exit_command_mode(psmouse);
+       return ret;
+}
+
 /* Must be in command mode when calling this function */
 static int alps_absolute_mode_v4(struct psmouse *psmouse)
 {
@@ -1875,6 +2421,7 @@ static void alps_set_defaults(struct alp
 		priv->set_abs_params = alps_set_abs_params_st;
 		priv->x_max = 1023;
 		priv->y_max = 767;
+		priv->slot_number = 1;
 		break;
 	case ALPS_PROTO_V3:
 		priv->hw_init = alps_hw_init_v3;
@@ -1883,6 +2430,7 @@ static void alps_set_defaults(struct alp
 		priv->decode_fields = alps_decode_pinnacle;
 		priv->nibble_commands = alps_v3_nibble_commands;
 		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V4:
 		priv->hw_init = alps_hw_init_v4;
@@ -1890,6 +2438,7 @@ static void alps_set_defaults(struct alp
 		priv->set_abs_params = alps_set_abs_params_mt;
 		priv->nibble_commands = alps_v4_nibble_commands;
 		priv->addr_command = PSMOUSE_CMD_DISABLE;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V5:
 		priv->hw_init = alps_hw_init_dolphin_v1;
@@ -1905,6 +2454,7 @@ static void alps_set_defaults(struct alp
 		priv->y_max = 660;
 		priv->x_bits = 23;
 		priv->y_bits = 12;
+		priv->slot_number = 2;
 		break;
 	case ALPS_PROTO_V6:
 		priv->hw_init = alps_hw_init_v6;
@@ -1913,6 +2463,28 @@ static void alps_set_defaults(struct alp
 		priv->nibble_commands = alps_v6_nibble_commands;
 		priv->x_max = 2047;
 		priv->y_max = 1535;
+		priv->slot_number = 2;
+		break;
+	case ALPS_PROTO_V7:
+		priv->hw_init = alps_hw_init_v7;
+		priv->process_packet = alps_process_packet_v7;
+		priv->decode_fields = alps_decode_packet_v7;
+		priv->set_abs_params = alps_set_abs_params_mt;
+		priv->nibble_commands = alps_v3_nibble_commands;
+		priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+		priv->x_max = 0xfff;
+		priv->y_max = 0x7ff;
+		priv->resting_zone_y_min = 0x654;
+		priv->byte0 = 0x48;
+		priv->mask0 = 0x48;
+		priv->flags = 0;
+		priv->slot_number = 2;
+
+		priv->phy_btn = 0;
+		priv->prev_phy_btn = 0;
+		priv->btn_delay_cnt = 0;
+		priv->pressed_btn_bits = 0;
+		memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
 		break;
 	}
 }
@@ -1982,6 +2554,11 @@ static int alps_identify(struct psmouse
 			return -EIO;
 		else
 			return 0;
+	} else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
+		priv->proto_version = ALPS_PROTO_V7;
+		alps_set_defaults(priv);
+
+		return 0;
 	} else if (ec[0] == 0x88 && ec[1] == 0x08) {
 		priv->proto_version = ALPS_PROTO_V3;
 		alps_set_defaults(priv);
@@ -2045,7 +2622,7 @@ static void alps_set_abs_params_mt(struc
 				   struct input_dev *dev1)
 {
 	set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
-	input_mt_init_slots(dev1, 2, 0);
+	input_mt_init_slots(dev1, priv->slot_number, 0);
 	input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
 	input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
 
diff -upr a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
--- a/drivers/input/mouse/alps.h	2014-03-26 11:31:28.215133549 +0100
+++ b/drivers/input/mouse/alps.h	2014-03-25 20:08:10.875728761 +0100
@@ -18,11 +18,37 @@
 #define ALPS_PROTO_V4	4
 #define ALPS_PROTO_V5	5
 #define ALPS_PROTO_V6	6
+#define ALPS_PROTO_V7	7
+
+#define MAX_IMG_PT_NUM	5
+#define V7_IMG_PT_NUM	2
+
+#define ZONE_NORMAL		0x01
+#define ZONE_RESTING	0x02
+#define ZONE_LEFT_BTN	0x04
+#define ZONE_RIGHT_BTN	0x08
 
 #define DOLPHIN_COUNT_PER_ELECTRODE	64
 #define DOLPHIN_PROFILE_XOFFSET		8	/* x-electrode offset */
 #define DOLPHIN_PROFILE_YOFFSET		1	/* y-electrode offset */
 
+/*
+ * enum V7_PACKET_ID - defines the packet type for V7
+ * V7_PACKET_ID_IDLE: There's no finger and no button activity.
+ * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
+ *  or there's button activities.
+ * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
+ * V7_PACKET_ID_NEW: The finger position in slot is not continues from
+ *  previous packet.
+*/
+enum V7_PACKET_ID {
+	V7_PACKET_ID_IDLE,
+	V7_PACKET_ID_TWO,
+	V7_PACKET_ID_MULTI,
+	V7_PACKET_ID_NEW,
+	V7_PACKET_ID_TRACKSTICK,
+};
+
 /**
  * struct alps_model_info - touchpad ID table
  * @signature: E7 response string to match.
@@ -66,15 +92,7 @@ struct alps_nibble_commands {
 };
 
 /**
- * struct alps_fields - decoded version of the report packet
- * @x_map: Bitmap of active X positions for MT.
- * @y_map: Bitmap of active Y positions for MT.
- * @fingers: Number of fingers for MT.
- * @x: X position for ST.
- * @y: Y position for ST.
- * @z: Z position for ST.
- * @first_mp: Packet is the first of a multi-packet report.
- * @is_mp: Packet is part of a multi-packet report.
+ * struct alps_btn - decoded version of the button status
  * @left: Left touchpad button is active.
  * @right: Right touchpad button is active.
  * @middle: Middle touchpad button is active.
@@ -82,16 +100,7 @@ struct alps_nibble_commands {
  * @ts_right: Right trackstick button is active.
  * @ts_middle: Middle trackstick button is active.
  */
-struct alps_fields {
-	unsigned int x_map;
-	unsigned int y_map;
-	unsigned int fingers;
-	unsigned int x;
-	unsigned int y;
-	unsigned int z;
-	unsigned int first_mp:1;
-	unsigned int is_mp:1;
-
+struct alps_btn {
 	unsigned int left:1;
 	unsigned int right:1;
 	unsigned int middle:1;
@@ -102,6 +111,73 @@ struct alps_fields {
 };
 
 /**
+ * struct alps_btn - decoded version of the X Y Z postion for ST.
+ * @x: X position for ST.
+ * @y: Y position for ST.
+ * @z: Z position for ST.
+ */
+struct alps_abs_data {
+	unsigned int x;
+	unsigned int y;
+	unsigned int z;
+};
+
+/**
+ * struct alps_fields - decoded version of the report packet
+ * @fingers: Number of fingers for MT.
+ * @pt: X Y Z postion for ST.
+ * @pt: X Y Z postion for image MT.
+ * @x_map: Bitmap of active X positions for MT.
+ * @y_map: Bitmap of active Y positions for MT.
+ * @first_mp: Packet is the first of a multi-packet report.
+ * @is_mp: Packet is part of a multi-packet report.
+ * @btn: Button activity status
+ */
+struct alps_fields {
+	unsigned int fingers;
+	struct alps_abs_data pt;
+	struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
+	unsigned int x_map;
+	unsigned int y_map;
+	unsigned int first_mp:1;
+	unsigned int is_mp:1;
+	struct alps_btn btn;
+};
+
+/**
+ * struct v7_raw - data decoded from raw packet for V7.
+ * @pkt_id: An id that specifies the type of packet.
+ * @additional_fingers: Number of additional finger that is neighter included
+ *  in pt slot nor reflected in rest_left and rest_right flag of data packet.
+ * @rest_left: There are fingers on left resting zone.
+ * @rest_right: There are fingers on right resting zone.
+ * @raw_fn: The number of finger on touchpad.
+ */
+struct v7_raw {
+	unsigned char pkt_id;
+	unsigned int additional_fingers;
+	unsigned char rest_left;
+	unsigned char rest_right;
+	unsigned char raw_fn;
+};
+
+/**
+ * struct alps_bl_pt_attr - generic attributes of touch points for buttonless device
+ * @zone: The part of touchpad that the touch point locates
+ * @is_counted: The touch point is not a resting finger.
+ * @is_init_pt_got: The touch down point is got.
+ * @init_pt: The X Y Z position of the touch down point.
+ * @init_dead_pt: The touch down point of a finger used by dead zone process.
+ */
+struct alps_bl_pt_attr {
+	unsigned char zone;
+	unsigned char is_counted;
+	unsigned char is_init_pt_got;
+	struct alps_abs_data init_pt;
+	struct alps_abs_data init_dead_pt;
+};
+
+/**
  * struct alps_data - private data structure for the ALPS driver
  * @dev2: "Relative" device used to report trackstick or mouse activity.
  * @phys: Physical path for the relative device.
@@ -116,8 +192,10 @@ struct alps_fields {
  * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
  * @x_max: Largest possible X position value.
  * @y_max: Largest possible Y position value.
+ * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
  * @x_bits: Number of X bits in the MT bitmap.
  * @y_bits: Number of Y bits in the MT bitmap.
+ * @img_fingers: Number of image fingers.
  * @hw_init: Protocol-specific hardware init function.
  * @process_packet: Protocol-specific function to process a report packet.
  * @decode_fields: Protocol-specific function to read packet bitfields.
@@ -132,6 +210,11 @@ struct alps_fields {
  * @fingers: Number of fingers from last MT report.
  * @quirks: Bitmap of ALPS_QUIRK_*.
  * @timer: Timer for flushing out the final report packet in the stream.
+ * @v7: Data decoded from raw packet for V7
+ * @phy_btn: Physical button is active.
+ * @prev_phy_btn: Physical button of previous packet is active.
+ * @pressed_btn_bits: Pressed positon of button zone
+ * @pt_attr: Generic attributes of touch points for buttonless device.
  */
 struct alps_data {
 	struct input_dev *dev2;
@@ -145,8 +228,10 @@ struct alps_data {
 	unsigned char flags;
 	int x_max;
 	int y_max;
+	int resting_zone_y_min;
 	int x_bits;
 	int y_bits;
+	unsigned char slot_number;
 
 	int (*hw_init)(struct psmouse *psmouse);
 	void (*process_packet)(struct psmouse *psmouse);
@@ -161,6 +246,16 @@ struct alps_data {
 	int fingers;
 	u8 quirks;
 	struct timer_list timer;
+
+	/* these are used for buttonless touchpad*/
+	union {
+		struct v7_raw v7;
+	} r;
+	unsigned char phy_btn;
+	unsigned char prev_phy_btn;
+	unsigned char btn_delay_cnt;
+	unsigned char pressed_btn_bits;
+	struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
 };
 
 #define ALPS_QUIRK_TRACKSTICK_BUTTONS	1 /* trakcstick buttons in trackstick packet */

^ permalink raw reply

* [PATCH] Input: mousedev - fix race when creating mixed device
From: Dmitry Torokhov @ 2014-03-26 16:13 UTC (permalink / raw)
  To: linux-input; +Cc: linux-kernel

We should not be using static variable mousedev_mix in methods that can be
called before that singleton gets assigned. While at it let's add open and
close methods to mousedev structure so that we do not need to test if we
are dealing with multiplexor or normal device and simply call appropriate
method directly.

Reported-by: depasquale.giulio@gmail.com
Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/mousedev.c | 73 ++++++++++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 31 deletions(-)

diff --git a/drivers/input/mousedev.c b/drivers/input/mousedev.c
index 4c842c3..b604564 100644
--- a/drivers/input/mousedev.c
+++ b/drivers/input/mousedev.c
@@ -67,7 +67,6 @@ struct mousedev {
 	struct device dev;
 	struct cdev cdev;
 	bool exist;
-	bool is_mixdev;
 
 	struct list_head mixdev_node;
 	bool opened_by_mixdev;
@@ -77,6 +76,9 @@ struct mousedev {
 	int old_x[4], old_y[4];
 	int frac_dx, frac_dy;
 	unsigned long touch;
+
+	int (*open_device)(struct mousedev *mousedev);
+	void (*close_device)(struct mousedev *mousedev);
 };
 
 enum mousedev_emul {
@@ -116,9 +118,6 @@ static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 static struct mousedev *mousedev_mix;
 static LIST_HEAD(mousedev_mix_list);
 
-static void mixdev_open_devices(void);
-static void mixdev_close_devices(void);
-
 #define fx(i)  (mousedev->old_x[(mousedev->pkt_count - (i)) & 03])
 #define fy(i)  (mousedev->old_y[(mousedev->pkt_count - (i)) & 03])
 
@@ -428,9 +427,7 @@ static int mousedev_open_device(struct mousedev *mousedev)
 	if (retval)
 		return retval;
 
-	if (mousedev->is_mixdev)
-		mixdev_open_devices();
-	else if (!mousedev->exist)
+	if (!mousedev->exist)
 		retval = -ENODEV;
 	else if (!mousedev->open++) {
 		retval = input_open_device(&mousedev->handle);
@@ -446,9 +443,7 @@ static void mousedev_close_device(struct mousedev *mousedev)
 {
 	mutex_lock(&mousedev->mutex);
 
-	if (mousedev->is_mixdev)
-		mixdev_close_devices();
-	else if (mousedev->exist && !--mousedev->open)
+	if (mousedev->exist && !--mousedev->open)
 		input_close_device(&mousedev->handle);
 
 	mutex_unlock(&mousedev->mutex);
@@ -459,21 +454,29 @@ static void mousedev_close_device(struct mousedev *mousedev)
  * stream. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_open_devices(void)
+static int mixdev_open_devices(struct mousedev *mixdev)
 {
-	struct mousedev *mousedev;
+	int error;
+
+	error = mutex_lock_interruptible(&mixdev->mutex);
+	if (error)
+		return error;
 
-	if (mousedev_mix->open++)
-		return;
+	if (!mixdev->open++) {
+		struct mousedev *mousedev;
 
-	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-		if (!mousedev->opened_by_mixdev) {
-			if (mousedev_open_device(mousedev))
-				continue;
+		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+			if (!mousedev->opened_by_mixdev) {
+				if (mousedev_open_device(mousedev))
+					continue;
 
-			mousedev->opened_by_mixdev = true;
+				mousedev->opened_by_mixdev = true;
+			}
 		}
 	}
+
+	mutex_unlock(&mixdev->mutex);
+	return 0;
 }
 
 /*
@@ -481,19 +484,22 @@ static void mixdev_open_devices(void)
  * device. Note that this function is called with mousedev_mix->mutex
  * held.
  */
-static void mixdev_close_devices(void)
+static void mixdev_close_devices(struct mousedev *mixdev)
 {
-	struct mousedev *mousedev;
+	mutex_lock(&mixdev->mutex);
 
-	if (--mousedev_mix->open)
-		return;
+	if (!--mixdev->open) {
+		struct mousedev *mousedev;
 
-	list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
-		if (mousedev->opened_by_mixdev) {
-			mousedev->opened_by_mixdev = false;
-			mousedev_close_device(mousedev);
+		list_for_each_entry(mousedev, &mousedev_mix_list, mixdev_node) {
+			if (mousedev->opened_by_mixdev) {
+				mousedev->opened_by_mixdev = false;
+				mousedev_close_device(mousedev);
+			}
 		}
 	}
+
+	mutex_unlock(&mixdev->mutex);
 }
 
 
@@ -522,7 +528,7 @@ static int mousedev_release(struct inode *inode, struct file *file)
 	mousedev_detach_client(mousedev, client);
 	kfree(client);
 
-	mousedev_close_device(mousedev);
+	mousedev->close_device(mousedev);
 
 	return 0;
 }
@@ -550,7 +556,7 @@ static int mousedev_open(struct inode *inode, struct file *file)
 	client->mousedev = mousedev;
 	mousedev_attach_client(mousedev, client);
 
-	error = mousedev_open_device(mousedev);
+	error = mousedev->open_device(mousedev);
 	if (error)
 		goto err_free_client;
 
@@ -861,16 +867,21 @@ static struct mousedev *mousedev_create(struct input_dev *dev,
 
 	if (mixdev) {
 		dev_set_name(&mousedev->dev, "mice");
+
+		mousedev->open_device = mixdev_open_devices;
+		mousedev->close_device = mixdev_close_devices;
 	} else {
 		int dev_no = minor;
 		/* Normalize device number if it falls into legacy range */
 		if (dev_no < MOUSEDEV_MINOR_BASE + MOUSEDEV_MINORS)
 			dev_no -= MOUSEDEV_MINOR_BASE;
 		dev_set_name(&mousedev->dev, "mouse%d", dev_no);
+
+		mousedev->open_device = mousedev_open_device;
+		mousedev->close_device = mousedev_close_device;
 	}
 
 	mousedev->exist = true;
-	mousedev->is_mixdev = mixdev;
 	mousedev->handle.dev = input_get_device(dev);
 	mousedev->handle.name = dev_name(&mousedev->dev);
 	mousedev->handle.handler = handler;
@@ -919,7 +930,7 @@ static void mousedev_destroy(struct mousedev *mousedev)
 	device_del(&mousedev->dev);
 	mousedev_cleanup(mousedev);
 	input_free_minor(MINOR(mousedev->dev.devt));
-	if (!mousedev->is_mixdev)
+	if (mousedev != mousedev_mix)
 		input_unregister_handle(&mousedev->handle);
 	put_device(&mousedev->dev);
 }
-- 
1.8.5.3


-- 
Dmitry

^ permalink raw reply related

* Re: [PATCH v3] touchscreen: tps6507x-ts: only poll while touch event is occurring
From: Jon Ringle @ 2014-03-26 16:55 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input, linux-kernel@vger.kernel.org; +Cc: Jon Ringle
In-Reply-To: <1394006982-30184-1-git-send-email-jon@ringle.org>

I've not heard anything regarding this patch. I just want to make sure
it doesn't get lost :)

Jon

On Wed, Mar 5, 2014 at 3:09 AM,  <jon@ringle.org> wrote:
> From: Jon Ringle <jringle@gridpoint.com>
>
> (Resending without corporate dislaimer in email footer)
>
> We only need to poll for touch events after an interrupt occurs due to the
> user touching the screen. We continue to poll until the user stops touching
> the screen
>
> Signed-off-by: Jon Ringle <jringle@gridpoint.com>
> ---
>  drivers/input/touchscreen/tps6507x-ts.c | 189 +++++++++++++++++++++++++-------
>  include/linux/input/tps6507x-ts.h       |   1 +
>  include/linux/mfd/tps6507x.h            |   1 +
>  3 files changed, 151 insertions(+), 40 deletions(-)
>
> diff --git a/drivers/input/touchscreen/tps6507x-ts.c b/drivers/input/touchscreen/tps6507x-ts.c
> index 94cde2c..c051419 100644
> --- a/drivers/input/touchscreen/tps6507x-ts.c
> +++ b/drivers/input/touchscreen/tps6507x-ts.c
> @@ -17,11 +17,14 @@
>  #include <linux/workqueue.h>
>  #include <linux/slab.h>
>  #include <linux/input.h>
> -#include <linux/input-polldev.h>
>  #include <linux/platform_device.h>
>  #include <linux/mfd/tps6507x.h>
>  #include <linux/input/tps6507x-ts.h>
>  #include <linux/delay.h>
> +#include <linux/gpio.h>
> +#include <linux/i2c.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
>
>  #define TSC_DEFAULT_POLL_PERIOD 30 /* ms */
>  #define TPS_DEFAULT_MIN_PRESSURE 0x30
> @@ -39,13 +42,17 @@ struct ts_event {
>  };
>
>  struct tps6507x_ts {
> +       struct input_dev        *input_dev;
>         struct device           *dev;
> -       struct input_polled_dev *poll_dev;
>         struct tps6507x_dev     *mfd;
>         char                    phys[32];
> +       struct delayed_work     work;
>         struct ts_event         tc;
> +       int                     irq;
> +       unsigned long           poll_period;    /* ms */
>         u16                     min_pressure;
>         bool                    pendown;
> +       int                     open_count;
>  };
>
>  static int tps6507x_read_u8(struct tps6507x_ts *tsc, u8 reg, u8 *data)
> @@ -155,13 +162,20 @@ static s32 tps6507x_adc_standby(struct tps6507x_ts *tsc)
>         return ret;
>  }
>
> -static void tps6507x_ts_poll(struct input_polled_dev *poll_dev)
> +static void tps6507x_ts_handler(struct work_struct *work)
>  {
> -       struct tps6507x_ts *tsc = poll_dev->private;
> -       struct input_dev *input_dev = poll_dev->input;
> +       struct tps6507x_ts *tsc =  container_of(work, struct tps6507x_ts, work.work);
> +       struct input_dev *input_dev = tsc->input_dev;
>         bool pendown;
> +       int schd;
> +       int poll = 0;
>         s32 ret;
>
> +       if (tsc->irq) {
> +               // Disable the touch interrupt
> +               tps6507x_write_u8(tsc, TPS6507X_REG_INT, 0);
> +       }
> +
>         ret = tps6507x_adc_conversion(tsc, TPS6507X_TSCMODE_PRESSURE,
>                                       &tsc->tc.pressure);
>         if (ret)
> @@ -178,10 +192,11 @@ static void tps6507x_ts_poll(struct input_polled_dev *poll_dev)
>         }
>
>         if (pendown) {
> +               int report_pendown = 0;
>
>                 if (!tsc->pendown) {
>                         dev_dbg(tsc->dev, "DOWN\n");
> -                       input_report_key(input_dev, BTN_TOUCH, 1);
> +                       report_pendown = 1;
>                 } else
>                         dev_dbg(tsc->dev, "still down\n");
>
> @@ -195,15 +210,86 @@ static void tps6507x_ts_poll(struct input_polled_dev *poll_dev)
>                 if (ret)
>                         goto done;
>
> -               input_report_abs(input_dev, ABS_X, tsc->tc.x);
> -               input_report_abs(input_dev, ABS_Y, tsc->tc.y);
> -               input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
> -               input_sync(input_dev);
> -               tsc->pendown = true;
> +               if (tsc->tc.x && tsc->tc.y) {
> +                       if (report_pendown)
> +                               input_report_key(input_dev, BTN_TOUCH, 1);
> +
> +                       input_report_abs(input_dev, ABS_X, tsc->tc.x);
> +                       input_report_abs(input_dev, ABS_Y, tsc->tc.y);
> +                       input_report_abs(input_dev, ABS_PRESSURE, tsc->tc.pressure);
> +                       input_sync(input_dev);
> +                       tsc->pendown = true;
> +               } else {
> +                       dev_dbg(tsc->dev, "discarding bogus read x=%d, y=%d, pressure=%d\n", tsc->tc.x, tsc->tc.y, tsc->tc.pressure);
> +               }
> +               poll = 1;
>         }
>
>  done:
>         tps6507x_adc_standby(tsc);
> +       if (tsc->irq && !poll) {
> +               // Re-enable the interrupt
> +               tps6507x_write_u8(tsc, TPS6507X_REG_INT, TPS6507X_REG_MASK_TSC);
> +       } else {
> +               /* always poll if not using interrupts */
> +               schd = schedule_delayed_work(&tsc->work,
> +                                            msecs_to_jiffies(tsc->poll_period));
> +       }
> +}
> +
> +static irqreturn_t tps6507x_ts_irq(int irq, void * dev_id)
> +{
> +       struct tps6507x_ts * tsc = (struct tps6507x_ts *)dev_id;
> +
> +       schedule_delayed_work(&tsc->work, 0);
> +
> +       return IRQ_HANDLED;
> +}
> +
> +static int tps6507x_ts_open(struct input_dev *input_dev)
> +{
> +       int ret;
> +       struct tps6507x_ts *tsc = input_get_drvdata(input_dev);
> +
> +       tsc->open_count++;
> +
> +       if (tsc->irq) {
> +
> +               tps6507x_write_u8(tsc, TPS6507X_REG_INT, 0);
> +               tps6507x_adc_standby(tsc);
> +
> +               ret = request_irq(tsc->irq,tps6507x_ts_irq, 0, "TPS6507x",tsc);
> +
> +               if(ret < 0) {
> +                       tsc->open_count--;
> +                       dev_err(tsc->dev, "cannot register irq");
> +                       return ret;
> +               }
> +               // Enable the touch event interrupt
> +               tps6507x_write_u8(tsc, TPS6507X_REG_INT, TPS6507X_REG_MASK_TSC);
> +       } else {
> +               ret = schedule_delayed_work(&tsc->work,
> +                                           msecs_to_jiffies(tsc->poll_period));
> +
> +               if (!ret) {
> +                       tsc->open_count--;
> +                       dev_err(tsc->dev, "schedule failed");
> +                       return -ENOMEM;
> +               }
> +       }
> +
> +       return 0;
> +}
> +
> +static void tps6507x_ts_close(struct input_dev *input_dev)
> +{
> +       struct tps6507x_ts *tsc = input_get_drvdata(input_dev);
> +
> +       tsc->open_count--;
> +
> +       if(tsc->irq) {
> +               free_irq(tsc->irq,tsc);
> +       }
>  }
>
>  static int tps6507x_ts_probe(struct platform_device *pdev)
> @@ -212,8 +298,8 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
>         const struct tps6507x_board *tps_board;
>         const struct touchscreen_init_data *init_data;
>         struct tps6507x_ts *tsc;
> -       struct input_polled_dev *poll_dev;
>         struct input_dev *input_dev;
> +       int schd;
>         int error;
>
>         /*
> @@ -239,29 +325,18 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
>                 return -ENOMEM;
>         }
>
> +       tps6507x_dev->ts = tsc;
>         tsc->mfd = tps6507x_dev;
>         tsc->dev = tps6507x_dev->dev;
> -       tsc->min_pressure = init_data ?
> -                       init_data->min_pressure : TPS_DEFAULT_MIN_PRESSURE;
> -
> -       snprintf(tsc->phys, sizeof(tsc->phys),
> -                "%s/input0", dev_name(tsc->dev));
> -
> -       poll_dev = input_allocate_polled_device();
> -       if (!poll_dev) {
> -               dev_err(tsc->dev, "Failed to allocate polled input device.\n");
> +       input_dev = input_allocate_device();
> +       if (!input_dev) {
> +               dev_err(tsc->dev, "Failed to allocate input device.\n");
>                 error = -ENOMEM;
>                 goto err_free_mem;
>         }
>
> -       tsc->poll_dev = poll_dev;
> -
> -       poll_dev->private = tsc;
> -       poll_dev->poll = tps6507x_ts_poll;
> -       poll_dev->poll_interval = init_data ?
> -                       init_data->poll_period : TSC_DEFAULT_POLL_PERIOD;
> -
> -       input_dev = poll_dev->input;
> +       input_dev->open = tps6507x_ts_open;
> +       input_dev->close = tps6507x_ts_close;
>         input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
>         input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
>
> @@ -270,42 +345,76 @@ static int tps6507x_ts_probe(struct platform_device *pdev)
>         input_set_abs_params(input_dev, ABS_PRESSURE, 0, MAX_10BIT, 0, 0);
>
>         input_dev->name = "TPS6507x Touchscreen";
> -       input_dev->phys = tsc->phys;
> -       input_dev->dev.parent = tsc->dev;
>         input_dev->id.bustype = BUS_I2C;
> +       input_dev->dev.parent = tsc->dev;
> +
> +       snprintf(tsc->phys, sizeof(tsc->phys),
> +                "%s/input0", dev_name(tsc->dev));
> +       input_dev->phys = tsc->phys;
> +
> +       dev_dbg(tsc->dev, "device: %s\n", input_dev->phys);
> +
> +       input_set_drvdata(input_dev, tsc);
> +
> +       tsc->input_dev = input_dev;
> +
> +       INIT_DELAYED_WORK(&tsc->work, tps6507x_ts_handler);
>         if (init_data) {
> +               tsc->poll_period = init_data->poll_period;
> +               tsc->irq = gpio_to_irq(init_data->irq_pin);
> +               tsc->min_pressure = init_data->min_pressure;
>                 input_dev->id.vendor = init_data->vendor;
>                 input_dev->id.product = init_data->product;
>                 input_dev->id.version = init_data->version;
> +       } else {
> +               tsc->poll_period = TSC_DEFAULT_POLL_PERIOD;
> +               tsc->min_pressure = TPS_DEFAULT_MIN_PRESSURE;
>         }
>
>         error = tps6507x_adc_standby(tsc);
>         if (error)
> -               goto err_free_polled_dev;
> +               goto err_free_dev;
>
> -       error = input_register_polled_device(poll_dev);
> +       error = input_register_device(input_dev);
>         if (error)
> -               goto err_free_polled_dev;
> +               goto err_free_dev;
> +
> +       if (!tsc->irq) {
> +               schd = schedule_delayed_work(&tsc->work,
> +                                            msecs_to_jiffies(tsc->poll_period));
> +
> +               if (!schd) {
> +                       dev_err(tsc->dev, "schedule failed");
> +                       goto err_cancel_work;
> +               }
> +       }
>
>         platform_set_drvdata(pdev, tsc);
>
>         return 0;
>
> -err_free_polled_dev:
> -       input_free_polled_device(poll_dev);
> +err_cancel_work:
> +       cancel_delayed_work_sync(&tsc->work);
> +err_free_dev:
> +       input_free_device(input_dev);
>  err_free_mem:
>         kfree(tsc);
> +       tps6507x_dev->ts = NULL;
> +
>         return error;
>  }
>
>  static int tps6507x_ts_remove(struct platform_device *pdev)
>  {
> -       struct tps6507x_ts *tsc = platform_get_drvdata(pdev);
> -       struct input_polled_dev *poll_dev = tsc->poll_dev;
> +       struct tps6507x_dev *tps6507x_dev = platform_get_drvdata(pdev);
> +       struct tps6507x_ts *tsc = tps6507x_dev->ts;
> +       struct input_dev *input_dev = tsc->input_dev;
> +
> +       cancel_delayed_work_sync(&tsc->work);
>
> -       input_unregister_polled_device(poll_dev);
> -       input_free_polled_device(poll_dev);
> +       input_unregister_device(input_dev);
>
> +       tps6507x_dev->ts = NULL;
>         kfree(tsc);
>
>         return 0;
> diff --git a/include/linux/input/tps6507x-ts.h b/include/linux/input/tps6507x-ts.h
> index b433df8..3c5aa7b 100644
> --- a/include/linux/input/tps6507x-ts.h
> +++ b/include/linux/input/tps6507x-ts.h
> @@ -14,6 +14,7 @@
>  /* Board specific touch screen initial values */
>  struct touchscreen_init_data {
>         int     poll_period;    /* ms */
> +       int     irq_pin;
>         __u16   min_pressure;   /* min reading to be treated as a touch */
>         __u16   vendor;
>         __u16   product;
> diff --git a/include/linux/mfd/tps6507x.h b/include/linux/mfd/tps6507x.h
> index c2ae569..c923e486 100644
> --- a/include/linux/mfd/tps6507x.h
> +++ b/include/linux/mfd/tps6507x.h
> @@ -163,6 +163,7 @@ struct tps6507x_dev {
>
>         /* Client devices */
>         struct tps6507x_pmic *pmic;
> +       struct tps6507x_ts *ts;
>  };
>
>  #endif /*  __LINUX_MFD_TPS6507X_H */
> --
> 1.8.5.4
>

^ permalink raw reply

* Re: [PATCH] input: misc: Add driver for Intel Bay Trail GPIO buttons
From: One Thousand Gnomes @ 2014-03-26 17:04 UTC (permalink / raw)
  To: Zhu, Lejun; +Cc: Dmitry Torokhov, linux-kernel, linux-input
In-Reply-To: <53325F30.4030006@linux.intel.com>

On Wed, 26 Mar 2014 13:01:36 +0800
"Zhu, Lejun" <lejun.zhu@linux.intel.com> wrote:

> This patch adds support for the GPIO buttons on some Intel Bay Trail
> tablets originally running Windows 8. The ACPI description of these
> buttons follows "Windows ACPI Design Guide for SoC Platforms".

I'm not sure calling it "Baytrail" is right here - it's in theory a
generic interface so probably should be named accordingly

Otherwise looks good to me.

Alan

^ permalink raw reply

* Re: [PATCH] input: misc: Add driver for Intel Bay Trail GPIO buttons
From: Dmitry Torokhov @ 2014-03-26 20:20 UTC (permalink / raw)
  To: One Thousand Gnomes; +Cc: Zhu, Lejun, linux-kernel, linux-input
In-Reply-To: <20140326170404.47a6380a@alan.etchedpixels.co.uk>

On Wed, Mar 26, 2014 at 05:04:04PM +0000, One Thousand Gnomes wrote:
> On Wed, 26 Mar 2014 13:01:36 +0800
> "Zhu, Lejun" <lejun.zhu@linux.intel.com> wrote:
> 
> > This patch adds support for the GPIO buttons on some Intel Bay Trail
> > tablets originally running Windows 8. The ACPI description of these
> > buttons follows "Windows ACPI Design Guide for SoC Platforms".
> 
> I'm not sure calling it "Baytrail" is right here - it's in theory a
> generic interface so probably should be named accordingly
> 
> Otherwise looks good to me.

It uses static devices in non-board code - if I unbind and rebind PNP
device that produces gpio-keys platform devices driver core will not be
happy.

Thanks.

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] input synaptics-rmi4: Trivial F11 tidy up
From: Dmitry Torokhov @ 2014-03-01 18:41 UTC (permalink / raw)
  To: Christopher Heiny
  Cc: Linux Input, Andrew Duggan, Vincent Huang, Vivian Ly,
	Daniel Rosenberg, Linus Walleij
In-Reply-To: <1393366096-5524-1-git-send-email-cheiny@synaptics.com>

On Tue, Feb 25, 2014 at 02:08:16PM -0800, Christopher Heiny wrote:
> Delete an unused symbol and update copyright date.
> 
> Signed-off-by: Christopher Heiny <cheiny@synaptics.com>
> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com>

Applied, thank you.

> 
> --
> 
>  drivers/input/rmi4/rmi_f11.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)
> 
> diff --git a/drivers/input/rmi4/rmi_f11.c b/drivers/input/rmi4/rmi_f11.c
> index 2aa7d17..9cc1406 100644
> --- a/drivers/input/rmi4/rmi_f11.c
> +++ b/drivers/input/rmi4/rmi_f11.c
> @@ -1,5 +1,5 @@
>  /*
> - * Copyright (c) 2011-2013 Synaptics Incorporated
> + * Copyright (c) 2011-2014 Synaptics Incorporated
>   * Copyright (c) 2011 Unixphere
>   *
>   * This program is free software; you can redistribute it and/or modify it
> @@ -7,8 +7,6 @@
>   * the Free Software Foundation.
>   */
>  
> -#define FUNCTION_DATA f11_data
> -
>  #include <linux/kernel.h>
>  #include <linux/delay.h>
>  #include <linux/device.h>

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH] drivers/input: Use RCU_INIT_POINTER(x, NULL) in evdev.c
From: Dmitry Torokhov @ 2014-03-26 20:30 UTC (permalink / raw)
  To: Monam Agarwal; +Cc: linux-input, linux-kernel
In-Reply-To: <1395599177-6776-1-git-send-email-monamagarwal123@gmail.com>

Hi Monam,

On Sun, Mar 23, 2014 at 11:56:17PM +0530, Monam Agarwal wrote:
> This patch replaces rcu_assign_pointer(x, NULL) with RCU_INIT_POINTER(x, NULL)
> 
> The rcu_assign_pointer() ensures that the initialization of a structure       
> is carried out before storing a pointer to that structure. 
> And in the case of the NULL pointer, there is no structure to initialize. 
> So, rcu_assign_pointer(p, NULL) can be safely converted to RCU_INIT_POINTER(p, NULL)

Logically speaking we perform assignment, not initialization there.
Since we are not in hot path I think we should leave the code as is.

Thanks.

> 
> Signed-off-by: Monam Agarwal <monamagarwal123@gmail.com>
> ---
>  drivers/input/evdev.c |    2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
> index a06e125..fffa107 100644
> --- a/drivers/input/evdev.c
> +++ b/drivers/input/evdev.c
> @@ -291,7 +291,7 @@ static int evdev_ungrab(struct evdev *evdev, struct evdev_client *client)
>  	if (grab != client)
>  		return  -EINVAL;
>  
> -	rcu_assign_pointer(evdev->grab, NULL);
> +	RCU_INIT_POINTER(evdev->grab, NULL);
>  	synchronize_rcu();
>  	input_release_device(&evdev->handle);
>  
> -- 
> 1.7.9.5
> 

-- 
Dmitry

^ permalink raw reply

* [PATCH v2] HID: quirk for Saitek RAT7 and MMO7 mices' mode button
From: Harald Brinkmann @ 2014-03-26 22:53 UTC (permalink / raw)
  To: Benjamin Tissoires; +Cc: Jiri Kosina, linux-input, linux-kernel, Darren Salt

Hi all,

and thanks for the pointers, Benjamin. I finally had some time to fix it.
- Moved the quirk to hid-saitek
- Tracking the mode and setting only one bit on a mode change in .raw_event
- Generating instant release events for the button in .event

One question:
Is there any way other than loading hid-saitek before hid-generic to ensure
the device is claimed by the more specific driver?

And a call for data:
My R.A.T.7 has an USB device ID of 0cd7. Not 0ccb as this patch [1] suggests.
If someone sends me the HID report descriptor (acquired with
'libhid-detach-device 06a3:0ccb && lsusb -d 06a3:0ccb -vvv'), and 
a trace generated with hid-recorder [2] containing three consecutive mode
button presses, I will add support for that version.

[1] https://patchwork.kernel.org/patch/653481/
[2] http://bentiss.github.io/hid-replay-docs/

Some saitek mice implement a tristate button (for switching button
mappings in the original driver) by keeping one of three (non-physical)
buttons constantly pressed.
This breaks X and probably other userspace software.
This patch implements a quirk for the R.A.T.7 and M.M.O.7, tracking
the mode and generating presses of a single button if it changes.
Also the missing release event is generated instantly.

Signed-off-by: Harald Brinkmann <hbrinkmann@braincalibration.de>
---
 drivers/hid/Kconfig      |    5 -
 drivers/hid/hid-ids.h    |    2 
 drivers/hid/hid-saitek.c |  154 +++++++++++++++++++++++++++++++++++--
 3 files changed, 153 insertions(+), 8 deletions(-)

diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index f722001..99df241 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -599,7 +599,10 @@ config HID_SAITEK
 	Support for Saitek devices that are not fully compliant with the
 	HID standard.
 
-	Currently only supports the PS1000 controller.
+	Supported devices:
+	- PS1000 Dual Analog Pad
+	- R.A.T.7 Gaming Mouse
+	- M.M.O.7 Gaming Mouse
 
 config HID_SAMSUNG
 	tristate "Samsung InfraRed remote control or keyboards"
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 22f28d6..307352d 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -757,6 +757,8 @@
 #define USB_VENDOR_ID_SAITEK		0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD	0xff17
 #define USB_DEVICE_ID_SAITEK_PS1000	0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7	0x0cd7
+#define USB_DEVICE_ID_SAITEK_MMO7	0x0cd0
 
 #define USB_VENDOR_ID_SAMSUNG		0x0419
 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE	0x0001
diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c
index 37961c7..69cca14 100644
--- a/drivers/hid/hid-saitek.c
+++ b/drivers/hid/hid-saitek.c
@@ -1,10 +1,17 @@
 /*
- *  HID driver for Saitek devices, currently only the PS1000 (USB gamepad).
+ *  HID driver for Saitek devices.
+ *
+ *  PS1000 (USB gamepad):
  *  Fixes the HID report descriptor by removing a non-existent axis and
  *  clearing the constant bit on the input reports for buttons and d-pad.
  *  (This module is based on "hid-ortek".)
- *
  *  Copyright (c) 2012 Andreas Hübner
+ *
+ *  R.A.T.7, M.M.O.7 (USB gaming mice):
+ *  Fixes the mode button which cycles through three constantly pressed
+ *  buttons. All three press events are mapped to one button and the
+ *  missing release event is generated immediately.
+ *
  */
 
 /*
@@ -21,12 +28,57 @@
 
 #include "hid-ids.h"
 
+#define SAITEK_FIX_PS1000	0x0001
+#define SAITEK_RELEASE_MODE_RAT7	0x0002
+#define SAITEK_RELEASE_MODE_MMO7	0x0004
+
+struct saitek_sc {
+	unsigned long quirks;
+	int mode;
+};
+
+static int saitek_probe(struct hid_device *hdev,
+		const struct hid_device_id *id)
+{
+	unsigned long quirks = id->driver_data;
+	struct saitek_sc *ssc;
+	int ret;
+
+	ssc = devm_kzalloc(&hdev->dev, sizeof(*ssc), GFP_KERNEL);
+	if (ssc == NULL) {
+		hid_err(hdev, "can't alloc saitek descriptor\n");
+		return -ENOMEM;
+	}
+
+	ssc->quirks = quirks;
+	ssc->mode = -1;
+
+	hid_set_drvdata(hdev, ssc);
+
+	ret = hid_parse(hdev);
+	if (ret) {
+		hid_err(hdev, "parse failed\n");
+		return ret;
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		hid_err(hdev, "hw start failed\n");
+		return ret;
+	}
+
+	return 0;
+}
+
 static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 		unsigned int *rsize)
 {
-	if (*rsize == 137 && rdesc[20] == 0x09 && rdesc[21] == 0x33
-			&& rdesc[94] == 0x81 && rdesc[95] == 0x03
-			&& rdesc[110] == 0x81 && rdesc[111] == 0x03) {
+	struct saitek_sc *ssc = hid_get_drvdata(hdev);
+
+	if ((ssc->quirks & SAITEK_FIX_PS1000) && *rsize == 137 &&
+			rdesc[20] == 0x09 && rdesc[21] == 0x33 &&
+			rdesc[94] == 0x81 && rdesc[95] == 0x03 &&
+			rdesc[110] == 0x81 && rdesc[111] == 0x03) {
 
 		hid_info(hdev, "Fixing up Saitek PS1000 report descriptor\n");
 
@@ -42,8 +94,93 @@ static __u8 *saitek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 	return rdesc;
 }
 
+static int saitek_raw_event(struct hid_device *hdev,
+		struct hid_report *report, u8 *raw_data, int size)
+{
+	struct saitek_sc *ssc = hid_get_drvdata(hdev);
+
+	if (ssc->quirks & SAITEK_RELEASE_MODE_RAT7 && size == 7) {
+		/* R.A.T.7 uses bits 13, 14, 15 for the mode */
+		int mode = -1;
+		if (raw_data[1] & 0x01)
+			mode = 0;
+		else if (raw_data[1] & 0x02)
+			mode = 1;
+		else if (raw_data[1] & 0x04)
+			mode = 2;
+
+		/* clear mode bits */
+		raw_data[1] &= ~0x07;
+
+		if (mode != ssc->mode) {
+			hid_dbg(hdev, "entered mode %d\n", mode);
+			if (ssc->mode != -1) {
+				/* use bit 13 as the mode button */
+				raw_data[1] |= 0x04;
+			}
+			ssc->mode = mode;
+		}
+	} else if (ssc->quirks & SAITEK_RELEASE_MODE_MMO7 && size == 8) {
+
+		/* M.M.O.7 uses bits 8, 22, 23 for the mode */
+		int mode = -1;
+		if (raw_data[1] & 0x80)
+			mode = 0;
+		else if (raw_data[2] & 0x01)
+			mode = 1;
+		else if (raw_data[2] & 0x02)
+			mode = 2;
+
+		/* clear mode bits */
+		raw_data[1] &= ~0x80;
+		raw_data[2] &= ~0x03;
+
+		if (mode != ssc->mode) {
+			hid_dbg(hdev, "entered mode %d\n", mode);
+			if (ssc->mode != -1) {
+				/* use bit 8 as the mode button, bits 22
+				 * and 23 do not represent buttons
+				 * according to the HID report descriptor
+				 */
+				raw_data[1] |= 0x80;
+			}
+			ssc->mode = mode;
+		}
+	}
+
+	return 0;
+}
+
+static int saitek_event(struct hid_device *hdev, struct hid_field *field,
+		struct hid_usage *usage, __s32 value)
+{
+	struct saitek_sc *ssc = hid_get_drvdata(hdev);
+	struct input_dev *input = field->hidinput->input;
+
+	if (usage->type == EV_KEY && value &&
+			(((ssc->quirks & SAITEK_RELEASE_MODE_RAT7) &&
+			  usage->code - BTN_MOUSE == 10) ||
+			((ssc->quirks & SAITEK_RELEASE_MODE_MMO7) &&
+			 usage->code - BTN_MOUSE == 15))) {
+
+		input_report_key(input, usage->code, 1);
+
+		/* report missing release event */
+		input_report_key(input, usage->code, 0);
+
+		return 1;
+	}
+
+	return 0;
+}
+
 static const struct hid_device_id saitek_devices[] = {
-	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000)},
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
+		.driver_data = SAITEK_FIX_PS1000 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
+		.driver_data = SAITEK_RELEASE_MODE_RAT7 },
+	{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7),
+		.driver_data = SAITEK_RELEASE_MODE_MMO7 },
 	{ }
 };
 
@@ -52,7 +189,10 @@ MODULE_DEVICE_TABLE(hid, saitek_devices);
 static struct hid_driver saitek_driver = {
 	.name = "saitek",
 	.id_table = saitek_devices,
-	.report_fixup = saitek_report_fixup
+	.probe = saitek_probe,
+	.report_fixup = saitek_report_fixup,
+	.raw_event = saitek_raw_event,
+	.event = saitek_event,
 };
 module_hid_driver(saitek_driver);
 
--
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

^ permalink raw reply related

* Re: [PATCH] input: misc: Add driver for Intel Bay Trail GPIO buttons
From: Zhu, Lejun @ 2014-03-27  1:09 UTC (permalink / raw)
  To: Dmitry Torokhov, One Thousand Gnomes; +Cc: linux-kernel, linux-input
In-Reply-To: <20140326202029.GB11013@core.coreip.homeip.net>

On 3/27/2014 4:20 AM, Dmitry Torokhov wrote:
> On Wed, Mar 26, 2014 at 05:04:04PM +0000, One Thousand Gnomes wrote:
>> On Wed, 26 Mar 2014 13:01:36 +0800
>> "Zhu, Lejun" <lejun.zhu@linux.intel.com> wrote:
>>
>>> This patch adds support for the GPIO buttons on some Intel Bay Trail
>>> tablets originally running Windows 8. The ACPI description of these
>>> buttons follows "Windows ACPI Design Guide for SoC Platforms".
>>
>> I'm not sure calling it "Baytrail" is right here - it's in theory a
>> generic interface so probably should be named accordingly
>>
>> Otherwise looks good to me.
> 
> It uses static devices in non-board code - if I unbind and rebind PNP
> device that produces gpio-keys platform devices driver core will not be
> happy.
> 
> Thanks.
> 

Alan, I will think of a better name for it. This is supposed to work for
other "win8 ready" tablets as well, just all I have today are Baytrail
tablets.

Dmitry, thank you for pointing out the bug. I'll fix it and submit again.

Thanks.
Lejun

^ permalink raw reply

* Re: [PATCH] input: sirfsoc-onkey - set the capability of reporting KEY_POWER
From: Barry Song @ 2014-03-27  7:35 UTC (permalink / raw)
  To: Dmitry Torokhov, linux-input@vger.kernel.org
  Cc: DL-SHA-WorkGroupLinux, Xianglong Du, Barry Song
In-Reply-To: <1393335375-1870-1-git-send-email-21cnbao@gmail.com>

2014-02-25 21:36 GMT+08:00 Barry Song <21cnbao@gmail.com>:
> From: Xianglong Du <Xianglong.Du@csr.com>
>
> commit a1a7521064428fc1cf8 moved to report EV_KEY event(KEY_POWER) instead of
> reporting EV_PWR event(KEY_SUSPEND), but it didn't enable the capability, so
> the KEY_POWER will not be reported to userspace by input core. this patch fixes
> the issue.
>
> Signed-off-by: Xianglong Du <Xianglong.Du@csr.com>
> Signed-off-by: Barry Song <Baohua.Song@csr.com>
> ---

Dmitry, i guess you missed this one, this one should be in 3.15,
otherwise, onkey is broken.


>  drivers/input/misc/sirfsoc-onkey.c |    1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/drivers/input/misc/sirfsoc-onkey.c b/drivers/input/misc/sirfsoc-onkey.c
> index 4d66c72..e4104f9 100644
> --- a/drivers/input/misc/sirfsoc-onkey.c
> +++ b/drivers/input/misc/sirfsoc-onkey.c
> @@ -136,6 +136,7 @@ static int sirfsoc_pwrc_probe(struct platform_device *pdev)
>         pwrcdrv->input->name = "sirfsoc pwrckey";
>         pwrcdrv->input->phys = "pwrc/input0";
>         pwrcdrv->input->evbit[0] = BIT_MASK(EV_KEY);
> +       input_set_capability(pwrcdrv->input, EV_KEY, KEY_POWER);
>
>         INIT_DELAYED_WORK(&pwrcdrv->work, sirfsoc_pwrc_report_event);
>
> --
> 1.7.9.5
>

-barry

^ permalink raw reply

* Re: [PATCH] input: add support for ALPS v7 protocol device
From: vencik @ 2014-03-27  8:41 UTC (permalink / raw)
  To: Elaine Chen
  Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, linux-input,
	Niels de Vos, jclift, Qiting Chen, Justin Clift
In-Reply-To: <CAKvfdtKRqaCVJiFQcF2Q+buSRpacLisaMz6eHK9GmXZbvz9bAA@mail.gmail.com>

Hello Elaine,

the SP works just fine for me with the changes I've sent.
It was quite some job to detect the [x,y] vector bits all with
the device being so sensitive, so I wouldn't be surprised
if I got some of them wrong (namely the low bits).
But the general behaviour seems OK, I don't experience
any erratic movements, buttons work just fine, too.

I'll test your implementation next week, then; thanks for that.

About application of the patch; I think I see what the problem was;
the thing is that in your post at linux-input, the patch is inlined to the mail
and that turned tabs into spaces.
That's apparently why the hunks failed for me (and probably also the reason
why indentation didn't fit).

Thank you,

Best wishes

vencik



______________________________________________________________
> Od: Elaine Chen <elaineee66@gmail.com>
> Komu: "Václav Krpec" <vencik@razdva.cz>
> Datum: 27.03.2014 08:57
> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>
> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>Hello Vencik,
>
>Thank you for evaluating the patch.
>
>1/ About stickpoint support
>Yes, this patch hasn't added stickpoint support for v7 protocol device.
>What's the SP behavior on your Toshiba laptop after
>applying our patch? No function or works abnormally? Please let me know the
>phenomenon as I don't have a v7 TP/SP dual device currently.
>I also checked your stickpoint process code. The SP packet decode seems
>doesn't match the format of Specification. Sorry I haven't tested it as
>lack of
>device.Did it work on your machine?
>I'll get down to support for SP next week I got such a device. And will
>release it with next patch.
>
>2/ This patch is against Dmitry Torokhov's input tree(3.13-rc4)
>https://git.kernel.org/cgit/linux/kernel/git/dtor/input.git/
>I've checked the alps.(ch) from 3.13-rc4 and 3.14-rc8, they are the same.
>Maybe there are something unmatch with patch format.
>My patch is made from git format-patch.
>
>
>
>2014-03-26 20:20 GMT+08:00 Václav Krpec <vencik@razdva.cz>:
>
>> Hello Qiting,
>>
>> I've applied your patch and tested the driver on my Toshiba Portege
>> Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22).
>>
>> The TP driver works nicely, however, I've observed a few things to note:
>>
>> 1/
>> There's no support for trackstick; my device has one.
>> Justin has suggested that it may be a Toshiba mod of the device...
>> Nevertheless, since I was in process of RA of the device myself before
>> you've committed the patch, I merged the TS driver to your patch;
>> see alps_process_trackstick_packet_v7 function + tiny bit of
>> refactoring of the packet ID resolving mechanism in the patch attached.
>> I hope it shouldn't break the driver functionality for devices w/o
>> the trackstick, but testing should definitely be done.
>>
>> 2/
>> I've noticed that your patch wasn't cleanly applicable to current 3.14
>> kernel; could you be more specific on what branch should it be applied?
>> The patch attached is valid for 3.14-rc8 tree.
>>
>> 3/
>> I also took the liberty of fixing indentation of your code a bit to put
>> it (hopefully) more in line with the conventions of the alps.[ch]
>>
>> So, could you (or anyone else) test the patch attached?
>> Comments, recommendations etc welcome.
>>
>> Thanks,
>>
>> Best regards
>>
>> vencik
>>
>>
>>
>> On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote:
>> > Here is a patch of supporting ALPS v7 protocol device.
>> > ALPS v7 protocol device is a clickpad that is currently used on
>> > Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1,
>> > as well as other machines with ALPS Touchpad of following infomation:
>> >       Device ID = 0x73, 0x03, 0x0a
>> >       Firmware ID = 0x88, 0xb*, 0x**
>> >
>> > A v7 protocol support patch is first relesed 2 months ago:
>> > http://www.spinics.net/lists/linux-input/msg29084.html
>> > After that some feedbacks were received from end user. Now this patch
>> fixed the bugs
>> > reported by them:
>> > 1) Fix cursor jump when doing a right click drag
>> > 2) Fix cursor jitter when button clicking
>> >
>> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>> > ---
>> >  drivers/input/mouse/alps.c | 560
>> ++++++++++++++++++++++++++++++++++++++++++---
>> >  drivers/input/mouse/alps.h | 132 +++++++++--
>> >  2 files changed, 641 insertions(+), 51 deletions(-)
>> >
>> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>> > index fb15c64..383281f 100644
>> > --- a/drivers/input/mouse/alps.c
>> > +++ b/drivers/input/mouse/alps.c
>> > @@ -32,6 +32,13 @@
>> >  #define ALPS_REG_BASE_RUSHMORE       0xc2c0
>> >  #define ALPS_REG_BASE_PINNACLE       0x0000
>> >
>> > +#define LEFT_BUTTON_BIT                      0x01
>> > +#define RIGHT_BUTTON_BIT             0x02
>> > +
>> > +#define V7_LARGE_MOVEMENT            130
>> > +#define V7_DEAD_ZONE_OFFSET_X        72
>> > +#define V7_DEAD_ZONE_OFFSET_Y        72
>> > +
>> >  static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>> >       { PSMOUSE_CMD_SETPOLL,          0x00 }, /* 0 */
>> >       { PSMOUSE_CMD_RESET_DIS,        0x00 }, /* 1 */
>> > @@ -99,6 +106,7 @@ static const struct alps_nibble_commands
>> alps_v6_nibble_commands[] = {
>> >  #define ALPS_FOUR_BUTTONS    0x40    /* 4 direction button present */
>> >  #define ALPS_PS2_INTERLEAVED 0x80    /* 3-byte PS/2 packet interleaved
>> with
>> >                                          6-byte ALPS packet */
>> > +#define ALPS_BTNLESS                 0x100   /* ALPS ClickPad flag */
>> >
>> >  static const struct alps_model_info alps_model_data[] = {
>> >       { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS
>> | ALPS_DUALPOINT },  /* Toshiba Salellite Pro M10 */
>> > @@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struct alps_data
>> *priv,
>> >   * isn't valid per PS/2 spec.
>> >   */
>> >
>> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>> > +                                 struct alps_abs_data *pt1)
>> > +{
>> > +     int vect_x, vect_y;
>> > +
>> > +     if (!pt0 || !pt1)
>> > +             return 0;
>> > +
>> > +     vect_x = pt0->x - pt1->x;
>> > +     vect_y = pt0->y - pt1->y;
>> > +
>> > +     return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>> > +}
>> > +
>> >  /* Packet formats are described in Documentation/input/alps.txt */
>> >
>> >  static bool alps_is_valid_first_byte(struct alps_data *priv,
>> > @@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(struct
>> alps_data *priv,
>> >               end_bit = y_msb - 1;
>> >               box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>> >                               (2 * (priv->y_bits - 1));
>> > -             *x1 = fields->x;
>> > -             *y1 = fields->y;
>> > +             *x1 = fields->pt.x;
>> > +             *y1 = fields->pt.y;
>> >               *x2 = 2 * box_middle_x - *x1;
>> >               *y2 = 2 * box_middle_y - *y1;
>> >       }
>> > @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct
>> input_dev *dev, int num_fingers,
>> >       alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>> >  }
>> >
>> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>> > +                                   struct alps_fields *f)
>> > +{
>> > +     struct input_dev *dev;
>> > +
>> > +     if (!psmouse || !f)
>> > +             return;
>> > +
>> > +     dev = psmouse->dev;
>> > +
>> > +     if (f->fingers) {
>> > +             input_report_key(dev, BTN_TOUCH, 1);
>> > +             alps_report_semi_mt_data(dev, f->fingers,
>> > +                     f->pt_img[0].x, f->pt_img[0].y,
>> > +                     f->pt_img[1].x, f->pt_img[1].y);
>> > +             input_mt_report_finger_count(dev, f->fingers);
>> > +
>> > +             input_report_abs(dev, ABS_X, f->pt_img[0].x);
>> > +             input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>> > +             input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>> > +     } else {
>> > +             input_report_key(dev, BTN_TOUCH, 0);
>> > +             input_mt_report_finger_count(dev, 0);
>> > +             input_report_abs(dev, ABS_PRESSURE, 0);
>> > +     }
>> > +
>> > +     input_report_key(dev, BTN_LEFT, f->btn.left);
>> > +     input_report_key(dev, BTN_RIGHT, f->btn.right);
>> > +
>> > +     input_sync(dev);
>> > +}
>> > +
>> >  static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> >  {
>> >       struct alps_data *priv = psmouse->private;
>> > @@ -523,13 +577,13 @@ static void
>> alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> >
>> >  static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char
>> *p)
>> >  {
>> > -     f->left = !!(p[3] & 0x01);
>> > -     f->right = !!(p[3] & 0x02);
>> > -     f->middle = !!(p[3] & 0x04);
>> > +     f->btn.left = !!(p[3] & 0x01);
>> > +     f->btn.right = !!(p[3] & 0x02);
>> > +     f->btn.middle = !!(p[3] & 0x04);
>> >
>> > -     f->ts_left = !!(p[3] & 0x10);
>> > -     f->ts_right = !!(p[3] & 0x20);
>> > -     f->ts_middle = !!(p[3] & 0x40);
>> > +     f->btn.ts_left = !!(p[3] & 0x10);
>> > +     f->btn.ts_right = !!(p[3] & 0x20);
>> > +     f->btn.ts_middle = !!(p[3] & 0x40);
>> >  }
>> >
>> >  static void alps_decode_pinnacle(struct alps_fields *f, unsigned char
>> *p,
>> > @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct
>> alps_fields *f, unsigned char *p,
>> >                  ((p[2] & 0x7f) << 1) |
>> >                  (p[4] & 0x01);
>> >
>> > -     f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > +     f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> >              ((p[0] & 0x30) >> 4);
>> > -     f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > -     f->z = p[5] & 0x7f;
>> > +     f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > +     f->pt.z = p[5] & 0x7f;
>> >
>> >       alps_decode_buttons_v3(f, p);
>> >  }
>> > @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields
>> *f, unsigned char *p,
>> >       f->is_mp = !!(p[0] & 0x20);
>> >
>> >       if (!f->is_mp) {
>> > -             f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > -             f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > -             f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > +             f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > +             f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > +             f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> >               alps_decode_buttons_v3(f, p);
>> >       } else {
>> >               f->fingers = ((p[0] & 0x6) >> 1 |
>> > @@ -687,7 +741,7 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >        * with x, y, and z all zero, so these seem to be flukes.
>> >        * Ignore them.
>> >        */
>> > -     if (f.x && f.y && !f.z)
>> > +     if (f.pt.x && f.pt.y && !f.pt.z)
>> >               return;
>> >
>> >       /*
>> > @@ -695,12 +749,12 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >        * to rely on ST data.
>> >        */
>> >       if (!fingers) {
>> > -             x1 = f.x;
>> > -             y1 = f.y;
>> > -             fingers = f.z > 0 ? 1 : 0;
>> > +             x1 = f.pt.x;
>> > +             y1 = f.pt.y;
>> > +             fingers = f.pt.z > 0 ? 1 : 0;
>> >       }
>> >
>> > -     if (f.z >= 64)
>> > +     if (f.pt.z >= 64)
>> >               input_report_key(dev, BTN_TOUCH, 1);
>> >       else
>> >               input_report_key(dev, BTN_TOUCH, 0);
>> > @@ -709,22 +763,22 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >
>> >       input_mt_report_finger_count(dev, fingers);
>> >
>> > -     input_report_key(dev, BTN_LEFT, f.left);
>> > -     input_report_key(dev, BTN_RIGHT, f.right);
>> > -     input_report_key(dev, BTN_MIDDLE, f.middle);
>> > +     input_report_key(dev, BTN_LEFT, f.btn.left);
>> > +     input_report_key(dev, BTN_RIGHT, f.btn.right);
>> > +     input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>> >
>> > -     if (f.z > 0) {
>> > -             input_report_abs(dev, ABS_X, f.x);
>> > -             input_report_abs(dev, ABS_Y, f.y);
>> > +     if (f.pt.z > 0) {
>> > +             input_report_abs(dev, ABS_X, f.pt.x);
>> > +             input_report_abs(dev, ABS_Y, f.pt.y);
>> >       }
>> > -     input_report_abs(dev, ABS_PRESSURE, f.z);
>> > +     input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>> >
>> >       input_sync(dev);
>> >
>> >       if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>> > -             input_report_key(dev2, BTN_LEFT, f.ts_left);
>> > -             input_report_key(dev2, BTN_RIGHT, f.ts_right);
>> > -             input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
>> > +             input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>> > +             input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>> > +             input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>> >               input_sync(dev2);
>> >       }
>> >  }
>> > @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse
>> *psmouse)
>> >       input_sync(dev);
>> >  }
>> >
>> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>> > +{
>> > +     if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) !=
>> 0x40))
>> > +             return false;
>> > +     if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) !=
>> 0x48))
>> > +             return false;
>> > +     if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>> > +             return false;
>> > +     return true;
>> > +}
>> > +
>> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int drop = 1;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > +             drop = 0;
>> > +
>> > +     return drop;
>> > +}
>> > +
>> > +static unsigned char alps_get_packet_id_v7(char *byte)
>> > +{
>> > +     unsigned char packet_id;
>> > +
>> > +     if (byte[4] & 0x40)
>> > +             packet_id = V7_PACKET_ID_TWO;
>> > +     else if (byte[4] & 0x01)
>> > +             packet_id = V7_PACKET_ID_MULTI;
>> > +     else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>> > +             packet_id = V7_PACKET_ID_NEW;
>> > +     else
>> > +             packet_id = V7_PACKET_ID_IDLE;
>> > +
>> > +     return packet_id;
>> > +}
>> > +
>> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>> > +                                       unsigned char *pkt,
>> > +                                       unsigned char pkt_id)
>> > +{
>> > +     if ((pkt_id == V7_PACKET_ID_TWO) ||
>> > +        (pkt_id == V7_PACKET_ID_MULTI) ||
>> > +        (pkt_id == V7_PACKET_ID_NEW)) {
>> > +             pt[0].x = ((pkt[2] & 0x80) << 4);
>> > +             pt[0].x |= ((pkt[2] & 0x3F) << 5);
>> > +             pt[0].x |= ((pkt[3] & 0x30) >> 1);
>> > +             pt[0].x |= (pkt[3] & 0x07);
>> > +             pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>> > +
>> > +             pt[1].x = ((pkt[3] & 0x80) << 4);
>> > +             pt[1].x |= ((pkt[4] & 0x80) << 3);
>> > +             pt[1].x |= ((pkt[4] & 0x3F) << 4);
>> > +             pt[1].y = ((pkt[5] & 0x80) << 3);
>> > +             pt[1].y |= ((pkt[5] & 0x3F) << 4);
>> > +
>> > +             if (pkt_id == V7_PACKET_ID_TWO) {
>> > +                     pt[1].x &= ~0x000F;
>> > +                     pt[1].y |= 0x000F;
>> > +             } else if (pkt_id == V7_PACKET_ID_MULTI) {
>> > +                     pt[1].x &= ~0x003F;
>> > +                     pt[1].y &= ~0x0020;
>> > +                     pt[1].y |= ((pkt[4] & 0x02) << 4);
>> > +                     pt[1].y |= 0x001F;
>> > +             } else if (pkt_id == V7_PACKET_ID_NEW) {
>> > +                     pt[1].x &= ~0x003F;
>> > +                     pt[1].x |= (pkt[0] & 0x20);
>> > +                     pt[1].y |= 0x000F;
>> > +             }
>> > +
>> > +             pt[0].y = 0x7FF - pt[0].y;
>> > +             pt[1].y = 0x7FF - pt[1].y;
>> > +
>> > +             pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>> > +             pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>> > +     }
>> > +}
>> > +
>> > +static void alps_decode_packet_v7(struct alps_fields *f,
>> > +                               unsigned char *p,
>> > +                               struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     static struct v7_raw prev_r;
>> > +
>> > +     priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>> > +
>> > +     alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>> > +
>> > +     priv->r.v7.rest_left = 0;
>> > +     priv->r.v7.rest_right = 0;
>> > +     priv->r.v7.additional_fingers = 0;
>> > +     priv->phy_btn = 0;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>> > +             priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>> > +             priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>> > +     }
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > +             priv->r.v7.additional_fingers = p[5] & 0x03;
>> > +
>> > +     priv->phy_btn = (p[0] & 0x80) >> 7;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
>> > +             if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
>> > +                     priv->r.v7.raw_fn = 2;
>> > +             else
>> > +                     priv->r.v7.raw_fn = 1;
>> > +     } else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > +             priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > +             priv->r.v7.raw_fn = 0;
>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
>> > +             priv->r.v7.raw_fn = prev_r.raw_fn;
>> > +
>> > +     /* It is a trick to bypass firmware bug of older version
>> > +     that 'New' Packet is missed when finger number changed.
>> > +     We fake a 'New' Packet in such cases.*/
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) {
>> > +             if (priv->r.v7.raw_fn != prev_r.raw_fn)
>> > +                     priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
>> > +     }
>> > +
>> > +     memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
>> > +}
>> > +
>> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>> > +                                  struct alps_abs_data *pt,
>> > +                                  struct alps_bl_pt_attr *pt_attr)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     unsigned int dist;
>> > +
>> > +     if (!pt_attr->is_init_pt_got && pt->z != 0) {
>> > +             pt_attr->is_init_pt_got = 1;
>> > +             pt_attr->is_counted = 0;
>> > +             memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>> > +     }
>> > +
>> > +     if (pt->z != 0) {
>> > +             if (pt->y < priv->resting_zone_y_min) {
>> > +                     /* A finger is recognized as a non-resting finger
>> > +                     if it's position is outside the resting finger
>> zone.*/
>> > +                     pt_attr->zone = ZONE_NORMAL;
>> > +                     pt_attr->is_counted = 1;
>> > +             } else {
>> > +                     /* A finger is recognized as a resting finger if
>> it's
>> > +                     position is inside the resting finger zone and
>> there's
>> > +                     no large movement from it's touch down position.*/
>> > +                     pt_attr->zone = ZONE_RESTING;
>> > +
>> > +                     if (pt->x > priv->x_max / 2)
>> > +                             pt_attr->zone |= ZONE_RIGHT_BTN;
>> > +                     else
>> > +                             pt_attr->zone |= ZONE_LEFT_BTN;
>> > +
>> > +                     /* A resting finger will turn to be a non-resting
>> > +                     finger if it has made large movement from it's
>> touch
>> > +                     down position. A non-resting finger will never turn
>> > +                     to a resting finger before it leaves the touchpad
>> > +                     surface.*/
>> > +                     if (pt_attr->is_init_pt_got) {
>> > +                             dist = alps_pt_distance(pt,
>> &pt_attr->init_pt);
>> > +
>> > +                             if (dist > V7_LARGE_MOVEMENT)
>> > +                                     pt_attr->is_counted = 1;
>> > +                     }
>> > +             }
>> > +     }
>> > +}
>> > +
>> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>> > +                                    struct alps_fields *f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int i;
>> > +
>> > +     switch (priv->r.v7.pkt_id) {
>> > +     case  V7_PACKET_ID_TWO:
>> > +     case  V7_PACKET_ID_MULTI:
>> > +             for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > +                     alps_set_each_pt_attr_v7(psmouse,
>> > +                                              &f->pt_img[i],
>> > +                                              &priv->pt_attr[i]);
>> > +             }
>> > +             break;
>> > +     default:
>> > +             /*All finger attributes are cleared when packet ID is
>> > +             'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>> > +             indicates that there's no finger and no button activity.
>> > +             A 'NEW' packet indicates the finger position in packet
>> > +             is not continues from previous packet. Such as the
>> > +             condition there's finger placed or lifted. In these cases,
>> > +             finger attributes will be reset.*/
>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> > +             break;
>> > +     }
>> > +}
>> > +
>> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>> > +                                     struct alps_fields *f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     unsigned int fn = 0;
>> > +     int i;
>> > +
>> > +     switch (priv->r.v7.pkt_id) {
>> > +     case V7_PACKET_ID_IDLE:
>> > +     case V7_PACKET_ID_NEW:
>> > +             /*No finger is reported when packet ID is 'IDLE' or 'New'.
>> > +             An 'IDLE' packet indicates that there's no finger on
>> touchpad.
>> > +             A 'NEW' packet indicates there's finger placed or lifted.
>> > +             Finger position of 'New' packet is not continues from the
>> > +             previous packet.*/
>> > +             fn = 0;
>> > +             break;
>> > +     case V7_PACKET_ID_TWO:
>> > +             if (f->pt_img[0].z == 0) {
>> > +                     /*The first finger slot is zero when a non-resting
>> > +                     finger lifted and remaining only one resting finger
>> > +                     on touchpad. Hardware report the remaining resting
>> > +                     finger in second slot. This resting is ignored*/
>> > +                     fn = 0;
>> > +             } else if (f->pt_img[1].z == 0) {
>> > +                     /* The second finger slot is zero if there's
>> > +                     only one finger*/
>> > +                     fn = 1;
>> > +             } else {
>> > +                     /*All non-resting fingers will be counted to
>> report*/
>> > +                     fn = 0;
>> > +                     for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > +                             if (priv->pt_attr[i].is_counted)
>> > +                                     fn++;
>> > +                     }
>> > +
>> > +                     /*In the case that both fingers are
>> > +                     resting fingers, report the first one*/
>> > +                     if (!priv->pt_attr[0].is_counted &&
>> > +                         !priv->pt_attr[1].is_counted) {
>> > +                             fn = 1;
>> > +                     }
>> > +             }
>> > +             break;
>> > +     case V7_PACKET_ID_MULTI:
>> > +             /*A packet ID 'MULTI' indicats that at least 3 non-resting
>> > +             finger exist.*/
>> > +             fn = 3 + priv->r.v7.additional_fingers;
>> > +             break;
>> > +     }
>> > +
>> > +     f->fingers = fn;
>> > +}
>> > +
>> > +static void alps_button_dead_zone_filter(struct psmouse *psmouse,
>> > +                                struct alps_fields *f,
>> > +                                struct alps_fields *prev_f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int dx, dy;
>> > +
>> > +     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
>> > +             memcpy(&priv->pt_attr[0].init_dead_pt,
>> > +                             &f->pt_img[0],
>> > +                             sizeof(struct alps_abs_data));
>> > +     }
>> > +
>> > +     if (priv->pt_attr[0].init_dead_pt.x != 0 &&
>> > +             priv->pt_attr[0].init_dead_pt.x != 0) {
>> > +                     dx = f->pt_img[0].x -
>> priv->pt_attr[0].init_dead_pt.x;
>> > +                     dy = f->pt_img[0].y -
>> priv->pt_attr[0].init_dead_pt.y;
>> > +             if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
>> > +                     (abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) {
>> > +                             memset(&priv->pt_attr[0].init_dead_pt, 0,
>> > +                                             sizeof(struct
>> alps_abs_data));
>> > +                             priv->btn_delay_cnt = 0;
>> > +             } else {
>> > +                     memcpy(&f->pt_img[0],
>> > +                                     &prev_f->pt_img[0],
>> > +                                     sizeof(struct alps_abs_data));
>> > +                     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
>> > +                             priv->btn_delay_cnt = 2;
>> > +             }
>> > +     }
>> > +
>> > +     if (priv->btn_delay_cnt > 0) {
>> > +             f->btn.left = 0;
>> > +             f->btn.right = 0;
>> > +             priv->btn_delay_cnt--;
>> > +     }
>> > +}
>> > +
>> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>> > +                                struct alps_fields *f,
>> > +                                struct alps_fields *prev_f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +
>> > +     if (priv->phy_btn) {
>> > +             if (!priv->prev_phy_btn) {
>> > +                     /* Report a right click as long as there's finger
>> on
>> > +                     right button zone. Othrewise, report a left
>> click.*/
>> > +                     if (priv->r.v7.rest_right ||
>> > +                         priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>> > +                         priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>> > +                             f->btn.right = 1;
>> > +                             priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>> > +                     } else {
>> > +                             f->btn.left = 1;
>> > +                             priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>> > +                     }
>> > +             } else {
>> > +                     if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>> > +                             f->btn.right = 1;
>> > +                     if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>> > +                             f->btn.left = 1;
>> > +             }
>> > +     } else {
>> > +             priv->pressed_btn_bits = 0;
>> > +             f->btn.right = 0;
>> > +             f->btn.left = 0;
>> > +     }
>> > +
>> > +     alps_button_dead_zone_filter(psmouse, f, prev_f);
>> > +
>> > +     priv->prev_phy_btn = priv->phy_btn;
>> > +}
>> > +
>> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     struct alps_fields f = {0};
>> > +     static struct alps_fields prev_f;
>> > +     unsigned char *packet = psmouse->packet;
>> > +
>> > +     priv->decode_fields(&f, packet, psmouse);
>> > +
>> > +     if (alps_drop_unsupported_packet_v7(psmouse))
>> > +             return;
>> > +
>> > +     alps_set_pt_attr_v7(psmouse, &f);
>> > +
>> > +     alps_cal_output_finger_num_v7(psmouse, &f);
>> > +
>> > +     alps_assign_buttons_v7(psmouse, &f, &prev_f);
>> > +
>> > +     alps_report_coord_and_btn(psmouse, &f);
>> > +
>> > +     memcpy(&prev_f, &f, sizeof(struct alps_fields));
>> > +}
>> > +
>> >  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>> >                                       unsigned char packet[],
>> >                                       bool report_buttons)
>> > @@ -1080,6 +1492,14 @@ static psmouse_ret_t alps_process_byte(struct
>> psmouse *psmouse)
>> >               return PSMOUSE_BAD_DATA;
>> >       }
>> >
>> > +     if ((priv->proto_version == ALPS_PROTO_V7 &&
>> > +         !alps_is_valid_package_v7(psmouse))) {
>> > +             psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>> > +                         psmouse->pktcnt - 1,
>> > +                         psmouse->packet[psmouse->pktcnt - 1]);
>> > +             return PSMOUSE_BAD_DATA;
>> > +     }
>> > +
>> >       if (psmouse->pktcnt == psmouse->pktsize) {
>> >               priv->process_packet(psmouse);
>> >               return PSMOUSE_FULL_PACKET;
>> > @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse,
>> int init_command,
>> >       return 0;
>> >  }
>> >
>> > +static int alps_check_valid_firmware_id(unsigned char id[])
>> > +{
>> > +     int valid = 1;
>> > +
>> > +     if (id[0] == 0x73)
>> > +             valid = 1;
>> > +     else if (id[0] == 0x88) {
>> > +             if ((id[1] == 0x07) ||
>> > +                 (id[1] == 0x08) ||
>> > +                 ((id[1] & 0xf0) == 0xB0))
>> > +                     valid = 1;
>> > +     }
>> > +
>> > +     return valid;
>> > +}
>> > +
>> >  static int alps_enter_command_mode(struct psmouse *psmouse)
>> >  {
>> >       unsigned char param[4];
>> > @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse
>> *psmouse)
>> >               return -1;
>> >       }
>> >
>> > -     if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>> > -         param[0] != 0x73) {
>> > +     if (!alps_check_valid_firmware_id(param)) {
>> >               psmouse_dbg(psmouse,
>> >                           "unknown response while entering command
>> mode\n");
>> >               return -1;
>> > @@ -1704,6 +2139,36 @@ error:
>> >       return ret;
>> >  }
>> >
>> > +static int alps_hw_init_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct ps2dev *ps2dev = &psmouse->ps2dev;
>> > +     int reg_val, ret = -1;
>> > +
>> > +     if (alps_enter_command_mode(psmouse))
>> > +             goto error;
>> > +
>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
>> > +     if (reg_val == -1)
>> > +             goto error;
>> > +
>> > +     if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
>> > +             goto error;
>> > +
>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
>> > +     if (reg_val == -1)
>> > +             goto error;
>> > +
>> > +     if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
>> > +             goto error;
>> > +
>> > +     alps_exit_command_mode(psmouse);
>> > +     return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
>> > +
>> > +error:
>> > +     alps_exit_command_mode(psmouse);
>> > +     return ret;
>> > +}
>> > +
>> >  /* Must be in command mode when calling this function */
>> >  static int alps_absolute_mode_v4(struct psmouse *psmouse)
>> >  {
>> > @@ -1875,6 +2340,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->set_abs_params = alps_set_abs_params_st;
>> >               priv->x_max = 1023;
>> >               priv->y_max = 767;
>> > +             priv->slot_number = 1;
>> >               break;
>> >       case ALPS_PROTO_V3:
>> >               priv->hw_init = alps_hw_init_v3;
>> > @@ -1883,6 +2349,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->decode_fields = alps_decode_pinnacle;
>> >               priv->nibble_commands = alps_v3_nibble_commands;
>> >               priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V4:
>> >               priv->hw_init = alps_hw_init_v4;
>> > @@ -1890,6 +2357,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->set_abs_params = alps_set_abs_params_mt;
>> >               priv->nibble_commands = alps_v4_nibble_commands;
>> >               priv->addr_command = PSMOUSE_CMD_DISABLE;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V5:
>> >               priv->hw_init = alps_hw_init_dolphin_v1;
>> > @@ -1905,6 +2373,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->y_max = 660;
>> >               priv->x_bits = 23;
>> >               priv->y_bits = 12;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V6:
>> >               priv->hw_init = alps_hw_init_v6;
>> > @@ -1913,6 +2382,28 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->nibble_commands = alps_v6_nibble_commands;
>> >               priv->x_max = 2047;
>> >               priv->y_max = 1535;
>> > +             priv->slot_number = 2;
>> > +             break;
>> > +     case ALPS_PROTO_V7:
>> > +             priv->hw_init = alps_hw_init_v7;
>> > +             priv->process_packet = alps_process_packet_v7;
>> > +             priv->decode_fields = alps_decode_packet_v7;
>> > +             priv->set_abs_params = alps_set_abs_params_mt;
>> > +             priv->nibble_commands = alps_v3_nibble_commands;
>> > +             priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > +             priv->x_max = 0xfff;
>> > +             priv->y_max = 0x7ff;
>> > +             priv->resting_zone_y_min = 0x654;
>> > +             priv->byte0 = 0x48;
>> > +             priv->mask0 = 0x48;
>> > +             priv->flags = 0;
>> > +             priv->slot_number = 2;
>> > +
>> > +             priv->phy_btn = 0;
>> > +             priv->prev_phy_btn = 0;
>> > +             priv->btn_delay_cnt = 0;
>> > +             priv->pressed_btn_bits = 0;
>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> >               break;
>> >       }
>> >  }
>> > @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse,
>> struct alps_data *priv)
>> >                       return -EIO;
>> >               else
>> >                       return 0;
>> > +     } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>> > +             priv->proto_version = ALPS_PROTO_V7;
>> > +             alps_set_defaults(priv);
>> > +
>> > +             return 0;
>> >       } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>> >               priv->proto_version = ALPS_PROTO_V3;
>> >               alps_set_defaults(priv);
>> > @@ -2045,7 +2541,7 @@ static void alps_set_abs_params_mt(struct
>> alps_data *priv,
>> >                                  struct input_dev *dev1)
>> >  {
>> >       set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>> > -     input_mt_init_slots(dev1, 2, 0);
>> > +     input_mt_init_slots(dev1, priv->slot_number, 0);
>> >       input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0,
>> 0);
>> >       input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0,
>> 0);
>> >
>> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>> > index 03f88b6..dedbd27 100644
>> > --- a/drivers/input/mouse/alps.h
>> > +++ b/drivers/input/mouse/alps.h
>> > @@ -18,11 +18,36 @@
>> >  #define ALPS_PROTO_V4        4
>> >  #define ALPS_PROTO_V5        5
>> >  #define ALPS_PROTO_V6        6
>> > +#define ALPS_PROTO_V7        7
>> > +
>> > +#define MAX_IMG_PT_NUM               5
>> > +#define V7_IMG_PT_NUM                2
>> > +
>> > +#define ZONE_NORMAL                          0x01
>> > +#define ZONE_RESTING                 0x02
>> > +#define ZONE_LEFT_BTN                        0x04
>> > +#define ZONE_RIGHT_BTN                       0x08
>> >
>> >  #define DOLPHIN_COUNT_PER_ELECTRODE  64
>> >  #define DOLPHIN_PROFILE_XOFFSET              8       /* x-electrode
>> offset */
>> >  #define DOLPHIN_PROFILE_YOFFSET              1       /* y-electrode
>> offset */
>> >
>> > +/*
>> > + * enum V7_PACKET_ID - defines the packet type for V7
>> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>> > + *  or there's button activities.
>> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>> > + *  previous packet.
>> > +*/
>> > +enum V7_PACKET_ID {
>> > +      V7_PACKET_ID_IDLE,
>> > +      V7_PACKET_ID_TWO,
>> > +      V7_PACKET_ID_MULTI,
>> > +      V7_PACKET_ID_NEW,
>> > +};
>> > +
>> >  /**
>> >   * struct alps_model_info - touchpad ID table
>> >   * @signature: E7 response string to match.
>> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>> >  };
>> >
>> >  /**
>> > - * struct alps_fields - decoded version of the report packet
>> > - * @x_map: Bitmap of active X positions for MT.
>> > - * @y_map: Bitmap of active Y positions for MT.
>> > - * @fingers: Number of fingers for MT.
>> > - * @x: X position for ST.
>> > - * @y: Y position for ST.
>> > - * @z: Z position for ST.
>> > - * @first_mp: Packet is the first of a multi-packet report.
>> > - * @is_mp: Packet is part of a multi-packet report.
>> > + * struct alps_btn - decoded version of the button status
>> >   * @left: Left touchpad button is active.
>> >   * @right: Right touchpad button is active.
>> >   * @middle: Middle touchpad button is active.
>> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>> >   * @ts_right: Right trackstick button is active.
>> >   * @ts_middle: Middle trackstick button is active.
>> >   */
>> > -struct alps_fields {
>> > -     unsigned int x_map;
>> > -     unsigned int y_map;
>> > -     unsigned int fingers;
>> > -     unsigned int x;
>> > -     unsigned int y;
>> > -     unsigned int z;
>> > -     unsigned int first_mp:1;
>> > -     unsigned int is_mp:1;
>> > -
>> > +struct alps_btn {
>> >       unsigned int left:1;
>> >       unsigned int right:1;
>> >       unsigned int middle:1;
>> > @@ -102,6 +110,73 @@ struct alps_fields {
>> >  };
>> >
>> >  /**
>> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>> > + * @x: X position for ST.
>> > + * @y: Y position for ST.
>> > + * @z: Z position for ST.
>> > + */
>> > +struct alps_abs_data {
>> > +     unsigned int x;
>> > +     unsigned int y;
>> > +     unsigned int z;
>> > +};
>> > +
>> > +/**
>> > + * struct alps_fields - decoded version of the report packet
>> > + * @fingers: Number of fingers for MT.
>> > + * @pt: X Y Z postion for ST.
>> > + * @pt: X Y Z postion for image MT.
>> > + * @x_map: Bitmap of active X positions for MT.
>> > + * @y_map: Bitmap of active Y positions for MT.
>> > + * @first_mp: Packet is the first of a multi-packet report.
>> > + * @is_mp: Packet is part of a multi-packet report.
>> > + * @btn: Button activity status
>> > + */
>> > +struct alps_fields {
>> > +     unsigned int fingers;
>> > +     struct alps_abs_data pt;
>> > +     struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>> > +     unsigned int x_map;
>> > +     unsigned int y_map;
>> > +     unsigned int first_mp:1;
>> > +     unsigned int is_mp:1;
>> > +     struct alps_btn btn;
>> > +};
>> > +
>> > +/**
>> > + * struct v7_raw - data decoded from raw packet for V7.
>> > + * @pkt_id: An id that specifies the type of packet.
>> > + * @additional_fingers: Number of additional finger that is neighter
>> included
>> > + *  in pt slot nor reflected in rest_left and rest_right flag of data
>> packet.
>> > + * @rest_left: There are fingers on left resting zone.
>> > + * @rest_right: There are fingers on right resting zone.
>> > + * @raw_fn: The number of finger on touchpad.
>> > + */
>> > +struct v7_raw {
>> > +     unsigned char pkt_id;
>> > +     unsigned int additional_fingers;
>> > +     unsigned char rest_left;
>> > +     unsigned char rest_right;
>> > +     unsigned char raw_fn;
>> > +};
>> > +
>> > +/**
>> > + * struct alps_bl_pt_attr - generic attributes of touch points for
>> buttonless device
>> > + * @zone: The part of touchpad that the touch point locates
>> > + * @is_counted: The touch point is not a resting finger.
>> > + * @is_init_pt_got: The touch down point is got.
>> > + * @init_pt: The X Y Z position of the touch down point.
>> > + * @init_dead_pt: The touch down point of a finger used by dead zone
>> process.
>> > + */
>> > +struct alps_bl_pt_attr {
>> > +     unsigned char zone;
>> > +     unsigned char is_counted;
>> > +     unsigned char is_init_pt_got;
>> > +     struct alps_abs_data init_pt;
>> > +     struct alps_abs_data init_dead_pt;
>> > +};
>> > +
>> > +/**
>> >   * struct alps_data - private data structure for the ALPS driver
>> >   * @dev2: "Relative" device used to report trackstick or mouse activity.
>> >   * @phys: Physical path for the relative device.
>> > @@ -116,8 +191,10 @@ struct alps_fields {
>> >   * @flags: Additional device capabilities (passthrough port,
>> trackstick, etc.).
>> >   * @x_max: Largest possible X position value.
>> >   * @y_max: Largest possible Y position value.
>> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting
>> zone.
>> >   * @x_bits: Number of X bits in the MT bitmap.
>> >   * @y_bits: Number of Y bits in the MT bitmap.
>> > + * @img_fingers: Number of image fingers.
>> >   * @hw_init: Protocol-specific hardware init function.
>> >   * @process_packet: Protocol-specific function to process a report
>> packet.
>> >   * @decode_fields: Protocol-specific function to read packet bitfields.
>> > @@ -132,6 +209,11 @@ struct alps_fields {
>> >   * @fingers: Number of fingers from last MT report.
>> >   * @quirks: Bitmap of ALPS_QUIRK_*.
>> >   * @timer: Timer for flushing out the final report packet in the stream.
>> > + * @v7: Data decoded from raw packet for V7
>> > + * @phy_btn: Physical button is active.
>> > + * @prev_phy_btn: Physical button of previous packet is active.
>> > + * @pressed_btn_bits: Pressed positon of button zone
>> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>> >   */
>> >  struct alps_data {
>> >       struct input_dev *dev2;
>> > @@ -145,8 +227,10 @@ struct alps_data {
>> >       unsigned char flags;
>> >       int x_max;
>> >       int y_max;
>> > +     int resting_zone_y_min;
>> >       int x_bits;
>> >       int y_bits;
>> > +     unsigned char slot_number;
>> >
>> >       int (*hw_init)(struct psmouse *psmouse);
>> >       void (*process_packet)(struct psmouse *psmouse);
>> > @@ -161,6 +245,16 @@ struct alps_data {
>> >       int fingers;
>> >       u8 quirks;
>> >       struct timer_list timer;
>> > +
>> > +     /* these are used for buttonless touchpad*/
>> > +     union {
>> > +             struct v7_raw v7;
>> > +     } r;
>> > +     unsigned char phy_btn;
>> > +     unsigned char prev_phy_btn;
>> > +     unsigned char btn_delay_cnt;
>> > +     unsigned char pressed_btn_bits;
>> > +     struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>> >  };
>> >
>> >  #define ALPS_QUIRK_TRACKSTICK_BUTTONS        1 /* trakcstick buttons in
>> trackstick packet */
>>
>>
>
--
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

^ permalink raw reply

* Re: [PATCH] input: add support for ALPS v7 protocol device
From: vencik @ 2014-03-27  9:47 UTC (permalink / raw)
  To: Elaine Chen
  Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, linux-input,
	Niels de Vos, jclift, Qiting Chen, Justin Clift
In-Reply-To: <CAKvfdtKRqaCVJiFQcF2Q+buSRpacLisaMz6eHK9GmXZbvz9bAA@mail.gmail.com>

Hi again, Elaine,

just something to add to the TP driver functionality;
I've experienced something that looked as involuntary left
button clicking.

Using xev, I deduce that it happens when I remove the finger
after doing just a short motion on the pad; if the motion is longer
(apparently both in in distance and time) the click is not generated
at the end.
But when I do just a short and quite quick move, it produces a click.

Perhaps it's just necessary to tune the driver a bit; what I'm talking about
is something close to a tap, but past it; the motion may take about 1/2 second
and the cursor moves for about a centimeter...
I'll try to identify the code bit responsible and play with that.

Regards,

vencik


______________________________________________________________
> Od: Elaine Chen <elaineee66@gmail.com>
> Komu: "Václav Krpec" <vencik@razdva.cz>
> Datum: 27.03.2014 08:57
> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>
> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>Hello Vencik,
>
>Thank you for evaluating the patch.
>
>1/ About stickpoint support
>Yes, this patch hasn't added stickpoint support for v7 protocol device.
>What's the SP behavior on your Toshiba laptop after
>applying our patch? No function or works abnormally? Please let me know the
>phenomenon as I don't have a v7 TP/SP dual device currently.
>I also checked your stickpoint process code. The SP packet decode seems
>doesn't match the format of Specification. Sorry I haven't tested it as
>lack of
>device.Did it work on your machine?
>I'll get down to support for SP next week I got such a device. And will
>release it with next patch.
>
>2/ This patch is against Dmitry Torokhov's input tree(3.13-rc4)
>https://git.kernel.org/cgit/linux/kernel/git/dtor/input.git/
>I've checked the alps.(ch) from 3.13-rc4 and 3.14-rc8, they are the same.
>Maybe there are something unmatch with patch format.
>My patch is made from git format-patch.
>
>
>
>2014-03-26 20:20 GMT+08:00 Václav Krpec <vencik@razdva.cz>:
>
>> Hello Qiting,
>>
>> I've applied your patch and tested the driver on my Toshiba Portege
>> Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22).
>>
>> The TP driver works nicely, however, I've observed a few things to note:
>>
>> 1/
>> There's no support for trackstick; my device has one.
>> Justin has suggested that it may be a Toshiba mod of the device...
>> Nevertheless, since I was in process of RA of the device myself before
>> you've committed the patch, I merged the TS driver to your patch;
>> see alps_process_trackstick_packet_v7 function + tiny bit of
>> refactoring of the packet ID resolving mechanism in the patch attached.
>> I hope it shouldn't break the driver functionality for devices w/o
>> the trackstick, but testing should definitely be done.
>>
>> 2/
>> I've noticed that your patch wasn't cleanly applicable to current 3.14
>> kernel; could you be more specific on what branch should it be applied?
>> The patch attached is valid for 3.14-rc8 tree.
>>
>> 3/
>> I also took the liberty of fixing indentation of your code a bit to put
>> it (hopefully) more in line with the conventions of the alps.[ch]
>>
>> So, could you (or anyone else) test the patch attached?
>> Comments, recommendations etc welcome.
>>
>> Thanks,
>>
>> Best regards
>>
>> vencik
>>
>>
>>
>> On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote:
>> > Here is a patch of supporting ALPS v7 protocol device.
>> > ALPS v7 protocol device is a clickpad that is currently used on
>> > Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1,
>> > as well as other machines with ALPS Touchpad of following infomation:
>> >       Device ID = 0x73, 0x03, 0x0a
>> >       Firmware ID = 0x88, 0xb*, 0x**
>> >
>> > A v7 protocol support patch is first relesed 2 months ago:
>> > http://www.spinics.net/lists/linux-input/msg29084.html
>> > After that some feedbacks were received from end user. Now this patch
>> fixed the bugs
>> > reported by them:
>> > 1) Fix cursor jump when doing a right click drag
>> > 2) Fix cursor jitter when button clicking
>> >
>> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>> > ---
>> >  drivers/input/mouse/alps.c | 560
>> ++++++++++++++++++++++++++++++++++++++++++---
>> >  drivers/input/mouse/alps.h | 132 +++++++++--
>> >  2 files changed, 641 insertions(+), 51 deletions(-)
>> >
>> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>> > index fb15c64..383281f 100644
>> > --- a/drivers/input/mouse/alps.c
>> > +++ b/drivers/input/mouse/alps.c
>> > @@ -32,6 +32,13 @@
>> >  #define ALPS_REG_BASE_RUSHMORE       0xc2c0
>> >  #define ALPS_REG_BASE_PINNACLE       0x0000
>> >
>> > +#define LEFT_BUTTON_BIT                      0x01
>> > +#define RIGHT_BUTTON_BIT             0x02
>> > +
>> > +#define V7_LARGE_MOVEMENT            130
>> > +#define V7_DEAD_ZONE_OFFSET_X        72
>> > +#define V7_DEAD_ZONE_OFFSET_Y        72
>> > +
>> >  static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>> >       { PSMOUSE_CMD_SETPOLL,          0x00 }, /* 0 */
>> >       { PSMOUSE_CMD_RESET_DIS,        0x00 }, /* 1 */
>> > @@ -99,6 +106,7 @@ static const struct alps_nibble_commands
>> alps_v6_nibble_commands[] = {
>> >  #define ALPS_FOUR_BUTTONS    0x40    /* 4 direction button present */
>> >  #define ALPS_PS2_INTERLEAVED 0x80    /* 3-byte PS/2 packet interleaved
>> with
>> >                                          6-byte ALPS packet */
>> > +#define ALPS_BTNLESS                 0x100   /* ALPS ClickPad flag */
>> >
>> >  static const struct alps_model_info alps_model_data[] = {
>> >       { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS
>> | ALPS_DUALPOINT },  /* Toshiba Salellite Pro M10 */
>> > @@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struct alps_data
>> *priv,
>> >   * isn't valid per PS/2 spec.
>> >   */
>> >
>> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>> > +                                 struct alps_abs_data *pt1)
>> > +{
>> > +     int vect_x, vect_y;
>> > +
>> > +     if (!pt0 || !pt1)
>> > +             return 0;
>> > +
>> > +     vect_x = pt0->x - pt1->x;
>> > +     vect_y = pt0->y - pt1->y;
>> > +
>> > +     return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>> > +}
>> > +
>> >  /* Packet formats are described in Documentation/input/alps.txt */
>> >
>> >  static bool alps_is_valid_first_byte(struct alps_data *priv,
>> > @@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(struct
>> alps_data *priv,
>> >               end_bit = y_msb - 1;
>> >               box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>> >                               (2 * (priv->y_bits - 1));
>> > -             *x1 = fields->x;
>> > -             *y1 = fields->y;
>> > +             *x1 = fields->pt.x;
>> > +             *y1 = fields->pt.y;
>> >               *x2 = 2 * box_middle_x - *x1;
>> >               *y2 = 2 * box_middle_y - *y1;
>> >       }
>> > @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct
>> input_dev *dev, int num_fingers,
>> >       alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>> >  }
>> >
>> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>> > +                                   struct alps_fields *f)
>> > +{
>> > +     struct input_dev *dev;
>> > +
>> > +     if (!psmouse || !f)
>> > +             return;
>> > +
>> > +     dev = psmouse->dev;
>> > +
>> > +     if (f->fingers) {
>> > +             input_report_key(dev, BTN_TOUCH, 1);
>> > +             alps_report_semi_mt_data(dev, f->fingers,
>> > +                     f->pt_img[0].x, f->pt_img[0].y,
>> > +                     f->pt_img[1].x, f->pt_img[1].y);
>> > +             input_mt_report_finger_count(dev, f->fingers);
>> > +
>> > +             input_report_abs(dev, ABS_X, f->pt_img[0].x);
>> > +             input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>> > +             input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>> > +     } else {
>> > +             input_report_key(dev, BTN_TOUCH, 0);
>> > +             input_mt_report_finger_count(dev, 0);
>> > +             input_report_abs(dev, ABS_PRESSURE, 0);
>> > +     }
>> > +
>> > +     input_report_key(dev, BTN_LEFT, f->btn.left);
>> > +     input_report_key(dev, BTN_RIGHT, f->btn.right);
>> > +
>> > +     input_sync(dev);
>> > +}
>> > +
>> >  static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> >  {
>> >       struct alps_data *priv = psmouse->private;
>> > @@ -523,13 +577,13 @@ static void
>> alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> >
>> >  static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char
>> *p)
>> >  {
>> > -     f->left = !!(p[3] & 0x01);
>> > -     f->right = !!(p[3] & 0x02);
>> > -     f->middle = !!(p[3] & 0x04);
>> > +     f->btn.left = !!(p[3] & 0x01);
>> > +     f->btn.right = !!(p[3] & 0x02);
>> > +     f->btn.middle = !!(p[3] & 0x04);
>> >
>> > -     f->ts_left = !!(p[3] & 0x10);
>> > -     f->ts_right = !!(p[3] & 0x20);
>> > -     f->ts_middle = !!(p[3] & 0x40);
>> > +     f->btn.ts_left = !!(p[3] & 0x10);
>> > +     f->btn.ts_right = !!(p[3] & 0x20);
>> > +     f->btn.ts_middle = !!(p[3] & 0x40);
>> >  }
>> >
>> >  static void alps_decode_pinnacle(struct alps_fields *f, unsigned char
>> *p,
>> > @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct
>> alps_fields *f, unsigned char *p,
>> >                  ((p[2] & 0x7f) << 1) |
>> >                  (p[4] & 0x01);
>> >
>> > -     f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > +     f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> >              ((p[0] & 0x30) >> 4);
>> > -     f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > -     f->z = p[5] & 0x7f;
>> > +     f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > +     f->pt.z = p[5] & 0x7f;
>> >
>> >       alps_decode_buttons_v3(f, p);
>> >  }
>> > @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields
>> *f, unsigned char *p,
>> >       f->is_mp = !!(p[0] & 0x20);
>> >
>> >       if (!f->is_mp) {
>> > -             f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > -             f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > -             f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > +             f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > +             f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > +             f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> >               alps_decode_buttons_v3(f, p);
>> >       } else {
>> >               f->fingers = ((p[0] & 0x6) >> 1 |
>> > @@ -687,7 +741,7 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >        * with x, y, and z all zero, so these seem to be flukes.
>> >        * Ignore them.
>> >        */
>> > -     if (f.x && f.y && !f.z)
>> > +     if (f.pt.x && f.pt.y && !f.pt.z)
>> >               return;
>> >
>> >       /*
>> > @@ -695,12 +749,12 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >        * to rely on ST data.
>> >        */
>> >       if (!fingers) {
>> > -             x1 = f.x;
>> > -             y1 = f.y;
>> > -             fingers = f.z > 0 ? 1 : 0;
>> > +             x1 = f.pt.x;
>> > +             y1 = f.pt.y;
>> > +             fingers = f.pt.z > 0 ? 1 : 0;
>> >       }
>> >
>> > -     if (f.z >= 64)
>> > +     if (f.pt.z >= 64)
>> >               input_report_key(dev, BTN_TOUCH, 1);
>> >       else
>> >               input_report_key(dev, BTN_TOUCH, 0);
>> > @@ -709,22 +763,22 @@ static void
>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >
>> >       input_mt_report_finger_count(dev, fingers);
>> >
>> > -     input_report_key(dev, BTN_LEFT, f.left);
>> > -     input_report_key(dev, BTN_RIGHT, f.right);
>> > -     input_report_key(dev, BTN_MIDDLE, f.middle);
>> > +     input_report_key(dev, BTN_LEFT, f.btn.left);
>> > +     input_report_key(dev, BTN_RIGHT, f.btn.right);
>> > +     input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>> >
>> > -     if (f.z > 0) {
>> > -             input_report_abs(dev, ABS_X, f.x);
>> > -             input_report_abs(dev, ABS_Y, f.y);
>> > +     if (f.pt.z > 0) {
>> > +             input_report_abs(dev, ABS_X, f.pt.x);
>> > +             input_report_abs(dev, ABS_Y, f.pt.y);
>> >       }
>> > -     input_report_abs(dev, ABS_PRESSURE, f.z);
>> > +     input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>> >
>> >       input_sync(dev);
>> >
>> >       if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>> > -             input_report_key(dev2, BTN_LEFT, f.ts_left);
>> > -             input_report_key(dev2, BTN_RIGHT, f.ts_right);
>> > -             input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
>> > +             input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>> > +             input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>> > +             input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>> >               input_sync(dev2);
>> >       }
>> >  }
>> > @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse
>> *psmouse)
>> >       input_sync(dev);
>> >  }
>> >
>> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>> > +{
>> > +     if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) !=
>> 0x40))
>> > +             return false;
>> > +     if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) !=
>> 0x48))
>> > +             return false;
>> > +     if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>> > +             return false;
>> > +     return true;
>> > +}
>> > +
>> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int drop = 1;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > +             drop = 0;
>> > +
>> > +     return drop;
>> > +}
>> > +
>> > +static unsigned char alps_get_packet_id_v7(char *byte)
>> > +{
>> > +     unsigned char packet_id;
>> > +
>> > +     if (byte[4] & 0x40)
>> > +             packet_id = V7_PACKET_ID_TWO;
>> > +     else if (byte[4] & 0x01)
>> > +             packet_id = V7_PACKET_ID_MULTI;
>> > +     else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>> > +             packet_id = V7_PACKET_ID_NEW;
>> > +     else
>> > +             packet_id = V7_PACKET_ID_IDLE;
>> > +
>> > +     return packet_id;
>> > +}
>> > +
>> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>> > +                                       unsigned char *pkt,
>> > +                                       unsigned char pkt_id)
>> > +{
>> > +     if ((pkt_id == V7_PACKET_ID_TWO) ||
>> > +        (pkt_id == V7_PACKET_ID_MULTI) ||
>> > +        (pkt_id == V7_PACKET_ID_NEW)) {
>> > +             pt[0].x = ((pkt[2] & 0x80) << 4);
>> > +             pt[0].x |= ((pkt[2] & 0x3F) << 5);
>> > +             pt[0].x |= ((pkt[3] & 0x30) >> 1);
>> > +             pt[0].x |= (pkt[3] & 0x07);
>> > +             pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>> > +
>> > +             pt[1].x = ((pkt[3] & 0x80) << 4);
>> > +             pt[1].x |= ((pkt[4] & 0x80) << 3);
>> > +             pt[1].x |= ((pkt[4] & 0x3F) << 4);
>> > +             pt[1].y = ((pkt[5] & 0x80) << 3);
>> > +             pt[1].y |= ((pkt[5] & 0x3F) << 4);
>> > +
>> > +             if (pkt_id == V7_PACKET_ID_TWO) {
>> > +                     pt[1].x &= ~0x000F;
>> > +                     pt[1].y |= 0x000F;
>> > +             } else if (pkt_id == V7_PACKET_ID_MULTI) {
>> > +                     pt[1].x &= ~0x003F;
>> > +                     pt[1].y &= ~0x0020;
>> > +                     pt[1].y |= ((pkt[4] & 0x02) << 4);
>> > +                     pt[1].y |= 0x001F;
>> > +             } else if (pkt_id == V7_PACKET_ID_NEW) {
>> > +                     pt[1].x &= ~0x003F;
>> > +                     pt[1].x |= (pkt[0] & 0x20);
>> > +                     pt[1].y |= 0x000F;
>> > +             }
>> > +
>> > +             pt[0].y = 0x7FF - pt[0].y;
>> > +             pt[1].y = 0x7FF - pt[1].y;
>> > +
>> > +             pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>> > +             pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>> > +     }
>> > +}
>> > +
>> > +static void alps_decode_packet_v7(struct alps_fields *f,
>> > +                               unsigned char *p,
>> > +                               struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     static struct v7_raw prev_r;
>> > +
>> > +     priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>> > +
>> > +     alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>> > +
>> > +     priv->r.v7.rest_left = 0;
>> > +     priv->r.v7.rest_right = 0;
>> > +     priv->r.v7.additional_fingers = 0;
>> > +     priv->phy_btn = 0;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>> > +             priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>> > +             priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>> > +     }
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > +             priv->r.v7.additional_fingers = p[5] & 0x03;
>> > +
>> > +     priv->phy_btn = (p[0] & 0x80) >> 7;
>> > +
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
>> > +             if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
>> > +                     priv->r.v7.raw_fn = 2;
>> > +             else
>> > +                     priv->r.v7.raw_fn = 1;
>> > +     } else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > +             priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > +             priv->r.v7.raw_fn = 0;
>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
>> > +             priv->r.v7.raw_fn = prev_r.raw_fn;
>> > +
>> > +     /* It is a trick to bypass firmware bug of older version
>> > +     that 'New' Packet is missed when finger number changed.
>> > +     We fake a 'New' Packet in such cases.*/
>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) {
>> > +             if (priv->r.v7.raw_fn != prev_r.raw_fn)
>> > +                     priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
>> > +     }
>> > +
>> > +     memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
>> > +}
>> > +
>> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>> > +                                  struct alps_abs_data *pt,
>> > +                                  struct alps_bl_pt_attr *pt_attr)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     unsigned int dist;
>> > +
>> > +     if (!pt_attr->is_init_pt_got && pt->z != 0) {
>> > +             pt_attr->is_init_pt_got = 1;
>> > +             pt_attr->is_counted = 0;
>> > +             memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>> > +     }
>> > +
>> > +     if (pt->z != 0) {
>> > +             if (pt->y < priv->resting_zone_y_min) {
>> > +                     /* A finger is recognized as a non-resting finger
>> > +                     if it's position is outside the resting finger
>> zone.*/
>> > +                     pt_attr->zone = ZONE_NORMAL;
>> > +                     pt_attr->is_counted = 1;
>> > +             } else {
>> > +                     /* A finger is recognized as a resting finger if
>> it's
>> > +                     position is inside the resting finger zone and
>> there's
>> > +                     no large movement from it's touch down position.*/
>> > +                     pt_attr->zone = ZONE_RESTING;
>> > +
>> > +                     if (pt->x > priv->x_max / 2)
>> > +                             pt_attr->zone |= ZONE_RIGHT_BTN;
>> > +                     else
>> > +                             pt_attr->zone |= ZONE_LEFT_BTN;
>> > +
>> > +                     /* A resting finger will turn to be a non-resting
>> > +                     finger if it has made large movement from it's
>> touch
>> > +                     down position. A non-resting finger will never turn
>> > +                     to a resting finger before it leaves the touchpad
>> > +                     surface.*/
>> > +                     if (pt_attr->is_init_pt_got) {
>> > +                             dist = alps_pt_distance(pt,
>> &pt_attr->init_pt);
>> > +
>> > +                             if (dist > V7_LARGE_MOVEMENT)
>> > +                                     pt_attr->is_counted = 1;
>> > +                     }
>> > +             }
>> > +     }
>> > +}
>> > +
>> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>> > +                                    struct alps_fields *f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int i;
>> > +
>> > +     switch (priv->r.v7.pkt_id) {
>> > +     case  V7_PACKET_ID_TWO:
>> > +     case  V7_PACKET_ID_MULTI:
>> > +             for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > +                     alps_set_each_pt_attr_v7(psmouse,
>> > +                                              &f->pt_img[i],
>> > +                                              &priv->pt_attr[i]);
>> > +             }
>> > +             break;
>> > +     default:
>> > +             /*All finger attributes are cleared when packet ID is
>> > +             'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>> > +             indicates that there's no finger and no button activity.
>> > +             A 'NEW' packet indicates the finger position in packet
>> > +             is not continues from previous packet. Such as the
>> > +             condition there's finger placed or lifted. In these cases,
>> > +             finger attributes will be reset.*/
>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> > +             break;
>> > +     }
>> > +}
>> > +
>> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>> > +                                     struct alps_fields *f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     unsigned int fn = 0;
>> > +     int i;
>> > +
>> > +     switch (priv->r.v7.pkt_id) {
>> > +     case V7_PACKET_ID_IDLE:
>> > +     case V7_PACKET_ID_NEW:
>> > +             /*No finger is reported when packet ID is 'IDLE' or 'New'.
>> > +             An 'IDLE' packet indicates that there's no finger on
>> touchpad.
>> > +             A 'NEW' packet indicates there's finger placed or lifted.
>> > +             Finger position of 'New' packet is not continues from the
>> > +             previous packet.*/
>> > +             fn = 0;
>> > +             break;
>> > +     case V7_PACKET_ID_TWO:
>> > +             if (f->pt_img[0].z == 0) {
>> > +                     /*The first finger slot is zero when a non-resting
>> > +                     finger lifted and remaining only one resting finger
>> > +                     on touchpad. Hardware report the remaining resting
>> > +                     finger in second slot. This resting is ignored*/
>> > +                     fn = 0;
>> > +             } else if (f->pt_img[1].z == 0) {
>> > +                     /* The second finger slot is zero if there's
>> > +                     only one finger*/
>> > +                     fn = 1;
>> > +             } else {
>> > +                     /*All non-resting fingers will be counted to
>> report*/
>> > +                     fn = 0;
>> > +                     for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > +                             if (priv->pt_attr[i].is_counted)
>> > +                                     fn++;
>> > +                     }
>> > +
>> > +                     /*In the case that both fingers are
>> > +                     resting fingers, report the first one*/
>> > +                     if (!priv->pt_attr[0].is_counted &&
>> > +                         !priv->pt_attr[1].is_counted) {
>> > +                             fn = 1;
>> > +                     }
>> > +             }
>> > +             break;
>> > +     case V7_PACKET_ID_MULTI:
>> > +             /*A packet ID 'MULTI' indicats that at least 3 non-resting
>> > +             finger exist.*/
>> > +             fn = 3 + priv->r.v7.additional_fingers;
>> > +             break;
>> > +     }
>> > +
>> > +     f->fingers = fn;
>> > +}
>> > +
>> > +static void alps_button_dead_zone_filter(struct psmouse *psmouse,
>> > +                                struct alps_fields *f,
>> > +                                struct alps_fields *prev_f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     int dx, dy;
>> > +
>> > +     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
>> > +             memcpy(&priv->pt_attr[0].init_dead_pt,
>> > +                             &f->pt_img[0],
>> > +                             sizeof(struct alps_abs_data));
>> > +     }
>> > +
>> > +     if (priv->pt_attr[0].init_dead_pt.x != 0 &&
>> > +             priv->pt_attr[0].init_dead_pt.x != 0) {
>> > +                     dx = f->pt_img[0].x -
>> priv->pt_attr[0].init_dead_pt.x;
>> > +                     dy = f->pt_img[0].y -
>> priv->pt_attr[0].init_dead_pt.y;
>> > +             if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
>> > +                     (abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) {
>> > +                             memset(&priv->pt_attr[0].init_dead_pt, 0,
>> > +                                             sizeof(struct
>> alps_abs_data));
>> > +                             priv->btn_delay_cnt = 0;
>> > +             } else {
>> > +                     memcpy(&f->pt_img[0],
>> > +                                     &prev_f->pt_img[0],
>> > +                                     sizeof(struct alps_abs_data));
>> > +                     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
>> > +                             priv->btn_delay_cnt = 2;
>> > +             }
>> > +     }
>> > +
>> > +     if (priv->btn_delay_cnt > 0) {
>> > +             f->btn.left = 0;
>> > +             f->btn.right = 0;
>> > +             priv->btn_delay_cnt--;
>> > +     }
>> > +}
>> > +
>> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>> > +                                struct alps_fields *f,
>> > +                                struct alps_fields *prev_f)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +
>> > +     if (priv->phy_btn) {
>> > +             if (!priv->prev_phy_btn) {
>> > +                     /* Report a right click as long as there's finger
>> on
>> > +                     right button zone. Othrewise, report a left
>> click.*/
>> > +                     if (priv->r.v7.rest_right ||
>> > +                         priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>> > +                         priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>> > +                             f->btn.right = 1;
>> > +                             priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>> > +                     } else {
>> > +                             f->btn.left = 1;
>> > +                             priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>> > +                     }
>> > +             } else {
>> > +                     if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>> > +                             f->btn.right = 1;
>> > +                     if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>> > +                             f->btn.left = 1;
>> > +             }
>> > +     } else {
>> > +             priv->pressed_btn_bits = 0;
>> > +             f->btn.right = 0;
>> > +             f->btn.left = 0;
>> > +     }
>> > +
>> > +     alps_button_dead_zone_filter(psmouse, f, prev_f);
>> > +
>> > +     priv->prev_phy_btn = priv->phy_btn;
>> > +}
>> > +
>> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct alps_data *priv = psmouse->private;
>> > +     struct alps_fields f = {0};
>> > +     static struct alps_fields prev_f;
>> > +     unsigned char *packet = psmouse->packet;
>> > +
>> > +     priv->decode_fields(&f, packet, psmouse);
>> > +
>> > +     if (alps_drop_unsupported_packet_v7(psmouse))
>> > +             return;
>> > +
>> > +     alps_set_pt_attr_v7(psmouse, &f);
>> > +
>> > +     alps_cal_output_finger_num_v7(psmouse, &f);
>> > +
>> > +     alps_assign_buttons_v7(psmouse, &f, &prev_f);
>> > +
>> > +     alps_report_coord_and_btn(psmouse, &f);
>> > +
>> > +     memcpy(&prev_f, &f, sizeof(struct alps_fields));
>> > +}
>> > +
>> >  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>> >                                       unsigned char packet[],
>> >                                       bool report_buttons)
>> > @@ -1080,6 +1492,14 @@ static psmouse_ret_t alps_process_byte(struct
>> psmouse *psmouse)
>> >               return PSMOUSE_BAD_DATA;
>> >       }
>> >
>> > +     if ((priv->proto_version == ALPS_PROTO_V7 &&
>> > +         !alps_is_valid_package_v7(psmouse))) {
>> > +             psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>> > +                         psmouse->pktcnt - 1,
>> > +                         psmouse->packet[psmouse->pktcnt - 1]);
>> > +             return PSMOUSE_BAD_DATA;
>> > +     }
>> > +
>> >       if (psmouse->pktcnt == psmouse->pktsize) {
>> >               priv->process_packet(psmouse);
>> >               return PSMOUSE_FULL_PACKET;
>> > @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse,
>> int init_command,
>> >       return 0;
>> >  }
>> >
>> > +static int alps_check_valid_firmware_id(unsigned char id[])
>> > +{
>> > +     int valid = 1;
>> > +
>> > +     if (id[0] == 0x73)
>> > +             valid = 1;
>> > +     else if (id[0] == 0x88) {
>> > +             if ((id[1] == 0x07) ||
>> > +                 (id[1] == 0x08) ||
>> > +                 ((id[1] & 0xf0) == 0xB0))
>> > +                     valid = 1;
>> > +     }
>> > +
>> > +     return valid;
>> > +}
>> > +
>> >  static int alps_enter_command_mode(struct psmouse *psmouse)
>> >  {
>> >       unsigned char param[4];
>> > @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse
>> *psmouse)
>> >               return -1;
>> >       }
>> >
>> > -     if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>> > -         param[0] != 0x73) {
>> > +     if (!alps_check_valid_firmware_id(param)) {
>> >               psmouse_dbg(psmouse,
>> >                           "unknown response while entering command
>> mode\n");
>> >               return -1;
>> > @@ -1704,6 +2139,36 @@ error:
>> >       return ret;
>> >  }
>> >
>> > +static int alps_hw_init_v7(struct psmouse *psmouse)
>> > +{
>> > +     struct ps2dev *ps2dev = &psmouse->ps2dev;
>> > +     int reg_val, ret = -1;
>> > +
>> > +     if (alps_enter_command_mode(psmouse))
>> > +             goto error;
>> > +
>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
>> > +     if (reg_val == -1)
>> > +             goto error;
>> > +
>> > +     if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
>> > +             goto error;
>> > +
>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
>> > +     if (reg_val == -1)
>> > +             goto error;
>> > +
>> > +     if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
>> > +             goto error;
>> > +
>> > +     alps_exit_command_mode(psmouse);
>> > +     return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
>> > +
>> > +error:
>> > +     alps_exit_command_mode(psmouse);
>> > +     return ret;
>> > +}
>> > +
>> >  /* Must be in command mode when calling this function */
>> >  static int alps_absolute_mode_v4(struct psmouse *psmouse)
>> >  {
>> > @@ -1875,6 +2340,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->set_abs_params = alps_set_abs_params_st;
>> >               priv->x_max = 1023;
>> >               priv->y_max = 767;
>> > +             priv->slot_number = 1;
>> >               break;
>> >       case ALPS_PROTO_V3:
>> >               priv->hw_init = alps_hw_init_v3;
>> > @@ -1883,6 +2349,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->decode_fields = alps_decode_pinnacle;
>> >               priv->nibble_commands = alps_v3_nibble_commands;
>> >               priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V4:
>> >               priv->hw_init = alps_hw_init_v4;
>> > @@ -1890,6 +2357,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->set_abs_params = alps_set_abs_params_mt;
>> >               priv->nibble_commands = alps_v4_nibble_commands;
>> >               priv->addr_command = PSMOUSE_CMD_DISABLE;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V5:
>> >               priv->hw_init = alps_hw_init_dolphin_v1;
>> > @@ -1905,6 +2373,7 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->y_max = 660;
>> >               priv->x_bits = 23;
>> >               priv->y_bits = 12;
>> > +             priv->slot_number = 2;
>> >               break;
>> >       case ALPS_PROTO_V6:
>> >               priv->hw_init = alps_hw_init_v6;
>> > @@ -1913,6 +2382,28 @@ static void alps_set_defaults(struct alps_data
>> *priv)
>> >               priv->nibble_commands = alps_v6_nibble_commands;
>> >               priv->x_max = 2047;
>> >               priv->y_max = 1535;
>> > +             priv->slot_number = 2;
>> > +             break;
>> > +     case ALPS_PROTO_V7:
>> > +             priv->hw_init = alps_hw_init_v7;
>> > +             priv->process_packet = alps_process_packet_v7;
>> > +             priv->decode_fields = alps_decode_packet_v7;
>> > +             priv->set_abs_params = alps_set_abs_params_mt;
>> > +             priv->nibble_commands = alps_v3_nibble_commands;
>> > +             priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > +             priv->x_max = 0xfff;
>> > +             priv->y_max = 0x7ff;
>> > +             priv->resting_zone_y_min = 0x654;
>> > +             priv->byte0 = 0x48;
>> > +             priv->mask0 = 0x48;
>> > +             priv->flags = 0;
>> > +             priv->slot_number = 2;
>> > +
>> > +             priv->phy_btn = 0;
>> > +             priv->prev_phy_btn = 0;
>> > +             priv->btn_delay_cnt = 0;
>> > +             priv->pressed_btn_bits = 0;
>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> >               break;
>> >       }
>> >  }
>> > @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse,
>> struct alps_data *priv)
>> >                       return -EIO;
>> >               else
>> >                       return 0;
>> > +     } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>> > +             priv->proto_version = ALPS_PROTO_V7;
>> > +             alps_set_defaults(priv);
>> > +
>> > +             return 0;
>> >       } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>> >               priv->proto_version = ALPS_PROTO_V3;
>> >               alps_set_defaults(priv);
>> > @@ -2045,7 +2541,7 @@ static void alps_set_abs_params_mt(struct
>> alps_data *priv,
>> >                                  struct input_dev *dev1)
>> >  {
>> >       set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>> > -     input_mt_init_slots(dev1, 2, 0);
>> > +     input_mt_init_slots(dev1, priv->slot_number, 0);
>> >       input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0,
>> 0);
>> >       input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0,
>> 0);
>> >
>> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>> > index 03f88b6..dedbd27 100644
>> > --- a/drivers/input/mouse/alps.h
>> > +++ b/drivers/input/mouse/alps.h
>> > @@ -18,11 +18,36 @@
>> >  #define ALPS_PROTO_V4        4
>> >  #define ALPS_PROTO_V5        5
>> >  #define ALPS_PROTO_V6        6
>> > +#define ALPS_PROTO_V7        7
>> > +
>> > +#define MAX_IMG_PT_NUM               5
>> > +#define V7_IMG_PT_NUM                2
>> > +
>> > +#define ZONE_NORMAL                          0x01
>> > +#define ZONE_RESTING                 0x02
>> > +#define ZONE_LEFT_BTN                        0x04
>> > +#define ZONE_RIGHT_BTN                       0x08
>> >
>> >  #define DOLPHIN_COUNT_PER_ELECTRODE  64
>> >  #define DOLPHIN_PROFILE_XOFFSET              8       /* x-electrode
>> offset */
>> >  #define DOLPHIN_PROFILE_YOFFSET              1       /* y-electrode
>> offset */
>> >
>> > +/*
>> > + * enum V7_PACKET_ID - defines the packet type for V7
>> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>> > + *  or there's button activities.
>> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>> > + *  previous packet.
>> > +*/
>> > +enum V7_PACKET_ID {
>> > +      V7_PACKET_ID_IDLE,
>> > +      V7_PACKET_ID_TWO,
>> > +      V7_PACKET_ID_MULTI,
>> > +      V7_PACKET_ID_NEW,
>> > +};
>> > +
>> >  /**
>> >   * struct alps_model_info - touchpad ID table
>> >   * @signature: E7 response string to match.
>> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>> >  };
>> >
>> >  /**
>> > - * struct alps_fields - decoded version of the report packet
>> > - * @x_map: Bitmap of active X positions for MT.
>> > - * @y_map: Bitmap of active Y positions for MT.
>> > - * @fingers: Number of fingers for MT.
>> > - * @x: X position for ST.
>> > - * @y: Y position for ST.
>> > - * @z: Z position for ST.
>> > - * @first_mp: Packet is the first of a multi-packet report.
>> > - * @is_mp: Packet is part of a multi-packet report.
>> > + * struct alps_btn - decoded version of the button status
>> >   * @left: Left touchpad button is active.
>> >   * @right: Right touchpad button is active.
>> >   * @middle: Middle touchpad button is active.
>> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>> >   * @ts_right: Right trackstick button is active.
>> >   * @ts_middle: Middle trackstick button is active.
>> >   */
>> > -struct alps_fields {
>> > -     unsigned int x_map;
>> > -     unsigned int y_map;
>> > -     unsigned int fingers;
>> > -     unsigned int x;
>> > -     unsigned int y;
>> > -     unsigned int z;
>> > -     unsigned int first_mp:1;
>> > -     unsigned int is_mp:1;
>> > -
>> > +struct alps_btn {
>> >       unsigned int left:1;
>> >       unsigned int right:1;
>> >       unsigned int middle:1;
>> > @@ -102,6 +110,73 @@ struct alps_fields {
>> >  };
>> >
>> >  /**
>> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>> > + * @x: X position for ST.
>> > + * @y: Y position for ST.
>> > + * @z: Z position for ST.
>> > + */
>> > +struct alps_abs_data {
>> > +     unsigned int x;
>> > +     unsigned int y;
>> > +     unsigned int z;
>> > +};
>> > +
>> > +/**
>> > + * struct alps_fields - decoded version of the report packet
>> > + * @fingers: Number of fingers for MT.
>> > + * @pt: X Y Z postion for ST.
>> > + * @pt: X Y Z postion for image MT.
>> > + * @x_map: Bitmap of active X positions for MT.
>> > + * @y_map: Bitmap of active Y positions for MT.
>> > + * @first_mp: Packet is the first of a multi-packet report.
>> > + * @is_mp: Packet is part of a multi-packet report.
>> > + * @btn: Button activity status
>> > + */
>> > +struct alps_fields {
>> > +     unsigned int fingers;
>> > +     struct alps_abs_data pt;
>> > +     struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>> > +     unsigned int x_map;
>> > +     unsigned int y_map;
>> > +     unsigned int first_mp:1;
>> > +     unsigned int is_mp:1;
>> > +     struct alps_btn btn;
>> > +};
>> > +
>> > +/**
>> > + * struct v7_raw - data decoded from raw packet for V7.
>> > + * @pkt_id: An id that specifies the type of packet.
>> > + * @additional_fingers: Number of additional finger that is neighter
>> included
>> > + *  in pt slot nor reflected in rest_left and rest_right flag of data
>> packet.
>> > + * @rest_left: There are fingers on left resting zone.
>> > + * @rest_right: There are fingers on right resting zone.
>> > + * @raw_fn: The number of finger on touchpad.
>> > + */
>> > +struct v7_raw {
>> > +     unsigned char pkt_id;
>> > +     unsigned int additional_fingers;
>> > +     unsigned char rest_left;
>> > +     unsigned char rest_right;
>> > +     unsigned char raw_fn;
>> > +};
>> > +
>> > +/**
>> > + * struct alps_bl_pt_attr - generic attributes of touch points for
>> buttonless device
>> > + * @zone: The part of touchpad that the touch point locates
>> > + * @is_counted: The touch point is not a resting finger.
>> > + * @is_init_pt_got: The touch down point is got.
>> > + * @init_pt: The X Y Z position of the touch down point.
>> > + * @init_dead_pt: The touch down point of a finger used by dead zone
>> process.
>> > + */
>> > +struct alps_bl_pt_attr {
>> > +     unsigned char zone;
>> > +     unsigned char is_counted;
>> > +     unsigned char is_init_pt_got;
>> > +     struct alps_abs_data init_pt;
>> > +     struct alps_abs_data init_dead_pt;
>> > +};
>> > +
>> > +/**
>> >   * struct alps_data - private data structure for the ALPS driver
>> >   * @dev2: "Relative" device used to report trackstick or mouse activity.
>> >   * @phys: Physical path for the relative device.
>> > @@ -116,8 +191,10 @@ struct alps_fields {
>> >   * @flags: Additional device capabilities (passthrough port,
>> trackstick, etc.).
>> >   * @x_max: Largest possible X position value.
>> >   * @y_max: Largest possible Y position value.
>> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting
>> zone.
>> >   * @x_bits: Number of X bits in the MT bitmap.
>> >   * @y_bits: Number of Y bits in the MT bitmap.
>> > + * @img_fingers: Number of image fingers.
>> >   * @hw_init: Protocol-specific hardware init function.
>> >   * @process_packet: Protocol-specific function to process a report
>> packet.
>> >   * @decode_fields: Protocol-specific function to read packet bitfields.
>> > @@ -132,6 +209,11 @@ struct alps_fields {
>> >   * @fingers: Number of fingers from last MT report.
>> >   * @quirks: Bitmap of ALPS_QUIRK_*.
>> >   * @timer: Timer for flushing out the final report packet in the stream.
>> > + * @v7: Data decoded from raw packet for V7
>> > + * @phy_btn: Physical button is active.
>> > + * @prev_phy_btn: Physical button of previous packet is active.
>> > + * @pressed_btn_bits: Pressed positon of button zone
>> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>> >   */
>> >  struct alps_data {
>> >       struct input_dev *dev2;
>> > @@ -145,8 +227,10 @@ struct alps_data {
>> >       unsigned char flags;
>> >       int x_max;
>> >       int y_max;
>> > +     int resting_zone_y_min;
>> >       int x_bits;
>> >       int y_bits;
>> > +     unsigned char slot_number;
>> >
>> >       int (*hw_init)(struct psmouse *psmouse);
>> >       void (*process_packet)(struct psmouse *psmouse);
>> > @@ -161,6 +245,16 @@ struct alps_data {
>> >       int fingers;
>> >       u8 quirks;
>> >       struct timer_list timer;
>> > +
>> > +     /* these are used for buttonless touchpad*/
>> > +     union {
>> > +             struct v7_raw v7;
>> > +     } r;
>> > +     unsigned char phy_btn;
>> > +     unsigned char prev_phy_btn;
>> > +     unsigned char btn_delay_cnt;
>> > +     unsigned char pressed_btn_bits;
>> > +     struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>> >  };
>> >
>> >  #define ALPS_QUIRK_TRACKSTICK_BUTTONS        1 /* trakcstick buttons in
>> trackstick packet */
>>
>>
>
--
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

^ permalink raw reply

* Re: [PATCH] input: add support for ALPS v7 protocol device
From: vencik @ 2014-03-27 10:10 UTC (permalink / raw)
  To: vencik, Elaine Chen
  Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, linux-input,
	Niels de Vos, jclift, Qiting Chen, Justin Clift
In-Reply-To: <20140327104711.88846433@razdva.cz>

Another clue: the odd behaviour described below disappears
if I switch tap-to-click off in synaptics X11 driver
(but no tap-to-click functionality, then, of course).

vencik

______________________________________________________________
> Od: <vencik@razdva.cz>
> Komu: Elaine Chen <elaineee66@gmail.com>
> Datum: 27.03.2014 10:58
> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>
> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>Hi again, Elaine,
>
>just something to add to the TP driver functionality;
>I've experienced something that looked as involuntary left
>button clicking.
>
>Using xev, I deduce that it happens when I remove the finger
>after doing just a short motion on the pad; if the motion is longer
>(apparently both in in distance and time) the click is not generated
>at the end.
>But when I do just a short and quite quick move, it produces a click.
>
>Perhaps it's just necessary to tune the driver a bit; what I'm talking about
>is something close to a tap, but past it; the motion may take about 1/2 second
>and the cursor moves for about a centimeter...
>I'll try to identify the code bit responsible and play with that.
>
>Regards,
>
>vencik
>
>
>______________________________________________________________
>> Od: Elaine Chen <elaineee66@gmail.com>
>> Komu: "Václav Krpec" <vencik@razdva.cz>
>> Datum: 27.03.2014 08:57
>> Předmět: Re: [PATCH] input: add support for ALPS v7 protocol device
>>
>> CC: "Dmitry Torokhov" <dmitry.torokhov@gmail.com>, "Kevin Cernekee" <cernekee@gmail.com>, "david turvene" <dturvene@dahetral.com>, linux-input@vger.kernel.org, "Niels de Vos" <ndevos@redhat.com>, jclift@redhat.com--cc, "Qiting Chen" <qiting.chen@cn.alps.com>, "Justin Clift" <justin@gluster.org>
>>Hello Vencik,
>>
>>Thank you for evaluating the patch.
>>
>>1/ About stickpoint support
>>Yes, this patch hasn't added stickpoint support for v7 protocol device.
>>What's the SP behavior on your Toshiba laptop after
>>applying our patch? No function or works abnormally? Please let me know the
>>phenomenon as I don't have a v7 TP/SP dual device currently.
>>I also checked your stickpoint process code. The SP packet decode seems
>>doesn't match the format of Specification. Sorry I haven't tested it as
>>lack of
>>device.Did it work on your machine?
>>I'll get down to support for SP next week I got such a device. And will
>>release it with next patch.
>>
>>2/ This patch is against Dmitry Torokhov's input tree(3.13-rc4)
>>https://git.kernel.org/cgit/linux/kernel/git/dtor/input.git/
>>I've checked the alps.(ch) from 3.13-rc4 and 3.14-rc8, they are the same.
>>Maybe there are something unmatch with patch format.
>>My patch is made from git format-patch.
>>
>>
>>
>>2014-03-26 20:20 GMT+08:00 Václav Krpec <vencik@razdva.cz>:
>>
>>> Hello Qiting,
>>>
>>> I've applied your patch and tested the driver on my Toshiba Portege
>>> Z30-A-12N (device ID is 73 03 0a, FW ver: 88 b3 22).
>>>
>>> The TP driver works nicely, however, I've observed a few things to note:
>>>
>>> 1/
>>> There's no support for trackstick; my device has one.
>>> Justin has suggested that it may be a Toshiba mod of the device...
>>> Nevertheless, since I was in process of RA of the device myself before
>>> you've committed the patch, I merged the TS driver to your patch;
>>> see alps_process_trackstick_packet_v7 function + tiny bit of
>>> refactoring of the packet ID resolving mechanism in the patch attached.
>>> I hope it shouldn't break the driver functionality for devices w/o
>>> the trackstick, but testing should definitely be done.
>>>
>>> 2/
>>> I've noticed that your patch wasn't cleanly applicable to current 3.14
>>> kernel; could you be more specific on what branch should it be applied?
>>> The patch attached is valid for 3.14-rc8 tree.
>>>
>>> 3/
>>> I also took the liberty of fixing indentation of your code a bit to put
>>> it (hopefully) more in line with the conventions of the alps.[ch]
>>>
>>> So, could you (or anyone else) test the patch attached?
>>> Comments, recommendations etc welcome.
>>>
>>> Thanks,
>>>
>>> Best regards
>>>
>>> vencik
>>>
>>>
>>>
>>> On Wed, 2014-03-19 at 16:55 +0800, Qiting Chen wrote:
>>> > Here is a patch of supporting ALPS v7 protocol device.
>>> > ALPS v7 protocol device is a clickpad that is currently used on
>>> > Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1,
>>> > as well as other machines with ALPS Touchpad of following infomation:
>>> >       Device ID = 0x73, 0x03, 0x0a
>>> >       Firmware ID = 0x88, 0xb*, 0x**
>>> >
>>> > A v7 protocol support patch is first relesed 2 months ago:
>>> > http://www.spinics.net/lists/linux-input/msg29084.html
>>> > After that some feedbacks were received from end user. Now this patch
>>> fixed the bugs
>>> > reported by them:
>>> > 1) Fix cursor jump when doing a right click drag
>>> > 2) Fix cursor jitter when button clicking
>>> >
>>> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>>> > ---
>>> >  drivers/input/mouse/alps.c | 560
>>> ++++++++++++++++++++++++++++++++++++++++++---
>>> >  drivers/input/mouse/alps.h | 132 +++++++++--
>>> >  2 files changed, 641 insertions(+), 51 deletions(-)
>>> >
>>> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>>> > index fb15c64..383281f 100644
>>> > --- a/drivers/input/mouse/alps.c
>>> > +++ b/drivers/input/mouse/alps.c
>>> > @@ -32,6 +32,13 @@
>>> >  #define ALPS_REG_BASE_RUSHMORE       0xc2c0
>>> >  #define ALPS_REG_BASE_PINNACLE       0x0000
>>> >
>>> > +#define LEFT_BUTTON_BIT                      0x01
>>> > +#define RIGHT_BUTTON_BIT             0x02
>>> > +
>>> > +#define V7_LARGE_MOVEMENT            130
>>> > +#define V7_DEAD_ZONE_OFFSET_X        72
>>> > +#define V7_DEAD_ZONE_OFFSET_Y        72
>>> > +
>>> >  static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>>> >       { PSMOUSE_CMD_SETPOLL,          0x00 }, /* 0 */
>>> >       { PSMOUSE_CMD_RESET_DIS,        0x00 }, /* 1 */
>>> > @@ -99,6 +106,7 @@ static const struct alps_nibble_commands
>>> alps_v6_nibble_commands[] = {
>>> >  #define ALPS_FOUR_BUTTONS    0x40    /* 4 direction button present */
>>> >  #define ALPS_PS2_INTERLEAVED 0x80    /* 3-byte PS/2 packet interleaved
>>> with
>>> >                                          6-byte ALPS packet */
>>> > +#define ALPS_BTNLESS                 0x100   /* ALPS ClickPad flag */
>>> >
>>> >  static const struct alps_model_info alps_model_data[] = {
>>> >       { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS
>>> | ALPS_DUALPOINT },  /* Toshiba Salellite Pro M10 */
>>> > @@ -140,6 +148,20 @@ static void alps_set_abs_params_mt(struct alps_data
>>> *priv,
>>> >   * isn't valid per PS/2 spec.
>>> >   */
>>> >
>>> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>>> > +                                 struct alps_abs_data *pt1)
>>> > +{
>>> > +     int vect_x, vect_y;
>>> > +
>>> > +     if (!pt0 || !pt1)
>>> > +             return 0;
>>> > +
>>> > +     vect_x = pt0->x - pt1->x;
>>> > +     vect_y = pt0->y - pt1->y;
>>> > +
>>> > +     return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>>> > +}
>>> > +
>>> >  /* Packet formats are described in Documentation/input/alps.txt */
>>> >
>>> >  static bool alps_is_valid_first_byte(struct alps_data *priv,
>>> > @@ -320,8 +342,8 @@ static void alps_process_bitmap_dolphin(struct
>>> alps_data *priv,
>>> >               end_bit = y_msb - 1;
>>> >               box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>>> >                               (2 * (priv->y_bits - 1));
>>> > -             *x1 = fields->x;
>>> > -             *y1 = fields->y;
>>> > +             *x1 = fields->pt.x;
>>> > +             *y1 = fields->pt.y;
>>> >               *x2 = 2 * box_middle_x - *x1;
>>> >               *y2 = 2 * box_middle_y - *y1;
>>> >       }
>>> > @@ -461,6 +483,38 @@ static void alps_report_semi_mt_data(struct
>>> input_dev *dev, int num_fingers,
>>> >       alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>>> >  }
>>> >
>>> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>>> > +                                   struct alps_fields *f)
>>> > +{
>>> > +     struct input_dev *dev;
>>> > +
>>> > +     if (!psmouse || !f)
>>> > +             return;
>>> > +
>>> > +     dev = psmouse->dev;
>>> > +
>>> > +     if (f->fingers) {
>>> > +             input_report_key(dev, BTN_TOUCH, 1);
>>> > +             alps_report_semi_mt_data(dev, f->fingers,
>>> > +                     f->pt_img[0].x, f->pt_img[0].y,
>>> > +                     f->pt_img[1].x, f->pt_img[1].y);
>>> > +             input_mt_report_finger_count(dev, f->fingers);
>>> > +
>>> > +             input_report_abs(dev, ABS_X, f->pt_img[0].x);
>>> > +             input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>>> > +             input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>>> > +     } else {
>>> > +             input_report_key(dev, BTN_TOUCH, 0);
>>> > +             input_mt_report_finger_count(dev, 0);
>>> > +             input_report_abs(dev, ABS_PRESSURE, 0);
>>> > +     }
>>> > +
>>> > +     input_report_key(dev, BTN_LEFT, f->btn.left);
>>> > +     input_report_key(dev, BTN_RIGHT, f->btn.right);
>>> > +
>>> > +     input_sync(dev);
>>> > +}
>>> > +
>>> >  static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>>> >  {
>>> >       struct alps_data *priv = psmouse->private;
>>> > @@ -523,13 +577,13 @@ static void
>>> alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>>> >
>>> >  static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char
>>> *p)
>>> >  {
>>> > -     f->left = !!(p[3] & 0x01);
>>> > -     f->right = !!(p[3] & 0x02);
>>> > -     f->middle = !!(p[3] & 0x04);
>>> > +     f->btn.left = !!(p[3] & 0x01);
>>> > +     f->btn.right = !!(p[3] & 0x02);
>>> > +     f->btn.middle = !!(p[3] & 0x04);
>>> >
>>> > -     f->ts_left = !!(p[3] & 0x10);
>>> > -     f->ts_right = !!(p[3] & 0x20);
>>> > -     f->ts_middle = !!(p[3] & 0x40);
>>> > +     f->btn.ts_left = !!(p[3] & 0x10);
>>> > +     f->btn.ts_right = !!(p[3] & 0x20);
>>> > +     f->btn.ts_middle = !!(p[3] & 0x40);
>>> >  }
>>> >
>>> >  static void alps_decode_pinnacle(struct alps_fields *f, unsigned char
>>> *p,
>>> > @@ -546,10 +600,10 @@ static void alps_decode_pinnacle(struct
>>> alps_fields *f, unsigned char *p,
>>> >                  ((p[2] & 0x7f) << 1) |
>>> >                  (p[4] & 0x01);
>>> >
>>> > -     f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>>> > +     f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>>> >              ((p[0] & 0x30) >> 4);
>>> > -     f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>>> > -     f->z = p[5] & 0x7f;
>>> > +     f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>>> > +     f->pt.z = p[5] & 0x7f;
>>> >
>>> >       alps_decode_buttons_v3(f, p);
>>> >  }
>>> > @@ -573,9 +627,9 @@ static void alps_decode_dolphin(struct alps_fields
>>> *f, unsigned char *p,
>>> >       f->is_mp = !!(p[0] & 0x20);
>>> >
>>> >       if (!f->is_mp) {
>>> > -             f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>>> > -             f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>>> > -             f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>>> > +             f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>>> > +             f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>>> > +             f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>>> >               alps_decode_buttons_v3(f, p);
>>> >       } else {
>>> >               f->fingers = ((p[0] & 0x6) >> 1 |
>>> > @@ -687,7 +741,7 @@ static void
>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>> >        * with x, y, and z all zero, so these seem to be flukes.
>>> >        * Ignore them.
>>> >        */
>>> > -     if (f.x && f.y && !f.z)
>>> > +     if (f.pt.x && f.pt.y && !f.pt.z)
>>> >               return;
>>> >
>>> >       /*
>>> > @@ -695,12 +749,12 @@ static void
>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>> >        * to rely on ST data.
>>> >        */
>>> >       if (!fingers) {
>>> > -             x1 = f.x;
>>> > -             y1 = f.y;
>>> > -             fingers = f.z > 0 ? 1 : 0;
>>> > +             x1 = f.pt.x;
>>> > +             y1 = f.pt.y;
>>> > +             fingers = f.pt.z > 0 ? 1 : 0;
>>> >       }
>>> >
>>> > -     if (f.z >= 64)
>>> > +     if (f.pt.z >= 64)
>>> >               input_report_key(dev, BTN_TOUCH, 1);
>>> >       else
>>> >               input_report_key(dev, BTN_TOUCH, 0);
>>> > @@ -709,22 +763,22 @@ static void
>>> alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>>> >
>>> >       input_mt_report_finger_count(dev, fingers);
>>> >
>>> > -     input_report_key(dev, BTN_LEFT, f.left);
>>> > -     input_report_key(dev, BTN_RIGHT, f.right);
>>> > -     input_report_key(dev, BTN_MIDDLE, f.middle);
>>> > +     input_report_key(dev, BTN_LEFT, f.btn.left);
>>> > +     input_report_key(dev, BTN_RIGHT, f.btn.right);
>>> > +     input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>>> >
>>> > -     if (f.z > 0) {
>>> > -             input_report_abs(dev, ABS_X, f.x);
>>> > -             input_report_abs(dev, ABS_Y, f.y);
>>> > +     if (f.pt.z > 0) {
>>> > +             input_report_abs(dev, ABS_X, f.pt.x);
>>> > +             input_report_abs(dev, ABS_Y, f.pt.y);
>>> >       }
>>> > -     input_report_abs(dev, ABS_PRESSURE, f.z);
>>> > +     input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>>> >
>>> >       input_sync(dev);
>>> >
>>> >       if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>>> > -             input_report_key(dev2, BTN_LEFT, f.ts_left);
>>> > -             input_report_key(dev2, BTN_RIGHT, f.ts_right);
>>> > -             input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
>>> > +             input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>>> > +             input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>>> > +             input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>>> >               input_sync(dev2);
>>> >       }
>>> >  }
>>> > @@ -916,6 +970,364 @@ static void alps_process_packet_v4(struct psmouse
>>> *psmouse)
>>> >       input_sync(dev);
>>> >  }
>>> >
>>> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>>> > +{
>>> > +     if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) !=
>>> 0x40))
>>> > +             return false;
>>> > +     if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) !=
>>> 0x48))
>>> > +             return false;
>>> > +     if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>>> > +             return false;
>>> > +     return true;
>>> > +}
>>> > +
>>> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     int drop = 1;
>>> > +
>>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>>> > +             drop = 0;
>>> > +
>>> > +     return drop;
>>> > +}
>>> > +
>>> > +static unsigned char alps_get_packet_id_v7(char *byte)
>>> > +{
>>> > +     unsigned char packet_id;
>>> > +
>>> > +     if (byte[4] & 0x40)
>>> > +             packet_id = V7_PACKET_ID_TWO;
>>> > +     else if (byte[4] & 0x01)
>>> > +             packet_id = V7_PACKET_ID_MULTI;
>>> > +     else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>>> > +             packet_id = V7_PACKET_ID_NEW;
>>> > +     else
>>> > +             packet_id = V7_PACKET_ID_IDLE;
>>> > +
>>> > +     return packet_id;
>>> > +}
>>> > +
>>> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>>> > +                                       unsigned char *pkt,
>>> > +                                       unsigned char pkt_id)
>>> > +{
>>> > +     if ((pkt_id == V7_PACKET_ID_TWO) ||
>>> > +        (pkt_id == V7_PACKET_ID_MULTI) ||
>>> > +        (pkt_id == V7_PACKET_ID_NEW)) {
>>> > +             pt[0].x = ((pkt[2] & 0x80) << 4);
>>> > +             pt[0].x |= ((pkt[2] & 0x3F) << 5);
>>> > +             pt[0].x |= ((pkt[3] & 0x30) >> 1);
>>> > +             pt[0].x |= (pkt[3] & 0x07);
>>> > +             pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>>> > +
>>> > +             pt[1].x = ((pkt[3] & 0x80) << 4);
>>> > +             pt[1].x |= ((pkt[4] & 0x80) << 3);
>>> > +             pt[1].x |= ((pkt[4] & 0x3F) << 4);
>>> > +             pt[1].y = ((pkt[5] & 0x80) << 3);
>>> > +             pt[1].y |= ((pkt[5] & 0x3F) << 4);
>>> > +
>>> > +             if (pkt_id == V7_PACKET_ID_TWO) {
>>> > +                     pt[1].x &= ~0x000F;
>>> > +                     pt[1].y |= 0x000F;
>>> > +             } else if (pkt_id == V7_PACKET_ID_MULTI) {
>>> > +                     pt[1].x &= ~0x003F;
>>> > +                     pt[1].y &= ~0x0020;
>>> > +                     pt[1].y |= ((pkt[4] & 0x02) << 4);
>>> > +                     pt[1].y |= 0x001F;
>>> > +             } else if (pkt_id == V7_PACKET_ID_NEW) {
>>> > +                     pt[1].x &= ~0x003F;
>>> > +                     pt[1].x |= (pkt[0] & 0x20);
>>> > +                     pt[1].y |= 0x000F;
>>> > +             }
>>> > +
>>> > +             pt[0].y = 0x7FF - pt[0].y;
>>> > +             pt[1].y = 0x7FF - pt[1].y;
>>> > +
>>> > +             pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>>> > +             pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>>> > +     }
>>> > +}
>>> > +
>>> > +static void alps_decode_packet_v7(struct alps_fields *f,
>>> > +                               unsigned char *p,
>>> > +                               struct psmouse *psmouse)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     static struct v7_raw prev_r;
>>> > +
>>> > +     priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>>> > +
>>> > +     alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>>> > +
>>> > +     priv->r.v7.rest_left = 0;
>>> > +     priv->r.v7.rest_right = 0;
>>> > +     priv->r.v7.additional_fingers = 0;
>>> > +     priv->phy_btn = 0;
>>> > +
>>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>> > +         priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>>> > +             priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>>> > +             priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>>> > +     }
>>> > +
>>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>>> > +             priv->r.v7.additional_fingers = p[5] & 0x03;
>>> > +
>>> > +     priv->phy_btn = (p[0] & 0x80) >> 7;
>>> > +
>>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO) {
>>> > +             if (f->pt_img[0].z != 0 && f->pt_img[1].z != 0)
>>> > +                     priv->r.v7.raw_fn = 2;
>>> > +             else
>>> > +                     priv->r.v7.raw_fn = 1;
>>> > +     } else if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>>> > +             priv->r.v7.raw_fn = 3 + priv->r.v7.additional_fingers;
>>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>>> > +             priv->r.v7.raw_fn = 0;
>>> > +     else if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW)
>>> > +             priv->r.v7.raw_fn = prev_r.raw_fn;
>>> > +
>>> > +     /* It is a trick to bypass firmware bug of older version
>>> > +     that 'New' Packet is missed when finger number changed.
>>> > +     We fake a 'New' Packet in such cases.*/
>>> > +     if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>>> > +             priv->r.v7.pkt_id == V7_PACKET_ID_IDLE) {
>>> > +             if (priv->r.v7.raw_fn != prev_r.raw_fn)
>>> > +                     priv->r.v7.pkt_id = V7_PACKET_ID_NEW;
>>> > +     }
>>> > +
>>> > +     memcpy(&prev_r, &priv->r.v7, sizeof(struct v7_raw));
>>> > +}
>>> > +
>>> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>>> > +                                  struct alps_abs_data *pt,
>>> > +                                  struct alps_bl_pt_attr *pt_attr)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     unsigned int dist;
>>> > +
>>> > +     if (!pt_attr->is_init_pt_got && pt->z != 0) {
>>> > +             pt_attr->is_init_pt_got = 1;
>>> > +             pt_attr->is_counted = 0;
>>> > +             memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>>> > +     }
>>> > +
>>> > +     if (pt->z != 0) {
>>> > +             if (pt->y < priv->resting_zone_y_min) {
>>> > +                     /* A finger is recognized as a non-resting finger
>>> > +                     if it's position is outside the resting finger
>>> zone.*/
>>> > +                     pt_attr->zone = ZONE_NORMAL;
>>> > +                     pt_attr->is_counted = 1;
>>> > +             } else {
>>> > +                     /* A finger is recognized as a resting finger if
>>> it's
>>> > +                     position is inside the resting finger zone and
>>> there's
>>> > +                     no large movement from it's touch down position.*/
>>> > +                     pt_attr->zone = ZONE_RESTING;
>>> > +
>>> > +                     if (pt->x > priv->x_max / 2)
>>> > +                             pt_attr->zone |= ZONE_RIGHT_BTN;
>>> > +                     else
>>> > +                             pt_attr->zone |= ZONE_LEFT_BTN;
>>> > +
>>> > +                     /* A resting finger will turn to be a non-resting
>>> > +                     finger if it has made large movement from it's
>>> touch
>>> > +                     down position. A non-resting finger will never turn
>>> > +                     to a resting finger before it leaves the touchpad
>>> > +                     surface.*/
>>> > +                     if (pt_attr->is_init_pt_got) {
>>> > +                             dist = alps_pt_distance(pt,
>>> &pt_attr->init_pt);
>>> > +
>>> > +                             if (dist > V7_LARGE_MOVEMENT)
>>> > +                                     pt_attr->is_counted = 1;
>>> > +                     }
>>> > +             }
>>> > +     }
>>> > +}
>>> > +
>>> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>>> > +                                    struct alps_fields *f)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     int i;
>>> > +
>>> > +     switch (priv->r.v7.pkt_id) {
>>> > +     case  V7_PACKET_ID_TWO:
>>> > +     case  V7_PACKET_ID_MULTI:
>>> > +             for (i = 0; i < V7_IMG_PT_NUM; i++) {
>>> > +                     alps_set_each_pt_attr_v7(psmouse,
>>> > +                                              &f->pt_img[i],
>>> > +                                              &priv->pt_attr[i]);
>>> > +             }
>>> > +             break;
>>> > +     default:
>>> > +             /*All finger attributes are cleared when packet ID is
>>> > +             'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>>> > +             indicates that there's no finger and no button activity.
>>> > +             A 'NEW' packet indicates the finger position in packet
>>> > +             is not continues from previous packet. Such as the
>>> > +             condition there's finger placed or lifted. In these cases,
>>> > +             finger attributes will be reset.*/
>>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>>> > +             break;
>>> > +     }
>>> > +}
>>> > +
>>> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>>> > +                                     struct alps_fields *f)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     unsigned int fn = 0;
>>> > +     int i;
>>> > +
>>> > +     switch (priv->r.v7.pkt_id) {
>>> > +     case V7_PACKET_ID_IDLE:
>>> > +     case V7_PACKET_ID_NEW:
>>> > +             /*No finger is reported when packet ID is 'IDLE' or 'New'.
>>> > +             An 'IDLE' packet indicates that there's no finger on
>>> touchpad.
>>> > +             A 'NEW' packet indicates there's finger placed or lifted.
>>> > +             Finger position of 'New' packet is not continues from the
>>> > +             previous packet.*/
>>> > +             fn = 0;
>>> > +             break;
>>> > +     case V7_PACKET_ID_TWO:
>>> > +             if (f->pt_img[0].z == 0) {
>>> > +                     /*The first finger slot is zero when a non-resting
>>> > +                     finger lifted and remaining only one resting finger
>>> > +                     on touchpad. Hardware report the remaining resting
>>> > +                     finger in second slot. This resting is ignored*/
>>> > +                     fn = 0;
>>> > +             } else if (f->pt_img[1].z == 0) {
>>> > +                     /* The second finger slot is zero if there's
>>> > +                     only one finger*/
>>> > +                     fn = 1;
>>> > +             } else {
>>> > +                     /*All non-resting fingers will be counted to
>>> report*/
>>> > +                     fn = 0;
>>> > +                     for (i = 0; i < V7_IMG_PT_NUM; i++) {
>>> > +                             if (priv->pt_attr[i].is_counted)
>>> > +                                     fn++;
>>> > +                     }
>>> > +
>>> > +                     /*In the case that both fingers are
>>> > +                     resting fingers, report the first one*/
>>> > +                     if (!priv->pt_attr[0].is_counted &&
>>> > +                         !priv->pt_attr[1].is_counted) {
>>> > +                             fn = 1;
>>> > +                     }
>>> > +             }
>>> > +             break;
>>> > +     case V7_PACKET_ID_MULTI:
>>> > +             /*A packet ID 'MULTI' indicats that at least 3 non-resting
>>> > +             finger exist.*/
>>> > +             fn = 3 + priv->r.v7.additional_fingers;
>>> > +             break;
>>> > +     }
>>> > +
>>> > +     f->fingers = fn;
>>> > +}
>>> > +
>>> > +static void alps_button_dead_zone_filter(struct psmouse *psmouse,
>>> > +                                struct alps_fields *f,
>>> > +                                struct alps_fields *prev_f)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     int dx, dy;
>>> > +
>>> > +     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0) {
>>> > +             memcpy(&priv->pt_attr[0].init_dead_pt,
>>> > +                             &f->pt_img[0],
>>> > +                             sizeof(struct alps_abs_data));
>>> > +     }
>>> > +
>>> > +     if (priv->pt_attr[0].init_dead_pt.x != 0 &&
>>> > +             priv->pt_attr[0].init_dead_pt.x != 0) {
>>> > +                     dx = f->pt_img[0].x -
>>> priv->pt_attr[0].init_dead_pt.x;
>>> > +                     dy = f->pt_img[0].y -
>>> priv->pt_attr[0].init_dead_pt.y;
>>> > +             if ((abs(dx) > V7_DEAD_ZONE_OFFSET_X) ||
>>> > +                     (abs(dy) > V7_DEAD_ZONE_OFFSET_Y)) {
>>> > +                             memset(&priv->pt_attr[0].init_dead_pt, 0,
>>> > +                                             sizeof(struct
>>> alps_abs_data));
>>> > +                             priv->btn_delay_cnt = 0;
>>> > +             } else {
>>> > +                     memcpy(&f->pt_img[0],
>>> > +                                     &prev_f->pt_img[0],
>>> > +                                     sizeof(struct alps_abs_data));
>>> > +                     if (priv->prev_phy_btn == 0 && priv->phy_btn != 0)
>>> > +                             priv->btn_delay_cnt = 2;
>>> > +             }
>>> > +     }
>>> > +
>>> > +     if (priv->btn_delay_cnt > 0) {
>>> > +             f->btn.left = 0;
>>> > +             f->btn.right = 0;
>>> > +             priv->btn_delay_cnt--;
>>> > +     }
>>> > +}
>>> > +
>>> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>>> > +                                struct alps_fields *f,
>>> > +                                struct alps_fields *prev_f)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +
>>> > +     if (priv->phy_btn) {
>>> > +             if (!priv->prev_phy_btn) {
>>> > +                     /* Report a right click as long as there's finger
>>> on
>>> > +                     right button zone. Othrewise, report a left
>>> click.*/
>>> > +                     if (priv->r.v7.rest_right ||
>>> > +                         priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>>> > +                         priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>>> > +                             f->btn.right = 1;
>>> > +                             priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>>> > +                     } else {
>>> > +                             f->btn.left = 1;
>>> > +                             priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>>> > +                     }
>>> > +             } else {
>>> > +                     if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>>> > +                             f->btn.right = 1;
>>> > +                     if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>>> > +                             f->btn.left = 1;
>>> > +             }
>>> > +     } else {
>>> > +             priv->pressed_btn_bits = 0;
>>> > +             f->btn.right = 0;
>>> > +             f->btn.left = 0;
>>> > +     }
>>> > +
>>> > +     alps_button_dead_zone_filter(psmouse, f, prev_f);
>>> > +
>>> > +     priv->prev_phy_btn = priv->phy_btn;
>>> > +}
>>> > +
>>> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>>> > +{
>>> > +     struct alps_data *priv = psmouse->private;
>>> > +     struct alps_fields f = {0};
>>> > +     static struct alps_fields prev_f;
>>> > +     unsigned char *packet = psmouse->packet;
>>> > +
>>> > +     priv->decode_fields(&f, packet, psmouse);
>>> > +
>>> > +     if (alps_drop_unsupported_packet_v7(psmouse))
>>> > +             return;
>>> > +
>>> > +     alps_set_pt_attr_v7(psmouse, &f);
>>> > +
>>> > +     alps_cal_output_finger_num_v7(psmouse, &f);
>>> > +
>>> > +     alps_assign_buttons_v7(psmouse, &f, &prev_f);
>>> > +
>>> > +     alps_report_coord_and_btn(psmouse, &f);
>>> > +
>>> > +     memcpy(&prev_f, &f, sizeof(struct alps_fields));
>>> > +}
>>> > +
>>> >  static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>>> >                                       unsigned char packet[],
>>> >                                       bool report_buttons)
>>> > @@ -1080,6 +1492,14 @@ static psmouse_ret_t alps_process_byte(struct
>>> psmouse *psmouse)
>>> >               return PSMOUSE_BAD_DATA;
>>> >       }
>>> >
>>> > +     if ((priv->proto_version == ALPS_PROTO_V7 &&
>>> > +         !alps_is_valid_package_v7(psmouse))) {
>>> > +             psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>>> > +                         psmouse->pktcnt - 1,
>>> > +                         psmouse->packet[psmouse->pktcnt - 1]);
>>> > +             return PSMOUSE_BAD_DATA;
>>> > +     }
>>> > +
>>> >       if (psmouse->pktcnt == psmouse->pktsize) {
>>> >               priv->process_packet(psmouse);
>>> >               return PSMOUSE_FULL_PACKET;
>>> > @@ -1192,6 +1612,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse,
>>> int init_command,
>>> >       return 0;
>>> >  }
>>> >
>>> > +static int alps_check_valid_firmware_id(unsigned char id[])
>>> > +{
>>> > +     int valid = 1;
>>> > +
>>> > +     if (id[0] == 0x73)
>>> > +             valid = 1;
>>> > +     else if (id[0] == 0x88) {
>>> > +             if ((id[1] == 0x07) ||
>>> > +                 (id[1] == 0x08) ||
>>> > +                 ((id[1] & 0xf0) == 0xB0))
>>> > +                     valid = 1;
>>> > +     }
>>> > +
>>> > +     return valid;
>>> > +}
>>> > +
>>> >  static int alps_enter_command_mode(struct psmouse *psmouse)
>>> >  {
>>> >       unsigned char param[4];
>>> > @@ -1201,8 +1637,7 @@ static int alps_enter_command_mode(struct psmouse
>>> *psmouse)
>>> >               return -1;
>>> >       }
>>> >
>>> > -     if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>>> > -         param[0] != 0x73) {
>>> > +     if (!alps_check_valid_firmware_id(param)) {
>>> >               psmouse_dbg(psmouse,
>>> >                           "unknown response while entering command
>>> mode\n");
>>> >               return -1;
>>> > @@ -1704,6 +2139,36 @@ error:
>>> >       return ret;
>>> >  }
>>> >
>>> > +static int alps_hw_init_v7(struct psmouse *psmouse)
>>> > +{
>>> > +     struct ps2dev *ps2dev = &psmouse->ps2dev;
>>> > +     int reg_val, ret = -1;
>>> > +
>>> > +     if (alps_enter_command_mode(psmouse))
>>> > +             goto error;
>>> > +
>>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2d9);
>>> > +     if (reg_val == -1)
>>> > +             goto error;
>>> > +
>>> > +     if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
>>> > +             goto error;
>>> > +
>>> > +     reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
>>> > +     if (reg_val == -1)
>>> > +             goto error;
>>> > +
>>> > +     if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
>>> > +             goto error;
>>> > +
>>> > +     alps_exit_command_mode(psmouse);
>>> > +     return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
>>> > +
>>> > +error:
>>> > +     alps_exit_command_mode(psmouse);
>>> > +     return ret;
>>> > +}
>>> > +
>>> >  /* Must be in command mode when calling this function */
>>> >  static int alps_absolute_mode_v4(struct psmouse *psmouse)
>>> >  {
>>> > @@ -1875,6 +2340,7 @@ static void alps_set_defaults(struct alps_data
>>> *priv)
>>> >               priv->set_abs_params = alps_set_abs_params_st;
>>> >               priv->x_max = 1023;
>>> >               priv->y_max = 767;
>>> > +             priv->slot_number = 1;
>>> >               break;
>>> >       case ALPS_PROTO_V3:
>>> >               priv->hw_init = alps_hw_init_v3;
>>> > @@ -1883,6 +2349,7 @@ static void alps_set_defaults(struct alps_data
>>> *priv)
>>> >               priv->decode_fields = alps_decode_pinnacle;
>>> >               priv->nibble_commands = alps_v3_nibble_commands;
>>> >               priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>>> > +             priv->slot_number = 2;
>>> >               break;
>>> >       case ALPS_PROTO_V4:
>>> >               priv->hw_init = alps_hw_init_v4;
>>> > @@ -1890,6 +2357,7 @@ static void alps_set_defaults(struct alps_data
>>> *priv)
>>> >               priv->set_abs_params = alps_set_abs_params_mt;
>>> >               priv->nibble_commands = alps_v4_nibble_commands;
>>> >               priv->addr_command = PSMOUSE_CMD_DISABLE;
>>> > +             priv->slot_number = 2;
>>> >               break;
>>> >       case ALPS_PROTO_V5:
>>> >               priv->hw_init = alps_hw_init_dolphin_v1;
>>> > @@ -1905,6 +2373,7 @@ static void alps_set_defaults(struct alps_data
>>> *priv)
>>> >               priv->y_max = 660;
>>> >               priv->x_bits = 23;
>>> >               priv->y_bits = 12;
>>> > +             priv->slot_number = 2;
>>> >               break;
>>> >       case ALPS_PROTO_V6:
>>> >               priv->hw_init = alps_hw_init_v6;
>>> > @@ -1913,6 +2382,28 @@ static void alps_set_defaults(struct alps_data
>>> *priv)
>>> >               priv->nibble_commands = alps_v6_nibble_commands;
>>> >               priv->x_max = 2047;
>>> >               priv->y_max = 1535;
>>> > +             priv->slot_number = 2;
>>> > +             break;
>>> > +     case ALPS_PROTO_V7:
>>> > +             priv->hw_init = alps_hw_init_v7;
>>> > +             priv->process_packet = alps_process_packet_v7;
>>> > +             priv->decode_fields = alps_decode_packet_v7;
>>> > +             priv->set_abs_params = alps_set_abs_params_mt;
>>> > +             priv->nibble_commands = alps_v3_nibble_commands;
>>> > +             priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>>> > +             priv->x_max = 0xfff;
>>> > +             priv->y_max = 0x7ff;
>>> > +             priv->resting_zone_y_min = 0x654;
>>> > +             priv->byte0 = 0x48;
>>> > +             priv->mask0 = 0x48;
>>> > +             priv->flags = 0;
>>> > +             priv->slot_number = 2;
>>> > +
>>> > +             priv->phy_btn = 0;
>>> > +             priv->prev_phy_btn = 0;
>>> > +             priv->btn_delay_cnt = 0;
>>> > +             priv->pressed_btn_bits = 0;
>>> > +             memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>>> >               break;
>>> >       }
>>> >  }
>>> > @@ -1982,6 +2473,11 @@ static int alps_identify(struct psmouse *psmouse,
>>> struct alps_data *priv)
>>> >                       return -EIO;
>>> >               else
>>> >                       return 0;
>>> > +     } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>>> > +             priv->proto_version = ALPS_PROTO_V7;
>>> > +             alps_set_defaults(priv);
>>> > +
>>> > +             return 0;
>>> >       } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>>> >               priv->proto_version = ALPS_PROTO_V3;
>>> >               alps_set_defaults(priv);
>>> > @@ -2045,7 +2541,7 @@ static void alps_set_abs_params_mt(struct
>>> alps_data *priv,
>>> >                                  struct input_dev *dev1)
>>> >  {
>>> >       set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>>> > -     input_mt_init_slots(dev1, 2, 0);
>>> > +     input_mt_init_slots(dev1, priv->slot_number, 0);
>>> >       input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0,
>>> 0);
>>> >       input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0,
>>> 0);
>>> >
>>> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>>> > index 03f88b6..dedbd27 100644
>>> > --- a/drivers/input/mouse/alps.h
>>> > +++ b/drivers/input/mouse/alps.h
>>> > @@ -18,11 +18,36 @@
>>> >  #define ALPS_PROTO_V4        4
>>> >  #define ALPS_PROTO_V5        5
>>> >  #define ALPS_PROTO_V6        6
>>> > +#define ALPS_PROTO_V7        7
>>> > +
>>> > +#define MAX_IMG_PT_NUM               5
>>> > +#define V7_IMG_PT_NUM                2
>>> > +
>>> > +#define ZONE_NORMAL                          0x01
>>> > +#define ZONE_RESTING                 0x02
>>> > +#define ZONE_LEFT_BTN                        0x04
>>> > +#define ZONE_RIGHT_BTN                       0x08
>>> >
>>> >  #define DOLPHIN_COUNT_PER_ELECTRODE  64
>>> >  #define DOLPHIN_PROFILE_XOFFSET              8       /* x-electrode
>>> offset */
>>> >  #define DOLPHIN_PROFILE_YOFFSET              1       /* y-electrode
>>> offset */
>>> >
>>> > +/*
>>> > + * enum V7_PACKET_ID - defines the packet type for V7
>>> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>>> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>>> > + *  or there's button activities.
>>> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>>> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>>> > + *  previous packet.
>>> > +*/
>>> > +enum V7_PACKET_ID {
>>> > +      V7_PACKET_ID_IDLE,
>>> > +      V7_PACKET_ID_TWO,
>>> > +      V7_PACKET_ID_MULTI,
>>> > +      V7_PACKET_ID_NEW,
>>> > +};
>>> > +
>>> >  /**
>>> >   * struct alps_model_info - touchpad ID table
>>> >   * @signature: E7 response string to match.
>>> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>>> >  };
>>> >
>>> >  /**
>>> > - * struct alps_fields - decoded version of the report packet
>>> > - * @x_map: Bitmap of active X positions for MT.
>>> > - * @y_map: Bitmap of active Y positions for MT.
>>> > - * @fingers: Number of fingers for MT.
>>> > - * @x: X position for ST.
>>> > - * @y: Y position for ST.
>>> > - * @z: Z position for ST.
>>> > - * @first_mp: Packet is the first of a multi-packet report.
>>> > - * @is_mp: Packet is part of a multi-packet report.
>>> > + * struct alps_btn - decoded version of the button status
>>> >   * @left: Left touchpad button is active.
>>> >   * @right: Right touchpad button is active.
>>> >   * @middle: Middle touchpad button is active.
>>> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>>> >   * @ts_right: Right trackstick button is active.
>>> >   * @ts_middle: Middle trackstick button is active.
>>> >   */
>>> > -struct alps_fields {
>>> > -     unsigned int x_map;
>>> > -     unsigned int y_map;
>>> > -     unsigned int fingers;
>>> > -     unsigned int x;
>>> > -     unsigned int y;
>>> > -     unsigned int z;
>>> > -     unsigned int first_mp:1;
>>> > -     unsigned int is_mp:1;
>>> > -
>>> > +struct alps_btn {
>>> >       unsigned int left:1;
>>> >       unsigned int right:1;
>>> >       unsigned int middle:1;
>>> > @@ -102,6 +110,73 @@ struct alps_fields {
>>> >  };
>>> >
>>> >  /**
>>> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>>> > + * @x: X position for ST.
>>> > + * @y: Y position for ST.
>>> > + * @z: Z position for ST.
>>> > + */
>>> > +struct alps_abs_data {
>>> > +     unsigned int x;
>>> > +     unsigned int y;
>>> > +     unsigned int z;
>>> > +};
>>> > +
>>> > +/**
>>> > + * struct alps_fields - decoded version of the report packet
>>> > + * @fingers: Number of fingers for MT.
>>> > + * @pt: X Y Z postion for ST.
>>> > + * @pt: X Y Z postion for image MT.
>>> > + * @x_map: Bitmap of active X positions for MT.
>>> > + * @y_map: Bitmap of active Y positions for MT.
>>> > + * @first_mp: Packet is the first of a multi-packet report.
>>> > + * @is_mp: Packet is part of a multi-packet report.
>>> > + * @btn: Button activity status
>>> > + */
>>> > +struct alps_fields {
>>> > +     unsigned int fingers;
>>> > +     struct alps_abs_data pt;
>>> > +     struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>>> > +     unsigned int x_map;
>>> > +     unsigned int y_map;
>>> > +     unsigned int first_mp:1;
>>> > +     unsigned int is_mp:1;
>>> > +     struct alps_btn btn;
>>> > +};
>>> > +
>>> > +/**
>>> > + * struct v7_raw - data decoded from raw packet for V7.
>>> > + * @pkt_id: An id that specifies the type of packet.
>>> > + * @additional_fingers: Number of additional finger that is neighter
>>> included
>>> > + *  in pt slot nor reflected in rest_left and rest_right flag of data
>>> packet.
>>> > + * @rest_left: There are fingers on left resting zone.
>>> > + * @rest_right: There are fingers on right resting zone.
>>> > + * @raw_fn: The number of finger on touchpad.
>>> > + */
>>> > +struct v7_raw {
>>> > +     unsigned char pkt_id;
>>> > +     unsigned int additional_fingers;
>>> > +     unsigned char rest_left;
>>> > +     unsigned char rest_right;
>>> > +     unsigned char raw_fn;
>>> > +};
>>> > +
>>> > +/**
>>> > + * struct alps_bl_pt_attr - generic attributes of touch points for
>>> buttonless device
>>> > + * @zone: The part of touchpad that the touch point locates
>>> > + * @is_counted: The touch point is not a resting finger.
>>> > + * @is_init_pt_got: The touch down point is got.
>>> > + * @init_pt: The X Y Z position of the touch down point.
>>> > + * @init_dead_pt: The touch down point of a finger used by dead zone
>>> process.
>>> > + */
>>> > +struct alps_bl_pt_attr {
>>> > +     unsigned char zone;
>>> > +     unsigned char is_counted;
>>> > +     unsigned char is_init_pt_got;
>>> > +     struct alps_abs_data init_pt;
>>> > +     struct alps_abs_data init_dead_pt;
>>> > +};
>>> > +
>>> > +/**
>>> >   * struct alps_data - private data structure for the ALPS driver
>>> >   * @dev2: "Relative" device used to report trackstick or mouse activity.
>>> >   * @phys: Physical path for the relative device.
>>> > @@ -116,8 +191,10 @@ struct alps_fields {
>>> >   * @flags: Additional device capabilities (passthrough port,
>>> trackstick, etc.).
>>> >   * @x_max: Largest possible X position value.
>>> >   * @y_max: Largest possible Y position value.
>>> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting
>>> zone.
>>> >   * @x_bits: Number of X bits in the MT bitmap.
>>> >   * @y_bits: Number of Y bits in the MT bitmap.
>>> > + * @img_fingers: Number of image fingers.
>>> >   * @hw_init: Protocol-specific hardware init function.
>>> >   * @process_packet: Protocol-specific function to process a report
>>> packet.
>>> >   * @decode_fields: Protocol-specific function to read packet bitfields.
>>> > @@ -132,6 +209,11 @@ struct alps_fields {
>>> >   * @fingers: Number of fingers from last MT report.
>>> >   * @quirks: Bitmap of ALPS_QUIRK_*.
>>> >   * @timer: Timer for flushing out the final report packet in the stream.
>>> > + * @v7: Data decoded from raw packet for V7
>>> > + * @phy_btn: Physical button is active.
>>> > + * @prev_phy_btn: Physical button of previous packet is active.
>>> > + * @pressed_btn_bits: Pressed positon of button zone
>>> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>>> >   */
>>> >  struct alps_data {
>>> >       struct input_dev *dev2;
>>> > @@ -145,8 +227,10 @@ struct alps_data {
>>> >       unsigned char flags;
>>> >       int x_max;
>>> >       int y_max;
>>> > +     int resting_zone_y_min;
>>> >       int x_bits;
>>> >       int y_bits;
>>> > +     unsigned char slot_number;
>>> >
>>> >       int (*hw_init)(struct psmouse *psmouse);
>>> >       void (*process_packet)(struct psmouse *psmouse);
>>> > @@ -161,6 +245,16 @@ struct alps_data {
>>> >       int fingers;
>>> >       u8 quirks;
>>> >       struct timer_list timer;
>>> > +
>>> > +     /* these are used for buttonless touchpad*/
>>> > +     union {
>>> > +             struct v7_raw v7;
>>> > +     } r;
>>> > +     unsigned char phy_btn;
>>> > +     unsigned char prev_phy_btn;
>>> > +     unsigned char btn_delay_cnt;
>>> > +     unsigned char pressed_btn_bits;
>>> > +     struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>>> >  };
>>> >
>>> >  #define ALPS_QUIRK_TRACKSTICK_BUTTONS        1 /* trakcstick buttons in
>>> trackstick packet */
>>>
>>>
>>
>--
>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

^ permalink raw reply

* Re: [PATCH v3 0/8] HID: sony: More Sony controller fixes and improvements.
From: Frank Praznik @ 2014-03-27 14:27 UTC (permalink / raw)
  To: open list:HID CORE LAYER
In-Reply-To: <1394890882-2039-1-git-send-email-frank.praznik@oh.rr.com>

On Sat, Mar 15, 2014 at 9:41 AM, Frank Praznik <frank.praznik@oh.rr.com> wrote:
> Just a couple of small changes in v3:
>
> Patch 6 was changed to use the controller Bluetooth MAC address as the unique
> value for the battery name string.
>
> The IDA code was moved from patch 6 to 7 since it was no longer needed in
> patch 6.  It's the same otherwise.

Just a quick note since the 3.15 merge window is approaching: patches
1 and 2 are strictly bug fixes and should be merged into the 3.15 tree
even if the rest of the series has to wait until 3.16.

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox