* [PATCH] input: wm97xx: adapt parameters to tosa touchscreen.
From: Dmitry Eremin-Solenikov @ 2014-10-24 17:18 UTC (permalink / raw)
To: linux-input
Cc: patches, Dmitry Torokhov, Mark Brown, Liam Girdwood,
Dmitry Eremin-Solenikov
From: Dmitry Eremin-Solenikov <dmitry_eremin@mentor.com>
Sharp SL-6000 (tosa) touchscreen needs wider limits to properly map all
points on the screen. Expand ranges in abs_x and abs_y arrays according
to the touchscreen area.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov@gmail.com>
---
drivers/input/touchscreen/wm97xx-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
index d0ef91f..b1ae779 100644
--- a/drivers/input/touchscreen/wm97xx-core.c
+++ b/drivers/input/touchscreen/wm97xx-core.c
@@ -70,11 +70,11 @@
* Documentation/input/input-programming.txt for more details.
*/
-static int abs_x[3] = {350, 3900, 5};
+static int abs_x[3] = {150, 4000, 5};
module_param_array(abs_x, int, NULL, 0);
MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
-static int abs_y[3] = {320, 3750, 40};
+static int abs_y[3] = {200, 4000, 40};
module_param_array(abs_y, int, NULL, 0);
MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
--
2.1.1
^ permalink raw reply related
* Re: [PATCH v2] input: Add ROHM BU21023/24 Dual touch support resistive touchscreens
From: Yuasa Yoichi @ 2014-10-24 16:06 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Yoichi Yuasa
In-Reply-To: <20140912072302.GE31165@core.coreip.homeip.net>
Hi Dmitry,
I'm sorry that I didn't find your e-mail earlier.
2014-09-12 16:23 GMT+09:00 Dmitry Torokhov <dmitry.torokhov@gmail.com>:
> Hi Yoichi,
>
> Just finishing a review I started a while back. I see that you posted v3
> in the meantime, but I think majority of the comments are still
> applicable.
Thank you for your comments.
I'll try to update them by v4.
Thanks,
Yoichi
^ permalink raw reply
* Re: [PATCH 0/2] Qualcomm PM8941 power key driver
From: Bjorn Andersson @ 2014-10-24 15:23 UTC (permalink / raw)
To: Ivan T. Ivanov
Cc: Dmitry Torokhov, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Grant Likely,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-input-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
In-Reply-To: <1412761807.13569.12.camel@iivanov-dev>
On Wed 08 Oct 02:50 PDT 2014, Ivan T. Ivanov wrote:
> On Tue, 2014-10-07 at 11:46 -0700, Bjorn Andersson wrote:
> > On Tue 07 Oct 02:01 PDT 2014, Ivan T. Ivanov wrote:
> >
> > >
> > > Hi Bjorn,
> > >
> > > On Mon, 2014-10-06 at 18:11 -0700, Bjorn Andersson wrote:
[..]
> > > > create mode 100644 drivers/input/misc/pm8941-pwrkey.c
> > >
> > > Any reason why we cannot reuse pm8xxx-pwrkey driver? It have been
> > > converted to regmap already.
> > >
> >
> > The boilerplate code is the same,
>
> The boilerplate code is almost 100% :-)
>
> > but configuration registers have different
> > layout and values written in them are different.
>
> We talk about 3 registers and 2 bit defines. struct regmap_field
> should be able to help here.
>
You're totally right, we could rewrite the driver to use regmap_field and make
the rest of the differences conditional. In my eyes we end up with two drivers
in one file - but it can be done.
A difference however is that in pm8941 the ps hold behavious (reboot vs power
off) is controlled by this same block. So I have an additional patch that adds
a restart handler here that sets the pmic in the right state before we pull
pshold (but I haven't been able to test it properly).
In pm8xxx this is handled in the pmic misc block and does not belong in this
driver.
[..]
> >
> > Maybe if we introduce some vagueness related to interrupts in the dt binding
> > documentation for pm8xxx we could simply reuse that binding.
> >
>
> I would not say vagueness, we just can say that pm8941 did not have
> second interrupt?
>
I don't like having conditional documentation - it's not only that the second
interrupt is missing, the first one have different meaning. But you're right
that it's a minor thing and can be done.
Regards,
Bjorn
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] i8042: Add notimeout quirk for Fujitsu Lifebook A544 and Lifebook AH544
From: Hans de Goede @ 2014-10-24 9:39 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, Hans de Goede, stable
These models need i8042.notimeout, otherwise the touchpad will not work.
BugLink: https://bugzilla.kernel.org/show_bug.cgi?id=69731
BugLink: https://bugzilla.redhat.com/show_bug.cgi?id=1111138
Cc: stable@vger.kernel.org
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
drivers/input/serio/i8042-x86ia64io.h | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index a0bcbb6..aa9b299 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -364,6 +364,22 @@ static const struct dmi_system_id __initconst i8042_dmi_notimeout_table[] = {
},
},
{
+ /* Fujitsu A544 laptop */
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1111138 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK A544"),
+ },
+ },
+ {
+ /* Fujitsu AH544 laptop */
+ /* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK AH544"),
+ },
+ },
+ {
/* Fujitsu U574 laptop */
/* https://bugzilla.kernel.org/show_bug.cgi?id=69731 */
.matches = {
--
2.1.0
^ permalink raw reply related
* Re: [PATCH] Alps source code update
From: Andreas Bosch @ 2014-10-24 8:03 UTC (permalink / raw)
To: Masaki Ota, dmitry.torokhov, cernekee, dturvene
Cc: linux-input, ndevos, jclift, Masaki Ota
In-Reply-To: <1414102883-11084-1-git-send-email-masaki.ota@jp.alps.com>
Am 24.10.2014 um 00:21 schrieb Masaki Ota:
> Signed-off-by: Masaki Ota <masaki.ota@jp.alps.com>
> - Support Alps Button-less Touchpad device(Rushmore and SS4). New device type and a data decode logic were added.
> ---
> drivers/input/mouse/alps.c | 1680 +++++++++++++++++++++++++++++++++++---------
> drivers/input/mouse/alps.h | 263 ++++++-
> 2 files changed, 1574 insertions(+), 369 deletions(-)
Hello,
This patch is reversing changes introduced in commit
02d04254a5dfb8de1459805c3433cd0e9e4853d7 (Input: alps - use struct
input_mt_pos to track coordinates), maybe some others, too. Is this
deliberate?
These are two examples of that.
> [...]
>
> * The bitmaps don't have enough data to track fingers, so this function
> * only generates points representing a bounding box of at most two contacts.
> - * These two points are returned in fields->mt.
> + * These two points are returned in x1, y1, x2, and y2.
> */
> static void alps_process_bitmap_dolphin(struct alps_data *priv,
> - struct alps_fields *fields)
> + struct alps_fields *fields,
> + int *x1, int *y1, int *x2, int *y2)
> {
> int box_middle_x, box_middle_y;
> unsigned int x_map, y_map;
> @@ -309,6 +329,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> if (x_msb > priv->x_bits || y_msb > priv->y_bits)
> return;
> [...]
>
and
> [...]
>
> @@ -168,27 +351,35 @@ struct alps_data {
> int addr_command;
>
> [...]
>
> - struct alps_fields f;
> + int x1, x2, y1, y2;
> + int fingers;
> u8 quirks;
> struct timer_list timer;
> [...]
^ permalink raw reply
* Re: [PATCH] Alps source code update
From: Niels de Vos @ 2014-10-24 7:18 UTC (permalink / raw)
To: Masaki Ota
Cc: dmitry.torokhov, cernekee, dturvene, linux-input, jclift,
Masaki Ota
In-Reply-To: <1414102883-11084-1-git-send-email-masaki.ota@jp.alps.com>
On Fri, Oct 24, 2014 at 06:21:23AM +0800, Masaki Ota wrote:
> Signed-off-by: Masaki Ota <masaki.ota@jp.alps.com>
> - Support Alps Button-less Touchpad device(Rushmore and SS4). New device type and a data decode logic were added.
Thanks Masaki. I can't say much about the change to the alps driver
itself, but you should probably re-post this patch with a more suitable
subject and description of the change. The format would be something
like this (this text may not be correct though, it's just an example):
[PATCH v2] input/alps: support for button-less touchpads
Add support for Alps button-less touchpads (Rushmore and SS4). These
devices use a different protocol, so additional decoding routines
are added.
These devices are found in <some laptop vendor/model(s)>.
Signed-off-by: ...
Reviewed-by: ... (maybe one of your colleagues?)
Tested-by: ... (maybe one of your colleagues?)
---
v2 changes:
- reformat commit message
<patch follows below>
Now, this is quite a big patch. It will be easier for others to review
and check your change if you can split it up in multiple logical
patches. For example, add the v8 protocol and the supported device(s) in
the 1st patch, and the v9 protocol in a 2nd one.
If you can include some laptop vendor/model(s) in the message for the
commit, we can see if there are any bugs filed in the Red Hat Bugzilla
for these. Maybe there are some users that want to do some testing and
can offer feedback.
Thanks,
Niels
> ---
> drivers/input/mouse/alps.c | 1680 +++++++++++++++++++++++++++++++++++---------
> drivers/input/mouse/alps.h | 263 ++++++-
> 2 files changed, 1574 insertions(+), 369 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index a59a1a6..d4fc568 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -20,6 +20,7 @@
> #include <linux/input/mt.h>
> #include <linux/serio.h>
> #include <linux/libps2.h>
> +#include <linux/kernel.h>
>
> #include "psmouse.h"
> #include "alps.h"
> @@ -32,6 +33,8 @@
> #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> #define ALPS_REG_BASE_PINNACLE 0x0000
>
> +#define V7_LARGE_MOVEMENT 130
> +
> static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> @@ -99,8 +102,10 @@ 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_IS_RUSHMORE 0x100 /* device is a rushmore */
> -#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
> +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
> +
> +#define DOL_IS_APDATA(_BY) ((_BY[0]&0x01) == 0x01)
> +#define DOL_IS_PROFDATA(_BY) ((_BY[0]&0x20) == 0x20)
>
> 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 */
> @@ -142,6 +147,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,
> @@ -283,10 +302,11 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
> *
> * The bitmaps don't have enough data to track fingers, so this function
> * only generates points representing a bounding box of at most two contacts.
> - * These two points are returned in fields->mt.
> + * These two points are returned in x1, y1, x2, and y2.
> */
> static void alps_process_bitmap_dolphin(struct alps_data *priv,
> - struct alps_fields *fields)
> + struct alps_fields *fields,
> + int *x1, int *y1, int *x2, int *y2)
> {
> int box_middle_x, box_middle_y;
> unsigned int x_map, y_map;
> @@ -309,6 +329,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> if (x_msb > priv->x_bits || y_msb > priv->y_bits)
> return;
>
> + *x1 = *y1 = *x2 = *y2 = 0;
> +
> if (fields->fingers > 1) {
> start_bit = priv->x_bits - x_msb;
> end_bit = priv->x_bits - x_lsb;
> @@ -319,35 +341,10 @@ 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));
> - fields->mt[0] = fields->st;
> - fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
> - fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
> - }
> -}
> -
> -static void alps_get_bitmap_points(unsigned int map,
> - struct alps_bitmap_point *low,
> - struct alps_bitmap_point *high,
> - int *fingers)
> -{
> - struct alps_bitmap_point *point;
> - int i, bit, prev_bit = 0;
> -
> - point = low;
> - for (i = 0; map != 0; i++, map >>= 1) {
> - bit = map & 1;
> - if (bit) {
> - if (!prev_bit) {
> - point->start_bit = i;
> - point->num_bits = 0;
> - (*fingers)++;
> - }
> - point->num_bits++;
> - } else {
> - if (prev_bit)
> - point = high;
> - }
> - prev_bit = bit;
> + *x1 = fields->pt.x;
> + *y1 = fields->pt.y;
> + *x2 = 2 * box_middle_x - *x1;
> + *y2 = 2 * box_middle_y - *y1;
> }
> }
>
> @@ -358,21 +355,71 @@ static void alps_get_bitmap_points(unsigned int map,
> *
> * The bitmaps don't have enough data to track fingers, so this function
> * only generates points representing a bounding box of all contacts.
> - * These points are returned in fields->mt when the return value
> + * These points are returned in x1, y1, x2, and y2 when the return value
> * is greater than 0.
> */
> static int alps_process_bitmap(struct alps_data *priv,
> - struct alps_fields *fields)
> + unsigned int x_map, unsigned int y_map,
> + int *x1, int *y1, int *x2, int *y2)
> {
> - int i, fingers_x = 0, fingers_y = 0, fingers;
> + struct alps_bitmap_point {
> + int start_bit;
> + int num_bits;
> + };
> +
> + int fingers_x = 0, fingers_y = 0, fingers;
> + int i, bit, prev_bit;
> struct alps_bitmap_point x_low = {0,}, x_high = {0,};
> struct alps_bitmap_point y_low = {0,}, y_high = {0,};
> + struct alps_bitmap_point *point;
>
> - if (!fields->x_map || !fields->y_map)
> + if (!x_map || !y_map)
> return 0;
>
> - alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
> - alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
> + *x1 = *y1 = *x2 = *y2 = 0;
> +
> + prev_bit = 0;
> + point = &x_low;
> + for (i = 0; x_map != 0; i++, x_map >>= 1) {
> + bit = x_map & 1;
> + if (bit) {
> + if (!prev_bit) {
> + point->start_bit = i;
> + fingers_x++;
> + }
> + point->num_bits++;
> + } else {
> + if (prev_bit)
> + point = &x_high;
> + else
> + point->num_bits = 0;
> + }
> + prev_bit = bit;
> + }
> +
> + /*
> + * y bitmap is reversed for what we need (lower positions are in
> + * higher bits), so we process from the top end.
> + */
> + y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
> + prev_bit = 0;
> + point = &y_low;
> + for (i = 0; y_map != 0; i++, y_map <<= 1) {
> + bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
> + if (bit) {
> + if (!prev_bit) {
> + point->start_bit = i;
> + fingers_y++;
> + }
> + point->num_bits++;
> + } else {
> + if (prev_bit)
> + point = &y_high;
> + else
> + point->num_bits = 0;
> + }
> + prev_bit = bit;
> + }
>
> /*
> * Fingers can overlap, so we use the maximum count of fingers
> @@ -381,89 +428,103 @@ static int alps_process_bitmap(struct alps_data *priv,
> fingers = max(fingers_x, fingers_y);
>
> /*
> - * If an axis reports only a single contact, we have overlapping or
> - * adjacent fingers. Divide the single contact between the two points.
> + * If total fingers is > 1 but either axis reports only a single
> + * contact, we have overlapping or adjacent fingers. For the
> + * purposes of creating a bounding box, divide the single contact
> + * (roughly) equally between the two points.
> */
> - if (fingers_x == 1) {
> - i = (x_low.num_bits - 1) / 2;
> - x_low.num_bits = x_low.num_bits - i;
> - x_high.start_bit = x_low.start_bit + i;
> - x_high.num_bits = max(i, 1);
> - }
> - if (fingers_y == 1) {
> - i = (y_low.num_bits - 1) / 2;
> - y_low.num_bits = y_low.num_bits - i;
> - y_high.start_bit = y_low.start_bit + i;
> - y_high.num_bits = max(i, 1);
> - }
> -
> - fields->mt[0].x =
> - (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
> - (2 * (priv->x_bits - 1));
> - fields->mt[0].y =
> - (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
> - (2 * (priv->y_bits - 1));
> -
> - fields->mt[1].x =
> - (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
> - (2 * (priv->x_bits - 1));
> - fields->mt[1].y =
> - (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
> - (2 * (priv->y_bits - 1));
> -
> - /* y-bitmap order is reversed, except on rushmore */
> - if (!(priv->flags & ALPS_IS_RUSHMORE)) {
> - fields->mt[0].y = priv->y_max - fields->mt[0].y;
> - fields->mt[1].y = priv->y_max - fields->mt[1].y;
> + if (fingers > 1) {
> + if (fingers_x == 1) {
> + i = x_low.num_bits / 2;
> + x_low.num_bits = x_low.num_bits - i;
> + x_high.start_bit = x_low.start_bit + i;
> + x_high.num_bits = max(i, 1);
> + } else if (fingers_y == 1) {
> + i = y_low.num_bits / 2;
> + y_low.num_bits = y_low.num_bits - i;
> + y_high.start_bit = y_low.start_bit + i;
> + y_high.num_bits = max(i, 1);
> + }
> + }
> +
> + *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
> + (2 * (priv->x_bits - 1));
> + *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
> + (2 * (priv->y_bits - 1));
> +
> + if (fingers > 1) {
> + *x2 = (priv->x_max *
> + (2 * x_high.start_bit + x_high.num_bits - 1)) /
> + (2 * (priv->x_bits - 1));
> + *y2 = (priv->y_max *
> + (2 * y_high.start_bit + y_high.num_bits - 1)) /
> + (2 * (priv->y_bits - 1));
> }
>
> return fingers;
> }
>
> -static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
> +static void alps_set_slot(struct input_dev *dev, int slot, bool active,
> + int x, int y)
> {
> input_mt_slot(dev, slot);
> - input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
> - input_report_abs(dev, ABS_MT_POSITION_X, x);
> - input_report_abs(dev, ABS_MT_POSITION_Y, y);
> + input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
> + if (active) {
> + input_report_abs(dev, ABS_MT_POSITION_X, x);
> + input_report_abs(dev, ABS_MT_POSITION_Y, y);
> + }
> }
>
> -static void alps_report_mt_data(struct psmouse *psmouse, int n)
> +static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> + int x1, int y1, int x2, int y2)
> {
> - struct alps_data *priv = psmouse->private;
> - struct input_dev *dev = psmouse->dev;
> - struct alps_fields *f = &priv->f;
> - int i, slot[MAX_TOUCHES];
> + alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
> + alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> +}
>
> - input_mt_assign_slots(dev, slot, f->mt, n);
> - for (i = 0; i < n; i++)
> - alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
> +static void alps_report_semi_mt_data_ex(struct input_dev *dev, int num_fingers,
> + struct alps_abs_data coord[])
> +{
> + unsigned char i;
>
> - input_mt_sync_frame(dev);
> + for (i = 0; i < num_fingers; i++) {
> + if (!coord[i].x || !coord[i].y || !coord[i].z)
> + alps_set_slot(dev, i, 0, coord[i].x, coord[i].y);
> + else
> + alps_set_slot(dev, i, 1, coord[i].x, coord[i].y);
> + }
> }
>
> -static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
> +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> + struct alps_fields *f)
> {
> - struct alps_data *priv = psmouse->private;
> - struct input_dev *dev = psmouse->dev;
> - struct alps_fields *f = &priv->f;
> + struct input_dev *dev;
>
> - /* Use st data when we don't have mt data */
> - if (fingers < 2) {
> - f->mt[0].x = f->st.x;
> - f->mt[0].y = f->st.y;
> - fingers = f->pressure > 0 ? 1 : 0;
> - }
> + if (!psmouse || !f)
> + return;
>
> - alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
> + dev = psmouse->dev;
>
> - input_mt_report_finger_count(dev, fingers);
> + 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_key(dev, BTN_LEFT, f->left);
> - input_report_key(dev, BTN_RIGHT, f->right);
> - input_report_key(dev, BTN_MIDDLE, f->middle);
> + 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_abs(dev, ABS_PRESSURE, f->pressure);
> + 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);
>
> input_sync(dev);
> }
> @@ -530,16 +591,25 @@ 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 int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> +/* proto_v9 */
> +static void alps_decode_button_ss3(struct alps_fields *f, unsigned char *p,
> + struct alps_data *priv)
> +{
> + if (f->dol_packet_type == DOL_GPDATA ||
> + f->dol_packet_type == DOL_APDATA)
> + f->btn.left = !!(p[3]&0x01);
> +}
> +
> +static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> struct psmouse *psmouse)
> {
> f->first_mp = !!(p[4] & 0x40);
> @@ -553,17 +623,15 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> ((p[2] & 0x7f) << 1) |
> (p[4] & 0x01);
>
> - f->st.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->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> - f->pressure = 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);
> -
> - return 0;
> }
>
> -static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
> +static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
> struct psmouse *psmouse)
> {
> alps_decode_pinnacle(f, p, psmouse);
> @@ -573,25 +641,20 @@ static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
> f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
> f->x_map |= (p[5] & 0x10) << 11;
> f->y_map |= (p[5] & 0x20) << 6;
> -
> - return 0;
> }
>
> -static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> +static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> struct psmouse *psmouse)
> {
> u64 palm_data = 0;
> struct alps_data *priv = psmouse->private;
>
> - f->first_mp = !!(p[0] & 0x02);
> - f->is_mp = !!(p[0] & 0x20);
> + f->is_mp = 0;
> + f->first_mp = 0;
>
> - if (!f->is_mp) {
> - f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> - f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> - f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
> - alps_decode_buttons_v3(f, p);
> - } else {
> + if (DOL_IS_PROFDATA(p)) {
> + f->is_mp = 1;
> + f->dol_packet_type = DOL_PROFDATA;
> f->fingers = ((p[0] & 0x6) >> 1 |
> (p[0] & 0x10) >> 2);
>
> @@ -609,22 +672,415 @@ static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
> f->x_map = (palm_data >> priv->y_bits) &
> (BIT(priv->x_bits) - 1);
> + } else {
> + if (DOL_IS_APDATA(p)) {
> + f->dol_packet_type = DOL_APDATA;
> + f->fingers = 2;
> + f->pt_img[0].x = p[1]<<3;
> + f->pt_img[0].y = p[2]<<2;
> + f->pt_img[0].z = 64;
> + f->pt_img[1].x = p[4]<<3;
> + f->pt_img[1].y = p[5]<<2;
> + f->pt_img[1].z = 64;
> + } else {/* is gp data */
> + f->dol_packet_type = DOL_GPDATA;
> + f->first_mp = !!(p[0]&0x02);
> + f->pt.x = f->pt_img[0].x =
> + ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> + f->pt.y = f->pt_img[0].y =
> + ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> + f->pt.z = f->pt_img[0].z =
> + min(((p[0] & 0x04) ? 0 : p[5] & 0x7f) * 2, 127);
> +
> + /*
> + Button number will be included in
> + the PROFILE data for a 3-f packet.
> + So do not change .fingers because
> + it will be updated in Profile data packet.
> + */
> + if (!f->first_mp)
> + f->fingers = (f->pt_img[0].x &&
> + f->pt_img[0].y && f->pt_img[0].z)?1:0;
> + }
> +
> + if (priv->proto_version == ALPS_PROTO_V9)
> + alps_decode_button_ss3(f, p, priv);
> + else
> + alps_decode_buttons_v3(f, p);
> }
> +}
>
> - return 0;
> +unsigned char alps_get_pkt_id_ss4_v1(char *byte)
> +{
> + unsigned char pkt_id = SS4_PACKET_ID_IDLE;
> +
> + if (((byte[0] & 0xFF) == 0x08) && ((byte[1] & 0xFF) == 0x10) &&
> + ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x8F) == 0x08) &&
> + ((byte[4] & 0xFF) == 0x01) && ((byte[5] & 0xFF) == 0x00)) {
> + pkt_id = SS4_PACKET_ID_IDLE;
> + } else if (((byte[0] & 0x08) == 0x08) && ((byte[1] & 0x10) == 0x10) &&
> + ((byte[3] & 0x8E) == 0x08) && ((byte[4] & 0x81) == 0x01)) {
> + pkt_id = SS4_PACKET_ID_ONE;
> + } else if (((byte[0] & 0x08) == 0x08) && ((byte[3] & 0x08) == 0x08) &&
> + ((byte[4] & 0x01) == 0x01)) {
> + if (((byte[5] & 0x01) == 0x01))
> + pkt_id = SS4_PACKET_ID_TWO;
> + else
> + pkt_id = SS4_PACKET_ID_MULTI;
> + }
> +
> + return pkt_id;
> +}
> +
> +unsigned char alps_get_pkt_id_ss4_v2(char *byte)
> +{
> + unsigned char pkt_id = SS4_PACKET_ID_IDLE;
> +
> + if (((byte[0] & 0xFF) == 0x18) && ((byte[1] & 0xFF) == 0x10) &&
> + ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x88) == 0x08) &&
> + ((byte[4] & 0xFF) == 0x10) && ((byte[5] & 0xFF) == 0x00)) {
> + pkt_id = SS4_PACKET_ID_IDLE;
> + } else if (!(byte[3] & 0x10)) {
> + pkt_id = SS4_PACKET_ID_ONE;
> + } else {
> + if (!(byte[3] & 0x20))
> + pkt_id = SS4_PACKET_ID_TWO;
> + else
> + pkt_id = SS4_PACKET_ID_MULTI;
> + }
> +
> + return pkt_id;
> +}
> +
> +static void alps_process_btnless_click(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> +
> + if (!f->btn.left)
> + return;
> +
> + /* Clear button flag */
> + f->btn.left = 0;
> +
> + switch (f->fingers) {
> + case 1:
> + /* In Left Resting Area */
> + if (PT_IN_LEFT_BTN_AREA(f->pt_img[0].x,
> + f->pt_img[0].y, priv->x_max, priv->y_max)) {
> + f->btn.left = 1;
> + } else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
> + f->pt_img[0].y, priv->x_max, priv->y_max)) {
> + /* In Right Resting Area */
> + f->btn.right = 1;
> + } else {
> + /* In Normal area */
> + f->btn.left = 1;
> + }
> + break;
> +
> + case 2:
> + /* Both two fingers are in Normal area */
> + if (!PT_IN_BTN_AREA(f->pt_img[0].x,
> + f->pt_img[0].y, priv->x_max, priv->y_max) &&
> + !PT_IN_BTN_AREA(f->pt_img[1].x,
> + f->pt_img[1].y, priv->x_max, priv->y_max)) {
> + f->btn.right = 1;
> + } else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
> + f->pt_img[0].y, priv->x_max, priv->y_max) ||
> + PT_IN_RIGHT_BTN_AREA(f->pt_img[1].x,
> + f->pt_img[1].y, priv->x_max, priv->y_max)) {
> + /* Either one finger is in Right Area */
> + f->btn.right = 1;
> + } else {
> + f->btn.left = 1;
> + }
> + break;
> +
> + case 3:
> + f->btn.middle = 1;
> + break;
> +
> + case 0:
> + default:
> + break;
> + }
> +}
> +
> +static void alps_process_resting_finger(struct psmouse *psmouse,
> + struct alps_fields *f, struct alps_abs_data *output,
> + unsigned char *p_fn)
> +{
> + struct alps_data *priv = psmouse->private;
> + static struct alps_abs_data prev_pt[10];
> + static struct alps_abs_data init_pt[10];
> + static unsigned char is_moved[10];
> + static unsigned char prev_fn;
> + static unsigned char prev_coord_is_output[10];
> + unsigned char cur_coord_is_output[10];
> + unsigned char in_resting_area[10];
> + unsigned char i, index;
> + unsigned char output_fn = 0;
> +
> + memset(in_resting_area, 0, sizeof(in_resting_area));
> + memset(cur_coord_is_output, 0, sizeof(cur_coord_is_output));
> +
> + /* Clear "is_moved" flag when finger number changed */
> + if (f->fingers != prev_fn) {
> + memset(is_moved, 0, sizeof(is_moved));
> + memcpy(init_pt, f->pt_img, sizeof(f->pt_img));
> + }
> +
> + /* Calculate output finger */
> + for (i = 0, index = 0; i < f->fingers; i++) {
> + if (is_moved[i] == 0 &&
> + (abs(f->pt_img[i].x - init_pt[i].x)
> + > RESTING_FN_LARGE_MOVEMENT)) {
> + is_moved[i] = 1;
> + }
> +
> + /* Check if in resting area */
> + if (PT_IN_BTN_AREA(f->pt_img[i].x,
> + f->pt_img[i].y, priv->x_max, priv->y_max))
> + in_resting_area[i] = 1;
> +
> + if (!in_resting_area[i] ||
> + (in_resting_area[i] && is_moved[i])) {
> + memcpy(&output[index++], &f->pt_img[i],
> + sizeof(struct alps_abs_data));
> + cur_coord_is_output[i] = 1;
> + output_fn++;
> + }
> + }
> +
> + /* A normal finger becomes a resting finger */
> + for (i = 0; i < f->fingers; i++) {
> + if (prev_coord_is_output[i] &&
> + !cur_coord_is_output[i] && f->pt_img[i].z) {
> + output_fn = 0;
> + memset(output, 0,
> + sizeof(struct alps_abs_data)*f->fingers);
> + }
> + }
> +
> + memcpy(prev_pt, f->pt_img, sizeof(f->pt_img));
> + memcpy(prev_coord_is_output, cur_coord_is_output,
> + sizeof(cur_coord_is_output));
> + prev_fn = f->fingers;
> + *p_fn = output_fn;
> +}
> +
> +static void alps_decode_ss4_v1(struct alps_fields *f,
> + unsigned char *p, struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned char pkt_id;
> + unsigned int no_data_x, no_data_y;
> +
> + if (!psmouse || !f || !p)
> + return;
> +
> + pkt_id = alps_get_pkt_id_ss4_v1(p);
> +
> + /* Current packet is 1Finger coordinate packet */
> + switch (pkt_id) {
> + case SS4_PACKET_ID_ONE:
> + f->pt_img[0].x = SS4_1F_X_V1(p);
> + f->pt_img[0].y = SS4_1F_Y_V1(p);
> + /* Keep Z-value in 0-127 */
> + f->pt_img[0].z = min(((SS4_1F_Z_V1(p)) * 2), 127);
> + f->large_fn |= SS4_1F_LFB(p) ? 0x01 : 0x00;
> + f->fingers = 1;
> + f->first_mp = 0;
> + f->is_mp = 0;
> + break;
> +
> + case SS4_PACKET_ID_TWO:
> + if (priv->flags & ALPS_BTNLESS) {
> + f->pt_img[0].x = SS4_BTL_MF_X_V1(p, 0);
> + f->pt_img[0].y = SS4_BTL_MF_Y_V1(p, 0);
> + f->pt_img[1].x = SS4_BTL_MF_X_V1(p, 1);
> + f->pt_img[1].y = SS4_BTL_MF_Y_V1(p, 1);
> + } else {
> + f->pt_img[0].x = SS4_STD_MF_X_V1(p, 0);
> + f->pt_img[0].y = SS4_STD_MF_Y_V1(p, 0);
> + f->pt_img[1].x = SS4_STD_MF_X_V1(p, 1);
> + f->pt_img[1].y = SS4_STD_MF_Y_V1(p, 1);
> + }
> + f->pt_img[0].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
> + f->pt_img[1].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
> +
> + if (SS4_IS_MF_CONTINUE_V1(p)) {
> + f->first_mp = 1;
> + } else {
> + f->fingers = 2;
> + f->first_mp = 0;
> + }
> + f->is_mp = 0;
> +
> + break;
> +
> + case SS4_PACKET_ID_MULTI:
> + if (priv->flags & ALPS_BTNLESS) {
> + f->pt_img[2].x = SS4_BTL_MF_X_V1(p, 0);
> + f->pt_img[2].y = SS4_BTL_MF_Y_V1(p, 0);
> + f->pt_img[3].x = SS4_BTL_MF_X_V1(p, 1);
> + f->pt_img[3].y = SS4_BTL_MF_Y_V1(p, 1);
> + no_data_x = SS4_MFPACKET_NO_AX_BL;
> + no_data_y = SS4_MFPACKET_NO_AY_BL;
> + } else {
> + f->pt_img[2].x = SS4_STD_MF_X_V1(p, 0);
> + f->pt_img[2].y = SS4_STD_MF_Y_V1(p, 0);
> + f->pt_img[3].x = SS4_STD_MF_X_V1(p, 1);
> + f->pt_img[3].y = SS4_STD_MF_Y_V1(p, 1);
> + no_data_x = SS4_MFPACKET_NO_AX;
> + no_data_y = SS4_MFPACKET_NO_AY;
> + }
> + f->pt_img[2].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
> + f->pt_img[3].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
> +
> + f->first_mp = 0;
> + f->is_mp = 1;
> +
> + if (SS4_IS_5F_DETECTED_V1(p)) {
> + f->fingers = 5;
> + } else if (f->pt_img[3].x == no_data_x &&
> + f->pt_img[3].y == no_data_y) {
> + f->fingers = 3;
> + f->pt_img[3].x = 0;
> + f->pt_img[3].y = 0;
> + f->pt_img[3].z = 0;
> + } else {
> + f->fingers = 4;
> + }
> + break;
> +
> + case SS4_PACKET_ID_IDLE:
> + default:
> + memset(f, 0, sizeof(struct alps_fields));
> + break;
> + }
> +
> + f->btn.left = !!(SS4_BTN_V1(p) & 0x01);
> + if (!(priv->flags & ALPS_BTNLESS)) {
> + f->btn.right = !!(SS4_BTN_V1(p) & 0x02);
> + f->btn.middle = !!(SS4_BTN_V1(p) & 0x04);
> + }
> +}
> +
> +static void alps_decode_ss4_v2(struct alps_fields *f,
> + unsigned char *p, struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned char pkt_id;
> + unsigned int no_data_x, no_data_y;
> +
> + if (!psmouse || !f || !p)
> + return;
> +
> + pkt_id = alps_get_pkt_id_ss4_v2(p);
> +
> + /* Current packet is 1Finger coordinate packet */
> + switch (pkt_id) {
> + case SS4_PACKET_ID_ONE:
> + f->pt_img[0].x = SS4_1F_X_V2(p);
> + f->pt_img[0].y = SS4_1F_Y_V2(p);
> + /* Keep Z-value in 0-127 */
> + f->pt_img[0].z = min(((SS4_1F_Z_V2(p)) * 2), 127);
> + f->large_fn |= SS4_1F_LFB_V2(p) ? 0x01 : 0x00;
> + f->fingers = 1;
> + f->first_mp = 0;
> + f->is_mp = 0;
> + break;
> +
> + case SS4_PACKET_ID_TWO:
> + if (priv->flags & ALPS_BTNLESS) {
> + f->pt_img[0].x = SS4_BTL_MF_X_V2(p, 0);
> + f->pt_img[0].y = SS4_BTL_MF_Y_V2(p, 0);
> + f->pt_img[1].x = SS4_BTL_MF_X_V2(p, 1);
> + f->pt_img[1].y = SS4_BTL_MF_Y_V2(p, 1);
> + } else {
> + f->pt_img[0].x = SS4_STD_MF_X_V2(p, 0);
> + f->pt_img[0].y = SS4_STD_MF_Y_V2(p, 0);
> + f->pt_img[1].x = SS4_STD_MF_X_V2(p, 1);
> + f->pt_img[1].y = SS4_STD_MF_Y_V2(p, 1);
> + }
> + f->pt_img[0].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
> + f->pt_img[1].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
> +
> + f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x01 : 0;
> + f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x02 : 0;
> +
> + if (SS4_IS_MF_CONTINUE_V2(p)) {
> + f->first_mp = 1;
> + } else {
> + f->fingers = 2;
> + f->first_mp = 0;
> + }
> + f->is_mp = 0;
> + break;
> +
> + case SS4_PACKET_ID_MULTI:
> + if (priv->flags & ALPS_BTNLESS) {
> + f->pt_img[2].x = SS4_BTL_MF_X_V2(p, 0);
> + f->pt_img[2].y = SS4_BTL_MF_Y_V2(p, 0);
> + f->pt_img[3].x = SS4_BTL_MF_X_V2(p, 1);
> + f->pt_img[3].y = SS4_BTL_MF_Y_V2(p, 1);
> + no_data_x = SS4_MFPACKET_NO_AX_BL;
> + no_data_y = SS4_MFPACKET_NO_AY_BL;
> + } else {
> + f->pt_img[2].x = SS4_STD_MF_X_V2(p, 0);
> + f->pt_img[2].y = SS4_STD_MF_Y_V2(p, 0);
> + f->pt_img[3].x = SS4_STD_MF_X_V2(p, 1);
> + f->pt_img[3].y = SS4_STD_MF_Y_V2(p, 1);
> + no_data_x = SS4_MFPACKET_NO_AX;
> + no_data_y = SS4_MFPACKET_NO_AY;
> + }
> + f->pt_img[2].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
> + f->pt_img[3].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
> +
> + f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x04 : 0;
> + f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x08 : 0;
> + f->first_mp = 0;
> + f->is_mp = 1;
> +
> + if (SS4_IS_5F_DETECTED_V2(p)) {
> + f->fingers = 5;
> + } else if (f->pt_img[3].x == no_data_x &&
> + f->pt_img[3].y == no_data_y) {
> + f->fingers = 3;
> + f->pt_img[3].x = 0;
> + f->pt_img[3].y = 0;
> + f->pt_img[3].z = 0;
> + } else {
> + f->fingers = 4;
> + }
> + break;
> +
> + case SS4_PACKET_ID_IDLE:
> + default:
> + memset(f, 0, sizeof(struct alps_fields));
> + break;
> + }
> +
> + f->btn.left = !!(SS4_BTN_V2(p) & 0x01);
> + if (!(priv->flags & ALPS_BTNLESS)) {
> + f->btn.right = !!(SS4_BTN_V2(p) & 0x02);
> + f->btn.middle = !!(SS4_BTN_V2(p) & 0x04);
> + }
> }
>
> static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> unsigned char *packet = psmouse->packet;
> + struct input_dev *dev = psmouse->dev;
> struct input_dev *dev2 = priv->dev2;
> - struct alps_fields *f = &priv->f;
> - int fingers = 0;
> + int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
> + int fingers = 0, bmap_fn;
> + struct alps_fields f = {0};
>
> - memset(f, 0, sizeof(*f));
> -
> - priv->decode_fields(f, packet, psmouse);
> + priv->decode_fields(&f, packet, psmouse);
>
> /*
> * There's no single feature of touchpad position and bitmap packets
> @@ -639,14 +1095,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * packet. Check for this, and when it happens process the
> * position packet as usual.
> */
> - if (f->is_mp) {
> - fingers = f->fingers;
> + if (f.is_mp) {
> + fingers = f.fingers;
> if (priv->proto_version == ALPS_PROTO_V3) {
> - if (alps_process_bitmap(priv, f) == 0)
> - fingers = 0; /* Use st data */
> + bmap_fn = alps_process_bitmap(priv, f.x_map,
> + f.y_map, &x1, &y1,
> + &x2, &y2);
> +
> + /*
> + * We shouldn't report more than one finger if
> + * we don't have two coordinates.
> + */
> + if (fingers > 1 && bmap_fn < 2)
> + fingers = bmap_fn;
>
> /* Now process position packet */
> - priv->decode_fields(f, priv->multi_data,
> + priv->decode_fields(&f, priv->multi_data,
> psmouse);
> } else {
> /*
> @@ -655,14 +1119,15 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * calculate Pt2, so we need to do position
> * packet decode first.
> */
> - priv->decode_fields(f, priv->multi_data,
> + priv->decode_fields(&f, priv->multi_data,
> psmouse);
>
> /*
> * Since Dolphin's finger number is reliable,
> * there is no need to compare with bmap_fn.
> */
> - alps_process_bitmap_dolphin(priv, f);
> + alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
> + &x2, &y2);
> }
> } else {
> priv->multi_packet = 0;
> @@ -677,10 +1142,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * out misidentified bitmap packets, we reject anything with this
> * bit set.
> */
> - if (f->is_mp)
> + if (f.is_mp)
> return;
>
> - if (!priv->multi_packet && f->first_mp) {
> + if (!priv->multi_packet && f.first_mp) {
> priv->multi_packet = 1;
> memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
> return;
> @@ -694,15 +1159,44 @@ 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->st.x && f->st.y && !f->pressure)
> + if (f.pt.x && f.pt.y && !f.pt.z)
> return;
>
> - alps_report_semi_mt_data(psmouse, fingers);
> + /*
> + * If we don't have MT data or the bitmaps were empty, we have
> + * to rely on ST data.
> + */
> + if (!fingers) {
> + x1 = f.pt.x;
> + y1 = f.pt.y;
> + fingers = f.pt.z > 0 ? 1 : 0;
> + }
> +
> + if (f.pt.z > 0)
> + input_report_key(dev, BTN_TOUCH, 1);
> + else
> + input_report_key(dev, BTN_TOUCH, 0);
> +
> + alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +
> + input_mt_report_finger_count(dev, fingers);
> +
> + 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.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);
> }
> }
> @@ -727,6 +1221,64 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
> alps_process_touchpad_packet_v3_v5(psmouse);
> }
>
> +/* proto_v9 */
> +static void alps_process_touchpad_packet_ss3(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned char *packet = psmouse->packet;
> + struct input_dev *dev = psmouse->dev;
> + int fingers = 0;
> + struct alps_fields f = {0};
> + struct alps_abs_data pt_output[2] = { {0, 0, 0}, {0, 0, 0} };
> + unsigned char output_fn_num = 0;
> +
> + priv->decode_fields(&f, packet, psmouse);
> +
> + if ((!!priv->multi_packet) != (!!f.is_mp)) {
> + priv->multi_packet = 0;
> + return;
> + }
> +
> + /* When f.first_mp is 1, next packet should be a
> + * bitmap packet(when there is no error).
> + */
> + priv->multi_packet = f.first_mp;
> +
> + /* Don't process any 3-f data */
> + if (f.first_mp || f.is_mp)
> + return;
> +
> + /*
> + * If we don't have MT data or the bitmaps were empty, we have
> + * to rely on ST data.
> + */
> + fingers = f.fingers;
> +
> + alps_process_resting_finger(psmouse, &f, pt_output, &output_fn_num);
> + alps_process_btnless_click(psmouse, &f);
> +
> + if (pt_output[0].z || pt_output[1].z)
> + input_report_key(dev, BTN_TOUCH, 1);
> + else
> + input_report_key(dev, BTN_TOUCH, 0);
> +
> + alps_report_semi_mt_data_ex(dev, 2, pt_output);
> +
> + input_mt_report_finger_count(dev, output_fn_num);
> +
> + 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 (pt_output[0].z > 0) {
> + input_report_abs(dev, ABS_X, pt_output[0].x);
> + input_report_abs(dev, ABS_Y, pt_output[0].y);
> + }
> + input_report_abs(dev, ABS_PRESSURE, pt_output[0].z ? 30 : 0);
> +
> + input_sync(dev);
> +}
> +
> static void alps_process_packet_v6(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> @@ -801,8 +1353,13 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> unsigned char *packet = psmouse->packet;
> - struct alps_fields *f = &priv->f;
> + struct input_dev *dev = psmouse->dev;
> int offset;
> + int x, y, z;
> + int left, right;
> + int x1, y1, x2, y2;
> + int fingers = 0;
> + unsigned int x_bitmap, y_bitmap;
>
> /*
> * v4 has a 6-byte encoding for bitmap data, but this data is
> @@ -824,41 +1381,96 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> if (++priv->multi_packet > 2) {
> priv->multi_packet = 0;
>
> - f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
> + x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
> ((priv->multi_data[3] & 0x60) << 3) |
> ((priv->multi_data[0] & 0x3f) << 2) |
> ((priv->multi_data[1] & 0x60) >> 5);
> - f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
> + y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
> ((priv->multi_data[3] & 0x1f) << 5) |
> (priv->multi_data[1] & 0x1f);
>
> - f->fingers = alps_process_bitmap(priv, f);
> + fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
> + &x1, &y1, &x2, &y2);
> +
> + /* Store MT data.*/
> + priv->fingers = fingers;
> + priv->x1 = x1;
> + priv->x2 = x2;
> + priv->y1 = y1;
> + priv->y2 = y2;
> }
>
> - f->left = packet[4] & 0x01;
> - f->right = packet[4] & 0x02;
> + left = packet[4] & 0x01;
> + right = packet[4] & 0x02;
> +
> + x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
> + ((packet[0] & 0x30) >> 4);
> + y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
> + z = packet[5] & 0x7f;
> +
> + /*
> + * If there were no contacts in the bitmap, use ST
> + * points in MT reports.
> + * If there were two contacts or more, report MT data.
> + */
> + if (priv->fingers < 2) {
> + x1 = x;
> + y1 = y;
> + fingers = z > 0 ? 1 : 0;
> + } else {
> + fingers = priv->fingers;
> + x1 = priv->x1;
> + x2 = priv->x2;
> + y1 = priv->y1;
> + y2 = priv->y2;
> + }
> +
> + if (z >= 64)
> + input_report_key(dev, BTN_TOUCH, 1);
> + else
> + input_report_key(dev, BTN_TOUCH, 0);
> +
> + alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
> +
> + input_mt_report_finger_count(dev, fingers);
> +
> + input_report_key(dev, BTN_LEFT, left);
> + input_report_key(dev, BTN_RIGHT, right);
>
> - f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
> - ((packet[0] & 0x30) >> 4);
> - f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
> - f->pressure = packet[5] & 0x7f;
> + if (z > 0) {
> + input_report_abs(dev, ABS_X, x);
> + input_report_abs(dev, ABS_Y, y);
> + }
> + input_report_abs(dev, ABS_PRESSURE, z);
>
> - alps_report_semi_mt_data(psmouse, f->fingers);
> + input_sync(dev);
> }
>
> static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> {
> - switch (psmouse->pktcnt) {
> - case 3:
> - return (psmouse->packet[2] & 0x40) == 0x40;
> - case 4:
> - return (psmouse->packet[3] & 0x48) == 0x48;
> - case 6:
> - return (psmouse->packet[5] & 0x40) == 0x00;
> - }
> + 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;
> @@ -874,85 +1486,251 @@ static unsigned char alps_get_packet_id_v7(char *byte)
> else
> packet_id = V7_PACKET_ID_UNKNOWN;
>
> - return packet_id;
> + 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;
> +
> + 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;
> + memset(&f->btn, 0, sizeof(struct alps_btn));
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> +
> + if (priv->flags & ALPS_BTNLESS) {
> + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> + f->btn.middle = (p[0] & 0x80) >> 7;
> + } else {
> + f->btn.left = (p[0] & 0x80) >> 7;
> + f->btn.right = (p[0] & 0x20) >> 5;
> + f->btn.middle = (p[0] & 0x10) >> 4;
> + }
> + }
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> + priv->r.v7.additional_fingers = p[5] & 0x03;
> }
>
> -static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
> - unsigned char *pkt,
> - unsigned char pkt_id)
> +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_abs_data *pt,
> + struct alps_bl_pt_attr *pt_attr)
> {
> - mt[0].x = ((pkt[2] & 0x80) << 4);
> - mt[0].x |= ((pkt[2] & 0x3F) << 5);
> - mt[0].x |= ((pkt[3] & 0x30) >> 1);
> - mt[0].x |= (pkt[3] & 0x07);
> - mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> + struct alps_data *priv = psmouse->private;
> + unsigned int dist;
>
> - mt[1].x = ((pkt[3] & 0x80) << 4);
> - mt[1].x |= ((pkt[4] & 0x80) << 3);
> - mt[1].x |= ((pkt[4] & 0x3F) << 4);
> - mt[1].y = ((pkt[5] & 0x80) << 3);
> - mt[1].y |= ((pkt[5] & 0x3F) << 4);
> + 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));
> + }
>
> - switch (pkt_id) {
> - case V7_PACKET_ID_TWO:
> - mt[1].x &= ~0x000F;
> - mt[1].y |= 0x000F;
> - break;
> + 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;
> + }
> + }
> + }
> +}
>
> - case V7_PACKET_ID_MULTI:
> - mt[1].x &= ~0x003F;
> - mt[1].y &= ~0x0020;
> - mt[1].y |= ((pkt[4] & 0x02) << 4);
> - mt[1].y |= 0x001F;
> - break;
> +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> + int i;
>
> - case V7_PACKET_ID_NEW:
> - mt[1].x &= ~0x003F;
> - mt[1].x |= (pkt[0] & 0x20);
> - mt[1].y |= 0x000F;
> + 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]) * V7_IMG_PT_NUM);
> break;
> }
> -
> - mt[0].y = 0x7FF - mt[0].y;
> - mt[1].y = 0x7FF - mt[1].y;
> }
>
> -static int alps_get_mt_count(struct input_mt_pos *mt)
> +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;
>
> - for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
> - /* empty */;
> + 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;
> + }
>
> - return i;
> + f->fingers = fn;
> }
>
> -static int alps_decode_packet_v7(struct alps_fields *f,
> - unsigned char *p,
> - struct psmouse *psmouse)
> +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> {
> - unsigned char pkt_id;
> + struct alps_data *priv = psmouse->private;
>
> - pkt_id = alps_get_packet_id_v7(p);
> - if (pkt_id == V7_PACKET_ID_IDLE)
> - return 0;
> - if (pkt_id == V7_PACKET_ID_UNKNOWN)
> - return -1;
> + /* It's ClickPad */
> + if (priv->flags & ALPS_BTNLESS) {
> + if (!f->btn.middle)
> + goto exit;
> +
> + f->btn.middle = 0;
> + if (priv->prev_btn.left || priv->prev_btn.middle ||
> + priv->prev_btn.right) {
> + memcpy(&f->btn, &priv->prev_btn,
> + sizeof(struct alps_btn));
> + goto exit;
> + }
>
> - alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
> + 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;
> + } else {
> + f->btn.left = 1;
> + }
>
> - if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
> - f->left = (p[0] & 0x80) >> 7;
> - f->right = (p[0] & 0x20) >> 5;
> - f->middle = (p[0] & 0x10) >> 4;
> + goto exit;
> }
>
> - if (pkt_id == V7_PACKET_ID_TWO)
> - f->fingers = alps_get_mt_count(f->mt);
> - else if (pkt_id == V7_PACKET_ID_MULTI)
> - f->fingers = 3 + (p[5] & 0x03);
> + /* It's Standard, do nothing */
>
> - return 0;
> +exit:
> + memcpy(&priv->prev_btn, &f->btn, sizeof(struct alps_btn));
> }
>
> static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
> @@ -962,21 +1740,9 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
> struct input_dev *dev2 = priv->dev2;
> int x, y, z, left, right, middle;
>
> - /*
> - * b7 b6 b5 b4 b3 b2 b1 b0
> - * Byte0 0 1 0 0 1 0 0 0
> - * Byte1 1 1 * * 1 M R L
> - * Byte2 X7 1 X5 X4 X3 X2 X1 X0
> - * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
> - * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
> - * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
> - * M / R / L: Middle / Right / Left button
> - */
> -
> - x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
> - y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
> - ((packet[3] & 0x20) << 1);
> - z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
> + x = ((packet[2] & 0xBF)) | ((packet[3] & 0x10) << 2);
> + y = (packet[3] & 0x03) | (packet[4] & 0xB8) | ((packet[3] & 0x20) << 1);
> + z = (packet[5] & 0x3F) | ((packet[3] & 0x80) >> 1);
>
> left = (packet[1] & 0x01);
> right = (packet[1] & 0x02) >> 1;
> @@ -996,35 +1762,115 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
> static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> - struct input_dev *dev = psmouse->dev;
> - struct alps_fields *f = &priv->f;
> + struct alps_fields f = {0};
> + unsigned char *packet = psmouse->packet;
>
> - memset(f, 0, sizeof(*f));
> + priv->decode_fields(&f, packet, psmouse);
>
> - if (priv->decode_fields(f, psmouse->packet, psmouse))
> + if (alps_drop_unsupported_packet_v7(psmouse))
> return;
>
> - alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
> + alps_set_pt_attr_v7(psmouse, &f);
>
> - input_mt_report_finger_count(dev, f->fingers);
> + alps_cal_output_finger_num_v7(psmouse, &f);
>
> - input_report_key(dev, BTN_LEFT, f->left);
> - input_report_key(dev, BTN_RIGHT, f->right);
> - input_report_key(dev, BTN_MIDDLE, f->middle);
> + alps_assign_buttons_v7(psmouse, &f);
>
> - input_sync(dev);
> + alps_report_coord_and_btn(psmouse, &f);
> }
>
> static void alps_process_packet_v7(struct psmouse *psmouse)
> {
> unsigned char *packet = psmouse->packet;
>
> - if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
> + if ((packet[0] == 0x48) && ((packet[4] & 0x47) == 0x06))
> alps_process_trackstick_packet_v7(psmouse);
> else
> alps_process_touchpad_packet_v7(psmouse);
> }
>
> +static void alps_process_packet_ss4(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned char *packet = psmouse->packet;
> + struct input_dev *dev = psmouse->dev;
> + struct alps_fields f;
> + struct alps_abs_data output_data[5];
> + unsigned char output_fn;
> +
> + memset(&f, 0, sizeof(struct alps_fields));
> + priv->decode_fields(&f, packet, psmouse);
> +
> + if (priv->multi_packet) {
> + /*
> + * Sometimes the first packet will indicate a multi-packet
> + * sequence, but sometimes the next multi-packet would not come.
> + * Check for this, and when it happens process the
> + * position packet as usual.
> + */
> + if (f.is_mp) {
> + /* Now process the 1st packet */
> + priv->decode_fields(&f, priv->multi_data, psmouse);
> + } else {
> + priv->multi_packet = 0;
> + }
> + }
> +
> + /*
> + * "f.is_mp" would always be '0' after merging the 1st and 2nd packet.
> + * When it is set, it means 2nd packet comes without 1st packet come.
> + */
> + if (f.is_mp)
> + return;
> +
> + /* Save the first packet */
> + if (!priv->multi_packet && f.first_mp) {
> + priv->multi_packet = 1;
> + memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
> + return;
> + }
> +
> + priv->multi_packet = 0;
> +
> + /* Set "output_data" and "output_fn" */
> + memset(&output_data[0], 0, sizeof(output_data));
> + if (priv->flags & ALPS_BTNLESS) {
> + alps_process_resting_finger(psmouse, &f,
> + output_data, &output_fn);
> + alps_process_btnless_click(psmouse, &f);
> + } else {
> + memcpy(&output_data[0], &f.pt_img[0],
> + sizeof(struct alps_abs_data) * f.fingers);
> + output_fn = f.fingers;
> + }
> +
> + f.pt.x = output_data[0].x;
> + f.pt.y = output_data[0].y;
> + f.pt.z = output_data[0].z;
> +
> + if (output_data[0].z || output_data[1].z ||
> + output_data[2].z || output_data[3].z)
> + input_report_key(dev, BTN_TOUCH, 1);
> + else
> + input_report_key(dev, BTN_TOUCH, 0);
> +
> + alps_report_semi_mt_data_ex(dev, 4, output_data);
> +
> + input_mt_report_finger_count(dev, output_fn);
> +
> + 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.pt.z);
> +
> + input_sync(dev);
> +}
> +
> static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> unsigned char packet[],
> bool report_buttons)
> @@ -1152,11 +1998,22 @@ static void alps_flush_packet(unsigned long data)
> serio_continue_rx(psmouse->ps2dev.serio);
> }
>
> +static bool alps_is_valid_package_ss4(struct psmouse *psmouse)
> +{
> + if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08))
> + return false;
> + if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0))
> + return false;
> + return true;
> +}
> +
> static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
>
> - if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
> + /* Can not distinguish V8's first byte from PS/2 packet's */
> + if ((psmouse->packet[0] & 0xc8) == 0x08 &&
> + priv->proto_version != ALPS_PROTO_V8) {
> if (psmouse->pktcnt == 3) {
> alps_report_bare_ps2_packet(psmouse, psmouse->packet,
> true);
> @@ -1189,8 +2046,10 @@ 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)) {
> + if ((priv->proto_version == ALPS_PROTO_V7 &&
> + !alps_is_valid_package_v7(psmouse)) ||
> + (priv->proto_version == ALPS_PROTO_V8 &&
> + !alps_is_valid_package_ss4(psmouse))) {
> psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> psmouse->pktcnt - 1,
> psmouse->packet[psmouse->pktcnt - 1]);
> @@ -1309,20 +2168,20 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> return 0;
> }
>
> -static bool alps_check_valid_firmware_id(unsigned char id[])
> +static int alps_check_valid_firmware_id(unsigned char id[])
> {
> - if (id[0] == 0x73)
> - return true;
> + int valid = 1;
>
> - if (id[0] == 0x88 &&
> - (id[1] == 0x07 ||
> - id[1] == 0x08 ||
> - (id[1] & 0xf0) == 0xb0 ||
> - (id[1] & 0xf0) == 0xc0)) {
> - return true;
> + 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 false;
> + return valid;
> }
>
> static int alps_enter_command_mode(struct psmouse *psmouse)
> @@ -1792,45 +2651,6 @@ error:
> return -1;
> }
>
> -static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
> -{
> - int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
> - struct alps_data *priv = psmouse->private;
> -
> - reg = alps_command_mode_read_reg(psmouse, reg_pitch);
> - if (reg < 0)
> - return reg;
> -
> - x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
> - x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
> -
> - y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
> - y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
> -
> - reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
> - if (reg < 0)
> - return reg;
> -
> - x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
> - x_electrode = 17 + x_electrode;
> -
> - y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
> - y_electrode = 13 + y_electrode;
> -
> - x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
> - y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
> -
> - priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
> - priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
> -
> - psmouse_dbg(psmouse,
> - "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
> - x_pitch, y_pitch, x_electrode, y_electrode,
> - x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
> -
> - return 0;
> -}
> -
> static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> @@ -1851,9 +2671,6 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
> alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
> goto error;
>
> - if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
> - goto error;
> -
> reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
> if (reg_val == -1)
> goto error;
> @@ -1878,6 +2695,32 @@ 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) ||
> + alps_command_mode_read_reg(psmouse, 0xc2d9) == -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)
> {
> @@ -1967,6 +2810,102 @@ error:
> return -1;
> }
>
> +static int alps_get_otp_values_ss4(struct psmouse *psmouse,
> + unsigned char index, unsigned char otp[])
> +{
> + struct ps2dev *ps2dev = &psmouse->ps2dev;
> +
> + switch (index) {
> + case 0:
> + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
> + return -1;
> +
> + break;
> +
> + case 1:
> + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
> + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
> + ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
> + return -1;
> +
> + break;
> + }
> +
> + return 0;
> +}
> +
> +int alps_update_device_area_ss4_v1(
> + unsigned char otp[][4], struct alps_data *priv)
> +{
> + int num_x_electrode;
> + int num_y_electrode;
> +
> + num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
> + num_y_electrode = ((otp[1][0] >> 4) & 0x0F);
> +
> + priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
> + priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
> +
> + return 0;
> +}
> +
> +int alps_update_device_area_ss4_v2(
> + unsigned char otp[][4], struct alps_data *priv)
> +{
> + int num_x_electrode;
> + int num_y_electrode;
> +
> + num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
> + if ((priv->fw_ver[1] > 2) ||
> + (priv->fw_ver[1] == 2 && priv->fw_ver[2] > 0x33)) {
> + num_y_electrode =
> + SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x07);
> + } else {
> + num_y_electrode = ((otp[1][0] >> 4) & 0x0F);
> + }
> +
> + priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
> + priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
> +
> + return 0;
> +}
> +
> +int alps_update_btn_info_ss4(unsigned char otp[][4], struct alps_data *priv)
> +{
> +
> + unsigned char is_btnless = 0;
> +
> + is_btnless = (otp[1][1] >> 3) & 0x01;
> +
> + if (is_btnless)
> + priv->flags |= ALPS_BTNLESS;
> +
> + return 0;
> +}
> +
> +static int alps_set_defaults_ss4(struct psmouse *psmouse,
> + struct alps_data *priv)
> +{
> + unsigned char otp[2][4];
> +
> + memset(otp, 0, sizeof(otp));
> +
> + if (alps_get_otp_values_ss4(psmouse, 0, &otp[0][0]) ||
> + alps_get_otp_values_ss4(psmouse, 1, &otp[1][0]))
> + return -1;
> +
> + if (priv->fw_ver[1] >= 2)
> + alps_update_device_area_ss4_v2(otp, priv);
> + else
> + alps_update_device_area_ss4_v1(otp, priv);
> +
> + alps_update_btn_info_ss4(otp, priv);
> +
> + return 0;
> +}
> +
> static int alps_dolphin_get_device_area(struct psmouse *psmouse,
> struct alps_data *priv)
> {
> @@ -2030,28 +2969,54 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
> return 0;
> }
>
> -static int alps_hw_init_v7(struct psmouse *psmouse)
> +static int alps_hw_init_ss3(struct psmouse *psmouse)
> {
> struct ps2dev *ps2dev = &psmouse->ps2dev;
> - int reg_val, ret = -1;
> + unsigned char f3param0 = 0x00,
> + f3param1 = 0x00;
>
> - if (alps_enter_command_mode(psmouse) ||
> - alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
> + if (alps_enter_command_mode(psmouse))
> goto error;
>
> - if (alps_get_v3_v7_resolution(psmouse, 0xc397))
> + /* Set to 2 pt-mode */
> + f3param0 = 0x50;
> + f3param1 = 0x3c;
> + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
> + ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
> goto error;
>
> - if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
> - goto error;
> + /* output APDATA when 1 finger is in resting area */
> + f3param0 = 0xc8;
> + f3param1 = 0x28;
> + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
> + ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
> + 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))
> + return 0;
> +
> +error:
> + return -1;
> +}
> +
> +
> +static int alps_hw_init_ss4(struct psmouse *psmouse)
> +{
> + struct ps2dev *ps2dev = &psmouse->ps2dev;
> + char param[2] = {0x64, 0x28};
> + int ret = -1;
> +
> + /* enter absolute mode */
> + if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
> + ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
> + ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) {
> goto error;
> + }
>
> - alps_exit_command_mode(psmouse);
> return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
>
> error:
> @@ -2078,6 +3043,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;
> @@ -2086,6 +3052,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;
> @@ -2093,6 +3060,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;
> @@ -2108,6 +3076,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;
> @@ -2116,6 +3085,7 @@ 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 = 1;
> break;
> case ALPS_PROTO_V7:
> priv->hw_init = alps_hw_init_v7;
> @@ -2129,8 +3099,44 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->byte0 = 0x48;
> priv->mask0 = 0x48;
>
> - if (priv->fw_ver[1] != 0xba)
> - priv->flags |= ALPS_BUTTONPAD;
> + if (priv->fw_ver[1] == 0xBA) {
> + priv->flags = 0;
> + /* No resting finger area */
> + priv->resting_zone_y_min = priv->y_max;
> + } else {
> + priv->flags = ALPS_BTNLESS;
> + priv->resting_zone_y_min = 0x654;
> + }
> +
> + priv->slot_number = 2;
> + break;
> + case ALPS_PROTO_V8:
> + if (priv->fw_ver[1] >= 2)
> + priv->decode_fields = alps_decode_ss4_v2;
> + else
> + priv->decode_fields = alps_decode_ss4_v1;
> +
> + priv->hw_init = alps_hw_init_ss4;
> + priv->process_packet = alps_process_packet_ss4;
> + 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->byte0 = 0x18;
> + priv->mask0 = 0x18;
> + priv->flags = 0;
> + priv->slot_number = 4;
> + break;
> + case ALPS_PROTO_V9:
> + priv->hw_init = alps_hw_init_ss3;
> + priv->process_packet = alps_process_touchpad_packet_ss3;
> + priv->decode_fields = alps_decode_dolphin;
> + priv->set_abs_params = alps_set_abs_params_mt;
> + priv->nibble_commands = alps_v3_nibble_commands;
> + priv->byte0 = 0xc8;
> + priv->mask0 = 0xc8;
> + priv->slot_number = 2;
> break;
> }
> }
> @@ -2204,7 +3210,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> else
> return 0;
> } else if (ec[0] == 0x88 &&
> - ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
> + ((ec[1] & 0xf0) == 0xB0 || (ec[1] & 0xf0) == 0xC0)) {
> priv->proto_version = ALPS_PROTO_V7;
> alps_set_defaults(priv);
>
> @@ -2217,7 +3223,6 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> priv->decode_fields = alps_decode_rushmore;
> priv->x_bits = 16;
> priv->y_bits = 12;
> - priv->flags |= ALPS_IS_RUSHMORE;
>
> /* hack to make addr_command, nibble_command available */
> psmouse->private = priv;
> @@ -2232,6 +3237,22 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> alps_set_defaults(priv);
>
> return 0;
> + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14) {
> + priv->proto_version = ALPS_PROTO_V8;
> + alps_set_defaults(priv);
> +
> + if (alps_set_defaults_ss4(psmouse, priv))
> + return -EIO;
> +
> + return 0;
> + } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) {
> + priv->proto_version = ALPS_PROTO_V9;
> + alps_set_defaults(priv);
> +
> + if (alps_dolphin_get_device_area(psmouse, priv))
> + return -EIO;
> +
> + return 0;
> }
>
> psmouse_info(psmouse,
> @@ -2272,21 +3293,17 @@ static void alps_set_abs_params_st(struct alps_data *priv,
> 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, 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);
>
> - input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
> - input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
> -
> - input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
> - INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
> -
> + set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
> set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
> set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
>
> - /* V7 is real multi-touch */
> - if (priv->proto_version == ALPS_PROTO_V7)
> - clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> + input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
> + input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
> }
>
> int alps_init(struct psmouse *psmouse)
> @@ -2332,9 +3349,7 @@ int alps_init(struct psmouse *psmouse)
> dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
>
> priv->set_abs_params(priv, dev1);
> - /* No pressure on V7 */
> - if (priv->proto_version != ALPS_PROTO_V7)
> - input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
> + input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
>
> if (priv->flags & ALPS_WHEEL) {
> dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
> @@ -2351,14 +3366,12 @@ int alps_init(struct psmouse *psmouse)
> dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
> dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
> dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
> - } else if (priv->flags & ALPS_BUTTONPAD) {
> - set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
> - clear_bit(BTN_RIGHT, dev1->keybit);
> } else {
> dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
> }
>
> - snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
> + snprintf(priv->phys, sizeof(priv->phys),
> + "%s/input1", psmouse->ps2dev.serio->phys);
> dev2->phys = priv->phys;
> dev2->name = (priv->flags & ALPS_DUALPOINT) ?
> "DualPoint Stick" : "ALPS PS/2 Device";
> @@ -2382,7 +3395,8 @@ int alps_init(struct psmouse *psmouse)
> psmouse->reconnect = alps_reconnect;
> psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
>
> - /* We are having trouble resyncing ALPS touchpads so disable it for now */
> + /* We are having trouble resyncing ALPS touchpads
> + so disable it for now */
> psmouse->resync_time = 0;
>
> return 0;
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index 66240b4..55f5193 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -12,8 +12,6 @@
> #ifndef _ALPS_H
> #define _ALPS_H
>
> -#include <linux/input/mt.h>
> -
> #define ALPS_PROTO_V1 1
> #define ALPS_PROTO_V2 2
> #define ALPS_PROTO_V3 3
> @@ -21,8 +19,17 @@
> #define ALPS_PROTO_V5 5
> #define ALPS_PROTO_V6 6
> #define ALPS_PROTO_V7 7 /* t3btl t4s */
> +#define ALPS_PROTO_V8 8 /* ss4 */
> +#define ALPS_PROTO_V9 9 /* ss3btl */
> +
> +
> +#define MAX_IMG_PT_NUM 5
> +#define V7_IMG_PT_NUM 2
>
> -#define MAX_TOUCHES 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 */
> @@ -45,6 +52,124 @@ enum V7_PACKET_ID {
> V7_PACKET_ID_UNKNOWN,
> };
>
> +enum SS4_PACKET_ID {
> + SS4_PACKET_ID_IDLE = 0,
> + SS4_PACKET_ID_ONE,
> + SS4_PACKET_ID_TWO,
> + SS4_PACKET_ID_MULTI,
> +};
> +
> +#define SS4_COUNT_PER_ELECTRODE 256
> +#define SS4_NUMSENSOR_XOFFSET 7
> +#define SS4_NUMSENSOR_YOFFSET 7
> +
> +/* SWC status( 0:SW OFF, 1: SW ON) */
> +#define SS4_BUTTONLESS_BUTTONS 0x01
> +
> +#define SS4_MASK_NORMAL_BUTTONS 0x07
> +
> +#define SS4_1F_X_V1(_b) (((_b[0] << 5) & 0x1E00) | \
> + ((_b[0] << 6) & 0x01C0) | \
> + ((_b[1] >> 2) & 0x0038) | \
> + ((_b[1] >> 1) & 0x0007) \
> + )
> +
> +#define SS4_1F_Y_V1(_b) (((_b[2] >> 1) & 0x007F) | \
> + ((_b[4] << 5) & 0x0F80) \
> + )
> +
> +#define SS4_1F_Z_V1(_b) (_b[5] & 0xFF)
> +
> +#define SS4_1F_LFB(_b) ((_b[4] >> 1) & 0x01)
> +
> +#define SS4_BTN_V1(_b) (_b[3] & SS4_BUTTONLESS_BUTTONS)
> +
> +#define SS4_STD_MF_X_V1(_b, _i) (((_b[0 + _i * 3] >> 2) & 0x0020) | \
> + ((_b[1 + _i * 3] << 5) & 0x1FC0) \
> + )
> +
> +#define SS4_STD_MF_Y_V1(_b, _i) (((_b[0 + _i * 3] >> 2) & 0x0010) | \
> + ((_b[2 + _i * 3] << 4) & 0x0FE0) \
> + )
> +
> +#define SS4_BTL_BTN_V1(_b) (_b[3] & SS4_BUTTONLESS_BUTTONS)
> +
> +#define SS4_BTL_MF_X_V1(_b, _i) (SS4_STD_MF_X_V1(_b, _i) | \
> + ((_b[0 + _i * 3] << 2) & 0x0010))
> +
> +#define SS4_BTL_MF_Y_V1(_b, _i) (SS4_STD_MF_Y_V1(_b, _i) | \
> + ((_b[0 + _i * 3] << 2) & 0x0008))
> +
> +#define SS4_MF_Z_V1(_b, _i) ((_b[0 + _i * 3] >> 4) & 0x0003)
> +
> +#define SS4_IS_MF_CONTINUE_V1(_b) ((_b[0] & 0x01) == 0x01)
> +#define SS4_IS_5F_DETECTED_V1(_b) ((_b[0] & 0x01) == 0x01)
> +
> +#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
> + ((_b[1] << 3) & 0x0078) | \
> + ((_b[1] << 2) & 0x0380) | \
> + ((_b[2] << 5) & 0x1C00) \
> + )
> +
> +#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \
> + ((_b[3] >> 2) & 0x0030) | \
> + ((_b[4] << 6) & 0x03C0) | \
> + ((_b[4] << 5) & 0x0C00) \
> + )
> +
> +#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \
> + ((_b[5] >> 1) & 0x70) | \
> + ((_b[4]) & 0x80) \
> + )
> +
> +#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01)
> +
> +#define SS4_MF_LF_V2(_b, _i) ((_b[1 + _i * 3] & 0x0004) == 0x0004)
> +
> +#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS)
> +
> +#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + _i * 3] << 5) & 0x00E0) | \
> + ((_b[1 + _i * 3] << 5) & 0x1F00) \
> + )
> +
> +#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + _i * 3] << 3) & 0x0010) | \
> + ((_b[2 + _i * 3] << 5) & 0x01E0) | \
> + ((_b[2 + _i * 3] << 4) & 0x0E00) \
> + )
> +
> +#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \
> + ((_b[0 + _i * 3] >> 3) & 0x0010))
> +
> +#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
> + ((_b[0 + _i * 3] >> 3) & 0x0008))
> +
> +#define SS4_MF_Z_V2(_b, _i) (((_b[1 + _i * 3]) & 0x0001) | \
> + ((_b[1 + _i * 3] >> 1) & 0x0002) \
> + )
> +
> +#define SS4_IS_MF_CONTINUE_V2(_b) ((_b[2] & 0x10) == 0x10)
> +#define SS4_IS_5F_DETECTED_V2(_b) ((_b[2] & 0x10) == 0x10)
> +
> +
> +#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
> +#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
> +#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */
> +#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */
> +
> +/* Threshold for resting finger's large movement */
> +#define RESTING_FN_LARGE_MOVEMENT 50
> +
> +#define PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max)
> + (((_x) < (_x_max)/2) && ((_y) > (_y_max)*4/5))
> +
> +#define PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
> + (((_x) >= (_x_max)/2) && ((_y) > (_y_max)*4/5))
> +
> +#define PT_IN_BTN_AREA(_x, _y, _x_max, _y_max)
> + (PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max) ||
> + PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
> + )
> +
> /**
> * struct alps_model_info - touchpad ID table
> * @signature: E7 response string to match.
> @@ -68,7 +193,7 @@ struct alps_model_info {
> unsigned char command_mode_resp;
> unsigned char proto_version;
> unsigned char byte0, mask0;
> - int flags;
> + unsigned int flags;
> };
>
> /**
> @@ -87,47 +212,95 @@ struct alps_nibble_commands {
> unsigned char data;
> };
>
> -struct alps_bitmap_point {
> - int start_bit;
> - int num_bits;
> +/**
> + * 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.
> + * @ts_left: Left trackstick button is active.
> + * @ts_right: Right trackstick button is active.
> + * @ts_middle: Middle trackstick button is active.
> + */
> +struct alps_btn {
> + unsigned int left:1;
> + unsigned int right:1;
> + unsigned int middle:1;
> +
> + unsigned int ts_left:1;
> + unsigned int ts_right:1;
> + unsigned int ts_middle:1;
> +};
> +
> +/**
> + * 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;
> +};
> +
> +enum dol_Packet {
> + DOL_UNKNOWN,
> + DOL_GPDATA,
> + DOL_PROFDATA,
> + DOL_APDATA
> };
>
> /**
> * 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.
> - * @fingers: Number of fingers for MT.
> - * @pressure: Pressure.
> - * @st: position for ST.
> - * @mt: position for MT.
> * @first_mp: Packet is the first of a multi-packet report.
> * @is_mp: Packet is part of a multi-packet report.
> - * @left: Left touchpad button is active.
> - * @right: Right touchpad button is active.
> - * @middle: Middle touchpad button is active.
> - * @ts_left: Left trackstick button is active.
> - * @ts_right: Right trackstick button is active.
> - * @ts_middle: Middle trackstick button is active.
> + * @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 fingers;
> -
> - int pressure;
> - struct input_mt_pos st;
> - struct input_mt_pos mt[MAX_TOUCHES];
> -
> + unsigned int large_fn;
> unsigned int first_mp:1;
> unsigned int is_mp:1;
> + enum dol_Packet dol_packet_type;
> + struct alps_btn btn;
> +};
>
> - unsigned int left:1;
> - unsigned int right:1;
> - unsigned int middle:1;
> +/**
> + * 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.
> + */
> +struct v7_raw {
> + unsigned char pkt_id;
> + unsigned int additional_fingers;
> + unsigned char rest_left;
> + unsigned char rest_right;
> +};
>
> - unsigned int ts_left:1;
> - unsigned int ts_right:1;
> - unsigned int ts_middle:1;
> +/**
> + * 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.
> + */
> +struct alps_bl_pt_attr {
> + unsigned char zone;
> + unsigned char is_counted;
> + unsigned char is_init_pt_got;
> + struct alps_abs_data init_pt;
> };
>
> /**
> @@ -142,12 +315,13 @@ struct alps_fields {
> * known format for this model. The first byte of the report, ANDed with
> * mask0, should match byte0.
> * @mask0: The mask used to check the first byte of the report.
> - * @fw_ver: cached copy of firmware version (EC report)
> * @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.
> @@ -155,9 +329,18 @@ struct alps_fields {
> * @prev_fin: Finger bit from previous packet.
> * @multi_packet: Multi-packet data in progress.
> * @multi_data: Saved multi-packet data.
> - * @f: Decoded packet data fields.
> + * @x1: First X coordinate from last MT report.
> + * @x2: Second X coordinate from last MT report.
> + * @y1: First Y coordinate from last MT report.
> + * @y2: Second Y coordinate from last MT report.
> + * @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;
> @@ -168,27 +351,35 @@ struct alps_data {
> int addr_command;
> unsigned char proto_version;
> unsigned char byte0, mask0;
> + unsigned int flags;
> unsigned char fw_ver[3];
> - int flags;
> int x_max;
> int y_max;
> + int resting_zone_y_min;
> int x_bits;
> int y_bits;
> - unsigned int x_res;
> - unsigned int y_res;
> + unsigned char slot_number;
>
> int (*hw_init)(struct psmouse *psmouse);
> void (*process_packet)(struct psmouse *psmouse);
> - int (*decode_fields)(struct alps_fields *f, unsigned char *p,
> + void (*decode_fields)(struct alps_fields *f, unsigned char *p,
> struct psmouse *psmouse);
> void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
>
> int prev_fin;
> int multi_packet;
> unsigned char multi_data[6];
> - struct alps_fields f;
> + int x1, x2, y1, y2;
> + int fingers;
> u8 quirks;
> struct timer_list timer;
> +
> + /* these are used for buttonless touchpad*/
> + union {
> + struct v7_raw v7;
> + } r;
> + struct alps_btn prev_btn;
> + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> };
>
> #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> --
> 1.9.1
>
^ permalink raw reply
* Re: Plantronics Telephony Device HID Driver
From: Dmitry Torokhov @ 2014-10-23 23:49 UTC (permalink / raw)
To: Cole, JD
Cc: linux-input@vger.kernel.org, Wesselman, Tom, Dsouza, Sunil,
Junge, Terry, dtor@chromium.org, bleung@chromium.org,
vpalatin@chromium.org, adlr@chromium.org, Jiri Kosina
In-Reply-To: <05963dc6f4db439e88525351d4e9a0b8@usscmb04.plt.plantronics.com>
Hi JD,
On Tue, Oct 21, 2014 at 06:40:26PM +0000, Cole, JD wrote:
> Plantronics telephony devices equipped with HID-enabled controls have been reported to cause odd mouse behaviors when buttons are clicked. This is due to how the hid-input driver handles "unmapped" usages and the fact that Plantronics devices send Vendor Unique usages in addition to standards, e.g. Consumer Page Mute. It is the vendor unique usages that are mis-interpreted by the hid-input driver and mapped as mouse events.
>
> This driver serves to prevent unhandled usages from reaching the hid-input driver. Two patches are included:
>
> (1) The minimal driver
> (2) The more complete additions to hid.h Consumer Page MACROS
>
> Cheers,
>
> jd
>
> From ee603e2aa62906a65b08b440c4b440e324269295 Mon Sep 17 00:00:00 2001
> From: JD Cole <jd.cole@plantronics.com>
> Date: Fri, 17 Oct 2014 12:21:49 -0700
> Subject: [PATCH 1/2] Created base Plantronics HID driver.
>
> A fix for Plantronics telephony device controls interfering with
> the mouse.
>
> This version of the driver prevents Telephony pages which are not
> mapped as Consumer Control applications AND are not on the Consumer Page
> from being registered by the hid-input driver.
>
> BUG=chromium:417434
> TEST=Tested with multiple Plantronics devices on 'peppy' Acer C720p.
>
> Change-Id: I7a55880d6082467274b693c48415e9331d9bbd81
> Signed-off-by: JD Cole <jd.cole@plantronics.com>
> ---
> drivers/hid/Kconfig | 7 ++++
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-ids.h | 2 +
> drivers/hid/hid-plantronics.c | 92 +++++++++++++++++++++++++++++++++++++++++++
> include/linux/hid.h | 3 ++
> 5 files changed, 105 insertions(+)
> create mode 100644 drivers/hid/hid-plantronics.c
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index 2f38a7b..b245c28 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -594,6 +594,13 @@ config HID_PICOLCD_CIR
> ---help---
> Provide access to PicoLCD's CIR interface via remote control (LIRC).
>
> +config HID_PLANTRONICS
> + tristate "Plantronics USB HID Driver"
> + default !EXPERT
> + depends on HID
> + ---help---
> + Provides HID support for Plantronics telephony devices.
> +
> config HID_PRIMAX
> tristate "Primax non-fully HID-compliant devices"
> depends on HID
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index 6684b30..7080637 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -93,6 +93,7 @@ ifdef CONFIG_DEBUG_FS
> hid-picolcd-y += hid-picolcd_debugfs.o
> endif
>
> +obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
> obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
> obj-$(CONFIG_HID_QUICKSTEP) += hid-quickstep.o
> obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 7fd93c3..1c8ede1 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -703,6 +703,8 @@
> #define USB_DEVICE_ID_ORTEK_PKB1700 0x1700
> #define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
>
> +#define USB_VENDOR_ID_PLANTRONICS 0x047f
> +
> #define USB_VENDOR_ID_PANASONIC 0x04da
> #define USB_DEVICE_ID_PANABOARD_UBT780 0x1044
> #define USB_DEVICE_ID_PANABOARD_UBT880 0x104d
> diff --git a/drivers/hid/hid-plantronics.c b/drivers/hid/hid-plantronics.c
> new file mode 100644
> index 0000000..c43440a
> --- /dev/null
> +++ b/drivers/hid/hid-plantronics.c
> @@ -0,0 +1,92 @@
> +/*
> + * Plantronics USB HID Driver
> + *
> + * Copyright (c) 2014 JD Cole <jd.cole@plantronics.com>
> + * Copyright (c) 2014 Terry Junge <terry.junge@plantronics.com>
> + */
> +
> +/*
> + * 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 "hid-ids.h"
> +
> +#include <linux/hid.h>
> +#include <linux/module.h>
> +
> +static bool plt_debug;
> +module_param_named(debug, plt_debug, bool, 0644);
> +MODULE_PARM_DESC(debug, "enables extra debugging info");
Instead of introducing module-specific option can we simply use
dbg_hid() and rely on hid's 'debug' option to activate debug output?
> +
> +static bool plt_passall;
> +module_param_named(passall, plt_passall, bool, 0644);
> +MODULE_PARM_DESC(passall, "force all usages to be accepted (requires debug=1)");
Can't we simply unload the driver if we want to pass all usages?
Thanks.
> +
> +static int plantronics_input_mapping(struct hid_device *hdev,
> + struct hid_input *hi,
> + struct hid_field *field,
> + struct hid_usage *usage,
> + unsigned long **bit, int *max)
> +{
> + if ((field->application == HID_CP_CONSUMERCONTROL
> + && ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER))
> + || (plt_debug && plt_passall)) {
> + if (plt_debug)
> + hid_info(hdev, "usage: %08x (appl: %08x) - defaulted\n",
> + usage->hid, field->application);
> + return 0;
> + }
> +
> + if (plt_debug)
> + hid_info(hdev, "usage: %08x (appl: %08x) - ignored\n",
> + usage->hid, field->application);
> +
> + return -1;
> +}
> +
> +static int plantronics_probe(struct hid_device *hdev,
> + const struct hid_device_id *id)
> +{
> + int ret;
> +
> + if (plt_debug)
> + hid_info(hdev, "found plantronics device\n");
> +
> + ret = hid_parse(hdev);
> + if (ret) {
> + hid_err(hdev, "parse failed\n");
> + goto err;
> + }
> +
> + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
> + if (ret) {
> + hid_err(hdev, "hw start failed\n");
> + goto err;
> + }
> +
> + return 0;
> + err:
> + return ret;
> +}
> +
> +static const struct hid_device_id plantronics_devices[] = {
> + { HID_USB_DEVICE(USB_VENDOR_ID_PLANTRONICS, HID_ANY_ID) },
> + { }
> +};
> +MODULE_DEVICE_TABLE(hid, plantronics_devices);
> +
> +static struct hid_driver plantronics_driver = {
> + .name = "plantronics",
> + .id_table = plantronics_devices,
> + .input_mapping = plantronics_input_mapping,
> + .probe = plantronics_probe,
> +};
> +module_hid_driver(plantronics_driver);
> +
> +MODULE_AUTHOR("JD Cole <jd.cole@plantronics.com>");
> +MODULE_AUTHOR("Terry Junge <terry.junge@plantronics.com>");
> +MODULE_DESCRIPTION("Plantronics USB HID Driver");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index 10c9be6..2806146 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -230,6 +230,9 @@ struct hid_item {
> #define HID_DG_BARRELSWITCH 0x000d0044
> #define HID_DG_ERASER 0x000d0045
> #define HID_DG_TABLETPICK 0x000d0046
> +
> +#define HID_CP_CONSUMERCONTROL 0x000c0001
> +
> /*
> * as of May 20, 2009 the usages below are not yet in the official USB spec
> * but are being pushed by Microsft as described in their paper "Digitizer
> --
> 1.8.3.2
>
> From 6564f0972c5d4e9acba9ebbd8d83cd5a1e95f254 Mon Sep 17 00:00:00 2001
> From: JD Cole <jd.cole@plantronics.com>
> Date: Fri, 17 Oct 2014 15:52:40 -0700
> Subject: [PATCH 2/2] Added missing HID Consumer Page identifiers, for
> completeness.
>
> Adds CA and NAry usage type identifiers.
>
> BUG=chromium:417434
> TEST=Tested with multiple Plantronics devices on 'peppy' Acer C720p.
>
> Change-Id: I7a55880d6082467274b693c48415e9331d9bbd81
> Signed-off-by: JD Cole <jd.cole@plantronics.com>
> ---
> include/linux/hid.h | 24 ++++++++++++++++++++++++
> 1 file changed, 24 insertions(+)
>
> diff --git a/include/linux/hid.h b/include/linux/hid.h
> index 2806146..e923f3d 100644
> --- a/include/linux/hid.h
> +++ b/include/linux/hid.h
> @@ -232,6 +232,30 @@ struct hid_item {
> #define HID_DG_TABLETPICK 0x000d0046
>
> #define HID_CP_CONSUMERCONTROL 0x000c0001
> +#define HID_CP_NUMERICKEYPAD 0x000c0002
> +#define HID_CP_PROGRAMMABLEBUTTONS 0x000c0003
> +#define HID_CP_MICROPHONE 0x000c0004
> +#define HID_CP_HEADPHONE 0x000c0005
> +#define HID_CP_GRAPHICEQUALIZER 0x000c0006
> +#define HID_CP_FUNCTIONBUTTONS 0x000c0036
> +#define HID_CP_SELECTION 0x000c0080
> +#define HID_CP_MEDIASELECTION 0x000c0087
> +#define HID_CP_SELECTDISC 0x000c00ba
> +#define HID_CP_PLAYBACKSPEED 0x000c00f1
> +#define HID_CP_PROXIMITY 0x000c0109
> +#define HID_CP_SPEAKERSYSTEM 0x000c0160
> +#define HID_CP_CHANNELLEFT 0x000c0161
> +#define HID_CP_CHANNELRIGHT 0x000c0162
> +#define HID_CP_CHANNELCENTER 0x000c0163
> +#define HID_CP_CHANNELFRONT 0x000c0164
> +#define HID_CP_CHANNELCENTERFRONT 0x000c0165
> +#define HID_CP_CHANNELSIDE 0x000c0166
> +#define HID_CP_CHANNELSURROUND 0x000c0167
> +#define HID_CP_CHANNELLOWFREQUENCYENHANCEMENT 0x000c0168
> +#define HID_CP_CHANNELTOP 0x000c0169
> +#define HID_CP_CHANNELUNKNOWN 0x000c016a
> +#define HID_CP_APPLICATIONLAUNCHBUTTONS 0x000c0180
> +#define HID_CP_GENERICGUIAPPLICATIONCONTROLS 0x000c0200
>
> /*
> * as of May 20, 2009 the usages below are not yet in the official USB spec
> --
> 1.8.3.2
>
>
>
> ________________________________
>
> CONFIDENTIALITY NOTICE: This e-mail transmission, and any documents, files or previous e-mail messages attached to it, may contain information that is confidential and/or legally privileged. If you are not the intended recipient, or a person responsible for delivering it to the intended recipient, please DO NOT disclose the contents to another person, store or copy the information in any medium, or use any of the information contained in or attached to this transmission for any purpose. If you have received this transmission in error, please immediately notify the sender by reply email or at privacy@plantronics.com, and destroy the original transmission and its attachments without reading or saving in any manner.
>
> For further information about Plantronics - the Company, its products, brands, partners, please visit our website www.plantronics.com.
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Dmitry
^ permalink raw reply
* Re: [PATCH] Input: atkbd - correct MSC_SCAN events for force_release keys
From: Dmitry Torokhov @ 2014-10-23 23:44 UTC (permalink / raw)
To: Stefan Brüns; +Cc: linux-input
In-Reply-To: <2149226.863NAkGi8a@pebbles.site>
On Sat, Oct 18, 2014 at 12:48:59AM +0200, Stefan Brüns wrote:
> On Sunday, September 28, 2014 11:13:24 PM you wrote:
> > Without the change either no scancode would be reported on release
> > of force_release keys, or - if the key is marked as force_release
> > erroneously - the release event and the scancode would be reported
> > in separate reports to the input layer.
> >
> > Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>
> > ---
> > drivers/input/keyboard/atkbd.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
> > index 2dd1d0d..6375ae6 100644
> > --- a/drivers/input/keyboard/atkbd.c
> > +++ b/drivers/input/keyboard/atkbd.c
> > @@ -456,8 +456,9 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
> >
> > keycode = atkbd->keycode[code];
> >
> > - if (keycode != ATKBD_KEY_NULL)
> > - input_event(dev, EV_MSC, MSC_SCAN, code);
> > + if (!(atkbd->release && test_bit(code, atkbd->force_release_mask)))
> > + if (keycode != ATKBD_KEY_NULL)
> > + input_event(dev, EV_MSC, MSC_SCAN, code);
> >
> > switch (keycode) {
> > case ATKBD_KEY_NULL:
> > @@ -511,6 +512,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
> > input_sync(dev);
> >
> > if (value && test_bit(code, atkbd->force_release_mask)) {
> > + input_event(dev, EV_MSC, MSC_SCAN, code);
> > input_report_key(dev, keycode, 0);
> > input_sync(dev);
> > }
> >
>
> Ping!
>
> Kind regards,
I do not see the original patch mail, could you please resend (and CC
me)?
Thanks.
--
Dmitry
--
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
* [PATCH] Alps source code update
From: Masaki Ota @ 2014-10-23 22:21 UTC (permalink / raw)
To: dmitry.torokhov, cernekee, dturvene
Cc: linux-input, ndevos, jclift, 012nexus, Masaki Ota
Signed-off-by: Masaki Ota <masaki.ota@jp.alps.com>
- Support Alps Button-less Touchpad device(Rushmore and SS4). New device type and a data decode logic were added.
---
drivers/input/mouse/alps.c | 1680 +++++++++++++++++++++++++++++++++++---------
drivers/input/mouse/alps.h | 263 ++++++-
2 files changed, 1574 insertions(+), 369 deletions(-)
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index a59a1a6..d4fc568 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -20,6 +20,7 @@
#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/libps2.h>
+#include <linux/kernel.h>
#include "psmouse.h"
#include "alps.h"
@@ -32,6 +33,8 @@
#define ALPS_REG_BASE_RUSHMORE 0xc2c0
#define ALPS_REG_BASE_PINNACLE 0x0000
+#define V7_LARGE_MOVEMENT 130
+
static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
{ PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
{ PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
@@ -99,8 +102,10 @@ 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_IS_RUSHMORE 0x100 /* device is a rushmore */
-#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
+#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
+
+#define DOL_IS_APDATA(_BY) ((_BY[0]&0x01) == 0x01)
+#define DOL_IS_PROFDATA(_BY) ((_BY[0]&0x20) == 0x20)
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 */
@@ -142,6 +147,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,
@@ -283,10 +302,11 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
*
* The bitmaps don't have enough data to track fingers, so this function
* only generates points representing a bounding box of at most two contacts.
- * These two points are returned in fields->mt.
+ * These two points are returned in x1, y1, x2, and y2.
*/
static void alps_process_bitmap_dolphin(struct alps_data *priv,
- struct alps_fields *fields)
+ struct alps_fields *fields,
+ int *x1, int *y1, int *x2, int *y2)
{
int box_middle_x, box_middle_y;
unsigned int x_map, y_map;
@@ -309,6 +329,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
if (x_msb > priv->x_bits || y_msb > priv->y_bits)
return;
+ *x1 = *y1 = *x2 = *y2 = 0;
+
if (fields->fingers > 1) {
start_bit = priv->x_bits - x_msb;
end_bit = priv->x_bits - x_lsb;
@@ -319,35 +341,10 @@ 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));
- fields->mt[0] = fields->st;
- fields->mt[1].x = 2 * box_middle_x - fields->mt[0].x;
- fields->mt[1].y = 2 * box_middle_y - fields->mt[0].y;
- }
-}
-
-static void alps_get_bitmap_points(unsigned int map,
- struct alps_bitmap_point *low,
- struct alps_bitmap_point *high,
- int *fingers)
-{
- struct alps_bitmap_point *point;
- int i, bit, prev_bit = 0;
-
- point = low;
- for (i = 0; map != 0; i++, map >>= 1) {
- bit = map & 1;
- if (bit) {
- if (!prev_bit) {
- point->start_bit = i;
- point->num_bits = 0;
- (*fingers)++;
- }
- point->num_bits++;
- } else {
- if (prev_bit)
- point = high;
- }
- prev_bit = bit;
+ *x1 = fields->pt.x;
+ *y1 = fields->pt.y;
+ *x2 = 2 * box_middle_x - *x1;
+ *y2 = 2 * box_middle_y - *y1;
}
}
@@ -358,21 +355,71 @@ static void alps_get_bitmap_points(unsigned int map,
*
* The bitmaps don't have enough data to track fingers, so this function
* only generates points representing a bounding box of all contacts.
- * These points are returned in fields->mt when the return value
+ * These points are returned in x1, y1, x2, and y2 when the return value
* is greater than 0.
*/
static int alps_process_bitmap(struct alps_data *priv,
- struct alps_fields *fields)
+ unsigned int x_map, unsigned int y_map,
+ int *x1, int *y1, int *x2, int *y2)
{
- int i, fingers_x = 0, fingers_y = 0, fingers;
+ struct alps_bitmap_point {
+ int start_bit;
+ int num_bits;
+ };
+
+ int fingers_x = 0, fingers_y = 0, fingers;
+ int i, bit, prev_bit;
struct alps_bitmap_point x_low = {0,}, x_high = {0,};
struct alps_bitmap_point y_low = {0,}, y_high = {0,};
+ struct alps_bitmap_point *point;
- if (!fields->x_map || !fields->y_map)
+ if (!x_map || !y_map)
return 0;
- alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
- alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
+ *x1 = *y1 = *x2 = *y2 = 0;
+
+ prev_bit = 0;
+ point = &x_low;
+ for (i = 0; x_map != 0; i++, x_map >>= 1) {
+ bit = x_map & 1;
+ if (bit) {
+ if (!prev_bit) {
+ point->start_bit = i;
+ fingers_x++;
+ }
+ point->num_bits++;
+ } else {
+ if (prev_bit)
+ point = &x_high;
+ else
+ point->num_bits = 0;
+ }
+ prev_bit = bit;
+ }
+
+ /*
+ * y bitmap is reversed for what we need (lower positions are in
+ * higher bits), so we process from the top end.
+ */
+ y_map = y_map << (sizeof(y_map) * BITS_PER_BYTE - priv->y_bits);
+ prev_bit = 0;
+ point = &y_low;
+ for (i = 0; y_map != 0; i++, y_map <<= 1) {
+ bit = y_map & (1 << (sizeof(y_map) * BITS_PER_BYTE - 1));
+ if (bit) {
+ if (!prev_bit) {
+ point->start_bit = i;
+ fingers_y++;
+ }
+ point->num_bits++;
+ } else {
+ if (prev_bit)
+ point = &y_high;
+ else
+ point->num_bits = 0;
+ }
+ prev_bit = bit;
+ }
/*
* Fingers can overlap, so we use the maximum count of fingers
@@ -381,89 +428,103 @@ static int alps_process_bitmap(struct alps_data *priv,
fingers = max(fingers_x, fingers_y);
/*
- * If an axis reports only a single contact, we have overlapping or
- * adjacent fingers. Divide the single contact between the two points.
+ * If total fingers is > 1 but either axis reports only a single
+ * contact, we have overlapping or adjacent fingers. For the
+ * purposes of creating a bounding box, divide the single contact
+ * (roughly) equally between the two points.
*/
- if (fingers_x == 1) {
- i = (x_low.num_bits - 1) / 2;
- x_low.num_bits = x_low.num_bits - i;
- x_high.start_bit = x_low.start_bit + i;
- x_high.num_bits = max(i, 1);
- }
- if (fingers_y == 1) {
- i = (y_low.num_bits - 1) / 2;
- y_low.num_bits = y_low.num_bits - i;
- y_high.start_bit = y_low.start_bit + i;
- y_high.num_bits = max(i, 1);
- }
-
- fields->mt[0].x =
- (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
- (2 * (priv->x_bits - 1));
- fields->mt[0].y =
- (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
- (2 * (priv->y_bits - 1));
-
- fields->mt[1].x =
- (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
- (2 * (priv->x_bits - 1));
- fields->mt[1].y =
- (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
- (2 * (priv->y_bits - 1));
-
- /* y-bitmap order is reversed, except on rushmore */
- if (!(priv->flags & ALPS_IS_RUSHMORE)) {
- fields->mt[0].y = priv->y_max - fields->mt[0].y;
- fields->mt[1].y = priv->y_max - fields->mt[1].y;
+ if (fingers > 1) {
+ if (fingers_x == 1) {
+ i = x_low.num_bits / 2;
+ x_low.num_bits = x_low.num_bits - i;
+ x_high.start_bit = x_low.start_bit + i;
+ x_high.num_bits = max(i, 1);
+ } else if (fingers_y == 1) {
+ i = y_low.num_bits / 2;
+ y_low.num_bits = y_low.num_bits - i;
+ y_high.start_bit = y_low.start_bit + i;
+ y_high.num_bits = max(i, 1);
+ }
+ }
+
+ *x1 = (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ *y1 = (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
+
+ if (fingers > 1) {
+ *x2 = (priv->x_max *
+ (2 * x_high.start_bit + x_high.num_bits - 1)) /
+ (2 * (priv->x_bits - 1));
+ *y2 = (priv->y_max *
+ (2 * y_high.start_bit + y_high.num_bits - 1)) /
+ (2 * (priv->y_bits - 1));
}
return fingers;
}
-static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
+static void alps_set_slot(struct input_dev *dev, int slot, bool active,
+ int x, int y)
{
input_mt_slot(dev, slot);
- input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
- input_report_abs(dev, ABS_MT_POSITION_X, x);
- input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, y);
+ }
}
-static void alps_report_mt_data(struct psmouse *psmouse, int n)
+static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
+ int x1, int y1, int x2, int y2)
{
- struct alps_data *priv = psmouse->private;
- struct input_dev *dev = psmouse->dev;
- struct alps_fields *f = &priv->f;
- int i, slot[MAX_TOUCHES];
+ alps_set_slot(dev, 0, num_fingers != 0, x1, y1);
+ alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
+}
- input_mt_assign_slots(dev, slot, f->mt, n);
- for (i = 0; i < n; i++)
- alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
+static void alps_report_semi_mt_data_ex(struct input_dev *dev, int num_fingers,
+ struct alps_abs_data coord[])
+{
+ unsigned char i;
- input_mt_sync_frame(dev);
+ for (i = 0; i < num_fingers; i++) {
+ if (!coord[i].x || !coord[i].y || !coord[i].z)
+ alps_set_slot(dev, i, 0, coord[i].x, coord[i].y);
+ else
+ alps_set_slot(dev, i, 1, coord[i].x, coord[i].y);
+ }
}
-static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
+static void alps_report_coord_and_btn(struct psmouse *psmouse,
+ struct alps_fields *f)
{
- struct alps_data *priv = psmouse->private;
- struct input_dev *dev = psmouse->dev;
- struct alps_fields *f = &priv->f;
+ struct input_dev *dev;
- /* Use st data when we don't have mt data */
- if (fingers < 2) {
- f->mt[0].x = f->st.x;
- f->mt[0].y = f->st.y;
- fingers = f->pressure > 0 ? 1 : 0;
- }
+ if (!psmouse || !f)
+ return;
- alps_report_mt_data(psmouse, (fingers <= 2) ? fingers : 2);
+ dev = psmouse->dev;
- input_mt_report_finger_count(dev, fingers);
+ 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_key(dev, BTN_LEFT, f->left);
- input_report_key(dev, BTN_RIGHT, f->right);
- input_report_key(dev, BTN_MIDDLE, f->middle);
+ 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_abs(dev, ABS_PRESSURE, f->pressure);
+ 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);
input_sync(dev);
}
@@ -530,16 +591,25 @@ 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 int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
+/* proto_v9 */
+static void alps_decode_button_ss3(struct alps_fields *f, unsigned char *p,
+ struct alps_data *priv)
+{
+ if (f->dol_packet_type == DOL_GPDATA ||
+ f->dol_packet_type == DOL_APDATA)
+ f->btn.left = !!(p[3]&0x01);
+}
+
+static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
f->first_mp = !!(p[4] & 0x40);
@@ -553,17 +623,15 @@ static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
((p[2] & 0x7f) << 1) |
(p[4] & 0x01);
- f->st.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->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
- f->pressure = 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);
-
- return 0;
}
-static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
+static void alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
alps_decode_pinnacle(f, p, psmouse);
@@ -573,25 +641,20 @@ static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
f->x_map |= (p[5] & 0x10) << 11;
f->y_map |= (p[5] & 0x20) << 6;
-
- return 0;
}
-static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
+static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse)
{
u64 palm_data = 0;
struct alps_data *priv = psmouse->private;
- f->first_mp = !!(p[0] & 0x02);
- f->is_mp = !!(p[0] & 0x20);
+ f->is_mp = 0;
+ f->first_mp = 0;
- if (!f->is_mp) {
- f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
- f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
- f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
- alps_decode_buttons_v3(f, p);
- } else {
+ if (DOL_IS_PROFDATA(p)) {
+ f->is_mp = 1;
+ f->dol_packet_type = DOL_PROFDATA;
f->fingers = ((p[0] & 0x6) >> 1 |
(p[0] & 0x10) >> 2);
@@ -609,22 +672,415 @@ static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
/* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
f->x_map = (palm_data >> priv->y_bits) &
(BIT(priv->x_bits) - 1);
+ } else {
+ if (DOL_IS_APDATA(p)) {
+ f->dol_packet_type = DOL_APDATA;
+ f->fingers = 2;
+ f->pt_img[0].x = p[1]<<3;
+ f->pt_img[0].y = p[2]<<2;
+ f->pt_img[0].z = 64;
+ f->pt_img[1].x = p[4]<<3;
+ f->pt_img[1].y = p[5]<<2;
+ f->pt_img[1].z = 64;
+ } else {/* is gp data */
+ f->dol_packet_type = DOL_GPDATA;
+ f->first_mp = !!(p[0]&0x02);
+ f->pt.x = f->pt_img[0].x =
+ ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
+ f->pt.y = f->pt_img[0].y =
+ ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
+ f->pt.z = f->pt_img[0].z =
+ min(((p[0] & 0x04) ? 0 : p[5] & 0x7f) * 2, 127);
+
+ /*
+ Button number will be included in
+ the PROFILE data for a 3-f packet.
+ So do not change .fingers because
+ it will be updated in Profile data packet.
+ */
+ if (!f->first_mp)
+ f->fingers = (f->pt_img[0].x &&
+ f->pt_img[0].y && f->pt_img[0].z)?1:0;
+ }
+
+ if (priv->proto_version == ALPS_PROTO_V9)
+ alps_decode_button_ss3(f, p, priv);
+ else
+ alps_decode_buttons_v3(f, p);
}
+}
- return 0;
+unsigned char alps_get_pkt_id_ss4_v1(char *byte)
+{
+ unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+
+ if (((byte[0] & 0xFF) == 0x08) && ((byte[1] & 0xFF) == 0x10) &&
+ ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x8F) == 0x08) &&
+ ((byte[4] & 0xFF) == 0x01) && ((byte[5] & 0xFF) == 0x00)) {
+ pkt_id = SS4_PACKET_ID_IDLE;
+ } else if (((byte[0] & 0x08) == 0x08) && ((byte[1] & 0x10) == 0x10) &&
+ ((byte[3] & 0x8E) == 0x08) && ((byte[4] & 0x81) == 0x01)) {
+ pkt_id = SS4_PACKET_ID_ONE;
+ } else if (((byte[0] & 0x08) == 0x08) && ((byte[3] & 0x08) == 0x08) &&
+ ((byte[4] & 0x01) == 0x01)) {
+ if (((byte[5] & 0x01) == 0x01))
+ pkt_id = SS4_PACKET_ID_TWO;
+ else
+ pkt_id = SS4_PACKET_ID_MULTI;
+ }
+
+ return pkt_id;
+}
+
+unsigned char alps_get_pkt_id_ss4_v2(char *byte)
+{
+ unsigned char pkt_id = SS4_PACKET_ID_IDLE;
+
+ if (((byte[0] & 0xFF) == 0x18) && ((byte[1] & 0xFF) == 0x10) &&
+ ((byte[2] & 0xFF) == 0x00) && ((byte[3] & 0x88) == 0x08) &&
+ ((byte[4] & 0xFF) == 0x10) && ((byte[5] & 0xFF) == 0x00)) {
+ pkt_id = SS4_PACKET_ID_IDLE;
+ } else if (!(byte[3] & 0x10)) {
+ pkt_id = SS4_PACKET_ID_ONE;
+ } else {
+ if (!(byte[3] & 0x20))
+ pkt_id = SS4_PACKET_ID_TWO;
+ else
+ pkt_id = SS4_PACKET_ID_MULTI;
+ }
+
+ return pkt_id;
+}
+
+static void alps_process_btnless_click(struct psmouse *psmouse,
+ struct alps_fields *f)
+{
+ struct alps_data *priv = psmouse->private;
+
+ if (!f->btn.left)
+ return;
+
+ /* Clear button flag */
+ f->btn.left = 0;
+
+ switch (f->fingers) {
+ case 1:
+ /* In Left Resting Area */
+ if (PT_IN_LEFT_BTN_AREA(f->pt_img[0].x,
+ f->pt_img[0].y, priv->x_max, priv->y_max)) {
+ f->btn.left = 1;
+ } else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
+ f->pt_img[0].y, priv->x_max, priv->y_max)) {
+ /* In Right Resting Area */
+ f->btn.right = 1;
+ } else {
+ /* In Normal area */
+ f->btn.left = 1;
+ }
+ break;
+
+ case 2:
+ /* Both two fingers are in Normal area */
+ if (!PT_IN_BTN_AREA(f->pt_img[0].x,
+ f->pt_img[0].y, priv->x_max, priv->y_max) &&
+ !PT_IN_BTN_AREA(f->pt_img[1].x,
+ f->pt_img[1].y, priv->x_max, priv->y_max)) {
+ f->btn.right = 1;
+ } else if (PT_IN_RIGHT_BTN_AREA(f->pt_img[0].x,
+ f->pt_img[0].y, priv->x_max, priv->y_max) ||
+ PT_IN_RIGHT_BTN_AREA(f->pt_img[1].x,
+ f->pt_img[1].y, priv->x_max, priv->y_max)) {
+ /* Either one finger is in Right Area */
+ f->btn.right = 1;
+ } else {
+ f->btn.left = 1;
+ }
+ break;
+
+ case 3:
+ f->btn.middle = 1;
+ break;
+
+ case 0:
+ default:
+ break;
+ }
+}
+
+static void alps_process_resting_finger(struct psmouse *psmouse,
+ struct alps_fields *f, struct alps_abs_data *output,
+ unsigned char *p_fn)
+{
+ struct alps_data *priv = psmouse->private;
+ static struct alps_abs_data prev_pt[10];
+ static struct alps_abs_data init_pt[10];
+ static unsigned char is_moved[10];
+ static unsigned char prev_fn;
+ static unsigned char prev_coord_is_output[10];
+ unsigned char cur_coord_is_output[10];
+ unsigned char in_resting_area[10];
+ unsigned char i, index;
+ unsigned char output_fn = 0;
+
+ memset(in_resting_area, 0, sizeof(in_resting_area));
+ memset(cur_coord_is_output, 0, sizeof(cur_coord_is_output));
+
+ /* Clear "is_moved" flag when finger number changed */
+ if (f->fingers != prev_fn) {
+ memset(is_moved, 0, sizeof(is_moved));
+ memcpy(init_pt, f->pt_img, sizeof(f->pt_img));
+ }
+
+ /* Calculate output finger */
+ for (i = 0, index = 0; i < f->fingers; i++) {
+ if (is_moved[i] == 0 &&
+ (abs(f->pt_img[i].x - init_pt[i].x)
+ > RESTING_FN_LARGE_MOVEMENT)) {
+ is_moved[i] = 1;
+ }
+
+ /* Check if in resting area */
+ if (PT_IN_BTN_AREA(f->pt_img[i].x,
+ f->pt_img[i].y, priv->x_max, priv->y_max))
+ in_resting_area[i] = 1;
+
+ if (!in_resting_area[i] ||
+ (in_resting_area[i] && is_moved[i])) {
+ memcpy(&output[index++], &f->pt_img[i],
+ sizeof(struct alps_abs_data));
+ cur_coord_is_output[i] = 1;
+ output_fn++;
+ }
+ }
+
+ /* A normal finger becomes a resting finger */
+ for (i = 0; i < f->fingers; i++) {
+ if (prev_coord_is_output[i] &&
+ !cur_coord_is_output[i] && f->pt_img[i].z) {
+ output_fn = 0;
+ memset(output, 0,
+ sizeof(struct alps_abs_data)*f->fingers);
+ }
+ }
+
+ memcpy(prev_pt, f->pt_img, sizeof(f->pt_img));
+ memcpy(prev_coord_is_output, cur_coord_is_output,
+ sizeof(cur_coord_is_output));
+ prev_fn = f->fingers;
+ *p_fn = output_fn;
+}
+
+static void alps_decode_ss4_v1(struct alps_fields *f,
+ unsigned char *p, struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char pkt_id;
+ unsigned int no_data_x, no_data_y;
+
+ if (!psmouse || !f || !p)
+ return;
+
+ pkt_id = alps_get_pkt_id_ss4_v1(p);
+
+ /* Current packet is 1Finger coordinate packet */
+ switch (pkt_id) {
+ case SS4_PACKET_ID_ONE:
+ f->pt_img[0].x = SS4_1F_X_V1(p);
+ f->pt_img[0].y = SS4_1F_Y_V1(p);
+ /* Keep Z-value in 0-127 */
+ f->pt_img[0].z = min(((SS4_1F_Z_V1(p)) * 2), 127);
+ f->large_fn |= SS4_1F_LFB(p) ? 0x01 : 0x00;
+ f->fingers = 1;
+ f->first_mp = 0;
+ f->is_mp = 0;
+ break;
+
+ case SS4_PACKET_ID_TWO:
+ if (priv->flags & ALPS_BTNLESS) {
+ f->pt_img[0].x = SS4_BTL_MF_X_V1(p, 0);
+ f->pt_img[0].y = SS4_BTL_MF_Y_V1(p, 0);
+ f->pt_img[1].x = SS4_BTL_MF_X_V1(p, 1);
+ f->pt_img[1].y = SS4_BTL_MF_Y_V1(p, 1);
+ } else {
+ f->pt_img[0].x = SS4_STD_MF_X_V1(p, 0);
+ f->pt_img[0].y = SS4_STD_MF_Y_V1(p, 0);
+ f->pt_img[1].x = SS4_STD_MF_X_V1(p, 1);
+ f->pt_img[1].y = SS4_STD_MF_Y_V1(p, 1);
+ }
+ f->pt_img[0].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
+ f->pt_img[1].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
+
+ if (SS4_IS_MF_CONTINUE_V1(p)) {
+ f->first_mp = 1;
+ } else {
+ f->fingers = 2;
+ f->first_mp = 0;
+ }
+ f->is_mp = 0;
+
+ break;
+
+ case SS4_PACKET_ID_MULTI:
+ if (priv->flags & ALPS_BTNLESS) {
+ f->pt_img[2].x = SS4_BTL_MF_X_V1(p, 0);
+ f->pt_img[2].y = SS4_BTL_MF_Y_V1(p, 0);
+ f->pt_img[3].x = SS4_BTL_MF_X_V1(p, 1);
+ f->pt_img[3].y = SS4_BTL_MF_Y_V1(p, 1);
+ no_data_x = SS4_MFPACKET_NO_AX_BL;
+ no_data_y = SS4_MFPACKET_NO_AY_BL;
+ } else {
+ f->pt_img[2].x = SS4_STD_MF_X_V1(p, 0);
+ f->pt_img[2].y = SS4_STD_MF_Y_V1(p, 0);
+ f->pt_img[3].x = SS4_STD_MF_X_V1(p, 1);
+ f->pt_img[3].y = SS4_STD_MF_Y_V1(p, 1);
+ no_data_x = SS4_MFPACKET_NO_AX;
+ no_data_y = SS4_MFPACKET_NO_AY;
+ }
+ f->pt_img[2].z = SS4_MF_Z_V1(p, 0) ? 0x30 : 0;
+ f->pt_img[3].z = SS4_MF_Z_V1(p, 1) ? 0x30 : 0;
+
+ f->first_mp = 0;
+ f->is_mp = 1;
+
+ if (SS4_IS_5F_DETECTED_V1(p)) {
+ f->fingers = 5;
+ } else if (f->pt_img[3].x == no_data_x &&
+ f->pt_img[3].y == no_data_y) {
+ f->fingers = 3;
+ f->pt_img[3].x = 0;
+ f->pt_img[3].y = 0;
+ f->pt_img[3].z = 0;
+ } else {
+ f->fingers = 4;
+ }
+ break;
+
+ case SS4_PACKET_ID_IDLE:
+ default:
+ memset(f, 0, sizeof(struct alps_fields));
+ break;
+ }
+
+ f->btn.left = !!(SS4_BTN_V1(p) & 0x01);
+ if (!(priv->flags & ALPS_BTNLESS)) {
+ f->btn.right = !!(SS4_BTN_V1(p) & 0x02);
+ f->btn.middle = !!(SS4_BTN_V1(p) & 0x04);
+ }
+}
+
+static void alps_decode_ss4_v2(struct alps_fields *f,
+ unsigned char *p, struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char pkt_id;
+ unsigned int no_data_x, no_data_y;
+
+ if (!psmouse || !f || !p)
+ return;
+
+ pkt_id = alps_get_pkt_id_ss4_v2(p);
+
+ /* Current packet is 1Finger coordinate packet */
+ switch (pkt_id) {
+ case SS4_PACKET_ID_ONE:
+ f->pt_img[0].x = SS4_1F_X_V2(p);
+ f->pt_img[0].y = SS4_1F_Y_V2(p);
+ /* Keep Z-value in 0-127 */
+ f->pt_img[0].z = min(((SS4_1F_Z_V2(p)) * 2), 127);
+ f->large_fn |= SS4_1F_LFB_V2(p) ? 0x01 : 0x00;
+ f->fingers = 1;
+ f->first_mp = 0;
+ f->is_mp = 0;
+ break;
+
+ case SS4_PACKET_ID_TWO:
+ if (priv->flags & ALPS_BTNLESS) {
+ f->pt_img[0].x = SS4_BTL_MF_X_V2(p, 0);
+ f->pt_img[0].y = SS4_BTL_MF_Y_V2(p, 0);
+ f->pt_img[1].x = SS4_BTL_MF_X_V2(p, 1);
+ f->pt_img[1].y = SS4_BTL_MF_Y_V2(p, 1);
+ } else {
+ f->pt_img[0].x = SS4_STD_MF_X_V2(p, 0);
+ f->pt_img[0].y = SS4_STD_MF_Y_V2(p, 0);
+ f->pt_img[1].x = SS4_STD_MF_X_V2(p, 1);
+ f->pt_img[1].y = SS4_STD_MF_Y_V2(p, 1);
+ }
+ f->pt_img[0].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
+ f->pt_img[1].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
+
+ f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x01 : 0;
+ f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x02 : 0;
+
+ if (SS4_IS_MF_CONTINUE_V2(p)) {
+ f->first_mp = 1;
+ } else {
+ f->fingers = 2;
+ f->first_mp = 0;
+ }
+ f->is_mp = 0;
+ break;
+
+ case SS4_PACKET_ID_MULTI:
+ if (priv->flags & ALPS_BTNLESS) {
+ f->pt_img[2].x = SS4_BTL_MF_X_V2(p, 0);
+ f->pt_img[2].y = SS4_BTL_MF_Y_V2(p, 0);
+ f->pt_img[3].x = SS4_BTL_MF_X_V2(p, 1);
+ f->pt_img[3].y = SS4_BTL_MF_Y_V2(p, 1);
+ no_data_x = SS4_MFPACKET_NO_AX_BL;
+ no_data_y = SS4_MFPACKET_NO_AY_BL;
+ } else {
+ f->pt_img[2].x = SS4_STD_MF_X_V2(p, 0);
+ f->pt_img[2].y = SS4_STD_MF_Y_V2(p, 0);
+ f->pt_img[3].x = SS4_STD_MF_X_V2(p, 1);
+ f->pt_img[3].y = SS4_STD_MF_Y_V2(p, 1);
+ no_data_x = SS4_MFPACKET_NO_AX;
+ no_data_y = SS4_MFPACKET_NO_AY;
+ }
+ f->pt_img[2].z = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
+ f->pt_img[3].z = SS4_MF_Z_V2(p, 1) ? 0x30 : 0;
+
+ f->large_fn |= SS4_MF_LF_V2(p, 0) ? 0x04 : 0;
+ f->large_fn |= SS4_MF_LF_V2(p, 1) ? 0x08 : 0;
+ f->first_mp = 0;
+ f->is_mp = 1;
+
+ if (SS4_IS_5F_DETECTED_V2(p)) {
+ f->fingers = 5;
+ } else if (f->pt_img[3].x == no_data_x &&
+ f->pt_img[3].y == no_data_y) {
+ f->fingers = 3;
+ f->pt_img[3].x = 0;
+ f->pt_img[3].y = 0;
+ f->pt_img[3].z = 0;
+ } else {
+ f->fingers = 4;
+ }
+ break;
+
+ case SS4_PACKET_ID_IDLE:
+ default:
+ memset(f, 0, sizeof(struct alps_fields));
+ break;
+ }
+
+ f->btn.left = !!(SS4_BTN_V2(p) & 0x01);
+ if (!(priv->flags & ALPS_BTNLESS)) {
+ f->btn.right = !!(SS4_BTN_V2(p) & 0x02);
+ f->btn.middle = !!(SS4_BTN_V2(p) & 0x04);
+ }
}
static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
struct input_dev *dev2 = priv->dev2;
- struct alps_fields *f = &priv->f;
- int fingers = 0;
+ int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
+ int fingers = 0, bmap_fn;
+ struct alps_fields f = {0};
- memset(f, 0, sizeof(*f));
-
- priv->decode_fields(f, packet, psmouse);
+ priv->decode_fields(&f, packet, psmouse);
/*
* There's no single feature of touchpad position and bitmap packets
@@ -639,14 +1095,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* packet. Check for this, and when it happens process the
* position packet as usual.
*/
- if (f->is_mp) {
- fingers = f->fingers;
+ if (f.is_mp) {
+ fingers = f.fingers;
if (priv->proto_version == ALPS_PROTO_V3) {
- if (alps_process_bitmap(priv, f) == 0)
- fingers = 0; /* Use st data */
+ bmap_fn = alps_process_bitmap(priv, f.x_map,
+ f.y_map, &x1, &y1,
+ &x2, &y2);
+
+ /*
+ * We shouldn't report more than one finger if
+ * we don't have two coordinates.
+ */
+ if (fingers > 1 && bmap_fn < 2)
+ fingers = bmap_fn;
/* Now process position packet */
- priv->decode_fields(f, priv->multi_data,
+ priv->decode_fields(&f, priv->multi_data,
psmouse);
} else {
/*
@@ -655,14 +1119,15 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* calculate Pt2, so we need to do position
* packet decode first.
*/
- priv->decode_fields(f, priv->multi_data,
+ priv->decode_fields(&f, priv->multi_data,
psmouse);
/*
* Since Dolphin's finger number is reliable,
* there is no need to compare with bmap_fn.
*/
- alps_process_bitmap_dolphin(priv, f);
+ alps_process_bitmap_dolphin(priv, &f, &x1, &y1,
+ &x2, &y2);
}
} else {
priv->multi_packet = 0;
@@ -677,10 +1142,10 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
* out misidentified bitmap packets, we reject anything with this
* bit set.
*/
- if (f->is_mp)
+ if (f.is_mp)
return;
- if (!priv->multi_packet && f->first_mp) {
+ if (!priv->multi_packet && f.first_mp) {
priv->multi_packet = 1;
memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
return;
@@ -694,15 +1159,44 @@ 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->st.x && f->st.y && !f->pressure)
+ if (f.pt.x && f.pt.y && !f.pt.z)
return;
- alps_report_semi_mt_data(psmouse, fingers);
+ /*
+ * If we don't have MT data or the bitmaps were empty, we have
+ * to rely on ST data.
+ */
+ if (!fingers) {
+ x1 = f.pt.x;
+ y1 = f.pt.y;
+ fingers = f.pt.z > 0 ? 1 : 0;
+ }
+
+ if (f.pt.z > 0)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_mt_report_finger_count(dev, fingers);
+
+ 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.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);
}
}
@@ -727,6 +1221,64 @@ static void alps_process_packet_v3(struct psmouse *psmouse)
alps_process_touchpad_packet_v3_v5(psmouse);
}
+/* proto_v9 */
+static void alps_process_touchpad_packet_ss3(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ int fingers = 0;
+ struct alps_fields f = {0};
+ struct alps_abs_data pt_output[2] = { {0, 0, 0}, {0, 0, 0} };
+ unsigned char output_fn_num = 0;
+
+ priv->decode_fields(&f, packet, psmouse);
+
+ if ((!!priv->multi_packet) != (!!f.is_mp)) {
+ priv->multi_packet = 0;
+ return;
+ }
+
+ /* When f.first_mp is 1, next packet should be a
+ * bitmap packet(when there is no error).
+ */
+ priv->multi_packet = f.first_mp;
+
+ /* Don't process any 3-f data */
+ if (f.first_mp || f.is_mp)
+ return;
+
+ /*
+ * If we don't have MT data or the bitmaps were empty, we have
+ * to rely on ST data.
+ */
+ fingers = f.fingers;
+
+ alps_process_resting_finger(psmouse, &f, pt_output, &output_fn_num);
+ alps_process_btnless_click(psmouse, &f);
+
+ if (pt_output[0].z || pt_output[1].z)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ alps_report_semi_mt_data_ex(dev, 2, pt_output);
+
+ input_mt_report_finger_count(dev, output_fn_num);
+
+ 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 (pt_output[0].z > 0) {
+ input_report_abs(dev, ABS_X, pt_output[0].x);
+ input_report_abs(dev, ABS_Y, pt_output[0].y);
+ }
+ input_report_abs(dev, ABS_PRESSURE, pt_output[0].z ? 30 : 0);
+
+ input_sync(dev);
+}
+
static void alps_process_packet_v6(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
@@ -801,8 +1353,13 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
unsigned char *packet = psmouse->packet;
- struct alps_fields *f = &priv->f;
+ struct input_dev *dev = psmouse->dev;
int offset;
+ int x, y, z;
+ int left, right;
+ int x1, y1, x2, y2;
+ int fingers = 0;
+ unsigned int x_bitmap, y_bitmap;
/*
* v4 has a 6-byte encoding for bitmap data, but this data is
@@ -824,41 +1381,96 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
if (++priv->multi_packet > 2) {
priv->multi_packet = 0;
- f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
+ x_bitmap = ((priv->multi_data[2] & 0x1f) << 10) |
((priv->multi_data[3] & 0x60) << 3) |
((priv->multi_data[0] & 0x3f) << 2) |
((priv->multi_data[1] & 0x60) >> 5);
- f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
+ y_bitmap = ((priv->multi_data[5] & 0x01) << 10) |
((priv->multi_data[3] & 0x1f) << 5) |
(priv->multi_data[1] & 0x1f);
- f->fingers = alps_process_bitmap(priv, f);
+ fingers = alps_process_bitmap(priv, x_bitmap, y_bitmap,
+ &x1, &y1, &x2, &y2);
+
+ /* Store MT data.*/
+ priv->fingers = fingers;
+ priv->x1 = x1;
+ priv->x2 = x2;
+ priv->y1 = y1;
+ priv->y2 = y2;
}
- f->left = packet[4] & 0x01;
- f->right = packet[4] & 0x02;
+ left = packet[4] & 0x01;
+ right = packet[4] & 0x02;
+
+ x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
+ ((packet[0] & 0x30) >> 4);
+ y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
+ z = packet[5] & 0x7f;
+
+ /*
+ * If there were no contacts in the bitmap, use ST
+ * points in MT reports.
+ * If there were two contacts or more, report MT data.
+ */
+ if (priv->fingers < 2) {
+ x1 = x;
+ y1 = y;
+ fingers = z > 0 ? 1 : 0;
+ } else {
+ fingers = priv->fingers;
+ x1 = priv->x1;
+ x2 = priv->x2;
+ y1 = priv->y1;
+ y2 = priv->y2;
+ }
+
+ if (z >= 64)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ alps_report_semi_mt_data(dev, fingers, x1, y1, x2, y2);
+
+ input_mt_report_finger_count(dev, fingers);
+
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_RIGHT, right);
- f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
- ((packet[0] & 0x30) >> 4);
- f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
- f->pressure = packet[5] & 0x7f;
+ if (z > 0) {
+ input_report_abs(dev, ABS_X, x);
+ input_report_abs(dev, ABS_Y, y);
+ }
+ input_report_abs(dev, ABS_PRESSURE, z);
- alps_report_semi_mt_data(psmouse, f->fingers);
+ input_sync(dev);
}
static bool alps_is_valid_package_v7(struct psmouse *psmouse)
{
- switch (psmouse->pktcnt) {
- case 3:
- return (psmouse->packet[2] & 0x40) == 0x40;
- case 4:
- return (psmouse->packet[3] & 0x48) == 0x48;
- case 6:
- return (psmouse->packet[5] & 0x40) == 0x00;
- }
+ 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;
@@ -874,85 +1486,251 @@ static unsigned char alps_get_packet_id_v7(char *byte)
else
packet_id = V7_PACKET_ID_UNKNOWN;
- return packet_id;
+ 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;
+
+ 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;
+ memset(&f->btn, 0, sizeof(struct alps_btn));
+
+ if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
+ priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
+
+ if (priv->flags & ALPS_BTNLESS) {
+ priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
+ priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
+ f->btn.middle = (p[0] & 0x80) >> 7;
+ } else {
+ f->btn.left = (p[0] & 0x80) >> 7;
+ f->btn.right = (p[0] & 0x20) >> 5;
+ f->btn.middle = (p[0] & 0x10) >> 4;
+ }
+ }
+
+ if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
+ priv->r.v7.additional_fingers = p[5] & 0x03;
}
-static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
- unsigned char *pkt,
- unsigned char pkt_id)
+static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
+ struct alps_abs_data *pt,
+ struct alps_bl_pt_attr *pt_attr)
{
- mt[0].x = ((pkt[2] & 0x80) << 4);
- mt[0].x |= ((pkt[2] & 0x3F) << 5);
- mt[0].x |= ((pkt[3] & 0x30) >> 1);
- mt[0].x |= (pkt[3] & 0x07);
- mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
+ struct alps_data *priv = psmouse->private;
+ unsigned int dist;
- mt[1].x = ((pkt[3] & 0x80) << 4);
- mt[1].x |= ((pkt[4] & 0x80) << 3);
- mt[1].x |= ((pkt[4] & 0x3F) << 4);
- mt[1].y = ((pkt[5] & 0x80) << 3);
- mt[1].y |= ((pkt[5] & 0x3F) << 4);
+ 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));
+ }
- switch (pkt_id) {
- case V7_PACKET_ID_TWO:
- mt[1].x &= ~0x000F;
- mt[1].y |= 0x000F;
- break;
+ 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;
+ }
+ }
+ }
+}
- case V7_PACKET_ID_MULTI:
- mt[1].x &= ~0x003F;
- mt[1].y &= ~0x0020;
- mt[1].y |= ((pkt[4] & 0x02) << 4);
- mt[1].y |= 0x001F;
- break;
+static void alps_set_pt_attr_v7(struct psmouse *psmouse,
+ struct alps_fields *f)
+{
+ struct alps_data *priv = psmouse->private;
+ int i;
- case V7_PACKET_ID_NEW:
- mt[1].x &= ~0x003F;
- mt[1].x |= (pkt[0] & 0x20);
- mt[1].y |= 0x000F;
+ 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]) * V7_IMG_PT_NUM);
break;
}
-
- mt[0].y = 0x7FF - mt[0].y;
- mt[1].y = 0x7FF - mt[1].y;
}
-static int alps_get_mt_count(struct input_mt_pos *mt)
+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;
- for (i = 0; i < MAX_TOUCHES && mt[i].x != 0 && mt[i].y != 0; i++)
- /* empty */;
+ 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;
+ }
- return i;
+ f->fingers = fn;
}
-static int alps_decode_packet_v7(struct alps_fields *f,
- unsigned char *p,
- struct psmouse *psmouse)
+static void alps_assign_buttons_v7(struct psmouse *psmouse,
+ struct alps_fields *f)
{
- unsigned char pkt_id;
+ struct alps_data *priv = psmouse->private;
- pkt_id = alps_get_packet_id_v7(p);
- if (pkt_id == V7_PACKET_ID_IDLE)
- return 0;
- if (pkt_id == V7_PACKET_ID_UNKNOWN)
- return -1;
+ /* It's ClickPad */
+ if (priv->flags & ALPS_BTNLESS) {
+ if (!f->btn.middle)
+ goto exit;
+
+ f->btn.middle = 0;
+ if (priv->prev_btn.left || priv->prev_btn.middle ||
+ priv->prev_btn.right) {
+ memcpy(&f->btn, &priv->prev_btn,
+ sizeof(struct alps_btn));
+ goto exit;
+ }
- alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
+ 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;
+ } else {
+ f->btn.left = 1;
+ }
- if (pkt_id == V7_PACKET_ID_TWO || pkt_id == V7_PACKET_ID_MULTI) {
- f->left = (p[0] & 0x80) >> 7;
- f->right = (p[0] & 0x20) >> 5;
- f->middle = (p[0] & 0x10) >> 4;
+ goto exit;
}
- if (pkt_id == V7_PACKET_ID_TWO)
- f->fingers = alps_get_mt_count(f->mt);
- else if (pkt_id == V7_PACKET_ID_MULTI)
- f->fingers = 3 + (p[5] & 0x03);
+ /* It's Standard, do nothing */
- return 0;
+exit:
+ memcpy(&priv->prev_btn, &f->btn, sizeof(struct alps_btn));
}
static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
@@ -962,21 +1740,9 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
struct input_dev *dev2 = priv->dev2;
int x, y, z, left, right, middle;
- /*
- * b7 b6 b5 b4 b3 b2 b1 b0
- * Byte0 0 1 0 0 1 0 0 0
- * Byte1 1 1 * * 1 M R L
- * Byte2 X7 1 X5 X4 X3 X2 X1 X0
- * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
- * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
- * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
- * M / R / L: Middle / Right / Left button
- */
-
- x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
- y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
- ((packet[3] & 0x20) << 1);
- z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
+ x = ((packet[2] & 0xBF)) | ((packet[3] & 0x10) << 2);
+ y = (packet[3] & 0x03) | (packet[4] & 0xB8) | ((packet[3] & 0x20) << 1);
+ z = (packet[5] & 0x3F) | ((packet[3] & 0x80) >> 1);
left = (packet[1] & 0x01);
right = (packet[1] & 0x02) >> 1;
@@ -996,35 +1762,115 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- struct input_dev *dev = psmouse->dev;
- struct alps_fields *f = &priv->f;
+ struct alps_fields f = {0};
+ unsigned char *packet = psmouse->packet;
- memset(f, 0, sizeof(*f));
+ priv->decode_fields(&f, packet, psmouse);
- if (priv->decode_fields(f, psmouse->packet, psmouse))
+ if (alps_drop_unsupported_packet_v7(psmouse))
return;
- alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
+ alps_set_pt_attr_v7(psmouse, &f);
- input_mt_report_finger_count(dev, f->fingers);
+ alps_cal_output_finger_num_v7(psmouse, &f);
- input_report_key(dev, BTN_LEFT, f->left);
- input_report_key(dev, BTN_RIGHT, f->right);
- input_report_key(dev, BTN_MIDDLE, f->middle);
+ alps_assign_buttons_v7(psmouse, &f);
- input_sync(dev);
+ alps_report_coord_and_btn(psmouse, &f);
}
static void alps_process_packet_v7(struct psmouse *psmouse)
{
unsigned char *packet = psmouse->packet;
- if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
+ if ((packet[0] == 0x48) && ((packet[4] & 0x47) == 0x06))
alps_process_trackstick_packet_v7(psmouse);
else
alps_process_touchpad_packet_v7(psmouse);
}
+static void alps_process_packet_ss4(struct psmouse *psmouse)
+{
+ struct alps_data *priv = psmouse->private;
+ unsigned char *packet = psmouse->packet;
+ struct input_dev *dev = psmouse->dev;
+ struct alps_fields f;
+ struct alps_abs_data output_data[5];
+ unsigned char output_fn;
+
+ memset(&f, 0, sizeof(struct alps_fields));
+ priv->decode_fields(&f, packet, psmouse);
+
+ if (priv->multi_packet) {
+ /*
+ * Sometimes the first packet will indicate a multi-packet
+ * sequence, but sometimes the next multi-packet would not come.
+ * Check for this, and when it happens process the
+ * position packet as usual.
+ */
+ if (f.is_mp) {
+ /* Now process the 1st packet */
+ priv->decode_fields(&f, priv->multi_data, psmouse);
+ } else {
+ priv->multi_packet = 0;
+ }
+ }
+
+ /*
+ * "f.is_mp" would always be '0' after merging the 1st and 2nd packet.
+ * When it is set, it means 2nd packet comes without 1st packet come.
+ */
+ if (f.is_mp)
+ return;
+
+ /* Save the first packet */
+ if (!priv->multi_packet && f.first_mp) {
+ priv->multi_packet = 1;
+ memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
+ return;
+ }
+
+ priv->multi_packet = 0;
+
+ /* Set "output_data" and "output_fn" */
+ memset(&output_data[0], 0, sizeof(output_data));
+ if (priv->flags & ALPS_BTNLESS) {
+ alps_process_resting_finger(psmouse, &f,
+ output_data, &output_fn);
+ alps_process_btnless_click(psmouse, &f);
+ } else {
+ memcpy(&output_data[0], &f.pt_img[0],
+ sizeof(struct alps_abs_data) * f.fingers);
+ output_fn = f.fingers;
+ }
+
+ f.pt.x = output_data[0].x;
+ f.pt.y = output_data[0].y;
+ f.pt.z = output_data[0].z;
+
+ if (output_data[0].z || output_data[1].z ||
+ output_data[2].z || output_data[3].z)
+ input_report_key(dev, BTN_TOUCH, 1);
+ else
+ input_report_key(dev, BTN_TOUCH, 0);
+
+ alps_report_semi_mt_data_ex(dev, 4, output_data);
+
+ input_mt_report_finger_count(dev, output_fn);
+
+ 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.pt.z);
+
+ input_sync(dev);
+}
+
static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
unsigned char packet[],
bool report_buttons)
@@ -1152,11 +1998,22 @@ static void alps_flush_packet(unsigned long data)
serio_continue_rx(psmouse->ps2dev.serio);
}
+static bool alps_is_valid_package_ss4(struct psmouse *psmouse)
+{
+ if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08))
+ return false;
+ if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0))
+ return false;
+ return true;
+}
+
static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
- if ((psmouse->packet[0] & 0xc8) == 0x08) { /* PS/2 packet */
+ /* Can not distinguish V8's first byte from PS/2 packet's */
+ if ((psmouse->packet[0] & 0xc8) == 0x08 &&
+ priv->proto_version != ALPS_PROTO_V8) {
if (psmouse->pktcnt == 3) {
alps_report_bare_ps2_packet(psmouse, psmouse->packet,
true);
@@ -1189,8 +2046,10 @@ 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)) {
+ if ((priv->proto_version == ALPS_PROTO_V7 &&
+ !alps_is_valid_package_v7(psmouse)) ||
+ (priv->proto_version == ALPS_PROTO_V8 &&
+ !alps_is_valid_package_ss4(psmouse))) {
psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
psmouse->pktcnt - 1,
psmouse->packet[psmouse->pktcnt - 1]);
@@ -1309,20 +2168,20 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
return 0;
}
-static bool alps_check_valid_firmware_id(unsigned char id[])
+static int alps_check_valid_firmware_id(unsigned char id[])
{
- if (id[0] == 0x73)
- return true;
+ int valid = 1;
- if (id[0] == 0x88 &&
- (id[1] == 0x07 ||
- id[1] == 0x08 ||
- (id[1] & 0xf0) == 0xb0 ||
- (id[1] & 0xf0) == 0xc0)) {
- return true;
+ 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 false;
+ return valid;
}
static int alps_enter_command_mode(struct psmouse *psmouse)
@@ -1792,45 +2651,6 @@ error:
return -1;
}
-static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
-{
- int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
- struct alps_data *priv = psmouse->private;
-
- reg = alps_command_mode_read_reg(psmouse, reg_pitch);
- if (reg < 0)
- return reg;
-
- x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
- x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
-
- y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
- y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
-
- reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
- if (reg < 0)
- return reg;
-
- x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
- x_electrode = 17 + x_electrode;
-
- y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
- y_electrode = 13 + y_electrode;
-
- x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
- y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
-
- priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
- priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
-
- psmouse_dbg(psmouse,
- "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
- x_pitch, y_pitch, x_electrode, y_electrode,
- x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
-
- return 0;
-}
-
static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
{
struct alps_data *priv = psmouse->private;
@@ -1851,9 +2671,6 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
goto error;
- if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
- goto error;
-
reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
if (reg_val == -1)
goto error;
@@ -1878,6 +2695,32 @@ 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) ||
+ alps_command_mode_read_reg(psmouse, 0xc2d9) == -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)
{
@@ -1967,6 +2810,102 @@ error:
return -1;
}
+static int alps_get_otp_values_ss4(struct psmouse *psmouse,
+ unsigned char index, unsigned char otp[])
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+
+ switch (index) {
+ case 0:
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ break;
+
+ case 1:
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
+ ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
+ return -1;
+
+ break;
+ }
+
+ return 0;
+}
+
+int alps_update_device_area_ss4_v1(
+ unsigned char otp[][4], struct alps_data *priv)
+{
+ int num_x_electrode;
+ int num_y_electrode;
+
+ num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+ num_y_electrode = ((otp[1][0] >> 4) & 0x0F);
+
+ priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+ priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+ return 0;
+}
+
+int alps_update_device_area_ss4_v2(
+ unsigned char otp[][4], struct alps_data *priv)
+{
+ int num_x_electrode;
+ int num_y_electrode;
+
+ num_x_electrode = SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
+ if ((priv->fw_ver[1] > 2) ||
+ (priv->fw_ver[1] == 2 && priv->fw_ver[2] > 0x33)) {
+ num_y_electrode =
+ SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x07);
+ } else {
+ num_y_electrode = ((otp[1][0] >> 4) & 0x0F);
+ }
+
+ priv->x_max = (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+ priv->y_max = (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
+
+ return 0;
+}
+
+int alps_update_btn_info_ss4(unsigned char otp[][4], struct alps_data *priv)
+{
+
+ unsigned char is_btnless = 0;
+
+ is_btnless = (otp[1][1] >> 3) & 0x01;
+
+ if (is_btnless)
+ priv->flags |= ALPS_BTNLESS;
+
+ return 0;
+}
+
+static int alps_set_defaults_ss4(struct psmouse *psmouse,
+ struct alps_data *priv)
+{
+ unsigned char otp[2][4];
+
+ memset(otp, 0, sizeof(otp));
+
+ if (alps_get_otp_values_ss4(psmouse, 0, &otp[0][0]) ||
+ alps_get_otp_values_ss4(psmouse, 1, &otp[1][0]))
+ return -1;
+
+ if (priv->fw_ver[1] >= 2)
+ alps_update_device_area_ss4_v2(otp, priv);
+ else
+ alps_update_device_area_ss4_v1(otp, priv);
+
+ alps_update_btn_info_ss4(otp, priv);
+
+ return 0;
+}
+
static int alps_dolphin_get_device_area(struct psmouse *psmouse,
struct alps_data *priv)
{
@@ -2030,28 +2969,54 @@ static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
return 0;
}
-static int alps_hw_init_v7(struct psmouse *psmouse)
+static int alps_hw_init_ss3(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
- int reg_val, ret = -1;
+ unsigned char f3param0 = 0x00,
+ f3param1 = 0x00;
- if (alps_enter_command_mode(psmouse) ||
- alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
+ if (alps_enter_command_mode(psmouse))
goto error;
- if (alps_get_v3_v7_resolution(psmouse, 0xc397))
+ /* Set to 2 pt-mode */
+ f3param0 = 0x50;
+ f3param1 = 0x3c;
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
goto error;
- if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
- goto error;
+ /* output APDATA when 1 finger is in resting area */
+ f3param0 = 0xc8;
+ f3param1 = 0x28;
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, &f3param0, PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, &f3param1, PSMOUSE_CMD_SETRATE))
+ 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))
+ return 0;
+
+error:
+ return -1;
+}
+
+
+static int alps_hw_init_ss4(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ char param[2] = {0x64, 0x28};
+ int ret = -1;
+
+ /* enter absolute mode */
+ if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
+ ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
+ ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) {
goto error;
+ }
- alps_exit_command_mode(psmouse);
return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
error:
@@ -2078,6 +3043,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;
@@ -2086,6 +3052,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;
@@ -2093,6 +3060,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;
@@ -2108,6 +3076,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;
@@ -2116,6 +3085,7 @@ 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 = 1;
break;
case ALPS_PROTO_V7:
priv->hw_init = alps_hw_init_v7;
@@ -2129,8 +3099,44 @@ static void alps_set_defaults(struct alps_data *priv)
priv->byte0 = 0x48;
priv->mask0 = 0x48;
- if (priv->fw_ver[1] != 0xba)
- priv->flags |= ALPS_BUTTONPAD;
+ if (priv->fw_ver[1] == 0xBA) {
+ priv->flags = 0;
+ /* No resting finger area */
+ priv->resting_zone_y_min = priv->y_max;
+ } else {
+ priv->flags = ALPS_BTNLESS;
+ priv->resting_zone_y_min = 0x654;
+ }
+
+ priv->slot_number = 2;
+ break;
+ case ALPS_PROTO_V8:
+ if (priv->fw_ver[1] >= 2)
+ priv->decode_fields = alps_decode_ss4_v2;
+ else
+ priv->decode_fields = alps_decode_ss4_v1;
+
+ priv->hw_init = alps_hw_init_ss4;
+ priv->process_packet = alps_process_packet_ss4;
+ 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->byte0 = 0x18;
+ priv->mask0 = 0x18;
+ priv->flags = 0;
+ priv->slot_number = 4;
+ break;
+ case ALPS_PROTO_V9:
+ priv->hw_init = alps_hw_init_ss3;
+ priv->process_packet = alps_process_touchpad_packet_ss3;
+ priv->decode_fields = alps_decode_dolphin;
+ priv->set_abs_params = alps_set_abs_params_mt;
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->byte0 = 0xc8;
+ priv->mask0 = 0xc8;
+ priv->slot_number = 2;
break;
}
}
@@ -2204,7 +3210,7 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
else
return 0;
} else if (ec[0] == 0x88 &&
- ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
+ ((ec[1] & 0xf0) == 0xB0 || (ec[1] & 0xf0) == 0xC0)) {
priv->proto_version = ALPS_PROTO_V7;
alps_set_defaults(priv);
@@ -2217,7 +3223,6 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
priv->decode_fields = alps_decode_rushmore;
priv->x_bits = 16;
priv->y_bits = 12;
- priv->flags |= ALPS_IS_RUSHMORE;
/* hack to make addr_command, nibble_command available */
psmouse->private = priv;
@@ -2232,6 +3237,22 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
alps_set_defaults(priv);
return 0;
+ } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x14) {
+ priv->proto_version = ALPS_PROTO_V8;
+ alps_set_defaults(priv);
+
+ if (alps_set_defaults_ss4(psmouse, priv))
+ return -EIO;
+
+ return 0;
+ } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) {
+ priv->proto_version = ALPS_PROTO_V9;
+ alps_set_defaults(priv);
+
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
+
+ return 0;
}
psmouse_info(psmouse,
@@ -2272,21 +3293,17 @@ static void alps_set_abs_params_st(struct alps_data *priv,
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, 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);
- input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
- input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
-
- input_mt_init_slots(dev1, MAX_TOUCHES, INPUT_MT_POINTER |
- INPUT_MT_DROP_UNUSED | INPUT_MT_TRACK | INPUT_MT_SEMI_MT);
-
+ set_bit(BTN_TOOL_DOUBLETAP, dev1->keybit);
set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
- /* V7 is real multi-touch */
- if (priv->proto_version == ALPS_PROTO_V7)
- clear_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
+ input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
}
int alps_init(struct psmouse *psmouse)
@@ -2332,9 +3349,7 @@ int alps_init(struct psmouse *psmouse)
dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
priv->set_abs_params(priv, dev1);
- /* No pressure on V7 */
- if (priv->proto_version != ALPS_PROTO_V7)
- input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
+ input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
if (priv->flags & ALPS_WHEEL) {
dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
@@ -2351,14 +3366,12 @@ int alps_init(struct psmouse *psmouse)
dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
- } else if (priv->flags & ALPS_BUTTONPAD) {
- set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
- clear_bit(BTN_RIGHT, dev1->keybit);
} else {
dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
}
- snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
+ snprintf(priv->phys, sizeof(priv->phys),
+ "%s/input1", psmouse->ps2dev.serio->phys);
dev2->phys = priv->phys;
dev2->name = (priv->flags & ALPS_DUALPOINT) ?
"DualPoint Stick" : "ALPS PS/2 Device";
@@ -2382,7 +3395,8 @@ int alps_init(struct psmouse *psmouse)
psmouse->reconnect = alps_reconnect;
psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
- /* We are having trouble resyncing ALPS touchpads so disable it for now */
+ /* We are having trouble resyncing ALPS touchpads
+ so disable it for now */
psmouse->resync_time = 0;
return 0;
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 66240b4..55f5193 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -12,8 +12,6 @@
#ifndef _ALPS_H
#define _ALPS_H
-#include <linux/input/mt.h>
-
#define ALPS_PROTO_V1 1
#define ALPS_PROTO_V2 2
#define ALPS_PROTO_V3 3
@@ -21,8 +19,17 @@
#define ALPS_PROTO_V5 5
#define ALPS_PROTO_V6 6
#define ALPS_PROTO_V7 7 /* t3btl t4s */
+#define ALPS_PROTO_V8 8 /* ss4 */
+#define ALPS_PROTO_V9 9 /* ss3btl */
+
+
+#define MAX_IMG_PT_NUM 5
+#define V7_IMG_PT_NUM 2
-#define MAX_TOUCHES 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 */
@@ -45,6 +52,124 @@ enum V7_PACKET_ID {
V7_PACKET_ID_UNKNOWN,
};
+enum SS4_PACKET_ID {
+ SS4_PACKET_ID_IDLE = 0,
+ SS4_PACKET_ID_ONE,
+ SS4_PACKET_ID_TWO,
+ SS4_PACKET_ID_MULTI,
+};
+
+#define SS4_COUNT_PER_ELECTRODE 256
+#define SS4_NUMSENSOR_XOFFSET 7
+#define SS4_NUMSENSOR_YOFFSET 7
+
+/* SWC status( 0:SW OFF, 1: SW ON) */
+#define SS4_BUTTONLESS_BUTTONS 0x01
+
+#define SS4_MASK_NORMAL_BUTTONS 0x07
+
+#define SS4_1F_X_V1(_b) (((_b[0] << 5) & 0x1E00) | \
+ ((_b[0] << 6) & 0x01C0) | \
+ ((_b[1] >> 2) & 0x0038) | \
+ ((_b[1] >> 1) & 0x0007) \
+ )
+
+#define SS4_1F_Y_V1(_b) (((_b[2] >> 1) & 0x007F) | \
+ ((_b[4] << 5) & 0x0F80) \
+ )
+
+#define SS4_1F_Z_V1(_b) (_b[5] & 0xFF)
+
+#define SS4_1F_LFB(_b) ((_b[4] >> 1) & 0x01)
+
+#define SS4_BTN_V1(_b) (_b[3] & SS4_BUTTONLESS_BUTTONS)
+
+#define SS4_STD_MF_X_V1(_b, _i) (((_b[0 + _i * 3] >> 2) & 0x0020) | \
+ ((_b[1 + _i * 3] << 5) & 0x1FC0) \
+ )
+
+#define SS4_STD_MF_Y_V1(_b, _i) (((_b[0 + _i * 3] >> 2) & 0x0010) | \
+ ((_b[2 + _i * 3] << 4) & 0x0FE0) \
+ )
+
+#define SS4_BTL_BTN_V1(_b) (_b[3] & SS4_BUTTONLESS_BUTTONS)
+
+#define SS4_BTL_MF_X_V1(_b, _i) (SS4_STD_MF_X_V1(_b, _i) | \
+ ((_b[0 + _i * 3] << 2) & 0x0010))
+
+#define SS4_BTL_MF_Y_V1(_b, _i) (SS4_STD_MF_Y_V1(_b, _i) | \
+ ((_b[0 + _i * 3] << 2) & 0x0008))
+
+#define SS4_MF_Z_V1(_b, _i) ((_b[0 + _i * 3] >> 4) & 0x0003)
+
+#define SS4_IS_MF_CONTINUE_V1(_b) ((_b[0] & 0x01) == 0x01)
+#define SS4_IS_5F_DETECTED_V1(_b) ((_b[0] & 0x01) == 0x01)
+
+#define SS4_1F_X_V2(_b) ((_b[0] & 0x0007) | \
+ ((_b[1] << 3) & 0x0078) | \
+ ((_b[1] << 2) & 0x0380) | \
+ ((_b[2] << 5) & 0x1C00) \
+ )
+
+#define SS4_1F_Y_V2(_b) (((_b[2]) & 0x000F) | \
+ ((_b[3] >> 2) & 0x0030) | \
+ ((_b[4] << 6) & 0x03C0) | \
+ ((_b[4] << 5) & 0x0C00) \
+ )
+
+#define SS4_1F_Z_V2(_b) (((_b[5]) & 0x0F) | \
+ ((_b[5] >> 1) & 0x70) | \
+ ((_b[4]) & 0x80) \
+ )
+
+#define SS4_1F_LFB_V2(_b) (((_b[2] >> 4) & 0x01) == 0x01)
+
+#define SS4_MF_LF_V2(_b, _i) ((_b[1 + _i * 3] & 0x0004) == 0x0004)
+
+#define SS4_BTN_V2(_b) ((_b[0] >> 5) & SS4_MASK_NORMAL_BUTTONS)
+
+#define SS4_STD_MF_X_V2(_b, _i) (((_b[0 + _i * 3] << 5) & 0x00E0) | \
+ ((_b[1 + _i * 3] << 5) & 0x1F00) \
+ )
+
+#define SS4_STD_MF_Y_V2(_b, _i) (((_b[1 + _i * 3] << 3) & 0x0010) | \
+ ((_b[2 + _i * 3] << 5) & 0x01E0) | \
+ ((_b[2 + _i * 3] << 4) & 0x0E00) \
+ )
+
+#define SS4_BTL_MF_X_V2(_b, _i) (SS4_STD_MF_X_V2(_b, _i) | \
+ ((_b[0 + _i * 3] >> 3) & 0x0010))
+
+#define SS4_BTL_MF_Y_V2(_b, _i) (SS4_STD_MF_Y_V2(_b, _i) | \
+ ((_b[0 + _i * 3] >> 3) & 0x0008))
+
+#define SS4_MF_Z_V2(_b, _i) (((_b[1 + _i * 3]) & 0x0001) | \
+ ((_b[1 + _i * 3] >> 1) & 0x0002) \
+ )
+
+#define SS4_IS_MF_CONTINUE_V2(_b) ((_b[2] & 0x10) == 0x10)
+#define SS4_IS_5F_DETECTED_V2(_b) ((_b[2] & 0x10) == 0x10)
+
+
+#define SS4_MFPACKET_NO_AX 8160 /* X-Coordinate value */
+#define SS4_MFPACKET_NO_AY 4080 /* Y-Coordinate value */
+#define SS4_MFPACKET_NO_AX_BL 8176 /* Buttonless X-Coordinate value */
+#define SS4_MFPACKET_NO_AY_BL 4088 /* Buttonless Y-Coordinate value */
+
+/* Threshold for resting finger's large movement */
+#define RESTING_FN_LARGE_MOVEMENT 50
+
+#define PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max)
+ (((_x) < (_x_max)/2) && ((_y) > (_y_max)*4/5))
+
+#define PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
+ (((_x) >= (_x_max)/2) && ((_y) > (_y_max)*4/5))
+
+#define PT_IN_BTN_AREA(_x, _y, _x_max, _y_max)
+ (PT_IN_LEFT_BTN_AREA(_x, _y, _x_max, _y_max) ||
+ PT_IN_RIGHT_BTN_AREA(_x, _y, _x_max, _y_max)
+ )
+
/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
@@ -68,7 +193,7 @@ struct alps_model_info {
unsigned char command_mode_resp;
unsigned char proto_version;
unsigned char byte0, mask0;
- int flags;
+ unsigned int flags;
};
/**
@@ -87,47 +212,95 @@ struct alps_nibble_commands {
unsigned char data;
};
-struct alps_bitmap_point {
- int start_bit;
- int num_bits;
+/**
+ * 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.
+ * @ts_left: Left trackstick button is active.
+ * @ts_right: Right trackstick button is active.
+ * @ts_middle: Middle trackstick button is active.
+ */
+struct alps_btn {
+ unsigned int left:1;
+ unsigned int right:1;
+ unsigned int middle:1;
+
+ unsigned int ts_left:1;
+ unsigned int ts_right:1;
+ unsigned int ts_middle:1;
+};
+
+/**
+ * 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;
+};
+
+enum dol_Packet {
+ DOL_UNKNOWN,
+ DOL_GPDATA,
+ DOL_PROFDATA,
+ DOL_APDATA
};
/**
* 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.
- * @fingers: Number of fingers for MT.
- * @pressure: Pressure.
- * @st: position for ST.
- * @mt: position for MT.
* @first_mp: Packet is the first of a multi-packet report.
* @is_mp: Packet is part of a multi-packet report.
- * @left: Left touchpad button is active.
- * @right: Right touchpad button is active.
- * @middle: Middle touchpad button is active.
- * @ts_left: Left trackstick button is active.
- * @ts_right: Right trackstick button is active.
- * @ts_middle: Middle trackstick button is active.
+ * @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 fingers;
-
- int pressure;
- struct input_mt_pos st;
- struct input_mt_pos mt[MAX_TOUCHES];
-
+ unsigned int large_fn;
unsigned int first_mp:1;
unsigned int is_mp:1;
+ enum dol_Packet dol_packet_type;
+ struct alps_btn btn;
+};
- unsigned int left:1;
- unsigned int right:1;
- unsigned int middle:1;
+/**
+ * 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.
+ */
+struct v7_raw {
+ unsigned char pkt_id;
+ unsigned int additional_fingers;
+ unsigned char rest_left;
+ unsigned char rest_right;
+};
- unsigned int ts_left:1;
- unsigned int ts_right:1;
- unsigned int ts_middle:1;
+/**
+ * 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.
+ */
+struct alps_bl_pt_attr {
+ unsigned char zone;
+ unsigned char is_counted;
+ unsigned char is_init_pt_got;
+ struct alps_abs_data init_pt;
};
/**
@@ -142,12 +315,13 @@ struct alps_fields {
* known format for this model. The first byte of the report, ANDed with
* mask0, should match byte0.
* @mask0: The mask used to check the first byte of the report.
- * @fw_ver: cached copy of firmware version (EC report)
* @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.
@@ -155,9 +329,18 @@ struct alps_fields {
* @prev_fin: Finger bit from previous packet.
* @multi_packet: Multi-packet data in progress.
* @multi_data: Saved multi-packet data.
- * @f: Decoded packet data fields.
+ * @x1: First X coordinate from last MT report.
+ * @x2: Second X coordinate from last MT report.
+ * @y1: First Y coordinate from last MT report.
+ * @y2: Second Y coordinate from last MT report.
+ * @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;
@@ -168,27 +351,35 @@ struct alps_data {
int addr_command;
unsigned char proto_version;
unsigned char byte0, mask0;
+ unsigned int flags;
unsigned char fw_ver[3];
- int flags;
int x_max;
int y_max;
+ int resting_zone_y_min;
int x_bits;
int y_bits;
- unsigned int x_res;
- unsigned int y_res;
+ unsigned char slot_number;
int (*hw_init)(struct psmouse *psmouse);
void (*process_packet)(struct psmouse *psmouse);
- int (*decode_fields)(struct alps_fields *f, unsigned char *p,
+ void (*decode_fields)(struct alps_fields *f, unsigned char *p,
struct psmouse *psmouse);
void (*set_abs_params)(struct alps_data *priv, struct input_dev *dev1);
int prev_fin;
int multi_packet;
unsigned char multi_data[6];
- struct alps_fields f;
+ int x1, x2, y1, y2;
+ int fingers;
u8 quirks;
struct timer_list timer;
+
+ /* these are used for buttonless touchpad*/
+ union {
+ struct v7_raw v7;
+ } r;
+ struct alps_btn prev_btn;
+ struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
};
#define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
--
1.9.1
^ permalink raw reply related
* Re: Input: add driver for Elan I2C/SMbus touchpad
From: Dmitry Torokhov @ 2014-10-23 22:02 UTC (permalink / raw)
To: Dan Carpenter; +Cc: dusonlin, linux-input
In-Reply-To: <20141023145813.GA20197@mwanda>
Hi Dan,
On Thu, Oct 23, 2014 at 05:58:13PM +0300, Dan Carpenter wrote:
> Hello Duson Lin,
>
> The patch 29fbd64b0fd2: "Input: add driver for Elan I2C/SMbus
> touchpad" from Oct 3, 2014, leads to the following static checker
> warning:
Can you copy committer on such reports as well please?
>
> drivers/input/mouse/elan_i2c_smbus.c:372 elan_smbus_prepare_fw_update()
> warn: sizeof(NUMBER)?
>
> drivers/input/mouse/elan_i2c_smbus.c
> 365 /*
> 366 * Read back password to make sure we enabled flash
> 367 * successfully.
> 368 */
> 369 len = i2c_smbus_read_block_data(client,
> 370 ETP_SMBUS_IAP_PASSWORD_READ,
> 371 val);
> 372 if (len != sizeof(ETP_SMBUS_IAP_PASSWORD)) {
> ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> sizeof(int) is 4.
> val is a 3 byte array.
> If we read 4 bytes then we are writing beyond the end of the val[]
> array.
We should be checking sizeof(u16) here, I'll fix it up.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: [PATCH 0/5] Input: elantech - support the Fujitsu H730 laptop
From: ulrik.debie-os @ 2014-10-23 18:36 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: Jan Kiszka, Hans de Goede, linux-input, David Herrmann
In-Reply-To: <542FBF9A.5040003@redhat.com>
Hi Dmitry,
On Sat, Oct 04, 2014 at 11:36:26AM +0200, Hans de Goede wrote:
> Hi,
>
> On 10/04/2014 11:33 AM, Jan Kiszka wrote:
> > On 2014-08-30 16:10, Ulrik De Bie wrote:
> >> This patch set makes the elantech driver work for the Fujitsu H730 laptop. It
> >> also adds a sysfs knob to allow other laptops that are facing similar
> >> problems as the Fujitsu H730 to have working touchpad.
> >>
> >> I'm considering adding a WARN_ONCE when the crc_enabled signature check
> >> fails. The message would then point the user to the crc_enabled sysfs knob,
> >> and kindly ask the user to report the laptop to linux-input mailinglist ?
> >> Any suggestions ?
> >>
> >> Two users have tested the combination of this patchset and confirmed that
> >> it makes the H730 touchpad/trackpoint work.
> >>
> >> Here an overview of the patchset:
> >>
> >> Patch 1/ : Input: elantech - use elantech_report_trackpoint for hardware v4 too
> >> The Fujitsu H730 is the first v4 hardware identified that also sends the
> >> trackpoint packets. This patch enables the trackpoint on v4 hardware.
> >> With this patch the trackpoint will work.
> >>
> >> Patch 2/ : Input: elantech - Fix crc_enabled for Fujitsu H730
> >> Uses DMI to detect the H730 and ,if detected, will set crc_enabled to 1.
> >> With this patch the touchpad and left/right button will start to work.
> >>
> >> Patch 3/ : Input: elantech - report the middle button of the touchpad
> >> The Fujitsu H730 is the first laptop listed in the elantech.c file with
> >> 3 touchpad buttons. This patch enables the middle button for all elantech
> >> hardware and enables the reporting for v4 hardware.
> >> I want to hear feedback here on what preferences exist for the conditions
> >> to enable the middle button:
> >> - DMI
> >> - enable only for v4
> >> - enable for all/report for v3+v4
> >> ...
> >>
> >> Patch 4/ : Input: Elantech - provide a sysfs knob for crc_enabled
> >> Probably H730 will not remain the only elantech laptop that has this failing
> >> detection for the crc_enabled. This provides users with a workaround when
> >> the crc_enabled detection fails.
> >>
> >> Patch 5/ : Elantech - Update the documentation: trackpoint,v3/v4,crc_enabled
> >> This provides an update of the elantech documentation.
> >>
> >> Patch 4 depends on patch 2, and for consistency, patch 5 depends on patch 1-2-4.
> >>
> >> Ulrik De Bie (5):
> >> Input: elantech - use elantech_report_trackpoint for hardware v4 too
> >> Input: elantech - Fix crc_enabled for Fujitsu H730
> >> Input: elantech - report the middle button of the touchpad
> >> Input: elantech - provide a sysfs knob for crc_enabled
> >> Input: elantech - Update the documentation:
> >> trackpoint,v3/v4,crc_enabled
> >>
> >> Documentation/input/elantech.txt | 85 ++++++++++++++++++++++++++--
> >> drivers/input/mouse/elantech.c | 119 ++++++++++++++++++++++++++++++++-------
> >> drivers/input/mouse/elantech.h | 2 +-
> >> 3 files changed, 179 insertions(+), 27 deletions(-)
> >>
> >> Best regards,
> >> Ulrik De Bie
> >>
> >
> > What's the status of this series? Is it queued for 3.18 already?
>
> I don't see them in next yet:
>
> http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/log/drivers/input/mouse/elantech.c
>
> I agree it would be nice to get these into 3.18.
>
> Dmitry, what is the plan here ?
Ping Dmitry ?
Do you want me to resend the patch ?
Kind regards,
Ulrik
^ permalink raw reply
* Re: [PATCH] HID: i2c-hid: Add hid-over-i2c name to i2c id table.
From: Benjamin Tissoires @ 2014-10-23 18:45 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Benson Leung, jkosina, aduggan, linux-input, linux-kernel, olofj,
satoshi.noguchi
In-Reply-To: <20141014225935.GA22177@dtor-ws>
On Oct 14 2014 or thereabouts, Dmitry Torokhov wrote:
> On Tue, Oct 14, 2014 at 02:44:01PM -0700, Benson Leung wrote:
> > When using the device tree binding of compatible = "hid-over-i2c"
> > the i2c id table also needs to have that name in order to
> > auto load this driver.
> >
> > Signed-off-by: Benson Leung <bleung@chromium.org>
> > ---
> > drivers/hid/i2c-hid/i2c-hid.c | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
> > index 747d544..1a7605f 100644
> > --- a/drivers/hid/i2c-hid/i2c-hid.c
> > +++ b/drivers/hid/i2c-hid/i2c-hid.c
> > @@ -1123,6 +1123,7 @@ static const struct dev_pm_ops i2c_hid_pm = {
> >
> > static const struct i2c_device_id i2c_hid_id_table[] = {
> > { "hid", 0 },
> > + { "hid-over-i2c", 0 },
> > { },
> > };
> > MODULE_DEVICE_TABLE(i2c, i2c_hid_id_table);
>
> So we already emit this string this as a module device table (OF one),
> why do we need to duplicate it in I2C? This seems like a generic problem
> and not an individual driver one.
>
Correct me if I am wrong, but isn't it a chromium problem, rather than a
generic OF one?
IIRC, when I introduced the OF binding, the name did not need to be in
the i2c id table because udev was taking that in charge. At least I do
not remember having to manually modprobing the driver.
A quick check in the drivers/input/touchscreen shows that many OF
enumerated touchscreens do not have an exact duplicate of the of
compatible name and the i2c device id one. Most of them have a vendor
prefix in the of name.
I did not used this binding for a long time, so I can not guarantee I am
right, but this change seems weird to me.
Cheers,
Benjamin
^ permalink raw reply
* Re: [PATCH 0/5] Input: elantech - support the Fujitsu H730 laptop
From: Dmitry Torokhov @ 2014-10-23 18:39 UTC (permalink / raw)
To: ulrik.debie-os; +Cc: Jan Kiszka, Hans de Goede, linux-input, David Herrmann
In-Reply-To: <20141023183618.GA7637@lantern>
On Thursday, October 23, 2014 08:36:19 PM ulrik.debie-os@e2big.org wrote:
> Hi Dmitry,
>
> On Sat, Oct 04, 2014 at 11:36:26AM +0200, Hans de Goede wrote:
> > Hi,
> >
> > On 10/04/2014 11:33 AM, Jan Kiszka wrote:
> > > On 2014-08-30 16:10, Ulrik De Bie wrote:
> > >> This patch set makes the elantech driver work for the Fujitsu H730
> > >> laptop. It also adds a sysfs knob to allow other laptops that are
> > >> facing similar problems as the Fujitsu H730 to have working touchpad.
> > >>
> > >> I'm considering adding a WARN_ONCE when the crc_enabled signature check
> > >> fails. The message would then point the user to the crc_enabled sysfs
> > >> knob,
> > >> and kindly ask the user to report the laptop to linux-input mailinglist
> > >> ?
> > >> Any suggestions ?
> > >>
> > >> Two users have tested the combination of this patchset and confirmed
> > >> that
> > >> it makes the H730 touchpad/trackpoint work.
> > >>
> > >> Here an overview of the patchset:
> > >>
> > >> Patch 1/ : Input: elantech - use elantech_report_trackpoint for
> > >> hardware v4 too The Fujitsu H730 is the first v4 hardware identified
> > >> that also sends the trackpoint packets. This patch enables the
> > >> trackpoint on v4 hardware. With this patch the trackpoint will work.
> > >>
> > >> Patch 2/ : Input: elantech - Fix crc_enabled for Fujitsu H730
> > >> Uses DMI to detect the H730 and ,if detected, will set crc_enabled to
> > >> 1.
> > >> With this patch the touchpad and left/right button will start to work.
> > >>
> > >> Patch 3/ : Input: elantech - report the middle button of the touchpad
> > >> The Fujitsu H730 is the first laptop listed in the elantech.c file with
> > >> 3 touchpad buttons. This patch enables the middle button for all
> > >> elantech
> > >> hardware and enables the reporting for v4 hardware.
> > >> I want to hear feedback here on what preferences exist for the
> > >> conditions
> > >> to enable the middle button:
> > >> - DMI
> > >> - enable only for v4
> > >> - enable for all/report for v3+v4
> > >> ...
> > >>
> > >> Patch 4/ : Input: Elantech - provide a sysfs knob for crc_enabled
> > >> Probably H730 will not remain the only elantech laptop that has this
> > >> failing detection for the crc_enabled. This provides users with a
> > >> workaround when the crc_enabled detection fails.
> > >>
> > >> Patch 5/ : Elantech - Update the documentation:
> > >> trackpoint,v3/v4,crc_enabled This provides an update of the elantech
> > >> documentation.
> > >>
> > >> Patch 4 depends on patch 2, and for consistency, patch 5 depends on
> > >> patch 1-2-4.> >>
> > >> Ulrik De Bie (5):
> > >> Input: elantech - use elantech_report_trackpoint for hardware v4 too
> > >> Input: elantech - Fix crc_enabled for Fujitsu H730
> > >> Input: elantech - report the middle button of the touchpad
> > >> Input: elantech - provide a sysfs knob for crc_enabled
> > >>
> > >> Input: elantech - Update the documentation:
> > >> trackpoint,v3/v4,crc_enabled
> > >>
> > >> Documentation/input/elantech.txt | 85 ++++++++++++++++++++++++++--
> > >> drivers/input/mouse/elantech.c | 119
> > >> ++++++++++++++++++++++++++++++++-------
> > >> drivers/input/mouse/elantech.h | 2 +-
> > >> 3 files changed, 179 insertions(+), 27 deletions(-)
> > >>
> > >> Best regards,
> > >> Ulrik De Bie
> > >
> > > What's the status of this series? Is it queued for 3.18 already?
> >
> > I don't see them in next yet:
> >
> > http://git.kernel.org/cgit/linux/kernel/git/next/linux-next.git/log/driver
> > s/input/mouse/elantech.c
> >
> > I agree it would be nice to get these into 3.18.
> >
> > Dmitry, what is the plan here ?
>
> Ping Dmitry ?
>
> Do you want me to resend the patch ?
Hi Ulrik,
No, I have it, didn't have a chance to look at it though. Give me a day or so
please.
Thanks.
--
Dmitry
^ permalink raw reply
* Re: ASUS N550JK Touchpad recognized wrongly as PS/2 mouse
From: Benjamin Tissoires @ 2014-10-23 17:49 UTC (permalink / raw)
To: Hans de Goede; +Cc: Carla Rosenfield, linux-input
In-Reply-To: <5445FCAD.7020406@redhat.com>
On Tue, Oct 21, 2014 at 2:26 AM, Hans de Goede <hdegoede@redhat.com> wrote:
> Hi,
>
> On 10/20/2014 09:48 PM, Benjamin Tissoires wrote:
>> On Mon, Oct 20, 2014 at 1:56 PM, Hans de Goede <hdegoede@redhat.com> wrote:
>>> Hi,
>>>
>>> On 10/20/2014 05:38 PM, Benjamin Tissoires wrote:
>>>> Hi Carla,
>>>>
>>>> just FYI, I have the same laptop model than you, and can reproduce
>>>> your bug report in the same way. I'll work on that to make it working
>>>> properly.
>>>>
>>>> Hans, (unfortunately,) this laptop has a ETD0105 touchpad from Elan.
>>>> That means that we do not have the X550 touchpad in house, but also
>>>> means that we should be able to get in working faster than the X550
>>>> one :)
>>>
>>> Ok, so 2 things:
>>>
>>> 1) On the ETD0105 touchpad not working, does the kernel you're using
>>> already have this patch ? :
>>>
>>> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/drivers/input/mouse/elantech.c?id=271329b3c798b2102120f5df829071c211ef00ed
>>
>> I tried the RHEL 6.6 kernel (the only I had on a usb disk handy at that time).
>> The Fedora 21 snapshot (3.17.0) makes it detected properly :)
>
> Good.
>
>> However, landing 8 fingers on the touchpad makes it completely lost
>> (waiting few seconds without touching it is enough to get it back
>> alive).
>
> Hmm, might be a firmware bug, but this also might mean it can detect
> more fingers then previous versions, and sends a new packet type when
> more then X fingers are present, we should probably end a mail to
> our contacts at elantech about this. Since you've the hardware I
> assume you will be sending such a mail ?
>
I tried to dump the PS2 events, and checked if a new packet was
coming, and it appears that nothing indicates that the device is
capable of tracking more than 5 fingers. Sometimes, the first time I
land 8 fingers on the touchpad after a hard reboot, the device
receives a lost sync events, and has to reconnect, but then, these
lost sync events do not occurs anymore.
I would be tempted to say that this is a firmware bug and that we can
not do much for it, but I'll ask Elantech about it.
Cheers,
Benjamin
^ permalink raw reply
* Re: 3.18.rc1: compile failure in tsc2005.c
From: Pavel Machek @ 2014-10-23 16:42 UTC (permalink / raw)
To: Pali Rohár
Cc: kernel list, dmitry.torokhov, sre, B38611, aaro.koskinen, jg1.han,
linux-input
In-Reply-To: <201410231501.04540@pali>
Hi!
Oops, ignore me, this is part of n900 changes that did not make it to
mainline.
> > I get this. Before I start patching it, perhaps someone has
> > fixed it already?
> >
> > CC drivers/input/touchscreen/tsc2005.o
> > drivers/input/touchscreen/tsc2005.c: In function
> > 'tsc2005_disable_store':
> > drivers/input/touchscreen/tsc2005.c:406:2: error: implicit
> > declaration of function 'strict_strtoul'
> > [-Werror=implicit-function-declaration] cc1: some warnings
> > being treated as errors
n> > scripts/Makefile.build:257: recipe for target
> > 'drivers/input/touchscreen/tsc2005.o' failed
> > make[3]: *** [drivers/input/touchscreen/tsc2005.o] Error 1
> > scripts/Makefile.build:402: recipe for target
> > 'drivers/input/touchscreen' failed
> > make[2]: *** [drivers/input/touchscreen] Error 2
> > scripts/Makefile.build:402: recipe for target 'drivers/input'
> > failed make[1]: *** [drivers/input] Error 2
> > make[1]: *** Waiting for unfinished jobs....
> > CC net/core/request_sock.o
>
> Hi, I read somewhere that strict_strtoul function was replaced by
> some kstrtol function... So maybe somebody forgot to fix tsc2005
> driver?
Yes.. there are four places in n900 patches that will need fixing.
This only applies to Pali's tree.
Signed-off-by: Pavel Machek <pavel@ucw.cz>
Pavel
commit 1f031685bd14a13242f78e7cc9cc1cd767aa3dbc
Author: Pavel <pavel@ucw.cz>
Date: Thu Oct 23 17:23:16 2014 +0200
Fix compilation by replacing strict_strtoul to kstrtoul
Signed-off-by: Pavel Machek <pavel@ucw.cz>
diff --git a/arch/arm/plat-omap/gpio-switch.c b/arch/arm/plat-omap/gpio-switch.c
index 394c45b..ceed4f3 100644
--- a/arch/arm/plat-omap/gpio-switch.c
+++ b/arch/arm/plat-omap/gpio-switch.c
@@ -197,7 +197,7 @@ static ssize_t gpio_sw_disable_store(struct device *dev,
struct gpio_switch *sw = dev_get_drvdata(dev);
unsigned long res;
- if (strict_strtoul(buf, 10, &res) < 0)
+ if (kstrtoul(buf, 10, &res) < 0)
return -EINVAL;
if (!!res == sw->disabled)
diff --git a/drivers/input/touchscreen/tsc2005.c b/drivers/input/touchscreen/tsc2005.c
index 422ec6e..ec1c276 100644
--- a/drivers/input/touchscreen/tsc2005.c
+++ b/drivers/input/touchscreen/tsc2005.c
@@ -403,7 +403,7 @@ static ssize_t tsc2005_disable_store(struct device *dev,
unsigned long val;
int error;
- error = strict_strtoul(buf, 10, &val);
+ error = kstrtoul(buf, 10, &val);
if (error)
return error;
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 3a986f3..f697e5f 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -1506,7 +1506,7 @@ static ssize_t wl1251_sysfs_store_tx_mgmt_frm_rate(struct device *dev,
unsigned long res;
int ret;
- ret = strict_strtoul(buf, 10, &res);
+ ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1251_warning("incorrect value written to tx_mgmt_frm_rate");
@@ -1600,7 +1600,7 @@ static ssize_t wl1251_sysfs_store_bt_coex_mode(struct device *dev,
unsigned long res;
int ret;
- ret = strict_strtoul(buf, 10, &res);
+ ret = kstrtoul(buf, 10, &res);
if (ret < 0) {
wl1251_warning("incorrect value written to bt_coex_mode");
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply related
* Re: 3.18.rc1: compile failure in tsc2005.c
From: Daniel Walter @ 2014-10-23 16:07 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Pali Rohár, Pavel Machek, kernel list, sre, B38611,
aaro.koskinen, jg1.han, linux-input
In-Reply-To: <20141023154751.GB18714@dtor-ws>
On Thu, Oct 23, 2014 at 08:47:51AM -0700, Dmitry Torokhov wrote:
> On Thu, Oct 23, 2014 at 03:01:04PM +0200, Pali Rohár wrote:
> > On Thursday 23 October 2014 14:53:25 Pavel Machek wrote:
> > > Hi!
> > >
> > > I get this. Before I start patching it, perhaps someone has
> > > fixed it already?
> > >
> > > Pavel
> > >
> > > CC drivers/input/touchscreen/tsc2005.o
> > > drivers/input/touchscreen/tsc2005.c: In function
> > > 'tsc2005_disable_store':
> > > drivers/input/touchscreen/tsc2005.c:406:2: error: implicit
> > > declaration of function 'strict_strtoul'
> > > [-Werror=implicit-function-declaration] cc1: some warnings
> > > being treated as errors
> > > scripts/Makefile.build:257: recipe for target
> > > 'drivers/input/touchscreen/tsc2005.o' failed
> > > make[3]: *** [drivers/input/touchscreen/tsc2005.o] Error 1
> > > scripts/Makefile.build:402: recipe for target
> > > 'drivers/input/touchscreen' failed
> > > make[2]: *** [drivers/input/touchscreen] Error 2
> > > scripts/Makefile.build:402: recipe for target 'drivers/input'
> > > failed make[1]: *** [drivers/input] Error 2
> > > make[1]: *** Waiting for unfinished jobs....
> > > CC net/core/request_sock.o
> >
> > Hi, I read somewhere that strict_strtoul function was replaced by
> > some kstrtol function... So maybe somebody forgot to fix tsc2005
> > driver?
>
> Yeah, I see patch from Daniel removing these but forgettign tsc2005.
>
> Pavel, if you have hardware then a patch connverting to kstro* would be
> very welcome.
>
> Thanks.
>
> --
> Dmitry
Hi Pavel,
what tree are you working with, since I do not see any reference to
strict_strto* in mainline,
thanks
--
Daniel
^ permalink raw reply
* Microsoft Surface Pro 3 Type Cover keyboard
From: Jarrad Whitaker @ 2014-10-23 15:57 UTC (permalink / raw)
To: linux-input; +Cc: jkosina
[-- Attachment #1: Type: text/plain, Size: 1653 bytes --]
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
The keyboard on the Surface Pro 3 type cover does not function without
some patching, similar to what was apparently required for the SP2
type/touch covers.
A working patch against 3.16 attached, it's an amalgamation of "some
dude posted this on the ubuntu/arch forums and it seems to work" so
I'm making no claims that it's kernel-quality! Just trying to give a
better indication of what needs to be added. My C is rudimentary and
my knowledge of the kernel limited to 'fakeroot debian/rules
updateconfigs', sorry. :)
Happy to test any improved version, but note I only have a type, not a
touch cover.
Patch source is
http://winaero.com/blog/how-to-install-linux-on-surface-pro-3/, which
in turn sources a Russian site.
c.f. https://bugzilla.kernel.org/show_bug.cgi?id=86641
Jarrad
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1
iQIcBAEBAgAGBQJUSSVZAAoJED3oB8CFhvqeL2oP/3aaFFjCMaVKyJKB7Xi5DgLq
WuHLnKUVVVcriW+ZP6AoCdowNEDqlmtrW0Ytvr0wbPGNOutPpWrrNKn9/LDXblt/
26CLTM3M44hnyST3QbyfCNOhKKncPBMdqz0jwcsJnElSRWVjSmiQ4LoHcBkrnUTV
TwoURkA75TzRKqcy5v9FHHAezGXLmqiSym8/F9RBO2ELi2s8bRuL/a8BLo3HQjSS
HPCoCiZ0wlrTImT/w1DW1EpPNXkQ1EjhHZdnz9DrGlr0ha9LtstrFeM15TXWBLME
/hqn7wFehwuxIZccMg1ZiDidf2tMPNnvPOnng/PiJDa7pOlzSn9OAMggLm//yk4m
oyyvzr75onZa4m61Ay2Llhs+2NLAywke+04FXJ3YxQ4h+3AW+cMOIcdqzHbof2tI
TfwMfVlmVbgdIRnzYDVXGCh7odnd18Bt/xR/YSGJVpoMZMsMlav8QTNzVw8kkiIZ
35j2C/MBme3NPhXVsg7pgILgSQH0MdHqdC/aRMQQiqItVvobGgPpTf8KtGXwBbEy
7wEAlUkr4bgdsAkX1hNuFCtCPZ7fm2lJoxWm8sOUBkbp2gx+JaSmL4Qyv8CkWj+C
K2FNqlf4DFb6JyN21fENmou9lTfhUujC3/ECeOfRiip/6ol01VFebUDS6dQcM7PK
kQInY7SjFoCx0u8y4YMM
=CI1g
-----END PGP SIGNATURE-----
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: s3typecover.patch --]
[-- Type: text/x-patch; name="s3typecover.patch", Size: 2588 bytes --]
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8ed66fd..420810c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -702,6 +702,10 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type)
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
+ if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
+ hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 &&
+ hid->group == HID_GROUP_MULTITOUCH)
+ hid->group = HID_GROUP_GENERIC;
}
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 48b66bb..cd0ca8d 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -638,6 +638,7 @@
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
+#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index 8ba17a9..d878567 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -274,7 +274,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_NOGET },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500),
.driver_data = MS_DUPLICATE_USAGES },
-
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
+ .driver_data = MS_HIDINPUT },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
{ }
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 31e6727..18cd2c6 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -74,6 +74,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
+ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
[-- Attachment #3: s3typecover.patch.sig --]
[-- Type: application/pgp-signature, Size: 543 bytes --]
^ permalink raw reply related
* Re: [PATCH] input: soc_button_array: update calls to gpiod_get*()
From: Dmitry Torokhov @ 2014-10-23 15:53 UTC (permalink / raw)
To: Alexandre Courbot; +Cc: linux-input, linux-kernel, gnurou
In-Reply-To: <1414052275-20310-1-git-send-email-acourbot@nvidia.com>
On Thu, Oct 23, 2014 at 05:17:55PM +0900, Alexandre Courbot wrote:
> Add the new flags argument to calls of (devm_)gpiod_get*().
>
> Currently both forms (with or without the flags argument)
> are valid thanks to transitional macros in
> <linux/gpio/consumer.h>. These macros will be removed once
> all consumers are updated and the flags argument will become
> compulsary.
>
> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
Applied, thank you.
> ---
> drivers/input/misc/soc_button_array.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
> index 735604753568..e097f1ab427f 100644
> --- a/drivers/input/misc/soc_button_array.c
> +++ b/drivers/input/misc/soc_button_array.c
> @@ -55,7 +55,7 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
> struct gpio_desc *desc;
> int gpio;
>
> - desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
> + desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS);
> if (IS_ERR(desc))
> return PTR_ERR(desc);
>
> --
> 2.1.2
>
--
Dmitry
^ permalink raw reply
* Re: 3.18.rc1: compile failure in tsc2005.c
From: Dmitry Torokhov @ 2014-10-23 15:47 UTC (permalink / raw)
To: Pali Rohár
Cc: Pavel Machek, kernel list, sre, B38611, aaro.koskinen, jg1.han,
linux-input, Daniel Walter
In-Reply-To: <201410231501.04540@pali>
On Thu, Oct 23, 2014 at 03:01:04PM +0200, Pali Rohár wrote:
> On Thursday 23 October 2014 14:53:25 Pavel Machek wrote:
> > Hi!
> >
> > I get this. Before I start patching it, perhaps someone has
> > fixed it already?
> >
> > Pavel
> >
> > CC drivers/input/touchscreen/tsc2005.o
> > drivers/input/touchscreen/tsc2005.c: In function
> > 'tsc2005_disable_store':
> > drivers/input/touchscreen/tsc2005.c:406:2: error: implicit
> > declaration of function 'strict_strtoul'
> > [-Werror=implicit-function-declaration] cc1: some warnings
> > being treated as errors
> > scripts/Makefile.build:257: recipe for target
> > 'drivers/input/touchscreen/tsc2005.o' failed
> > make[3]: *** [drivers/input/touchscreen/tsc2005.o] Error 1
> > scripts/Makefile.build:402: recipe for target
> > 'drivers/input/touchscreen' failed
> > make[2]: *** [drivers/input/touchscreen] Error 2
> > scripts/Makefile.build:402: recipe for target 'drivers/input'
> > failed make[1]: *** [drivers/input] Error 2
> > make[1]: *** Waiting for unfinished jobs....
> > CC net/core/request_sock.o
>
> Hi, I read somewhere that strict_strtoul function was replaced by
> some kstrtol function... So maybe somebody forgot to fix tsc2005
> driver?
Yeah, I see patch from Daniel removing these but forgettign tsc2005.
Pavel, if you have hardware then a patch connverting to kstro* would be
very welcome.
Thanks.
--
Dmitry
--
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 1/3] input: alps: Reset mouse before identifying it
From: Dmitry Torokhov @ 2014-10-23 15:44 UTC (permalink / raw)
To: Pali Rohár
Cc: Tommy Will, Hans de Goede, Yunkang Tang, linux-input,
linux-kernel
In-Reply-To: <201410191307.41313@pali>
On Sun, Oct 19, 2014 at 01:07:41PM +0200, Pali Rohár wrote:
> On Wednesday 15 October 2014 20:22:56 Dmitry Torokhov wrote:
> > On Wed, Oct 15, 2014 at 08:10:39PM +0200, Pali Rohár wrote:
> > > On Wednesday 15 October 2014 20:00:11 Dmitry Torokhov wrote:
> > > > On Wed, Oct 15, 2014 at 07:57:37PM +0200, Pali Rohár wrote:
> > > > > On Wednesday 15 October 2014 19:43:15 Dmitry Torokhov
> wrote:
> > > > > > On Wed, Oct 15, 2014 at 02:53:11PM +0200, Pali Rohár
> wrote:
> > > > > > > On Tuesday 14 October 2014 08:08:34 Dmitry Torokhov
> > >
> > > wrote:
> > > > > > > > On Fri, Oct 03, 2014 at 11:47:59AM +0200, Hans de
> > > > > > > > Goede
> > > > >
> > > > > wrote:
> > > > > > > > > Hi,
> > > > > > > > >
> > > > > > > > > Thanks for working on this!
> > > > > > > > >
> > > > > > > > > On 10/03/2014 11:43 AM, Pali Rohár wrote:
> > > > > > > > > > On some systems after starting computer
> > > > > > > > > > function alps_identify() does not detect dual
> > > > > > > > > > ALPS touchpad+trackstick device correctly and
> > > > > > > > > > detect only touchpad.
> > > > > > > > > >
> > > > > > > > > > Resetting ALPS device before identifiying it
> > > > > > > > > > fixing this problem and both parts touchpad
> > > > > > > > > > and trackstick are detected.
> > > > > > > > > >
> > > > > > > > > > Signed-off-by: Pali Rohár
> > > > > > > > > > <pali.rohar@gmail.com> Tested-by: Pali Rohár
> > > > > > > > > > <pali.rohar@gmail.com>
> > > > > > > > >
> > > > > > > > > Looks good and seems sensible:
> > > > > > > > >
> > > > > > > > > Acked-by: Hans de Goede <hdegoede@redhat.com>
> > > > > > > >
> > > > > > > > *sigh* I am not really happy about this, as we
> > > > > > > > making boot longer and longer for people without
> > > > > > > > ALPS touchpads. It would be better if we only
> > > > > > > > reset the mouse when we knew we are dealing with
> > > > > > > > ALPS, and even better if we only reset it when we
> > > > > > > > suspected that we missed trackstick. Any chance
> > > > > > > > of doing this?
> > > > > > > >
> > > > > > > > Thanks.
> > > > > > >
> > > > > > > Dmitry, problem is that function check which
> > > > > > > detecting trackstick does not working when I start
> > > > > > > my laptop from power-off state and do not reset
> > > > > > > PS/2 device. But detecting ALPS touchpad looks like
> > > > > > > working. So if do not like this idea, what about
> > > > > > > doing something like this in alps_dectect function?
> > > > > > >
> > > > > > > int alps_detect(...)
> > > > > > > {
> > > > > > > ...
> > > > > > > /* detect if device is ALPS */
> > > > > > > if (alps_identify(...) < 0)
> > > > > > > return -1;
> > > > > > > /* now we know that device is ALPS */
> > > > > > > if (!(flags & ALPS_DUALPOINT)) {
> > > > > > > /* reset it and identify again, maybe there is
> > > > > > > trackstick */ psmouse_reset(...);
> > > > > > > alps_identify(...);
> > > > > > > }
> > > > > > > ...
> > > > > > > }
> > > > > > >
> > > > > > > It will does not affect non ALPS devices (because
> > > > > > > first identify call will fail), but will affect
> > > > > > > ALPS devices without trackstick (because identify
> > > > > > > will be called twice and reset too).
> > > > > >
> > > > > > I think this is a step in right direction. Do you know
> > > > > > what exactly fails in alps_identify() on your box if
> > > > > > you do not call psmouse_reset?
> > > > > >
> > > > > > Thanks.
> > > > >
> > > > > Yes, I know. It is failing in
> > > > > alps_probe_trackstick_v3(). It calls
> > > > > alps_command_mode_read_reg(...) and it returns 0 which
> > > > > means trackstick is not there.
> > > >
> > > > OK, so can we try sticking psmouse_reset() there? This
> > > > will limit the exposure of the new delay.
> > > >
> > > > Thanks.
> > >
> > > Sorry, but I think this is not safe. Function psmouse_reset
> > > will reset device (set it to relative mode, etc...) and
> > > before and after alps_probe_trackstick_v3() are called
> > > other functions. So it could break something else.
> >
> > We might need to repeat bits of alps_identify() after
> > resetting the mouse, you are right. It should still be doable
> > though.
>
> What about checking "E6 report" and if that pass reset device and
> do full alps_identify? With check for "E6 report" we can filter
> probably all PS/2 devices which are not ALPS.
>
Why don't you pull alps_probe_trackstick_v3() from alps_identify(),
rename it into __alps_identify() and then have real alps_identify be:
static int alps_identfy(struct psmouse *psmouse, struct alps_data *priv)
{
int error;
error = __alps_identify(psmouse, priv);
if (error)
return error;
if (priv->proto_version == ALPS_PROTO_V3 &&
(priv->flags & ALPS_IS_RUSHMORE)) {
/*
* Some Dell Lattitudes may not always recognize
* tracksticks without resetting the device.
*/
psmouse_reset(psmouse);
error = __alps_identify(psmouse, priv);
if (error)
return error;
if (alps_probe_trackstick_v3(psmouse,
ALPS_REG_BASE_RUSHMORE))
priv->flags &= ~ALPS_DUALPOINT;
}
return 0;
}
This way you minimize number of devices exposed to extra reset.
Thanks.
--
Dmitry
--
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: Input: add driver for Elan I2C/SMbus touchpad
From: Dan Carpenter @ 2014-10-23 14:58 UTC (permalink / raw)
To: dusonlin; +Cc: linux-input
Hello Duson Lin,
The patch 29fbd64b0fd2: "Input: add driver for Elan I2C/SMbus
touchpad" from Oct 3, 2014, leads to the following static checker
warning:
drivers/input/mouse/elan_i2c_smbus.c:372 elan_smbus_prepare_fw_update()
warn: sizeof(NUMBER)?
drivers/input/mouse/elan_i2c_smbus.c
365 /*
366 * Read back password to make sure we enabled flash
367 * successfully.
368 */
369 len = i2c_smbus_read_block_data(client,
370 ETP_SMBUS_IAP_PASSWORD_READ,
371 val);
372 if (len != sizeof(ETP_SMBUS_IAP_PASSWORD)) {
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
sizeof(int) is 4.
val is a 3 byte array.
If we read 4 bytes then we are writing beyond the end of the val[]
array.
373 error = len < 0 ? len : -EIO;
374 dev_err(dev, "failed to read iap password: %d\n",
375 error);
376 return error;
377 }
378
379 password = be16_to_cpup((__be16 *)val);
380 if (password != ETP_SMBUS_IAP_PASSWORD) {
381 dev_err(dev, "wrong iap password = 0x%X\n", password);
382 return -EIO;
383 }
regards,
dan carpenter
^ permalink raw reply
* Re: 3.18.rc1: compile failure in tsc2005.c
From: Pali Rohár @ 2014-10-23 13:01 UTC (permalink / raw)
To: Pavel Machek
Cc: kernel list, dmitry.torokhov, sre, B38611, aaro.koskinen, jg1.han,
linux-input
In-Reply-To: <20141023125325.GB30572@amd>
[-- Attachment #1: Type: Text/Plain, Size: 1185 bytes --]
On Thursday 23 October 2014 14:53:25 Pavel Machek wrote:
> Hi!
>
> I get this. Before I start patching it, perhaps someone has
> fixed it already?
>
> Pavel
>
> CC drivers/input/touchscreen/tsc2005.o
> drivers/input/touchscreen/tsc2005.c: In function
> 'tsc2005_disable_store':
> drivers/input/touchscreen/tsc2005.c:406:2: error: implicit
> declaration of function 'strict_strtoul'
> [-Werror=implicit-function-declaration] cc1: some warnings
> being treated as errors
> scripts/Makefile.build:257: recipe for target
> 'drivers/input/touchscreen/tsc2005.o' failed
> make[3]: *** [drivers/input/touchscreen/tsc2005.o] Error 1
> scripts/Makefile.build:402: recipe for target
> 'drivers/input/touchscreen' failed
> make[2]: *** [drivers/input/touchscreen] Error 2
> scripts/Makefile.build:402: recipe for target 'drivers/input'
> failed make[1]: *** [drivers/input] Error 2
> make[1]: *** Waiting for unfinished jobs....
> CC net/core/request_sock.o
Hi, I read somewhere that strict_strtoul function was replaced by
some kstrtol function... So maybe somebody forgot to fix tsc2005
driver?
--
Pali Rohár
pali.rohar@gmail.com
[-- Attachment #2: This is a digitally signed message part. --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* 3.18.rc1: compile failure in tsc2005.c
From: Pavel Machek @ 2014-10-23 12:53 UTC (permalink / raw)
To: kernel list
Cc: dmitry.torokhov, sre, B38611, pali.rohar, aaro.koskinen, jg1.han,
linux-input
Hi!
I get this. Before I start patching it, perhaps someone has fixed it
already?
Pavel
CC drivers/input/touchscreen/tsc2005.o
drivers/input/touchscreen/tsc2005.c: In function
'tsc2005_disable_store':
drivers/input/touchscreen/tsc2005.c:406:2: error: implicit declaration
of function 'strict_strtoul' [-Werror=implicit-function-declaration]
cc1: some warnings being treated as errors
scripts/Makefile.build:257: recipe for target
'drivers/input/touchscreen/tsc2005.o' failed
make[3]: *** [drivers/input/touchscreen/tsc2005.o] Error 1
scripts/Makefile.build:402: recipe for target
'drivers/input/touchscreen' failed
make[2]: *** [drivers/input/touchscreen] Error 2
scripts/Makefile.build:402: recipe for target 'drivers/input' failed
make[1]: *** [drivers/input] Error 2
make[1]: *** Waiting for unfinished jobs....
CC net/core/request_sock.o
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
^ permalink raw reply
* [PATCH] input: soc_button_array: update calls to gpiod_get*()
From: Alexandre Courbot @ 2014-10-23 8:17 UTC (permalink / raw)
To: Dmitry Torokhov; +Cc: linux-input, linux-kernel, gnurou, Alexandre Courbot
Add the new flags argument to calls of (devm_)gpiod_get*().
Currently both forms (with or without the flags argument)
are valid thanks to transitional macros in
<linux/gpio/consumer.h>. These macros will be removed once
all consumers are updated and the flags argument will become
compulsary.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/input/misc/soc_button_array.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 735604753568..e097f1ab427f 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -55,7 +55,7 @@ static int soc_button_lookup_gpio(struct device *dev, int acpi_index)
struct gpio_desc *desc;
int gpio;
- desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index);
+ desc = gpiod_get_index(dev, KBUILD_MODNAME, acpi_index, GPIOD_ASIS);
if (IS_ERR(desc))
return PTR_ERR(desc);
--
2.1.2
^ permalink raw reply related
* Re: Problems with Wacom Intuos PT M (CTH680) on FreeBSD
From: Hans Petter Selasky @ 2014-10-23 5:54 UTC (permalink / raw)
To: Denis Akiyakov, Dmitry Torokhov
Cc: linux-input, nox@jelal.kn-bremen.de >> Juergen Lock
In-Reply-To: <544889FD.5030004@gmail.com>
On 10/23/14 06:54, Denis Akiyakov wrote:
> On 22.10.2014 05:33, Dmitry Torokhov wrote:
>> Hi Denis,
>>
>> On Sat, Oct 18, 2014 at 05:56:48PM +0700, Denis Akiyakov wrote:
>>> Hello,
>>>
>>> I'm using FreeBSD 10.1 and FreeBSD use webcamd witch contain linux
>>> wacom driver to provide wacom tablets support. More info here:
>>> http://www.selasky.org/hans_petter/video4bsd/ or
>>> http://www.freshports.org/multimedia/webcamd/
>>>
>>> I've got latest version of webcamd and Wacom device CTH680, but
>>> device isn't working correct.
>> Have you tried the device with Linux instead of FreeBSD? If it works in
>> Linux that means that the port of linux drivers to BSD is to blame and
>> you need to contact its authors, otherwise we need to adjust wacom
>> driver in kernel for this device.
>>
>> Thanks.
>>
> Hello, Dmitry.
>
> I've tried tablet in Ubuntu 14.04.1. All functions that work in Windows
> 7 (in Krita) work under Ubuntu's Krita.
>
> Thank you for your attention.
>
Hi,
The problem appears to be that webcamd launches two instances for each
interface, so the shared data is not the same like with Linux. Actually
the shared data is NULL.
I think however it would be clever that the Linux Wacom code would check
"wacom->shared->touch_input" for NULL before using it, because it is not
always set. This can be an easy way to crash the kernel when plugging a
USB devices.
drivers/hid/wacom_wac.c:1395
and some more places.
--HPS
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox