* [PATCHv2 1/3] Input: edt_ft5x06: use devm_* functions where appropriate
From: Lothar Waßmann @ 2014-01-16 8:02 UTC (permalink / raw)
To: linux-input, Simon Budig, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Rob Landley, Dmitry Torokhov,
Thierry Reding, Grant Likely, Jonathan Cameron, Shawn Guo,
Silvio F, Guennadi Liakhovetski, Jingoo Han, Fugang Duan,
Sachin Kamat, devicetree, linux-doc, linux-kernel
Cc: Lothar Waßmann
In-Reply-To: <1389859338-11685-1-git-send-email-LW@KARO-electronics.de>
Simplify the error path and remove() function by using devm_*
functions for requesting gpios and irq and allocating the input
device.
Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
---
drivers/input/touchscreen/edt-ft5x06.c | 62 ++++++++++---------------------
1 files changed, 20 insertions(+), 42 deletions(-)
diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index af0d68b..acb6b9f 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -623,8 +623,9 @@ static int edt_ft5x06_ts_reset(struct i2c_client *client,
if (gpio_is_valid(reset_pin)) {
/* this pulls reset down, enabling the low active reset */
- error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW,
- "edt-ft5x06 reset");
+ error = devm_gpio_request_one(&client->dev, reset_pin,
+ GPIOF_OUT_INIT_LOW,
+ "edt-ft5x06 reset");
if (error) {
dev_err(&client->dev,
"Failed to request GPIO %d as reset pin, error %d\n",
@@ -723,7 +724,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
return error;
if (gpio_is_valid(pdata->irq_pin)) {
- error = gpio_request_one(pdata->irq_pin,
+ error = devm_gpio_request_one(&client->dev, pdata->irq_pin,
GPIOF_IN, "edt-ft5x06 irq");
if (error) {
dev_err(&client->dev,
@@ -734,11 +735,10 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
}
tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
- input = input_allocate_device();
- if (!tsdata || !input) {
- dev_err(&client->dev, "failed to allocate driver data.\n");
- error = -ENOMEM;
- goto err_free_mem;
+ input = devm_input_allocate_device(&client->dev);
+ if (!input) {
+ dev_err(&client->dev, "failed to allocate input device.\n");
+ return -ENOMEM;
}
mutex_init(&tsdata->mutex);
@@ -749,7 +749,7 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
error = edt_ft5x06_ts_identify(client, tsdata->name, fw_version);
if (error) {
dev_err(&client->dev, "touchscreen probe failed\n");
- goto err_free_mem;
+ return error;
}
edt_ft5x06_ts_get_defaults(tsdata, pdata);
@@ -776,27 +776,30 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
error = input_mt_init_slots(input, MAX_SUPPORT_POINTS, 0);
if (error) {
dev_err(&client->dev, "Unable to init MT slots.\n");
- goto err_free_mem;
+ return error;
}
input_set_drvdata(input, tsdata);
i2c_set_clientdata(client, tsdata);
- error = request_threaded_irq(client->irq, NULL, edt_ft5x06_ts_isr,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- client->name, tsdata);
+ error = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ edt_ft5x06_ts_isr,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ client->name, tsdata);
if (error) {
dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
- goto err_free_mem;
+ return error;
}
error = sysfs_create_group(&client->dev.kobj, &edt_ft5x06_attr_group);
if (error)
- goto err_free_irq;
+ return error;
error = input_register_device(input);
- if (error)
- goto err_remove_attrs;
+ if (error) {
+ sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
+ return error;
+ }
edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
device_init_wakeup(&client->dev, 1);
@@ -806,40 +809,15 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
pdata->irq_pin, pdata->reset_pin);
return 0;
-
-err_remove_attrs:
- sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
-err_free_irq:
- free_irq(client->irq, tsdata);
-err_free_mem:
- input_free_device(input);
- kfree(tsdata);
-
- if (gpio_is_valid(pdata->irq_pin))
- gpio_free(pdata->irq_pin);
-
- return error;
}
static int edt_ft5x06_ts_remove(struct i2c_client *client)
{
- const struct edt_ft5x06_platform_data *pdata =
- dev_get_platdata(&client->dev);
struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
edt_ft5x06_ts_teardown_debugfs(tsdata);
sysfs_remove_group(&client->dev.kobj, &edt_ft5x06_attr_group);
- free_irq(client->irq, tsdata);
- input_unregister_device(tsdata->input);
-
- if (gpio_is_valid(pdata->irq_pin))
- gpio_free(pdata->irq_pin);
- if (gpio_is_valid(pdata->reset_pin))
- gpio_free(pdata->reset_pin);
-
- kfree(tsdata);
-
return 0;
}
--
1.7.2.5
^ permalink raw reply related
* [PATCHv2 0/3] Input: edt-ft5x06: Add DT support
From: Lothar Waßmann @ 2014-01-16 8:02 UTC (permalink / raw)
To: linux-input, Simon Budig, Rob Herring, Pawel Moll, Mark Rutland,
Ian Campbell, Kumar Gala, Rob Landley, Dmitry Torokhov,
Thierry Reding, Grant Likely, Jonathan Cameron, Shawn Guo,
Silvio F, Guennadi Liakhovetski, Jingoo Han, Fugang Duan,
Sachin Kamat, devicetree, linux-doc, linux-kernel
Changes wrt. v1:
addressed the comments from Jingoo Han and Mark Rutland
- added another patch to convert the driver to use devm_* functions
- removed sysfs reference from bindings documentation
- changed '_' to '-' in property name
- added 'edt,' prefix to properties names
- added sanity check for parameters read from DT
- cleaned up the gpio handling code
^ permalink raw reply
* Re: [PATCH 2/2] Input: edt-ft5x06: Add DT support
From: Lothar Waßmann @ 2014-01-16 7:49 UTC (permalink / raw)
To: Mark Rutland
Cc: linux-input@vger.kernel.org, Rob Herring, Pawel Moll,
Ian Campbell, Kumar Gala, Rob Landley, Dmitry Torokhov,
grant.likely@linaro.org, Thierry Reding, Jonathan Cameron,
Shawn Guo, Silvio F, Guennadi Liakhovetski, Jingoo Han,
Fugang Duan, Sachin Kamat, devicetree@vger.kernel.org,
linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
Simon Budig
In-Reply-To: <20140113134441.GD1273@e106331-lin.cambridge.arm.com>
Hi,
Mark Rutland wrote:
> On Mon, Jan 13, 2014 at 10:17:04AM +0000, Lothar Waßmann wrote:
> > This patch allows the edt-ft5x06 multitouch panel driver to be
> > configured via DT.
> >
> > Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
> > ---
> > .../bindings/input/touchscreen/edt-ft5x06.txt | 31 ++++
> > drivers/input/touchscreen/edt-ft5x06.c | 145 +++++++++++++++----
> > 2 files changed, 145 insertions(+), 31 deletions(-)
> > create mode 100644 Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> >
> > diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> > new file mode 100644
> > index 0000000..629dbdd
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> > @@ -0,0 +1,31 @@
> > +* EDT FT5x06 Multiple Touch Controller
> > +
[...]
> > +- threshold: allows setting the "click"-threshold in the range from 20 to 80.
> > +- gain: sensitivity (0..31) (lower value -> higher sensitivity)
> > +- offset: edge compensation (0..31)
> > +- report_rate: report rate (3..14)
>
> s/_/-/ on property names please. Also, it may make sense to prefix these
> as they're rather generic sounding names.
>
> Could you elaborate on these a litle please? What units are each of
> these in? Why does it make sense to have them in the dt?
>
I just converted them from being passed via platform_data. I have no
idea what they actually control and what units they use. I could not
even find a manual where they are documented.
Maybe Simon Budig can help out here as the original driver author.
Lothar Waßmann
--
___________________________________________________________
Ka-Ro electronics GmbH | Pascalstraße 22 | D - 52076 Aachen
Phone: +49 2408 1402-0 | Fax: +49 2408 1402-10
Geschäftsführer: Matthias Kaussen
Handelsregistereintrag: Amtsgericht Aachen, HRB 4996
www.karo-electronics.de | info@karo-electronics.de
___________________________________________________________
--
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: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Elaine Chen @ 2014-01-16 5:36 UTC (permalink / raw)
To: Dylan Thurston
Cc: Tommy Will, Dmitry Torokhov, Kevin Cernekee, david turvene,
Niels de Vos, Justin Clift, Qiting Chen, linux-input
In-Reply-To: <20140115181555.GA13606@bostoncoop.net>
Do you mean that cursor jitters, moves away from target when hitting the button?
2014/1/16 Dylan Thurston <dpthurst@indiana.edu>:
> Another small issue: it's a little difficult to click in the touchpad
> area without moving the mouse. This can make it difficult to hit small
> buttons.
>
> --Dylan
>
> On Wed, Jan 15, 2014 at 08:00:34AM -0500, Dylan Thurston wrote:
>> One glitch: I see mouse jumping sometimes when dragging. This has
>> happened a couple times when resizing windows with a right-click and
>> drag.
>>
>> I'm using X.org from Debian unstable, in case that's relevant.
>>
>> --Dylan
>>
>> On Wed, Jan 15, 2014 at 12:16:50AM -0500, Dylan Thurston wrote:
>> > This patch seems to work in the 3.13-rc8 kernel, at least on an
>> > initial check. The problems with excess clicks while typing have
>> > disappeared. I'll report back with any glitches I see.
>> >
>> > Thank you!
>> >
>> > --Dylan
>> >
>> > On Wed, Jan 15, 2014 at 11:15:02AM +0800, Elaine Chen wrote:
>> > > Hi Dylan,
>> > >
>> > > Thank you! This patch is againt Dmitry Torokhov's input tree, based on
>> > > the modification of:
>> > > 2013-12-26 Input: ALPS - add support for "Dolphin" devices Yunkang Tang
>> > > As linux-next-20140114 has already merged Dolphin support, the patch
>> > > should be matched.
>> > > As for the blank screen, I'll debug on my side. Sorry for that.
>> > > What is the kernel version on your HP side? Is it 3.13-rc8?
>> > >
>> > > Yes, it is safe to copy both alps.c and alps.h from linux-next version
>> > > to 3.13-rc8 kerenl.
>> > >
>> > >
>> > >
>> > > 2014/1/15 Dylan Thurston <dpthurst@indiana.edu>:
>> > > > Thank you! Which versions does this apply against? It patched for me
>> > > > with no fuzz against linux-next-20140114, but unfortunately X seems to
>> > > > be broken for me on that version (blank screen). I get fuzz and
>> > > > rejected patches when applying it to 3.13-rc8. Is it safe to just copy
>> > > > over alps.c from the linux-next version?
>> > > >
>> > > > (Of course, it's possible that the blank screen is a side effect of
>> > > > the correct recognition of the touchpad.)
>> > > >
>> > > > Thanks,
>> > > > Dylan
>> > > >
>> > > > On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
>> > > >> Hi Dylan,
>> > > >>
>> > > >> My colleague Elaine has prepared the patch for new ALPS touchpad that
>> > > >> being used on your HP Revolve 810 G1 laptop.
>> > > >> You can have a try~
>> > > >>
>> > > >> --
>> > > >> Best Regards,
>> > > >> Tommy
>> > > >>
>> > > >> ---------- Forwarded message ----------
>> > > >> From: Elaine Chen <elaineee66@gmail.com>
>> > > >> Date: 2014/1/14
>> > > >> Subject: Re: [PATCH] add support for ALPS v7 protocol device
>> > > >> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
>> > > >> david turvene <dturvene@dahetral.com>
>> > > >> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
>> > > >> Qiting Chen <qiting.chen@cn.alps.com>
>> > > >>
>> > > >>
>> > > >> As far as I know, the ALPS v7 protocol device is used on following laptops:
>> > > >>
>> > > >> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
>> > > >>
>> > > >> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
>> > > >> > Here is the patch of supporting ALPS v7 protocol device.
>> > > >> >
>> > > >> > v7 device is a clickpad device.
>> > > >> > Device info:
>> > > >> > Device ID = 0x73, 0x03, 0x0a
>> > > >> > Firmware ID = 0x88, 0xb*, 0x**
>> > > >> >
>> > > >> > Support function of v7 device:
>> > > >> > - Cursor
>> > > >> > - Tap, double tap, tap drag, 2finger tap
>> > > >> > - Pan, pinch
>> > > >> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
>> > > >> > Click touchpad with all fingers outside right Button Area --> left click
>> > > >> > Click touchpad with at lease 1 finger inside right Button Area --> right click
>> > > >> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
>> > > >> >
>> > > >> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
>> > > >> > We tried registering our device as a clickpad by:
>> > > >> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
>> > > >> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
>> > > >> >
>> > > >> >
>> > > >> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>> > > >> > ---
>> > > >> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
>> > > >> > drivers/input/mouse/alps.h | 127 ++++++++++--
>> > > >> > 2 files changed, 554 insertions(+), 51 deletions(-)
>> > > >> >
>> > > >> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>> > > >> > index fb15c64..3e8e8f7 100644
>> > > >> > --- a/drivers/input/mouse/alps.c
>> > > >> > +++ b/drivers/input/mouse/alps.c
>> > > >> > @@ -32,6 +32,11 @@
>> > > >> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
>> > > >> > #define ALPS_REG_BASE_PINNACLE 0x0000
>> > > >> >
>> > > >> > +#define LEFT_BUTTON_BIT 0x01
>> > > >> > +#define RIGHT_BUTTON_BIT 0x02
>> > > >> > +
>> > > >> > +#define V7_LARGE_MOVEMENT 130
>> > > >> > +
>> > > >> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>> > > >> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
>> > > >> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
>> > > >> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
>> > > >> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
>> > > >> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
>> > > >> > 6-byte ALPS packet */
>> > > >> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
>> > > >> >
>> > > >> > static const struct alps_model_info alps_model_data[] = {
>> > > >> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
>> > > >> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>> > > >> > * isn't valid per PS/2 spec.
>> > > >> > */
>> > > >> >
>> > > >> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>> > > >> > + struct alps_abs_data *pt1)
>> > > >> > +{
>> > > >> > + int vect_x, vect_y;
>> > > >> > +
>> > > >> > + if (!pt0 || !pt1)
>> > > >> > + return 0;
>> > > >> > +
>> > > >> > + vect_x = pt0->x - pt1->x;
>> > > >> > + vect_y = pt0->y - pt1->y;
>> > > >> > +
>> > > >> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>> > > >> > +}
>> > > >> > +
>> > > >> > /* Packet formats are described in Documentation/input/alps.txt */
>> > > >> >
>> > > >> > static bool alps_is_valid_first_byte(struct alps_data *priv,
>> > > >> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
>> > > >> > end_bit = y_msb - 1;
>> > > >> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>> > > >> > (2 * (priv->y_bits - 1));
>> > > >> > - *x1 = fields->x;
>> > > >> > - *y1 = fields->y;
>> > > >> > + *x1 = fields->pt.x;
>> > > >> > + *y1 = fields->pt.y;
>> > > >> > *x2 = 2 * box_middle_x - *x1;
>> > > >> > *y2 = 2 * box_middle_y - *y1;
>> > > >> > }
>> > > >> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
>> > > >> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>> > > >> > }
>> > > >> >
>> > > >> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>> > > >> > + struct alps_fields *f)
>> > > >> > +{
>> > > >> > + struct input_dev *dev;
>> > > >> > +
>> > > >> > + if (!psmouse || !f)
>> > > >> > + return;
>> > > >> > +
>> > > >> > + dev = psmouse->dev;
>> > > >> > +
>> > > >> > + if (f->fingers) {
>> > > >> > + input_report_key(dev, BTN_TOUCH, 1);
>> > > >> > + alps_report_semi_mt_data(dev, f->fingers,
>> > > >> > + f->pt_img[0].x, f->pt_img[0].y,
>> > > >> > + f->pt_img[1].x, f->pt_img[1].y);
>> > > >> > + input_mt_report_finger_count(dev, f->fingers);
>> > > >> > +
>> > > >> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
>> > > >> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>> > > >> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>> > > >> > + } else {
>> > > >> > + input_report_key(dev, BTN_TOUCH, 0);
>> > > >> > + input_mt_report_finger_count(dev, 0);
>> > > >> > + input_report_abs(dev, ABS_PRESSURE, 0);
>> > > >> > + }
>> > > >> > +
>> > > >> > + input_report_key(dev, BTN_LEFT, f->btn.left);
>> > > >> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
>> > > >> > +
>> > > >> > + input_sync(dev);
>> > > >> > +}
>> > > >> > +
>> > > >> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> > > >> > {
>> > > >> > struct alps_data *priv = psmouse->private;
>> > > >> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> > > >> >
>> > > >> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
>> > > >> > {
>> > > >> > - f->left = !!(p[3] & 0x01);
>> > > >> > - f->right = !!(p[3] & 0x02);
>> > > >> > - f->middle = !!(p[3] & 0x04);
>> > > >> > + f->btn.left = !!(p[3] & 0x01);
>> > > >> > + f->btn.right = !!(p[3] & 0x02);
>> > > >> > + f->btn.middle = !!(p[3] & 0x04);
>> > > >> >
>> > > >> > - f->ts_left = !!(p[3] & 0x10);
>> > > >> > - f->ts_right = !!(p[3] & 0x20);
>> > > >> > - f->ts_middle = !!(p[3] & 0x40);
>> > > >> > + f->btn.ts_left = !!(p[3] & 0x10);
>> > > >> > + f->btn.ts_right = !!(p[3] & 0x20);
>> > > >> > + f->btn.ts_middle = !!(p[3] & 0x40);
>> > > >> > }
>> > > >> >
>> > > >> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
>> > > >> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
>> > > >> > ((p[2] & 0x7f) << 1) |
>> > > >> > (p[4] & 0x01);
>> > > >> >
>> > > >> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > > >> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > > >> > ((p[0] & 0x30) >> 4);
>> > > >> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > > >> > - f->z = p[5] & 0x7f;
>> > > >> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > > >> > + f->pt.z = p[5] & 0x7f;
>> > > >> >
>> > > >> > alps_decode_buttons_v3(f, p);
>> > > >> > }
>> > > >> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
>> > > >> > f->is_mp = !!(p[0] & 0x20);
>> > > >> >
>> > > >> > if (!f->is_mp) {
>> > > >> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > > >> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > > >> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > > >> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > > >> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > > >> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > > >> > alps_decode_buttons_v3(f, p);
>> > > >> > } else {
>> > > >> > f->fingers = ((p[0] & 0x6) >> 1 |
>> > > >> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> > > >> > * with x, y, and z all zero, so these seem to be flukes.
>> > > >> > * Ignore them.
>> > > >> > */
>> > > >> > - if (f.x && f.y && !f.z)
>> > > >> > + if (f.pt.x && f.pt.y && !f.pt.z)
>> > > >> > return;
>> > > >> >
>> > > >> > /*
>> > > >> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> > > >> > * to rely on ST data.
>> > > >> > */
>> > > >> > if (!fingers) {
>> > > >> > - x1 = f.x;
>> > > >> > - y1 = f.y;
>> > > >> > - fingers = f.z > 0 ? 1 : 0;
>> > > >> > + x1 = f.pt.x;
>> > > >> > + y1 = f.pt.y;
>> > > >> > + fingers = f.pt.z > 0 ? 1 : 0;
>> > > >> > }
>> > > >> >
>> > > >> > - if (f.z >= 64)
>> > > >> > + if (f.pt.z >= 64)
>> > > >> > input_report_key(dev, BTN_TOUCH, 1);
>> > > >> > else
>> > > >> > input_report_key(dev, BTN_TOUCH, 0);
>> > > >> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> > > >> >
>> > > >> > input_mt_report_finger_count(dev, fingers);
>> > > >> >
>> > > >> > - input_report_key(dev, BTN_LEFT, f.left);
>> > > >> > - input_report_key(dev, BTN_RIGHT, f.right);
>> > > >> > - input_report_key(dev, BTN_MIDDLE, f.middle);
>> > > >> > + input_report_key(dev, BTN_LEFT, f.btn.left);
>> > > >> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
>> > > >> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>> > > >> >
>> > > >> > - if (f.z > 0) {
>> > > >> > - input_report_abs(dev, ABS_X, f.x);
>> > > >> > - input_report_abs(dev, ABS_Y, f.y);
>> > > >> > + if (f.pt.z > 0) {
>> > > >> > + input_report_abs(dev, ABS_X, f.pt.x);
>> > > >> > + input_report_abs(dev, ABS_Y, f.pt.y);
>> > > >> > }
>> > > >> > - input_report_abs(dev, ABS_PRESSURE, f.z);
>> > > >> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>> > > >> >
>> > > >> > input_sync(dev);
>> > > >> >
>> > > >> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>> > > >> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
>> > > >> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
>> > > >> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
>> > > >> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>> > > >> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>> > > >> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>> > > >> > input_sync(dev2);
>> > > >> > }
>> > > >> > }
>> > > >> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
>> > > >> > input_sync(dev);
>> > > >> > }
>> > > >> >
>> > > >> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>> > > >> > +{
>> > > >> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
>> > > >> > + return false;
>> > > >> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
>> > > >> > + return false;
>> > > >> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>> > > >> > + return false;
>> > > >> > + return true;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > + int drop = 1;
>> > > >> > +
>> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > > >> > + drop = 0;
>> > > >> > +
>> > > >> > + return drop;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static unsigned char alps_get_packet_id_v7(char *byte)
>> > > >> > +{
>> > > >> > + unsigned char packet_id;
>> > > >> > +
>> > > >> > + if (byte[4] & 0x40)
>> > > >> > + packet_id = V7_PACKET_ID_TWO;
>> > > >> > + else if (byte[4] & 0x01)
>> > > >> > + packet_id = V7_PACKET_ID_MULTI;
>> > > >> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>> > > >> > + packet_id = V7_PACKET_ID_NEW;
>> > > >> > + else
>> > > >> > + packet_id = V7_PACKET_ID_IDLE;
>> > > >> > +
>> > > >> > + return packet_id;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>> > > >> > + unsigned char *pkt,
>> > > >> > + unsigned char pkt_id)
>> > > >> > +{
>> > > >> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
>> > > >> > + (pkt_id == V7_PACKET_ID_MULTI) ||
>> > > >> > + (pkt_id == V7_PACKET_ID_NEW)) {
>> > > >> > + pt[0].x = ((pkt[2] & 0x80) << 4);
>> > > >> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
>> > > >> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
>> > > >> > + pt[0].x |= (pkt[3] & 0x07);
>> > > >> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>> > > >> > +
>> > > >> > + pt[1].x = ((pkt[3] & 0x80) << 4);
>> > > >> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
>> > > >> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
>> > > >> > + pt[1].y = ((pkt[5] & 0x80) << 3);
>> > > >> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
>> > > >> > +
>> > > >> > + if (pkt_id == V7_PACKET_ID_TWO) {
>> > > >> > + pt[1].x &= ~0x000F;
>> > > >> > + pt[1].y |= 0x000F;
>> > > >> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
>> > > >> > + pt[1].x &= ~0x003F;
>> > > >> > + pt[1].y &= ~0x0020;
>> > > >> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
>> > > >> > + pt[1].y |= 0x001F;
>> > > >> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
>> > > >> > + pt[1].x &= ~0x003F;
>> > > >> > + pt[1].x |= (pkt[0] & 0x20);
>> > > >> > + pt[1].y |= 0x000F;
>> > > >> > + }
>> > > >> > +
>> > > >> > + pt[0].y = 0x7FF - pt[0].y;
>> > > >> > + pt[1].y = 0x7FF - pt[1].y;
>> > > >> > +
>> > > >> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>> > > >> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>> > > >> > + }
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_decode_packet_v7(struct alps_fields *f,
>> > > >> > + unsigned char *p,
>> > > >> > + struct psmouse *psmouse)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > +
>> > > >> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>> > > >> > +
>> > > >> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>> > > >> > +
>> > > >> > + priv->r.v7.rest_left = 0;
>> > > >> > + priv->r.v7.rest_right = 0;
>> > > >> > + priv->r.v7.additional_fingers = 0;
>> > > >> > + priv->phy_btn = 0;
>> > > >> > +
>> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>> > > >> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>> > > >> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>> > > >> > + }
>> > > >> > +
>> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > > >> > + priv->r.v7.additional_fingers = p[5] & 0x03;
>> > > >> > +
>> > > >> > + priv->phy_btn = (p[0] & 0x80) >> 7;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>> > > >> > + struct alps_abs_data *pt,
>> > > >> > + struct alps_bl_pt_attr *pt_attr)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > + unsigned int dist;
>> > > >> > +
>> > > >> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
>> > > >> > + pt_attr->is_init_pt_got = 1;
>> > > >> > + pt_attr->is_counted = 0;
>> > > >> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>> > > >> > + }
>> > > >> > +
>> > > >> > + if (pt->z != 0) {
>> > > >> > + if (pt->y < priv->resting_zone_y_min) {
>> > > >> > + /* A finger is recognized as a non-resting finger
>> > > >> > + if it's position is outside the resting finger zone.*/
>> > > >> > + pt_attr->zone = ZONE_NORMAL;
>> > > >> > + pt_attr->is_counted = 1;
>> > > >> > + } else {
>> > > >> > + /* A finger is recognized as a resting finger if it's
>> > > >> > + position is inside the resting finger zone and there's
>> > > >> > + no large movement from it's touch down position.*/
>> > > >> > + pt_attr->zone = ZONE_RESTING;
>> > > >> > +
>> > > >> > + if (pt->x > priv->x_max / 2)
>> > > >> > + pt_attr->zone |= ZONE_RIGHT_BTN;
>> > > >> > + else
>> > > >> > + pt_attr->zone |= ZONE_LEFT_BTN;
>> > > >> > +
>> > > >> > + /* A resting finger will turn to be a non-resting
>> > > >> > + finger if it has made large movement from it's touch
>> > > >> > + down position. A non-resting finger will never turn
>> > > >> > + to a resting finger before it leaves the touchpad
>> > > >> > + surface.*/
>> > > >> > + if (pt_attr->is_init_pt_got) {
>> > > >> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
>> > > >> > +
>> > > >> > + if (dist > V7_LARGE_MOVEMENT)
>> > > >> > + pt_attr->is_counted = 1;
>> > > >> > + }
>> > > >> > + }
>> > > >> > + }
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>> > > >> > + struct alps_fields *f)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > + int i;
>> > > >> > +
>> > > >> > + switch (priv->r.v7.pkt_id) {
>> > > >> > + case V7_PACKET_ID_TWO:
>> > > >> > + case V7_PACKET_ID_MULTI:
>> > > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
>> > > >> > + alps_set_each_pt_attr_v7(psmouse,
>> > > >> > + &f->pt_img[i],
>> > > >> > + &priv->pt_attr[i]);
>> > > >> > + break;
>> > > >> > + default:
>> > > >> > + /*All finger attributes are cleared when packet ID is
>> > > >> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>> > > >> > + indicates that there's no finger and no button activity.
>> > > >> > + A 'NEW' packet indicates the finger position in packet
>> > > >> > + is not continues from previous packet. Such as the
>> > > >> > + condition there's finger placed or lifted. In these cases,
>> > > >> > + finger attributes will be reset.*/
>> > > >> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> > > >> > + break;
>> > > >> > + }
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>> > > >> > + struct alps_fields *f)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > + unsigned int fn = 0;
>> > > >> > + int i;
>> > > >> > +
>> > > >> > + switch (priv->r.v7.pkt_id) {
>> > > >> > + case V7_PACKET_ID_IDLE:
>> > > >> > + case V7_PACKET_ID_NEW:
>> > > >> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
>> > > >> > + An 'IDLE' packet indicates that there's no finger on touchpad.
>> > > >> > + A 'NEW' packet indicates there's finger placed or lifted.
>> > > >> > + Finger position of 'New' packet is not continues from the
>> > > >> > + previous packet.*/
>> > > >> > + fn = 0;
>> > > >> > + break;
>> > > >> > + case V7_PACKET_ID_TWO:
>> > > >> > + if (f->pt_img[0].z == 0) {
>> > > >> > + /*The first finger slot is zero when a non-resting
>> > > >> > + finger lifted and remaining only one resting finger
>> > > >> > + on touchpad. Hardware report the remaining resting
>> > > >> > + finger in second slot. This resting is ignored*/
>> > > >> > + fn = 0;
>> > > >> > + } else if (f->pt_img[1].z == 0) {
>> > > >> > + /* The second finger slot is zero if there's
>> > > >> > + only one finger*/
>> > > >> > + fn = 1;
>> > > >> > + } else {
>> > > >> > + /*All non-resting fingers will be counted to report*/
>> > > >> > + fn = 0;
>> > > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > > >> > + if (priv->pt_attr[i].is_counted)
>> > > >> > + fn++;
>> > > >> > + }
>> > > >> > +
>> > > >> > + /*In the case that both fingers are
>> > > >> > + resting fingers, report the first one*/
>> > > >> > + if (!priv->pt_attr[0].is_counted &&
>> > > >> > + !priv->pt_attr[1].is_counted) {
>> > > >> > + fn = 1;
>> > > >> > + }
>> > > >> > + }
>> > > >> > + break;
>> > > >> > + case V7_PACKET_ID_MULTI:
>> > > >> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
>> > > >> > + finger exist.*/
>> > > >> > + fn = 3 + priv->r.v7.additional_fingers;
>> > > >> > + break;
>> > > >> > + }
>> > > >> > +
>> > > >> > + f->fingers = fn;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>> > > >> > + struct alps_fields *f)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > +
>> > > >> > + if (priv->phy_btn) {
>> > > >> > + if (!priv->prev_phy_btn) {
>> > > >> > + /* Report a right click as long as there's finger on
>> > > >> > + right button zone. Othrewise, report a left click.*/
>> > > >> > + if (priv->r.v7.rest_right ||
>> > > >> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>> > > >> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>> > > >> > + f->btn.right = 1;
>> > > >> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>> > > >> > + } else {
>> > > >> > + f->btn.left = 1;
>> > > >> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>> > > >> > + }
>> > > >> > + } else {
>> > > >> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>> > > >> > + f->btn.right = 1;
>> > > >> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>> > > >> > + f->btn.left = 1;
>> > > >> > + }
>> > > >> > + } else {
>> > > >> > + priv->pressed_btn_bits = 0;
>> > > >> > + f->btn.right = 0;
>> > > >> > + f->btn.left = 0;
>> > > >> > + }
>> > > >> > +
>> > > >> > + priv->prev_phy_btn = priv->phy_btn;
>> > > >> > +}
>> > > >> > +
>> > > >> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>> > > >> > +{
>> > > >> > + struct alps_data *priv = psmouse->private;
>> > > >> > + struct alps_fields f = {0};
>> > > >> > + unsigned char *packet = psmouse->packet;
>> > > >> > +
>> > > >> > + priv->decode_fields(&f, packet, psmouse);
>> > > >> > +
>> > > >> > + if (alps_drop_unsupported_packet_v7(psmouse))
>> > > >> > + return;
>> > > >> > +
>> > > >> > + alps_set_pt_attr_v7(psmouse, &f);
>> > > >> > +
>> > > >> > + alps_cal_output_finger_num_v7(psmouse, &f);
>> > > >> > +
>> > > >> > + alps_assign_buttons_v7(psmouse, &f);
>> > > >> > +
>> > > >> > + alps_report_coord_and_btn(psmouse, &f);
>> > > >> > +}
>> > > >> > +
>> > > >> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>> > > >> > unsigned char packet[],
>> > > >> > bool report_buttons)
>> > > >> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
>> > > >> > return PSMOUSE_BAD_DATA;
>> > > >> > }
>> > > >> >
>> > > >> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
>> > > >> > + !alps_is_valid_package_v7(psmouse))) {
>> > > >> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>> > > >> > + psmouse->pktcnt - 1,
>> > > >> > + psmouse->packet[psmouse->pktcnt - 1]);
>> > > >> > + return PSMOUSE_BAD_DATA;
>> > > >> > + }
>> > > >> > +
>> > > >> > if (psmouse->pktcnt == psmouse->pktsize) {
>> > > >> > priv->process_packet(psmouse);
>> > > >> > return PSMOUSE_FULL_PACKET;
>> > > >> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
>> > > >> > return 0;
>> > > >> > }
>> > > >> >
>> > > >> > +static int alps_check_valid_firmware_id(unsigned char id[])
>> > > >> > +{
>> > > >> > + int valid = 1;
>> > > >> > +
>> > > >> > + if (id[0] == 0x73)
>> > > >> > + valid = 1;
>> > > >> > + else if (id[0] == 0x88) {
>> > > >> > + if ((id[1] == 0x07) ||
>> > > >> > + (id[1] == 0x08) ||
>> > > >> > + ((id[1] & 0xf0) == 0xB0))
>> > > >> > + valid = 1;
>> > > >> > + }
>> > > >> > +
>> > > >> > + return valid;
>> > > >> > +}
>> > > >> > +
>> > > >> > static int alps_enter_command_mode(struct psmouse *psmouse)
>> > > >> > {
>> > > >> > unsigned char param[4];
>> > > >> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
>> > > >> > return -1;
>> > > >> > }
>> > > >> >
>> > > >> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>> > > >> > - param[0] != 0x73) {
>> > > >> > + if (!alps_check_valid_firmware_id(param)) {
>> > > >> > psmouse_dbg(psmouse,
>> > > >> > "unknown response while entering command mode\n");
>> > > >> > return -1;
>> > > >> > @@ -1704,6 +2067,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)
>> > > >> > {
>> > > >> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > > >> > priv->set_abs_params = alps_set_abs_params_st;
>> > > >> > priv->x_max = 1023;
>> > > >> > priv->y_max = 767;
>> > > >> > + priv->slot_number = 1;
>> > > >> > break;
>> > > >> > case ALPS_PROTO_V3:
>> > > >> > priv->hw_init = alps_hw_init_v3;
>> > > >> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > > >> > priv->decode_fields = alps_decode_pinnacle;
>> > > >> > priv->nibble_commands = alps_v3_nibble_commands;
>> > > >> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > > >> > + priv->slot_number = 2;
>> > > >> > break;
>> > > >> > case ALPS_PROTO_V4:
>> > > >> > priv->hw_init = alps_hw_init_v4;
>> > > >> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > > >> > priv->set_abs_params = alps_set_abs_params_mt;
>> > > >> > priv->nibble_commands = alps_v4_nibble_commands;
>> > > >> > priv->addr_command = PSMOUSE_CMD_DISABLE;
>> > > >> > + priv->slot_number = 2;
>> > > >> > break;
>> > > >> > case ALPS_PROTO_V5:
>> > > >> > priv->hw_init = alps_hw_init_dolphin_v1;
>> > > >> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > > >> > priv->y_max = 660;
>> > > >> > priv->x_bits = 23;
>> > > >> > priv->y_bits = 12;
>> > > >> > + priv->slot_number = 2;
>> > > >> > break;
>> > > >> > case ALPS_PROTO_V6:
>> > > >> > priv->hw_init = alps_hw_init_v6;
>> > > >> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
>> > > >> > priv->nibble_commands = alps_v6_nibble_commands;
>> > > >> > priv->x_max = 2047;
>> > > >> > priv->y_max = 1535;
>> > > >> > + priv->slot_number = 2;
>> > > >> > + break;
>> > > >> > + case ALPS_PROTO_V7:
>> > > >> > + priv->hw_init = alps_hw_init_v7;
>> > > >> > + priv->process_packet = alps_process_packet_v7;
>> > > >> > + priv->decode_fields = alps_decode_packet_v7;
>> > > >> > + priv->set_abs_params = alps_set_abs_params_mt;
>> > > >> > + priv->nibble_commands = alps_v3_nibble_commands;
>> > > >> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > > >> > + priv->x_max = 0xfff;
>> > > >> > + priv->y_max = 0x7ff;
>> > > >> > + priv->resting_zone_y_min = 0x654;
>> > > >> > + priv->byte0 = 0x48;
>> > > >> > + priv->mask0 = 0x48;
>> > > >> > + priv->flags = 0;
>> > > >> > + priv->slot_number = 2;
>> > > >> > break;
>> > > >> > }
>> > > >> > }
>> > > >> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
>> > > >> > return -EIO;
>> > > >> > else
>> > > >> > return 0;
>> > > >> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>> > > >> > + priv->proto_version = ALPS_PROTO_V7;
>> > > >> > + alps_set_defaults(priv);
>> > > >> > +
>> > > >> > + return 0;
>> > > >> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>> > > >> > priv->proto_version = ALPS_PROTO_V3;
>> > > >> > alps_set_defaults(priv);
>> > > >> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>> > > >> > struct input_dev *dev1)
>> > > >> > {
>> > > >> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>> > > >> > - input_mt_init_slots(dev1, 2, 0);
>> > > >> > + input_mt_init_slots(dev1, priv->slot_number, 0);
>> > > >> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
>> > > >> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
>> > > >> >
>> > > >> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>> > > >> > index 03f88b6..5d2f9ea 100644
>> > > >> > --- a/drivers/input/mouse/alps.h
>> > > >> > +++ b/drivers/input/mouse/alps.h
>> > > >> > @@ -18,11 +18,36 @@
>> > > >> > #define ALPS_PROTO_V4 4
>> > > >> > #define ALPS_PROTO_V5 5
>> > > >> > #define ALPS_PROTO_V6 6
>> > > >> > +#define ALPS_PROTO_V7 7
>> > > >> > +
>> > > >> > +#define MAX_IMG_PT_NUM 5
>> > > >> > +#define V7_IMG_PT_NUM 2
>> > > >> > +
>> > > >> > +#define ZONE_NORMAL 0x01
>> > > >> > +#define ZONE_RESTING 0x02
>> > > >> > +#define ZONE_LEFT_BTN 0x04
>> > > >> > +#define ZONE_RIGHT_BTN 0x08
>> > > >> >
>> > > >> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
>> > > >> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
>> > > >> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
>> > > >> >
>> > > >> > +/*
>> > > >> > + * enum V7_PACKET_ID - defines the packet type for V7
>> > > >> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>> > > >> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>> > > >> > + * or there's button activities.
>> > > >> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>> > > >> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>> > > >> > + * previous packet.
>> > > >> > +*/
>> > > >> > +enum V7_PACKET_ID {
>> > > >> > + V7_PACKET_ID_IDLE,
>> > > >> > + V7_PACKET_ID_TWO,
>> > > >> > + V7_PACKET_ID_MULTI,
>> > > >> > + V7_PACKET_ID_NEW,
>> > > >> > +};
>> > > >> > +
>> > > >> > /**
>> > > >> > * struct alps_model_info - touchpad ID table
>> > > >> > * @signature: E7 response string to match.
>> > > >> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>> > > >> > };
>> > > >> >
>> > > >> > /**
>> > > >> > - * struct alps_fields - decoded version of the report packet
>> > > >> > - * @x_map: Bitmap of active X positions for MT.
>> > > >> > - * @y_map: Bitmap of active Y positions for MT.
>> > > >> > - * @fingers: Number of fingers for MT.
>> > > >> > - * @x: X position for ST.
>> > > >> > - * @y: Y position for ST.
>> > > >> > - * @z: Z position for ST.
>> > > >> > - * @first_mp: Packet is the first of a multi-packet report.
>> > > >> > - * @is_mp: Packet is part of a multi-packet report.
>> > > >> > + * struct alps_btn - decoded version of the button status
>> > > >> > * @left: Left touchpad button is active.
>> > > >> > * @right: Right touchpad button is active.
>> > > >> > * @middle: Middle touchpad button is active.
>> > > >> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>> > > >> > * @ts_right: Right trackstick button is active.
>> > > >> > * @ts_middle: Middle trackstick button is active.
>> > > >> > */
>> > > >> > -struct alps_fields {
>> > > >> > - unsigned int x_map;
>> > > >> > - unsigned int y_map;
>> > > >> > - unsigned int fingers;
>> > > >> > - unsigned int x;
>> > > >> > - unsigned int y;
>> > > >> > - unsigned int z;
>> > > >> > - unsigned int first_mp:1;
>> > > >> > - unsigned int is_mp:1;
>> > > >> > -
>> > > >> > +struct alps_btn {
>> > > >> > unsigned int left:1;
>> > > >> > unsigned int right:1;
>> > > >> > unsigned int middle:1;
>> > > >> > @@ -102,6 +110,69 @@ struct alps_fields {
>> > > >> > };
>> > > >> >
>> > > >> > /**
>> > > >> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>> > > >> > + * @x: X position for ST.
>> > > >> > + * @y: Y position for ST.
>> > > >> > + * @z: Z position for ST.
>> > > >> > + */
>> > > >> > +struct alps_abs_data {
>> > > >> > + unsigned int x;
>> > > >> > + unsigned int y;
>> > > >> > + unsigned int z;
>> > > >> > +};
>> > > >> > +
>> > > >> > +/**
>> > > >> > + * struct alps_fields - decoded version of the report packet
>> > > >> > + * @fingers: Number of fingers for MT.
>> > > >> > + * @pt: X Y Z postion for ST.
>> > > >> > + * @pt: X Y Z postion for image MT.
>> > > >> > + * @x_map: Bitmap of active X positions for MT.
>> > > >> > + * @y_map: Bitmap of active Y positions for MT.
>> > > >> > + * @first_mp: Packet is the first of a multi-packet report.
>> > > >> > + * @is_mp: Packet is part of a multi-packet report.
>> > > >> > + * @btn: Button activity status
>> > > >> > + */
>> > > >> > +struct alps_fields {
>> > > >> > + unsigned int fingers;
>> > > >> > + struct alps_abs_data pt;
>> > > >> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>> > > >> > + unsigned int x_map;
>> > > >> > + unsigned int y_map;
>> > > >> > + unsigned int first_mp:1;
>> > > >> > + unsigned int is_mp:1;
>> > > >> > + struct alps_btn btn;
>> > > >> > +};
>> > > >> > +
>> > > >> > +/**
>> > > >> > + * struct v7_raw - data decoded from raw packet for V7.
>> > > >> > + * @pkt_id: An id that specifies the type of packet.
>> > > >> > + * @additional_fingers: Number of additional finger that is neighter included
>> > > >> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
>> > > >> > + * @rest_left: There are fingers on left resting zone.
>> > > >> > + * @rest_right: There are fingers on right resting zone.
>> > > >> > + */
>> > > >> > +struct v7_raw {
>> > > >> > + unsigned char pkt_id;
>> > > >> > + unsigned int additional_fingers;
>> > > >> > + unsigned char rest_left;
>> > > >> > + unsigned char rest_right;
>> > > >> > +};
>> > > >> > +
>> > > >> > +/**
>> > > >> > + * 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;
>> > > >> > +};
>> > > >> > +
>> > > >> > +/**
>> > > >> > * struct alps_data - private data structure for the ALPS driver
>> > > >> > * @dev2: "Relative" device used to report trackstick or mouse activity.
>> > > >> > * @phys: Physical path for the relative device.
>> > > >> > @@ -116,8 +187,10 @@ struct alps_fields {
>> > > >> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
>> > > >> > * @x_max: Largest possible X position value.
>> > > >> > * @y_max: Largest possible Y position value.
>> > > >> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
>> > > >> > * @x_bits: Number of X bits in the MT bitmap.
>> > > >> > * @y_bits: Number of Y bits in the MT bitmap.
>> > > >> > + * @img_fingers: Number of image fingers.
>> > > >> > * @hw_init: Protocol-specific hardware init function.
>> > > >> > * @process_packet: Protocol-specific function to process a report packet.
>> > > >> > * @decode_fields: Protocol-specific function to read packet bitfields.
>> > > >> > @@ -132,6 +205,11 @@ struct alps_fields {
>> > > >> > * @fingers: Number of fingers from last MT report.
>> > > >> > * @quirks: Bitmap of ALPS_QUIRK_*.
>> > > >> > * @timer: Timer for flushing out the final report packet in the stream.
>> > > >> > + * @v7: Data decoded from raw packet for V7
>> > > >> > + * @phy_btn: Physical button is active.
>> > > >> > + * @prev_phy_btn: Physical button of previous packet is active.
>> > > >> > + * @pressed_btn_bits: Pressed positon of button zone
>> > > >> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>> > > >> > */
>> > > >> > struct alps_data {
>> > > >> > struct input_dev *dev2;
>> > > >> > @@ -145,8 +223,10 @@ struct alps_data {
>> > > >> > unsigned char flags;
>> > > >> > int x_max;
>> > > >> > int y_max;
>> > > >> > + int resting_zone_y_min;
>> > > >> > int x_bits;
>> > > >> > int y_bits;
>> > > >> > + unsigned char slot_number;
>> > > >> >
>> > > >> > int (*hw_init)(struct psmouse *psmouse);
>> > > >> > void (*process_packet)(struct psmouse *psmouse);
>> > > >> > @@ -161,6 +241,15 @@ struct alps_data {
>> > > >> > int fingers;
>> > > >> > u8 quirks;
>> > > >> > struct timer_list timer;
>> > > >> > +
>> > > >> > + /* these are used for buttonless touchpad*/
>> > > >> > + union {
>> > > >> > + struct v7_raw v7;
>> > > >> > + } r;
>> > > >> > + unsigned char phy_btn;
>> > > >> > + unsigned char prev_phy_btn;
>> > > >> > + unsigned char pressed_btn_bits;
>> > > >> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>> > > >> > };
>> > > >> >
>> > > >> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
>> > > >> > --
>> > > >> > 1.8.3.2
>> > > >> >
>> > > >> --
>> > > >> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>> > > >> the body of a message to majordomo@vger.kernel.org
>> > > >> More majordomo info at http://vger.kernel.org/majordomo-info.html
>> > > >>
>> > >
>> >
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] Input: wacom - Fix wacom->shared guards for dual input devices
From: Ping Cheng @ 2014-01-15 22:04 UTC (permalink / raw)
To: linux-input; +Cc: dmitry.torokhov, Ping Cheng
features->quirks can have multiple bits set. For dual input, we only
need to check WACOM_QUIRK_MULTI_INPUT.
Reviewed-by: Jason Gerecke <killertofu@gmail.com>
Signed-off-by: Ping Cheng <pingc@wacom.com>
---
drivers/input/tablet/wacom_wac.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index 048e5b3..0bcc7a6 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -331,7 +331,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
- if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
+ if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = true;
/* serial number of the tool */
@@ -436,7 +436,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
- if (features->quirks == WACOM_QUIRK_MULTI_INPUT)
+ if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = false;
/*
--
1.8.3.2
^ permalink raw reply related
* Re: [PATCH] ARM: Kirkwood: Add DT description of QNAP 419
From: Arnd Bergmann @ 2014-01-15 18:20 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrew Lunn, Jason Cooper, devicetree, linux-input,
Sebastian Hesselbarth, Ian Campbell, Gregory Clement, tbm
In-Reply-To: <20140115174519.GE17530@lunn.ch>
On Wednesday 15 January 2014 18:45:19 Andrew Lunn wrote:
> > > But i'm also a little bit concerned by the "unique number" and this
> > > ending up in /dev/input/by-path/platform-gpio_keys.3-event. Is this
> > > path supposed to be stable? This unique number is not stable. An
> > > unwitting change to the DT could cause its value to change. Do we need
> > > to make it stable?
> > >
> >
> > One possibility would be to create an artificial bus in DT for all
> > gpio-keys devices, use #address-cells=<1> and #size-cells=<0>
> > for it, and give each device a unique reg property. Not sure if that
> > would be considered an elegant solution though.
>
> Hi Arnd
>
> Can i imply from your answer that you think
>
> /dev/input/by-path/platform-gpio_keys.3-event
>
> should be stable?
No, I have no idea whether it should be or not. I was just trying
to come up with a way to make it stable if that's desired.
> A quick look at udev rules seems to suggestion this is an issue for
> input/gpio-keys and maybe audio and video if there is a top level DT
> property collecting the different sub devices together for ASOC and
> V4L.
For some other subsystems, we have entries in /aliases/ to sort
them. Maybe that would work here to get a stable path independent
of the location in DT.
Arnd
^ permalink raw reply
* Re: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Dylan Thurston @ 2014-01-15 18:15 UTC (permalink / raw)
To: Elaine Chen
Cc: Tommy Will, Dmitry Torokhov, Kevin Cernekee, david turvene,
Niels de Vos, Justin Clift, Qiting Chen, linux-input
In-Reply-To: <20140115130034.GB6043@bostoncoop.net>
Another small issue: it's a little difficult to click in the touchpad
area without moving the mouse. This can make it difficult to hit small
buttons.
--Dylan
On Wed, Jan 15, 2014 at 08:00:34AM -0500, Dylan Thurston wrote:
> One glitch: I see mouse jumping sometimes when dragging. This has
> happened a couple times when resizing windows with a right-click and
> drag.
>
> I'm using X.org from Debian unstable, in case that's relevant.
>
> --Dylan
>
> On Wed, Jan 15, 2014 at 12:16:50AM -0500, Dylan Thurston wrote:
> > This patch seems to work in the 3.13-rc8 kernel, at least on an
> > initial check. The problems with excess clicks while typing have
> > disappeared. I'll report back with any glitches I see.
> >
> > Thank you!
> >
> > --Dylan
> >
> > On Wed, Jan 15, 2014 at 11:15:02AM +0800, Elaine Chen wrote:
> > > Hi Dylan,
> > >
> > > Thank you! This patch is againt Dmitry Torokhov's input tree, based on
> > > the modification of:
> > > 2013-12-26 Input: ALPS - add support for "Dolphin" devices Yunkang Tang
> > > As linux-next-20140114 has already merged Dolphin support, the patch
> > > should be matched.
> > > As for the blank screen, I'll debug on my side. Sorry for that.
> > > What is the kernel version on your HP side? Is it 3.13-rc8?
> > >
> > > Yes, it is safe to copy both alps.c and alps.h from linux-next version
> > > to 3.13-rc8 kerenl.
> > >
> > >
> > >
> > > 2014/1/15 Dylan Thurston <dpthurst@indiana.edu>:
> > > > Thank you! Which versions does this apply against? It patched for me
> > > > with no fuzz against linux-next-20140114, but unfortunately X seems to
> > > > be broken for me on that version (blank screen). I get fuzz and
> > > > rejected patches when applying it to 3.13-rc8. Is it safe to just copy
> > > > over alps.c from the linux-next version?
> > > >
> > > > (Of course, it's possible that the blank screen is a side effect of
> > > > the correct recognition of the touchpad.)
> > > >
> > > > Thanks,
> > > > Dylan
> > > >
> > > > On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
> > > >> Hi Dylan,
> > > >>
> > > >> My colleague Elaine has prepared the patch for new ALPS touchpad that
> > > >> being used on your HP Revolve 810 G1 laptop.
> > > >> You can have a try~
> > > >>
> > > >> --
> > > >> Best Regards,
> > > >> Tommy
> > > >>
> > > >> ---------- Forwarded message ----------
> > > >> From: Elaine Chen <elaineee66@gmail.com>
> > > >> Date: 2014/1/14
> > > >> Subject: Re: [PATCH] add support for ALPS v7 protocol device
> > > >> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
> > > >> david turvene <dturvene@dahetral.com>
> > > >> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
> > > >> Qiting Chen <qiting.chen@cn.alps.com>
> > > >>
> > > >>
> > > >> As far as I know, the ALPS v7 protocol device is used on following laptops:
> > > >>
> > > >> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
> > > >>
> > > >> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> > > >> > Here is the patch of supporting ALPS v7 protocol device.
> > > >> >
> > > >> > v7 device is a clickpad device.
> > > >> > Device info:
> > > >> > Device ID = 0x73, 0x03, 0x0a
> > > >> > Firmware ID = 0x88, 0xb*, 0x**
> > > >> >
> > > >> > Support function of v7 device:
> > > >> > - Cursor
> > > >> > - Tap, double tap, tap drag, 2finger tap
> > > >> > - Pan, pinch
> > > >> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> > > >> > Click touchpad with all fingers outside right Button Area --> left click
> > > >> > Click touchpad with at lease 1 finger inside right Button Area --> right click
> > > >> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
> > > >> >
> > > >> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> > > >> > We tried registering our device as a clickpad by:
> > > >> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> > > >> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
> > > >> >
> > > >> >
> > > >> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> > > >> > ---
> > > >> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> > > >> > drivers/input/mouse/alps.h | 127 ++++++++++--
> > > >> > 2 files changed, 554 insertions(+), 51 deletions(-)
> > > >> >
> > > >> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > > >> > index fb15c64..3e8e8f7 100644
> > > >> > --- a/drivers/input/mouse/alps.c
> > > >> > +++ b/drivers/input/mouse/alps.c
> > > >> > @@ -32,6 +32,11 @@
> > > >> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> > > >> > #define ALPS_REG_BASE_PINNACLE 0x0000
> > > >> >
> > > >> > +#define LEFT_BUTTON_BIT 0x01
> > > >> > +#define RIGHT_BUTTON_BIT 0x02
> > > >> > +
> > > >> > +#define V7_LARGE_MOVEMENT 130
> > > >> > +
> > > >> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> > > >> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> > > >> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> > > >> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> > > >> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> > > >> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> > > >> > 6-byte ALPS packet */
> > > >> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
> > > >> >
> > > >> > static const struct alps_model_info alps_model_data[] = {
> > > >> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> > > >> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > > >> > * isn't valid per PS/2 spec.
> > > >> > */
> > > >> >
> > > >> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> > > >> > + struct alps_abs_data *pt1)
> > > >> > +{
> > > >> > + int vect_x, vect_y;
> > > >> > +
> > > >> > + if (!pt0 || !pt1)
> > > >> > + return 0;
> > > >> > +
> > > >> > + vect_x = pt0->x - pt1->x;
> > > >> > + vect_y = pt0->y - pt1->y;
> > > >> > +
> > > >> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> > > >> > +}
> > > >> > +
> > > >> > /* Packet formats are described in Documentation/input/alps.txt */
> > > >> >
> > > >> > static bool alps_is_valid_first_byte(struct alps_data *priv,
> > > >> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> > > >> > end_bit = y_msb - 1;
> > > >> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> > > >> > (2 * (priv->y_bits - 1));
> > > >> > - *x1 = fields->x;
> > > >> > - *y1 = fields->y;
> > > >> > + *x1 = fields->pt.x;
> > > >> > + *y1 = fields->pt.y;
> > > >> > *x2 = 2 * box_middle_x - *x1;
> > > >> > *y2 = 2 * box_middle_y - *y1;
> > > >> > }
> > > >> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> > > >> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> > > >> > }
> > > >> >
> > > >> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> > > >> > + struct alps_fields *f)
> > > >> > +{
> > > >> > + struct input_dev *dev;
> > > >> > +
> > > >> > + if (!psmouse || !f)
> > > >> > + return;
> > > >> > +
> > > >> > + dev = psmouse->dev;
> > > >> > +
> > > >> > + if (f->fingers) {
> > > >> > + input_report_key(dev, BTN_TOUCH, 1);
> > > >> > + alps_report_semi_mt_data(dev, f->fingers,
> > > >> > + f->pt_img[0].x, f->pt_img[0].y,
> > > >> > + f->pt_img[1].x, f->pt_img[1].y);
> > > >> > + input_mt_report_finger_count(dev, f->fingers);
> > > >> > +
> > > >> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> > > >> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> > > >> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> > > >> > + } else {
> > > >> > + input_report_key(dev, BTN_TOUCH, 0);
> > > >> > + input_mt_report_finger_count(dev, 0);
> > > >> > + input_report_abs(dev, ABS_PRESSURE, 0);
> > > >> > + }
> > > >> > +
> > > >> > + input_report_key(dev, BTN_LEFT, f->btn.left);
> > > >> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
> > > >> > +
> > > >> > + input_sync(dev);
> > > >> > +}
> > > >> > +
> > > >> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> > > >> > {
> > > >> > struct alps_data *priv = psmouse->private;
> > > >> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> > > >> >
> > > >> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> > > >> > {
> > > >> > - f->left = !!(p[3] & 0x01);
> > > >> > - f->right = !!(p[3] & 0x02);
> > > >> > - f->middle = !!(p[3] & 0x04);
> > > >> > + f->btn.left = !!(p[3] & 0x01);
> > > >> > + f->btn.right = !!(p[3] & 0x02);
> > > >> > + f->btn.middle = !!(p[3] & 0x04);
> > > >> >
> > > >> > - f->ts_left = !!(p[3] & 0x10);
> > > >> > - f->ts_right = !!(p[3] & 0x20);
> > > >> > - f->ts_middle = !!(p[3] & 0x40);
> > > >> > + f->btn.ts_left = !!(p[3] & 0x10);
> > > >> > + f->btn.ts_right = !!(p[3] & 0x20);
> > > >> > + f->btn.ts_middle = !!(p[3] & 0x40);
> > > >> > }
> > > >> >
> > > >> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > > >> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > > >> > ((p[2] & 0x7f) << 1) |
> > > >> > (p[4] & 0x01);
> > > >> >
> > > >> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > > >> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > > >> > ((p[0] & 0x30) >> 4);
> > > >> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > > >> > - f->z = p[5] & 0x7f;
> > > >> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > > >> > + f->pt.z = p[5] & 0x7f;
> > > >> >
> > > >> > alps_decode_buttons_v3(f, p);
> > > >> > }
> > > >> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> > > >> > f->is_mp = !!(p[0] & 0x20);
> > > >> >
> > > >> > if (!f->is_mp) {
> > > >> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > > >> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > > >> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > > >> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > > >> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > > >> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > > >> > alps_decode_buttons_v3(f, p);
> > > >> > } else {
> > > >> > f->fingers = ((p[0] & 0x6) >> 1 |
> > > >> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > > >> > * with x, y, and z all zero, so these seem to be flukes.
> > > >> > * Ignore them.
> > > >> > */
> > > >> > - if (f.x && f.y && !f.z)
> > > >> > + if (f.pt.x && f.pt.y && !f.pt.z)
> > > >> > return;
> > > >> >
> > > >> > /*
> > > >> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > > >> > * to rely on ST data.
> > > >> > */
> > > >> > if (!fingers) {
> > > >> > - x1 = f.x;
> > > >> > - y1 = f.y;
> > > >> > - fingers = f.z > 0 ? 1 : 0;
> > > >> > + x1 = f.pt.x;
> > > >> > + y1 = f.pt.y;
> > > >> > + fingers = f.pt.z > 0 ? 1 : 0;
> > > >> > }
> > > >> >
> > > >> > - if (f.z >= 64)
> > > >> > + if (f.pt.z >= 64)
> > > >> > input_report_key(dev, BTN_TOUCH, 1);
> > > >> > else
> > > >> > input_report_key(dev, BTN_TOUCH, 0);
> > > >> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > > >> >
> > > >> > input_mt_report_finger_count(dev, fingers);
> > > >> >
> > > >> > - input_report_key(dev, BTN_LEFT, f.left);
> > > >> > - input_report_key(dev, BTN_RIGHT, f.right);
> > > >> > - input_report_key(dev, BTN_MIDDLE, f.middle);
> > > >> > + input_report_key(dev, BTN_LEFT, f.btn.left);
> > > >> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
> > > >> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
> > > >> >
> > > >> > - if (f.z > 0) {
> > > >> > - input_report_abs(dev, ABS_X, f.x);
> > > >> > - input_report_abs(dev, ABS_Y, f.y);
> > > >> > + if (f.pt.z > 0) {
> > > >> > + input_report_abs(dev, ABS_X, f.pt.x);
> > > >> > + input_report_abs(dev, ABS_Y, f.pt.y);
> > > >> > }
> > > >> > - input_report_abs(dev, ABS_PRESSURE, f.z);
> > > >> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
> > > >> >
> > > >> > input_sync(dev);
> > > >> >
> > > >> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> > > >> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
> > > >> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> > > >> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> > > >> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> > > >> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> > > >> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> > > >> > input_sync(dev2);
> > > >> > }
> > > >> > }
> > > >> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> > > >> > input_sync(dev);
> > > >> > }
> > > >> >
> > > >> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> > > >> > +{
> > > >> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> > > >> > + return false;
> > > >> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> > > >> > + return false;
> > > >> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> > > >> > + return false;
> > > >> > + return true;
> > > >> > +}
> > > >> > +
> > > >> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > + int drop = 1;
> > > >> > +
> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> > > >> > + drop = 0;
> > > >> > +
> > > >> > + return drop;
> > > >> > +}
> > > >> > +
> > > >> > +static unsigned char alps_get_packet_id_v7(char *byte)
> > > >> > +{
> > > >> > + unsigned char packet_id;
> > > >> > +
> > > >> > + if (byte[4] & 0x40)
> > > >> > + packet_id = V7_PACKET_ID_TWO;
> > > >> > + else if (byte[4] & 0x01)
> > > >> > + packet_id = V7_PACKET_ID_MULTI;
> > > >> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> > > >> > + packet_id = V7_PACKET_ID_NEW;
> > > >> > + else
> > > >> > + packet_id = V7_PACKET_ID_IDLE;
> > > >> > +
> > > >> > + return packet_id;
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> > > >> > + unsigned char *pkt,
> > > >> > + unsigned char pkt_id)
> > > >> > +{
> > > >> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
> > > >> > + (pkt_id == V7_PACKET_ID_MULTI) ||
> > > >> > + (pkt_id == V7_PACKET_ID_NEW)) {
> > > >> > + pt[0].x = ((pkt[2] & 0x80) << 4);
> > > >> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> > > >> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> > > >> > + pt[0].x |= (pkt[3] & 0x07);
> > > >> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> > > >> > +
> > > >> > + pt[1].x = ((pkt[3] & 0x80) << 4);
> > > >> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
> > > >> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> > > >> > + pt[1].y = ((pkt[5] & 0x80) << 3);
> > > >> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> > > >> > +
> > > >> > + if (pkt_id == V7_PACKET_ID_TWO) {
> > > >> > + pt[1].x &= ~0x000F;
> > > >> > + pt[1].y |= 0x000F;
> > > >> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> > > >> > + pt[1].x &= ~0x003F;
> > > >> > + pt[1].y &= ~0x0020;
> > > >> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
> > > >> > + pt[1].y |= 0x001F;
> > > >> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
> > > >> > + pt[1].x &= ~0x003F;
> > > >> > + pt[1].x |= (pkt[0] & 0x20);
> > > >> > + pt[1].y |= 0x000F;
> > > >> > + }
> > > >> > +
> > > >> > + pt[0].y = 0x7FF - pt[0].y;
> > > >> > + pt[1].y = 0x7FF - pt[1].y;
> > > >> > +
> > > >> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> > > >> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> > > >> > + }
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_decode_packet_v7(struct alps_fields *f,
> > > >> > + unsigned char *p,
> > > >> > + struct psmouse *psmouse)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > +
> > > >> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> > > >> > +
> > > >> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> > > >> > +
> > > >> > + priv->r.v7.rest_left = 0;
> > > >> > + priv->r.v7.rest_right = 0;
> > > >> > + priv->r.v7.additional_fingers = 0;
> > > >> > + priv->phy_btn = 0;
> > > >> > +
> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> > > >> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> > > >> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> > > >> > + }
> > > >> > +
> > > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> > > >> > + priv->r.v7.additional_fingers = p[5] & 0x03;
> > > >> > +
> > > >> > + priv->phy_btn = (p[0] & 0x80) >> 7;
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> > > >> > + struct alps_abs_data *pt,
> > > >> > + struct alps_bl_pt_attr *pt_attr)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > + unsigned int dist;
> > > >> > +
> > > >> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> > > >> > + pt_attr->is_init_pt_got = 1;
> > > >> > + pt_attr->is_counted = 0;
> > > >> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> > > >> > + }
> > > >> > +
> > > >> > + if (pt->z != 0) {
> > > >> > + if (pt->y < priv->resting_zone_y_min) {
> > > >> > + /* A finger is recognized as a non-resting finger
> > > >> > + if it's position is outside the resting finger zone.*/
> > > >> > + pt_attr->zone = ZONE_NORMAL;
> > > >> > + pt_attr->is_counted = 1;
> > > >> > + } else {
> > > >> > + /* A finger is recognized as a resting finger if it's
> > > >> > + position is inside the resting finger zone and there's
> > > >> > + no large movement from it's touch down position.*/
> > > >> > + pt_attr->zone = ZONE_RESTING;
> > > >> > +
> > > >> > + if (pt->x > priv->x_max / 2)
> > > >> > + pt_attr->zone |= ZONE_RIGHT_BTN;
> > > >> > + else
> > > >> > + pt_attr->zone |= ZONE_LEFT_BTN;
> > > >> > +
> > > >> > + /* A resting finger will turn to be a non-resting
> > > >> > + finger if it has made large movement from it's touch
> > > >> > + down position. A non-resting finger will never turn
> > > >> > + to a resting finger before it leaves the touchpad
> > > >> > + surface.*/
> > > >> > + if (pt_attr->is_init_pt_got) {
> > > >> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> > > >> > +
> > > >> > + if (dist > V7_LARGE_MOVEMENT)
> > > >> > + pt_attr->is_counted = 1;
> > > >> > + }
> > > >> > + }
> > > >> > + }
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> > > >> > + struct alps_fields *f)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > + int i;
> > > >> > +
> > > >> > + switch (priv->r.v7.pkt_id) {
> > > >> > + case V7_PACKET_ID_TWO:
> > > >> > + case V7_PACKET_ID_MULTI:
> > > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
> > > >> > + alps_set_each_pt_attr_v7(psmouse,
> > > >> > + &f->pt_img[i],
> > > >> > + &priv->pt_attr[i]);
> > > >> > + break;
> > > >> > + default:
> > > >> > + /*All finger attributes are cleared when packet ID is
> > > >> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> > > >> > + indicates that there's no finger and no button activity.
> > > >> > + A 'NEW' packet indicates the finger position in packet
> > > >> > + is not continues from previous packet. Such as the
> > > >> > + condition there's finger placed or lifted. In these cases,
> > > >> > + finger attributes will be reset.*/
> > > >> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> > > >> > + break;
> > > >> > + }
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> > > >> > + struct alps_fields *f)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > + unsigned int fn = 0;
> > > >> > + int i;
> > > >> > +
> > > >> > + switch (priv->r.v7.pkt_id) {
> > > >> > + case V7_PACKET_ID_IDLE:
> > > >> > + case V7_PACKET_ID_NEW:
> > > >> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> > > >> > + An 'IDLE' packet indicates that there's no finger on touchpad.
> > > >> > + A 'NEW' packet indicates there's finger placed or lifted.
> > > >> > + Finger position of 'New' packet is not continues from the
> > > >> > + previous packet.*/
> > > >> > + fn = 0;
> > > >> > + break;
> > > >> > + case V7_PACKET_ID_TWO:
> > > >> > + if (f->pt_img[0].z == 0) {
> > > >> > + /*The first finger slot is zero when a non-resting
> > > >> > + finger lifted and remaining only one resting finger
> > > >> > + on touchpad. Hardware report the remaining resting
> > > >> > + finger in second slot. This resting is ignored*/
> > > >> > + fn = 0;
> > > >> > + } else if (f->pt_img[1].z == 0) {
> > > >> > + /* The second finger slot is zero if there's
> > > >> > + only one finger*/
> > > >> > + fn = 1;
> > > >> > + } else {
> > > >> > + /*All non-resting fingers will be counted to report*/
> > > >> > + fn = 0;
> > > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> > > >> > + if (priv->pt_attr[i].is_counted)
> > > >> > + fn++;
> > > >> > + }
> > > >> > +
> > > >> > + /*In the case that both fingers are
> > > >> > + resting fingers, report the first one*/
> > > >> > + if (!priv->pt_attr[0].is_counted &&
> > > >> > + !priv->pt_attr[1].is_counted) {
> > > >> > + fn = 1;
> > > >> > + }
> > > >> > + }
> > > >> > + break;
> > > >> > + case V7_PACKET_ID_MULTI:
> > > >> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> > > >> > + finger exist.*/
> > > >> > + fn = 3 + priv->r.v7.additional_fingers;
> > > >> > + break;
> > > >> > + }
> > > >> > +
> > > >> > + f->fingers = fn;
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> > > >> > + struct alps_fields *f)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > +
> > > >> > + if (priv->phy_btn) {
> > > >> > + if (!priv->prev_phy_btn) {
> > > >> > + /* Report a right click as long as there's finger on
> > > >> > + right button zone. Othrewise, report a left click.*/
> > > >> > + if (priv->r.v7.rest_right ||
> > > >> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> > > >> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> > > >> > + f->btn.right = 1;
> > > >> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> > > >> > + } else {
> > > >> > + f->btn.left = 1;
> > > >> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> > > >> > + }
> > > >> > + } else {
> > > >> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> > > >> > + f->btn.right = 1;
> > > >> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> > > >> > + f->btn.left = 1;
> > > >> > + }
> > > >> > + } else {
> > > >> > + priv->pressed_btn_bits = 0;
> > > >> > + f->btn.right = 0;
> > > >> > + f->btn.left = 0;
> > > >> > + }
> > > >> > +
> > > >> > + priv->prev_phy_btn = priv->phy_btn;
> > > >> > +}
> > > >> > +
> > > >> > +static void alps_process_packet_v7(struct psmouse *psmouse)
> > > >> > +{
> > > >> > + struct alps_data *priv = psmouse->private;
> > > >> > + struct alps_fields f = {0};
> > > >> > + unsigned char *packet = psmouse->packet;
> > > >> > +
> > > >> > + priv->decode_fields(&f, packet, psmouse);
> > > >> > +
> > > >> > + if (alps_drop_unsupported_packet_v7(psmouse))
> > > >> > + return;
> > > >> > +
> > > >> > + alps_set_pt_attr_v7(psmouse, &f);
> > > >> > +
> > > >> > + alps_cal_output_finger_num_v7(psmouse, &f);
> > > >> > +
> > > >> > + alps_assign_buttons_v7(psmouse, &f);
> > > >> > +
> > > >> > + alps_report_coord_and_btn(psmouse, &f);
> > > >> > +}
> > > >> > +
> > > >> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> > > >> > unsigned char packet[],
> > > >> > bool report_buttons)
> > > >> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > > >> > return PSMOUSE_BAD_DATA;
> > > >> > }
> > > >> >
> > > >> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
> > > >> > + !alps_is_valid_package_v7(psmouse))) {
> > > >> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> > > >> > + psmouse->pktcnt - 1,
> > > >> > + psmouse->packet[psmouse->pktcnt - 1]);
> > > >> > + return PSMOUSE_BAD_DATA;
> > > >> > + }
> > > >> > +
> > > >> > if (psmouse->pktcnt == psmouse->pktsize) {
> > > >> > priv->process_packet(psmouse);
> > > >> > return PSMOUSE_FULL_PACKET;
> > > >> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> > > >> > return 0;
> > > >> > }
> > > >> >
> > > >> > +static int alps_check_valid_firmware_id(unsigned char id[])
> > > >> > +{
> > > >> > + int valid = 1;
> > > >> > +
> > > >> > + if (id[0] == 0x73)
> > > >> > + valid = 1;
> > > >> > + else if (id[0] == 0x88) {
> > > >> > + if ((id[1] == 0x07) ||
> > > >> > + (id[1] == 0x08) ||
> > > >> > + ((id[1] & 0xf0) == 0xB0))
> > > >> > + valid = 1;
> > > >> > + }
> > > >> > +
> > > >> > + return valid;
> > > >> > +}
> > > >> > +
> > > >> > static int alps_enter_command_mode(struct psmouse *psmouse)
> > > >> > {
> > > >> > unsigned char param[4];
> > > >> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> > > >> > return -1;
> > > >> > }
> > > >> >
> > > >> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> > > >> > - param[0] != 0x73) {
> > > >> > + if (!alps_check_valid_firmware_id(param)) {
> > > >> > psmouse_dbg(psmouse,
> > > >> > "unknown response while entering command mode\n");
> > > >> > return -1;
> > > >> > @@ -1704,6 +2067,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)
> > > >> > {
> > > >> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > > >> > priv->set_abs_params = alps_set_abs_params_st;
> > > >> > priv->x_max = 1023;
> > > >> > priv->y_max = 767;
> > > >> > + priv->slot_number = 1;
> > > >> > break;
> > > >> > case ALPS_PROTO_V3:
> > > >> > priv->hw_init = alps_hw_init_v3;
> > > >> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > > >> > priv->decode_fields = alps_decode_pinnacle;
> > > >> > priv->nibble_commands = alps_v3_nibble_commands;
> > > >> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > > >> > + priv->slot_number = 2;
> > > >> > break;
> > > >> > case ALPS_PROTO_V4:
> > > >> > priv->hw_init = alps_hw_init_v4;
> > > >> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > > >> > priv->set_abs_params = alps_set_abs_params_mt;
> > > >> > priv->nibble_commands = alps_v4_nibble_commands;
> > > >> > priv->addr_command = PSMOUSE_CMD_DISABLE;
> > > >> > + priv->slot_number = 2;
> > > >> > break;
> > > >> > case ALPS_PROTO_V5:
> > > >> > priv->hw_init = alps_hw_init_dolphin_v1;
> > > >> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > > >> > priv->y_max = 660;
> > > >> > priv->x_bits = 23;
> > > >> > priv->y_bits = 12;
> > > >> > + priv->slot_number = 2;
> > > >> > break;
> > > >> > case ALPS_PROTO_V6:
> > > >> > priv->hw_init = alps_hw_init_v6;
> > > >> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> > > >> > priv->nibble_commands = alps_v6_nibble_commands;
> > > >> > priv->x_max = 2047;
> > > >> > priv->y_max = 1535;
> > > >> > + priv->slot_number = 2;
> > > >> > + break;
> > > >> > + case ALPS_PROTO_V7:
> > > >> > + priv->hw_init = alps_hw_init_v7;
> > > >> > + priv->process_packet = alps_process_packet_v7;
> > > >> > + priv->decode_fields = alps_decode_packet_v7;
> > > >> > + priv->set_abs_params = alps_set_abs_params_mt;
> > > >> > + priv->nibble_commands = alps_v3_nibble_commands;
> > > >> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > > >> > + priv->x_max = 0xfff;
> > > >> > + priv->y_max = 0x7ff;
> > > >> > + priv->resting_zone_y_min = 0x654;
> > > >> > + priv->byte0 = 0x48;
> > > >> > + priv->mask0 = 0x48;
> > > >> > + priv->flags = 0;
> > > >> > + priv->slot_number = 2;
> > > >> > break;
> > > >> > }
> > > >> > }
> > > >> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> > > >> > return -EIO;
> > > >> > else
> > > >> > return 0;
> > > >> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> > > >> > + priv->proto_version = ALPS_PROTO_V7;
> > > >> > + alps_set_defaults(priv);
> > > >> > +
> > > >> > + return 0;
> > > >> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> > > >> > priv->proto_version = ALPS_PROTO_V3;
> > > >> > alps_set_defaults(priv);
> > > >> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > > >> > struct input_dev *dev1)
> > > >> > {
> > > >> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> > > >> > - input_mt_init_slots(dev1, 2, 0);
> > > >> > + input_mt_init_slots(dev1, priv->slot_number, 0);
> > > >> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> > > >> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
> > > >> >
> > > >> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> > > >> > index 03f88b6..5d2f9ea 100644
> > > >> > --- a/drivers/input/mouse/alps.h
> > > >> > +++ b/drivers/input/mouse/alps.h
> > > >> > @@ -18,11 +18,36 @@
> > > >> > #define ALPS_PROTO_V4 4
> > > >> > #define ALPS_PROTO_V5 5
> > > >> > #define ALPS_PROTO_V6 6
> > > >> > +#define ALPS_PROTO_V7 7
> > > >> > +
> > > >> > +#define MAX_IMG_PT_NUM 5
> > > >> > +#define V7_IMG_PT_NUM 2
> > > >> > +
> > > >> > +#define ZONE_NORMAL 0x01
> > > >> > +#define ZONE_RESTING 0x02
> > > >> > +#define ZONE_LEFT_BTN 0x04
> > > >> > +#define ZONE_RIGHT_BTN 0x08
> > > >> >
> > > >> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
> > > >> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> > > >> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
> > > >> >
> > > >> > +/*
> > > >> > + * enum V7_PACKET_ID - defines the packet type for V7
> > > >> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> > > >> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> > > >> > + * or there's button activities.
> > > >> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> > > >> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> > > >> > + * previous packet.
> > > >> > +*/
> > > >> > +enum V7_PACKET_ID {
> > > >> > + V7_PACKET_ID_IDLE,
> > > >> > + V7_PACKET_ID_TWO,
> > > >> > + V7_PACKET_ID_MULTI,
> > > >> > + V7_PACKET_ID_NEW,
> > > >> > +};
> > > >> > +
> > > >> > /**
> > > >> > * struct alps_model_info - touchpad ID table
> > > >> > * @signature: E7 response string to match.
> > > >> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> > > >> > };
> > > >> >
> > > >> > /**
> > > >> > - * struct alps_fields - decoded version of the report packet
> > > >> > - * @x_map: Bitmap of active X positions for MT.
> > > >> > - * @y_map: Bitmap of active Y positions for MT.
> > > >> > - * @fingers: Number of fingers for MT.
> > > >> > - * @x: X position for ST.
> > > >> > - * @y: Y position for ST.
> > > >> > - * @z: Z position for ST.
> > > >> > - * @first_mp: Packet is the first of a multi-packet report.
> > > >> > - * @is_mp: Packet is part of a multi-packet report.
> > > >> > + * struct alps_btn - decoded version of the button status
> > > >> > * @left: Left touchpad button is active.
> > > >> > * @right: Right touchpad button is active.
> > > >> > * @middle: Middle touchpad button is active.
> > > >> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> > > >> > * @ts_right: Right trackstick button is active.
> > > >> > * @ts_middle: Middle trackstick button is active.
> > > >> > */
> > > >> > -struct alps_fields {
> > > >> > - unsigned int x_map;
> > > >> > - unsigned int y_map;
> > > >> > - unsigned int fingers;
> > > >> > - unsigned int x;
> > > >> > - unsigned int y;
> > > >> > - unsigned int z;
> > > >> > - unsigned int first_mp:1;
> > > >> > - unsigned int is_mp:1;
> > > >> > -
> > > >> > +struct alps_btn {
> > > >> > unsigned int left:1;
> > > >> > unsigned int right:1;
> > > >> > unsigned int middle:1;
> > > >> > @@ -102,6 +110,69 @@ struct alps_fields {
> > > >> > };
> > > >> >
> > > >> > /**
> > > >> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
> > > >> > + * @x: X position for ST.
> > > >> > + * @y: Y position for ST.
> > > >> > + * @z: Z position for ST.
> > > >> > + */
> > > >> > +struct alps_abs_data {
> > > >> > + unsigned int x;
> > > >> > + unsigned int y;
> > > >> > + unsigned int z;
> > > >> > +};
> > > >> > +
> > > >> > +/**
> > > >> > + * struct alps_fields - decoded version of the report packet
> > > >> > + * @fingers: Number of fingers for MT.
> > > >> > + * @pt: X Y Z postion for ST.
> > > >> > + * @pt: X Y Z postion for image MT.
> > > >> > + * @x_map: Bitmap of active X positions for MT.
> > > >> > + * @y_map: Bitmap of active Y positions for MT.
> > > >> > + * @first_mp: Packet is the first of a multi-packet report.
> > > >> > + * @is_mp: Packet is part of a multi-packet report.
> > > >> > + * @btn: Button activity status
> > > >> > + */
> > > >> > +struct alps_fields {
> > > >> > + unsigned int fingers;
> > > >> > + struct alps_abs_data pt;
> > > >> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> > > >> > + unsigned int x_map;
> > > >> > + unsigned int y_map;
> > > >> > + unsigned int first_mp:1;
> > > >> > + unsigned int is_mp:1;
> > > >> > + struct alps_btn btn;
> > > >> > +};
> > > >> > +
> > > >> > +/**
> > > >> > + * struct v7_raw - data decoded from raw packet for V7.
> > > >> > + * @pkt_id: An id that specifies the type of packet.
> > > >> > + * @additional_fingers: Number of additional finger that is neighter included
> > > >> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> > > >> > + * @rest_left: There are fingers on left resting zone.
> > > >> > + * @rest_right: There are fingers on right resting zone.
> > > >> > + */
> > > >> > +struct v7_raw {
> > > >> > + unsigned char pkt_id;
> > > >> > + unsigned int additional_fingers;
> > > >> > + unsigned char rest_left;
> > > >> > + unsigned char rest_right;
> > > >> > +};
> > > >> > +
> > > >> > +/**
> > > >> > + * 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;
> > > >> > +};
> > > >> > +
> > > >> > +/**
> > > >> > * struct alps_data - private data structure for the ALPS driver
> > > >> > * @dev2: "Relative" device used to report trackstick or mouse activity.
> > > >> > * @phys: Physical path for the relative device.
> > > >> > @@ -116,8 +187,10 @@ struct alps_fields {
> > > >> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> > > >> > * @x_max: Largest possible X position value.
> > > >> > * @y_max: Largest possible Y position value.
> > > >> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> > > >> > * @x_bits: Number of X bits in the MT bitmap.
> > > >> > * @y_bits: Number of Y bits in the MT bitmap.
> > > >> > + * @img_fingers: Number of image fingers.
> > > >> > * @hw_init: Protocol-specific hardware init function.
> > > >> > * @process_packet: Protocol-specific function to process a report packet.
> > > >> > * @decode_fields: Protocol-specific function to read packet bitfields.
> > > >> > @@ -132,6 +205,11 @@ struct alps_fields {
> > > >> > * @fingers: Number of fingers from last MT report.
> > > >> > * @quirks: Bitmap of ALPS_QUIRK_*.
> > > >> > * @timer: Timer for flushing out the final report packet in the stream.
> > > >> > + * @v7: Data decoded from raw packet for V7
> > > >> > + * @phy_btn: Physical button is active.
> > > >> > + * @prev_phy_btn: Physical button of previous packet is active.
> > > >> > + * @pressed_btn_bits: Pressed positon of button zone
> > > >> > + * @pt_attr: Generic attributes of touch points for buttonless device.
> > > >> > */
> > > >> > struct alps_data {
> > > >> > struct input_dev *dev2;
> > > >> > @@ -145,8 +223,10 @@ struct alps_data {
> > > >> > unsigned char flags;
> > > >> > int x_max;
> > > >> > int y_max;
> > > >> > + int resting_zone_y_min;
> > > >> > int x_bits;
> > > >> > int y_bits;
> > > >> > + unsigned char slot_number;
> > > >> >
> > > >> > int (*hw_init)(struct psmouse *psmouse);
> > > >> > void (*process_packet)(struct psmouse *psmouse);
> > > >> > @@ -161,6 +241,15 @@ struct alps_data {
> > > >> > int fingers;
> > > >> > u8 quirks;
> > > >> > struct timer_list timer;
> > > >> > +
> > > >> > + /* these are used for buttonless touchpad*/
> > > >> > + union {
> > > >> > + struct v7_raw v7;
> > > >> > + } r;
> > > >> > + unsigned char phy_btn;
> > > >> > + unsigned char prev_phy_btn;
> > > >> > + unsigned char pressed_btn_bits;
> > > >> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> > > >> > };
> > > >> >
> > > >> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> > > >> > --
> > > >> > 1.8.3.2
> > > >> >
> > > >> --
> > > >> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> > > >> the body of a message to majordomo@vger.kernel.org
> > > >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> > > >>
> > >
> >
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] ARM: Kirkwood: Add DT description of QNAP 419
From: Andrew Lunn @ 2014-01-15 17:45 UTC (permalink / raw)
To: Arnd Bergmann
Cc: linux-arm-kernel, Andrew Lunn, Jason Cooper, devicetree,
Ian Campbell, Sebastian Hesselbarth, linux-input, Gregory Clement,
tbm
In-Reply-To: <201401151736.46280.arnd@arndb.de>
> > But i'm also a little bit concerned by the "unique number" and this
> > ending up in /dev/input/by-path/platform-gpio_keys.3-event. Is this
> > path supposed to be stable? This unique number is not stable. An
> > unwitting change to the DT could cause its value to change. Do we need
> > to make it stable?
> >
>
> One possibility would be to create an artificial bus in DT for all
> gpio-keys devices, use #address-cells=<1> and #size-cells=<0>
> for it, and give each device a unique reg property. Not sure if that
> would be considered an elegant solution though.
Hi Arnd
Can i imply from your answer that you think
/dev/input/by-path/platform-gpio_keys.3-event
should be stable?
A quick look at udev rules seems to suggestion this is an issue for
input/gpio-keys and maybe audio and video if there is a top level DT
property collecting the different sub devices together for ASOC and
V4L.
Thanks
Andrew
^ permalink raw reply
* Re: [PATCH] ARM: Kirkwood: Add DT description of QNAP 419
From: Arnd Bergmann @ 2014-01-15 16:36 UTC (permalink / raw)
To: linux-arm-kernel
Cc: Andrew Lunn, Ian Campbell, devicetree, linux-input, Jason Cooper,
Sebastian Hesselbarth, Gregory Clement, tbm
In-Reply-To: <20140111210443.GT9681@lunn.ch>
On Saturday 11 January 2014, Andrew Lunn wrote:
> The id of -1 causes platform_device_add() to set the device name to
> plain "gpio-keys".
>
> When using DT, the device name is created by the function
> of_device_make_bus_id(). It has the following comment:
>
> * This routine will first try using either the dcr-reg or the reg property
> * value to derive a unique name. As a last resort it will use the node
> * name followed by a unique number.
>
> Since the gpio_keys node does not have a reg properties, it gets a
> unique number appended to it. We end up with the device name
> "gpio_keys.3"
>
> So as it stands, it does not appear i can make the DT system use the
> same device name as a board system.
>
> But i'm also a little bit concerned by the "unique number" and this
> ending up in /dev/input/by-path/platform-gpio_keys.3-event. Is this
> path supposed to be stable? This unique number is not stable. An
> unwitting change to the DT could cause its value to change. Do we need
> to make it stable?
>
One possibility would be to create an artificial bus in DT for all
gpio-keys devices, use #address-cells=<1> and #size-cells=<0>
for it, and give each device a unique reg property. Not sure if that
would be considered an elegant solution though.
Arnd
^ permalink raw reply
* [PATCH] input: Add new driver for ARM CLPS711X keypad
From: Alexander Shiyan @ 2014-01-15 16:27 UTC (permalink / raw)
To: linux-input; +Cc: Dmitry Torokhov, devicetree, Alexander Shiyan
This patch adds a new driver for keypad for Cirrus Logic CLPS711X CPUs
and devicetree binding documentation.
Target CPU contain keyboard interface which can scan 8 column lines,
so we can read row GPIOs to read status and determine asserted state.
Signed-off-by: Alexander Shiyan <shc_work@mail.ru>
---
.../devicetree/bindings/input/clps711x-keypad.txt | 29 +++
drivers/input/keyboard/Kconfig | 12 ++
drivers/input/keyboard/Makefile | 1 +
drivers/input/keyboard/clps711x-keypad.c | 209 +++++++++++++++++++++
4 files changed, 251 insertions(+)
create mode 100644 Documentation/devicetree/bindings/input/clps711x-keypad.txt
create mode 100644 drivers/input/keyboard/clps711x-keypad.c
diff --git a/Documentation/devicetree/bindings/input/clps711x-keypad.txt b/Documentation/devicetree/bindings/input/clps711x-keypad.txt
new file mode 100644
index 0000000..26b7fe5
--- /dev/null
+++ b/Documentation/devicetree/bindings/input/clps711x-keypad.txt
@@ -0,0 +1,29 @@
+* Cirrus Logic CLPS711X matrix keypad device tree bindings
+
+Required Properties:
+- compatible: Should be "cirrus,clps711x--keypad".
+- syscon: phandle to syscon device node which control keypad (SYSCON1).
+- row-gpios: List of GPIOs used as row lines.
+- poll-interval: Poll interval time in milliseconds.
+- linux,keymap: The definition can be found at
+ bindings/input/matrix-keymap.txt.
+
+Optional Properties:
+- autorepeat: Enable autorepeat feature.
+
+Example:
+ keypad {
+ compatible = "cirrus,clps711x--keypad";
+ syscon = <&syscon1>;
+ autorepeat;
+ poll-interval = <120>;
+ row-gpios = <&porta 0 0>,
+ <&porta 1 0>;
+
+ linux,keymap = <
+ MATRIX_KEY(0, 0, KEY_UP)
+ MATRIX_KEY(0, 1, KEY_DOWN)
+ MATRIX_KEY(1, 0, KEY_LEFT)
+ MATRIX_KEY(1, 1, KEY_RIGHT)
+ >;
+ };
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a673c9f..126901b 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -151,6 +151,18 @@ config KEYBOARD_BFIN
To compile this driver as a module, choose M here: the
module will be called bf54x-keys.
+config KEYBOARD_CLPS711X
+ tristate "CLPS711X Keypad support"
+ depends on OF_GPIO && (ARCH_CLPS711X || COMPILE_TEST)
+ select INPUT_MATRIXKMAP
+ select INPUT_POLLDEV
+ help
+ Say Y here to enable the matrix keypad on the Cirrus Logic
+ CLPS711X CPU.
+
+ To compile this driver as a module, choose M here: the
+ module will be called clps711x-keypad.
+
config KEYBOARD_LKKBD
tristate "DECstation/VAXstation LK201/LK401 keyboard"
select SERIO
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index a699b61..f8589fe 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_KEYBOARD_AMIGA) += amikbd.o
obj-$(CONFIG_KEYBOARD_ATARI) += atakbd.o
obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o
obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o
+obj-$(CONFIG_KEYBOARD_CLPS711X) += clps711x-keypad.o
obj-$(CONFIG_KEYBOARD_CROS_EC) += cros_ec_keyb.o
obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o
obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o
diff --git a/drivers/input/keyboard/clps711x-keypad.c b/drivers/input/keyboard/clps711x-keypad.c
new file mode 100644
index 0000000..1e2c93f
--- /dev/null
+++ b/drivers/input/keyboard/clps711x-keypad.c
@@ -0,0 +1,209 @@
+/*
+ * Cirrus Logic CLPS711X Keypad driver
+ *
+ * Copyright (C) 2014 Alexander Shiyan <shc_work@mail.ru>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/input-polldev.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/input/matrix_keypad.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/clps711x.h>
+
+#define CLPS711X_KEYPAD_COL_COUNT 8
+
+struct clps711x_gpio_data {
+ int gpio;
+ bool active_low;
+ DECLARE_BITMAP(last_state, CLPS711X_KEYPAD_COL_COUNT);
+};
+
+struct clps711x_keypad_data {
+ struct regmap *syscon;
+ int row_count;
+ unsigned int row_shift;
+ struct clps711x_gpio_data *gpio_data;
+};
+
+static void clps711x_keypad_poll(struct input_polled_dev *dev)
+{
+ const unsigned short *keycodes = dev->input->keycode;
+ struct clps711x_keypad_data *priv = dev->private;
+ int col, row;
+
+ for (col = 0; col < CLPS711X_KEYPAD_COL_COUNT; col++) {
+ /* Assert column */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET,
+ SYSCON1_KBDSCAN_MASK,
+ SYSCON1_KBDSCAN(8 + col));
+
+ /* Scan rows */
+ for (row = 0; row < priv->row_count; row++) {
+ struct clps711x_gpio_data *data = &priv->gpio_data[row];
+ bool state, state1;
+
+ /* Protection against fluctuations */
+ do {
+ state = gpio_get_value_cansleep(data->gpio);
+ udelay(1);
+ state1 = gpio_get_value_cansleep(data->gpio);
+ } while (state != state1);
+
+ state ^= data->active_low;
+
+ if (test_bit(col, data->last_state) != state) {
+ int code = MATRIX_SCAN_CODE(row, col,
+ priv->row_shift);
+
+ if (state)
+ set_bit(col, data->last_state);
+ else
+ clear_bit(col, data->last_state);
+
+ input_event(dev->input, EV_MSC, MSC_SCAN, code);
+ if (keycodes[code])
+ input_report_key(dev->input,
+ keycodes[code], state);
+ }
+ }
+
+ /* Set all columns to low */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET,
+ SYSCON1_KBDSCAN_MASK, SYSCON1_KBDSCAN(1));
+ }
+
+ input_sync(dev->input);
+}
+
+static int clps711x_keypad_probe(struct platform_device *pdev)
+{
+ struct clps711x_keypad_data *priv;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct input_polled_dev *poll_dev;
+ u32 poll_interval;
+ int i, err;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->syscon = syscon_regmap_lookup_by_phandle(np, "syscon");
+ if (IS_ERR(priv->syscon))
+ return PTR_ERR(priv->syscon);
+
+ priv->row_count = of_gpio_named_count(np, "row-gpios");
+ if (priv->row_count < 1)
+ return -EINVAL;
+
+ priv->gpio_data = devm_kzalloc(dev, sizeof(*priv->gpio_data) *
+ priv->row_count, GFP_KERNEL);
+ if (!priv->gpio_data)
+ return -ENOMEM;
+
+ priv->row_shift = get_count_order(CLPS711X_KEYPAD_COL_COUNT);
+
+ for (i = 0; i < priv->row_count; i++) {
+ struct clps711x_gpio_data *data = &priv->gpio_data[i];
+ enum of_gpio_flags flg;
+
+ data->gpio = of_get_named_gpio_flags(np, "row-gpios", i, &flg);
+ if (data->gpio < 0)
+ return data->gpio;
+
+ err = devm_gpio_request_one(dev, data->gpio, GPIOF_IN, NULL);
+ if (err)
+ return err;
+
+ data->active_low = flg & OF_GPIO_ACTIVE_LOW;
+ }
+
+ err = of_property_read_u32(np, "poll-interval", &poll_interval);
+ if (err)
+ return err;
+
+ poll_dev = input_allocate_polled_device();
+ if (!poll_dev)
+ return -ENOMEM;
+
+ poll_dev->private = priv;
+ poll_dev->poll = clps711x_keypad_poll;
+ poll_dev->poll_interval = poll_interval;
+ poll_dev->input->name = pdev->name;
+ poll_dev->input->dev.parent = &pdev->dev;
+ poll_dev->input->id.bustype = BUS_HOST;
+ poll_dev->input->id.vendor = 0x0001;
+ poll_dev->input->id.product = 0x0001;
+ poll_dev->input->id.version = 0x0100;
+
+ err = matrix_keypad_build_keymap(NULL, NULL, priv->row_count,
+ CLPS711X_KEYPAD_COL_COUNT,
+ NULL, poll_dev->input);
+ if (err)
+ goto out_err;
+
+ input_set_capability(poll_dev->input, EV_MSC, MSC_SCAN);
+ if (of_property_read_bool(np, "autorepeat"))
+ __set_bit(EV_REP, poll_dev->input->evbit);
+
+ platform_set_drvdata(pdev, poll_dev);
+
+ /* Set all columns to low */
+ regmap_update_bits(priv->syscon, SYSCON_OFFSET, SYSCON1_KBDSCAN_MASK,
+ SYSCON1_KBDSCAN(1));
+
+ err = input_register_polled_device(poll_dev);
+ if (err)
+ goto out_err;
+
+ /* Report initial state */
+ clps711x_keypad_poll(poll_dev);
+
+ return 0;
+
+out_err:
+ input_free_polled_device(poll_dev);
+
+ return err;
+}
+
+static int clps711x_keypad_remove(struct platform_device *pdev)
+{
+ struct input_polled_dev *poll_dev = platform_get_drvdata(pdev);
+
+ input_unregister_polled_device(poll_dev);
+ input_free_polled_device(poll_dev);
+
+ return 0;
+}
+
+static struct of_device_id clps711x_keypad_of_match[] = {
+ { .compatible = "cirrus,clps711x-keypad", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, clps711x_keypad_of_match);
+
+static struct platform_driver clps711x_keypad_driver = {
+ .driver = {
+ .name = "clps711x-keypad",
+ .owner = THIS_MODULE,
+ .of_match_table = clps711x_keypad_of_match,
+ },
+ .probe = clps711x_keypad_probe,
+ .remove = clps711x_keypad_remove,
+};
+module_platform_driver(clps711x_keypad_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("Cirrus Logic CLPS711X Keypad driver");
+MODULE_LICENSE("GPL");
--
1.8.3.2
^ permalink raw reply related
* ALPS: Cirque Smart Cat Pro AG Touchpad Support
From: AJ Guillon @ 2014-01-15 16:16 UTC (permalink / raw)
To: linux-input
Hi everyone,
I bought a Cirque Glidepoint (Model GP415U-5321) that I would like to
use with Linux. I haven't hacked on the kernel before, but I'm happy to
test and modify alps.c as required to get this device working.
I downloaded alps-reg-dump from
git://kernel.ubuntu.com/sforshee/alps-reg-dump.git and it reports:
Found serio mouse at /sys/bus/serio/devices/serio1/
Invalid ack byte 0xfe after command
Invalid ack byte 0xfe after command
E6 report failed, not an ALPS touchpad
The PCI ID of the device is: 0488:0282
I'm not sure if there is anything else I should try. I am currently
running Ubuntu 12.04 with kernel 3.2.0-29-generic.
AJ
^ permalink raw reply
* Re: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Dylan Thurston @ 2014-01-15 13:00 UTC (permalink / raw)
To: Elaine Chen
Cc: Tommy Will, Dmitry Torokhov, Kevin Cernekee, david turvene,
Niels de Vos, Justin Clift, Qiting Chen, linux-input
In-Reply-To: <20140115051650.GA4620@bostoncoop.net>
One glitch: I see mouse jumping sometimes when dragging. This has
happened a couple times when resizing windows with a right-click and
drag.
I'm using X.org from Debian unstable, in case that's relevant.
--Dylan
On Wed, Jan 15, 2014 at 12:16:50AM -0500, Dylan Thurston wrote:
> This patch seems to work in the 3.13-rc8 kernel, at least on an
> initial check. The problems with excess clicks while typing have
> disappeared. I'll report back with any glitches I see.
>
> Thank you!
>
> --Dylan
>
> On Wed, Jan 15, 2014 at 11:15:02AM +0800, Elaine Chen wrote:
> > Hi Dylan,
> >
> > Thank you! This patch is againt Dmitry Torokhov's input tree, based on
> > the modification of:
> > 2013-12-26 Input: ALPS - add support for "Dolphin" devices Yunkang Tang
> > As linux-next-20140114 has already merged Dolphin support, the patch
> > should be matched.
> > As for the blank screen, I'll debug on my side. Sorry for that.
> > What is the kernel version on your HP side? Is it 3.13-rc8?
> >
> > Yes, it is safe to copy both alps.c and alps.h from linux-next version
> > to 3.13-rc8 kerenl.
> >
> >
> >
> > 2014/1/15 Dylan Thurston <dpthurst@indiana.edu>:
> > > Thank you! Which versions does this apply against? It patched for me
> > > with no fuzz against linux-next-20140114, but unfortunately X seems to
> > > be broken for me on that version (blank screen). I get fuzz and
> > > rejected patches when applying it to 3.13-rc8. Is it safe to just copy
> > > over alps.c from the linux-next version?
> > >
> > > (Of course, it's possible that the blank screen is a side effect of
> > > the correct recognition of the touchpad.)
> > >
> > > Thanks,
> > > Dylan
> > >
> > > On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
> > >> Hi Dylan,
> > >>
> > >> My colleague Elaine has prepared the patch for new ALPS touchpad that
> > >> being used on your HP Revolve 810 G1 laptop.
> > >> You can have a try~
> > >>
> > >> --
> > >> Best Regards,
> > >> Tommy
> > >>
> > >> ---------- Forwarded message ----------
> > >> From: Elaine Chen <elaineee66@gmail.com>
> > >> Date: 2014/1/14
> > >> Subject: Re: [PATCH] add support for ALPS v7 protocol device
> > >> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
> > >> david turvene <dturvene@dahetral.com>
> > >> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
> > >> Qiting Chen <qiting.chen@cn.alps.com>
> > >>
> > >>
> > >> As far as I know, the ALPS v7 protocol device is used on following laptops:
> > >>
> > >> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
> > >>
> > >> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> > >> > Here is the patch of supporting ALPS v7 protocol device.
> > >> >
> > >> > v7 device is a clickpad device.
> > >> > Device info:
> > >> > Device ID = 0x73, 0x03, 0x0a
> > >> > Firmware ID = 0x88, 0xb*, 0x**
> > >> >
> > >> > Support function of v7 device:
> > >> > - Cursor
> > >> > - Tap, double tap, tap drag, 2finger tap
> > >> > - Pan, pinch
> > >> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> > >> > Click touchpad with all fingers outside right Button Area --> left click
> > >> > Click touchpad with at lease 1 finger inside right Button Area --> right click
> > >> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
> > >> >
> > >> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> > >> > We tried registering our device as a clickpad by:
> > >> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> > >> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
> > >> >
> > >> >
> > >> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> > >> > ---
> > >> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> > >> > drivers/input/mouse/alps.h | 127 ++++++++++--
> > >> > 2 files changed, 554 insertions(+), 51 deletions(-)
> > >> >
> > >> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > >> > index fb15c64..3e8e8f7 100644
> > >> > --- a/drivers/input/mouse/alps.c
> > >> > +++ b/drivers/input/mouse/alps.c
> > >> > @@ -32,6 +32,11 @@
> > >> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> > >> > #define ALPS_REG_BASE_PINNACLE 0x0000
> > >> >
> > >> > +#define LEFT_BUTTON_BIT 0x01
> > >> > +#define RIGHT_BUTTON_BIT 0x02
> > >> > +
> > >> > +#define V7_LARGE_MOVEMENT 130
> > >> > +
> > >> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> > >> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> > >> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> > >> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> > >> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> > >> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> > >> > 6-byte ALPS packet */
> > >> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
> > >> >
> > >> > static const struct alps_model_info alps_model_data[] = {
> > >> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> > >> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > >> > * isn't valid per PS/2 spec.
> > >> > */
> > >> >
> > >> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> > >> > + struct alps_abs_data *pt1)
> > >> > +{
> > >> > + int vect_x, vect_y;
> > >> > +
> > >> > + if (!pt0 || !pt1)
> > >> > + return 0;
> > >> > +
> > >> > + vect_x = pt0->x - pt1->x;
> > >> > + vect_y = pt0->y - pt1->y;
> > >> > +
> > >> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> > >> > +}
> > >> > +
> > >> > /* Packet formats are described in Documentation/input/alps.txt */
> > >> >
> > >> > static bool alps_is_valid_first_byte(struct alps_data *priv,
> > >> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> > >> > end_bit = y_msb - 1;
> > >> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> > >> > (2 * (priv->y_bits - 1));
> > >> > - *x1 = fields->x;
> > >> > - *y1 = fields->y;
> > >> > + *x1 = fields->pt.x;
> > >> > + *y1 = fields->pt.y;
> > >> > *x2 = 2 * box_middle_x - *x1;
> > >> > *y2 = 2 * box_middle_y - *y1;
> > >> > }
> > >> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> > >> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> > >> > }
> > >> >
> > >> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> > >> > + struct alps_fields *f)
> > >> > +{
> > >> > + struct input_dev *dev;
> > >> > +
> > >> > + if (!psmouse || !f)
> > >> > + return;
> > >> > +
> > >> > + dev = psmouse->dev;
> > >> > +
> > >> > + if (f->fingers) {
> > >> > + input_report_key(dev, BTN_TOUCH, 1);
> > >> > + alps_report_semi_mt_data(dev, f->fingers,
> > >> > + f->pt_img[0].x, f->pt_img[0].y,
> > >> > + f->pt_img[1].x, f->pt_img[1].y);
> > >> > + input_mt_report_finger_count(dev, f->fingers);
> > >> > +
> > >> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> > >> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> > >> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> > >> > + } else {
> > >> > + input_report_key(dev, BTN_TOUCH, 0);
> > >> > + input_mt_report_finger_count(dev, 0);
> > >> > + input_report_abs(dev, ABS_PRESSURE, 0);
> > >> > + }
> > >> > +
> > >> > + input_report_key(dev, BTN_LEFT, f->btn.left);
> > >> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
> > >> > +
> > >> > + input_sync(dev);
> > >> > +}
> > >> > +
> > >> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> > >> > {
> > >> > struct alps_data *priv = psmouse->private;
> > >> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> > >> >
> > >> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> > >> > {
> > >> > - f->left = !!(p[3] & 0x01);
> > >> > - f->right = !!(p[3] & 0x02);
> > >> > - f->middle = !!(p[3] & 0x04);
> > >> > + f->btn.left = !!(p[3] & 0x01);
> > >> > + f->btn.right = !!(p[3] & 0x02);
> > >> > + f->btn.middle = !!(p[3] & 0x04);
> > >> >
> > >> > - f->ts_left = !!(p[3] & 0x10);
> > >> > - f->ts_right = !!(p[3] & 0x20);
> > >> > - f->ts_middle = !!(p[3] & 0x40);
> > >> > + f->btn.ts_left = !!(p[3] & 0x10);
> > >> > + f->btn.ts_right = !!(p[3] & 0x20);
> > >> > + f->btn.ts_middle = !!(p[3] & 0x40);
> > >> > }
> > >> >
> > >> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > >> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > >> > ((p[2] & 0x7f) << 1) |
> > >> > (p[4] & 0x01);
> > >> >
> > >> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > >> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > >> > ((p[0] & 0x30) >> 4);
> > >> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > >> > - f->z = p[5] & 0x7f;
> > >> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > >> > + f->pt.z = p[5] & 0x7f;
> > >> >
> > >> > alps_decode_buttons_v3(f, p);
> > >> > }
> > >> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> > >> > f->is_mp = !!(p[0] & 0x20);
> > >> >
> > >> > if (!f->is_mp) {
> > >> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > >> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > >> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > >> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > >> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > >> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > >> > alps_decode_buttons_v3(f, p);
> > >> > } else {
> > >> > f->fingers = ((p[0] & 0x6) >> 1 |
> > >> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > >> > * with x, y, and z all zero, so these seem to be flukes.
> > >> > * Ignore them.
> > >> > */
> > >> > - if (f.x && f.y && !f.z)
> > >> > + if (f.pt.x && f.pt.y && !f.pt.z)
> > >> > return;
> > >> >
> > >> > /*
> > >> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > >> > * to rely on ST data.
> > >> > */
> > >> > if (!fingers) {
> > >> > - x1 = f.x;
> > >> > - y1 = f.y;
> > >> > - fingers = f.z > 0 ? 1 : 0;
> > >> > + x1 = f.pt.x;
> > >> > + y1 = f.pt.y;
> > >> > + fingers = f.pt.z > 0 ? 1 : 0;
> > >> > }
> > >> >
> > >> > - if (f.z >= 64)
> > >> > + if (f.pt.z >= 64)
> > >> > input_report_key(dev, BTN_TOUCH, 1);
> > >> > else
> > >> > input_report_key(dev, BTN_TOUCH, 0);
> > >> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > >> >
> > >> > input_mt_report_finger_count(dev, fingers);
> > >> >
> > >> > - input_report_key(dev, BTN_LEFT, f.left);
> > >> > - input_report_key(dev, BTN_RIGHT, f.right);
> > >> > - input_report_key(dev, BTN_MIDDLE, f.middle);
> > >> > + input_report_key(dev, BTN_LEFT, f.btn.left);
> > >> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
> > >> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
> > >> >
> > >> > - if (f.z > 0) {
> > >> > - input_report_abs(dev, ABS_X, f.x);
> > >> > - input_report_abs(dev, ABS_Y, f.y);
> > >> > + if (f.pt.z > 0) {
> > >> > + input_report_abs(dev, ABS_X, f.pt.x);
> > >> > + input_report_abs(dev, ABS_Y, f.pt.y);
> > >> > }
> > >> > - input_report_abs(dev, ABS_PRESSURE, f.z);
> > >> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
> > >> >
> > >> > input_sync(dev);
> > >> >
> > >> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> > >> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
> > >> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> > >> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> > >> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> > >> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> > >> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> > >> > input_sync(dev2);
> > >> > }
> > >> > }
> > >> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> > >> > input_sync(dev);
> > >> > }
> > >> >
> > >> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> > >> > +{
> > >> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> > >> > + return false;
> > >> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> > >> > + return false;
> > >> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> > >> > + return false;
> > >> > + return true;
> > >> > +}
> > >> > +
> > >> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > + int drop = 1;
> > >> > +
> > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> > >> > + drop = 0;
> > >> > +
> > >> > + return drop;
> > >> > +}
> > >> > +
> > >> > +static unsigned char alps_get_packet_id_v7(char *byte)
> > >> > +{
> > >> > + unsigned char packet_id;
> > >> > +
> > >> > + if (byte[4] & 0x40)
> > >> > + packet_id = V7_PACKET_ID_TWO;
> > >> > + else if (byte[4] & 0x01)
> > >> > + packet_id = V7_PACKET_ID_MULTI;
> > >> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> > >> > + packet_id = V7_PACKET_ID_NEW;
> > >> > + else
> > >> > + packet_id = V7_PACKET_ID_IDLE;
> > >> > +
> > >> > + return packet_id;
> > >> > +}
> > >> > +
> > >> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> > >> > + unsigned char *pkt,
> > >> > + unsigned char pkt_id)
> > >> > +{
> > >> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
> > >> > + (pkt_id == V7_PACKET_ID_MULTI) ||
> > >> > + (pkt_id == V7_PACKET_ID_NEW)) {
> > >> > + pt[0].x = ((pkt[2] & 0x80) << 4);
> > >> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> > >> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> > >> > + pt[0].x |= (pkt[3] & 0x07);
> > >> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> > >> > +
> > >> > + pt[1].x = ((pkt[3] & 0x80) << 4);
> > >> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
> > >> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> > >> > + pt[1].y = ((pkt[5] & 0x80) << 3);
> > >> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> > >> > +
> > >> > + if (pkt_id == V7_PACKET_ID_TWO) {
> > >> > + pt[1].x &= ~0x000F;
> > >> > + pt[1].y |= 0x000F;
> > >> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> > >> > + pt[1].x &= ~0x003F;
> > >> > + pt[1].y &= ~0x0020;
> > >> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
> > >> > + pt[1].y |= 0x001F;
> > >> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
> > >> > + pt[1].x &= ~0x003F;
> > >> > + pt[1].x |= (pkt[0] & 0x20);
> > >> > + pt[1].y |= 0x000F;
> > >> > + }
> > >> > +
> > >> > + pt[0].y = 0x7FF - pt[0].y;
> > >> > + pt[1].y = 0x7FF - pt[1].y;
> > >> > +
> > >> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> > >> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> > >> > + }
> > >> > +}
> > >> > +
> > >> > +static void alps_decode_packet_v7(struct alps_fields *f,
> > >> > + unsigned char *p,
> > >> > + struct psmouse *psmouse)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > +
> > >> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> > >> > +
> > >> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> > >> > +
> > >> > + priv->r.v7.rest_left = 0;
> > >> > + priv->r.v7.rest_right = 0;
> > >> > + priv->r.v7.additional_fingers = 0;
> > >> > + priv->phy_btn = 0;
> > >> > +
> > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> > >> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> > >> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> > >> > + }
> > >> > +
> > >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> > >> > + priv->r.v7.additional_fingers = p[5] & 0x03;
> > >> > +
> > >> > + priv->phy_btn = (p[0] & 0x80) >> 7;
> > >> > +}
> > >> > +
> > >> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> > >> > + struct alps_abs_data *pt,
> > >> > + struct alps_bl_pt_attr *pt_attr)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > + unsigned int dist;
> > >> > +
> > >> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> > >> > + pt_attr->is_init_pt_got = 1;
> > >> > + pt_attr->is_counted = 0;
> > >> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> > >> > + }
> > >> > +
> > >> > + if (pt->z != 0) {
> > >> > + if (pt->y < priv->resting_zone_y_min) {
> > >> > + /* A finger is recognized as a non-resting finger
> > >> > + if it's position is outside the resting finger zone.*/
> > >> > + pt_attr->zone = ZONE_NORMAL;
> > >> > + pt_attr->is_counted = 1;
> > >> > + } else {
> > >> > + /* A finger is recognized as a resting finger if it's
> > >> > + position is inside the resting finger zone and there's
> > >> > + no large movement from it's touch down position.*/
> > >> > + pt_attr->zone = ZONE_RESTING;
> > >> > +
> > >> > + if (pt->x > priv->x_max / 2)
> > >> > + pt_attr->zone |= ZONE_RIGHT_BTN;
> > >> > + else
> > >> > + pt_attr->zone |= ZONE_LEFT_BTN;
> > >> > +
> > >> > + /* A resting finger will turn to be a non-resting
> > >> > + finger if it has made large movement from it's touch
> > >> > + down position. A non-resting finger will never turn
> > >> > + to a resting finger before it leaves the touchpad
> > >> > + surface.*/
> > >> > + if (pt_attr->is_init_pt_got) {
> > >> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> > >> > +
> > >> > + if (dist > V7_LARGE_MOVEMENT)
> > >> > + pt_attr->is_counted = 1;
> > >> > + }
> > >> > + }
> > >> > + }
> > >> > +}
> > >> > +
> > >> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> > >> > + struct alps_fields *f)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > + int i;
> > >> > +
> > >> > + switch (priv->r.v7.pkt_id) {
> > >> > + case V7_PACKET_ID_TWO:
> > >> > + case V7_PACKET_ID_MULTI:
> > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
> > >> > + alps_set_each_pt_attr_v7(psmouse,
> > >> > + &f->pt_img[i],
> > >> > + &priv->pt_attr[i]);
> > >> > + break;
> > >> > + default:
> > >> > + /*All finger attributes are cleared when packet ID is
> > >> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> > >> > + indicates that there's no finger and no button activity.
> > >> > + A 'NEW' packet indicates the finger position in packet
> > >> > + is not continues from previous packet. Such as the
> > >> > + condition there's finger placed or lifted. In these cases,
> > >> > + finger attributes will be reset.*/
> > >> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> > >> > + break;
> > >> > + }
> > >> > +}
> > >> > +
> > >> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> > >> > + struct alps_fields *f)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > + unsigned int fn = 0;
> > >> > + int i;
> > >> > +
> > >> > + switch (priv->r.v7.pkt_id) {
> > >> > + case V7_PACKET_ID_IDLE:
> > >> > + case V7_PACKET_ID_NEW:
> > >> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> > >> > + An 'IDLE' packet indicates that there's no finger on touchpad.
> > >> > + A 'NEW' packet indicates there's finger placed or lifted.
> > >> > + Finger position of 'New' packet is not continues from the
> > >> > + previous packet.*/
> > >> > + fn = 0;
> > >> > + break;
> > >> > + case V7_PACKET_ID_TWO:
> > >> > + if (f->pt_img[0].z == 0) {
> > >> > + /*The first finger slot is zero when a non-resting
> > >> > + finger lifted and remaining only one resting finger
> > >> > + on touchpad. Hardware report the remaining resting
> > >> > + finger in second slot. This resting is ignored*/
> > >> > + fn = 0;
> > >> > + } else if (f->pt_img[1].z == 0) {
> > >> > + /* The second finger slot is zero if there's
> > >> > + only one finger*/
> > >> > + fn = 1;
> > >> > + } else {
> > >> > + /*All non-resting fingers will be counted to report*/
> > >> > + fn = 0;
> > >> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> > >> > + if (priv->pt_attr[i].is_counted)
> > >> > + fn++;
> > >> > + }
> > >> > +
> > >> > + /*In the case that both fingers are
> > >> > + resting fingers, report the first one*/
> > >> > + if (!priv->pt_attr[0].is_counted &&
> > >> > + !priv->pt_attr[1].is_counted) {
> > >> > + fn = 1;
> > >> > + }
> > >> > + }
> > >> > + break;
> > >> > + case V7_PACKET_ID_MULTI:
> > >> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> > >> > + finger exist.*/
> > >> > + fn = 3 + priv->r.v7.additional_fingers;
> > >> > + break;
> > >> > + }
> > >> > +
> > >> > + f->fingers = fn;
> > >> > +}
> > >> > +
> > >> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> > >> > + struct alps_fields *f)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > +
> > >> > + if (priv->phy_btn) {
> > >> > + if (!priv->prev_phy_btn) {
> > >> > + /* Report a right click as long as there's finger on
> > >> > + right button zone. Othrewise, report a left click.*/
> > >> > + if (priv->r.v7.rest_right ||
> > >> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> > >> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> > >> > + f->btn.right = 1;
> > >> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> > >> > + } else {
> > >> > + f->btn.left = 1;
> > >> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> > >> > + }
> > >> > + } else {
> > >> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> > >> > + f->btn.right = 1;
> > >> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> > >> > + f->btn.left = 1;
> > >> > + }
> > >> > + } else {
> > >> > + priv->pressed_btn_bits = 0;
> > >> > + f->btn.right = 0;
> > >> > + f->btn.left = 0;
> > >> > + }
> > >> > +
> > >> > + priv->prev_phy_btn = priv->phy_btn;
> > >> > +}
> > >> > +
> > >> > +static void alps_process_packet_v7(struct psmouse *psmouse)
> > >> > +{
> > >> > + struct alps_data *priv = psmouse->private;
> > >> > + struct alps_fields f = {0};
> > >> > + unsigned char *packet = psmouse->packet;
> > >> > +
> > >> > + priv->decode_fields(&f, packet, psmouse);
> > >> > +
> > >> > + if (alps_drop_unsupported_packet_v7(psmouse))
> > >> > + return;
> > >> > +
> > >> > + alps_set_pt_attr_v7(psmouse, &f);
> > >> > +
> > >> > + alps_cal_output_finger_num_v7(psmouse, &f);
> > >> > +
> > >> > + alps_assign_buttons_v7(psmouse, &f);
> > >> > +
> > >> > + alps_report_coord_and_btn(psmouse, &f);
> > >> > +}
> > >> > +
> > >> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> > >> > unsigned char packet[],
> > >> > bool report_buttons)
> > >> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > >> > return PSMOUSE_BAD_DATA;
> > >> > }
> > >> >
> > >> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
> > >> > + !alps_is_valid_package_v7(psmouse))) {
> > >> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> > >> > + psmouse->pktcnt - 1,
> > >> > + psmouse->packet[psmouse->pktcnt - 1]);
> > >> > + return PSMOUSE_BAD_DATA;
> > >> > + }
> > >> > +
> > >> > if (psmouse->pktcnt == psmouse->pktsize) {
> > >> > priv->process_packet(psmouse);
> > >> > return PSMOUSE_FULL_PACKET;
> > >> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> > >> > return 0;
> > >> > }
> > >> >
> > >> > +static int alps_check_valid_firmware_id(unsigned char id[])
> > >> > +{
> > >> > + int valid = 1;
> > >> > +
> > >> > + if (id[0] == 0x73)
> > >> > + valid = 1;
> > >> > + else if (id[0] == 0x88) {
> > >> > + if ((id[1] == 0x07) ||
> > >> > + (id[1] == 0x08) ||
> > >> > + ((id[1] & 0xf0) == 0xB0))
> > >> > + valid = 1;
> > >> > + }
> > >> > +
> > >> > + return valid;
> > >> > +}
> > >> > +
> > >> > static int alps_enter_command_mode(struct psmouse *psmouse)
> > >> > {
> > >> > unsigned char param[4];
> > >> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> > >> > return -1;
> > >> > }
> > >> >
> > >> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> > >> > - param[0] != 0x73) {
> > >> > + if (!alps_check_valid_firmware_id(param)) {
> > >> > psmouse_dbg(psmouse,
> > >> > "unknown response while entering command mode\n");
> > >> > return -1;
> > >> > @@ -1704,6 +2067,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)
> > >> > {
> > >> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > >> > priv->set_abs_params = alps_set_abs_params_st;
> > >> > priv->x_max = 1023;
> > >> > priv->y_max = 767;
> > >> > + priv->slot_number = 1;
> > >> > break;
> > >> > case ALPS_PROTO_V3:
> > >> > priv->hw_init = alps_hw_init_v3;
> > >> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > >> > priv->decode_fields = alps_decode_pinnacle;
> > >> > priv->nibble_commands = alps_v3_nibble_commands;
> > >> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > >> > + priv->slot_number = 2;
> > >> > break;
> > >> > case ALPS_PROTO_V4:
> > >> > priv->hw_init = alps_hw_init_v4;
> > >> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > >> > priv->set_abs_params = alps_set_abs_params_mt;
> > >> > priv->nibble_commands = alps_v4_nibble_commands;
> > >> > priv->addr_command = PSMOUSE_CMD_DISABLE;
> > >> > + priv->slot_number = 2;
> > >> > break;
> > >> > case ALPS_PROTO_V5:
> > >> > priv->hw_init = alps_hw_init_dolphin_v1;
> > >> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > >> > priv->y_max = 660;
> > >> > priv->x_bits = 23;
> > >> > priv->y_bits = 12;
> > >> > + priv->slot_number = 2;
> > >> > break;
> > >> > case ALPS_PROTO_V6:
> > >> > priv->hw_init = alps_hw_init_v6;
> > >> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> > >> > priv->nibble_commands = alps_v6_nibble_commands;
> > >> > priv->x_max = 2047;
> > >> > priv->y_max = 1535;
> > >> > + priv->slot_number = 2;
> > >> > + break;
> > >> > + case ALPS_PROTO_V7:
> > >> > + priv->hw_init = alps_hw_init_v7;
> > >> > + priv->process_packet = alps_process_packet_v7;
> > >> > + priv->decode_fields = alps_decode_packet_v7;
> > >> > + priv->set_abs_params = alps_set_abs_params_mt;
> > >> > + priv->nibble_commands = alps_v3_nibble_commands;
> > >> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > >> > + priv->x_max = 0xfff;
> > >> > + priv->y_max = 0x7ff;
> > >> > + priv->resting_zone_y_min = 0x654;
> > >> > + priv->byte0 = 0x48;
> > >> > + priv->mask0 = 0x48;
> > >> > + priv->flags = 0;
> > >> > + priv->slot_number = 2;
> > >> > break;
> > >> > }
> > >> > }
> > >> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> > >> > return -EIO;
> > >> > else
> > >> > return 0;
> > >> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> > >> > + priv->proto_version = ALPS_PROTO_V7;
> > >> > + alps_set_defaults(priv);
> > >> > +
> > >> > + return 0;
> > >> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> > >> > priv->proto_version = ALPS_PROTO_V3;
> > >> > alps_set_defaults(priv);
> > >> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > >> > struct input_dev *dev1)
> > >> > {
> > >> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> > >> > - input_mt_init_slots(dev1, 2, 0);
> > >> > + input_mt_init_slots(dev1, priv->slot_number, 0);
> > >> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> > >> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
> > >> >
> > >> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> > >> > index 03f88b6..5d2f9ea 100644
> > >> > --- a/drivers/input/mouse/alps.h
> > >> > +++ b/drivers/input/mouse/alps.h
> > >> > @@ -18,11 +18,36 @@
> > >> > #define ALPS_PROTO_V4 4
> > >> > #define ALPS_PROTO_V5 5
> > >> > #define ALPS_PROTO_V6 6
> > >> > +#define ALPS_PROTO_V7 7
> > >> > +
> > >> > +#define MAX_IMG_PT_NUM 5
> > >> > +#define V7_IMG_PT_NUM 2
> > >> > +
> > >> > +#define ZONE_NORMAL 0x01
> > >> > +#define ZONE_RESTING 0x02
> > >> > +#define ZONE_LEFT_BTN 0x04
> > >> > +#define ZONE_RIGHT_BTN 0x08
> > >> >
> > >> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
> > >> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> > >> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
> > >> >
> > >> > +/*
> > >> > + * enum V7_PACKET_ID - defines the packet type for V7
> > >> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> > >> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> > >> > + * or there's button activities.
> > >> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> > >> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> > >> > + * previous packet.
> > >> > +*/
> > >> > +enum V7_PACKET_ID {
> > >> > + V7_PACKET_ID_IDLE,
> > >> > + V7_PACKET_ID_TWO,
> > >> > + V7_PACKET_ID_MULTI,
> > >> > + V7_PACKET_ID_NEW,
> > >> > +};
> > >> > +
> > >> > /**
> > >> > * struct alps_model_info - touchpad ID table
> > >> > * @signature: E7 response string to match.
> > >> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> > >> > };
> > >> >
> > >> > /**
> > >> > - * struct alps_fields - decoded version of the report packet
> > >> > - * @x_map: Bitmap of active X positions for MT.
> > >> > - * @y_map: Bitmap of active Y positions for MT.
> > >> > - * @fingers: Number of fingers for MT.
> > >> > - * @x: X position for ST.
> > >> > - * @y: Y position for ST.
> > >> > - * @z: Z position for ST.
> > >> > - * @first_mp: Packet is the first of a multi-packet report.
> > >> > - * @is_mp: Packet is part of a multi-packet report.
> > >> > + * struct alps_btn - decoded version of the button status
> > >> > * @left: Left touchpad button is active.
> > >> > * @right: Right touchpad button is active.
> > >> > * @middle: Middle touchpad button is active.
> > >> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> > >> > * @ts_right: Right trackstick button is active.
> > >> > * @ts_middle: Middle trackstick button is active.
> > >> > */
> > >> > -struct alps_fields {
> > >> > - unsigned int x_map;
> > >> > - unsigned int y_map;
> > >> > - unsigned int fingers;
> > >> > - unsigned int x;
> > >> > - unsigned int y;
> > >> > - unsigned int z;
> > >> > - unsigned int first_mp:1;
> > >> > - unsigned int is_mp:1;
> > >> > -
> > >> > +struct alps_btn {
> > >> > unsigned int left:1;
> > >> > unsigned int right:1;
> > >> > unsigned int middle:1;
> > >> > @@ -102,6 +110,69 @@ struct alps_fields {
> > >> > };
> > >> >
> > >> > /**
> > >> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
> > >> > + * @x: X position for ST.
> > >> > + * @y: Y position for ST.
> > >> > + * @z: Z position for ST.
> > >> > + */
> > >> > +struct alps_abs_data {
> > >> > + unsigned int x;
> > >> > + unsigned int y;
> > >> > + unsigned int z;
> > >> > +};
> > >> > +
> > >> > +/**
> > >> > + * struct alps_fields - decoded version of the report packet
> > >> > + * @fingers: Number of fingers for MT.
> > >> > + * @pt: X Y Z postion for ST.
> > >> > + * @pt: X Y Z postion for image MT.
> > >> > + * @x_map: Bitmap of active X positions for MT.
> > >> > + * @y_map: Bitmap of active Y positions for MT.
> > >> > + * @first_mp: Packet is the first of a multi-packet report.
> > >> > + * @is_mp: Packet is part of a multi-packet report.
> > >> > + * @btn: Button activity status
> > >> > + */
> > >> > +struct alps_fields {
> > >> > + unsigned int fingers;
> > >> > + struct alps_abs_data pt;
> > >> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> > >> > + unsigned int x_map;
> > >> > + unsigned int y_map;
> > >> > + unsigned int first_mp:1;
> > >> > + unsigned int is_mp:1;
> > >> > + struct alps_btn btn;
> > >> > +};
> > >> > +
> > >> > +/**
> > >> > + * struct v7_raw - data decoded from raw packet for V7.
> > >> > + * @pkt_id: An id that specifies the type of packet.
> > >> > + * @additional_fingers: Number of additional finger that is neighter included
> > >> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> > >> > + * @rest_left: There are fingers on left resting zone.
> > >> > + * @rest_right: There are fingers on right resting zone.
> > >> > + */
> > >> > +struct v7_raw {
> > >> > + unsigned char pkt_id;
> > >> > + unsigned int additional_fingers;
> > >> > + unsigned char rest_left;
> > >> > + unsigned char rest_right;
> > >> > +};
> > >> > +
> > >> > +/**
> > >> > + * 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;
> > >> > +};
> > >> > +
> > >> > +/**
> > >> > * struct alps_data - private data structure for the ALPS driver
> > >> > * @dev2: "Relative" device used to report trackstick or mouse activity.
> > >> > * @phys: Physical path for the relative device.
> > >> > @@ -116,8 +187,10 @@ struct alps_fields {
> > >> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> > >> > * @x_max: Largest possible X position value.
> > >> > * @y_max: Largest possible Y position value.
> > >> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> > >> > * @x_bits: Number of X bits in the MT bitmap.
> > >> > * @y_bits: Number of Y bits in the MT bitmap.
> > >> > + * @img_fingers: Number of image fingers.
> > >> > * @hw_init: Protocol-specific hardware init function.
> > >> > * @process_packet: Protocol-specific function to process a report packet.
> > >> > * @decode_fields: Protocol-specific function to read packet bitfields.
> > >> > @@ -132,6 +205,11 @@ struct alps_fields {
> > >> > * @fingers: Number of fingers from last MT report.
> > >> > * @quirks: Bitmap of ALPS_QUIRK_*.
> > >> > * @timer: Timer for flushing out the final report packet in the stream.
> > >> > + * @v7: Data decoded from raw packet for V7
> > >> > + * @phy_btn: Physical button is active.
> > >> > + * @prev_phy_btn: Physical button of previous packet is active.
> > >> > + * @pressed_btn_bits: Pressed positon of button zone
> > >> > + * @pt_attr: Generic attributes of touch points for buttonless device.
> > >> > */
> > >> > struct alps_data {
> > >> > struct input_dev *dev2;
> > >> > @@ -145,8 +223,10 @@ struct alps_data {
> > >> > unsigned char flags;
> > >> > int x_max;
> > >> > int y_max;
> > >> > + int resting_zone_y_min;
> > >> > int x_bits;
> > >> > int y_bits;
> > >> > + unsigned char slot_number;
> > >> >
> > >> > int (*hw_init)(struct psmouse *psmouse);
> > >> > void (*process_packet)(struct psmouse *psmouse);
> > >> > @@ -161,6 +241,15 @@ struct alps_data {
> > >> > int fingers;
> > >> > u8 quirks;
> > >> > struct timer_list timer;
> > >> > +
> > >> > + /* these are used for buttonless touchpad*/
> > >> > + union {
> > >> > + struct v7_raw v7;
> > >> > + } r;
> > >> > + unsigned char phy_btn;
> > >> > + unsigned char prev_phy_btn;
> > >> > + unsigned char pressed_btn_bits;
> > >> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> > >> > };
> > >> >
> > >> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> > >> > --
> > >> > 1.8.3.2
> > >> >
> > >> --
> > >> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> > >> the body of a message to majordomo@vger.kernel.org
> > >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> > >>
> >
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Atmel updates to atmel_mxt_ts touch controller driver - v6
From: Nick Dyer @ 2014-01-15 10:44 UTC (permalink / raw)
To: Yufeng Shen, Dmitry Torokhov
Cc: Henrik Rydberg, Daniel Kurtz, Joonyoung Shim, Alan Bowens,
linux-input, linux-kernel, Peter Meerwald, Benson Leung,
Olof Johansson, adlr
In-Reply-To: <CAPDwgkOo7FYLujk16kJM=BqmXRKvZ2S_LOYURW0cXT5t=cmi6w@mail.gmail.com>
Yufeng Shen wrote:
> On Tue, Sep 10, 2013 at 9:58 AM, Nick Dyer <nick.dyer@itdev.co.uk
> <mailto:nick.dyer@itdev.co.uk>> wrote:
>> Dmitry Torokhov wrote:
>> > On Thu, Aug 15, 2013 at 04:55:57PM +0100, Nick Dyer wrote:
>> >> rydberg@euromail.se <mailto:rydberg@euromail.se> wrote:
>> >>> First: thanks for the patches and you work on this driver.
>> >>
>> >> Thank you for your time in looking at these changes.
>> >>
>> >>> Now, I don't swear much, but I would like to emphasize line 161 of
>> >>> Documentation/SubmittingPatches:
>> >>>
>> >>> **Do not send more than 15 patches at once to the vger mailing
> lists!!!***
>> >>>
>> >>> One reason that should be obvious by now is that your work will be
>> >>> attended to much quicker. One may think that it is more efficient to
>> >>> send the whole backlog at once, but in fact, the time it takes to get
>> >>> a patchset accepted is inversely proportional to the length of the
>> >>> patchset. So please, keep it small and simple next time,
>> >>
>> >> Apologies. I will split this lot up into several smaller series of
> patches.
>> >
>> > Wait, I am in the process of applying it actually...
>>
>> I wonder, have you made any progress with this? Is there any way I can
>> assist?
>
> Hey Dimitry,
>
> What's the status on this ?
>
> I noticed that at /pub/scm/linux/kernel/git/dtor/input, branch
> atmel-mxt-ts has part of Nick's patches applied
> but not all. The upstream tree and Nick's tree
> https://github.com/ndyer/linux/commits/for-next are still
> significantly diverged.
>
> I am wondering any plan on your side to apply more patches that sent out by
> Nick ?
>
> We (Chromium authors) are planning on bringing our local tree of atmel
> driver to be as close as possible to
> upstream and trying to figure out what's the best tree to rebase against.
I was considering picking up the patches that Dimitry has already reviewed
and rebasing them against the current mainline to try and get things moving
again - would that be useful?
^ permalink raw reply
* Re: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Dylan Thurston @ 2014-01-15 5:16 UTC (permalink / raw)
To: Elaine Chen
Cc: Tommy Will, Dmitry Torokhov, Kevin Cernekee, david turvene,
Niels de Vos, Justin Clift, Qiting Chen, linux-input
In-Reply-To: <CAKvfdtLoQvfu-u51NCLTRU8020ZQGXksh1f6Cj84dzK=O1NCjQ@mail.gmail.com>
This patch seems to work in the 3.13-rc8 kernel, at least on an
initial check. The problems with excess clicks while typing have
disappeared. I'll report back with any glitches I see.
Thank you!
--Dylan
On Wed, Jan 15, 2014 at 11:15:02AM +0800, Elaine Chen wrote:
> Hi Dylan,
>
> Thank you! This patch is againt Dmitry Torokhov's input tree, based on
> the modification of:
> 2013-12-26 Input: ALPS - add support for "Dolphin" devices Yunkang Tang
> As linux-next-20140114 has already merged Dolphin support, the patch
> should be matched.
> As for the blank screen, I'll debug on my side. Sorry for that.
> What is the kernel version on your HP side? Is it 3.13-rc8?
>
> Yes, it is safe to copy both alps.c and alps.h from linux-next version
> to 3.13-rc8 kerenl.
>
>
>
> 2014/1/15 Dylan Thurston <dpthurst@indiana.edu>:
> > Thank you! Which versions does this apply against? It patched for me
> > with no fuzz against linux-next-20140114, but unfortunately X seems to
> > be broken for me on that version (blank screen). I get fuzz and
> > rejected patches when applying it to 3.13-rc8. Is it safe to just copy
> > over alps.c from the linux-next version?
> >
> > (Of course, it's possible that the blank screen is a side effect of
> > the correct recognition of the touchpad.)
> >
> > Thanks,
> > Dylan
> >
> > On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
> >> Hi Dylan,
> >>
> >> My colleague Elaine has prepared the patch for new ALPS touchpad that
> >> being used on your HP Revolve 810 G1 laptop.
> >> You can have a try~
> >>
> >> --
> >> Best Regards,
> >> Tommy
> >>
> >> ---------- Forwarded message ----------
> >> From: Elaine Chen <elaineee66@gmail.com>
> >> Date: 2014/1/14
> >> Subject: Re: [PATCH] add support for ALPS v7 protocol device
> >> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
> >> david turvene <dturvene@dahetral.com>
> >> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
> >> Qiting Chen <qiting.chen@cn.alps.com>
> >>
> >>
> >> As far as I know, the ALPS v7 protocol device is used on following laptops:
> >>
> >> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
> >>
> >> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> >> > Here is the patch of supporting ALPS v7 protocol device.
> >> >
> >> > v7 device is a clickpad device.
> >> > Device info:
> >> > Device ID = 0x73, 0x03, 0x0a
> >> > Firmware ID = 0x88, 0xb*, 0x**
> >> >
> >> > Support function of v7 device:
> >> > - Cursor
> >> > - Tap, double tap, tap drag, 2finger tap
> >> > - Pan, pinch
> >> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> >> > Click touchpad with all fingers outside right Button Area --> left click
> >> > Click touchpad with at lease 1 finger inside right Button Area --> right click
> >> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
> >> >
> >> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> >> > We tried registering our device as a clickpad by:
> >> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> >> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
> >> >
> >> >
> >> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> >> > ---
> >> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> >> > drivers/input/mouse/alps.h | 127 ++++++++++--
> >> > 2 files changed, 554 insertions(+), 51 deletions(-)
> >> >
> >> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> >> > index fb15c64..3e8e8f7 100644
> >> > --- a/drivers/input/mouse/alps.c
> >> > +++ b/drivers/input/mouse/alps.c
> >> > @@ -32,6 +32,11 @@
> >> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> >> > #define ALPS_REG_BASE_PINNACLE 0x0000
> >> >
> >> > +#define LEFT_BUTTON_BIT 0x01
> >> > +#define RIGHT_BUTTON_BIT 0x02
> >> > +
> >> > +#define V7_LARGE_MOVEMENT 130
> >> > +
> >> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> >> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> >> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> >> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> >> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> >> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> >> > 6-byte ALPS packet */
> >> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
> >> >
> >> > static const struct alps_model_info alps_model_data[] = {
> >> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> >> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> >> > * isn't valid per PS/2 spec.
> >> > */
> >> >
> >> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> >> > + struct alps_abs_data *pt1)
> >> > +{
> >> > + int vect_x, vect_y;
> >> > +
> >> > + if (!pt0 || !pt1)
> >> > + return 0;
> >> > +
> >> > + vect_x = pt0->x - pt1->x;
> >> > + vect_y = pt0->y - pt1->y;
> >> > +
> >> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> >> > +}
> >> > +
> >> > /* Packet formats are described in Documentation/input/alps.txt */
> >> >
> >> > static bool alps_is_valid_first_byte(struct alps_data *priv,
> >> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> >> > end_bit = y_msb - 1;
> >> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> >> > (2 * (priv->y_bits - 1));
> >> > - *x1 = fields->x;
> >> > - *y1 = fields->y;
> >> > + *x1 = fields->pt.x;
> >> > + *y1 = fields->pt.y;
> >> > *x2 = 2 * box_middle_x - *x1;
> >> > *y2 = 2 * box_middle_y - *y1;
> >> > }
> >> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> >> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> >> > }
> >> >
> >> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> >> > + struct alps_fields *f)
> >> > +{
> >> > + struct input_dev *dev;
> >> > +
> >> > + if (!psmouse || !f)
> >> > + return;
> >> > +
> >> > + dev = psmouse->dev;
> >> > +
> >> > + if (f->fingers) {
> >> > + input_report_key(dev, BTN_TOUCH, 1);
> >> > + alps_report_semi_mt_data(dev, f->fingers,
> >> > + f->pt_img[0].x, f->pt_img[0].y,
> >> > + f->pt_img[1].x, f->pt_img[1].y);
> >> > + input_mt_report_finger_count(dev, f->fingers);
> >> > +
> >> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> >> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> >> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> >> > + } else {
> >> > + input_report_key(dev, BTN_TOUCH, 0);
> >> > + input_mt_report_finger_count(dev, 0);
> >> > + input_report_abs(dev, ABS_PRESSURE, 0);
> >> > + }
> >> > +
> >> > + input_report_key(dev, BTN_LEFT, f->btn.left);
> >> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
> >> > +
> >> > + input_sync(dev);
> >> > +}
> >> > +
> >> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> >> > {
> >> > struct alps_data *priv = psmouse->private;
> >> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> >> >
> >> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> >> > {
> >> > - f->left = !!(p[3] & 0x01);
> >> > - f->right = !!(p[3] & 0x02);
> >> > - f->middle = !!(p[3] & 0x04);
> >> > + f->btn.left = !!(p[3] & 0x01);
> >> > + f->btn.right = !!(p[3] & 0x02);
> >> > + f->btn.middle = !!(p[3] & 0x04);
> >> >
> >> > - f->ts_left = !!(p[3] & 0x10);
> >> > - f->ts_right = !!(p[3] & 0x20);
> >> > - f->ts_middle = !!(p[3] & 0x40);
> >> > + f->btn.ts_left = !!(p[3] & 0x10);
> >> > + f->btn.ts_right = !!(p[3] & 0x20);
> >> > + f->btn.ts_middle = !!(p[3] & 0x40);
> >> > }
> >> >
> >> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> >> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> >> > ((p[2] & 0x7f) << 1) |
> >> > (p[4] & 0x01);
> >> >
> >> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> >> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> >> > ((p[0] & 0x30) >> 4);
> >> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> >> > - f->z = p[5] & 0x7f;
> >> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> >> > + f->pt.z = p[5] & 0x7f;
> >> >
> >> > alps_decode_buttons_v3(f, p);
> >> > }
> >> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> >> > f->is_mp = !!(p[0] & 0x20);
> >> >
> >> > if (!f->is_mp) {
> >> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> >> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> >> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> >> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> >> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> >> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> >> > alps_decode_buttons_v3(f, p);
> >> > } else {
> >> > f->fingers = ((p[0] & 0x6) >> 1 |
> >> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> >> > * with x, y, and z all zero, so these seem to be flukes.
> >> > * Ignore them.
> >> > */
> >> > - if (f.x && f.y && !f.z)
> >> > + if (f.pt.x && f.pt.y && !f.pt.z)
> >> > return;
> >> >
> >> > /*
> >> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> >> > * to rely on ST data.
> >> > */
> >> > if (!fingers) {
> >> > - x1 = f.x;
> >> > - y1 = f.y;
> >> > - fingers = f.z > 0 ? 1 : 0;
> >> > + x1 = f.pt.x;
> >> > + y1 = f.pt.y;
> >> > + fingers = f.pt.z > 0 ? 1 : 0;
> >> > }
> >> >
> >> > - if (f.z >= 64)
> >> > + if (f.pt.z >= 64)
> >> > input_report_key(dev, BTN_TOUCH, 1);
> >> > else
> >> > input_report_key(dev, BTN_TOUCH, 0);
> >> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> >> >
> >> > input_mt_report_finger_count(dev, fingers);
> >> >
> >> > - input_report_key(dev, BTN_LEFT, f.left);
> >> > - input_report_key(dev, BTN_RIGHT, f.right);
> >> > - input_report_key(dev, BTN_MIDDLE, f.middle);
> >> > + input_report_key(dev, BTN_LEFT, f.btn.left);
> >> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
> >> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
> >> >
> >> > - if (f.z > 0) {
> >> > - input_report_abs(dev, ABS_X, f.x);
> >> > - input_report_abs(dev, ABS_Y, f.y);
> >> > + if (f.pt.z > 0) {
> >> > + input_report_abs(dev, ABS_X, f.pt.x);
> >> > + input_report_abs(dev, ABS_Y, f.pt.y);
> >> > }
> >> > - input_report_abs(dev, ABS_PRESSURE, f.z);
> >> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
> >> >
> >> > input_sync(dev);
> >> >
> >> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> >> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
> >> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> >> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> >> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> >> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> >> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> >> > input_sync(dev2);
> >> > }
> >> > }
> >> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> >> > input_sync(dev);
> >> > }
> >> >
> >> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> >> > +{
> >> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> >> > + return false;
> >> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> >> > + return false;
> >> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> >> > + return false;
> >> > + return true;
> >> > +}
> >> > +
> >> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > + int drop = 1;
> >> > +
> >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> >> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> >> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> >> > + drop = 0;
> >> > +
> >> > + return drop;
> >> > +}
> >> > +
> >> > +static unsigned char alps_get_packet_id_v7(char *byte)
> >> > +{
> >> > + unsigned char packet_id;
> >> > +
> >> > + if (byte[4] & 0x40)
> >> > + packet_id = V7_PACKET_ID_TWO;
> >> > + else if (byte[4] & 0x01)
> >> > + packet_id = V7_PACKET_ID_MULTI;
> >> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> >> > + packet_id = V7_PACKET_ID_NEW;
> >> > + else
> >> > + packet_id = V7_PACKET_ID_IDLE;
> >> > +
> >> > + return packet_id;
> >> > +}
> >> > +
> >> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> >> > + unsigned char *pkt,
> >> > + unsigned char pkt_id)
> >> > +{
> >> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
> >> > + (pkt_id == V7_PACKET_ID_MULTI) ||
> >> > + (pkt_id == V7_PACKET_ID_NEW)) {
> >> > + pt[0].x = ((pkt[2] & 0x80) << 4);
> >> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> >> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> >> > + pt[0].x |= (pkt[3] & 0x07);
> >> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> >> > +
> >> > + pt[1].x = ((pkt[3] & 0x80) << 4);
> >> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
> >> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> >> > + pt[1].y = ((pkt[5] & 0x80) << 3);
> >> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> >> > +
> >> > + if (pkt_id == V7_PACKET_ID_TWO) {
> >> > + pt[1].x &= ~0x000F;
> >> > + pt[1].y |= 0x000F;
> >> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> >> > + pt[1].x &= ~0x003F;
> >> > + pt[1].y &= ~0x0020;
> >> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
> >> > + pt[1].y |= 0x001F;
> >> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
> >> > + pt[1].x &= ~0x003F;
> >> > + pt[1].x |= (pkt[0] & 0x20);
> >> > + pt[1].y |= 0x000F;
> >> > + }
> >> > +
> >> > + pt[0].y = 0x7FF - pt[0].y;
> >> > + pt[1].y = 0x7FF - pt[1].y;
> >> > +
> >> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> >> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> >> > + }
> >> > +}
> >> > +
> >> > +static void alps_decode_packet_v7(struct alps_fields *f,
> >> > + unsigned char *p,
> >> > + struct psmouse *psmouse)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > +
> >> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> >> > +
> >> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> >> > +
> >> > + priv->r.v7.rest_left = 0;
> >> > + priv->r.v7.rest_right = 0;
> >> > + priv->r.v7.additional_fingers = 0;
> >> > + priv->phy_btn = 0;
> >> > +
> >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> >> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> >> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> >> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> >> > + }
> >> > +
> >> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> >> > + priv->r.v7.additional_fingers = p[5] & 0x03;
> >> > +
> >> > + priv->phy_btn = (p[0] & 0x80) >> 7;
> >> > +}
> >> > +
> >> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> >> > + struct alps_abs_data *pt,
> >> > + struct alps_bl_pt_attr *pt_attr)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > + unsigned int dist;
> >> > +
> >> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> >> > + pt_attr->is_init_pt_got = 1;
> >> > + pt_attr->is_counted = 0;
> >> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> >> > + }
> >> > +
> >> > + if (pt->z != 0) {
> >> > + if (pt->y < priv->resting_zone_y_min) {
> >> > + /* A finger is recognized as a non-resting finger
> >> > + if it's position is outside the resting finger zone.*/
> >> > + pt_attr->zone = ZONE_NORMAL;
> >> > + pt_attr->is_counted = 1;
> >> > + } else {
> >> > + /* A finger is recognized as a resting finger if it's
> >> > + position is inside the resting finger zone and there's
> >> > + no large movement from it's touch down position.*/
> >> > + pt_attr->zone = ZONE_RESTING;
> >> > +
> >> > + if (pt->x > priv->x_max / 2)
> >> > + pt_attr->zone |= ZONE_RIGHT_BTN;
> >> > + else
> >> > + pt_attr->zone |= ZONE_LEFT_BTN;
> >> > +
> >> > + /* A resting finger will turn to be a non-resting
> >> > + finger if it has made large movement from it's touch
> >> > + down position. A non-resting finger will never turn
> >> > + to a resting finger before it leaves the touchpad
> >> > + surface.*/
> >> > + if (pt_attr->is_init_pt_got) {
> >> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> >> > +
> >> > + if (dist > V7_LARGE_MOVEMENT)
> >> > + pt_attr->is_counted = 1;
> >> > + }
> >> > + }
> >> > + }
> >> > +}
> >> > +
> >> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> >> > + struct alps_fields *f)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > + int i;
> >> > +
> >> > + switch (priv->r.v7.pkt_id) {
> >> > + case V7_PACKET_ID_TWO:
> >> > + case V7_PACKET_ID_MULTI:
> >> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
> >> > + alps_set_each_pt_attr_v7(psmouse,
> >> > + &f->pt_img[i],
> >> > + &priv->pt_attr[i]);
> >> > + break;
> >> > + default:
> >> > + /*All finger attributes are cleared when packet ID is
> >> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> >> > + indicates that there's no finger and no button activity.
> >> > + A 'NEW' packet indicates the finger position in packet
> >> > + is not continues from previous packet. Such as the
> >> > + condition there's finger placed or lifted. In these cases,
> >> > + finger attributes will be reset.*/
> >> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> >> > + break;
> >> > + }
> >> > +}
> >> > +
> >> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> >> > + struct alps_fields *f)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > + unsigned int fn = 0;
> >> > + int i;
> >> > +
> >> > + switch (priv->r.v7.pkt_id) {
> >> > + case V7_PACKET_ID_IDLE:
> >> > + case V7_PACKET_ID_NEW:
> >> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> >> > + An 'IDLE' packet indicates that there's no finger on touchpad.
> >> > + A 'NEW' packet indicates there's finger placed or lifted.
> >> > + Finger position of 'New' packet is not continues from the
> >> > + previous packet.*/
> >> > + fn = 0;
> >> > + break;
> >> > + case V7_PACKET_ID_TWO:
> >> > + if (f->pt_img[0].z == 0) {
> >> > + /*The first finger slot is zero when a non-resting
> >> > + finger lifted and remaining only one resting finger
> >> > + on touchpad. Hardware report the remaining resting
> >> > + finger in second slot. This resting is ignored*/
> >> > + fn = 0;
> >> > + } else if (f->pt_img[1].z == 0) {
> >> > + /* The second finger slot is zero if there's
> >> > + only one finger*/
> >> > + fn = 1;
> >> > + } else {
> >> > + /*All non-resting fingers will be counted to report*/
> >> > + fn = 0;
> >> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> >> > + if (priv->pt_attr[i].is_counted)
> >> > + fn++;
> >> > + }
> >> > +
> >> > + /*In the case that both fingers are
> >> > + resting fingers, report the first one*/
> >> > + if (!priv->pt_attr[0].is_counted &&
> >> > + !priv->pt_attr[1].is_counted) {
> >> > + fn = 1;
> >> > + }
> >> > + }
> >> > + break;
> >> > + case V7_PACKET_ID_MULTI:
> >> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> >> > + finger exist.*/
> >> > + fn = 3 + priv->r.v7.additional_fingers;
> >> > + break;
> >> > + }
> >> > +
> >> > + f->fingers = fn;
> >> > +}
> >> > +
> >> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> >> > + struct alps_fields *f)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > +
> >> > + if (priv->phy_btn) {
> >> > + if (!priv->prev_phy_btn) {
> >> > + /* Report a right click as long as there's finger on
> >> > + right button zone. Othrewise, report a left click.*/
> >> > + if (priv->r.v7.rest_right ||
> >> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> >> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> >> > + f->btn.right = 1;
> >> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> >> > + } else {
> >> > + f->btn.left = 1;
> >> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> >> > + }
> >> > + } else {
> >> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> >> > + f->btn.right = 1;
> >> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> >> > + f->btn.left = 1;
> >> > + }
> >> > + } else {
> >> > + priv->pressed_btn_bits = 0;
> >> > + f->btn.right = 0;
> >> > + f->btn.left = 0;
> >> > + }
> >> > +
> >> > + priv->prev_phy_btn = priv->phy_btn;
> >> > +}
> >> > +
> >> > +static void alps_process_packet_v7(struct psmouse *psmouse)
> >> > +{
> >> > + struct alps_data *priv = psmouse->private;
> >> > + struct alps_fields f = {0};
> >> > + unsigned char *packet = psmouse->packet;
> >> > +
> >> > + priv->decode_fields(&f, packet, psmouse);
> >> > +
> >> > + if (alps_drop_unsupported_packet_v7(psmouse))
> >> > + return;
> >> > +
> >> > + alps_set_pt_attr_v7(psmouse, &f);
> >> > +
> >> > + alps_cal_output_finger_num_v7(psmouse, &f);
> >> > +
> >> > + alps_assign_buttons_v7(psmouse, &f);
> >> > +
> >> > + alps_report_coord_and_btn(psmouse, &f);
> >> > +}
> >> > +
> >> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> >> > unsigned char packet[],
> >> > bool report_buttons)
> >> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> >> > return PSMOUSE_BAD_DATA;
> >> > }
> >> >
> >> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
> >> > + !alps_is_valid_package_v7(psmouse))) {
> >> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> >> > + psmouse->pktcnt - 1,
> >> > + psmouse->packet[psmouse->pktcnt - 1]);
> >> > + return PSMOUSE_BAD_DATA;
> >> > + }
> >> > +
> >> > if (psmouse->pktcnt == psmouse->pktsize) {
> >> > priv->process_packet(psmouse);
> >> > return PSMOUSE_FULL_PACKET;
> >> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> >> > return 0;
> >> > }
> >> >
> >> > +static int alps_check_valid_firmware_id(unsigned char id[])
> >> > +{
> >> > + int valid = 1;
> >> > +
> >> > + if (id[0] == 0x73)
> >> > + valid = 1;
> >> > + else if (id[0] == 0x88) {
> >> > + if ((id[1] == 0x07) ||
> >> > + (id[1] == 0x08) ||
> >> > + ((id[1] & 0xf0) == 0xB0))
> >> > + valid = 1;
> >> > + }
> >> > +
> >> > + return valid;
> >> > +}
> >> > +
> >> > static int alps_enter_command_mode(struct psmouse *psmouse)
> >> > {
> >> > unsigned char param[4];
> >> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> >> > return -1;
> >> > }
> >> >
> >> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> >> > - param[0] != 0x73) {
> >> > + if (!alps_check_valid_firmware_id(param)) {
> >> > psmouse_dbg(psmouse,
> >> > "unknown response while entering command mode\n");
> >> > return -1;
> >> > @@ -1704,6 +2067,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)
> >> > {
> >> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> >> > priv->set_abs_params = alps_set_abs_params_st;
> >> > priv->x_max = 1023;
> >> > priv->y_max = 767;
> >> > + priv->slot_number = 1;
> >> > break;
> >> > case ALPS_PROTO_V3:
> >> > priv->hw_init = alps_hw_init_v3;
> >> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> >> > priv->decode_fields = alps_decode_pinnacle;
> >> > priv->nibble_commands = alps_v3_nibble_commands;
> >> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> >> > + priv->slot_number = 2;
> >> > break;
> >> > case ALPS_PROTO_V4:
> >> > priv->hw_init = alps_hw_init_v4;
> >> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> >> > priv->set_abs_params = alps_set_abs_params_mt;
> >> > priv->nibble_commands = alps_v4_nibble_commands;
> >> > priv->addr_command = PSMOUSE_CMD_DISABLE;
> >> > + priv->slot_number = 2;
> >> > break;
> >> > case ALPS_PROTO_V5:
> >> > priv->hw_init = alps_hw_init_dolphin_v1;
> >> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> >> > priv->y_max = 660;
> >> > priv->x_bits = 23;
> >> > priv->y_bits = 12;
> >> > + priv->slot_number = 2;
> >> > break;
> >> > case ALPS_PROTO_V6:
> >> > priv->hw_init = alps_hw_init_v6;
> >> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> >> > priv->nibble_commands = alps_v6_nibble_commands;
> >> > priv->x_max = 2047;
> >> > priv->y_max = 1535;
> >> > + priv->slot_number = 2;
> >> > + break;
> >> > + case ALPS_PROTO_V7:
> >> > + priv->hw_init = alps_hw_init_v7;
> >> > + priv->process_packet = alps_process_packet_v7;
> >> > + priv->decode_fields = alps_decode_packet_v7;
> >> > + priv->set_abs_params = alps_set_abs_params_mt;
> >> > + priv->nibble_commands = alps_v3_nibble_commands;
> >> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> >> > + priv->x_max = 0xfff;
> >> > + priv->y_max = 0x7ff;
> >> > + priv->resting_zone_y_min = 0x654;
> >> > + priv->byte0 = 0x48;
> >> > + priv->mask0 = 0x48;
> >> > + priv->flags = 0;
> >> > + priv->slot_number = 2;
> >> > break;
> >> > }
> >> > }
> >> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> >> > return -EIO;
> >> > else
> >> > return 0;
> >> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> >> > + priv->proto_version = ALPS_PROTO_V7;
> >> > + alps_set_defaults(priv);
> >> > +
> >> > + return 0;
> >> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> >> > priv->proto_version = ALPS_PROTO_V3;
> >> > alps_set_defaults(priv);
> >> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> >> > struct input_dev *dev1)
> >> > {
> >> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> >> > - input_mt_init_slots(dev1, 2, 0);
> >> > + input_mt_init_slots(dev1, priv->slot_number, 0);
> >> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> >> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
> >> >
> >> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> >> > index 03f88b6..5d2f9ea 100644
> >> > --- a/drivers/input/mouse/alps.h
> >> > +++ b/drivers/input/mouse/alps.h
> >> > @@ -18,11 +18,36 @@
> >> > #define ALPS_PROTO_V4 4
> >> > #define ALPS_PROTO_V5 5
> >> > #define ALPS_PROTO_V6 6
> >> > +#define ALPS_PROTO_V7 7
> >> > +
> >> > +#define MAX_IMG_PT_NUM 5
> >> > +#define V7_IMG_PT_NUM 2
> >> > +
> >> > +#define ZONE_NORMAL 0x01
> >> > +#define ZONE_RESTING 0x02
> >> > +#define ZONE_LEFT_BTN 0x04
> >> > +#define ZONE_RIGHT_BTN 0x08
> >> >
> >> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
> >> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> >> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
> >> >
> >> > +/*
> >> > + * enum V7_PACKET_ID - defines the packet type for V7
> >> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> >> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> >> > + * or there's button activities.
> >> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> >> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> >> > + * previous packet.
> >> > +*/
> >> > +enum V7_PACKET_ID {
> >> > + V7_PACKET_ID_IDLE,
> >> > + V7_PACKET_ID_TWO,
> >> > + V7_PACKET_ID_MULTI,
> >> > + V7_PACKET_ID_NEW,
> >> > +};
> >> > +
> >> > /**
> >> > * struct alps_model_info - touchpad ID table
> >> > * @signature: E7 response string to match.
> >> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> >> > };
> >> >
> >> > /**
> >> > - * struct alps_fields - decoded version of the report packet
> >> > - * @x_map: Bitmap of active X positions for MT.
> >> > - * @y_map: Bitmap of active Y positions for MT.
> >> > - * @fingers: Number of fingers for MT.
> >> > - * @x: X position for ST.
> >> > - * @y: Y position for ST.
> >> > - * @z: Z position for ST.
> >> > - * @first_mp: Packet is the first of a multi-packet report.
> >> > - * @is_mp: Packet is part of a multi-packet report.
> >> > + * struct alps_btn - decoded version of the button status
> >> > * @left: Left touchpad button is active.
> >> > * @right: Right touchpad button is active.
> >> > * @middle: Middle touchpad button is active.
> >> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> >> > * @ts_right: Right trackstick button is active.
> >> > * @ts_middle: Middle trackstick button is active.
> >> > */
> >> > -struct alps_fields {
> >> > - unsigned int x_map;
> >> > - unsigned int y_map;
> >> > - unsigned int fingers;
> >> > - unsigned int x;
> >> > - unsigned int y;
> >> > - unsigned int z;
> >> > - unsigned int first_mp:1;
> >> > - unsigned int is_mp:1;
> >> > -
> >> > +struct alps_btn {
> >> > unsigned int left:1;
> >> > unsigned int right:1;
> >> > unsigned int middle:1;
> >> > @@ -102,6 +110,69 @@ struct alps_fields {
> >> > };
> >> >
> >> > /**
> >> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
> >> > + * @x: X position for ST.
> >> > + * @y: Y position for ST.
> >> > + * @z: Z position for ST.
> >> > + */
> >> > +struct alps_abs_data {
> >> > + unsigned int x;
> >> > + unsigned int y;
> >> > + unsigned int z;
> >> > +};
> >> > +
> >> > +/**
> >> > + * struct alps_fields - decoded version of the report packet
> >> > + * @fingers: Number of fingers for MT.
> >> > + * @pt: X Y Z postion for ST.
> >> > + * @pt: X Y Z postion for image MT.
> >> > + * @x_map: Bitmap of active X positions for MT.
> >> > + * @y_map: Bitmap of active Y positions for MT.
> >> > + * @first_mp: Packet is the first of a multi-packet report.
> >> > + * @is_mp: Packet is part of a multi-packet report.
> >> > + * @btn: Button activity status
> >> > + */
> >> > +struct alps_fields {
> >> > + unsigned int fingers;
> >> > + struct alps_abs_data pt;
> >> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> >> > + unsigned int x_map;
> >> > + unsigned int y_map;
> >> > + unsigned int first_mp:1;
> >> > + unsigned int is_mp:1;
> >> > + struct alps_btn btn;
> >> > +};
> >> > +
> >> > +/**
> >> > + * struct v7_raw - data decoded from raw packet for V7.
> >> > + * @pkt_id: An id that specifies the type of packet.
> >> > + * @additional_fingers: Number of additional finger that is neighter included
> >> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> >> > + * @rest_left: There are fingers on left resting zone.
> >> > + * @rest_right: There are fingers on right resting zone.
> >> > + */
> >> > +struct v7_raw {
> >> > + unsigned char pkt_id;
> >> > + unsigned int additional_fingers;
> >> > + unsigned char rest_left;
> >> > + unsigned char rest_right;
> >> > +};
> >> > +
> >> > +/**
> >> > + * 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;
> >> > +};
> >> > +
> >> > +/**
> >> > * struct alps_data - private data structure for the ALPS driver
> >> > * @dev2: "Relative" device used to report trackstick or mouse activity.
> >> > * @phys: Physical path for the relative device.
> >> > @@ -116,8 +187,10 @@ struct alps_fields {
> >> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> >> > * @x_max: Largest possible X position value.
> >> > * @y_max: Largest possible Y position value.
> >> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> >> > * @x_bits: Number of X bits in the MT bitmap.
> >> > * @y_bits: Number of Y bits in the MT bitmap.
> >> > + * @img_fingers: Number of image fingers.
> >> > * @hw_init: Protocol-specific hardware init function.
> >> > * @process_packet: Protocol-specific function to process a report packet.
> >> > * @decode_fields: Protocol-specific function to read packet bitfields.
> >> > @@ -132,6 +205,11 @@ struct alps_fields {
> >> > * @fingers: Number of fingers from last MT report.
> >> > * @quirks: Bitmap of ALPS_QUIRK_*.
> >> > * @timer: Timer for flushing out the final report packet in the stream.
> >> > + * @v7: Data decoded from raw packet for V7
> >> > + * @phy_btn: Physical button is active.
> >> > + * @prev_phy_btn: Physical button of previous packet is active.
> >> > + * @pressed_btn_bits: Pressed positon of button zone
> >> > + * @pt_attr: Generic attributes of touch points for buttonless device.
> >> > */
> >> > struct alps_data {
> >> > struct input_dev *dev2;
> >> > @@ -145,8 +223,10 @@ struct alps_data {
> >> > unsigned char flags;
> >> > int x_max;
> >> > int y_max;
> >> > + int resting_zone_y_min;
> >> > int x_bits;
> >> > int y_bits;
> >> > + unsigned char slot_number;
> >> >
> >> > int (*hw_init)(struct psmouse *psmouse);
> >> > void (*process_packet)(struct psmouse *psmouse);
> >> > @@ -161,6 +241,15 @@ struct alps_data {
> >> > int fingers;
> >> > u8 quirks;
> >> > struct timer_list timer;
> >> > +
> >> > + /* these are used for buttonless touchpad*/
> >> > + union {
> >> > + struct v7_raw v7;
> >> > + } r;
> >> > + unsigned char phy_btn;
> >> > + unsigned char prev_phy_btn;
> >> > + unsigned char pressed_btn_bits;
> >> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> >> > };
> >> >
> >> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> >> > --
> >> > 1.8.3.2
> >> >
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> >> the body of a message to majordomo@vger.kernel.org
> >> More majordomo info at http://vger.kernel.org/majordomo-info.html
> >>
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Elaine Chen @ 2014-01-15 3:15 UTC (permalink / raw)
To: Dylan Thurston
Cc: Tommy Will, Dmitry Torokhov, Kevin Cernekee, david turvene,
Niels de Vos, Justin Clift, Qiting Chen, linux-input
In-Reply-To: <20140114201736.GA4755@bostoncoop.net>
Hi Dylan,
Thank you! This patch is againt Dmitry Torokhov's input tree, based on
the modification of:
2013-12-26 Input: ALPS - add support for "Dolphin" devices Yunkang Tang
As linux-next-20140114 has already merged Dolphin support, the patch
should be matched.
As for the blank screen, I'll debug on my side. Sorry for that.
What is the kernel version on your HP side? Is it 3.13-rc8?
Yes, it is safe to copy both alps.c and alps.h from linux-next version
to 3.13-rc8 kerenl.
2014/1/15 Dylan Thurston <dpthurst@indiana.edu>:
> Thank you! Which versions does this apply against? It patched for me
> with no fuzz against linux-next-20140114, but unfortunately X seems to
> be broken for me on that version (blank screen). I get fuzz and
> rejected patches when applying it to 3.13-rc8. Is it safe to just copy
> over alps.c from the linux-next version?
>
> (Of course, it's possible that the blank screen is a side effect of
> the correct recognition of the touchpad.)
>
> Thanks,
> Dylan
>
> On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
>> Hi Dylan,
>>
>> My colleague Elaine has prepared the patch for new ALPS touchpad that
>> being used on your HP Revolve 810 G1 laptop.
>> You can have a try~
>>
>> --
>> Best Regards,
>> Tommy
>>
>> ---------- Forwarded message ----------
>> From: Elaine Chen <elaineee66@gmail.com>
>> Date: 2014/1/14
>> Subject: Re: [PATCH] add support for ALPS v7 protocol device
>> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
>> david turvene <dturvene@dahetral.com>
>> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
>> Qiting Chen <qiting.chen@cn.alps.com>
>>
>>
>> As far as I know, the ALPS v7 protocol device is used on following laptops:
>>
>> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
>>
>> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
>> > Here is the patch of supporting ALPS v7 protocol device.
>> >
>> > v7 device is a clickpad device.
>> > Device info:
>> > Device ID = 0x73, 0x03, 0x0a
>> > Firmware ID = 0x88, 0xb*, 0x**
>> >
>> > Support function of v7 device:
>> > - Cursor
>> > - Tap, double tap, tap drag, 2finger tap
>> > - Pan, pinch
>> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
>> > Click touchpad with all fingers outside right Button Area --> left click
>> > Click touchpad with at lease 1 finger inside right Button Area --> right click
>> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
>> >
>> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
>> > We tried registering our device as a clickpad by:
>> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
>> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
>> >
>> >
>> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
>> > ---
>> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
>> > drivers/input/mouse/alps.h | 127 ++++++++++--
>> > 2 files changed, 554 insertions(+), 51 deletions(-)
>> >
>> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
>> > index fb15c64..3e8e8f7 100644
>> > --- a/drivers/input/mouse/alps.c
>> > +++ b/drivers/input/mouse/alps.c
>> > @@ -32,6 +32,11 @@
>> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
>> > #define ALPS_REG_BASE_PINNACLE 0x0000
>> >
>> > +#define LEFT_BUTTON_BIT 0x01
>> > +#define RIGHT_BUTTON_BIT 0x02
>> > +
>> > +#define V7_LARGE_MOVEMENT 130
>> > +
>> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
>> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
>> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
>> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
>> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
>> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
>> > 6-byte ALPS packet */
>> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
>> >
>> > static const struct alps_model_info alps_model_data[] = {
>> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
>> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>> > * isn't valid per PS/2 spec.
>> > */
>> >
>> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
>> > + struct alps_abs_data *pt1)
>> > +{
>> > + int vect_x, vect_y;
>> > +
>> > + if (!pt0 || !pt1)
>> > + return 0;
>> > +
>> > + vect_x = pt0->x - pt1->x;
>> > + vect_y = pt0->y - pt1->y;
>> > +
>> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
>> > +}
>> > +
>> > /* Packet formats are described in Documentation/input/alps.txt */
>> >
>> > static bool alps_is_valid_first_byte(struct alps_data *priv,
>> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
>> > end_bit = y_msb - 1;
>> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
>> > (2 * (priv->y_bits - 1));
>> > - *x1 = fields->x;
>> > - *y1 = fields->y;
>> > + *x1 = fields->pt.x;
>> > + *y1 = fields->pt.y;
>> > *x2 = 2 * box_middle_x - *x1;
>> > *y2 = 2 * box_middle_y - *y1;
>> > }
>> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
>> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
>> > }
>> >
>> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
>> > + struct alps_fields *f)
>> > +{
>> > + struct input_dev *dev;
>> > +
>> > + if (!psmouse || !f)
>> > + return;
>> > +
>> > + dev = psmouse->dev;
>> > +
>> > + if (f->fingers) {
>> > + input_report_key(dev, BTN_TOUCH, 1);
>> > + alps_report_semi_mt_data(dev, f->fingers,
>> > + f->pt_img[0].x, f->pt_img[0].y,
>> > + f->pt_img[1].x, f->pt_img[1].y);
>> > + input_mt_report_finger_count(dev, f->fingers);
>> > +
>> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
>> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
>> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
>> > + } else {
>> > + input_report_key(dev, BTN_TOUCH, 0);
>> > + input_mt_report_finger_count(dev, 0);
>> > + input_report_abs(dev, ABS_PRESSURE, 0);
>> > + }
>> > +
>> > + input_report_key(dev, BTN_LEFT, f->btn.left);
>> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
>> > +
>> > + input_sync(dev);
>> > +}
>> > +
>> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> > {
>> > struct alps_data *priv = psmouse->private;
>> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>> >
>> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
>> > {
>> > - f->left = !!(p[3] & 0x01);
>> > - f->right = !!(p[3] & 0x02);
>> > - f->middle = !!(p[3] & 0x04);
>> > + f->btn.left = !!(p[3] & 0x01);
>> > + f->btn.right = !!(p[3] & 0x02);
>> > + f->btn.middle = !!(p[3] & 0x04);
>> >
>> > - f->ts_left = !!(p[3] & 0x10);
>> > - f->ts_right = !!(p[3] & 0x20);
>> > - f->ts_middle = !!(p[3] & 0x40);
>> > + f->btn.ts_left = !!(p[3] & 0x10);
>> > + f->btn.ts_right = !!(p[3] & 0x20);
>> > + f->btn.ts_middle = !!(p[3] & 0x40);
>> > }
>> >
>> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
>> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
>> > ((p[2] & 0x7f) << 1) |
>> > (p[4] & 0x01);
>> >
>> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
>> > ((p[0] & 0x30) >> 4);
>> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > - f->z = p[5] & 0x7f;
>> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
>> > + f->pt.z = p[5] & 0x7f;
>> >
>> > alps_decode_buttons_v3(f, p);
>> > }
>> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
>> > f->is_mp = !!(p[0] & 0x20);
>> >
>> > if (!f->is_mp) {
>> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
>> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
>> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
>> > alps_decode_buttons_v3(f, p);
>> > } else {
>> > f->fingers = ((p[0] & 0x6) >> 1 |
>> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> > * with x, y, and z all zero, so these seem to be flukes.
>> > * Ignore them.
>> > */
>> > - if (f.x && f.y && !f.z)
>> > + if (f.pt.x && f.pt.y && !f.pt.z)
>> > return;
>> >
>> > /*
>> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> > * to rely on ST data.
>> > */
>> > if (!fingers) {
>> > - x1 = f.x;
>> > - y1 = f.y;
>> > - fingers = f.z > 0 ? 1 : 0;
>> > + x1 = f.pt.x;
>> > + y1 = f.pt.y;
>> > + fingers = f.pt.z > 0 ? 1 : 0;
>> > }
>> >
>> > - if (f.z >= 64)
>> > + if (f.pt.z >= 64)
>> > input_report_key(dev, BTN_TOUCH, 1);
>> > else
>> > input_report_key(dev, BTN_TOUCH, 0);
>> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>> >
>> > input_mt_report_finger_count(dev, fingers);
>> >
>> > - input_report_key(dev, BTN_LEFT, f.left);
>> > - input_report_key(dev, BTN_RIGHT, f.right);
>> > - input_report_key(dev, BTN_MIDDLE, f.middle);
>> > + input_report_key(dev, BTN_LEFT, f.btn.left);
>> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
>> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>> >
>> > - if (f.z > 0) {
>> > - input_report_abs(dev, ABS_X, f.x);
>> > - input_report_abs(dev, ABS_Y, f.y);
>> > + if (f.pt.z > 0) {
>> > + input_report_abs(dev, ABS_X, f.pt.x);
>> > + input_report_abs(dev, ABS_Y, f.pt.y);
>> > }
>> > - input_report_abs(dev, ABS_PRESSURE, f.z);
>> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>> >
>> > input_sync(dev);
>> >
>> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
>> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
>> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
>> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
>> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
>> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
>> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
>> > input_sync(dev2);
>> > }
>> > }
>> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
>> > input_sync(dev);
>> > }
>> >
>> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
>> > +{
>> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
>> > + return false;
>> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
>> > + return false;
>> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
>> > + return false;
>> > + return true;
>> > +}
>> > +
>> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > + int drop = 1;
>> > +
>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
>> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
>> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
>> > + drop = 0;
>> > +
>> > + return drop;
>> > +}
>> > +
>> > +static unsigned char alps_get_packet_id_v7(char *byte)
>> > +{
>> > + unsigned char packet_id;
>> > +
>> > + if (byte[4] & 0x40)
>> > + packet_id = V7_PACKET_ID_TWO;
>> > + else if (byte[4] & 0x01)
>> > + packet_id = V7_PACKET_ID_MULTI;
>> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
>> > + packet_id = V7_PACKET_ID_NEW;
>> > + else
>> > + packet_id = V7_PACKET_ID_IDLE;
>> > +
>> > + return packet_id;
>> > +}
>> > +
>> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
>> > + unsigned char *pkt,
>> > + unsigned char pkt_id)
>> > +{
>> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
>> > + (pkt_id == V7_PACKET_ID_MULTI) ||
>> > + (pkt_id == V7_PACKET_ID_NEW)) {
>> > + pt[0].x = ((pkt[2] & 0x80) << 4);
>> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
>> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
>> > + pt[0].x |= (pkt[3] & 0x07);
>> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
>> > +
>> > + pt[1].x = ((pkt[3] & 0x80) << 4);
>> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
>> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
>> > + pt[1].y = ((pkt[5] & 0x80) << 3);
>> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
>> > +
>> > + if (pkt_id == V7_PACKET_ID_TWO) {
>> > + pt[1].x &= ~0x000F;
>> > + pt[1].y |= 0x000F;
>> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
>> > + pt[1].x &= ~0x003F;
>> > + pt[1].y &= ~0x0020;
>> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
>> > + pt[1].y |= 0x001F;
>> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
>> > + pt[1].x &= ~0x003F;
>> > + pt[1].x |= (pkt[0] & 0x20);
>> > + pt[1].y |= 0x000F;
>> > + }
>> > +
>> > + pt[0].y = 0x7FF - pt[0].y;
>> > + pt[1].y = 0x7FF - pt[1].y;
>> > +
>> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
>> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
>> > + }
>> > +}
>> > +
>> > +static void alps_decode_packet_v7(struct alps_fields *f,
>> > + unsigned char *p,
>> > + struct psmouse *psmouse)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > +
>> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
>> > +
>> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
>> > +
>> > + priv->r.v7.rest_left = 0;
>> > + priv->r.v7.rest_right = 0;
>> > + priv->r.v7.additional_fingers = 0;
>> > + priv->phy_btn = 0;
>> > +
>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
>> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
>> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
>> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
>> > + }
>> > +
>> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
>> > + priv->r.v7.additional_fingers = p[5] & 0x03;
>> > +
>> > + priv->phy_btn = (p[0] & 0x80) >> 7;
>> > +}
>> > +
>> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
>> > + struct alps_abs_data *pt,
>> > + struct alps_bl_pt_attr *pt_attr)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > + unsigned int dist;
>> > +
>> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
>> > + pt_attr->is_init_pt_got = 1;
>> > + pt_attr->is_counted = 0;
>> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
>> > + }
>> > +
>> > + if (pt->z != 0) {
>> > + if (pt->y < priv->resting_zone_y_min) {
>> > + /* A finger is recognized as a non-resting finger
>> > + if it's position is outside the resting finger zone.*/
>> > + pt_attr->zone = ZONE_NORMAL;
>> > + pt_attr->is_counted = 1;
>> > + } else {
>> > + /* A finger is recognized as a resting finger if it's
>> > + position is inside the resting finger zone and there's
>> > + no large movement from it's touch down position.*/
>> > + pt_attr->zone = ZONE_RESTING;
>> > +
>> > + if (pt->x > priv->x_max / 2)
>> > + pt_attr->zone |= ZONE_RIGHT_BTN;
>> > + else
>> > + pt_attr->zone |= ZONE_LEFT_BTN;
>> > +
>> > + /* A resting finger will turn to be a non-resting
>> > + finger if it has made large movement from it's touch
>> > + down position. A non-resting finger will never turn
>> > + to a resting finger before it leaves the touchpad
>> > + surface.*/
>> > + if (pt_attr->is_init_pt_got) {
>> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
>> > +
>> > + if (dist > V7_LARGE_MOVEMENT)
>> > + pt_attr->is_counted = 1;
>> > + }
>> > + }
>> > + }
>> > +}
>> > +
>> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
>> > + struct alps_fields *f)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > + int i;
>> > +
>> > + switch (priv->r.v7.pkt_id) {
>> > + case V7_PACKET_ID_TWO:
>> > + case V7_PACKET_ID_MULTI:
>> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
>> > + alps_set_each_pt_attr_v7(psmouse,
>> > + &f->pt_img[i],
>> > + &priv->pt_attr[i]);
>> > + break;
>> > + default:
>> > + /*All finger attributes are cleared when packet ID is
>> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
>> > + indicates that there's no finger and no button activity.
>> > + A 'NEW' packet indicates the finger position in packet
>> > + is not continues from previous packet. Such as the
>> > + condition there's finger placed or lifted. In these cases,
>> > + finger attributes will be reset.*/
>> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
>> > + break;
>> > + }
>> > +}
>> > +
>> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
>> > + struct alps_fields *f)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > + unsigned int fn = 0;
>> > + int i;
>> > +
>> > + switch (priv->r.v7.pkt_id) {
>> > + case V7_PACKET_ID_IDLE:
>> > + case V7_PACKET_ID_NEW:
>> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
>> > + An 'IDLE' packet indicates that there's no finger on touchpad.
>> > + A 'NEW' packet indicates there's finger placed or lifted.
>> > + Finger position of 'New' packet is not continues from the
>> > + previous packet.*/
>> > + fn = 0;
>> > + break;
>> > + case V7_PACKET_ID_TWO:
>> > + if (f->pt_img[0].z == 0) {
>> > + /*The first finger slot is zero when a non-resting
>> > + finger lifted and remaining only one resting finger
>> > + on touchpad. Hardware report the remaining resting
>> > + finger in second slot. This resting is ignored*/
>> > + fn = 0;
>> > + } else if (f->pt_img[1].z == 0) {
>> > + /* The second finger slot is zero if there's
>> > + only one finger*/
>> > + fn = 1;
>> > + } else {
>> > + /*All non-resting fingers will be counted to report*/
>> > + fn = 0;
>> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
>> > + if (priv->pt_attr[i].is_counted)
>> > + fn++;
>> > + }
>> > +
>> > + /*In the case that both fingers are
>> > + resting fingers, report the first one*/
>> > + if (!priv->pt_attr[0].is_counted &&
>> > + !priv->pt_attr[1].is_counted) {
>> > + fn = 1;
>> > + }
>> > + }
>> > + break;
>> > + case V7_PACKET_ID_MULTI:
>> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
>> > + finger exist.*/
>> > + fn = 3 + priv->r.v7.additional_fingers;
>> > + break;
>> > + }
>> > +
>> > + f->fingers = fn;
>> > +}
>> > +
>> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
>> > + struct alps_fields *f)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > +
>> > + if (priv->phy_btn) {
>> > + if (!priv->prev_phy_btn) {
>> > + /* Report a right click as long as there's finger on
>> > + right button zone. Othrewise, report a left click.*/
>> > + if (priv->r.v7.rest_right ||
>> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
>> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
>> > + f->btn.right = 1;
>> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
>> > + } else {
>> > + f->btn.left = 1;
>> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
>> > + }
>> > + } else {
>> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
>> > + f->btn.right = 1;
>> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
>> > + f->btn.left = 1;
>> > + }
>> > + } else {
>> > + priv->pressed_btn_bits = 0;
>> > + f->btn.right = 0;
>> > + f->btn.left = 0;
>> > + }
>> > +
>> > + priv->prev_phy_btn = priv->phy_btn;
>> > +}
>> > +
>> > +static void alps_process_packet_v7(struct psmouse *psmouse)
>> > +{
>> > + struct alps_data *priv = psmouse->private;
>> > + struct alps_fields f = {0};
>> > + unsigned char *packet = psmouse->packet;
>> > +
>> > + priv->decode_fields(&f, packet, psmouse);
>> > +
>> > + if (alps_drop_unsupported_packet_v7(psmouse))
>> > + return;
>> > +
>> > + alps_set_pt_attr_v7(psmouse, &f);
>> > +
>> > + alps_cal_output_finger_num_v7(psmouse, &f);
>> > +
>> > + alps_assign_buttons_v7(psmouse, &f);
>> > +
>> > + alps_report_coord_and_btn(psmouse, &f);
>> > +}
>> > +
>> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
>> > unsigned char packet[],
>> > bool report_buttons)
>> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
>> > return PSMOUSE_BAD_DATA;
>> > }
>> >
>> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
>> > + !alps_is_valid_package_v7(psmouse))) {
>> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
>> > + psmouse->pktcnt - 1,
>> > + psmouse->packet[psmouse->pktcnt - 1]);
>> > + return PSMOUSE_BAD_DATA;
>> > + }
>> > +
>> > if (psmouse->pktcnt == psmouse->pktsize) {
>> > priv->process_packet(psmouse);
>> > return PSMOUSE_FULL_PACKET;
>> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
>> > return 0;
>> > }
>> >
>> > +static int alps_check_valid_firmware_id(unsigned char id[])
>> > +{
>> > + int valid = 1;
>> > +
>> > + if (id[0] == 0x73)
>> > + valid = 1;
>> > + else if (id[0] == 0x88) {
>> > + if ((id[1] == 0x07) ||
>> > + (id[1] == 0x08) ||
>> > + ((id[1] & 0xf0) == 0xB0))
>> > + valid = 1;
>> > + }
>> > +
>> > + return valid;
>> > +}
>> > +
>> > static int alps_enter_command_mode(struct psmouse *psmouse)
>> > {
>> > unsigned char param[4];
>> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
>> > return -1;
>> > }
>> >
>> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
>> > - param[0] != 0x73) {
>> > + if (!alps_check_valid_firmware_id(param)) {
>> > psmouse_dbg(psmouse,
>> > "unknown response while entering command mode\n");
>> > return -1;
>> > @@ -1704,6 +2067,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)
>> > {
>> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > priv->set_abs_params = alps_set_abs_params_st;
>> > priv->x_max = 1023;
>> > priv->y_max = 767;
>> > + priv->slot_number = 1;
>> > break;
>> > case ALPS_PROTO_V3:
>> > priv->hw_init = alps_hw_init_v3;
>> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > priv->decode_fields = alps_decode_pinnacle;
>> > priv->nibble_commands = alps_v3_nibble_commands;
>> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > + priv->slot_number = 2;
>> > break;
>> > case ALPS_PROTO_V4:
>> > priv->hw_init = alps_hw_init_v4;
>> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > priv->set_abs_params = alps_set_abs_params_mt;
>> > priv->nibble_commands = alps_v4_nibble_commands;
>> > priv->addr_command = PSMOUSE_CMD_DISABLE;
>> > + priv->slot_number = 2;
>> > break;
>> > case ALPS_PROTO_V5:
>> > priv->hw_init = alps_hw_init_dolphin_v1;
>> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
>> > priv->y_max = 660;
>> > priv->x_bits = 23;
>> > priv->y_bits = 12;
>> > + priv->slot_number = 2;
>> > break;
>> > case ALPS_PROTO_V6:
>> > priv->hw_init = alps_hw_init_v6;
>> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
>> > priv->nibble_commands = alps_v6_nibble_commands;
>> > priv->x_max = 2047;
>> > priv->y_max = 1535;
>> > + priv->slot_number = 2;
>> > + break;
>> > + case ALPS_PROTO_V7:
>> > + priv->hw_init = alps_hw_init_v7;
>> > + priv->process_packet = alps_process_packet_v7;
>> > + priv->decode_fields = alps_decode_packet_v7;
>> > + priv->set_abs_params = alps_set_abs_params_mt;
>> > + priv->nibble_commands = alps_v3_nibble_commands;
>> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
>> > + priv->x_max = 0xfff;
>> > + priv->y_max = 0x7ff;
>> > + priv->resting_zone_y_min = 0x654;
>> > + priv->byte0 = 0x48;
>> > + priv->mask0 = 0x48;
>> > + priv->flags = 0;
>> > + priv->slot_number = 2;
>> > break;
>> > }
>> > }
>> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
>> > return -EIO;
>> > else
>> > return 0;
>> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
>> > + priv->proto_version = ALPS_PROTO_V7;
>> > + alps_set_defaults(priv);
>> > +
>> > + return 0;
>> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
>> > priv->proto_version = ALPS_PROTO_V3;
>> > alps_set_defaults(priv);
>> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
>> > struct input_dev *dev1)
>> > {
>> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
>> > - input_mt_init_slots(dev1, 2, 0);
>> > + input_mt_init_slots(dev1, priv->slot_number, 0);
>> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
>> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
>> >
>> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
>> > index 03f88b6..5d2f9ea 100644
>> > --- a/drivers/input/mouse/alps.h
>> > +++ b/drivers/input/mouse/alps.h
>> > @@ -18,11 +18,36 @@
>> > #define ALPS_PROTO_V4 4
>> > #define ALPS_PROTO_V5 5
>> > #define ALPS_PROTO_V6 6
>> > +#define ALPS_PROTO_V7 7
>> > +
>> > +#define MAX_IMG_PT_NUM 5
>> > +#define V7_IMG_PT_NUM 2
>> > +
>> > +#define ZONE_NORMAL 0x01
>> > +#define ZONE_RESTING 0x02
>> > +#define ZONE_LEFT_BTN 0x04
>> > +#define ZONE_RIGHT_BTN 0x08
>> >
>> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
>> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
>> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
>> >
>> > +/*
>> > + * enum V7_PACKET_ID - defines the packet type for V7
>> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
>> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
>> > + * or there's button activities.
>> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
>> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
>> > + * previous packet.
>> > +*/
>> > +enum V7_PACKET_ID {
>> > + V7_PACKET_ID_IDLE,
>> > + V7_PACKET_ID_TWO,
>> > + V7_PACKET_ID_MULTI,
>> > + V7_PACKET_ID_NEW,
>> > +};
>> > +
>> > /**
>> > * struct alps_model_info - touchpad ID table
>> > * @signature: E7 response string to match.
>> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
>> > };
>> >
>> > /**
>> > - * struct alps_fields - decoded version of the report packet
>> > - * @x_map: Bitmap of active X positions for MT.
>> > - * @y_map: Bitmap of active Y positions for MT.
>> > - * @fingers: Number of fingers for MT.
>> > - * @x: X position for ST.
>> > - * @y: Y position for ST.
>> > - * @z: Z position for ST.
>> > - * @first_mp: Packet is the first of a multi-packet report.
>> > - * @is_mp: Packet is part of a multi-packet report.
>> > + * struct alps_btn - decoded version of the button status
>> > * @left: Left touchpad button is active.
>> > * @right: Right touchpad button is active.
>> > * @middle: Middle touchpad button is active.
>> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
>> > * @ts_right: Right trackstick button is active.
>> > * @ts_middle: Middle trackstick button is active.
>> > */
>> > -struct alps_fields {
>> > - unsigned int x_map;
>> > - unsigned int y_map;
>> > - unsigned int fingers;
>> > - unsigned int x;
>> > - unsigned int y;
>> > - unsigned int z;
>> > - unsigned int first_mp:1;
>> > - unsigned int is_mp:1;
>> > -
>> > +struct alps_btn {
>> > unsigned int left:1;
>> > unsigned int right:1;
>> > unsigned int middle:1;
>> > @@ -102,6 +110,69 @@ struct alps_fields {
>> > };
>> >
>> > /**
>> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
>> > + * @x: X position for ST.
>> > + * @y: Y position for ST.
>> > + * @z: Z position for ST.
>> > + */
>> > +struct alps_abs_data {
>> > + unsigned int x;
>> > + unsigned int y;
>> > + unsigned int z;
>> > +};
>> > +
>> > +/**
>> > + * struct alps_fields - decoded version of the report packet
>> > + * @fingers: Number of fingers for MT.
>> > + * @pt: X Y Z postion for ST.
>> > + * @pt: X Y Z postion for image MT.
>> > + * @x_map: Bitmap of active X positions for MT.
>> > + * @y_map: Bitmap of active Y positions for MT.
>> > + * @first_mp: Packet is the first of a multi-packet report.
>> > + * @is_mp: Packet is part of a multi-packet report.
>> > + * @btn: Button activity status
>> > + */
>> > +struct alps_fields {
>> > + unsigned int fingers;
>> > + struct alps_abs_data pt;
>> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
>> > + unsigned int x_map;
>> > + unsigned int y_map;
>> > + unsigned int first_mp:1;
>> > + unsigned int is_mp:1;
>> > + struct alps_btn btn;
>> > +};
>> > +
>> > +/**
>> > + * struct v7_raw - data decoded from raw packet for V7.
>> > + * @pkt_id: An id that specifies the type of packet.
>> > + * @additional_fingers: Number of additional finger that is neighter included
>> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
>> > + * @rest_left: There are fingers on left resting zone.
>> > + * @rest_right: There are fingers on right resting zone.
>> > + */
>> > +struct v7_raw {
>> > + unsigned char pkt_id;
>> > + unsigned int additional_fingers;
>> > + unsigned char rest_left;
>> > + unsigned char rest_right;
>> > +};
>> > +
>> > +/**
>> > + * 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;
>> > +};
>> > +
>> > +/**
>> > * struct alps_data - private data structure for the ALPS driver
>> > * @dev2: "Relative" device used to report trackstick or mouse activity.
>> > * @phys: Physical path for the relative device.
>> > @@ -116,8 +187,10 @@ struct alps_fields {
>> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
>> > * @x_max: Largest possible X position value.
>> > * @y_max: Largest possible Y position value.
>> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
>> > * @x_bits: Number of X bits in the MT bitmap.
>> > * @y_bits: Number of Y bits in the MT bitmap.
>> > + * @img_fingers: Number of image fingers.
>> > * @hw_init: Protocol-specific hardware init function.
>> > * @process_packet: Protocol-specific function to process a report packet.
>> > * @decode_fields: Protocol-specific function to read packet bitfields.
>> > @@ -132,6 +205,11 @@ struct alps_fields {
>> > * @fingers: Number of fingers from last MT report.
>> > * @quirks: Bitmap of ALPS_QUIRK_*.
>> > * @timer: Timer for flushing out the final report packet in the stream.
>> > + * @v7: Data decoded from raw packet for V7
>> > + * @phy_btn: Physical button is active.
>> > + * @prev_phy_btn: Physical button of previous packet is active.
>> > + * @pressed_btn_bits: Pressed positon of button zone
>> > + * @pt_attr: Generic attributes of touch points for buttonless device.
>> > */
>> > struct alps_data {
>> > struct input_dev *dev2;
>> > @@ -145,8 +223,10 @@ struct alps_data {
>> > unsigned char flags;
>> > int x_max;
>> > int y_max;
>> > + int resting_zone_y_min;
>> > int x_bits;
>> > int y_bits;
>> > + unsigned char slot_number;
>> >
>> > int (*hw_init)(struct psmouse *psmouse);
>> > void (*process_packet)(struct psmouse *psmouse);
>> > @@ -161,6 +241,15 @@ struct alps_data {
>> > int fingers;
>> > u8 quirks;
>> > struct timer_list timer;
>> > +
>> > + /* these are used for buttonless touchpad*/
>> > + union {
>> > + struct v7_raw v7;
>> > + } r;
>> > + unsigned char phy_btn;
>> > + unsigned char prev_phy_btn;
>> > + unsigned char pressed_btn_bits;
>> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
>> > };
>> >
>> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
>> > --
>> > 1.8.3.2
>> >
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-input" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH 2/2] Input: edt-ft5x06: Add DT support
From: Jingoo Han @ 2014-01-15 0:46 UTC (permalink / raw)
To: 'Lothar Waßmann'
Cc: linux-input, 'Rob Herring', 'Pawel Moll',
'Mark Rutland', 'Ian Campbell',
'Kumar Gala', 'Rob Landley',
'Dmitry Torokhov', 'Grant Likely',
'Thierry Reding', 'Jonathan Cameron',
'Shawn Guo', 'Silvio F',
'Guennadi Liakhovetski', 'Fugang Duan',
'Sachin Kamat', devicetree, linux-doc, linux-kernel,
'Jingoo Han', 'Simon Budig'
In-Reply-To: <1389608224-9975-2-git-send-email-LW@KARO-electronics.de>
On Monday, January 13, 2014 7:17 PM, Lothar Waßmann wrote:
>
> This patch allows the edt-ft5x06 multitouch panel driver to be
> configured via DT.
>
> Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de>
(+cc Simon Budig)
This 'edt-ft5x06' driver was made by Simon Budig.
Please, add him to CC list.
Also, I added some comments. :-)
> ---
> .../bindings/input/touchscreen/edt-ft5x06.txt | 31 ++++
> drivers/input/touchscreen/edt-ft5x06.c | 145 +++++++++++++++----
> 2 files changed, 145 insertions(+), 31 deletions(-)
> create mode 100644 Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
>
> diff --git a/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> new file mode 100644
> index 0000000..629dbdd
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/input/touchscreen/edt-ft5x06.txt
> @@ -0,0 +1,31 @@
> +* EDT FT5x06 Multiple Touch Controller
> +
> +Required properties:
> +- compatible: must be "edt,ft5x06"
> +- reg: i2c slave address
> +- interrupt-parent: the phandle for the interrupt controller
> +- interrupts: touch controller interrupt
> +
> +Optional properties:
> +- reset-gpios: the gpio pin to be used for resetting the controller
> +- wakeup-gpios: the gpio pin to be used for waking up the controller
> +
> + The following properties provide default values for the
> + corresponding parameters configurable via sysfs
> + (see Documentation/input/edt-ft5x06.txt)
> +- threshold: allows setting the "click"-threshold in the range from 20 to 80.
> +- gain: sensitivity (0..31) (lower value -> higher sensitivity)
> +- offset: edge compensation (0..31)
> +- report_rate: report rate (3..14)
s/report_rate/report-rate
> +
> +Example:
> +
> + edt_ft5x06@38 {
> + compatible = "edt,ft5x06";
> + reg = <0x38>;
> + interrupt-parent = <&gpio2>;
> + interrupts = <5 0>;
> + wakeup-gpios = <&gpio1 9 0>;
> + reset-gpios = <&gpio2 6 1>;
> + wakeup-gpios = <&gpio4 9 0>;
> + };
> diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
> index af0d68b..02dce42 100644
> --- a/drivers/input/touchscreen/edt-ft5x06.c
> +++ b/drivers/input/touchscreen/edt-ft5x06.c
> @@ -33,6 +33,7 @@
> #include <linux/debugfs.h>
> #include <linux/slab.h>
> #include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> #include <linux/input/mt.h>
> #include <linux/input/edt-ft5x06.h>
>
> @@ -65,6 +66,10 @@ struct edt_ft5x06_ts_data {
> u16 num_x;
> u16 num_y;
>
> + int reset_pin;
> + int irq_pin;
> + int wake_pin;
> +
> #if defined(CONFIG_DEBUG_FS)
> struct dentry *debug_dir;
> u8 *raw_buffer;
> @@ -617,24 +622,37 @@ edt_ft5x06_ts_teardown_debugfs(struct edt_ft5x06_ts_data *tsdata)
>
>
> static int edt_ft5x06_ts_reset(struct i2c_client *client,
> - int reset_pin)
> + struct edt_ft5x06_ts_data *tsdata)
> {
> int error;
>
> - if (gpio_is_valid(reset_pin)) {
> + if (gpio_is_valid(tsdata->wake_pin)) {
> + error = gpio_request_one(tsdata->wake_pin, GPIOF_OUT_INIT_LOW,
> + "edt-ft5x06 wake");
Please use devm_gpio_request_one(), because it makes the code
simpler.
> + if (error) {
> + dev_err(&client->dev,
> + "Failed to request GPIO %d as wake pin, error %d\n",
> + tsdata->wake_pin, error);
> + return error;
> + }
> +
> + mdelay(5);
> + gpio_set_value(tsdata->wake_pin, 1);
> + }
> + if (gpio_is_valid(tsdata->reset_pin)) {
> /* this pulls reset down, enabling the low active reset */
> - error = gpio_request_one(reset_pin, GPIOF_OUT_INIT_LOW,
> + error = gpio_request_one(tsdata->reset_pin, GPIOF_OUT_INIT_LOW,
> "edt-ft5x06 reset");
Please use devm_gpio_request_one() too.
> if (error) {
> dev_err(&client->dev,
> "Failed to request GPIO %d as reset pin, error %d\n",
> - reset_pin, error);
> + tsdata->reset_pin, error);
> return error;
> }
>
> - mdelay(50);
> - gpio_set_value(reset_pin, 1);
> - mdelay(100);
> + mdelay(5);
> + gpio_set_value(tsdata->reset_pin, 1);
> + mdelay(300);
> }
>
> return 0;
> @@ -674,6 +692,21 @@ static int edt_ft5x06_ts_identify(struct i2c_client *client,
> pdata->name <= edt_ft5x06_attr_##name.limit_high) \
> edt_ft5x06_register_write(tsdata, reg, pdata->name)
>
> +#define EDT_GET_PROP(name, reg) { \
> + const u32 *prop = of_get_property(np, #name, NULL); \
> + if (prop) \
> + edt_ft5x06_register_write(tsdata, reg, be32_to_cpu(*prop)); \
> +}
> +
> +static void edt_ft5x06_ts_get_dt_defaults(struct device_node *np,
> + struct edt_ft5x06_ts_data *tsdata)
> +{
> + EDT_GET_PROP(threshold, WORK_REGISTER_THRESHOLD);
> + EDT_GET_PROP(gain, WORK_REGISTER_GAIN);
> + EDT_GET_PROP(offset, WORK_REGISTER_OFFSET);
> + EDT_GET_PROP(report_rate, WORK_REGISTER_REPORT_RATE);
> +}
> +
> static void
> edt_ft5x06_ts_get_defaults(struct edt_ft5x06_ts_data *tsdata,
> const struct edt_ft5x06_platform_data *pdata)
> @@ -701,6 +734,39 @@ edt_ft5x06_ts_get_parameters(struct edt_ft5x06_ts_data *tsdata)
> tsdata->num_y = edt_ft5x06_register_read(tsdata, WORK_REGISTER_NUM_Y);
> }
>
> +#ifdef CONFIG_OF
> +static int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
> + struct edt_ft5x06_ts_data *tsdata)
> +{
> + int ret;
> + struct device_node *np = dev->of_node;
> + enum of_gpio_flags gpio_flags;
> +
> + if (!np)
> + return -ENODEV;
> +
> + /*
> + * irq_pin is not needed for DT setup.
> + * irq is associated via 'interrupts' property in DT
> + */
> + tsdata->irq_pin = -EINVAL;
> +
> + ret = of_get_named_gpio_flags(np, "reset-gpios", 0, &gpio_flags);
> + tsdata->reset_pin = ret;
This code looks awkward.
There are two ways, please choose one of them.
1. Check the return value
ret = of_get_named_gpio_flags(np, "reset-gpios", 0, &gpio_flags);
if (ret < 0) {
dev_err(dev, "reset-gpios pin is not provided.\n");
return ret;
}
tsdata->reset_pin = ret;
2. No check the return value, passing it directly
tsdata->reset_pin = of_get_named_gpio_flags(np, "reset-gpios", 0, &gpio_flags);
> +
> + ret = of_get_named_gpio_flags(np, "wake-gpios", 0, &gpio_flags);
According to the Documentation 'edt-ft5x06.txt',
'wakeup-gpios' is used, instead of 'wake-gpios'.
What is the right name?
> + tsdata->wake_pin = ret;
> +
> + return 0;
> +}
> +#else
> +static inline int edt_ft5x06_i2c_ts_probe_dt(struct device *dev,
> + struct edt_ft5x06_i2c_ts_data *tsdata)
> +{
> + return -ENODEV;
> +}
> +#endif
> +
> static int edt_ft5x06_ts_probe(struct i2c_client *client,
> const struct i2c_device_id *id)
> {
> @@ -713,30 +779,43 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
>
> dev_dbg(&client->dev, "probing for EDT FT5x06 I2C\n");
>
> + tsdata = devm_kzalloc(&client->dev, sizeof(*tsdata), GFP_KERNEL);
> + if (!tsdata) {
> + dev_err(&client->dev, "failed to allocate driver data.\n");
> + return -ENOMEM;
> + }
> +
> if (!pdata) {
> - dev_err(&client->dev, "no platform data?\n");
> - return -EINVAL;
> + error = edt_ft5x06_i2c_ts_probe_dt(&client->dev, tsdata);
> + if (error) {
> + dev_err(&client->dev,
> + "DT probe failed and no platform data present\n");
> + return error;
> + }
> + } else {
> + tsdata->reset_pin = pdata->reset_pin;
> + tsdata->irq_pin = pdata->irq_pin;
> + tsdata->wake_pin = -EINVAL;
> }
>
> - error = edt_ft5x06_ts_reset(client, pdata->reset_pin);
> + error = edt_ft5x06_ts_reset(client, tsdata);
> if (error)
> return error;
>
> - if (gpio_is_valid(pdata->irq_pin)) {
> - error = gpio_request_one(pdata->irq_pin,
> + if (gpio_is_valid(tsdata->irq_pin)) {
> + error = gpio_request_one(tsdata->irq_pin,
> GPIOF_IN, "edt-ft5x06 irq");
Please use devm_gpio_request_one() too.
> if (error) {
> dev_err(&client->dev,
> "Failed to request GPIO %d, error %d\n",
> - pdata->irq_pin, error);
> + tsdata->irq_pin, error);
> return error;
> }
> }
>
> - tsdata = kzalloc(sizeof(*tsdata), GFP_KERNEL);
> input = input_allocate_device();
> - if (!tsdata || !input) {
> - dev_err(&client->dev, "failed to allocate driver data.\n");
> + if (!input) {
> + dev_err(&client->dev, "failed to allocate input device.\n");
> error = -ENOMEM;
> goto err_free_mem;
> }
> @@ -752,7 +831,11 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
> goto err_free_mem;
> }
>
> - edt_ft5x06_ts_get_defaults(tsdata, pdata);
> + if (!pdata)
> + edt_ft5x06_ts_get_dt_defaults(client->dev.of_node, tsdata);
> + else
> + edt_ft5x06_ts_get_defaults(tsdata, pdata);
> +
> edt_ft5x06_ts_get_parameters(tsdata);
>
> dev_dbg(&client->dev,
> @@ -802,8 +885,8 @@ static int edt_ft5x06_ts_probe(struct i2c_client *client,
> device_init_wakeup(&client->dev, 1);
>
> dev_dbg(&client->dev,
> - "EDT FT5x06 initialized: IRQ pin %d, Reset pin %d.\n",
> - pdata->irq_pin, pdata->reset_pin);
> + "EDT FT5x06 initialized: IRQ %d, WAKE pin %d, Reset pin %d.\n",
> + client->irq, tsdata->wake_pin, tsdata->reset_pin);
>
> return 0;
>
> @@ -813,18 +896,18 @@ err_free_irq:
> free_irq(client->irq, tsdata);
> err_free_mem:
> input_free_device(input);
> - kfree(tsdata);
> -
> - if (gpio_is_valid(pdata->irq_pin))
> - gpio_free(pdata->irq_pin);
> + if (gpio_is_valid(tsdata->irq_pin))
> + gpio_free(tsdata->irq_pin);
> + if (gpio_is_valid(tsdata->reset_pin))
> + gpio_free(tsdata->reset_pin);
> + if (gpio_is_valid(tsdata->wake_pin))
> + gpio_free(tsdata->wake_pin);
If you use devm_gpio_request_one(), these gpio_free()s are not
necessary.
>
> return error;
> }
>
> static int edt_ft5x06_ts_remove(struct i2c_client *client)
> {
> - const struct edt_ft5x06_platform_data *pdata =
> - dev_get_platdata(&client->dev);
> struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
>
> edt_ft5x06_ts_teardown_debugfs(tsdata);
> @@ -833,12 +916,12 @@ static int edt_ft5x06_ts_remove(struct i2c_client *client)
> free_irq(client->irq, tsdata);
> input_unregister_device(tsdata->input);
>
> - if (gpio_is_valid(pdata->irq_pin))
> - gpio_free(pdata->irq_pin);
> - if (gpio_is_valid(pdata->reset_pin))
> - gpio_free(pdata->reset_pin);
> -
> - kfree(tsdata);
> + if (gpio_is_valid(tsdata->irq_pin))
> + gpio_free(tsdata->irq_pin);
> + if (gpio_is_valid(tsdata->reset_pin))
> + gpio_free(tsdata->reset_pin);
> + if (gpio_is_valid(tsdata->wake_pin))
> + gpio_free(tsdata->wake_pin);
If you use devm_gpio_request_one(), these gpio_free()s are not
necessary.
Best regards,
Jingoo Han
^ permalink raw reply
* Re: [PATCH v2 02/10] genirq: Add devm_request_any_context_irq()
From: Stephen Boyd @ 2014-01-14 20:47 UTC (permalink / raw)
To: Thomas Gleixner
Cc: Dmitry Torokhov, linux-kernel, linux-arm-msm, linux-arm-kernel,
linux-input
In-Reply-To: <52CB2D29.3050107@codeaurora.org>
On 01/06/14 14:24, Stephen Boyd wrote:
> On 01/02/14 16:37, Stephen Boyd wrote:
>> Some drivers use request_any_context_irq() but there isn't a
>> devm_* function for it. Add one so that these drivers don't need
>> to explicitly free the irq on driver detach.
>>
>> Cc: Thomas Gleixner <tglx@linutronix.de>
>> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
> Thomas, can you please review this patch?
ping?
>> ---
>> include/linux/interrupt.h | 5 +++++
>> kernel/irq/devres.c | 45 +++++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 50 insertions(+)
>>
>> diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h
>> index 0053adde0ed9..a2678d35b5a2 100644
>> --- a/include/linux/interrupt.h
>> +++ b/include/linux/interrupt.h
>> @@ -158,6 +158,11 @@ devm_request_irq(struct device *dev, unsigned int irq, irq_handler_t handler,
>> devname, dev_id);
>> }
>>
>> +extern int __must_check
>> +devm_request_any_context_irq(struct device *dev, unsigned int irq,
>> + irq_handler_t handler, unsigned long irqflags,
>> + const char *devname, void *dev_id);
>> +
>> extern void devm_free_irq(struct device *dev, unsigned int irq, void *dev_id);
>>
>> /*
>> diff --git a/kernel/irq/devres.c b/kernel/irq/devres.c
>> index bd8e788d71e0..1ef0606797c9 100644
>> --- a/kernel/irq/devres.c
>> +++ b/kernel/irq/devres.c
>> @@ -73,6 +73,51 @@ int devm_request_threaded_irq(struct device *dev, unsigned int irq,
>> EXPORT_SYMBOL(devm_request_threaded_irq);
>>
>> /**
>> + * devm_request_any_context_irq - allocate an interrupt line for a managed device
>> + * @dev: device to request interrupt for
>> + * @irq: Interrupt line to allocate
>> + * @handler: Function to be called when the IRQ occurs
>> + * @thread_fn: function to be called in a threaded interrupt context. NULL
>> + * for devices which handle everything in @handler
>> + * @irqflags: Interrupt type flags
>> + * @devname: An ascii name for the claiming device
>> + * @dev_id: A cookie passed back to the handler function
>> + *
>> + * Except for the extra @dev argument, this function takes the
>> + * same arguments and performs the same function as
>> + * request_any_context_irq(). IRQs requested with this function will be
>> + * automatically freed on driver detach.
>> + *
>> + * If an IRQ allocated with this function needs to be freed
>> + * separately, devm_free_irq() must be used.
>> + */
>> +int devm_request_any_context_irq(struct device *dev, unsigned int irq,
>> + irq_handler_t handler, unsigned long irqflags,
>> + const char *devname, void *dev_id)
>> +{
>> + struct irq_devres *dr;
>> + int rc;
>> +
>> + dr = devres_alloc(devm_irq_release, sizeof(struct irq_devres),
>> + GFP_KERNEL);
>> + if (!dr)
>> + return -ENOMEM;
>> +
>> + rc = request_any_context_irq(irq, handler, irqflags, devname, dev_id);
>> + if (rc) {
>> + devres_free(dr);
>> + return rc;
>> + }
>> +
>> + dr->irq = irq;
>> + dr->dev_id = dev_id;
>> + devres_add(dev, dr);
>> +
>> + return 0;
>> +}
>> +EXPORT_SYMBOL(devm_request_any_context_irq);
>> +
>> +/**
>> * devm_free_irq - free an interrupt
>> * @dev: device to free interrupt for
>> * @irq: Interrupt line to free
--
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: Sony DualShock4 - basic functions work, but looking to improve support
From: simon @ 2014-01-14 20:30 UTC (permalink / raw)
To: Frank Praznik; +Cc: David Herrmann, Linux Input, Antonio Ospite
In-Reply-To: <7f868cfea581a565001fe18bb08b8abb.squirrel@mungewell.org>
[-- Attachment #1: Type: text/plain, Size: 770 bytes --]
>> The report descriptor actually describes a lot more report-IDs than
>> just "0x01" which you describe in hidraw.txt. Are you sure the
>> report-descriptors are the same for USB and BT?
>
> The report descriptor when connected via BT is different, or at least what
> I found at '/sys/bus/hid/devices/0005\:054C\:05C4.0006/report_descriptor'.
>
> Unfortunately I wasn't able to decode it.
> --
> simon@womble:~/dualshock4$ ~/hidrd-0.2.0/src/hidrd-convert des_bt.bin -o
> code
> Failed to read input item at offset 356:
> invalid item encountered
> --
After playing some more with the DS4, I noticed the comment in
'hid-sony.c' that the six-axis adds a trailing zero to it's HID... which
this file has too.
So it actually works after truncating it, see attached.
Simon
[-- Attachment #2: des_bt.txt --]
[-- Type: text/plain, Size: 10835 bytes --]
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x05, /* Usage (Gamepad), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x01, /* Report ID (1), */
0x09, 0x30, /* Usage (X), */
0x09, 0x31, /* Usage (Y), */
0x09, 0x32, /* Usage (Z), */
0x09, 0x35, /* Usage (Rz), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x04, /* Report Count (4), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x39, /* Usage (Hat Switch), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x07, /* Logical Maximum (7), */
0x75, 0x04, /* Report Size (4), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x42, /* Input (Variable, Null State), */
0x05, 0x09, /* Usage Page (Button), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x0E, /* Usage Maximum (0Eh), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x0E, /* Report Count (14), */
0x81, 0x02, /* Input (Variable), */
0x75, 0x06, /* Report Size (6), */
0x95, 0x01, /* Report Count (1), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x33, /* Usage (Rx), */
0x09, 0x34, /* Usage (Ry), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x02, /* Input (Variable), */
0x06, 0x04, 0xFF, /* Usage Page (FF04h), */
0x85, 0x02, /* Report ID (2), */
0x09, 0x24, /* Usage (24h), */
0x95, 0x24, /* Report Count (36), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xA3, /* Report ID (163), */
0x09, 0x25, /* Usage (25h), */
0x95, 0x30, /* Report Count (48), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x05, /* Report ID (5), */
0x09, 0x26, /* Usage (26h), */
0x95, 0x28, /* Report Count (40), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x06, /* Report ID (6), */
0x09, 0x27, /* Usage (27h), */
0x95, 0x34, /* Report Count (52), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x07, /* Report ID (7), */
0x09, 0x28, /* Usage (28h), */
0x95, 0x30, /* Report Count (48), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x08, /* Report ID (8), */
0x09, 0x29, /* Usage (29h), */
0x95, 0x2F, /* Report Count (47), */
0xB1, 0x02, /* Feature (Variable), */
0x06, 0x03, 0xFF, /* Usage Page (FF03h), */
0x85, 0x03, /* Report ID (3), */
0x09, 0x21, /* Usage (21h), */
0x95, 0x26, /* Report Count (38), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x04, /* Report ID (4), */
0x09, 0x22, /* Usage (22h), */
0x95, 0x2E, /* Report Count (46), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xF0, /* Report ID (240), */
0x09, 0x47, /* Usage (47h), */
0x95, 0x3F, /* Report Count (63), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xF1, /* Report ID (241), */
0x09, 0x48, /* Usage (48h), */
0x95, 0x3F, /* Report Count (63), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xF2, /* Report ID (242), */
0x09, 0x49, /* Usage (49h), */
0x95, 0x0F, /* Report Count (15), */
0xB1, 0x02, /* Feature (Variable), */
0x06, 0x00, 0xFF, /* Usage Page (FF00h), */
0x85, 0x11, /* Report ID (17), */
0x09, 0x20, /* Usage (20h), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x00, /* Logical Maximum (255), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x4D, /* Report Count (77), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x21, /* Usage (21h), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x12, /* Report ID (18), */
0x09, 0x22, /* Usage (22h), */
0x95, 0x8D, /* Report Count (141), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x23, /* Usage (23h), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x13, /* Report ID (19), */
0x09, 0x24, /* Usage (24h), */
0x95, 0xCD, /* Report Count (205), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x25, /* Usage (25h), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x14, /* Report ID (20), */
0x09, 0x26, /* Usage (26h), */
0x96, 0x0D, 0x01, /* Report Count (269), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x27, /* Usage (27h), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x15, /* Report ID (21), */
0x09, 0x28, /* Usage (28h), */
0x96, 0x4D, 0x01, /* Report Count (333), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x29, /* Usage (29h), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x16, /* Report ID (22), */
0x09, 0x2A, /* Usage (2Ah), */
0x96, 0x8D, 0x01, /* Report Count (397), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x2B, /* Usage (2Bh), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x17, /* Report ID (23), */
0x09, 0x2C, /* Usage (2Ch), */
0x96, 0xCD, 0x01, /* Report Count (461), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x2D, /* Usage (2Dh), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x18, /* Report ID (24), */
0x09, 0x2E, /* Usage (2Eh), */
0x96, 0x0D, 0x02, /* Report Count (525), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x2F, /* Usage (2Fh), */
0x91, 0x02, /* Output (Variable), */
0x85, 0x19, /* Report ID (25), */
0x09, 0x30, /* Usage (30h), */
0x96, 0x22, 0x02, /* Report Count (546), */
0x81, 0x02, /* Input (Variable), */
0x09, 0x31, /* Usage (31h), */
0x91, 0x02, /* Output (Variable), */
0x06, 0x80, 0xFF, /* Usage Page (FF80h), */
0x85, 0x82, /* Report ID (130), */
0x09, 0x22, /* Usage (22h), */
0x95, 0x3F, /* Report Count (63), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x83, /* Report ID (131), */
0x09, 0x23, /* Usage (23h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x84, /* Report ID (132), */
0x09, 0x24, /* Usage (24h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x90, /* Report ID (144), */
0x09, 0x30, /* Usage (30h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x91, /* Report ID (145), */
0x09, 0x31, /* Usage (31h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x92, /* Report ID (146), */
0x09, 0x32, /* Usage (32h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0x93, /* Report ID (147), */
0x09, 0x33, /* Usage (33h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xA0, /* Report ID (160), */
0x09, 0x40, /* Usage (40h), */
0xB1, 0x02, /* Feature (Variable), */
0x85, 0xA4, /* Report ID (164), */
0x09, 0x44, /* Usage (44h), */
0xB1, 0x02, /* Feature (Variable), */
0xC0 /* End Collection */
^ permalink raw reply
* Re: Fwd: [PATCH] add support for ALPS v7 protocol device
From: Dylan Thurston @ 2014-01-14 20:17 UTC (permalink / raw)
To: Tommy Will
Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, Niels de Vos,
Justin Clift, Qiting Chen, Qiting Chen, linux-input
In-Reply-To: <CA+F6ckM=K74LH4R_xRJaH6Er2DDyms8M8++qSynVJjfUQ=tnPg@mail.gmail.com>
Thank you! Which versions does this apply against? It patched for me
with no fuzz against linux-next-20140114, but unfortunately X seems to
be broken for me on that version (blank screen). I get fuzz and
rejected patches when applying it to 3.13-rc8. Is it safe to just copy
over alps.c from the linux-next version?
(Of course, it's possible that the blank screen is a side effect of
the correct recognition of the touchpad.)
Thanks,
Dylan
On Tue, Jan 14, 2014 at 02:11:59PM +0800, Tommy Will wrote:
> Hi Dylan,
>
> My colleague Elaine has prepared the patch for new ALPS touchpad that
> being used on your HP Revolve 810 G1 laptop.
> You can have a try~
>
> --
> Best Regards,
> Tommy
>
> ---------- Forwarded message ----------
> From: Elaine Chen <elaineee66@gmail.com>
> Date: 2014/1/14
> Subject: Re: [PATCH] add support for ALPS v7 protocol device
> To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
> david turvene <dturvene@dahetral.com>
> 抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
> Qiting Chen <qiting.chen@cn.alps.com>
>
>
> As far as I know, the ALPS v7 protocol device is used on following laptops:
>
> Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
>
> 2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> > Here is the patch of supporting ALPS v7 protocol device.
> >
> > v7 device is a clickpad device.
> > Device info:
> > Device ID = 0x73, 0x03, 0x0a
> > Firmware ID = 0x88, 0xb*, 0x**
> >
> > Support function of v7 device:
> > - Cursor
> > - Tap, double tap, tap drag, 2finger tap
> > - Pan, pinch
> > - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> > Click touchpad with all fingers outside right Button Area --> left click
> > Click touchpad with at lease 1 finger inside right Button Area --> right click
> > - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
> >
> > The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> > We tried registering our device as a clickpad by:
> > set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> > But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
> >
> >
> > Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> > ---
> > drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> > drivers/input/mouse/alps.h | 127 ++++++++++--
> > 2 files changed, 554 insertions(+), 51 deletions(-)
> >
> > diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> > index fb15c64..3e8e8f7 100644
> > --- a/drivers/input/mouse/alps.c
> > +++ b/drivers/input/mouse/alps.c
> > @@ -32,6 +32,11 @@
> > #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> > #define ALPS_REG_BASE_PINNACLE 0x0000
> >
> > +#define LEFT_BUTTON_BIT 0x01
> > +#define RIGHT_BUTTON_BIT 0x02
> > +
> > +#define V7_LARGE_MOVEMENT 130
> > +
> > static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> > { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> > { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> > @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> > #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> > #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> > 6-byte ALPS packet */
> > +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
> >
> > static const struct alps_model_info alps_model_data[] = {
> > { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> > @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > * isn't valid per PS/2 spec.
> > */
> >
> > +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> > + struct alps_abs_data *pt1)
> > +{
> > + int vect_x, vect_y;
> > +
> > + if (!pt0 || !pt1)
> > + return 0;
> > +
> > + vect_x = pt0->x - pt1->x;
> > + vect_y = pt0->y - pt1->y;
> > +
> > + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> > +}
> > +
> > /* Packet formats are described in Documentation/input/alps.txt */
> >
> > static bool alps_is_valid_first_byte(struct alps_data *priv,
> > @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> > end_bit = y_msb - 1;
> > box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> > (2 * (priv->y_bits - 1));
> > - *x1 = fields->x;
> > - *y1 = fields->y;
> > + *x1 = fields->pt.x;
> > + *y1 = fields->pt.y;
> > *x2 = 2 * box_middle_x - *x1;
> > *y2 = 2 * box_middle_y - *y1;
> > }
> > @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> > alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> > }
> >
> > +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> > + struct alps_fields *f)
> > +{
> > + struct input_dev *dev;
> > +
> > + if (!psmouse || !f)
> > + return;
> > +
> > + dev = psmouse->dev;
> > +
> > + if (f->fingers) {
> > + input_report_key(dev, BTN_TOUCH, 1);
> > + alps_report_semi_mt_data(dev, f->fingers,
> > + f->pt_img[0].x, f->pt_img[0].y,
> > + f->pt_img[1].x, f->pt_img[1].y);
> > + input_mt_report_finger_count(dev, f->fingers);
> > +
> > + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> > + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> > + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> > + } else {
> > + input_report_key(dev, BTN_TOUCH, 0);
> > + input_mt_report_finger_count(dev, 0);
> > + input_report_abs(dev, ABS_PRESSURE, 0);
> > + }
> > +
> > + input_report_key(dev, BTN_LEFT, f->btn.left);
> > + input_report_key(dev, BTN_RIGHT, f->btn.right);
> > +
> > + input_sync(dev);
> > +}
> > +
> > static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> > {
> > struct alps_data *priv = psmouse->private;
> > @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> >
> > static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> > {
> > - f->left = !!(p[3] & 0x01);
> > - f->right = !!(p[3] & 0x02);
> > - f->middle = !!(p[3] & 0x04);
> > + f->btn.left = !!(p[3] & 0x01);
> > + f->btn.right = !!(p[3] & 0x02);
> > + f->btn.middle = !!(p[3] & 0x04);
> >
> > - f->ts_left = !!(p[3] & 0x10);
> > - f->ts_right = !!(p[3] & 0x20);
> > - f->ts_middle = !!(p[3] & 0x40);
> > + f->btn.ts_left = !!(p[3] & 0x10);
> > + f->btn.ts_right = !!(p[3] & 0x20);
> > + f->btn.ts_middle = !!(p[3] & 0x40);
> > }
> >
> > static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> > ((p[2] & 0x7f) << 1) |
> > (p[4] & 0x01);
> >
> > - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> > ((p[0] & 0x30) >> 4);
> > - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > - f->z = p[5] & 0x7f;
> > + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> > + f->pt.z = p[5] & 0x7f;
> >
> > alps_decode_buttons_v3(f, p);
> > }
> > @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> > f->is_mp = !!(p[0] & 0x20);
> >
> > if (!f->is_mp) {
> > - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> > + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> > + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> > alps_decode_buttons_v3(f, p);
> > } else {
> > f->fingers = ((p[0] & 0x6) >> 1 |
> > @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > * with x, y, and z all zero, so these seem to be flukes.
> > * Ignore them.
> > */
> > - if (f.x && f.y && !f.z)
> > + if (f.pt.x && f.pt.y && !f.pt.z)
> > return;
> >
> > /*
> > @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> > * to rely on ST data.
> > */
> > if (!fingers) {
> > - x1 = f.x;
> > - y1 = f.y;
> > - fingers = f.z > 0 ? 1 : 0;
> > + x1 = f.pt.x;
> > + y1 = f.pt.y;
> > + fingers = f.pt.z > 0 ? 1 : 0;
> > }
> >
> > - if (f.z >= 64)
> > + if (f.pt.z >= 64)
> > input_report_key(dev, BTN_TOUCH, 1);
> > else
> > input_report_key(dev, BTN_TOUCH, 0);
> > @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> >
> > input_mt_report_finger_count(dev, fingers);
> >
> > - input_report_key(dev, BTN_LEFT, f.left);
> > - input_report_key(dev, BTN_RIGHT, f.right);
> > - input_report_key(dev, BTN_MIDDLE, f.middle);
> > + input_report_key(dev, BTN_LEFT, f.btn.left);
> > + input_report_key(dev, BTN_RIGHT, f.btn.right);
> > + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
> >
> > - if (f.z > 0) {
> > - input_report_abs(dev, ABS_X, f.x);
> > - input_report_abs(dev, ABS_Y, f.y);
> > + if (f.pt.z > 0) {
> > + input_report_abs(dev, ABS_X, f.pt.x);
> > + input_report_abs(dev, ABS_Y, f.pt.y);
> > }
> > - input_report_abs(dev, ABS_PRESSURE, f.z);
> > + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
> >
> > input_sync(dev);
> >
> > if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> > - input_report_key(dev2, BTN_LEFT, f.ts_left);
> > - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> > - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> > + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> > + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> > + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> > input_sync(dev2);
> > }
> > }
> > @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> > input_sync(dev);
> > }
> >
> > +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> > +{
> > + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> > + return false;
> > + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> > + return false;
> > + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> > + return false;
> > + return true;
> > +}
> > +
> > +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > + int drop = 1;
> > +
> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> > + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> > + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> > + drop = 0;
> > +
> > + return drop;
> > +}
> > +
> > +static unsigned char alps_get_packet_id_v7(char *byte)
> > +{
> > + unsigned char packet_id;
> > +
> > + if (byte[4] & 0x40)
> > + packet_id = V7_PACKET_ID_TWO;
> > + else if (byte[4] & 0x01)
> > + packet_id = V7_PACKET_ID_MULTI;
> > + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> > + packet_id = V7_PACKET_ID_NEW;
> > + else
> > + packet_id = V7_PACKET_ID_IDLE;
> > +
> > + return packet_id;
> > +}
> > +
> > +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> > + unsigned char *pkt,
> > + unsigned char pkt_id)
> > +{
> > + if ((pkt_id == V7_PACKET_ID_TWO) ||
> > + (pkt_id == V7_PACKET_ID_MULTI) ||
> > + (pkt_id == V7_PACKET_ID_NEW)) {
> > + pt[0].x = ((pkt[2] & 0x80) << 4);
> > + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> > + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> > + pt[0].x |= (pkt[3] & 0x07);
> > + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> > +
> > + pt[1].x = ((pkt[3] & 0x80) << 4);
> > + pt[1].x |= ((pkt[4] & 0x80) << 3);
> > + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> > + pt[1].y = ((pkt[5] & 0x80) << 3);
> > + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> > +
> > + if (pkt_id == V7_PACKET_ID_TWO) {
> > + pt[1].x &= ~0x000F;
> > + pt[1].y |= 0x000F;
> > + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> > + pt[1].x &= ~0x003F;
> > + pt[1].y &= ~0x0020;
> > + pt[1].y |= ((pkt[4] & 0x02) << 4);
> > + pt[1].y |= 0x001F;
> > + } else if (pkt_id == V7_PACKET_ID_NEW) {
> > + pt[1].x &= ~0x003F;
> > + pt[1].x |= (pkt[0] & 0x20);
> > + pt[1].y |= 0x000F;
> > + }
> > +
> > + pt[0].y = 0x7FF - pt[0].y;
> > + pt[1].y = 0x7FF - pt[1].y;
> > +
> > + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> > + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> > + }
> > +}
> > +
> > +static void alps_decode_packet_v7(struct alps_fields *f,
> > + unsigned char *p,
> > + struct psmouse *psmouse)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > +
> > + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> > +
> > + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> > +
> > + priv->r.v7.rest_left = 0;
> > + priv->r.v7.rest_right = 0;
> > + priv->r.v7.additional_fingers = 0;
> > + priv->phy_btn = 0;
> > +
> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> > + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> > + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> > + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> > + }
> > +
> > + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> > + priv->r.v7.additional_fingers = p[5] & 0x03;
> > +
> > + priv->phy_btn = (p[0] & 0x80) >> 7;
> > +}
> > +
> > +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> > + struct alps_abs_data *pt,
> > + struct alps_bl_pt_attr *pt_attr)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > + unsigned int dist;
> > +
> > + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> > + pt_attr->is_init_pt_got = 1;
> > + pt_attr->is_counted = 0;
> > + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> > + }
> > +
> > + if (pt->z != 0) {
> > + if (pt->y < priv->resting_zone_y_min) {
> > + /* A finger is recognized as a non-resting finger
> > + if it's position is outside the resting finger zone.*/
> > + pt_attr->zone = ZONE_NORMAL;
> > + pt_attr->is_counted = 1;
> > + } else {
> > + /* A finger is recognized as a resting finger if it's
> > + position is inside the resting finger zone and there's
> > + no large movement from it's touch down position.*/
> > + pt_attr->zone = ZONE_RESTING;
> > +
> > + if (pt->x > priv->x_max / 2)
> > + pt_attr->zone |= ZONE_RIGHT_BTN;
> > + else
> > + pt_attr->zone |= ZONE_LEFT_BTN;
> > +
> > + /* A resting finger will turn to be a non-resting
> > + finger if it has made large movement from it's touch
> > + down position. A non-resting finger will never turn
> > + to a resting finger before it leaves the touchpad
> > + surface.*/
> > + if (pt_attr->is_init_pt_got) {
> > + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> > +
> > + if (dist > V7_LARGE_MOVEMENT)
> > + pt_attr->is_counted = 1;
> > + }
> > + }
> > + }
> > +}
> > +
> > +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> > + struct alps_fields *f)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > + int i;
> > +
> > + switch (priv->r.v7.pkt_id) {
> > + case V7_PACKET_ID_TWO:
> > + case V7_PACKET_ID_MULTI:
> > + for (i = 0; i < V7_IMG_PT_NUM; i++)
> > + alps_set_each_pt_attr_v7(psmouse,
> > + &f->pt_img[i],
> > + &priv->pt_attr[i]);
> > + break;
> > + default:
> > + /*All finger attributes are cleared when packet ID is
> > + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> > + indicates that there's no finger and no button activity.
> > + A 'NEW' packet indicates the finger position in packet
> > + is not continues from previous packet. Such as the
> > + condition there's finger placed or lifted. In these cases,
> > + finger attributes will be reset.*/
> > + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> > + break;
> > + }
> > +}
> > +
> > +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> > + struct alps_fields *f)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > + unsigned int fn = 0;
> > + int i;
> > +
> > + switch (priv->r.v7.pkt_id) {
> > + case V7_PACKET_ID_IDLE:
> > + case V7_PACKET_ID_NEW:
> > + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> > + An 'IDLE' packet indicates that there's no finger on touchpad.
> > + A 'NEW' packet indicates there's finger placed or lifted.
> > + Finger position of 'New' packet is not continues from the
> > + previous packet.*/
> > + fn = 0;
> > + break;
> > + case V7_PACKET_ID_TWO:
> > + if (f->pt_img[0].z == 0) {
> > + /*The first finger slot is zero when a non-resting
> > + finger lifted and remaining only one resting finger
> > + on touchpad. Hardware report the remaining resting
> > + finger in second slot. This resting is ignored*/
> > + fn = 0;
> > + } else if (f->pt_img[1].z == 0) {
> > + /* The second finger slot is zero if there's
> > + only one finger*/
> > + fn = 1;
> > + } else {
> > + /*All non-resting fingers will be counted to report*/
> > + fn = 0;
> > + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> > + if (priv->pt_attr[i].is_counted)
> > + fn++;
> > + }
> > +
> > + /*In the case that both fingers are
> > + resting fingers, report the first one*/
> > + if (!priv->pt_attr[0].is_counted &&
> > + !priv->pt_attr[1].is_counted) {
> > + fn = 1;
> > + }
> > + }
> > + break;
> > + case V7_PACKET_ID_MULTI:
> > + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> > + finger exist.*/
> > + fn = 3 + priv->r.v7.additional_fingers;
> > + break;
> > + }
> > +
> > + f->fingers = fn;
> > +}
> > +
> > +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> > + struct alps_fields *f)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > +
> > + if (priv->phy_btn) {
> > + if (!priv->prev_phy_btn) {
> > + /* Report a right click as long as there's finger on
> > + right button zone. Othrewise, report a left click.*/
> > + if (priv->r.v7.rest_right ||
> > + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> > + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> > + f->btn.right = 1;
> > + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> > + } else {
> > + f->btn.left = 1;
> > + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> > + }
> > + } else {
> > + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> > + f->btn.right = 1;
> > + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> > + f->btn.left = 1;
> > + }
> > + } else {
> > + priv->pressed_btn_bits = 0;
> > + f->btn.right = 0;
> > + f->btn.left = 0;
> > + }
> > +
> > + priv->prev_phy_btn = priv->phy_btn;
> > +}
> > +
> > +static void alps_process_packet_v7(struct psmouse *psmouse)
> > +{
> > + struct alps_data *priv = psmouse->private;
> > + struct alps_fields f = {0};
> > + unsigned char *packet = psmouse->packet;
> > +
> > + priv->decode_fields(&f, packet, psmouse);
> > +
> > + if (alps_drop_unsupported_packet_v7(psmouse))
> > + return;
> > +
> > + alps_set_pt_attr_v7(psmouse, &f);
> > +
> > + alps_cal_output_finger_num_v7(psmouse, &f);
> > +
> > + alps_assign_buttons_v7(psmouse, &f);
> > +
> > + alps_report_coord_and_btn(psmouse, &f);
> > +}
> > +
> > static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> > unsigned char packet[],
> > bool report_buttons)
> > @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> > return PSMOUSE_BAD_DATA;
> > }
> >
> > + if ((priv->proto_version == ALPS_PROTO_V7 &&
> > + !alps_is_valid_package_v7(psmouse))) {
> > + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> > + psmouse->pktcnt - 1,
> > + psmouse->packet[psmouse->pktcnt - 1]);
> > + return PSMOUSE_BAD_DATA;
> > + }
> > +
> > if (psmouse->pktcnt == psmouse->pktsize) {
> > priv->process_packet(psmouse);
> > return PSMOUSE_FULL_PACKET;
> > @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> > return 0;
> > }
> >
> > +static int alps_check_valid_firmware_id(unsigned char id[])
> > +{
> > + int valid = 1;
> > +
> > + if (id[0] == 0x73)
> > + valid = 1;
> > + else if (id[0] == 0x88) {
> > + if ((id[1] == 0x07) ||
> > + (id[1] == 0x08) ||
> > + ((id[1] & 0xf0) == 0xB0))
> > + valid = 1;
> > + }
> > +
> > + return valid;
> > +}
> > +
> > static int alps_enter_command_mode(struct psmouse *psmouse)
> > {
> > unsigned char param[4];
> > @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> > return -1;
> > }
> >
> > - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> > - param[0] != 0x73) {
> > + if (!alps_check_valid_firmware_id(param)) {
> > psmouse_dbg(psmouse,
> > "unknown response while entering command mode\n");
> > return -1;
> > @@ -1704,6 +2067,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)
> > {
> > @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > priv->set_abs_params = alps_set_abs_params_st;
> > priv->x_max = 1023;
> > priv->y_max = 767;
> > + priv->slot_number = 1;
> > break;
> > case ALPS_PROTO_V3:
> > priv->hw_init = alps_hw_init_v3;
> > @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > priv->decode_fields = alps_decode_pinnacle;
> > priv->nibble_commands = alps_v3_nibble_commands;
> > priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > + priv->slot_number = 2;
> > break;
> > case ALPS_PROTO_V4:
> > priv->hw_init = alps_hw_init_v4;
> > @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > priv->set_abs_params = alps_set_abs_params_mt;
> > priv->nibble_commands = alps_v4_nibble_commands;
> > priv->addr_command = PSMOUSE_CMD_DISABLE;
> > + priv->slot_number = 2;
> > break;
> > case ALPS_PROTO_V5:
> > priv->hw_init = alps_hw_init_dolphin_v1;
> > @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> > priv->y_max = 660;
> > priv->x_bits = 23;
> > priv->y_bits = 12;
> > + priv->slot_number = 2;
> > break;
> > case ALPS_PROTO_V6:
> > priv->hw_init = alps_hw_init_v6;
> > @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> > priv->nibble_commands = alps_v6_nibble_commands;
> > priv->x_max = 2047;
> > priv->y_max = 1535;
> > + priv->slot_number = 2;
> > + break;
> > + case ALPS_PROTO_V7:
> > + priv->hw_init = alps_hw_init_v7;
> > + priv->process_packet = alps_process_packet_v7;
> > + priv->decode_fields = alps_decode_packet_v7;
> > + priv->set_abs_params = alps_set_abs_params_mt;
> > + priv->nibble_commands = alps_v3_nibble_commands;
> > + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> > + priv->x_max = 0xfff;
> > + priv->y_max = 0x7ff;
> > + priv->resting_zone_y_min = 0x654;
> > + priv->byte0 = 0x48;
> > + priv->mask0 = 0x48;
> > + priv->flags = 0;
> > + priv->slot_number = 2;
> > break;
> > }
> > }
> > @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> > return -EIO;
> > else
> > return 0;
> > + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> > + priv->proto_version = ALPS_PROTO_V7;
> > + alps_set_defaults(priv);
> > +
> > + return 0;
> > } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> > priv->proto_version = ALPS_PROTO_V3;
> > alps_set_defaults(priv);
> > @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> > struct input_dev *dev1)
> > {
> > set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> > - input_mt_init_slots(dev1, 2, 0);
> > + input_mt_init_slots(dev1, priv->slot_number, 0);
> > input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> > input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
> >
> > diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> > index 03f88b6..5d2f9ea 100644
> > --- a/drivers/input/mouse/alps.h
> > +++ b/drivers/input/mouse/alps.h
> > @@ -18,11 +18,36 @@
> > #define ALPS_PROTO_V4 4
> > #define ALPS_PROTO_V5 5
> > #define ALPS_PROTO_V6 6
> > +#define ALPS_PROTO_V7 7
> > +
> > +#define MAX_IMG_PT_NUM 5
> > +#define V7_IMG_PT_NUM 2
> > +
> > +#define ZONE_NORMAL 0x01
> > +#define ZONE_RESTING 0x02
> > +#define ZONE_LEFT_BTN 0x04
> > +#define ZONE_RIGHT_BTN 0x08
> >
> > #define DOLPHIN_COUNT_PER_ELECTRODE 64
> > #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> > #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
> >
> > +/*
> > + * enum V7_PACKET_ID - defines the packet type for V7
> > + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> > + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> > + * or there's button activities.
> > + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> > + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> > + * previous packet.
> > +*/
> > +enum V7_PACKET_ID {
> > + V7_PACKET_ID_IDLE,
> > + V7_PACKET_ID_TWO,
> > + V7_PACKET_ID_MULTI,
> > + V7_PACKET_ID_NEW,
> > +};
> > +
> > /**
> > * struct alps_model_info - touchpad ID table
> > * @signature: E7 response string to match.
> > @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> > };
> >
> > /**
> > - * struct alps_fields - decoded version of the report packet
> > - * @x_map: Bitmap of active X positions for MT.
> > - * @y_map: Bitmap of active Y positions for MT.
> > - * @fingers: Number of fingers for MT.
> > - * @x: X position for ST.
> > - * @y: Y position for ST.
> > - * @z: Z position for ST.
> > - * @first_mp: Packet is the first of a multi-packet report.
> > - * @is_mp: Packet is part of a multi-packet report.
> > + * struct alps_btn - decoded version of the button status
> > * @left: Left touchpad button is active.
> > * @right: Right touchpad button is active.
> > * @middle: Middle touchpad button is active.
> > @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> > * @ts_right: Right trackstick button is active.
> > * @ts_middle: Middle trackstick button is active.
> > */
> > -struct alps_fields {
> > - unsigned int x_map;
> > - unsigned int y_map;
> > - unsigned int fingers;
> > - unsigned int x;
> > - unsigned int y;
> > - unsigned int z;
> > - unsigned int first_mp:1;
> > - unsigned int is_mp:1;
> > -
> > +struct alps_btn {
> > unsigned int left:1;
> > unsigned int right:1;
> > unsigned int middle:1;
> > @@ -102,6 +110,69 @@ struct alps_fields {
> > };
> >
> > /**
> > + * struct alps_btn - decoded version of the X Y Z postion for ST.
> > + * @x: X position for ST.
> > + * @y: Y position for ST.
> > + * @z: Z position for ST.
> > + */
> > +struct alps_abs_data {
> > + unsigned int x;
> > + unsigned int y;
> > + unsigned int z;
> > +};
> > +
> > +/**
> > + * struct alps_fields - decoded version of the report packet
> > + * @fingers: Number of fingers for MT.
> > + * @pt: X Y Z postion for ST.
> > + * @pt: X Y Z postion for image MT.
> > + * @x_map: Bitmap of active X positions for MT.
> > + * @y_map: Bitmap of active Y positions for MT.
> > + * @first_mp: Packet is the first of a multi-packet report.
> > + * @is_mp: Packet is part of a multi-packet report.
> > + * @btn: Button activity status
> > + */
> > +struct alps_fields {
> > + unsigned int fingers;
> > + struct alps_abs_data pt;
> > + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> > + unsigned int x_map;
> > + unsigned int y_map;
> > + unsigned int first_mp:1;
> > + unsigned int is_mp:1;
> > + struct alps_btn btn;
> > +};
> > +
> > +/**
> > + * struct v7_raw - data decoded from raw packet for V7.
> > + * @pkt_id: An id that specifies the type of packet.
> > + * @additional_fingers: Number of additional finger that is neighter included
> > + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> > + * @rest_left: There are fingers on left resting zone.
> > + * @rest_right: There are fingers on right resting zone.
> > + */
> > +struct v7_raw {
> > + unsigned char pkt_id;
> > + unsigned int additional_fingers;
> > + unsigned char rest_left;
> > + unsigned char rest_right;
> > +};
> > +
> > +/**
> > + * 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;
> > +};
> > +
> > +/**
> > * struct alps_data - private data structure for the ALPS driver
> > * @dev2: "Relative" device used to report trackstick or mouse activity.
> > * @phys: Physical path for the relative device.
> > @@ -116,8 +187,10 @@ struct alps_fields {
> > * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> > * @x_max: Largest possible X position value.
> > * @y_max: Largest possible Y position value.
> > + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> > * @x_bits: Number of X bits in the MT bitmap.
> > * @y_bits: Number of Y bits in the MT bitmap.
> > + * @img_fingers: Number of image fingers.
> > * @hw_init: Protocol-specific hardware init function.
> > * @process_packet: Protocol-specific function to process a report packet.
> > * @decode_fields: Protocol-specific function to read packet bitfields.
> > @@ -132,6 +205,11 @@ struct alps_fields {
> > * @fingers: Number of fingers from last MT report.
> > * @quirks: Bitmap of ALPS_QUIRK_*.
> > * @timer: Timer for flushing out the final report packet in the stream.
> > + * @v7: Data decoded from raw packet for V7
> > + * @phy_btn: Physical button is active.
> > + * @prev_phy_btn: Physical button of previous packet is active.
> > + * @pressed_btn_bits: Pressed positon of button zone
> > + * @pt_attr: Generic attributes of touch points for buttonless device.
> > */
> > struct alps_data {
> > struct input_dev *dev2;
> > @@ -145,8 +223,10 @@ struct alps_data {
> > unsigned char flags;
> > int x_max;
> > int y_max;
> > + int resting_zone_y_min;
> > int x_bits;
> > int y_bits;
> > + unsigned char slot_number;
> >
> > int (*hw_init)(struct psmouse *psmouse);
> > void (*process_packet)(struct psmouse *psmouse);
> > @@ -161,6 +241,15 @@ struct alps_data {
> > int fingers;
> > u8 quirks;
> > struct timer_list timer;
> > +
> > + /* these are used for buttonless touchpad*/
> > + union {
> > + struct v7_raw v7;
> > + } r;
> > + unsigned char phy_btn;
> > + unsigned char prev_phy_btn;
> > + unsigned char pressed_btn_bits;
> > + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> > };
> >
> > #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> > --
> > 1.8.3.2
> >
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] HID: hid-sensor-hub:Fix buggy report descriptors
From: Srinivas Pandruvada @ 2014-01-14 17:30 UTC (permalink / raw)
To: jkosina; +Cc: linux-input, Srinivas Pandruvada
This addresses regression caused by commit id "751d17e23a9f7"
iio: hid-sensors: Fix power and report state.
This commit removed a quirk, to change the enumeration base
to 1 from 0 based on an CONFIG paramter. There was objection to
add more changes under this quirk, instead suggested to add an
HID quirk. But there is no easy way to add HID qurik as the
reports are not properly using collection class.
The solution was to use logical minimum, which is a correct way.
There were changes done in firmware to address this.
Unfortunately some devices, still use old FW and can't be upgraded
to newer version on Linux devices as there is no FW upgrade tool
available for Linux devices. So we need to fix report descriptors,
for such devices. This will not have any impact, if the FW uses
logical 1 as minimum.
In this patch we look for usage id for "power and report state", and
modify logical minimum value to 1.
Background on enum:
In the original HID sensor hub firmwares all Named array enums were
to 0-based. But the most recent hub implemented as 1-based,
because of the implementation by one of the major OS vendor.
Using logical minimum for the field as the base of enum. So we add
logical minimum to the selector values before setting those fields.
Some sensor hub FWs already changed logical minimum from 0 to 1
to reflect this and hope every other vendor will follow.
There is no easy way to add a common HID quirk for NAry elements,
even if the standard specifies these field as NAry, the collection
used to describe selectors is still just "logical".
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
---
drivers/hid/hid-ids.h | 4 ++++
drivers/hid/hid-sensor-hub.c | 45 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index f9304cb..fe9cd9d 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -445,6 +445,10 @@
#define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
+#define USB_VENDOR_ID_INTEL_0 0x8086
+#define USB_VENDOR_ID_INTEL_1 0x8087
+#define USB_DEVICE_ID_INTEL_HID_SENSOR 0x09fa
+
#define USB_VENDOR_ID_ION 0x15e4
#define USB_DEVICE_ID_ICADE 0x0132
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 8fab828..46f4480 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -26,6 +26,8 @@
#include <linux/hid-sensor-hub.h>
#include "hid-ids.h"
+#define HID_SENSOR_HUB_ENUM_QUIRK 0x01
+
/**
* struct sensor_hub_pending - Synchronous read pending information
* @status: Pending status true/false.
@@ -64,6 +66,7 @@ struct sensor_hub_data {
spinlock_t dyn_callback_lock;
struct mfd_cell *hid_sensor_hub_client_devs;
int hid_sensor_client_cnt;
+ unsigned long quirks;
};
/**
@@ -497,6 +500,40 @@ void sensor_hub_device_close(struct hid_sensor_hub_device *hsdev)
}
EXPORT_SYMBOL_GPL(sensor_hub_device_close);
+static __u8 *sensor_hub_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ int index;
+ struct sensor_hub_data *sd = hid_get_drvdata(hdev);
+ unsigned char report_block[] = {
+ 0x0a, 0x16, 0x03, 0x15, 0x00, 0x25, 0x05};
+ unsigned char power_block[] = {
+ 0x0a, 0x19, 0x03, 0x15, 0x00, 0x25, 0x05};
+
+ if (!(sd->quirks & HID_SENSOR_HUB_ENUM_QUIRK)) {
+ hid_dbg(hdev, "No Enum quirks\n");
+ return rdesc;
+ }
+
+ /* Looks for power and report state usage id and force to 1 */
+ for (index = 0; index < *rsize; ++index) {
+ if (((*rsize - index) > sizeof(report_block)) &&
+ !memcmp(&rdesc[index], report_block,
+ sizeof(report_block))) {
+ rdesc[index + 4] = 0x01;
+ index += sizeof(report_block);
+ }
+ if (((*rsize - index) > sizeof(power_block)) &&
+ !memcmp(&rdesc[index], power_block,
+ sizeof(power_block))) {
+ rdesc[index + 4] = 0x01;
+ index += sizeof(power_block);
+ }
+ }
+
+ return rdesc;
+}
+
static int sensor_hub_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@@ -520,6 +557,7 @@ static int sensor_hub_probe(struct hid_device *hdev,
return -ENOMEM;
}
hid_set_drvdata(hdev, sd);
+ sd->quirks = id->driver_data;
sd->hsdev->hdev = hdev;
sd->hsdev->vendor_id = hdev->vendor;
sd->hsdev->product_id = hdev->product;
@@ -621,6 +659,12 @@ static void sensor_hub_remove(struct hid_device *hdev)
}
static const struct hid_device_id sensor_hub_devices[] = {
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_0,
+ USB_DEVICE_ID_INTEL_HID_SENSOR),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
+ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, USB_VENDOR_ID_INTEL_1,
+ USB_DEVICE_ID_INTEL_HID_SENSOR),
+ .driver_data = HID_SENSOR_HUB_ENUM_QUIRK},
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_SENSOR_HUB, HID_ANY_ID,
HID_ANY_ID) },
{ }
@@ -633,6 +677,7 @@ static struct hid_driver sensor_hub_driver = {
.probe = sensor_hub_probe,
.remove = sensor_hub_remove,
.raw_event = sensor_hub_raw_event,
+ .report_fixup = sensor_hub_report_fixup,
#ifdef CONFIG_PM
.suspend = sensor_hub_suspend,
.resume = sensor_hub_resume,
--
1.8.3.1
^ permalink raw reply related
* Re(3): [PATCH] Introduce Naming Convention in Input Subsystem
From: Aniroop Mathur @ 2014-01-14 16:29 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Aniroop Mathur, Aniroop Mathur, linux-input@vger.kernel.org,
cpgs ., Anurag Aggarwal, Naveen Kumar, VIKAS KALA,
Poorva Srivastava
Hello Mr. Torokhov,
Greetings!
First of all, i am sorry but i am using office's computer,
so cannot install any 3rd party software due to restriction.
Using, Re(2): (Aniroop Mathur) for my comments.
On Sat, Jan 11, 2014 at 02:55:33AM +0530, Aniroop Mathur wrote:
> Hello Mr. Torokhov,
> Greetings!
>
> First of all, So sorry, unfortunately i used HTML text again.
> and Many thanks for all replies.
>
> Sending email again in plain text.
>
>
> On Sat, Jan 11, 2014 at 12:41 AM, Dmitry Torokhov
> wrote:
> > Hi Aniroop,
> >
> > On Fri, Jan 10, 2014 at 04:49:43PM +0000, Aniroop Mathur wrote:
> >> Hello Mr. Torokhov,
> >> Greetings!
> >>
> >> On Thu, Jan 09, 2014 at 10:27:56AM +0530, Aniroop Mathur wrote:
> >> > This patch allows user(driver) to set sysfs node name of input
> >> > devices. To set sysfs node name, user(driver) just needs to set
> >> > node_name_unique variable. If node_name_unique is not set, default
> >> > name is given(as before). So, this patch is completely
> >> > backward-compatible.
> >> >
> >> > Sysfs Input node name format is: input_
> >> > Sysfs Event node name format is: event_
> >> >
> >> > This "name" is given by user and automatically, prefix(input and
> >> > event) is added by input core.
> >> >
> >> > This name must be unique among all input devices and driver(user) has
> >> > the responsibility to ensure it. If same name is used again for other
> >> > input device, registration of that input device will fail because two
> >> > input devices cannot have same name.
> >> >
> >> > Advantages of this patch are:
> >> >
> >> > 1. Reduces Booting Time of HAL/Upper-Layer because now HAL or
> >> > Upper-Layer do not need to search input/event number corresponding to
> >> > each input device in /dev/input/... This searching in /dev/input/ was
> >> > taking too much time. (Especially in mobile devices, where there are
> >> > many input devices (many sensors, touchscreen, etc), it reduces a lot
> >> > of booting time)
> >>
> >> I am sorry, how much time does it take to scan a directory of what, 20
> >> devices? If it such a factor have udev create nodes that are easier for
> >> you to locate, similarly how we already create nodes by-id and by-path.
> >> For example you can encode major:minor in device name.
> >>
> >> Re: (Aniroop Mathur)
> >
> > First of all, it would be great if you could use MUA that can properly
> > quote and wrap long lines...
> >
> >> Its correct that we can set name of a device node using udev. Yes,
> >> this will change the name of device node(/dev/...) but not sysfs
> >> node.(/sys/class/input/...) So now, the problem area will shift from
> >> dev path to sysfs path, because now we dont know which sysfs node to
> >> refer for a particular input device and hence HAL/Upper-Layer will
> >> need to search in /sys/class/input/... instead of /dev/... directory.
> >
> > [dtor@dtor-d630 ~]$ mkdir my-sysfs-view
> > [dtor@dtor-d630 ~]$ ln -s
> > /sys/devices/platform/i8042/serio1/input/input6
> > my-sysfs-view/input_touchpad
> > [dtor@dtor-d630 ~]$ ls my-sysfs-view/input_touchpad/
> > capabilities/ event6/ modalias name power/
> > subsystem/ uniq
> > device/ id/ mouse1/ phys properties
> > uevent
> > [dtor@dtor-d630 ~]$ ls my-sysfs-view/input_touchpad/
> > capabilities device event6 id modalias mouse1 name phys power
> > properties subsystem uevent uniq
> > [dtor@dtor-d630 ~]$ ls my-sysfs-view/input_touchpad/event6/
> > dev device power subsystem uevent
> >
> > Mmmmkay?
> >
>
> Yes, agreed, we can use udev and soft links to achieve this.
> But i think there is something more to take care.
>
> So far, as per discussion, i understood that if an end user wants to use
> node names instead of numbers, he/she has to do the following things:
No, not the end user, system integrator, which is quite different
beast.
Re(2): (Aniroop Mathur)
Umm.. Sorry, i used wrong word "end user".
I meant to say "system integrator" only.
> 1. Create rules for all input devices in udev rule file i.e. set atleast
> unique id and unique name.
> (end user need to determine unique id too for every input device)
> 2. Create links for all input device nodes using names.
> (in probe function, after input_register_device)
>
> By following above two steps, the file structure will look like:
> devfs - /dev/input_proximity
> sysfs - my-sysfs-view/input_proximity --> sys/class/input/input2
> sysfs - my-sysfs-view/event_proximity --> sys/class/input/event2
>
> But my concern is why to create trouble for end user to perform
> and spend time for two extra steps, when an easy way is possible
> to achieve the same task ?
>
> With this patch, end user only need to set node_name_unique variable
> and right after that, both for devfs and sysfs,same node name is set.
> End user does not need to do or take care of any other extra work,
> like creating entry in udev rules, creating links, etc
>
> Also, with creating links for all input devices and checking udev rules
> before actually creating a device node, will only increase computation
> and time in kernel code.
So do not create links, use something else to track devices. You are
getting uevents, that is all you need.
Re(2): (Aniroop Mathur)
Firstly,
For input device event node, (/input/input1/event1)
we get below 7 uevents only:
Action, Devpath, Subsystem, Major, Minor, Devname, Seqnum
It is impossible to uniquely identify the device using
these 7 uevent variables, because all this is set in
input subsystem and not by driver developer or system integrator.
Devpath, Devname, minor is all set by input subsytem.
So, these uevents are not sufficient to identify the device.
Secondly,
For input device input node (/input/input1),
I know we get more uevents like Name, Phys, etc,
But problem area is not input node because that we can
already do this using dev_set_name(input_dev->dev) or
using init_name variable in driver code.
But evdev (event device) structure is not accessible to driver
so we cannot use the same for this.
Thirdly,
I know if these default uevents are not sufficient,
additionally, we can read sysfs attribute to identify device,
but as i already said, all this(udev rules or links),
will only increase computation time, and my purpose is to save time
and achieving the same task all together.
>
> My purpose is to avoid extra work load and directly create node names
> within input subsystem. Also backward compatibility is there.
> So i think, it is better than the other alternative way.
> Isn't this more easy ? Is there any side-effect or drawback of this patch ?
Yes, there is huge side effect - it is maintenance nightmare, where one
driver can now cause failure for others. What if I have 2 proximity
sensors? 2 accelerometers? How will generic drivers select names that
will satisfy all boards that might use the chips out there? Are you
proposing to put this data in device tree for example? Board files?
IOW no, this is not right solution and the patch will not be accepted.
Re:: (Aniroop Mathur)
Firstly,
Yes, i will put name of all input devices in one place i.e.
in board file or device tree. With this, it is very easy for system
integrator to assign unique names for all input devices.
Secondly,
As already mentioned, this patch is backward compatible.
It is not compulsory to use node_name_unique variable.
So generic drivers can still use the same numbering system.
Also, if there are two accelerometers, system integrator can
easily give "accelerometer1" and "accelerometer2" as names.
Moreover, this same problem is for existing kernel system also.
As you know, using dev_set_name function or init_name variable,
we can set name of input node(not event node). So, if same name
is used, device_add of that input device will fail here also
in existing kernel code.
Thirdly,
Using the existing init_name variable also, we can add naming convention
in input subystem. I can also submit patch using this variable already present
in kernel.
>
> >>
> >> Moreover, as i know, udev is mainly for hot-pluggable devices, but my
> >> problem is for platform devices, which are already present on the
> >> board during boot up. (Like in Embedded devices)
> >
> > No, udev also manages those by requesting to replay all events that
> > happened dyuring boot.
> >
> >>
> >> To avoid confusion and make the problem more clear,
> >> I would like to explain the problem and my suggestion by taking an example:
> >>
> >> Suppose in a mobile device, there are 10 embedded input devices as below:
> >> Proximity --- /dev/input0 --- /sys/class/input/input0 --- /sys/class/input/event0
> >> Magnetometer --- /dev/input1 --- /sys/class/input/input1 --- /sys/class/input/event1
> >> Accelerometer --- /dev/input2 --- /sys/class/input/input2 --- /sys/class/input/event2
> >> Touchscreen --- /dev/input3 --- /sys/class/input/input3 --- /sys/class/input/event3
> >> ... 6 more like this
> >> (All these are created during boot up time)
> >>
> >> Kernel has created all these nodes, so that HAL/UpperLayer can read or
> >> write values from it. HAL/Upper-Layer needs to do main tasks like:
> >> 1. Read raw data - does through /dev/input
> >> 2. Enable device - does through sys/class/input/enable
> >> 3. Set delay - does through sys/class/input/delay
> >> and many more...
> >>
> >> Now, Lets suppose we need to do these tasks for Accelerometer.
> >>
> >> If dev node name is set, HAL can directly read value from it (no
> >> search required) But for enabling the accelerometer device or set the
> >> delay of a hardware chip, there is no direct way, HAL can know which
> >> input node to refer for accelerometer because the input number is
> >> created dynamically as per device probe order, so this input number
> >> can be anything (0,1,2,3...) So HAL will need to search every input
> >> node and read its name attribute and keep on searching until a match
> >> is found between the "attribute name" and "name passed as parameter".
> >> Like for accelerometer, this searching needs to be done for all other
> >> input devices. All of this part is done during booting and this takes
> >> a lot for time from booting perspective.
> >>
> >
> > See the above. You can very easily create your own private 'view' of
> > sysfs, no kernel changes needed.
> >
> >> As I measured, if there are ten devices, it is taking 1 second to do
> >> all this searching. (for all devices) So for 20 devices, i guess, it
> >> could take upto 2 seconds.
> >
> > That seems _very_ high, maybe you need to profile your code a bit. To
> > search though 2 directories with less than a hundred files each should
> > not take 1 second.
> >
>
> In this i am including time to open a directory, close a directory, open file of
> that directory, close file of that directory, searching and computation part.
> Including all these, every time for each input device.
> All this sums upto 1 second.
Why are you doing it one at at time? It appears that this happens in
build at boot up for you...
Re:: (Aniroop Mathur)
Yes, this happenns at boot up of upper-layer.
Just as in kernel, probe of each device is
called by one by one, in upper-layer too, input device initialization
is done one by one in some order and input device number is searched.
So this is done every time.
Moreover, with naming convention, scanning is totally removed.
No need to scan/search even once.
>
> >>
> >> With naming convention, there is no need of search neither for dev
> >> path nor for sysfs path because HAL directly know which node to refer
> >> for which input device and hence this 1 second is reduced to 10ms or
> >> even less, therefore saving 990ms. I believe, this is a very good
> >> time saving. (from device booting perspective)
> >
> > OK, so create your own sysfs view and use it to do direct lookups.
> >
> >>
> >> (Is there any direct way, without scanning all nodes for every input
> >> device ?)
> >>
> >> >
> >> > 2. Improves Readabilty of input and event sysfs node paths because
> >> > names are used instead of numbers.
> >>
> >> I do not see why it is that important. If one wants overview
> >> /proc/bus/input/devices gives nice picture.
> >>
> >> Re: (Aniroop Mathur)
> >> Its correct, we can get an overview from /proc/bus/input/devices.
> >> And therefore using this, we can know input node number for every input device.
> >> But there are many input devices and input numbers are not fixed,
> >> so its quite difficult to memorize input number for all input devices.
> >> Therefore, if a user needs to open some input node from sysfs path,
> >> he needs to check /proc/bus/input/devices before opening because
> >> he does not know the input number. Moreover, this applies for all other
> >> input devices and hence a user need to check this every time.
> >>
> >> It improves readabilty as below
> >>
> >> Before: After patch:
> >> /dev/input0 /dev/input_proximity
> >> /dev/input1 /dev/input_accelerometer
> >> ...many more
> >>
> >> /sys/class/input/input0 /sys/class/input/input_proximity
> >> /sys/class/input/input1 /sys/class/input/input_accelerometer
> >> ...many more
> >>
> >> /sys/class/input/event0 /sys/class/input/event_proximity
> >> /sys/class/input/event1 /sys/class/input/event_accelerometer
> >> ...many more
> >>
> >> So, just by looking, user can directly open or refer any input node.
> >> (no need to refer any other path)
> >
> > User as in end user or your HAL layer?
> >
>
> End user.
Why would end user care? He wants his touchscreen to work, not fiddle
with its settings, And we aleady discussed what system integrator should
do.
Re:: (Aniroop Mathur)
Yeah, i meant system integrator only.
Sorry, not end user (i used wrong term).
System integrator or code developer cares for this.
>
> >>
> >> >
> >> > 3. Removes Input Devices Dependency. If one input device probe fails,
> >> > other input devices still work. Before this patch, if one input
> >> > device probe fails before input_register_device, then input number of
> >> > other input devices changes and due to this permission settings are
> >> > disturbed and hence HAL or upper layer cannot open the required sysfs
> >> > node because permission denied error comes.
> >>
> >> I have only one suggestion here: fix your userspace so that does not
> >> depend on device initialization ordering.
> >>
> >> Re: (Aniroop Mathur)
> >> We cannot fix userspace because these input/event/dev number are
> >> decided/allocated in kernel as per device initialization ordering
> >> during boot up. (userspace has no role in it) So, userspace is not
> >> aware, which exact input number corresponds to which input device so
> >> it ends up searching/scanning every input node untill a match is
> >> found.
> >>
> >> So, there is input device dependency which needs to be removed.
> >
> > Do not use numbers. We emit uevents describing the devices and there a
> > _lot_ of data there that helps identifying device, such as its path,
> > subsystem, name, etc.
> >
>
> Sorry, I am not able to understand this point with respect to removing input
> device dependency. Please elaborate a bit more.
Look at the data that is passed in uevents that are sent either when new
input device is created, or when you request replay of such evenst,
realize that it is enough to identify the device and stop relying on
inputX names to remain static. That's it.
Thanks.
--
Dmitry
Thanks,
Aniroop Mathur
^ permalink raw reply
* [PATCH] HID: i2c-hid: add runtime PM support
From: Mika Westerberg @ 2014-01-14 10:13 UTC (permalink / raw)
To: linux-input
Cc: Jiri Kosina, Benjamin Tissoires, linux-kernel, Mika Westerberg
This patch adds runtime PM support for the HID over I2C driver. When the
i2c-hid device is first opened we power it on and on the last close we
power it off.
The implementation is not the most power efficient because it needs some
interaction from the userspace (e.g close the device node whenever we are
no more interested in getting events), nevertheless it allows us to save
some power and works with devices that are not wake capable.
Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
drivers/hid/i2c-hid/i2c-hid.c | 81 ++++++++++++++++++++++++++++---------------
1 file changed, 54 insertions(+), 27 deletions(-)
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index d1f81f52481a..ff767d03d60e 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -25,6 +25,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/pm.h>
+#include <linux/pm_runtime.h>
#include <linux/device.h>
#include <linux/wait.h>
#include <linux/err.h>
@@ -454,10 +455,18 @@ static void i2c_hid_init_reports(struct hid_device *hid)
return;
}
+ /*
+ * The device must be powered on while we fetch initial reports
+ * from it.
+ */
+ pm_runtime_get_sync(&client->dev);
+
list_for_each_entry(report,
&hid->report_enum[HID_FEATURE_REPORT].report_list, list)
i2c_hid_init_report(report, inbuf, ihid->bufsize);
+ pm_runtime_put(&client->dev);
+
kfree(inbuf);
}
@@ -703,8 +712,8 @@ static int i2c_hid_open(struct hid_device *hid)
mutex_lock(&i2c_hid_open_mut);
if (!hid->open++) {
- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
- if (ret) {
+ ret = pm_runtime_get_sync(&client->dev);
+ if (ret < 0) {
hid->open--;
goto done;
}
@@ -712,7 +721,7 @@ static int i2c_hid_open(struct hid_device *hid)
}
done:
mutex_unlock(&i2c_hid_open_mut);
- return ret;
+ return ret < 0 ? ret : 0;
}
static void i2c_hid_close(struct hid_device *hid)
@@ -729,37 +738,17 @@ static void i2c_hid_close(struct hid_device *hid)
clear_bit(I2C_HID_STARTED, &ihid->flags);
/* Save some power */
- i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+ pm_runtime_put(&client->dev);
}
mutex_unlock(&i2c_hid_open_mut);
}
-static int i2c_hid_power(struct hid_device *hid, int lvl)
-{
- struct i2c_client *client = hid->driver_data;
- struct i2c_hid *ihid = i2c_get_clientdata(client);
- int ret = 0;
-
- i2c_hid_dbg(ihid, "%s lvl:%d\n", __func__, lvl);
-
- switch (lvl) {
- case PM_HINT_FULLON:
- ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
- break;
- case PM_HINT_NORMAL:
- ret = i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
- break;
- }
- return ret;
-}
-
static struct hid_ll_driver i2c_hid_ll_driver = {
.parse = i2c_hid_parse,
.start = i2c_hid_start,
.stop = i2c_hid_stop,
.open = i2c_hid_open,
.close = i2c_hid_close,
- .power = i2c_hid_power,
.request = i2c_hid_request,
};
@@ -973,13 +962,17 @@ static int i2c_hid_probe(struct i2c_client *client,
if (ret < 0)
goto err;
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+
ret = i2c_hid_fetch_hid_descriptor(ihid);
if (ret < 0)
- goto err;
+ goto err_pm;
ret = i2c_hid_init_irq(client);
if (ret < 0)
- goto err;
+ goto err_pm;
hid = hid_allocate_device();
if (IS_ERR(hid)) {
@@ -1010,6 +1003,7 @@ static int i2c_hid_probe(struct i2c_client *client,
goto err_mem_free;
}
+ pm_runtime_put(&client->dev);
return 0;
err_mem_free:
@@ -1018,6 +1012,10 @@ err_mem_free:
err_irq:
free_irq(client->irq, ihid);
+err_pm:
+ pm_runtime_put_noidle(&client->dev);
+ pm_runtime_disable(&client->dev);
+
err:
i2c_hid_free_buffers(ihid);
kfree(ihid);
@@ -1029,6 +1027,11 @@ static int i2c_hid_remove(struct i2c_client *client)
struct i2c_hid *ihid = i2c_get_clientdata(client);
struct hid_device *hid;
+ pm_runtime_get_sync(&client->dev);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
hid = ihid->hid;
hid_destroy_device(hid);
@@ -1074,7 +1077,31 @@ static int i2c_hid_resume(struct device *dev)
}
#endif
-static SIMPLE_DEV_PM_OPS(i2c_hid_pm, i2c_hid_suspend, i2c_hid_resume);
+#ifdef CONFIG_PM_RUNTIME
+static int i2c_hid_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+ disable_irq(client->irq);
+ return 0;
+}
+
+static int i2c_hid_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ enable_irq(client->irq);
+ i2c_hid_set_power(client, I2C_HID_PWR_ON);
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops i2c_hid_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(i2c_hid_suspend, i2c_hid_resume)
+ SET_RUNTIME_PM_OPS(i2c_hid_runtime_suspend, i2c_hid_runtime_resume,
+ NULL)
+};
static const struct i2c_device_id i2c_hid_id_table[] = {
{ "hid", 0 },
--
1.8.5.2
^ permalink raw reply related
* Re: [PATCH 4/4] Input: synaptics-rmi4 - switch to using i2c_transfer()
From: Christopher Heiny @ 2014-01-14 8:26 UTC (permalink / raw)
To: Dmitry Torokhov
Cc: Andrew Duggan, Vincent Huang, Vivian Ly, Daniel Rosenberg,
Linus Walleij, Benjamin Tissoires, Linux Input, Linux Kernel
In-Reply-To: <1389339867-8399-4-git-send-email-dmitry.torokhov@gmail.com>
On 01/09/2014 11:44 PM, Dmitry Torokhov wrote:
> Instead of using 2 separate transactions when reading from the device let's
> use i2c_transfer. Because we now have single point of failure I had to
> change how we collect statistics. I elected to drop control data from the
> stats and only track number of bytes read/written for the device data.
>
> Also, since we are not prepared to deal with short reads and writes change
> read_block_data and write_block_data to indicate error if we detect short
> transfers.
>
> Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
> ---
> drivers/input/rmi4/rmi_i2c.c | 71 ++++++++++++++++++++++++--------------------
> 1 file changed, 39 insertions(+), 32 deletions(-)
>
> diff --git a/drivers/input/rmi4/rmi_i2c.c b/drivers/input/rmi4/rmi_i2c.c
> index c176218..51f5bc8 100644
> --- a/drivers/input/rmi4/rmi_i2c.c
> +++ b/drivers/input/rmi4/rmi_i2c.c
> @@ -57,22 +57,17 @@ struct rmi_i2c_xport {
> */
> static int rmi_set_page(struct rmi_i2c_xport *rmi_i2c, u8 page)
> {
> - struct rmi_transport_dev *xport = &rmi_i2c->xport;
> struct i2c_client *client = rmi_i2c->client;
> u8 txbuf[2] = {RMI_PAGE_SELECT_REGISTER, page};
> int retval;
>
> - dev_dbg(&client->dev, "writes 3 bytes: %02x %02x\n",
> - txbuf[0], txbuf[1]);
> - xport->stats.tx_count++;
> - xport->stats.tx_bytes += sizeof(txbuf);
> retval = i2c_master_send(client, txbuf, sizeof(txbuf));
> if (retval != sizeof(txbuf)) {
> - xport->stats.tx_errs++;
> dev_err(&client->dev,
> "%s: set page failed: %d.", __func__, retval);
> return (retval < 0) ? retval : -EIO;
> }
> +
> rmi_i2c->page = page;
> return 0;
> }
> @@ -107,22 +102,27 @@ static int rmi_i2c_write_block(struct rmi_transport_dev *xport, u16 addr,
>
> if (RMI_I2C_PAGE(addr) != rmi_i2c->page) {
> retval = rmi_set_page(rmi_i2c, RMI_I2C_PAGE(addr));
> - if (retval < 0)
> + if (retval)
> goto exit;
> }
>
> + retval = i2c_master_send(client, rmi_i2c->tx_buf, tx_size);
> + if (retval == tx_size)
> + retval = 0;
> + else if (retval >= 0)
> + retval = -EIO;
> +
> +exit:
> dev_dbg(&client->dev,
> - "writes %zd bytes at %#06x: %*ph\n", len, addr, (int)len, buf);
> + "write %zd bytes at %#06x: %d (%*ph)\n",
> + len, addr, retval, (int)len, buf);
>
> xport->stats.tx_count++;
> - xport->stats.tx_bytes += tx_size;
> - retval = i2c_master_send(client, rmi_i2c->tx_buf, tx_size);
> - if (retval < 0)
> + if (retval)
> xport->stats.tx_errs++;
> else
> - retval--; /* don't count the address byte */
> + xport->stats.tx_bytes += len;
>
> -exit:
> mutex_unlock(&rmi_i2c->page_mutex);
> return retval;
> }
> @@ -133,40 +133,47 @@ static int rmi_i2c_read_block(struct rmi_transport_dev *xport, u16 addr,
> struct rmi_i2c_xport *rmi_i2c =
> container_of(xport, struct rmi_i2c_xport, xport);
> struct i2c_client *client = rmi_i2c->client;
> - u8 txbuf[1] = {addr & 0xff};
> + u8 addr_offset = addr & 0xff;
> int retval;
> + struct i2c_msg msgs[] = {
> + {
> + .addr = client->addr,
> + .len = sizeof(addr_offset),
> + .buf = &addr_offset,
> + },
> + {
> + .addr = client->addr,
> + .flags = I2C_M_RD,
> + .len = len,
> + .buf = buf,
> + },
> + };
>
> mutex_lock(&rmi_i2c->page_mutex);
>
> if (RMI_I2C_PAGE(addr) != rmi_i2c->page) {
> retval = rmi_set_page(rmi_i2c, RMI_I2C_PAGE(addr));
> - if (retval < 0)
> + if (retval)
> goto exit;
> }
>
> - dev_dbg(&client->dev, "writes 1 bytes: %02x\n", txbuf[0]);
> + retval = i2c_transfer(client->adapter, msgs, sizeof(msgs));
> + if (retval == sizeof(msgs))
I think this should be:
retval = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (retval == ARRAY_SIZE(msgs))
At least, that change resolved some random misbehaviors, including
kernel panics.
> + retval = 0; /* success */
> + else if (retval >= 0)
> + retval = -EIO;
>
> - xport->stats.tx_count++;
> - xport->stats.tx_bytes += sizeof(txbuf);
> - retval = i2c_master_send(client, txbuf, sizeof(txbuf));
> - if (retval != sizeof(txbuf)) {
> - xport->stats.tx_errs++;
> - retval = (retval < 0) ? retval : -EIO;
> - goto exit;
> - }
> +exit:
> + dev_dbg(&client->dev,
> + "read %zd bytes at %#06x: %d (%*ph)\n",
> + len, addr, retval, (int)len, buf);
>
> xport->stats.rx_count++;
> - xport->stats.rx_bytes += len;
> -
> - retval = i2c_master_recv(client, buf, len);
> - if (retval < 0)
> + if (retval)
> xport->stats.rx_errs++;
> else
> - dev_dbg(&client->dev,
> - "read %zd bytes at %#06x: %*ph\n",
> - len, addr, (int)len, buf);
> + xport->stats.rx_bytes += len;
>
> -exit:
> mutex_unlock(&rmi_i2c->page_mutex);
> return retval;
> }
>
--
Christopher Heiny
Senior Staff Firmware Engineer
Synaptics Incorporated
^ permalink raw reply
* Fwd: [PATCH] add support for ALPS v7 protocol device
From: Tommy Will @ 2014-01-14 6:11 UTC (permalink / raw)
To: Dylan Paul Thurston
Cc: Dmitry Torokhov, Kevin Cernekee, david turvene, Niels de Vos,
Justin Clift, Qiting Chen, Qiting Chen, linux-input
In-Reply-To: <CAKvfdt+SSis1f23j8E6ij9pjbCbWeVkGWZQq5P8kaiSA75DmQQ@mail.gmail.com>
Hi Dylan,
My colleague Elaine has prepared the patch for new ALPS touchpad that
being used on your HP Revolve 810 G1 laptop.
You can have a try~
--
Best Regards,
Tommy
---------- Forwarded message ----------
From: Elaine Chen <elaineee66@gmail.com>
Date: 2014/1/14
Subject: Re: [PATCH] add support for ALPS v7 protocol device
To: Dmitry Torokhov <dmitry.torokhov@gmail.com>, cernekee@gmail.com,
david turvene <dturvene@dahetral.com>
抄送: linux-input@vger.kernel.org, ndevos@redhat.com, jclift@redhat.com,
Qiting Chen <qiting.chen@cn.alps.com>
As far as I know, the ALPS v7 protocol device is used on following laptops:
Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> Here is the patch of supporting ALPS v7 protocol device.
>
> v7 device is a clickpad device.
> Device info:
> Device ID = 0x73, 0x03, 0x0a
> Firmware ID = 0x88, 0xb*, 0x**
>
> Support function of v7 device:
> - Cursor
> - Tap, double tap, tap drag, 2finger tap
> - Pan, pinch
> - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> Click touchpad with all fingers outside right Button Area --> left click
> Click touchpad with at lease 1 finger inside right Button Area --> right click
> - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
>
> The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> We tried registering our device as a clickpad by:
> set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
>
>
> Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> ---
> drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> drivers/input/mouse/alps.h | 127 ++++++++++--
> 2 files changed, 554 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index fb15c64..3e8e8f7 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -32,6 +32,11 @@
> #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> #define ALPS_REG_BASE_PINNACLE 0x0000
>
> +#define LEFT_BUTTON_BIT 0x01
> +#define RIGHT_BUTTON_BIT 0x02
> +
> +#define V7_LARGE_MOVEMENT 130
> +
> static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> 6-byte ALPS packet */
> +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
>
> static const struct alps_model_info alps_model_data[] = {
> { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> * isn't valid per PS/2 spec.
> */
>
> +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> + struct alps_abs_data *pt1)
> +{
> + int vect_x, vect_y;
> +
> + if (!pt0 || !pt1)
> + return 0;
> +
> + vect_x = pt0->x - pt1->x;
> + vect_y = pt0->y - pt1->y;
> +
> + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> +}
> +
> /* Packet formats are described in Documentation/input/alps.txt */
>
> static bool alps_is_valid_first_byte(struct alps_data *priv,
> @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> end_bit = y_msb - 1;
> box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> (2 * (priv->y_bits - 1));
> - *x1 = fields->x;
> - *y1 = fields->y;
> + *x1 = fields->pt.x;
> + *y1 = fields->pt.y;
> *x2 = 2 * box_middle_x - *x1;
> *y2 = 2 * box_middle_y - *y1;
> }
> @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> }
>
> +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct input_dev *dev;
> +
> + if (!psmouse || !f)
> + return;
> +
> + dev = psmouse->dev;
> +
> + if (f->fingers) {
> + input_report_key(dev, BTN_TOUCH, 1);
> + alps_report_semi_mt_data(dev, f->fingers,
> + f->pt_img[0].x, f->pt_img[0].y,
> + f->pt_img[1].x, f->pt_img[1].y);
> + input_mt_report_finger_count(dev, f->fingers);
> +
> + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> + } else {
> + input_report_key(dev, BTN_TOUCH, 0);
> + input_mt_report_finger_count(dev, 0);
> + input_report_abs(dev, ABS_PRESSURE, 0);
> + }
> +
> + input_report_key(dev, BTN_LEFT, f->btn.left);
> + input_report_key(dev, BTN_RIGHT, f->btn.right);
> +
> + input_sync(dev);
> +}
> +
> static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>
> static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> {
> - f->left = !!(p[3] & 0x01);
> - f->right = !!(p[3] & 0x02);
> - f->middle = !!(p[3] & 0x04);
> + f->btn.left = !!(p[3] & 0x01);
> + f->btn.right = !!(p[3] & 0x02);
> + f->btn.middle = !!(p[3] & 0x04);
>
> - f->ts_left = !!(p[3] & 0x10);
> - f->ts_right = !!(p[3] & 0x20);
> - f->ts_middle = !!(p[3] & 0x40);
> + f->btn.ts_left = !!(p[3] & 0x10);
> + f->btn.ts_right = !!(p[3] & 0x20);
> + f->btn.ts_middle = !!(p[3] & 0x40);
> }
>
> static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> ((p[2] & 0x7f) << 1) |
> (p[4] & 0x01);
>
> - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> ((p[0] & 0x30) >> 4);
> - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> - f->z = p[5] & 0x7f;
> + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> + f->pt.z = p[5] & 0x7f;
>
> alps_decode_buttons_v3(f, p);
> }
> @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> f->is_mp = !!(p[0] & 0x20);
>
> if (!f->is_mp) {
> - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> alps_decode_buttons_v3(f, p);
> } else {
> f->fingers = ((p[0] & 0x6) >> 1 |
> @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * with x, y, and z all zero, so these seem to be flukes.
> * Ignore them.
> */
> - if (f.x && f.y && !f.z)
> + if (f.pt.x && f.pt.y && !f.pt.z)
> return;
>
> /*
> @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * to rely on ST data.
> */
> if (!fingers) {
> - x1 = f.x;
> - y1 = f.y;
> - fingers = f.z > 0 ? 1 : 0;
> + x1 = f.pt.x;
> + y1 = f.pt.y;
> + fingers = f.pt.z > 0 ? 1 : 0;
> }
>
> - if (f.z >= 64)
> + if (f.pt.z >= 64)
> input_report_key(dev, BTN_TOUCH, 1);
> else
> input_report_key(dev, BTN_TOUCH, 0);
> @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>
> input_mt_report_finger_count(dev, fingers);
>
> - input_report_key(dev, BTN_LEFT, f.left);
> - input_report_key(dev, BTN_RIGHT, f.right);
> - input_report_key(dev, BTN_MIDDLE, f.middle);
> + input_report_key(dev, BTN_LEFT, f.btn.left);
> + input_report_key(dev, BTN_RIGHT, f.btn.right);
> + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>
> - if (f.z > 0) {
> - input_report_abs(dev, ABS_X, f.x);
> - input_report_abs(dev, ABS_Y, f.y);
> + if (f.pt.z > 0) {
> + input_report_abs(dev, ABS_X, f.pt.x);
> + input_report_abs(dev, ABS_Y, f.pt.y);
> }
> - input_report_abs(dev, ABS_PRESSURE, f.z);
> + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>
> input_sync(dev);
>
> if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> - input_report_key(dev2, BTN_LEFT, f.ts_left);
> - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> input_sync(dev2);
> }
> }
> @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> input_sync(dev);
> }
>
> +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> +{
> + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> + return false;
> + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> + return false;
> + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> + return false;
> + return true;
> +}
> +
> +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + int drop = 1;
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> + drop = 0;
> +
> + return drop;
> +}
> +
> +static unsigned char alps_get_packet_id_v7(char *byte)
> +{
> + unsigned char packet_id;
> +
> + if (byte[4] & 0x40)
> + packet_id = V7_PACKET_ID_TWO;
> + else if (byte[4] & 0x01)
> + packet_id = V7_PACKET_ID_MULTI;
> + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> + packet_id = V7_PACKET_ID_NEW;
> + else
> + packet_id = V7_PACKET_ID_IDLE;
> +
> + return packet_id;
> +}
> +
> +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> + unsigned char *pkt,
> + unsigned char pkt_id)
> +{
> + if ((pkt_id == V7_PACKET_ID_TWO) ||
> + (pkt_id == V7_PACKET_ID_MULTI) ||
> + (pkt_id == V7_PACKET_ID_NEW)) {
> + pt[0].x = ((pkt[2] & 0x80) << 4);
> + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> + pt[0].x |= (pkt[3] & 0x07);
> + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> +
> + pt[1].x = ((pkt[3] & 0x80) << 4);
> + pt[1].x |= ((pkt[4] & 0x80) << 3);
> + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> + pt[1].y = ((pkt[5] & 0x80) << 3);
> + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> +
> + if (pkt_id == V7_PACKET_ID_TWO) {
> + pt[1].x &= ~0x000F;
> + pt[1].y |= 0x000F;
> + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> + pt[1].x &= ~0x003F;
> + pt[1].y &= ~0x0020;
> + pt[1].y |= ((pkt[4] & 0x02) << 4);
> + pt[1].y |= 0x001F;
> + } else if (pkt_id == V7_PACKET_ID_NEW) {
> + pt[1].x &= ~0x003F;
> + pt[1].x |= (pkt[0] & 0x20);
> + pt[1].y |= 0x000F;
> + }
> +
> + pt[0].y = 0x7FF - pt[0].y;
> + pt[1].y = 0x7FF - pt[1].y;
> +
> + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> + }
> +}
> +
> +static void alps_decode_packet_v7(struct alps_fields *f,
> + unsigned char *p,
> + struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> +
> + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> +
> + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> +
> + priv->r.v7.rest_left = 0;
> + priv->r.v7.rest_right = 0;
> + priv->r.v7.additional_fingers = 0;
> + priv->phy_btn = 0;
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> + }
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> + priv->r.v7.additional_fingers = p[5] & 0x03;
> +
> + priv->phy_btn = (p[0] & 0x80) >> 7;
> +}
> +
> +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_abs_data *pt,
> + struct alps_bl_pt_attr *pt_attr)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned int dist;
> +
> + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> + pt_attr->is_init_pt_got = 1;
> + pt_attr->is_counted = 0;
> + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> + }
> +
> + if (pt->z != 0) {
> + if (pt->y < priv->resting_zone_y_min) {
> + /* A finger is recognized as a non-resting finger
> + if it's position is outside the resting finger zone.*/
> + pt_attr->zone = ZONE_NORMAL;
> + pt_attr->is_counted = 1;
> + } else {
> + /* A finger is recognized as a resting finger if it's
> + position is inside the resting finger zone and there's
> + no large movement from it's touch down position.*/
> + pt_attr->zone = ZONE_RESTING;
> +
> + if (pt->x > priv->x_max / 2)
> + pt_attr->zone |= ZONE_RIGHT_BTN;
> + else
> + pt_attr->zone |= ZONE_LEFT_BTN;
> +
> + /* A resting finger will turn to be a non-resting
> + finger if it has made large movement from it's touch
> + down position. A non-resting finger will never turn
> + to a resting finger before it leaves the touchpad
> + surface.*/
> + if (pt_attr->is_init_pt_got) {
> + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> +
> + if (dist > V7_LARGE_MOVEMENT)
> + pt_attr->is_counted = 1;
> + }
> + }
> + }
> +}
> +
> +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> + int i;
> +
> + switch (priv->r.v7.pkt_id) {
> + case V7_PACKET_ID_TWO:
> + case V7_PACKET_ID_MULTI:
> + for (i = 0; i < V7_IMG_PT_NUM; i++)
> + alps_set_each_pt_attr_v7(psmouse,
> + &f->pt_img[i],
> + &priv->pt_attr[i]);
> + break;
> + default:
> + /*All finger attributes are cleared when packet ID is
> + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> + indicates that there's no finger and no button activity.
> + A 'NEW' packet indicates the finger position in packet
> + is not continues from previous packet. Such as the
> + condition there's finger placed or lifted. In these cases,
> + finger attributes will be reset.*/
> + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> + break;
> + }
> +}
> +
> +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned int fn = 0;
> + int i;
> +
> + switch (priv->r.v7.pkt_id) {
> + case V7_PACKET_ID_IDLE:
> + case V7_PACKET_ID_NEW:
> + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> + An 'IDLE' packet indicates that there's no finger on touchpad.
> + A 'NEW' packet indicates there's finger placed or lifted.
> + Finger position of 'New' packet is not continues from the
> + previous packet.*/
> + fn = 0;
> + break;
> + case V7_PACKET_ID_TWO:
> + if (f->pt_img[0].z == 0) {
> + /*The first finger slot is zero when a non-resting
> + finger lifted and remaining only one resting finger
> + on touchpad. Hardware report the remaining resting
> + finger in second slot. This resting is ignored*/
> + fn = 0;
> + } else if (f->pt_img[1].z == 0) {
> + /* The second finger slot is zero if there's
> + only one finger*/
> + fn = 1;
> + } else {
> + /*All non-resting fingers will be counted to report*/
> + fn = 0;
> + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> + if (priv->pt_attr[i].is_counted)
> + fn++;
> + }
> +
> + /*In the case that both fingers are
> + resting fingers, report the first one*/
> + if (!priv->pt_attr[0].is_counted &&
> + !priv->pt_attr[1].is_counted) {
> + fn = 1;
> + }
> + }
> + break;
> + case V7_PACKET_ID_MULTI:
> + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> + finger exist.*/
> + fn = 3 + priv->r.v7.additional_fingers;
> + break;
> + }
> +
> + f->fingers = fn;
> +}
> +
> +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> +
> + if (priv->phy_btn) {
> + if (!priv->prev_phy_btn) {
> + /* Report a right click as long as there's finger on
> + right button zone. Othrewise, report a left click.*/
> + if (priv->r.v7.rest_right ||
> + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> + f->btn.right = 1;
> + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> + } else {
> + f->btn.left = 1;
> + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> + }
> + } else {
> + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> + f->btn.right = 1;
> + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> + f->btn.left = 1;
> + }
> + } else {
> + priv->pressed_btn_bits = 0;
> + f->btn.right = 0;
> + f->btn.left = 0;
> + }
> +
> + priv->prev_phy_btn = priv->phy_btn;
> +}
> +
> +static void alps_process_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + struct alps_fields f = {0};
> + unsigned char *packet = psmouse->packet;
> +
> + priv->decode_fields(&f, packet, psmouse);
> +
> + if (alps_drop_unsupported_packet_v7(psmouse))
> + return;
> +
> + alps_set_pt_attr_v7(psmouse, &f);
> +
> + alps_cal_output_finger_num_v7(psmouse, &f);
> +
> + alps_assign_buttons_v7(psmouse, &f);
> +
> + alps_report_coord_and_btn(psmouse, &f);
> +}
> +
> static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> unsigned char packet[],
> bool report_buttons)
> @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> return PSMOUSE_BAD_DATA;
> }
>
> + if ((priv->proto_version == ALPS_PROTO_V7 &&
> + !alps_is_valid_package_v7(psmouse))) {
> + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> + psmouse->pktcnt - 1,
> + psmouse->packet[psmouse->pktcnt - 1]);
> + return PSMOUSE_BAD_DATA;
> + }
> +
> if (psmouse->pktcnt == psmouse->pktsize) {
> priv->process_packet(psmouse);
> return PSMOUSE_FULL_PACKET;
> @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> return 0;
> }
>
> +static int alps_check_valid_firmware_id(unsigned char id[])
> +{
> + int valid = 1;
> +
> + if (id[0] == 0x73)
> + valid = 1;
> + else if (id[0] == 0x88) {
> + if ((id[1] == 0x07) ||
> + (id[1] == 0x08) ||
> + ((id[1] & 0xf0) == 0xB0))
> + valid = 1;
> + }
> +
> + return valid;
> +}
> +
> static int alps_enter_command_mode(struct psmouse *psmouse)
> {
> unsigned char param[4];
> @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> return -1;
> }
>
> - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> - param[0] != 0x73) {
> + if (!alps_check_valid_firmware_id(param)) {
> psmouse_dbg(psmouse,
> "unknown response while entering command mode\n");
> return -1;
> @@ -1704,6 +2067,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)
> {
> @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->set_abs_params = alps_set_abs_params_st;
> priv->x_max = 1023;
> priv->y_max = 767;
> + priv->slot_number = 1;
> break;
> case ALPS_PROTO_V3:
> priv->hw_init = alps_hw_init_v3;
> @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->decode_fields = alps_decode_pinnacle;
> priv->nibble_commands = alps_v3_nibble_commands;
> priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V4:
> priv->hw_init = alps_hw_init_v4;
> @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->set_abs_params = alps_set_abs_params_mt;
> priv->nibble_commands = alps_v4_nibble_commands;
> priv->addr_command = PSMOUSE_CMD_DISABLE;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V5:
> priv->hw_init = alps_hw_init_dolphin_v1;
> @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->y_max = 660;
> priv->x_bits = 23;
> priv->y_bits = 12;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V6:
> priv->hw_init = alps_hw_init_v6;
> @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->nibble_commands = alps_v6_nibble_commands;
> priv->x_max = 2047;
> priv->y_max = 1535;
> + priv->slot_number = 2;
> + break;
> + case ALPS_PROTO_V7:
> + priv->hw_init = alps_hw_init_v7;
> + priv->process_packet = alps_process_packet_v7;
> + priv->decode_fields = alps_decode_packet_v7;
> + priv->set_abs_params = alps_set_abs_params_mt;
> + priv->nibble_commands = alps_v3_nibble_commands;
> + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> + priv->x_max = 0xfff;
> + priv->y_max = 0x7ff;
> + priv->resting_zone_y_min = 0x654;
> + priv->byte0 = 0x48;
> + priv->mask0 = 0x48;
> + priv->flags = 0;
> + priv->slot_number = 2;
> break;
> }
> }
> @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> return -EIO;
> else
> return 0;
> + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> + priv->proto_version = ALPS_PROTO_V7;
> + alps_set_defaults(priv);
> +
> + return 0;
> } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> priv->proto_version = ALPS_PROTO_V3;
> alps_set_defaults(priv);
> @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> struct input_dev *dev1)
> {
> set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> - input_mt_init_slots(dev1, 2, 0);
> + input_mt_init_slots(dev1, priv->slot_number, 0);
> input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
>
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index 03f88b6..5d2f9ea 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,11 +18,36 @@
> #define ALPS_PROTO_V4 4
> #define ALPS_PROTO_V5 5
> #define ALPS_PROTO_V6 6
> +#define ALPS_PROTO_V7 7
> +
> +#define MAX_IMG_PT_NUM 5
> +#define V7_IMG_PT_NUM 2
> +
> +#define ZONE_NORMAL 0x01
> +#define ZONE_RESTING 0x02
> +#define ZONE_LEFT_BTN 0x04
> +#define ZONE_RIGHT_BTN 0x08
>
> #define DOLPHIN_COUNT_PER_ELECTRODE 64
> #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
>
> +/*
> + * enum V7_PACKET_ID - defines the packet type for V7
> + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> + * or there's button activities.
> + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> + * previous packet.
> +*/
> +enum V7_PACKET_ID {
> + V7_PACKET_ID_IDLE,
> + V7_PACKET_ID_TWO,
> + V7_PACKET_ID_MULTI,
> + V7_PACKET_ID_NEW,
> +};
> +
> /**
> * struct alps_model_info - touchpad ID table
> * @signature: E7 response string to match.
> @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> };
>
> /**
> - * struct alps_fields - decoded version of the report packet
> - * @x_map: Bitmap of active X positions for MT.
> - * @y_map: Bitmap of active Y positions for MT.
> - * @fingers: Number of fingers for MT.
> - * @x: X position for ST.
> - * @y: Y position for ST.
> - * @z: Z position for ST.
> - * @first_mp: Packet is the first of a multi-packet report.
> - * @is_mp: Packet is part of a multi-packet report.
> + * struct alps_btn - decoded version of the button status
> * @left: Left touchpad button is active.
> * @right: Right touchpad button is active.
> * @middle: Middle touchpad button is active.
> @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> * @ts_right: Right trackstick button is active.
> * @ts_middle: Middle trackstick button is active.
> */
> -struct alps_fields {
> - unsigned int x_map;
> - unsigned int y_map;
> - unsigned int fingers;
> - unsigned int x;
> - unsigned int y;
> - unsigned int z;
> - unsigned int first_mp:1;
> - unsigned int is_mp:1;
> -
> +struct alps_btn {
> unsigned int left:1;
> unsigned int right:1;
> unsigned int middle:1;
> @@ -102,6 +110,69 @@ struct alps_fields {
> };
>
> /**
> + * struct alps_btn - decoded version of the X Y Z postion for ST.
> + * @x: X position for ST.
> + * @y: Y position for ST.
> + * @z: Z position for ST.
> + */
> +struct alps_abs_data {
> + unsigned int x;
> + unsigned int y;
> + unsigned int z;
> +};
> +
> +/**
> + * struct alps_fields - decoded version of the report packet
> + * @fingers: Number of fingers for MT.
> + * @pt: X Y Z postion for ST.
> + * @pt: X Y Z postion for image MT.
> + * @x_map: Bitmap of active X positions for MT.
> + * @y_map: Bitmap of active Y positions for MT.
> + * @first_mp: Packet is the first of a multi-packet report.
> + * @is_mp: Packet is part of a multi-packet report.
> + * @btn: Button activity status
> + */
> +struct alps_fields {
> + unsigned int fingers;
> + struct alps_abs_data pt;
> + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> + unsigned int x_map;
> + unsigned int y_map;
> + unsigned int first_mp:1;
> + unsigned int is_mp:1;
> + struct alps_btn btn;
> +};
> +
> +/**
> + * struct v7_raw - data decoded from raw packet for V7.
> + * @pkt_id: An id that specifies the type of packet.
> + * @additional_fingers: Number of additional finger that is neighter included
> + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> + * @rest_left: There are fingers on left resting zone.
> + * @rest_right: There are fingers on right resting zone.
> + */
> +struct v7_raw {
> + unsigned char pkt_id;
> + unsigned int additional_fingers;
> + unsigned char rest_left;
> + unsigned char rest_right;
> +};
> +
> +/**
> + * 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;
> +};
> +
> +/**
> * struct alps_data - private data structure for the ALPS driver
> * @dev2: "Relative" device used to report trackstick or mouse activity.
> * @phys: Physical path for the relative device.
> @@ -116,8 +187,10 @@ struct alps_fields {
> * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> * @x_max: Largest possible X position value.
> * @y_max: Largest possible Y position value.
> + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> * @x_bits: Number of X bits in the MT bitmap.
> * @y_bits: Number of Y bits in the MT bitmap.
> + * @img_fingers: Number of image fingers.
> * @hw_init: Protocol-specific hardware init function.
> * @process_packet: Protocol-specific function to process a report packet.
> * @decode_fields: Protocol-specific function to read packet bitfields.
> @@ -132,6 +205,11 @@ struct alps_fields {
> * @fingers: Number of fingers from last MT report.
> * @quirks: Bitmap of ALPS_QUIRK_*.
> * @timer: Timer for flushing out the final report packet in the stream.
> + * @v7: Data decoded from raw packet for V7
> + * @phy_btn: Physical button is active.
> + * @prev_phy_btn: Physical button of previous packet is active.
> + * @pressed_btn_bits: Pressed positon of button zone
> + * @pt_attr: Generic attributes of touch points for buttonless device.
> */
> struct alps_data {
> struct input_dev *dev2;
> @@ -145,8 +223,10 @@ struct alps_data {
> unsigned char flags;
> int x_max;
> int y_max;
> + int resting_zone_y_min;
> int x_bits;
> int y_bits;
> + unsigned char slot_number;
>
> int (*hw_init)(struct psmouse *psmouse);
> void (*process_packet)(struct psmouse *psmouse);
> @@ -161,6 +241,15 @@ struct alps_data {
> int fingers;
> u8 quirks;
> struct timer_list timer;
> +
> + /* these are used for buttonless touchpad*/
> + union {
> + struct v7_raw v7;
> + } r;
> + unsigned char phy_btn;
> + unsigned char prev_phy_btn;
> + unsigned char pressed_btn_bits;
> + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> };
>
> #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> --
> 1.8.3.2
>
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] add support for ALPS v7 protocol device
From: Elaine Chen @ 2014-01-14 0:59 UTC (permalink / raw)
To: Dmitry Torokhov, cernekee, david turvene
Cc: linux-input, ndevos, jclift, Qiting Chen
In-Reply-To: <1389333218-31139-1-git-send-email-qiting.chen@cn.alps.com>
As far as I know, the ALPS v7 protocol device is used on following laptops:
Lenovo S430/S435/S530, Lenovo Z410/Z510, HP Odie, HP Revolve 810 G1
2014/1/10 Qiting Chen <elaineee66@gmail.com>:
> Here is the patch of supporting ALPS v7 protocol device.
>
> v7 device is a clickpad device.
> Device info:
> Device ID = 0x73, 0x03, 0x0a
> Firmware ID = 0x88, 0xb*, 0x**
>
> Support function of v7 device:
> - Cursor
> - Tap, double tap, tap drag, 2finger tap
> - Pan, pinch
> - Button click: v7 device has one physical button under the touchpad. A Button Area covers the bottom of touchpad. Clicking on Button Area produces button acitivities.
> Click touchpad with all fingers outside right Button Area --> left click
> Click touchpad with at lease 1 finger inside right Button Area --> right click
> - Resting finger function: Cursor and gestures won't be influenced with one finger placed still on Button Area.
>
> The resting finger process is in alps.c as it seems the latest xserver-xorg-input-synaptics(1.7.1) doesn't support that part.
> We tried registering our device as a clickpad by:
> set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit)
> But only button click can be correctly recognized. Yet a finger at Button Area won't be ignored while doing cursroing.
>
>
> Signed-off-by: Qiting Chen <qiting.chen@cn.alps.com>
> ---
> drivers/input/mouse/alps.c | 478 ++++++++++++++++++++++++++++++++++++++++++---
> drivers/input/mouse/alps.h | 127 ++++++++++--
> 2 files changed, 554 insertions(+), 51 deletions(-)
>
> diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
> index fb15c64..3e8e8f7 100644
> --- a/drivers/input/mouse/alps.c
> +++ b/drivers/input/mouse/alps.c
> @@ -32,6 +32,11 @@
> #define ALPS_REG_BASE_RUSHMORE 0xc2c0
> #define ALPS_REG_BASE_PINNACLE 0x0000
>
> +#define LEFT_BUTTON_BIT 0x01
> +#define RIGHT_BUTTON_BIT 0x02
> +
> +#define V7_LARGE_MOVEMENT 130
> +
> static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
> { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
> { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
> @@ -99,6 +104,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
> #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
> #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
> 6-byte ALPS packet */
> +#define ALPS_BTNLESS 0x100 /* ALPS ClickPad flag */
>
> static const struct alps_model_info alps_model_data[] = {
> { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
> @@ -140,6 +146,20 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> * isn't valid per PS/2 spec.
> */
>
> +static unsigned int alps_pt_distance(struct alps_abs_data *pt0,
> + struct alps_abs_data *pt1)
> +{
> + int vect_x, vect_y;
> +
> + if (!pt0 || !pt1)
> + return 0;
> +
> + vect_x = pt0->x - pt1->x;
> + vect_y = pt0->y - pt1->y;
> +
> + return int_sqrt(vect_x * vect_x + vect_y * vect_y);
> +}
> +
> /* Packet formats are described in Documentation/input/alps.txt */
>
> static bool alps_is_valid_first_byte(struct alps_data *priv,
> @@ -320,8 +340,8 @@ static void alps_process_bitmap_dolphin(struct alps_data *priv,
> end_bit = y_msb - 1;
> box_middle_y = (priv->y_max * (start_bit + end_bit)) /
> (2 * (priv->y_bits - 1));
> - *x1 = fields->x;
> - *y1 = fields->y;
> + *x1 = fields->pt.x;
> + *y1 = fields->pt.y;
> *x2 = 2 * box_middle_x - *x1;
> *y2 = 2 * box_middle_y - *y1;
> }
> @@ -461,6 +481,38 @@ static void alps_report_semi_mt_data(struct input_dev *dev, int num_fingers,
> alps_set_slot(dev, 1, num_fingers == 2, x2, y2);
> }
>
> +static void alps_report_coord_and_btn(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct input_dev *dev;
> +
> + if (!psmouse || !f)
> + return;
> +
> + dev = psmouse->dev;
> +
> + if (f->fingers) {
> + input_report_key(dev, BTN_TOUCH, 1);
> + alps_report_semi_mt_data(dev, f->fingers,
> + f->pt_img[0].x, f->pt_img[0].y,
> + f->pt_img[1].x, f->pt_img[1].y);
> + input_mt_report_finger_count(dev, f->fingers);
> +
> + input_report_abs(dev, ABS_X, f->pt_img[0].x);
> + input_report_abs(dev, ABS_Y, f->pt_img[0].y);
> + input_report_abs(dev, ABS_PRESSURE, f->pt_img[0].z);
> + } else {
> + input_report_key(dev, BTN_TOUCH, 0);
> + input_mt_report_finger_count(dev, 0);
> + input_report_abs(dev, ABS_PRESSURE, 0);
> + }
> +
> + input_report_key(dev, BTN_LEFT, f->btn.left);
> + input_report_key(dev, BTN_RIGHT, f->btn.right);
> +
> + input_sync(dev);
> +}
> +
> static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
> {
> struct alps_data *priv = psmouse->private;
> @@ -523,13 +575,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
>
> static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
> {
> - f->left = !!(p[3] & 0x01);
> - f->right = !!(p[3] & 0x02);
> - f->middle = !!(p[3] & 0x04);
> + f->btn.left = !!(p[3] & 0x01);
> + f->btn.right = !!(p[3] & 0x02);
> + f->btn.middle = !!(p[3] & 0x04);
>
> - f->ts_left = !!(p[3] & 0x10);
> - f->ts_right = !!(p[3] & 0x20);
> - f->ts_middle = !!(p[3] & 0x40);
> + f->btn.ts_left = !!(p[3] & 0x10);
> + f->btn.ts_right = !!(p[3] & 0x20);
> + f->btn.ts_middle = !!(p[3] & 0x40);
> }
>
> static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> @@ -546,10 +598,10 @@ static void alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
> ((p[2] & 0x7f) << 1) |
> (p[4] & 0x01);
>
> - f->x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> + f->pt.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
> ((p[0] & 0x30) >> 4);
> - f->y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> - f->z = p[5] & 0x7f;
> + f->pt.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
> + f->pt.z = p[5] & 0x7f;
>
> alps_decode_buttons_v3(f, p);
> }
> @@ -573,9 +625,9 @@ static void alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
> f->is_mp = !!(p[0] & 0x20);
>
> if (!f->is_mp) {
> - f->x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> - f->y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> - f->z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> + f->pt.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
> + f->pt.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
> + f->pt.z = (p[0] & 4) ? 0 : p[5] & 0x7f;
> alps_decode_buttons_v3(f, p);
> } else {
> f->fingers = ((p[0] & 0x6) >> 1 |
> @@ -687,7 +739,7 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * with x, y, and z all zero, so these seem to be flukes.
> * Ignore them.
> */
> - if (f.x && f.y && !f.z)
> + if (f.pt.x && f.pt.y && !f.pt.z)
> return;
>
> /*
> @@ -695,12 +747,12 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
> * to rely on ST data.
> */
> if (!fingers) {
> - x1 = f.x;
> - y1 = f.y;
> - fingers = f.z > 0 ? 1 : 0;
> + x1 = f.pt.x;
> + y1 = f.pt.y;
> + fingers = f.pt.z > 0 ? 1 : 0;
> }
>
> - if (f.z >= 64)
> + if (f.pt.z >= 64)
> input_report_key(dev, BTN_TOUCH, 1);
> else
> input_report_key(dev, BTN_TOUCH, 0);
> @@ -709,22 +761,22 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
>
> input_mt_report_finger_count(dev, fingers);
>
> - input_report_key(dev, BTN_LEFT, f.left);
> - input_report_key(dev, BTN_RIGHT, f.right);
> - input_report_key(dev, BTN_MIDDLE, f.middle);
> + input_report_key(dev, BTN_LEFT, f.btn.left);
> + input_report_key(dev, BTN_RIGHT, f.btn.right);
> + input_report_key(dev, BTN_MIDDLE, f.btn.middle);
>
> - if (f.z > 0) {
> - input_report_abs(dev, ABS_X, f.x);
> - input_report_abs(dev, ABS_Y, f.y);
> + if (f.pt.z > 0) {
> + input_report_abs(dev, ABS_X, f.pt.x);
> + input_report_abs(dev, ABS_Y, f.pt.y);
> }
> - input_report_abs(dev, ABS_PRESSURE, f.z);
> + input_report_abs(dev, ABS_PRESSURE, f.pt.z);
>
> input_sync(dev);
>
> if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
> - input_report_key(dev2, BTN_LEFT, f.ts_left);
> - input_report_key(dev2, BTN_RIGHT, f.ts_right);
> - input_report_key(dev2, BTN_MIDDLE, f.ts_middle);
> + input_report_key(dev2, BTN_LEFT, f.btn.ts_left);
> + input_report_key(dev2, BTN_RIGHT, f.btn.ts_right);
> + input_report_key(dev2, BTN_MIDDLE, f.btn.ts_middle);
> input_sync(dev2);
> }
> }
> @@ -916,6 +968,294 @@ static void alps_process_packet_v4(struct psmouse *psmouse)
> input_sync(dev);
> }
>
> +static bool alps_is_valid_package_v7(struct psmouse *psmouse)
> +{
> + if ((psmouse->pktcnt == 3) && ((psmouse->packet[2] & 0x40) != 0x40))
> + return false;
> + if ((psmouse->pktcnt == 4) && ((psmouse->packet[3] & 0x48) != 0x48))
> + return false;
> + if ((psmouse->pktcnt == 6) && ((psmouse->packet[5] & 0x40) != 0x0))
> + return false;
> + return true;
> +}
> +
> +static int alps_drop_unsupported_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + int drop = 1;
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_NEW ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_IDLE)
> + drop = 0;
> +
> + return drop;
> +}
> +
> +static unsigned char alps_get_packet_id_v7(char *byte)
> +{
> + unsigned char packet_id;
> +
> + if (byte[4] & 0x40)
> + packet_id = V7_PACKET_ID_TWO;
> + else if (byte[4] & 0x01)
> + packet_id = V7_PACKET_ID_MULTI;
> + else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
> + packet_id = V7_PACKET_ID_NEW;
> + else
> + packet_id = V7_PACKET_ID_IDLE;
> +
> + return packet_id;
> +}
> +
> +static void alps_get_finger_coordinate_v7(struct alps_abs_data *pt,
> + unsigned char *pkt,
> + unsigned char pkt_id)
> +{
> + if ((pkt_id == V7_PACKET_ID_TWO) ||
> + (pkt_id == V7_PACKET_ID_MULTI) ||
> + (pkt_id == V7_PACKET_ID_NEW)) {
> + pt[0].x = ((pkt[2] & 0x80) << 4);
> + pt[0].x |= ((pkt[2] & 0x3F) << 5);
> + pt[0].x |= ((pkt[3] & 0x30) >> 1);
> + pt[0].x |= (pkt[3] & 0x07);
> + pt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
> +
> + pt[1].x = ((pkt[3] & 0x80) << 4);
> + pt[1].x |= ((pkt[4] & 0x80) << 3);
> + pt[1].x |= ((pkt[4] & 0x3F) << 4);
> + pt[1].y = ((pkt[5] & 0x80) << 3);
> + pt[1].y |= ((pkt[5] & 0x3F) << 4);
> +
> + if (pkt_id == V7_PACKET_ID_TWO) {
> + pt[1].x &= ~0x000F;
> + pt[1].y |= 0x000F;
> + } else if (pkt_id == V7_PACKET_ID_MULTI) {
> + pt[1].x &= ~0x003F;
> + pt[1].y &= ~0x0020;
> + pt[1].y |= ((pkt[4] & 0x02) << 4);
> + pt[1].y |= 0x001F;
> + } else if (pkt_id == V7_PACKET_ID_NEW) {
> + pt[1].x &= ~0x003F;
> + pt[1].x |= (pkt[0] & 0x20);
> + pt[1].y |= 0x000F;
> + }
> +
> + pt[0].y = 0x7FF - pt[0].y;
> + pt[1].y = 0x7FF - pt[1].y;
> +
> + pt[0].z = (pt[0].x && pt[0].y) ? 62 : 0;
> + pt[1].z = (pt[1].x && pt[1].y) ? 62 : 0;
> + }
> +}
> +
> +static void alps_decode_packet_v7(struct alps_fields *f,
> + unsigned char *p,
> + struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> +
> + priv->r.v7.pkt_id = alps_get_packet_id_v7(p);
> +
> + alps_get_finger_coordinate_v7(f->pt_img, p, priv->r.v7.pkt_id);
> +
> + priv->r.v7.rest_left = 0;
> + priv->r.v7.rest_right = 0;
> + priv->r.v7.additional_fingers = 0;
> + priv->phy_btn = 0;
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_TWO ||
> + priv->r.v7.pkt_id == V7_PACKET_ID_MULTI) {
> + priv->r.v7.rest_left = (p[0] & 0x10) >> 4;
> + priv->r.v7.rest_right = (p[0] & 0x20) >> 5;
> + }
> +
> + if (priv->r.v7.pkt_id == V7_PACKET_ID_MULTI)
> + priv->r.v7.additional_fingers = p[5] & 0x03;
> +
> + priv->phy_btn = (p[0] & 0x80) >> 7;
> +}
> +
> +static void alps_set_each_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_abs_data *pt,
> + struct alps_bl_pt_attr *pt_attr)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned int dist;
> +
> + if (!pt_attr->is_init_pt_got && pt->z != 0) {
> + pt_attr->is_init_pt_got = 1;
> + pt_attr->is_counted = 0;
> + memcpy(&pt_attr->init_pt, pt, sizeof(pt_attr->init_pt));
> + }
> +
> + if (pt->z != 0) {
> + if (pt->y < priv->resting_zone_y_min) {
> + /* A finger is recognized as a non-resting finger
> + if it's position is outside the resting finger zone.*/
> + pt_attr->zone = ZONE_NORMAL;
> + pt_attr->is_counted = 1;
> + } else {
> + /* A finger is recognized as a resting finger if it's
> + position is inside the resting finger zone and there's
> + no large movement from it's touch down position.*/
> + pt_attr->zone = ZONE_RESTING;
> +
> + if (pt->x > priv->x_max / 2)
> + pt_attr->zone |= ZONE_RIGHT_BTN;
> + else
> + pt_attr->zone |= ZONE_LEFT_BTN;
> +
> + /* A resting finger will turn to be a non-resting
> + finger if it has made large movement from it's touch
> + down position. A non-resting finger will never turn
> + to a resting finger before it leaves the touchpad
> + surface.*/
> + if (pt_attr->is_init_pt_got) {
> + dist = alps_pt_distance(pt, &pt_attr->init_pt);
> +
> + if (dist > V7_LARGE_MOVEMENT)
> + pt_attr->is_counted = 1;
> + }
> + }
> + }
> +}
> +
> +static void alps_set_pt_attr_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> + int i;
> +
> + switch (priv->r.v7.pkt_id) {
> + case V7_PACKET_ID_TWO:
> + case V7_PACKET_ID_MULTI:
> + for (i = 0; i < V7_IMG_PT_NUM; i++)
> + alps_set_each_pt_attr_v7(psmouse,
> + &f->pt_img[i],
> + &priv->pt_attr[i]);
> + break;
> + default:
> + /*All finger attributes are cleared when packet ID is
> + 'IDLE', 'New'or other unknown IDs. An 'IDLE' packet
> + indicates that there's no finger and no button activity.
> + A 'NEW' packet indicates the finger position in packet
> + is not continues from previous packet. Such as the
> + condition there's finger placed or lifted. In these cases,
> + finger attributes will be reset.*/
> + memset(priv->pt_attr, 0, sizeof(priv->pt_attr[0]) * 2);
> + break;
> + }
> +}
> +
> +static void alps_cal_output_finger_num_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> + unsigned int fn = 0;
> + int i;
> +
> + switch (priv->r.v7.pkt_id) {
> + case V7_PACKET_ID_IDLE:
> + case V7_PACKET_ID_NEW:
> + /*No finger is reported when packet ID is 'IDLE' or 'New'.
> + An 'IDLE' packet indicates that there's no finger on touchpad.
> + A 'NEW' packet indicates there's finger placed or lifted.
> + Finger position of 'New' packet is not continues from the
> + previous packet.*/
> + fn = 0;
> + break;
> + case V7_PACKET_ID_TWO:
> + if (f->pt_img[0].z == 0) {
> + /*The first finger slot is zero when a non-resting
> + finger lifted and remaining only one resting finger
> + on touchpad. Hardware report the remaining resting
> + finger in second slot. This resting is ignored*/
> + fn = 0;
> + } else if (f->pt_img[1].z == 0) {
> + /* The second finger slot is zero if there's
> + only one finger*/
> + fn = 1;
> + } else {
> + /*All non-resting fingers will be counted to report*/
> + fn = 0;
> + for (i = 0; i < V7_IMG_PT_NUM; i++) {
> + if (priv->pt_attr[i].is_counted)
> + fn++;
> + }
> +
> + /*In the case that both fingers are
> + resting fingers, report the first one*/
> + if (!priv->pt_attr[0].is_counted &&
> + !priv->pt_attr[1].is_counted) {
> + fn = 1;
> + }
> + }
> + break;
> + case V7_PACKET_ID_MULTI:
> + /*A packet ID 'MULTI' indicats that at least 3 non-resting
> + finger exist.*/
> + fn = 3 + priv->r.v7.additional_fingers;
> + break;
> + }
> +
> + f->fingers = fn;
> +}
> +
> +static void alps_assign_buttons_v7(struct psmouse *psmouse,
> + struct alps_fields *f)
> +{
> + struct alps_data *priv = psmouse->private;
> +
> + if (priv->phy_btn) {
> + if (!priv->prev_phy_btn) {
> + /* Report a right click as long as there's finger on
> + right button zone. Othrewise, report a left click.*/
> + if (priv->r.v7.rest_right ||
> + priv->pt_attr[0].zone & ZONE_RIGHT_BTN ||
> + priv->pt_attr[1].zone & ZONE_RIGHT_BTN) {
> + f->btn.right = 1;
> + priv->pressed_btn_bits |= RIGHT_BUTTON_BIT;
> + } else {
> + f->btn.left = 1;
> + priv->pressed_btn_bits |= LEFT_BUTTON_BIT;
> + }
> + } else {
> + if (priv->pressed_btn_bits & RIGHT_BUTTON_BIT)
> + f->btn.right = 1;
> + if (priv->pressed_btn_bits & LEFT_BUTTON_BIT)
> + f->btn.left = 1;
> + }
> + } else {
> + priv->pressed_btn_bits = 0;
> + f->btn.right = 0;
> + f->btn.left = 0;
> + }
> +
> + priv->prev_phy_btn = priv->phy_btn;
> +}
> +
> +static void alps_process_packet_v7(struct psmouse *psmouse)
> +{
> + struct alps_data *priv = psmouse->private;
> + struct alps_fields f = {0};
> + unsigned char *packet = psmouse->packet;
> +
> + priv->decode_fields(&f, packet, psmouse);
> +
> + if (alps_drop_unsupported_packet_v7(psmouse))
> + return;
> +
> + alps_set_pt_attr_v7(psmouse, &f);
> +
> + alps_cal_output_finger_num_v7(psmouse, &f);
> +
> + alps_assign_buttons_v7(psmouse, &f);
> +
> + alps_report_coord_and_btn(psmouse, &f);
> +}
> +
> static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
> unsigned char packet[],
> bool report_buttons)
> @@ -1080,6 +1420,14 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
> return PSMOUSE_BAD_DATA;
> }
>
> + if ((priv->proto_version == ALPS_PROTO_V7 &&
> + !alps_is_valid_package_v7(psmouse))) {
> + psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
> + psmouse->pktcnt - 1,
> + psmouse->packet[psmouse->pktcnt - 1]);
> + return PSMOUSE_BAD_DATA;
> + }
> +
> if (psmouse->pktcnt == psmouse->pktsize) {
> priv->process_packet(psmouse);
> return PSMOUSE_FULL_PACKET;
> @@ -1192,6 +1540,22 @@ static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
> return 0;
> }
>
> +static int alps_check_valid_firmware_id(unsigned char id[])
> +{
> + int valid = 1;
> +
> + if (id[0] == 0x73)
> + valid = 1;
> + else if (id[0] == 0x88) {
> + if ((id[1] == 0x07) ||
> + (id[1] == 0x08) ||
> + ((id[1] & 0xf0) == 0xB0))
> + valid = 1;
> + }
> +
> + return valid;
> +}
> +
> static int alps_enter_command_mode(struct psmouse *psmouse)
> {
> unsigned char param[4];
> @@ -1201,8 +1565,7 @@ static int alps_enter_command_mode(struct psmouse *psmouse)
> return -1;
> }
>
> - if ((param[0] != 0x88 || (param[1] != 0x07 && param[1] != 0x08)) &&
> - param[0] != 0x73) {
> + if (!alps_check_valid_firmware_id(param)) {
> psmouse_dbg(psmouse,
> "unknown response while entering command mode\n");
> return -1;
> @@ -1704,6 +2067,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)
> {
> @@ -1875,6 +2264,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->set_abs_params = alps_set_abs_params_st;
> priv->x_max = 1023;
> priv->y_max = 767;
> + priv->slot_number = 1;
> break;
> case ALPS_PROTO_V3:
> priv->hw_init = alps_hw_init_v3;
> @@ -1883,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->decode_fields = alps_decode_pinnacle;
> priv->nibble_commands = alps_v3_nibble_commands;
> priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V4:
> priv->hw_init = alps_hw_init_v4;
> @@ -1890,6 +2281,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->set_abs_params = alps_set_abs_params_mt;
> priv->nibble_commands = alps_v4_nibble_commands;
> priv->addr_command = PSMOUSE_CMD_DISABLE;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V5:
> priv->hw_init = alps_hw_init_dolphin_v1;
> @@ -1905,6 +2297,7 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->y_max = 660;
> priv->x_bits = 23;
> priv->y_bits = 12;
> + priv->slot_number = 2;
> break;
> case ALPS_PROTO_V6:
> priv->hw_init = alps_hw_init_v6;
> @@ -1913,6 +2306,22 @@ static void alps_set_defaults(struct alps_data *priv)
> priv->nibble_commands = alps_v6_nibble_commands;
> priv->x_max = 2047;
> priv->y_max = 1535;
> + priv->slot_number = 2;
> + break;
> + case ALPS_PROTO_V7:
> + priv->hw_init = alps_hw_init_v7;
> + priv->process_packet = alps_process_packet_v7;
> + priv->decode_fields = alps_decode_packet_v7;
> + priv->set_abs_params = alps_set_abs_params_mt;
> + priv->nibble_commands = alps_v3_nibble_commands;
> + priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
> + priv->x_max = 0xfff;
> + priv->y_max = 0x7ff;
> + priv->resting_zone_y_min = 0x654;
> + priv->byte0 = 0x48;
> + priv->mask0 = 0x48;
> + priv->flags = 0;
> + priv->slot_number = 2;
> break;
> }
> }
> @@ -1982,6 +2391,11 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
> return -EIO;
> else
> return 0;
> + } else if (ec[0] == 0x88 && (ec[1] & 0xf0) == 0xB0) {
> + priv->proto_version = ALPS_PROTO_V7;
> + alps_set_defaults(priv);
> +
> + return 0;
> } else if (ec[0] == 0x88 && ec[1] == 0x08) {
> priv->proto_version = ALPS_PROTO_V3;
> alps_set_defaults(priv);
> @@ -2045,7 +2459,7 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
> struct input_dev *dev1)
> {
> set_bit(INPUT_PROP_SEMI_MT, dev1->propbit);
> - input_mt_init_slots(dev1, 2, 0);
> + input_mt_init_slots(dev1, priv->slot_number, 0);
> input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
> input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
>
> diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
> index 03f88b6..5d2f9ea 100644
> --- a/drivers/input/mouse/alps.h
> +++ b/drivers/input/mouse/alps.h
> @@ -18,11 +18,36 @@
> #define ALPS_PROTO_V4 4
> #define ALPS_PROTO_V5 5
> #define ALPS_PROTO_V6 6
> +#define ALPS_PROTO_V7 7
> +
> +#define MAX_IMG_PT_NUM 5
> +#define V7_IMG_PT_NUM 2
> +
> +#define ZONE_NORMAL 0x01
> +#define ZONE_RESTING 0x02
> +#define ZONE_LEFT_BTN 0x04
> +#define ZONE_RIGHT_BTN 0x08
>
> #define DOLPHIN_COUNT_PER_ELECTRODE 64
> #define DOLPHIN_PROFILE_XOFFSET 8 /* x-electrode offset */
> #define DOLPHIN_PROFILE_YOFFSET 1 /* y-electrode offset */
>
> +/*
> + * enum V7_PACKET_ID - defines the packet type for V7
> + * V7_PACKET_ID_IDLE: There's no finger and no button activity.
> + * V7_PACKET_ID_TWO: There's one or two non-resting fingers on touchpad
> + * or there's button activities.
> + * V7_PACKET_ID_MULTI: There are at least three non-resting fingers.
> + * V7_PACKET_ID_NEW: The finger position in slot is not continues from
> + * previous packet.
> +*/
> +enum V7_PACKET_ID {
> + V7_PACKET_ID_IDLE,
> + V7_PACKET_ID_TWO,
> + V7_PACKET_ID_MULTI,
> + V7_PACKET_ID_NEW,
> +};
> +
> /**
> * struct alps_model_info - touchpad ID table
> * @signature: E7 response string to match.
> @@ -66,15 +91,7 @@ struct alps_nibble_commands {
> };
>
> /**
> - * struct alps_fields - decoded version of the report packet
> - * @x_map: Bitmap of active X positions for MT.
> - * @y_map: Bitmap of active Y positions for MT.
> - * @fingers: Number of fingers for MT.
> - * @x: X position for ST.
> - * @y: Y position for ST.
> - * @z: Z position for ST.
> - * @first_mp: Packet is the first of a multi-packet report.
> - * @is_mp: Packet is part of a multi-packet report.
> + * struct alps_btn - decoded version of the button status
> * @left: Left touchpad button is active.
> * @right: Right touchpad button is active.
> * @middle: Middle touchpad button is active.
> @@ -82,16 +99,7 @@ struct alps_nibble_commands {
> * @ts_right: Right trackstick button is active.
> * @ts_middle: Middle trackstick button is active.
> */
> -struct alps_fields {
> - unsigned int x_map;
> - unsigned int y_map;
> - unsigned int fingers;
> - unsigned int x;
> - unsigned int y;
> - unsigned int z;
> - unsigned int first_mp:1;
> - unsigned int is_mp:1;
> -
> +struct alps_btn {
> unsigned int left:1;
> unsigned int right:1;
> unsigned int middle:1;
> @@ -102,6 +110,69 @@ struct alps_fields {
> };
>
> /**
> + * struct alps_btn - decoded version of the X Y Z postion for ST.
> + * @x: X position for ST.
> + * @y: Y position for ST.
> + * @z: Z position for ST.
> + */
> +struct alps_abs_data {
> + unsigned int x;
> + unsigned int y;
> + unsigned int z;
> +};
> +
> +/**
> + * struct alps_fields - decoded version of the report packet
> + * @fingers: Number of fingers for MT.
> + * @pt: X Y Z postion for ST.
> + * @pt: X Y Z postion for image MT.
> + * @x_map: Bitmap of active X positions for MT.
> + * @y_map: Bitmap of active Y positions for MT.
> + * @first_mp: Packet is the first of a multi-packet report.
> + * @is_mp: Packet is part of a multi-packet report.
> + * @btn: Button activity status
> + */
> +struct alps_fields {
> + unsigned int fingers;
> + struct alps_abs_data pt;
> + struct alps_abs_data pt_img[MAX_IMG_PT_NUM];
> + unsigned int x_map;
> + unsigned int y_map;
> + unsigned int first_mp:1;
> + unsigned int is_mp:1;
> + struct alps_btn btn;
> +};
> +
> +/**
> + * struct v7_raw - data decoded from raw packet for V7.
> + * @pkt_id: An id that specifies the type of packet.
> + * @additional_fingers: Number of additional finger that is neighter included
> + * in pt slot nor reflected in rest_left and rest_right flag of data packet.
> + * @rest_left: There are fingers on left resting zone.
> + * @rest_right: There are fingers on right resting zone.
> + */
> +struct v7_raw {
> + unsigned char pkt_id;
> + unsigned int additional_fingers;
> + unsigned char rest_left;
> + unsigned char rest_right;
> +};
> +
> +/**
> + * 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;
> +};
> +
> +/**
> * struct alps_data - private data structure for the ALPS driver
> * @dev2: "Relative" device used to report trackstick or mouse activity.
> * @phys: Physical path for the relative device.
> @@ -116,8 +187,10 @@ struct alps_fields {
> * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
> * @x_max: Largest possible X position value.
> * @y_max: Largest possible Y position value.
> + * @resting_zone_y_min: Smallest Y postion value of the bottom resting zone.
> * @x_bits: Number of X bits in the MT bitmap.
> * @y_bits: Number of Y bits in the MT bitmap.
> + * @img_fingers: Number of image fingers.
> * @hw_init: Protocol-specific hardware init function.
> * @process_packet: Protocol-specific function to process a report packet.
> * @decode_fields: Protocol-specific function to read packet bitfields.
> @@ -132,6 +205,11 @@ struct alps_fields {
> * @fingers: Number of fingers from last MT report.
> * @quirks: Bitmap of ALPS_QUIRK_*.
> * @timer: Timer for flushing out the final report packet in the stream.
> + * @v7: Data decoded from raw packet for V7
> + * @phy_btn: Physical button is active.
> + * @prev_phy_btn: Physical button of previous packet is active.
> + * @pressed_btn_bits: Pressed positon of button zone
> + * @pt_attr: Generic attributes of touch points for buttonless device.
> */
> struct alps_data {
> struct input_dev *dev2;
> @@ -145,8 +223,10 @@ struct alps_data {
> unsigned char flags;
> int x_max;
> int y_max;
> + int resting_zone_y_min;
> int x_bits;
> int y_bits;
> + unsigned char slot_number;
>
> int (*hw_init)(struct psmouse *psmouse);
> void (*process_packet)(struct psmouse *psmouse);
> @@ -161,6 +241,15 @@ struct alps_data {
> int fingers;
> u8 quirks;
> struct timer_list timer;
> +
> + /* these are used for buttonless touchpad*/
> + union {
> + struct v7_raw v7;
> + } r;
> + unsigned char phy_btn;
> + unsigned char prev_phy_btn;
> + unsigned char pressed_btn_bits;
> + struct alps_bl_pt_attr pt_attr[MAX_IMG_PT_NUM];
> };
>
> #define ALPS_QUIRK_TRACKSTICK_BUTTONS 1 /* trakcstick buttons in trackstick packet */
> --
> 1.8.3.2
>
^ 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