1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * ALPS touchpad PS/2 mouse driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
6*4882a593Smuzhiyun * Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
7*4882a593Smuzhiyun * Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
8*4882a593Smuzhiyun * Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
9*4882a593Smuzhiyun * Copyright (c) 2009 Sebastian Kapfer <sebastian_kapfer@gmx.net>
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * ALPS detection, tap switching and status querying info is taken from
12*4882a593Smuzhiyun * tpconfig utility (by C. Scott Ananian and Bruce Kall).
13*4882a593Smuzhiyun */
14*4882a593Smuzhiyun
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/input.h>
17*4882a593Smuzhiyun #include <linux/input/mt.h>
18*4882a593Smuzhiyun #include <linux/serio.h>
19*4882a593Smuzhiyun #include <linux/libps2.h>
20*4882a593Smuzhiyun #include <linux/dmi.h>
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun #include "psmouse.h"
23*4882a593Smuzhiyun #include "alps.h"
24*4882a593Smuzhiyun #include "trackpoint.h"
25*4882a593Smuzhiyun
26*4882a593Smuzhiyun /*
27*4882a593Smuzhiyun * Definitions for ALPS version 3 and 4 command mode protocol
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun #define ALPS_CMD_NIBBLE_10 0x01f2
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #define ALPS_REG_BASE_RUSHMORE 0xc2c0
32*4882a593Smuzhiyun #define ALPS_REG_BASE_V7 0xc2c0
33*4882a593Smuzhiyun #define ALPS_REG_BASE_PINNACLE 0x0000
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun static const struct alps_nibble_commands alps_v3_nibble_commands[] = {
36*4882a593Smuzhiyun { PSMOUSE_CMD_SETPOLL, 0x00 }, /* 0 */
37*4882a593Smuzhiyun { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
38*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
39*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
40*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
41*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
42*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
43*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
44*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
45*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
46*4882a593Smuzhiyun { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
47*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
48*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
49*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
50*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
51*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
52*4882a593Smuzhiyun };
53*4882a593Smuzhiyun
54*4882a593Smuzhiyun static const struct alps_nibble_commands alps_v4_nibble_commands[] = {
55*4882a593Smuzhiyun { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
56*4882a593Smuzhiyun { PSMOUSE_CMD_RESET_DIS, 0x00 }, /* 1 */
57*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* 2 */
58*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x0a }, /* 3 */
59*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x14 }, /* 4 */
60*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x28 }, /* 5 */
61*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x3c }, /* 6 */
62*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x50 }, /* 7 */
63*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x64 }, /* 8 */
64*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 9 */
65*4882a593Smuzhiyun { ALPS_CMD_NIBBLE_10, 0x00 }, /* a */
66*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x00 }, /* b */
67*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x01 }, /* c */
68*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x02 }, /* d */
69*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x03 }, /* e */
70*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
74*4882a593Smuzhiyun { PSMOUSE_CMD_ENABLE, 0x00 }, /* 0 */
75*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x0a }, /* 1 */
76*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x14 }, /* 2 */
77*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x28 }, /* 3 */
78*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x3c }, /* 4 */
79*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x50 }, /* 5 */
80*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0x64 }, /* 6 */
81*4882a593Smuzhiyun { PSMOUSE_CMD_SETRATE, 0xc8 }, /* 7 */
82*4882a593Smuzhiyun { PSMOUSE_CMD_GETID, 0x00 }, /* 8 */
83*4882a593Smuzhiyun { PSMOUSE_CMD_GETINFO, 0x00 }, /* 9 */
84*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x00 }, /* a */
85*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x01 }, /* b */
86*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x02 }, /* c */
87*4882a593Smuzhiyun { PSMOUSE_CMD_SETRES, 0x03 }, /* d */
88*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE21, 0x00 }, /* e */
89*4882a593Smuzhiyun { PSMOUSE_CMD_SETSCALE11, 0x00 }, /* f */
90*4882a593Smuzhiyun };
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun
93*4882a593Smuzhiyun #define ALPS_DUALPOINT 0x02 /* touchpad has trackstick */
94*4882a593Smuzhiyun #define ALPS_PASS 0x04 /* device has a pass-through port */
95*4882a593Smuzhiyun
96*4882a593Smuzhiyun #define ALPS_WHEEL 0x08 /* hardware wheel present */
97*4882a593Smuzhiyun #define ALPS_FW_BK_1 0x10 /* front & back buttons present */
98*4882a593Smuzhiyun #define ALPS_FW_BK_2 0x20 /* front & back buttons present */
99*4882a593Smuzhiyun #define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
100*4882a593Smuzhiyun #define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
101*4882a593Smuzhiyun 6-byte ALPS packet */
102*4882a593Smuzhiyun #define ALPS_STICK_BITS 0x100 /* separate stick button bits */
103*4882a593Smuzhiyun #define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
104*4882a593Smuzhiyun #define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */
105*4882a593Smuzhiyun
106*4882a593Smuzhiyun static const struct alps_model_info alps_model_data[] = {
107*4882a593Smuzhiyun /*
108*4882a593Smuzhiyun * XXX This entry is suspicious. First byte has zero lower nibble,
109*4882a593Smuzhiyun * which is what a normal mouse would report. Also, the value 0x0e
110*4882a593Smuzhiyun * isn't valid per PS/2 spec.
111*4882a593Smuzhiyun */
112*4882a593Smuzhiyun { { 0x20, 0x02, 0x0e }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun { { 0x22, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
115*4882a593Smuzhiyun { { 0x22, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */
116*4882a593Smuzhiyun { { 0x32, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */
117*4882a593Smuzhiyun { { 0x33, 0x02, 0x0a }, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */
118*4882a593Smuzhiyun { { 0x52, 0x01, 0x14 }, { ALPS_PROTO_V2, 0xff, 0xff,
119*4882a593Smuzhiyun ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */
120*4882a593Smuzhiyun { { 0x53, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
121*4882a593Smuzhiyun { { 0x53, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
122*4882a593Smuzhiyun { { 0x60, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */
123*4882a593Smuzhiyun { { 0x62, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xcf, 0xcf,
124*4882a593Smuzhiyun ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Dell Latitude E5500, E6400, E6500, Precision M4400 */
125*4882a593Smuzhiyun { { 0x63, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
126*4882a593Smuzhiyun { { 0x63, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
127*4882a593Smuzhiyun { { 0x63, 0x02, 0x28 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */
128*4882a593Smuzhiyun { { 0x63, 0x02, 0x3c }, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */
129*4882a593Smuzhiyun { { 0x63, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */
130*4882a593Smuzhiyun { { 0x63, 0x02, 0x64 }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
131*4882a593Smuzhiyun { { 0x63, 0x03, 0xc8 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */
132*4882a593Smuzhiyun { { 0x73, 0x00, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */
133*4882a593Smuzhiyun { { 0x73, 0x00, 0x14 }, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */
134*4882a593Smuzhiyun { { 0x73, 0x02, 0x0a }, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
135*4882a593Smuzhiyun { { 0x73, 0x02, 0x14 }, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */
136*4882a593Smuzhiyun { { 0x73, 0x02, 0x50 }, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */
137*4882a593Smuzhiyun };
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun static const struct alps_protocol_info alps_v3_protocol_data = {
140*4882a593Smuzhiyun ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
141*4882a593Smuzhiyun };
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun static const struct alps_protocol_info alps_v3_rushmore_data = {
144*4882a593Smuzhiyun ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
145*4882a593Smuzhiyun };
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun static const struct alps_protocol_info alps_v4_protocol_data = {
148*4882a593Smuzhiyun ALPS_PROTO_V4, 0x8f, 0x8f, 0
149*4882a593Smuzhiyun };
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun static const struct alps_protocol_info alps_v5_protocol_data = {
152*4882a593Smuzhiyun ALPS_PROTO_V5, 0xc8, 0xd8, 0
153*4882a593Smuzhiyun };
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun static const struct alps_protocol_info alps_v7_protocol_data = {
156*4882a593Smuzhiyun ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT | ALPS_DUALPOINT_WITH_PRESSURE
157*4882a593Smuzhiyun };
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun static const struct alps_protocol_info alps_v8_protocol_data = {
160*4882a593Smuzhiyun ALPS_PROTO_V8, 0x18, 0x18, 0
161*4882a593Smuzhiyun };
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun static const struct alps_protocol_info alps_v9_protocol_data = {
164*4882a593Smuzhiyun ALPS_PROTO_V9, 0xc8, 0xc8, 0
165*4882a593Smuzhiyun };
166*4882a593Smuzhiyun
167*4882a593Smuzhiyun /*
168*4882a593Smuzhiyun * Some v2 models report the stick buttons in separate bits
169*4882a593Smuzhiyun */
170*4882a593Smuzhiyun static const struct dmi_system_id alps_dmi_has_separate_stick_buttons[] = {
171*4882a593Smuzhiyun #if defined(CONFIG_DMI) && defined(CONFIG_X86)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun /* Extrapolated from other entries */
174*4882a593Smuzhiyun .matches = {
175*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
176*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D420"),
177*4882a593Smuzhiyun },
178*4882a593Smuzhiyun },
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun /* Reported-by: Hans de Bruin <jmdebruin@xmsnet.nl> */
181*4882a593Smuzhiyun .matches = {
182*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
183*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D430"),
184*4882a593Smuzhiyun },
185*4882a593Smuzhiyun },
186*4882a593Smuzhiyun {
187*4882a593Smuzhiyun /* Reported-by: Hans de Goede <hdegoede@redhat.com> */
188*4882a593Smuzhiyun .matches = {
189*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
190*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D620"),
191*4882a593Smuzhiyun },
192*4882a593Smuzhiyun },
193*4882a593Smuzhiyun {
194*4882a593Smuzhiyun /* Extrapolated from other entries */
195*4882a593Smuzhiyun .matches = {
196*4882a593Smuzhiyun DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
197*4882a593Smuzhiyun DMI_MATCH(DMI_PRODUCT_NAME, "Latitude D630"),
198*4882a593Smuzhiyun },
199*4882a593Smuzhiyun },
200*4882a593Smuzhiyun #endif
201*4882a593Smuzhiyun { }
202*4882a593Smuzhiyun };
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun static void alps_set_abs_params_st(struct alps_data *priv,
205*4882a593Smuzhiyun struct input_dev *dev1);
206*4882a593Smuzhiyun static void alps_set_abs_params_semi_mt(struct alps_data *priv,
207*4882a593Smuzhiyun struct input_dev *dev1);
208*4882a593Smuzhiyun static void alps_set_abs_params_v7(struct alps_data *priv,
209*4882a593Smuzhiyun struct input_dev *dev1);
210*4882a593Smuzhiyun static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
211*4882a593Smuzhiyun struct input_dev *dev1);
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun /* Packet formats are described in Documentation/input/devices/alps.rst */
214*4882a593Smuzhiyun
alps_is_valid_first_byte(struct alps_data * priv,unsigned char data)215*4882a593Smuzhiyun static bool alps_is_valid_first_byte(struct alps_data *priv,
216*4882a593Smuzhiyun unsigned char data)
217*4882a593Smuzhiyun {
218*4882a593Smuzhiyun return (data & priv->mask0) == priv->byte0;
219*4882a593Smuzhiyun }
220*4882a593Smuzhiyun
alps_report_buttons(struct input_dev * dev1,struct input_dev * dev2,int left,int right,int middle)221*4882a593Smuzhiyun static void alps_report_buttons(struct input_dev *dev1, struct input_dev *dev2,
222*4882a593Smuzhiyun int left, int right, int middle)
223*4882a593Smuzhiyun {
224*4882a593Smuzhiyun struct input_dev *dev;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun /*
227*4882a593Smuzhiyun * If shared button has already been reported on the
228*4882a593Smuzhiyun * other device (dev2) then this event should be also
229*4882a593Smuzhiyun * sent through that device.
230*4882a593Smuzhiyun */
231*4882a593Smuzhiyun dev = (dev2 && test_bit(BTN_LEFT, dev2->key)) ? dev2 : dev1;
232*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, left);
233*4882a593Smuzhiyun
234*4882a593Smuzhiyun dev = (dev2 && test_bit(BTN_RIGHT, dev2->key)) ? dev2 : dev1;
235*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, right);
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun dev = (dev2 && test_bit(BTN_MIDDLE, dev2->key)) ? dev2 : dev1;
238*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, middle);
239*4882a593Smuzhiyun
240*4882a593Smuzhiyun /*
241*4882a593Smuzhiyun * Sync the _other_ device now, we'll do the first
242*4882a593Smuzhiyun * device later once we report the rest of the events.
243*4882a593Smuzhiyun */
244*4882a593Smuzhiyun if (dev2)
245*4882a593Smuzhiyun input_sync(dev2);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun
alps_process_packet_v1_v2(struct psmouse * psmouse)248*4882a593Smuzhiyun static void alps_process_packet_v1_v2(struct psmouse *psmouse)
249*4882a593Smuzhiyun {
250*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
251*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
252*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
253*4882a593Smuzhiyun struct input_dev *dev2 = priv->dev2;
254*4882a593Smuzhiyun int x, y, z, ges, fin, left, right, middle;
255*4882a593Smuzhiyun int back = 0, forward = 0;
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun if (priv->proto_version == ALPS_PROTO_V1) {
258*4882a593Smuzhiyun left = packet[2] & 0x10;
259*4882a593Smuzhiyun right = packet[2] & 0x08;
260*4882a593Smuzhiyun middle = 0;
261*4882a593Smuzhiyun x = packet[1] | ((packet[0] & 0x07) << 7);
262*4882a593Smuzhiyun y = packet[4] | ((packet[3] & 0x07) << 7);
263*4882a593Smuzhiyun z = packet[5];
264*4882a593Smuzhiyun } else {
265*4882a593Smuzhiyun left = packet[3] & 1;
266*4882a593Smuzhiyun right = packet[3] & 2;
267*4882a593Smuzhiyun middle = packet[3] & 4;
268*4882a593Smuzhiyun x = packet[1] | ((packet[2] & 0x78) << (7 - 3));
269*4882a593Smuzhiyun y = packet[4] | ((packet[3] & 0x70) << (7 - 4));
270*4882a593Smuzhiyun z = packet[5];
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun if (priv->flags & ALPS_FW_BK_1) {
274*4882a593Smuzhiyun back = packet[0] & 0x10;
275*4882a593Smuzhiyun forward = packet[2] & 4;
276*4882a593Smuzhiyun }
277*4882a593Smuzhiyun
278*4882a593Smuzhiyun if (priv->flags & ALPS_FW_BK_2) {
279*4882a593Smuzhiyun back = packet[3] & 4;
280*4882a593Smuzhiyun forward = packet[2] & 4;
281*4882a593Smuzhiyun if ((middle = forward && back))
282*4882a593Smuzhiyun forward = back = 0;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun ges = packet[2] & 1;
286*4882a593Smuzhiyun fin = packet[2] & 2;
287*4882a593Smuzhiyun
288*4882a593Smuzhiyun if ((priv->flags & ALPS_DUALPOINT) && z == 127) {
289*4882a593Smuzhiyun input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
290*4882a593Smuzhiyun input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
291*4882a593Smuzhiyun
292*4882a593Smuzhiyun alps_report_buttons(dev2, dev, left, right, middle);
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun input_sync(dev2);
295*4882a593Smuzhiyun return;
296*4882a593Smuzhiyun }
297*4882a593Smuzhiyun
298*4882a593Smuzhiyun /* Some models have separate stick button bits */
299*4882a593Smuzhiyun if (priv->flags & ALPS_STICK_BITS) {
300*4882a593Smuzhiyun left |= packet[0] & 1;
301*4882a593Smuzhiyun right |= packet[0] & 2;
302*4882a593Smuzhiyun middle |= packet[0] & 4;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun alps_report_buttons(dev, dev2, left, right, middle);
306*4882a593Smuzhiyun
307*4882a593Smuzhiyun /* Convert hardware tap to a reasonable Z value */
308*4882a593Smuzhiyun if (ges && !fin)
309*4882a593Smuzhiyun z = 40;
310*4882a593Smuzhiyun
311*4882a593Smuzhiyun /*
312*4882a593Smuzhiyun * A "tap and drag" operation is reported by the hardware as a transition
313*4882a593Smuzhiyun * from (!fin && ges) to (fin && ges). This should be translated to the
314*4882a593Smuzhiyun * sequence Z>0, Z==0, Z>0, so the Z==0 event has to be generated manually.
315*4882a593Smuzhiyun */
316*4882a593Smuzhiyun if (ges && fin && !priv->prev_fin) {
317*4882a593Smuzhiyun input_report_abs(dev, ABS_X, x);
318*4882a593Smuzhiyun input_report_abs(dev, ABS_Y, y);
319*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, 0);
320*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_FINGER, 0);
321*4882a593Smuzhiyun input_sync(dev);
322*4882a593Smuzhiyun }
323*4882a593Smuzhiyun priv->prev_fin = fin;
324*4882a593Smuzhiyun
325*4882a593Smuzhiyun if (z > 30)
326*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, 1);
327*4882a593Smuzhiyun if (z < 25)
328*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, 0);
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun if (z > 0) {
331*4882a593Smuzhiyun input_report_abs(dev, ABS_X, x);
332*4882a593Smuzhiyun input_report_abs(dev, ABS_Y, y);
333*4882a593Smuzhiyun }
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, z);
336*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_FINGER, z > 0);
337*4882a593Smuzhiyun
338*4882a593Smuzhiyun if (priv->flags & ALPS_WHEEL)
339*4882a593Smuzhiyun input_report_rel(dev, REL_WHEEL, ((packet[2] << 1) & 0x08) - ((packet[0] >> 4) & 0x07));
340*4882a593Smuzhiyun
341*4882a593Smuzhiyun if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
342*4882a593Smuzhiyun input_report_key(dev, BTN_FORWARD, forward);
343*4882a593Smuzhiyun input_report_key(dev, BTN_BACK, back);
344*4882a593Smuzhiyun }
345*4882a593Smuzhiyun
346*4882a593Smuzhiyun if (priv->flags & ALPS_FOUR_BUTTONS) {
347*4882a593Smuzhiyun input_report_key(dev, BTN_0, packet[2] & 4);
348*4882a593Smuzhiyun input_report_key(dev, BTN_1, packet[0] & 0x10);
349*4882a593Smuzhiyun input_report_key(dev, BTN_2, packet[3] & 4);
350*4882a593Smuzhiyun input_report_key(dev, BTN_3, packet[0] & 0x20);
351*4882a593Smuzhiyun }
352*4882a593Smuzhiyun
353*4882a593Smuzhiyun input_sync(dev);
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun
alps_get_bitmap_points(unsigned int map,struct alps_bitmap_point * low,struct alps_bitmap_point * high,int * fingers)356*4882a593Smuzhiyun static void alps_get_bitmap_points(unsigned int map,
357*4882a593Smuzhiyun struct alps_bitmap_point *low,
358*4882a593Smuzhiyun struct alps_bitmap_point *high,
359*4882a593Smuzhiyun int *fingers)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun struct alps_bitmap_point *point;
362*4882a593Smuzhiyun int i, bit, prev_bit = 0;
363*4882a593Smuzhiyun
364*4882a593Smuzhiyun point = low;
365*4882a593Smuzhiyun for (i = 0; map != 0; i++, map >>= 1) {
366*4882a593Smuzhiyun bit = map & 1;
367*4882a593Smuzhiyun if (bit) {
368*4882a593Smuzhiyun if (!prev_bit) {
369*4882a593Smuzhiyun point->start_bit = i;
370*4882a593Smuzhiyun point->num_bits = 0;
371*4882a593Smuzhiyun (*fingers)++;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun point->num_bits++;
374*4882a593Smuzhiyun } else {
375*4882a593Smuzhiyun if (prev_bit)
376*4882a593Smuzhiyun point = high;
377*4882a593Smuzhiyun }
378*4882a593Smuzhiyun prev_bit = bit;
379*4882a593Smuzhiyun }
380*4882a593Smuzhiyun }
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun /*
383*4882a593Smuzhiyun * Process bitmap data from semi-mt protocols. Returns the number of
384*4882a593Smuzhiyun * fingers detected. A return value of 0 means at least one of the
385*4882a593Smuzhiyun * bitmaps was empty.
386*4882a593Smuzhiyun *
387*4882a593Smuzhiyun * The bitmaps don't have enough data to track fingers, so this function
388*4882a593Smuzhiyun * only generates points representing a bounding box of all contacts.
389*4882a593Smuzhiyun * These points are returned in fields->mt when the return value
390*4882a593Smuzhiyun * is greater than 0.
391*4882a593Smuzhiyun */
alps_process_bitmap(struct alps_data * priv,struct alps_fields * fields)392*4882a593Smuzhiyun static int alps_process_bitmap(struct alps_data *priv,
393*4882a593Smuzhiyun struct alps_fields *fields)
394*4882a593Smuzhiyun {
395*4882a593Smuzhiyun int i, fingers_x = 0, fingers_y = 0, fingers, closest;
396*4882a593Smuzhiyun struct alps_bitmap_point x_low = {0,}, x_high = {0,};
397*4882a593Smuzhiyun struct alps_bitmap_point y_low = {0,}, y_high = {0,};
398*4882a593Smuzhiyun struct input_mt_pos corner[4];
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (!fields->x_map || !fields->y_map)
401*4882a593Smuzhiyun return 0;
402*4882a593Smuzhiyun
403*4882a593Smuzhiyun alps_get_bitmap_points(fields->x_map, &x_low, &x_high, &fingers_x);
404*4882a593Smuzhiyun alps_get_bitmap_points(fields->y_map, &y_low, &y_high, &fingers_y);
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun /*
407*4882a593Smuzhiyun * Fingers can overlap, so we use the maximum count of fingers
408*4882a593Smuzhiyun * on either axis as the finger count.
409*4882a593Smuzhiyun */
410*4882a593Smuzhiyun fingers = max(fingers_x, fingers_y);
411*4882a593Smuzhiyun
412*4882a593Smuzhiyun /*
413*4882a593Smuzhiyun * If an axis reports only a single contact, we have overlapping or
414*4882a593Smuzhiyun * adjacent fingers. Divide the single contact between the two points.
415*4882a593Smuzhiyun */
416*4882a593Smuzhiyun if (fingers_x == 1) {
417*4882a593Smuzhiyun i = (x_low.num_bits - 1) / 2;
418*4882a593Smuzhiyun x_low.num_bits = x_low.num_bits - i;
419*4882a593Smuzhiyun x_high.start_bit = x_low.start_bit + i;
420*4882a593Smuzhiyun x_high.num_bits = max(i, 1);
421*4882a593Smuzhiyun }
422*4882a593Smuzhiyun if (fingers_y == 1) {
423*4882a593Smuzhiyun i = (y_low.num_bits - 1) / 2;
424*4882a593Smuzhiyun y_low.num_bits = y_low.num_bits - i;
425*4882a593Smuzhiyun y_high.start_bit = y_low.start_bit + i;
426*4882a593Smuzhiyun y_high.num_bits = max(i, 1);
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun
429*4882a593Smuzhiyun /* top-left corner */
430*4882a593Smuzhiyun corner[0].x =
431*4882a593Smuzhiyun (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
432*4882a593Smuzhiyun (2 * (priv->x_bits - 1));
433*4882a593Smuzhiyun corner[0].y =
434*4882a593Smuzhiyun (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
435*4882a593Smuzhiyun (2 * (priv->y_bits - 1));
436*4882a593Smuzhiyun
437*4882a593Smuzhiyun /* top-right corner */
438*4882a593Smuzhiyun corner[1].x =
439*4882a593Smuzhiyun (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
440*4882a593Smuzhiyun (2 * (priv->x_bits - 1));
441*4882a593Smuzhiyun corner[1].y =
442*4882a593Smuzhiyun (priv->y_max * (2 * y_low.start_bit + y_low.num_bits - 1)) /
443*4882a593Smuzhiyun (2 * (priv->y_bits - 1));
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun /* bottom-right corner */
446*4882a593Smuzhiyun corner[2].x =
447*4882a593Smuzhiyun (priv->x_max * (2 * x_high.start_bit + x_high.num_bits - 1)) /
448*4882a593Smuzhiyun (2 * (priv->x_bits - 1));
449*4882a593Smuzhiyun corner[2].y =
450*4882a593Smuzhiyun (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
451*4882a593Smuzhiyun (2 * (priv->y_bits - 1));
452*4882a593Smuzhiyun
453*4882a593Smuzhiyun /* bottom-left corner */
454*4882a593Smuzhiyun corner[3].x =
455*4882a593Smuzhiyun (priv->x_max * (2 * x_low.start_bit + x_low.num_bits - 1)) /
456*4882a593Smuzhiyun (2 * (priv->x_bits - 1));
457*4882a593Smuzhiyun corner[3].y =
458*4882a593Smuzhiyun (priv->y_max * (2 * y_high.start_bit + y_high.num_bits - 1)) /
459*4882a593Smuzhiyun (2 * (priv->y_bits - 1));
460*4882a593Smuzhiyun
461*4882a593Smuzhiyun /* x-bitmap order is reversed on v5 touchpads */
462*4882a593Smuzhiyun if (priv->proto_version == ALPS_PROTO_V5) {
463*4882a593Smuzhiyun for (i = 0; i < 4; i++)
464*4882a593Smuzhiyun corner[i].x = priv->x_max - corner[i].x;
465*4882a593Smuzhiyun }
466*4882a593Smuzhiyun
467*4882a593Smuzhiyun /* y-bitmap order is reversed on v3 and v4 touchpads */
468*4882a593Smuzhiyun if (priv->proto_version == ALPS_PROTO_V3 ||
469*4882a593Smuzhiyun priv->proto_version == ALPS_PROTO_V4) {
470*4882a593Smuzhiyun for (i = 0; i < 4; i++)
471*4882a593Smuzhiyun corner[i].y = priv->y_max - corner[i].y;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun
474*4882a593Smuzhiyun /*
475*4882a593Smuzhiyun * We only select a corner for the second touch once per 2 finger
476*4882a593Smuzhiyun * touch sequence to avoid the chosen corner (and thus the coordinates)
477*4882a593Smuzhiyun * jumping around when the first touch is in the middle.
478*4882a593Smuzhiyun */
479*4882a593Smuzhiyun if (priv->second_touch == -1) {
480*4882a593Smuzhiyun /* Find corner closest to our st coordinates */
481*4882a593Smuzhiyun closest = 0x7fffffff;
482*4882a593Smuzhiyun for (i = 0; i < 4; i++) {
483*4882a593Smuzhiyun int dx = fields->st.x - corner[i].x;
484*4882a593Smuzhiyun int dy = fields->st.y - corner[i].y;
485*4882a593Smuzhiyun int distance = dx * dx + dy * dy;
486*4882a593Smuzhiyun
487*4882a593Smuzhiyun if (distance < closest) {
488*4882a593Smuzhiyun priv->second_touch = i;
489*4882a593Smuzhiyun closest = distance;
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun }
492*4882a593Smuzhiyun /* And select the opposite corner to use for the 2nd touch */
493*4882a593Smuzhiyun priv->second_touch = (priv->second_touch + 2) % 4;
494*4882a593Smuzhiyun }
495*4882a593Smuzhiyun
496*4882a593Smuzhiyun fields->mt[0] = fields->st;
497*4882a593Smuzhiyun fields->mt[1] = corner[priv->second_touch];
498*4882a593Smuzhiyun
499*4882a593Smuzhiyun return fingers;
500*4882a593Smuzhiyun }
501*4882a593Smuzhiyun
alps_set_slot(struct input_dev * dev,int slot,int x,int y)502*4882a593Smuzhiyun static void alps_set_slot(struct input_dev *dev, int slot, int x, int y)
503*4882a593Smuzhiyun {
504*4882a593Smuzhiyun input_mt_slot(dev, slot);
505*4882a593Smuzhiyun input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
506*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_X, x);
507*4882a593Smuzhiyun input_report_abs(dev, ABS_MT_POSITION_Y, y);
508*4882a593Smuzhiyun }
509*4882a593Smuzhiyun
alps_report_mt_data(struct psmouse * psmouse,int n)510*4882a593Smuzhiyun static void alps_report_mt_data(struct psmouse *psmouse, int n)
511*4882a593Smuzhiyun {
512*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
513*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
514*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
515*4882a593Smuzhiyun int i, slot[MAX_TOUCHES];
516*4882a593Smuzhiyun
517*4882a593Smuzhiyun input_mt_assign_slots(dev, slot, f->mt, n, 0);
518*4882a593Smuzhiyun for (i = 0; i < n; i++)
519*4882a593Smuzhiyun alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun input_mt_sync_frame(dev);
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun
alps_report_semi_mt_data(struct psmouse * psmouse,int fingers)524*4882a593Smuzhiyun static void alps_report_semi_mt_data(struct psmouse *psmouse, int fingers)
525*4882a593Smuzhiyun {
526*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
527*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
528*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun /* Use st data when we don't have mt data */
531*4882a593Smuzhiyun if (fingers < 2) {
532*4882a593Smuzhiyun f->mt[0].x = f->st.x;
533*4882a593Smuzhiyun f->mt[0].y = f->st.y;
534*4882a593Smuzhiyun fingers = f->pressure > 0 ? 1 : 0;
535*4882a593Smuzhiyun priv->second_touch = -1;
536*4882a593Smuzhiyun }
537*4882a593Smuzhiyun
538*4882a593Smuzhiyun if (fingers >= 1)
539*4882a593Smuzhiyun alps_set_slot(dev, 0, f->mt[0].x, f->mt[0].y);
540*4882a593Smuzhiyun if (fingers >= 2)
541*4882a593Smuzhiyun alps_set_slot(dev, 1, f->mt[1].x, f->mt[1].y);
542*4882a593Smuzhiyun input_mt_sync_frame(dev);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun input_mt_report_finger_count(dev, fingers);
545*4882a593Smuzhiyun
546*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, f->left);
547*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, f->right);
548*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, f->middle);
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, f->pressure);
551*4882a593Smuzhiyun
552*4882a593Smuzhiyun input_sync(dev);
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun
alps_process_trackstick_packet_v3(struct psmouse * psmouse)555*4882a593Smuzhiyun static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
558*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
559*4882a593Smuzhiyun struct input_dev *dev = priv->dev2;
560*4882a593Smuzhiyun int x, y, z, left, right, middle;
561*4882a593Smuzhiyun
562*4882a593Smuzhiyun /* It should be a DualPoint when received trackstick packet */
563*4882a593Smuzhiyun if (!(priv->flags & ALPS_DUALPOINT)) {
564*4882a593Smuzhiyun psmouse_warn(psmouse,
565*4882a593Smuzhiyun "Rejected trackstick packet from non DualPoint device");
566*4882a593Smuzhiyun return;
567*4882a593Smuzhiyun }
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun /* Sanity check packet */
570*4882a593Smuzhiyun if (!(packet[0] & 0x40)) {
571*4882a593Smuzhiyun psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n");
572*4882a593Smuzhiyun return;
573*4882a593Smuzhiyun }
574*4882a593Smuzhiyun
575*4882a593Smuzhiyun /*
576*4882a593Smuzhiyun * There's a special packet that seems to indicate the end
577*4882a593Smuzhiyun * of a stream of trackstick data. Filter these out.
578*4882a593Smuzhiyun */
579*4882a593Smuzhiyun if (packet[1] == 0x7f && packet[2] == 0x7f && packet[4] == 0x7f)
580*4882a593Smuzhiyun return;
581*4882a593Smuzhiyun
582*4882a593Smuzhiyun x = (s8)(((packet[0] & 0x20) << 2) | (packet[1] & 0x7f));
583*4882a593Smuzhiyun y = (s8)(((packet[0] & 0x10) << 3) | (packet[2] & 0x7f));
584*4882a593Smuzhiyun z = packet[4] & 0x7f;
585*4882a593Smuzhiyun
586*4882a593Smuzhiyun /*
587*4882a593Smuzhiyun * The x and y values tend to be quite large, and when used
588*4882a593Smuzhiyun * alone the trackstick is difficult to use. Scale them down
589*4882a593Smuzhiyun * to compensate.
590*4882a593Smuzhiyun */
591*4882a593Smuzhiyun x /= 8;
592*4882a593Smuzhiyun y /= 8;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun input_report_rel(dev, REL_X, x);
595*4882a593Smuzhiyun input_report_rel(dev, REL_Y, -y);
596*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, z);
597*4882a593Smuzhiyun
598*4882a593Smuzhiyun /*
599*4882a593Smuzhiyun * Most ALPS models report the trackstick buttons in the touchpad
600*4882a593Smuzhiyun * packets, but a few report them here. No reliable way has been
601*4882a593Smuzhiyun * found to differentiate between the models upfront, so we enable
602*4882a593Smuzhiyun * the quirk in response to seeing a button press in the trackstick
603*4882a593Smuzhiyun * packet.
604*4882a593Smuzhiyun */
605*4882a593Smuzhiyun left = packet[3] & 0x01;
606*4882a593Smuzhiyun right = packet[3] & 0x02;
607*4882a593Smuzhiyun middle = packet[3] & 0x04;
608*4882a593Smuzhiyun
609*4882a593Smuzhiyun if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) &&
610*4882a593Smuzhiyun (left || right || middle))
611*4882a593Smuzhiyun priv->quirks |= ALPS_QUIRK_TRACKSTICK_BUTTONS;
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun if (priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS) {
614*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, left);
615*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, right);
616*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, middle);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun input_sync(dev);
620*4882a593Smuzhiyun return;
621*4882a593Smuzhiyun }
622*4882a593Smuzhiyun
alps_decode_buttons_v3(struct alps_fields * f,unsigned char * p)623*4882a593Smuzhiyun static void alps_decode_buttons_v3(struct alps_fields *f, unsigned char *p)
624*4882a593Smuzhiyun {
625*4882a593Smuzhiyun f->left = !!(p[3] & 0x01);
626*4882a593Smuzhiyun f->right = !!(p[3] & 0x02);
627*4882a593Smuzhiyun f->middle = !!(p[3] & 0x04);
628*4882a593Smuzhiyun
629*4882a593Smuzhiyun f->ts_left = !!(p[3] & 0x10);
630*4882a593Smuzhiyun f->ts_right = !!(p[3] & 0x20);
631*4882a593Smuzhiyun f->ts_middle = !!(p[3] & 0x40);
632*4882a593Smuzhiyun }
633*4882a593Smuzhiyun
alps_decode_pinnacle(struct alps_fields * f,unsigned char * p,struct psmouse * psmouse)634*4882a593Smuzhiyun static int alps_decode_pinnacle(struct alps_fields *f, unsigned char *p,
635*4882a593Smuzhiyun struct psmouse *psmouse)
636*4882a593Smuzhiyun {
637*4882a593Smuzhiyun f->first_mp = !!(p[4] & 0x40);
638*4882a593Smuzhiyun f->is_mp = !!(p[0] & 0x40);
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun if (f->is_mp) {
641*4882a593Smuzhiyun f->fingers = (p[5] & 0x3) + 1;
642*4882a593Smuzhiyun f->x_map = ((p[4] & 0x7e) << 8) |
643*4882a593Smuzhiyun ((p[1] & 0x7f) << 2) |
644*4882a593Smuzhiyun ((p[0] & 0x30) >> 4);
645*4882a593Smuzhiyun f->y_map = ((p[3] & 0x70) << 4) |
646*4882a593Smuzhiyun ((p[2] & 0x7f) << 1) |
647*4882a593Smuzhiyun (p[4] & 0x01);
648*4882a593Smuzhiyun } else {
649*4882a593Smuzhiyun f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
650*4882a593Smuzhiyun ((p[0] & 0x30) >> 4);
651*4882a593Smuzhiyun f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
652*4882a593Smuzhiyun f->pressure = p[5] & 0x7f;
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun alps_decode_buttons_v3(f, p);
655*4882a593Smuzhiyun }
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun return 0;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
alps_decode_rushmore(struct alps_fields * f,unsigned char * p,struct psmouse * psmouse)660*4882a593Smuzhiyun static int alps_decode_rushmore(struct alps_fields *f, unsigned char *p,
661*4882a593Smuzhiyun struct psmouse *psmouse)
662*4882a593Smuzhiyun {
663*4882a593Smuzhiyun f->first_mp = !!(p[4] & 0x40);
664*4882a593Smuzhiyun f->is_mp = !!(p[5] & 0x40);
665*4882a593Smuzhiyun
666*4882a593Smuzhiyun if (f->is_mp) {
667*4882a593Smuzhiyun f->fingers = max((p[5] & 0x3), ((p[5] >> 2) & 0x3)) + 1;
668*4882a593Smuzhiyun f->x_map = ((p[5] & 0x10) << 11) |
669*4882a593Smuzhiyun ((p[4] & 0x7e) << 8) |
670*4882a593Smuzhiyun ((p[1] & 0x7f) << 2) |
671*4882a593Smuzhiyun ((p[0] & 0x30) >> 4);
672*4882a593Smuzhiyun f->y_map = ((p[5] & 0x20) << 6) |
673*4882a593Smuzhiyun ((p[3] & 0x70) << 4) |
674*4882a593Smuzhiyun ((p[2] & 0x7f) << 1) |
675*4882a593Smuzhiyun (p[4] & 0x01);
676*4882a593Smuzhiyun } else {
677*4882a593Smuzhiyun f->st.x = ((p[1] & 0x7f) << 4) | ((p[4] & 0x30) >> 2) |
678*4882a593Smuzhiyun ((p[0] & 0x30) >> 4);
679*4882a593Smuzhiyun f->st.y = ((p[2] & 0x7f) << 4) | (p[4] & 0x0f);
680*4882a593Smuzhiyun f->pressure = p[5] & 0x7f;
681*4882a593Smuzhiyun
682*4882a593Smuzhiyun alps_decode_buttons_v3(f, p);
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun
685*4882a593Smuzhiyun return 0;
686*4882a593Smuzhiyun }
687*4882a593Smuzhiyun
alps_decode_dolphin(struct alps_fields * f,unsigned char * p,struct psmouse * psmouse)688*4882a593Smuzhiyun static int alps_decode_dolphin(struct alps_fields *f, unsigned char *p,
689*4882a593Smuzhiyun struct psmouse *psmouse)
690*4882a593Smuzhiyun {
691*4882a593Smuzhiyun u64 palm_data = 0;
692*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun f->first_mp = !!(p[0] & 0x02);
695*4882a593Smuzhiyun f->is_mp = !!(p[0] & 0x20);
696*4882a593Smuzhiyun
697*4882a593Smuzhiyun if (!f->is_mp) {
698*4882a593Smuzhiyun f->st.x = ((p[1] & 0x7f) | ((p[4] & 0x0f) << 7));
699*4882a593Smuzhiyun f->st.y = ((p[2] & 0x7f) | ((p[4] & 0xf0) << 3));
700*4882a593Smuzhiyun f->pressure = (p[0] & 4) ? 0 : p[5] & 0x7f;
701*4882a593Smuzhiyun alps_decode_buttons_v3(f, p);
702*4882a593Smuzhiyun } else {
703*4882a593Smuzhiyun f->fingers = ((p[0] & 0x6) >> 1 |
704*4882a593Smuzhiyun (p[0] & 0x10) >> 2);
705*4882a593Smuzhiyun
706*4882a593Smuzhiyun palm_data = (p[1] & 0x7f) |
707*4882a593Smuzhiyun ((p[2] & 0x7f) << 7) |
708*4882a593Smuzhiyun ((p[4] & 0x7f) << 14) |
709*4882a593Smuzhiyun ((p[5] & 0x7f) << 21) |
710*4882a593Smuzhiyun ((p[3] & 0x07) << 28) |
711*4882a593Smuzhiyun (((u64)p[3] & 0x70) << 27) |
712*4882a593Smuzhiyun (((u64)p[0] & 0x01) << 34);
713*4882a593Smuzhiyun
714*4882a593Smuzhiyun /* Y-profile is stored in P(0) to p(n-1), n = y_bits; */
715*4882a593Smuzhiyun f->y_map = palm_data & (BIT(priv->y_bits) - 1);
716*4882a593Smuzhiyun
717*4882a593Smuzhiyun /* X-profile is stored in p(n) to p(n+m-1), m = x_bits; */
718*4882a593Smuzhiyun f->x_map = (palm_data >> priv->y_bits) &
719*4882a593Smuzhiyun (BIT(priv->x_bits) - 1);
720*4882a593Smuzhiyun }
721*4882a593Smuzhiyun
722*4882a593Smuzhiyun return 0;
723*4882a593Smuzhiyun }
724*4882a593Smuzhiyun
alps_process_touchpad_packet_v3_v5(struct psmouse * psmouse)725*4882a593Smuzhiyun static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
726*4882a593Smuzhiyun {
727*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
728*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
729*4882a593Smuzhiyun struct input_dev *dev2 = priv->dev2;
730*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
731*4882a593Smuzhiyun int fingers = 0;
732*4882a593Smuzhiyun
733*4882a593Smuzhiyun memset(f, 0, sizeof(*f));
734*4882a593Smuzhiyun
735*4882a593Smuzhiyun priv->decode_fields(f, packet, psmouse);
736*4882a593Smuzhiyun
737*4882a593Smuzhiyun /*
738*4882a593Smuzhiyun * There's no single feature of touchpad position and bitmap packets
739*4882a593Smuzhiyun * that can be used to distinguish between them. We rely on the fact
740*4882a593Smuzhiyun * that a bitmap packet should always follow a position packet with
741*4882a593Smuzhiyun * bit 6 of packet[4] set.
742*4882a593Smuzhiyun */
743*4882a593Smuzhiyun if (priv->multi_packet) {
744*4882a593Smuzhiyun /*
745*4882a593Smuzhiyun * Sometimes a position packet will indicate a multi-packet
746*4882a593Smuzhiyun * sequence, but then what follows is another position
747*4882a593Smuzhiyun * packet. Check for this, and when it happens process the
748*4882a593Smuzhiyun * position packet as usual.
749*4882a593Smuzhiyun */
750*4882a593Smuzhiyun if (f->is_mp) {
751*4882a593Smuzhiyun fingers = f->fingers;
752*4882a593Smuzhiyun /*
753*4882a593Smuzhiyun * Bitmap processing uses position packet's coordinate
754*4882a593Smuzhiyun * data, so we need to do decode it first.
755*4882a593Smuzhiyun */
756*4882a593Smuzhiyun priv->decode_fields(f, priv->multi_data, psmouse);
757*4882a593Smuzhiyun if (alps_process_bitmap(priv, f) == 0)
758*4882a593Smuzhiyun fingers = 0; /* Use st data */
759*4882a593Smuzhiyun } else {
760*4882a593Smuzhiyun priv->multi_packet = 0;
761*4882a593Smuzhiyun }
762*4882a593Smuzhiyun }
763*4882a593Smuzhiyun
764*4882a593Smuzhiyun /*
765*4882a593Smuzhiyun * Bit 6 of byte 0 is not usually set in position packets. The only
766*4882a593Smuzhiyun * times it seems to be set is in situations where the data is
767*4882a593Smuzhiyun * suspect anyway, e.g. a palm resting flat on the touchpad. Given
768*4882a593Smuzhiyun * this combined with the fact that this bit is useful for filtering
769*4882a593Smuzhiyun * out misidentified bitmap packets, we reject anything with this
770*4882a593Smuzhiyun * bit set.
771*4882a593Smuzhiyun */
772*4882a593Smuzhiyun if (f->is_mp)
773*4882a593Smuzhiyun return;
774*4882a593Smuzhiyun
775*4882a593Smuzhiyun if (!priv->multi_packet && f->first_mp) {
776*4882a593Smuzhiyun priv->multi_packet = 1;
777*4882a593Smuzhiyun memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
778*4882a593Smuzhiyun return;
779*4882a593Smuzhiyun }
780*4882a593Smuzhiyun
781*4882a593Smuzhiyun priv->multi_packet = 0;
782*4882a593Smuzhiyun
783*4882a593Smuzhiyun /*
784*4882a593Smuzhiyun * Sometimes the hardware sends a single packet with z = 0
785*4882a593Smuzhiyun * in the middle of a stream. Real releases generate packets
786*4882a593Smuzhiyun * with x, y, and z all zero, so these seem to be flukes.
787*4882a593Smuzhiyun * Ignore them.
788*4882a593Smuzhiyun */
789*4882a593Smuzhiyun if (f->st.x && f->st.y && !f->pressure)
790*4882a593Smuzhiyun return;
791*4882a593Smuzhiyun
792*4882a593Smuzhiyun alps_report_semi_mt_data(psmouse, fingers);
793*4882a593Smuzhiyun
794*4882a593Smuzhiyun if ((priv->flags & ALPS_DUALPOINT) &&
795*4882a593Smuzhiyun !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
796*4882a593Smuzhiyun input_report_key(dev2, BTN_LEFT, f->ts_left);
797*4882a593Smuzhiyun input_report_key(dev2, BTN_RIGHT, f->ts_right);
798*4882a593Smuzhiyun input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
799*4882a593Smuzhiyun input_sync(dev2);
800*4882a593Smuzhiyun }
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun
alps_process_packet_v3(struct psmouse * psmouse)803*4882a593Smuzhiyun static void alps_process_packet_v3(struct psmouse *psmouse)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
806*4882a593Smuzhiyun
807*4882a593Smuzhiyun /*
808*4882a593Smuzhiyun * v3 protocol packets come in three types, two representing
809*4882a593Smuzhiyun * touchpad data and one representing trackstick data.
810*4882a593Smuzhiyun * Trackstick packets seem to be distinguished by always
811*4882a593Smuzhiyun * having 0x3f in the last byte. This value has never been
812*4882a593Smuzhiyun * observed in the last byte of either of the other types
813*4882a593Smuzhiyun * of packets.
814*4882a593Smuzhiyun */
815*4882a593Smuzhiyun if (packet[5] == 0x3f) {
816*4882a593Smuzhiyun alps_process_trackstick_packet_v3(psmouse);
817*4882a593Smuzhiyun return;
818*4882a593Smuzhiyun }
819*4882a593Smuzhiyun
820*4882a593Smuzhiyun alps_process_touchpad_packet_v3_v5(psmouse);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun
alps_process_packet_v6(struct psmouse * psmouse)823*4882a593Smuzhiyun static void alps_process_packet_v6(struct psmouse *psmouse)
824*4882a593Smuzhiyun {
825*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
826*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
827*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
828*4882a593Smuzhiyun struct input_dev *dev2 = priv->dev2;
829*4882a593Smuzhiyun int x, y, z;
830*4882a593Smuzhiyun
831*4882a593Smuzhiyun /*
832*4882a593Smuzhiyun * We can use Byte5 to distinguish if the packet is from Touchpad
833*4882a593Smuzhiyun * or Trackpoint.
834*4882a593Smuzhiyun * Touchpad: 0 - 0x7E
835*4882a593Smuzhiyun * Trackpoint: 0x7F
836*4882a593Smuzhiyun */
837*4882a593Smuzhiyun if (packet[5] == 0x7F) {
838*4882a593Smuzhiyun /* It should be a DualPoint when received Trackpoint packet */
839*4882a593Smuzhiyun if (!(priv->flags & ALPS_DUALPOINT)) {
840*4882a593Smuzhiyun psmouse_warn(psmouse,
841*4882a593Smuzhiyun "Rejected trackstick packet from non DualPoint device");
842*4882a593Smuzhiyun return;
843*4882a593Smuzhiyun }
844*4882a593Smuzhiyun
845*4882a593Smuzhiyun /* Trackpoint packet */
846*4882a593Smuzhiyun x = packet[1] | ((packet[3] & 0x20) << 2);
847*4882a593Smuzhiyun y = packet[2] | ((packet[3] & 0x40) << 1);
848*4882a593Smuzhiyun z = packet[4];
849*4882a593Smuzhiyun
850*4882a593Smuzhiyun /* To prevent the cursor jump when finger lifted */
851*4882a593Smuzhiyun if (x == 0x7F && y == 0x7F && z == 0x7F)
852*4882a593Smuzhiyun x = y = z = 0;
853*4882a593Smuzhiyun
854*4882a593Smuzhiyun /* Divide 4 since trackpoint's speed is too fast */
855*4882a593Smuzhiyun input_report_rel(dev2, REL_X, (char)x / 4);
856*4882a593Smuzhiyun input_report_rel(dev2, REL_Y, -((char)y / 4));
857*4882a593Smuzhiyun
858*4882a593Smuzhiyun psmouse_report_standard_buttons(dev2, packet[3]);
859*4882a593Smuzhiyun
860*4882a593Smuzhiyun input_sync(dev2);
861*4882a593Smuzhiyun return;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun
864*4882a593Smuzhiyun /* Touchpad packet */
865*4882a593Smuzhiyun x = packet[1] | ((packet[3] & 0x78) << 4);
866*4882a593Smuzhiyun y = packet[2] | ((packet[4] & 0x78) << 4);
867*4882a593Smuzhiyun z = packet[5];
868*4882a593Smuzhiyun
869*4882a593Smuzhiyun if (z > 30)
870*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, 1);
871*4882a593Smuzhiyun if (z < 25)
872*4882a593Smuzhiyun input_report_key(dev, BTN_TOUCH, 0);
873*4882a593Smuzhiyun
874*4882a593Smuzhiyun if (z > 0) {
875*4882a593Smuzhiyun input_report_abs(dev, ABS_X, x);
876*4882a593Smuzhiyun input_report_abs(dev, ABS_Y, y);
877*4882a593Smuzhiyun }
878*4882a593Smuzhiyun
879*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, z);
880*4882a593Smuzhiyun input_report_key(dev, BTN_TOOL_FINGER, z > 0);
881*4882a593Smuzhiyun
882*4882a593Smuzhiyun /* v6 touchpad does not have middle button */
883*4882a593Smuzhiyun packet[3] &= ~BIT(2);
884*4882a593Smuzhiyun psmouse_report_standard_buttons(dev2, packet[3]);
885*4882a593Smuzhiyun
886*4882a593Smuzhiyun input_sync(dev);
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun
alps_process_packet_v4(struct psmouse * psmouse)889*4882a593Smuzhiyun static void alps_process_packet_v4(struct psmouse *psmouse)
890*4882a593Smuzhiyun {
891*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
892*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
893*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
894*4882a593Smuzhiyun int offset;
895*4882a593Smuzhiyun
896*4882a593Smuzhiyun /*
897*4882a593Smuzhiyun * v4 has a 6-byte encoding for bitmap data, but this data is
898*4882a593Smuzhiyun * broken up between 3 normal packets. Use priv->multi_packet to
899*4882a593Smuzhiyun * track our position in the bitmap packet.
900*4882a593Smuzhiyun */
901*4882a593Smuzhiyun if (packet[6] & 0x40) {
902*4882a593Smuzhiyun /* sync, reset position */
903*4882a593Smuzhiyun priv->multi_packet = 0;
904*4882a593Smuzhiyun }
905*4882a593Smuzhiyun
906*4882a593Smuzhiyun if (WARN_ON_ONCE(priv->multi_packet > 2))
907*4882a593Smuzhiyun return;
908*4882a593Smuzhiyun
909*4882a593Smuzhiyun offset = 2 * priv->multi_packet;
910*4882a593Smuzhiyun priv->multi_data[offset] = packet[6];
911*4882a593Smuzhiyun priv->multi_data[offset + 1] = packet[7];
912*4882a593Smuzhiyun
913*4882a593Smuzhiyun f->left = !!(packet[4] & 0x01);
914*4882a593Smuzhiyun f->right = !!(packet[4] & 0x02);
915*4882a593Smuzhiyun
916*4882a593Smuzhiyun f->st.x = ((packet[1] & 0x7f) << 4) | ((packet[3] & 0x30) >> 2) |
917*4882a593Smuzhiyun ((packet[0] & 0x30) >> 4);
918*4882a593Smuzhiyun f->st.y = ((packet[2] & 0x7f) << 4) | (packet[3] & 0x0f);
919*4882a593Smuzhiyun f->pressure = packet[5] & 0x7f;
920*4882a593Smuzhiyun
921*4882a593Smuzhiyun if (++priv->multi_packet > 2) {
922*4882a593Smuzhiyun priv->multi_packet = 0;
923*4882a593Smuzhiyun
924*4882a593Smuzhiyun f->x_map = ((priv->multi_data[2] & 0x1f) << 10) |
925*4882a593Smuzhiyun ((priv->multi_data[3] & 0x60) << 3) |
926*4882a593Smuzhiyun ((priv->multi_data[0] & 0x3f) << 2) |
927*4882a593Smuzhiyun ((priv->multi_data[1] & 0x60) >> 5);
928*4882a593Smuzhiyun f->y_map = ((priv->multi_data[5] & 0x01) << 10) |
929*4882a593Smuzhiyun ((priv->multi_data[3] & 0x1f) << 5) |
930*4882a593Smuzhiyun (priv->multi_data[1] & 0x1f);
931*4882a593Smuzhiyun
932*4882a593Smuzhiyun f->fingers = alps_process_bitmap(priv, f);
933*4882a593Smuzhiyun }
934*4882a593Smuzhiyun
935*4882a593Smuzhiyun alps_report_semi_mt_data(psmouse, f->fingers);
936*4882a593Smuzhiyun }
937*4882a593Smuzhiyun
alps_is_valid_package_v7(struct psmouse * psmouse)938*4882a593Smuzhiyun static bool alps_is_valid_package_v7(struct psmouse *psmouse)
939*4882a593Smuzhiyun {
940*4882a593Smuzhiyun switch (psmouse->pktcnt) {
941*4882a593Smuzhiyun case 3:
942*4882a593Smuzhiyun return (psmouse->packet[2] & 0x40) == 0x40;
943*4882a593Smuzhiyun case 4:
944*4882a593Smuzhiyun return (psmouse->packet[3] & 0x48) == 0x48;
945*4882a593Smuzhiyun case 6:
946*4882a593Smuzhiyun return (psmouse->packet[5] & 0x40) == 0x00;
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun return true;
949*4882a593Smuzhiyun }
950*4882a593Smuzhiyun
alps_get_packet_id_v7(char * byte)951*4882a593Smuzhiyun static unsigned char alps_get_packet_id_v7(char *byte)
952*4882a593Smuzhiyun {
953*4882a593Smuzhiyun unsigned char packet_id;
954*4882a593Smuzhiyun
955*4882a593Smuzhiyun if (byte[4] & 0x40)
956*4882a593Smuzhiyun packet_id = V7_PACKET_ID_TWO;
957*4882a593Smuzhiyun else if (byte[4] & 0x01)
958*4882a593Smuzhiyun packet_id = V7_PACKET_ID_MULTI;
959*4882a593Smuzhiyun else if ((byte[0] & 0x10) && !(byte[4] & 0x43))
960*4882a593Smuzhiyun packet_id = V7_PACKET_ID_NEW;
961*4882a593Smuzhiyun else if (byte[1] == 0x00 && byte[4] == 0x00)
962*4882a593Smuzhiyun packet_id = V7_PACKET_ID_IDLE;
963*4882a593Smuzhiyun else
964*4882a593Smuzhiyun packet_id = V7_PACKET_ID_UNKNOWN;
965*4882a593Smuzhiyun
966*4882a593Smuzhiyun return packet_id;
967*4882a593Smuzhiyun }
968*4882a593Smuzhiyun
alps_get_finger_coordinate_v7(struct input_mt_pos * mt,unsigned char * pkt,unsigned char pkt_id)969*4882a593Smuzhiyun static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
970*4882a593Smuzhiyun unsigned char *pkt,
971*4882a593Smuzhiyun unsigned char pkt_id)
972*4882a593Smuzhiyun {
973*4882a593Smuzhiyun mt[0].x = ((pkt[2] & 0x80) << 4);
974*4882a593Smuzhiyun mt[0].x |= ((pkt[2] & 0x3F) << 5);
975*4882a593Smuzhiyun mt[0].x |= ((pkt[3] & 0x30) >> 1);
976*4882a593Smuzhiyun mt[0].x |= (pkt[3] & 0x07);
977*4882a593Smuzhiyun mt[0].y = (pkt[1] << 3) | (pkt[0] & 0x07);
978*4882a593Smuzhiyun
979*4882a593Smuzhiyun mt[1].x = ((pkt[3] & 0x80) << 4);
980*4882a593Smuzhiyun mt[1].x |= ((pkt[4] & 0x80) << 3);
981*4882a593Smuzhiyun mt[1].x |= ((pkt[4] & 0x3F) << 4);
982*4882a593Smuzhiyun mt[1].y = ((pkt[5] & 0x80) << 3);
983*4882a593Smuzhiyun mt[1].y |= ((pkt[5] & 0x3F) << 4);
984*4882a593Smuzhiyun
985*4882a593Smuzhiyun switch (pkt_id) {
986*4882a593Smuzhiyun case V7_PACKET_ID_TWO:
987*4882a593Smuzhiyun mt[1].x &= ~0x000F;
988*4882a593Smuzhiyun mt[1].y |= 0x000F;
989*4882a593Smuzhiyun /* Detect false-postive touches where x & y report max value */
990*4882a593Smuzhiyun if (mt[1].y == 0x7ff && mt[1].x == 0xff0) {
991*4882a593Smuzhiyun mt[1].x = 0;
992*4882a593Smuzhiyun /* y gets set to 0 at the end of this function */
993*4882a593Smuzhiyun }
994*4882a593Smuzhiyun break;
995*4882a593Smuzhiyun
996*4882a593Smuzhiyun case V7_PACKET_ID_MULTI:
997*4882a593Smuzhiyun mt[1].x &= ~0x003F;
998*4882a593Smuzhiyun mt[1].y &= ~0x0020;
999*4882a593Smuzhiyun mt[1].y |= ((pkt[4] & 0x02) << 4);
1000*4882a593Smuzhiyun mt[1].y |= 0x001F;
1001*4882a593Smuzhiyun break;
1002*4882a593Smuzhiyun
1003*4882a593Smuzhiyun case V7_PACKET_ID_NEW:
1004*4882a593Smuzhiyun mt[1].x &= ~0x003F;
1005*4882a593Smuzhiyun mt[1].x |= (pkt[0] & 0x20);
1006*4882a593Smuzhiyun mt[1].y |= 0x000F;
1007*4882a593Smuzhiyun break;
1008*4882a593Smuzhiyun }
1009*4882a593Smuzhiyun
1010*4882a593Smuzhiyun mt[0].y = 0x7FF - mt[0].y;
1011*4882a593Smuzhiyun mt[1].y = 0x7FF - mt[1].y;
1012*4882a593Smuzhiyun }
1013*4882a593Smuzhiyun
alps_get_mt_count(struct input_mt_pos * mt)1014*4882a593Smuzhiyun static int alps_get_mt_count(struct input_mt_pos *mt)
1015*4882a593Smuzhiyun {
1016*4882a593Smuzhiyun int i, fingers = 0;
1017*4882a593Smuzhiyun
1018*4882a593Smuzhiyun for (i = 0; i < MAX_TOUCHES; i++) {
1019*4882a593Smuzhiyun if (mt[i].x != 0 || mt[i].y != 0)
1020*4882a593Smuzhiyun fingers++;
1021*4882a593Smuzhiyun }
1022*4882a593Smuzhiyun
1023*4882a593Smuzhiyun return fingers;
1024*4882a593Smuzhiyun }
1025*4882a593Smuzhiyun
alps_decode_packet_v7(struct alps_fields * f,unsigned char * p,struct psmouse * psmouse)1026*4882a593Smuzhiyun static int alps_decode_packet_v7(struct alps_fields *f,
1027*4882a593Smuzhiyun unsigned char *p,
1028*4882a593Smuzhiyun struct psmouse *psmouse)
1029*4882a593Smuzhiyun {
1030*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1031*4882a593Smuzhiyun unsigned char pkt_id;
1032*4882a593Smuzhiyun
1033*4882a593Smuzhiyun pkt_id = alps_get_packet_id_v7(p);
1034*4882a593Smuzhiyun if (pkt_id == V7_PACKET_ID_IDLE)
1035*4882a593Smuzhiyun return 0;
1036*4882a593Smuzhiyun if (pkt_id == V7_PACKET_ID_UNKNOWN)
1037*4882a593Smuzhiyun return -1;
1038*4882a593Smuzhiyun /*
1039*4882a593Smuzhiyun * NEW packets are send to indicate a discontinuity in the finger
1040*4882a593Smuzhiyun * coordinate reporting. Specifically a finger may have moved from
1041*4882a593Smuzhiyun * slot 0 to 1 or vice versa. INPUT_MT_TRACK takes care of this for
1042*4882a593Smuzhiyun * us.
1043*4882a593Smuzhiyun *
1044*4882a593Smuzhiyun * NEW packets have 3 problems:
1045*4882a593Smuzhiyun * 1) They do not contain middle / right button info (on non clickpads)
1046*4882a593Smuzhiyun * this can be worked around by preserving the old button state
1047*4882a593Smuzhiyun * 2) They do not contain an accurate fingercount, and they are
1048*4882a593Smuzhiyun * typically send when the number of fingers changes. We cannot use
1049*4882a593Smuzhiyun * the old finger count as that may mismatch with the amount of
1050*4882a593Smuzhiyun * touch coordinates we've available in the NEW packet
1051*4882a593Smuzhiyun * 3) Their x data for the second touch is inaccurate leading to
1052*4882a593Smuzhiyun * a possible jump of the x coordinate by 16 units when the first
1053*4882a593Smuzhiyun * non NEW packet comes in
1054*4882a593Smuzhiyun * Since problems 2 & 3 cannot be worked around, just ignore them.
1055*4882a593Smuzhiyun */
1056*4882a593Smuzhiyun if (pkt_id == V7_PACKET_ID_NEW)
1057*4882a593Smuzhiyun return 1;
1058*4882a593Smuzhiyun
1059*4882a593Smuzhiyun alps_get_finger_coordinate_v7(f->mt, p, pkt_id);
1060*4882a593Smuzhiyun
1061*4882a593Smuzhiyun if (pkt_id == V7_PACKET_ID_TWO)
1062*4882a593Smuzhiyun f->fingers = alps_get_mt_count(f->mt);
1063*4882a593Smuzhiyun else /* pkt_id == V7_PACKET_ID_MULTI */
1064*4882a593Smuzhiyun f->fingers = 3 + (p[5] & 0x03);
1065*4882a593Smuzhiyun
1066*4882a593Smuzhiyun f->left = (p[0] & 0x80) >> 7;
1067*4882a593Smuzhiyun if (priv->flags & ALPS_BUTTONPAD) {
1068*4882a593Smuzhiyun if (p[0] & 0x20)
1069*4882a593Smuzhiyun f->fingers++;
1070*4882a593Smuzhiyun if (p[0] & 0x10)
1071*4882a593Smuzhiyun f->fingers++;
1072*4882a593Smuzhiyun } else {
1073*4882a593Smuzhiyun f->right = (p[0] & 0x20) >> 5;
1074*4882a593Smuzhiyun f->middle = (p[0] & 0x10) >> 4;
1075*4882a593Smuzhiyun }
1076*4882a593Smuzhiyun
1077*4882a593Smuzhiyun /* Sometimes a single touch is reported in mt[1] rather then mt[0] */
1078*4882a593Smuzhiyun if (f->fingers == 1 && f->mt[0].x == 0 && f->mt[0].y == 0) {
1079*4882a593Smuzhiyun f->mt[0].x = f->mt[1].x;
1080*4882a593Smuzhiyun f->mt[0].y = f->mt[1].y;
1081*4882a593Smuzhiyun f->mt[1].x = 0;
1082*4882a593Smuzhiyun f->mt[1].y = 0;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun
1085*4882a593Smuzhiyun return 0;
1086*4882a593Smuzhiyun }
1087*4882a593Smuzhiyun
alps_process_trackstick_packet_v7(struct psmouse * psmouse)1088*4882a593Smuzhiyun static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
1089*4882a593Smuzhiyun {
1090*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1091*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
1092*4882a593Smuzhiyun struct input_dev *dev2 = priv->dev2;
1093*4882a593Smuzhiyun int x, y, z;
1094*4882a593Smuzhiyun
1095*4882a593Smuzhiyun /* It should be a DualPoint when received trackstick packet */
1096*4882a593Smuzhiyun if (!(priv->flags & ALPS_DUALPOINT)) {
1097*4882a593Smuzhiyun psmouse_warn(psmouse,
1098*4882a593Smuzhiyun "Rejected trackstick packet from non DualPoint device");
1099*4882a593Smuzhiyun return;
1100*4882a593Smuzhiyun }
1101*4882a593Smuzhiyun
1102*4882a593Smuzhiyun x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
1103*4882a593Smuzhiyun y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
1104*4882a593Smuzhiyun ((packet[3] & 0x20) << 1);
1105*4882a593Smuzhiyun z = (packet[5] & 0x3f) | ((packet[3] & 0x80) >> 1);
1106*4882a593Smuzhiyun
1107*4882a593Smuzhiyun input_report_rel(dev2, REL_X, (char)x);
1108*4882a593Smuzhiyun input_report_rel(dev2, REL_Y, -((char)y));
1109*4882a593Smuzhiyun input_report_abs(dev2, ABS_PRESSURE, z);
1110*4882a593Smuzhiyun
1111*4882a593Smuzhiyun psmouse_report_standard_buttons(dev2, packet[1]);
1112*4882a593Smuzhiyun
1113*4882a593Smuzhiyun input_sync(dev2);
1114*4882a593Smuzhiyun }
1115*4882a593Smuzhiyun
alps_process_touchpad_packet_v7(struct psmouse * psmouse)1116*4882a593Smuzhiyun static void alps_process_touchpad_packet_v7(struct psmouse *psmouse)
1117*4882a593Smuzhiyun {
1118*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1119*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
1120*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
1121*4882a593Smuzhiyun
1122*4882a593Smuzhiyun memset(f, 0, sizeof(*f));
1123*4882a593Smuzhiyun
1124*4882a593Smuzhiyun if (priv->decode_fields(f, psmouse->packet, psmouse))
1125*4882a593Smuzhiyun return;
1126*4882a593Smuzhiyun
1127*4882a593Smuzhiyun alps_report_mt_data(psmouse, alps_get_mt_count(f->mt));
1128*4882a593Smuzhiyun
1129*4882a593Smuzhiyun input_mt_report_finger_count(dev, f->fingers);
1130*4882a593Smuzhiyun
1131*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, f->left);
1132*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, f->right);
1133*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, f->middle);
1134*4882a593Smuzhiyun
1135*4882a593Smuzhiyun input_sync(dev);
1136*4882a593Smuzhiyun }
1137*4882a593Smuzhiyun
alps_process_packet_v7(struct psmouse * psmouse)1138*4882a593Smuzhiyun static void alps_process_packet_v7(struct psmouse *psmouse)
1139*4882a593Smuzhiyun {
1140*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
1141*4882a593Smuzhiyun
1142*4882a593Smuzhiyun if (packet[0] == 0x48 && (packet[4] & 0x47) == 0x06)
1143*4882a593Smuzhiyun alps_process_trackstick_packet_v7(psmouse);
1144*4882a593Smuzhiyun else
1145*4882a593Smuzhiyun alps_process_touchpad_packet_v7(psmouse);
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun
alps_get_pkt_id_ss4_v2(unsigned char * byte)1148*4882a593Smuzhiyun static enum SS4_PACKET_ID alps_get_pkt_id_ss4_v2(unsigned char *byte)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun enum SS4_PACKET_ID pkt_id = SS4_PACKET_ID_IDLE;
1151*4882a593Smuzhiyun
1152*4882a593Smuzhiyun switch (byte[3] & 0x30) {
1153*4882a593Smuzhiyun case 0x00:
1154*4882a593Smuzhiyun if (SS4_IS_IDLE_V2(byte)) {
1155*4882a593Smuzhiyun pkt_id = SS4_PACKET_ID_IDLE;
1156*4882a593Smuzhiyun } else {
1157*4882a593Smuzhiyun pkt_id = SS4_PACKET_ID_ONE;
1158*4882a593Smuzhiyun }
1159*4882a593Smuzhiyun break;
1160*4882a593Smuzhiyun case 0x10:
1161*4882a593Smuzhiyun /* two-finger finger positions */
1162*4882a593Smuzhiyun pkt_id = SS4_PACKET_ID_TWO;
1163*4882a593Smuzhiyun break;
1164*4882a593Smuzhiyun case 0x20:
1165*4882a593Smuzhiyun /* stick pointer */
1166*4882a593Smuzhiyun pkt_id = SS4_PACKET_ID_STICK;
1167*4882a593Smuzhiyun break;
1168*4882a593Smuzhiyun case 0x30:
1169*4882a593Smuzhiyun /* third and fourth finger positions */
1170*4882a593Smuzhiyun pkt_id = SS4_PACKET_ID_MULTI;
1171*4882a593Smuzhiyun break;
1172*4882a593Smuzhiyun }
1173*4882a593Smuzhiyun
1174*4882a593Smuzhiyun return pkt_id;
1175*4882a593Smuzhiyun }
1176*4882a593Smuzhiyun
alps_decode_ss4_v2(struct alps_fields * f,unsigned char * p,struct psmouse * psmouse)1177*4882a593Smuzhiyun static int alps_decode_ss4_v2(struct alps_fields *f,
1178*4882a593Smuzhiyun unsigned char *p, struct psmouse *psmouse)
1179*4882a593Smuzhiyun {
1180*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1181*4882a593Smuzhiyun enum SS4_PACKET_ID pkt_id;
1182*4882a593Smuzhiyun unsigned int no_data_x, no_data_y;
1183*4882a593Smuzhiyun
1184*4882a593Smuzhiyun pkt_id = alps_get_pkt_id_ss4_v2(p);
1185*4882a593Smuzhiyun
1186*4882a593Smuzhiyun /* Current packet is 1Finger coordinate packet */
1187*4882a593Smuzhiyun switch (pkt_id) {
1188*4882a593Smuzhiyun case SS4_PACKET_ID_ONE:
1189*4882a593Smuzhiyun f->mt[0].x = SS4_1F_X_V2(p);
1190*4882a593Smuzhiyun f->mt[0].y = SS4_1F_Y_V2(p);
1191*4882a593Smuzhiyun f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f;
1192*4882a593Smuzhiyun /*
1193*4882a593Smuzhiyun * When a button is held the device will give us events
1194*4882a593Smuzhiyun * with x, y, and pressure of 0. This causes annoying jumps
1195*4882a593Smuzhiyun * if a touch is released while the button is held.
1196*4882a593Smuzhiyun * Handle this by claiming zero contacts.
1197*4882a593Smuzhiyun */
1198*4882a593Smuzhiyun f->fingers = f->pressure > 0 ? 1 : 0;
1199*4882a593Smuzhiyun f->first_mp = 0;
1200*4882a593Smuzhiyun f->is_mp = 0;
1201*4882a593Smuzhiyun break;
1202*4882a593Smuzhiyun
1203*4882a593Smuzhiyun case SS4_PACKET_ID_TWO:
1204*4882a593Smuzhiyun if (priv->flags & ALPS_BUTTONPAD) {
1205*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
1206*4882a593Smuzhiyun f->mt[0].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
1207*4882a593Smuzhiyun f->mt[1].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
1208*4882a593Smuzhiyun } else {
1209*4882a593Smuzhiyun f->mt[0].x = SS4_BTL_MF_X_V2(p, 0);
1210*4882a593Smuzhiyun f->mt[1].x = SS4_BTL_MF_X_V2(p, 1);
1211*4882a593Smuzhiyun }
1212*4882a593Smuzhiyun f->mt[0].y = SS4_BTL_MF_Y_V2(p, 0);
1213*4882a593Smuzhiyun f->mt[1].y = SS4_BTL_MF_Y_V2(p, 1);
1214*4882a593Smuzhiyun } else {
1215*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
1216*4882a593Smuzhiyun f->mt[0].x = SS4_PLUS_STD_MF_X_V2(p, 0);
1217*4882a593Smuzhiyun f->mt[1].x = SS4_PLUS_STD_MF_X_V2(p, 1);
1218*4882a593Smuzhiyun } else {
1219*4882a593Smuzhiyun f->mt[0].x = SS4_STD_MF_X_V2(p, 0);
1220*4882a593Smuzhiyun f->mt[1].x = SS4_STD_MF_X_V2(p, 1);
1221*4882a593Smuzhiyun }
1222*4882a593Smuzhiyun f->mt[0].y = SS4_STD_MF_Y_V2(p, 0);
1223*4882a593Smuzhiyun f->mt[1].y = SS4_STD_MF_Y_V2(p, 1);
1224*4882a593Smuzhiyun }
1225*4882a593Smuzhiyun f->pressure = SS4_MF_Z_V2(p, 0) ? 0x30 : 0;
1226*4882a593Smuzhiyun
1227*4882a593Smuzhiyun if (SS4_IS_MF_CONTINUE(p)) {
1228*4882a593Smuzhiyun f->first_mp = 1;
1229*4882a593Smuzhiyun } else {
1230*4882a593Smuzhiyun f->fingers = 2;
1231*4882a593Smuzhiyun f->first_mp = 0;
1232*4882a593Smuzhiyun }
1233*4882a593Smuzhiyun f->is_mp = 0;
1234*4882a593Smuzhiyun
1235*4882a593Smuzhiyun break;
1236*4882a593Smuzhiyun
1237*4882a593Smuzhiyun case SS4_PACKET_ID_MULTI:
1238*4882a593Smuzhiyun if (priv->flags & ALPS_BUTTONPAD) {
1239*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
1240*4882a593Smuzhiyun f->mt[2].x = SS4_PLUS_BTL_MF_X_V2(p, 0);
1241*4882a593Smuzhiyun f->mt[3].x = SS4_PLUS_BTL_MF_X_V2(p, 1);
1242*4882a593Smuzhiyun no_data_x = SS4_PLUS_MFPACKET_NO_AX_BL;
1243*4882a593Smuzhiyun } else {
1244*4882a593Smuzhiyun f->mt[2].x = SS4_BTL_MF_X_V2(p, 0);
1245*4882a593Smuzhiyun f->mt[3].x = SS4_BTL_MF_X_V2(p, 1);
1246*4882a593Smuzhiyun no_data_x = SS4_MFPACKET_NO_AX_BL;
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun no_data_y = SS4_MFPACKET_NO_AY_BL;
1249*4882a593Smuzhiyun
1250*4882a593Smuzhiyun f->mt[2].y = SS4_BTL_MF_Y_V2(p, 0);
1251*4882a593Smuzhiyun f->mt[3].y = SS4_BTL_MF_Y_V2(p, 1);
1252*4882a593Smuzhiyun } else {
1253*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
1254*4882a593Smuzhiyun f->mt[2].x = SS4_PLUS_STD_MF_X_V2(p, 0);
1255*4882a593Smuzhiyun f->mt[3].x = SS4_PLUS_STD_MF_X_V2(p, 1);
1256*4882a593Smuzhiyun no_data_x = SS4_PLUS_MFPACKET_NO_AX;
1257*4882a593Smuzhiyun } else {
1258*4882a593Smuzhiyun f->mt[2].x = SS4_STD_MF_X_V2(p, 0);
1259*4882a593Smuzhiyun f->mt[3].x = SS4_STD_MF_X_V2(p, 1);
1260*4882a593Smuzhiyun no_data_x = SS4_MFPACKET_NO_AX;
1261*4882a593Smuzhiyun }
1262*4882a593Smuzhiyun no_data_y = SS4_MFPACKET_NO_AY;
1263*4882a593Smuzhiyun
1264*4882a593Smuzhiyun f->mt[2].y = SS4_STD_MF_Y_V2(p, 0);
1265*4882a593Smuzhiyun f->mt[3].y = SS4_STD_MF_Y_V2(p, 1);
1266*4882a593Smuzhiyun }
1267*4882a593Smuzhiyun
1268*4882a593Smuzhiyun f->first_mp = 0;
1269*4882a593Smuzhiyun f->is_mp = 1;
1270*4882a593Smuzhiyun
1271*4882a593Smuzhiyun if (SS4_IS_5F_DETECTED(p)) {
1272*4882a593Smuzhiyun f->fingers = 5;
1273*4882a593Smuzhiyun } else if (f->mt[3].x == no_data_x &&
1274*4882a593Smuzhiyun f->mt[3].y == no_data_y) {
1275*4882a593Smuzhiyun f->mt[3].x = 0;
1276*4882a593Smuzhiyun f->mt[3].y = 0;
1277*4882a593Smuzhiyun f->fingers = 3;
1278*4882a593Smuzhiyun } else {
1279*4882a593Smuzhiyun f->fingers = 4;
1280*4882a593Smuzhiyun }
1281*4882a593Smuzhiyun break;
1282*4882a593Smuzhiyun
1283*4882a593Smuzhiyun case SS4_PACKET_ID_STICK:
1284*4882a593Smuzhiyun /*
1285*4882a593Smuzhiyun * x, y, and pressure are decoded in
1286*4882a593Smuzhiyun * alps_process_packet_ss4_v2()
1287*4882a593Smuzhiyun */
1288*4882a593Smuzhiyun f->first_mp = 0;
1289*4882a593Smuzhiyun f->is_mp = 0;
1290*4882a593Smuzhiyun break;
1291*4882a593Smuzhiyun
1292*4882a593Smuzhiyun case SS4_PACKET_ID_IDLE:
1293*4882a593Smuzhiyun default:
1294*4882a593Smuzhiyun memset(f, 0, sizeof(struct alps_fields));
1295*4882a593Smuzhiyun break;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun
1298*4882a593Smuzhiyun /* handle buttons */
1299*4882a593Smuzhiyun if (pkt_id == SS4_PACKET_ID_STICK) {
1300*4882a593Smuzhiyun f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
1301*4882a593Smuzhiyun f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
1302*4882a593Smuzhiyun f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
1303*4882a593Smuzhiyun } else {
1304*4882a593Smuzhiyun f->left = !!(SS4_BTN_V2(p) & 0x01);
1305*4882a593Smuzhiyun if (!(priv->flags & ALPS_BUTTONPAD)) {
1306*4882a593Smuzhiyun f->right = !!(SS4_BTN_V2(p) & 0x02);
1307*4882a593Smuzhiyun f->middle = !!(SS4_BTN_V2(p) & 0x04);
1308*4882a593Smuzhiyun }
1309*4882a593Smuzhiyun }
1310*4882a593Smuzhiyun
1311*4882a593Smuzhiyun return 0;
1312*4882a593Smuzhiyun }
1313*4882a593Smuzhiyun
alps_process_packet_ss4_v2(struct psmouse * psmouse)1314*4882a593Smuzhiyun static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
1315*4882a593Smuzhiyun {
1316*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1317*4882a593Smuzhiyun unsigned char *packet = psmouse->packet;
1318*4882a593Smuzhiyun struct input_dev *dev = psmouse->dev;
1319*4882a593Smuzhiyun struct input_dev *dev2 = priv->dev2;
1320*4882a593Smuzhiyun struct alps_fields *f = &priv->f;
1321*4882a593Smuzhiyun
1322*4882a593Smuzhiyun memset(f, 0, sizeof(struct alps_fields));
1323*4882a593Smuzhiyun priv->decode_fields(f, packet, psmouse);
1324*4882a593Smuzhiyun if (priv->multi_packet) {
1325*4882a593Smuzhiyun /*
1326*4882a593Smuzhiyun * Sometimes the first packet will indicate a multi-packet
1327*4882a593Smuzhiyun * sequence, but sometimes the next multi-packet would not
1328*4882a593Smuzhiyun * come. Check for this, and when it happens process the
1329*4882a593Smuzhiyun * position packet as usual.
1330*4882a593Smuzhiyun */
1331*4882a593Smuzhiyun if (f->is_mp) {
1332*4882a593Smuzhiyun /* Now process the 1st packet */
1333*4882a593Smuzhiyun priv->decode_fields(f, priv->multi_data, psmouse);
1334*4882a593Smuzhiyun } else {
1335*4882a593Smuzhiyun priv->multi_packet = 0;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun }
1338*4882a593Smuzhiyun
1339*4882a593Smuzhiyun /*
1340*4882a593Smuzhiyun * "f.is_mp" would always be '0' after merging the 1st and 2nd packet.
1341*4882a593Smuzhiyun * When it is set, it means 2nd packet comes without 1st packet come.
1342*4882a593Smuzhiyun */
1343*4882a593Smuzhiyun if (f->is_mp)
1344*4882a593Smuzhiyun return;
1345*4882a593Smuzhiyun
1346*4882a593Smuzhiyun /* Save the first packet */
1347*4882a593Smuzhiyun if (!priv->multi_packet && f->first_mp) {
1348*4882a593Smuzhiyun priv->multi_packet = 1;
1349*4882a593Smuzhiyun memcpy(priv->multi_data, packet, sizeof(priv->multi_data));
1350*4882a593Smuzhiyun return;
1351*4882a593Smuzhiyun }
1352*4882a593Smuzhiyun
1353*4882a593Smuzhiyun priv->multi_packet = 0;
1354*4882a593Smuzhiyun
1355*4882a593Smuzhiyun /* Report trackstick */
1356*4882a593Smuzhiyun if (alps_get_pkt_id_ss4_v2(packet) == SS4_PACKET_ID_STICK) {
1357*4882a593Smuzhiyun if (!(priv->flags & ALPS_DUALPOINT)) {
1358*4882a593Smuzhiyun psmouse_warn(psmouse,
1359*4882a593Smuzhiyun "Rejected trackstick packet from non DualPoint device");
1360*4882a593Smuzhiyun return;
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun
1363*4882a593Smuzhiyun input_report_rel(dev2, REL_X, SS4_TS_X_V2(packet));
1364*4882a593Smuzhiyun input_report_rel(dev2, REL_Y, SS4_TS_Y_V2(packet));
1365*4882a593Smuzhiyun input_report_abs(dev2, ABS_PRESSURE, SS4_TS_Z_V2(packet));
1366*4882a593Smuzhiyun
1367*4882a593Smuzhiyun input_report_key(dev2, BTN_LEFT, f->ts_left);
1368*4882a593Smuzhiyun input_report_key(dev2, BTN_RIGHT, f->ts_right);
1369*4882a593Smuzhiyun input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
1370*4882a593Smuzhiyun
1371*4882a593Smuzhiyun input_sync(dev2);
1372*4882a593Smuzhiyun return;
1373*4882a593Smuzhiyun }
1374*4882a593Smuzhiyun
1375*4882a593Smuzhiyun /* Report touchpad */
1376*4882a593Smuzhiyun alps_report_mt_data(psmouse, (f->fingers <= 4) ? f->fingers : 4);
1377*4882a593Smuzhiyun
1378*4882a593Smuzhiyun input_mt_report_finger_count(dev, f->fingers);
1379*4882a593Smuzhiyun
1380*4882a593Smuzhiyun input_report_key(dev, BTN_LEFT, f->left);
1381*4882a593Smuzhiyun input_report_key(dev, BTN_RIGHT, f->right);
1382*4882a593Smuzhiyun input_report_key(dev, BTN_MIDDLE, f->middle);
1383*4882a593Smuzhiyun
1384*4882a593Smuzhiyun input_report_abs(dev, ABS_PRESSURE, f->pressure);
1385*4882a593Smuzhiyun input_sync(dev);
1386*4882a593Smuzhiyun }
1387*4882a593Smuzhiyun
alps_is_valid_package_ss4_v2(struct psmouse * psmouse)1388*4882a593Smuzhiyun static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
1389*4882a593Smuzhiyun {
1390*4882a593Smuzhiyun if (psmouse->pktcnt == 4 && ((psmouse->packet[3] & 0x08) != 0x08))
1391*4882a593Smuzhiyun return false;
1392*4882a593Smuzhiyun if (psmouse->pktcnt == 6 && ((psmouse->packet[5] & 0x10) != 0x0))
1393*4882a593Smuzhiyun return false;
1394*4882a593Smuzhiyun return true;
1395*4882a593Smuzhiyun }
1396*4882a593Smuzhiyun
1397*4882a593Smuzhiyun static DEFINE_MUTEX(alps_mutex);
1398*4882a593Smuzhiyun
alps_register_bare_ps2_mouse(struct work_struct * work)1399*4882a593Smuzhiyun static void alps_register_bare_ps2_mouse(struct work_struct *work)
1400*4882a593Smuzhiyun {
1401*4882a593Smuzhiyun struct alps_data *priv =
1402*4882a593Smuzhiyun container_of(work, struct alps_data, dev3_register_work.work);
1403*4882a593Smuzhiyun struct psmouse *psmouse = priv->psmouse;
1404*4882a593Smuzhiyun struct input_dev *dev3;
1405*4882a593Smuzhiyun int error = 0;
1406*4882a593Smuzhiyun
1407*4882a593Smuzhiyun mutex_lock(&alps_mutex);
1408*4882a593Smuzhiyun
1409*4882a593Smuzhiyun if (priv->dev3)
1410*4882a593Smuzhiyun goto out;
1411*4882a593Smuzhiyun
1412*4882a593Smuzhiyun dev3 = input_allocate_device();
1413*4882a593Smuzhiyun if (!dev3) {
1414*4882a593Smuzhiyun psmouse_err(psmouse, "failed to allocate secondary device\n");
1415*4882a593Smuzhiyun error = -ENOMEM;
1416*4882a593Smuzhiyun goto out;
1417*4882a593Smuzhiyun }
1418*4882a593Smuzhiyun
1419*4882a593Smuzhiyun snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
1420*4882a593Smuzhiyun psmouse->ps2dev.serio->phys,
1421*4882a593Smuzhiyun (priv->dev2 ? "input2" : "input1"));
1422*4882a593Smuzhiyun dev3->phys = priv->phys3;
1423*4882a593Smuzhiyun
1424*4882a593Smuzhiyun /*
1425*4882a593Smuzhiyun * format of input device name is: "protocol vendor name"
1426*4882a593Smuzhiyun * see function psmouse_switch_protocol() in psmouse-base.c
1427*4882a593Smuzhiyun */
1428*4882a593Smuzhiyun dev3->name = "PS/2 ALPS Mouse";
1429*4882a593Smuzhiyun
1430*4882a593Smuzhiyun dev3->id.bustype = BUS_I8042;
1431*4882a593Smuzhiyun dev3->id.vendor = 0x0002;
1432*4882a593Smuzhiyun dev3->id.product = PSMOUSE_PS2;
1433*4882a593Smuzhiyun dev3->id.version = 0x0000;
1434*4882a593Smuzhiyun dev3->dev.parent = &psmouse->ps2dev.serio->dev;
1435*4882a593Smuzhiyun
1436*4882a593Smuzhiyun input_set_capability(dev3, EV_REL, REL_X);
1437*4882a593Smuzhiyun input_set_capability(dev3, EV_REL, REL_Y);
1438*4882a593Smuzhiyun input_set_capability(dev3, EV_KEY, BTN_LEFT);
1439*4882a593Smuzhiyun input_set_capability(dev3, EV_KEY, BTN_RIGHT);
1440*4882a593Smuzhiyun input_set_capability(dev3, EV_KEY, BTN_MIDDLE);
1441*4882a593Smuzhiyun
1442*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTER, dev3->propbit);
1443*4882a593Smuzhiyun
1444*4882a593Smuzhiyun error = input_register_device(dev3);
1445*4882a593Smuzhiyun if (error) {
1446*4882a593Smuzhiyun psmouse_err(psmouse,
1447*4882a593Smuzhiyun "failed to register secondary device: %d\n",
1448*4882a593Smuzhiyun error);
1449*4882a593Smuzhiyun input_free_device(dev3);
1450*4882a593Smuzhiyun goto out;
1451*4882a593Smuzhiyun }
1452*4882a593Smuzhiyun
1453*4882a593Smuzhiyun priv->dev3 = dev3;
1454*4882a593Smuzhiyun
1455*4882a593Smuzhiyun out:
1456*4882a593Smuzhiyun /*
1457*4882a593Smuzhiyun * Save the error code so that we can detect that we
1458*4882a593Smuzhiyun * already tried to create the device.
1459*4882a593Smuzhiyun */
1460*4882a593Smuzhiyun if (error)
1461*4882a593Smuzhiyun priv->dev3 = ERR_PTR(error);
1462*4882a593Smuzhiyun
1463*4882a593Smuzhiyun mutex_unlock(&alps_mutex);
1464*4882a593Smuzhiyun }
1465*4882a593Smuzhiyun
alps_report_bare_ps2_packet(struct psmouse * psmouse,unsigned char packet[],bool report_buttons)1466*4882a593Smuzhiyun static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
1467*4882a593Smuzhiyun unsigned char packet[],
1468*4882a593Smuzhiyun bool report_buttons)
1469*4882a593Smuzhiyun {
1470*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1471*4882a593Smuzhiyun struct input_dev *dev, *dev2 = NULL;
1472*4882a593Smuzhiyun
1473*4882a593Smuzhiyun /* Figure out which device to use to report the bare packet */
1474*4882a593Smuzhiyun if (priv->proto_version == ALPS_PROTO_V2 &&
1475*4882a593Smuzhiyun (priv->flags & ALPS_DUALPOINT)) {
1476*4882a593Smuzhiyun /* On V2 devices the DualPoint Stick reports bare packets */
1477*4882a593Smuzhiyun dev = priv->dev2;
1478*4882a593Smuzhiyun dev2 = psmouse->dev;
1479*4882a593Smuzhiyun } else if (unlikely(IS_ERR_OR_NULL(priv->dev3))) {
1480*4882a593Smuzhiyun /* Register dev3 mouse if we received PS/2 packet first time */
1481*4882a593Smuzhiyun if (!IS_ERR(priv->dev3))
1482*4882a593Smuzhiyun psmouse_queue_work(psmouse, &priv->dev3_register_work,
1483*4882a593Smuzhiyun 0);
1484*4882a593Smuzhiyun return;
1485*4882a593Smuzhiyun } else {
1486*4882a593Smuzhiyun dev = priv->dev3;
1487*4882a593Smuzhiyun }
1488*4882a593Smuzhiyun
1489*4882a593Smuzhiyun if (report_buttons)
1490*4882a593Smuzhiyun alps_report_buttons(dev, dev2,
1491*4882a593Smuzhiyun packet[0] & 1, packet[0] & 2, packet[0] & 4);
1492*4882a593Smuzhiyun
1493*4882a593Smuzhiyun psmouse_report_standard_motion(dev, packet);
1494*4882a593Smuzhiyun
1495*4882a593Smuzhiyun input_sync(dev);
1496*4882a593Smuzhiyun }
1497*4882a593Smuzhiyun
alps_handle_interleaved_ps2(struct psmouse * psmouse)1498*4882a593Smuzhiyun static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
1499*4882a593Smuzhiyun {
1500*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1501*4882a593Smuzhiyun
1502*4882a593Smuzhiyun if (psmouse->pktcnt < 6)
1503*4882a593Smuzhiyun return PSMOUSE_GOOD_DATA;
1504*4882a593Smuzhiyun
1505*4882a593Smuzhiyun if (psmouse->pktcnt == 6) {
1506*4882a593Smuzhiyun /*
1507*4882a593Smuzhiyun * Start a timer to flush the packet if it ends up last
1508*4882a593Smuzhiyun * 6-byte packet in the stream. Timer needs to fire
1509*4882a593Smuzhiyun * psmouse core times out itself. 20 ms should be enough
1510*4882a593Smuzhiyun * to decide if we are getting more data or not.
1511*4882a593Smuzhiyun */
1512*4882a593Smuzhiyun mod_timer(&priv->timer, jiffies + msecs_to_jiffies(20));
1513*4882a593Smuzhiyun return PSMOUSE_GOOD_DATA;
1514*4882a593Smuzhiyun }
1515*4882a593Smuzhiyun
1516*4882a593Smuzhiyun del_timer(&priv->timer);
1517*4882a593Smuzhiyun
1518*4882a593Smuzhiyun if (psmouse->packet[6] & 0x80) {
1519*4882a593Smuzhiyun
1520*4882a593Smuzhiyun /*
1521*4882a593Smuzhiyun * Highest bit is set - that means we either had
1522*4882a593Smuzhiyun * complete ALPS packet and this is start of the
1523*4882a593Smuzhiyun * next packet or we got garbage.
1524*4882a593Smuzhiyun */
1525*4882a593Smuzhiyun
1526*4882a593Smuzhiyun if (((psmouse->packet[3] |
1527*4882a593Smuzhiyun psmouse->packet[4] |
1528*4882a593Smuzhiyun psmouse->packet[5]) & 0x80) ||
1529*4882a593Smuzhiyun (!alps_is_valid_first_byte(priv, psmouse->packet[6]))) {
1530*4882a593Smuzhiyun psmouse_dbg(psmouse,
1531*4882a593Smuzhiyun "refusing packet %4ph (suspected interleaved ps/2)\n",
1532*4882a593Smuzhiyun psmouse->packet + 3);
1533*4882a593Smuzhiyun return PSMOUSE_BAD_DATA;
1534*4882a593Smuzhiyun }
1535*4882a593Smuzhiyun
1536*4882a593Smuzhiyun priv->process_packet(psmouse);
1537*4882a593Smuzhiyun
1538*4882a593Smuzhiyun /* Continue with the next packet */
1539*4882a593Smuzhiyun psmouse->packet[0] = psmouse->packet[6];
1540*4882a593Smuzhiyun psmouse->pktcnt = 1;
1541*4882a593Smuzhiyun
1542*4882a593Smuzhiyun } else {
1543*4882a593Smuzhiyun
1544*4882a593Smuzhiyun /*
1545*4882a593Smuzhiyun * High bit is 0 - that means that we indeed got a PS/2
1546*4882a593Smuzhiyun * packet in the middle of ALPS packet.
1547*4882a593Smuzhiyun *
1548*4882a593Smuzhiyun * There is also possibility that we got 6-byte ALPS
1549*4882a593Smuzhiyun * packet followed by 3-byte packet from trackpoint. We
1550*4882a593Smuzhiyun * can not distinguish between these 2 scenarios but
1551*4882a593Smuzhiyun * because the latter is unlikely to happen in course of
1552*4882a593Smuzhiyun * normal operation (user would need to press all
1553*4882a593Smuzhiyun * buttons on the pad and start moving trackpoint
1554*4882a593Smuzhiyun * without touching the pad surface) we assume former.
1555*4882a593Smuzhiyun * Even if we are wrong the wost thing that would happen
1556*4882a593Smuzhiyun * the cursor would jump but we should not get protocol
1557*4882a593Smuzhiyun * de-synchronization.
1558*4882a593Smuzhiyun */
1559*4882a593Smuzhiyun
1560*4882a593Smuzhiyun alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
1561*4882a593Smuzhiyun false);
1562*4882a593Smuzhiyun
1563*4882a593Smuzhiyun /*
1564*4882a593Smuzhiyun * Continue with the standard ALPS protocol handling,
1565*4882a593Smuzhiyun * but make sure we won't process it as an interleaved
1566*4882a593Smuzhiyun * packet again, which may happen if all buttons are
1567*4882a593Smuzhiyun * pressed. To avoid this let's reset the 4th bit which
1568*4882a593Smuzhiyun * is normally 1.
1569*4882a593Smuzhiyun */
1570*4882a593Smuzhiyun psmouse->packet[3] = psmouse->packet[6] & 0xf7;
1571*4882a593Smuzhiyun psmouse->pktcnt = 4;
1572*4882a593Smuzhiyun }
1573*4882a593Smuzhiyun
1574*4882a593Smuzhiyun return PSMOUSE_GOOD_DATA;
1575*4882a593Smuzhiyun }
1576*4882a593Smuzhiyun
alps_flush_packet(struct timer_list * t)1577*4882a593Smuzhiyun static void alps_flush_packet(struct timer_list *t)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun struct alps_data *priv = from_timer(priv, t, timer);
1580*4882a593Smuzhiyun struct psmouse *psmouse = priv->psmouse;
1581*4882a593Smuzhiyun
1582*4882a593Smuzhiyun serio_pause_rx(psmouse->ps2dev.serio);
1583*4882a593Smuzhiyun
1584*4882a593Smuzhiyun if (psmouse->pktcnt == psmouse->pktsize) {
1585*4882a593Smuzhiyun
1586*4882a593Smuzhiyun /*
1587*4882a593Smuzhiyun * We did not any more data in reasonable amount of time.
1588*4882a593Smuzhiyun * Validate the last 3 bytes and process as a standard
1589*4882a593Smuzhiyun * ALPS packet.
1590*4882a593Smuzhiyun */
1591*4882a593Smuzhiyun if ((psmouse->packet[3] |
1592*4882a593Smuzhiyun psmouse->packet[4] |
1593*4882a593Smuzhiyun psmouse->packet[5]) & 0x80) {
1594*4882a593Smuzhiyun psmouse_dbg(psmouse,
1595*4882a593Smuzhiyun "refusing packet %3ph (suspected interleaved ps/2)\n",
1596*4882a593Smuzhiyun psmouse->packet + 3);
1597*4882a593Smuzhiyun } else {
1598*4882a593Smuzhiyun priv->process_packet(psmouse);
1599*4882a593Smuzhiyun }
1600*4882a593Smuzhiyun psmouse->pktcnt = 0;
1601*4882a593Smuzhiyun }
1602*4882a593Smuzhiyun
1603*4882a593Smuzhiyun serio_continue_rx(psmouse->ps2dev.serio);
1604*4882a593Smuzhiyun }
1605*4882a593Smuzhiyun
alps_process_byte(struct psmouse * psmouse)1606*4882a593Smuzhiyun static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
1607*4882a593Smuzhiyun {
1608*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1609*4882a593Smuzhiyun
1610*4882a593Smuzhiyun /*
1611*4882a593Smuzhiyun * Check if we are dealing with a bare PS/2 packet, presumably from
1612*4882a593Smuzhiyun * a device connected to the external PS/2 port. Because bare PS/2
1613*4882a593Smuzhiyun * protocol does not have enough constant bits to self-synchronize
1614*4882a593Smuzhiyun * properly we only do this if the device is fully synchronized.
1615*4882a593Smuzhiyun * Can not distinguish V8's first byte from PS/2 packet's
1616*4882a593Smuzhiyun */
1617*4882a593Smuzhiyun if (priv->proto_version != ALPS_PROTO_V8 &&
1618*4882a593Smuzhiyun !psmouse->out_of_sync_cnt &&
1619*4882a593Smuzhiyun (psmouse->packet[0] & 0xc8) == 0x08) {
1620*4882a593Smuzhiyun
1621*4882a593Smuzhiyun if (psmouse->pktcnt == 3) {
1622*4882a593Smuzhiyun alps_report_bare_ps2_packet(psmouse, psmouse->packet,
1623*4882a593Smuzhiyun true);
1624*4882a593Smuzhiyun return PSMOUSE_FULL_PACKET;
1625*4882a593Smuzhiyun }
1626*4882a593Smuzhiyun return PSMOUSE_GOOD_DATA;
1627*4882a593Smuzhiyun }
1628*4882a593Smuzhiyun
1629*4882a593Smuzhiyun /* Check for PS/2 packet stuffed in the middle of ALPS packet. */
1630*4882a593Smuzhiyun
1631*4882a593Smuzhiyun if ((priv->flags & ALPS_PS2_INTERLEAVED) &&
1632*4882a593Smuzhiyun psmouse->pktcnt >= 4 && (psmouse->packet[3] & 0x0f) == 0x0f) {
1633*4882a593Smuzhiyun return alps_handle_interleaved_ps2(psmouse);
1634*4882a593Smuzhiyun }
1635*4882a593Smuzhiyun
1636*4882a593Smuzhiyun if (!alps_is_valid_first_byte(priv, psmouse->packet[0])) {
1637*4882a593Smuzhiyun psmouse_dbg(psmouse,
1638*4882a593Smuzhiyun "refusing packet[0] = %x (mask0 = %x, byte0 = %x)\n",
1639*4882a593Smuzhiyun psmouse->packet[0], priv->mask0, priv->byte0);
1640*4882a593Smuzhiyun return PSMOUSE_BAD_DATA;
1641*4882a593Smuzhiyun }
1642*4882a593Smuzhiyun
1643*4882a593Smuzhiyun /* Bytes 2 - pktsize should have 0 in the highest bit */
1644*4882a593Smuzhiyun if (priv->proto_version < ALPS_PROTO_V5 &&
1645*4882a593Smuzhiyun psmouse->pktcnt >= 2 && psmouse->pktcnt <= psmouse->pktsize &&
1646*4882a593Smuzhiyun (psmouse->packet[psmouse->pktcnt - 1] & 0x80)) {
1647*4882a593Smuzhiyun psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
1648*4882a593Smuzhiyun psmouse->pktcnt - 1,
1649*4882a593Smuzhiyun psmouse->packet[psmouse->pktcnt - 1]);
1650*4882a593Smuzhiyun
1651*4882a593Smuzhiyun if (priv->proto_version == ALPS_PROTO_V3_RUSHMORE &&
1652*4882a593Smuzhiyun psmouse->pktcnt == psmouse->pktsize) {
1653*4882a593Smuzhiyun /*
1654*4882a593Smuzhiyun * Some Dell boxes, such as Latitude E6440 or E7440
1655*4882a593Smuzhiyun * with closed lid, quite often smash last byte of
1656*4882a593Smuzhiyun * otherwise valid packet with 0xff. Given that the
1657*4882a593Smuzhiyun * next packet is very likely to be valid let's
1658*4882a593Smuzhiyun * report PSMOUSE_FULL_PACKET but not process data,
1659*4882a593Smuzhiyun * rather than reporting PSMOUSE_BAD_DATA and
1660*4882a593Smuzhiyun * filling the logs.
1661*4882a593Smuzhiyun */
1662*4882a593Smuzhiyun return PSMOUSE_FULL_PACKET;
1663*4882a593Smuzhiyun }
1664*4882a593Smuzhiyun
1665*4882a593Smuzhiyun return PSMOUSE_BAD_DATA;
1666*4882a593Smuzhiyun }
1667*4882a593Smuzhiyun
1668*4882a593Smuzhiyun if ((priv->proto_version == ALPS_PROTO_V7 &&
1669*4882a593Smuzhiyun !alps_is_valid_package_v7(psmouse)) ||
1670*4882a593Smuzhiyun (priv->proto_version == ALPS_PROTO_V8 &&
1671*4882a593Smuzhiyun !alps_is_valid_package_ss4_v2(psmouse))) {
1672*4882a593Smuzhiyun psmouse_dbg(psmouse, "refusing packet[%i] = %x\n",
1673*4882a593Smuzhiyun psmouse->pktcnt - 1,
1674*4882a593Smuzhiyun psmouse->packet[psmouse->pktcnt - 1]);
1675*4882a593Smuzhiyun return PSMOUSE_BAD_DATA;
1676*4882a593Smuzhiyun }
1677*4882a593Smuzhiyun
1678*4882a593Smuzhiyun if (psmouse->pktcnt == psmouse->pktsize) {
1679*4882a593Smuzhiyun priv->process_packet(psmouse);
1680*4882a593Smuzhiyun return PSMOUSE_FULL_PACKET;
1681*4882a593Smuzhiyun }
1682*4882a593Smuzhiyun
1683*4882a593Smuzhiyun return PSMOUSE_GOOD_DATA;
1684*4882a593Smuzhiyun }
1685*4882a593Smuzhiyun
alps_command_mode_send_nibble(struct psmouse * psmouse,int nibble)1686*4882a593Smuzhiyun static int alps_command_mode_send_nibble(struct psmouse *psmouse, int nibble)
1687*4882a593Smuzhiyun {
1688*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1689*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1690*4882a593Smuzhiyun int command;
1691*4882a593Smuzhiyun unsigned char *param;
1692*4882a593Smuzhiyun unsigned char dummy[4];
1693*4882a593Smuzhiyun
1694*4882a593Smuzhiyun BUG_ON(nibble > 0xf);
1695*4882a593Smuzhiyun
1696*4882a593Smuzhiyun command = priv->nibble_commands[nibble].command;
1697*4882a593Smuzhiyun param = (command & 0x0f00) ?
1698*4882a593Smuzhiyun dummy : (unsigned char *)&priv->nibble_commands[nibble].data;
1699*4882a593Smuzhiyun
1700*4882a593Smuzhiyun if (ps2_command(ps2dev, param, command))
1701*4882a593Smuzhiyun return -1;
1702*4882a593Smuzhiyun
1703*4882a593Smuzhiyun return 0;
1704*4882a593Smuzhiyun }
1705*4882a593Smuzhiyun
alps_command_mode_set_addr(struct psmouse * psmouse,int addr)1706*4882a593Smuzhiyun static int alps_command_mode_set_addr(struct psmouse *psmouse, int addr)
1707*4882a593Smuzhiyun {
1708*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1709*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1710*4882a593Smuzhiyun int i, nibble;
1711*4882a593Smuzhiyun
1712*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, priv->addr_command))
1713*4882a593Smuzhiyun return -1;
1714*4882a593Smuzhiyun
1715*4882a593Smuzhiyun for (i = 12; i >= 0; i -= 4) {
1716*4882a593Smuzhiyun nibble = (addr >> i) & 0xf;
1717*4882a593Smuzhiyun if (alps_command_mode_send_nibble(psmouse, nibble))
1718*4882a593Smuzhiyun return -1;
1719*4882a593Smuzhiyun }
1720*4882a593Smuzhiyun
1721*4882a593Smuzhiyun return 0;
1722*4882a593Smuzhiyun }
1723*4882a593Smuzhiyun
__alps_command_mode_read_reg(struct psmouse * psmouse,int addr)1724*4882a593Smuzhiyun static int __alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
1725*4882a593Smuzhiyun {
1726*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1727*4882a593Smuzhiyun unsigned char param[4];
1728*4882a593Smuzhiyun
1729*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
1730*4882a593Smuzhiyun return -1;
1731*4882a593Smuzhiyun
1732*4882a593Smuzhiyun /*
1733*4882a593Smuzhiyun * The address being read is returned in the first two bytes
1734*4882a593Smuzhiyun * of the result. Check that this address matches the expected
1735*4882a593Smuzhiyun * address.
1736*4882a593Smuzhiyun */
1737*4882a593Smuzhiyun if (addr != ((param[0] << 8) | param[1]))
1738*4882a593Smuzhiyun return -1;
1739*4882a593Smuzhiyun
1740*4882a593Smuzhiyun return param[2];
1741*4882a593Smuzhiyun }
1742*4882a593Smuzhiyun
alps_command_mode_read_reg(struct psmouse * psmouse,int addr)1743*4882a593Smuzhiyun static int alps_command_mode_read_reg(struct psmouse *psmouse, int addr)
1744*4882a593Smuzhiyun {
1745*4882a593Smuzhiyun if (alps_command_mode_set_addr(psmouse, addr))
1746*4882a593Smuzhiyun return -1;
1747*4882a593Smuzhiyun return __alps_command_mode_read_reg(psmouse, addr);
1748*4882a593Smuzhiyun }
1749*4882a593Smuzhiyun
__alps_command_mode_write_reg(struct psmouse * psmouse,u8 value)1750*4882a593Smuzhiyun static int __alps_command_mode_write_reg(struct psmouse *psmouse, u8 value)
1751*4882a593Smuzhiyun {
1752*4882a593Smuzhiyun if (alps_command_mode_send_nibble(psmouse, (value >> 4) & 0xf))
1753*4882a593Smuzhiyun return -1;
1754*4882a593Smuzhiyun if (alps_command_mode_send_nibble(psmouse, value & 0xf))
1755*4882a593Smuzhiyun return -1;
1756*4882a593Smuzhiyun return 0;
1757*4882a593Smuzhiyun }
1758*4882a593Smuzhiyun
alps_command_mode_write_reg(struct psmouse * psmouse,int addr,u8 value)1759*4882a593Smuzhiyun static int alps_command_mode_write_reg(struct psmouse *psmouse, int addr,
1760*4882a593Smuzhiyun u8 value)
1761*4882a593Smuzhiyun {
1762*4882a593Smuzhiyun if (alps_command_mode_set_addr(psmouse, addr))
1763*4882a593Smuzhiyun return -1;
1764*4882a593Smuzhiyun return __alps_command_mode_write_reg(psmouse, value);
1765*4882a593Smuzhiyun }
1766*4882a593Smuzhiyun
alps_rpt_cmd(struct psmouse * psmouse,int init_command,int repeated_command,unsigned char * param)1767*4882a593Smuzhiyun static int alps_rpt_cmd(struct psmouse *psmouse, int init_command,
1768*4882a593Smuzhiyun int repeated_command, unsigned char *param)
1769*4882a593Smuzhiyun {
1770*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1771*4882a593Smuzhiyun
1772*4882a593Smuzhiyun param[0] = 0;
1773*4882a593Smuzhiyun if (init_command && ps2_command(ps2dev, param, init_command))
1774*4882a593Smuzhiyun return -EIO;
1775*4882a593Smuzhiyun
1776*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, repeated_command) ||
1777*4882a593Smuzhiyun ps2_command(ps2dev, NULL, repeated_command) ||
1778*4882a593Smuzhiyun ps2_command(ps2dev, NULL, repeated_command))
1779*4882a593Smuzhiyun return -EIO;
1780*4882a593Smuzhiyun
1781*4882a593Smuzhiyun param[0] = param[1] = param[2] = 0xff;
1782*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
1783*4882a593Smuzhiyun return -EIO;
1784*4882a593Smuzhiyun
1785*4882a593Smuzhiyun psmouse_dbg(psmouse, "%2.2X report: %3ph\n",
1786*4882a593Smuzhiyun repeated_command, param);
1787*4882a593Smuzhiyun return 0;
1788*4882a593Smuzhiyun }
1789*4882a593Smuzhiyun
alps_check_valid_firmware_id(unsigned char id[])1790*4882a593Smuzhiyun static bool alps_check_valid_firmware_id(unsigned char id[])
1791*4882a593Smuzhiyun {
1792*4882a593Smuzhiyun if (id[0] == 0x73)
1793*4882a593Smuzhiyun return true;
1794*4882a593Smuzhiyun
1795*4882a593Smuzhiyun if (id[0] == 0x88 &&
1796*4882a593Smuzhiyun (id[1] == 0x07 ||
1797*4882a593Smuzhiyun id[1] == 0x08 ||
1798*4882a593Smuzhiyun (id[1] & 0xf0) == 0xb0 ||
1799*4882a593Smuzhiyun (id[1] & 0xf0) == 0xc0)) {
1800*4882a593Smuzhiyun return true;
1801*4882a593Smuzhiyun }
1802*4882a593Smuzhiyun
1803*4882a593Smuzhiyun return false;
1804*4882a593Smuzhiyun }
1805*4882a593Smuzhiyun
alps_enter_command_mode(struct psmouse * psmouse)1806*4882a593Smuzhiyun static int alps_enter_command_mode(struct psmouse *psmouse)
1807*4882a593Smuzhiyun {
1808*4882a593Smuzhiyun unsigned char param[4];
1809*4882a593Smuzhiyun
1810*4882a593Smuzhiyun if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_RESET_WRAP, param)) {
1811*4882a593Smuzhiyun psmouse_err(psmouse, "failed to enter command mode\n");
1812*4882a593Smuzhiyun return -1;
1813*4882a593Smuzhiyun }
1814*4882a593Smuzhiyun
1815*4882a593Smuzhiyun if (!alps_check_valid_firmware_id(param)) {
1816*4882a593Smuzhiyun psmouse_dbg(psmouse,
1817*4882a593Smuzhiyun "unknown response while entering command mode\n");
1818*4882a593Smuzhiyun return -1;
1819*4882a593Smuzhiyun }
1820*4882a593Smuzhiyun return 0;
1821*4882a593Smuzhiyun }
1822*4882a593Smuzhiyun
alps_exit_command_mode(struct psmouse * psmouse)1823*4882a593Smuzhiyun static inline int alps_exit_command_mode(struct psmouse *psmouse)
1824*4882a593Smuzhiyun {
1825*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1826*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM))
1827*4882a593Smuzhiyun return -1;
1828*4882a593Smuzhiyun return 0;
1829*4882a593Smuzhiyun }
1830*4882a593Smuzhiyun
1831*4882a593Smuzhiyun /*
1832*4882a593Smuzhiyun * For DualPoint devices select the device that should respond to
1833*4882a593Smuzhiyun * subsequent commands. It looks like glidepad is behind stickpointer,
1834*4882a593Smuzhiyun * I'd thought it would be other way around...
1835*4882a593Smuzhiyun */
alps_passthrough_mode_v2(struct psmouse * psmouse,bool enable)1836*4882a593Smuzhiyun static int alps_passthrough_mode_v2(struct psmouse *psmouse, bool enable)
1837*4882a593Smuzhiyun {
1838*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1839*4882a593Smuzhiyun int cmd = enable ? PSMOUSE_CMD_SETSCALE21 : PSMOUSE_CMD_SETSCALE11;
1840*4882a593Smuzhiyun
1841*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, cmd) ||
1842*4882a593Smuzhiyun ps2_command(ps2dev, NULL, cmd) ||
1843*4882a593Smuzhiyun ps2_command(ps2dev, NULL, cmd) ||
1844*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
1845*4882a593Smuzhiyun return -1;
1846*4882a593Smuzhiyun
1847*4882a593Smuzhiyun /* we may get 3 more bytes, just ignore them */
1848*4882a593Smuzhiyun ps2_drain(ps2dev, 3, 100);
1849*4882a593Smuzhiyun
1850*4882a593Smuzhiyun return 0;
1851*4882a593Smuzhiyun }
1852*4882a593Smuzhiyun
alps_absolute_mode_v1_v2(struct psmouse * psmouse)1853*4882a593Smuzhiyun static int alps_absolute_mode_v1_v2(struct psmouse *psmouse)
1854*4882a593Smuzhiyun {
1855*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1856*4882a593Smuzhiyun
1857*4882a593Smuzhiyun /* Try ALPS magic knock - 4 disable before enable */
1858*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1859*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1860*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1861*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1862*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
1863*4882a593Smuzhiyun return -1;
1864*4882a593Smuzhiyun
1865*4882a593Smuzhiyun /*
1866*4882a593Smuzhiyun * Switch mouse to poll (remote) mode so motion data will not
1867*4882a593Smuzhiyun * get in our way
1868*4882a593Smuzhiyun */
1869*4882a593Smuzhiyun return ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL);
1870*4882a593Smuzhiyun }
1871*4882a593Smuzhiyun
alps_monitor_mode_send_word(struct psmouse * psmouse,u16 word)1872*4882a593Smuzhiyun static int alps_monitor_mode_send_word(struct psmouse *psmouse, u16 word)
1873*4882a593Smuzhiyun {
1874*4882a593Smuzhiyun int i, nibble;
1875*4882a593Smuzhiyun
1876*4882a593Smuzhiyun /*
1877*4882a593Smuzhiyun * b0-b11 are valid bits, send sequence is inverse.
1878*4882a593Smuzhiyun * e.g. when word = 0x0123, nibble send sequence is 3, 2, 1
1879*4882a593Smuzhiyun */
1880*4882a593Smuzhiyun for (i = 0; i <= 8; i += 4) {
1881*4882a593Smuzhiyun nibble = (word >> i) & 0xf;
1882*4882a593Smuzhiyun if (alps_command_mode_send_nibble(psmouse, nibble))
1883*4882a593Smuzhiyun return -1;
1884*4882a593Smuzhiyun }
1885*4882a593Smuzhiyun
1886*4882a593Smuzhiyun return 0;
1887*4882a593Smuzhiyun }
1888*4882a593Smuzhiyun
alps_monitor_mode_write_reg(struct psmouse * psmouse,u16 addr,u16 value)1889*4882a593Smuzhiyun static int alps_monitor_mode_write_reg(struct psmouse *psmouse,
1890*4882a593Smuzhiyun u16 addr, u16 value)
1891*4882a593Smuzhiyun {
1892*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1893*4882a593Smuzhiyun
1894*4882a593Smuzhiyun /* 0x0A0 is the command to write the word */
1895*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE) ||
1896*4882a593Smuzhiyun alps_monitor_mode_send_word(psmouse, 0x0A0) ||
1897*4882a593Smuzhiyun alps_monitor_mode_send_word(psmouse, addr) ||
1898*4882a593Smuzhiyun alps_monitor_mode_send_word(psmouse, value) ||
1899*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE))
1900*4882a593Smuzhiyun return -1;
1901*4882a593Smuzhiyun
1902*4882a593Smuzhiyun return 0;
1903*4882a593Smuzhiyun }
1904*4882a593Smuzhiyun
alps_monitor_mode(struct psmouse * psmouse,bool enable)1905*4882a593Smuzhiyun static int alps_monitor_mode(struct psmouse *psmouse, bool enable)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1908*4882a593Smuzhiyun
1909*4882a593Smuzhiyun if (enable) {
1910*4882a593Smuzhiyun /* EC E9 F5 F5 E7 E6 E7 E9 to enter monitor mode */
1911*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
1912*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO) ||
1913*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1914*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1915*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
1916*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
1917*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
1918*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_GETINFO))
1919*4882a593Smuzhiyun return -1;
1920*4882a593Smuzhiyun } else {
1921*4882a593Smuzhiyun /* EC to exit monitor mode */
1922*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP))
1923*4882a593Smuzhiyun return -1;
1924*4882a593Smuzhiyun }
1925*4882a593Smuzhiyun
1926*4882a593Smuzhiyun return 0;
1927*4882a593Smuzhiyun }
1928*4882a593Smuzhiyun
alps_absolute_mode_v6(struct psmouse * psmouse)1929*4882a593Smuzhiyun static int alps_absolute_mode_v6(struct psmouse *psmouse)
1930*4882a593Smuzhiyun {
1931*4882a593Smuzhiyun u16 reg_val = 0x181;
1932*4882a593Smuzhiyun int ret;
1933*4882a593Smuzhiyun
1934*4882a593Smuzhiyun /* enter monitor mode, to write the register */
1935*4882a593Smuzhiyun if (alps_monitor_mode(psmouse, true))
1936*4882a593Smuzhiyun return -1;
1937*4882a593Smuzhiyun
1938*4882a593Smuzhiyun ret = alps_monitor_mode_write_reg(psmouse, 0x000, reg_val);
1939*4882a593Smuzhiyun
1940*4882a593Smuzhiyun if (alps_monitor_mode(psmouse, false))
1941*4882a593Smuzhiyun ret = -1;
1942*4882a593Smuzhiyun
1943*4882a593Smuzhiyun return ret;
1944*4882a593Smuzhiyun }
1945*4882a593Smuzhiyun
alps_get_status(struct psmouse * psmouse,char * param)1946*4882a593Smuzhiyun static int alps_get_status(struct psmouse *psmouse, char *param)
1947*4882a593Smuzhiyun {
1948*4882a593Smuzhiyun /* Get status: 0xF5 0xF5 0xF5 0xE9 */
1949*4882a593Smuzhiyun if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_DISABLE, param))
1950*4882a593Smuzhiyun return -1;
1951*4882a593Smuzhiyun
1952*4882a593Smuzhiyun return 0;
1953*4882a593Smuzhiyun }
1954*4882a593Smuzhiyun
1955*4882a593Smuzhiyun /*
1956*4882a593Smuzhiyun * Turn touchpad tapping on or off. The sequences are:
1957*4882a593Smuzhiyun * 0xE9 0xF5 0xF5 0xF3 0x0A to enable,
1958*4882a593Smuzhiyun * 0xE9 0xF5 0xF5 0xE8 0x00 to disable.
1959*4882a593Smuzhiyun * My guess that 0xE9 (GetInfo) is here as a sync point.
1960*4882a593Smuzhiyun * For models that also have stickpointer (DualPoints) its tapping
1961*4882a593Smuzhiyun * is controlled separately (0xE6 0xE6 0xE6 0xF3 0x14|0x0A) but
1962*4882a593Smuzhiyun * we don't fiddle with it.
1963*4882a593Smuzhiyun */
alps_tap_mode(struct psmouse * psmouse,int enable)1964*4882a593Smuzhiyun static int alps_tap_mode(struct psmouse *psmouse, int enable)
1965*4882a593Smuzhiyun {
1966*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
1967*4882a593Smuzhiyun int cmd = enable ? PSMOUSE_CMD_SETRATE : PSMOUSE_CMD_SETRES;
1968*4882a593Smuzhiyun unsigned char tap_arg = enable ? 0x0A : 0x00;
1969*4882a593Smuzhiyun unsigned char param[4];
1970*4882a593Smuzhiyun
1971*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO) ||
1972*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1973*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_DISABLE) ||
1974*4882a593Smuzhiyun ps2_command(ps2dev, &tap_arg, cmd))
1975*4882a593Smuzhiyun return -1;
1976*4882a593Smuzhiyun
1977*4882a593Smuzhiyun if (alps_get_status(psmouse, param))
1978*4882a593Smuzhiyun return -1;
1979*4882a593Smuzhiyun
1980*4882a593Smuzhiyun return 0;
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun
1983*4882a593Smuzhiyun /*
1984*4882a593Smuzhiyun * alps_poll() - poll the touchpad for current motion packet.
1985*4882a593Smuzhiyun * Used in resync.
1986*4882a593Smuzhiyun */
alps_poll(struct psmouse * psmouse)1987*4882a593Smuzhiyun static int alps_poll(struct psmouse *psmouse)
1988*4882a593Smuzhiyun {
1989*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
1990*4882a593Smuzhiyun unsigned char buf[sizeof(psmouse->packet)];
1991*4882a593Smuzhiyun bool poll_failed;
1992*4882a593Smuzhiyun
1993*4882a593Smuzhiyun if (priv->flags & ALPS_PASS)
1994*4882a593Smuzhiyun alps_passthrough_mode_v2(psmouse, true);
1995*4882a593Smuzhiyun
1996*4882a593Smuzhiyun poll_failed = ps2_command(&psmouse->ps2dev, buf,
1997*4882a593Smuzhiyun PSMOUSE_CMD_POLL | (psmouse->pktsize << 8)) < 0;
1998*4882a593Smuzhiyun
1999*4882a593Smuzhiyun if (priv->flags & ALPS_PASS)
2000*4882a593Smuzhiyun alps_passthrough_mode_v2(psmouse, false);
2001*4882a593Smuzhiyun
2002*4882a593Smuzhiyun if (poll_failed || (buf[0] & priv->mask0) != priv->byte0)
2003*4882a593Smuzhiyun return -1;
2004*4882a593Smuzhiyun
2005*4882a593Smuzhiyun if ((psmouse->badbyte & 0xc8) == 0x08) {
2006*4882a593Smuzhiyun /*
2007*4882a593Smuzhiyun * Poll the track stick ...
2008*4882a593Smuzhiyun */
2009*4882a593Smuzhiyun if (ps2_command(&psmouse->ps2dev, buf, PSMOUSE_CMD_POLL | (3 << 8)))
2010*4882a593Smuzhiyun return -1;
2011*4882a593Smuzhiyun }
2012*4882a593Smuzhiyun
2013*4882a593Smuzhiyun memcpy(psmouse->packet, buf, sizeof(buf));
2014*4882a593Smuzhiyun return 0;
2015*4882a593Smuzhiyun }
2016*4882a593Smuzhiyun
alps_hw_init_v1_v2(struct psmouse * psmouse)2017*4882a593Smuzhiyun static int alps_hw_init_v1_v2(struct psmouse *psmouse)
2018*4882a593Smuzhiyun {
2019*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2020*4882a593Smuzhiyun
2021*4882a593Smuzhiyun if ((priv->flags & ALPS_PASS) &&
2022*4882a593Smuzhiyun alps_passthrough_mode_v2(psmouse, true)) {
2023*4882a593Smuzhiyun return -1;
2024*4882a593Smuzhiyun }
2025*4882a593Smuzhiyun
2026*4882a593Smuzhiyun if (alps_tap_mode(psmouse, true)) {
2027*4882a593Smuzhiyun psmouse_warn(psmouse, "Failed to enable hardware tapping\n");
2028*4882a593Smuzhiyun return -1;
2029*4882a593Smuzhiyun }
2030*4882a593Smuzhiyun
2031*4882a593Smuzhiyun if (alps_absolute_mode_v1_v2(psmouse)) {
2032*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enable absolute mode\n");
2033*4882a593Smuzhiyun return -1;
2034*4882a593Smuzhiyun }
2035*4882a593Smuzhiyun
2036*4882a593Smuzhiyun if ((priv->flags & ALPS_PASS) &&
2037*4882a593Smuzhiyun alps_passthrough_mode_v2(psmouse, false)) {
2038*4882a593Smuzhiyun return -1;
2039*4882a593Smuzhiyun }
2040*4882a593Smuzhiyun
2041*4882a593Smuzhiyun /* ALPS needs stream mode, otherwise it won't report any data */
2042*4882a593Smuzhiyun if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSTREAM)) {
2043*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enable stream mode\n");
2044*4882a593Smuzhiyun return -1;
2045*4882a593Smuzhiyun }
2046*4882a593Smuzhiyun
2047*4882a593Smuzhiyun return 0;
2048*4882a593Smuzhiyun }
2049*4882a593Smuzhiyun
2050*4882a593Smuzhiyun /* Must be in passthrough mode when calling this function */
alps_trackstick_enter_extended_mode_v3_v6(struct psmouse * psmouse)2051*4882a593Smuzhiyun static int alps_trackstick_enter_extended_mode_v3_v6(struct psmouse *psmouse)
2052*4882a593Smuzhiyun {
2053*4882a593Smuzhiyun unsigned char param[2] = {0xC8, 0x14};
2054*4882a593Smuzhiyun
2055*4882a593Smuzhiyun if (ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
2056*4882a593Smuzhiyun ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
2057*4882a593Smuzhiyun ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_SETSCALE11) ||
2058*4882a593Smuzhiyun ps2_command(&psmouse->ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
2059*4882a593Smuzhiyun ps2_command(&psmouse->ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE))
2060*4882a593Smuzhiyun return -1;
2061*4882a593Smuzhiyun
2062*4882a593Smuzhiyun return 0;
2063*4882a593Smuzhiyun }
2064*4882a593Smuzhiyun
alps_hw_init_v6(struct psmouse * psmouse)2065*4882a593Smuzhiyun static int alps_hw_init_v6(struct psmouse *psmouse)
2066*4882a593Smuzhiyun {
2067*4882a593Smuzhiyun int ret;
2068*4882a593Smuzhiyun
2069*4882a593Smuzhiyun /* Enter passthrough mode to let trackpoint enter 6byte raw mode */
2070*4882a593Smuzhiyun if (alps_passthrough_mode_v2(psmouse, true))
2071*4882a593Smuzhiyun return -1;
2072*4882a593Smuzhiyun
2073*4882a593Smuzhiyun ret = alps_trackstick_enter_extended_mode_v3_v6(psmouse);
2074*4882a593Smuzhiyun
2075*4882a593Smuzhiyun if (alps_passthrough_mode_v2(psmouse, false))
2076*4882a593Smuzhiyun return -1;
2077*4882a593Smuzhiyun
2078*4882a593Smuzhiyun if (ret)
2079*4882a593Smuzhiyun return ret;
2080*4882a593Smuzhiyun
2081*4882a593Smuzhiyun if (alps_absolute_mode_v6(psmouse)) {
2082*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enable absolute mode\n");
2083*4882a593Smuzhiyun return -1;
2084*4882a593Smuzhiyun }
2085*4882a593Smuzhiyun
2086*4882a593Smuzhiyun return 0;
2087*4882a593Smuzhiyun }
2088*4882a593Smuzhiyun
2089*4882a593Smuzhiyun /*
2090*4882a593Smuzhiyun * Enable or disable passthrough mode to the trackstick.
2091*4882a593Smuzhiyun */
alps_passthrough_mode_v3(struct psmouse * psmouse,int reg_base,bool enable)2092*4882a593Smuzhiyun static int alps_passthrough_mode_v3(struct psmouse *psmouse,
2093*4882a593Smuzhiyun int reg_base, bool enable)
2094*4882a593Smuzhiyun {
2095*4882a593Smuzhiyun int reg_val, ret = -1;
2096*4882a593Smuzhiyun
2097*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse))
2098*4882a593Smuzhiyun return -1;
2099*4882a593Smuzhiyun
2100*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x0008);
2101*4882a593Smuzhiyun if (reg_val == -1)
2102*4882a593Smuzhiyun goto error;
2103*4882a593Smuzhiyun
2104*4882a593Smuzhiyun if (enable)
2105*4882a593Smuzhiyun reg_val |= 0x01;
2106*4882a593Smuzhiyun else
2107*4882a593Smuzhiyun reg_val &= ~0x01;
2108*4882a593Smuzhiyun
2109*4882a593Smuzhiyun ret = __alps_command_mode_write_reg(psmouse, reg_val);
2110*4882a593Smuzhiyun
2111*4882a593Smuzhiyun error:
2112*4882a593Smuzhiyun if (alps_exit_command_mode(psmouse))
2113*4882a593Smuzhiyun ret = -1;
2114*4882a593Smuzhiyun return ret;
2115*4882a593Smuzhiyun }
2116*4882a593Smuzhiyun
2117*4882a593Smuzhiyun /* Must be in command mode when calling this function */
alps_absolute_mode_v3(struct psmouse * psmouse)2118*4882a593Smuzhiyun static int alps_absolute_mode_v3(struct psmouse *psmouse)
2119*4882a593Smuzhiyun {
2120*4882a593Smuzhiyun int reg_val;
2121*4882a593Smuzhiyun
2122*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
2123*4882a593Smuzhiyun if (reg_val == -1)
2124*4882a593Smuzhiyun return -1;
2125*4882a593Smuzhiyun
2126*4882a593Smuzhiyun reg_val |= 0x06;
2127*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val))
2128*4882a593Smuzhiyun return -1;
2129*4882a593Smuzhiyun
2130*4882a593Smuzhiyun return 0;
2131*4882a593Smuzhiyun }
2132*4882a593Smuzhiyun
alps_probe_trackstick_v3_v7(struct psmouse * psmouse,int reg_base)2133*4882a593Smuzhiyun static int alps_probe_trackstick_v3_v7(struct psmouse *psmouse, int reg_base)
2134*4882a593Smuzhiyun {
2135*4882a593Smuzhiyun int ret = -EIO, reg_val;
2136*4882a593Smuzhiyun
2137*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse))
2138*4882a593Smuzhiyun goto error;
2139*4882a593Smuzhiyun
2140*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
2141*4882a593Smuzhiyun if (reg_val == -1)
2142*4882a593Smuzhiyun goto error;
2143*4882a593Smuzhiyun
2144*4882a593Smuzhiyun /* bit 7: trackstick is present */
2145*4882a593Smuzhiyun ret = reg_val & 0x80 ? 0 : -ENODEV;
2146*4882a593Smuzhiyun
2147*4882a593Smuzhiyun error:
2148*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2149*4882a593Smuzhiyun return ret;
2150*4882a593Smuzhiyun }
2151*4882a593Smuzhiyun
alps_setup_trackstick_v3(struct psmouse * psmouse,int reg_base)2152*4882a593Smuzhiyun static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
2153*4882a593Smuzhiyun {
2154*4882a593Smuzhiyun int ret = 0;
2155*4882a593Smuzhiyun int reg_val;
2156*4882a593Smuzhiyun unsigned char param[4];
2157*4882a593Smuzhiyun
2158*4882a593Smuzhiyun /*
2159*4882a593Smuzhiyun * We need to configure trackstick to report data for touchpad in
2160*4882a593Smuzhiyun * extended format. And also we need to tell touchpad to expect data
2161*4882a593Smuzhiyun * from trackstick in extended format. Without this configuration
2162*4882a593Smuzhiyun * trackstick packets sent from touchpad are in basic format which is
2163*4882a593Smuzhiyun * different from what we expect.
2164*4882a593Smuzhiyun */
2165*4882a593Smuzhiyun
2166*4882a593Smuzhiyun if (alps_passthrough_mode_v3(psmouse, reg_base, true))
2167*4882a593Smuzhiyun return -EIO;
2168*4882a593Smuzhiyun
2169*4882a593Smuzhiyun /*
2170*4882a593Smuzhiyun * E7 report for the trackstick
2171*4882a593Smuzhiyun *
2172*4882a593Smuzhiyun * There have been reports of failures to seem to trace back
2173*4882a593Smuzhiyun * to the above trackstick check failing. When these occur
2174*4882a593Smuzhiyun * this E7 report fails, so when that happens we continue
2175*4882a593Smuzhiyun * with the assumption that there isn't a trackstick after
2176*4882a593Smuzhiyun * all.
2177*4882a593Smuzhiyun */
2178*4882a593Smuzhiyun if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
2179*4882a593Smuzhiyun psmouse_warn(psmouse, "Failed to initialize trackstick (E7 report failed)\n");
2180*4882a593Smuzhiyun ret = -ENODEV;
2181*4882a593Smuzhiyun } else {
2182*4882a593Smuzhiyun psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param);
2183*4882a593Smuzhiyun if (alps_trackstick_enter_extended_mode_v3_v6(psmouse)) {
2184*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enter into trackstick extended mode\n");
2185*4882a593Smuzhiyun ret = -EIO;
2186*4882a593Smuzhiyun }
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun
2189*4882a593Smuzhiyun if (alps_passthrough_mode_v3(psmouse, reg_base, false))
2190*4882a593Smuzhiyun return -EIO;
2191*4882a593Smuzhiyun
2192*4882a593Smuzhiyun if (ret)
2193*4882a593Smuzhiyun return ret;
2194*4882a593Smuzhiyun
2195*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse))
2196*4882a593Smuzhiyun return -EIO;
2197*4882a593Smuzhiyun
2198*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, reg_base + 0x08);
2199*4882a593Smuzhiyun if (reg_val == -1) {
2200*4882a593Smuzhiyun ret = -EIO;
2201*4882a593Smuzhiyun } else {
2202*4882a593Smuzhiyun /*
2203*4882a593Smuzhiyun * Tell touchpad that trackstick is now in extended mode.
2204*4882a593Smuzhiyun * If bit 1 isn't set the packet format is different.
2205*4882a593Smuzhiyun */
2206*4882a593Smuzhiyun reg_val |= BIT(1);
2207*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val))
2208*4882a593Smuzhiyun ret = -EIO;
2209*4882a593Smuzhiyun }
2210*4882a593Smuzhiyun
2211*4882a593Smuzhiyun if (alps_exit_command_mode(psmouse))
2212*4882a593Smuzhiyun return -EIO;
2213*4882a593Smuzhiyun
2214*4882a593Smuzhiyun return ret;
2215*4882a593Smuzhiyun }
2216*4882a593Smuzhiyun
alps_hw_init_v3(struct psmouse * psmouse)2217*4882a593Smuzhiyun static int alps_hw_init_v3(struct psmouse *psmouse)
2218*4882a593Smuzhiyun {
2219*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2220*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2221*4882a593Smuzhiyun int reg_val;
2222*4882a593Smuzhiyun unsigned char param[4];
2223*4882a593Smuzhiyun
2224*4882a593Smuzhiyun if ((priv->flags & ALPS_DUALPOINT) &&
2225*4882a593Smuzhiyun alps_setup_trackstick_v3(psmouse, ALPS_REG_BASE_PINNACLE) == -EIO)
2226*4882a593Smuzhiyun goto error;
2227*4882a593Smuzhiyun
2228*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse) ||
2229*4882a593Smuzhiyun alps_absolute_mode_v3(psmouse)) {
2230*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enter absolute mode\n");
2231*4882a593Smuzhiyun goto error;
2232*4882a593Smuzhiyun }
2233*4882a593Smuzhiyun
2234*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0x0006);
2235*4882a593Smuzhiyun if (reg_val == -1)
2236*4882a593Smuzhiyun goto error;
2237*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
2238*4882a593Smuzhiyun goto error;
2239*4882a593Smuzhiyun
2240*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0x0007);
2241*4882a593Smuzhiyun if (reg_val == -1)
2242*4882a593Smuzhiyun goto error;
2243*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val | 0x01))
2244*4882a593Smuzhiyun goto error;
2245*4882a593Smuzhiyun
2246*4882a593Smuzhiyun if (alps_command_mode_read_reg(psmouse, 0x0144) == -1)
2247*4882a593Smuzhiyun goto error;
2248*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, 0x04))
2249*4882a593Smuzhiyun goto error;
2250*4882a593Smuzhiyun
2251*4882a593Smuzhiyun if (alps_command_mode_read_reg(psmouse, 0x0159) == -1)
2252*4882a593Smuzhiyun goto error;
2253*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, 0x03))
2254*4882a593Smuzhiyun goto error;
2255*4882a593Smuzhiyun
2256*4882a593Smuzhiyun if (alps_command_mode_read_reg(psmouse, 0x0163) == -1)
2257*4882a593Smuzhiyun goto error;
2258*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0163, 0x03))
2259*4882a593Smuzhiyun goto error;
2260*4882a593Smuzhiyun
2261*4882a593Smuzhiyun if (alps_command_mode_read_reg(psmouse, 0x0162) == -1)
2262*4882a593Smuzhiyun goto error;
2263*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0162, 0x04))
2264*4882a593Smuzhiyun goto error;
2265*4882a593Smuzhiyun
2266*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2267*4882a593Smuzhiyun
2268*4882a593Smuzhiyun /* Set rate and enable data reporting */
2269*4882a593Smuzhiyun param[0] = 0x64;
2270*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
2271*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
2272*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enable data reporting\n");
2273*4882a593Smuzhiyun return -1;
2274*4882a593Smuzhiyun }
2275*4882a593Smuzhiyun
2276*4882a593Smuzhiyun return 0;
2277*4882a593Smuzhiyun
2278*4882a593Smuzhiyun error:
2279*4882a593Smuzhiyun /*
2280*4882a593Smuzhiyun * Leaving the touchpad in command mode will essentially render
2281*4882a593Smuzhiyun * it unusable until the machine reboots, so exit it here just
2282*4882a593Smuzhiyun * to be safe
2283*4882a593Smuzhiyun */
2284*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2285*4882a593Smuzhiyun return -1;
2286*4882a593Smuzhiyun }
2287*4882a593Smuzhiyun
alps_get_v3_v7_resolution(struct psmouse * psmouse,int reg_pitch)2288*4882a593Smuzhiyun static int alps_get_v3_v7_resolution(struct psmouse *psmouse, int reg_pitch)
2289*4882a593Smuzhiyun {
2290*4882a593Smuzhiyun int reg, x_pitch, y_pitch, x_electrode, y_electrode, x_phys, y_phys;
2291*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2292*4882a593Smuzhiyun
2293*4882a593Smuzhiyun reg = alps_command_mode_read_reg(psmouse, reg_pitch);
2294*4882a593Smuzhiyun if (reg < 0)
2295*4882a593Smuzhiyun return reg;
2296*4882a593Smuzhiyun
2297*4882a593Smuzhiyun x_pitch = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
2298*4882a593Smuzhiyun x_pitch = 50 + 2 * x_pitch; /* In 0.1 mm units */
2299*4882a593Smuzhiyun
2300*4882a593Smuzhiyun y_pitch = (char)reg >> 4; /* sign extend upper 4 bits */
2301*4882a593Smuzhiyun y_pitch = 36 + 2 * y_pitch; /* In 0.1 mm units */
2302*4882a593Smuzhiyun
2303*4882a593Smuzhiyun reg = alps_command_mode_read_reg(psmouse, reg_pitch + 1);
2304*4882a593Smuzhiyun if (reg < 0)
2305*4882a593Smuzhiyun return reg;
2306*4882a593Smuzhiyun
2307*4882a593Smuzhiyun x_electrode = (char)(reg << 4) >> 4; /* sign extend lower 4 bits */
2308*4882a593Smuzhiyun x_electrode = 17 + x_electrode;
2309*4882a593Smuzhiyun
2310*4882a593Smuzhiyun y_electrode = (char)reg >> 4; /* sign extend upper 4 bits */
2311*4882a593Smuzhiyun y_electrode = 13 + y_electrode;
2312*4882a593Smuzhiyun
2313*4882a593Smuzhiyun x_phys = x_pitch * (x_electrode - 1); /* In 0.1 mm units */
2314*4882a593Smuzhiyun y_phys = y_pitch * (y_electrode - 1); /* In 0.1 mm units */
2315*4882a593Smuzhiyun
2316*4882a593Smuzhiyun priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
2317*4882a593Smuzhiyun priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
2318*4882a593Smuzhiyun
2319*4882a593Smuzhiyun psmouse_dbg(psmouse,
2320*4882a593Smuzhiyun "pitch %dx%d num-electrodes %dx%d physical size %dx%d mm res %dx%d\n",
2321*4882a593Smuzhiyun x_pitch, y_pitch, x_electrode, y_electrode,
2322*4882a593Smuzhiyun x_phys / 10, y_phys / 10, priv->x_res, priv->y_res);
2323*4882a593Smuzhiyun
2324*4882a593Smuzhiyun return 0;
2325*4882a593Smuzhiyun }
2326*4882a593Smuzhiyun
alps_hw_init_rushmore_v3(struct psmouse * psmouse)2327*4882a593Smuzhiyun static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
2328*4882a593Smuzhiyun {
2329*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2330*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2331*4882a593Smuzhiyun int reg_val, ret = -1;
2332*4882a593Smuzhiyun
2333*4882a593Smuzhiyun if (priv->flags & ALPS_DUALPOINT) {
2334*4882a593Smuzhiyun reg_val = alps_setup_trackstick_v3(psmouse,
2335*4882a593Smuzhiyun ALPS_REG_BASE_RUSHMORE);
2336*4882a593Smuzhiyun if (reg_val == -EIO)
2337*4882a593Smuzhiyun goto error;
2338*4882a593Smuzhiyun }
2339*4882a593Smuzhiyun
2340*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse) ||
2341*4882a593Smuzhiyun alps_command_mode_read_reg(psmouse, 0xc2d9) == -1 ||
2342*4882a593Smuzhiyun alps_command_mode_write_reg(psmouse, 0xc2cb, 0x00))
2343*4882a593Smuzhiyun goto error;
2344*4882a593Smuzhiyun
2345*4882a593Smuzhiyun if (alps_get_v3_v7_resolution(psmouse, 0xc2da))
2346*4882a593Smuzhiyun goto error;
2347*4882a593Smuzhiyun
2348*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0xc2c6);
2349*4882a593Smuzhiyun if (reg_val == -1)
2350*4882a593Smuzhiyun goto error;
2351*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val & 0xfd))
2352*4882a593Smuzhiyun goto error;
2353*4882a593Smuzhiyun
2354*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
2355*4882a593Smuzhiyun goto error;
2356*4882a593Smuzhiyun
2357*4882a593Smuzhiyun /* enter absolute mode */
2358*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
2359*4882a593Smuzhiyun if (reg_val == -1)
2360*4882a593Smuzhiyun goto error;
2361*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
2362*4882a593Smuzhiyun goto error;
2363*4882a593Smuzhiyun
2364*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2365*4882a593Smuzhiyun return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
2366*4882a593Smuzhiyun
2367*4882a593Smuzhiyun error:
2368*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2369*4882a593Smuzhiyun return ret;
2370*4882a593Smuzhiyun }
2371*4882a593Smuzhiyun
2372*4882a593Smuzhiyun /* Must be in command mode when calling this function */
alps_absolute_mode_v4(struct psmouse * psmouse)2373*4882a593Smuzhiyun static int alps_absolute_mode_v4(struct psmouse *psmouse)
2374*4882a593Smuzhiyun {
2375*4882a593Smuzhiyun int reg_val;
2376*4882a593Smuzhiyun
2377*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0x0004);
2378*4882a593Smuzhiyun if (reg_val == -1)
2379*4882a593Smuzhiyun return -1;
2380*4882a593Smuzhiyun
2381*4882a593Smuzhiyun reg_val |= 0x02;
2382*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val))
2383*4882a593Smuzhiyun return -1;
2384*4882a593Smuzhiyun
2385*4882a593Smuzhiyun return 0;
2386*4882a593Smuzhiyun }
2387*4882a593Smuzhiyun
alps_hw_init_v4(struct psmouse * psmouse)2388*4882a593Smuzhiyun static int alps_hw_init_v4(struct psmouse *psmouse)
2389*4882a593Smuzhiyun {
2390*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2391*4882a593Smuzhiyun unsigned char param[4];
2392*4882a593Smuzhiyun
2393*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse))
2394*4882a593Smuzhiyun goto error;
2395*4882a593Smuzhiyun
2396*4882a593Smuzhiyun if (alps_absolute_mode_v4(psmouse)) {
2397*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enter absolute mode\n");
2398*4882a593Smuzhiyun goto error;
2399*4882a593Smuzhiyun }
2400*4882a593Smuzhiyun
2401*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0007, 0x8c))
2402*4882a593Smuzhiyun goto error;
2403*4882a593Smuzhiyun
2404*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0149, 0x03))
2405*4882a593Smuzhiyun goto error;
2406*4882a593Smuzhiyun
2407*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0160, 0x03))
2408*4882a593Smuzhiyun goto error;
2409*4882a593Smuzhiyun
2410*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x017f, 0x15))
2411*4882a593Smuzhiyun goto error;
2412*4882a593Smuzhiyun
2413*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0151, 0x01))
2414*4882a593Smuzhiyun goto error;
2415*4882a593Smuzhiyun
2416*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0168, 0x03))
2417*4882a593Smuzhiyun goto error;
2418*4882a593Smuzhiyun
2419*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x014a, 0x03))
2420*4882a593Smuzhiyun goto error;
2421*4882a593Smuzhiyun
2422*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0x0161, 0x03))
2423*4882a593Smuzhiyun goto error;
2424*4882a593Smuzhiyun
2425*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2426*4882a593Smuzhiyun
2427*4882a593Smuzhiyun /*
2428*4882a593Smuzhiyun * This sequence changes the output from a 9-byte to an
2429*4882a593Smuzhiyun * 8-byte format. All the same data seems to be present,
2430*4882a593Smuzhiyun * just in a more compact format.
2431*4882a593Smuzhiyun */
2432*4882a593Smuzhiyun param[0] = 0xc8;
2433*4882a593Smuzhiyun param[1] = 0x64;
2434*4882a593Smuzhiyun param[2] = 0x50;
2435*4882a593Smuzhiyun if (ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
2436*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE) ||
2437*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[2], PSMOUSE_CMD_SETRATE) ||
2438*4882a593Smuzhiyun ps2_command(ps2dev, param, PSMOUSE_CMD_GETID))
2439*4882a593Smuzhiyun return -1;
2440*4882a593Smuzhiyun
2441*4882a593Smuzhiyun /* Set rate and enable data reporting */
2442*4882a593Smuzhiyun param[0] = 0x64;
2443*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRATE) ||
2444*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE)) {
2445*4882a593Smuzhiyun psmouse_err(psmouse, "Failed to enable data reporting\n");
2446*4882a593Smuzhiyun return -1;
2447*4882a593Smuzhiyun }
2448*4882a593Smuzhiyun
2449*4882a593Smuzhiyun return 0;
2450*4882a593Smuzhiyun
2451*4882a593Smuzhiyun error:
2452*4882a593Smuzhiyun /*
2453*4882a593Smuzhiyun * Leaving the touchpad in command mode will essentially render
2454*4882a593Smuzhiyun * it unusable until the machine reboots, so exit it here just
2455*4882a593Smuzhiyun * to be safe
2456*4882a593Smuzhiyun */
2457*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2458*4882a593Smuzhiyun return -1;
2459*4882a593Smuzhiyun }
2460*4882a593Smuzhiyun
alps_get_otp_values_ss4_v2(struct psmouse * psmouse,unsigned char index,unsigned char otp[])2461*4882a593Smuzhiyun static int alps_get_otp_values_ss4_v2(struct psmouse *psmouse,
2462*4882a593Smuzhiyun unsigned char index, unsigned char otp[])
2463*4882a593Smuzhiyun {
2464*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2465*4882a593Smuzhiyun
2466*4882a593Smuzhiyun switch (index) {
2467*4882a593Smuzhiyun case 0:
2468*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
2469*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
2470*4882a593Smuzhiyun ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
2471*4882a593Smuzhiyun return -1;
2472*4882a593Smuzhiyun
2473*4882a593Smuzhiyun break;
2474*4882a593Smuzhiyun
2475*4882a593Smuzhiyun case 1:
2476*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
2477*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
2478*4882a593Smuzhiyun ps2_command(ps2dev, otp, PSMOUSE_CMD_GETINFO))
2479*4882a593Smuzhiyun return -1;
2480*4882a593Smuzhiyun
2481*4882a593Smuzhiyun break;
2482*4882a593Smuzhiyun }
2483*4882a593Smuzhiyun
2484*4882a593Smuzhiyun return 0;
2485*4882a593Smuzhiyun }
2486*4882a593Smuzhiyun
alps_update_device_area_ss4_v2(unsigned char otp[][4],struct alps_data * priv)2487*4882a593Smuzhiyun static int alps_update_device_area_ss4_v2(unsigned char otp[][4],
2488*4882a593Smuzhiyun struct alps_data *priv)
2489*4882a593Smuzhiyun {
2490*4882a593Smuzhiyun int num_x_electrode;
2491*4882a593Smuzhiyun int num_y_electrode;
2492*4882a593Smuzhiyun int x_pitch, y_pitch, x_phys, y_phys;
2493*4882a593Smuzhiyun
2494*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
2495*4882a593Smuzhiyun num_x_electrode =
2496*4882a593Smuzhiyun SS4PLUS_NUMSENSOR_XOFFSET + (otp[0][2] & 0x0F);
2497*4882a593Smuzhiyun num_y_electrode =
2498*4882a593Smuzhiyun SS4PLUS_NUMSENSOR_YOFFSET + ((otp[0][2] >> 4) & 0x0F);
2499*4882a593Smuzhiyun
2500*4882a593Smuzhiyun priv->x_max =
2501*4882a593Smuzhiyun (num_x_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
2502*4882a593Smuzhiyun priv->y_max =
2503*4882a593Smuzhiyun (num_y_electrode - 1) * SS4PLUS_COUNT_PER_ELECTRODE;
2504*4882a593Smuzhiyun
2505*4882a593Smuzhiyun x_pitch = (otp[0][1] & 0x0F) + SS4PLUS_MIN_PITCH_MM;
2506*4882a593Smuzhiyun y_pitch = ((otp[0][1] >> 4) & 0x0F) + SS4PLUS_MIN_PITCH_MM;
2507*4882a593Smuzhiyun
2508*4882a593Smuzhiyun } else {
2509*4882a593Smuzhiyun num_x_electrode =
2510*4882a593Smuzhiyun SS4_NUMSENSOR_XOFFSET + (otp[1][0] & 0x0F);
2511*4882a593Smuzhiyun num_y_electrode =
2512*4882a593Smuzhiyun SS4_NUMSENSOR_YOFFSET + ((otp[1][0] >> 4) & 0x0F);
2513*4882a593Smuzhiyun
2514*4882a593Smuzhiyun priv->x_max =
2515*4882a593Smuzhiyun (num_x_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
2516*4882a593Smuzhiyun priv->y_max =
2517*4882a593Smuzhiyun (num_y_electrode - 1) * SS4_COUNT_PER_ELECTRODE;
2518*4882a593Smuzhiyun
2519*4882a593Smuzhiyun x_pitch = ((otp[1][2] >> 2) & 0x07) + SS4_MIN_PITCH_MM;
2520*4882a593Smuzhiyun y_pitch = ((otp[1][2] >> 5) & 0x07) + SS4_MIN_PITCH_MM;
2521*4882a593Smuzhiyun }
2522*4882a593Smuzhiyun
2523*4882a593Smuzhiyun x_phys = x_pitch * (num_x_electrode - 1); /* In 0.1 mm units */
2524*4882a593Smuzhiyun y_phys = y_pitch * (num_y_electrode - 1); /* In 0.1 mm units */
2525*4882a593Smuzhiyun
2526*4882a593Smuzhiyun priv->x_res = priv->x_max * 10 / x_phys; /* units / mm */
2527*4882a593Smuzhiyun priv->y_res = priv->y_max * 10 / y_phys; /* units / mm */
2528*4882a593Smuzhiyun
2529*4882a593Smuzhiyun return 0;
2530*4882a593Smuzhiyun }
2531*4882a593Smuzhiyun
alps_update_btn_info_ss4_v2(unsigned char otp[][4],struct alps_data * priv)2532*4882a593Smuzhiyun static int alps_update_btn_info_ss4_v2(unsigned char otp[][4],
2533*4882a593Smuzhiyun struct alps_data *priv)
2534*4882a593Smuzhiyun {
2535*4882a593Smuzhiyun unsigned char is_btnless;
2536*4882a593Smuzhiyun
2537*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id))
2538*4882a593Smuzhiyun is_btnless = (otp[1][0] >> 1) & 0x01;
2539*4882a593Smuzhiyun else
2540*4882a593Smuzhiyun is_btnless = (otp[1][1] >> 3) & 0x01;
2541*4882a593Smuzhiyun
2542*4882a593Smuzhiyun if (is_btnless)
2543*4882a593Smuzhiyun priv->flags |= ALPS_BUTTONPAD;
2544*4882a593Smuzhiyun
2545*4882a593Smuzhiyun return 0;
2546*4882a593Smuzhiyun }
2547*4882a593Smuzhiyun
alps_update_dual_info_ss4_v2(unsigned char otp[][4],struct alps_data * priv,struct psmouse * psmouse)2548*4882a593Smuzhiyun static int alps_update_dual_info_ss4_v2(unsigned char otp[][4],
2549*4882a593Smuzhiyun struct alps_data *priv,
2550*4882a593Smuzhiyun struct psmouse *psmouse)
2551*4882a593Smuzhiyun {
2552*4882a593Smuzhiyun bool is_dual = false;
2553*4882a593Smuzhiyun int reg_val = 0;
2554*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2555*4882a593Smuzhiyun
2556*4882a593Smuzhiyun if (IS_SS4PLUS_DEV(priv->dev_id)) {
2557*4882a593Smuzhiyun is_dual = (otp[0][0] >> 4) & 0x01;
2558*4882a593Smuzhiyun
2559*4882a593Smuzhiyun if (!is_dual) {
2560*4882a593Smuzhiyun /* For support TrackStick of Thinkpad L/E series */
2561*4882a593Smuzhiyun if (alps_exit_command_mode(psmouse) == 0 &&
2562*4882a593Smuzhiyun alps_enter_command_mode(psmouse) == 0) {
2563*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse,
2564*4882a593Smuzhiyun 0xD7);
2565*4882a593Smuzhiyun }
2566*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2567*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
2568*4882a593Smuzhiyun
2569*4882a593Smuzhiyun if (reg_val == 0x0C || reg_val == 0x1D)
2570*4882a593Smuzhiyun is_dual = true;
2571*4882a593Smuzhiyun }
2572*4882a593Smuzhiyun }
2573*4882a593Smuzhiyun
2574*4882a593Smuzhiyun if (is_dual)
2575*4882a593Smuzhiyun priv->flags |= ALPS_DUALPOINT |
2576*4882a593Smuzhiyun ALPS_DUALPOINT_WITH_PRESSURE;
2577*4882a593Smuzhiyun
2578*4882a593Smuzhiyun return 0;
2579*4882a593Smuzhiyun }
2580*4882a593Smuzhiyun
alps_set_defaults_ss4_v2(struct psmouse * psmouse,struct alps_data * priv)2581*4882a593Smuzhiyun static int alps_set_defaults_ss4_v2(struct psmouse *psmouse,
2582*4882a593Smuzhiyun struct alps_data *priv)
2583*4882a593Smuzhiyun {
2584*4882a593Smuzhiyun unsigned char otp[2][4];
2585*4882a593Smuzhiyun
2586*4882a593Smuzhiyun memset(otp, 0, sizeof(otp));
2587*4882a593Smuzhiyun
2588*4882a593Smuzhiyun if (alps_get_otp_values_ss4_v2(psmouse, 1, &otp[1][0]) ||
2589*4882a593Smuzhiyun alps_get_otp_values_ss4_v2(psmouse, 0, &otp[0][0]))
2590*4882a593Smuzhiyun return -1;
2591*4882a593Smuzhiyun
2592*4882a593Smuzhiyun alps_update_device_area_ss4_v2(otp, priv);
2593*4882a593Smuzhiyun
2594*4882a593Smuzhiyun alps_update_btn_info_ss4_v2(otp, priv);
2595*4882a593Smuzhiyun
2596*4882a593Smuzhiyun alps_update_dual_info_ss4_v2(otp, priv, psmouse);
2597*4882a593Smuzhiyun
2598*4882a593Smuzhiyun return 0;
2599*4882a593Smuzhiyun }
2600*4882a593Smuzhiyun
alps_dolphin_get_device_area(struct psmouse * psmouse,struct alps_data * priv)2601*4882a593Smuzhiyun static int alps_dolphin_get_device_area(struct psmouse *psmouse,
2602*4882a593Smuzhiyun struct alps_data *priv)
2603*4882a593Smuzhiyun {
2604*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2605*4882a593Smuzhiyun unsigned char param[4] = {0};
2606*4882a593Smuzhiyun int num_x_electrode, num_y_electrode;
2607*4882a593Smuzhiyun
2608*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse))
2609*4882a593Smuzhiyun return -1;
2610*4882a593Smuzhiyun
2611*4882a593Smuzhiyun param[0] = 0x0a;
2612*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_RESET_WRAP) ||
2613*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
2614*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETPOLL) ||
2615*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
2616*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE))
2617*4882a593Smuzhiyun return -1;
2618*4882a593Smuzhiyun
2619*4882a593Smuzhiyun if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
2620*4882a593Smuzhiyun return -1;
2621*4882a593Smuzhiyun
2622*4882a593Smuzhiyun /*
2623*4882a593Smuzhiyun * Dolphin's sensor line number is not fixed. It can be calculated
2624*4882a593Smuzhiyun * by adding the device's register value with DOLPHIN_PROFILE_X/YOFFSET.
2625*4882a593Smuzhiyun * Further more, we can get device's x_max and y_max by multiplying
2626*4882a593Smuzhiyun * sensor line number with DOLPHIN_COUNT_PER_ELECTRODE.
2627*4882a593Smuzhiyun *
2628*4882a593Smuzhiyun * e.g. When we get register's sensor_x = 11 & sensor_y = 8,
2629*4882a593Smuzhiyun * real sensor line number X = 11 + 8 = 19, and
2630*4882a593Smuzhiyun * real sensor line number Y = 8 + 1 = 9.
2631*4882a593Smuzhiyun * So, x_max = (19 - 1) * 64 = 1152, and
2632*4882a593Smuzhiyun * y_max = (9 - 1) * 64 = 512.
2633*4882a593Smuzhiyun */
2634*4882a593Smuzhiyun num_x_electrode = DOLPHIN_PROFILE_XOFFSET + (param[2] & 0x0F);
2635*4882a593Smuzhiyun num_y_electrode = DOLPHIN_PROFILE_YOFFSET + ((param[2] >> 4) & 0x0F);
2636*4882a593Smuzhiyun priv->x_bits = num_x_electrode;
2637*4882a593Smuzhiyun priv->y_bits = num_y_electrode;
2638*4882a593Smuzhiyun priv->x_max = (num_x_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
2639*4882a593Smuzhiyun priv->y_max = (num_y_electrode - 1) * DOLPHIN_COUNT_PER_ELECTRODE;
2640*4882a593Smuzhiyun
2641*4882a593Smuzhiyun if (alps_exit_command_mode(psmouse))
2642*4882a593Smuzhiyun return -1;
2643*4882a593Smuzhiyun
2644*4882a593Smuzhiyun return 0;
2645*4882a593Smuzhiyun }
2646*4882a593Smuzhiyun
alps_hw_init_dolphin_v1(struct psmouse * psmouse)2647*4882a593Smuzhiyun static int alps_hw_init_dolphin_v1(struct psmouse *psmouse)
2648*4882a593Smuzhiyun {
2649*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2650*4882a593Smuzhiyun unsigned char param[2];
2651*4882a593Smuzhiyun
2652*4882a593Smuzhiyun /* This is dolphin "v1" as empirically defined by florin9doi */
2653*4882a593Smuzhiyun param[0] = 0x64;
2654*4882a593Smuzhiyun param[1] = 0x28;
2655*4882a593Smuzhiyun
2656*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
2657*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
2658*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE))
2659*4882a593Smuzhiyun return -1;
2660*4882a593Smuzhiyun
2661*4882a593Smuzhiyun return 0;
2662*4882a593Smuzhiyun }
2663*4882a593Smuzhiyun
alps_hw_init_v7(struct psmouse * psmouse)2664*4882a593Smuzhiyun static int alps_hw_init_v7(struct psmouse *psmouse)
2665*4882a593Smuzhiyun {
2666*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2667*4882a593Smuzhiyun int reg_val, ret = -1;
2668*4882a593Smuzhiyun
2669*4882a593Smuzhiyun if (alps_enter_command_mode(psmouse) ||
2670*4882a593Smuzhiyun alps_command_mode_read_reg(psmouse, 0xc2d9) == -1)
2671*4882a593Smuzhiyun goto error;
2672*4882a593Smuzhiyun
2673*4882a593Smuzhiyun if (alps_get_v3_v7_resolution(psmouse, 0xc397))
2674*4882a593Smuzhiyun goto error;
2675*4882a593Smuzhiyun
2676*4882a593Smuzhiyun if (alps_command_mode_write_reg(psmouse, 0xc2c9, 0x64))
2677*4882a593Smuzhiyun goto error;
2678*4882a593Smuzhiyun
2679*4882a593Smuzhiyun reg_val = alps_command_mode_read_reg(psmouse, 0xc2c4);
2680*4882a593Smuzhiyun if (reg_val == -1)
2681*4882a593Smuzhiyun goto error;
2682*4882a593Smuzhiyun if (__alps_command_mode_write_reg(psmouse, reg_val | 0x02))
2683*4882a593Smuzhiyun goto error;
2684*4882a593Smuzhiyun
2685*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2686*4882a593Smuzhiyun return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
2687*4882a593Smuzhiyun
2688*4882a593Smuzhiyun error:
2689*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2690*4882a593Smuzhiyun return ret;
2691*4882a593Smuzhiyun }
2692*4882a593Smuzhiyun
alps_hw_init_ss4_v2(struct psmouse * psmouse)2693*4882a593Smuzhiyun static int alps_hw_init_ss4_v2(struct psmouse *psmouse)
2694*4882a593Smuzhiyun {
2695*4882a593Smuzhiyun struct ps2dev *ps2dev = &psmouse->ps2dev;
2696*4882a593Smuzhiyun char param[2] = {0x64, 0x28};
2697*4882a593Smuzhiyun int ret = -1;
2698*4882a593Smuzhiyun
2699*4882a593Smuzhiyun /* enter absolute mode */
2700*4882a593Smuzhiyun if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
2701*4882a593Smuzhiyun ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSTREAM) ||
2702*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[0], PSMOUSE_CMD_SETRATE) ||
2703*4882a593Smuzhiyun ps2_command(ps2dev, ¶m[1], PSMOUSE_CMD_SETRATE)) {
2704*4882a593Smuzhiyun goto error;
2705*4882a593Smuzhiyun }
2706*4882a593Smuzhiyun
2707*4882a593Smuzhiyun /* T.B.D. Decread noise packet number, delete in the future */
2708*4882a593Smuzhiyun if (alps_exit_command_mode(psmouse) ||
2709*4882a593Smuzhiyun alps_enter_command_mode(psmouse) ||
2710*4882a593Smuzhiyun alps_command_mode_write_reg(psmouse, 0x001D, 0x20)) {
2711*4882a593Smuzhiyun goto error;
2712*4882a593Smuzhiyun }
2713*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2714*4882a593Smuzhiyun
2715*4882a593Smuzhiyun return ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE);
2716*4882a593Smuzhiyun
2717*4882a593Smuzhiyun error:
2718*4882a593Smuzhiyun alps_exit_command_mode(psmouse);
2719*4882a593Smuzhiyun return ret;
2720*4882a593Smuzhiyun }
2721*4882a593Smuzhiyun
alps_set_protocol(struct psmouse * psmouse,struct alps_data * priv,const struct alps_protocol_info * protocol)2722*4882a593Smuzhiyun static int alps_set_protocol(struct psmouse *psmouse,
2723*4882a593Smuzhiyun struct alps_data *priv,
2724*4882a593Smuzhiyun const struct alps_protocol_info *protocol)
2725*4882a593Smuzhiyun {
2726*4882a593Smuzhiyun psmouse->private = priv;
2727*4882a593Smuzhiyun
2728*4882a593Smuzhiyun timer_setup(&priv->timer, alps_flush_packet, 0);
2729*4882a593Smuzhiyun
2730*4882a593Smuzhiyun priv->proto_version = protocol->version;
2731*4882a593Smuzhiyun priv->byte0 = protocol->byte0;
2732*4882a593Smuzhiyun priv->mask0 = protocol->mask0;
2733*4882a593Smuzhiyun priv->flags = protocol->flags;
2734*4882a593Smuzhiyun
2735*4882a593Smuzhiyun priv->x_max = 2000;
2736*4882a593Smuzhiyun priv->y_max = 1400;
2737*4882a593Smuzhiyun priv->x_bits = 15;
2738*4882a593Smuzhiyun priv->y_bits = 11;
2739*4882a593Smuzhiyun
2740*4882a593Smuzhiyun switch (priv->proto_version) {
2741*4882a593Smuzhiyun case ALPS_PROTO_V1:
2742*4882a593Smuzhiyun case ALPS_PROTO_V2:
2743*4882a593Smuzhiyun priv->hw_init = alps_hw_init_v1_v2;
2744*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v1_v2;
2745*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_st;
2746*4882a593Smuzhiyun priv->x_max = 1023;
2747*4882a593Smuzhiyun priv->y_max = 767;
2748*4882a593Smuzhiyun if (dmi_check_system(alps_dmi_has_separate_stick_buttons))
2749*4882a593Smuzhiyun priv->flags |= ALPS_STICK_BITS;
2750*4882a593Smuzhiyun break;
2751*4882a593Smuzhiyun
2752*4882a593Smuzhiyun case ALPS_PROTO_V3:
2753*4882a593Smuzhiyun priv->hw_init = alps_hw_init_v3;
2754*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v3;
2755*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_semi_mt;
2756*4882a593Smuzhiyun priv->decode_fields = alps_decode_pinnacle;
2757*4882a593Smuzhiyun priv->nibble_commands = alps_v3_nibble_commands;
2758*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2759*4882a593Smuzhiyun
2760*4882a593Smuzhiyun if (alps_probe_trackstick_v3_v7(psmouse,
2761*4882a593Smuzhiyun ALPS_REG_BASE_PINNACLE) < 0)
2762*4882a593Smuzhiyun priv->flags &= ~ALPS_DUALPOINT;
2763*4882a593Smuzhiyun
2764*4882a593Smuzhiyun break;
2765*4882a593Smuzhiyun
2766*4882a593Smuzhiyun case ALPS_PROTO_V3_RUSHMORE:
2767*4882a593Smuzhiyun priv->hw_init = alps_hw_init_rushmore_v3;
2768*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v3;
2769*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_semi_mt;
2770*4882a593Smuzhiyun priv->decode_fields = alps_decode_rushmore;
2771*4882a593Smuzhiyun priv->nibble_commands = alps_v3_nibble_commands;
2772*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2773*4882a593Smuzhiyun priv->x_bits = 16;
2774*4882a593Smuzhiyun priv->y_bits = 12;
2775*4882a593Smuzhiyun
2776*4882a593Smuzhiyun if (alps_probe_trackstick_v3_v7(psmouse,
2777*4882a593Smuzhiyun ALPS_REG_BASE_RUSHMORE) < 0)
2778*4882a593Smuzhiyun priv->flags &= ~ALPS_DUALPOINT;
2779*4882a593Smuzhiyun
2780*4882a593Smuzhiyun break;
2781*4882a593Smuzhiyun
2782*4882a593Smuzhiyun case ALPS_PROTO_V4:
2783*4882a593Smuzhiyun priv->hw_init = alps_hw_init_v4;
2784*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v4;
2785*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_semi_mt;
2786*4882a593Smuzhiyun priv->nibble_commands = alps_v4_nibble_commands;
2787*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_DISABLE;
2788*4882a593Smuzhiyun break;
2789*4882a593Smuzhiyun
2790*4882a593Smuzhiyun case ALPS_PROTO_V5:
2791*4882a593Smuzhiyun priv->hw_init = alps_hw_init_dolphin_v1;
2792*4882a593Smuzhiyun priv->process_packet = alps_process_touchpad_packet_v3_v5;
2793*4882a593Smuzhiyun priv->decode_fields = alps_decode_dolphin;
2794*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_semi_mt;
2795*4882a593Smuzhiyun priv->nibble_commands = alps_v3_nibble_commands;
2796*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2797*4882a593Smuzhiyun priv->x_bits = 23;
2798*4882a593Smuzhiyun priv->y_bits = 12;
2799*4882a593Smuzhiyun
2800*4882a593Smuzhiyun if (alps_dolphin_get_device_area(psmouse, priv))
2801*4882a593Smuzhiyun return -EIO;
2802*4882a593Smuzhiyun
2803*4882a593Smuzhiyun break;
2804*4882a593Smuzhiyun
2805*4882a593Smuzhiyun case ALPS_PROTO_V6:
2806*4882a593Smuzhiyun priv->hw_init = alps_hw_init_v6;
2807*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v6;
2808*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_st;
2809*4882a593Smuzhiyun priv->nibble_commands = alps_v6_nibble_commands;
2810*4882a593Smuzhiyun priv->x_max = 2047;
2811*4882a593Smuzhiyun priv->y_max = 1535;
2812*4882a593Smuzhiyun break;
2813*4882a593Smuzhiyun
2814*4882a593Smuzhiyun case ALPS_PROTO_V7:
2815*4882a593Smuzhiyun priv->hw_init = alps_hw_init_v7;
2816*4882a593Smuzhiyun priv->process_packet = alps_process_packet_v7;
2817*4882a593Smuzhiyun priv->decode_fields = alps_decode_packet_v7;
2818*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_v7;
2819*4882a593Smuzhiyun priv->nibble_commands = alps_v3_nibble_commands;
2820*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2821*4882a593Smuzhiyun priv->x_max = 0xfff;
2822*4882a593Smuzhiyun priv->y_max = 0x7ff;
2823*4882a593Smuzhiyun
2824*4882a593Smuzhiyun if (priv->fw_ver[1] != 0xba)
2825*4882a593Smuzhiyun priv->flags |= ALPS_BUTTONPAD;
2826*4882a593Smuzhiyun
2827*4882a593Smuzhiyun if (alps_probe_trackstick_v3_v7(psmouse, ALPS_REG_BASE_V7) < 0)
2828*4882a593Smuzhiyun priv->flags &= ~ALPS_DUALPOINT;
2829*4882a593Smuzhiyun
2830*4882a593Smuzhiyun break;
2831*4882a593Smuzhiyun
2832*4882a593Smuzhiyun case ALPS_PROTO_V8:
2833*4882a593Smuzhiyun priv->hw_init = alps_hw_init_ss4_v2;
2834*4882a593Smuzhiyun priv->process_packet = alps_process_packet_ss4_v2;
2835*4882a593Smuzhiyun priv->decode_fields = alps_decode_ss4_v2;
2836*4882a593Smuzhiyun priv->set_abs_params = alps_set_abs_params_ss4_v2;
2837*4882a593Smuzhiyun priv->nibble_commands = alps_v3_nibble_commands;
2838*4882a593Smuzhiyun priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
2839*4882a593Smuzhiyun
2840*4882a593Smuzhiyun if (alps_set_defaults_ss4_v2(psmouse, priv))
2841*4882a593Smuzhiyun return -EIO;
2842*4882a593Smuzhiyun
2843*4882a593Smuzhiyun break;
2844*4882a593Smuzhiyun }
2845*4882a593Smuzhiyun
2846*4882a593Smuzhiyun return 0;
2847*4882a593Smuzhiyun }
2848*4882a593Smuzhiyun
alps_match_table(unsigned char * e7,unsigned char * ec)2849*4882a593Smuzhiyun static const struct alps_protocol_info *alps_match_table(unsigned char *e7,
2850*4882a593Smuzhiyun unsigned char *ec)
2851*4882a593Smuzhiyun {
2852*4882a593Smuzhiyun const struct alps_model_info *model;
2853*4882a593Smuzhiyun int i;
2854*4882a593Smuzhiyun
2855*4882a593Smuzhiyun for (i = 0; i < ARRAY_SIZE(alps_model_data); i++) {
2856*4882a593Smuzhiyun model = &alps_model_data[i];
2857*4882a593Smuzhiyun
2858*4882a593Smuzhiyun if (!memcmp(e7, model->signature, sizeof(model->signature)))
2859*4882a593Smuzhiyun return &model->protocol_info;
2860*4882a593Smuzhiyun }
2861*4882a593Smuzhiyun
2862*4882a593Smuzhiyun return NULL;
2863*4882a593Smuzhiyun }
2864*4882a593Smuzhiyun
alps_is_cs19_trackpoint(struct psmouse * psmouse)2865*4882a593Smuzhiyun static bool alps_is_cs19_trackpoint(struct psmouse *psmouse)
2866*4882a593Smuzhiyun {
2867*4882a593Smuzhiyun u8 param[2] = { 0 };
2868*4882a593Smuzhiyun
2869*4882a593Smuzhiyun if (ps2_command(&psmouse->ps2dev,
2870*4882a593Smuzhiyun param, MAKE_PS2_CMD(0, 2, TP_READ_ID)))
2871*4882a593Smuzhiyun return false;
2872*4882a593Smuzhiyun
2873*4882a593Smuzhiyun /*
2874*4882a593Smuzhiyun * param[0] contains the trackpoint device variant_id while
2875*4882a593Smuzhiyun * param[1] contains the firmware_id. So far all alps
2876*4882a593Smuzhiyun * trackpoint-only devices have their variant_ids equal
2877*4882a593Smuzhiyun * TP_VARIANT_ALPS and their firmware_ids are in 0x20~0x2f range.
2878*4882a593Smuzhiyun */
2879*4882a593Smuzhiyun return param[0] == TP_VARIANT_ALPS && ((param[1] & 0xf0) == 0x20);
2880*4882a593Smuzhiyun }
2881*4882a593Smuzhiyun
alps_identify(struct psmouse * psmouse,struct alps_data * priv)2882*4882a593Smuzhiyun static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
2883*4882a593Smuzhiyun {
2884*4882a593Smuzhiyun const struct alps_protocol_info *protocol;
2885*4882a593Smuzhiyun unsigned char e6[4], e7[4], ec[4];
2886*4882a593Smuzhiyun int error;
2887*4882a593Smuzhiyun
2888*4882a593Smuzhiyun /*
2889*4882a593Smuzhiyun * First try "E6 report".
2890*4882a593Smuzhiyun * ALPS should return 0,0,10 or 0,0,100 if no buttons are pressed.
2891*4882a593Smuzhiyun * The bits 0-2 of the first byte will be 1s if some buttons are
2892*4882a593Smuzhiyun * pressed.
2893*4882a593Smuzhiyun */
2894*4882a593Smuzhiyun if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
2895*4882a593Smuzhiyun PSMOUSE_CMD_SETSCALE11, e6))
2896*4882a593Smuzhiyun return -EIO;
2897*4882a593Smuzhiyun
2898*4882a593Smuzhiyun if ((e6[0] & 0xf8) != 0 || e6[1] != 0 || (e6[2] != 10 && e6[2] != 100))
2899*4882a593Smuzhiyun return -EINVAL;
2900*4882a593Smuzhiyun
2901*4882a593Smuzhiyun /*
2902*4882a593Smuzhiyun * Now get the "E7" and "EC" reports. These will uniquely identify
2903*4882a593Smuzhiyun * most ALPS touchpads.
2904*4882a593Smuzhiyun */
2905*4882a593Smuzhiyun if (alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
2906*4882a593Smuzhiyun PSMOUSE_CMD_SETSCALE21, e7) ||
2907*4882a593Smuzhiyun alps_rpt_cmd(psmouse, PSMOUSE_CMD_SETRES,
2908*4882a593Smuzhiyun PSMOUSE_CMD_RESET_WRAP, ec) ||
2909*4882a593Smuzhiyun alps_exit_command_mode(psmouse))
2910*4882a593Smuzhiyun return -EIO;
2911*4882a593Smuzhiyun
2912*4882a593Smuzhiyun protocol = alps_match_table(e7, ec);
2913*4882a593Smuzhiyun if (!protocol) {
2914*4882a593Smuzhiyun if (e7[0] == 0x73 && e7[1] == 0x02 && e7[2] == 0x64 &&
2915*4882a593Smuzhiyun ec[2] == 0x8a) {
2916*4882a593Smuzhiyun protocol = &alps_v4_protocol_data;
2917*4882a593Smuzhiyun } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
2918*4882a593Smuzhiyun ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
2919*4882a593Smuzhiyun protocol = &alps_v5_protocol_data;
2920*4882a593Smuzhiyun } else if (ec[0] == 0x88 &&
2921*4882a593Smuzhiyun ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
2922*4882a593Smuzhiyun protocol = &alps_v7_protocol_data;
2923*4882a593Smuzhiyun } else if (ec[0] == 0x88 && ec[1] == 0x08) {
2924*4882a593Smuzhiyun protocol = &alps_v3_rushmore_data;
2925*4882a593Smuzhiyun } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
2926*4882a593Smuzhiyun ec[2] >= 0x90 && ec[2] <= 0x9d) {
2927*4882a593Smuzhiyun protocol = &alps_v3_protocol_data;
2928*4882a593Smuzhiyun } else if (e7[0] == 0x73 && e7[1] == 0x03 &&
2929*4882a593Smuzhiyun (e7[2] == 0x14 || e7[2] == 0x28)) {
2930*4882a593Smuzhiyun protocol = &alps_v8_protocol_data;
2931*4882a593Smuzhiyun } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0xc8) {
2932*4882a593Smuzhiyun protocol = &alps_v9_protocol_data;
2933*4882a593Smuzhiyun psmouse_warn(psmouse,
2934*4882a593Smuzhiyun "Unsupported ALPS V9 touchpad: E7=%3ph, EC=%3ph\n",
2935*4882a593Smuzhiyun e7, ec);
2936*4882a593Smuzhiyun return -EINVAL;
2937*4882a593Smuzhiyun } else {
2938*4882a593Smuzhiyun psmouse_dbg(psmouse,
2939*4882a593Smuzhiyun "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
2940*4882a593Smuzhiyun return -EINVAL;
2941*4882a593Smuzhiyun }
2942*4882a593Smuzhiyun }
2943*4882a593Smuzhiyun
2944*4882a593Smuzhiyun if (priv) {
2945*4882a593Smuzhiyun /* Save Device ID and Firmware version */
2946*4882a593Smuzhiyun memcpy(priv->dev_id, e7, 3);
2947*4882a593Smuzhiyun memcpy(priv->fw_ver, ec, 3);
2948*4882a593Smuzhiyun error = alps_set_protocol(psmouse, priv, protocol);
2949*4882a593Smuzhiyun if (error)
2950*4882a593Smuzhiyun return error;
2951*4882a593Smuzhiyun }
2952*4882a593Smuzhiyun
2953*4882a593Smuzhiyun return 0;
2954*4882a593Smuzhiyun }
2955*4882a593Smuzhiyun
alps_reconnect(struct psmouse * psmouse)2956*4882a593Smuzhiyun static int alps_reconnect(struct psmouse *psmouse)
2957*4882a593Smuzhiyun {
2958*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2959*4882a593Smuzhiyun
2960*4882a593Smuzhiyun psmouse_reset(psmouse);
2961*4882a593Smuzhiyun
2962*4882a593Smuzhiyun if (alps_identify(psmouse, priv) < 0)
2963*4882a593Smuzhiyun return -1;
2964*4882a593Smuzhiyun
2965*4882a593Smuzhiyun return priv->hw_init(psmouse);
2966*4882a593Smuzhiyun }
2967*4882a593Smuzhiyun
alps_disconnect(struct psmouse * psmouse)2968*4882a593Smuzhiyun static void alps_disconnect(struct psmouse *psmouse)
2969*4882a593Smuzhiyun {
2970*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
2971*4882a593Smuzhiyun
2972*4882a593Smuzhiyun psmouse_reset(psmouse);
2973*4882a593Smuzhiyun del_timer_sync(&priv->timer);
2974*4882a593Smuzhiyun if (priv->dev2)
2975*4882a593Smuzhiyun input_unregister_device(priv->dev2);
2976*4882a593Smuzhiyun if (!IS_ERR_OR_NULL(priv->dev3))
2977*4882a593Smuzhiyun input_unregister_device(priv->dev3);
2978*4882a593Smuzhiyun kfree(priv);
2979*4882a593Smuzhiyun }
2980*4882a593Smuzhiyun
alps_set_abs_params_st(struct alps_data * priv,struct input_dev * dev1)2981*4882a593Smuzhiyun static void alps_set_abs_params_st(struct alps_data *priv,
2982*4882a593Smuzhiyun struct input_dev *dev1)
2983*4882a593Smuzhiyun {
2984*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_X, 0, priv->x_max, 0, 0);
2985*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_Y, 0, priv->y_max, 0, 0);
2986*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
2987*4882a593Smuzhiyun }
2988*4882a593Smuzhiyun
alps_set_abs_params_mt_common(struct alps_data * priv,struct input_dev * dev1)2989*4882a593Smuzhiyun static void alps_set_abs_params_mt_common(struct alps_data *priv,
2990*4882a593Smuzhiyun struct input_dev *dev1)
2991*4882a593Smuzhiyun {
2992*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
2993*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
2994*4882a593Smuzhiyun
2995*4882a593Smuzhiyun input_abs_set_res(dev1, ABS_MT_POSITION_X, priv->x_res);
2996*4882a593Smuzhiyun input_abs_set_res(dev1, ABS_MT_POSITION_Y, priv->y_res);
2997*4882a593Smuzhiyun
2998*4882a593Smuzhiyun set_bit(BTN_TOOL_TRIPLETAP, dev1->keybit);
2999*4882a593Smuzhiyun set_bit(BTN_TOOL_QUADTAP, dev1->keybit);
3000*4882a593Smuzhiyun }
3001*4882a593Smuzhiyun
alps_set_abs_params_semi_mt(struct alps_data * priv,struct input_dev * dev1)3002*4882a593Smuzhiyun static void alps_set_abs_params_semi_mt(struct alps_data *priv,
3003*4882a593Smuzhiyun struct input_dev *dev1)
3004*4882a593Smuzhiyun {
3005*4882a593Smuzhiyun alps_set_abs_params_mt_common(priv, dev1);
3006*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
3007*4882a593Smuzhiyun
3008*4882a593Smuzhiyun input_mt_init_slots(dev1, MAX_TOUCHES,
3009*4882a593Smuzhiyun INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
3010*4882a593Smuzhiyun INPUT_MT_SEMI_MT);
3011*4882a593Smuzhiyun }
3012*4882a593Smuzhiyun
alps_set_abs_params_v7(struct alps_data * priv,struct input_dev * dev1)3013*4882a593Smuzhiyun static void alps_set_abs_params_v7(struct alps_data *priv,
3014*4882a593Smuzhiyun struct input_dev *dev1)
3015*4882a593Smuzhiyun {
3016*4882a593Smuzhiyun alps_set_abs_params_mt_common(priv, dev1);
3017*4882a593Smuzhiyun set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
3018*4882a593Smuzhiyun
3019*4882a593Smuzhiyun input_mt_init_slots(dev1, MAX_TOUCHES,
3020*4882a593Smuzhiyun INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
3021*4882a593Smuzhiyun INPUT_MT_TRACK);
3022*4882a593Smuzhiyun
3023*4882a593Smuzhiyun set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
3024*4882a593Smuzhiyun }
3025*4882a593Smuzhiyun
alps_set_abs_params_ss4_v2(struct alps_data * priv,struct input_dev * dev1)3026*4882a593Smuzhiyun static void alps_set_abs_params_ss4_v2(struct alps_data *priv,
3027*4882a593Smuzhiyun struct input_dev *dev1)
3028*4882a593Smuzhiyun {
3029*4882a593Smuzhiyun alps_set_abs_params_mt_common(priv, dev1);
3030*4882a593Smuzhiyun input_set_abs_params(dev1, ABS_PRESSURE, 0, 127, 0, 0);
3031*4882a593Smuzhiyun set_bit(BTN_TOOL_QUINTTAP, dev1->keybit);
3032*4882a593Smuzhiyun
3033*4882a593Smuzhiyun input_mt_init_slots(dev1, MAX_TOUCHES,
3034*4882a593Smuzhiyun INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED |
3035*4882a593Smuzhiyun INPUT_MT_TRACK);
3036*4882a593Smuzhiyun }
3037*4882a593Smuzhiyun
alps_init(struct psmouse * psmouse)3038*4882a593Smuzhiyun int alps_init(struct psmouse *psmouse)
3039*4882a593Smuzhiyun {
3040*4882a593Smuzhiyun struct alps_data *priv = psmouse->private;
3041*4882a593Smuzhiyun struct input_dev *dev1 = psmouse->dev;
3042*4882a593Smuzhiyun int error;
3043*4882a593Smuzhiyun
3044*4882a593Smuzhiyun error = priv->hw_init(psmouse);
3045*4882a593Smuzhiyun if (error)
3046*4882a593Smuzhiyun goto init_fail;
3047*4882a593Smuzhiyun
3048*4882a593Smuzhiyun /*
3049*4882a593Smuzhiyun * Undo part of setup done for us by psmouse core since touchpad
3050*4882a593Smuzhiyun * is not a relative device.
3051*4882a593Smuzhiyun */
3052*4882a593Smuzhiyun __clear_bit(EV_REL, dev1->evbit);
3053*4882a593Smuzhiyun __clear_bit(REL_X, dev1->relbit);
3054*4882a593Smuzhiyun __clear_bit(REL_Y, dev1->relbit);
3055*4882a593Smuzhiyun
3056*4882a593Smuzhiyun /*
3057*4882a593Smuzhiyun * Now set up our capabilities.
3058*4882a593Smuzhiyun */
3059*4882a593Smuzhiyun dev1->evbit[BIT_WORD(EV_KEY)] |= BIT_MASK(EV_KEY);
3060*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_TOUCH)] |= BIT_MASK(BTN_TOUCH);
3061*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_TOOL_FINGER)] |= BIT_MASK(BTN_TOOL_FINGER);
3062*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_LEFT)] |=
3063*4882a593Smuzhiyun BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_RIGHT);
3064*4882a593Smuzhiyun
3065*4882a593Smuzhiyun dev1->evbit[BIT_WORD(EV_ABS)] |= BIT_MASK(EV_ABS);
3066*4882a593Smuzhiyun
3067*4882a593Smuzhiyun priv->set_abs_params(priv, dev1);
3068*4882a593Smuzhiyun
3069*4882a593Smuzhiyun if (priv->flags & ALPS_WHEEL) {
3070*4882a593Smuzhiyun dev1->evbit[BIT_WORD(EV_REL)] |= BIT_MASK(EV_REL);
3071*4882a593Smuzhiyun dev1->relbit[BIT_WORD(REL_WHEEL)] |= BIT_MASK(REL_WHEEL);
3072*4882a593Smuzhiyun }
3073*4882a593Smuzhiyun
3074*4882a593Smuzhiyun if (priv->flags & (ALPS_FW_BK_1 | ALPS_FW_BK_2)) {
3075*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_FORWARD)] |= BIT_MASK(BTN_FORWARD);
3076*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_BACK)] |= BIT_MASK(BTN_BACK);
3077*4882a593Smuzhiyun }
3078*4882a593Smuzhiyun
3079*4882a593Smuzhiyun if (priv->flags & ALPS_FOUR_BUTTONS) {
3080*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_0)] |= BIT_MASK(BTN_0);
3081*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_1)] |= BIT_MASK(BTN_1);
3082*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_2)] |= BIT_MASK(BTN_2);
3083*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_3)] |= BIT_MASK(BTN_3);
3084*4882a593Smuzhiyun } else if (priv->flags & ALPS_BUTTONPAD) {
3085*4882a593Smuzhiyun set_bit(INPUT_PROP_BUTTONPAD, dev1->propbit);
3086*4882a593Smuzhiyun clear_bit(BTN_RIGHT, dev1->keybit);
3087*4882a593Smuzhiyun } else {
3088*4882a593Smuzhiyun dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
3089*4882a593Smuzhiyun }
3090*4882a593Smuzhiyun
3091*4882a593Smuzhiyun if (priv->flags & ALPS_DUALPOINT) {
3092*4882a593Smuzhiyun struct input_dev *dev2;
3093*4882a593Smuzhiyun
3094*4882a593Smuzhiyun dev2 = input_allocate_device();
3095*4882a593Smuzhiyun if (!dev2) {
3096*4882a593Smuzhiyun psmouse_err(psmouse,
3097*4882a593Smuzhiyun "failed to allocate trackstick device\n");
3098*4882a593Smuzhiyun error = -ENOMEM;
3099*4882a593Smuzhiyun goto init_fail;
3100*4882a593Smuzhiyun }
3101*4882a593Smuzhiyun
3102*4882a593Smuzhiyun snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1",
3103*4882a593Smuzhiyun psmouse->ps2dev.serio->phys);
3104*4882a593Smuzhiyun dev2->phys = priv->phys2;
3105*4882a593Smuzhiyun
3106*4882a593Smuzhiyun /*
3107*4882a593Smuzhiyun * format of input device name is: "protocol vendor name"
3108*4882a593Smuzhiyun * see function psmouse_switch_protocol() in psmouse-base.c
3109*4882a593Smuzhiyun */
3110*4882a593Smuzhiyun dev2->name = "AlpsPS/2 ALPS DualPoint Stick";
3111*4882a593Smuzhiyun
3112*4882a593Smuzhiyun dev2->id.bustype = BUS_I8042;
3113*4882a593Smuzhiyun dev2->id.vendor = 0x0002;
3114*4882a593Smuzhiyun dev2->id.product = PSMOUSE_ALPS;
3115*4882a593Smuzhiyun dev2->id.version = priv->proto_version;
3116*4882a593Smuzhiyun dev2->dev.parent = &psmouse->ps2dev.serio->dev;
3117*4882a593Smuzhiyun
3118*4882a593Smuzhiyun input_set_capability(dev2, EV_REL, REL_X);
3119*4882a593Smuzhiyun input_set_capability(dev2, EV_REL, REL_Y);
3120*4882a593Smuzhiyun if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) {
3121*4882a593Smuzhiyun input_set_capability(dev2, EV_ABS, ABS_PRESSURE);
3122*4882a593Smuzhiyun input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0);
3123*4882a593Smuzhiyun }
3124*4882a593Smuzhiyun input_set_capability(dev2, EV_KEY, BTN_LEFT);
3125*4882a593Smuzhiyun input_set_capability(dev2, EV_KEY, BTN_RIGHT);
3126*4882a593Smuzhiyun input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
3127*4882a593Smuzhiyun
3128*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTER, dev2->propbit);
3129*4882a593Smuzhiyun __set_bit(INPUT_PROP_POINTING_STICK, dev2->propbit);
3130*4882a593Smuzhiyun
3131*4882a593Smuzhiyun error = input_register_device(dev2);
3132*4882a593Smuzhiyun if (error) {
3133*4882a593Smuzhiyun psmouse_err(psmouse,
3134*4882a593Smuzhiyun "failed to register trackstick device: %d\n",
3135*4882a593Smuzhiyun error);
3136*4882a593Smuzhiyun input_free_device(dev2);
3137*4882a593Smuzhiyun goto init_fail;
3138*4882a593Smuzhiyun }
3139*4882a593Smuzhiyun
3140*4882a593Smuzhiyun priv->dev2 = dev2;
3141*4882a593Smuzhiyun }
3142*4882a593Smuzhiyun
3143*4882a593Smuzhiyun priv->psmouse = psmouse;
3144*4882a593Smuzhiyun
3145*4882a593Smuzhiyun INIT_DELAYED_WORK(&priv->dev3_register_work,
3146*4882a593Smuzhiyun alps_register_bare_ps2_mouse);
3147*4882a593Smuzhiyun
3148*4882a593Smuzhiyun psmouse->protocol_handler = alps_process_byte;
3149*4882a593Smuzhiyun psmouse->poll = alps_poll;
3150*4882a593Smuzhiyun psmouse->disconnect = alps_disconnect;
3151*4882a593Smuzhiyun psmouse->reconnect = alps_reconnect;
3152*4882a593Smuzhiyun psmouse->pktsize = priv->proto_version == ALPS_PROTO_V4 ? 8 : 6;
3153*4882a593Smuzhiyun
3154*4882a593Smuzhiyun /* We are having trouble resyncing ALPS touchpads so disable it for now */
3155*4882a593Smuzhiyun psmouse->resync_time = 0;
3156*4882a593Smuzhiyun
3157*4882a593Smuzhiyun /* Allow 2 invalid packets without resetting device */
3158*4882a593Smuzhiyun psmouse->resetafter = psmouse->pktsize * 2;
3159*4882a593Smuzhiyun
3160*4882a593Smuzhiyun return 0;
3161*4882a593Smuzhiyun
3162*4882a593Smuzhiyun init_fail:
3163*4882a593Smuzhiyun psmouse_reset(psmouse);
3164*4882a593Smuzhiyun /*
3165*4882a593Smuzhiyun * Even though we did not allocate psmouse->private we do free
3166*4882a593Smuzhiyun * it here.
3167*4882a593Smuzhiyun */
3168*4882a593Smuzhiyun kfree(psmouse->private);
3169*4882a593Smuzhiyun psmouse->private = NULL;
3170*4882a593Smuzhiyun return error;
3171*4882a593Smuzhiyun }
3172*4882a593Smuzhiyun
alps_detect(struct psmouse * psmouse,bool set_properties)3173*4882a593Smuzhiyun int alps_detect(struct psmouse *psmouse, bool set_properties)
3174*4882a593Smuzhiyun {
3175*4882a593Smuzhiyun struct alps_data *priv;
3176*4882a593Smuzhiyun int error;
3177*4882a593Smuzhiyun
3178*4882a593Smuzhiyun error = alps_identify(psmouse, NULL);
3179*4882a593Smuzhiyun if (error)
3180*4882a593Smuzhiyun return error;
3181*4882a593Smuzhiyun
3182*4882a593Smuzhiyun /*
3183*4882a593Smuzhiyun * ALPS cs19 is a trackpoint-only device, and uses different
3184*4882a593Smuzhiyun * protocol than DualPoint ones, so we return -EINVAL here and let
3185*4882a593Smuzhiyun * trackpoint.c drive this device. If the trackpoint driver is not
3186*4882a593Smuzhiyun * enabled, the device will fall back to a bare PS/2 mouse.
3187*4882a593Smuzhiyun * If ps2_command() fails here, we depend on the immediately
3188*4882a593Smuzhiyun * followed psmouse_reset() to reset the device to normal state.
3189*4882a593Smuzhiyun */
3190*4882a593Smuzhiyun if (alps_is_cs19_trackpoint(psmouse)) {
3191*4882a593Smuzhiyun psmouse_dbg(psmouse,
3192*4882a593Smuzhiyun "ALPS CS19 trackpoint-only device detected, ignoring\n");
3193*4882a593Smuzhiyun return -EINVAL;
3194*4882a593Smuzhiyun }
3195*4882a593Smuzhiyun
3196*4882a593Smuzhiyun /*
3197*4882a593Smuzhiyun * Reset the device to make sure it is fully operational:
3198*4882a593Smuzhiyun * on some laptops, like certain Dell Latitudes, we may
3199*4882a593Smuzhiyun * fail to properly detect presence of trackstick if device
3200*4882a593Smuzhiyun * has not been reset.
3201*4882a593Smuzhiyun */
3202*4882a593Smuzhiyun psmouse_reset(psmouse);
3203*4882a593Smuzhiyun
3204*4882a593Smuzhiyun priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
3205*4882a593Smuzhiyun if (!priv)
3206*4882a593Smuzhiyun return -ENOMEM;
3207*4882a593Smuzhiyun
3208*4882a593Smuzhiyun error = alps_identify(psmouse, priv);
3209*4882a593Smuzhiyun if (error) {
3210*4882a593Smuzhiyun kfree(priv);
3211*4882a593Smuzhiyun return error;
3212*4882a593Smuzhiyun }
3213*4882a593Smuzhiyun
3214*4882a593Smuzhiyun if (set_properties) {
3215*4882a593Smuzhiyun psmouse->vendor = "ALPS";
3216*4882a593Smuzhiyun psmouse->name = priv->flags & ALPS_DUALPOINT ?
3217*4882a593Smuzhiyun "DualPoint TouchPad" : "GlidePoint";
3218*4882a593Smuzhiyun psmouse->model = priv->proto_version;
3219*4882a593Smuzhiyun } else {
3220*4882a593Smuzhiyun /*
3221*4882a593Smuzhiyun * Destroy alps_data structure we allocated earlier since
3222*4882a593Smuzhiyun * this was just a "trial run". Otherwise we'll keep it
3223*4882a593Smuzhiyun * to be used by alps_init() which has to be called if
3224*4882a593Smuzhiyun * we succeed and set_properties is true.
3225*4882a593Smuzhiyun */
3226*4882a593Smuzhiyun kfree(priv);
3227*4882a593Smuzhiyun psmouse->private = NULL;
3228*4882a593Smuzhiyun }
3229*4882a593Smuzhiyun
3230*4882a593Smuzhiyun return 0;
3231*4882a593Smuzhiyun }
3232*4882a593Smuzhiyun
3233